1;;; gEDA - GPL Electronic Design Automation
2;;; gnetlist - gEDA Netlist
3;;; Copyright (C) 1998-2010 Ales Hvezda
4;;; Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
5;;;
6;;; This program is free software; you can redistribute it and/or modify
7;;; it under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 2 of the License, or
9;;; (at your option) any later version.
10;;;
11;;; This program is distributed in the hope that it will be useful,
12;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with this program; if not, write to the Free Software
18;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19;;; MA 02111-1301 USA.
20
21;;
22;; Verilog netlist backend written by Mike Jarabek starts here
23;;
24;; 14 July 2011 - VERY basic concatenation support added by Frank Thomson
25;;
26;; --------------------------------------------------------------------------
27
28;; some useful regexes for working with net-names
29;;
30(use-modules (ice-9 regex))
31
32(define id-regexp "[a-zA-Z_][a-zA-Z0-9_$]*")
33(define numeric  "[0-9]+")
34;; match on a verilog concatened net like:  {netname[x:y],othernet}
35;; Will not expand a bus for replication so
36(define concat-bus-reg (make-regexp
37		       (string-append "^[[:space:]]*"
38				      "\\{"
39				      ".*"
40				      "\\}")))
41
42;; match on a verilog identifier like:  netname[x:y]
43(define bit-range-reg (make-regexp
44		       (string-append "^(" id-regexp ")[[:space:]]*"
45				      "\\["
46				      "[[:space:]]*(" numeric ")[[:space:]]*"
47				      ":"
48				      "[[:space:]]*(" numeric ")[[:space:]]*"
49				      "\\]")))
50
51;; match on a verilog identifier like:  netname[x]
52(define single-bit-reg (make-regexp
53			(string-append "^(" id-regexp ")[[:space:]]*"
54				       "\\["
55				       "[[:space:]]*(" numeric ")[[:space:]]*"
56				       "\\]" )))
57
58;; match on a verilog identifier like:  netname
59(define simple-id-reg (make-regexp
60		       ( string-append "^(" id-regexp ")$" )))
61
62
63;; return the top level block name for the module
64(define verilog:get-module-name
65  ( gnetlist:get-toplevel-attribute "module_name" ))
66
67;; return a list of nets whose pins have the desired attribute name/value
68;; pair
69(define verilog:get-matching-nets
70  (lambda (attribute value)
71    (map car (verilog:filter attribute value packages))))
72
73;; This function takes an attribute name, desired value, and a list of
74;; packages.  For each of the packages, it looks up that attribute, and
75;; if it matches, that package name is added to the list, and the function
76;; recurses on the remaining packages.  If the attribute does not match,
77;; the function just recuses on the remaing packages. Thanks to Mohina Lal
78;; for this trick.
79;;
80
81(define verilog:filter
82  (lambda (attribute value package-list)
83    (cond ((null? package-list) '())
84	  ((string=? (gnetlist:get-package-attribute (car package-list)
85						      attribute) value)
86	   (cons
87	    (map (lambda (pin)
88		   (car (gnetlist:get-nets (car package-list) pin)))
89		 (pins (car package-list)))
90	    (verilog:filter attribute value (cdr package-list))))
91	  (else (verilog:filter attribute value (cdr package-list)))))
92)
93
94
95;;
96;; Output the guts of the module ports here
97;;
98;; Scan through the list of components, and pins from each one, finding the
99;; pins that have PINTYPE == CHIPIN, CHIPOUT, CHIPTRI (for inout)
100;; build three lists one each for the inputs, outputs and inouts
101;; return the a list of three lists that contain the pins in the order
102;; we want.
103(define verilog:get-port-list
104  (lambda ()
105    ;; construct list
106    (list (verilog:get-matching-nets "device" "IPAD")
107	  (verilog:get-matching-nets "device" "OPAD")
108	  (verilog:get-matching-nets "device" "IOPAD"))))
109
110;;
111;; output the meat of the module port section
112;;
113;; each line in the declaration is formatted like this:
114;;
115;;       PORTNAME , <newline>
116;;
117(define verilog:write-module-declaration
118  (lambda (module-name port-list p)
119    (begin
120      (display "module " p)
121      (verilog:display-escaped-identifier module-name p)
122      (display " (" p)
123      (newline p)
124      (let ((the-pins ( append (car port-list)     ; build up list of pins
125			       (cadr  port-list)
126			       (caddr port-list))))
127	(begin
128	  ;(display the-pins)
129	  ; do pins, but take care of last comma
130	  (if (not (null? the-pins))
131	      (begin
132		(display "       " p)
133		(display (verilog:netname (car the-pins)) p)
134		(if (not (null? (cdr the-pins)))
135		    (for-each (lambda (pin)   ; loop over outputs
136				(begin
137				  (display " ," p)
138				  (newline p)
139				  (display "       " p)
140				  (display (verilog:netname pin) p)))
141			      (cdr the-pins) ))))
142	(newline p)
143	(display "      );" p)
144	(newline p))))))
145;;
146;; output the module direction section
147;;
148(define verilog:write-port-directions
149  (lambda (port-list p)
150    (let ((in    (car   port-list))    ; extract list of pins
151	  (out   (cadr  port-list))
152	  (inout (caddr port-list)))
153      (begin
154	(display "/* Port directions begin here */" p)
155	(newline p)
156	(for-each (lambda (pin)
157		    (begin
158		      (display "input " p)
159		      (verilog:display-wire (verilog:get-net
160					     (verilog:netname pin)) p)
161		      (display " ;" p)
162		      (newline p))) in)       ; do each input
163
164	(for-each (lambda (pin)
165		    (begin
166		      (display "output " p)
167		      (verilog:display-wire (verilog:get-net
168					     (verilog:netname pin)) p)
169		      (display " ;" p)
170		      (newline p))) out)      ; do each output
171
172	(for-each (lambda (pin)
173		    (begin
174		      (display "inout " p)
175		      (verilog:display-wire (verilog:get-net
176					     (verilog:netname pin)) p)
177		      (display " ;" p)
178		      (newline p))) inout)    ; do each inout
179
180	(newline p)))))
181;;
182;; Top level header
183;;
184
185(define verilog:write-top-header
186	(lambda (p)
187	  (let ((port-list (verilog:get-port-list)))
188	    (begin
189	      (display "/* structural Verilog generated by gnetlist */\n" p)
190	      (display "/* WARNING: This is a generated file, edits */\n" p)
191	      (display "/*        made here will be lost next time  */\n" p)
192	      (display "/*        you run gnetlist!                 */\n" p)
193	      (display "/* Id ..........$Id$ */\n" p)
194	      (display "/* Source.......$Source$ */\n" p)
195	      (display "/* Revision.....$Revision$ */\n" p)
196	      (display "/* Author.......$Author$ */\n" p)
197	      (newline p)
198	      (verilog:write-module-declaration verilog:get-module-name
199						port-list p)
200	      (newline p)
201	      (verilog:write-port-directions port-list p)
202	      (newline p)))))
203
204;;
205;; Footer for file
206;;
207(define verilog:write-bottom-footer
208  (lambda (p)
209    (display "endmodule" p)
210    (newline p)
211    )
212)
213
214;;
215;; Take a netname and parse it into a structure that describes the net:
216;;
217;;    (   netname            ; name of the wire
218;;      ( N1                 ; first limit
219;;        N2                 ; second limit
220;;        Increasing_order   ; #t if N2>N1
221;;        sure               ; #t if we are sure about the order
222;;      ))
223(define verilog:net-parse
224  (lambda (netname)
225    (let
226	((bit-range (regexp-exec bit-range-reg netname))
227	 (concat-bus (regexp-exec concat-bus-reg netname))
228	 (single-bit (regexp-exec single-bit-reg netname))
229	 (simple-id (regexp-exec simple-id-reg netname)))
230
231      ;; check over each expression type, and build the appropriate
232      ;; result
233      ;(display netname) (display ": ")
234      (cond
235       ;; is it a bit range?
236       (bit-range
237	;(display "bit-range" )
238	(list (match:substring bit-range 1)
239	      (list (string->number (match:substring bit-range 2))
240		    (string->number (match:substring bit-range 3))
241		    (> (string->number (match:substring bit-range 3))
242		       (string->number (match:substring bit-range 2)))
243		    '#t netname)))
244
245       ;; just a single bit?
246       (single-bit
247	;(display "single-bit")
248	(list (match:substring single-bit 1)
249	      (list (string->number (match:substring single-bit 2))
250		    (string->number (match:substring single-bit 2))
251		    '#f '#f netname)))
252
253       ;; or a net without anything
254       (simple-id
255	;(display "bare-net")
256	(list (match:substring simple-id 1) (list 0 0 #f #f netname)))
257
258       (else
259	(display
260	 (string-append "Warning: `" netname
261			"' is not likely a valid Verilog identifier"))
262	(newline)
263	(list netname (list 0 0 #f #f netname)))
264       ))))
265
266;;
267;; Return #t if the passed name is something that might pass as a
268;; verilog identifier.
269;;
270(define verilog:identifier?
271  (lambda (netname)
272    (let
273	((bit-range (regexp-exec bit-range-reg netname))
274	 (concat-bus (regexp-exec concat-bus-reg netname))
275	 (single-bit (regexp-exec single-bit-reg netname))
276	 (simple-id (regexp-exec simple-id-reg netname)))
277
278      ;; check over each expression type, return
279      ;; result
280      ;;(display netname) (display ": ")(display concat-bus)(display "\n")
281      (cond
282       (bit-range  `#t )
283       (concat-bus  `#t )
284       (single-bit `#t )
285       (simple-id  `#t )
286       (else       `#f )
287       ))))
288
289;;
290;; Display a verilog identifier that is escaped if needed
291;;
292(define verilog:display-escaped-identifier
293  (lambda (netname port)
294    (if (verilog:identifier? netname)
295	(display netname port) ; just display the identifier
296	(display (string-append "\\" netname " ") port)))) ; need to escape
297
298
299;;
300;; return just the netname part of a verilog identifier
301;;
302(define verilog:netname
303  (lambda (netname)
304    (car (verilog:net-parse netname))))
305
306;;  Update the given bit range with data passed.  Take care
307;;  of ordering issues.
308;;
309;;   n1     : new first range
310;;   n2     : new second range
311;;   old-n1 : first range to be updated
312;;   old-n2 : second range to be updated
313;;   increasing : original order was increasing
314(define verilog:update-range
315  (lambda (n1 n2 old-n1 old-n2 increasing)
316    (let ((rn1 (if increasing
317		   (min n1 old-n1)     ; originally increasing
318		   (max n1 old-n1)))   ; originally decreasing
319
320	  (rn2 (if increasing
321		   (max n2 old-n2)     ; originally increasing
322		   (min n2 old-n2))))
323;      (display (string-append "increasing:"
324;			      (if increasing "increasing" "decreasing")
325;			      " rn1:" (number->string rn1)
326;			      " rn2:" (number->string rn2)
327;			      " n1:" (number->string n1)
328;			      " n2:" (number->string n2)
329;			      " old-n1:" (number->string old-n1)
330;			      " old-n2:" (number->string old-n2))) (newline)
331      (list rn1 rn2)
332
333      )))
334
335
336;; return a record that has been updated with the given
337;; parameters
338(define verilog:update-record
339  (lambda (n1
340	   n2
341	   list-n1
342	   list-n2
343	   increasing
344	   sure
345	   real)
346    (list
347     (append (verilog:update-range
348	      n1 n2 list-n1 list-n2
349	      increasing)
350	     (list increasing
351		   sure
352		   real)))))
353
354;;
355;;  Work over the list of `unique' nets in the design,
356;;  extracting names, and bit ranges, if appropriate.
357;;  return a list of net description objects
358;;
359
360
361(define verilog:get-nets '())
362
363
364(define verilog:get-nets-once!
365  (lambda nil
366    (define the-nets '())
367    (set! verilog:get-nets
368      (begin
369        (for-each
370         (lambda (netname)
371           ; parse the netname, and see if it is already on the list
372           (let* ((parsed (verilog:net-parse netname))
373                  (listed (assoc (car parsed) the-nets)))
374             (if listed
375                 (begin ; it is, do some checks, and update the record
376                   ;; extract fields from list
377                   (let* ((list-name       (car listed))
378                          (list-n1         (car (cadr listed)))
379                          (list-n2         (cadr (cadr listed)))
380                          (list-increasing (caddr (cadr listed)))
381                          (list-sure       (cadddr (cadr listed)))
382                          (list-real       (cadddr (cdr (cadr listed))))
383
384                          (name            (car parsed))
385                          (n1              (car (cadr parsed)))
386                          (n2              (cadr (cadr parsed)))
387                          (increasing      (caddr (cadr parsed)))
388                          (sure            (cadddr (cadr parsed)))
389                          (real            (cadddr (cdr (cadr parsed))))
390
391                          (consistant      (or (and list-increasing increasing)
392                                               (and (not list-increasing)
393                                                    (not increasing))))
394
395                         )
396
397                     (cond
398                      ((and list-sure consistant)
399                       (begin
400                         (set-cdr! listed
401                                   (verilog:update-record n1 n2
402                                                          list-n1 list-n2
403                                                          increasing
404                                                          #t
405                                                          real)
406                                   )))
407                       ((and list-sure (not sure) (zero? n1) (zero? n2))
408                        '() ;; this is a net without any expression, leave it
409                        )
410                      ((and list-sure (not consistant))
411                       (begin      ;; order is inconsistent
412                         (display
413                          (string-append "Warning: Net `" real "' has a "
414                                         "bit order that conflicts with "
415                                         "the original definition of `"
416                                         list-real "', ignoring `"
417                                         real "'"
418                                         ))
419                         (newline)))
420                       ((and (not list-sure) sure consistant)
421                        (begin
422                          (set-cdr! listed
423                                    (verilog:update-record n1 n2
424                                                           list-n1 list-n2
425                                                           increasing
426                                                           #t
427                                                           real))))
428
429                       ((and (not list-sure) sure (not consistant))
430                        (begin
431                          (set-cdr! listed
432                                    (verilog:update-record n1 n2
433                                                           list-n2 list-n1
434                                                           increasing
435                                                           #t
436                                                           real))))
437                       ((and (not list-sure) (not sure))
438                        (begin
439                          (set-cdr! listed
440                                    (verilog:update-record n1 n2
441                                                           list-n1 list-n2
442                                                           increasing
443                                                           #f
444                                                           real))))
445                       (else
446                        (begin
447                          (display "This should never happen!")
448                          (newline)))
449                       )
450                 )
451             )
452           (begin ; it is not, just add it to the end
453             (set! the-nets
454                   (append the-nets
455                           (list parsed))))
456           ))
457         )
458
459        all-unique-nets)
460      the-nets)
461    )
462    verilog:get-nets
463))
464
465;; Retrieve the requested net record from the database.
466
467(define verilog:get-net
468  (lambda (wire)
469    (begin
470      (assoc wire verilog:get-nets)
471      )))
472
473;;
474;;  Display wires from the design
475;;
476;;  Display a net in a legal verilog format, based on the object passed
477(define verilog:display-wire
478  (lambda (wire p)
479    ;; figure out if we need a bit range
480    (let ((name            (car wire))
481	  (n1              (car (cadr wire)))
482	  (n2              (cadr (cadr wire)))
483	  )
484
485      (if (not (and (zero? n1) (zero? n2)))
486	  (begin     ;; yes, print it
487	    (display "[ " p)
488	    (display n1 p)
489	    (display " : " p)
490	    (display n2 p)
491	    (display " ] " p)
492	  )
493	)
494    ;; print the wire name
495      (verilog:display-escaped-identifier name p))))
496
497;;
498;;  Loop over the list of nets in the design, writing one by one
499;;
500(define verilog:write-wires
501  (lambda (p)
502    (display "/* Wires from the design */" p)
503    (newline p)
504    (for-each (lambda (wire)          ; print a wire statement for each
505		; if it does not appear to be a concatenated bus then print it
506		(if (not (regexp-exec concat-bus-reg (car(cdr(cdr(cdr(cdr(cadr wire))))))))
507			(begin
508			(display "wire " p)   ; net in the design
509			(verilog:display-wire wire p)
510			(display " ;" p)
511			(newline p)
512			) ;; begin
513		 ) ;; if
514		) ;; lambda
515	      verilog:get-nets ) ;; for-each
516    (newline p)
517	) ;; lambda
518) ;; define
519
520;;
521;;  Output any continuous assignment statements generated
522;; by placing `high' and `low' components on the board
523;;
524(define verilog:write-continuous-assigns
525  (lambda (p)
526    (display "/* continuous assignments */" p) (newline p)
527    (for-each (lambda (wire)             ; do high values
528		(begin
529		  (display "assign " p)
530		  ;; XXX fixme, multiple bit widths!
531		  (verilog:display-escaped-identifier wire p)
532		  (display " = 1'b1;" p)
533		  (newline p)))
534	      (verilog:get-matching-nets "device" "HIGH"))
535
536    (for-each (lambda (wire)
537		(begin
538		  (display "assign " p)
539		  ;; XXX fixme, multiple bit widths!
540		  (verilog:display-escaped-identifier wire p)
541		  (display " = 1'b0;" p)
542		  (newline p)))
543	      (verilog:get-matching-nets "device" "LOW"))
544    (newline p))
545)
546
547
548
549;;
550;; Top level component writing
551;;
552;; Output a compoment instatantiation for each of the
553;; components on the board
554;;
555;; use the format:
556;;
557;;  device-attribute refdes (
558;;        .pinname ( net_name ),
559;;        ...
560;;    );
561;;
562(define verilog:components
563  (lambda (packages port)
564    (begin
565      (display "/* Package instantiations */" port)
566      (newline port)
567      (for-each (lambda (package)         ; loop on packages
568		  (begin
569		    (let ((device (get-device package)))
570 		      (if (not (memv (string->symbol device) ; ignore specials
571 				     (map string->symbol
572 					  (list "IOPAD" "IPAD" "OPAD"
573 						"HIGH" "LOW"))))
574 			  (begin
575 			    (verilog:display-escaped-identifier
576			     (get-device package) port)
577 			    (display " " port)
578 			    (verilog:display-escaped-identifier package port)
579 			    (display " ( " port)
580			    ; if this module wants positional pins,
581			    ; then output that format, otherwise
582			    ; output normal named declaration
583			    (verilog:display-connections
584			     package
585			     (string=? (gnetlist:get-package-attribute
586					package "VERILOG_PORTS" )
587				       "POSITIONAL")
588			     port)
589 			    (display "    );" port)
590	 		    (newline port)
591 			    (newline port))))))
592 		packages)))
593)
594
595;;
596;; output a module connection for the package given to us with named ports
597;;
598(define verilog:display-connections
599   (lambda (package positional port)
600     (begin
601       (let ( (pin-list (gnetlist:get-pins-nets package))
602	      (comma_pending #f) )
603 	(if (not (null? pin-list))
604 	    (begin
605	      (newline port)
606 	      (for-each (lambda (pin)
607 			  (if (not (strncmp? "unconnected_pin" (cdr pin) 15))
608			      (begin
609				;; handle commas after the first pin
610				(if comma_pending
611				    (begin
612				      (display "," port)
613				      (newline port))
614				    (set! comma_pending #t))
615				(verilog:display-pin pin positional port))))
616 			pin-list)
617 	      (newline port))))))
618)
619
620;;
621;; Display the individual net connections
622;;  in this format if positional is true:
623;;
624;;    /* PINNAME */ NETNAME
625;;
626;;  otherwise emit:
627;;
628;;      .PINNAME ( NETNAME )
629;;
630(define verilog:display-pin
631    (lambda (pin positional port)
632      (begin
633	(if positional
634	    (begin    ; output a positional port instanace
635	      (display "  /* " port)
636	      (display (car pin) port)  ; add in name for debugging
637	      (display " */ " port )
638	      (display (cdr pin) port))
639	    (begin    ; else output a named port instance
640	      (display "    ." port)
641	      ; Display the escaped version of the identifier
642	      (verilog:display-escaped-identifier (verilog:netname (car pin))
643						  port)
644	      (display " ( " port)
645	      (verilog:display-escaped-identifier (cdr pin) port)
646	      (display " )" port))))))
647
648
649
650;;; Highest level function
651;;; Write Structural verilog representation of the schematic
652;;;
653(define verilog
654  (lambda (output-filename)
655    (let ((port (open-output-file output-filename)))
656      (begin
657	(verilog:get-nets-once!)
658	(verilog:write-top-header port)
659	(verilog:write-wires port)
660	(verilog:write-continuous-assigns port)
661	(verilog:components packages port)
662	(verilog:write-bottom-footer port)
663	)
664      (close-output-port port)
665      )
666    )
667)
668;;
669;; Verilog netlist backend written by Mike Jarabek ends here
670;;
671;; --------------------------------------------------------------------------
672
673