1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: ioeagleo.c
6 * Input/output tool: EAGLE output
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 /*
33 * ----------------- FORMAT ----------------------
34 * ADD SO14 'IC1' R0 (0 0)
35 * ADD SO16 'IC2' R0 (0 0)
36 * ADD SO24L 'IC3' R0 (0 0)
37 * ;
38 * Signal 'A0' 'IC1' '5' \
39 * 'IC2' '10' \
40 * 'IC3' '8' \
41 * ;
42 * Signal 'A1' 'IC1' '6' \
43 * 'IC2' '11' \
44 * 'IC3' '5' \
45 * ;
46 */
47
48 #include "config.h"
49 #include "global.h"
50 #include "eio.h"
51
52 #define NOEAGLENET ((EAGLENET *)-1)
53
54 typedef struct Inexteaglenet
55 {
56 CHAR *netname;
57 CHAR *packagename;
58 CHAR *pinname;
59 struct Inexteaglenet *nexteaglenet;
60 } EAGLENET;
61
62 static EAGLENET *io_eaglefirstnet;
63
64 /* prototypes for local routines */
65 static INTBIG io_eagledumpcell(NODEPROTO *curcell, CHAR *prefix);
66 static void io_eaglemarkcells(NODEPROTO *curcell);
67
io_writeeaglelibrary(LIBRARY * lib)68 BOOLEAN io_writeeaglelibrary(LIBRARY *lib)
69 {
70 CHAR file[100], *truename;
71 REGISTER INTBIG i, sorted, maxnetname, maxpackagename;
72 REGISTER CHAR *name;
73 REGISTER NODEPROTO *curcell;
74 REGISTER EAGLENET *en, *lasten, *nexten;
75 REGISTER PORTPROTO *pp;
76
77 /* create the proper disk file for the EAGLE */
78 curcell = lib->curnodeproto;
79 if (curcell == NONODEPROTO)
80 {
81 ttyputerr(_("Must be editing a cell to generate EAGLE output"));
82 return(TRUE);
83 }
84 (void)estrcpy(file, curcell->protoname);
85 (void)estrcat(file, x_(".txt"));
86 name = truepath(file);
87 io_fileout = xcreate(name, io_filetypeeagle, _("EAGLE File"), &truename);
88 if (io_fileout == NULL)
89 {
90 if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
91 return(TRUE);
92 }
93
94 /* recurse through the circuit, gathering network connections */
95 io_eaglefirstnet = NOEAGLENET;
96 for(pp = curcell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
97 pp->temp1 = 0;
98 if (io_eagledumpcell(curcell, x_("")) != 0)
99 ttyputmsg(_("Back-annotation information has been added (library must be saved)"));
100 xprintf(io_fileout, x_(";\n"));
101
102 /* warn the user if nets not found */
103 if (io_eaglefirstnet == NOEAGLENET)
104 {
105 ttyputmsg(_("Packages with attribute 'ref_des' not found or their ports are without 'pin' attribute"));
106 }
107
108 /* sort the signals */
109 sorted = 0;
110 while (sorted == 0)
111 {
112 sorted = 1;
113 lasten = NOEAGLENET;
114 for(en = io_eaglefirstnet; en != NOEAGLENET; en = en->nexteaglenet)
115 {
116 nexten = en->nexteaglenet;
117 if (nexten == NOEAGLENET) break;
118 if (namesame(en->netname, nexten->netname) > 0)
119 {
120 if (lasten == NOEAGLENET) io_eaglefirstnet = nexten; else
121 lasten->nexteaglenet = nexten;
122 en->nexteaglenet = nexten->nexteaglenet;
123 nexten->nexteaglenet = en;
124 en = nexten;
125 sorted = 0;
126 }
127 lasten = en;
128 }
129 }
130
131 /* determine longest name */
132 maxnetname = maxpackagename = 0;
133 for(en = io_eaglefirstnet; en != NOEAGLENET; en = en->nexteaglenet)
134 {
135 i = estrlen(en->netname);
136 if (i > maxnetname) maxnetname = i;
137 i = estrlen(en->packagename);
138 if (i > maxpackagename) maxpackagename = i;
139 }
140 maxnetname += 4;
141 maxpackagename += 4;
142
143 /* write networks */
144 lasten = NOEAGLENET;
145 for(en = io_eaglefirstnet; en != NOEAGLENET; en = en->nexteaglenet)
146 {
147 if (lasten == NOEAGLENET || namesame(lasten->netname, en->netname) != 0)
148 {
149 if (lasten != NOEAGLENET) xprintf(io_fileout, x_(";\n"));
150 xprintf(io_fileout, _("Signal '%s'"), en->netname);
151 } else
152 {
153 xprintf(io_fileout, x_(" '%s'"), en->netname);
154 }
155 for(i=estrlen(en->netname); i<maxnetname; i++)
156 xprintf(io_fileout, x_(" "));
157
158 /* write "Part" column */
159 xprintf(io_fileout, x_("'%s'"), en->packagename);
160 for(i=estrlen(en->packagename); i<maxpackagename; i++)
161 xprintf(io_fileout, x_(" "));
162
163 /* write "Pad" column (an attribute with a number) */
164 xprintf(io_fileout, x_("'%s' \\\n"), en->pinname);
165 lasten = en;
166 }
167 if (lasten != NOEAGLENET) xprintf(io_fileout, x_(";\n"));
168
169 /* free memory */
170 while (io_eaglefirstnet != NOEAGLENET)
171 {
172 en = io_eaglefirstnet;
173 io_eaglefirstnet = en->nexteaglenet;
174 efree(en->netname);
175 efree(en->packagename);
176 efree(en->pinname);
177 efree((CHAR *)en);
178 }
179
180 /* clean up */
181 xclose(io_fileout);
182
183 /* tell the user that the file is written */
184 ttyputmsg(_("%s written"), truename);
185 return(FALSE);
186 }
187
188 /*
189 * Routine to write out all cells in the current library that are marked (temp1 != 0).
190 * Returns nonzero if backannotation has been added.
191 */
io_eagledumpcell(NODEPROTO * curcell,CHAR * prefix)192 INTBIG io_eagledumpcell(NODEPROTO *curcell, CHAR *prefix)
193 {
194 CHAR *name;
195 CHAR line[50], *newprefix, *tempname;
196 REGISTER NODEPROTO *np, *subnp, *subcnp;
197 REGISTER NETWORK *net;
198 REGISTER NODEINST *ni;
199 REGISTER VARIABLE *varpart, *var, *varpackagetype;
200 REGISTER PORTARCINST *pi;
201 REGISTER PORTPROTO *pp;
202 REGISTER EAGLENET *en;
203 REGISTER INTBIG backannotate;
204 REGISTER void *infstr;
205
206 /* make sure that all arcs have network names on them */
207 backannotate = 0;
208 if (asktool(net_tool, x_("name-nets"), (INTBIG)curcell) != 0) backannotate++;
209
210 /* mark those cells that will be included in this dump */
211 io_eaglemarkcells(curcell);
212
213 /* write the symbols */
214 for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
215 {
216 if (np->temp1 == 0) continue;
217
218 /* if this is the main entry cell, pickup net names */
219 for(net = np->firstnetwork; net != NONETWORK; net = net->nextnetwork)
220 net->temp1 = 0;
221 if (np == curcell)
222 {
223 for(pp = curcell->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
224 {
225 if (pp->temp1 == 0) continue;
226 pp->network->temp1 = pp->temp1;
227 }
228 }
229
230 /* dump symbols in this cell */
231 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
232 {
233 /* see if this node has a part name */
234 if (ni->proto->primindex != 0) continue;
235 subnp = ni->proto;
236
237 /* ignore recursive references (showing icon in contents) */
238 if (isiconof(subnp, np)) continue;
239
240 varpart = getval((INTBIG)ni, VNODEINST, -1, x_("ATTR_ref_des"));
241 if (varpart == NOVARIABLE)
242 {
243 subcnp = contentsview(subnp);
244 if (subcnp != NONODEPROTO) subnp = subcnp;
245
246 /* compute new prefix for nets in the subcell */
247 infstr = initinfstr();
248 addstringtoinfstr(infstr, prefix);
249 var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
250 if (var == NOVARIABLE)
251 {
252 esnprintf(line, 50, x_("NODE%ld."), (INTBIG)ni);
253 addstringtoinfstr(infstr, line);
254 } else
255 {
256 addstringtoinfstr(infstr, (CHAR *)var->addr);
257 addtoinfstr(infstr, '.');
258 }
259 (void)allocstring(&newprefix, returninfstr(infstr), el_tempcluster);
260
261 /* store net names on ports for use inside the subcell */
262 for(pp = subnp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
263 pp->temp1 = 0;
264 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
265 {
266 pp = equivalentport(ni->parent, pi->proto, subnp);
267 if (pp == NOPORTPROTO || pp->temp1 != 0) continue;
268 net = pi->conarcinst->network;
269 infstr = initinfstr();
270 addstringtoinfstr(infstr, prefix);
271 addstringtoinfstr(infstr, networkname(net, 0));
272 (void)allocstring(&tempname, returninfstr(infstr), io_tool->cluster);
273 pp->temp1 = (INTBIG)tempname;
274 }
275
276 /* recurse */
277 if (io_eagledumpcell(subnp, newprefix) != 0) backannotate++;
278
279 /* remark the cells at the current level and clean up memory */
280 io_eaglemarkcells(curcell);
281 efree(newprefix);
282 for(pp = subnp->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
283 if (pp->temp1 != 0) efree((CHAR *)pp->temp1);
284 } else
285 {
286 /* found package at bottom of hierarchy */
287 (void)allocstring(&name, describevariable(varpart, -1, -1), el_tempcluster);
288 varpackagetype = getval((INTBIG)ni, VNODEINST, -1, x_("ATTR_pkg_type"));
289 if (varpackagetype == NOVARIABLE)
290 {
291 xprintf(io_fileout, x_("ADD %s '%s%s'"), ni->proto->protoname,
292 prefix, name);
293 } else
294 {
295 xprintf(io_fileout, x_("ADD %s '%s%s'"), describevariable(varpackagetype, -1, -1),
296 prefix, name);
297 }
298 xprintf(io_fileout, x_(" (0 0)\n"));
299
300 /* record all networks */
301 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
302 {
303 /* get "Pad" information */
304 infstr = initinfstr();
305 addstringtoinfstr(infstr, x_("ATTRP_"));
306 addstringtoinfstr(infstr, pi->proto->protoname);
307 addstringtoinfstr(infstr, x_("_pin"));
308 var = getval((INTBIG)ni, VNODEINST, -1, returninfstr(infstr));
309 if (var == NOVARIABLE)
310 {
311 /* "Pad" not found on instance: look for it inside of prototype */
312 var = getval((INTBIG)pi->proto, VPORTPROTO, -1, x_("ATTR_pin"));
313 if (var == NOVARIABLE) continue;
314 }
315
316 /* create a new net connection */
317 en = (EAGLENET *)emalloc(sizeof (EAGLENET), io_tool->cluster);
318 if (en == 0) return(backannotate);
319 net = pi->conarcinst->network;
320 if (net->temp1 != 0)
321 {
322 (void)allocstring(&en->netname, (CHAR *)net->temp1, io_tool->cluster);
323 } else if (net->namecount > 0)
324 {
325 infstr = initinfstr();
326 addstringtoinfstr(infstr, prefix);
327 addstringtoinfstr(infstr, networkname(net, 0));
328 (void)allocstring(&en->netname, returninfstr(infstr), io_tool->cluster);
329 } else
330 {
331 infstr = initinfstr();
332 formatinfstr(infstr, x_("%sNET%ld"), prefix, (INTBIG)net);
333 (void)allocstring(&en->netname, returninfstr(infstr), io_tool->cluster);
334 }
335 infstr = initinfstr();
336 addstringtoinfstr(infstr, prefix);
337 addstringtoinfstr(infstr, name);
338 (void)allocstring(&en->packagename, returninfstr(infstr), io_tool->cluster);
339 (void)allocstring(&en->pinname, describevariable(var, -1, -1), io_tool->cluster);
340 en->nexteaglenet = io_eaglefirstnet;
341 io_eaglefirstnet = en;
342 }
343 efree((CHAR *)name);
344 }
345 }
346 }
347 return(backannotate);
348 }
349
350 /*
351 * Routine to mark the cells in the current library that should be included
352 * along with "curcell". The cells are marked by setting their "temp1" field
353 * nonzero. These cells include all that are part of a multipage schematic.
354 */
io_eaglemarkcells(NODEPROTO * curcell)355 void io_eaglemarkcells(NODEPROTO *curcell)
356 {
357 REGISTER NODEPROTO *np;
358
359 /* mark those cells that will be included in this dump */
360 for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
361 np->temp1 = 0;
362 if ((curcell->cellview->viewstate&MULTIPAGEVIEW) != 0 ||
363 namesamen(curcell->cellview->viewname, x_("schematic-page-"), 15) == 0)
364 {
365 /* original cell is a multipage: allow all multipage in this cell */
366 FOR_CELLGROUP(np, curcell)
367 np->temp1 = 1;
368 } else
369 {
370 np->temp1 = 1;
371 }
372 }
373