1 ;;; gEDA - GPL Electronic Design Automation
2 ;;; gnetlist - gEDA Netlist
3 ;;; Copyright (C) 1998-2010 Ales Hvezda
4 ;;; Copyright (C) 1998-2020 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., 51 Franklin Street, Fifth Floor, Boston,
19 ;;; MA 02111-1301 USA.
21 ;; --------------------------------------------------------------------------
23 ;; SPICE netlist backend written by S. Gieltjes starts here
25 ;; further modified by W. Kazubski to use scaling parameters for devices
28 ;;----------------------------------------------------------------------
30 ;; Started with gnet-spice1.scm by W. Kazubski. Radically
31 ;; hacked by SDB to support advanced spice netlist generation.
32 ;; Project started 3.5.2003 -- SDB.
34 ;; Details and documentation at http://www.brorson.com/gEDA/SPICE/
37 ;; 3.5.2003 -- Started hacking. SDB.
38 ;; 3.17.2003 -- 2nd version. Hacked to allow for .SUBCKT files to model ics.
39 ;; Changed write-ic. Added get-file-type. Added
40 ;; write-subcircuit. SDB.
41 ;; 3.31.2003 -- 3rd version. Hacked to enable creating .SUBCKT schematics for
42 ;; hierarchical circuit modeling.
43 ;; 8.29.2003 -- 4th version. Include patches from Ken Healy to sort netlist,
44 ;; code by SDB to use gnetlist command line args in Scheme fcns,
45 ;; as well as from Theo Deckers to fix strange problem with '.SUBCKT
47 ;; 9.9.2003 -- 5th version. Rearranged code for more organization (I was beginning
48 ;; to get lost. . . .). Incorporated changes to handle external SPICE
49 ;; files more intelligently. Changed spew to be configurable by setting
50 ;; -v from the command line. Placed new fcn debug-spew into gnetlist.scm.
51 ;; Added -I command line flag.
52 ;; 10.14.2003 -- Bugfixes: Added empty-string? and hacked get-file-type to handle
53 ;; case where a model file has an empty line before .SUBCKT or .MODEL.
54 ;; Also modified write-net-names-on-component to gracefully handle
55 ;; case where not every pin has a pinseq attribute. Now only outputs
56 ;; pins with valid pinseq attribute.
57 ;; 12.25.2003 -- Bugfix: Unswizzled emission of pins from user-defined .subckts.
58 ;; (Now correctly uses pinseq to define emission order of pins.) Also
59 ;; added ability to emit attributes for semiconductors (e.g. area, off,
60 ;; ic, etc.) Added in response to user requests.
61 ;; 12.29.2003 -- Two small enhancements requested by Peter Kaiser.
62 ;; 12.29.2003.a -- Minor bugfix.
63 ;; 12.29.2003.b -- Second minor bugfix.
64 ;; 12.29.2003.c -- Change res & cap to incorporate modelname & "area=" attrib.
65 ;; 3.24.2004 -- Bugfixes made to JFET stuff during Feb. Change released now.
66 ;; 8.22.2004 -- Added command line as first line of file.
67 ;; 8.29.2004 -- Changed sense source naming in controlled sources because the old convention
68 ;; was confusing ngspice.
69 ;; 10.9.2004 -- Added patches for voltage controlled switches from Peter Kaiser.
70 ;; 3.16.2005 -- Fixed CCCS bug (typo in Vsense) noticed by David Logan
71 ;; 5.16.2005 -- Modified behavior of .INCLUDE directive. Now by default it just
72 ;; spits out the string instead of putting the contents of the file
73 ;; into the SPICE netlist. You can force insertion of the file using
75 ;; 6.12.2005 -- Changed order of writing out netlist and .model/.subckt cards to
76 ;; facilitate use of numparam with ngspice. Change supplied by
78 ;; 9.11.2005 -- Incorporated patch from Paul Bunyk to enable netlisting of
79 ;; Josephson junctions and "K" mutual inductances. Also enabled
80 ;; netlisting of "COIL" devices as inductors.
81 ;; 12.27.2005 -- Fix bug discovered by John Doty: spice-IO pins with refdes greater
82 ;; than P9 were sorted incorrectly (as strings). Now they are sorted
84 ;; 3.10.2006 -- Added "m" attribute to PMOS and NMOS per request of Peter Kaiser.
85 ;; 4.11.2006 -- Changed the .END and .ENDS cards to lowercase.
86 ;; This fixes bug 1442912. Carlos Nieves Onega.
87 ;; 2.10.2007 -- Various bugfixes. Also incorporated slotted part
88 ;; netlist patch from Jeff Mallatt. SDB.
89 ;; 4.28.2007 -- Fixed slotted part stuff so that it uses pinseq to emit pins. SDB
90 ;; 1.9.2008 -- Fix slotted part handling to work without a modified pinseq. pcjc2
91 ;; 1.3.2011 -- Combine write-ic and write-subcircuit with a fix to the unbound
92 ;; type variable. Fully document a check for the special "?" value
93 ;; explaining why it fails silently. Clean up
94 ;; write-net-names-on-component to make it a bit more flexible.
95 ;; Combine write-probe-item and write-net-names-on-component. Add
96 ;; a range utility function. CC
97 ;; 1.13.2011 -- Add four lines of code (and some comments) that allow formaitting strings
98 ;; to be used for netlisting NGspice device models. CC
99 ;; 6.12.2011 -- Updated the Problematci name=? symbols to name=unknown and removed the
100 ;; FIXME check for them. This should be a step closer to place holder consistancy. CC
101 ;; 10.11.2020 -- Added support for a spice-title device to prove a netlist
104 ;;**********************************************************************************
106 ;; Organization of gnet-spice-sdb.scm file:
107 ;; -- Functions for program housekeeping, handling of calling flags, file manipulation.
108 ;; -- Functions for handling nets & devices and creating SPICE cards.
109 ;; -- High-level functions which control program flow. Note that the program entry
110 ;; point lives at the very bottom of this file.
112 ;; Unfortunately, no organization is present beneath this top level. . . .
114 ;;**********************************************************************************
117 ;;**********************************************************************************
118 ;;************ Program housekeeping, handling calling flags, etc. ****************
119 ;;**********************************************************************************
121 ;; The following is needed to make guile 1.8.x happy.
122 (use-modules (ice-9 rdelim) (srfi srfi-1))
124 ;; Common functions for the `spice' and `spice-sdb' backends
125 (load-from-path "spice-common.scm")
127 ;;--------------------------------------------------------------------------------
128 ;; spice-sdb:loop-through-files -- loops through the model-file list, and for each file
129 ;; name discovered in the list, it processes the file by invoking handle-spice-file.
130 ;;--------------------------------------------------------------------------------
131 (define spice-sdb:loop-through-files
132 (lambda (file-info-list)
133 (if (not (null? file-info-list))
134 (let* ((list-element (car file-info-list))
135 (model-name (car list-element))
136 (file-name (cadr list-element))
137 (file-type (caddr list-element))
139 (spice-sdb:handle-spice-file file-name)
140 (spice-sdb:loop-through-files (cdr file-info-list))
145 ;;--------------------------------------------------------------------------------
146 ;; spice-sdb:get-file-info-list-item -- loops through the model-file list looking
147 ;; for triplet corresponding to model-name. If found, it returns the corresponding
148 ;; list. If not found, returns #f
149 ;;--------------------------------------------------------------------------------
150 (define spice-sdb:get-file-info-list-item
151 (lambda (model-name file-info-list)
152 (if (null? file-info-list)
153 '() ;; return #f upon empty list.
154 ;; #f replaced with '() by peter
155 (let* ((list-element (car file-info-list)) ;; else process list-item
156 (list-elt-model-name (car list-element))
157 (list-elt-file-name (cadr list-element))
158 (list-elt-file-type (caddr list-element))
160 (if (string=? list-elt-model-name model-name)
161 list-element ;; found model-name. Return list-element.
162 (spice-sdb:get-file-info-list-item model-name (cdr file-info-list)) ;; otherwise, recurse.
168 ;;--------------------------------------------------------------------------
169 ;; handle-spice-file: This wraps insert-text-file.
170 ;; Calling form: (handle-spice-file file-name)
171 ;; It looks to see if the -I flag was set at the command line. If so,
172 ;; it just writes a .INCLUDE card with the file name. If not, it calls
173 ;; insert-text-file to stick the file's contents into the SPICE netlist.
174 ;;--------------------------------------------------------------------------
175 (define spice-sdb:handle-spice-file
177 (debug-spew (string-append "Handling spice model file " file-name "\n"))
178 (if (calling-flag? "include_mode" (gnetlist:get-calling-flags))
179 (display (string-append ".INCLUDE " file-name "\n")) ;; -I found: just print out .INCLUDE card
180 (spice-sdb:insert-text-file file-name) ;; -I not found: invoke insert-text-file
181 ) ;; end of if (calling-flag
185 ;;--------------------------------------------------------------------------
186 ;; Given a filename, open the file, get the contents, and dump them
187 ;; into the spice file.
188 ;; Calling form is "(insert-text-file input-file output-file)"
189 ;; The function opens input-file, but assumes that output-file is
192 ;; This function is usually used to include spice models contained in
193 ;; files into the netlist. Note that it doesn't
194 ;; check the correctness of the spice code in the file -- you're on your own!
195 ;;---------------------------------------------------------------------------
196 (define spice-sdb:insert-text-file
197 (lambda (model-filename)
198 (if (file-exists? model-filename)
199 (let ((model-file (open-input-file model-filename)) )
200 (display (string-append "*vvvvvvvv Included SPICE model from " model-filename " vvvvvvvv\n"))
201 (let while ((model-line (read-line model-file)))
202 (if (not (eof-object? model-line))
204 (display (string-append model-line "\n"))
205 (while (read-line model-file))
206 ) ;; end of inner begin
208 ) ;; end of inner let
209 (close-port model-file)
210 (display (string-append "*^^^^^^^^ End of included SPICE model from " model-filename " ^^^^^^^^\n*\n"))
211 ) ;; end of outer let
213 (message (string-append "ERROR: File '" model-filename "' not found.\n"))
220 ;;----------------------------------------------------------
221 ;; Figure out if this schematic is a .SUBCKT lower level.
222 ;; This is determined if there is a spice-subcircuit-LL
223 ;; device instantiated somewhere on the schematic.
224 ;; If it is a .SUBCKT, return ".SUBCKT model-name"
225 ;;----------------------------------------------------------
226 (define spice-sdb:get-schematic-type
229 (let* ((package (car ls)) ;; assign package
230 (device (get-device package)) ;; assign device.
231 ) ;; end of let* assignments
232 (if (string=? device "spice-subcircuit-LL") ;; look for subcircuit label
233 (string-append ".SUBCKT " (gnetlist:get-package-attribute package "model-name"))
234 (spice-sdb:get-schematic-type (cdr ls)) ;; otherwise just iterate to next package.
237 "normal schematic" ; return "normal schematic" if no spice-subcircuit-LL is found
242 ;;----------------------------------------------------------
243 ;; Extract the modelname from the .SUBCKT modelname line.
244 ;; Just grab the chars from char 8 to the end of the string.
245 ;;---------------------------------------------------------
246 (define spice-sdb:get-subcircuit-modelname
247 (lambda (schematic-type)
248 (substring schematic-type 8 (string-length schematic-type))
253 ;;-----------------------------------------------------------
254 ;; This iterates through the schematic and compiles a list of
255 ;; all spice-IO pins found. This is used when writing out
256 ;; a .SUBCKT lower level netlist.
257 ;;-----------------------------------------------------------
258 (define spice-sdb:get-spice-IO-pins
259 (lambda (ls spice-io-package-list)
262 spice-io-package-list ;; end iteration & return list if ls is empty.
264 (let* ((package (car ls)) ;; otherwise process package. . .
265 (device (get-device package))
267 (if (string=? device "spice-IO") ;; look for subcircuit label
269 ;; we have found a spice-IO pin.
270 (spice-sdb:get-spice-IO-pins (cdr ls) (cons package spice-io-package-list))
272 ;; no spice-IO pin found. Iterate . . . .
273 (spice-sdb:get-spice-IO-pins (cdr ls) spice-io-package-list)
275 ) ;; end of if string=?
283 ;;----------------------------------------------------------------
284 ;; This takes the list of io-pin-packages and sorts it in order of
286 ;; Repaired on 12.27.2005 to correctly sort pin numbers > 9.
287 ;;----------------------------------------------------------------
288 (define spice-sdb:sort-spice-IO-pins
289 (lambda (package-list)
290 ;; Yes, this isn't good Scheme form. Tough! Writing this out
291 ;; in a functional programming form would be totally confusing!
292 ;; Note that this fcn requires that
293 ;; each spice-IO pin have the same, single character prefix (i.e. 'P')
294 (let* ((char-prefixes (map car (map string->list package-list))) ;; Pull off first char (prefix)
295 (prefixes (map string char-prefixes)) ;; Make list of strings from prefixes
296 (split-numbers-list (map cdr (map string->list package-list))) ;; Pull off refdes numbers as list elements
297 (string-numbers-list (map list->string split-numbers-list)) ;; Recombine split up (multidigit) number strings
298 (numbers-list (map string->number string-numbers-list)) ;; Convert strings to numbers for sorting
299 (sorted-numbers-list (sort numbers-list <)) ;; Sort refdes numbers as numbers
300 (sorted-string-numbers-list (map number->string sorted-numbers-list)) ) ;; Create sorted list of refdes strings.
302 (map-in-order string-append prefixes sorted-string-numbers-list) ;; Laminate prefixes back onto refdes numbers & return.
309 ;;----------------------------------------------------------------
310 ;; Given a list of spice-IO packages (refdeses), this function returns the list
311 ;; of nets attached to the IOs.
312 ;;----------------------------------------------------------------
313 (define spice-sdb:get-IO-nets
314 (lambda (package-list net-list)
315 (if (null? package-list)
317 net-list ;; end iteration & return net-list if ls is empty.
319 (let* ((package (car package-list)) ;; otherwise process package. . .
320 (net (car (gnetlist:get-nets package "1"))) ;; get the net attached to pin 1
323 (spice-sdb:get-IO-nets (cdr package-list) (cons net net-list))
330 ;;----------------------------------------------------------
331 ;; This takes a list and turns it into a string.
332 ;; The difference between this and list->string is that
333 ;; this fun can handle lists made up of multi-char strings.
334 ;;----------------------------------------------------------
335 (define list-2-string
341 (if (null? local-list)
342 st ;; end iteration & return string if list is empty.
343 (begin ;; otherwise turn next element of list into string. . .
344 (set! st (string-append (car local-list) " " st)) ;; stuff next element onto st
345 (while st (cdr local-list)) ;; iterate with remainder of ls
353 ;;----------------------------------------------------------
354 ;; This returns #t if the string is composed only of
355 ;; whitespace. It works by turning the string into
356 ;; a list, and then checking to see if it is the empty
357 ;; list. If so, it returns #t.
358 ;;----------------------------------------------------------
359 (define empty-string?
361 (null? (string->list string))
366 ;;----------------------------------------------------------
367 ;; This returns a list of all the integers from start to
368 ;; stop, with the optional step size.
369 ;; It is similar to perl's range operator '..'
370 ;;----------------------------------------------------------
371 (define (range start stop . step)
373 (iota (+ (- stop start) 1) start)
375 (set! step (car step))
376 (iota (+ (ceiling (/ (- stop start) step)) 1) start step)
382 ;;----------------------------------------------------------
383 ;; Given a filename, open the file, get the first line,
384 ;; and see if it is a .MODEL or .SUBCKT file.
385 ;; Returns either ".MODEL" or ".SUBCKT" or "OTHER"
386 ;; Calling form is "(spice-sdb:get-file-type input-file)"
387 ;; The function opens input-file, and closes it when it is done.
388 ;;----------------------------------------------------------
389 (define spice-sdb:get-file-type
390 (lambda (model-filename)
392 (if (file-exists? model-filename)
393 (let ((model-file (open-input-file model-filename)) )
394 (let while ((file-line (read-line model-file)) )
397 ((eof-object? file-line) ;; Arrived at end of line without finding .MODEL or .SUBCKT. Return "OTHER"
400 ((empty-string? file-line)
401 (while (read-line model-file)) ) ;; Found empty line. Iterate before doing anything else.
403 ((string=? (string (string-ref file-line 0)) "*")
404 (while (read-line model-file)) ) ;; Found *comment. Iterate.
406 ((string=? (string (string-ref file-line 0)) ".")
408 (debug-spew "In get-file-type, first-char = .\n") ;; DEBUG stuff
411 ((string-ci=? (safe-string-head file-line 7) ".subckt") ;; found .subckt as first line.
414 ((string-ci=? (safe-string-head file-line 6) ".model") ;; found .model as first line.
417 (else "OTHER") ;; first . spice card is neither .model nor .subckt
424 (while (read-line model-file))
429 ) ;; end of inner lets
430 ) ;; end of outer let
432 (message (string-append "ERROR: File '" model-filename "' not found.\n"))
439 ;;---------------------------------------------------------------
440 ;; write prefix if first char of refdes is improper,
441 ;; eg. if MOSFET is named T1 then becomes MT1 in SPICE
442 ;;---------------------------------------------------------------
443 (define spice-sdb:write-prefix
444 (lambda (package prefix)
445 (let ((different-prefix (not (string=? (substring package 0 1) prefix)) )
446 (nomunge (calling-flag? "nomunge_mode" (gnetlist:get-calling-flags)) )
448 (debug-spew (string-append "Checking prefix. Package prefix =" (substring package 0 1) "\n"))
449 (debug-spew (string-append " correct prefix =" prefix "\n"))
450 (debug-spew " nomunge mode = ")
452 (debug-spew (string-append "\n different-prefix="))
453 (debug-spew different-prefix)
455 (if (and different-prefix (not nomunge))
462 ;;---------------------------------------------------------------
463 ;; spice-sdb:packsort
464 ;; Sort procedure to order refdes's alphabetically but
465 ;; keep A? packages at the end of list so SPICE simulation
466 ;; directives operate correctly.
467 ;; This fcn written by Ken Healy to enable SPICE netlisting for
468 ;; Gnucap, which wants A refdes cards (i.e. SPICE directives)
469 ;; to appear last in the SPICE netlist. Slightly modified
470 ;; and incorporated into main spice-sdb release by SDB on 9.1.2003.
471 ;; To output the netlist in sorted order, use the -s switch
472 ;; when invoking gnetlist from the command line. Example:
473 ;; gnetlist -s -g spice-sdb -o output.spice Schematic.sch
474 ;; The default behavior (i.e. if -s is not specified) is to do
476 ;;---------------------------------------------------------------
477 (define spice-sdb:packsort
479 (let ((xdes (string-ref x 0))
480 (ydes (string-ref y 0))
481 (xnum (string-tail x 1))
482 (ynum (string-tail y 1))
485 (if (char-ci=? xdes ydes)
486 (if (string-ci<? xnum ynum) #t #f)
487 (if (char-ci=? xdes #\A) #f
488 (if (char-ci=? ydes #\A) #t
489 (if (char-ci<? xdes ydes) #t #f)))))))
491 (define (string-tail string start)
492 (substring string start (string-length string)))
495 ;;---------------------------------------------------------------
496 ;; spice-sdb:sort_refdes?
497 ;; Returns #t or #f depending upon if -s was discovered in
498 ;; the calling flags given to gnetlist. Used in conjunction with
499 ;; spice-sdb:packsort.
500 ;; Calling form: (spice-sdb:sort-refdes? (gnetlist:get-calling-flags))
502 ;;---------------------------------------------------------------
503 ;; Note: I should re-write this to use calling-flag? . . . .
504 (define spice-sdb:sort-refdes?
505 (lambda (calling-flag-list)
507 (if (null? calling-flag-list)
508 '#f ;; return #f if null list -- sort_mode not found.
509 (let* ((calling-pair (car calling-flag-list)) ;; otherwise look for sort_mode in remainder of list.
510 (calling-flag (car calling-pair))
511 (flag-value (cadr calling-pair)) )
513 (if (string=? calling-flag "sort_mode")
514 flag-value ;; return flag-value if sort_mode found
515 (spice-sdb:sort-refdes? (cdr calling-flag-list)) ;; otherwise recurse until sort_mode is found
522 ;;**********************************************************************************
523 ;;*************** Dealing with nets, devices, & SPICE cards. *******************
524 ;;**********************************************************************************
527 ;;----------------------------------------------------------------
529 ;; Write-transistor-diode: writes out component followed by
530 ;; model or model file associated
531 ;; with the component.
532 ;; This function does the following:
533 ;; 1. Writes out the correct refdes prefix (if specified and necessary).
534 ;; 2. Writes out the refdes and nets
535 ;; 3. Looks for "model-name" attribute. Writes it out if it exists.
536 ;; 4. If there is no "model-name" attribute, it writes out the "value"
537 ;; attribute. If there is no "value" attribute, it writes out "unknown"
538 ;; and returns, causing the spice simulator to puke when the netlist
539 ;; is run. This is important
540 ;; 'cause the spice simulator needs to have some indication of what
541 ;; model to look for.
542 ;; 5. Outputs optional attributes attached to device, if any. Feature
543 ;; added by SDB on 12.25.2003.
544 ;; 6. Outputs a new line
545 ;; 7. Looks for a the "model" attribute. If it exists, it it writes out
546 ;; a .MODEL line like this: .MODEL model-name type (model)
548 ;;----------------------------------------------------------------
549 (define spice-sdb:write-transistor-diode
550 (lambda (package prefix type attrib-list)
552 ;; First do local assignments
553 (let ((model-name (gnetlist:get-package-attribute package "model-name"))
554 (model (gnetlist:get-package-attribute package "model"))
555 (value (gnetlist:get-package-attribute package "value"))
556 (area (gnetlist:get-package-attribute package "area"))
557 (off (gnetlist:get-package-attribute package "off"))
558 (model-file (gnetlist:get-package-attribute package "file"))
559 ) ;; end of local assignments
561 ;; Write out the refdes prefix, if specified and necessary.
563 (spice-sdb:write-prefix package prefix)
566 ;; Next we write out the refdes and nets.
567 (spice-sdb:write-component-no-value package)
569 ;; next look for "model-name" attribute. Write it out if it exists.
570 ;; otherwise look for "value" attribute.
571 (if (not (string=? model-name "unknown"))
572 (display (string-append model-name " " )) ;; display model-name if known
573 (display (string-append value " "))) ;; otherwise display value
575 ;; Next write out attributes if they exist
576 ;; First attribute is area. It is written as a simple string
577 (if (not (string=? area "unknown"))
578 (display (string-append area " ")))
580 ;; Next attribute is off. It is written as a simple string
581 (if (not (string=? off "unknown"))
582 (display (string-append off " ")))
584 ;; Write out remaining attributes
585 (spice:write-list-of-attributes package attrib-list)
587 ;; Now write out newline in preparation for writing out model.
590 ;; Now write out any model which is pointed to by the part.
593 ;; one line model and model name exist
594 ( (not (or (string=? model "unknown") (string=? model-name "unknown")))
595 (debug-spew (string-append "found model and model-name for " package "\n"))
596 (display (string-append ".MODEL " model-name " " type " (" model ")\n")) )
598 ;; one line model and component value exist
599 ( (not (or (string=? model "unknown") (string=? value "unknown")))
600 (debug-spew (string-append "found model and value for " package "\n"))
601 (display (string-append ".MODEL " model-name " " type " (" value ")\n")) )
603 ;; model file and model name exist
604 ( (not (or (string=? model-file "unknown") (string=? model-name "unknown")))
605 (debug-spew (string-append "found file and model-name for " package "\n"))
606 (debug-spew "I'll deal with the file later . . .\n")
609 ;; model file and component value exist
610 ( (not (or (string=? model-file "unknown") (string=? value "unknown")))
611 (debug-spew (string-append "found file and value for " package "\n"))
612 (debug-spew "I'll deal with the file later . . .\n")
621 ;;----------------------------------------------------------------
623 ;; This writes out a valid diode refdes & then calls
624 ;; the function which writes the rest of the line.
625 ;;----------------------------------------------------------------
626 (define spice-sdb:write-diode
628 (debug-spew (string-append "Found diode. Refdes = " package "\n"))
629 (let ((attrib-list (list "ic" "temp") ))
630 (spice-sdb:write-transistor-diode package "D" "D" attrib-list))
635 ;;----------------------------------------------------------------
636 ;; spice-sdb:write-ic
637 ;; This writes out a valid ic or subcircuit line.
638 ;; The algorithm is as follows:
639 ;; 1. Figure out what type of model goes with this part from
640 ;; file-info-list. If it isn't listed, look for a MODEL attribute.
641 ;; If MODEL attribute is attached, write out SPICE card, and then
642 ;; write out .MODEL on next line.
643 ;; If no MODEL attribute is attached, just write out what little
644 ;; we know. Then return
645 ;; 2. If the model-name is in the file-info-list, get the associated
646 ;; file-type. Compare it against the component's refdes. If model-type
647 ;; is .MODEL or .SUBCKT and refdes doesn't begin with a U or X
648 ;; respectively, prepend the correct prefix to the refdes.
649 ;; 3. Print out the rest of the line.
651 ;;----------------------------------------------------------------
652 (define (spice-sdb:write-ic package file-info-list)
654 ;; First do local assignments
655 (let ((first-char (string (string-ref package 0))) ;; extract first char of refdes
656 (model-name (gnetlist:get-package-attribute package "model-name"))
657 (model (gnetlist:get-package-attribute package "model"))
658 (value (gnetlist:get-package-attribute package "value"))
659 (type (gnetlist:get-package-attribute package "type"))
660 (model-file (gnetlist:get-package-attribute package "file"))
662 ) ;; end of local assignments
665 ((string=? first-char "U") (debug-spew (string-append "Found ic. Refdes = " package "\n")))
666 ((string=? first-char "X") (debug-spew (string-append "Found subcircuit. Refdes = " package "\n")))
669 ;; First, if model-name is empty, we use value attribute instead.
670 ;; We do this by sticking the contents of "value" into "model-name".
671 (if (string=? model-name "unknown")
672 (set! model-name value))
674 ;; Now get item from file-info-list using model-name as key
675 (set! list-item (spice-sdb:get-file-info-list-item model-name file-info-list))
677 ;; check to see if list-item is null.
678 (if (null? list-item)
680 ;; list-item is null. Evidently, we didn't discover any files holding this model.
681 ;; Instead we look for model attribute
682 (if (not (string=? model "unknown"))
683 (begin ;; model attribute exists -- write out card and model.
684 (debug-spew "Model info not found in model file list, but model attribute exists. Write out spice card and .model line..\n")
685 (spice-sdb:write-component-no-value package)
686 (display (string-append model-name "\n" ))
687 (display (string-append ".MODEL " model-name " "))
688 (if (not (string=? type "unknown")) (display (string-append type " "))) ;; If no type then just skip it.
689 (display (string-append "(" model ")\n"))
691 (begin ;; no model attribute either. Just write out card.
692 (debug-spew "Model info not found in model file list. No model attribute either. Just write what we know.\n")
693 (spice-sdb:write-component-no-value package)
694 (display (string-append model-name "\n" ))
696 ) ;; end if (not (string=? . . . .
698 ;; list-item is not null. Therefore we process line depending upon contents of list-item
699 (let ((file-type (caddr list-item)) )
701 ;; ---- file holds a model ----
702 ((string=? file-type ".MODEL")
704 (debug-spew (string-append "Found .MODEL with model-file and model-name for " package "\n"))
705 (spice-sdb:write-prefix package "U") ;; this prepends an "U" to the refdes if needed, since we have a .model
706 (spice-sdb:write-component-no-value package)
707 (display (string-append model-name "\n" ))
708 (debug-spew "We'll handle the file contents later . . .\n")
711 ;; ---- file holds a subcircuit ----
712 ((string=? file-type ".SUBCKT")
714 (debug-spew (string-append "Found .SUBCKT with model-file and model-name for " package "\n"))
715 (spice-sdb:write-prefix package "X") ;; this prepends an "X" to the refdes if needed, since we have a .subckt
716 (spice-sdb:write-component-no-value package)
717 (display (string-append model-name "\n" ))
718 (debug-spew "We'll handle the file contents later . . .\n")
720 ) ;; close of inner cond
721 ) ;; end of inner let
722 ) ;; end of if (null? list-item
724 ) ;; end of outer let
728 ;;-----------------------------------------------------------
729 ;; write npn bipolar transistor
730 ;; This writes out a valid transistor refdes & then calls
731 ;; the function which writes the rest of the line.
732 ;;-----------------------------------------------------------
733 (define spice-sdb:write-npn-bipolar-transistor
735 (debug-spew (string-append "Found npn bipolar transistor. Refdes = " package "\n"))
736 (let ((attrib-list (list "ic" "temp") ))
737 (spice-sdb:write-transistor-diode package "Q" "NPN" attrib-list))
742 ;;-----------------------------------------------------------
743 ;; write pnp bipolar transistor
744 ;;-----------------------------------------------------------
745 (define spice-sdb:write-pnp-bipolar-transistor
747 (debug-spew (string-append "Found pnp bipolar transistor. Refdes = " package "\n"))
748 (let ((attrib-list (list "ic" "temp") ))
749 (spice-sdb:write-transistor-diode package "Q" "PNP" attrib-list))
754 ;;-----------------------------------------------------------
755 ;; write n-channel jfet transistor
756 ;;-----------------------------------------------------------
757 (define spice-sdb:write-nfet-transistor
759 (debug-spew (string-append "Found n-channel JFET. Refdes = " package "\n"))
760 (let ((attrib-list (list "ic" "temp") ))
761 (spice-sdb:write-transistor-diode package "J" "NJF" attrib-list))
766 ;;-----------------------------------------------------------
767 ;; write p-channel jfet transistor
768 ;;-----------------------------------------------------------
769 (define spice-sdb:write-pfet-transistor
771 (debug-spew (string-append "Found p-channel JFET. Refdes = " package "\n"))
772 (let ((attrib-list (list "ic" "temp") ))
773 (spice-sdb:write-transistor-diode package "J" "PJF" attrib-list))
778 ;;------------------------------------------------------
779 ;; write pmos transistor
780 ;;------------------------------------------------------
781 (define spice-sdb:write-pmos-transistor
783 (debug-spew (string-append "Found PMOS transistor. Refdes = " package "\n"))
784 (let ((attrib-list (list "l" "w" "as" "ad" "pd" "ps" "nrd" "nrs" "temp" "ic" "m")))
785 (spice-sdb:write-transistor-diode package "M" "PMOS" attrib-list))
790 ;;------------------------------------------------------
791 ;; write nmos transistor
792 ;;------------------------------------------------------
793 (define spice-sdb:write-nmos-transistor
795 (debug-spew (string-append "Found NMOS transistor. Refdes = " package "\n"))
796 (let ((attrib-list (list "l" "w" "as" "ad" "pd" "ps" "nrd" "nrs" "temp" "ic" "m")))
797 (spice-sdb:write-transistor-diode package "M" "NMOS" attrib-list))
802 ;;------------------------------------------------------
803 ;; write subckt pmos transistor
804 ;;------------------------------------------------------
805 (define spice-sdb:write-subckt-pmos-transistor
807 (debug-spew (string-append "Found PMOS subcircuit transistor. Refdes = " package "\n"))
808 (let ((attrib-list (list "l" "w" "as" "ad" "pd" "ps" "nrd" "nrs" "temp" "ic" "m")))
809 (spice-sdb:write-transistor-diode package "X" "PMOS" attrib-list))
813 ;;------------------------------------------------------
814 ;; write subckt nmos transistor
815 ;;------------------------------------------------------
816 (define spice-sdb:write-subckt-nmos-transistor
818 (debug-spew (string-append "Found NMOS subcircuit transistor. Refdes = " package "\n"))
819 (let ((attrib-list (list "l" "w" "as" "ad" "pd" "ps" "nrd" "nrs" "temp" "ic" "m")))
820 (spice-sdb:write-transistor-diode package "X" "NMOS" attrib-list))
823 ;;------------------------------------------------------------
824 ;; write mesfet transistor
825 ;;------------------------------------------------------------
826 ;; ************ Fix this!!!!!!!!!! **************
827 (define spice-sdb:write-mesfet-transistor
829 (spice-sdb:write-transistor-diode package "Z" "MESFET" (list)))) ;; XXXXXX Fix this!!!
832 ;;-----------------------------------------------------------
833 ;; write voltage controled switch
834 ;;-----------------------------------------------------------
835 (define spice-sdb:write-vc-switch
837 (debug-spew (string-append "Found voltage controlled switch. Refdes = " package "\n"))
838 (let ((attrib-list (list " " ) ))
839 (spice-sdb:write-transistor-diode package "S" "SW" attrib-list))
844 ;;--------------------------------------------------------------------
846 ;;--------------------------------------------------------------------
847 (define spice-sdb:write-resistor
850 (debug-spew (string-append "Found resistor. Refdes = " package "\n"))
852 ;; first write out refdes and attached nets
853 (spice-sdb:write-component-no-value package)
855 ;; next write out mandatory resistor value if it exists.
856 (let ((value (gnetlist:get-package-attribute package "value")))
857 (if (not (string=? value "unknown"))
858 (display (string-append value " " )))
861 ;; next write our model name if it exists
862 (let ((model-name (gnetlist:get-package-attribute package "model-name")))
863 (if (not (string=? model-name "unknown"))
864 (display (string-append model-name " " )))
867 ;; next create list of attributes which can be attached to a resistor.
868 ;; I include non-standard "area" attrib here per popular demand.
869 (let ((attrib-list (list "area" "l" "w" "temp")))
870 ;; write the attributes (if any) separately
871 (spice:write-list-of-attributes package attrib-list)
872 (display " ")) ;; add additional space. . . .
874 ;; finally output a new line
881 ;;----------------------------------------------------------------------------
883 ;;----------------------------------------------------------------------------
884 (define spice-sdb:write-capacitor
887 (debug-spew (string-append "Found capacitor. Refdes = " package "\n"))
889 ;; first write out refdes and attached nets
890 (spice-sdb:write-component-no-value package)
892 ;; next write capacitor value, if any. Note that if the
893 ;; component value is not assigned nothing will be written out.
894 (let ((value (gnetlist:get-package-attribute package "value")))
895 (if (not (string=? value "unknown"))
896 (display (string-append value " " )))
899 ;; next write capacitor model name, if any. This is applicable to
900 ;; semiconductor caps used in chip design.
901 (let ((model-name (gnetlist:get-package-attribute package "model-name")))
902 (if (not (string=? model-name "unknown"))
903 (display (string-append model-name " " )))
906 ;; Next write out attributes if they exist. Use
907 ;; a list of attributes which can be attached to a capacitor.
908 ;; I include non-standard "area" attrib here per request of Peter Kaiser.
909 (let ((attrib-list (list "area" "l" "w" "ic")))
910 (spice:write-list-of-attributes package attrib-list)
911 ;; write the off attribute separately
912 (display " ")) ;; add additional space. . . .
919 ;;----------------------------------------------------------------------------
921 ;;----------------------------------------------------------------------------
922 (define spice-sdb:write-inductor
925 (debug-spew (string-append "Found inductor. Refdes = " package "\n"))
927 ;; first write out refdes and attached nets
928 (spice-sdb:write-component-no-value package)
931 ;; next write inductor value, if any. Note that if the
932 ;; component value is not assigned, then it will write "unknown"
933 (let ((value (gnetlist:get-package-attribute package "value")))
938 ;; create list of attributes which can be attached to a inductor
939 (let ((attrib-list (list "l" "w" "ic")))
940 (spice:write-list-of-attributes package attrib-list)
942 ;; write the off attribute separately
943 (display " ")) ;; add additional space. . . .
950 ;;-------------------------------------------------------------------------
951 ;; write independent voltage source
952 ;; The behavior of the voltage source is held in the "value" attribute
953 ;;-------------------------------------------------------------------------
954 (define spice-sdb:write-independent-voltage-source
956 (debug-spew (string-append "Found independent voltage source. Refdes = " package "\n"))
958 ;; first write out refdes and attached nets
959 (spice-sdb:write-component-no-value package)
961 ;; next write voltage value, if any. Note that if the
962 ;; voltage value is not assigned, then it will write "unknown"
963 (let ((value (gnetlist:get-package-attribute package "value")))
972 ;;-------------------------------------------------------------------------
973 ;; write independent current source
974 ;; The behavior of the current source is held in the "value" attribute
975 ;;-------------------------------------------------------------------------
976 (define spice-sdb:write-independent-current-source
979 (debug-spew (string-append "Found independent current source. Refdes = " package "\n"))
981 ;; first write out refdes and attached nets
982 (spice-sdb:write-component-no-value package)
984 ;; next write current value, if any. Note that if the
985 ;; current value is not assigned, then it will write "unknown"
986 (let ((value (gnetlist:get-package-attribute package "value")))
995 ;;----------------------------------------------------------------------------
996 ;; write Josephson junction in wrspice format. Paul Bunyk, Sep 2, 2005
997 ;;----------------------------------------------------------------------------
998 (define spice-sdb:write-josephson-junction
1001 (debug-spew (string-append "Found Josephson junction. Refdes = " package "\n"))
1003 ;; first write out refdes and attached nets
1004 (spice-sdb:write-component-no-value package)
1006 ;; next, add a dummy node for JJ phase. Unlike in Xic netlister, give it
1007 ;; a reasonable name, not a number, e.g., refdes.
1008 (display (string-append package " "))
1010 ;; next write JJ model name, if any.
1011 (let ((model-name (gnetlist:get-package-attribute package "model-name")))
1012 (if (not (string=? model-name "unknown"))
1013 (display (string-append model-name " " )))
1016 ;; Next write out attributes if they exist. Use
1017 ;; a list of attributes which can be attached to a junction.
1018 (spice:write-list-of-attributes package (list "area"))
1024 ;;----------------------------------------------------------------------------
1025 ;; write mutual inductance(actually K). Paul Bunyk, Sep 2, 2005
1026 ;;----------------------------------------------------------------------------
1027 (define spice-sdb:write-coupling-coefficient
1030 (debug-spew (string-append "Found mutual inductance. Refdes = " package "\n"))
1032 ;; first write out refdes and attached nets (none)
1033 (spice-sdb:write-component-no-value package)
1035 ;; next two inductor names and value
1036 (let ((inductors (gnetlist:get-package-attribute package "inductors"))
1037 (value (gnetlist:get-package-attribute package "value")) )
1038 (if (not (string=? inductors "unknown"))
1039 (display (string-append inductors " " )))
1040 (if (not (string=? value "unknown"))
1041 (display (string-append value " " )))
1050 ;;----------------------------------------------------------------------------
1051 ;; write a voltage probe
1052 ;;----------------------------------------------------------------------------
1053 (define (spice-sdb:write-probe package)
1054 ;; fetch only one attr we care about, so far
1055 (let ((value (gnetlist:get-package-attribute package "value"))
1056 ) ;; end of local assignments
1058 (debug-spew (string-append "Found Probe item, refdes = " package "\n"))
1060 (if (string=? value "unknown")
1061 (set! value "TRAN"))
1063 (display (string-append "* Probe device " package " on nets "))
1064 (spice-sdb:write-net-names-on-component package)
1066 (display (string-append ".print " value " +"))
1067 (spice-sdb:write-net-names-on-component package
1068 (string-join (map (lambda (x) "V(~a)") (gnetlist:get-pins package)) " " 'infix) ) ;; make format string
1071 ) ;; close of define
1074 ;;--------------------------------------------------------------------
1075 ;; Given a refdes, and optionally a format string, this writes
1076 ;; out the nets attached to the component's pins. If it's not called
1077 ;; with a format string it looks for one in the net-format attribute,
1078 ;; otherwise it writes out the pins unformatted. This is used to write
1079 ;; out non-slotted parts.
1080 ;;--------------------------------------------------------------------
1081 (define (spice-sdb:write-net-names-on-component refdes . format)
1083 ;; get-net-name -- helper function. Called with pinseq, returns net name,
1084 ;; unless net name is "ERROR_INVALID_PIN" then it returns false.
1085 (define (get-net-name pin)
1086 (set! pin (number->string pin))
1088 ;; ------- Super debug stuff --------
1091 (debug-spew " In write-net-names-on-component. . . . \n")
1092 (debug-spew (string-append " pin-name = " pin "\n"))
1093 (debug-spew (string-append " pinnumber = " (gnetlist:get-attribute-by-pinseq refdes pin "pinnumber") "\n"))
1094 (debug-spew (string-append " pinseq = " (gnetlist:get-attribute-by-pinseq refdes pin "pinseq")))
1095 (if (not (string=? pin (gnetlist:get-attribute-by-pinseq refdes pin "pinseq")))
1096 (debug-spew " <== INCONSISTENT!\n")
1098 (debug-spew (string-append " netname = " (car (spice:get-net refdes (gnetlist:get-attribute-by-pinseq refdes pin "pinnumber"))) "\n"))
1099 )) ;; if #T for super debugging
1100 ;; -------------------------------------
1102 (set! pin (car (spice:get-net refdes (gnetlist:get-attribute-by-pinseq refdes pin "pinnumber"))))
1103 (if (string=? pin "ERROR_INVALID_PIN")
1105 (debug-spew (string-append "For " refdes ", found pin with no pinseq attribute. Ignoring. . . .\n"))
1108 ) ;; define get-net-name
1110 ;; First do local assignments
1111 (let ((netnames (filter-map get-net-name (range 1 (length (gnetlist:get-pins refdes)))))
1113 (if (null? format) ;; Format agument take priority, otherwise use attribute
1114 (set! format (gnetlist:get-package-attribute refdes "net-format"))
1115 (set! format (car format)) )
1116 (if (string=? format "unknown")
1117 (display (string-join netnames " " 'suffix)) ;; write out nets.
1118 (apply simple-format (cons #t (cons format netnames))) ) ;; write out nets with format string
1123 ;;-------------------------------------------------------------------
1124 ;; Write the refdes and the net names connected to pins on this component.
1125 ;; No return, and no component value is written, or extra attribs.
1126 ;; Those are handled later.
1127 ;;-------------------------------------------------------------------
1128 (define spice-sdb:write-component-no-value
1130 (display (string-append package " ")) ;; write component refdes
1131 (spice-sdb:write-net-names-on-component package)
1136 ;;------------------------------------------------------------
1137 ;; Given a refdes, returns the device attribute "value" as string
1138 ;; Used when "value" is an optional attribute.
1139 ;; Returns "unknown" if not available.
1140 ;;------------------------------------------------------------
1141 (define spice-sdb:component-optional-value
1143 (let ((value (gnetlist:get-package-attribute package "value")))
1144 (if (not (string=? value "unknown"))
1145 (string-append value " ")
1149 ;;-----------------------------------------------------------
1150 ;; Given a refdes, returns the device attribute "model" as string
1151 ;;-----------------------------------------------------------
1152 (define spice-sdb:component-model
1154 (let ((model (gnetlist:get-package-attribute package "model")))
1155 (if (not (string=? model "unknown"))
1156 model spice:component-value))))
1159 ;;----------------------------------------------------------
1160 ;; Include SPICE statements from a SPICE directive block.
1161 ;;----------------------------------------------------------
1162 (define spice-sdb:write-directive
1164 ;; Collect variables used in creating spice code
1165 (let ((value (gnetlist:get-package-attribute package "value"))
1166 (file (gnetlist:get-package-attribute package "file"))
1167 ) ;; end of local assignments
1169 (debug-spew (string-append "Found SPICE directive box. Refdes = " package "\n"))
1173 ;; First look to see if there is a value.
1174 ((not (string=? value "unknown"))
1176 (display (string-append value "\n"))
1177 (debug-spew (string-append "Appending value = \"" value "\" to output file.\n"))
1180 ;; since there is no value, look for file.
1181 ((not (string=? file "unknown"))
1183 (spice-sdb:insert-text-file file) ;; Note that we don't wait until the end here. Is that OK?
1184 (debug-spew (string-append "Inserting contents of file = " file " into output file.\n"))
1189 ) ;; close of lambda
1190 ) ;; close of define
1193 ;;----------------------------------------------------------
1194 ;; Include a file using an .INCLUDE directive
1195 ;; Changed on 6.12.2005: to embed the contents of the file,
1196 ;; you must call gnetlist with the -e flag set.
1197 ;;----------------------------------------------------------
1198 (define spice-sdb:write-include
1200 (let ((file (gnetlist:get-package-attribute package "file")))
1202 (debug-spew (string-append "Found SPICE include box. Refdes = " package "\n"))
1204 (if (not (string=? file "unknown"))
1205 (if (calling-flag? "embedd_mode" (gnetlist:get-calling-flags))
1207 (spice-sdb:insert-text-file file) ;; -e found: invoke insert-text-file
1208 (debug-spew (string-append "embedding contents of file " file " into netlist.\n")))
1210 (display (string-append ".INCLUDE " file "\n")) ;; -e not found: just print out .INCLUDE card
1211 (debug-spew "placing .include directive string into netlist.\n"))
1213 (debug-spew "silently skip \"unknown\" file.\n")
1218 ;;----------------------------------------------------------
1219 ;; Include an option using an .OPTIONS directive
1220 ;;----------------------------------------------------------
1221 (define spice-sdb:write-options
1223 (debug-spew (string-append "Found .OPTIONS box. Refdes = " package "\n"))
1224 (display (string-append ".OPTIONS " (spice:component-value package) "\n"))))
1227 ;;----------------------------------------------------------
1228 ;; Include a spice model (instantiated as a model box on the schematic)
1229 ;; Two types of model can be included:
1230 ;; 1. An embedded model, which is a one- or multi-line string held in the attribute "model".
1231 ;; In this case, the following attributes are mandatory:
1232 ;; -- model (i.e. list of parameter=value strings)
1235 ;; In this case, the function creates and formats the correct spice model line(s).
1236 ;; 2. A model held in a file whose name is held in the attribute "file"
1237 ;; In this case, the following attribute are mandatory:
1238 ;; -- file (i.e. list of parameter=value strings)
1239 ;; In this case, the function just opens the file and dumps the contents
1240 ;; into the netlist.
1241 ;;----------------------------------------------------------
1242 (define spice-sdb:write-model
1244 ;; Collect variables used in creating spice code
1245 (let ((model-name (gnetlist:get-package-attribute package "model-name"))
1246 (model-file (gnetlist:get-package-attribute package "file"))
1247 (model (gnetlist:get-package-attribute package "model"))
1248 (type (gnetlist:get-package-attribute package "type"))
1249 ) ;; end of local assignments
1251 (debug-spew (string-append "Found .MODEL box. Refdes = " package "\n"))
1253 ;; Now, depending upon what combination of model, model-file, and model-name
1254 ;; exist (as described above) write out lines into spice netlist.
1256 ;; one model and model name exist
1257 ( (not (or (string=? model "unknown") (string=? model-name "unknown")))
1258 (debug-spew (string-append "found model and model-name for " package "\n"))
1259 (display (string-append ".MODEL " model-name " " type " (" model ")\n")) )
1261 ;; model file exists
1262 ( (not (or (string=? model-file "unknown") ))
1263 (debug-spew (string-append "found model-file for " package "\n"))
1264 ;; (spice-sdb:insert-text-file model-file) ;; don't write it out -- it's handled after the second pass.
1269 ) ;; close of lambda
1270 ) ;; close of define
1273 ;;-------------------------------------------------------------------
1274 ;; This writes out the default component (i.e. the "device" attribute
1275 ;; was not recognized). This function does the following:
1277 ;; 1. Gets the refdes (package).
1278 ;; 2. Checks the refdes against a short list of possible values.
1279 ;; Depending upon the refdes, it does the following thing:
1280 ;; A? -- Invokes write-ic. This provides the opportunity for a code model
1281 ;; which may include a .model line.
1282 ;; D? -- Invokes write-diode
1283 ;; Q? -- Invokes write-transistor-diode. (The "type" attribute is <unknown>
1284 ;; in this case so that the spice simulator will barf if the user
1285 ;; has been careless.)
1287 ;; U? -- Invokes write-ic. This provides the opportunity for a component
1288 ;; model to be instantiated.
1289 ;; X? -- Invokes write-ic. This provides the opportunity for a component
1290 ;; subcircuit to be instantiated.
1291 ;; V? -- Invokes write-independent-voltage-source
1292 ;; I? -- Invokes write-independent-current-source
1293 ;; Otherwise, it just outputs the refdes, the attached nets, and the
1294 ;; value of the "value" attribute.
1296 ;;-------------------------------------------------------------------
1297 (define spice-sdb:write-default-component
1298 (lambda (package file-info-list)
1300 (let ((first-char (string (string-ref package 0)) )) ;; extract first char of refdes.
1302 ((string=? first-char "A") (spice-sdb:write-ic package file-info-list))
1303 ((string=? first-char "D") (spice-sdb:write-diode package))
1304 ((string=? first-char "Q") (spice-sdb:write-transistor-diode package #f "<unknown>" (list)))
1305 ((string=? first-char "M") (spice-sdb:write-transistor-diode package #f "<unknown>" (list)))
1306 ((string=? first-char "U") (spice-sdb:write-ic package file-info-list))
1307 ((string=? first-char "V") (spice-sdb:write-independent-voltage-source package))
1308 ((string=? first-char "I") (spice-sdb:write-independent-current-source package))
1309 ((string=? first-char "X") (spice-sdb:write-ic package file-info-list))
1311 (message (string-append "Found unknown component. Refdes = " package "\n"))
1312 (spice-sdb:write-component-no-value package)
1313 ;; write component value, if components have a label "value=#"
1314 ;; what if a component has no value label, currently unknown is written
1315 (display (spice:component-value package))
1324 ;;**********************************************************************************
1325 ;;*************** High-level functions for program control ***********************
1326 ;;**********************************************************************************
1328 ;;----------------------------------------------------------------------
1329 ;; write-netlist is passed a list of refdesses (ls). It uses
1330 ;; each refdes to get the corresponding
1331 ;; "device" attribute. Depending upon the device, it then invokes one or another of the
1332 ;; spice line output fcns to output a line of the spice netlist.
1333 ;; I have enlarged the number of devices it recognizes -- SDB.
1334 ;; write the refdes, to the pin# connected net and component
1335 ;; value and optional extra attributes
1336 ;; check if the component is a special spice component.
1337 ;;----------------------------------------------------------------------
1338 (define spice-sdb:write-netlist
1339 (lambda (file-info-list ls)
1340 (if (not (null? ls))
1341 (let* ((package (car ls)) ;; assign package
1342 (device (get-device package)) ;; assign device.
1343 ) ;; end of let* assignments
1345 ;; Super debug stuff -- outputs line describing device being processed.
1346 (debug-spew (string-append "--- checking package = " package "\n"))
1347 (debug-spew (string-append " device = " device "\n"))
1348 ;; done with debug stuff
1351 ( (string=? device "none")) ;; do nothing for graphical symbols.
1352 ( (string=? device "spice-subcircuit-LL")) ;; do nothing for subcircuit declaration.
1353 ( (string=? device "spice-IO")) ;; do nothing for SPICE IO pins.
1354 ( (string=? device "spice-title")) ;; do nothing for spice title blocks
1355 ( (string=? device "SPICE-ccvs")
1356 (spice:write-ccvs package))
1357 ( (string=? device "SPICE-cccs")
1358 (spice:write-cccs package))
1359 ( (string=? device "SPICE-vcvs")
1360 (spice:write-vcvs package))
1361 ( (string=? device "SPICE-vccs")
1362 (spice:write-vccs package))
1363 ( (string=? device "SPICE-nullor")
1364 (spice:write-nullor package))
1365 ( (string=? device "DIODE")
1366 (spice-sdb:write-diode package))
1367 ( (string=? device "PMOS_TRANSISTOR")
1368 (spice-sdb:write-pmos-transistor package))
1369 ( (string=? device "NMOS_TRANSISTOR")
1370 (spice-sdb:write-nmos-transistor package))
1371 ( (string=? device "PNP_TRANSISTOR")
1372 (spice-sdb:write-pnp-bipolar-transistor package))
1373 ( (string=? device "SPICE-PNP")
1374 (spice-sdb:write-pnp-bipolar-transistor package))
1375 ( (string=? device "NPN_TRANSISTOR")
1376 (spice-sdb:write-npn-bipolar-transistor package))
1377 ( (string=? device "SPICE-NPN")
1378 (spice-sdb:write-npn-bipolar-transistor package))
1379 ( (string=? device "PFET_TRANSISTOR")
1380 (spice-sdb:write-pfet-transistor package))
1381 ( (string=? device "NFET_TRANSISTOR")
1382 (spice-sdb:write-nfet-transistor package))
1383 ( (string=? device "MESFET_TRANSISTOR")
1384 (spice-sdb:write-mesfet-transistor package))
1385 ( (string=? device "SPICE-VC-switch")
1386 (spice-sdb:write-vc-switch package))
1387 ( (string=? device "RESISTOR")
1388 (spice-sdb:write-resistor package))
1389 ( (string=? device "CAPACITOR")
1390 (spice-sdb:write-capacitor package))
1391 ( (string=? device "POLARIZED_CAPACITOR")
1392 (spice-sdb:write-capacitor package)) ;; change someday
1393 ( (string=? device "INDUCTOR")
1394 (spice-sdb:write-inductor package))
1395 ( (string=? device "COIL") ;; Added to enable netlisting of coil-*.sym
1396 (spice-sdb:write-inductor package))
1397 ( (string=? device "VOLTAGE_SOURCE")
1398 (spice-sdb:write-independent-voltage-source package)) ;; change someday
1399 ( (string=? device "CURRENT_SOURCE")
1400 (spice-sdb:write-independent-current-source package)) ;; change someday
1401 ( (string=? device "JOSEPHSON_JUNCTION")
1402 (spice-sdb:write-josephson-junction package))
1403 ( (string=? device "K")
1404 (spice-sdb:write-coupling-coefficient package))
1405 ( (string=? device "model")
1406 (spice-sdb:write-model package))
1407 ( (string=? device "options")
1408 (spice-sdb:write-options package))
1409 ( (string=? device "directive")
1410 (spice-sdb:write-directive package))
1411 ( (string=? device "include")
1412 (spice-sdb:write-include package))
1413 ( (string=? device "TESTPOINT")
1414 (spice-sdb:write-probe package))
1415 ( (string=? device "SUBCKT_PMOS")
1416 (spice-sdb:write-subckt-pmos-transistor package))
1417 ( (string=? device "SUBCKT_NMOS")
1418 (spice-sdb:write-subckt-nmos-transistor package))
1420 (spice-sdb:write-default-component package file-info-list))
1422 (spice-sdb:write-netlist file-info-list (cdr ls))
1426 ;;----------------------------------------------------------------------
1427 ;; create-file-info-list: This takes as argument the list of packages (refdesses).
1428 ;; It runs through the package list, and for each gets the attributes. If there is a
1429 ;; "FILE" attribute, it gets the file info & uses it to build the
1430 ;; file-info-list. When done, it returns the file-info-list.
1431 ;;----------------------------------------------------------------------
1432 (define spice-sdb:create-file-info-list
1433 (lambda (package-list file-info-list)
1434 (if (null? package-list)
1435 file-info-list ;; end of packages processed. Return file-info-list
1436 (let* ((package (car package-list)) ;; otherwise get next package (i.e. refdes)
1440 (model-file (string))
1441 ) ;; end of let* assignments
1443 (set! device (get-device package) )
1444 (set! model (gnetlist:get-package-attribute package "model-name") )
1445 (set! value (gnetlist:get-package-attribute package "value") )
1446 (set! model-file (gnetlist:get-package-attribute package "file") )
1448 ;; Now run a series of checks to see if we should stick this file into the file-info-list
1449 ;; Check to see if "file" attribute is non-empty
1450 (if (not (string-ci=? model-file "unknown"))
1453 (string-append "found file attribute for " package ". File name = " model-file "\n")) ;; ******* Debug stuff
1455 ;; Now check to see if file is in file-info-list
1456 (if (not (spice-sdb:in-file-info-list? model-file file-info-list))
1458 ;; File is new. Open file, find out what type it is, and push info into file-info-list
1459 (let ((file-type (spice-sdb:get-file-type model-file))
1461 (debug-spew (string-append "File is new. New file type is " file-type " \n")) ;; DEBUG
1463 ;; Check to see if file-type is known.
1464 (if (not (string=? file-type "OTHER"))
1465 ;; file-type is OK. Return file-info-list with new triplet attached.
1467 (debug-spew (string-append "Inserting " model-file " into list of known model files.\n"))
1468 (set! file-info-list (append (list (list model model-file file-type)) file-info-list) )
1471 ;; Otherwise, file type is not a model type. Don't stick it in list. Print debug spew if desired.
1472 (debug-spew "File type is OTHER, and therefore will not be entered in known model file list.\n")
1473 ) ;; end if (not (string=?
1475 ) ;; end let ((file-type . . .
1477 ;; File is already in list. Print debug spew if desired.
1478 (debug-spew "File has already been seen and entered into known model file list.\n")
1479 ) ;; end if (spice-sdb:in-file-info-list . . .
1481 ) ;; end begin . . .
1482 ) ;; end if (not( string-ci=? model-file
1484 ;; having done checking and processing of this package, iterate to the next one.
1485 (spice-sdb:create-file-info-list (cdr package-list) file-info-list)
1488 ) ;; end if (null? package-list . . .
1493 ;; in-file-info-list? -- helper function. Returns #t if file is already in file-info-list, otherwise #f
1494 ;; assumes file-info-list of form: ((model1 file1 file-type1) (model2 file2 file-type2) . . . .)
1495 (define spice-sdb:in-file-info-list?
1496 (lambda (model-file file-info-list)
1497 (if (null? file-info-list)
1499 #f ;; return #f if file-info-list itself is empty.
1501 (let ((list-element (car file-info-list)) ) ;; otherwise process list-element
1502 (if (null? list-element)
1503 #f ;; item not found. Return #f. Note that we should never get here . . .
1504 (let ((list-file-name (cadr list-element)) )
1505 (if (string=? list-file-name model-file)
1506 #t ;; item found. Return #t
1507 (spice-sdb:in-file-info-list? model-file (cdr file-info-list)) ;; iterate . . .
1508 ) ;; end if (string=?
1509 ) ;; end of let . . .
1510 ) ;; end if (null? list-element . . .
1511 ) ;; end let* ((list-element . . .
1512 ) ;; end if (null? file-info-list . .
1513 )) ;; end define spice-sdb:in-file-info-list?
1516 ;;--------------------------------------------------------------
1517 ;; Write out spice netlist header
1518 ;;--------------------------------------------------------------
1519 (define (spice-sdb:write-top-header)
1520 (display "*********************************************************\n")
1521 (display "* Spice file generated by gnetlist *\n")
1522 (display "* spice-sdb version 4.28.2007 by SDB -- *\n")
1523 (display "* provides advanced spice netlisting capability. *\n")
1524 (display "* Documentation at http://www.brorson.com/gEDA/SPICE/ *\n")
1525 (display "*********************************************************\n")
1529 ;;--------------------------------------------------------------
1530 ;; Write out .SUBCKT netlist header
1531 ;;--------------------------------------------------------------
1532 (define (spice-sdb:write-subcircuit-header)
1533 (display "*******************************\n")
1534 (display "* Begin .SUBCKT model *\n")
1535 (display "* spice-sdb ver 4.28.2007 *\n")
1536 (display "*******************************\n")
1540 ;;---------------------------------------------------------------
1541 ;; Write the .END line
1542 ;;---------------------------------------------------------------
1543 (define (spice-sdb:write-bottom-footer salutation)
1544 (display salutation)
1548 ;;---------------------------------------------------------------
1549 ;; Spice netlist generation
1550 ;; This is the entry point.
1551 ;; Hacked on 3.31.2003 to enable writing out .SUBCKT models -- SDB.
1552 ;; Hacked again in Sept 2003 to enable more intelligent embedding of external
1553 ;; SPICE files into netlist -- SDB.
1554 ;; The algorithm is as follows:
1555 ;; 1. Figure out if there is a .SUBCKT block on the schematic,
1556 ;; or if it is just a normal schematic.
1558 ;; -- Write out subcircuit header (a comment identifying the netlister).
1559 ;; -- find all spice-IO pins. Get a list of the packages.
1560 ;; -- put them in order (ordered by package refdes)
1561 ;; -- get the list of nets attached to the spice-IO pins.
1562 ;; -- write out .SUBCKT line
1563 ;; If a normal schematic:
1564 ;; -- Write out top header (a comment identifying the netlister).
1565 ;; 2. Loop through all components, looking for components with a "file"
1566 ;; attribute. Every time a "file" attribute is found do this:
1567 ;; -- Open the file and find out what kind of file it is (.SUBCKT or .MODEL).
1568 ;; -- Determine if the file has previously been processed. If not: stick the
1569 ;; following info into the file-info list: (model-name file-name file-type).
1570 ;; Otherwise just continue.
1571 ;; 3. Loop through all components again, and write out a SPICE card for each.
1572 ;; 4. Afterwards, for each item in the file-info list, open the file, and
1573 ; write its contents into the netlist.
1574 ;; 5. If the schematic-type is .SUBCKT: write out .ENDS, Otherwise: write out .END
1575 ;; 6. Close up the SPICE netlist file and return.
1576 ;;---------------------------------------------------------------
1578 (lambda (output-filename)
1579 ;; Redefine write-net-names-on-component
1580 (set! spice:write-net-names-on-component spice-sdb:write-net-names-on-component)
1583 ;; First find out if this is a .SUBCKT lower level,
1584 ;; or if it is a regular schematic.
1586 (set-current-output-port (gnetlist:output-port output-filename))
1587 (let* ((schematic-type (spice-sdb:get-schematic-type packages))
1588 (model-name (spice-sdb:get-subcircuit-modelname schematic-type))
1589 (file-info-list (list))
1591 (message "Using SPICE backend by SDB -- Version of 4.28.2007\n")
1592 (message (string-append "schematic-type = " schematic-type "\n"))
1594 (if (not (string=? schematic-type "normal schematic"))
1595 ;; we have found a .SUBCKT type schematic.
1596 (let* ((io-pin-packages (spice-sdb:get-spice-IO-pins packages (list) ))
1597 (io-pin-packages-ordered (spice-sdb:sort-spice-IO-pins io-pin-packages))
1598 (io-nets-list (spice-sdb:get-IO-nets io-pin-packages-ordered (list) ))
1600 (debug-spew "found .SUBCKT type schematic")
1601 ;; now write out .SUBCKT header and .SUBCKT line
1602 (spice-sdb:write-subcircuit-header)
1603 (let ((io-nets-string (list-2-string io-nets-list)) )
1604 (display (string-append schematic-type " " (list-2-string io-nets-list) "\n"))
1608 ;; Otherwise it's a regular schematic. Write out command line followed by comments in file header.
1610 (debug-spew "found normal type schematic")
1611 (let ((title (find-device packages "spice-title"))) ;; If the schematic contains a spice-title device
1612 (when (string? title)
1613 (set! title (get-value title)) ;; and the value attribute is a string
1614 (when (string? title)
1615 (display title) ;;use that as the title of the spice netlist
1620 (display (string-append "* " (gnetlist:get-command-line) "\n"))
1621 (spice-sdb:write-top-header)
1624 ) ;; end of if (not (string=? . . . .
1628 ;; Now loop through all devices and process all "FILE" attributes. Create
1630 ;; Thanks to Carlos Nieves Onega for his e-mail to
1631 ;; geda-dev which is the genesis of this section.
1633 (debug-spew "\nMake first pass through design and create list of all model files referenced.\n")
1634 (set! file-info-list (spice-sdb:create-file-info-list packages file-info-list))
1635 (debug-spew "Done creating file-info-list.\n\n")
1639 ;; Moved this loop before the next one to get numparam to work with ngspice,
1640 ;; because numparam will at the subckt definition come before the main netlist.
1641 ;; Change suggested by Dominique Michel; implemented in code on 6.12.2005.
1643 ;; Next loop through all items in file-info-list in the SPICE netlist.
1644 ;; For each model-name, open up the corresponding file, and call handle-spice-file
1645 ;; to stick the corresponding stuff into the output SPICE file.
1647 (debug-spew "Now process the items in model file list -- stick appropriate references to models in output SPICE file.\n")
1648 (spice-sdb:loop-through-files file-info-list)
1649 (debug-spew "Done processing items in model file list.\n")
1653 ;; Now write out netlist as before. But don't write file contents out.
1654 ;; **** Modified by kh to sort list of packages so Spice directives, etc. (A?) are output last,
1655 ;; **** and in increasing order.
1657 (debug-spew "Make second pass through design and write out a SPICE card for each component found.\n")
1658 (display "*============== Begin SPICE netlist of main design ============\n")
1659 (if (spice-sdb:sort-refdes? (gnetlist:get-calling-flags))
1660 (spice-sdb:write-netlist file-info-list (sort packages spice-sdb:packsort)) ;; sort on refdes
1661 (spice-sdb:write-netlist file-info-list packages) ;; don't sort.
1663 (debug-spew "Done writing SPICE cards . . .\n\n")
1667 ;; Now write out .END(S) of netlist, depending upon whether this schematic is a
1668 ;; "normal schematic" or a .SUBCKT.
1670 (if (not (string=? schematic-type "normal schematic"))
1672 (spice-sdb:write-bottom-footer (string-append ".ends " model-name))
1673 (display "*******************************\n")
1675 (if (not (calling-flag? "no_end_card" (gnetlist:get-calling-flags)))
1676 (spice-sdb:write-bottom-footer ".end"))
1680 (debug-spew "\nOutput file is written. We are done.\n")
1683 ;; Finally, close up and go home.
1685 (close-output-port (current-output-port))
1690 ;; Custom get-uref function to append ".${SLOT}" where a component
1691 ;; has a "slot=${SLOT}" attribute attached.
1693 ;; NOTE: Original test for appending the ".<SLOT>" was this:
1694 ;; (let ((numslots (gnetlist:get-package-attribute package "numslots"))
1695 ;; (slot-count (length (gnetlist:get-unique-slots package)))
1696 ;; (if (or (string=? numslots "unknown") (string=? numslots "0"))
1700 (let ((real_uref (gnetlist:get-uref object)))
1701 (if (null? (get-attrib-value-by-attrib-name object "slot"))
1703 (string-append real_uref "."
1704 (car (get-attrib-value-by-attrib-name object "slot")))