File: geda-gnetlist_scheme_tutorial.html

package info (click to toggle)
lepton-eda 1.9.18-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 41,024 kB
  • sloc: ansic: 66,688; lisp: 29,508; sh: 6,792; makefile: 3,111; perl: 1,404; pascal: 1,161; lex: 887; sed: 16; cpp: 8
file content (288 lines) | stat: -rw-r--r-- 17,541 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
  <link rel="stylesheet" media="screen" type="text/css" href="./style.css" />
  <link rel="stylesheet" media="screen" type="text/css" href="./design.css" />
  <link rel="stylesheet" media="print" type="text/css" href="./print.css" />

  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<div class="dokuwiki export">

<p>
<em>Translations of this page are also available in the following languages:</em> <a href="geda-gnetlist_scheme_tutorial.ru.html" class="wikilink1" title="geda-gnetlist_scheme_tutorial.ru.html">Русский</a>.
</p>

<h1 class="sectionedit1"><a name="scripting_a_gnetlist_backend_in_scheme" id="scripting_a_gnetlist_backend_in_scheme">Scripting a gnetlist backend in Scheme</a></h1>
<div class="level1">

<p>
<strong>by John Doty</strong>
</p>

<p>
(this was <a href="http://archives.seul.org/geda/user/Jul-2009/msg00235.html" class="urlextern" title="http://archives.seul.org/geda/user/Jul-2009/msg00235.html"  rel="nofollow">originally posted</a> to the gEDA-user mailing list in July 2009)
</p>

<p>
Don&#039;t Panic!
</p>

<p>
If you&#039;ve never written a program in Lisp, it looks daunting. But it&#039;s a lot easier than it looks. Wrap a little bit of “syntactic
sugar” around Lisp, and it becomes Logo, which elementary school children can learn.
</p>

<p>
And, just to make it clear what some of the funny words mean, <a href="http://en.wikipedia.org/wiki/Lisp_(programming_language)" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/Lisp_(programming_language)">Lisp</a> is a computer language, <a href="http://en.wikipedia.org/wiki/Scheme_(programming_language)" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/Scheme_(programming_language)">Scheme</a> is a dialect of Lisp, and <a href="http://en.wikipedia.org/wiki/GNU_Guile" class="interwiki iw_wp" title="http://en.wikipedia.org/wiki/GNU_Guile">Guile</a> is an
implementation of Scheme. Guile is used for “scripting” gEDA. In particular, the gnetlist front end, written in C, extracts topology
and attribute information from schematics, and then presents that data to “back end” Guile scripts for processing and output.
</p>

<p>
This tutorial is specifically about programming gnetlist back ends in Scheme. If you don&#039;t already know Scheme, you should probably look at
other material too, such as:
</p>

<p>
<a href="http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html" class="urlextern" title="http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html"  rel="nofollow">http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html</a>
</p>

<p>
Or look up “Scheme tutorial” with your favorite engine: there are many.
</p>

<p>
The reference document at:
</p>

<p>
<a href="http://www.gnu.org/software/guile/manual/html_node/index.html" class="urlextern" title="http://www.gnu.org/software/guile/manual/html_node/index.html"  rel="nofollow">http://www.gnu.org/software/guile/manual/html_node/index.html</a>
</p>

<p>
may also be useful.
</p>

<p>
OK, let&#039;s get started. Here&#039;s a particularly simple back end:
</p>
<pre class="code lisp"><span class="co1">;; gnetlist development playground</span>
&nbsp;
<span class="br0">&#40;</span>use-modules <span class="br0">&#40;</span>ice-<span class="nu0">9</span> readline<span class="br0">&#41;</span><span class="br0">&#41;</span>
<span class="br0">&#40;</span>activate-readline<span class="br0">&#41;</span>
&nbsp;
<span class="br0">&#40;</span>define <span class="br0">&#40;</span>devel output-filename<span class="br0">&#41;</span>
	<span class="br0">&#40;</span>scm-style-repl<span class="br0">&#41;</span>
<span class="br0">&#41;</span></pre>

<p>
To use this, put it in a file called <code>gnet-devel.scm</code>. Copy this file
to wherever gnetlist Scheme files are kept on your system. On the
machine I&#039;m using today, the command is:
</p>
<pre class="code bash">$ <span class="kw2">sudo</span> <span class="kw2">cp</span> gnet-devel.scm <span class="sy0">/</span>sw<span class="sy0">/</span>share<span class="sy0">/</span>gEDA<span class="sy0">/</span>scheme<span class="sy0">/</span></pre>

<p>
The <code>”/sw/”</code> will be <code>”/usr/”</code> for most Linux package installations, maybe <code>”/usr/local”</code> or <code>”~/mygeda/”</code> for a tarball installation. You&#039;ll have to figure that out. If the target location is writable by you without superuser privileges, you won&#039;t need the <code>“sudo”</code>.
</p>

<p>
Now, translating <code>”/sw/”</code> as needed, type:
</p>
<pre class="code bash">$ gnetlist <span class="re5">-g</span> devel <span class="sy0">/</span>sw<span class="sy0">/</span>share<span class="sy0">/</span>gEDA<span class="sy0">/</span>examples<span class="sy0">/</span>lightning_detector<span class="sy0">/</span>lightning.sch</pre>

<p>
You should see the usual gnetlist boiler plate, followed by:
</p>
<pre class="code">guile&gt;</pre>

<p>
Try:
</p>
<pre class="code">guile&gt; packages</pre>

<p>
You should see:
</p>
<pre class="code lisp"><span class="br0">&#40;</span><span class="st0">&quot;Q3&quot;</span> <span class="st0">&quot;R5&quot;</span> <span class="st0">&quot;Q2&quot;</span> <span class="st0">&quot;R4&quot;</span> <span class="st0">&quot;Q1&quot;</span> <span class="st0">&quot;C6&quot;</span> <span class="st0">&quot;R3&quot;</span> <span class="st0">&quot;L2&quot;</span> <span class="st0">&quot;A1&quot;</span> <span class="st0">&quot;bat(+3v)&quot;</span> <span class="st0">&quot;lamp(1)&quot;</span> <span class="st0">&quot;R2&quot;</span> <span class="st0">&quot;C5&quot;</span> <span class="st0">&quot;L1&quot;</span> <span class="st0">&quot;R1&quot;</span> <span class="st0">&quot;C4&quot;</span> <span class="st0">&quot;lamp(2)&quot;</span> <span class="st0">&quot;C3&quot;</span> <span class="st0">&quot;C2&quot;</span> <span class="st0">&quot;C1&quot;</span> <span class="st0">&quot;D1&quot;</span> <span class="st0">&quot;bat(0v)&quot;</span> <span class="st0">&quot;R7&quot;</span> <span class="st0">&quot;Q4&quot;</span> <span class="st0">&quot;R6&quot;</span><span class="br0">&#41;</span></pre>

<p>
<code>“packages”</code> is a handy variable, containing a list of all unique <code>“refdes=”</code> attribute values. By typing it, you fed it to the “REPL”,
the Read, Evaluate, Print Loop. So, the REPL read it, evaluated it (getting a list), and printed it.
</p>

<p>
Now try:
</p>
<pre class="code">guile&gt; (length packages)
25</pre>

<p>
What happened here? Here, the REPL evaluated the list
</p>
<pre class="code lisp"><span class="br0">&#40;</span><span class="kw1">length</span> packages<span class="br0">&#41;</span></pre>

<p>
In most programming languages, you&#039;d write this expression in more traditional functional notation as <code>“length( packages )”</code>. <code>“length”</code> is a function, which tells you the length of a list.
</p>

<p>
Use the same notation to do arithmetic. For example, calculate “2+3” as:
</p>
<pre class="code">guile&gt; (+ 2 3)
5</pre>

<p>
Note that the procedure ”+” can be used to add any number of quantities, including none at all:
</p>
<pre class="code">guile&gt; (+)
0
guile&gt; (+ 1 2 3)
6</pre>

<p>
We&#039;ll make use of this later on.
</p>

<p>
The readline stuff in our <code>gnet-devel.scm</code> back end allows you to use the cursor keys on your keyboard to move around through the history and edit input. Very handy when interacting. Try it.
</p>

<p>
Another useful variable gnetlist defines is <code>“all-unique-nets”</code> (type it). Just as <code>”(length packages)”</code> tells you how many packages you
have, <code>”(length all-unique-nets)”</code> will tell you how many nets you have.
</p>

<p>
Then there&#039;s <code>all-pins</code>:
</p>
<pre class="code">guile&gt; all-pins
((&quot;1&quot; &quot;2&quot; &quot;3&quot;) (&quot;2&quot; &quot;3&quot; &quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;1&quot;) (&quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;2&quot; &quot;3&quot; &quot;1&quot;) (&quot;2&quot; &quot;3&quot; &quot;1&quot;) (&quot;1&quot;) (&quot;2&quot; &quot;1&quot;) (&quot;2&quot; &quot;3&quot; &quot;1&quot;) (&quot;1&quot; &quot;2&quot;) (&quot;1&quot;) (&quot;1&quot;))</pre>

<p>
Note that this is a little more complicated than the previous examples: it&#039;s a list of lists, not just a list of strings. Each of the lists corresponds to the pins on one package. One thing we might want to extract from this is a count of the number of pins. We can&#039;t just take the length of <code>all-pins</code> to get this: that gives us the number of lists it contains, which is the number of packages:
</p>
<pre class="code">guile&gt; (length all-pins)
25</pre>

<p>
To get the pin count, first get the individual pin counts for each package:
</p>
<pre class="code">guile&gt; (map length all-pins)
(3 3 2 2 2 2 2 2 2 2 2 2 2 2 1 1 2 3 3 1 2 3 2 1 1)</pre>

<p>
This is one of the easy ways to do a “loop” in Scheme; <code>(map p x)</code> yields a list of the results of calling procedure <code>p</code> individually for each element of <code>x</code>. Then we can add them up with a slightly different kind of “loop”:
</p>
<pre class="code">guile&gt; (apply + (map length all-pins))
50</pre>

<p>
(apply p x) calls procedure p once, with all of the elements of x as arguments. So the expression above winds up evaluating:
</p>
<pre class="code lisp"><span class="br0">&#40;</span>+ <span class="nu0">3</span> <span class="nu0">3</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">2</span> <span class="nu0">1</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span> <span class="nu0">3</span> <span class="nu0">1</span> <span class="nu0">2</span> <span class="nu0">3</span> <span class="nu0">2</span> <span class="nu0">1</span> <span class="nu0">1</span><span class="br0">&#41;</span></pre>

<p>
Thus far we&#039;ve been using predefined variables and procedures. We&#039;ll want to be able to define our own. It&#039;s easy:
</p>
<pre class="code">guile&gt; (define the-answer 42)
guile&gt; the-answer
42</pre>

<p>
This defines a variable, <code>the-answer</code>, and gives it the value 42.
</p>

<p>
We can also define procedures:
</p>
<pre class="code">guile&gt; (define add1 (lambda (x) (+ x 1)))
guile&gt; (add1 100)
101</pre>

<p>
When you see <code>“lambda”</code> think “procedure”. The first thing (the technical term is “form”) following <code>“lambda”</code> is a list of the arguments of the procedure, in this case <code>”(x)”</code>. When the the procedure is called, Guile evaluates the remaining forms, in this case just one, <code>”(+ x 1)”</code>, with actual arguments substituted. The result of the procedure is the result of evaluating the last form. So, <code>”(add1 100)”</code> becomes <code>”(+ 100 1)”</code>, which evaluates to 101.
</p>

<p>
Now we can put our statistics collection together into a back end. First, define a procedure to write a line of output:
</p>
<pre class="code lisp"><span class="br0">&#40;</span>define format-line
     <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="kw1">name</span> <span class="kw1">value</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>display <span class="kw1">name</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>display <span class="kw1">value</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>newline<span class="br0">&#41;</span>
     <span class="br0">&#41;</span>
<span class="br0">&#41;</span></pre>

<p>
We&#039;re using two new builtin procedures here, <code>“display”</code> and <code>“newline”</code>, which should be self-explanatory. Now:
</p>
<pre class="code lisp"><span class="br0">&#40;</span>define display-stats
     <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="br0">&#41;</span>                  <span class="co1">; no arguments</span>
         <span class="br0">&#40;</span>format-line <span class="st0">&quot;pins:     &quot;</span> <span class="br0">&#40;</span><span class="kw1">apply</span><span class="sy0"> + </span><span class="br0">&#40;</span>map <span class="kw1">length</span> all-pins<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>format-line <span class="st0">&quot;packages: &quot;</span> <span class="br0">&#40;</span><span class="kw1">length</span> packages<span class="br0">&#41;</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>format-line <span class="st0">&quot;nets:     &quot;</span> <span class="br0">&#40;</span><span class="kw1">length</span> all-unique-nets<span class="br0">&#41;</span><span class="br0">&#41;</span>
     <span class="br0">&#41;</span>
<span class="br0">&#41;</span></pre>
<pre class="code">guile&gt; (display-stats)
pins:     50
packages: 25
nets:     13</pre>

<p>
To finish off a back end, we need a “main program”. By convention, that has the name of the back end. It has the responsibility of opening the output file, too. So, for a “stats” back end for collecting the stats, the entire file looks like:
</p>
<pre class="code lisp"><span class="co1">;; gnetlist back end for extracting design statistics</span>
<span class="co1">;;</span>
<span class="co1">;; Legal boilerplate here as needed</span>
&nbsp;
<span class="br0">&#40;</span>define stats
     <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span>filename<span class="br0">&#41;</span>
         <span class="br0">&#40;</span>set-current-output-port <span class="br0">&#40;</span>open-output-file filename<span class="br0">&#41;</span><span class="br0">&#41;</span>
	<span class="br0">&#40;</span>display-stats<span class="br0">&#41;</span>
     <span class="br0">&#41;</span>
<span class="br0">&#41;</span>
&nbsp;
<span class="co1">;; Collect and output the statistics</span>
&nbsp;
<span class="br0">&#40;</span>define display-stats
     <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="br0">&#41;</span>                  <span class="co1">; no arguments</span>
         <span class="br0">&#40;</span>format-line <span class="st0">&quot;pins:     &quot;</span> <span class="br0">&#40;</span><span class="kw1">apply</span><span class="sy0"> + </span><span class="br0">&#40;</span>map <span class="kw1">length</span> all-pins<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>format-line <span class="st0">&quot;packages: &quot;</span> <span class="br0">&#40;</span><span class="kw1">length</span> packages<span class="br0">&#41;</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>format-line <span class="st0">&quot;nets:     &quot;</span> <span class="br0">&#40;</span><span class="kw1">length</span> all-unique-nets<span class="br0">&#41;</span><span class="br0">&#41;</span>
     <span class="br0">&#41;</span>
<span class="br0">&#41;</span>
&nbsp;
<span class="co1">;; Simple output format</span>
&nbsp;
<span class="br0">&#40;</span>define format-line
     <span class="br0">&#40;</span><span class="kw1">lambda</span> <span class="br0">&#40;</span><span class="kw1">name</span> <span class="kw1">value</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>display <span class="kw1">name</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>display <span class="kw1">value</span><span class="br0">&#41;</span>
         <span class="br0">&#40;</span>newline<span class="br0">&#41;</span>
     <span class="br0">&#41;</span>
<span class="br0">&#41;</span></pre>

<p>
Put this in a file named <code>gnet-stats.scm</code>, copy it to where it belongs with something like
</p>
<pre class="code bash">$ <span class="kw2">sudo</span> <span class="kw2">cp</span> gnet-stats.scm <span class="sy0">/</span>sw<span class="sy0">/</span>share<span class="sy0">/</span>gEDA<span class="sy0">/</span>scheme<span class="sy0">/</span></pre>

<p>
and then <code>“gnetlist -g stats”</code> followed by the usual other arguments and schematic pathnames will put your design&#039;s statistics in the
output file (default <code>output.net</code>).
</p>

<p>
Pretty easy, huh? Useful, too. Lately I&#039;ve been designing systems that consist of stacks of boards: statistics like these are helpful
in figuring out which subsystems I should combine on each board.
</p>

</div>
<!-- EDIT1 SECTION "Scripting a gnetlist backend in Scheme" [127-] --></div>
</body>
</html>