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