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)
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
21 ;; SystemC netlist backend written by Jaume Masip
22 ;; (based on gnet-verilog.scm by Mike Jarabek)
24 ;; some useful regexes for working with net-names
26 (use-modules (ice-9 regex))
28 (define id-regexp "[a-zA-Z_][a-zA-Z0-9_$]*")
29 (define numeric "[0-9]+")
30 ;; match on a systemc identifier like: netname[x:y]
31 (define bit-range-reg (make-regexp
32 (string-append "^(" id-regexp ")[[:space:]]*"
34 "[[:space:]]*(" numeric ")[[:space:]]*"
36 "[[:space:]]*(" numeric ")[[:space:]]*"
39 ;; match on a systemc identifier like: netname[x]
40 (define single-bit-reg (make-regexp
41 (string-append "^(" id-regexp ")[[:space:]]*"
43 "[[:space:]]*(" numeric ")[[:space:]]*"
46 ;; match on a systemc identifier like: netname<type>
47 (define systemc-reg (make-regexp
48 (string-append "^(" id-regexp ")[[:space:]]*"
50 "[[:space:]]*(" id-regexp ")[[:space:]]*"
53 ;; match on a systemc identifier like: netname
54 (define simple-id-reg (make-regexp
55 ( string-append "^(" id-regexp ")$" )))
58 ;; return the top level block name for the module
59 (define systemc:get-module-name
60 ( gnetlist:get-toplevel-attribute "module_name" ))
62 ;; return a list of nets whose pins have the desired attribute name/value
64 (define systemc:get-matching-nets
65 (lambda (attribute value)
66 (map car (systemc:filter attribute value packages))))
68 ;; This function takes an attribute name, desired value, and a list of
69 ;; packages. For each of the packages, it looks up that attribute, and
70 ;; if it matches, that package name is added to the list, and the function
71 ;; recurses on the remaining packages. If the attribute does not match,
72 ;; the function just recuses on the remaing packages. Thanks to Mohina Lal
76 (define systemc:filter
77 (lambda (attribute value package-list)
78 (cond ((null? package-list) '())
79 ((string=? (gnetlist:get-package-attribute (car package-list)
83 (car (gnetlist:get-nets (car package-list) pin)))
84 (pins (car package-list)))
85 (systemc:filter attribute value (cdr package-list))))
86 (else (systemc:filter attribute value (cdr package-list)))))
91 ;; Output the guts of the module ports here
93 ;; Scan through the list of components, and pins from each one, finding the
94 ;; pins that have PINTYPE == CHIPIN, CHIPOUT, CHIPTRI (for inout)
95 ;; build three lists one each for the inputs, outputs and inouts
96 ;; return the a list of three lists that contain the pins in the order
98 (define systemc:get-port-list
101 (list (systemc:get-matching-nets "device" "IPAD")
102 (systemc:get-matching-nets "device" "OPAD")
103 (systemc:get-matching-nets "device" "IOPAD"))))
106 ;; output the meat of the module port section
108 ;; each line in the declaration is formatted like this:
110 ;; PORTNAME , <newline>
112 (define systemc:write-module-declaration
113 (lambda (module-name port-list p)
116 (display "#include \"systemc.h\"\n" p)
118 (for-each (lambda (package) ; loop on packages
120 (let ((device (get-device package)))
121 (if (not (memv (string->symbol device) ; ignore specials
122 (map string->symbol (list "IOPAD" "IPAD" "OPAD" "HIGH" "LOW"))))
124 (display "#include \"" p)
125 (systemc:display-escaped-identifier (get-device package) p)
126 (display ".h\"\n" p))))))
129 (display "SC_MODULE (" p) (systemc:display-escaped-identifier module-name p) (display ")\n{\n" p)
134 ;; output the module direction section
136 (define systemc:write-port-directions
137 (lambda (port-list p)
138 (let ((in (car port-list)) ; extract list of pins
139 (out (cadr port-list))
140 (inout (caddr port-list)))
142 (display "/* Port directions begin here */" p)
144 (for-each (lambda (pin)
146 (display "sc_in<bool> " p)(systemc:display-escaped-identifier (systemc:netname pin) p)(display ";" p)(newline p)
148 ;; (display "sc_in<" p)(display (cadr (cadr pin)) p) (display "> " p) (systemc:display-wire pin p)(display ";" p)(newline p)
149 ;; (display " /* " )(display(car pin) ) (display " */ " ) (display(cdr pin))
150 ;; (display " /* " )(systemc:display-escaped-identifier (systemc:netname pin) ) (display " */ " )
151 )) in) ; do each input
153 (for-each (lambda (pin)
155 (display "sc_out<bool> " p)
156 (systemc:display-escaped-identifier
157 (systemc:netname pin) p)
159 (newline p))) out) ; do each output
161 (for-each (lambda (pin)
163 (display "sc_inout<bool> " p)
164 (systemc:display-escaped-identifier
165 (systemc:netname pin) p)
167 (newline p))) inout) ; do each inout
174 (define systemc:write-top-header
176 (let ((port-list (systemc:get-port-list)))
178 (display "/* structural SystemC generated by gnetlist */\n" p)
179 (display "/* WARNING: This is a generated file, edits */\n" p)
180 (display "/* made here will be lost next time */\n" p)
181 (display "/* you run gnetlist! */\n" p)
182 (display "/* Id ........gnet-systemc.scm (04/09/2003) */\n" p)
183 (display "/* Source...../home/geda/gnet-systemc.scm */\n" p)
184 (display "/* Revision...0.3 (23/09/2003) */\n" p)
185 (display "/* Author.....Jaume Masip */\n" p)
187 (systemc:write-module-declaration systemc:get-module-name
190 (systemc:write-port-directions port-list p)
196 (define systemc:write-bottom-footer
198 (display " }\n};\n" p)
204 ;; Take a netname and parse it into a structure that describes the net:
206 ;; ( netname ; name of the wire
207 ;; ( N1 ; first limit
209 ;; Increasing_order ; #t if N2>N1
210 ;; sure ; #t if we are sure about the order
212 (define systemc:net-parse
215 ((bit-range (regexp-exec bit-range-reg netname))
216 (single-bit (regexp-exec single-bit-reg netname))
217 (simple-id (regexp-exec simple-id-reg netname))
218 (systemc (regexp-exec systemc-reg netname)))
221 ;; (display " systemc:net-parse ")
222 ;; (if systemc (begin (display systemc) (display "->") (display (match:substring systemc 2) )))
223 ;; (if simple-id (display simple-id))
226 ;; check over each expression type, and build the appropriate
228 ;(display netname) (display ": ")
230 ;; is it a bit range?
232 ;(display "bit-range" )
233 (list (match:substring bit-range 1)
234 (list (string->number (match:substring bit-range 2))
235 (string->number (match:substring bit-range 3))
236 (> (string->number (match:substring bit-range 3))
237 (string->number (match:substring bit-range 2)))
240 ;; just a single bit?
242 ;(display "single-bit")
243 (list (match:substring single-bit 1)
244 (list (string->number (match:substring single-bit 2))
245 (string->number (match:substring single-bit 2))
248 ;; just a systemc signal?
251 ;; (display "done systemc")(newline)
252 (list (match:substring systemc 1)
253 (list (string->number (match:substring systemc 2))
254 (match:substring systemc 2)
255 ;; (string->number (match:substring systemc 2))
259 ;; or a net without anything
261 ;(display "bare-net")
262 (list (match:substring simple-id 1) (list 0 0 #f #f netname)))
266 (string-append "Warning: `" netname
267 "' is not likely a valid Verilog identifier"))
269 (list netname (list 0 0 #f #f netname)))
274 ;; Return #t if the passed name is something that might pass as a
275 ;; systemc identifier.
277 (define systemc:identifier?
280 ((bit-range (regexp-exec bit-range-reg netname))
281 (single-bit (regexp-exec single-bit-reg netname))
282 (simple-id (regexp-exec simple-id-reg netname))
283 (systemc (regexp-exec systemc-reg netname)))
285 ;; check over each expression type, return
287 ;(display netname) (display ": ")
297 ;; Display a systemc identifier that is escaped if needed
299 (define systemc:display-escaped-identifier
300 (lambda (netname port)
301 (if (systemc:identifier? netname)
302 (display netname port) ; just display the identifier
303 ;;(display (string-append "\\" netname " ") port)))) ; need to escape
304 (display netname port)))) ; need to escape
308 ;; return just the netname part of a systemc identifier
310 (define systemc:netname
312 (car (systemc:net-parse netname))))
314 ;; Update the given bit range with data passed. Take care
315 ;; of ordering issues.
317 ;; n1 : new first range
318 ;; n2 : new second range
319 ;; old-n1 : first range to be updated
320 ;; old-n2 : second range to be updated
321 ;; increasing : original order was increasing
322 (define systemc:update-range
323 (lambda (n1 n2 old-n1 old-n2 increasing)
324 (let ((rn1 (if increasing
325 (min n1 old-n1) ; originally increasing
326 (max n1 old-n1))) ; originally decreasing
329 (max n2 old-n2) ; originally increasing
331 ; (display (string-append "increasing:"
332 ; (if increasing "increasing" "decreasing")
333 ; " rn1:" (number->string rn1)
334 ; " rn2:" (number->string rn2)
335 ; " n1:" (number->string n1)
336 ; " n2:" (number->string n2)
337 ; " old-n1:" (number->string old-n1)
338 ; " old-n2:" (number->string old-n2))) (newline)
344 ;; return a record that has been updated with the given
346 (define systemc:update-record
355 (append (systemc:update-range
356 n1 n2 list-n1 list-n2
363 ;; Work over the list of `unique' nets in the design,
364 ;; extracting names, and bit ranges, if appropriate.
365 ;; return a list of net description objects
368 (define systemc:get-nets '())
370 (define systemc:get-nets-once!
372 (define the-nets '())
373 (set! systemc:get-nets
377 ; parse the netname, and see if it is already on the list
378 (let* ((parsed (systemc:net-parse netname))
379 (listed (assoc (car parsed) the-nets)))
381 ;; (display "systemc:get-nets(parsed)-> ")
382 ;; (display parsed)(display " (listed)-> ")
387 (begin ; it is, do some checks, and update the record
388 ;; extract fields from list
389 (let* ((list-name (car listed))
390 (list-n1 (car (cadr listed)))
391 (list-n2 (cadr (cadr listed)))
392 (list-increasing (caddr (cadr listed)))
393 (list-sure (cadddr (cadr listed)))
394 (list-real (cadddr (cdr (cadr listed))))
397 (n1 (car (cadr parsed)))
398 (n2 (cadr (cadr parsed)))
399 (increasing (caddr (cadr parsed)))
400 (sure (cadddr (cadr parsed)))
401 (real (cadddr (cdr (cadr parsed))))
403 (consistant (or (and list-increasing increasing)
404 (and (not list-increasing)
410 ((and list-sure consistant)
413 (systemc:update-record n1 n2
419 ((and list-sure (not sure) (zero? n1) (zero? n2))
420 '() ;; this is a net without any expression, leave it
422 ((and list-sure (not consistant))
423 (begin ;; order is inconsistent
425 (string-append "Warning: Net `" real "' has a "
426 "bit order that conflicts with "
427 "the original definition of `"
428 list-real "', ignoring `"
432 ((and (not list-sure) sure consistant)
435 (systemc:update-record n1 n2
441 ((and (not list-sure) sure (not consistant))
444 (systemc:update-record n1 n2
449 ((and (not list-sure) (not sure))
452 (systemc:update-record n1 n2
459 (display "This should never happen!")
464 (begin ; it is not, just add it to the end
469 ;; (display "systemc:get-nets(parsed)-> ")
479 ;; Display wires from the design
481 ;; Display a net in a legal systemc format, based on the object passed
482 (define systemc:display-wire
484 ;; figure out if we need a bit range
485 (let ((name (car wire))
486 (n1 (car (cadr wire)))
487 (n2 (cadr (cadr wire)))
488 (increasing (caddr (cadr wire)))
491 ;; (if (not (and (zero? n1) (zero? n2)))
492 ;; (begin ;; yes, print it
493 ;; (display "[ " p)(display n1 p)(display " : " p)(display n2 p)(display " ] " p) ) )
494 ;; print the wire name
495 (systemc:display-escaped-identifier name p)
496 ;;(systemc:display-escaped-identifier n1 p)
497 ;;(systemc:display-escaped-identifier n2 p)
498 ;;(systemc:display-escaped-identifier increasing p)
504 ;; Loop over the list of nets in the design, writing one by one
506 (define systemc:write-wires
508 (display "/* Wires from the design */" p)
510 (for-each (lambda (wire) ; print a wire statement for each
511 ;; (let ((name (car wire)) (n1 (car (cadr wire))) (n2 (cadr (cadr wire))) (increasing (caddr (cadr wire)))))
512 ;; (display "/* Wires from the design */")(newline)
513 ;; (display "systemc:write-wires -> ")(display wire)(newline)
514 (display "sc_signal<" p)
515 (display (cadr (cadr wire)) p)
517 (systemc:display-wire wire p)
524 ;; Output any continuous assignment statements generated
525 ;; by placing `high' and `low' components on the board
527 (define systemc:write-continuous-assigns
529 ;; (display "/* continuous assignments */" p) (newline p)
530 (for-each (lambda (wire) ; do high values
532 (display "assign " p)
533 ;; XXX fixme, multiple bit widths!
534 (systemc:display-escaped-identifier wire p)
535 (display " = 1'b1;" p)
537 (systemc:get-matching-nets "device" "HIGH"))
539 (for-each (lambda (wire)
541 (display "assign " p)
542 ;; XXX fixme, multiple bit widths!
543 (systemc:display-escaped-identifier wire p)
544 (display " = 1'b0;" p)
546 (systemc:get-matching-nets "device" "LOW"))
553 ;; Top level component writing
555 ;; Output a compoment instatantiation for each of the
556 ;; components on the board
560 ;; device-attribute refdes (
561 ;; .pinname ( net_name ),
568 (define systemc:components
569 (lambda (packages port)
572 (display "/* Package instantiations */" port) (newline port)
574 (for-each (lambda (package) ; loop on packages
576 (let ((device (get-device package)))
577 (if (not (memv (string->symbol device) ; ignore specials
578 (map string->symbol (list "IOPAD" "IPAD" "OPAD" "HIGH" "LOW"))))
580 (systemc:display-escaped-identifier (get-device package) port) (display " " port)
581 (systemc:display-escaped-identifier package port) (display ";" port)
586 (display "SC_CTOR(" port) (systemc:display-escaped-identifier systemc:get-module-name port)
587 (display "):\n" port)
589 (for-each (lambda (package) ; loop on packages
591 (let ((device (get-device package)))
592 (if (not (memv (string->symbol device) ; ignore specials
593 (map string->symbol (list "IOPAD" "IPAD" "OPAD" "HIGH" "LOW"))))
595 (if c_p (begin (display "," port) (newline port)) (set! c_p #t))
597 (systemc:display-escaped-identifier package port)
599 (systemc:display-escaped-identifier package port)
600 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
602 ;;(do ((i n (- i 1))) ((zero? i)) (move-n-turn (/ 360 n)))
603 (do ((lp 1 (+ lp 1))) ((> lp 32))
604 ;; (begin (display lp)(newline)))
605 (let* ((attr (string-append "attr" (number->string lp)))
606 (description (gnetlist:get-package-attribute package attr)))
608 (if (not (string=? description "unknown"))
609 (begin (display "\",\"" port) (display description port)))))
612 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
616 (display "\n {" port)
618 (for-each (lambda (package) ; loop on packages
620 (let ((device (get-device package)))
621 (if (not (memv (string->symbol device) ; ignore specials
622 (map string->symbol (list "IOPAD" "IPAD" "OPAD" "HIGH" "LOW"))))
624 ; if this module wants positional pins,
625 ; then output that format, otherwise
626 ; output normal named declaration
627 (systemc:display-connections package
628 (string=? (gnetlist:get-package-attribute package "VERILOG_PORTS" ) "POSITIONAL") port)
633 ;; output a module connection for the package given to us with named ports
635 (define systemc:display-connections
636 (lambda (package positional port)
638 (let ( (pin-list (gnetlist:get-pins-nets package))
640 (if (not (null? pin-list))
643 (for-each (lambda (pin)
644 (if (not (strncmp? (cdr pin) "unconnected_pin" 15) )
646 (display " " port)(systemc:display-escaped-identifier package port)
647 (systemc:display-pin pin positional port)
648 (display ";" port) (newline port))))
654 ;; Display the individual net connections
655 ;; in this format if positional is true:
657 ;; /* PINNAME */ NETNAME
661 ;; .PINNAME ( NETNAME )
663 (define systemc:display-pin
664 (lambda (pin positional port)
666 ((systemc (regexp-exec systemc-reg (cdr pin))))
669 (begin ; output a positional port instanace
670 (display " /* " port)
671 (display (car pin) port) ; add in name for debugging
672 (display " */ " port )
673 (display (cdr pin) port))
674 (begin ; else output a named port instance
676 ; Display the escaped version of the identifier
677 (systemc:display-escaped-identifier (car pin) port)
680 (display (match:substring systemc 1) port)
681 (systemc:display-escaped-identifier (cdr pin) port))
682 (display ")" port)))))))
686 ;;; Highest level function
687 ;;; Write Structural systemc representation of the schematic
690 (lambda (output-filename)
691 (let ((port (open-output-file output-filename)))
693 (systemc:get-nets-once!)
694 (systemc:write-top-header port)
695 ;; (display "***** start write-wires ********")(newline)
696 (systemc:write-wires port)
697 ;; (display "***** end write-wires ********")(newline)
698 (systemc:write-continuous-assigns port)
699 (systemc:components packages port)
700 (systemc:write-bottom-footer port)
702 (close-output-port port)