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