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