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