;;-------------------------------------------------------------------------------------------------- ;; gnet-spice-msw.scm ;; -------------------- ;; Description : gEDA - GPL Electronic Design Automation ;; gnetlist - gEDA Netlist ;; gnet-spice-msw.scm - gnetlist SPICE backend ;; Last Update : Refer to version string declaration ;; Authors : Copyright (C) 1998-2010 Ales Hvezda ;; Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) ;; SPICE netlist backend written by S. Gieltjes. ;; Modified by W. Kazubski to use scaling parameters for devices other than MOSFETS. ;; Hacked by SDB (Stuart Brorson) to support advanced SPICE netlist generation. ;; Refactoring and debugging by Mike Waters (2016). ;;-------------------------------------------------------------------------------------------------- ;; This program is free software; you can redistribute it and/or modify it under the terms of the ;; GNU General Public License as published by the Free Software Foundation; either version 2 of the ;; License, or (at your option) any later version. ;; ;; This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without ;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;; General Public License for more details. ;;-------------------------------------------------------------------------------------------------- ;; New Features : ;; ;; 1. Program is now case insensitive. ;; 2. Refactored code to make it more readable eg. matched indenting of matching parenthesis. ;; 3. In verbose mode the debug spew has been tidied up. ;; 4. Documentation of procedure argument list and return values where appropriate. ;; 5. Documentation of program call options. ;; 6. Fixed a bug where JFETs could be identified as unknown components. ;; 7. Removed unnecessary procedures eg. "write-footer" and "empty-string?". ;; 8. Inserted the contents of spice-common.scm in this file. Easier to debug and maintain. ;; 9. Extend nomunge_mode to include all components eg. resistor, capacitors, etc. ;; 10. Add support for current controlled switches. ;; 11. Procedure "get-file-type" now only stops before EOF if it encounters a .SUBCKT or .MODEL line. ;;-------------------------------------------------------------------------------------------------- ;; Usage : ;; ;; 1. Invoke this guile backend from gnetlist : ;; gnetlist -g spice-msw -o circuit.ckt circuit.sch ;; 2. Send command line arguments to the guile backend : ;; gnetlist -O -O -g spice-msw circuit.sch ;; 2. Send the gnetlist output to standard out : ;; gnetlist -g spice-msw -o - circuit.sch ;; ;; Options : ;; ;; include_mode - Enable .INCLUDE directives instead of inserting file contents eg. for model files ;; nomunge_mode - Enable testing of package prefix and prepending the correct prefix if required ;; sort_mode - Enable sorting of packages alphabetically according to refdes's ;; embedd_mode - Enable inserting of file contents when a .INCLUDE directive is encountered ;; no_end_mode - Disable appending of .END or .ENDS directives at the end of the netlist file ;;-------------------------------------------------------------------------------------------------- ;; Organization : ;; ;; - The program entry point is at the top of the file. ;; - High-level functions which control program flow. ;; - Functions for program housekeeping, handling of calling flags, file manipulation. ;; - Functions for handling nets & devices and creating SPICE cards. ;;-------------------------------------------------------------------------------------------------- ;; Things To Do : ;; ;; 2016-10-24 The Josephson Junction procedure "write-joseph-jn" uses the prefix B for the refdes ;; but in SPICE this is the prefix for a non-linear dependent source. ;; 2016-09-08 Search for "???" to find locations needing attention ;;-------------------------------------------------------------------------------------------------- ;; Change Log : ;; ;; 2016-11-05 Removed unecessary space characters from component definition lines in netlist ;; 2016-09-08 Procedure "get-file-type" now overlooks SPICE .DIRECTIVE commands (eg. .PARAM) and ;; only stop before EOF if it encounters a .SUBCKT or .MODEL line. ;; 2016-10-24 Extend procedure "write-def-cmpnt" to include as many components as possible. ;; 2016-10-24 Removed procedure "get-cmpnt-value", it didn't do enough to justify it's existence. ;; 2016-10-23 Drop support for Guile 1.8.x (gnetlist has dropped support for it). ;; 2016-10-22 Removed procedure "write-footer", unnecessary obfuscation. ;; 2016-10-21 Dropped case sensitivity by using string-ci? instead of string? when testing strings. ;; 2016-10-20 Document procedure argument lists and return values ;; 2016-10-20 Moved to a case insensitive model. This backend should now be less finicky. ;; 2016-10-16 Move the script entry point to the top of the file (seems more logical to me). ;; 2016-09-17 Refactor code : choose more readable procedure names where necessary. ;; 2016-09-17 Removed procedure "component-model" as it wasn't used. ;; 2016-09-17 Removed procedure "component-optional-value" as it wasn't used. ;; 2016-09-16 Insert contents of spice-common.scm in this file. Easier to debug. ;; 2016-09-12 Removed procedure "empty-string?" and replaced it with call to builtin "string-null?" ;; 2016-09-10 Refactor code : use short hand procedure definitions (remove lambda lines), ;; 2016-09-10 Refactor code : match indenting of matched parenthesis. ;; 2016-09-10 Refactor code : general tidy up of file formatting. ;;-------------------------------------------------------------------------------------------------- ;; Define modules needed by this program (use-modules (ice-9 rdelim)) ;;(use-modules (srfi srfi-1)) ;; This is needed to make guile 1.8.x happy ;;-------------------------------------------------------------------------------------------------- ;; Get the current version of this Guile script. ;; ;; Note : This procedure definition is to get the version string at the top of the file ;; ;; Return Values : ;; The current version string. (define version "2016-11-06") ;;************************************************************************************************** ;;* * ;;* Program Entry Point * ;;* * ;;************************************************************************************************** ;;-------------------------------------------------------------------------------------------------- ;; Spice netlist generation entry point. ;; ;; The algorithm is as follows : ;; ;; 1. Determine if there's a .SUBCKT block in the schematic or if it is just a normal schematic. ;; If there's a .SUBCKT block : ;; - Write out subcircuit header (a comment identifying the netlister). ;; - Find all spice-IO pins. Get a list of the packages. ;; - Put them in order (ordered by package refdes) ;; - Get the list of nets attached to the spice-IO pins. ;; - Write out .SUBCKT line ;; If a normal schematic : ;; - Write out top header (a comment identifying the netlister). ;; 2. Loop through all components looking for components with a "file" attribute. Every time a ;; "file" attribute is found : ;; - Open the file and find out what kind of file it is (.SUBCKT or .MODEL). ;; - Determine if the file has previously been processed. If not stick the following info. ;; into the file-info list : (model-name file-name file-type), otherwise just continue. ;; 3. Loop through all components again, and write out a SPICE card for each. ;; 4. Afterwards, for each item in the file-info list, open the file and write it's contents into ;; the netlist. ;; 5. If the schematic type is .SUBCKT : write out .ENDS otherwise write out .END ;; 6. Close the SPICE netlist file and return. ;; ;; Argument List : ;; netlist-filename - The name of the SPICE netlist file (define (spice-msw netlist-filename) ;; Send the script output to the SPICE netlist file (set-current-output-port (gnetlist:output-port netlist-filename)) (let* ( (schem-type (spice-msw:get-schem-type packages)) (model-name (substring schem-type 8 (string-length schem-type))) (file-list (list)) ) (message "Running the SPICE backend to gnetlist :\n\n") ;; First decide if this is a .SUBCKT lower level, or if it is a regular schematic (if (string=? schem-type "normal schematic") ;; This is a regular schematic (begin (debug-spew "Found a normal type schematic\n\n") (display (string-append "* " (gnetlist:get-command-line) "\n")) (spice-msw:write-netlist-header) ) ;; This is a .SUBCKT type schematic (let* ( (io-pin-packages (spice-msw:get-spice-io-pins packages (list))) (io-pin-packages-ordered (spice-msw:sort-spice-io-pins io-pin-packages)) (io-nets-list (spice-msw:get-io-nets io-pin-packages-ordered (list))) ) ;; The procedure "debug-spew" is defined in : gnetlist.scm (debug-spew "Found a .SUBCKT type schematic\n\n") ;; Write out a .SUBCKT header and .SUBCKT line (spice-msw:write-subcircuit-header) (let ( (io-nets-string (list-2-string io-nets-list)) ) (display (string-append schem-type " " io-nets-string "\n")) ) ) ) ;; Search all the devices and compile a file list from all the "file" attributes (debug-spew "Make first pass through design and create list of all model files referenced :\n") (set! file-list (spice-msw:create-file-list packages file-list)) (debug-spew "\nDone creating file-list\n\n") ;; Loop through the file list and write the file contents or a reference to it to the netlist (debug-spew "Now process the items in the model file list :\n") (spice-msw:process-files file-list) (debug-spew "Done processing items in the model file list\n\n") ;; Write components to the netlist file (sorting components if required) (debug-spew "Make second pass through design and write out a SPICE card for each component found :\n") (if (calling-flag? "sort_mode" (gnetlist:get-calling-flags)) (spice-msw:write-netlist file-list (sort packages spice-msw:package-sort)) ;; Sort on refdes (spice-msw:write-netlist file-list packages) ;; Don't sort ) (debug-spew "\n") ;; Write .END(S) of netlist, depending upon whether schematic is a "normal schematic" or .SUBCKT (if (not (string=? schem-type "normal schematic")) (display (string-append ".ENDS " model-name "\n")) (if (not (calling-flag? "no_end_mode" (gnetlist:get-calling-flags))) (display ".END\n") ) ) ) (debug-spew "\nDone writing SPICE cards\n\n") ;; Finally, close the netlist file (close-output-port (current-output-port)) ) ;;************************************************************************************************** ;;* * ;;* High-level functions for program control * ;;* * ;;************************************************************************************************** ;;-------------------------------------------------------------------------------------------------- ;; Determine the schematic type ie. a normal schematic or a .SUBCKT lower level. ;; ;; Search for a "spice-subcircuit-LL" device instantiated somewhere in the schematic. If it is a ;; .SUBCKT return ".SUBCKT model-name" else return "normal schematic". ;; ;; Argument List : ;; package-list - A list of package (component) labels (refdes's) (define (spice-msw:get-schem-type package-list) (if (not (null? package-list)) (let* ( (package (car package-list)) (device (gnetlist:get-package-attribute package "device")) ) (if (string-ci=? device "SPICE-SUBCIRCUIT-LL") ;; Look for a subcircuit label (string-append ".SUBCKT " (gnetlist:get-package-attribute package "model-name")) (spice-msw:get-schem-type (cdr package-list)) ;; Iterate to the next package ) ) "normal schematic" ) ) ;;-------------------------------------------------------------------------------------------------- ;; This function takes as argument the list of packages (refdes's). It runs through the package ;; list, and for each gets the attributes. If there is a "FILE" attribute, it gets the file info & ;; uses it to build the file-list. When done, it returns the file-list. ;; ;; Argument List : ;; package-list - A list of package (component) labels (refdes's) ;; file-list - A list of files referred to in the schematic file (define (spice-msw:create-file-list package-list file-list) (if (null? package-list) file-list ;; Return the file-list (let* ( (package (car package-list)) ;; Get the next package (ie. refdes) (device (string)) (model (string)) (value (string)) (model-file (string)) ) (set! device (gnetlist:get-package-attribute package "device") ) (set! model (gnetlist:get-package-attribute package "model-name") ) (set! value (gnetlist:get-package-attribute package "value") ) (set! model-file (gnetlist:get-package-attribute package "file") ) ;; Now run a series of checks to see if we should stick this file into the file-list ;; Check to see if "file" attribute is non-empty (if (not (string-ci=? model-file "unknown")) (begin (debug-spew "\n spice-msw:create-file-list : ") (debug-spew (string-append "Found file attribute for package " package " = " model-file "\n")) ;; Now check if the file is already in the file-list (if (not (spice-msw:in-file-list? model-file file-list)) ;; File is new, open it and find out what type it is (let ( (file-type (spice-msw:get-file-type model-file)) ) (debug-spew " spice-msw:create-file-list : ") (debug-spew (string-append "File is not in the list and has type " file-type "\n")) ;; Check to see if file-type is known. (if (not (string-ci=? file-type "OTHER")) (begin (debug-spew " spice-msw:create-file-list : Adding it to the list of model files\n") (set! file-list (append (list (list model model-file file-type)) file-list) ) ) (debug-spew " spice-msw:create-file-list : File type is OTHER so ignore it\n") ) ) ;; File is already in list. Print debug spew if desired. (debug-spew " spice-msw:create-file-list : File is already in the model file list.\n") ) ) ) ;; having done checking and processing of this package, iterate to the next one. (spice-msw:create-file-list (cdr package-list) file-list) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; This is a helper function which returns #t if a file is already in file-list, otherwise #f. ;; ;; Note : It is assumed that file-list is of the form : ;; ( (model1 file-name1 file-type1) (model2 file-name2 file-type2) . . . . ) ;; ;; Argument List : ;; file-name - The file name to search for ;; file-list - The list of file info. to search ;; ;; Return Values : ;; Success - #t (the file was found in the list) ;; Failure - #f (the file wasn't found in the list) (define (spice-msw:in-file-list? file-name file-list) (if (null? file-list) #f ;; file-list is empty (let ( (list-element (car file-list)) ) ;; Get a list element and process it (if (null? list-element) #f ;; list-element is empty (should never get here) (let ( (list-file-name (cadr list-element)) ) (if (string=? list-file-name file-name) #t ;; file-name was found in file-list (spice-msw:in-file-list? file-name (cdr file-list)) ;; Iterate . . . ) ) ) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Search a file and determine it's type based on it's contents. ;; ;; Note : The function opens input-file and closes it when it is done. ;; ;; Argument List : ;; file-name - The file to test ;; ;; Return Values : ;; ".MODEL" - The file contains a model ;; ".SUBCKT" - The file contains a sub-circuit ;; "OTHER" - The file is neither of the above (define (spice-msw:get-file-type file-name) (if (file-exists? file-name) (let ( (in-file (open-input-file file-name)) ) (let while ( (file-line (read-line in-file)) ) (cond ((eof-object? file-line) ;; Arrived at end of line without finding .MODEL or .SUBCKT "OTHER" ) ((string-null? file-line) ;; Found empty line, iterate before doing anything else (while (read-line in-file)) ) ((string=? (string (string-ref file-line 0)) "*") ;; Found comment, iterate (while (read-line in-file)) ) ((string=? (string (string-ref file-line 0)) ".") ;; The first char is a '.' (begin (cond ((string-ci=? (safe-string-head file-line 7) ".SUBCKT") ;; Found .SUBCKT line ".SUBCKT" ) ((string-ci=? (safe-string-head file-line 6) ".MODEL") ;; Found .MODEL line ".MODEL" ) (else (while (read-line in-file)) ) ) ) ) (else (while (read-line in-file)) ) ) ) ) (begin (message (string-append "ERROR: File '" file-name "' not found.\n")) (primitive-exit 1) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Take a list and turns it into a string. ;; ;; The difference between this and list->string is that this function can handle lists made up of ;; multi-char strings. ;; ;; Argument List : ;; str-list - A list of strings (define (list-2-string str-list) (let while ( (st (string)) (local-list str-list) ) (if (null? local-list) st ;; end iteration & return string if list is empty. (begin ;; otherwise turn next element of list into string. . . (set! st (string-append (car local-list) " " st)) ;; stuff next element onto st (while st (cdr local-list)) ;; iterate with remainder of ls ) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write out spice netlist header. (define (spice-msw:write-netlist-header) (display "**************************************************\n") (display "* SPICE file generated by gnetlist *\n") (display (string-append "* using spice-msw (" version ") backend *\n")) (display "**************************************************\n\n") ) ;;-------------------------------------------------------------------------------------------------- ;; Write out .SUBCKT netlist header. (define (spice-msw:write-subckt-header) (display "*************************************\n") (display "* Begin .SUBCKT model *\n") (display "*************************************\n") ) ;;************************************************************************************************** ;;* * ;;* Program housekeeping, handling calling flags, file manipulation * ;;* * ;;************************************************************************************************** ;;-------------------------------------------------------------------------------------------------- ;; Loop through the model-file list looking for a triplet corresponding to a particular model-name. ;; ;; Argument List : ;; model-name - The model name being sort ;; file-list - A list of files referred to in the schematic file ;; ;; Return Values : ;; Success - The file list item associated with the model name ;; Failure - #f (define (spice-msw:get-file-list-item model-name file-list) (if (null? file-list) (quote #f) (let* ( (list-item (car file-list)) (item-model-name (car list-item)) (item-file-name (cadr list-item)) (item-file-type (caddr list-item)) ) (if (string-ci=? item-model-name model-name) list-item ;; Found model-name (spice-msw:get-file-list-item model-name (cdr file-list)) ;; Keep looking ) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Loop through the model file list and for each file invoke handle-spice-file. ;; ;; Argument List : ;; file-list - A list of files referred to in the schematic file (define (spice-msw:process-files file-list) (if (not (null? file-list)) (let* ( (list-element (car file-list)) (model-name (car list-element)) (file-name (cadr list-element)) (file-type (caddr list-element)) ) (spice-msw:process-spice-file file-name) (spice-msw:process-files (cdr file-list)) ) (display "\n") ) ) ;;-------------------------------------------------------------------------------------------------- ;; This wraps insert-text-file. ;; ;; If "include_mode" has been enabled just write an .INCLUDE card with the file name. If not it ;; call insert-text-file to insert the file's contents into the SPICE netlist. ;; ;; Argument List : ;; file-name - The file name to be processed (define (spice-msw:process-spice-file file-name) (debug-spew (string-append "\n spice-msw:process-spice-file : " file-name "\n")) (if (calling-flag? "include_mode" (gnetlist:get-calling-flags)) (display (string-append ".INCLUDE " file-name "\n")) ;; Use .INCLUDE card (spice-msw:insert-text-file file-name) ;; Insert file contents ) ) ;;-------------------------------------------------------------------------------------------------- ;; Open a file, get the contents and insert it into the SPICE file. ;; ;; This function is usually used to include SPICE models contained in files into the netlist. ;; ;; Argument List : ;; file-name - The name of the file (define (spice-msw:insert-text-file file-name) (if (file-exists? file-name) (let ( (in-file (open-input-file file-name)) ) (display (string-append "* Include SPICE model file : " file-name "\n") ) (let while ((line (read-line in-file))) (if (not (eof-object? line)) (begin (display (string-append line "\n")) (while (read-line in-file)) ) ) ) (close-port in-file) (newline) ) (begin (message (string-append "ERROR: File '" file-name "' not found.\n")) (primitive-exit 1) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Iterate through the schematic and compile a list of all SPICE-IO pins found. This is used when ;; writing out a .SUBCKT lower level netlist. ;; ;; Argument List : ;; package-list - A list of package (component) labels (refdes's) ;; ;; Return Values : ;; spice-io-pin-list - A list of the SPICE-IO pins (define (spice-msw:get-spice-io-pins package-list spice-io-pin-list) (if (null? package-list) spice-io-pin-list (let* ( (package (car package-list)) (device (gnetlist:get-package-attribute package "device")) ) (if (string-ci=? device "SPICE-IO") ;; Look for subcircuit label ;; Found a spice-IO pin. (spice-msw:get-spice-io-pins (cdr ls) (cons package spice-io-pin-list)) ;; No spice-IO pin found. Iterate . . . . (spice-msw:get-spice-io-pins (cdr ls) spice-io-pin-list) ) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; This takes the list of io-pin-packages and sorts it in order of refdes. ;; ;; Argument List : ;; package-list - A list of package (component) labels (refdes's) (define (spice-msw:sort-spice-io-pins package-list) ;; Yes, this isn't good Scheme form. Tough! Writing this out in a functional programming form ;; would be totally confusing! Note that this function requires that each spice-IO pin have the ;; same, single character prefix (i.e. 'P') (let* ( (char-prefixes (map car (map string->list package-list))) ;; Pull off first char (prefix) (prefixes (map string char-prefixes)) ;; Make list of strings from prefixes (split-numbers-list (map cdr (map string->list package-list))) ;; Pull off refdes numbers as list elements (string-numbers-list (map list->string split-numbers-list)) ;; Recombine split up (multidigit) number strings (numbers-list (map string->number string-numbers-list)) ;; Convert strings to numbers for sorting (sorted-numbers-list (sort numbers-list <)) ;; Sort refdes numbers as numbers (sorted-string-numbers-list (map number->string sorted-numbers-list)) ) ;; Create sorted list of refdes strings. (map-in-order string-append prefixes sorted-string-numbers-list) ;; Laminate prefixes back onto refdes numbers & return. ) ) ;;-------------------------------------------------------------------------------------------------- ;; Given a list of spice-IO packages (refdes's), return the list of nets attached to the IOs. ;; ;; Argument List : ;; package-list - A list of package (component) labels (refdes's) ;; ;; Return Values : ;; net-list - A list of nets (define (spice-msw:get-io-nets package-list net-list) (if (null? package-list) net-list ;; End iteration & return net-list if ls is empty. (let* ( (package (car package-list)) ;; otherwise process package. . . (net (car (gnetlist:get-nets package "1"))) ) ;; get the net attached to pin 1 ;; Now iterate (spice-msw:get-io-nets (cdr package-list) (cons net net-list)) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write netnames connected to pin-a and pin-b. ;; ;; Currently used by the controlled sources eg. f and h. ;; ;; Argument List : ;; package - The refdes of a component eg. R1 ;; pin-a - The name of pin-a ;; pin-b - The name of pin-b (define (spice-msw:write-two-pin-names package pin-a pin-b) (display (string-append (car (spice-msw:get-net package (gnetlist:get-attribute-by-pinseq package pin-a "pinnumber"))) " ")) (display (string-append (car (spice-msw:get-net package (gnetlist:get-attribute-by-pinseq package pin-b "pinnumber"))) " ")) ) ;;-------------------------------------------------------------------------------------------------- ;; Write all listed and available attributes in the form of =. ;; ;; Argument List : ;; package - The refdes of a component eg. R1 ;; attrib-list - A list of attributes (define (spice-msw:write-attrib-list package attrib-list) (if (not (null? attrib-list)) (let ( (attrib (gnetlist:get-package-attribute package (car attrib-list))) ) (if (not (string-ci=? attrib "unknown")) (display (string-append " " (car attrib-list) "=" attrib)) ) (spice-msw:write-attrib-list package (cdr attrib-list)) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; A replacement of the procedure gnetlist:get-nets. A net labeled "GND" becomes 0. ;; ;; Argument List : ;; package - The refdes of a component eg. R1 ;; pin-name - The component pin name connected to the net (define (spice-msw:get-net package pin-name) (let ( (net-name (gnetlist:get-nets package pin-name)) ) (cond ((string-ci=? (car net-name) "GND") (cons "0" #t)) (else (cons (car net-name) #t)) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Sort procedure to order refdes's alphabetically but keep A? packages at the end of the list so ;; SPICE simulation directives operate correctly. ;; ;; This function was written by Ken Healy to facilitate SPICE netlisting for GNU-CAP, which wants A? ;; refdes cards (ie. SPICE directives) to appear last in the SPICE netlist. ;; ;; Argument List : ;; x - First item to compare ;; y - Second item to compare (define (spice-msw:package-sort x y) (define (string-tail string start) (substring string start (string-length string))) (let ( (xdes (string-ref x 0)) (ydes (string-ref y 0)) (xnum (string-tail x 1)) (ynum (string-tail y 1)) ) (if (char-ci=? xdes ydes) (if (string-ci in this case so that the ;; SPICE simulator will barf if the user has been careless). ;; M? -- Same as Q. ;; U? -- Invoke write-ic. This provides the opportunity for a component model to be ;; instantiated. ;; X? -- Invoke write-ic. This provides the opportunity for a component subcircuit to be ;; instantiated. ;; V? -- Invoke write-ivs. ;; I? -- Invoke write-ics. ;; 3. Otherwise, just output the refdes, the attached nets and the "value" attribute. ;; ;; Argument List : ;; package - The refdes of a component eg. R1 ;; device - The device attribute value for the package ;; file-list - A list of files referred to in the schematic file (define (spice-msw:write-def-cmpnt package device file-list) (let ( (first-char (string (string-ref package 0))) ) ;; Extract first char of refdes (cond ((string-ci=? first-char "A") (spice-msw:write-ic package file-list)) ((string-ci=? first-char "C") (spice-msw:write-capacitor package)) ((string-ci=? first-char "D") (spice-msw:write-diode package)) ((string-ci=? first-char "E") (spice-msw:write-vcvs package)) ((string-ci=? first-char "F") (spice-msw:write-cccs package)) ((string-ci=? first-char "G") (spice-msw:write-vccs package)) ((string-ci=? first-char "H") (spice-msw:write-ccvs package)) ((string-ci=? first-char "I") (spice-msw:write-ics package)) ((string-ci=? first-char "J") (spice-msw:write-component package #f "" (list))) ((string-ci=? first-char "K") (spice-msw:write-coupled-ind package)) ((string-ci=? first-char "L") (spice-msw:write-inductor package)) ((string-ci=? first-char "M") (spice-msw:write-component package #f "" (list))) ((string-ci=? first-char "Q") (spice-msw:write-component package #f "" (list))) ((string-ci=? first-char "R") (spice-msw:write-resistor package)) ((string-ci=? first-char "S") (spice-msw:write-vc-switch package)) ((string-ci=? first-char "M") (spice-msw:write-component package #f "" (list))) ((string-ci=? first-char "U") (spice-msw:write-ic package file-list)) ((string-ci=? first-char "V") (spice-msw:write-ivs package)) ((string-ci=? first-char "W") (spice-msw:write-cc-switch package)) ((string-ci=? first-char "X") (spice-msw:write-ic package file-list)) ((string-ci=? first-char "Z") (spice-msw:write-mesfet package)) (else (debug-spew " spice-msw:write-def-cmpnt : ") (debug-spew (string-append "Found unknown device " device "\n")) (spice-msw:write-refdes-nets package) (display (gnetlist:get-package-attribute package "value")) (newline) ) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write out component followed by model or model file associated with the component. ;; ;; This function does the following : ;; 1. Writes out the correct refdes prefix (if specified and necessary). ;; 2. Writes out the refdes and nets ;; 3. Looks for "model-name" attribute. Writes it out if it exists. ;; 4. If there is no "model-name" attribute, it writes out the "value" attribute. If there is no ;; "value" attribute, it writes out "unknown" and returns, causing the spice simulator to puke ;; when the netlist is run. This is important because the spice simulator needs to have some ;; indication of what model to look for. ;; 5. Outputs optional attributes attached to device, if any. ;; 6. Outputs a new line ;; 7. Looks for a "model" attribute. If it exists, it writes a .MODEL line like : ;; .MODEL model-name type ( model ) ;; ;; Argument List : ;; package - The refdes of a component eg. Q1 ;; prefix - The correct refdes prefix for this package type ;; type - The SPICE model type eg. NPN or JFT ;; attrib-list - A list of attributes for the package (define (spice-msw:write-component package prefix type attrib-list) (let ( (model-name (gnetlist:get-package-attribute package "model-name")) (model (gnetlist:get-package-attribute package "model" )) (value (gnetlist:get-package-attribute package "value" )) (area (gnetlist:get-package-attribute package "area" )) (off (gnetlist:get-package-attribute package "off" )) (model-file (gnetlist:get-package-attribute package "file" )) ) ;; Write out the refdes prefix, if required (if prefix (spice-msw:write-prefix package prefix) ) ;; Next we write out the refdes and nets. (spice-msw:write-refdes-nets package) ;; Look for "model-name" attribute. Write it out if it exists otherwise look for "value" attribute (if (not (string-ci=? model-name "unknown")) (display model-name) ;; Display the model-name (display value) ;; Otherwise display the value ) ;; Next write out attributes if they exist ;; First attribute is area. It is written as a simple string (if (not (string-ci=? area "unknown")) (display (string-append " " area)) ) ;; Next attribute is off. It is written as a simple string (if (not (string-ci=? off "unknown")) (display (string-append " " off)) ) ;; Write out remaining attributes (spice-msw:write-attrib-list package attrib-list) ;; Now write out newline in preparation for writing out model. (newline) ;; Now write out any model which is pointed to by the part. (cond ;; One line model and model name exist ( (not (or (string-ci=? model "unknown") (string-ci=? model-name "unknown"))) (begin (debug-spew " spice-msw:write-component : ") (debug-spew (string-append "Found model and model-name for " package "\n")) ) (display (string-append ".MODEL " model-name " " type " (" model ")\n")) ) ;; One line model and component value exist ( (not (or (string-ci=? model "unknown") (string-ci=? value "unknown"))) (begin (debug-spew " spice-msw:write-component : ") (debug-spew (string-append "Found model and value for " package "\n")) ) (display (string-append ".MODEL " model-name " " type " (" value ")\n")) ) ;; Model file and model name exist ( (not (or (string-ci=? model-file "unknown") (string-ci=? model-name "unknown"))) (begin (debug-spew " spice-msw:write-component : ") (debug-spew (string-append "Found file and model-name for " package "\n")) ) ) ;; Model file and component value exist ( (not (or (string-ci=? model-file "unknown") (string-ci=? value "unknown"))) (begin (debug-spew " spice-msw:write-component : ") (debug-spew (string-append "Found file and value for " package "\n")) ) ) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a diode. ;; ;; Write out a valid diode refdes & then call the function which writes the rest of the line. ;; ;; Argument List : ;; package - The refdes of a component eg. D1 (define (spice-msw:write-diode package) (debug-spew " spice-msw:write-diode : Found a diode\n") (let ( (attrib-list (list "IC" "TEMP")) ) (spice-msw:write-component package "D" "D" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write out a valid IC or sub-circuit line. ;; ;; The algorithm is as follows : ;; 1. Figure out what type of model goes with this part from file-list. If it isn't listed ;; look for a MODEL attribute. If a MODEL attribute is attached write out SPICE card and then ;; write out .MODEL on next line. If no MODEL attribute is attached just write out what little ;; we know then return. ;; 2. If the model-name is in the file-list, get the associated file-type. Compare it against ;; the component's refdes. If model-type is .MODEL or .SUBCKT and refdes doesn't begin with a U ;; or X respectively, prepend the correct prefix to the refdes. ;; 3. Print out the rest of the line. ;; ;; Argument List : ;; package - The refdes of a component eg. U1 ;; file-list - A list of files referred to in the schematic file (define (spice-msw:write-ic package file-list) ;; First do local assignments (let ( (first-char (string (string-ref package 0))) ;; extract first char of refdes (model-name (gnetlist:get-package-attribute package "model-name")) (model (gnetlist:get-package-attribute package "model")) (value (gnetlist:get-package-attribute package "value")) (type (gnetlist:get-package-attribute package "type")) (model-file (gnetlist:get-package-attribute package "file")) (list-item (list)) ) (cond ( (string-ci=? first-char "U") (debug-spew " spice-msw:write-ic : Found a Integrated Circuit\n") ) ( (string-ci=? first-char "X") (debug-spew " spice-msw:write-ic : Found a Sub-Circuit\n") ) ) ;; First, if model-name is empty, we use value attribute instead. ;; We do this by sticking the contents of "value" into "model-name". (if (string-ci=? model-name "unknown") (set! model-name value) ) ;; Now get item from file-list using model-name as key (set! list-item (spice-msw:get-file-list-item model-name file-list) ) ;; Check if list-item is null (if (or (null? list-item) (eq? list-item #f)) ;; list-item is null. Evidently, we didn't discover any files holding this model. ;; Instead we look for model attribute (if (not (string-ci=? model "unknown")) (begin ;; Model attribute exists, write card and model (debug-spew " spice-msw:write-ic : ") (debug-spew "Model info not found in model file list, but model attribute exists, write out spice card and .MODEL line\n") (spice-msw:write-refdes-nets package) (display (string-append model-name "\n" )) (display (string-append ".MODEL " model-name " ")) (if (not (string-ci=? type "unknown")) (display (string-append type " ")) ) ;; If no type then just skip it. (display (string-append "(" model ")\n")) ) (begin ;; No model attribute either, just write out card (debug-spew " spice-msw:write-ic : ") (debug-spew "Model info not found in model file list, no model attribute either\n") (spice-msw:write-refdes-nets package) (display (string-append model-name "\n" )) ) ) ;; list-item is not null. Therefore we process line depending upon contents of list-item (let ( (file-type (caddr list-item)) ) (cond ;; File contains a model ((string-ci=? file-type ".MODEL") (begin (debug-spew " spice-msw:write-ic : ") (debug-spew (string-append "Found .MODEL with model-file and model-name for " package "\n")) (spice-msw:write-prefix package "U") ;; Write out the refdes prefix, if required (spice-msw:write-refdes-nets package) (display (string-append model-name "\n" )) ) ) ;; File contains a subcircuit ((string-ci=? file-type ".SUBCKT") (begin (debug-spew " spice-msw:write-ic : ") (debug-spew (string-append "Found .SUBCKT with model-file and model-name for " package "\n")) (spice-msw:write-prefix package "X") ;; Write out the refdes prefix, if required (spice-msw:write-refdes-nets package) (display (string-append model-name "\n" )) ) ) ) ) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write an NPN bipolar transistor. ;; ;; Write a valid transistor refdes & then call the function which writes the rest of the line. ;; ;; Argument List : ;; package - The refdes of a component eg. Q1 (define (spice-msw:write-npn package) (debug-spew " spice-msw:write-npn : Found a NPN Bipolar Transistor\n") (let ( (attrib-list (list "IC" "TEMP")) ) (spice-msw:write-component package "Q" "NPN" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a PNP bipolar transistor. ;; ;; Argument List : ;; package - The refdes of a component eg. Q1 (define (spice-msw:write-pnp package) (debug-spew " spice-msw:write-pnp : Found a PNP Bipolar Transistor\n") (let ( (attrib-list (list "IC" "TEMP")) ) (spice-msw:write-component package "Q" "PNP" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write an N-channel JFET transistor. ;; ;; Argument List : ;; package - The refdes of a component eg. J1 (define (spice-msw:write-nfet package) (debug-spew " spice-msw:write-nfet : Found a N-channel JFET\n") (let ( (attrib-list (list "IC" "TEMP") )) (spice-msw:write-component package "J" "NJF" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a P-channel JFET transistor. ;; ;; Argument List : ;; package - The refdes of a component eg. J1 (define (spice-msw:write-pfet package) (debug-spew " spice-msw:write-pfet : Found a P-channel JFET\n") (let ( (attrib-list (list "IC" "TEMP")) ) (spice-msw:write-component package "J" "PJF" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a PMOS transistor. ;; ;; Argument List : ;; package - The refdes of a component eg. M1 (define (spice-msw:write-pmos package) (debug-spew " spice-msw:write-pmos : Found a PMOS Transistor\n") (let ( (attrib-list (list "L" "W" "AS" "AD" "PD" "PS" "NRD" "NRS" "TEMP" "IC" "M")) ) (spice-msw:write-component package "M" "PMOS" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a NMOS transistor. ;; ;; Argument List : ;; package - The refdes of a component eg. M1 (define (spice-msw:write-nmos package) (debug-spew " spice-msw:write-nmos : Found a NMOS Transistor\n") (let ( (attrib-list (list "L" "W" "AS" "AD" "PD" "PS" "NRD" "NRS" "TEMP" "IC" "M")) ) (spice-msw:write-component package "M" "NMOS" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a subckt PMOS transistor. ;; ;; Argument List : ;; package - The refdes of a component eg. X1 (define (spice-msw:write-pmos-subckt package) (debug-spew " spice-msw:write-pmos-subckt : Found a PMOS Transistor sub-circuit\n") (let ( (attrib-list (list "L" "W" "AS" "AD" "PD" "PS" "NRD" "NRS" "TEMP" "IC" "M")) ) (spice-msw:write-component package "X" "PMOS" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a subckt NMOS transistor. ;; ;; Argument List : ;; package - The refdes of a component eg. X1 (define (spice-msw:write-nmos-subckt package) (debug-spew " spice-msw:write-nmos-subckt : Found a NMOS Transistor sub-circuit\n") (let ( (attrib-list (list "L" "W" "AS" "AD" "PD" "PS" "NRD" "NRS" "TEMP" "IC" "M")) ) (spice-msw:write-component package "X" "NMOS" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a MESFET transistor. ;; ;; Argument List : ;; package - The refdes of a component eg. Z1 (define (spice-msw:write-mesfet package) (debug-spew " spice-msw:write-mesfet : Found a MESFET Transistor\n") (let ( (attrib-list (list "IC")) ) (spice-msw:write-component package "Z" "MESFET" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a voltage controled switch. ;; ;; Argument List : ;; package - The refdes of a component eg. S1 (define (spice-msw:write-vc-switch package) (debug-spew " spice-msw:write-vc-switch : Found a Voltage Controlled Switch\n") (let ( (attrib-list (list " ")) ) (spice-msw:write-component package "S" "SW" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a current controled switch. ;; ;; Argument List : ;; package - The refdes of a component eg. W1 (define (spice-msw:write-cc-switch package) (debug-spew " spice-msw:write-cc-switch : Found a Voltage Controlled Switch\n") (let ( (attrib-list (list " ")) ) (spice-msw:write-component package "W" "CSW" attrib-list) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a resistor. ;; ;; Argument List : ;; package - The refdes of a component eg. R1 (define (spice-msw:write-resistor package) (debug-spew " spice-msw:write-resistor : Found a Resistor\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "R") ;; First write out refdes and attached nets (spice-msw:write-refdes-nets package) ;; Next write mandatory resistor value if it exists. (let ( (value (gnetlist:get-package-attribute package "value")) ) (if (not (string-ci=? value "unknown")) (display value) ) ) ;; Next write our model name if it exists (let ( (model-name (gnetlist:get-package-attribute package "model-name"))) (if (not (string-ci=? model-name "unknown")) (display (string-append " " model-name)) ) ) ;; next create list of attributes which can be attached to a resistor. ;; I include non-standard "area" attrib here per popular demand. (let ((attrib-list (list "AREA" "L" "W" "TEMP"))) (spice-msw:write-attrib-list package attrib-list) ;; write the attributes (if any) separately ) ;; finally output a new line (newline) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a capacitor. ;; ;; Argument List : ;; package - The refdes of a component eg. C1 (define (spice-msw:write-capacitor package) (debug-spew " spice-msw:write-capacitor : Found a Capacitor\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "C") ;; first write out refdes and attached nets (spice-msw:write-refdes-nets package) ;; next write capacitor value, if any. Note that if the ;; component value is not assigned nothing will be written out. (let ( (value (gnetlist:get-package-attribute package "value")) ) (if (not (string-ci=? value "unknown")) (display value) ) ) ;; next write capacitor model name, if any. This is applicable to ;; semiconductor caps used in chip design. (let ( (model-name (gnetlist:get-package-attribute package "model-name")) ) (if (not (string-ci=? model-name "unknown")) (display (string-append " " model-name)) ) ) ;; Next write out attributes if they exist. Use ;; a list of attributes which can be attached to a capacitor. ;; I include non-standard "area" attrib here per request of Peter Kaiser. (let ( (attrib-list (list "AREA" "L" "W" "IC")) ) (spice-msw:write-attrib-list package attrib-list) ) (newline) ) ;;-------------------------------------------------------------------------------------------------- ;; Write an inductor. ;; ;; Argument List : ;; package - The refdes of a component eg. L1 (define (spice-msw:write-inductor package) (debug-spew " spice-msw:write-inductor : Found a Inductor\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "L") ;; first write out refdes and attached nets (spice-msw:write-refdes-nets package) ;; next write inductor value, if any. Note that if the ;; component value is not assigned, then it will write "unknown" (let ( (value (gnetlist:get-package-attribute package "value")) ) (display value) ) ;; create list of attributes which can be attached to a inductor (let ( (attrib-list (list "L" "W" "IC")) ) (spice-msw:write-attrib-list package attrib-list) ) (newline) ) ;;-------------------------------------------------------------------------------------------------- ;; Write an independent voltage source. ;; ;; The behavior of the voltage source is held in the "value" attribute. ;; ;; Argument List : ;; package - The refdes of a component eg. V1 (define (spice-msw:write-ivs package) (debug-spew " spice-msw:write-ivs : Found a Independent Voltage Source\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "V") ;; First write out refdes and attached nets (spice-msw:write-refdes-nets package) ;; Next write voltage value, if any. Note that if the voltage value is not assigned, then it will ;; write "unknown". (let ( (value (gnetlist:get-package-attribute package "value")) ) (display value) ) (newline) ) ;;-------------------------------------------------------------------------------------------------- ;; Write an independent current source. ;; ;; The behavior of the current source is held in the "value" attribute ;; ;; Argument List : ;; package - The refdes of a component eg. I1 (define (spice-msw:write-ics package) (debug-spew " write-ics : Found a Independent Current Source\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "I") ;; First write out refdes and attached nets (spice-msw:write-refdes-nets package) ;; Next write current value, if any. Note that if the current value is not assigned, then it will ;; write "unknown". (let ( (value (gnetlist:get-package-attribute package "value")) ) (display value) ) (newline) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a current controlled voltage source and implement the necessary current measuring voltage ;; source. ;; ;; Argument List : ;; package - The refdes of a component eg. H1 (define (spice-msw:write-ccvs package) (debug-spew " spice-msw:write-ccvs : Found a Current Controlled Voltage Source\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "H") ;; Implement the controlled current source (display (string-append package " ")) (spice-msw:write-two-pin-names package "1" "2") (display (string-append "Vsense_" package " " (spice-msw:component-value package) "\n" )) ;; Implement the current measuring voltage source (display (string-append "Vsense_" package " ")) (spice-msw:write-two-pin-names package "3" "4") (display "DC 0\n") ;; It's possible to leave the output voltage source unconnected, SPICE won't complain about ;; unconnected nodes (display (string-append "IOut_" package " ")) (spice-msw:write-two-pin-names package "1" "2") (display "DC 0\n") ) ;;-------------------------------------------------------------------------------------------------- ;; Write a current controlled current source and implement the necessary current measuring voltage ;; source. ;; ;; Argument List : ;; package - The refdes of a component eg. F1 (define (spice-msw:write-cccs package) (debug-spew " spice-msw:write-cccs : Found a Current Controlled Current Source\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "F") ;; Implement the controlled current source (display (string-append package " ")) (spice-msw:write-two-pin-names package "1" "2") (display (string-append "Vsense_" package " " (gnetlist:get-package-attribute package "value") "\n")) ;; Implement the current measuring voltage source (display (string-append "Vsense_" package " ")) (spice-msw:write-two-pin-names package "3" "4") (display "DC 0\n") ) ;;-------------------------------------------------------------------------------------------------- ;; Write a voltage controlled current source and implement the necessary voltage measuring current ;; source. ;; ;; Argument List : ;; package - The refdes of a component eg. G1 (define (spice-msw:write-vccs package) (debug-spew " spice-msw:write-vccs : Found a Voltage Controlled Current Source\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "G") ;; Implement the controlled current source (display (string-append package " ")) (spice-msw:write-net-names package) (display (string-append (spice-msw:component-value package) "\n")) ;; Implement the voltage measuring current source ;; Imagine copying the voltage of a voltage source with an internal impedance, SPICE complains ;; about unconnected nets if this current source is not here. (display (string-append "IMeasure_" package " ")) (spice-msw:write-two-pin-names package "3" "4") (display "DC 0\n") ) ;;-------------------------------------------------------------------------------------------------- ;; Write a voltage controlled voltage source and implement the necessary voltage measuring current ;; source. ;; ;; Argument List : ;; package - The refdes of a component eg. E1 (define (spice-msw:write-vcvs package) (debug-spew " spice-msw:write-vcvs : Found a Voltage Controlled Voltage Source\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "E") ;; Implement the controlled voltage source (display (string-append package " ")) (spice-msw:write-net-names package) (display (string-append (gnetlist:get-package-attribute package "value") "\n" )) ;; Implement the voltage measuring current source ;; Imagine copying the voltage of a voltage source with an internal impedance, SPICE complains ;; about unconnected nets if this current source is not here. (display (string-append "Isense_" package " ")) (spice-msw:write-two-pin-names package "3" "4") (display "DC 0\n") ;; With an output current source it is possible to leave the output voltage source unconnected, ;; SPICE won't complain about unconnected nodes (display (string-append "IOut_" package " ")) (spice-msw:write-two-pin-names package "1" "2") (display "DC 0\n") ) ;;-------------------------------------------------------------------------------------------------- ;; Create a nullor, make sure it consists of a voltage controlled source. ;; ;; Argument List : ;; package - The refdes of a component eg. E1 (define (spice-msw:write-nullor package) (debug-spew " spice-msw:write-nullor : Found a Nullor\n") (let ( (value (gnetlist:get-package-attribute package "value")) ) ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "E") ;; Implement the controlled voltage source (display (string-append package " ")) (spice-msw:write-net-names package) (display (string-append (if (string-ci=? value "unknown") "1000Meg" value) "\n")) ;; Implement the voltage measuring current source. ;; Imagine yourself copying the voltage of a voltage source with an internal impedance, SPICE ;; complains about unconnected nets if this current source is not here. (display (string-append "IMeasure_" package " ")) (spice-msw:write-two-pin-names package "3" "4") (display "DC 0\n") ;; With an output current source it is possible to leave the output voltage source unconnected, ;; SPICE won't complain about unconnected nodes (display (string-append "IOut_" package " ")) (spice-msw:write-two-pin-names package "1" "2") (display "DC 0\n") ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a Josephson junction. ;; ;; Argument List : ;; package - The refdes of a component eg. B1 (define (spice-msw:write-joseph-jn package) (debug-spew " spice-msw:write-joseph-jn : Found a Josephson junction\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "B") ;; First write out refdes and attached nets (spice-msw:write-refdes-nets package) ;; Next, add a dummy node for JJ phase. Unlike in Xic netlister, give it ;; a reasonable name, not a number, eg. refdes (display (string-append package " ")) ;; Next write JJ model name, if any. (let ((model-name (gnetlist:get-package-attribute package "model-name"))) (if (not (string-ci=? model-name "unknown")) (display (string-append model-name " " ))) ) ;; Next write out attributes if they exist. Use a list of attributes which can be attached to a ;; junction. (spice-msw:write-attrib-list package (list "AREA")) (newline) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a coupled (mutual) inductor. ;; ;; Argument List : ;; package - The refdes of a component eg. K1 (define (spice-msw:write-coupled-ind package) (debug-spew " spice-msw:write-coupled-ind : Found a coupled (mutual) inductor\n") ;; Write out the refdes prefix, if required (spice-msw:write-prefix package "K") ;; First write out refdes and attached nets (none) (spice-msw:write-refdes-nets package) ;; Next two inductor names and value (let ( (inductors (gnetlist:get-package-attribute package "inductors")) (value (gnetlist:get-package-attribute package "value")) ) (if (not (string-ci=? inductors "unknown")) (display (string-append inductors " " ))) (if (not (string-ci=? value "unknown")) (display (string-append value " " ))) ) (newline) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a voltage probe. ;; ;; Argument List : ;; package - The refdes of a component eg. R1 (define (spice-msw:write-probe package) (debug-spew " spice-msw:write-probe : Found a probe\n") (let ((value (gnetlist:get-package-attribute package "value")) ) (if (string-ci=? value "unknown") (set! value "TRAN") ) (display (string-append "* Probe device " package " on nets ")) (spice-msw:write-net-names package) (newline) (display (string-append ".print " value " +")) (spice-msw:write-net-names package (string-join (map (lambda (x) "V(~a)") (gnetlist:get-pins package)) " " 'infix) ) ;; make format string (newline) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write a prefix if first char of refdes is improper. ;; ;; Eg. if MOSFET is named T1 then it becomes MT1 in the SPICE file. ;; ;; Argument List : ;; package - The refdes of a component eg. R1 ;; prefix - The desired prefix character (define (spice-msw:write-prefix package prefix) (let ( (different-prefix (not (string-ci=? (substring package 0 1) prefix))) (nomunge-mode (calling-flag? "nomunge_mode" (gnetlist:get-calling-flags))) ) (debug-spew " spice-msw:write-prefix : Check refdes ") (debug-spew (string-append "prefix = " (substring package 0 1))) (debug-spew (string-append " (correct prefix = " prefix ")\n")) (if (and different-prefix (not nomunge-mode)) (display prefix)) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Given a refdes, and optionally a format string, write out the nets attached to the component's ;; pins. ;; ;; If it's not called with a format string it looks for one in the net-format attribute, otherwise ;; it writes out the pins unformatted. This is used to write out non-slotted parts. ;; ;; Argument List : ;; ??? (define (spice-msw:write-net-names refdes . format) ;; get-net-name - helper function. Called with pinseq, returns net name, unless net name is ;; "ERROR_INVALID_PIN" then it returns false. (define (get-net-name pin) (set! pin (number->string pin)) ;; ------- Super debug stuff -------- (if #f (begin (debug-spew " spice-msw:write-net-names :\n") (debug-spew (string-append " pin-name = " pin "\n")) (debug-spew (string-append " pinnumber = " (gnetlist:get-attribute-by-pinseq refdes pin "pinnumber") "\n")) (debug-spew (string-append " pinseq = " (gnetlist:get-attribute-by-pinseq refdes pin "pinseq"))) (if (not (string-ci=? pin (gnetlist:get-attribute-by-pinseq refdes pin "pinseq"))) (debug-spew " <== INCONSISTENT!\n") (debug-spew "\n") ) (debug-spew (string-append " netname = " (car (spice-msw:get-net refdes (gnetlist:get-attribute-by-pinseq refdes pin "pinnumber"))) "\n")) ) ) ;; ------------------------------------- (set! pin (car (spice-msw:get-net refdes (gnetlist:get-attribute-by-pinseq refdes pin "pinnumber")))) (if (string-ci=? pin "ERROR_INVALID_PIN") (begin (debug-spew (string-append "For " refdes ", found pin with no pinseq attribute. Ignoring. . . .\n")) #f ) pin ) ) ;; First do local assignments (let ( (netnames (filter-map get-net-name (range 1 (length (gnetlist:get-pins refdes))))) ) (if (null? format) ;; Format agument take priority, otherwise use attribute (set! format (gnetlist:get-package-attribute refdes "net-format")) (set! format (car format)) ) (if (string-ci=? format "unknown") (display (string-join netnames " " 'suffix)) ;; Write out nets. (apply simple-format (cons #t (cons format netnames))) ;; Write out nets with format string ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Return a list of all the integers from start to stop, with the optional step size. ;; ;; It is similar to perl's range operator '..' ;; ;; Argument List : ;; ??? (define (range start stop . step) (if (null? step) (iota (+ (- stop start) 1) start) (begin (set! step (car step)) (iota (+ (ceiling (/ (- stop start) step)) 1) start step) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Write the refdes and the net names connected to pins on this component. ;; ;; No component value is written or extra attributes. Those are handled later. ;; ;; Argument List : ;; package - The refdes of a component eg. R1 (define (spice-msw:write-refdes-nets package) (display (string-append package " ")) ;; Write component refdes (spice-msw:write-net-names package) ;; Write the net names ) ;;-------------------------------------------------------------------------------------------------- ;; Include SPICE statements from a directive block. ;; ;; Argument List : ;; package - The refdes of a component eg. ??? (define (spice-msw:write-directive package) (debug-spew " spice-msw:write-directive : Found a SPICE directive\n") ;; Collect variables used in creating spice code (let ( (value (gnetlist:get-package-attribute package "value")) (file (gnetlist:get-package-attribute package "file")) ) (cond ;; First look to see if there is a value. ((not (string-ci=? value "unknown")) (begin (display (string-append value "\n")) (debug-spew (string-append "Appending value = \"" value "\" to output file.\n")) ) ) ;; Since there is no value, look for file. ((not (string-ci=? file "unknown")) (begin (spice-msw:insert-text-file file) ;; Note that we don't wait until the end here. Is that OK? (debug-spew (string-append "Inserting contents of file = " file " into output file.\n")) ) ) ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Include a file using an .INCLUDE directive. ;; ;; Argument List : ;; package - The refdes of a component eg. .INCLUDE (define (spice-msw:write-include package) (debug-spew " spice-msw:write-include : Found a .INCLUDE directive\n") (let ( (file (gnetlist:get-package-attribute package "file")) ) (if (not (string-ci=? file "unknown")) (if (calling-flag? "embedd_mode" (gnetlist:get-calling-flags)) (begin (spice-msw:insert-text-file file) (debug-spew (string-append "embedding contents of file " file " into netlist.\n")) ) (begin (display (string-append ".INCLUDE " file "\n")) (debug-spew "placing .include directive string into netlist.\n") ) ) (debug-spew "silently skip \"unknown\" file.\n") ) ) ) ;;-------------------------------------------------------------------------------------------------- ;; Include an option using an .OPTIONS directive. ;; ;; Argument List : ;; package - The refdes of a component eg. .OPTIONS (define (spice-msw:write-options package) (debug-spew " spice-msw:write-options : Found a .OPTIONS directive\n") (display (string-append ".OPTIONS " (gnetlist:get-package-attribute package "value") "\n")) ) ;;-------------------------------------------------------------------------------------------------- ;; Include a spice model (instantiated as a model box on the schematic). ;; ;; Two types of model can be included: ;; 1. An embedded model, which is a one- or multi-line string held in the attribute "model". ;; In this case, the following attributes are mandatory : ;; - model (i.e. list of parameter=value strings) ;; - model-name ;; - type ;; In this case, the function creates and formats the correct spice model line(s). ;; 2. A model held in a file whose name is held in the attribute "file" ;; In this case, the following attribute are mandatory : ;; - file (i.e. list of parameter=value strings) ;; In this case, the function just opens the file and dumps the contents into the netlist. ;; ;; Argument List : ;; package - The refdes of a component eg. .MODEL (define (spice-msw:write-model package) (debug-spew " spice-msw:write-model : Found a .MODEL directive") ;; Collect variables used in creating spice code (let ( (model-name (gnetlist:get-package-attribute package "model-name")) (model-file (gnetlist:get-package-attribute package "file")) (model (gnetlist:get-package-attribute package "model")) (type (gnetlist:get-package-attribute package "type")) ) ;; Now, depending upon what combination of model, model-file, and model-name ;; exist (as described above) write out lines into spice netlist. (cond ;; one model and model name exist ((not (or (string-ci=? model "unknown") (string-ci=? model-name "unknown"))) (debug-spew (string-append " and model and model-name for " package "\n")) (display (string-append ".MODEL " model-name " " type " (" model ")\n")) ) ;; model file exists ((not (or (string-ci=? model-file "unknown") )) (debug-spew (string-append " and model-file for " package "\n")) ) (else (debug-spew " but no model, model-name or model-file\n") ) ) ) ) ;;**************************************************************************************************