1 /* -*- tab-width: 4 -*-
2  *
3  * Electric(tm) VLSI Design System
4  *
5  * File: tecfpga.c
6  * FPGA technology
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 #define USE_REDOPRIM            /* use "net_redoprim" for network calculation */
33 
34 #include "config.h"
35 #include "global.h"
36 #include "egraphics.h"
37 #include "tech.h"
38 #include "tecfpga.h"
39 #include "tecgen.h"
40 #include "efunction.h"
41 #include "usr.h"
42 #include "edialogs.h"
43 #ifdef USE_REDOPRIM
44 # include "network.h"
45 #endif
46 
47 /******************** TREE STRUCTURE FOR ARCHITECTURE FILE ********************/
48 
49 #define MAXLINE	   500		/* max characters on FPGA input line */
50 #define MAXDEPTH	50		/* max depth of FPGA nesting */
51 
52 #define PARAMBRANCH  1		/* parameter is a subtree */
53 #define PARAMATOM    2		/* parameter is atomic */
54 
55 typedef struct
56 {
57 	CHAR   *keyword;
58 	INTBIG  lineno;
59 	INTBIG  paramtotal;
60 	INTBIG  parameters;
61 	INTBIG *paramtype;
62 	void  **paramvalue;
63 } LISPTREE;
64 
65 static LISPTREE *fpga_treestack[MAXDEPTH];
66 static INTBIG    fpga_treedepth;
67 static LISPTREE *fpga_treepos;
68 static LISPTREE *fpga_freelisptree = 0;
69 
70 /******************** ADDITIONAL INFORMATION ABOUT PRIMITIVES ********************/
71 
72 #define ACTIVEPART   1			/* set if segment or pip is active */
73 #define ACTIVESAVE   2			/* saved area for segment/pip activity */
74 
75 typedef struct
76 {
77 	INTBIG     posx, posy;
78 	INTBIG     con;
79 	PORTPROTO *pp;
80 } FPGAPORT;
81 
82 typedef struct
83 {
84 	CHAR      *netname;
85 	INTBIG     segactive;
86 	INTBIG     segcount;
87 	INTBIG    *segfx, *segfy;
88 	INTBIG    *segtx, *segty;
89 } FPGANET;
90 
91 typedef struct
92 {
93 	CHAR      *pipname;
94 	INTBIG     pipactive;
95 	INTBIG     con1, con2;
96 	INTBIG     posx, posy;
97 } FPGAPIP;
98 
99 typedef struct
100 {
101 	INTBIG       portcount;
102 	FPGAPORT   **portlist;
103 	INTBIG       netcount;
104 	FPGANET    **netlist;
105 	INTBIG       pipcount;
106 	FPGAPIP    **piplist;
107 } FPGANODE;
108 
109 static INTBIG     fpga_nodecount;
110 static FPGANODE **fpga_nodes;
111 
112 /******************** STANDARD TECHNOLOGY STRUCTURES ********************/
113 
114 /* the options table */
115 static COMCOMP fpgareadp = {NOKEYWORD, topoffile, nextfile, NOPARAMS,
116 	0, x_(" \t"), M_("FPGA Architecture file"), x_("")};
117 static KEYWORD fpgadltopt[] =
118 {
119 	{x_("on"),            0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
120 	{x_("off"),           0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
121 	TERMKEY
122 };
123 static COMCOMP fpgatdispp = {fpgadltopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
124 	0, x_(" \t"), M_("FPGA text display option"), x_("")};
125 static KEYWORD fpgadlopt[] =
126 {
127 	{x_("full"),          0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
128 	{x_("active"),        0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
129 	{x_("text"),          1,{&fpgatdispp,NOKEY,NOKEY,NOKEY,NOKEY}},
130 	{x_("empty"),         0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
131 	TERMKEY
132 };
133 static COMCOMP fpgadispp = {fpgadlopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
134 	0, x_(" \t"), M_("FPGA display level"), x_("")};
135 static KEYWORD fpgaopt[] =
136 {
137 	{x_("read-architecture-file"),    1,{&fpgareadp,NOKEY,NOKEY,NOKEY,NOKEY}},
138 	{x_("only-primitives-file"),      1,{&fpgareadp,NOKEY,NOKEY,NOKEY,NOKEY}},
139 	{x_("display-level"),             1,{&fpgadispp,NOKEY,NOKEY,NOKEY,NOKEY}},
140 	{x_("clear-node-cache"),          0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
141 	{x_("wipe-cache"),                0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
142 	TERMKEY
143 };
144 COMCOMP fpga_parse = {fpgaopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
145 	0, x_(" \t"), M_("FPGA option"), x_("")};
146 
147 /* the display level */
148 #define DISPLAYLEVEL       07		/* level of display */
149 #define NOPRIMDISPLAY       0		/*   display no internals */
150 #define FULLPRIMDISPLAY    01		/*   display all internals */
151 #define ACTIVEPRIMDISPLAY  02		/*   display only active internals */
152 #define TEXTDISPLAY       010		/* set to display text */
153 
154 static TECHNOLOGY    *fpga_tech;
155 static INTBIG         fpga_internaldisplay;
156 static INTBIG         fpga_curpip;
157 static INTBIG         fpga_curnet, fpga_cursegment;
158 static INTBIG         fpga_lineno;
159 static INTBIG         fpga_filesize;
160 static INTBIG         fpga_activepipskey;		/* variable key for "FPGA_activepips" */
161 static INTBIG         fpga_activerepeaterskey;	/* variable key for "FPGA_activerepeaters" */
162 static INTBIG         fpga_nodepipcachekey;		/* variable key for "FPGA_nodepipcache" */
163 static INTBIG         fpga_arcactivecachekey;	/* variable key for "FPGA_arcactivecache" */
164 static FPGANODE      *fpga_fn;					/* current pointer for pip examining */
165 static CHAR          *fpga_repeatername;		/* name of current repeater for activity examining */
166 static BOOLEAN        fpga_repeaterisactive;	/* nonzero if current repeater is found to be active */
167 static NODEPROTO     *fpga_wirepinprim;			/* wire pin */
168 static NODEPROTO     *fpga_repeaterprim;		/* repeater */
169 
170 /* working memory for "fpga_arcactive()" */
171 static INTBIG         fpga_arcbufsize = 0;
172 static UCHAR1        *fpga_arcbuf;
173 
174 /* working memory for "fpga_reevaluatepips()" */
175 static INTBIG         fpga_pipbufsize = 0;
176 static UCHAR1        *fpga_pipbuf;
177 
178 /* prototypes for local routines */
179 static BOOLEAN    fpga_addparameter(LISPTREE *tree, INTBIG type, void *value);
180 static LISPTREE  *fpga_alloclisptree(void);
181 static BOOLEAN    fpga_arcactive(ARCINST *ai);
182 static BOOLEAN    fpga_arcendactive(ARCINST *ai, INTBIG j);
183 static void       fpga_clearcache(NODEINST *ni);
184 static void       fpga_describenetseg(NODEINST *ni, FPGANET *fnet, INTBIG whichseg, POLYGON *poly);
185 static void       fpga_describepip(NODEINST *ni, FPGANODE *fn, INTBIG pipindex, POLYGON *poly);
186 static void       fpga_findvariableobjects(NODEINST *ni, INTBIG varkey, void (*setit)(CHAR*));
187 static void       fpga_killptree(LISPTREE *lt);
188 static BOOLEAN    fpga_makeblockinstance(NODEPROTO *np, LISPTREE *lt);
189 static BOOLEAN    fpga_makeblocknet(NODEPROTO *cell, LISPTREE *lt);
190 static BOOLEAN    fpga_makeblockport(NODEPROTO *np, LISPTREE *lt);
191 static BOOLEAN    fpga_makeblockrepeater(NODEPROTO *np, LISPTREE *lt);
192 static NODEPROTO *fpga_makecell(LISPTREE *lt);
193 static BOOLEAN    fpga_makeprimitive(LISPTREE *lt);
194 static INTBIG     fpga_makeprimitives(LISPTREE *lt);
195 static BOOLEAN    fpga_makeprimnet(NODEPROTO *np, LISPTREE *lt, FPGANODE *fn, FPGANET *fnet);
196 static BOOLEAN    fpga_makeprimpip(NODEPROTO *np, LISPTREE *lt, FPGANODE *fn, FPGAPIP *fpip);
197 static BOOLEAN    fpga_makeprimport(NODEPROTO *np, LISPTREE *lt, FPGAPORT *fp);
198 static NODEPROTO *fpga_placeprimitives(LISPTREE *lt);
199 static BOOLEAN    fpga_pushkeyword(CHAR *pt);
200 static LISPTREE  *fpga_readfile(FILE *f, void *dia);
201 static void       fpga_reevaluatepips(NODEINST *ni, FPGANODE *fn);
202 static BOOLEAN    fpga_repeateractive(NODEINST *ni);
203 static void       fpga_setpips(CHAR *name);
204 static void       fpga_setrepeater(CHAR *name);
205 static INTBIG     fpga_intarcpolys(ARCINST *ai, WINDOWPART *win, POLYLOOP *pl);
206 static void       fpga_intshapearcpoly(ARCINST *ai, INTBIG box, POLYGON *poly, POLYLOOP *pl);
207 static INTBIG     fpga_intnodepolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win, POLYLOOP *pl);
208 static void       fpga_intshapenodepoly(NODEINST *ni, INTBIG box, POLYGON *poly, POLYLOOP *pl);
209 
210 /******************** LAYERS ********************/
211 
212 #define MAXLAYERS   4		/* total layers below      */
213 
214 #define LWIRE       0		/* wire                    */
215 #define LCOMP       1		/* component               */
216 #define LPIP        2		/* pip                     */
217 #define LREPEATER   3		/* repeater                */
218 
219 static GRAPHICS fpga_w_lay = {LAYERO, RED, SOLIDC, SOLIDC,
220 	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
221 	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
222 static GRAPHICS fpga_c_lay = {LAYERO, BLACK, SOLIDC, SOLIDC,
223 	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
224 	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
225 static GRAPHICS fpga_p_lay = {LAYERO, GREEN, SOLIDC, SOLIDC,
226 	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
227 	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
228 static GRAPHICS fpga_r_lay = {LAYERO, BLUE, SOLIDC, SOLIDC,
229 	{0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
230 	0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF}, NOVARIABLE, 0};
231 
232 /* these tables must be updated together */
233 GRAPHICS *fpga_layers[MAXLAYERS+1] = {&fpga_w_lay, &fpga_c_lay, &fpga_p_lay, &fpga_r_lay, NOGRAPHICS};
234 static CHAR *fpga_layer_names[MAXLAYERS] = {x_("Wire"), x_("Component"), x_("Pip"), x_("Repeater")};
235 static INTBIG fpga_layer_function[MAXLAYERS] = {LFMETAL1, LFART, LFART, LFART};
236 static CHAR *fpga_layer_letters[MAXLAYERS] = {x_("w"), x_("c"), x_("p"), x_("r")};
237 
238 /******************** ARCS ********************/
239 
240 #define ARCPROTOCOUNT   1
241 
242 #define AWIRE           0	/* wire               */
243 
244 /* wire arc */
245 static TECH_ARCLAY fpga_al_w[] = { {LWIRE,0,FILLED} };
246 static TECH_ARCS fpga_a_w = {
247 	x_("wire"),0,AWIRE,NOARCPROTO,													/* name */
248 	1,fpga_al_w,																	/* layers */
249 	(APMETAL1<<AFUNCTIONSH)|WANTFIXANG|WANTCANTSLIDE|AEDGESELECT|(45<<AANGLEINCSH)}; /* userbits */
250 
251 TECH_ARCS *fpga_arcprotos[ARCPROTOCOUNT+1] = {&fpga_a_w, ((TECH_ARCS *)-1)};
252 
253 /******************** PORTINST CONNECTIONS ********************/
254 
255 /* these values are replaced with actual arcproto addresses */
256 static INTBIG fpga_pc_wire[]	= {-1, AWIRE, ALLGEN, -1};
257 
258 /******************** NODES ********************/
259 
260 #define NODEPROTOCOUNT	3
261 
262 #define NWIREPIN	 1		/* wire pin */
263 #define NPIP		 2		/* pip */
264 #define NREPEATER	 3		/* repeater */
265 
266 /******************** POLYGONS ********************/
267 
268 static INTBIG fpga_g_pindisc[]   = {CENTER,    CENTER,    RIGHTEDGE, CENTER};
269 static INTBIG fpga_g_fullbox[8]  = {LEFTEDGE, BOTEDGE,  RIGHTEDGE,TOPEDGE};
270 
271 /******************** NODES ********************/
272 
273 /* wire-pin */
274 static TECH_PORTS fpga_wirepin_p[] = {				/* ports */
275 	{fpga_pc_wire, x_("wire"), NOPORTPROTO, (180<<PORTARANGESH),
276 		CENTER, CENTER, CENTER, CENTER}};
277 static TECH_POLYGON fpga_wirepin_l[] = {			/* layers */
278 	{LWIRE, 0, 2, DISC, POINTS, fpga_g_pindisc}};
279 static TECH_NODES fpga_wirepin = {
280 	x_("Wire_Pin"),NWIREPIN,NONODEPROTO,			/* name */
281 	K1,K1,											/* size */
282 	1,fpga_wirepin_p,								/* ports */
283 	1,fpga_wirepin_l,								/* layers */
284 	(NPPIN<<NFUNCTIONSH)|NSQUARE|WIPEON1OR2,		/* userbits */
285 	0,0,0,0,0,0,0,0,0};								/* characteristics */
286 
287 /* pip */
288 static TECH_PORTS fpga_pip_p[] = {					/* ports */
289 	{fpga_pc_wire, x_("pip"), NOPORTPROTO, (180<<PORTARANGESH),
290 		CENTER, CENTER, CENTER, CENTER}};
291 static TECH_POLYGON fpga_pip_l[] = {				/* layers */
292 	{LPIP, 0, 4, FILLEDRECT, BOX, fpga_g_fullbox}};
293 static TECH_NODES fpga_pip = {
294 	x_("Pip"),NPIP,NONODEPROTO,						/* name */
295 	K2,K2,											/* size */
296 	1,fpga_pip_p,									/* ports */
297 	1,fpga_pip_l,									/* layers */
298 	(NPCONNECT<<NFUNCTIONSH)|NSQUARE,				/* userbits */
299 	0,0,0,0,0,0,0,0,0};								/* characteristics */
300 
301 /* repeater */
302 static TECH_PORTS fpga_repeater_p[] = {				/* ports */
303 	{fpga_pc_wire, x_("a"), NOPORTPROTO, (180<<PORTANGLESH) | (45<<PORTARANGESH),
304 		LEFTEDGE, CENTER, LEFTEDGE, CENTER},
305 	{fpga_pc_wire, x_("b"), NOPORTPROTO, (45<<PORTARANGESH) | (1<<PORTNETSH),
306 		RIGHTEDGE, CENTER, RIGHTEDGE, CENTER}};
307 static TECH_POLYGON fpga_repeater_l[] = {			/* layers */
308 	{LREPEATER, 0, 4, FILLEDRECT, BOX, fpga_g_fullbox}};
309 static TECH_NODES fpga_repeater = {
310 	x_("Repeater"),NREPEATER,NONODEPROTO,			/* name */
311 	K10,K3,											/* size */
312 	2,fpga_repeater_p,								/* ports */
313 	1,fpga_repeater_l,								/* layers */
314 	(NPCONNECT<<NFUNCTIONSH),						/* userbits */
315 	0,0,0,0,0,0,0,0,0};								/* characteristics */
316 
317 TECH_NODES *fpga_nodeprotos[NODEPROTOCOUNT+1] = {
318 	&fpga_wirepin,  &fpga_pip, &fpga_repeater,
319 	((TECH_NODES *)-1)
320 };
321 
322 static INTBIG fpga_node_widoff[NODEPROTOCOUNT*4] = {
323 	 H0,H0,H0,H0,   H1,H1,H1,H1,   0,0,0,0
324 };
325 
326 /******************** VARIABLE AGGREGATION ********************/
327 
328 TECH_VARIABLES fpga_variables[] =
329 {
330 	/* set general information about the technology */
331 	{x_("TECH_layer_names"), (CHAR *)fpga_layer_names, 0.0,
332 		VSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
333 	{x_("TECH_layer_function"), (CHAR *)fpga_layer_function, 0.0,
334 		VINTEGER|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
335 	{x_("TECH_node_width_offset"), (CHAR *)fpga_node_widoff, 0.0,
336 		VFRACT|VDONTSAVE|VISARRAY|((NODEPROTOCOUNT*4)<<VLENGTHSH)},
337 
338 	/* set information for the USER analysis tool */
339 	{x_("USER_layer_letters"), (CHAR *)fpga_layer_letters, 0.0,
340 		VSTRING|VDONTSAVE|VISARRAY|(MAXLAYERS<<VLENGTHSH)},
341 	{NULL, NULL, 0.0, 0}
342 };
343 
344 /******************** INTERFACE ROUTINES ********************/
345 
fpga_initprocess(TECHNOLOGY * tech,INTBIG pass)346 BOOLEAN fpga_initprocess(TECHNOLOGY *tech, INTBIG pass)
347 {
348 	if (pass == 0) fpga_tech = tech; else
349 		if (pass == 1)
350 	{
351 		fpga_wirepinprim = getnodeproto(x_("fpga:Wire_Pin"));
352 		fpga_repeaterprim = getnodeproto(x_("fpga:Repeater"));
353 		fpga_activepipskey = makekey(x_("FPGA_activepips"));
354 		fpga_activerepeaterskey = makekey(x_("FPGA_activerepeaters"));
355 		fpga_nodepipcachekey = makekey(x_("FPGA_nodepipcache"));
356 		fpga_arcactivecachekey = makekey(x_("FPGA_arcactivecache"));
357 	}
358 	fpga_internaldisplay = ACTIVEPRIMDISPLAY | TEXTDISPLAY;
359 	fpga_nodecount = 0;
360 	return(FALSE);
361 }
362 
fpga_termprocess(void)363 void fpga_termprocess(void)
364 {
365 #ifdef DEBUGMEMORY
366 	LISPTREE *lt;
367 	REGISTER INTBIG i, j;
368 	REGISTER FPGANET *fnet;
369 	REGISTER FPGAPIP *fpip;
370 	REGISTER FPGANODE *fn;
371 
372 	if (fpga_arcbufsize > 0) efree((CHAR *)fpga_arcbuf);
373 	if (fpga_pipbufsize > 0) efree((CHAR *)fpga_pipbuf);
374 
375 	/* deallocate lisp-tree objects */
376 	while (fpga_freelisptree != 0)
377 	{
378 		lt = fpga_freelisptree;
379 		fpga_freelisptree = (LISPTREE *)fpga_freelisptree->paramvalue;
380 		efree((CHAR *)lt);
381 	}
382 
383 	/* free the extra info associated with the technology */
384 	for(i=0; i<fpga_nodecount; i++)
385 	{
386 		fn = fpga_nodes[i];
387 
388 #ifndef USE_REDOPRIM
389 		for(j=0; j<fn->portcount; j++)
390 		{
391 			fp = fn->portlist[j];
392 			if (fp->pp == NOPORTPROTO || fp->pp->network == NONETWORK) continue;
393 
394 			for(k=j+1; k<fn->portcount; k++)
395 			{
396 				ofp = fn->portlist[k];
397 				if (ofp->pp == NOPORTPROTO || ofp->pp->network == NONETWORK) continue;
398 				if (ofp->pp->network == fp->pp->network) ofp->pp->network = NONETWORK;
399 			}
400 			efree((CHAR *)fp->pp->network);
401 		}
402 #endif
403 		if (fn->portcount > 0)
404 		{
405 			efree((CHAR *)fn->portlist[0]);
406 			efree((CHAR *)fn->portlist);
407 		}
408 
409 		for(j=0; j<fn->netcount; j++)
410 		{
411 			fnet = fn->netlist[j];
412 			if (fnet->netname != 0) efree((CHAR *)fnet->netname);
413 			if (fnet->segcount > 0)
414 				efree((CHAR *)fnet->segfx);
415 		}
416 		if (fn->netcount > 0)
417 		{
418 			efree((CHAR *)fn->netlist[0]);
419 			efree((CHAR *)fn->netlist);
420 		}
421 
422 		for(j=0; j<fn->pipcount; j++)
423 		{
424 			fpip = fn->piplist[j];
425 			if (fpip->pipname != 0) efree((CHAR *)fpip->pipname);
426 		}
427 		if (fn->pipcount > 0)
428 		{
429 			efree((CHAR *)fn->piplist[0]);
430 			efree((CHAR *)fn->piplist);
431 		}
432 
433 		efree((CHAR *)fn);
434 	}
435 	if (fpga_nodecount > 0) efree((CHAR *)fpga_nodes);
436 #endif
437 }
438 
fpga_setmode(INTBIG count,CHAR * par[])439 void fpga_setmode(INTBIG count, CHAR *par[])
440 {
441 	REGISTER CHAR *pp;
442 	REGISTER NODEPROTO *topcell;
443 	REGISTER NODEINST *ni;
444 	CHAR *filename, *subpar[1];
445 	FILE *f;
446 	REGISTER INTBIG l, total;
447 	REGISTER LISPTREE *lt;
448 	static INTBIG filetypefpga = -1;
449 	REGISTER void *infstr, *dia;
450 
451 	if (count == 0)
452 	{
453 		ttyputusage(x_("technology tell fpga OPTIONS"));
454 		return;
455 	}
456 
457 	l = estrlen(pp = par[0]);
458 	if (namesamen(pp, x_("display-level"), l) == 0)
459 	{
460 		if (count == 1)
461 		{
462 			infstr = initinfstr();
463 			switch (fpga_internaldisplay & DISPLAYLEVEL)
464 			{
465 				case NOPRIMDISPLAY:     addstringtoinfstr(infstr, _("No internal display"));       break;
466 				case FULLPRIMDISPLAY:   addstringtoinfstr(infstr, _("Full internal display"));     break;
467 				case ACTIVEPRIMDISPLAY: addstringtoinfstr(infstr, _("Active internal display"));   break;
468 			}
469 			if ((fpga_internaldisplay & TEXTDISPLAY) == 0)
470 				 addstringtoinfstr(infstr, _(", no text")); else
471 					 addstringtoinfstr(infstr, _(", with text"));
472 			ttyputmsg(x_("%s"), returninfstr(infstr));
473 			return;
474 		}
475 
476 		l = estrlen(pp = par[1]);
477 		if (namesamen(pp, x_("empty"), l) == 0)
478 		{
479 			fpga_internaldisplay = (fpga_internaldisplay & ~DISPLAYLEVEL) | NOPRIMDISPLAY;
480 			ttyputverbose(M_("No internal display"));
481 			return;
482 		}
483 		if (namesamen(pp, x_("full"), l) == 0)
484 		{
485 			fpga_internaldisplay = (fpga_internaldisplay & ~DISPLAYLEVEL) | FULLPRIMDISPLAY;
486 			ttyputverbose(M_("Full internal display"));
487 			return;
488 		}
489 		if (namesamen(pp, x_("active"), l) == 0)
490 		{
491 			fpga_internaldisplay = (fpga_internaldisplay & ~DISPLAYLEVEL) | ACTIVEPRIMDISPLAY;
492 			ttyputverbose(M_("Active internal display"));
493 			return;
494 		}
495 		if (namesamen(pp, x_("text"), l) == 0)
496 		{
497 			if (count == 2)
498 			{
499 				if ((fpga_internaldisplay & TEXTDISPLAY) == 0)
500 					ttyputmsg(M_("Text not displayed")); else
501 						ttyputmsg(M_("Text is displayed"));
502 				return;
503 			}
504 			l = estrlen(pp = par[2]);
505 			if (namesamen(pp, x_("on"), l) == 0 && l >= 2)
506 			{
507 				fpga_internaldisplay |= TEXTDISPLAY;
508 				ttyputverbose(M_("Text is displayed"));
509 				return;
510 			}
511 			if (namesamen(pp, x_("off"), l) == 0 && l >= 2)
512 			{
513 				fpga_internaldisplay &= ~TEXTDISPLAY;
514 				ttyputverbose(M_("Text not displayed"));
515 				return;
516 			}
517 			ttyputbadusage(x_("technology tell fpga display-level text"));
518 			return;
519 		}
520 		ttyputbadusage(x_("technology tell fpga display-level"));
521 		return;
522 	}
523 
524 	if (namesamen(pp, x_("wipe-cache"), l) == 0)
525 	{
526 		fpga_clearcache(NONODEINST);
527 		return;
528 	}
529 	if (namesamen(pp, x_("clear-node-cache"), l) == 0)
530 	{
531 		ni = (NODEINST *)us_getobject(VNODEINST, FALSE);
532 		if (ni == NONODEINST) return;
533 		fpga_clearcache(ni);
534 		return;
535 	}
536 
537 	if (namesamen(pp, x_("read-architecture-file"), l) == 0 || namesamen(pp, x_("only-primitives-file"), l) == 0)
538 	{
539 		if (fpga_nodecount != 0)
540 		{
541 			ttyputmsg(_("This technology already has primitives defined"));
542 			return;
543 		}
544 
545 		if (count <= 1)
546 		{
547 			ttyputmsg(_("Need FILENAME after 'read' keyword"));
548 			return;
549 		}
550 
551 		/* get architecture file */
552 		if (filetypefpga < 0)
553 			filetypefpga = setupfiletype(x_("fpga"), x_("*.fpga"), MACFSTAG('TEXT'), FALSE, x_("fpga"), _("FPGA Architecture"));
554 		f = xopen(par[1], filetypefpga, el_libdir, &filename);
555 		if (f == NULL)
556 		{
557 			ttyputerr(_("Cannot find %s"), par[1]);
558 			return;
559 		}
560 
561 		/* prepare for input */
562 		fpga_filesize = filesize(f);
563 		dia = DiaInitProgress(_("Reading FPGA architecture file..."), 0);
564 		if (dia == 0)
565 		{
566 			xclose(f);
567 			return;
568 		}
569 		DiaSetProgress(dia, 0, fpga_filesize);
570 
571 		/* read the file */
572 		lt = fpga_readfile(f, dia);
573 		DiaDoneProgress(dia);
574 		xclose(f);
575 		if (lt == 0)
576 		{
577 			ttyputerr(_("Error reading file"));
578 			return;
579 		}
580 		ttyputmsg(_("FPGA file %s read"), par[1]);
581 
582 		/* turn the tree into primitives */
583 		total = fpga_makeprimitives(lt);
584 		ttyputmsg(_("Created %ld primitives"), total);
585 #ifdef USE_REDOPRIM
586 		net_redoprim();
587 #endif
588 
589 		/* place and wire the primitives */
590 		if (namesamen(pp, x_("read-architecture-file"), l) == 0)
591 		{
592 			topcell = fpga_placeprimitives(lt);
593 			if (topcell != NONODEPROTO)
594 			{
595 				/* recompute bounds */
596 				(*el_curconstraint->solve)(NONODEPROTO);
597 
598 				/* recompute networks */
599 				(void)asktool(net_tool, x_("total-re-number"));
600 
601 				/* display top cell */
602 				subpar[0] = describenodeproto(topcell);
603 				us_editcell(1, subpar);
604 			}
605 		}
606 
607 		/* release tree memory */
608 		fpga_killptree(lt);
609 		return;
610 	}
611 	ttyputbadusage(x_("technology tell fpga"));
612 }
613 
fpga_nodepolys(NODEINST * ni,INTBIG * reasonable,WINDOWPART * win)614 INTBIG fpga_nodepolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win)
615 {
616 	return(fpga_intnodepolys(ni, reasonable, win, &tech_oneprocpolyloop));
617 }
618 
fpga_intnodepolys(NODEINST * ni,INTBIG * reasonable,WINDOWPART * win,POLYLOOP * pl)619 INTBIG fpga_intnodepolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win, POLYLOOP *pl)
620 {
621 	REGISTER INTBIG total, i, pindex, j, otherend;
622 	INTBIG depth, *indexlist;
623 	REGISTER ARCINST *ai;
624 	REGISTER NODEINST *oni;
625 	NODEINST **nilist;
626 	REGISTER PORTARCINST *pi;
627 	REGISTER FPGANODE *fn;
628 
629 	/* get the default number of polygons and list of layers */
630 	pindex = ni->proto->primindex;
631 	if (pindex <= NODEPROTOCOUNT)
632 	{
633 		/* static primitive */
634 		total = fpga_nodeprotos[pindex-1]->layercount;
635 		switch(pindex)
636 		{
637 			case NWIREPIN:
638 				if (tech_pinusecount(ni, win)) total = 0;
639 				break;
640 			case NREPEATER:
641 				if ((fpga_internaldisplay&DISPLAYLEVEL) == ACTIVEPRIMDISPLAY)
642 				{
643 					if (!fpga_repeateractive(ni)) total = 0;
644 				}
645 				break;
646 		}
647 	} else
648 	{
649 		/* dynamic primitive */
650 		switch (fpga_internaldisplay & DISPLAYLEVEL)
651 		{
652 			case NOPRIMDISPLAY:
653 				total = 1;
654 				if ((fpga_internaldisplay&TEXTDISPLAY) != 0) total++;
655 				break;
656 			case ACTIVEPRIMDISPLAY:
657 				/* count number of active nets and pips */
658 				fn = fpga_nodes[pindex - NODEPROTOCOUNT - 1];
659 
660 				/* hard reset of all segment and pip activity */
661 				for(i=0; i<fn->netcount; i++) fn->netlist[i]->segactive = 0;
662 				for(i=0; i<fn->pipcount; i++) fn->piplist[i]->pipactive = 0;
663 
664 				/* determine the active segments and pips */
665 				fpga_reevaluatepips(ni, fn);
666 
667 				/* save the activity bits */
668 				for(i=0; i<fn->netcount; i++)
669 					if ((fn->netlist[i]->segactive&ACTIVEPART) != 0)
670 						fn->netlist[i]->segactive |= ACTIVESAVE;
671 				for(i=0; i<fn->pipcount; i++)
672 					if ((fn->piplist[i]->pipactive&ACTIVEPART) != 0)
673 						fn->piplist[i]->pipactive |= ACTIVESAVE;
674 
675 				/* propagate inactive segments to others that may be active */
676 				gettraversalpath(ni->parent, NOWINDOWPART, &nilist, &indexlist, &depth, 1);
677 				if (depth > 0)
678 				{
679 					oni = nilist[depth-1];
680 					uphierarchy();
681 					for(i=0; i<fn->netcount; i++)
682 					{
683 						if ((fn->netlist[i]->segactive&ACTIVESAVE) != 0) continue;
684 						for(j=0; j<fn->portcount; j++)
685 						{
686 							if (fn->portlist[j]->con != i) continue;
687 							for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
688 							{
689 								if (pi->proto != fn->portlist[j]->pp) continue;
690 								ai = pi->conarcinst;
691 								if (ai->end[0].nodeinst == ni) otherend = 1; else otherend = 0;
692 								if (fpga_arcendactive(ai, otherend)) break;
693 							}
694 							if (pi != NOPORTARCINST) break;
695 						}
696 						if (j < fn->portcount) fn->netlist[i]->segactive |= ACTIVESAVE;
697 					}
698 					downhierarchy(oni, oni->proto, 0);
699 				}
700 
701 				/* add up the active segments */
702 				total = 1;
703 				for(i=0; i<fn->pipcount; i++)
704 					if ((fn->piplist[i]->pipactive&ACTIVESAVE) != 0) total++;
705 				for(i=0; i<fn->netcount; i++)
706 					if ((fn->netlist[i]->segactive&ACTIVESAVE) != 0)
707 						total += fn->netlist[i]->segcount;
708 				fpga_curpip = fpga_curnet = 0;   fpga_cursegment = -1;
709 				break;
710 			case FULLPRIMDISPLAY:
711 				fn = fpga_nodes[pindex - NODEPROTOCOUNT - 1];
712 				total = fn->pipcount + 1;
713 				for(i=0; i<fn->netcount; i++) total += fn->netlist[i]->segcount;
714 				fpga_curnet = fpga_cursegment = 0;
715 				break;
716 			default:
717 				total = 0;
718 		}
719 	}
720 
721 	/* add in displayable variables */
722 	pl->realpolys = total;
723 	if ((fpga_internaldisplay&TEXTDISPLAY) != 0)
724 		total += tech_displayablenvars(ni, pl->curwindowpart, pl);
725 	if (reasonable != 0) *reasonable = total;
726 	return(total);
727 }
728 
fpga_shapenodepoly(NODEINST * ni,INTBIG box,POLYGON * poly)729 void fpga_shapenodepoly(NODEINST *ni, INTBIG box, POLYGON *poly)
730 {
731 	fpga_intshapenodepoly(ni, box, poly, &tech_oneprocpolyloop);
732 }
733 
fpga_intshapenodepoly(NODEINST * ni,INTBIG box,POLYGON * poly,POLYLOOP * pl)734 void fpga_intshapenodepoly(NODEINST *ni, INTBIG box, POLYGON *poly, POLYLOOP *pl)
735 {
736 	REGISTER INTBIG pindex;
737 	REGISTER INTBIG lambda;
738 	REGISTER FPGANODE *fn;
739 	REGISTER FPGANET *fnet;
740 
741 	/* handle displayable variables */
742 	if (box >= pl->realpolys)
743 	{
744 		(void)tech_filldisplayablenvar(ni, poly, pl->curwindowpart, 0, pl);
745 		return;
746 	}
747 
748 	lambda = lambdaofnode(ni);
749 	pindex = ni->proto->primindex;
750 	if (pindex <= NODEPROTOCOUNT)
751 	{
752 		/* static primitive */
753 		tech_fillpoly(poly, &fpga_nodeprotos[pindex-1]->layerlist[box], ni, lambda,
754 			FILLED);
755 		poly->desc = fpga_layers[poly->layer];
756 		return;
757 	}
758 
759 	/* dynamic primitive */
760 	if (box == 0)
761 	{
762 		/* first box is always the outline */
763 		if (poly->limit < 2) (void)extendpolygon(poly, 2);
764 		subrange(ni->lowx, ni->highx, -H0, 0, H0, 0, &poly->xv[0], &poly->xv[1], lambda);
765 		subrange(ni->lowy, ni->highy, -H0, 0, H0, 0, &poly->yv[0], &poly->yv[1], lambda);
766 		poly->count = 2;
767 		poly->style = CLOSEDRECT;
768 		poly->layer = LCOMP;
769 	} else
770 	{
771 		/* subsequent boxes depend on the display level */
772 		switch (fpga_internaldisplay & DISPLAYLEVEL)
773 		{
774 			case NOPRIMDISPLAY:
775 				/* just the name */
776 				if (poly->limit < 4) (void)extendpolygon(poly, 4);
777 				subrange(ni->lowx, ni->highx, -H0, 0, H0, 0, &poly->xv[0], &poly->xv[2], lambda);
778 				subrange(ni->lowy, ni->highy, -H0, 0, H0, 0, &poly->yv[0], &poly->yv[1], lambda);
779 				poly->xv[1] = poly->xv[0];   poly->xv[3] = poly->xv[2];
780 				poly->yv[3] = poly->yv[0];   poly->yv[2] = poly->yv[1];
781 				poly->count = 4;
782 				poly->style = TEXTBOX;
783 				poly->string = ni->proto->protoname;
784 				TDCLEAR(poly->textdescript);
785 				TDSETSIZE(poly->textdescript, TXTSETQLAMBDA(12));
786 				poly->tech = fpga_tech;
787 				poly->layer = LCOMP;
788 				break;
789 
790 			case ACTIVEPRIMDISPLAY:
791 				fn = fpga_nodes[pindex - NODEPROTOCOUNT - 1];
792 
793 				/* draw active segments */
794 				if (fpga_curnet < fn->netcount)
795 				{
796 					/* advance to next active net */
797 					if (fpga_cursegment < 0)
798 					{
799 						for( ; fpga_curnet<fn->netcount; fpga_curnet++)
800 							if ((fn->netlist[fpga_curnet]->segactive&ACTIVESAVE) != 0) break;
801 						fpga_cursegment = 0;
802 					}
803 
804 					/* add in a net segment */
805 					if (fpga_curnet < fn->netcount)
806 					{
807 						fnet = fn->netlist[fpga_curnet];
808 						fpga_describenetseg(ni, fnet, fpga_cursegment, poly);
809 
810 						/* advance to next segment */
811 						fpga_cursegment++;
812 						if (fpga_cursegment >= fn->netlist[fpga_curnet]->segcount)
813 						{
814 							fpga_curnet++;
815 							fpga_cursegment = -1;
816 						}
817 						break;
818 					}
819 				}
820 
821 				/* draw active pips */
822 				if (fpga_curpip < fn->pipcount)
823 				{
824 					for( ; fpga_curpip<fn->pipcount; fpga_curpip++)
825 						if ((fn->piplist[fpga_curpip]->pipactive&ACTIVESAVE) != 0) break;
826 					if (fpga_curpip < fn->pipcount)
827 					{
828 						fpga_describepip(ni, fn, fpga_curpip, poly);
829 						fpga_curpip++;
830 						break;
831 					}
832 				}
833 				break;
834 
835 			case FULLPRIMDISPLAY:
836 				/* show pips */
837 				fn = fpga_nodes[pindex - NODEPROTOCOUNT - 1];
838 				if (box <= fn->pipcount)
839 				{
840 					fpga_describepip(ni, fn, box-1, poly);
841 					break;
842 				}
843 
844 				/* add in a net segment */
845 				fnet = fn->netlist[fpga_curnet];
846 				fpga_describenetseg(ni, fnet, fpga_cursegment, poly);
847 
848 				/* advance to next segment */
849 				fpga_cursegment++;
850 				if (fpga_cursegment >= fn->netlist[fpga_curnet]->segcount)
851 				{
852 					fpga_curnet++;
853 					fpga_cursegment = 0;
854 				}
855 				break;
856 		}
857 	}
858 	poly->desc = fpga_layers[poly->layer];
859 }
860 
861 /*
862  * Warning: to make this routine truly callable in parallel, you must either:
863  * (1) take care of the setting of globals such as "fpga_nodes".
864  * (2) wrap the routine in mutual-exclusion locks
865  */
fpga_allnodepolys(NODEINST * ni,POLYLIST * plist,WINDOWPART * win,BOOLEAN onlyreasonable)866 INTBIG fpga_allnodepolys(NODEINST *ni, POLYLIST *plist, WINDOWPART *win, BOOLEAN onlyreasonable)
867 {
868 	REGISTER INTBIG tot, j;
869 	INTBIG reasonable;
870 	REGISTER NODEPROTO *np;
871 	REGISTER POLYGON *poly;
872 	POLYLOOP mypl;
873 
874 	/* code cannot be called by multiple procesors: uses globals */
875 	NOT_REENTRANT;
876 
877 	np = ni->proto;
878 	mypl.curwindowpart = win;
879 	tot = fpga_intnodepolys(ni, &reasonable, win, &mypl);
880 	if (onlyreasonable) tot = reasonable;
881 	if (mypl.realpolys < tot) tot = mypl.realpolys;
882 	if (ensurepolylist(plist, tot, db_cluster)) return(-1);
883 	for(j = 0; j < tot; j++)
884 	{
885 		poly = plist->polygons[j];
886 		poly->tech = fpga_tech;
887 		fpga_intshapenodepoly(ni, j, poly, &mypl);
888 	}
889 	return(tot);
890 }
891 
fpga_nodeEpolys(NODEINST * ni,INTBIG * reasonable,WINDOWPART * win)892 INTBIG fpga_nodeEpolys(NODEINST *ni, INTBIG *reasonable, WINDOWPART *win)
893 {
894 	Q_UNUSED( ni );
895 	Q_UNUSED( win );
896 
897 	if (reasonable != 0) *reasonable = 0;
898 	return(0);
899 }
900 
fpga_shapeEnodepoly(NODEINST * ni,INTBIG box,POLYGON * poly)901 void fpga_shapeEnodepoly(NODEINST *ni, INTBIG box, POLYGON *poly)
902 {
903 	Q_UNUSED( ni );
904 	Q_UNUSED( box );
905 	Q_UNUSED( poly );
906 }
907 
fpga_allnodeEpolys(NODEINST * ni,POLYLIST * plist,WINDOWPART * win,BOOLEAN onlyreasonable)908 INTBIG fpga_allnodeEpolys(NODEINST *ni, POLYLIST *plist, WINDOWPART *win, BOOLEAN onlyreasonable)
909 {
910 	Q_UNUSED( ni );
911 	Q_UNUSED( plist );
912 	Q_UNUSED( win );
913 	Q_UNUSED( onlyreasonable );
914 	return(0);
915 }
916 
fpga_shapeportpoly(NODEINST * ni,PORTPROTO * pp,POLYGON * poly,XARRAY trans,BOOLEAN purpose)917 void fpga_shapeportpoly(NODEINST *ni, PORTPROTO *pp, POLYGON *poly, XARRAY trans, BOOLEAN purpose)
918 {
919 	REGISTER INTBIG pindex, i;
920 	REGISTER FPGANODE *fn;
921 	Q_UNUSED( purpose );
922 
923 	pindex = ni->proto->primindex;
924 	if (pindex <= NODEPROTOCOUNT)
925 	{
926 		/* static primitive */
927 		tech_fillportpoly(ni, pp, poly, trans, fpga_nodeprotos[pindex-1], CLOSED, lambdaofnode(ni));
928 		return;
929 	}
930 
931 	/* dynamic primitive */
932 	if (poly->limit < 1) (void)extendpolygon(poly, 1);
933 	fn = fpga_nodes[pindex - NODEPROTOCOUNT - 1];
934 	poly->count = 1;
935 	poly->style = CROSS;
936 	poly->xv[0] = (ni->lowx+ni->highx) / 2;
937 	poly->yv[0] = (ni->lowy+ni->highy) / 2;
938 	for(i=0; i<fn->portcount; i++)
939 		if (fn->portlist[i]->pp == pp)
940 	{
941 		poly->xv[0] += fn->portlist[i]->posx;
942 		poly->yv[0] += fn->portlist[i]->posy;
943 		break;
944 	}
945 	xform(poly->xv[0], poly->yv[0], &poly->xv[0], &poly->yv[0], trans);
946 }
947 
fpga_arcpolys(ARCINST * ai,WINDOWPART * win)948 INTBIG fpga_arcpolys(ARCINST *ai, WINDOWPART *win)
949 {
950 	return(fpga_intarcpolys(ai, win, &tech_oneprocpolyloop));
951 }
952 
fpga_intarcpolys(ARCINST * ai,WINDOWPART * win,POLYLOOP * pl)953 INTBIG fpga_intarcpolys(ARCINST *ai, WINDOWPART *win, POLYLOOP *pl)
954 {
955 	REGISTER INTBIG i, aindex;
956 
957 	aindex = ai->proto->arcindex;
958 
959 	/* presume display of the arc */
960 	i = fpga_arcprotos[aindex]->laycount;
961 	if ((fpga_internaldisplay&DISPLAYLEVEL) == NOPRIMDISPLAY ||
962 		(fpga_internaldisplay&DISPLAYLEVEL) == ACTIVEPRIMDISPLAY)
963 	{
964 		if (!fpga_arcactive(ai)) i = 0;
965 	}
966 
967 	/* add in displayable variables */
968 	pl->realpolys = i;
969 	if ((fpga_internaldisplay&TEXTDISPLAY) != 0)
970 		i += tech_displayableavars(ai, win, pl);
971 	return(i);
972 }
973 
fpga_shapearcpoly(ARCINST * ai,INTBIG box,POLYGON * poly)974 void fpga_shapearcpoly(ARCINST *ai, INTBIG box, POLYGON *poly)
975 {
976 	fpga_intshapearcpoly(ai, box, poly, &tech_oneprocpolyloop);
977 }
978 
fpga_intshapearcpoly(ARCINST * ai,INTBIG box,POLYGON * poly,POLYLOOP * pl)979 void fpga_intshapearcpoly(ARCINST *ai, INTBIG box, POLYGON *poly, POLYLOOP *pl)
980 {
981 	REGISTER INTBIG aindex;
982 	REGISTER TECH_ARCLAY *thista;
983 
984 	/* handle displayable variables */
985 	if (box >= pl->realpolys)
986 	{
987 		(void)tech_filldisplayableavar(ai, poly, pl->curwindowpart, 0, pl);
988 		return;
989 	}
990 
991 	/* initialize for the arc */
992 	aindex = ai->proto->arcindex;
993 
994 	/* normal wires */
995 	thista = &fpga_arcprotos[aindex]->list[box];
996 	poly->layer = thista->lay;
997 	poly->desc = fpga_layers[poly->layer];
998 
999 	/* simple wire arc */
1000 	makearcpoly(ai->length, ai->width-thista->off*lambdaofarc(ai)/WHOLE,
1001 		ai, poly, thista->style);
1002 }
1003 
fpga_allarcpolys(ARCINST * ai,POLYLIST * plist,WINDOWPART * win)1004 INTBIG fpga_allarcpolys(ARCINST *ai, POLYLIST *plist, WINDOWPART *win)
1005 {
1006 	REGISTER INTBIG tot, j;
1007 	POLYLOOP mypl;
1008 
1009 	mypl.curwindowpart = win;
1010 	tot = fpga_intarcpolys(ai, win, &mypl);
1011 	tot = mypl.realpolys;
1012 	if (ensurepolylist(plist, tot, db_cluster)) return(-1);
1013 	for(j = 0; j < tot; j++)
1014 	{
1015 		fpga_intshapearcpoly(ai, j, plist->polygons[j], &mypl);
1016 	}
1017 	return(tot);
1018 }
1019 
1020 /******************** TECHNOLOGY INTERFACE SUPPORT ********************/
1021 
fpga_arcendactive(ARCINST * ai,INTBIG j)1022 BOOLEAN fpga_arcendactive(ARCINST *ai, INTBIG j)
1023 {
1024 	REGISTER PORTARCINST *pi;
1025 	REGISTER PORTEXPINST *pe;
1026 	REGISTER ARCINST *oai;
1027 	REGISTER NODEINST *ni, *oni, *subni;
1028 	REGISTER PORTPROTO *pp, *opp;
1029 	REGISTER INTBIG pindex, i, newend;
1030 	REGISTER FPGANODE *fn;
1031 	NODEINST **nilist;
1032 	INTBIG depth, *indexlist;
1033 
1034 	/* examine end */
1035 	ni = ai->end[j].nodeinst;
1036 	pi = ai->end[j].portarcinst;
1037 	if (pi == NOPORTARCINST) return(FALSE);
1038 	pp = pi->proto;
1039 	pindex = ni->proto->primindex;
1040 	if (pindex == 0)
1041 	{
1042 		/* follow down into cell */
1043 		downhierarchy(ni, ni->proto, 0);
1044 		subni = pp->subnodeinst;
1045 		for(pi = subni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1046 		{
1047 			oai = pi->conarcinst;
1048 			if (oai->end[0].nodeinst == subni) newend = 1; else newend = 0;
1049 			if (fpga_arcendactive(oai, newend)) break;
1050 		}
1051 		uphierarchy();
1052 		if (pi != NOPORTARCINST) return(TRUE);
1053 		return(FALSE);
1054 	} else
1055 	{
1056 		/* primitive: see if it is one of ours */
1057 		if (ni->proto->tech == fpga_tech && pindex > NODEPROTOCOUNT)
1058 		{
1059 			fn = fpga_nodes[pindex - NODEPROTOCOUNT - 1];
1060 			downhierarchy(ni, ni->proto, 0);
1061 			fpga_reevaluatepips(ni, fn);
1062 			uphierarchy();
1063 			if (fn->netcount != 0)
1064 			{
1065 				for(i = 0; i < fn->portcount; i++)
1066 				{
1067 					if (fn->portlist[i]->pp != pp) continue;
1068 					if ((fn->netlist[fn->portlist[i]->con]->segactive&ACTIVEPART) != 0) return(TRUE);
1069 					break;
1070 				}
1071 			}
1072 		}
1073 	}
1074 
1075 	/* propagate */
1076 	if (pp->network != NONETWORK)
1077 	{
1078 		for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1079 		{
1080 			oai = pi->conarcinst;
1081 			if (oai == ai) continue;
1082 			if (pi->proto->network != pp->network) continue;
1083 			if (oai->end[0].nodeinst == ni) newend = 1; else newend = 0;
1084 			if (fpga_arcendactive(oai, newend)) return(TRUE);
1085 		}
1086 
1087 		gettraversalpath(ni->parent, NOWINDOWPART, &nilist, &indexlist, &depth, 1);
1088 		if (depth > 0)
1089 		{
1090 			oni = nilist[depth-1];
1091 			for(pe = ni->firstportexpinst; pe != NOPORTEXPINST; pe = pe->nextportexpinst)
1092 			{
1093 				opp = pe->exportproto;
1094 				uphierarchy();
1095 
1096 				for(pi = oni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1097 				{
1098 					oai = pi->conarcinst;
1099 					if (pi->proto != opp) continue;
1100 					if (oai->end[0].nodeinst == oni) newend = 1; else newend = 0;
1101 					if (fpga_arcendactive(oai, newend)) break;
1102 				}
1103 
1104 				downhierarchy(oni, oni->proto, 0);
1105 				if (pi != NOPORTARCINST) return(TRUE);
1106 			}
1107 		}
1108 	}
1109 	return(FALSE);
1110 }
1111 
fpga_arcactive(ARCINST * ai)1112 BOOLEAN fpga_arcactive(ARCINST *ai)
1113 {
1114 	REGISTER INTBIG i, size, cachedepth;
1115 	REGISTER BOOLEAN value;
1116 	INTBIG depth, *indexlist;
1117 	REGISTER NODEINST *oni;
1118 	REGISTER VARIABLE *var;
1119 	NODEINST **nilist;
1120 	UCHAR1 *ptr;
1121 
1122 	if (ai->end[0].portarcinst == NOPORTARCINST) return(FALSE);
1123 
1124 	/* see if there is a cache on the arc */
1125 	gettraversalpath(ai->parent, NOWINDOWPART, &nilist, &indexlist, &depth, 0);
1126 	var = getvalkey((INTBIG)ai, VARCINST, VCHAR|VISARRAY, fpga_arcactivecachekey);
1127 	if (var != NOVARIABLE)
1128 	{
1129 		ptr = (UCHAR1 *)var->addr;
1130 		cachedepth = ((INTBIG *)ptr)[0];   ptr += SIZEOFINTBIG;
1131 		if (cachedepth == depth)
1132 		{
1133 			for(i=0; i<cachedepth; i++)
1134 			{
1135 				oni = ((NODEINST **)ptr)[0];   ptr += (sizeof (NODEINST *));
1136 				if (oni != nilist[i]) break;
1137 			}
1138 			if (i >= cachedepth)
1139 			{
1140 				/* cache applies to this arc: get active factor */
1141 				if (((INTSML *)ptr)[0] == 0) return(FALSE);
1142 				return(TRUE);
1143 			}
1144 		}
1145 	}
1146 
1147 	/* compute arc activity */
1148 	value = FALSE;
1149 	if (fpga_arcendactive(ai, 0)) value = TRUE; else
1150 		if (fpga_arcendactive(ai, 1)) value = TRUE;
1151 
1152 	/* store the cache */
1153 	size = depth * (sizeof (NODEINST *)) + SIZEOFINTBIG + SIZEOFINTSML;
1154 	if (size > fpga_arcbufsize)
1155 	{
1156 		if (fpga_arcbufsize > 0) efree((CHAR *)fpga_arcbuf);
1157 		fpga_arcbufsize = 0;
1158 		fpga_arcbuf = (UCHAR1 *)emalloc(size, fpga_tech->cluster);
1159 		if (fpga_arcbuf == 0) return(value);
1160 		fpga_arcbufsize = size;
1161 	}
1162 	ptr = fpga_arcbuf;
1163 	((INTBIG *)ptr)[0] = depth;   ptr += SIZEOFINTBIG;
1164 	for(i=0; i<depth; i++)
1165 	{
1166 		((NODEINST **)ptr)[0] = nilist[i];   ptr += (sizeof (NODEINST *));
1167 	}
1168 	((INTSML *)ptr)[0] = value ? 1 : 0;
1169 	nextchangequiet();
1170 	setvalkey((INTBIG)ai, VARCINST, fpga_arcactivecachekey, (INTBIG)fpga_arcbuf,
1171 		VCHAR|VISARRAY|(size<<VLENGTHSH)|VDONTSAVE);
1172 	return(value);
1173 }
1174 
1175 /*
1176  * Routine to reevaluate primitive node "ni" (which is associated with internal
1177  * structure "fn").  Finds programming of pips and sets pip and net activity.
1178  */
fpga_reevaluatepips(NODEINST * ni,FPGANODE * fn)1179 void fpga_reevaluatepips(NODEINST *ni, FPGANODE *fn)
1180 {
1181 	REGISTER INTBIG i, value, size, cachedepth;
1182 	INTBIG depth, *indexlist;
1183 	REGISTER FPGAPIP *fpip;
1184 	REGISTER NODEINST *oni;
1185 	REGISTER VARIABLE *var;
1186 	NODEINST **nilist;
1187 	UCHAR1 *ptr;
1188 
1189 	/* primitives with no pips or nets need no evaluation */
1190 	if (fn->netcount == 0 && fn->pipcount == 0) return;
1191 
1192 	/* see if there is a cache on the node */
1193 	gettraversalpath(ni->parent, NOWINDOWPART, &nilist, &indexlist, &depth, 0);
1194 	var = getvalkey((INTBIG)ni, VNODEINST, VCHAR|VISARRAY, fpga_nodepipcachekey);
1195 	if (var != NOVARIABLE)
1196 	{
1197 		ptr = (UCHAR1 *)var->addr;
1198 		cachedepth = ((INTBIG *)ptr)[0];   ptr += SIZEOFINTBIG;
1199 		if (cachedepth == depth)
1200 		{
1201 			for(i=0; i<cachedepth; i++)
1202 			{
1203 				oni = ((NODEINST **)ptr)[0];   ptr += (sizeof (NODEINST *));
1204 				if (oni != nilist[i]) break;
1205 			}
1206 			if (i >= cachedepth)
1207 			{
1208 				/* cache applies to this node: get values */
1209 				for(i=0; i<fn->netcount; i++)
1210 				{
1211 					value = ((INTSML *)ptr)[0];   ptr += SIZEOFINTSML;
1212 					if (value != 0) fn->netlist[i]->segactive |= ACTIVEPART; else
1213 						fn->netlist[i]->segactive &= ~ACTIVEPART;
1214 				}
1215 				for(i=0; i<fn->pipcount; i++)
1216 				{
1217 					value = ((INTSML *)ptr)[0];   ptr += SIZEOFINTSML;
1218 					if (value != 0) fn->piplist[i]->pipactive |= ACTIVEPART; else
1219 						fn->piplist[i]->pipactive &= ~ACTIVEPART;
1220 				}
1221 				return;
1222 			}
1223 		}
1224 	}
1225 
1226 	/* reevaluate: presume all nets and pips are inactive */
1227 	for(i=0; i<fn->netcount; i++) fn->netlist[i]->segactive &= ~ACTIVEPART;
1228 	for(i=0; i<fn->pipcount; i++) fn->piplist[i]->pipactive &= ~ACTIVEPART;
1229 
1230 	/* look for pip programming */
1231 	fpga_fn = fn;
1232 	fpga_findvariableobjects(ni, fpga_activepipskey, fpga_setpips);
1233 
1234 	/* set nets active where they touch active pips */
1235 	for(i=0; i<fn->pipcount; i++)
1236 	{
1237 		fpip = fn->piplist[i];
1238 		if ((fpip->pipactive&ACTIVEPART) == 0) continue;
1239 		if (fpip->con1 > 0) fn->netlist[fpip->con1]->segactive |= ACTIVEPART;
1240 		if (fpip->con2 > 0) fn->netlist[fpip->con2]->segactive |= ACTIVEPART;
1241 	}
1242 
1243 	/* store the cache */
1244 	size = depth * (sizeof (NODEINST *)) + SIZEOFINTBIG + fn->netcount * SIZEOFINTSML +
1245 		fn->pipcount * SIZEOFINTSML;
1246 	if (size > fpga_pipbufsize)
1247 	{
1248 		if (fpga_pipbufsize > 0) efree((CHAR *)fpga_pipbuf);
1249 		fpga_pipbufsize = 0;
1250 		fpga_pipbuf = (UCHAR1 *)emalloc(size, fpga_tech->cluster);
1251 		if (fpga_pipbuf == 0) return;
1252 		fpga_pipbufsize = size;
1253 	}
1254 	ptr = fpga_pipbuf;
1255 	((INTBIG *)ptr)[0] = depth;   ptr += SIZEOFINTBIG;
1256 	for(i=0; i<depth; i++)
1257 	{
1258 		((NODEINST **)ptr)[0] = nilist[i];   ptr += (sizeof (NODEINST *));
1259 	}
1260 	for(i=0; i<fn->netcount; i++)
1261 	{
1262 		if ((fn->netlist[i]->segactive&ACTIVEPART) != 0) ((INTSML *)ptr)[0] = 1; else
1263 			((INTSML *)ptr)[0] = 0;
1264 		ptr += SIZEOFINTSML;
1265 	}
1266 	for(i=0; i<fn->pipcount; i++)
1267 	{
1268 		if ((fn->piplist[i]->pipactive&ACTIVEPART) != 0) ((INTSML *)ptr)[0] = 1; else
1269 			((INTSML *)ptr)[0] = 0;
1270 		ptr += SIZEOFINTSML;
1271 	}
1272 	nextchangequiet();
1273 	setvalkey((INTBIG)ni, VNODEINST, fpga_nodepipcachekey, (INTBIG)fpga_pipbuf,
1274 		VCHAR|VISARRAY|(size<<VLENGTHSH)|VDONTSAVE);
1275 }
1276 
1277 /*
1278  * Helper routine for fpga_reevaluatepips() to set pip "name".
1279  */
fpga_setpips(CHAR * name)1280 void fpga_setpips(CHAR *name)
1281 {
1282 	REGISTER INTBIG i;
1283 
1284 	for(i=0; i<fpga_fn->pipcount; i++)
1285 		if (namesame(fpga_fn->piplist[i]->pipname, name) == 0)
1286 	{
1287 		fpga_fn->piplist[i]->pipactive |= ACTIVEPART;
1288 		return;
1289 	}
1290 }
1291 
1292 /*
1293  * Routine to examine primitive node "ni" and return true if the repeater is active.
1294  */
fpga_repeateractive(NODEINST * ni)1295 BOOLEAN fpga_repeateractive(NODEINST *ni)
1296 {
1297 	REGISTER VARIABLE *var;
1298 
1299 	var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
1300 	if (var == NOVARIABLE) return(FALSE);
1301 	fpga_repeatername = (CHAR *)var->addr;
1302 	fpga_repeaterisactive = FALSE;
1303 	fpga_findvariableobjects(ni, fpga_activerepeaterskey, fpga_setrepeater);
1304 	return(fpga_repeaterisactive);
1305 }
1306 
1307 /*
1308  * Helper routine for fpga_repeateractive() to determine whether repeater "name" is on.
1309  */
fpga_setrepeater(CHAR * name)1310 void fpga_setrepeater(CHAR *name)
1311 {
1312 	if (namesame(fpga_repeatername, name) == 0) fpga_repeaterisactive = TRUE;
1313 }
1314 
1315 /*
1316  * Routine to clear the cache of arc activity in the current cell.  If "ni" is NONODEINST,
1317  * clear all node caches as well, otherwise only clear the node cache on "ni".
1318  */
fpga_clearcache(NODEINST * ni)1319 void fpga_clearcache(NODEINST *ni)
1320 {
1321 	REGISTER VARIABLE *var;
1322 	REGISTER ARCINST *ai;
1323 	REGISTER NODEPROTO *np;
1324 
1325 	np = getcurcell();
1326 	if (np == NONODEPROTO)
1327 	{
1328 		ttyputerr(_("Must edit a cell to clear its cache"));
1329 		return;
1330 	}
1331 	for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1332 	{
1333 		var = getvalkey((INTBIG)ai, VARCINST, VCHAR|VISARRAY, fpga_arcactivecachekey);
1334 		if (var != NOVARIABLE)
1335 			(void)delvalkey((INTBIG)ai, VARCINST, fpga_arcactivecachekey);
1336 	}
1337 	if (ni != NONODEINST)
1338 	{
1339 		var = getvalkey((INTBIG)ni, VNODEINST, VCHAR|VISARRAY, fpga_nodepipcachekey);
1340 		if (var != NOVARIABLE)
1341 			(void)delvalkey((INTBIG)ni, VNODEINST, fpga_nodepipcachekey);
1342 	}
1343 }
1344 
fpga_findvariableobjects(NODEINST * ni,INTBIG varkey,void (* setit)(CHAR *))1345 void fpga_findvariableobjects(NODEINST *ni, INTBIG varkey, void (*setit)(CHAR*))
1346 {
1347 	static NODEINST *mynilist[200];
1348 	NODEINST **localnilist;
1349 	REGISTER INTBIG curdepth, i, pathgood, depth;
1350 	INTBIG localdepth, *indexlist;
1351 	REGISTER CHAR *pt, *start, save1, save2, *dotpos;
1352 	REGISTER VARIABLE *var;
1353 	CHAR tempbuf[100];
1354 
1355 	/* search hierarchical path */
1356 	gettraversalpath(ni->parent, NOWINDOWPART, &localnilist, &indexlist, &localdepth, 0);
1357 	depth = 0;
1358 	for(i = localdepth - 1; i >= 0; i--)
1359 	{
1360 		ni = localnilist[i];
1361 		mynilist[depth] = ni;
1362 		depth++;
1363 		var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, varkey);
1364 		if (var != NOVARIABLE)
1365 		{
1366 			pt = (CHAR *)var->addr;
1367 			for(;;)
1368 			{
1369 				while (*pt == ' ' || *pt == '\t') pt++;
1370 				start = pt;
1371 				while (*pt != ' ' && *pt != '\t' && *pt != 0) pt++;
1372 				save1 = *pt;
1373 				*pt = 0;
1374 
1375 				/* find pip name in "start" */
1376 				pathgood = 1;
1377 				for(curdepth = depth-2; curdepth >= 0; curdepth--)
1378 				{
1379 					if (*start == 0) { pathgood = 0;   break; }
1380 					dotpos = start;
1381 					while (*dotpos != '.' && *dotpos != 0) dotpos++;
1382 					if (*dotpos != '.') break;
1383 
1384 					save2 = *dotpos;   *dotpos = 0;
1385 					estrcpy(tempbuf, start);
1386 					*dotpos++ = save2;
1387 					start = dotpos;
1388 
1389 					/* make sure instance has the right name */
1390 					var = getvalkey((INTBIG)mynilist[curdepth], VNODEINST, VSTRING, el_node_name_key);
1391 					if (var == NOVARIABLE) { pathgood = 0;   break; }
1392 					if (namesame((CHAR *)var->addr, tempbuf) != 0) { pathgood = 0;   break; }
1393 				}
1394 				if (pathgood != 0) setit(start);
1395 
1396 				*pt = save1;
1397 				if (*pt == 0) break;
1398 			}
1399 			return;
1400 		}
1401 	}
1402 }
1403 
1404 /*
1405  * Routine to fill polygon "poly" with a description of pip "pipindex" on node "ni"
1406  * which is a FPGA NODE "fn".
1407  */
fpga_describepip(NODEINST * ni,FPGANODE * fn,INTBIG pipindex,POLYGON * poly)1408 void fpga_describepip(NODEINST *ni, FPGANODE *fn, INTBIG pipindex, POLYGON *poly)
1409 {
1410 	REGISTER INTBIG xc, yc, lambda;
1411 
1412 	lambda = lambdaofnode(ni);
1413 	if (poly->limit < 2) (void)extendpolygon(poly, 2);
1414 	xc = (ni->lowx+ni->highx)/2;
1415 	yc = (ni->lowy+ni->highy)/2;
1416 	poly->xv[0] = fn->piplist[pipindex]->posx + xc - lambda;
1417 	poly->yv[0] = fn->piplist[pipindex]->posy + yc - lambda;
1418 	poly->xv[1] = fn->piplist[pipindex]->posx + xc + lambda;
1419 	poly->yv[1] = fn->piplist[pipindex]->posy + yc + lambda;
1420 	poly->count = 2;
1421 	poly->style = FILLEDRECT;
1422 	poly->layer = LPIP;
1423 	poly->desc = fpga_layers[poly->layer];
1424 }
1425 
1426 /*
1427  * Routine to fill polygon "poly" with a description of network segment "whichseg"
1428  * on node "ni".  The network is in "fnet".
1429  */
fpga_describenetseg(NODEINST * ni,FPGANET * fnet,INTBIG whichseg,POLYGON * poly)1430 void fpga_describenetseg(NODEINST *ni, FPGANET *fnet, INTBIG whichseg, POLYGON *poly)
1431 {
1432 	REGISTER INTBIG xc, yc;
1433 
1434 	if (poly->limit < 2) (void)extendpolygon(poly, 2);
1435 	xc = (ni->lowx+ni->highx)/2;
1436 	yc = (ni->lowy+ni->highy)/2;
1437 	poly->xv[0] = fnet->segfx[whichseg] + xc;
1438 	poly->yv[0] = fnet->segfy[whichseg] + yc;
1439 	poly->xv[1] = fnet->segtx[whichseg] + xc;
1440 	poly->yv[1] = fnet->segty[whichseg] + yc;
1441 	poly->count = 2;
1442 	poly->style = OPENED;
1443 	poly->layer = LWIRE;
1444 }
1445 
1446 /******************** ARCHITECTURE FILE READING ********************/
1447 
1448 /*
1449  * Routine to read the FPGA file in "f" and create a LISPTREE structure which is returned.
1450  * Returns zero on error.
1451  */
fpga_readfile(FILE * f,void * dia)1452 LISPTREE *fpga_readfile(FILE *f, void *dia)
1453 {
1454 	CHAR line[MAXLINE];
1455 	REGISTER CHAR save, *pt, *ptend;
1456 	REGISTER INTBIG filepos;
1457 	LISPTREE *treetop;
1458 
1459 	/* make the tree top */
1460 	treetop = (LISPTREE *)emalloc((sizeof (LISPTREE)), fpga_tech->cluster);
1461 	if (treetop == 0) return(0);
1462 	if (allocstring(&treetop->keyword, x_("TOP"), fpga_tech->cluster)) return(0);
1463 	treetop->paramtotal = 0;
1464 	treetop->parameters = 0;
1465 
1466 	/* initialize current position and stack */
1467 	fpga_treepos = treetop;
1468 	fpga_treedepth = 0;
1469 	fpga_lineno = 0;
1470 
1471 	for(;;)
1472 	{
1473 		/* get the next line of text */
1474 		if (xfgets(line, MAXLINE, f)) break;
1475 		fpga_lineno++;
1476 		if ((fpga_lineno%50) == 0)
1477 		{
1478 			filepos = xtell(f);
1479 			DiaSetProgress(dia, filepos, fpga_filesize);
1480 		}
1481 
1482 		/* stop now if it is a comment */
1483 		for(pt = line; *pt != 0; pt++) if (*pt != ' ' && *pt != '\t') break;
1484 		if (*pt == '#') continue;
1485 
1486 		/* keep parsing it */
1487 		pt = line;
1488 		for(;;)
1489 		{
1490 			/* skip spaces */
1491 			while (*pt == ' ' || *pt == '\t') pt++;
1492 			if (*pt == 0) break;
1493 
1494 			/* check for special characters */
1495 			if (*pt == ')')
1496 			{
1497 				save = pt[1];
1498 				pt[1] = 0;
1499 				if (fpga_pushkeyword(pt)) return(0);
1500 				pt[1] = save;
1501 				pt++;
1502 				continue;
1503 			}
1504 
1505 			/* gather a keyword */
1506 			ptend = pt;
1507 			for(;;)
1508 			{
1509 				if (*ptend == ')' || *ptend == ' ' || *ptend == '\t' || *ptend == 0) break;
1510 				if (*ptend == '"')
1511 				{
1512 					ptend++;
1513 					for(;;)
1514 					{
1515 						if (*ptend == 0 || *ptend == '"') break;
1516 						ptend++;
1517 					}
1518 					if (*ptend == '"') ptend++;
1519 					break;
1520 				}
1521 				ptend++;
1522 			}
1523 			save = *ptend;   *ptend = 0;
1524 			if (fpga_pushkeyword(pt)) return(0);
1525 			*ptend = save;
1526 			pt = ptend;
1527 		}
1528 	}
1529 
1530 	if (fpga_treedepth != 0)
1531 	{
1532 		ttyputerr(_("Not enough close parenthesis in file"));
1533 		return(0);
1534 	}
1535 	return(treetop);
1536 }
1537 
1538 /*
1539  * Routine to add the next keyword "keyword" to the lisp tree in the globals.
1540  * Returns true on error.
1541  */
fpga_pushkeyword(CHAR * keyword)1542 BOOLEAN fpga_pushkeyword(CHAR *keyword)
1543 {
1544 	REGISTER LISPTREE *newtree;
1545 	CHAR *savekey;
1546 	REGISTER CHAR *pt;
1547 
1548 	if (keyword[0] == '(')
1549 	{
1550 		if (fpga_treedepth >= MAXDEPTH)
1551 		{
1552 			ttyputerr(_("Nesting too deep (more than %d)"), MAXDEPTH);
1553 			return(TRUE);
1554 		}
1555 
1556 		/* create a new tree branch */
1557 		newtree = fpga_alloclisptree();
1558 		newtree->parameters = 0;
1559 		newtree->paramtotal = 0;
1560 		newtree->lineno = fpga_lineno;
1561 
1562 		/* add branch to previous branch */
1563 		if (fpga_addparameter(fpga_treepos, PARAMBRANCH, newtree)) return(TRUE);
1564 
1565 		/* add keyword */
1566 		pt = &keyword[1];
1567 		while (*pt == ' ' && *pt == '\t') pt++;
1568 		if (allocstring(&newtree->keyword, pt, fpga_tech->cluster)) return(TRUE);
1569 
1570 		/* push tree onto stack */
1571 		fpga_treestack[fpga_treedepth] = fpga_treepos;
1572 		fpga_treedepth++;
1573 		fpga_treepos = newtree;
1574 		return(FALSE);
1575 	}
1576 
1577 	if (estrcmp(keyword, x_(")")) == 0)
1578 	{
1579 		/* pop tree stack */
1580 		if (fpga_treedepth <= 0)
1581 		{
1582 			ttyputerr(_("Too many close parenthesis"));
1583 			return(TRUE);
1584 		}
1585 		fpga_treedepth--;
1586 		fpga_treepos = fpga_treestack[fpga_treedepth];
1587 		return(FALSE);
1588 	}
1589 
1590 	/* just add the atomic keyword */
1591 	if (keyword[0] == '"' && keyword[estrlen(keyword)-1] == '"')
1592 	{
1593 		keyword++;
1594 		keyword[estrlen(keyword)-1] = 0;
1595 	}
1596 	if (allocstring(&savekey, keyword, fpga_tech->cluster)) return(TRUE);
1597 	if (fpga_addparameter(fpga_treepos, PARAMATOM, savekey)) return(TRUE);
1598 	return(FALSE);
1599 }
1600 
1601 /*
1602  * Routine to add a parameter of type "type" and value "value" to the tree element "tree".
1603  * Returns true on memory error.
1604  */
fpga_addparameter(LISPTREE * tree,INTBIG type,void * value)1605 BOOLEAN fpga_addparameter(LISPTREE *tree, INTBIG type, void *value)
1606 {
1607 	REGISTER INTBIG *newparamtypes;
1608 	REGISTER INTBIG i, newlimit;
1609 	REGISTER void **newparamvalues;
1610 
1611 	if (tree->parameters >= tree->paramtotal)
1612 	{
1613 		newlimit = tree->paramtotal * 2;
1614 		if (newlimit <= 0)
1615 		{
1616 			/* intelligent determination of parameter needs */
1617 			if (namesame(tree->keyword, x_("port")) == 0) newlimit = 3; else
1618 			if (namesame(tree->keyword, x_("name")) == 0) newlimit = 1; else
1619 			if (namesame(tree->keyword, x_("position")) == 0) newlimit = 2; else
1620 			if (namesame(tree->keyword, x_("direction")) == 0) newlimit = 1; else
1621 			if (namesame(tree->keyword, x_("size")) == 0) newlimit = 2; else
1622 			if (namesame(tree->keyword, x_("segment")) == 0) newlimit = 6; else
1623 			if (namesame(tree->keyword, x_("pip")) == 0) newlimit = 3; else
1624 			if (namesame(tree->keyword, x_("connectivity")) == 0) newlimit = 2; else
1625 			if (namesame(tree->keyword, x_("repeater")) == 0) newlimit = 4; else
1626 			if (namesame(tree->keyword, x_("porta")) == 0) newlimit = 2; else
1627 			if (namesame(tree->keyword, x_("portb")) == 0) newlimit = 2; else
1628 			if (namesame(tree->keyword, x_("type")) == 0) newlimit = 1; else
1629 				newlimit = 3;
1630 		}
1631 		newparamtypes = (INTBIG *)emalloc(newlimit * SIZEOFINTBIG, fpga_tech->cluster);
1632 		if (newparamtypes == 0) return(TRUE);
1633 		newparamvalues = (void **)emalloc(newlimit * (sizeof (void *)), fpga_tech->cluster);
1634 		if (newparamvalues == 0) return(TRUE);
1635 		for(i=0; i<tree->parameters; i++)
1636 		{
1637 			newparamtypes[i] = tree->paramtype[i];
1638 			newparamvalues[i] = tree->paramvalue[i];
1639 		}
1640 		if (tree->paramtotal > 0)
1641 		{
1642 			efree((CHAR *)tree->paramtype);
1643 			efree((CHAR *)tree->paramvalue);
1644 		}
1645 		tree->paramtype = newparamtypes;
1646 		tree->paramvalue = newparamvalues;
1647 		tree->paramtotal = newlimit;
1648 	}
1649 	tree->paramtype[tree->parameters] = type;
1650 	tree->paramvalue[tree->parameters] = value;
1651 	tree->parameters++;
1652 	return(FALSE);
1653 }
1654 
fpga_alloclisptree(void)1655 LISPTREE *fpga_alloclisptree(void)
1656 {
1657 	LISPTREE *lt;
1658 
1659 	if (fpga_freelisptree != 0)
1660 	{
1661 		lt = fpga_freelisptree;
1662 		fpga_freelisptree = (LISPTREE *)lt->paramvalue;
1663 	} else
1664 	{
1665 		lt = (LISPTREE *)emalloc(sizeof (LISPTREE), fpga_tech->cluster);
1666 		if (lt == 0) return(0);
1667 	}
1668 	return(lt);
1669 }
1670 
fpga_killptree(LISPTREE * lt)1671 void fpga_killptree(LISPTREE *lt)
1672 {
1673 	REGISTER INTBIG i;
1674 
1675 	if (lt->keyword != 0) efree(lt->keyword);
1676 	for(i=0; i<lt->parameters; i++)
1677 	{
1678 		if (lt->paramtype[i] == PARAMBRANCH)
1679 		{
1680 			fpga_killptree((LISPTREE *)lt->paramvalue[i]);
1681 		} else
1682 		{
1683 			efree((CHAR *)lt->paramvalue[i]);
1684 		}
1685 	}
1686 	if (lt->parameters > 0)
1687 	{
1688 		efree((CHAR *)lt->paramtype);
1689 		efree((CHAR *)lt->paramvalue);
1690 	}
1691 
1692 	/* put it back on the free list */
1693 	lt->paramvalue = (void **)fpga_freelisptree;
1694 	fpga_freelisptree = lt;
1695 }
1696 
1697 /******************** ARCHITECTURE PARSING: PRIMITIVES ********************/
1698 
1699 /*
1700  * Routine to parse the entire tree and create primitives.
1701  * Returns the number of primitives made.
1702  */
fpga_makeprimitives(LISPTREE * lt)1703 INTBIG fpga_makeprimitives(LISPTREE *lt)
1704 {
1705 	REGISTER INTBIG i, total;
1706 	REGISTER LISPTREE *sublt;
1707 
1708 	/* look through top level for the "primdef"s */
1709 	total = 0;
1710 	for(i=0; i<lt->parameters; i++)
1711 	{
1712 		if (lt->paramtype[i] != PARAMBRANCH) continue;
1713 		sublt = (LISPTREE *)lt->paramvalue[i];
1714 		if (namesame(sublt->keyword, x_("primdef")) != 0) continue;
1715 
1716 		/* create the primitive */
1717 		if (fpga_makeprimitive(sublt)) return(0);
1718 		total++;
1719 	}
1720 	return(total);
1721 }
1722 
1723 /*
1724  * Routine to create a primitive from a subtree "lt".
1725  * Tree has "(primdef...)" structure.
1726  */
fpga_makeprimitive(LISPTREE * lt)1727 BOOLEAN fpga_makeprimitive(LISPTREE *lt)
1728 {
1729 #ifdef USE_REDOPRIM
1730 	REGISTER INTBIG i, j, k;
1731 #else
1732 	REGISTER INTBIG i, j, k, l;
1733 #endif
1734 	REGISTER INTBIG sizex, sizey, *newnodewidoff, lambda;
1735 	REGISTER NODEPROTO *np, *primnp, *lastnp;
1736 	REGISTER LISPTREE *scanlt, *ltattribute, *ltnets, *ltports, *ltcomponents;
1737 	REGISTER VARIABLE *var;
1738 	REGISTER FPGANODE *fn, **fnlist;
1739 	REGISTER FPGANET *fnetblock;
1740 	REGISTER FPGAPIP *fpipblock;
1741 	REGISTER FPGAPORT *fpblock, *fp;
1742 	REGISTER CHAR *primname, *primsizex, *primsizey;
1743 
1744 	/* find all of the pieces of this primitive */
1745 	ltattribute = ltnets = ltports = ltcomponents = 0;
1746 	for(i=0; i<lt->parameters; i++)
1747 	{
1748 		if (lt->paramtype[i] != PARAMBRANCH) continue;
1749 		scanlt = (LISPTREE *)lt->paramvalue[i];
1750 		if (namesame(scanlt->keyword, x_("attributes")) == 0)
1751 		{
1752 			if (ltattribute != 0)
1753 			{
1754 				ttyputerr(_("Multiple 'attributes' sections for a primitive (line %ld)"), scanlt->lineno);
1755 				return(TRUE);
1756 			}
1757 			ltattribute = scanlt;
1758 			continue;
1759 		}
1760 		if (namesame(scanlt->keyword, x_("nets")) == 0)
1761 		{
1762 			if (ltnets != 0)
1763 			{
1764 				ttyputerr(_("Multiple 'nets' sections for a primitive (line %ld)"), scanlt->lineno);
1765 				return(TRUE);
1766 			}
1767 			ltnets = scanlt;
1768 			continue;
1769 		}
1770 		if (namesame(scanlt->keyword, x_("ports")) == 0)
1771 		{
1772 			if (ltports != 0)
1773 			{
1774 				ttyputerr(_("Multiple 'ports' sections for a primitive (line %ld)"), scanlt->lineno);
1775 				return(TRUE);
1776 			}
1777 			ltports = scanlt;
1778 			continue;
1779 		}
1780 		if (namesame(scanlt->keyword, x_("components")) == 0)
1781 		{
1782 			if (ltcomponents != 0)
1783 			{
1784 				ttyputerr(_("Multiple 'components' sections for a primitive (line %ld)"),
1785 					scanlt->lineno);
1786 				return(TRUE);
1787 			}
1788 			ltcomponents = scanlt;
1789 			continue;
1790 		}
1791 	}
1792 
1793 	/* scan the attributes section */
1794 	if (ltattribute == 0)
1795 	{
1796 		ttyputerr(_("Missing 'attributes' sections on a primitive (line %ld)"), lt->lineno);
1797 		return(TRUE);
1798 	}
1799 	primname = 0;
1800 	primsizex = 0;
1801 	primsizey = 0;
1802 	for(j=0; j<ltattribute->parameters; j++)
1803 	{
1804 		if (ltattribute->paramtype[j] != PARAMBRANCH) continue;
1805 		scanlt = (LISPTREE *)ltattribute->paramvalue[j];
1806 		if (namesame(scanlt->keyword, x_("name")) == 0)
1807 		{
1808 			if (scanlt->parameters != 1 || scanlt->paramtype[0] != PARAMATOM)
1809 			{
1810 				ttyputerr(_("Primitive 'name' attribute should take a single atomic parameter (line %ld)"),
1811 					scanlt->lineno);
1812 				return(TRUE);
1813 			}
1814 			primname = (CHAR *)scanlt->paramvalue[0];
1815 			continue;
1816 		}
1817 		if (namesame(scanlt->keyword, x_("size")) == 0)
1818 		{
1819 			if (scanlt->parameters != 2 || scanlt->paramtype[0] != PARAMATOM ||
1820 				scanlt->paramtype[1] != PARAMATOM)
1821 			{
1822 				ttyputerr(_("Primitive 'size' attribute should take two atomic parameters (line %ld)"),
1823 					scanlt->lineno);
1824 				return(TRUE);
1825 			}
1826 			primsizex = (CHAR *)scanlt->paramvalue[0];
1827 			primsizey = (CHAR *)scanlt->paramvalue[1];
1828 			continue;
1829 		}
1830 	}
1831 
1832 	/* make sure a name and size were given */
1833 	if (primname == 0)
1834 	{
1835 		ttyputerr(_("Missing 'name' attribute in primitive definition (line %ld)"),
1836 			ltattribute->lineno);
1837 		return(TRUE);
1838 	}
1839 	if (primsizex == 0 || primsizey == 0)
1840 	{
1841 		ttyputerr(_("Missing 'size' attribute in primitive definition (line %ld)"),
1842 			ltattribute->lineno);
1843 		return(TRUE);
1844 	}
1845 
1846 	/* make the primitive */
1847 	primnp = allocnodeproto(fpga_tech->cluster);
1848 	if (primnp == NONODEPROTO) return(TRUE);
1849 	if (allocstring(&primnp->protoname, primname, fpga_tech->cluster)) return(TRUE);
1850 	lambda = el_curlib->lambda[fpga_tech->techindex];
1851 	sizex = myatoi(primsizex) * lambda;
1852 	sizey = myatoi(primsizey) * lambda;
1853 	primnp->lowx = -sizex/2;   primnp->highx = primnp->lowx + sizex;
1854 	primnp->lowy = -sizey/2;   primnp->highy = primnp->lowy + sizey;
1855 	primnp->tech = fpga_tech;
1856 	primnp->userbits |= LOCKEDPRIM;
1857 
1858 	/* link it into this technology */
1859 	lastnp = NONODEPROTO;
1860 	for(np = fpga_tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1861 		lastnp = np;
1862 	lastnp->nextnodeproto = primnp;
1863 	primnp->prevnodeproto = lastnp;
1864 	primnp->primindex = lastnp->primindex + 1;
1865 
1866 	/* extend the node width offset array */
1867 	var = getval((INTBIG)fpga_tech, VTECHNOLOGY, VFRACT|VISARRAY, x_("TECH_node_width_offset"));
1868 	if (var != NOVARIABLE)
1869 	{
1870 		newnodewidoff = (INTBIG *)emalloc(primnp->primindex * 4 * SIZEOFINTBIG, fpga_tech->cluster);
1871 		if (newnodewidoff == 0) return(TRUE);
1872 		for(j=0; j<(primnp->primindex-1)*4; j++)
1873 			newnodewidoff[j] = ((INTBIG *)var->addr)[j];
1874 		newnodewidoff[primnp->primindex*4-1] = 0;
1875 		newnodewidoff[primnp->primindex*4-2] = 0;
1876 		newnodewidoff[primnp->primindex*4-3] = 0;
1877 		newnodewidoff[primnp->primindex*4-4] = 0;
1878 		setval((INTBIG)fpga_tech, VTECHNOLOGY, x_("TECH_node_width_offset"), (INTBIG)newnodewidoff,
1879 			VFRACT|VDONTSAVE|VISARRAY|((primnp->primindex*4)<<VLENGTHSH));
1880 		efree((CHAR *)newnodewidoff);
1881 	}
1882 
1883 	/* add any unrecognized attributes */
1884 	for(j=0; j<ltattribute->parameters; j++)
1885 	{
1886 		if (ltattribute->paramtype[j] != PARAMBRANCH) continue;
1887 		scanlt = (LISPTREE *)ltattribute->paramvalue[j];
1888 		if (namesame(scanlt->keyword, x_("name")) == 0) continue;
1889 		if (namesame(scanlt->keyword, x_("size")) == 0) continue;
1890 
1891 		if (scanlt->parameters != 1 || scanlt->paramtype[0] != PARAMATOM)
1892 		{
1893 			ttyputerr(_("Attribute '%s' attribute should take a single atomic parameter (line %ld)"),
1894 				scanlt->keyword, scanlt->lineno);
1895 			return(TRUE);
1896 		}
1897 		(void)setval((INTBIG)primnp, VNODEPROTO, scanlt->keyword, (INTBIG)scanlt->paramvalue[0],
1898 			VSTRING);
1899 	}
1900 
1901 	/* create a local structure for this node */
1902 	fn = (FPGANODE *)emalloc(sizeof (FPGANODE), fpga_tech->cluster);
1903 	if (fn == 0) return(TRUE);
1904 	fnlist = (FPGANODE **)emalloc((primnp->primindex - NODEPROTOCOUNT) * (sizeof (FPGANODE *)),
1905 		fpga_tech->cluster);
1906 	if (fnlist == 0) return(TRUE);
1907 	for(j=0; j<primnp->primindex - NODEPROTOCOUNT - 1; j++)
1908 		fnlist[j] = fpga_nodes[j];
1909 	fnlist[primnp->primindex - NODEPROTOCOUNT - 1] = fn;
1910 	if (fpga_nodecount > 0) efree((CHAR *)fpga_nodes);
1911 	fpga_nodes = fnlist;
1912 	fpga_nodecount++;
1913 
1914 	/* get ports */
1915 	fn->portcount = 0;
1916 	if (ltports != 0)
1917 	{
1918 		/* count ports */
1919 		for(j=0; j<ltports->parameters; j++)
1920 		{
1921 			if (ltports->paramtype[j] != PARAMBRANCH) continue;
1922 			scanlt = (LISPTREE *)ltports->paramvalue[j];
1923 			if (namesame(scanlt->keyword, x_("port")) == 0) fn->portcount++;
1924 		}
1925 
1926 		/* create local port structures */
1927 		fn->portlist = (FPGAPORT **)emalloc(fn->portcount * (sizeof (FPGAPORT *)), fpga_tech->cluster);
1928 		if (fn->portlist == 0) return(TRUE);
1929 		fpblock = (FPGAPORT *)emalloc(fn->portcount * (sizeof (FPGAPORT)), fpga_tech->cluster);
1930 		for(i=0; i<fn->portcount; i++)
1931 		{
1932 			fn->portlist[i] = fpblock;
1933 			fn->portlist[i]->pp = NOPORTPROTO;
1934 			fpblock++;
1935 		}
1936 
1937 		/* create the ports */
1938 		for(j=i=0; j<ltports->parameters; j++)
1939 		{
1940 			if (ltports->paramtype[j] != PARAMBRANCH) continue;
1941 			scanlt = (LISPTREE *)ltports->paramvalue[j];
1942 			if (namesame(scanlt->keyword, x_("port")) == 0)
1943 			{
1944 				if (fpga_makeprimport(primnp, scanlt, fn->portlist[i])) return(TRUE);
1945 				i++;
1946 			}
1947 		}
1948 	}
1949 
1950 	/* get nets */
1951 	fn->netcount = 0;
1952 	if (ltnets != 0)
1953 	{
1954 		/* count the nets */
1955 		for(j=0; j<ltnets->parameters; j++)
1956 		{
1957 			if (ltnets->paramtype[j] != PARAMBRANCH) continue;
1958 			scanlt = (LISPTREE *)ltnets->paramvalue[j];
1959 			if (namesame(scanlt->keyword, x_("net")) == 0) fn->netcount++;
1960 		}
1961 
1962 		/* create local net structures */
1963 		fn->netlist = (FPGANET **)emalloc(fn->netcount * (sizeof (FPGANET *)), fpga_tech->cluster);
1964 		if (fn->netlist == 0) return(TRUE);
1965 		fnetblock = (FPGANET *)emalloc(fn->netcount * (sizeof (FPGANET)), fpga_tech->cluster);
1966 		if (fnetblock == 0) return(TRUE);
1967 		for(i=0; i<fn->netcount; i++)
1968 		{
1969 			fn->netlist[i] = fnetblock;
1970 			fn->netlist[i]->netname = 0;
1971 			fn->netlist[i]->segcount = 0;
1972 			fnetblock++;
1973 		}
1974 
1975 		/* create the nets */
1976 		for(j=i=0; j<ltnets->parameters; j++)
1977 		{
1978 			if (ltnets->paramtype[j] != PARAMBRANCH) continue;
1979 			scanlt = (LISPTREE *)ltnets->paramvalue[j];
1980 			if (namesame(scanlt->keyword, x_("net")) == 0)
1981 			{
1982 				if (fpga_makeprimnet(primnp, scanlt, fn, fn->netlist[i])) return(TRUE);
1983 				i++;
1984 			}
1985 		}
1986 	}
1987 
1988 	/* associate nets and ports */
1989 	for(k=0; k<fn->portcount; k++)
1990 	{
1991 		fp = fn->portlist[k];
1992 		for(i=0; i<fn->netcount; i++)
1993 		{
1994 			for(j=0; j<fn->netlist[i]->segcount; j++)
1995 			{
1996 				if ((fn->netlist[i]->segfx[j] == fp->posx && fn->netlist[i]->segfy[j] == fp->posy) ||
1997 					(fn->netlist[i]->segtx[j] == fp->posx && fn->netlist[i]->segty[j] == fp->posy))
1998 				{
1999 					fp->con = i;
2000 					break;
2001 				}
2002 			}
2003 			if (j < fn->netlist[i]->segcount) break;
2004 		}
2005 	}
2006 
2007 	/* set electrical connectivity */
2008 #ifdef USE_REDOPRIM
2009 	for(k=0; k<fn->portcount; k++)
2010 	{
2011 		if (fn->portlist[k]->con < 0)
2012 		{
2013 			fn->portlist[k]->pp->userbits |= PORTNET;
2014 		} else
2015 		{
2016 			if (fn->portlist[k]->con >= (PORTNET >> PORTNETSH))
2017 			{
2018 				ttyputerr(_("Too many networks in FPGA primitive"));
2019 			}
2020 			fn->portlist[k]->pp->userbits |= (fn->portlist[k]->con >> PORTNETSH);
2021 		}
2022 	}
2023 #else
2024 	for(k=0; k<fn->portcount; k++)
2025 	{
2026 		if (fn->portlist[k]->con < 0) continue;
2027 		for(l=k+1; l<fn->portcount; l++)
2028 		{
2029 			if (fn->portlist[k]->con != fn->portlist[l]->con) continue;
2030 			if (fn->portlist[l]->pp->network != fn->portlist[k]->pp->network)
2031 			{
2032 				efree((CHAR *)fn->portlist[l]->pp->network);
2033 				fn->portlist[l]->pp->network = fn->portlist[k]->pp->network;
2034 			}
2035 		}
2036 	}
2037 #endif
2038 
2039 	/* get pips */
2040 	fn->pipcount = 0;
2041 	if (ltcomponents != 0)
2042 	{
2043 		/* count the pips */
2044 		for(j=0; j<ltcomponents->parameters; j++)
2045 		{
2046 			if (ltcomponents->paramtype[j] != PARAMBRANCH) continue;
2047 			scanlt = (LISPTREE *)ltcomponents->paramvalue[j];
2048 			if (namesame(scanlt->keyword, x_("pip")) == 0) fn->pipcount++;
2049 		}
2050 
2051 		/* create local pips structures */
2052 		fn->piplist = (FPGAPIP **)emalloc(fn->pipcount * (sizeof (FPGANET *)), fpga_tech->cluster);
2053 		if (fn->piplist == 0) return(TRUE);
2054 		fpipblock = (FPGAPIP *)emalloc(fn->pipcount * (sizeof (FPGANET)), fpga_tech->cluster);
2055 		if (fpipblock == 0) return(TRUE);
2056 		for(i=0; i<fn->pipcount; i++)
2057 		{
2058 			fn->piplist[i] = fpipblock;
2059 			fpipblock++;
2060 		}
2061 
2062 		/* create the pips */
2063 		for(j=i=0; j<ltcomponents->parameters; j++)
2064 		{
2065 			if (ltcomponents->paramtype[j] != PARAMBRANCH) continue;
2066 			scanlt = (LISPTREE *)ltcomponents->paramvalue[j];
2067 			if (namesame(scanlt->keyword, x_("pip")) == 0)
2068 			{
2069 				if (fpga_makeprimpip(primnp, scanlt, fn, fn->piplist[i])) return(TRUE);
2070 				i++;
2071 			}
2072 		}
2073 	}
2074 	return(FALSE);
2075 }
2076 
2077 /*
2078  * Routine to add a port to primitive "np" from the tree in "lt" and
2079  * store information about it in the local structure "fp".
2080  * Tree has "(port...)" structure.  Returns true on error.
2081  */
fpga_makeprimport(NODEPROTO * np,LISPTREE * lt,FPGAPORT * fp)2082 BOOLEAN fpga_makeprimport(NODEPROTO *np, LISPTREE *lt, FPGAPORT *fp)
2083 {
2084 	REGISTER INTBIG j;
2085 	REGISTER INTBIG lambda;
2086 	PORTPROTO *pp, *newpp, *lastpp;
2087 	REGISTER LISPTREE *ltname, *ltposition, *ltdirection, *scanlt;
2088 
2089 	/* look for keywords */
2090 	ltname = ltposition = ltdirection = 0;
2091 	for(j=0; j<lt->parameters; j++)
2092 	{
2093 		if (lt->paramtype[j] != PARAMBRANCH) continue;
2094 		scanlt = (LISPTREE *)lt->paramvalue[j];
2095 		if (namesame(scanlt->keyword, x_("name")) == 0)
2096 		{
2097 			ltname = scanlt;
2098 			continue;
2099 		}
2100 		if (namesame(scanlt->keyword, x_("position")) == 0)
2101 		{
2102 			ltposition = scanlt;
2103 			continue;
2104 		}
2105 		if (namesame(scanlt->keyword, x_("direction")) == 0)
2106 		{
2107 			ltdirection = scanlt;
2108 			continue;
2109 		}
2110 	}
2111 
2112 	/* validate */
2113 	if (ltname == 0)
2114 	{
2115 		ttyputerr(_("Port has no name (line %ld)"), lt->lineno);
2116 		return(TRUE);
2117 	}
2118 	if (ltname->parameters != 1 || ltname->paramtype[0] != PARAMATOM)
2119 	{
2120 		ttyputerr(_("Port name must be a single atom (line %ld)"), ltname->lineno);
2121 		return(TRUE);
2122 	}
2123 	if (ltposition == 0)
2124 	{
2125 		ttyputerr(_("Port has no position (line %ld)"), lt->lineno);
2126 		return(TRUE);
2127 	}
2128 	if (ltposition->parameters != 2 || ltposition->paramtype[0] != PARAMATOM ||
2129 		ltposition->paramtype[1] != PARAMATOM)
2130 	{
2131 		ttyputerr(_("Port position must be two atoms (line %ld)"), ltposition->lineno);
2132 		return(TRUE);
2133 	}
2134 	pp = getportproto(np, (CHAR *)ltname->paramvalue[0]);
2135 	if (pp != NOPORTPROTO)
2136 	{
2137 		ttyputerr(_("Duplicate port name (line %ld)"), lt->lineno);
2138 		return(TRUE);
2139 	}
2140 
2141 	/* create the portproto */
2142 	newpp = allocportproto(fpga_tech->cluster);
2143 	if (newpp == NOPORTPROTO) return(TRUE);
2144 	newpp->parent = np;
2145 	if (allocstring(&newpp->protoname, (CHAR *)ltname->paramvalue[0], fpga_tech->cluster)) return(TRUE);
2146 	TDCLEAR(newpp->textdescript);
2147 	newpp->userbits = (180 << PORTARANGESH);
2148 	newpp->connects = fpga_wirepinprim->firstportproto->connects;
2149 
2150 #ifndef USE_REDOPRIM
2151 	/* make a unique network for the port */
2152 	newpp->network = (NETWORK *)emalloc(sizeof (NETWORK), fpga_tech->cluster);
2153 	if (newpp->network == 0) return(TRUE);
2154 	newpp->network->namecount = 0;
2155 	newpp->network->buswidth = 1;
2156 	newpp->network->nextnetwork  = NONETWORK;
2157 	newpp->network->prevnetwork = NONETWORK;
2158 	newpp->network->networklist = (NETWORK **)NONETWORK;
2159 	newpp->network->parent = NONODEPROTO;
2160 	newpp->network->netname = NOSTRING;
2161 	newpp->network->arccount = 0;
2162 	newpp->network->refcount = 0;
2163 	newpp->network->portcount = 0;
2164 	newpp->network->buslinkcount = 0;
2165 	newpp->network->numvar = 0;
2166 #endif
2167 
2168 	/* add in directionality */
2169 	if (ltdirection != 0)
2170 	{
2171 		if (ltdirection->parameters != 1 || ltdirection->paramtype[0] != PARAMATOM)
2172 		{
2173 			ttyputerr(_("Port direction must be a single atom (line %ld)"), ltdirection->lineno);
2174 			return(TRUE);
2175 		}
2176 		if (namesame((CHAR *)ltdirection->paramvalue[0], x_("input")) == 0) newpp->userbits |= INPORT; else
2177 			if (namesame((CHAR *)ltdirection->paramvalue[0], x_("output")) == 0) newpp->userbits |= OUTPORT; else
2178 				if (namesame((CHAR *)ltdirection->paramvalue[0], x_("bidir")) == 0) newpp->userbits |= BIDIRPORT; else
2179 		{
2180 			ttyputerr(_("Unknown port direction (line %ld)"), ltdirection->lineno);
2181 			return(TRUE);
2182 		}
2183 	}
2184 
2185 	/* link it into the primitive */
2186 	lastpp = NOPORTPROTO;
2187 	for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2188 		lastpp = pp;
2189 	if (lastpp == NOPORTPROTO) np->firstportproto = newpp; else
2190 		lastpp->nextportproto = newpp;
2191 
2192 	/* set unique topology for this port */
2193 	if (lastpp == NOPORTPROTO) j = 0; else
2194 		j = ((lastpp->userbits & PORTNET) >> PORTNETSH) + 1;
2195 	newpp->userbits |= (j << PORTNETSH);
2196 
2197 	/* add it to the local port structure */
2198 	lambda = el_curlib->lambda[fpga_tech->techindex];
2199 	fp->posx = myatoi((CHAR *)ltposition->paramvalue[0]) * lambda + np->lowx;
2200 	fp->posy = myatoi((CHAR *)ltposition->paramvalue[1]) * lambda + np->lowy;
2201 	fp->pp = newpp;
2202 	fp->con = -1;
2203 	return(FALSE);
2204 }
2205 
2206 /*
2207  * Routine to add a net to primitive "np" from the tree in "lt" and store information
2208  * about it in the local object "fnet".
2209  * Tree has "(net...)" structure.  Returns true on error.
2210  */
fpga_makeprimnet(NODEPROTO * np,LISPTREE * lt,FPGANODE * fn,FPGANET * fnet)2211 BOOLEAN fpga_makeprimnet(NODEPROTO *np, LISPTREE *lt, FPGANODE *fn, FPGANET *fnet)
2212 {
2213 	REGISTER INTBIG i, j, k, pos;
2214 	REGISTER INTBIG *newsegfx, *newsegfy, *newsegtx, *newsegty, *newsegcoords, lambda;
2215 	REGISTER LISPTREE *scanlt;
2216 	INTBIG sx[2], sy[2];
2217 
2218 	/* scan for information in the tree */
2219 	fnet->netname = 0;
2220 	fnet->segcount = 0;
2221 	for(j=0; j<lt->parameters; j++)
2222 	{
2223 		if (lt->paramtype[j] != PARAMBRANCH) continue;
2224 		scanlt = (LISPTREE *)lt->paramvalue[j];
2225 		if (namesame(scanlt->keyword, x_("name")) == 0 && scanlt->parameters == 1 &&
2226 			scanlt->paramtype[0] == PARAMATOM)
2227 		{
2228 			if (fnet->netname != 0)
2229 			{
2230 				ttyputerr(_("Multiple names for network (line %ld)"), lt->lineno);
2231 				return(TRUE);
2232 			}
2233 			if (allocstring(&fnet->netname, (CHAR *)scanlt->paramvalue[0], fpga_tech->cluster)) return(TRUE);
2234 			continue;
2235 		}
2236 		if (namesame(scanlt->keyword, x_("segment")) == 0)
2237 		{
2238 			pos = 0;
2239 			for(i=0; i<2; i++)
2240 			{
2241 				/* get end of net segment */
2242 				if (scanlt->parameters < pos+1)
2243 				{
2244 					ttyputerr(_("Incomplete block net segment (line %ld)"), scanlt->lineno);
2245 					return(TRUE);
2246 				}
2247 				if (scanlt->paramtype[pos] != PARAMATOM)
2248 				{
2249 					ttyputerr(_("Must have atoms in block net segment (line %ld)"), scanlt->lineno);
2250 					return(TRUE);
2251 				}
2252 				if (namesame((CHAR *)scanlt->paramvalue[pos], x_("coord")) == 0)
2253 				{
2254 					if (scanlt->parameters < pos+3)
2255 					{
2256 						ttyputerr(_("Incomplete block net segment (line %ld)"), scanlt->lineno);
2257 						return(TRUE);
2258 					}
2259 					if (scanlt->paramtype[pos+1] != PARAMATOM || scanlt->paramtype[pos+2] != PARAMATOM)
2260 					{
2261 						ttyputerr(_("Must have atoms in block net segment (line %ld)"), scanlt->lineno);
2262 						return(TRUE);
2263 					}
2264 					lambda = el_curlib->lambda[fpga_tech->techindex];
2265 					sx[i] = myatoi((CHAR *)scanlt->paramvalue[pos+1]) * lambda + np->lowx;
2266 					sy[i] = myatoi((CHAR *)scanlt->paramvalue[pos+2]) * lambda + np->lowy;
2267 					pos += 3;
2268 				} else if (namesame((CHAR *)scanlt->paramvalue[pos], x_("port")) == 0)
2269 				{
2270 					if (scanlt->parameters < pos+2)
2271 					{
2272 						ttyputerr(_("Incomplete block net segment (line %ld)"), scanlt->lineno);
2273 						return(TRUE);
2274 					}
2275 					if (scanlt->paramtype[pos+1] != PARAMATOM)
2276 					{
2277 						ttyputerr(_("Must have atoms in block net segment (line %ld)"), scanlt->lineno);
2278 						return(TRUE);
2279 					}
2280 
2281 					/* find port */
2282 					for(k=0; k<fn->portcount; k++)
2283 					{
2284 						if (namesame(fn->portlist[k]->pp->protoname, (CHAR *)scanlt->paramvalue[pos+1]) == 0)
2285 							break;
2286 					}
2287 					if (k >= fn->portcount)
2288 					{
2289 						ttyputerr(_("Unknown port on primitive net segment (line %ld)"), scanlt->lineno);
2290 						return(TRUE);
2291 					}
2292 					sx[i] = fn->portlist[k]->posx;
2293 					sy[i] = fn->portlist[k]->posy;
2294 					pos += 2;
2295 				} else
2296 				{
2297 					ttyputerr(_("Unknown keyword '%s' in block net segment (line %ld)"),
2298 						(CHAR *)scanlt->paramvalue[pos], scanlt->lineno);
2299 					return(TRUE);
2300 				}
2301 			}
2302 
2303 			newsegcoords = (INTBIG *)emalloc((fnet->segcount+1) * 4 * SIZEOFINTBIG, fpga_tech->cluster);
2304 			if (newsegcoords == 0) return(TRUE);
2305 			newsegfx = newsegcoords;
2306 			newsegfy = newsegfx;   newsegfy += fnet->segcount+1;
2307 			newsegtx = newsegfy;   newsegtx += fnet->segcount+1;
2308 			newsegty = newsegtx;   newsegty += fnet->segcount+1;
2309 			for(i=0; i<fnet->segcount; i++)
2310 			{
2311 				newsegfx[i] = fnet->segfx[i];
2312 				newsegfy[i] = fnet->segfy[i];
2313 				newsegtx[i] = fnet->segtx[i];
2314 				newsegty[i] = fnet->segty[i];
2315 			}
2316 			newsegfx[fnet->segcount] = sx[0];
2317 			newsegfy[fnet->segcount] = sy[0];
2318 			newsegtx[fnet->segcount] = sx[1];
2319 			newsegty[fnet->segcount] = sy[1];
2320 			if (fnet->segcount > 0)
2321 			{
2322 				efree((CHAR *)fnet->segfx);
2323 				efree((CHAR *)fnet->segfy);
2324 				efree((CHAR *)fnet->segtx);
2325 				efree((CHAR *)fnet->segty);
2326 			}
2327 			fnet->segfx = newsegfx;   fnet->segfy = newsegfy;
2328 			fnet->segtx = newsegtx;   fnet->segty = newsegty;
2329 			fnet->segcount++;
2330 			continue;
2331 		}
2332 	}
2333 	return(FALSE);
2334 }
2335 
2336 /*
2337  * Routine to add a pip to primitive "np" from the tree in "lt" and save
2338  * information about it in the local object "fpip".
2339  * Tree has "(pip...)" structure.  Returns true on error.
2340  */
fpga_makeprimpip(NODEPROTO * np,LISPTREE * lt,FPGANODE * fn,FPGAPIP * fpip)2341 BOOLEAN fpga_makeprimpip(NODEPROTO *np, LISPTREE *lt, FPGANODE *fn, FPGAPIP *fpip)
2342 {
2343 	REGISTER INTBIG i, j;
2344 	REGISTER INTBIG lambda;
2345 	REGISTER LISPTREE *scanlt;
2346 
2347 	/* scan for information in this FPGAPIP object */
2348 	fpip->pipname = 0;
2349 	fpip->con1 = fpip->con2 = -1;
2350 	for(j=0; j<lt->parameters; j++)
2351 	{
2352 		if (lt->paramtype[j] != PARAMBRANCH) continue;
2353 		scanlt = (LISPTREE *)lt->paramvalue[j];
2354 		if (namesame(scanlt->keyword, x_("name")) == 0 && scanlt->parameters == 1 &&
2355 			scanlt->paramtype[0] == PARAMATOM)
2356 		{
2357 			if (fpip->pipname != 0)
2358 			{
2359 				ttyputerr(_("Multiple names for pip (line %ld)"), lt->lineno);
2360 				return(TRUE);
2361 			}
2362 			if (allocstring(&fpip->pipname, (CHAR *)scanlt->paramvalue[0], fpga_tech->cluster)) return(TRUE);
2363 			continue;
2364 		}
2365 		if (namesame(scanlt->keyword, x_("position")) == 0 && scanlt->parameters == 2 &&
2366 			scanlt->paramtype[0] == PARAMATOM && scanlt->paramtype[1] == PARAMATOM)
2367 		{
2368 			lambda = el_curlib->lambda[fpga_tech->techindex];
2369 			fpip->posx = myatoi((CHAR *)scanlt->paramvalue[0]) * lambda + np->lowx;
2370 			fpip->posy = myatoi((CHAR *)scanlt->paramvalue[1]) * lambda + np->lowy;
2371 			continue;
2372 		}
2373 		if (namesame(scanlt->keyword, x_("connectivity")) == 0 && scanlt->parameters == 2 &&
2374 			scanlt->paramtype[0] == PARAMATOM && scanlt->paramtype[1] == PARAMATOM)
2375 		{
2376 			for(i=0; i<fn->netcount; i++)
2377 			{
2378 				if (namesame(fn->netlist[i]->netname, (CHAR *)scanlt->paramvalue[0]) == 0)
2379 					fpip->con1 = i;
2380 				if (namesame(fn->netlist[i]->netname, (CHAR *)scanlt->paramvalue[1]) == 0)
2381 					fpip->con2 = i;
2382 			}
2383 			continue;
2384 		}
2385 	}
2386 	return(FALSE);
2387 }
2388 
2389 /******************** ARCHITECTURE PARSING: LAYOUT ********************/
2390 
2391 /*
2392  * Routine to scan the entire tree for block definitions and create them.
2393  */
fpga_placeprimitives(LISPTREE * lt)2394 NODEPROTO *fpga_placeprimitives(LISPTREE *lt)
2395 {
2396 	REGISTER INTBIG i;
2397 	REGISTER LISPTREE *sublt;
2398 	REGISTER NODEPROTO *np, *toplevel;
2399 
2400 	/* look through top level for the "blockdef"s */
2401 	toplevel = NONODEPROTO;
2402 	for(i=0; i<lt->parameters; i++)
2403 	{
2404 		if (lt->paramtype[i] != PARAMBRANCH) continue;
2405 		sublt = (LISPTREE *)lt->paramvalue[i];
2406 		if (namesame(sublt->keyword, x_("blockdef")) != 0 &&
2407 			namesame(sublt->keyword, x_("architecture")) != 0) continue;
2408 
2409 		/* create the primitive */
2410 		np = fpga_makecell(sublt);
2411 		if (np == NONODEPROTO) return(NONODEPROTO);
2412 		if (namesame(sublt->keyword, x_("architecture")) == 0) toplevel = np;
2413 	}
2414 	return(toplevel);
2415 }
2416 
2417 /*
2418  * Routine to create a cell from a subtree "lt".
2419  * Tree has "(blockdef...)" or "(architecture...)" structure.
2420  * Returns nonzero on error.
2421  */
fpga_makecell(LISPTREE * lt)2422 NODEPROTO *fpga_makecell(LISPTREE *lt)
2423 {
2424 	REGISTER INTBIG i, j;
2425 	REGISTER BOOLEAN gotsize;
2426 	REGISTER INTBIG sizex, sizey, lambda;
2427 	REGISTER NODEPROTO *cell;
2428 	REGISTER LISPTREE *scanlt, *ltattribute, *ltnets, *ltports, *ltcomponents;
2429 	REGISTER CHAR *blockname;
2430 
2431 	/* find all of the pieces of this block */
2432 	lambda = el_curlib->lambda[fpga_tech->techindex];
2433 	ltattribute = ltnets = ltports = ltcomponents = 0;
2434 	for(i=0; i<lt->parameters; i++)
2435 	{
2436 		if (lt->paramtype[i] != PARAMBRANCH) continue;
2437 		scanlt = (LISPTREE *)lt->paramvalue[i];
2438 		if (namesame(scanlt->keyword, x_("attributes")) == 0)
2439 		{
2440 			if (ltattribute != 0)
2441 			{
2442 				ttyputerr(_("Multiple 'attributes' sections for a block (line %ld)"), lt->lineno);
2443 				return(NONODEPROTO);
2444 			}
2445 			ltattribute = scanlt;
2446 			continue;
2447 		}
2448 		if (namesame(scanlt->keyword, x_("nets")) == 0)
2449 		{
2450 			if (ltnets != 0)
2451 			{
2452 				ttyputerr(_("Multiple 'nets' sections for a block (line %ld)"), lt->lineno);
2453 				return(NONODEPROTO);
2454 			}
2455 			ltnets = scanlt;
2456 			continue;
2457 		}
2458 		if (namesame(scanlt->keyword, x_("ports")) == 0)
2459 		{
2460 			if (ltports != 0)
2461 			{
2462 				ttyputerr(_("Multiple 'ports' sections for a block (line %ld)"), lt->lineno);
2463 				return(NONODEPROTO);
2464 			}
2465 			ltports = scanlt;
2466 			continue;
2467 		}
2468 		if (namesame(scanlt->keyword, x_("components")) == 0)
2469 		{
2470 			if (ltcomponents != 0)
2471 			{
2472 				ttyputerr(_("Multiple 'components' sections for a block (line %ld)"), lt->lineno);
2473 				return(NONODEPROTO);
2474 			}
2475 			ltcomponents = scanlt;
2476 			continue;
2477 		}
2478 	}
2479 
2480 	/* scan the attributes section */
2481 	if (ltattribute == 0)
2482 	{
2483 		ttyputerr(_("Missing 'attributes' sections on a block (line %ld)"), lt->lineno);
2484 		return(NONODEPROTO);
2485 	}
2486 	blockname = 0;
2487 	gotsize = FALSE;
2488 	sizex = sizey = 0;
2489 	for(j=0; j<ltattribute->parameters; j++)
2490 	{
2491 		if (ltattribute->paramtype[j] != PARAMBRANCH) continue;
2492 		scanlt = (LISPTREE *)ltattribute->paramvalue[j];
2493 		if (namesame(scanlt->keyword, x_("name")) == 0)
2494 		{
2495 			if (scanlt->parameters != 1 || scanlt->paramtype[0] != PARAMATOM)
2496 			{
2497 				ttyputerr(_("Block 'name' attribute should take a single atomic parameter (line %ld)"),
2498 					scanlt->lineno);
2499 				return(NONODEPROTO);
2500 			}
2501 			blockname = (CHAR *)scanlt->paramvalue[0];
2502 			continue;
2503 		}
2504 		if (namesame(scanlt->keyword, x_("size")) == 0 && scanlt->parameters == 2 &&
2505 			scanlt->paramtype[0] == PARAMATOM && scanlt->paramtype[1] == PARAMATOM)
2506 		{
2507 			gotsize = TRUE;
2508 			sizex = myatoi((CHAR *)scanlt->paramvalue[0]) * lambda;
2509 			sizey = myatoi((CHAR *)scanlt->paramvalue[1]) * lambda;
2510 			continue;
2511 		}
2512 	}
2513 
2514 	/* validate */
2515 	if (blockname == 0)
2516 	{
2517 		ttyputerr(_("Missing 'name' attribute in block definition (line %ld)"),
2518 			ltattribute->lineno);
2519 		return(NONODEPROTO);
2520 	}
2521 
2522 	/* make the cell */
2523 	cell = us_newnodeproto(blockname, el_curlib);
2524 	if (cell == NONODEPROTO) return(NONODEPROTO);
2525 	ttyputmsg(_("Creating cell '%s'"), blockname);
2526 
2527 	/* force size by placing pins in the corners */
2528 	if (gotsize)
2529 	{
2530 		newnodeinst(fpga_wirepinprim, 0, lambda, 0, lambda, 0, 0, cell);
2531 		newnodeinst(fpga_wirepinprim, sizex-lambda, sizex, 0, lambda, 0, 0, cell);
2532 		newnodeinst(fpga_wirepinprim, 0, lambda, sizey-lambda, sizey, 0, 0, cell);
2533 		newnodeinst(fpga_wirepinprim, sizex-lambda, sizex, sizey-lambda, sizey, 0, 0, cell);
2534 	}
2535 
2536 	/* add any unrecognized attributes */
2537 	for(j=0; j<ltattribute->parameters; j++)
2538 	{
2539 		if (ltattribute->paramtype[j] != PARAMBRANCH) continue;
2540 		scanlt = (LISPTREE *)ltattribute->paramvalue[j];
2541 		if (namesame(scanlt->keyword, x_("name")) == 0) continue;
2542 		if (namesame(scanlt->keyword, x_("size")) == 0) continue;
2543 
2544 		if (scanlt->parameters != 1 || scanlt->paramtype[0] != PARAMATOM)
2545 		{
2546 			ttyputerr(_("Attribute '%s' attribute should take a single atomic parameter (line %ld)"),
2547 				scanlt->keyword, scanlt->lineno);
2548 			return(NONODEPROTO);
2549 		}
2550 		(void)setval((INTBIG)cell, VNODEPROTO, scanlt->keyword, (INTBIG)scanlt->paramvalue[0],
2551 			VSTRING);
2552 	}
2553 
2554 	/* place block components */
2555 	if (ltcomponents != 0)
2556 	{
2557 		for(j=0; j<ltcomponents->parameters; j++)
2558 		{
2559 			if (ltcomponents->paramtype[j] != PARAMBRANCH) continue;
2560 			scanlt = (LISPTREE *)ltcomponents->paramvalue[j];
2561 			if (namesame(scanlt->keyword, x_("repeater")) == 0)
2562 			{
2563 				if (fpga_makeblockrepeater(cell, scanlt)) return(NONODEPROTO);
2564 				continue;
2565 			}
2566 			if (namesame(scanlt->keyword, x_("instance")) == 0)
2567 			{
2568 				if (fpga_makeblockinstance(cell, scanlt)) return(NONODEPROTO);
2569 				continue;
2570 			}
2571 		}
2572 	}
2573 
2574 	/* place block ports */
2575 	if (ltports != 0)
2576 	{
2577 		for(j=0; j<ltports->parameters; j++)
2578 		{
2579 			if (ltports->paramtype[j] != PARAMBRANCH) continue;
2580 			scanlt = (LISPTREE *)ltports->paramvalue[j];
2581 			if (namesame(scanlt->keyword, x_("port")) == 0)
2582 			{
2583 				if (fpga_makeblockport(cell, scanlt)) return(NONODEPROTO);
2584 			}
2585 		}
2586 	}
2587 
2588 	/* place block nets */
2589 	if (ltnets != 0)
2590 	{
2591 		/* read the block nets */
2592 		for(j=0; j<ltnets->parameters; j++)
2593 		{
2594 			if (ltnets->paramtype[j] != PARAMBRANCH) continue;
2595 			scanlt = (LISPTREE *)ltnets->paramvalue[j];
2596 			if (namesame(scanlt->keyword, x_("net")) == 0)
2597 			{
2598 				if (fpga_makeblocknet(cell, scanlt)) return(NONODEPROTO);
2599 				i++;
2600 			}
2601 		}
2602 	}
2603 	return(cell);
2604 }
2605 
2606 /*
2607  * Routine to place an instance in cell "cell" from the LISPTREE in "lt".
2608  * Tree has "(instance...)" structure.  Returns true on error.
2609  */
fpga_makeblockinstance(NODEPROTO * cell,LISPTREE * lt)2610 BOOLEAN fpga_makeblockinstance(NODEPROTO *cell, LISPTREE *lt)
2611 {
2612 	REGISTER INTBIG i, rotation;
2613 	REGISTER INTBIG posx, posy, yoff, lambda;
2614 	REGISTER LISPTREE *scanlt, *lttype, *ltname, *ltposition, *ltrotation, *ltattribute;
2615 	REGISTER NODEPROTO *np;
2616 	REGISTER VARIABLE *var;
2617 	REGISTER NODEINST *ni;
2618 
2619 	/* scan for information in this block instance object */
2620 	lttype = ltname = ltposition = ltrotation = ltattribute = 0;
2621 	for(i=0; i<lt->parameters; i++)
2622 	{
2623 		if (lt->paramtype[i] != PARAMBRANCH) continue;
2624 		scanlt = (LISPTREE *)lt->paramvalue[i];
2625 		if (namesame(scanlt->keyword, x_("type")) == 0)
2626 		{
2627 			if (lttype != 0)
2628 			{
2629 				ttyputerr(_("Multiple 'type' sections for a block (line %ld)"), lt->lineno);
2630 				return(TRUE);
2631 			}
2632 			lttype = scanlt;
2633 			continue;
2634 		}
2635 		if (namesame(scanlt->keyword, x_("name")) == 0)
2636 		{
2637 			if (ltname != 0)
2638 			{
2639 				ttyputerr(_("Multiple 'name' sections for a block (line %ld)"), lt->lineno);
2640 				return(TRUE);
2641 			}
2642 			ltname = scanlt;
2643 			continue;
2644 		}
2645 		if (namesame(scanlt->keyword, x_("position")) == 0)
2646 		{
2647 			if (ltposition != 0)
2648 			{
2649 				ttyputerr(_("Multiple 'position' sections for a block (line %ld)"), lt->lineno);
2650 				return(TRUE);
2651 			}
2652 			ltposition = scanlt;
2653 			continue;
2654 		}
2655 		if (namesame(scanlt->keyword, x_("rotation")) == 0)
2656 		{
2657 			if (ltrotation != 0)
2658 			{
2659 				ttyputerr(_("Multiple 'rotation' sections for a block (line %ld)"), lt->lineno);
2660 				return(TRUE);
2661 			}
2662 			ltrotation = scanlt;
2663 			continue;
2664 		}
2665 		if (namesame(scanlt->keyword, x_("attributes")) == 0)
2666 		{
2667 			if (ltattribute != 0)
2668 			{
2669 				ttyputerr(_("Multiple 'attributes' sections for a block (line %ld)"), lt->lineno);
2670 				return(TRUE);
2671 			}
2672 			ltattribute = scanlt;
2673 			continue;
2674 		}
2675 	}
2676 
2677 	/* validate */
2678 	if (lttype == 0)
2679 	{
2680 		ttyputerr(_("No 'type' specified for block instance (line %ld)"), lt->lineno);
2681 		return(TRUE);
2682 	}
2683 	if (lttype->parameters != 1 || lttype->paramtype[0] != PARAMATOM)
2684 	{
2685 		ttyputerr(_("Need one atom in 'type' of block instance (line %ld)"), lttype->lineno);
2686 		return(TRUE);
2687 	}
2688 	for(np = fpga_tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2689 		if (namesame(np->protoname, (CHAR *)lttype->paramvalue[0]) == 0) break;
2690 	if (np == NONODEPROTO)
2691 		np = getnodeproto((CHAR *)lttype->paramvalue[0]);
2692 	if (np == NONODEPROTO)
2693 	{
2694 		ttyputerr(_("Cannot find block type '%s' (line %ld)"), (CHAR *)lttype->paramvalue[0], lttype->lineno);
2695 		return(TRUE);
2696 	}
2697 	if (ltposition == 0)
2698 	{
2699 		ttyputerr(_("No 'position' specified for block instance (line %ld)"), lt->lineno);
2700 		return(TRUE);
2701 	}
2702 	if (ltposition->parameters != 2 || ltposition->paramtype[0] != PARAMATOM ||
2703 		ltposition->paramtype[1] != PARAMATOM)
2704 	{
2705 		ttyputerr(_("Need two atoms in 'position' of block instance (line %ld)"), ltposition->lineno);
2706 		return(TRUE);
2707 	}
2708 	rotation = 0;
2709 	if (ltrotation != 0)
2710 	{
2711 		if (ltrotation->parameters != 1 || ltrotation->paramtype[0] != PARAMATOM)
2712 		{
2713 			ttyputerr(_("Need one atom in 'rotation' of block instance (line %ld)"), ltrotation->lineno);
2714 			return(TRUE);
2715 		}
2716 		rotation = myatoi((CHAR *)ltrotation->paramvalue[0]) * 10;
2717 	}
2718 
2719 	/* place the instance */
2720 	lambda = el_curlib->lambda[fpga_tech->techindex];
2721 	posx = myatoi((CHAR *)ltposition->paramvalue[0]) * lambda;
2722 	posy = myatoi((CHAR *)ltposition->paramvalue[1]) * lambda;
2723 	ni = newnodeinst(np, posx, posx+np->highx-np->lowx, posy, posy+np->highy-np->lowy, 0, rotation, cell);
2724 	if (ni == NONODEINST) return(TRUE);
2725 
2726 	/* add any attributes */
2727 	if (ltattribute != 0)
2728 	{
2729 		for(i=0; i<ltattribute->parameters; i++)
2730 		{
2731 			if (ltattribute->paramtype[i] != PARAMBRANCH) continue;
2732 			scanlt = (LISPTREE *)ltattribute->paramvalue[i];
2733 			if (scanlt->parameters != 1 || scanlt->paramtype[0] != PARAMATOM)
2734 			{
2735 				ttyputerr(_("Attribute '%s' attribute should take a single atomic parameter (line %ld)"),
2736 					scanlt->keyword, scanlt->lineno);
2737 				return(TRUE);
2738 			}
2739 			(void)setval((INTBIG)ni, VNODEINST, scanlt->keyword, (INTBIG)scanlt->paramvalue[0],
2740 				VSTRING);
2741 		}
2742 	}
2743 
2744 	/* name the instance if one is given */
2745 	if (ltname != 0)
2746 	{
2747 		if (ltname->parameters != 1 || ltname->paramtype[0] != PARAMATOM)
2748 		{
2749 			ttyputerr(_("Need one atom in 'name' of block instance (line %ld)"), ltname->lineno);
2750 			return(TRUE);
2751 		}
2752 		var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key, (INTBIG)ltname->paramvalue[0], VSTRING|VDISPLAY);
2753 		if (var != NOVARIABLE)
2754 		{
2755 			yoff = (ni->highy-ni->lowy) / lambda;
2756 			defaulttextsize(3, var->textdescript);
2757 			TDSETPOS(var->textdescript, VTPOSBOXED);
2758 			TDSETOFF(var->textdescript, TDGETXOFF(var->textdescript), yoff);
2759 		}
2760 	}
2761 	return(FALSE);
2762 }
2763 
2764 /*
2765  * Routine to add a port to block "cell" from the tree in "lt".
2766  * Tree has "(port...)" structure.  Returns true on error.
2767  */
fpga_makeblockport(NODEPROTO * cell,LISPTREE * lt)2768 BOOLEAN fpga_makeblockport(NODEPROTO *cell, LISPTREE *lt)
2769 {
2770 	REGISTER INTBIG j;
2771 	REGISTER INTBIG posx, posy, lambda;
2772 	PORTPROTO *pp, *expp;
2773 	REGISTER NODEINST *ni;
2774 	REGISTER LISPTREE *ltname, *ltposition, *scanlt;
2775 
2776 	ltname = ltposition = 0;
2777 	for(j=0; j<lt->parameters; j++)
2778 	{
2779 		if (lt->paramtype[j] != PARAMBRANCH) continue;
2780 		scanlt = (LISPTREE *)lt->paramvalue[j];
2781 		if (namesame(scanlt->keyword, x_("name")) == 0)
2782 		{
2783 			ltname = scanlt;
2784 			continue;
2785 		}
2786 		if (namesame(scanlt->keyword, x_("position")) == 0)
2787 		{
2788 			ltposition = scanlt;
2789 			continue;
2790 		}
2791 		if (namesame(scanlt->keyword, x_("direction")) == 0)
2792 		{
2793 			/* ltdirection = scanlt; */
2794 			continue;
2795 		}
2796 	}
2797 
2798 	/* make the port */
2799 	if (ltname == 0)
2800 	{
2801 		ttyputerr(_("Port has no name (line %ld)"), lt->lineno);
2802 		return(TRUE);
2803 	}
2804 	if (ltname->parameters != 1 || ltname->paramtype[0] != PARAMATOM)
2805 	{
2806 		ttyputerr(_("Port name must be a single atom (line %ld)"), ltname->lineno);
2807 	}
2808 	if (ltposition == 0)
2809 	{
2810 		ttyputerr(_("Port has no position (line %ld)"), lt->lineno);
2811 		return(TRUE);
2812 	}
2813 	if (ltposition->parameters != 2 || ltposition->paramtype[0] != PARAMATOM ||
2814 		ltposition->paramtype[1] != PARAMATOM)
2815 	{
2816 		ttyputerr(_("Port position must be two atoms (line %ld)"), ltposition->lineno);
2817 	}
2818 
2819 	/* create the structure */
2820 	lambda = el_curlib->lambda[fpga_tech->techindex];
2821 	posx = myatoi((CHAR *)ltposition->paramvalue[0]) * lambda;
2822 	posy = myatoi((CHAR *)ltposition->paramvalue[1]) * lambda;
2823 	ni = newnodeinst(fpga_wirepinprim, posx, posx, posy, posy, 0, 0, cell);
2824 	if (ni == NONODEINST)
2825 	{
2826 		ttyputerr(_("Error creating pin for port '%s' (line %ld)"),
2827 			(CHAR *)ltname->paramvalue[0], lt->lineno);
2828 		return(TRUE);
2829 	}
2830 	pp = fpga_wirepinprim->firstportproto;
2831 	expp = newportproto(cell, ni, pp, (CHAR *)ltname->paramvalue[0]);
2832 	if (expp == NOPORTPROTO)
2833 	{
2834 		ttyputerr(_("Error creating port '%s' (line %ld)"),
2835 			(CHAR *)ltname->paramvalue[0], lt->lineno);
2836 		return(TRUE);
2837 	}
2838 	return(FALSE);
2839 }
2840 
2841 /*
2842  * Routine to place a repeater in cell "cell" from the LISPTREE in "lt".
2843  * Tree has "(repeater...)" structure.  Returns true on error.
2844  */
fpga_makeblockrepeater(NODEPROTO * cell,LISPTREE * lt)2845 BOOLEAN fpga_makeblockrepeater(NODEPROTO *cell, LISPTREE *lt)
2846 {
2847 	REGISTER INTBIG j, angle;
2848 	REGISTER INTBIG portax, portay, portbx, portby, ctrx, ctry, length, lambda;
2849 	REGISTER NODEINST *ni;
2850 	REGISTER VARIABLE *var;
2851 	REGISTER LISPTREE *ltname, *ltporta, *ltportb, *scanlt;
2852 
2853 	ltname = ltporta = ltportb = 0;
2854 	for(j=0; j<lt->parameters; j++)
2855 	{
2856 		if (lt->paramtype[j] != PARAMBRANCH) continue;
2857 		scanlt = (LISPTREE *)lt->paramvalue[j];
2858 		if (namesame(scanlt->keyword, x_("name")) == 0)
2859 		{
2860 			ltname = scanlt;
2861 			continue;
2862 		}
2863 		if (namesame(scanlt->keyword, x_("porta")) == 0)
2864 		{
2865 			ltporta = scanlt;
2866 			continue;
2867 		}
2868 		if (namesame(scanlt->keyword, x_("portb")) == 0)
2869 		{
2870 			ltportb = scanlt;
2871 			continue;
2872 		}
2873 		if (namesame(scanlt->keyword, x_("direction")) == 0)
2874 		{
2875 			/* ltdirection = scanlt; */
2876 			continue;
2877 		}
2878 	}
2879 
2880 	/* make the repeater */
2881 	if (ltporta == 0)
2882 	{
2883 		ttyputerr(_("Repeater has no 'porta' (line %ld)"), lt->lineno);
2884 		return(TRUE);
2885 	}
2886 	if (ltporta->parameters != 2 || ltporta->paramtype[0] != PARAMATOM ||
2887 		ltporta->paramtype[1] != PARAMATOM)
2888 	{
2889 		ttyputerr(_("Repeater 'porta' position must be two atoms (line %ld)"), ltporta->lineno);
2890 	}
2891 	if (ltportb == 0)
2892 	{
2893 		ttyputerr(_("Repeater has no 'portb' (line %ld)"), lt->lineno);
2894 		return(TRUE);
2895 	}
2896 	if (ltportb->parameters != 2 || ltportb->paramtype[0] != PARAMATOM ||
2897 		ltportb->paramtype[1] != PARAMATOM)
2898 	{
2899 		ttyputerr(_("Repeater 'portb' position must be two atoms (line %ld)"), ltportb->lineno);
2900 	}
2901 
2902 	/* create the repeater */
2903 	lambda = el_curlib->lambda[fpga_tech->techindex];
2904 	portax = myatoi((CHAR *)ltporta->paramvalue[0]) * lambda;
2905 	portay = myatoi((CHAR *)ltporta->paramvalue[1]) * lambda;
2906 	portbx = myatoi((CHAR *)ltportb->paramvalue[0]) * lambda;
2907 	portby = myatoi((CHAR *)ltportb->paramvalue[1]) * lambda;
2908 	angle = figureangle(portax, portay, portbx, portby);
2909 	length = computedistance(portax, portay, portbx, portby);
2910 	ctrx = (portax + portbx) / 2;
2911 	ctry = (portay + portby) / 2;
2912 	ni = newnodeinst(fpga_repeaterprim, ctrx-length/2, ctrx+length/2,
2913 		ctry-lambda, ctry+lambda, 0, angle, cell);
2914 	if (ni == NONODEINST)
2915 	{
2916 		ttyputerr(_("Error creating repeater (line %ld)"), lt->lineno);
2917 		return(TRUE);
2918 	}
2919 
2920 	/* name the repeater if one is given */
2921 	if (ltname != 0)
2922 	{
2923 		if (ltname->parameters != 1 || ltname->paramtype[0] != PARAMATOM)
2924 		{
2925 			ttyputerr(_("Need one atom in 'name' of block repeater (line %ld)"), ltname->lineno);
2926 			return(TRUE);
2927 		}
2928 		var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key, (INTBIG)ltname->paramvalue[0], VSTRING);
2929 		if (var != NOVARIABLE)
2930 			defaulttextsize(3, var->textdescript);
2931 	}
2932 	return(FALSE);
2933 }
2934 
2935 /*
2936  * Routine to extract block net information from the LISPTREE in "lt".
2937  * Tree has "(net...)" structure.  Returns true on error.
2938  */
fpga_makeblocknet(NODEPROTO * cell,LISPTREE * lt)2939 BOOLEAN fpga_makeblocknet(NODEPROTO *cell, LISPTREE *lt)
2940 {
2941 	REGISTER INTBIG i, j, pos;
2942 	REGISTER NODEINST *ni;
2943 	REGISTER PORTPROTO *pp;
2944 	REGISTER ARCINST *ai;
2945 	REGISTER VARIABLE *var;
2946 	INTBIG px0, py0, px1, py1;
2947 	REGISTER INTBIG x, y, sea, lambda;
2948 	REGISTER GEOM *geom;
2949 	NODEINST *nis[2];
2950 	PORTPROTO *pps[2];
2951 	REGISTER LISPTREE *scanlt;
2952 
2953 	/* find the net name */
2954 	for(j=0; j<lt->parameters; j++)
2955 	{
2956 		if (lt->paramtype[j] != PARAMBRANCH) continue;
2957 		scanlt = (LISPTREE *)lt->paramvalue[j];
2958 		if (namesame(scanlt->keyword, x_("name")) == 0)
2959 		{
2960 			if (scanlt->parameters != 1 || scanlt->paramtype[0] != PARAMATOM)
2961 			{
2962 				ttyputerr(_("Net name must be a single atom (line %ld)"), scanlt->lineno);
2963 				return(TRUE);
2964 			}
2965 			/* ltname = scanlt; */
2966 			continue;
2967 		}
2968 	}
2969 
2970 	/* scan for segment objects */
2971 	for(j=0; j<lt->parameters; j++)
2972 	{
2973 		if (lt->paramtype[j] != PARAMBRANCH) continue;
2974 		scanlt = (LISPTREE *)lt->paramvalue[j];
2975 		if (namesame(scanlt->keyword, x_("segment")) == 0)
2976 		{
2977 			pos = 0;
2978 			for(i=0; i<2; i++)
2979 			{
2980 				/* get end of arc */
2981 				if (scanlt->parameters < pos+1)
2982 				{
2983 					ttyputerr(_("Incomplete block net segment (line %ld)"), scanlt->lineno);
2984 					return(TRUE);
2985 				}
2986 				if (scanlt->paramtype[pos] != PARAMATOM)
2987 				{
2988 					ttyputerr(_("Must have atoms in block net segment (line %ld)"), scanlt->lineno);
2989 					return(TRUE);
2990 				}
2991 				if (namesame((CHAR *)scanlt->paramvalue[pos], x_("component")) == 0)
2992 				{
2993 					if (scanlt->parameters < pos+3)
2994 					{
2995 						ttyputerr(_("Incomplete block net segment (line %ld)"), scanlt->lineno);
2996 						return(TRUE);
2997 					}
2998 					if (scanlt->paramtype[pos+1] != PARAMATOM || scanlt->paramtype[pos+2] != PARAMATOM)
2999 					{
3000 						ttyputerr(_("Must have atoms in block net segment (line %ld)"), scanlt->lineno);
3001 						return(TRUE);
3002 					}
3003 
3004 					/* find component and port */
3005 					for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
3006 					{
3007 						var = getvalkey((INTBIG)ni, VNODEINST, VSTRING, el_node_name_key);
3008 						if (var == NOVARIABLE) continue;
3009 						if (namesame((CHAR *)var->addr, (CHAR *)scanlt->paramvalue[pos+1]) == 0)
3010 							break;
3011 					}
3012 					if (ni == NONODEINST)
3013 					{
3014 						ttyputerr(_("Cannot find component '%s' in block net segment (line %ld)"),
3015 							(CHAR *)scanlt->paramvalue[pos+1], scanlt->lineno);
3016 						return(TRUE);
3017 					}
3018 					nis[i] = ni;
3019 					pps[i] = getportproto(ni->proto, (CHAR *)scanlt->paramvalue[pos+2]);
3020 					if (pps[i] == NOPORTPROTO)
3021 					{
3022 						ttyputerr(_("Cannot find port '%s' on component '%s' in block net segment (line %ld)"),
3023 							(CHAR *)scanlt->paramvalue[pos+2], (CHAR *)scanlt->paramvalue[pos+1], scanlt->lineno);
3024 						return(TRUE);
3025 					}
3026 					pos += 3;
3027 				} else if (namesame((CHAR *)scanlt->paramvalue[pos], x_("coord")) == 0)
3028 				{
3029 					if (scanlt->parameters < pos+3)
3030 					{
3031 						ttyputerr(_("Incomplete block net segment (line %ld)"), scanlt->lineno);
3032 						return(TRUE);
3033 					}
3034 					if (scanlt->paramtype[pos+1] != PARAMATOM || scanlt->paramtype[pos+2] != PARAMATOM)
3035 					{
3036 						ttyputerr(_("Must have atoms in block net segment (line %ld)"), scanlt->lineno);
3037 						return(TRUE);
3038 					}
3039 					lambda = el_curlib->lambda[fpga_tech->techindex];
3040 					x = myatoi((CHAR *)scanlt->paramvalue[pos+1]) * lambda;
3041 					y = myatoi((CHAR *)scanlt->paramvalue[pos+2]) * lambda;
3042 
3043 					/* find pin at this point */
3044 					sea = initsearch(x, x, y, y, cell);
3045 					ni = NONODEINST;
3046 					for(;;)
3047 					{
3048 						geom = nextobject(sea);
3049 						if (geom == NOGEOM) break;
3050 						if (!geom->entryisnode) continue;
3051 						ni = geom->entryaddr.ni;
3052 						if (ni->proto != fpga_wirepinprim) continue;
3053 						if ((ni->lowx + ni->highx) / 2 == x && (ni->lowy + ni->highy) / 2 == y)
3054 						{
3055 							termsearch(sea);
3056 							break;
3057 						}
3058 					}
3059 					if (geom == NOGEOM)
3060 					{
3061 						ni = newnodeinst(fpga_wirepinprim, x, x, y, y, 0, 0, cell);
3062 						if (ni == NONODEINST)
3063 						{
3064 							ttyputerr(_("Cannot create pin for block net segment (line %ld)"), scanlt->lineno);
3065 							return(TRUE);
3066 						}
3067 					}
3068 					nis[i] = ni;
3069 					pps[i] = ni->proto->firstportproto;
3070 					pos += 3;
3071 				} else if (namesame((CHAR *)scanlt->paramvalue[pos], x_("port")) == 0)
3072 				{
3073 					if (scanlt->parameters < pos+2)
3074 					{
3075 						ttyputerr(_("Incomplete block net segment (line %ld)"), scanlt->lineno);
3076 						return(TRUE);
3077 					}
3078 					if (scanlt->paramtype[pos+1] != PARAMATOM)
3079 					{
3080 						ttyputerr(_("Must have atoms in block net segment (line %ld)"), scanlt->lineno);
3081 						return(TRUE);
3082 					}
3083 
3084 					/* find port */
3085 					pp = getportproto(cell, (CHAR *)scanlt->paramvalue[pos+1]);
3086 					if (pp == NOPORTPROTO)
3087 					{
3088 						ttyputerr(_("Cannot find port '%s' in block net segment (line %ld)"),
3089 							(CHAR *)scanlt->paramvalue[pos+1], scanlt->lineno);
3090 						return(TRUE);
3091 					}
3092 					pps[i] = pp->subportproto;
3093 					nis[i] = pp->subnodeinst;
3094 					pos += 2;
3095 				} else
3096 				{
3097 					ttyputerr(_("Unknown keyword '%s' in block net segment (line %ld)"),
3098 						(CHAR *)scanlt->paramvalue[pos], scanlt->lineno);
3099 					return(TRUE);
3100 				}
3101 			}
3102 
3103 			/* now create the arc */
3104 			portposition(nis[0], pps[0], &px0, &py0);
3105 			portposition(nis[1], pps[1], &px1, &py1);
3106 			ai = newarcinst(fpga_tech->firstarcproto, 0, FIXANG, nis[0], pps[0], px0, py0,
3107 				nis[1], pps[1], px1, py1, cell);
3108 			if (ai == NOARCINST)
3109 			{
3110 				ttyputerr(_("Cannot run segment (line %ld)"), scanlt->lineno);
3111 				return(TRUE);
3112 			}
3113 		}
3114 	}
3115 	return(FALSE);
3116 }
3117