gnetlist: spice-sdb MOS subcircuits
[geda-gaf/peter-b.git] / gnetlist / scheme / gnet-spice-sdb.scm
blobb355dd6787e699b5f124b785ee4ed0851063f1f4
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., 675 Mass Ave, Cambridge, MA 02139, USA.
20 ;; --------------------------------------------------------------------------
22 ;; SPICE netlist backend written by S. Gieltjes starts here
24 ;; further modified by W. Kazubski to use scaling parameters for devices 
25 ;; other than MOSFETS
27 ;;----------------------------------------------------------------------
29 ;; Started with gnet-spice1.scm by W. Kazubski.  Radically 
30 ;; hacked by SDB to support advanced spice netlist generation.
31 ;; Project started 3.5.2003 -- SDB.    
33 ;; Details and documentation at http://www.brorson.com/gEDA/SPICE/
35 ;;  Change log:
36 ;;  3.5.2003 -- Started hacking.  SDB.
37 ;;  3.17.2003 -- 2nd version.  Hacked to allow for .SUBCKT files to model ics.
38 ;;               Changed write-ic.  Added get-file-type.  Added 
39 ;;               write-subcircuit.  SDB.
40 ;;  3.31.2003 -- 3rd version.  Hacked to enable creating .SUBCKT schematics for
41 ;;               hierarchical circuit modeling.
42 ;;  8.29.2003 -- 4th version.  Include patches from Ken Healy to sort netlist, 
43 ;;               code by SDB to use gnetlist command line args in Scheme fcns,
44 ;;               as well as from Theo Deckers to fix strange problem with '.SUBCKT 
45 ;;               quoting.
46 ;;  9.9.2003  -- 5th version.  Rearranged code for more organization (I was beginning
47 ;;               to get lost. . . .).  Incorporated changes to handle external SPICE
48 ;;               files more intelligently.  Changed spew to be configurable by setting
49 ;;               -v from the command line.  Placed new fcn debug-spew into gnetlist.scm.
50 ;;               Added -I command line flag.
51 ;;  10.14.2003 -- Bugfixes: Added empty-string? and hacked get-file-type to handle 
52 ;;                case where a model file has an empty line before .SUBCKT or .MODEL.  
53 ;;                Also modified write-net-names-on-component to gracefully handle
54 ;;                case where not every pin has a pinseq attribute.  Now only outputs
55 ;;                pins with valid pinseq attribute.
56 ;;  12.25.2003 -- Bugfix:  Unswizzled emission of pins from user-defined .subckts.
57 ;;                (Now correctly uses pinseq to define emission order of pins.)  Also
58 ;;                added ability to emit attributes for semiconductors (e.g. area, off,
59 ;;                ic, etc.)  Added in response to user requests.
60 ;;  12.29.2003 -- Two small enhancements requested by Peter Kaiser.
61 ;;  12.29.2003.a -- Minor bugfix.
62 ;;  12.29.2003.b -- Second minor bugfix.
63 ;;  12.29.2003.c -- Change res & cap to incorporate modelname & "area=" attrib.
64 ;;  3.24.2004 -- Bugfixes made to JFET stuff during Feb.  Change released now.
65 ;;  8.22.2004 -- Added command line as first line of file.
66 ;;  8.29.2004 -- Changed sense source naming in controlled sources because the old convention
67 ;;               was confusing ngspice.
68 ;;  10.9.2004 -- Added patches for voltage controlled switches from Peter Kaiser.
69 ;;  3.16.2005 -- Fixed CCCS bug (typo in Vsense) noticed by David Logan
70 ;;  5.16.2005 -- Modified behavior of .INCLUDE directive.  Now by default it just 
71 ;;               spits out the string instead of putting the contents of the file
72 ;;               into the SPICE netlist.  You can force insertion of the file using
73 ;;               the -e flag.
74 ;;  6.12.2005 -- Changed order of writing out netlist and .model/.subckt cards to 
75 ;;               facilitate use of numparam with ngspice.  Change supplied by 
76 ;;               Dominique Michel.
77 ;;  9.11.2005 -- Incorporated patch from Paul Bunyk to enable netlisting of
78 ;;               Josephson junctions and "K" mutual inductances.  Also enabled 
79 ;;               netlisting of "COIL" devices as inductors.
80 ;;  12.27.2005 -- Fix bug discovered by John Doty: spice-IO pins with refdes greater
81 ;;                than P9 were sorted incorrectly (as strings).  Now they are sorted
82 ;;                as numbers.
83 ;;  3.10.2006 -- Added "m" attribute to PMOS and NMOS per request of Peter Kaiser.
84 ;;  4.11.2006 --  Changed the .END and .ENDS cards to lowercase. 
85 ;;                This fixes bug 1442912. Carlos Nieves Onega.
86 ;;  2.10.2007 -- Various bugfixes.  Also incorporated slotted part
87 ;;               netlist patch from Jeff Mallatt.  SDB.
88 ;;  4.28.2007 -- Fixed slotted part stuff so that it uses pinseq to emit pins.  SDB
89 ;;  1.9.2008 -- Fix slotted part handling to work without a modified pinseq.  pcjc2
90 ;;  1.3.2011 -- Combine write-ic and write-subcircuit with a fix to the unbound
91 ;;              type variable.  Fully document a check for the special "?" value
92 ;;              explaining why it fails silently.  Clean up
93 ;;              write-net-names-on-component to make it a bit more flexible.
94 ;;              Combine write-probe-item and write-net-names-on-component.  Add
95 ;;              a range utility function.  CC
97 ;;**********************************************************************************
99 ;;  Organization of gnet-spice-sdb.scm file:
100 ;;  --  Functions for program housekeeping, handling of calling flags, file manipulation.
101 ;;  --  Functions for handling nets & devices and creating SPICE cards.
102 ;;  --  High-level functions which control program flow.  Note that the program entry
103 ;;      point lives at the very bottom of this file.
105 ;;  Unfortunately, no organization is present beneath this top level. . . .
107 ;;**********************************************************************************
110 ;;**********************************************************************************
111 ;;************  Program housekeeping, handling calling flags, etc.  ****************
112 ;;**********************************************************************************
114 ;; The following is needed to make guile 1.8.x happy.
115 (use-modules (ice-9 rdelim) (srfi srfi-1))
117 ;;--------------------------------------------------------------------------------
118 ;; spice-sdb:loop-through-files -- loops through the model-file list, and for each file
119 ;;  name discovered in the list, it processes the file by invoking handle-spice-file.
120 ;;--------------------------------------------------------------------------------
121 (define spice-sdb:loop-through-files
122   (lambda (file-info-list port)
123     (if (not (null? file-info-list))
124         (let*  ((list-element (car file-info-list))
125                 (model-name (car list-element))
126                 (file-name (cadr list-element))
127                 (file-type (caddr list-element))
128                )
129           (spice-sdb:handle-spice-file file-name port)
130           (spice-sdb:loop-through-files (cdr file-info-list) port)
131         )  ;; end of let*
135 ;;--------------------------------------------------------------------------------
136 ;; spice-sdb:get-file-info-list-item  -- loops through the model-file list looking
137 ;;  for triplet corresponding to model-name.  If found, it returns the corresponding
138 ;;  list.  If not found, returns #f
139 ;;--------------------------------------------------------------------------------
140 (define spice-sdb:get-file-info-list-item
141   (lambda (model-name file-info-list)
142     (if (null? file-info-list)
143         '()                                           ;; return #f upon empty list.
144                                                       ;; #f replaced with '() by peter
145         (let*  ((list-element (car file-info-list))   ;; else process list-item
146                 (list-elt-model-name (car list-element))
147                 (list-elt-file-name (cadr list-element))
148                 (list-elt-file-type (caddr list-element))
149                )
150           (if (string=? list-elt-model-name model-name)
151               list-element                                                        ;; found model-name.  Reutrn list-element.
152               (spice-sdb:get-file-info-list-item model-name (cdr file-info-list)) ;; otherwise, recurse.
153           )
154         )  ;; end of let*
158 ;;--------------------------------------------------------------------------
159 ;; handle-spice-file:  This wraps insert-text-file.
160 ;; Calling form: (handle-spice-file file-name)
161 ;; It looks to see if the -I flag was set at the command line.  If so,
162 ;; it just writes a .INCLUDE card with the file name.  If not,  it calls
163 ;; insert-text-file to stick the file's contents into the SPICE netlist.
164 ;;--------------------------------------------------------------------------
165 (define spice-sdb:handle-spice-file
166   (lambda (file-name port)
167     (debug-spew (string-append "Handling spice model file " file-name "\n"))
168     (if (calling-flag? "include_mode" (gnetlist:get-calling-flags))
169         (display (string-append ".INCLUDE " file-name "\n") port)       ;; -I found: just print out .INCLUDE card
170         (spice-sdb:insert-text-file file-name port)                     ;; -I not found: invoke insert-text-file
171     )  ;; end of if (calling-flag
175 ;;--------------------------------------------------------------------------
176 ;; Given a filename, open the file, get the contents, and dump them
177 ;; into the spice file.
178 ;; Calling form is "(insert-text-file input-file output-file)"
179 ;; The function opens input-file, but assumes that output-file is
180 ;; already open. 
182 ;; This function is usually used to include spice models contained in 
183 ;; files into the netlist.  Note that it doesn't
184 ;; check the correctness of the spice code in the file -- you're on your own!
185 ;;---------------------------------------------------------------------------
186 (define spice-sdb:insert-text-file
187   (lambda (model-filename port)
188     (let ((model-file (open-input-file model-filename)) )
189       (display (string-append "*vvvvvvvv  Included SPICE model from " model-filename " vvvvvvvv\n") port)
190       (let while ((model-line (read-line model-file)))
191           (if (not (eof-object? model-line))
192                    (begin
193                      (display (string-append model-line "\n") port)
194                      ;; (display (string-append "-- model-line = " model-line "\n")) ;; super debug statement
195                      (while (read-line model-file))
196                    )  ;; end of inner begin
197           ) ;; end of if
198         )  ;; end of inner let
199         (close-port model-file)
200         (display (string-append "*^^^^^^^^  End of included SPICE model from " model-filename " ^^^^^^^^\n") port)
201         (display (string-append "*\n") port)
202      ) ;; end of outer let
203   )
207 ;;----------------------------------------------------------
208 ;; Figure out if this schematic is a .SUBCKT lower level.
209 ;; This is determined if there is a spice-subcircuit-LL  
210 ;; device instantiated somewhere on the schematic.
211 ;; If it is a .SUBCKT, return ".SUBCKT model-name"
212 ;;----------------------------------------------------------
213 (define spice-sdb:get-schematic-type
214   (lambda (ls)     
215      (if (not (null? ls))
216       (let* ((package (car ls))             ;; assign package
217              (device (get-device package))  ;; assign device.    
218             )                               ;; end of let* assignments
219         (begin 
220           ;; (display (string-append "in get-schematic-type, device = " device "\n"))
221           (if (string=? device "spice-subcircuit-LL")  ;; look for subcircuit label
222               (string-append ".SUBCKT " (gnetlist:get-package-attribute package "model-name"))
223               (spice-sdb:get-schematic-type (cdr ls))  ;; otherwise just iterate to next package.
224           )
225         )
226       )    ; end of let*
227       "normal schematic"   ; return "normal schematic" if no spice-subcircuit-LL is found
228     )    ; end of if 
232 ;;----------------------------------------------------------
233 ;; Extract the modelname from the .SUBCKT modelname line.
234 ;; Just grab the chars from char 8 to the end of the string.
235 ;;---------------------------------------------------------
236 (define spice-sdb:get-subcircuit-modelname
237   (lambda (schematic-type)
238     (substring schematic-type 8 (string-length schematic-type))
239   )
243 ;;-----------------------------------------------------------
244 ;;  This iterates through the schematic and compiles a list of
245 ;;  all spice-IO pins found.  This is used when writing out
246 ;;  a .SUBCKT lower level netlist.
247 ;;-----------------------------------------------------------
248 (define spice-sdb:get-spice-IO-pins
249   (lambda (ls spice-io-package-list)
250     (if (null? ls)
252         spice-io-package-list        ;; end iteration & return list if ls is empty.
254         (let* ((package (car ls))    ;; otherwise process package. . .     
255                (device (get-device package))  
256               )
257            (if (string=? device "spice-IO")  ;; look for subcircuit label
259                ;; we have found a spice-IO pin.
260                (spice-sdb:get-spice-IO-pins (cdr ls) (cons package spice-io-package-list))
262                ;; no spice-IO pin found.  Iterate . . . .
263                (spice-sdb:get-spice-IO-pins (cdr ls) spice-io-package-list)
265            ) ;; end of if string=?
267         )  ;; end of let*
268    ) ;; end if null
273 ;;----------------------------------------------------------------
274 ;;  This takes the list of io-pin-packages and sorts it in order of 
275 ;;  refdes.
276 ;;  Repaired on 12.27.2005 to correctly sort pin numbers > 9.
277 ;;----------------------------------------------------------------
278 (define spice-sdb:sort-spice-IO-pins 
279   (lambda (package-list)
280     ;;  Yes, this isn't good Scheme form.  Tough!  Writing this out
281     ;;  in a functional programming form would be totally confusing!
282     ;;  Note that this fcn requires that 
283     ;;  each spice-IO pin have the same, single character prefix (i.e. 'P')
284     (let* ((char-prefixes              (map car (map string->list package-list)))  ;; Pull off first char (prefix)
285            (prefixes                   (map string char-prefixes))                 ;; Make list of strings from prefixes
286            (split-numbers-list         (map cdr (map string->list package-list)))  ;; Pull off refdes numbers as list elements
287            (string-numbers-list        (map list->string split-numbers-list))      ;; Recombine split up (multidigit) number strings
288            (numbers-list               (map string->number string-numbers-list))   ;; Convert strings to numbers for sorting
289            (sorted-numbers-list        (sort numbers-list <))                      ;; Sort refdes numbers as numbers
290            (sorted-string-numbers-list (map number->string sorted-numbers-list)) ) ;; Create sorted list of refdes strings.
292       ;; (debug-spew "Packages found = \n")
293       ;; (debug-spew package-list)
294       ;; (debug-spew "\nPrefixes found = \n")
295       ;; (debug-spew prefixes)
296       ;; (debug-spew "\nNumbers found -- split-numbers-list\n")
297       ;; (debug-spew split-numbers-list)
298       ;; (debug-spew "\nNumbers found -- numbers-list\n")
299       ;; (debug-spew numbers-list)
300       ;; (debug-spew "\nSorted-numbers-list\n")
301       ;; (debug-spew sorted-numbers-list)
302       ;; (debug-spew "\nSorted-string-numbers-list\n")
303       ;; (debug-spew sorted-string-numbers-list)
305       (map-in-order string-append  prefixes sorted-string-numbers-list)  ;; Laminate prefixes back onto refdes numbers & return.
307     )
308   )
312 ;;----------------------------------------------------------------
313 ;;  Given a list of spice-IO packages (refdeses), this function returns the list
314 ;;  of nets attached to the IOs.
315 ;;----------------------------------------------------------------
316 (define spice-sdb:get-IO-nets
317   (lambda (package-list net-list)
318     (if (null? package-list)
320         net-list        ;; end iteration & return net-list if ls is empty.
322         (let* ((package (car package-list))                  ;; otherwise process package. . .     
323                (net (car (gnetlist:get-nets package "1")))   ;; get the net attached to pin 1
324               )
325          ;; now iterate
326           (spice-sdb:get-IO-nets (cdr package-list) (cons net net-list))
327         )
328     ) ;; end of if
329   )
333 ;;----------------------------------------------------------
334 ;;  This takes a list and turns it into a string.
335 ;;  The difference between this and list->string is that
336 ;;  this fun can handle lists made up of multi-char strings.
337 ;;----------------------------------------------------------
338 (define list-2-string
339   (lambda (ls)
340     (let while 
341         ((st (string)) 
342          (local-list ls)
343         )
344       (if (null? local-list)
345           st                                                    ;; end iteration & return string if list is empty.
346           (begin                                                ;; otherwise turn next element of list into string. . .     
347             (set! st (string-append (car local-list) " " st))   ;; stuff next element onto st
348             (while st (cdr local-list))                         ;; iterate with remainder of ls
349           )
350       ) ;; end of if
351     )
352   )
356 ;;----------------------------------------------------------
357 ;;  This returns #t if the string is composed only of
358 ;;  whitespace.  It works by turning the string into 
359 ;;  a list, and then checking to see if it is the empty
360 ;;  list.  If so, it returns #t.
361 ;;----------------------------------------------------------
362 (define empty-string?
363   (lambda (string)
364     (null? (string->list string))
365   )
369 ;;----------------------------------------------------------
370 ;;  This returns a list of all the integers from start to
371 ;;  stop. It is similar to perl's range operator '..'
372 ;;----------------------------------------------------------
373 (define (range start stop . step)
374   (if (null? step)
375     (iota (+ (- stop start) 1) start)
376     (begin
377       (set! step (car step))
378       (iota (+ (ceiling (/ (- stop start) step)) 1) start step)
379     )
380   )
384 ;;----------------------------------------------------------
385 ;; Given a filename, open the file, get the first line,
386 ;; and see if it is a .MODEL or .SUBCKT file.  
387 ;; Returns either ".MODEL" or ".SUBCKT" or "OTHER"
388 ;; Calling form is "(spice-sdb:get-file-type input-file)"
389 ;; The function opens input-file, and closes it when it is done.
390 ;;----------------------------------------------------------
391 (define spice-sdb:get-file-type
392   (lambda (model-filename)
393     
394     (let ((model-file (open-input-file model-filename)) )
395       (let while ((file-line (read-line model-file)) )
397         (cond
398          ((eof-object? file-line)         ;;  Arrived at end of line without finding .MODEL or .SUBCKT.  Return "OTHER"
399             "OTHER")
400            
401          ((empty-string? file-line)
402             (while (read-line model-file)) )        ;; Found empty line.  Iterate before doing anything else.
404          ((string=? (string (string-ref file-line 0)) "*")
405             (while (read-line model-file)) )                       ;; Found *comment.  Iterate.
406            
407          ((string=? (string (string-ref file-line 0)) ".")
408           (begin
409             (debug-spew "In get-file-type, first-char = .\n")  ;; DEBUG stuff
410             (cond
412               ((string-ci=? (safe-string-head file-line 7) ".subckt")  ;; found .subckt as first line.
413                ".SUBCKT" )
415               ((string-ci=? (safe-string-head file-line 6) ".model")   ;; found .model as first line.
416                ".MODEL"  )
417              
418               (else "OTHER")   ;; first . spice card is neither .model nor .subckt
420             ) ; inner cond
421           ) ; inner begin
422          )
424          (else
425           (begin
426             ;; (display "In get-file-type, first-char = <other>\n")
427             (while (read-line model-file))
428             )
429           )
431         ) ; outer cond
433        ) ;; end of inner lets
434       ) ;; end of outer let
435   )
436 ) ;; end define
439 ;;-------------------------------------------------------------------
440 ;; write all listed and available attributes in the form of <variable>=<value>
441 ;;-------------------------------------------------------------------
442 (define spice-sdb:write-list-of-attributes
443   (lambda (package attrib-list port)
444     (if (not (null? attrib-list))
445       (begin
446             ; Is it possible to make no differentiation between upper and lower case?
447             ; That relieves you of mixed case forms e.g. As, AS, as..., they are the
448             ; same attributes, spice3f5 is case insensitive.  And other spice versions?
449         (if (not (string=? (gnetlist:get-package-attribute package (car attrib-list)) "unknown"))
450           (display (string-append  " " (car attrib-list) "="
451                                (gnetlist:get-package-attribute package (car attrib-list))) port))
452         (spice-sdb:write-list-of-attributes package (cdr attrib-list) port)))))
455 ;;---------------------------------------------------------------
456 ;;  write prefix if first char of refdes is improper,
457 ;;  eg. if MOSFET is named T1 then becomes MT1 in SPICE
458 ;;---------------------------------------------------------------
459 (define spice-sdb:write-prefix
460     (lambda (package prefix port)
461       (let ((different-prefix (not (string=? (substring package 0 1) prefix)) )
462             (nomunge (calling-flag? "nomunge_mode" (gnetlist:get-calling-flags)) )
463            )
464         (debug-spew (string-append "Checking prefix.  Package prefix =" (substring package 0 1) "\n"))
465         (debug-spew (string-append "                  correct prefix =" prefix "\n"))
466         (debug-spew "   nomunge mode = ")
467         (debug-spew nomunge)
468         (debug-spew (string-append "\n  different-prefix="))
469         (debug-spew different-prefix)
470         (debug-spew "\n")
471         (if (and different-prefix (not nomunge))
472             (display prefix port) )
473       )
474     )
478 ;;---------------------------------------------------------------
479 ;; spice-sdb:packsort
480 ;;   Sort procedure to order refdes's alphabetically but
481 ;;   keep A? packages at the end of list so SPICE simulation
482 ;;   directives operate correctly.
483 ;;  This fcn written by Ken Healy to enable SPICE netlisting for 
484 ;;  Gnucap, which wants A refdes cards (i.e. SPICE directives) 
485 ;;  to appear last in the SPICE netlist.  Slightly modified
486 ;;  and incorporated into main spice-sdb release by SDB on 9.1.2003.
487 ;;  To output the netlist in sorted order, use the -s switch 
488 ;;  when invoking gnetlist from the command line.  Example:
489 ;;  gnetlist -s -g spice-sdb -o output.spice Schematic.sch
490 ;;  The default behavior (i.e. if -s is not specified) is to do
491 ;;  no sorting.
492 ;;---------------------------------------------------------------
493 (define spice-sdb:packsort
494   (lambda (x y)
495     (let ((xdes (string-ref x 0)) 
496           (ydes (string-ref y 0))
497           (xnum (string-tail x 1)) 
498           (ynum (string-tail y 1)) 
499          )
501       (if (char-ci=? xdes ydes)
502           (if (string-ci<? xnum ynum) #t #f)
503           (if (char-ci=? xdes #\A) #f
504               (if (char-ci=? ydes #\A) #t 
505                   (if (char-ci<? xdes ydes) #t #f)))))))
507 (define (string-tail string start)
508   (substring string start (string-length string)))
511 ;;---------------------------------------------------------------
512 ;; spice-sdb:sort_refdes?
513 ;;   Returns #t or #f depending upon if -s was discovered in 
514 ;;   the calling flags given to gnetlist.   Used in conjunction with 
515 ;;   spice-sdb:packsort.
516 ;;   Calling form: (spice-sdb:sort-refdes? (gnetlist:get-calling-flags))
517 ;;   9.1.2003 -- SDB.
518 ;;---------------------------------------------------------------
519 ;;  Note:  I should re-write this to use calling-flag? . . . .
520 (define spice-sdb:sort-refdes?
521   (lambda (calling-flag-list)
523     (if (null? calling-flag-list)
524           '#f                                             ;; return #f if null list -- sort_mode not found.
525           (let* ((calling-pair (car calling-flag-list))   ;; otherwise look for sort_mode in remainder of list.
526                  (calling-flag (car calling-pair))
527                  (flag-value (cadr calling-pair))  )
529             (if (string=? calling-flag "sort_mode")
530                 flag-value                                               ;; return flag-value if sort_mode found
531                 (spice-sdb:sort-refdes? (cdr calling-flag-list))    ;; otherwise recurse until sort_mode is found
532             )  ;; end if  
533           )  ;; end of let*
534      )  ;; end of if
536             
538 ;;**********************************************************************************
539 ;;***************  Dealing with nets, devices, & SPICE cards.    *******************
540 ;;**********************************************************************************
542 ;;-----------------------------------------------------------
543 ;; gnet-spice replacement of gnetlist:get-nets, a net labeled "GND" becomes 0
544 ;;-----------------------------------------------------------
545 (define spice-sdb:get-net
546   (lambda (refdes pin-name)
547     (let ((net-name (gnetlist:get-nets refdes pin-name)))
548       (cond ((string=? (car net-name) "GND") (cons "0" #t))
549             (else                            (cons (car net-name) #t)))
550     )
551   )
555 ;;---------------------------------------------------------------------
556 ;; write netnames connected to pin-a and pin-b
557 ;;   (currently used by the controlled sources (e, g, f and h)
558 ;;---------------------------------------------------------------------
559 (define spice-sdb:write-two-pin-names
560   (lambda (package pin-a pin-b port)
561     (display (string-append 
562       (car (spice-sdb:get-net package (gnetlist:get-attribute-by-pinseq package pin-a "pinnumber"))) " ") port)
563     (display (string-append 
564       (car (spice-sdb:get-net package (gnetlist:get-attribute-by-pinseq package pin-b "pinnumber"))) " ") port)))
567 ;;----------------------------------------------------------------
568 ;; write a current controlled voltage source and implement the necessary
569 ;;   current measuring voltage source
570 ;;----------------------------------------------------------------
571 (define spice-sdb:write-ccvs
572   (lambda (package port)
573     ( begin
574       (display "* begin ccvs expansion, h<name>\n" port)
575           ;; implement the controlled current source
576           ;; the user should create the refdes label begining with a h
577       (display (string-append package " ") port)
578       (spice-sdb:write-two-pin-names package "1" "2" port)
579       (display (string-append "Vsense_" package  " " (spice-sdb:component-value package) "\n" ) port)
580           ;; implement the current measuring voltage source
581       (display (string-append "Vsense_" package " ") port)
582       (spice-sdb:write-two-pin-names package "3" "4" port)
583       (display "dc 0\n" port)
584           ;; now it is possible to leave the output voltage source unconnected
585           ;; i.e. spice won't complain about unconnected nodes
586       (display (string-append "IOut_" package " ") port)
587       (spice-sdb:write-two-pin-names package "1" "2" port)
588       (display "dc 0\n" port)
589       (display "* end ccvs expansion\n" port))))
592 ;;-----------------------------------------------------------------------
593 ;; write a current controlled current source and implement the necessary
594 ;;   current measuring voltage source
595 ;;-----------------------------------------------------------------------
596 (define spice-sdb:write-cccs
597   (lambda (package port)
598     ( begin
599       (display "* begin cccs expansion, f<name>\n" port)
600           ;; implement the controlled current source
601           ;; the user should create the refdes label begining with a f
602       (display (string-append package " ") port)
603       (spice-sdb:write-two-pin-names package "1" "2" port)
604       (display (string-append "Vsense_" package " " (gnetlist:get-package-attribute package "value") "\n" ) port)
605           ;; implement the current measuring voltage source
606       (display (string-append "Vsense_" package " ") port)
607       (spice-sdb:write-two-pin-names package "3" "4" port)
608       (display "dc 0\n" port)
609       (display "* end cccs expansion\n" port))))
612 ;;-------------------------------------------------------------------------
613 ;; write a voltage controlled current source and implement the necessary
614 ;;   voltage measuring current source
615 ;;-------------------------------------------------------------------------
616 (define spice-sdb:write-vccs
617   (lambda (package port)
618     ( begin
619       (display "* begin vccs expansion, g<name>\n" port)
620           ;; implement the controlled current source
621           ;; the user should create a refdes label beginning with a g
622       (display (string-append package " ") port)
623       (spice-sdb:write-net-names-on-component package port)
624        (display  (string-append (spice-sdb:component-value package) "\n")  port)
625           ;; implement the voltage measuring current source
626           ;; imagine yourself copying the voltage of a voltage source with an internal
627           ;; impedance, spice starts complaining about unconnected nets if this current
628           ;; source is not here.
629       (display (string-append "IMeasure_" package " ") port)
630       (spice-sdb:write-two-pin-names package "3" "4" port)
631       (display "dc 0\n" port)
632       (display "* end vccs expansion\n" port))))
635 ;;------------------------------------------------------------------------
636 ;; write a voltage controlled voltage source and implement the necessary
637 ;;   voltage measuring current source
638 ;;------------------------------------------------------------------------
639 (define spice-sdb:write-vcvs
640   (lambda (package port)
641     ( begin
642       (display "* begin vcvs expansion, e<name>\n" port)
643           ;; implement the controlled voltage source
644           ;; the user should create a refdes label beginning with an e
645       (display (string-append package " ") port)
646       (spice-sdb:write-net-names-on-component package port)
647       (display (string-append (gnetlist:get-package-attribute package "value") "\n" ) port)
648           ;; implement the voltage measuring current source
649           ;; imagine yourself copying the voltage of a voltage source with an internal
650           ;; impedance, spice starts complaining about unconnected nets if this current
651           ;; source is not here.
652       (display (string-append "Isense_" package " ") port)
653       (spice-sdb:write-two-pin-names package "3" "4" port)
654       (display "dc 0\n" port)
655           ;; with an output current source it is possible to leave the output voltage source
656           ;; unconnected i.e. spice won't complain about unconnected nodes
657       (display (string-append "IOut_" package " ") port)
658       (spice-sdb:write-two-pin-names package "1" "2" port)
659       (display "dc 0\n" port)
660       (display "* end vcvs expansion\n" port))))
663 ;;--------------------------------------------------------------------------
664 ;; Create a nullor, make sure it consists of a voltage controlled source
665 ;;--------------------------------------------------------------------------
666 (define spice-sdb:write-nullor
667   (lambda (package port)
668     ( begin
669       (display "* begin nullor expansion, e<name>\n" port)
670           ;; implement the controlled voltage source
671       (display (string-append "E-" package " ") port)
672       (spice-sdb:write-net-names-on-component package port)
673       (display (string-append (gnetlist:get-package-attribute package "value") "\n" ) port)
674           ;; implement the voltage measuring current source
675           ;; imagine yourself copying the voltage of a voltage source with an internal
676           ;; impedance, spice starts complaining about unconnected nets if this current
677           ;; source is not here.
678       (display (string-append "IMeasure_" package " ") port)
679       (spice-sdb:write-two-pin-names package "3" "4" port)
680       (display "dc 0\n" port)
681           ;; with an output current source it is possible to leave the output voltage source
682           ;; unconnected i.e. spice won't complain about unconnected nodes
683       (display (string-append "IOut_" package " ") port)
684       (spice-sdb:write-two-pin-names package "1" "2" port)
685       (display "dc 0\n" port)
686       (display "* end of nullor expansion\n" port))))
689 ;;----------------------------------------------------------------
691 ;; Write-transistor-diode: writes out component followed by 
692 ;; model or model file associated
693 ;; with the component.
694 ;;  This function does the following:
695 ;;   1.  Writes out the correct refdes prefix (if specified and necessary).
696 ;;   2.  Writes out the refdes and nets 
697 ;;   3.  Looks for "model-name" attribute. Writes it out if it exists.
698 ;;   4.  If there is no "model-name" attribute, it writes out the "value"
699 ;;       attribute.  If there is no "value" attribute, it writes out "unknown"
700 ;;       and returns, causing the spice simulator to puke when the netlist 
701 ;;       is run.  This is important 
702 ;;       'cause the spice simulator needs to have some indication of what
703 ;;       model to look for.
704 ;;   5.  Outputs optional attributes attached to device, if any.  Feature 
705 ;;       added by SDB on 12.25.2003.
706 ;;   6.  Outputs a new line
707 ;;   7.  Looks for a the "model" attribute.  If it exists, it it writes out
708 ;;       a .MODEL line like this:  .MODEL model-name type (model)
709 ;;      
710 ;;----------------------------------------------------------------
711 (define spice-sdb:write-transistor-diode
712   (lambda (package prefix type attrib-list port)
714     ;; First do local assignments
715     (let ((model-name (gnetlist:get-package-attribute package "model-name"))
716           (model (gnetlist:get-package-attribute package "model"))
717           (value (gnetlist:get-package-attribute package "value"))
718           (area (gnetlist:get-package-attribute package "area"))
719           (off (gnetlist:get-package-attribute package "off"))
720           (model-file (gnetlist:get-package-attribute package "file"))
721          )   ;; end of local assignments
723    ;; Write out the refdes prefix, if specified and necessary.
724       (if prefix
725         (spice-sdb:write-prefix package prefix port)
726       )
728    ;; Next we write out the refdes and nets.
729       (spice-sdb:write-component-no-value package port)
731    ;; next look for "model-name" attribute.  Write it out if it exists.
732    ;; otherwise look for "device" attribute.
733       (if (not (string=? model-name "unknown"))
734           (display (string-append model-name " " ) port)  ;; display model-name if known
735           (display (string-append value " ") port))       ;; otherwise display device
737   ;; Next write out attribtes if they exist
738   ;; First attribute is area.  It is written as a simple string
739       (if (not (string=? area "unknown"))
740           (display (string-append area " ") port))
742   ;; Next attribute is off.    It is written as a simple string
743       (if (not (string=? off "unknown"))
744           (display (string-append off " ") port))
746   ;; Write out remaining attributes
747       (spice-sdb:write-list-of-attributes package attrib-list port)
749   ;; Now write out newline in preparation for writing out model.
750       (newline port)
752      ;; Now write out any model which is pointed to by the part.
753         (cond
755      ;; one line model and model name exist
756          ( (not (or (string=? model "unknown") (string=? model-name "unknown")))
757            (debug-spew (string-append "found model and model-name for " package "\n"))
758            (display (string-append ".MODEL " model-name " " type " (" model ")\n") port) )
760      ;; one line model and component value exist
761          ( (not (or (string=? model "unknown") (string=? value "unknown")))
762            (debug-spew (string-append "found model and value for " package "\n"))
763            (display (string-append ".MODEL " model-name " " type " (" value ")\n") port) )
765      ;; model file and model name exist
766          ( (not (or (string=? model-file "unknown") (string=? model-name "unknown")))
767            (debug-spew (string-append "found file and model-name for " package "\n"))
768            (debug-spew "I'll deal with the file later . . .\n")
769          )
771      ;; model file and component value exist
772          ( (not (or (string=? model-file "unknown") (string=? value "unknown")))
773            (debug-spew (string-append "found file and value for " package "\n"))
774            (debug-spew "I'll deal with the file later . . .\n")
775          )
777          )  ;; close of cond
778         )
779     )
783 ;;----------------------------------------------------------------
784 ;;  write diode
785 ;;  This writes out a valid diode refdes & then calls
786 ;;  the function which writes the rest of the line.
787 ;;----------------------------------------------------------------
788 (define spice-sdb:write-diode
789   (lambda (package port)
790     (debug-spew (string-append "Found diode.  Refdes = " package "\n"))
791     (let ((attrib-list (list "ic" "temp") ))  
792       (spice-sdb:write-transistor-diode package "D" "D" attrib-list port))
793   )
797 ;;----------------------------------------------------------------
798 ;;  spice-sdb:write-ic
799 ;;  This writes out a valid ic or subcircuit line.
800 ;;  The algorithm is as follows:
801 ;;  1.  Figure out what type of model goes with this part from
802 ;;      file-info-list.  If it isn't listed, look for a MODEL attribute.
803 ;;      If MODEL attribute is attached, write out SPICE card, and then
804 ;;      write out .MODEL on next line.
805 ;;      If no MODEL attribute is attached, just write out what little
806 ;;      we know.  Then return
807 ;;  2.  If the model-name is in the file-info-list, get the associated
808 ;;      file-type.  Compare it against the component's refdes.  If model-type 
809 ;;      is .MODEL or .SUBCKT and refdes doesn't begin with a U or X
810 ;;      respectively, prepend the correct prefix to the refdes.
811 ;; 3.   Print out the rest of the line.     
813 ;;----------------------------------------------------------------
814 (define (spice-sdb:write-ic package file-info-list port)
816     ;; First do local assignments
817     (let ((first-char (string (string-ref package 0)))  ;; extract first char of refdes
818           (model-name (gnetlist:get-package-attribute package "model-name"))
819           (model (gnetlist:get-package-attribute package "model"))
820           (value (gnetlist:get-package-attribute package "value"))
821           (type  (gnetlist:get-package-attribute package "type"))
822           (model-file (gnetlist:get-package-attribute package "file"))
823           (list-item (list))
824          )   ;; end of local assignments
826       (cond
827         ((string=? first-char "U") (debug-spew (string-append "Found ic.  Refdes = " package "\n")))
828         ((string=? first-char "X") (debug-spew (string-append "Found subcircuit.  Refdes = " package "\n")))
829       )
831     ;; First, if model-name is empty, we use value attribute instead.
832     ;; We do this by sticking the contents of "value" into "model-name".
833       (if (string=? model-name "unknown")
834           (set! model-name value))
835       
836     ;; Now get item from file-info-list using model-name as key
837       (set! list-item (spice-sdb:get-file-info-list-item model-name file-info-list))
839     ;; check to see if list-item is null.
840       (if (null? list-item)
842     ;; list-item is null.  Evidently, we didn't discover any files holding this model.  
843     ;; Instead we look for model attribute
844           (if (not (string=? model "unknown"))             
845             (begin                                     ;; model attribute exists -- write out card and model.
846               (debug-spew "Model info not found in model file list, but model attribute exists.  Write out spice card and .model line..\n") 
847               (spice-sdb:write-component-no-value package port)
848               (display (string-append model-name "\n" ) port)
849               (display (string-append ".MODEL " model-name " ") port)
850               (if (not (string=? type "unknown")) (display (string-append type " ") port))  ;; If no type then just skip it.
851               (display (string-append "(" model ")\n") port)
852             )
853             (begin                                     ;; no model attribute either.  Just write out card.
854               (debug-spew "Model info not found in model file list.  No model attribute either.  Just write what we know.\n")
855               (spice-sdb:write-component-no-value package port)
856               (display (string-append model-name "\n" ) port)
857             )
858           )   ;; end if (not (string=? . . . .
860     ;; list-item is not null.  Therefore we process line depending upon contents of list-item
861           (let ((file-type (caddr list-item)) )
862            (cond 
863               ;; ---- file holds a model ----
864               ((string=? file-type ".MODEL") 
865                (begin
866                 (debug-spew (string-append "Found .MODEL with model-file and model-name for " package "\n")) 
867                  (spice-sdb:write-prefix package "U" port)  ;; this prepends an "U" to the refdes if needed, since we have a .model
868                  (spice-sdb:write-component-no-value package port)
869                  (display (string-append model-name "\n" ) port)
870                 (debug-spew "We'll handle the file contents later . . .\n")
871                ))
873               ;; ---- file holds a subcircuit ----
874               ((string=? file-type ".SUBCKT") 
875                (begin
876                  (debug-spew (string-append "Found .SUBCKT with model-file and model-name for " package "\n")) 
877                  (spice-sdb:write-prefix package "X" port)  ;; this prepends an "X" to the refdes if needed, since we have a .subckt
878                  (spice-sdb:write-component-no-value package port)
879                  (display (string-append model-name "\n" ) port)
880                  (debug-spew "We'll handle the file contents later . . .\n")
881                ))
882            )  ;; close of inner cond
883          )   ;; end of inner let
884        )  ;; end of if (null? list-item
886   ) ;; end of outer let
890 ;;-----------------------------------------------------------
891 ;;  write npn bipolar transistor
892 ;;  This writes out a valid transistor refdes & then calls
893 ;;  the function which writes the rest of the line.
894 ;;-----------------------------------------------------------
895 (define spice-sdb:write-npn-bipolar-transistor
896   (lambda (package port)
897     (debug-spew (string-append "Found npn bipolar transistor.  Refdes = " package "\n"))
898     (let ((attrib-list (list "ic" "temp") ))  
899       (spice-sdb:write-transistor-diode package "Q" "NPN" attrib-list port))
900   )
904 ;;-----------------------------------------------------------
905 ;;  write pnp bipolar transistor
906 ;;-----------------------------------------------------------
907 (define spice-sdb:write-pnp-bipolar-transistor
908   (lambda (package port)
909     (debug-spew (string-append "Found pnp bipolar transistor.  Refdes = " package "\n"))
910     (let ((attrib-list (list "ic" "temp") ))  
911       (spice-sdb:write-transistor-diode package "Q" "PNP" attrib-list port))
912   )
916 ;;-----------------------------------------------------------
917 ;;  write n-channel jfet transistor
918 ;;-----------------------------------------------------------
919 (define spice-sdb:write-nfet-transistor
920   (lambda (package port)
921     (debug-spew (string-append "Found n-channel JFET.  Refdes = " package "\n"))
922     (let ((attrib-list (list "ic" "temp") ))
923       (spice-sdb:write-transistor-diode package "J" "NJF" attrib-list port))
924   )
928 ;;-----------------------------------------------------------
929 ;;  write p-channel jfet transistor
930 ;;-----------------------------------------------------------
931 (define spice-sdb:write-pfet-transistor
932   (lambda (package port)
933     (debug-spew (string-append "Found p-channel JFET.  Refdes = " package "\n"))
934     (let ((attrib-list (list "ic" "temp") ))
935       (spice-sdb:write-transistor-diode package "J" "PJF" attrib-list port))
936   )
940 ;;------------------------------------------------------
941 ;;  write pmos transistor
942 ;;------------------------------------------------------
943 (define spice-sdb:write-pmos-transistor
944   (lambda (package port)
945     (debug-spew (string-append "Found PMOS transistor.  Refdes = " package "\n"))
946     (let ((attrib-list (list "l" "w" "as" "ad" "pd" "ps" "nrd" "nrs" "temp" "ic" "m")))
947       (spice-sdb:write-transistor-diode package "M" "PMOS" attrib-list port))
948   )
952 ;;------------------------------------------------------
953 ;;  write nmos transistor
954 ;;------------------------------------------------------
955 (define spice-sdb:write-nmos-transistor
956   (lambda (package port)
957     (debug-spew (string-append "Found NMOS transistor.  Refdes = " package "\n"))
958     (let ((attrib-list (list "l" "w" "as" "ad" "pd" "ps" "nrd" "nrs" "temp" "ic" "m")))
959       (spice-sdb:write-transistor-diode package "M" "NMOS" attrib-list port))
960   )
964 ;;------------------------------------------------------
965 ;;  write subckt pmos transistor
966 ;;------------------------------------------------------
967 (define spice-sdb:write-subckt-pmos-transistor
968   (lambda (package port)
969     (debug-spew (string-append "Found PMOS subcircuit transistor.  Refdes = " package "\n"))
970     (let ((attrib-list (list "l" "w" "as" "ad" "pd" "ps" "nrd" "nrs" "temp" "ic" "m")))
971       (spice-sdb:write-transistor-diode package "X" "PMOS" attrib-list port))
972   )
975 ;;------------------------------------------------------
976 ;;  write subckt nmos transistor
977 ;;------------------------------------------------------
978 (define spice-sdb:write-subckt-nmos-transistor
979   (lambda (package port)
980     (debug-spew (string-append "Found NMOS subcircuit transistor.  Refdes = " package "\n"))
981     (let ((attrib-list (list "l" "w" "as" "ad" "pd" "ps" "nrd" "nrs" "temp" "ic" "m")))
982       (spice-sdb:write-transistor-diode package "X" "NMOS" attrib-list port))
983   )
985 ;;------------------------------------------------------------
986 ;;  write mesfet transistor
987 ;;------------------------------------------------------------
988 ;; ************  Fix this!!!!!!!!!!  **************
989 (define spice-sdb:write-mesfet-transistor
990   (lambda (package port)
991     (spice-sdb:write-transistor-diode package "Z" "MESFET" (list) port)))  ;; XXXXXX Fix this!!!
994 ;;-----------------------------------------------------------
995 ;;  write voltage controled switch
996 ;;-----------------------------------------------------------
997 (define spice-sdb:write-vc-switch
998   (lambda (package port)
999     (debug-spew (string-append "Found voltage controled switch.  Refdes = " package "\n"))
1000     (let ((attrib-list (list " " ) ))
1001       (spice-sdb:write-transistor-diode package "S" "SW" attrib-list port))
1002   )
1006 ;;--------------------------------------------------------------------
1007 ;;  write resistor
1008 ;;--------------------------------------------------------------------
1009 (define spice-sdb:write-resistor
1010   (lambda (package port)
1012     (debug-spew (string-append "Found resistor.  Refdes = " package "\n"))
1014     ;; first write out refdes and attached nets
1015     (spice-sdb:write-component-no-value package port)
1017     ;; next write out mandatory resistor value if it exists.
1018     (let ((value (gnetlist:get-package-attribute package "value")))
1019         (if (not (string=? value "unknown")) 
1020                 (display (string-append value " " ) port))
1021     )
1023     ;; next write our model name if it exists
1024     (let* ((model-name (gnetlist:get-package-attribute package "model-name")))
1025         (if (not (string=? model-name "unknown")) 
1026                 (display (string-append model-name " " ) port))
1027     )
1029     ;; next create list of attributes which can be attached to a resistor.
1030     ;; I include non-standard "area" attrib here per popular demand.
1031     (let ((attrib-list (list "area" "l" "w" "temp")))
1032             ;; write the attributes (if any) separately
1033       (spice-sdb:write-list-of-attributes package attrib-list port)
1034       (display " " port))  ;; add additional space. . . . 
1036     ;; finally output a new line
1037     (newline port)
1039   )
1043 ;;----------------------------------------------------------------------------
1044 ;;  write capacitor
1045 ;;----------------------------------------------------------------------------
1046 (define spice-sdb:write-capacitor
1047   (lambda (package port)
1049     (debug-spew (string-append "Found capacitor.  Refdes = " package "\n"))
1051     ;; first write out refdes and attached nets
1052     (spice-sdb:write-component-no-value package port)
1054     ;; next write capacitor value, if any.  Note that if the 
1055     ;; component value is not assigned nothing will be written out.
1056     (let ((value (gnetlist:get-package-attribute package "value")))
1057         (if (not (string=? value "unknown"))
1058                 (display (string-append value " " ) port))
1059     )
1061     ;; next write capacitor model name, if any.  This is applicable to 
1062     ;; semiconductor caps used in chip design.
1063     (let ((model-name (gnetlist:get-package-attribute package "model-name")))
1064         (if (not (string=? model-name "unknown"))
1065                 (display (string-append model-name " " ) port))
1066     )
1068     ;; Next write out attribtes if they exist.  Use 
1069     ;; a list of attributes which can be attached to a capacitor.
1070     ;; I include non-standard "area" attrib here per request of Peter Kaiser.
1071     (let ((attrib-list (list "area" "l" "w" "ic")))
1072       (spice-sdb:write-list-of-attributes package attrib-list port)
1073             ;; write the off attribute separately
1074                 (display " " port))  ;; add additional space. . . . 
1076     (newline port)
1077   )
1081 ;;----------------------------------------------------------------------------
1082 ;;  write inductor
1083 ;;----------------------------------------------------------------------------
1084 (define spice-sdb:write-inductor
1085   (lambda (package port)
1087     (debug-spew (string-append "Found inductor.  Refdes = " package "\n"))
1089     ;; first write out refdes and attached nets
1090     (spice-sdb:write-component-no-value package port)
1092 ;;            ;; next write inductor model name, if any.
1093 ;;    (let ((model-name (gnetlist:get-package-attribute package "model-name")))
1094 ;;        (if (not (string=? model "unknown"))
1095 ;;              (display (string-append model-name " " ) port)
1096 ;;    )
1098     ;; next write inductor value, if any.  Note that if the 
1099     ;; component value is not assigned, then it will write "unknown"
1100     (let ((value (gnetlist:get-package-attribute package "value")))
1101                 (display value port)
1102     )
1105     ;; create list of attributes which can be attached to a inductor
1106     (let ((attrib-list (list "l" "w" "ic")))
1107       (spice-sdb:write-list-of-attributes package attrib-list port)
1109       ;; write the off attribute separately
1110       (display " " port))  ;; add additional space. . . . 
1112     (newline port)
1113   )
1117 ;;-------------------------------------------------------------------------
1118 ;;  write independent voltage source
1119 ;;  The behavior of the voltage source is held in the "value" attribute
1120 ;;-------------------------------------------------------------------------
1121 (define spice-sdb:write-independent-voltage-source
1122   (lambda (package port)
1123     (debug-spew (string-append "Found independent voltage source.  Refdes = " package "\n"))
1125             ;; first write out refdes and attached nets
1126     (spice-sdb:write-component-no-value package port)
1128             ;; next write voltage value, if any.  Note that if the 
1129             ;; voltage value is not assigned, then it will write "unknown"
1130     (let ((value (gnetlist:get-package-attribute package "value")))
1131                 (display value port)
1132     )
1134     (newline port)
1135   )
1139 ;;-------------------------------------------------------------------------
1140 ;;  write independent current source
1141 ;;  The behavior of the current source is held in the "value" attribute
1142 ;;-------------------------------------------------------------------------
1143 (define spice-sdb:write-independent-current-source
1144   (lambda (package port)
1146         (debug-spew (string-append "Found independent current source.  Refdes = " package "\n")) 
1148             ;; first write out refdes and attached nets
1149     (spice-sdb:write-component-no-value package port)
1151             ;; next write current value, if any.  Note that if the 
1152             ;; current value is not assigned, then it will write "unknown"
1153     (let ((value (gnetlist:get-package-attribute package "value")))
1154                 (display value port)
1155     )
1157     (newline port)
1158   )
1162 ;;----------------------------------------------------------------------------
1163 ;;  write Josephson junction in wrspice format. Paul Bunyk, Sep 2, 2005
1164 ;;----------------------------------------------------------------------------
1165 (define spice-sdb:write-josephson-junction
1166   (lambda (package port)
1168     (debug-spew (string-append "Found Josephson junction.  Refdes = " package "\n"))
1170     ;; first write out refdes and attached nets
1171     (spice-sdb:write-component-no-value package port)
1173     ;; next, add a dummy node for JJ phase. Unlike in Xic netlister, give it 
1174     ;; a reasonable name, not a number, e.g., refdes.
1175     (display (string-append package " ") port)
1177     ;; next write JJ model name, if any.  
1178     (let ((model-name (gnetlist:get-package-attribute package "model-name")))
1179         (if (not (string=? model-name "unknown"))
1180                 (display (string-append model-name " " ) port))
1181     )
1183     ;; Next write out attribtes if they exist.  Use 
1184     ;; a list of attributes which can be attached to a junction.
1185     (let ((attrib-list (list "area")))
1186       (spice-sdb:write-list-of-attributes package attrib-list port)
1187             ;; write the off attribute separately
1188                 (display " " port))  ;; add additional space. . . . 
1190     (newline port)
1191   )
1195 ;;----------------------------------------------------------------------------
1196 ;;  write mutual inductance(actually K). Paul Bunyk, Sep 2, 2005
1197 ;;----------------------------------------------------------------------------
1198 (define spice-sdb:write-coupling-coefficient
1199   (lambda (package port)
1201     (debug-spew (string-append "Found mutual inductance.  Refdes = " package "\n"))
1203     ;; first write out refdes and attached nets (none)
1204     (spice-sdb:write-component-no-value package port)
1206     ;; next two inductor names and value
1207     (let ((inductors (gnetlist:get-package-attribute package "inductors"))
1208           (value (gnetlist:get-package-attribute package "value")) )
1209         (if (not (string=? inductors "unknown"))
1210                 (display (string-append inductors " " ) port))  
1211         (if (not (string=? value "unknown"))
1212                 (display (string-append value " " ) port))
1213         
1214     )
1216     (newline port)
1217   )
1221 ;;----------------------------------------------------------------------------
1222 ; write a voltage probe
1223 ;;----------------------------------------------------------------------------
1224 (define (spice-sdb:write-probe package port)
1225     ;; fetch only one attr we care about, so far
1226     (let ((value (gnetlist:get-package-attribute package "value"))
1227          ) ;; end of local assignments
1229     (debug-spew (string-append "Found Probe item, refdes = " package "\n"))
1231     (if (string=? value "unknown")
1232       (set! value "TRAN"))
1234     (display (string-append "* Probe device " package " on nets ") port)
1235     (spice-sdb:write-net-names-on-component package port)
1236     (newline port)
1237     (display (string-append ".print " value " +") port)
1238     (spice-sdb:write-net-names-on-component package port
1239       (string-join (map (lambda (x) "V(~a)") (gnetlist:get-pins package)) " " 'infix) ) ;; make format string
1240     (newline port)
1241   ) ;; end of let
1242 ) ;; close of define
1245 ;;--------------------------------------------------------------------
1246 ;; Given a refdes and port, and optionaly a format string, this writes
1247 ;; out the nets attached to the component's pins.  This is used to write
1248 ;; out non-slotted parts.
1249 ;;--------------------------------------------------------------------
1250 (define (spice-sdb:write-net-names-on-component refdes port . format)
1252 ;; get-net-name -- helper function. Called with pinseq, returns net name,
1253 ;; unless net name is "ERROR_INVALID_PIN" then it returns false.
1254     (define (get-net-name pin)
1255         (set! pin (number->string pin))
1257 ;; -------  Super debug stuff  --------
1258           (if #f
1259             (begin
1260               (debug-spew "  In write-net-names-on-component. . . . \n")
1261               (debug-spew (string-append "     pin-name = " pin "\n"))
1262               (debug-spew (string-append "     pinnumber = " (gnetlist:get-attribute-by-pinseq refdes pin "pinnumber") "\n"))
1263               (debug-spew (string-append "     pinseq = " (gnetlist:get-attribute-by-pinseq refdes pin "pinseq")))
1264               (if (not (string=? pin (gnetlist:get-attribute-by-pinseq refdes pin "pinseq")))
1265                 (debug-spew " <== INCONSISTANT!\n")
1266                 (debug-spew "\n") )
1267               (debug-spew (string-append "     netname = " (car (spice-sdb:get-net refdes (gnetlist:get-attribute-by-pinseq refdes pin "pinnumber"))) "\n"))
1268           )) ;; if #T for super debugging
1269 ;; -------------------------------------
1271         (set! pin (car (spice-sdb:get-net refdes (gnetlist:get-attribute-by-pinseq refdes pin "pinnumber"))))
1272         (if (string=? pin "ERROR_INVALID_PIN")
1273           (begin
1274             (debug-spew (string-append "For " refdes ", found pin with no pinseq attribute.  Ignoring. . . .\n"))
1275             #f)  ;; begin
1276         pin)  ;; if
1277     )  ;; define get-net-name
1279     ;; First do local assignments
1280     (let ((netnames (filter-map get-net-name (range 1 (length (gnetlist:get-pins refdes)))))
1281          )  ;; let
1282       (if (null? format)
1283         (display (string-join netnames " " 'suffix) port)                       ;; write out nets.
1284         (apply simple-format (cons port (cons (car format) netnames))) )        ;; write out nets with format string
1285     )  ;; let
1289 ;;-------------------------------------------------------------------
1290 ;; Write the refdes and the net names connected to pins on this component.
1291 ;; No return, and no component value is written, or extra attribs.
1292 ;; Those are handled later.
1293 ;;-------------------------------------------------------------------
1294 (define spice-sdb:write-component-no-value
1295   (lambda (package port)
1296     (display (string-append package " ") port)  ;; write component refdes
1297     (spice-sdb:write-net-names-on-component package port)
1298   )
1302 ;;-----------------------------------------------------------
1303 ;; Given a refdes, returns the device attribute "value" as string
1304 ;; Used when "value" is a mandatory attribute.
1305 ;; Returns "<no valid attribute . . .>" if not available.
1306 ;;-----------------------------------------------------------
1307 (define spice-sdb:component-value
1308   (lambda (package)
1309     (let ((value (gnetlist:get-package-attribute package "value")))
1310 ;;      (display (string-append "in get-package-attribute, value = " value "\n"))
1311       (if (not (string=? value "unknown"))
1312         value
1313         "<No valid value attribute found>"))))
1316 ;;------------------------------------------------------------
1317 ;; Given a refdes, returns the device attribute "value" as string
1318 ;; Used when "value" is an optional attribute.
1319 ;; Returns "unknown" if not available.
1320 ;;------------------------------------------------------------
1321 (define spice-sdb:component-optional-value
1322   (lambda (package)
1323     (let ((value (gnetlist:get-package-attribute package "value")))
1324       (if (not (string=? value "unknown"))
1325         (string-append value " ")
1326         ""))))
1329 ;;-----------------------------------------------------------
1330 ;; Given a refdes, returns the device attribute "model" as string
1331 ;;-----------------------------------------------------------
1332 (define spice-sdb:component-model
1333   (lambda (package)
1334     (let ((model (gnetlist:get-package-attribute package "model")))
1335       (if (not (string=? model "unknown"))
1336         model spice-sdb:component-value))))
1339 ;;----------------------------------------------------------
1340 ;; Include SPICE statements from a SPICE directive block.
1341 ;;----------------------------------------------------------
1342 (define spice-sdb:write-directive
1343   (lambda (package port)
1344              ;; Collect variables used in creating spice code
1345         (let ((value (gnetlist:get-package-attribute package "value"))
1346               (file (gnetlist:get-package-attribute package "file"))
1347              )   ;; end of local assignments
1349           (debug-spew (string-append "Found SPICE directive box.  Refdes = " package "\n"))
1351           (cond
1353               ;; First look to see if there is a value.
1354            ((not (string=? value "unknown"))
1355             (begin
1356               (display (string-append value "\n") port)
1357               (debug-spew (string-append "Appending value = \"" value "\" to output file.\n"))
1358             ))
1360               ;; since there is no value, look for file. 
1361            ((not (string=? file "unknown"))
1362             (begin
1363               (spice-sdb:insert-text-file file port)   ;; Note that we don't wait until the end here.  Is that OK?
1364               (debug-spew (string-append "Inserting contents of file = " file " into output file.\n"))
1365             ))
1367           ) ;; close of cond
1368         ) ;; close of let
1369     ) ;; close of lambda
1370 ) ;; close of define
1373 ;;----------------------------------------------------------
1374 ;; Include a file using an .INCLUDE directive
1375 ;; Changed on 6.12.2005: to embedd the contents of the file,
1376 ;; you must call gnetlist with the -e flag set.
1377 ;;----------------------------------------------------------
1378 (define spice-sdb:write-include
1379   (lambda (package port)
1380     (let ((value (gnetlist:get-package-attribute package "value"))
1381           (file (gnetlist:get-package-attribute package "file"))
1382           )   ;; end of local assignments
1384       (debug-spew (string-append "Found SPICE include box.  Refdes = " package "\n"))
1385       ;; (debug-spew (string-append "   value = " value "\n"))
1386       ;; (debug-spew (string-append "   file = " file "\n"))
1387       
1388       (cond
1389        ;; First look to see if value attribute is used
1390        ((not (string=? value "unknown"))
1391         (begin
1392           ;; (debug-spew "This include directive uses a value attribute.\n")
1393           (if (calling-flag? "embedd_mode" (gnetlist:get-calling-flags))
1394               (begin
1395                 (spice-sdb:insert-text-file value port)                 ;; -e found: invoke insert-text-file
1396                 (debug-spew (string-append "embedding contents of " value " into netlist.\n")))
1397               (begin
1398                 (display (string-append ".INCLUDE " value "\n") port)   ;; -e not found: just print out .INCLUDE card
1399                 (debug-spew "placing .include directive string into netlist.\n"))
1400          )))
1402        ;; Now look to see if file is used
1403        ((not (string=? file "unknown"))
1404         (begin
1405           ;; (debug-spew "This include directive uses a file attribute.\n")
1406           (if (calling-flag? "embedd_mode" (gnetlist:get-calling-flags))
1407               (begin
1408                 (spice-sdb:insert-text-file file port)                 ;; -e found: invoke insert-text-file
1409                 (debug-spew (string-append "embedding contents of " value " into netlist.\n")))
1410               (begin
1411                 (display (string-append ".INCLUDE " file "\n") port)   ;; -e not found: just print out .INCLUDE card
1412                 (debug-spew "placing .include directive string into netlist.\n"))
1413           )  ;; end of if (calling-flag
1414         )
1415        )
1416      ) ;; end of cond
1420 ;;----------------------------------------------------------
1421 ;; Include an option using an .OPTIONS directive
1422 ;;----------------------------------------------------------
1423 (define spice-sdb:write-options
1424   (lambda (package port)
1425     (debug-spew (string-append "Found .OPTIONS box.  Refdes = " package "\n")) 
1426     (display (string-append ".OPTIONS " (spice-sdb:component-value package) "\n") port)))
1429 ;;----------------------------------------------------------
1430 ;; Include a spice model (instantiated as a model box on the schematic)
1431 ;;  Two types of model can be included:
1432 ;;  1.  An embedded model, which is a one- or multi-line string held in the attribute "model".
1433 ;;      In this case, the following attributes are mandatory:
1434 ;;      --  model (i.e. list of parameter=value strings)
1435 ;;      --  model-name
1436 ;;      --  type
1437 ;;      In this case, the function creates and formats the correct spice model line(s).
1438 ;;  2.  A model held in a file whose name is held in the attribute "file"
1439 ;;      In this case, the following attribute are mandatory:
1440 ;;      --  file (i.e. list of parameter=value strings)
1441 ;;      In this case, the function just opens the file and dumps the contents
1442 ;;      into the netlist.
1443 ;;----------------------------------------------------------
1444 (define spice-sdb:write-model
1445   (lambda (package port)
1446              ;; Collect variables used in creating spice code
1447         (let ((model-name (gnetlist:get-package-attribute package "model-name"))
1448               (model-file (gnetlist:get-package-attribute package "file"))
1449               (model (gnetlist:get-package-attribute package "model"))
1450               (type (gnetlist:get-package-attribute package "type"))
1451              )   ;; end of local assignments
1453           (debug-spew (string-append "Found .MODEL box.  Refdes = " package "\n"))
1454           
1455           ;; Now, depending upon what combination of model, model-file, and model-name
1456           ;; exist (as described above) write out lines into spice netlist.
1457           (cond
1458              ;; one model and model name exist
1459            ( (not (or (string=? model "unknown") (string=? model-name "unknown")))
1460              (debug-spew (string-append "found model and model-name for " package "\n"))
1461              (display (string-append ".MODEL " model-name " " type " (" model ")\n") port) )
1463              ;; model file exists
1464            ( (not (or (string=? model-file "unknown") ))
1465              (debug-spew (string-append "found model-file for " package "\n"))
1466              ;; (spice-sdb:insert-text-file model-file port)   ;; don't write it out -- it's handled after the second pass.
1467            )
1469           )  ;; close of cond
1470         ) ;; close of let
1471     ) ;; close of lambda
1472 ) ;; close of define
1475 ;;-------------------------------------------------------------------
1476 ;;  This writes out the default component (i.e. the "device" attribute
1477 ;;  was not recognized).  This function does the following:
1479 ;;  1.  Gets the refdes (package).
1480 ;;  2.  Checks the refdes against a short list of possible values.
1481 ;;      Depending upon the refdes, it does the following thing:
1482 ;;      D? -- Invokes write-diode
1483 ;;      Q? -- Invokes write-transistor-diode. (The "type" attribute is <unknown> 
1484 ;;            in this case so that the spice simulator will barf if the user
1485 ;;            has been careless.)
1486 ;;      U? -- Invokes write-ic. This provides the opportunity for a component
1487 ;;            model to be instantiated.
1488 ;;      X? -- Invokes write-ic.  This provides the opportunity for a component
1489 ;;            subcircuit to be instantiated.
1490 ;;      V? -- Invokes write-independent-voltage-source
1491 ;;      I? -- Invokes write-independent-current-source
1492 ;;      Otherwise, it just outputs the refdes, the attached nets, and the 
1493 ;;      value of the "value" attribute.
1494 ;;  
1495 ;;-------------------------------------------------------------------
1496 (define spice-sdb:write-default-component
1497   (lambda (package file-info-list port)
1499     (let ((first-char (string (string-ref package 0)) ))  ;; extract first char of refdes.
1500       (cond
1501        ((string=? first-char "D") (spice-sdb:write-diode package port))
1502        ((string=? first-char "Q") (spice-sdb:write-transistor-diode package #f "<unknown>" (list) port))
1503        ((string=? first-char "M") (spice-sdb:write-transistor-diode package #f "<unknown>" (list) port))
1504        ((string=? first-char "U") (spice-sdb:write-ic package file-info-list port))
1505        ((string=? first-char "V") (spice-sdb:write-independent-voltage-source package port))
1506        ((string=? first-char "I") (spice-sdb:write-independent-current-source package port))
1507        ((string=? first-char "X") (spice-sdb:write-ic package file-info-list port))
1508        (else 
1509         (display (string-append "Found unknown component.  Refdes = " package "\n"))
1510         (spice-sdb:write-component-no-value package port)
1511         ;; write component value, if components have a label "value=#"
1512         ;; what if a component has no value label, currently unknown is written
1513         (display (spice-sdb:component-value package) port)
1514         (newline port)
1515        )
1516       ) ;; end cond
1517      )  ;; end let
1518   )
1522 ;;**********************************************************************************
1523 ;;***************  High-level functions for program control  ***********************
1524 ;;**********************************************************************************
1526 ;;----------------------------------------------------------------------
1527 ;; write-netlist is passed a list of refdess (ls).  It uses 
1528 ;; each refdes to get the corresponding
1529 ;; "device" attribute.  Depending upon the device, it then invokes one or another of the 
1530 ;; spice line output fcns to output a line of the spice netlist.
1531 ;; I have enlarged the number of devices it recognizes -- SDB.
1532 ;; write the refdes, to the pin# connected net and component 
1533 ;; value and optional extra attributes
1534 ;; check if the component is a special spice component.
1535 ;;----------------------------------------------------------------------
1536 (define spice-sdb:write-netlist
1537   (lambda (port file-info-list ls)     
1538      (if (not (null? ls))
1539       (let* ((package (car ls))             ;; assign package
1540              (device (get-device package))  ;; assign device.    
1541             )                               ;; end of let* assignments
1543 ;; Super debug stuff -- outputs line describing device being processed.
1544         (debug-spew (string-append "--- checking package = " package "\n"))
1545         (debug-spew (string-append "    device = " device "\n"))
1546 ;; done with debug stuff
1548         (cond
1549           ( (string=? device "none"))                 ;; do nothing for graphical symbols.
1550           ( (string=? device "spice-subcircuit-LL"))  ;; do nothing for subcircuit declaration.
1551           ( (string=? device "spice-IO"))             ;; do nothing for SPICE IO pins.
1552           ( (string=? device "SPICE-ccvs")
1553               (spice-sdb:write-ccvs package port))
1554           ( (string=? device "SPICE-cccs")
1555               (spice-sdb:write-cccs package port))
1556           ( (string=? device "SPICE-vcvs")
1557               (spice-sdb:write-vcvs package port))
1558           ( (string=? device "SPICE-vccs")
1559               (spice-sdb:write-vccs package port))
1560           ( (string=? device "SPICE-nullor")
1561               (spice-sdb:write-nullor package port))
1562           ( (string=? device "DIODE")
1563               (spice-sdb:write-diode package port))
1564           ( (string=? device "PMOS_TRANSISTOR")
1565               (spice-sdb:write-pmos-transistor package port))
1566           ( (string=? device "NMOS_TRANSISTOR")
1567               (spice-sdb:write-nmos-transistor package port))
1568           ( (string=? device "PNP_TRANSISTOR")
1569               (spice-sdb:write-pnp-bipolar-transistor package port))
1570           ( (string=? device "SPICE-PNP")
1571               (spice-sdb:write-pnp-bipolar-transistor package port))
1572           ( (string=? device "NPN_TRANSISTOR")
1573               (spice-sdb:write-npn-bipolar-transistor package port))
1574           ( (string=? device "SPICE-NPN")
1575               (spice-sdb:write-npn-bipolar-transistor package port))
1576           ( (string=? device "PFET_TRANSISTOR")
1577               (spice-sdb:write-pfet-transistor package port))
1578           ( (string=? device "NFET_TRANSISTOR")
1579               (spice-sdb:write-nfet-transistor package port))
1580           ( (string=? device "MESFET_TRANSISTOR")
1581               (spice-sdb:write-mesfet-transistor package port))
1582           ( (string=? device "SPICE-VC-switch")
1583               (spice-sdb:write-vc-switch package port))
1584           ( (string=? device "RESISTOR")
1585               (spice-sdb:write-resistor package port))
1586           ( (string=? device "CAPACITOR")
1587               (spice-sdb:write-capacitor package port))
1588           ( (string=? device "POLARIZED_CAPACITOR")
1589               (spice-sdb:write-capacitor package port))                  ;; change someday
1590           ( (string=? device "INDUCTOR")
1591               (spice-sdb:write-inductor package port))     
1592           ( (string=? device "COIL")           ;; Added to enable netlisting of coil-*.sym
1593               (spice-sdb:write-inductor package port))     
1594           ( (string=? device "VOLTAGE_SOURCE")
1595               (spice-sdb:write-independent-voltage-source package port)) ;; change someday
1596           ( (string=? device "CURRENT_SOURCE")
1597               (spice-sdb:write-independent-current-source package port)) ;; change someday
1598           ( (string=? device "JOSEPHSON_JUNCTION")
1599               (spice-sdb:write-josephson-junction package port)) 
1600           ( (string=? device "K")
1601               (spice-sdb:write-coupling-coefficient package port)) 
1602           ( (string=? device "model")
1603               (spice-sdb:write-model package port))
1604           ( (string=? device "options")
1605               (spice-sdb:write-options package port))
1606           ( (string=? device "directive")
1607               (spice-sdb:write-directive package port))
1608           ( (string=? device "include")
1609               (spice-sdb:write-include package port))
1610           ( (string=? device "TESTPOINT")
1611               (spice-sdb:write-probe package port))
1612           ( (string=? device "SUBCKT_PMOS")
1613               (spice-sdb:write-subckt-pmos-transistor package port))
1614           ( (string=? device "SUBCKT_NMOS")
1615               (spice-sdb:write-subckt-nmos-transistor package port))
1616           ( else 
1617               (spice-sdb:write-default-component package file-info-list port))
1618         ) ;; end of cond
1619         (spice-sdb:write-netlist port file-info-list (cdr ls))
1620          ))))
1623 ;;----------------------------------------------------------------------
1624 ;; create-file-info-list: This takes as arugment the list of packages (refdesses).
1625 ;;   It runs through the package list, and for each gets the attributes.  If there is a
1626 ;;   "FILE" attribute, it gets the file info & uses it to build the
1627 ;;   file-info-list.  When done, it returns the file-info-list.
1628 ;;----------------------------------------------------------------------
1629 (define spice-sdb:create-file-info-list
1630   (lambda (package-list file-info-list)     
1631      (if (null? package-list)
1632         file-info-list                          ;; end of packages processed.  Return file-info-list     
1633         (let* ((package (car package-list))     ;; otherwise get next package (i.e. refdes)
1634                (device (string))
1635                (model (string))
1636                (value (string))
1637                (model-file (string))
1638               )                                 ;; end of let* assignments
1640           (set! device (get-device package) )  
1641           (set! model (gnetlist:get-package-attribute package "model-name") )
1642           (set! value (gnetlist:get-package-attribute package "value") )
1643           (set! model-file (gnetlist:get-package-attribute package "file") )
1645           ;; Sometimes get-package-attribute returns "?" instead of "unknown".
1646           ;; This is because some symbols use file=? as a place holder value to indicate that
1647           ;; it needs to be filled in. It is simular other place holders like  footprint=none, and refdes=R?.
1648           ;; ? seems to be an ad hoc place holder for other attributes as well, like value for example.
1649           ;; FIXME: Of couse there could be many other places that this problem occurs. An effort should be
1650           ;; made to come up with a consistant way of representing place holders.
1652           (if (string-ci=? model-file "?")
1653               (set! model-file "unknown"))
1655           ;; Now run a series of checks to see if we should stick this file into the file-info-list
1656           ;; Check to see if "file" attribute is non-empty
1657           (if (not (string-ci=? model-file "unknown"))
1658               (begin 
1659                 (debug-spew 
1660                    (string-append "found file attribute for " package ".  File name = " model-file "\n"))  ;;  ******* Debug stuff
1661               
1662               ;; Now check to see if file is in file-info-list
1663                 (if (not (spice-sdb:in-file-info-list? model-file file-info-list))
1665               ;; File is new.  Open file, find out what type it is, and push info into file-info-list
1666                     (let ((file-type (spice-sdb:get-file-type model-file))
1667                          )
1668                       (debug-spew (string-append "File is new.  New file type is " file-type " \n"))      ;; DEBUG
1669                   
1670               ;; Check to see if file-type is known.
1671                       (if (not (string=? file-type "OTHER"))
1672               ;; file-type is OK.  Return file-info-list with new triplet attached.  
1673                           (begin
1674                             (debug-spew (string-append "Inserting " model-file " into list of known model files.\n"))
1675                             (set! file-info-list (append (list (list model model-file file-type)) file-info-list) )
1676                           )
1678               ;;  Otherwise, file type is not a model type.  Don't stick it in list.  Print debug spew if desired.
1679                           (debug-spew "File type is OTHER, and therefore will not be entered in known model file list.\n")
1680                        )   ;; end if (not (string=?
1682                      )  ;; end let ((file-type . . .
1684               ;;  File is already in list.  Print debug spew if desired.
1685                     (debug-spew "File has already been seen and entered into known model file list.\n")
1686                 )  ;; end if (spice-sdb:in-file-info-list . . .
1688               )  ;; end begin . . .
1689           )  ;; end if (not( string-ci=? model-file
1691           ;; having done checking and processing of this package, iterate to the next one.
1692           (spice-sdb:create-file-info-list (cdr package-list) file-info-list)
1694       )  ;; end let*
1695    )  ;; end if (null? package-list . . .
1696  ) 
1700 ;;  in-file-info-list? -- helper function.  Returns #t if file is already in file-info-list, otherwise #f
1701 ;;  assumes file-info-list of form: ((model1 file1 file-type1)  (model2 file2 file-type2) . . . .)
1702 (define spice-sdb:in-file-info-list?
1703   (lambda (model-file file-info-list)
1704     (if (null? file-info-list)
1705         (begin
1706           #f                                            ;; return #f if file-info-list itself is empty.
1707         )
1708         (let ((list-element (car file-info-list)) )   ;; otherwise process list-element
1709           (if (null? list-element)
1710               #f                                      ;;  item not found.  Return #f.  Note that we should never get here . . .
1711               (let ((list-file-name (cadr list-element)) )
1712                 (if (string=? list-file-name model-file)
1713                    #t                            ;; item found.  Return #t
1714                    (spice-sdb:in-file-info-list? model-file (cdr file-info-list))  ;; iterate . . .
1715                 )  ;; end if (string=?
1716               )  ;; end of let . . .
1717           )  ;; end if (null? list-element . . .
1718         )  ;; end let* ((list-element . . .
1719     )  ;; end if (null? file-info-list . .
1720 ))  ;; end define spice-sdb:in-file-info-list?
1723 ;;--------------------------------------------------------------
1724 ;; Write out spice netlist header
1725 ;;--------------------------------------------------------------
1726 (define spice-sdb:write-top-header
1727   (lambda (port)
1728     (display "*********************************************************\n" port)
1729     (display "* Spice file generated by gnetlist                      *\n" port)
1730     (display "* spice-sdb version 4.28.2007 by SDB --                 *\n" port)
1731     (display "* provides advanced spice netlisting capability.        *\n" port)
1732     (display "* Documentation at http://www.brorson.com/gEDA/SPICE/   *\n" port)
1733     (display "*********************************************************\n" port)
1734   )
1738 ;;--------------------------------------------------------------
1739 ;; Write out .SUBCKT netlist header
1740 ;;--------------------------------------------------------------
1741 (define spice-sdb:write-subcircuit-header
1742   (lambda (port)
1743     (display "*******************************\n" port)
1744     (display "* Begin .SUBCKT model         *\n" port)
1745     (display "* spice-sdb ver 4.28.2007     *\n" port)
1746     (display "*******************************\n" port)
1747   )
1751 ;;---------------------------------------------------------------
1752 ;; Write the .END line
1753 ;;---------------------------------------------------------------
1754 (define spice-sdb:write-bottom-footer
1755   (lambda (salutation port)
1756     (display salutation port)
1757     (newline port)))
1760 ;;---------------------------------------------------------------
1761 ;; Spice netlist generation
1762 ;;   This is the entry point.
1763 ;;   Hacked on 3.31.2003 to enable writing out .SUBCKT models -- SDB.
1764 ;;   Hacked again in Sept 2003 to enable more intelligent embedding of external
1765 ;;       SPICE files into netlist -- SDB.
1766 ;;   The algorithm is as follows:
1767 ;;   1.  Figure out if there is a .SUBCKT block on the schematic,
1768 ;;       or if it is just a normal schematic.
1769 ;;       If a .SUBCKT:
1770 ;;       -- Write out subcircuit header (a comment identifying the netlister).
1771 ;;       -- find all spice-IO pins.  Get a list of the packages.
1772 ;;       -- put them in order (ordered by package refdes)
1773 ;;       -- get the list of nets attached to the spice-IO pins.
1774 ;;       -- write out .SUBCKT line
1775 ;;       If a normal schematic: 
1776 ;;       -- Write out top header (a comment identifying the netlister).
1777 ;;   2.  Loop through all components, looking for components with a "file"
1778 ;;       attribute.  Every time a "file" attribute is found do this:
1779 ;;       --  Open the file and find out what kind of file it is (.SUBCKT or .MODEL).
1780 ;;       --  Determine if the file has previously been processed.  If not: stick the 
1781 ;;           follwing info into the file-info list: (model-name file-name file-type). 
1782 ;;           Otherwise just continue.
1783 ;;   3.  Loop through all components again, and write out a SPICE card for each.  
1784 ;;   4.  Afterwards, for each item in the file-info list, open the file, and
1785 ;        write its contents into the netlist.
1786 ;;   5.  If the schematic-type is .SUBCKT:  write out .ENDS,  Otherwise: write out .END
1787 ;;   6.  Close up the SPICE netlist file and return.
1788 ;;---------------------------------------------------------------
1789 (define spice-sdb
1790   (lambda (output-filename)
1791 ;; 
1792 ;; First find out if this is a .SUBCKT lower level, 
1793 ;; or if it is a regular schematic.
1795     (let* ((port (open-output-file output-filename))
1796            (schematic-type (spice-sdb:get-schematic-type packages))
1797            (model-name (spice-sdb:get-subcircuit-modelname schematic-type)) 
1798            (file-info-list (list))
1799           )
1800       (display "Using SPICE backend by SDB -- Version of 4.28.2007\n")
1801       (display (string-append "schematic-type = " schematic-type "\n"))
1802       ;; (display (string-append "model-name = " model-name "\n"))
1804       (if (not (string=? schematic-type "normal schematic"))
1805       ;; we have found a .SUBCKT type schematic.
1806           (let* ((io-pin-packages (spice-sdb:get-spice-IO-pins packages (list) ))
1807                  (io-pin-packages-ordered (spice-sdb:sort-spice-IO-pins io-pin-packages))
1808                  (io-nets-list (spice-sdb:get-IO-nets io-pin-packages-ordered (list) ))
1809                 )
1810             (debug-spew "found .SUBCKT type schematic")
1811       ;; now write out .SUBCKT header and .SUBCKT line
1812             (spice-sdb:write-subcircuit-header port)   
1813             (let ((io-nets-string (list-2-string io-nets-list)) )
1814               ;; (display (string-append "Found IO nets for subckt = " io-nets-string "\n"))   ;; DEBUG stuff . . .
1815               ;; (write io-nets-list)
1816               ;; (display "\n")
1817               (display (string-append schematic-type " " (list-2-string io-nets-list) "\n") port)
1818             )
1819           )
1820           
1821       ;; Otherwise it's a regular schematic.  Write out command line followed by comments in file header.
1822           (begin
1823             (debug-spew "found normal type schematic")
1824             (display (string-append "* " (gnetlist:get-command-line) "\n") port)
1825             (spice-sdb:write-top-header port)   
1826           )
1828       ) ;; end of if (not (string=? . . . .
1832 ;; Now loop through all devices and process all "FILE" attributes.  Create
1833 ;; file-info-list.
1834 ;; Thanks to Carlos Nieves Onega for his e-mail to 
1835 ;; geda-dev which is the genesis of this section.
1837       (debug-spew "\nMake first pass through design and create list of all model files referenced.\n")
1838       (set! file-info-list (spice-sdb:create-file-info-list packages file-info-list))
1839       (debug-spew "Done creating file-info-list.\n")
1841       ;;  extra debug spew -- comment out when done . . .
1842       ;; (display "file-info-list = \n")
1843       ;; (write file-info-list)
1844       ;; (display "\n")
1846       (debug-spew "\n")
1850 ;;  Moved this loop before the next one to get numparam to work with ngspice,
1851 ;;  because numparam will at the subckt definition come before the main netlist.
1852 ;;  Change suggested by Dominique Michel; implemented in code on 6.12.2005.
1854 ;;  Next loop through all items in file-info-list in the SPICE netlist.  
1855 ;;  For each model-name, open up the corresponding file, and call handle-spice-file 
1856 ;;  to stick the corresponding stuff into the output SPICE file.
1858       (debug-spew "Now process the items in model file list -- stick appropriate references to models in output SPICE file.\n")
1859       (spice-sdb:loop-through-files file-info-list port)
1860       (debug-spew "Done processing items in model file list.\n")
1864 ;; Now write out netlist as before.  But don't write file contents out.
1865 ;; **** Modified by kh to sort list of packages so Spice directives, etc. (A?) are output last,
1866 ;; **** and in increasing order.
1868       (debug-spew "Make second pass through design and write out a SPICE card for each component found.\n")
1869       (display (string-append "*==============  Begin SPICE netlist of main design ============\n") port)
1870       (if (spice-sdb:sort-refdes? (gnetlist:get-calling-flags))
1871           (spice-sdb:write-netlist port file-info-list (sort packages spice-sdb:packsort))  ;; sort on refdes
1872           (spice-sdb:write-netlist port file-info-list packages)                            ;; don't sort.
1873       )
1874       (debug-spew "Done writing SPICE cards . . .\n\n")
1878 ;;  Now write out .END(S) of netlist, depending upon whether this schematic is a
1879 ;;  "normal schematic" or a .SUBCKT.
1881       (if (not (string=? schematic-type "normal schematic"))
1882           (begin 
1883             (spice-sdb:write-bottom-footer (string-append ".ends " model-name) port)
1884             (display "*******************************\n" port)
1885           )
1886           (spice-sdb:write-bottom-footer ".end" port)
1887       )
1891 ;;  Finally, close up and go home.
1893       (close-output-port port)
1894       (debug-spew "\nOutput file is written.  We are done.\n")
1895    )    ;; (let* ((port . . . .
1900 ;; Custom get-uref function to append ".${SLOT}" where a component
1901 ;; has a "slot=${SLOT}" attribute attached.
1903 ;; NOTE: Original test for appending the ".<SLOT>" was this:
1904 ;;   (let ((numslots (gnetlist:get-package-attribute package "numslots"))
1905 ;;        (slot-count (length (gnetlist:get-unique-slots package)))
1906 ;;     (if (or (string=? numslots "unknown") (string=? numslots "0"))
1908 (define get-uref
1909   (lambda (object)
1910     (let ((real_uref (gnetlist:get-uref object)))
1911       (if (null? (get-attrib-value-by-attrib-name object "slot"))
1912         real_uref
1913         (string-append real_uref "."
1914           (car (get-attrib-value-by-attrib-name object "slot")))
1915       )
1916     )
1917   )