1;;; Lepton EDA netlister
2;;; Copyright (C) 2003, 2005-2010 Dan McMahill
3;;; Copyright (C) 2003-2017 gEDA Contributors
4;;; Copyright (C) 2018-2020 Lepton EDA Contributors
5;;;
6;;; This program is free software; you can redistribute it and/or modify
7;;; it under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 2 of the License, or
9;;; (at your option) any later version.
10;;;
11;;; This program is distributed in the hope that it will be useful,
12;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with this program; if not, write to the Free Software
18;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
20;; --------------------------------------------------------------------------
21;; This is gnetlist backend for the SWITCAP switched capacitor
22;; simulator.  This backend was written by Dan McMahill
23;; 'mcmahill at alum dot mit dotedu' who used the SPICE backend by
24;; S. Gieltjes as a starting point.
25
26;; The following is needed to make guile 1.8.x happy.
27(use-modules (ice-9 rdelim)
28             (netlist error)
29             (netlist schematic)
30             (netlist schematic toplevel))
31
32;; ----------------------------------------------------------------------------
33;; Utility functions used by this netlister
34;; ----------------------------------------------------------------------------
35
36;; This procedure takes a net name as determined by gnetlist and
37;; modifies it to be a valid SWITCAP net name.
38;;
39(define switcap:map-net-names
40  (lambda (net-name)
41    (let ((rx (make-regexp "^unnamed_net"))
42          (net-alias net-name)
43          )
44      ;; XXX we should use a dynamic regexp based on the current value
45      ;; for the unnamed net base string.
46
47      (cond
48       ;; Change "GND" to "0"
49       ((string=? net-name "GND") (set! net-alias "0"))
50       ;; remove the 'unnamed_net' part
51       ((regexp-exec rx net-name) (set! net-alias (substring net-name 11)))
52       (else net-name)
53       )
54
55      ;; Truncate to 7 characters
56      (if (> (string-length net-alias) 7)
57          (set! net-alias (substring net-alias 0 7))
58          )
59      ;; Convert to all upper case
60      (string-upcase net-alias)
61
62      )
63    )
64  )
65
66;; This procedure takes a refdes as determined by gnetlist and
67;; modifies it to be a valid SWITCAP refdes.  In particular,
68;; we need to make sure that
69;;
70;; - the first character is correct for the component type
71;;
72;; - we do not exceed 8 characters.  Note the 8 comes from
73;;   the first character which denotes component type plus
74;;   7 for the unique identifier part.
75;;
76;; - we are all caps (switcap is not case sensitive)
77;;
78(define switcap:map-refdes
79  (lambda (refdes)
80    (let ((refdes-alias refdes)
81          )
82
83      ;; Convert to all upper case
84      (string-upcase refdes-alias)
85
86      ;; Make sure the first character is correct for
87      ;; this component type
88      (cond
89       ( (string=? (get-device refdes) "SWITCAP-switch")
90         (if (not (string=? (substring refdes-alias 0 1) "S"))
91             (set! refdes-alias (string-append "S" refdes-alias))))
92
93       ( (string=? (get-device refdes) "SWITCAP-capacitor")
94         (if (not (string=? (substring refdes-alias 0 1) "C"))
95             (set! refdes-alias (string-append "C" refdes-alias))))
96
97       ( (string=? (get-device refdes) "SWITCAP-vcvs")
98         (if (not (string=? (substring refdes-alias 0 1) "E"))
99             (set! refdes-alias (string-append "E" refdes-alias))))
100
101       ( (string=? (get-device refdes) "SWITCAP-vsrc")
102         (if (not (string=? (substring refdes-alias 0 1) "V"))
103             (set! refdes-alias (string-append "V" refdes-alias))))
104
105       )
106
107      ;; Truncate to 8 characters (1 for the first character and
108      ;; 7 for the identifier)
109      (if (> (string-length refdes-alias) 8)
110          (set! refdes-alias (substring refdes-alias 0 8))
111          )
112
113      ;; set to #t for debugging
114      (if #f
115          (let ()
116            (display "(switcap:map-refdes ")
117            (display refdes)
118            (display ") ===> " )
119            (display refdes-alias )
120            (display "\n")
121            )
122          )
123
124      refdes-alias
125      )
126    )
127  )
128
129;;
130;; Given a reference designator and pin number
131;; write out the net name
132;;
133(define switcap:write-pin-net
134  (lambda (package pin)
135    (display (gnetlist:alias-net (pin-netname package pin)))
136    )
137  )
138
139;;
140;; Given a reference designator and attribute name
141;; write out the attribute with warnings if the attribute has
142;; not been set
143;;
144(define switcap:write-attrib
145  (lambda (package attrib)
146      (let ((val (gnetlist:get-package-attribute package attrib)))
147        (if (string=? val "unknown")
148            (begin
149              (display "*** WARNING ***\n")
150              (display "Required attribute \"")
151              (display attrib)
152              (display "\" is not set on component \"")
153              (display package)
154              (display "\".  Please correct this.\n\n")
155              ))
156        (display val)
157        val
158        )))
159
160;; ----------------------------------------------------------------------------
161;; Individual component netlist functions
162;; ----------------------------------------------------------------------------
163
164;;
165;; capacitor
166;;
167;; Form is:
168;;
169;; C### (N1 N2) value;
170;;
171;;
172(define switcap:write-cap
173  (lambda (package)
174    ( begin
175      ;; Write out the refdes
176      (display "     ")
177      (display (gnetlist:alias-refdes package))
178      (display " ")
179
180      ;; Write out the nodes
181      ;; Write out the nodes
182      (display "(")
183      (switcap:write-pin-net package "1")
184      (display " ")
185      (switcap:write-pin-net package "2")
186      (display ") ")
187
188      ;; Write the value
189      (switcap:write-attrib package "value")
190
191      ;; finish the line
192      (display ";\n")
193      )))
194
195;;
196;; switch
197;;
198;; Form is:
199;;
200;; S### (N1 N2) clk;
201;;
202;;
203(define switcap:write-switch
204  (lambda (package)
205    ( begin
206      ;; Write out the refdes
207      (display "     ")
208      (display (gnetlist:alias-refdes package))
209      (display " ")
210
211      ;; Write out the nodes
212      (display "(")
213      (switcap:write-pin-net package "1")
214      (display " ")
215      (switcap:write-pin-net package "2")
216      (display ") ")
217
218      ;; Write the clock
219      (switcap:write-attrib package "clock")
220
221      ;; finish the line
222      (display ";\n")
223      )))
224
225;;
226;; voltage controlled voltage source
227;;
228;; Form is:
229;;
230;; E### (OUTP OUTM INP INM) gain;
231;;
232;;
233(define switcap:write-vcvs
234  (lambda (package)
235    ( begin
236      ;; Write out the refdes
237      (display "     ")
238      (display (gnetlist:alias-refdes package))
239      (display " ")
240
241      ;; Write out the nodes
242      (display "(")
243      (switcap:write-pin-net package "1")
244      (display " ")
245      (switcap:write-pin-net package "2")
246      (display " ")
247      (switcap:write-pin-net package "3")
248      (display " ")
249      (switcap:write-pin-net package "4")
250      (display ") ")
251
252      ;; Write the clock
253      (switcap:write-attrib package "gain")
254
255      ;; finish the line
256      (display ";\n")
257      )))
258
259;;
260;; voltage source
261;;
262;; Form is:
263;;
264;; V### (OUTP OUTM);
265;;
266;;
267(define switcap:write-vsrc
268  (lambda (package)
269    ( begin
270      ;; Write out the refdes
271      (display "     ")
272      (display (gnetlist:alias-refdes package))
273      (display " ")
274
275      ;; Write out the nodes
276      (display "(")
277      (switcap:write-pin-net package "1")
278      (display " ")
279      (switcap:write-pin-net package "2")
280      (display ")")
281
282      ;; finish the line
283      (display ";\n")
284      )))
285
286;;
287;; Timing block -- clock definition
288;;
289;; Form is:
290;;
291;; CLOCK clock_name period (phi_start phi_stop)
292;;
293;;
294(define switcap:write-clock
295  (lambda (package)
296    ( begin
297      (display "     CLOCK ")
298      (display (string-append package " "))
299      (switcap:write-attrib package "PERIOD")
300      (display " (")
301      (switcap:write-attrib package "PSTART")
302      (display " ")
303      (switcap:write-attrib package "PSTOP")
304      (display ");\n")
305      )))
306
307;;
308;; Timing block -- master clock period
309;;
310;; Form is:
311;;
312;; PERIOD clock_period;
313;;
314;;
315(define switcap:write-timing
316  (lambda (package)
317    ( begin
318      (display "     PERIOD ")
319      (switcap:write-attrib package "PERIOD")
320
321      ;; finish the line
322      (display ";\n")
323      )))
324
325;;
326;; Title
327;;
328;; Form is:
329;;
330;; TITLE: my title;
331;;
332;; Can only have 64 characters in the title
333;; XXX - need to truncate to 64 chars
334(define switcap:write-title
335  (lambda (package)
336    ( begin
337      (display "TITLE:")
338      (switcap:write-attrib package "TITLE")
339
340      ;; finish the line
341      (display ";\n\n")
342      )))
343
344;;
345;; Options
346;;
347;; Form is:
348;;
349;; OPTIONS; OPT1; OPT2; ...; END;
350;;
351;; valid options are:
352;;   WIDTH132
353;;   NOLIST
354;;   REPORT
355;;   NOOVRLAY
356;;   GRID
357(define switcap:write-options
358  (lambda (package)
359    ( begin
360      (display "OPTIONS; ")
361      (switcap:write-attrib package "OPTIONS")
362
363      ;; finish the line
364      (display " END;\n\n")
365      )))
366
367;;
368;; Analysis block
369;;
370;; For now, we only support writing the analysis blocks in a file
371;; and including that via a switcap-analysis-1.sym instantiation
372;;
373(define switcap:write-analysis
374  (lambda (package)
375    (display "/* reading analysis from \"")
376    (let ((fname (switcap:write-attrib package "file")))
377      (display "\" */\n")
378      (if (file-exists? fname)
379        (switcap:cat-file (open-input-file fname) (current-output-port))
380        (netlist-error 1 "ERROR: Analysis file ~S not found.\n" fname)))))
381
382(define switcap:cat-file
383  (lambda (ip op)
384    (define line "")
385    (set! line (read-line ip))
386    (if (not (eof-object? line))
387        (begin
388          (write-line line op)
389          (switcap:cat-file ip op)
390        )
391        (close-port ip))
392    ))
393
394;; ----------------------------------------------------------------------------
395;; Netlist functions for each of the blocks in the switcap netlist
396;; ----------------------------------------------------------------------------
397
398
399;;
400;; Switcap netlist header
401;;
402(define switcap:write-top-header
403  (lambda ()
404    (display "/* Switcap netlist produced by lepton-netlist (part of Lepton EDA) */\n")
405    (display "/* See http://www.geda-project.org/ for more information.          */\n")
406    (display "/* Switcap backend written by Dan McMahill                         */\n")
407    (display "\n\n")
408    )
409  )
410
411;;
412;; The main TITLE and OPTIONS block dispatcher
413;;
414(define switcap:write-title-block
415  (lambda (ls)
416     (if (not (null? ls))
417      (let ((package (car ls)))
418        (cond
419          ( (string=? (get-device package) "SWITCAP-options")
420              (switcap:write-options package))
421          ( (string=? (get-device package) "SWITCAP-title")
422              (switcap:write-title package))
423          )
424        (switcap:write-title-block (cdr ls)) ))))
425
426;;
427;; The main TIMING block dispatcher
428;;
429(define switcap:write-timing-block
430  (lambda (ls)
431     (if (not (null? ls))
432      (let ((package (car ls)))
433        (cond
434          ( (string=? (get-device package) "SWITCAP-clock")
435              (switcap:write-clock package))
436          ( (string=? (get-device package) "SWITCAP-timing")
437              (switcap:write-timing package))
438          )
439        (switcap:write-timing-block (cdr ls)) ))))
440
441;;
442;; The main CIRCUIT block netlist dispatcher.
443;;
444(define switcap:write-netlist
445  (lambda (ls)
446     (if (not (null? ls))
447      (let ((package (car ls)))
448        (cond
449          ( (string=? (get-device package) "SWITCAP-switch")
450              (switcap:write-switch package))
451          ( (string=? (get-device package) "SWITCAP-capacitor")
452              (switcap:write-cap package))
453          ( (string=? (get-device package) "SWITCAP-vcvs")
454              (switcap:write-vcvs package))
455          ( (string=? (get-device package) "SWITCAP-vsrc")
456              (switcap:write-vsrc package))
457          )
458        (switcap:write-netlist (cdr ls)) ))))
459
460;;
461;; The main ANALYSIS block dispatcher
462;;
463(define switcap:write-analysis-block
464  (lambda (ls)
465     (if (not (null? ls))
466      (let ((package (car ls)))
467        (cond
468          ( (string=? (get-device package) "SWITCAP-analysis")
469              (switcap:write-analysis package))
470          )
471        (switcap:write-analysis-block (cdr ls)) ))))
472
473
474;; ----------------------------------------------------------------------------
475;; Switcap netlist generation -- top level
476;; ----------------------------------------------------------------------------
477(define (switcap output-filename)
478  (let ((nets (schematic-nets (toplevel-schematic)))
479        (packages (schematic-package-names (toplevel-schematic))))
480
481    ;; initialize the net-name aliasing
482    (gnetlist:build-net-aliases switcap:map-net-names nets)
483
484    ;; initialize the refdes aliasing
485    (gnetlist:build-refdes-aliases switcap:map-refdes packages)
486
487    (switcap:write-top-header)
488    (switcap:write-title-block packages)
489    (display "TIMING;\n")
490    (switcap:write-timing-block packages)
491    (display "END;\n\n")
492    (display "CIRCUIT;\n")
493    (switcap:write-netlist packages)
494    (display "END;\n\n")
495    (switcap:write-analysis-block packages)
496    (display "\n\n/* End of SWITCAP netlist */\n")
497    (display "END;\n")))
498
499
500;; --------------------------------------------------------------------------
501