1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: usrcomcd.c
6 * User interface tool: command handler for C through D
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 #include "global.h"
33 #include "egraphics.h"
34 #include "edialogs.h"
35 #include "usr.h"
36 #include "usrtrack.h"
37 #include "database.h"
38 #include "tecgen.h"
39 #include "tecart.h"
40 #include "tecschem.h"
41 #include "efunction.h"
42 #include "usrdiacom.h"
43 #include <math.h>
44
45 #define MAXLINE 200 /* max characters on color map input line */
46 static struct {
47 INTBIG bits;
48 INTBIG set;
49 } us_overlappables[] =
50 {
51 {LAYERT1, 0},
52 {LAYERT2, 0},
53 {LAYERT3, 0},
54 {LAYERT4, 0},
55 {LAYERT5, 0},
56 {0, 0}
57 };
58
us_color(INTBIG count,CHAR * par[])59 void us_color(INTBIG count, CHAR *par[])
60 {
61 REGISTER INTBIG i, j, k, l, high, totalcolor, max, red, green, blue,
62 newmax, style, newraster;
63 CHAR line[MAXLINE], *layerlabel[5], *layerabbrev[5], *filename, *truename, **layernames;
64 INTBIG redt[256], greent[256], bluet[256], rr, rg, rb, *layerdata;
65 float hue, sat, inten, amt;
66 REGISTER VARIABLE *varred, *vargreen, *varblue;
67 REGISTER CHAR *pp, *orig, *s, *la;
68 GRAPHICS *desc;
69 REGISTER FILE *f;
70 extern COMCOMP us_colorp, us_colorentryp, us_colorreadp, us_colorwritep;
71 REGISTER void *infstr;
72
73 if (count == 0)
74 {
75 count = ttygetparam(M_("COLOR option: "), &us_colorp, MAXPARS, par);
76 if (count == 0)
77 {
78 us_abortedmsg();
79 return;
80 }
81 }
82 l = estrlen(pp = par[0]);
83
84 if (namesamen(pp, x_("black-background"), l) == 0 && l >= 1)
85 {
86 us_getcolormap(el_curtech, COLORSBLACK, TRUE);
87 ttyputverbose(M_("Black-background colormap loaded"));
88 return;
89 }
90
91 if (namesamen(pp, x_("white-background"), l) == 0 && l >= 1)
92 {
93 us_getcolormap(el_curtech, COLORSWHITE, TRUE);
94 ttyputverbose(M_("White-background colormap loaded"));
95 return;
96 }
97
98 if (namesamen(pp, x_("default"), l) == 0 && l >= 1)
99 {
100 us_getcolormap(el_curtech, COLORSDEFAULT, TRUE);
101 ttyputverbose(M_("Default colormap loaded"));
102 return;
103 }
104
105 if (namesamen(pp, x_("highlight"), l) == 0 && l >= 1)
106 {
107 if (us_needwindow()) return;
108 if (count < 2)
109 {
110 ttyputusage(x_("color highlight LAYERLETTERS [AMOUNT]"));
111 return;
112 }
113 amt = 0.2f;
114 if (count >= 3)
115 {
116 amt = (float)atofr(par[2]);
117 amt /= WHOLE;
118 }
119 if (amt < 0.0 || amt > 1.0)
120 {
121 us_abortcommand(_("Highlight amount must be from 0 to 1"));
122 return;
123 }
124
125 /* check the list of letters */
126 for(k=0; us_overlappables[k].bits != 0; k++)
127 us_overlappables[k].set = 0;
128 for(i=0; par[1][i] != 0 && par[1][i] != '('; i++)
129 {
130 for(j=0; j<el_curtech->layercount; j++)
131 {
132 la = us_layerletters(el_curtech, j);
133 for(k=0; la[k] != 0; k++) if (par[1][i] == la[k]) break;
134 if (la[k] != 0) break;
135 }
136 if (j >= el_curtech->layercount)
137 {
138 us_abortcommand(_("Unknown layer letter: %c"), par[1][i]);
139 return;
140 }
141 for(k=0; us_overlappables[k].bits != 0; k++)
142 if (el_curtech->layers[j]->bits == us_overlappables[k].bits) break;
143 if (us_overlappables[k].bits == 0)
144 {
145 us_abortcommand(_("Layer %s(%c) is not transparent"), layername(el_curtech, j), par[1][i]);
146 return;
147 }
148 us_overlappables[k].set = 1;
149 }
150
151 /* get the color map */
152 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
153 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
154 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
155 if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE)
156 {
157 ttyputerr(_("Cannot get current color map"));
158 return;
159 }
160
161 /* copy the color arrays from the variables */
162 for(i=0; i<256; i++)
163 {
164 redt[i] = ((INTBIG *)varred->addr)[i];
165 greent[i] = ((INTBIG *)vargreen->addr)[i];
166 bluet[i] = ((INTBIG *)varblue->addr)[i];
167 }
168
169 /* adjust the color arrays */
170 for(i=1; i<256; i++)
171 {
172 /* ignore if nonoverlappable, grid, or highlight */
173 if ((i&(LAYERG|LAYERH|LAYEROE)) != 0) continue;
174
175 /* skip if it is one of the highlighted layers */
176 for(k=0; us_overlappables[k].bits != 0; k++)
177 if ((us_overlappables[k].bits&i) != 0 && us_overlappables[k].set != 0) break;
178 if (us_overlappables[k].bits != 0) continue;
179
180 /* dim the layer */
181 us_rgbtohsv(redt[i], greent[i], bluet[i], &hue, &sat, &inten);
182 sat *= amt;
183 us_hsvtorgb(hue, sat, inten, &rr, &rg, &rb);
184 redt[i] = rr; greent[i] = rg; bluet[i] = rb;
185 }
186
187 /* set the new color map */
188 startobjectchange((INTBIG)us_tool, VTOOL);
189 (void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, (INTBIG)redt,
190 VINTEGER|VISARRAY|(256<<VLENGTHSH));
191 (void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, (INTBIG)greent,
192 VINTEGER|VISARRAY|(256<<VLENGTHSH));
193 (void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, (INTBIG)bluet,
194 VINTEGER|VISARRAY|(256<<VLENGTHSH));
195 endobjectchange((INTBIG)us_tool, VTOOL);
196 return;
197 }
198
199 if ((namesamen(pp, x_("entry"), l) == 0 ||
200 namesamen(pp, x_("pattern"), l) == 0) && l >= 1)
201 {
202 /* force pattern references on black&white display */
203 style = *pp;
204 if (us_needwindow()) return;
205
206 /* get the entry number */
207 if (count < 2)
208 {
209 count = ttygetparam(M_("Entry: "), &us_colorentryp, MAXPARS-1, &par[1]) + 1;
210 if (count == 1)
211 {
212 us_abortedmsg();
213 return;
214 }
215 }
216
217 if (style == 'p')
218 {
219 /* pattern specification */
220 j = el_curtech->layercount;
221 totalcolor = us_getcolormapentry(par[1], TRUE);
222 } else
223 {
224 /* color map entry specification */
225 j = el_maplength;
226 totalcolor = us_getcolormapentry(par[1], FALSE);
227 }
228 if (totalcolor < 0) return;
229 if (totalcolor >= j)
230 {
231 us_abortcommand(_("Entry must be from 0 to %ld"), j-1);
232 return;
233 }
234
235 /* get color arrays */
236 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
237 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
238 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
239 if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE)
240 {
241 ttyputerr(_("Cannot get current color map"));
242 return;
243 }
244
245 /* if more values specified, get new entry */
246 if (count >= 3)
247 {
248 if (style == 'p')
249 {
250 /* get a stipple pattern for this layer */
251 desc = el_curtech->layers[totalcolor];
252 pp = par[2];
253 for(j=0; j<8; j++)
254 {
255 if (*pp == 0) pp = par[2];
256 if (*pp == '/')
257 {
258 pp++;
259 continue;
260 }
261 newraster = myatoi(pp);
262 (void)setind((INTBIG)desc, VGRAPHICS, x_("raster"), j, newraster);
263 while (*pp != '/' && *pp != 0) pp++;
264 if (*pp == '/') pp++;
265 }
266 } else
267 {
268 /* get three colors for the map */
269 if (count < 5)
270 {
271 ttyputusage(x_("color entry INDEX [RED GREEN BLUE]"));
272 return;
273 }
274 us_setcolorentry(totalcolor, myatoi(par[2]), myatoi(par[3]),
275 myatoi(par[4]), 0, TRUE);
276 }
277 }
278
279 /* report the current color values */
280 if (style == 'p')
281 {
282 ttyputmsg(_("Entry %ld (%s) is bits:"), totalcolor,
283 layername(el_curtech, totalcolor));
284 desc = el_curtech->layers[totalcolor];
285 for(j=0; j<8; j++)
286 {
287 (void)esnprintf(line, MAXLINE, x_("0x%04x |"), desc->raster[j]&0xFFFF);
288 for(k=0; k<16; k++)
289 if ((desc->raster[j] & (1<<(15-k))) != 0)
290 (void)estrcat(line, x_("X")); else
291 (void)estrcat(line, x_(" "));
292 (void)estrcat(line, x_("|"));
293 ttyputmsg(x_("%s"), line);
294 }
295 } else us_printcolorvalue(totalcolor);
296 return;
297 }
298
299 if (namesamen(pp, x_("mix"), l) == 0 && l >= 1)
300 {
301 if (us_needwindow()) return;
302 for(i=0; i<5; i++) layerlabel[i] = 0;
303 j = el_curtech->layercount;
304 for(i=0; i<j; i++)
305 {
306 desc = el_curtech->layers[i];
307 switch (desc->bits)
308 {
309 case LAYERT1: k = 0; break;
310 case LAYERT2: k = 1; break;
311 case LAYERT3: k = 2; break;
312 case LAYERT4: k = 3; break;
313 case LAYERT5: k = 4; break;
314 default: k = -1; break;
315 }
316 if (k < 0) continue;
317 if (layerlabel[k] != 0) continue;
318 layerlabel[k] = layername(el_curtech, i);
319 layerabbrev[k] = (CHAR *)emalloc(2 * SIZEOFCHAR, el_tempcluster);
320 layerabbrev[k][0] = *us_layerletters(el_curtech, i);
321 layerabbrev[k][1] = 0;
322 }
323 layerdata = us_getprintcolors(el_curtech);
324 if (layerdata == 0)
325 {
326 ttyputerr(_("Cannot get print colors for technology '%s'"), el_curtech->techname);
327 return;
328 }
329 for(i=0; i<5; i++) if (layerlabel[i] == 0)
330 {
331 layerlabel[i] = x_("UNUSED");
332 (void)allocstring(&layerabbrev[i], x_("?"), el_tempcluster);
333 }
334 layernames = (CHAR **)emalloc(el_curtech->layercount*(sizeof (CHAR *)), el_tempcluster);
335 if (layernames == 0) return;
336 for(i=0; i<el_curtech->layercount; i++)
337 layernames[i] = layername(el_curtech, i);
338 if (us_colormixdlog(layerlabel, el_curtech->layercount, layernames, layerdata))
339 {
340 /* data changed: update the print colors (other information is already set) */
341 setval((INTBIG)el_curtech, VTECHNOLOGY, x_("USER_print_colors"), (INTBIG)layerdata,
342 VINTEGER|VISARRAY|((el_curtech->layercount*5)<<VLENGTHSH));
343 }
344 for(i=0; i<5; i++) efree(layerabbrev[i]);
345 efree((CHAR *)layernames);
346 return;
347 }
348
349 if (namesamen(pp, x_("read"), l) == 0 && l >= 1)
350 {
351 if (count < 2)
352 {
353 infstr = initinfstr();
354 addstringtoinfstr(infstr, x_("color/"));
355 addstringtoinfstr(infstr, _("Color Map File"));
356 count = ttygetparam(returninfstr(infstr), &us_colorreadp, MAXPARS-1, &par[1]) + 1;
357 if (count == 1)
358 {
359 us_abortedmsg();
360 return;
361 }
362 }
363 orig = par[1];
364
365 /* get color map from file */
366 f = xopen(orig, us_filetypecolormap, el_libdir, &filename);
367 if (f == NULL)
368 {
369 us_abortcommand(_("Cannot find %s"), orig);
370 return;
371 }
372 ttyputmsg(_("Reading %s"), orig);
373
374 /* see if technology name is right */
375 (void)xfgets(line, MAXLINE, f);
376 if (estrncmp(line, x_("technology="), 11) != 0)
377 {
378 us_abortcommand(_("Invalid color map file"));
379 xclose(f);
380 return;
381 }
382 pp = &line[11];
383 if (estrcmp(pp, el_curtech->techname) != 0)
384 ttyputverbose(M_("Warning: color map is for %s technology"), pp);
385
386 max = 0;
387 for(;;)
388 {
389 if (xfgets(line, MAXLINE, f))
390 {
391 us_abortcommand(_("Map ends prematurely"));
392 return;
393 }
394 (void)estrcat(line, x_("\t\t\t\t"));
395 pp = line; red = eatoi(pp);
396 while (*pp != '\t' && *pp != 0) pp++; green = eatoi(++pp);
397 while (*pp != '\t' && *pp != 0) pp++; blue = eatoi(++pp);
398 while (*pp != '\t' && *pp != 0) pp++; newmax = eatoi(++pp);
399 if (newmax < max || newmax >= 256)
400 {
401 us_abortcommand(_("Bad map indices: %s"), line);
402 xclose(f);
403 return;
404 }
405 for(; max <= newmax; max++)
406 {
407 redt[max] = red&0377;
408 greent[max] = green&0377;
409 bluet[max] = blue&0377;
410 }
411 if (max >= 256) break;
412 }
413
414 /* set the color map */
415 startobjectchange((INTBIG)us_tool, VTOOL);
416 (void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_red_key, (INTBIG)redt,
417 VINTEGER|VISARRAY|(256<<VLENGTHSH));
418 (void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_green_key, (INTBIG)greent,
419 VINTEGER|VISARRAY|(256<<VLENGTHSH));
420 (void)setvalkey((INTBIG)us_tool, VTOOL, us_colormap_blue_key, (INTBIG)bluet,
421 VINTEGER|VISARRAY|(256<<VLENGTHSH));
422 endobjectchange((INTBIG)us_tool, VTOOL);
423
424 /* now get the bit-map information */
425 if (xfgets(line, MAXLINE, f))
426 {
427 ttyputmsg(_("Warning: no bit-map information in file"));
428 return;
429 }
430 j = eatoi(line);
431 high = el_curtech->layercount;
432 for(i=0; i<j; i++)
433 {
434 if (xfgets(line, MAXLINE, f))
435 {
436 ttyputmsg(_("Warning: EOF during bit-map data"));
437 break;
438 }
439 for(k=0; k<high; k++)
440 {
441 pp = us_layerletters(el_curtech, k);
442 for(l=0; pp[l] != 0; l++) if (pp[l] == line[0]) break;
443 if (pp[l] != 0)
444 {
445 desc = el_curtech->layers[k];
446 pp = &line[1];
447 for(l=0; l<8; l++)
448 {
449 while (*pp != ' ' && *pp != 0) pp++;
450 newraster = myatoi(++pp);
451 (void)setind((INTBIG)desc, VGRAPHICS, x_("raster"), l, newraster);
452 }
453 break;
454 }
455 }
456 if (k >= high) ttyputmsg(_("Warning: no layer '%c' in this technology"), line[0]);
457 }
458 xclose(f);
459
460 ttyputmsg(_("Color map in %s read"), orig);
461 return;
462 }
463
464 if (namesamen(pp, x_("write"), l) == 0 && l >= 1)
465 {
466 if (count < 2)
467 {
468 infstr = initinfstr();
469 addstringtoinfstr(infstr, x_("color/"));
470 addstringtoinfstr(infstr, _("Color map file name: "));
471 count = ttygetparam(returninfstr(infstr), &us_colorwritep, MAXPARS-1, &par[1]) + 1;
472 if (count == 1)
473 {
474 us_abortedmsg();
475 return;
476 }
477 }
478 orig = par[1];
479
480 /* get color arrays */
481 varred = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_red_key);
482 vargreen = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_green_key);
483 varblue = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER|VISARRAY, us_colormap_blue_key);
484 if (varred == NOVARIABLE || vargreen == NOVARIABLE || varblue == NOVARIABLE)
485 {
486 ttyputerr(_("Cannot get current color map"));
487 return;
488 }
489
490 /* write color map to file */
491 f = xcreate(orig, us_filetypecolormap, _("Color Map File"), &truename);
492 if (f == NULL)
493 {
494 if (truename != 0) us_abortcommand(_("Cannot write %s"), truename);
495 return;
496 }
497 xprintf(f, x_("technology=%s\n"), el_curtech->techname);
498 for(i=0; i<256; i++)
499 if (i == 255 || ((INTBIG *)varred->addr)[i] != ((INTBIG *)varred->addr)[i+1] ||
500 ((INTBIG *)vargreen->addr)[i] != ((INTBIG *)vargreen->addr)[i+1] ||
501 ((INTBIG *)varblue->addr)[i] != ((INTBIG *)varblue->addr)[i+1])
502 {
503 xprintf(f, x_("%ld\t%ld\t%ld\t%ld\n"), ((INTBIG *)varred->addr)[i],
504 ((INTBIG *)vargreen->addr)[i], ((INTBIG *)varblue->addr)[i], i);
505 }
506
507 /* write the bit maps */
508 high = el_curtech->layercount;
509 xprintf(f, x_("%ld\n"), high);
510 for(i=0; i<high; i++)
511 {
512 desc = el_curtech->layers[i];
513 s = us_layerletters(el_curtech, i);
514 xprintf(f, x_("%c"), s[0]);
515 for(j=0; j<8; j++)
516 xprintf(f, x_(" 0%o"), desc->raster[j] & 0xFFFF);
517 xprintf(f, x_("\n"));
518 }
519 xclose(f);
520 ttyputverbose(M_("%s written"), truepath(orig));
521 return;
522 }
523
524 ttyputbadusage(x_("color"));
525 }
526
us_commandfile(INTBIG count,CHAR * par[])527 void us_commandfile(INTBIG count, CHAR *par[])
528 {
529 REGISTER FILE *in;
530 REGISTER BOOLEAN verbose;
531 REGISTER CHAR *pp;
532 CHAR *filename;
533 REGISTER MACROPACK *lastmacropack;
534 extern COMCOMP us_colorreadp;
535 REGISTER void *infstr;
536
537 if (count >= 2 && namesamen(par[1], x_("verbose"), estrlen(par[1])) == 0) verbose = TRUE; else
538 verbose = FALSE;
539
540 if (count == 0)
541 {
542 infstr = initinfstr();
543 addstringtoinfstr(infstr, x_("macro/"));
544 addstringtoinfstr(infstr, _("Command File: "));
545 count = ttygetparam(returninfstr(infstr), &us_colorreadp, MAXPARS, par);
546 if (count == 0)
547 {
548 us_abortedmsg();
549 return;
550 }
551 }
552 pp = par[0];
553
554 in = xopen(pp, us_filetypemacro, el_libdir, &filename);
555 if (in == NULL)
556 {
557 us_abortcommand(_("Command file %s not found"), pp);
558 return;
559 }
560
561 /* create a new macro package entry */
562 lastmacropack = us_curmacropack;
563 us_curmacropack = us_newmacropack(pp);
564
565 /* read the commands */
566 us_docommands(in, verbose, x_(""));
567 xclose(in);
568
569 /* now there is no macro package */
570 us_curmacropack = lastmacropack;
571 }
572
us_constraint(INTBIG count,CHAR * par[])573 void us_constraint(INTBIG count, CHAR *par[])
574 {
575 REGISTER INTBIG l, c;
576 REGISTER CHAR *pp;
577
578 /* get the name of the constraint solver */
579 if (count <= 1)
580 {
581 ttyputusage(x_("constraint (use | tell) SOLVER [OPTIONS]"));
582 return;
583 }
584 for(c=0; el_constraints[c].conname != 0; c++)
585 if (namesame(el_constraints[c].conname, par[1]) == 0) break;
586 if (el_constraints[c].conname == 0)
587 {
588 us_abortcommand(_("No constraint solver called %s"), par[1]);
589 return;
590 }
591
592 l = estrlen(pp = par[0]);
593
594 if (namesamen(pp, x_("tell"), l) == 0 && l >= 1)
595 {
596 (*(el_constraints[c].setmode))(count-2, &par[2]);
597 return;
598 }
599
600 if (namesamen(pp, x_("use"), l) == 0 && l >= 1)
601 {
602 if (el_curconstraint == &el_constraints[c])
603 {
604 ttyputerr(_("Already using that constraint solver"));
605 return;
606 }
607 us_clearhighlightcount();
608 (void)setvalkey((INTBIG)us_tool, VTOOL, us_current_constraint_key,
609 (INTBIG)&el_constraints[c], VCONSTRAINT|VDONTSAVE);
610 ttyputmsg(M_("Switching to %s"), TRANSLATE(el_constraints[c].condesc));
611 return;
612 }
613
614 ttyputbadusage(x_("constraint"));
615 }
616
us_copycell(INTBIG count,CHAR * par[])617 void us_copycell(INTBIG count, CHAR *par[])
618 {
619 REGISTER NODEPROTO *np, *onp, *oinp;
620 REGISTER LIBRARY *fromlib, *tolib;
621 REGISTER CHAR *pt, *ppt, *lastch, save;
622 extern COMCOMP us_copycellp;
623 REGISTER NODEINST *ni, *newni;
624 REGISTER VIEW *nview;
625 REGISTER INTBIG i;
626 CHAR *subpar[5];
627 BOOLEAN quiet, norelatedviews, showcopy, move, nosubcells, newframe, useexisting;
628 INTBIG lx, hx, ly, hy;
629 REGISTER void *infstr;
630 extern COMCOMP us_yesnop;
631
632 /* get name of old cell */
633 if (count == 0)
634 {
635 count = ttygetparam(M_("Old cell name: "), &us_copycellp, MAXPARS, par);
636 if (count == 0)
637 {
638 us_abortedmsg();
639 return;
640 }
641 }
642 np = getnodeproto(par[0]);
643 if (np == NONODEPROTO)
644 {
645 us_abortcommand(_("Cannot find source cell %s"), par[0]);
646 return;
647 }
648 if (np->primindex != 0)
649 {
650 us_abortcommand(_("Cannot copy primitives"));
651 return;
652 }
653 fromlib = np->lib;
654 tolib = fromlib;
655
656 /* get name of new cell */
657 newframe = showcopy = quiet = norelatedviews = move = nosubcells = useexisting = FALSE;
658 if (count <= 1) pt = np->protoname; else
659 {
660 /* if there is a version number in the new name, remove it */
661 for(ppt = par[1]; *ppt != 0; ppt++) if (*ppt == ';') break;
662 if (*ppt != 0)
663 {
664 infstr = initinfstr();
665 *ppt = 0;
666 addstringtoinfstr(infstr, par[1]);
667 *ppt++ = ';';
668 for( ; *ppt != 0; ppt++) if (*ppt == '{') break;
669 addstringtoinfstr(infstr, ppt);
670 par[1] = returninfstr(infstr);
671 }
672 pt = par[1];
673
674 for(ppt = pt; *ppt != 0; ppt++) if (*ppt == ':') break;
675 if (*ppt == ':')
676 {
677 *ppt++ = 0;
678 tolib = getlibrary(pt);
679 if (tolib == NOLIBRARY)
680 {
681 us_abortcommand(_("Unknown destination library: %s"), pt);
682 return;
683 }
684 pt = ppt;
685 }
686 if (namesame(pt, x_("{ic}")) == 0 || namesame(pt, x_("{sk}")) == 0)
687 {
688 infstr = initinfstr();
689 addstringtoinfstr(infstr, np->protoname);
690 addstringtoinfstr(infstr, par[1]);
691 pt = returninfstr(infstr);
692 }
693 while (count > 2)
694 {
695 i = estrlen(ppt = par[2]);
696 if (namesamen(ppt, x_("quiet"), i) == 0) quiet = TRUE; else
697 if (namesamen(ppt, x_("move"), i) == 0) move = TRUE; else
698 if (namesamen(ppt, x_("replace-copy"), i) == 0) showcopy = TRUE; else
699 if (namesamen(ppt, x_("show-copy"), i) == 0) showcopy = newframe = TRUE; else
700 if (namesamen(ppt, x_("no-related-views"), i) == 0 && i >= 4) norelatedviews = TRUE; else
701 if (namesamen(ppt, x_("no-subcells"), i) == 0 && i >= 4) nosubcells = TRUE; else
702 if (namesamen(ppt, x_("use-existing-subcells"), i) == 0) useexisting = TRUE; else
703 {
704 ttyputbadusage(x_("copycell"));
705 return;
706 }
707 count--;
708 par++;
709 }
710 }
711
712 /* see if icon generation is requested */
713 i = estrlen(pt);
714 if (count > 1 && i > 4 && namesame(&pt[i-4], x_("{ic}")) == 0 && np->cellview != el_iconview)
715 {
716 /* cannot iconize text-only views */
717 if ((np->cellview->viewstate&TEXTVIEW) != 0)
718 {
719 us_abortcommand(_("Cannot iconize textual views: only layout and schematic"));
720 return;
721 }
722
723 /* cannot cross libraries when iconizing */
724 if (fromlib != tolib)
725 {
726 us_abortcommand(_("Can only generate icons within the same library"));
727 return;
728 }
729
730 /* generate the icon */
731 onp = us_makeiconcell(np->firstportproto, np->protoname, pt, tolib);
732 if (onp == NONODEPROTO) return;
733 if (!quiet)
734 ttyputmsg(_("Cell %s created with an iconic representation of %s"),
735 describenodeproto(onp), describenodeproto(np));
736 if (showcopy)
737 {
738 us_fullview(onp, &lx, &hx, &ly, &hy);
739 if (el_curwindowpart == NOWINDOWPART) newframe = TRUE;
740 us_switchtocell(onp, lx, hx, ly, hy, NONODEINST, NOPORTPROTO, newframe, FALSE, FALSE);
741 }
742 return;
743 }
744
745 /* see if skeletonization is requested */
746 i = estrlen(pt);
747 if (count > 1 && i > 4 && namesame(&pt[i-4], x_("{sk}")) == 0 && np->cellview != el_skeletonview)
748 {
749 onp = us_skeletonize(np, pt, tolib, quiet);
750 if (onp == NONODEPROTO) return;
751 if (showcopy)
752 {
753 us_fullview(onp, &lx, &hx, &ly, &hy);
754 if (el_curwindowpart == NOWINDOWPART) newframe = TRUE;
755 us_switchtocell(onp, lx, hx, ly, hy, NONODEINST, NOPORTPROTO, newframe, FALSE, FALSE);
756 }
757 return;
758 }
759
760 /* see if the name already exists in the destination library */
761 for(onp = tolib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
762 {
763 if (namesame(onp->protoname, pt) != 0) continue;
764 if (np->cellview == onp->cellview) break;
765 }
766 if (onp != NONODEPROTO)
767 {
768 infstr = initinfstr();
769 formatinfstr(infstr, _("Cell %s already exists; create a new version?"), describenodeproto(onp));
770 i = ttygetparam(returninfstr(infstr), &us_yesnop, MAXPARS, subpar);
771 if (i > 0 && namesamen(subpar[0], x_("no"), estrlen(subpar[0])) == 0) return;
772 }
773
774 /* if going within the same library, let the database do it */
775 if (fromlib == tolib)
776 {
777 onp = copynodeproto(np, tolib, pt, FALSE);
778 if (onp == NONODEPROTO)
779 {
780 ttyputerr(_("Error copying cell"));
781 return;
782 }
783 if (onp->cellview != np->cellview || !insamecellgrp(onp, np))
784 {
785 if (!quiet)
786 ttyputmsg(_("Cell %s copied to %s"), describenodeproto(np),
787 describenodeproto(onp));
788
789 /* see if renaming a schematic with an icon of itself inside */
790 for(ppt = pt; *ppt != 0; ppt++) if (*ppt == '{') break;
791 if (*ppt == 0)
792 {
793 /* just a rename, not to a different view type */
794 for(ni = onp->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
795 {
796 if (ni->proto->primindex != 0) continue;
797 if (isiconof(ni->proto, np)) break;
798 }
799 if (ni != NONODEINST)
800 {
801 /* need a properly-named icon: see if it exists */
802 infstr = initinfstr();
803 formatinfstr(infstr, x_("%s:%s{ic}"), tolib->libname, pt);
804 oinp = getnodeproto(returninfstr(infstr));
805 if (oinp == NONODEPROTO)
806 {
807 /* duplicate the icon and replace the old one with the duplicate */
808 oinp = copynodeproto(ni->proto, tolib, pt, FALSE);
809 }
810 if (oinp == NONODEPROTO)
811 {
812 ttyputerr(_("Error duplicating icon node %s to %s"),
813 describenodeinst(ni), pt);
814 } else
815 {
816 startobjectchange((INTBIG)ni, VNODEINST);
817 newni = replacenodeinst(ni, oinp, TRUE, TRUE);
818 if (newni != NONODEINST)
819 endobjectchange((INTBIG)newni, VNODEINST);
820 }
821 }
822 }
823 } else
824 {
825 if (!quiet)
826 ttyputmsg(_("New version of cell %s created, old is %s"),
827 describenodeproto(onp), describenodeproto(np));
828
829 /* set current nodeproto to itself to redisplay its name */
830 if (np == getcurcell())
831 (void)setval((INTBIG)el_curlib, VLIBRARY, x_("curnodeproto"), (INTBIG)np, VNODEPROTO);
832
833 /* update display of any unexpanded old versions */
834 for(ni = np->firstinst; ni != NONODEINST; ni = ni->nextinst)
835 {
836 if ((ni->userbits&NEXPAND) != 0) continue;
837 startobjectchange((INTBIG)ni, VNODEINST);
838 endobjectchange((INTBIG)ni, VNODEINST);
839 }
840 }
841 if (showcopy)
842 {
843 us_fullview(onp, &lx, &hx, &ly, &hy);
844 if (el_curwindowpart == NOWINDOWPART) newframe = TRUE;
845 us_switchtocell(onp, lx, hx, ly, hy, NONODEINST, NOPORTPROTO, newframe, FALSE, FALSE);
846 }
847 return;
848 }
849
850 /* get the new view type */
851 nview = np->cellview;
852 for(ppt = pt; *ppt != 0; ppt++) if (*ppt == '{') break;
853 if (*ppt == '{')
854 {
855 lastch = &pt[estrlen(pt)-1];
856 if (*lastch != '}')
857 {
858 us_abortcommand(_("View name '%s'must end with a '}'"), &ppt[1]);
859 return;
860 }
861 *lastch = 0;
862 nview = getview(&ppt[1]);
863 *lastch = '}';
864 if (nview == NOVIEW)
865 {
866 us_abortcommand(_("Unknown view abbreviation: %s"), ppt);
867 return;
868 }
869 }
870
871 save = *ppt;
872 *ppt = 0;
873 onp = us_copyrecursively(np, pt, tolib, nview, TRUE, move, x_(""),
874 norelatedviews, nosubcells, useexisting);
875 *ppt = save;
876 if (showcopy)
877 {
878 us_fullview(onp, &lx, &hx, &ly, &hy);
879 if (el_curwindowpart == NOWINDOWPART) newframe = TRUE;
880 us_switchtocell(onp, lx, hx, ly, hy, NONODEINST, NOPORTPROTO, newframe, FALSE, FALSE);
881 }
882 }
883
us_create(INTBIG count,CHAR * par[])884 void us_create(INTBIG count, CHAR *par[])
885 {
886 REGISTER NODEPROTO *np, *curcell;
887 REGISTER NODEINST *ni, *newno, *ni2;
888 REGISTER PORTPROTO *pp, *ppt, *fpt, *pp1, *pp2;
889 PORTPROTO *fromport, *toport;
890 REGISTER ARCPROTO *ap, *wantap;
891 REGISTER ARCINST *ai, *newai;
892 REGISTER TECHNOLOGY *tech;
893 NODEINST *ani[2];
894 REGISTER INTBIG ang, pangle, l, bestdist, bestdist1, bestdist2, wid, truewid, i, j, k,
895 bits1, bits2, dist, alignment, edgealignment;
896 BOOLEAN remainhighlighted, ishor, isver, join, angledcreate,
897 waitfordown, centeredprimitives, getcontents;
898 INTBIG px, py, nx, ny, cx, cy, x, y, xp[2], yp[2], xcur, ycur, otheralign, pxs, pys,
899 lx, hx, ly, hy;
900 PORTPROTO *app[2], *splitpp;
901 REGISTER VARIABLE *var;
902 static POLYGON *poly = NOPOLYGON, *poly2 = NOPOLYGON;
903 ARCINST *alt1, *alt2;
904 NODEINST *con1, *con2;
905 CHAR *oldarcname, *newpar[2];
906 HIGHLIGHT newhigh, *high;
907 REGISTER GEOM *foundgeom, *geom, **list;
908 GEOM *fromgeom, *togeom;
909 extern GRAPHICS us_hbox;
910
911 /* get polygon */
912 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
913 (void)needstaticpolygon(&poly2, 4, us_tool->cluster);
914
915 /* make sure there is a cell being edited */
916 if (us_needwindow()) return;
917 if ((el_curwindowpart->state&WINDOWTYPE) != DISPWINDOW)
918 {
919 us_abortcommand(_("Can only place components in graphical editing windows"));
920 return;
921 }
922 curcell = us_needcell();
923 if (curcell == NONODEPROTO) return;
924
925 /* in outline edit, create a point */
926 if ((el_curwindowpart->state&WINDOWOUTLINEEDMODE) != 0)
927 {
928 par[0] = x_("trace");
929 par[1] = x_("add-point");
930 us_node(2, par);
931 return;
932 }
933
934 if ((us_useroptions&CENTEREDPRIMITIVES) != 0) centeredprimitives = TRUE; else
935 centeredprimitives = FALSE;
936 join = angledcreate = remainhighlighted = getcontents = FALSE;
937 waitfordown = FALSE;
938 while (count > 0)
939 {
940 l = estrlen(par[0]);
941 if (namesamen(par[0], x_("remain-highlighted"), l) == 0 && l >= 1)
942 {
943 remainhighlighted = TRUE;
944 count--;
945 par++;
946 continue;
947 }
948 if (namesamen(par[0], x_("contents"), l) == 0 && l >= 1)
949 {
950 getcontents = TRUE;
951 count--;
952 par++;
953 continue;
954 }
955 if (namesamen(par[0], x_("wait-for-down"), l) == 0 && l >= 1)
956 {
957 waitfordown = TRUE;
958 count--;
959 par++;
960 continue;
961 }
962 if ((namesamen(par[0], x_("angle"), l) == 0 ||
963 namesamen(par[0], x_("join-angle"), l) == 0) && l >= 1)
964 {
965 if (namesamen(par[0], x_("join-angle"), l) == 0) join = TRUE;
966 angledcreate = TRUE;
967 count--;
968 par++;
969 if (count >= 1)
970 {
971 ang = atofr(par[0])*10/WHOLE;
972 count--;
973 par++;
974 } else ang = ((us_curarcproto->userbits&AANGLEINC) >> AANGLEINCSH) * 10;
975 }
976 break;
977 }
978
979 /* create a node or arc */
980 if (count == 0)
981 {
982 /* if no "angle" specified, simply create a node */
983 if (!angledcreate)
984 {
985 /* determine the node type being created */
986 np = us_nodetocreate(getcontents, curcell);
987 if (np == NONODEPROTO) return;
988
989 /* adjust the cursor position if selecting interactively */
990 us_clearhighlightcount();
991 if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(np);
992
993 /* get placement angle */
994 pangle = us_getplacementangle(np);
995
996 if ((us_tool->toolstate&INTERACTIVE) != 0)
997 {
998 us_createinit(0, 0, np, pangle, FALSE, NOGEOM, NOPORTPROTO);
999 trackcursor(waitfordown, us_ignoreup, us_createbegin, us_dragdown,
1000 us_stoponchar, us_dragup, TRACKDRAGGING);
1001 if (el_pleasestop != 0) return;
1002 }
1003 if (us_demandxy(&xcur, &ycur)) return;
1004 gridalign(&xcur, &ycur, 1, curcell);
1005
1006 /* get current cell (in case interactive placement changed the window) */
1007 curcell = us_needcell();
1008
1009 /* disallow creating if lock is on */
1010 if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1011
1012 /* determine size of the nodeinst */
1013 corneroffset(NONODEINST, np, pangle%3600, pangle/3600, &cx, &cy,
1014 centeredprimitives);
1015 defaultnodesize(np, &pxs, &pys);
1016
1017 /* adjust size if technologies differ */
1018 us_adjustfornodeincell(np, curcell, &cx, &cy);
1019 us_adjustfornodeincell(np, curcell, &pxs, &pys);
1020
1021 xcur -= cx; ycur -= cy;
1022 newno = newnodeinst(np, xcur, xcur+pxs, ycur, ycur+pys,
1023 pangle/3600, pangle%3600, curcell);
1024 if (newno == NONODEINST)
1025 {
1026 us_abortcommand(_("Cannot create node"));
1027 return;
1028 }
1029 if ((np->userbits&WANTNEXPAND) != 0) newno->userbits |= NEXPAND;
1030 if (np == gen_cellcenterprim) newno->userbits |= HARDSELECTN|NVISIBLEINSIDE; else
1031 if (np == gen_essentialprim) newno->userbits |= HARDSELECTN;
1032
1033 /* copy "inheritable" attributes */
1034 us_inheritattributes(newno);
1035 endobjectchange((INTBIG)newno, VNODEINST);
1036
1037 newhigh.status = HIGHFROM;
1038 newhigh.cell = newno->parent;
1039 newhigh.fromgeom = newno->geom;
1040 newhigh.fromport = NOPORTPROTO;
1041 newhigh.frompoint = 0;
1042 us_addhighlight(&newhigh);
1043 return;
1044 }
1045
1046 /* see if two objects are selected (and arc should connect them) */
1047 if (!us_gettwoobjects(&fromgeom, &fromport, &togeom, &toport))
1048 {
1049 /* two objects highlighted: create an arc between them */
1050 if (us_demandxy(&xcur, &ycur)) return;
1051 gridalign(&xcur, &ycur, 1, geomparent(togeom));
1052 if (geomparent(fromgeom) != geomparent(togeom))
1053 {
1054 us_abortcommand(_("Cannot run an arc between different cells"));
1055 return;
1056 }
1057
1058 if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1059
1060 /* run an arc from "fromgeom" to "togeom" */
1061 if (remainhighlighted) us_pushhighlight();
1062 us_clearhighlightcount();
1063 if (!angledcreate) ang = 900;
1064 ai = aconnect(fromgeom, fromport, togeom, toport, us_curarcproto,
1065 xcur, ycur, &alt1, &alt2, &con1, &con2, ang, FALSE, TRUE);
1066 if (remainhighlighted) us_pophighlight(FALSE);
1067 if (ai == NOARCINST) return;
1068
1069 /* unless indicated, leave only one object highlighted */
1070 if (!remainhighlighted)
1071 {
1072 /* if an arc was highlighted and it got broken, fix the highlight */
1073 geom = togeom;
1074 if (!geom->entryisnode && (geom->entryaddr.ai->userbits&DEADA) != 0)
1075 {
1076 geom = fromgeom;
1077 if (!geom->entryisnode && (geom->entryaddr.ai->userbits&DEADA) != 0) return;
1078 }
1079
1080 newhigh.status = HIGHFROM;
1081 newhigh.cell = geomparent(geom);
1082 newhigh.fromgeom = geom;
1083 newhigh.fromport = NOPORTPROTO;
1084 us_addhighlight(&newhigh);
1085 }
1086 return;
1087 }
1088
1089 /* "create angle": get cursor co-ordinates */
1090 if (us_demandxy(&xcur, &ycur)) return;
1091 gridalign(&xcur, &ycur, 1, curcell);
1092
1093 /* get nodeinst from which to draw */
1094 list = us_gethighlighted(WANTNODEINST|WANTARCINST, 0, 0);
1095 if (list[0] == NOGEOM || list[1] != NOGEOM)
1096 {
1097 us_abortcommand(_("Must start new arcs from one node or arc"));
1098 return;
1099 }
1100 splitpp = NOPORTPROTO;
1101 if (list[0]->entryisnode)
1102 {
1103 ni = list[0]->entryaddr.ni;
1104 high = us_getonehighlight();
1105 if (high != NOHIGHLIGHT && (high->status&HIGHTYPE) == HIGHFROM)
1106 splitpp = high->fromport;
1107 } else
1108 {
1109 ni = us_getnodeonarcinst(&list[0], &splitpp, list[0], NOPORTPROTO, xcur, ycur, 0);
1110 if (ni == NONODEINST)
1111 {
1112 us_abortcommand(_("Cannot find starting point of new arc"));
1113 return;
1114 }
1115 us_endchanges(NOWINDOWPART);
1116 }
1117
1118 /* ensure that cursor is in proper window */
1119 if (ni->parent != curcell)
1120 {
1121 us_abortcommand(_("Cursor must be in the same cell as the highlighted node"));
1122 return;
1123 }
1124 if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1125
1126 /* find the closest port to the cursor */
1127 bestdist1 = bestdist2 = MAXINTBIG;
1128 ppt = fpt = NOPORTPROTO;
1129 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1130 {
1131 if (splitpp != NOPORTPROTO && pp != splitpp) continue;
1132 shapeportpoly(ni, pp, poly, FALSE);
1133 k = polydistance(poly, xcur, ycur);
1134
1135 /* find the closest port to the cursor */
1136 if (k < bestdist1)
1137 {
1138 bestdist1 = k;
1139 ppt = pp; /* pp is the closest port to (xcur, ycur) */
1140 }
1141
1142 /* find the closest port that can connect with the current arc */
1143 if (k < bestdist2)
1144 {
1145 for (i=0; pp->connects[i] != NOARCPROTO; i++)
1146 {
1147 if (pp->connects[i] == us_curarcproto)
1148 {
1149 /* can connect */
1150 bestdist2 = k;
1151 fpt = pp;
1152 }
1153 }
1154 }
1155 }
1156
1157 /* error if there is no port */
1158 if (ppt == NOPORTPROTO)
1159 {
1160 us_abortcommand(_("Cannot run wires out of this node"));
1161 return;
1162 }
1163
1164 /*
1165 * now ppt is the closest port, and fpt is the closest port that can
1166 * connect with the current arc.
1167 */
1168 if (fpt == NOPORTPROTO)
1169 {
1170 /* no arcproto of correct type: first reset all arcprotos */
1171 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
1172 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1173 ap->userbits &= ~CANCONNECT;
1174
1175 /* now set all arcs that can connect this node's closest port */
1176 for(i=0; ppt->connects[i] != NOARCPROTO; i++)
1177 ppt->connects[i]->userbits |= CANCONNECT;
1178
1179 /* see if current arcproto is acceptable */
1180 if ((us_curarcproto->userbits&CANCONNECT) == 0)
1181 {
1182 /* search this technology for another arcproto */
1183 for(ap = el_curtech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
1184 {
1185 if ((ap->userbits&CANCONNECT) == 0) continue;
1186 if (getpinproto(ap) == NONODEPROTO) return;
1187 us_setarcproto(ap, FALSE);
1188 break;
1189 }
1190
1191 /* if nothing in this technology can connect, see what can */
1192 if (ap == NOARCPROTO && ppt->connects[0] != NOARCPROTO)
1193 {
1194 ap = ppt->connects[0];
1195 if (getpinproto(ap) == NONODEPROTO) return;
1196 us_setarcproto(ap, FALSE);
1197 }
1198
1199 /* error if no acceptable arcprotos */
1200 if (ap == NOARCPROTO)
1201 {
1202 us_abortcommand(_("No ports on this node"));
1203 return;
1204 }
1205 }
1206 } else ppt = fpt;
1207 splitpp = ppt;
1208
1209 /* make sure the selected arc connects to this port */
1210 wantap = us_curarcproto;
1211 for(i=0; splitpp->connects[i] != NOARCPROTO; i++)
1212 if (splitpp->connects[i] == us_curarcproto) break;
1213 if (splitpp->connects[i] == NOARCPROTO)
1214 {
1215 /* cannot: see if anything in this technology can connect */
1216 for(i=0; splitpp->connects[i] != NOARCPROTO; i++)
1217 if (splitpp->connects[i]->tech == us_curarcproto->tech) break;
1218 if (splitpp->connects[i] != NOARCPROTO) wantap = splitpp->connects[i]; else
1219 {
1220 /* cannot: see if anything nongeneric can connect */
1221 for(i=0; splitpp->connects[i] != NOARCPROTO; i++)
1222 if (splitpp->connects[i]->tech != gen_tech) break;
1223 if (splitpp->connects[i] != NOARCPROTO) wantap = splitpp->connects[i]; else
1224 {
1225 /* cannot: select the first possible arcproto */
1226 wantap = splitpp->connects[0];
1227 }
1228 }
1229 }
1230
1231 /* turn off highlighting */
1232 us_clearhighlightcount();
1233
1234 /* specify precise location for new port */
1235 poly->xv[0] = xcur; poly->yv[0] = ycur; poly->count = 1;
1236 shapeportpoly(ni, ppt, poly, 1);
1237
1238 /* determine pin for making the connection */
1239 np = getpinproto(wantap);
1240 if (np == NONODEPROTO) return;
1241
1242 /* get placement angle */
1243 pangle = us_getplacementangle(np);
1244
1245 /* determine location of pin */
1246 defaultnodesize(np, &pxs, &pys);
1247 corneroffset(NONODEINST, np, pangle%3600, pangle/3600, &cx, &cy,
1248 centeredprimitives);
1249
1250 /* adjust size if technologies differ */
1251 us_adjustfornodeincell(np, curcell, &cx, &cy);
1252 us_adjustfornodeincell(np, curcell, &pxs, &pys);
1253 px = pxs / 2; py = pys / 2;
1254
1255 /* adjust the cursor position if selecting interactively */
1256 switch (poly->style)
1257 {
1258 case FILLED:
1259 case FILLEDRECT:
1260 case CROSSED:
1261 case CROSS:
1262 case BIGCROSS:
1263 case TEXTCENT:
1264 case TEXTTOP:
1265 case TEXTBOT:
1266 case TEXTLEFT:
1267 case TEXTRIGHT:
1268 case TEXTTOPLEFT:
1269 case TEXTBOTLEFT:
1270 case TEXTTOPRIGHT:
1271 case TEXTBOTRIGHT:
1272 case TEXTBOX:
1273 case DISC:
1274 getcenter(poly, &x, &y);
1275 nx = x; ny = y;
1276 gridalign(&nx, &ny, 1, curcell);
1277 if (nx != x || ny != y)
1278 {
1279 if (isinside(nx, ny, poly))
1280 {
1281 x = nx;
1282 y = ny;
1283 }
1284 }
1285 break;
1286
1287 default:
1288 x = xcur; y = ycur;
1289 closestpoint(poly, &x, &y);
1290 break;
1291 }
1292 if ((us_tool->toolstate&INTERACTIVE) != 0)
1293 {
1294 fromgeom = ni->geom;
1295 us_createinit(x-px+cx, y-py+cy, np, ang, join, fromgeom, ppt);
1296 trackcursor(waitfordown, us_ignoreup, us_createabegin, us_createadown,
1297 us_stoponchar, us_createaup, TRACKDRAGGING);
1298 if (el_pleasestop != 0) return;
1299 if (us_demandxy(&xcur, &ycur)) return;
1300 if (join)
1301 {
1302 us_createajoinedobject(&togeom, &toport);
1303 if (togeom != NOGEOM)
1304 {
1305 if (us_figuredrawpath(fromgeom, ppt, togeom, toport, &xcur, &ycur))
1306 return;
1307 us_clearhighlightcount();
1308 ai = aconnect(fromgeom, ppt, togeom, toport, wantap,
1309 xcur, ycur, &alt1, &alt2, &con1, &con2, ang, FALSE, TRUE);
1310 if (ai == NOARCINST) return;
1311
1312 /* if an arc was highlighted and it got broken, fix the highlight */
1313 if (!togeom->entryisnode && (togeom->entryaddr.ai->userbits&DEADA) != 0)
1314 {
1315 togeom = fromgeom;
1316 if (!togeom->entryisnode && (togeom->entryaddr.ai->userbits&DEADA) != 0) return;
1317 }
1318
1319 newhigh.status = HIGHFROM;
1320 newhigh.cell = geomparent(togeom);
1321 newhigh.fromgeom = togeom;
1322 newhigh.fromport = toport;
1323 us_addhighlight(&newhigh);
1324 return;
1325 }
1326 }
1327 gridalign(&xcur, &ycur, 1, curcell);
1328 }
1329
1330 /* determine the proper point on the polygon to draw radials */
1331 us_getslide(ang, x-px+cx, y-py+cy, xcur, ycur, &nx, &ny);
1332
1333 /* adjust for the box corner */
1334 nx -= cx;
1335 ny -= cy;
1336
1337 /* handle connection if not interactive */
1338 if ((us_tool->toolstate&INTERACTIVE) == 0)
1339 {
1340 /* find the object under the cursor */
1341 if (!join) foundgeom = NOGEOM; else
1342 {
1343 alignment = muldiv(us_alignment_ratio, el_curlib->lambda[el_curtech->techindex], WHOLE);
1344 foundgeom = us_getclosest(nx+px, ny+py, alignment/2, ni->parent);
1345 }
1346 if (foundgeom != NOGEOM)
1347 {
1348 /* found another object: connect to it */
1349 fpt = ppt = NOPORTPROTO;
1350 bestdist = bestdist2 = MAXINTBIG;
1351 if (foundgeom->entryisnode)
1352 {
1353 /* find the closest port */
1354 ni = foundgeom->entryaddr.ni;
1355 for(pp = ni->proto->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1356 {
1357 shapeportpoly(ni, pp, poly, FALSE);
1358 dist = polydistance(poly, xcur, ycur);
1359
1360 /* find the closest port to the cursor */
1361 if (dist < bestdist)
1362 {
1363 bestdist = dist;
1364 fpt = pp;
1365 }
1366
1367 /* find the closest port that can connect with the current arc */
1368 if (dist < bestdist2)
1369 {
1370 for (i=0; pp->connects[i] != NOARCPROTO; i++)
1371 {
1372 if (pp->connects[i] == wantap)
1373 {
1374 /* can connect */
1375 bestdist2 = dist;
1376 ppt = pp;
1377 }
1378 }
1379 }
1380 }
1381 if (fpt != ppt)
1382 {
1383 /* the closest port cannot connect, but maybe it can with a different arc */
1384 for(i=0; fpt->connects[i] != NOARCPROTO; i++)
1385 {
1386 if (fpt->connects[i]->tech == gen_tech) continue;
1387 for(j=0; splitpp->connects[j] != NOARCPROTO; j++)
1388 {
1389 if (fpt->connects[i] == splitpp->connects[j]) break;
1390 }
1391 if (splitpp->connects[j] != NOARCPROTO) break;
1392 }
1393 if (fpt->connects[i] != NOARCPROTO)
1394 {
1395 us_setarcproto(fpt->connects[i], FALSE);
1396 ppt = fpt;
1397 }
1398 }
1399 if (ppt != NOPORTPROTO) fpt = ppt;
1400 }
1401 (void)aconnect(ni->geom, splitpp, foundgeom,
1402 fpt, wantap, xcur, ycur, &alt1, &alt2, &con1, &con2, ang, TRUE, TRUE);
1403
1404 /* if an arc will be highlighted and it broke, fix the highlight */
1405 if (!foundgeom->entryisnode &&
1406 (foundgeom->entryaddr.ai->userbits&DEADA) != 0) return;
1407
1408 /* highlight the found object */
1409 newhigh.status = HIGHFROM;
1410 newhigh.cell = ni->parent;
1411 newhigh.fromgeom = foundgeom;
1412 newhigh.fromport = fpt;
1413 newhigh.frompoint = 0;
1414 us_addhighlight(&newhigh);
1415 return;
1416 }
1417 }
1418
1419 /* determine arc width */
1420 truewid = maxi(defaultarcwidth(wantap), us_widestarcinst(wantap, ni, ppt));
1421 i = us_stretchtonodes(wantap, truewid, ni, ppt, xcur, ycur);
1422 if (i > truewid) truewid = i;
1423 wid = truewid - arcprotowidthoffset(wantap);
1424
1425 /* see if arc edge alignment is appropriate */
1426 if (us_edgealignment_ratio != 0 && (x == nx || y == ny))
1427 {
1428 edgealignment = muldiv(us_edgealignment_ratio, WHOLE, el_curlib->lambda[el_curtech->techindex]);
1429 if (x != nx) isver = FALSE; else
1430 {
1431 isver = TRUE;
1432 ny = us_alignvalue(ny + wid/2, edgealignment, &otheralign) - wid/2;
1433 }
1434 if (y != ny) ishor = FALSE; else
1435 {
1436 ishor = TRUE;
1437 nx = us_alignvalue(nx + wid/2, edgealignment, &otheralign) - wid/2;
1438 }
1439
1440 shapeportpoly(ni, ppt, poly, FALSE);
1441 i = us_alignvalue(x + wid/2, edgealignment, &otheralign) - wid/2;
1442 otheralign -= wid/2;
1443 if (isinside(i, y, poly))
1444 {
1445 if (isver) nx = i;
1446 x = i;
1447 } else if (isinside(otheralign, y, poly))
1448 {
1449 if (isver) nx = otheralign;
1450 x = otheralign;
1451 }
1452
1453 i = us_alignvalue(y + wid/2, edgealignment, &otheralign) - wid/2;
1454 otheralign -= wid/2;
1455 if (isinside(x, i, poly))
1456 {
1457 if (ishor) ny = i;
1458 y = i;
1459 } else if (isinside(x, otheralign, poly))
1460 {
1461 if (ishor) ny = otheralign;
1462 y = otheralign;
1463 }
1464 }
1465
1466 /* create the pin and the arcinst to it */
1467 defaultnodesize(np, &pxs, &pys);
1468 us_adjustfornodeincell(np, curcell, &pxs, &pys);
1469 newno = newnodeinst(np, nx, nx+pxs, ny, ny+pys,
1470 pangle/3600, pangle%3600, curcell);
1471 if (newno == NONODEINST)
1472 {
1473 us_abortcommand(_("Cannot create pin"));
1474 return;
1475 }
1476 nx += px; ny += py;
1477 if ((np->userbits&WANTNEXPAND) != 0) newno->userbits |= NEXPAND;
1478 endobjectchange((INTBIG)newno, VNODEINST);
1479 if (((ppt->userbits&PORTARANGE) >> PORTARANGESH) == 180)
1480 {
1481 ai = us_runarcinst(ni, ppt, x, y, newno,
1482 newno->proto->firstportproto, nx, ny, wantap, truewid);
1483 if (ai != NOARCINST) us_reportarcscreated(0, 1, wantap->protoname, 0, x_(""));
1484 } else
1485 {
1486 k = us_bottomrecurse(ni, ppt) % 3600;
1487 if (k < 0) k += 3600;
1488 xcur = x + mult(cosine(k), ni->highx-ni->lowx);
1489 ycur = y + mult(sine(k), ni->highy-ni->lowy);
1490 (void)aconnect(ni->geom, ppt, newno->geom, newno->proto->firstportproto,
1491 wantap, xcur, ycur, &alt1, &alt2, &con1, &con2, ang, TRUE, TRUE);
1492 }
1493
1494 newhigh.status = HIGHFROM;
1495 newhigh.cell = newno->parent;
1496 newhigh.fromgeom = newno->geom;
1497 newhigh.fromport = NOPORTPROTO;
1498 newhigh.frompoint = 0;
1499 us_addhighlight(&newhigh);
1500 return;
1501 }
1502
1503 /* handle the creation of an icon */
1504 if (namesamen(par[0], x_("icon"), l) == 0 && l >= 2)
1505 {
1506 /* find the icon for the current cell */
1507 np = iconview(curcell);
1508 if (np == NONODEPROTO)
1509 {
1510 us_abortcommand(_("No icon view for cell %s"),
1511 describenodeproto(curcell));
1512 return;
1513 }
1514
1515 /* make sure there isn't already one of these */
1516 for(ni = curcell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1517 if (ni->proto == np) break;
1518 if (ni != NONODEINST) return;
1519
1520 var = getval((INTBIG)us_tool, VTOOL, VINTEGER, x_("USER_icon_style"));
1521 if (var != NOVARIABLE) j = var->addr; else j = ICONSTYLEDEFAULT;
1522 i = (j & ICONINSTLOC) >> ICONINSTLOCSH;
1523 px = np->highx - np->lowx;
1524 py = np->highy - np->lowy;
1525 switch (i)
1526 {
1527 case 0: /* upper-right */
1528 lx = curcell->highx - px;
1529 ly = curcell->highy - py;
1530 break;
1531 case 1: /* upper-left */
1532 lx = curcell->lowx;
1533 ly = curcell->highy - py;
1534 break;
1535 case 2: /* lower-right */
1536 lx = curcell->highx - px;
1537 ly = curcell->lowy;
1538 break;
1539 case 3: /* lower-left */
1540 lx = curcell->lowx;
1541 ly = curcell->lowy;
1542 break;
1543 }
1544 gridalign(&lx, &ly, 1, curcell);
1545 hx = lx + px; hy = ly + py;
1546 ni = newnodeinst(np, lx, hx, ly, hy, 0, 0, curcell);
1547 if (ni != NONODEINST)
1548 {
1549 ni->userbits |= NEXPAND;
1550 us_inheritattributes(ni);
1551 endobjectchange((INTBIG)ni, VNODEINST);
1552 us_clearhighlightcount();
1553 newhigh.status = HIGHFROM;
1554 newhigh.cell = curcell;
1555 newhigh.fromgeom = ni->geom;
1556 newhigh.fromport = NOPORTPROTO;
1557 newhigh.frompoint = 0;
1558 us_addhighlight(&newhigh);
1559 if (lx > el_curwindowpart->screenhx || hx < el_curwindowpart->screenlx ||
1560 ly > el_curwindowpart->screenhy || hy < el_curwindowpart->screenly)
1561 {
1562 newpar[0] = x_("center-highlight");
1563 us_window(1, newpar);
1564 }
1565 }
1566 return;
1567 }
1568
1569 /* handle the absolute placement option */
1570 if (namesamen(par[0], x_("to"), l) == 0 && l >= 1)
1571 {
1572 /* get the location */
1573 if (count < 3)
1574 {
1575 ttyputusage(x_("create to X Y"));
1576 return;
1577 }
1578 nx = atola(par[1], 0);
1579 ny = atola(par[2], 0);
1580
1581 /* disallow copying if lock is on */
1582 np = us_nodetocreate(TRUE, curcell);
1583 if (np == NONODEPROTO) return;
1584
1585 if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1586
1587 /* get placement angle */
1588 pangle = us_getplacementangle(np);
1589
1590 corneroffset(NONODEINST, np, pangle%3600, pangle/3600, &cx, &cy,
1591 centeredprimitives);
1592 nx -= cx; ny -= cy;
1593 defaultnodesize(np, &pxs, &pys);
1594 newno = newnodeinst(np, nx, nx+pxs, ny, ny+pys,
1595 pangle/3600, pangle%3600, curcell);
1596 if (newno == NONODEINST)
1597 {
1598 us_abortcommand(_("Cannot create pin"));
1599 return;
1600 }
1601 if ((np->userbits&WANTNEXPAND) != 0) newno->userbits |= NEXPAND;
1602 if (np == gen_cellcenterprim) newno->userbits |= HARDSELECTN|NVISIBLEINSIDE; else
1603 if (np == gen_essentialprim) newno->userbits |= HARDSELECTN;
1604 endobjectchange((INTBIG)newno, VNODEINST);
1605
1606 us_clearhighlightcount();
1607 newhigh.status = HIGHFROM;
1608 newhigh.cell = newno->parent;
1609 newhigh.fromgeom = newno->geom;
1610 newhigh.fromport = NOPORTPROTO;
1611 newhigh.frompoint = 0;
1612 us_addhighlight(&newhigh);
1613 return;
1614 }
1615
1616 if (namesamen(par[0], x_("insert"), l) == 0 && l >= 2)
1617 {
1618 if (us_demandxy(&xcur, &ycur)) return;
1619 gridalign(&xcur, &ycur, 1, curcell);
1620
1621 /* get the highlighted arc */
1622 ai = (ARCINST *)us_getobject(VARCINST, FALSE);
1623 if (ai == NOARCINST) return;
1624 ap = ai->proto;
1625
1626 /* get the node to insert */
1627 np = us_nodetocreate(TRUE, curcell);
1628 if (np == NONODEPROTO) return;
1629
1630 /* disallow creating if lock is on */
1631 if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1632
1633 /* turn off highlighting */
1634 us_clearhighlightcount();
1635 if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(np);
1636
1637 /* adjust position interactively if possible */
1638 if ((us_tool->toolstate&INTERACTIVE) != 0)
1639 {
1640 us_createinsinit(ai, np);
1641 trackcursor(waitfordown, us_ignoreup, us_createinsbegin, us_createinsdown,
1642 us_stoponchar, us_dragup, TRACKDRAGGING);
1643 if (el_pleasestop != 0) return;
1644 }
1645 if (us_demandxy(&xcur, &ycur)) return;
1646 gridalign(&xcur, &ycur, 1, curcell);
1647
1648 /* find two ports on this node that connect to the arc */
1649 pp1 = pp2 = NOPORTPROTO;
1650 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
1651 {
1652 /* make sure this port can connect to this arc */
1653 for(i=0; pp->connects[i] != NOARCPROTO; i++)
1654 if (pp->connects[i] == ap) break;
1655 if (pp->connects[i] == NOARCPROTO) continue;
1656
1657 /* save the port */
1658 if (pp1 == NOPORTPROTO) pp1 = pp; else
1659 if (pp2 == NOPORTPROTO) pp2 = pp;
1660 }
1661
1662 /* make sure there are two ports for connection */
1663 if (pp1 == NOPORTPROTO)
1664 {
1665 us_abortcommand(_("No ports on %s node connect to %s arcs"), describenodeproto(np),
1666 describearcproto(ap));
1667 return;
1668 }
1669 if (pp2 == NOPORTPROTO) pp2 = pp1;
1670
1671 /* determine position of the new node */
1672 ang = ((ai->userbits&AANGLE) >> AANGLESH) * 10;
1673 (void)intersect(ai->end[0].xpos, ai->end[0].ypos, ang, xcur,
1674 ycur, (ang+900)%3600, &nx, &ny);
1675 cx = mini(ai->end[0].xpos, ai->end[1].xpos);
1676 if (nx < cx) nx = cx;
1677 cx = maxi(ai->end[0].xpos, ai->end[1].xpos);
1678 if (nx > cx) nx = cx;
1679 cy = mini(ai->end[0].ypos, ai->end[1].ypos);
1680 if (ny < cy) ny = cy;
1681 cy = maxi(ai->end[0].ypos, ai->end[1].ypos);
1682 if (ny > cy) ny = cy;
1683 defaultnodesize(np, &px, &py);
1684 x = nx - px/2; y = ny - py/2;
1685
1686 /* create the new node */
1687 ni = newnodeinst(np, x,x+px, y,y+py, 0, 0, curcell);
1688 if (ni == NONODEINST)
1689 {
1690 us_abortcommand(_("Cannot create node %s"), describenodeproto(np));
1691 return;
1692 }
1693 endobjectchange((INTBIG)ni, VNODEINST);
1694 portposition(ni, pp1, &nx, &ny);
1695 portposition(ni, pp2, &cx, &cy);
1696
1697 /* see if any rotation needs to be applied to this node */
1698 if (pp1 != pp2)
1699 {
1700 k = figureangle(nx, ny, cx, cy);
1701 if (k != ang)
1702 {
1703 if ((k+1800)%3600 == ang)
1704 {
1705 /* simple 180 degree rotation: reverse the ports */
1706 pp = pp1; pp1 = pp2; pp2 = pp;
1707 } else
1708 {
1709 /* complex rotation: rotate the node */
1710 ang -= k; if (ang < 0) ang += 3600;
1711 startobjectchange((INTBIG)ni, VNODEINST);
1712 modifynodeinst(ni, 0, 0, 0, 0, ang, 0);
1713 endobjectchange((INTBIG)ni, VNODEINST);
1714 portposition(ni, pp1, &nx, &ny);
1715 portposition(ni, pp2, &cx, &cy);
1716 }
1717 }
1718 }
1719
1720 /* see if node edge alignment is appropriate */
1721 if (us_edgealignment_ratio != 0 && (ai->end[0].xpos == ai->end[1].xpos ||
1722 ai->end[0].ypos == ai->end[1].ypos))
1723 {
1724 edgealignment = muldiv(us_edgealignment_ratio, WHOLE, el_curlib->lambda[el_curtech->techindex]);
1725 px = us_alignvalue(x, edgealignment, &otheralign);
1726 py = us_alignvalue(y, edgealignment, &otheralign);
1727 if (px != x || py != y)
1728 {
1729 /* shift the node and make sure the ports are still valid */
1730 startobjectchange((INTBIG)ni, VNODEINST);
1731 modifynodeinst(ni, px-x, py-y, px-x, py-y, 0, 0);
1732 endobjectchange((INTBIG)ni, VNODEINST);
1733 (void)shapeportpoly(ni, pp1, poly, FALSE);
1734 if (!isinside(nx, ny, poly)) getcenter(poly, &nx, &ny);
1735 (void)shapeportpoly(ni, pp2, poly, FALSE);
1736 if (!isinside(cx, cy, poly)) getcenter(poly, &cx, &cy);
1737 }
1738 }
1739
1740 /* now save the arc information and delete it */
1741 for(i=0; i<2; i++)
1742 {
1743 xp[i] = ai->end[i].xpos;
1744 yp[i] = ai->end[i].ypos;
1745 app[i] = ai->end[i].portarcinst->proto;
1746 ani[i] = ai->end[i].nodeinst;
1747 }
1748 wid = ai->width;
1749 bits1 = bits2 = ai->userbits;
1750 if ((bits1&ISNEGATED) != 0)
1751 {
1752 if ((bits1&REVERSEEND) == 0) bits2 &= ~ISNEGATED; else
1753 bits1 &= ~ISNEGATED;
1754 }
1755 var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
1756 if (var == NOVARIABLE) oldarcname = 0; else
1757 {
1758 (void)allocstring(&oldarcname, (CHAR *)var->addr, el_tempcluster);
1759 (void)asktool(net_tool, x_("delname"), (INTBIG)oldarcname,
1760 (INTBIG)curcell);
1761 }
1762 startobjectchange((INTBIG)ai, VARCINST);
1763 (void)killarcinst(ai);
1764
1765 /* create the two new arcs */
1766 newai = newarcinst(ap, wid, bits1, ani[0], app[0], xp[0], yp[0], ni, pp1, nx, ny, curcell);
1767 if (oldarcname != 0 && newai != NOARCINST)
1768 {
1769 (void)asktool(net_tool, x_("setname"), (INTBIG)newai, (INTBIG)oldarcname);
1770 var = setvalkey((INTBIG)newai, VARCINST, el_arc_name_key, (INTBIG)oldarcname, VSTRING|VDISPLAY);
1771 if (var != NOVARIABLE)
1772 defaulttextsize(4, var->textdescript);
1773 efree(oldarcname);
1774 }
1775 if (newai != NOARCINST) endobjectchange((INTBIG)newai, VARCINST);
1776 newai = newarcinst(ap, wid, bits2, ni, pp2, cx, cy, ani[1],app[1],xp[1],yp[1], curcell);
1777 if (newai != NOARCINST) endobjectchange((INTBIG)newai, VARCINST);
1778
1779 /* highlight the node */
1780 newhigh.status = HIGHFROM;
1781 newhigh.cell = curcell;
1782 newhigh.fromgeom = ni->geom;
1783 newhigh.fromport = NOPORTPROTO;
1784 newhigh.frompoint = 0;
1785 us_addhighlight(&newhigh);
1786 return;
1787 }
1788
1789 if (namesamen(par[0], x_("breakpoint"), l) == 0 && l >= 1)
1790 {
1791 /* get the highlighted arc */
1792 ai = (ARCINST *)us_getobject(VARCINST, FALSE);
1793 if (ai == NOARCINST) return;
1794 ap = ai->proto;
1795
1796 /* get the pin to insert */
1797 np = getpinproto(ap);
1798 if (np == NONODEPROTO)
1799 {
1800 us_abortcommand(_("Cannot determine pin type to insert in arc"));
1801 return;
1802 }
1803 ppt = np->firstportproto;
1804
1805 if (us_cantedit(curcell, NONODEINST, TRUE)) return;
1806
1807 /* turn off highlighting */
1808 us_clearhighlightcount();
1809 if ((us_state&NONPERSISTENTCURNODE) != 0) us_setnodeproto(np);
1810
1811 /* adjust position interactively if possible */
1812 if ((us_tool->toolstate&INTERACTIVE) != 0)
1813 {
1814 /* highlight the arc */
1815 i = ai->width - arcwidthoffset(ai);
1816 if (curvedarcoutline(ai, poly, OPENEDO1, i))
1817 makearcpoly(ai->length, i, ai, poly, OPENEDO1);
1818 if (poly->limit < poly->count+1) (void)extendpolygon(poly, poly->count+1);
1819 poly->xv[poly->count] = poly->xv[0];
1820 poly->yv[poly->count] = poly->yv[0];
1821 poly->count++;
1822 poly->desc = &us_hbox;
1823 poly->desc->col = HIGHLIT;
1824 us_showpoly(poly, el_curwindowpart);
1825
1826 /* interactively select the break location */
1827 us_createinsinit(ai, np);
1828 trackcursor(waitfordown, us_ignoreup, us_createinsbegin, us_createinsdown,
1829 us_stoponchar, us_dragup, TRACKDRAGGING);
1830
1831 /* unhighlight the arc */
1832 poly->desc->col = 0;
1833 us_showpoly(poly, el_curwindowpart);
1834 if (el_pleasestop != 0) return;
1835 }
1836 if (us_demandxy(&xcur, &ycur)) return;
1837 gridalign(&xcur, &ycur, 1, curcell);
1838
1839 /* determine position of the new pins */
1840 ang = ((ai->userbits&AANGLE) >> AANGLESH) * 10;
1841 (void)intersect(ai->end[0].xpos, ai->end[0].ypos, ang, xcur, ycur, (ang+900)%3600, &nx, &ny);
1842 cx = mini(ai->end[0].xpos, ai->end[1].xpos);
1843 if (nx < cx) nx = cx;
1844 cx = maxi(ai->end[0].xpos, ai->end[1].xpos);
1845 if (nx > cx) nx = cx;
1846 cy = mini(ai->end[0].ypos, ai->end[1].ypos);
1847 if (ny < cy) ny = cy;
1848 cy = maxi(ai->end[0].ypos, ai->end[1].ypos);
1849 if (ny > cy) ny = cy;
1850 defaultnodesize(np, &px, &py);
1851 x = nx - px/2; y = ny - py/2;
1852
1853 /* create the break pins */
1854 ni = newnodeinst(np, x,x+px, y,y+py, 0, 0, curcell);
1855 if (ni == NONODEINST)
1856 {
1857 us_abortcommand(_("Cannot create pin %s"), describenodeproto(np));
1858 return;
1859 }
1860 endobjectchange((INTBIG)ni, VNODEINST);
1861 ni2 = newnodeinst(np, x,x+px, y,y+py, 0, 0, curcell);
1862 if (ni2 == NONODEINST)
1863 {
1864 us_abortcommand(_("Cannot create pin %s"), describenodeproto(np));
1865 return;
1866 }
1867 endobjectchange((INTBIG)ni2, VNODEINST);
1868
1869 /* get location of connection to these pins */
1870 portposition(ni, ppt, &nx, &ny);
1871
1872 /* see if edge alignment is appropriate */
1873 if (us_edgealignment_ratio != 0 && (ai->end[0].xpos == ai->end[1].xpos ||
1874 ai->end[0].ypos == ai->end[1].ypos))
1875 {
1876 edgealignment = muldiv(us_edgealignment_ratio, WHOLE, el_curlib->lambda[el_curtech->techindex]);
1877 px = us_alignvalue(x, edgealignment, &otheralign);
1878 py = us_alignvalue(y, edgealignment, &otheralign);
1879 if (px != x || py != y)
1880 {
1881 /* shift the nodes and make sure the ports are still valid */
1882 startobjectchange((INTBIG)ni, VNODEINST);
1883 modifynodeinst(ni, px-x, py-y, px-x, py-y, 0, 0);
1884 endobjectchange((INTBIG)ni, VNODEINST);
1885 startobjectchange((INTBIG)ni2, VNODEINST);
1886 modifynodeinst(ni2, px-x, py-y, px-x, py-y, 0, 0);
1887 endobjectchange((INTBIG)ni2, VNODEINST);
1888 (void)shapeportpoly(ni, ppt, poly, FALSE);
1889 if (!isinside(nx, ny, poly)) getcenter(poly, &nx, &ny);
1890 }
1891 }
1892
1893 /* now save the arc information and delete it */
1894 for(i=0; i<2; i++)
1895 {
1896 xp[i] = ai->end[i].xpos;
1897 yp[i] = ai->end[i].ypos;
1898 app[i] = ai->end[i].portarcinst->proto;
1899 ani[i] = ai->end[i].nodeinst;
1900 }
1901 wid = ai->width;
1902 bits1 = bits2 = ai->userbits;
1903 if ((bits1&ISNEGATED) != 0)
1904 {
1905 if ((bits1&REVERSEEND) == 0) bits2 &= ~ISNEGATED; else
1906 bits1 &= ~ISNEGATED;
1907 }
1908 var = getvalkey((INTBIG)ai, VARCINST, VSTRING, el_arc_name_key);
1909 if (var == NOVARIABLE) oldarcname = 0; else
1910 {
1911 (void)allocstring(&oldarcname, (CHAR *)var->addr, el_tempcluster);
1912 (void)asktool(net_tool, x_("delname"), (INTBIG)oldarcname,
1913 (INTBIG)curcell);
1914 }
1915 startobjectchange((INTBIG)ai, VARCINST);
1916 (void)killarcinst(ai);
1917
1918 /* create the new arcs */
1919 newai = newarcinst(ap, wid, bits1, ani[0], app[0], xp[0], yp[0], ni, ppt, nx, ny, curcell);
1920 if (oldarcname != 0 && newai != NOARCINST)
1921 {
1922 (void)asktool(net_tool, x_("setname"), (INTBIG)newai, (INTBIG)oldarcname);
1923 var = setvalkey((INTBIG)newai, VARCINST, el_arc_name_key, (INTBIG)oldarcname, VSTRING|VDISPLAY);
1924 if (var != NOVARIABLE)
1925 defaulttextsize(4, var->textdescript);
1926 efree(oldarcname);
1927 }
1928 if (newai != NOARCINST) endobjectchange((INTBIG)newai, VARCINST);
1929 newai = newarcinst(ap, wid, bits2, ni2, ppt, nx, ny, ani[1],app[1],xp[1],yp[1], curcell);
1930 if (newai != NOARCINST) endobjectchange((INTBIG)newai, VARCINST);
1931 bits2 &= ~ISNEGATED;
1932 ang = (ang + 900) % 3600;
1933 newai = newarcinst(ap, wid, bits2, ni, ppt, nx, ny, ni2, ppt, nx, ny, curcell);
1934 if (newai != NOARCINST)
1935 {
1936 endobjectchange((INTBIG)newai, VARCINST);
1937
1938 /* must set the angle explicitly since zero-length arcs have indeterminate angle */
1939 newai->userbits = (newai->userbits & ~AANGLE) | (((ang+5)/10) << AANGLESH);
1940 }
1941
1942 /* highlight the arc */
1943 newhigh.status = HIGHFROM;
1944 newhigh.cell = curcell;
1945 newhigh.fromgeom = newai->geom;
1946 newhigh.fromport = NOPORTPROTO;
1947 newhigh.frompoint = 0;
1948 us_addhighlight(&newhigh);
1949 return;
1950 }
1951
1952 ttyputbadusage(x_("create"));
1953 }
1954
1955 #define DEBUGMERGE 1
1956
1957 #ifdef DEBUGMERGE
1958 INTBIG us_debugmergeoffset;
1959 void us_debugwritepolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count);
1960
us_debugwritepolygon(INTBIG layer,TECHNOLOGY * tech,INTBIG * x,INTBIG * y,INTBIG count)1961 void us_debugwritepolygon(INTBIG layer, TECHNOLOGY *tech, INTBIG *x, INTBIG *y, INTBIG count)
1962 {
1963 REGISTER NODEPROTO *cell, *prim;
1964 REGISTER NODEINST *ni;
1965 REGISTER INTBIG lx, hx, ly, hy, cx, cy, *newlist;
1966 REGISTER INTBIG i;
1967 HIGHLIGHT high;
1968
1969 prim = getnodeproto(x_("metal-1-node"));
1970 cell = us_needcell();
1971 if (cell == NONODEPROTO) return;
1972 lx = hx = x[0];
1973 ly = hy = y[0];
1974 for(i=1; i<count; i++)
1975 {
1976 if (x[i] < lx) lx = x[i];
1977 if (x[i] > hx) hx = x[i];
1978 if (y[i] < ly) ly = y[i];
1979 if (y[i] > hy) hy = y[i];
1980 }
1981 cx = (lx+hx) / 2; cy = (ly+hy) / 2;
1982 ni = newnodeinst(prim, lx, hx, ly+us_debugmergeoffset, hy+us_debugmergeoffset, 0, 0, cell);
1983 newlist = (INTBIG *)emalloc(count * 2 * SIZEOFINTBIG, el_tempcluster);
1984 if (newlist == 0) return;
1985 for(i=0; i<count; i++)
1986 {
1987 newlist[i*2] = x[i] - cx;
1988 newlist[i*2+1] = y[i] - cy;
1989 }
1990 (void)setvalkey((INTBIG)ni, VNODEINST, el_trace_key, (INTBIG)newlist,
1991 VINTEGER|VISARRAY|((count*2)<<VLENGTHSH));
1992 endobjectchange((INTBIG)ni, VNODEINST);
1993 high.status = HIGHFROM;
1994 high.fromgeom = ni->geom;
1995 high.fromport = NOPORTPROTO;
1996 high.frompoint = 0;
1997 high.cell = cell;
1998 us_addhighlight(&high);
1999 }
2000 #endif
2001
2002 /*#define TESTMODELESS 1*/
2003
2004 #ifdef TESTMODELESS
2005 #include "edialogs.h"
2006 /* test */
2007 static DIALOGITEM us_testdialogitems[] =
2008 {
2009 /* 1 */ {0, {172,164,196,244}, BUTTON, N_("Done")},
2010 /* 2 */ {0, {28,8,44,88}, BUTTON, N_("Button")},
2011 /* 3 */ {0, {28,100,44,216}, CHECK, N_("Check Box")},
2012 /* 4 */ {0, {56,8,72,124}, RADIO, N_("Radio 1")},
2013 /* 5 */ {0, {76,8,92,124}, RADIO, N_("Radio 2")},
2014 /* 6 */ {0, {96,8,112,124}, RADIO, N_("Radio 3")},
2015 /* 7 */ {0, {132,8,232,132}, SCROLL, x_("")},
2016 /* 8 */ {0, {4,4,20,220}, MESSAGE, N_("A Modeless Dialog")},
2017 /* 9 */ {0, {56,140,72,280}, EDITTEXT, x_("")},
2018 /* 10 */ {0, {120,8,121,288}, DIVIDELINE, x_("")},
2019 /* 11 */ {0, {93,140,109,280}, POPUP, x_("")}
2020 };
2021 static DIALOG us_testdialog = {{75,75,316,372}, x_("Modeless Dialog"), 0, 11, us_testdialogitems, 0, 0};
2022 void *us_testmodelessdia;
2023 void us_modelessdialoghitroutine(void *dia, INTBIG item);
us_modelessdialoghitroutine(void * dia,INTBIG item)2024 void us_modelessdialoghitroutine(void *dia, INTBIG item)
2025 {
2026 if (item == 1)
2027 {
2028 DiaDoneDialog(us_testmodelessdia);
2029 return;
2030 }
2031 if (item == 2)
2032 {
2033 ttyputmsg(x_("Button clicked"));
2034 return;
2035 }
2036 if (item == 3)
2037 {
2038 DiaSetControl(us_testmodelessdia, item, 1-DiaGetControl(us_testmodelessdia, item));
2039 return;
2040 }
2041 if (item == 4 || item == 5 || item == 6)
2042 {
2043 DiaSetControl(us_testmodelessdia, 4, 0);
2044 DiaSetControl(us_testmodelessdia, 5, 0);
2045 DiaSetControl(us_testmodelessdia, 6, 0);
2046 DiaSetControl(us_testmodelessdia, item, 1);
2047 return;
2048 }
2049 if (item == 9)
2050 {
2051 ttyputmsg(x_("Edit now is '%s'"), DiaGetText(us_testmodelessdia, 9));
2052 return;
2053 }
2054 if (item == 11)
2055 {
2056 ttyputmsg(x_("Selected popup item %d"), DiaGetPopupEntry(us_testmodelessdia, 11));
2057 return;
2058 }
2059 }
2060 #endif
2061
us_debug(INTBIG count,CHAR * par[])2062 void us_debug(INTBIG count, CHAR *par[])
2063 {
2064 REGISTER NODEPROTO *np;
2065 REGISTER PORTPROTO *pp;
2066 REGISTER NODEINST *ni;
2067 REGISTER ARCINST *ai;
2068 REGISTER LIBRARY *lib;
2069 REGISTER VARIABLE *var;
2070 REGISTER INTBIG i, j, l, let1, let2, let3, filestatus;
2071 CHAR line[200], *pt, *libname, *libfile;
2072 extern BOOLEAN db_printerrors;
2073
2074 if (count == 0) return;
2075 l = estrlen(par[0]);
2076
2077 /********** THESE ARE SPECIAL CASES **********/
2078 #ifdef TESTMODELESS
2079 if (namesamen(par[0], x_("modeless"), l) == 0)
2080 {
2081 CHAR *popups[3];
2082 us_testmodelessdia = DiaInitDialogModeless(&us_testdialog, us_modelessdialoghitroutine);
2083 if (us_testmodelessdia == 0) return;
2084 DiaInitTextDialog(us_testmodelessdia, 7, DiaNullDlogList, DiaNullDlogItem,
2085 DiaNullDlogDone, -1, SCSELMOUSE|SCREPORT);
2086 DiaStuffLine(us_testmodelessdia, 7, x_("First Line"));
2087 DiaStuffLine(us_testmodelessdia, 7, x_("Second Line"));
2088 DiaStuffLine(us_testmodelessdia, 7, x_("Third Line"));
2089 DiaStuffLine(us_testmodelessdia, 7, x_("Fourth Line"));
2090 DiaStuffLine(us_testmodelessdia, 7, x_("Fifth Line"));
2091 DiaStuffLine(us_testmodelessdia, 7, x_("Sixth Line"));
2092 DiaStuffLine(us_testmodelessdia, 7, x_("Seventh Line"));
2093 DiaStuffLine(us_testmodelessdia, 7, x_("Eighth Line"));
2094 DiaStuffLine(us_testmodelessdia, 7, x_("Ninth Line"));
2095 DiaStuffLine(us_testmodelessdia, 7, x_("Tenth Line"));
2096 DiaSelectLine(us_testmodelessdia, 7, -1);
2097 DiaSetText(us_testmodelessdia, 9, x_("Initial edit"));
2098 popups[0] = x_("First popup");
2099 popups[1] = x_("Second popup");
2100 popups[2] = x_("Third popup");
2101 DiaSetPopup(us_testmodelessdia, 11, 3, popups);
2102 DiaSetControl(us_testmodelessdia, 4, 1);
2103 return;
2104 }
2105 #endif
2106
2107 #if 0 /* place 1 million parts */
2108 # define MILLIONSIZE 1000 /* square this to get number of nodes */
2109 if (namesamen(par[0], x_("million"), l) == 0)
2110 {
2111 NODEPROTO *item;
2112 extern TOOL *dr_tool, *ro_tool;
2113 REGISTER ARCPROTO *apwire;
2114 REGISTER PORTPROTO *ppy, *ppa;
2115 float duration;
2116 NODEINST *nilast;
2117 REGISTER void *dia;
2118 INTBIG lx, hx, ly, hy, wid, hei, maxy, maxx, nilastx, nilasty, nix, niy;
2119
2120 toolturnoff(dr_tool, FALSE);
2121 toolturnoff(ro_tool, FALSE);
2122 toolturnoff(us_tool, FALSE);
2123 apwire = getarcproto(x_("schematic:wire"));
2124 item = getnodeproto(x_("schematic:Off-Page"));
2125 if (item == NONODEPROTO) return;
2126 ppy = getportproto(item, x_("y"));
2127 ppa = getportproto(item, x_("a"));
2128 wid = item->highx - item->lowx;
2129 hei = item->highy - item->lowy;
2130 np = newnodeproto(x_("million"), el_curlib);
2131 dia = DiaInitProgress(x_("Building..."));
2132 if (dia == 0) return;
2133 maxy = MILLIONSIZE; maxx = MILLIONSIZE;
2134 starttimer();
2135 for(i=0; i<maxy; i++)
2136 {
2137 DiaSetProgress(dia, i, maxy);
2138 nilast = NONODEINST;
2139 for(j=0; j<maxx; j++)
2140 {
2141 lx = wid*j*2; hx = lx + wid;
2142 ly = hei*i*2; hy = ly + hei;
2143 ni = newnodeinst(item, lx, hx, ly, hy, 0, 0, np);
2144 if (nilast != NONODEINST)
2145 {
2146 portposition(nilast, ppy, &nilastx, &nilasty);
2147 portposition(ni, ppa, &nix, &niy);
2148 newarcinst(apwire, 0, 0, nilast, ppy, nilastx, nilasty,
2149 ni, ppa, nix, niy, np);
2150 }
2151 nilast = ni;
2152 }
2153 }
2154 duration = endtimer();
2155 ttyputmsg(x_("Took %s"), explainduration(duration));
2156 DiaDoneProgress(dia);
2157 toolturnon(us_tool);
2158 toolturnon(ro_tool);
2159 return;
2160 }
2161 #endif
2162
2163 #ifdef DEBUGMERGE
2164 if (namesamen(par[0], x_("merge"), l) == 0)
2165 {
2166 static POLYGON *poly = NOPOLYGON;
2167 NODEINST **nilist, *nisub;
2168 GEOM **list;
2169 void *merge;
2170 INTBIG total, done, thisx, thisy, lastx, lasty;
2171
2172 (void)needstaticpolygon(&poly, 4, us_tool->cluster);
2173 np = us_needcell();
2174 if (np == NONODEPROTO) return;
2175
2176 /* see what is highlighted (highlighted node is subtracted) */
2177 nisub = NONODEINST;
2178 list = us_gethighlighted(WANTNODEINST, 0, 0);
2179 if (list[0] != NOGEOM && list[1] == NOGEOM) nisub = list[0]->entryaddr.ni;
2180
2181 us_debugmergeoffset = np->highy - np->lowy +
2182 el_curlib->lambda[el_curtech->techindex]*4;
2183 total = 0;
2184 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2185 {
2186 if (ni->proto->primindex == 0) continue;
2187 if (((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH) != NPNODE) continue;
2188 if (ni == nisub) continue;
2189 total++;
2190 }
2191 if (total == 0) return;
2192 nilist = (NODEINST **)emalloc(total * (sizeof (NODEINST *)), el_tempcluster);
2193 total = 0;
2194 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2195 {
2196 if (ni->proto->primindex == 0) continue;
2197 if (((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH) != NPNODE) continue;
2198 if (ni == nisub) continue;
2199 nilist[total++] = ni;
2200 }
2201 done = 0;
2202 while (done == 0)
2203 {
2204 done = 1;
2205 for(i=1; i<total; i++)
2206 {
2207 thisx = (nilist[i]->lowx + nilist[i]->highx) / 2;
2208 thisy = (nilist[i]->lowy + nilist[i]->highy) / 2;
2209 lastx = (nilist[i-1]->lowx + nilist[i-1]->highx) / 2;
2210 lasty = (nilist[i-1]->lowy + nilist[i-1]->highy) / 2;
2211 if (lasty > thisy || (lasty == thisy && lastx <= thisx)) continue;
2212 ni = nilist[i]; nilist[i] = nilist[i-1]; nilist[i-1] = ni;
2213 done = 0;
2214 }
2215 }
2216 merge = mergenew(us_tool->cluster);
2217 for(l=0; l<total; l++)
2218 {
2219 ni = nilist[l];
2220 j = nodepolys(ni, 0, NOWINDOWPART);
2221 for(i=0; i<j; i++)
2222 {
2223 shapenodepoly(ni, i, poly);
2224 mergeaddpolygon(merge, poly->layer, poly->tech, poly);
2225 }
2226 }
2227 if (nisub != NONODEINST)
2228 {
2229 /* subtract this one */
2230 j = nodepolys(nisub, 0, NOWINDOWPART);
2231 for(i=0; i<j; i++)
2232 {
2233 shapenodepoly(nisub, i, poly);
2234 mergesubpolygon(merge, poly->layer, poly->tech, poly);
2235 }
2236 }
2237 mergeextract(merge, us_debugwritepolygon);
2238 mergedelete(merge);
2239 efree((CHAR *)nilist);
2240 return;
2241 }
2242 #endif
2243
2244 #if 0 /* find floating ends of arcs */
2245 if (namesamen(par[0], x_("show-isolated-pins"), l) == 0)
2246 {
2247 INTBIG fun;
2248 HIGHLIGHT newhigh;
2249 PORTARCINST *pi;
2250
2251 j = 0;
2252 np = us_needcell();
2253 if (np == NONODEPROTO) return;
2254 us_clearhighlightcount();
2255
2256 /* look for pins sitting alone at the end of an arc */
2257 for(ni=np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2258 {
2259 /* see if it is a pin */
2260 fun = nodefunction(ni);
2261 if (fun != NPPIN) continue;
2262
2263 /* ignore if it has exports on it */
2264 if (ni->firstportexpinst != NOPORTEXPINST) continue;
2265
2266 /* must connect to exactly 1 arc */
2267 if (ni->firstportarcinst == NOPORTARCINST) continue;
2268 if (ni->firstportarcinst->nextportarcinst != NOPORTARCINST) continue;
2269
2270 /* highlight the node */
2271 j++;
2272 newhigh.status = HIGHFROM;
2273 newhigh.cell = ni->parent;
2274 newhigh.fromgeom = ni->geom;
2275 newhigh.fromport = NOPORTPROTO;
2276 newhigh.frompoint = 0;
2277 us_addhighlight(&newhigh);
2278 }
2279
2280 /* look for bus pins that don't connect to bus wires */
2281 for(ni=np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2282 {
2283 /* see if it is a pin */
2284 if (ni->proto != sch_buspinprim) continue;
2285
2286 /* ignore if it has exports on it */
2287 if (ni->firstportexpinst != NOPORTEXPINST) continue;
2288
2289 /* must not connect to any bus arcs */
2290 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
2291 if (pi->conarcinst->proto == sch_busarc) break;
2292 if (pi != NOPORTARCINST) continue;
2293
2294 /* highlight the node */
2295 j++;
2296 newhigh.status = HIGHFROM;
2297 newhigh.cell = ni->parent;
2298 newhigh.fromgeom = ni->geom;
2299 newhigh.fromport = NOPORTPROTO;
2300 newhigh.frompoint = 0;
2301 us_addhighlight(&newhigh);
2302 }
2303 if (j == 0) ttyputmsg("No floating pins"); else
2304 ttyputmsg("Found %ld floating pins", j);
2305 return;
2306 }
2307 #endif
2308
2309 if (namesamen(par[0], x_("postscript-schematics"), l) == 0 && l >= 2)
2310 {
2311 WINDOWPART *win;
2312 win = el_curwindowpart;
2313 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2314 {
2315 if ((lib->userbits&HIDDENLIBRARY) != 0) continue;
2316
2317 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2318 {
2319 NODEPROTO *onp;
2320
2321 if (np->cellview != el_schematicview) continue;
2322 ttyputmsg("Dumping Postscript for %s", describenodeproto(np));
2323 onp = lib->curnodeproto;
2324 lib->curnodeproto = np;
2325 win->curnodeproto = np;
2326 (void)asktool(io_tool, x_("write"), (INTBIG)lib, (INTBIG)"postscript");
2327 win->curnodeproto = onp;
2328 lib->curnodeproto = onp;
2329 }
2330 }
2331 return;
2332 }
2333
2334 if (namesamen(par[0], x_("list-cells-with-universal-arcs"), l) == 0 && l >= 2)
2335 {
2336 LIBRARY *libwalk;
2337 NODEPROTO *np;
2338 ARCINST *ai;
2339
2340 for (libwalk = el_curlib; libwalk != NOLIBRARY; libwalk = libwalk->nextlibrary) {
2341 for (np = libwalk->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto) {
2342 /* check for universal arcs only in layout and schematic cells */
2343 if (np->cellview == el_schematicview || np->cellview == el_layoutview) {
2344 for (ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst) {
2345 if (ai->proto == gen_universalarc) {
2346 ttyputmsg(x_("Found universal arc in %s, arc %s"), describenodeproto(np), describearcinst(ai));
2347 }
2348 }
2349 }
2350 }
2351 }
2352 return;
2353 }
2354
2355 if (namesamen(par[0], x_("find-universal-arcs"), l) == 0 && l >= 2)
2356 {
2357 NODEPROTO *cell;
2358 void *infstr;
2359 ARCINST *ai;
2360 INTBIG count;
2361
2362 count = 0;
2363 cell = getcurcell();
2364 if (cell == NONODEPROTO) {
2365 ttyputerr(_("No current cell to search for universal arcs"));
2366 return;
2367 }
2368 /* remove highlighting */
2369 (void)asktool(us_tool, x_("clear"));
2370
2371 /* find any universal arcs in current cell and highlight them */
2372 infstr = initinfstr();
2373 for (ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst) {
2374 if (ai->proto == gen_universalarc) {
2375 us_highlighteverywhere(ai->geom, NOPORTPROTO, 1, TRUE, getecolor("white"), FALSE);
2376 /* JKG: this isn't quite right, but I'm not sure what is...disabling for now */
2377 count++;
2378 }
2379 }
2380 if (count == 0) ttyputmsg(_("none found"));
2381 else ttyputmsg(x_("%d universal arcs found"), count);
2382 return;
2383 }
2384
2385 if (namesamen(par[0], x_("prepare-tsmc-io"), l) == 0 && l >= 2)
2386 {
2387 INTBIG total;
2388 CHAR **filelist, libfile[200], libname[50];
2389 LIBRARY *leflib, *gdslib, *prepfile;
2390 extern TOOL *dr_tool;
2391
2392 #define TSMCELECDIRECTORY x_("E:\\DevelE\\Artisan\\TPZ872G_150C\\ELIB\\")
2393 #define TSMCGDSDIRECTORY x_("E:\\DevelE\\Artisan\\TPZ872G_150C\\GDS\\")
2394 #define TSMCLEFFILE x_("E:\\DevelE\\Artisan\\TPZ872G_150C\\LEF\\tpz872g_4lm.lef")
2395 #define TSMCPREPFILE x_("E:\\DevelE\\Artisan\\tsmc25m4.txt")
2396
2397 /* turn off DRC */
2398 toolturnoff(dr_tool, TRUE);
2399
2400 /* read the TSMC preparation file */
2401 estrcpy(libname, x_("prep"));
2402 estrcpy(libfile, TSMCPREPFILE);
2403 prepfile = newlibrary(libname, libfile);
2404 ttyputmsg(x_("Reading Preparation file %s"), libfile);
2405 if (asktool(io_tool, x_("read"), (INTBIG)prepfile, (INTBIG)x_("text"), 0))
2406 {
2407 ttyputerr(x_("Cannot find TSMC preparation file %s"), libfile);
2408 return;
2409 }
2410
2411 /* read the LEF library with ports */
2412 estrcpy(libname, x_("lef"));
2413 estrcpy(libfile, TSMCLEFFILE);
2414 leflib = newlibrary(libname, libfile);
2415 ttyputmsg(x_("Reading LEF file %s"), libfile);
2416 if (asktool(io_tool, x_("read"), (INTBIG)leflib, (INTBIG)x_("lef"), 0) != 0)
2417 {
2418 ttyputerr(x_("Cannot find LEF file %s"), libfile);
2419 return;
2420 }
2421
2422 /* create a library for the GDS files */
2423 estrcpy(libname, x_("gds"));
2424 estrcpy(libfile, x_("gds.elib"));
2425 gdslib = newlibrary(libname, libfile);
2426 selectlibrary(gdslib, TRUE);
2427
2428 total = filesindirectory(TSMCGDSDIRECTORY, &filelist);
2429 for(i=0; i<total; i++)
2430 {
2431 if (filelist[i][0] == '.') continue;
2432
2433 /* read the GDS file */
2434 eraselibrary(gdslib);
2435 estrcpy(libfile, TSMCGDSDIRECTORY);
2436 estrcat(libfile, filelist[i]);
2437 (void)reallocstring(&gdslib->libfile, libfile, gdslib->cluster);
2438 ttyputmsg(x_("Reading GDS file %s"), libfile);
2439 if (asktool(io_tool, x_("read"), (INTBIG)gdslib, (INTBIG)x_("gds"), 0) != 0) break;
2440
2441 /* synchronize the ports */
2442 us_portsynchronize(leflib);
2443
2444 /* mark all cells as part of a "cell library" */
2445 for(np = gdslib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2446 np->userbits |= INCELLLIBRARY;
2447
2448 /* write the Electric library */
2449 estrcpy(libfile, TSMCELECDIRECTORY);
2450 estrcat(libfile, filelist[i]);
2451 j = estrlen(libfile);
2452 if (namesame(&libfile[j-4], x_(".gds")) == 0) libfile[j-4] = 0;
2453 (void)reallocstring(&gdslib->libfile, libfile, gdslib->cluster);
2454 gdslib->userbits |= READFROMDISK;
2455 if (asktool(io_tool, x_("write"), (INTBIG)gdslib, (INTBIG)x_("binary")) != 0) break;
2456 }
2457 prepfile->userbits &= ~(LIBCHANGEDMAJOR|LIBCHANGEDMINOR);
2458 leflib->userbits &= ~(LIBCHANGEDMAJOR|LIBCHANGEDMINOR);
2459 return;
2460 }
2461
2462 if (namesamen(par[0], x_("erase-bits"), l) == 0 && l >= 2)
2463 {
2464 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
2465 {
2466 /* clear the library bits */
2467 lib->temp1 = lib->temp2 = 0;
2468 lib->userbits &= (LIBCHANGEDMAJOR | LIBCHANGEDMINOR | LIBUNITS);
2469
2470 /* look at every cell in the library */
2471 for(np=lib->firstnodeproto; np!=NONODEPROTO; np=np->nextnodeproto)
2472 {
2473 /* clear the node prototype bits */
2474 np->temp1 = np->temp2 = 0;
2475 np->userbits &= WANTNEXPAND;
2476
2477 /* clear the port prototype bits */
2478 for(pp = np->firstportproto; pp != NOPORTPROTO; pp = pp->nextportproto)
2479 {
2480 pp->temp1 = pp->temp2 = 0;
2481 pp->userbits &= (STATEBITS|PORTANGLE|PORTARANGE);
2482 }
2483
2484 /* clear the node instance bits */
2485 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2486 {
2487 ni->temp1 = ni->temp2 = 0;
2488 ni->userbits &= NEXPAND;
2489
2490 /* compute WIPED bit on node instance */
2491 ni->userbits |= us_computewipestate(ni);
2492 }
2493
2494 /* clear the arc instance bits */
2495 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
2496 {
2497 ai->temp1 = ai->temp2 = 0;
2498 ai->userbits &= (FIXED|FIXANG|ISNEGATED|NOEXTEND|NOTEND0|NOTEND1|REVERSEEND|CANTSLIDE);
2499 determineangle(ai);
2500 (void)setshrinkvalue(ai, FALSE);
2501 }
2502 }
2503 }
2504 ttyputmsg(x_("All tool words reset"));
2505 return;
2506 }
2507
2508 if (namesamen(par[0], x_("label-cell"), l) == 0 && l >= 1)
2509 {
2510 np = us_needcell();
2511 if (np == NONODEPROTO) return;
2512 us_clearhighlightcount();
2513 let1 = 'A'; let2 = let3 = 0;
2514 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
2515 {
2516 line[0] = (CHAR)let1; line[1] = (CHAR)let2;
2517 line[2] = (CHAR)let3; line[3] = 0;
2518 var = getvalkey((INTBIG)ni, VNODEINST, -1, el_node_name_key);
2519 if (var != NOVARIABLE) continue;
2520 var = setvalkey((INTBIG)ni, VNODEINST, el_node_name_key, (INTBIG)line,
2521 VSTRING|VDISPLAY);
2522 if (var != NOVARIABLE)
2523 defaulttextsize(3, var->textdescript);
2524 let1++;
2525 if (let1 > 'Z')
2526 {
2527 let1 = 'A';
2528 if (let2 == 0) let2 = 'A'; else let2++;
2529 if (let2 > 'Z')
2530 {
2531 let2 = 'A';
2532 if (let3 == 0) let3 = 'A'; else let3++;
2533 }
2534 }
2535 }
2536 i = 1;
2537 for(ai = np->firstarcinst; ai != NOARCINST;
2538 ai = ai->nextarcinst)
2539 {
2540 (void)esnprintf(line, 200, x_("%ld"), i++);
2541 var = getvalkey((INTBIG)ai, VARCINST, -1, el_arc_name_key);
2542 if (var != NOVARIABLE) continue;
2543 var = setvalkey((INTBIG)ai, VARCINST, el_arc_name_key, (INTBIG)line,
2544 VSTRING|VDISPLAY);
2545 if (var != NOVARIABLE)
2546 defaulttextsize(4, var->textdescript);
2547 }
2548 us_redisplay(el_curwindowpart);
2549 return;
2550 }
2551
2552 /********** THESE ARE STANDARD **********/
2553
2554 if (namesamen(par[0], x_("arena"), l) == 0 && l >= 1)
2555 {
2556 if (count > 1) db_printclusterarena(par[1]); else
2557 db_printclusterarena(x_(""));
2558 return;
2559 }
2560
2561 if (namesamen(par[0], x_("check-database"), l) == 0 && l >= 1)
2562 {
2563 if (count > 1 && namesamen(par[1], x_("verbose"), estrlen(par[1])) == 0)
2564 us_checkdatabase(TRUE); else
2565 us_checkdatabase(FALSE);
2566 return;
2567 }
2568
2569 if (namesamen(par[0], x_("translate"), l) == 0 && l >= 1)
2570 {
2571 us_translationdlog();
2572 return;
2573 }
2574
2575 if (namesamen(par[0], x_("dialog-edit"), l) == 0 && l >= 1)
2576 {
2577 us_dialogeditor();
2578 return;
2579 }
2580
2581 if (namesamen(par[0], x_("examine-options"), l) == 0 && l >= 2)
2582 {
2583 libname = us_tempoptionslibraryname();
2584 libfile = optionsfilepath();
2585 filestatus = fileexistence(truepath(libfile));
2586 if (filestatus == 1 || filestatus == 3)
2587 {
2588 lib = newlibrary(libname, libfile);
2589 if (lib == NOLIBRARY) return;
2590 (void)asktool(io_tool, x_("read"), (INTBIG)lib, (INTBIG)x_("binary"));
2591 (void)asktool(io_tool, x_("write"), (INTBIG)lib, (INTBIG)x_("text"));
2592 killlibrary(lib);
2593 }
2594 return;
2595 }
2596
2597 if (namesamen(par[0], x_("freeze-user-interface"), l) == 0 && l >= 1)
2598 {
2599 j = l = 0;
2600 for(i=0; i<us_tool->numvar; i++)
2601 {
2602 var = &us_tool->firstvar[i];
2603 pt = makename(var->key);
2604 if (namesamen(pt, x_("USER_binding_"), 13) == 0)
2605 {
2606 if (namesame(pt, x_("USER_binding_menu")) == 0) continue;
2607 var->type &= ~VDONTSAVE;
2608 j++;
2609 } else if (namesamen(pt, x_("USER_macro_"), 11) == 0)
2610 {
2611 var->type &= ~VDONTSAVE;
2612
2613 /*
2614 * when saving macros to disk, must erase entry 2, which
2615 * is the address of the parsing structures: these cannot
2616 * be valid when read back in.
2617 */
2618 setindkey((INTBIG)us_tool, VTOOL, var->key, 2, (INTBIG)x_(""));
2619 l++;
2620 }
2621 }
2622 ttyputmsg(x_("Made %ld macros and %ld bindings permanent"), l, j);
2623 return;
2624 }
2625
2626 if (namesamen(par[0], x_("internal-errors"), l) == 0 && l >= 1)
2627 {
2628 db_printerrors = !db_printerrors;
2629 ttyputmsg(x_("Internal database errors will %sbe printed"),
2630 (db_printerrors ? x_("") : x_("not ")));
2631 return;
2632 }
2633
2634 if (namesamen(par[0], x_("namespace"), l) == 0 && l >= 1)
2635 {
2636 ttyputmsg(x_("%ld names in global namespace:"), el_numnames);
2637 for(i=0; i<el_numnames; i++) ttyputmsg(x_("'%s'"), el_namespace[i]);
2638 return;
2639 }
2640
2641 if (namesamen(par[0], x_("options-changed"), l) == 0 && l >= 1)
2642 {
2643 explainoptionchanges(-1, 0);
2644 return;
2645 }
2646
2647 if (namesamen(par[0], x_("rtree"), l) == 0 && l >= 2)
2648 {
2649 np = us_needcell();
2650 if (np == NONODEPROTO) return;
2651 ttyputmsg(x_("R-tree for cell %s (nodes hold from %d to %d entries)"),
2652 describenodeproto(np), MINRTNODESIZE, MAXRTNODESIZE);
2653 db_printrtree(NORTNODE, np->rtree, 0);
2654 return;
2655 }
2656
2657 if (namesamen(par[0], x_("undo"), l) == 0 && l >= 1)
2658 {
2659 db_undodlog();
2660 return;
2661 }
2662
2663 ttyputbadusage(x_("debug"));
2664 }
2665
us_defarc(INTBIG count,CHAR * par[])2666 void us_defarc(INTBIG count, CHAR *par[])
2667 {
2668 REGISTER CHAR *aname, *pt;
2669 REGISTER BOOLEAN negate;
2670 REGISTER INTBIG l, i, wid, style, bits;
2671 REGISTER ARCPROTO *ap;
2672 REGISTER PORTPROTO *pp;
2673 REGISTER NODEPROTO *np;
2674 extern COMCOMP us_defarcsp, us_defarcnotp, us_defarcwidp, us_defarcpinp, us_defarcangp;
2675 REGISTER VARIABLE *var;
2676 REGISTER void *infstr;
2677
2678 if (count == 0)
2679 {
2680 count = ttygetparam(_("Arc prototype: "), &us_defarcsp, MAXPARS, par);
2681 if (count == 0)
2682 {
2683 us_abortedmsg();
2684 return;
2685 }
2686 }
2687
2688 /* get arc prototype name */
2689 if (estrcmp(par[0], x_("*")) == 0)
2690 {
2691 ap = NOARCPROTO;
2692 aname = x_("all");
2693 } else
2694 {
2695 ap = getarcproto(par[0]);
2696 if (ap == NOARCPROTO)
2697 {
2698 us_abortcommand(_("Unknown arc prototype: %s"), par[0]);
2699 return;
2700 }
2701 aname = ap->protoname;
2702 }
2703
2704 if (count <= 1)
2705 {
2706 /* get style to report */
2707 if (ap != NOARCPROTO)
2708 {
2709 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2710 if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2711 } else
2712 {
2713 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2714 if (var != NOVARIABLE) style = var->addr; else style = -1;
2715 if (style == -1)
2716 {
2717 ttyputmsg(_("No overriding defaults set for arcs"));
2718 return;
2719 }
2720 }
2721 infstr = initinfstr();
2722 formatinfstr(infstr, _("%s arcs drawn "), aname);
2723 if ((style&WANTFIX) != 0) addstringtoinfstr(infstr, _("rigid")); else
2724 {
2725 addstringtoinfstr(infstr, _("nonrigid, "));
2726 if ((style&WANTFIXANG) == 0) addstringtoinfstr(infstr, _("not fixed angle, ")); else
2727 addstringtoinfstr(infstr, _("fixed angle, "));
2728 if ((style&WANTCANTSLIDE) != 0) addstringtoinfstr(infstr, _("nonslidable")); else
2729 addstringtoinfstr(infstr, _("slidable"));
2730 }
2731 if ((style&WANTDIRECTIONAL) != 0) addstringtoinfstr(infstr, _(", directional"));
2732 if ((style&WANTNEGATED) != 0) addstringtoinfstr(infstr, _(", negated"));
2733 addstringtoinfstr(infstr, x_(", "));
2734 if ((style&WANTNOEXTEND) != 0) addstringtoinfstr(infstr, _("not ends-extended")); else
2735 addstringtoinfstr(infstr, _("ends-extended"));
2736 if (ap != NOARCPROTO)
2737 formatinfstr(infstr, _(", width %s, angle %ld"),
2738 latoa(defaultarcwidth(ap)-arcprotowidthoffset(ap), 0),
2739 (ap->userbits&AANGLEINC) >> AANGLEINCSH);
2740 ttyputmsg(x_("%s"), returninfstr(infstr));
2741 return;
2742 }
2743
2744 l = estrlen(pt = par[1]);
2745 negate = FALSE;
2746
2747 if (namesamen(pt, x_("not"), l) == 0 && l >= 2)
2748 {
2749 if (count <= 2)
2750 {
2751 count = ttygetparam(_("Defarc option: "), &us_defarcnotp, MAXPARS-2, &par[2])+2;
2752 if (count == 2)
2753 {
2754 us_abortedmsg();
2755 return;
2756 }
2757 }
2758 count--;
2759 par++;
2760 negate = TRUE;
2761 l = estrlen(pt = par[1]);
2762 }
2763
2764 if (namesamen(pt, x_("default"), l) == 0 && l >= 2)
2765 {
2766 if (ap != NOARCPROTO)
2767 {
2768 (void)delvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey);
2769 ttyputverbose(M_("%s arcs drawn in default style"), describearcproto(ap));
2770 return;
2771 }
2772 (void)delvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey);
2773 ttyputverbose(M_("All arcs drawn in default style"));
2774 return;
2775 }
2776
2777 if ((namesamen(pt, x_("manhattan"), l) == 0 || namesamen(pt, x_("fixed-angle"), l) == 0) && l >= 1)
2778 {
2779 if (namesamen(pt, x_("manhattan"), l) == 0)
2780 ttyputmsg(_("It is now proper to use 'defarc fixed-angle' instead of 'defarc manhattan'"));
2781 if (ap != NOARCPROTO)
2782 {
2783 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2784 if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2785 if (negate) style &= ~WANTFIXANG; else style |= WANTFIXANG;
2786 (void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2787 } else
2788 {
2789 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2790 if (var != NOVARIABLE) style = var->addr; else style = 0;
2791 if (negate) style &= ~WANTFIXANG; else style |= WANTFIXANG;
2792 (void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2793 }
2794 if (negate) ttyputverbose(M_("%s arcs drawn not fixed-angle"), aname); else
2795 ttyputverbose(M_("%s arcs drawn fixed-angle"), aname);
2796 return;
2797 }
2798
2799 if (namesamen(pt, x_("rigid"), l) == 0 && l >= 1)
2800 {
2801 if (ap != NOARCPROTO)
2802 {
2803 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2804 if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2805 if (negate) style &= ~WANTFIX; else style |= WANTFIX;
2806 (void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2807 } else
2808 {
2809 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2810 if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2811 if (negate) style &= ~WANTFIX; else style |= WANTFIX;
2812 (void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2813 }
2814 if (negate) ttyputverbose(M_("%s arcs drawn un-rigid"), aname); else
2815 ttyputverbose(M_("%s arcs drawn rigid"), aname);
2816 return;
2817 }
2818
2819 if (namesamen(pt, x_("directional"), l) == 0 && l >= 2)
2820 {
2821 if (ap != NOARCPROTO)
2822 {
2823 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2824 if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2825 if (negate) style &= ~WANTDIRECTIONAL; else
2826 style |= WANTDIRECTIONAL;
2827 (void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2828 } else
2829 {
2830 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2831 if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2832 if (negate) style &= ~WANTDIRECTIONAL; else
2833 style |= WANTDIRECTIONAL;
2834 (void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2835 }
2836 if (negate) ttyputverbose(M_("%s arcs drawn nondirectional"), aname); else
2837 ttyputverbose(M_("%s arcs drawn directional"), aname);
2838 return;
2839 }
2840
2841 if (namesamen(pt, x_("slide"), l) == 0 && l >= 1)
2842 {
2843 if (ap != NOARCPROTO)
2844 {
2845 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2846 if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2847 if (negate) style &= ~WANTCANTSLIDE; else
2848 style |= WANTCANTSLIDE;
2849 (void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2850 } else
2851 {
2852 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2853 if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2854 if (negate) style &= ~WANTCANTSLIDE; else
2855 style |= WANTCANTSLIDE;
2856 (void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2857 }
2858 if (negate) ttyputverbose(M_("%s arcs can not slide in their ports"), aname); else
2859 ttyputverbose(M_("%s arcs can slide in their ports"), aname);
2860 return;
2861 }
2862
2863 if (namesamen(pt, x_("negated"), l) == 0 && l >= 2)
2864 {
2865 if (ap != NOARCPROTO)
2866 {
2867 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2868 if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2869 if (negate) style &= ~WANTNEGATED; else style |= WANTNEGATED;
2870 (void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2871 } else
2872 {
2873 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2874 if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2875 if (negate) style &= ~WANTNEGATED; else style |= WANTNEGATED;
2876 (void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2877 }
2878 if (negate) ttyputverbose(M_("%s arcs drawn un-negated"), aname); else
2879 ttyputverbose(M_("%s arcs drawn negated"), aname);
2880 return;
2881 }
2882
2883 if (namesamen(pt, x_("ends-extend"), l) == 0 && l >= 1)
2884 {
2885 if (ap != NOARCPROTO)
2886 {
2887 var = getvalkey((INTBIG)ap, VARCPROTO, VINTEGER, us_arcstylekey);
2888 if (var != NOVARIABLE) style = var->addr; else style = ap->userbits;
2889 if (negate) style |= WANTNOEXTEND; else style &= ~WANTNOEXTEND;
2890 (void)setvalkey((INTBIG)ap, VARCPROTO, us_arcstylekey, style, VINTEGER);
2891 } else
2892 {
2893 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_arcstylekey);
2894 if (var != NOVARIABLE) style = var->addr; else style = WANTFIXANG;
2895 if (negate) style |= WANTNOEXTEND; else style &= ~WANTNOEXTEND;
2896 (void)setvalkey((INTBIG)us_tool, VTOOL, us_arcstylekey, style, VINTEGER|VDONTSAVE);
2897 }
2898 if (negate) ttyputverbose(M_("%s arcs drawn with ends not extended"), aname); else
2899 ttyputverbose(M_("%s arcs drawn with ends extended by half-width"), aname);
2900 return;
2901 }
2902
2903 if (namesamen(pt, x_("width"), l) == 0 && l >= 1)
2904 {
2905 if (ap == NOARCPROTO)
2906 {
2907 us_abortcommand(_("Default width requires specific arc prototypes"));
2908 return;
2909 }
2910 if (count <= 2)
2911 {
2912 count = ttygetparam(_("Width: "), &us_defarcwidp, MAXPARS-2, &par[2]) + 2;
2913 if (count == 2)
2914 {
2915 us_abortedmsg();
2916 return;
2917 }
2918 }
2919 pt = par[2];
2920 i = atola(pt, 0);
2921 if (i&1) i++;
2922 if (i < 0)
2923 {
2924 us_abortcommand(_("Width must not be negative"));
2925 return;
2926 }
2927 wid = arcprotowidthoffset(ap) + i;
2928 wid = wid * WHOLE / el_curlib->lambda[ap->tech->techindex];
2929 (void)setvalkey((INTBIG)ap, VARCPROTO, el_arc_width_default_key, wid, VINTEGER);
2930 ttyputverbose(M_("%s arcs default to %s wide"), aname, latoa(i, 0));
2931 return;
2932 }
2933
2934 if (namesamen(pt, x_("angle"), l) == 0 && l >= 1)
2935 {
2936 if (ap == NOARCPROTO)
2937 {
2938 us_abortcommand(_("Default angle increment requires specific arc prototypes"));
2939 return;
2940 }
2941 if (count <= 2)
2942 {
2943 count = ttygetparam(_("Angle: "), &us_defarcangp, MAXPARS-2, &par[2]) + 2;
2944 if (count == 2)
2945 {
2946 us_abortedmsg();
2947 return;
2948 }
2949 }
2950 pt = par[2];
2951 i = eatoi(pt) % 360;
2952 if (i < 0)
2953 {
2954 us_abortcommand(_("Angle increment must not be negative"));
2955 return;
2956 }
2957 bits = (ap->userbits & ~AANGLEINC) | (i << AANGLEINCSH);
2958 (void)setval((INTBIG)ap, VARCPROTO, x_("userbits"), bits, VINTEGER);
2959 ttyputverbose(M_("%s arcs will run at %ld degree angle increments"), aname, i);
2960 return;
2961 }
2962
2963 if (namesamen(pt, x_("pin"), l) == 0 && l >= 1)
2964 {
2965 if (ap == NOARCPROTO)
2966 {
2967 us_abortcommand(_("Default pin requires specific arc prototypes"));
2968 return;
2969 }
2970 if (count <= 2)
2971 {
2972 count = ttygetparam(_("Pin: "), &us_defarcpinp, MAXPARS-2, &par[2]) + 2;
2973 if (count == 2)
2974 {
2975 us_abortedmsg();
2976 return;
2977 }
2978 }
2979 np = getnodeproto(par[2]);
2980 if (np == NONODEPROTO)
2981 {
2982 us_abortcommand(_("Cannot find primitive %s"), par[2]);
2983 return;
2984 }
2985 pp = np->firstportproto;
2986 for(i=0; pp->connects[i] != NOARCPROTO; i++)
2987 if (pp->connects[i] == ap) break;
2988 if (pp->connects[i] == NOARCPROTO)
2989 {
2990 us_abortcommand(_("Cannot: the %s node must connect to %s arcs on its first port (%s)"),
2991 describenodeproto(np), aname, pp->protoname);
2992 return;
2993 }
2994 (void)setval((INTBIG)ap, VARCPROTO, x_("ARC_Default_Pin"), (INTBIG)np, VNODEPROTO|VDONTSAVE);
2995 ttyputverbose(M_("Default pins for arc %s will be %s"), aname, describenodeproto(np));
2996 return;
2997 }
2998
2999 ttyputbadusage(x_("defarc"));
3000 }
3001
us_defnode(INTBIG count,CHAR * par[])3002 void us_defnode(INTBIG count, CHAR *par[])
3003 {
3004 REGISTER CHAR *pp, *nname;
3005 BOOLEAN negated;
3006 REGISTER INTBIG l, pangle;
3007 REGISTER INTBIG i, j;
3008 INTBIG plx, ply, phx, phy, nodesize[2];
3009 REGISTER VARIABLE *var;
3010 REGISTER NODEPROTO *np, *onp;
3011 extern COMCOMP us_defnodesp, us_defnodexsp, us_defnodeysp;
3012
3013 if (count == 0)
3014 {
3015 count = ttygetparam(_("Node prototype: "), &us_defnodesp, MAXPARS, par);
3016 if (count == 0)
3017 {
3018 us_abortedmsg();
3019 return;
3020 }
3021 }
3022
3023 /* get node prototype name */
3024 if (estrcmp(par[0], x_("*")) == 0)
3025 {
3026 np = NONODEPROTO;
3027 nname = _("All complex");
3028 } else
3029 {
3030 np = getnodeproto(par[0]);
3031 if (np == NONODEPROTO)
3032 {
3033 us_abortcommand(_("Unknown node prototype: %s"), par[0]);
3034 return;
3035 }
3036 nname = describenodeproto(np);
3037 }
3038
3039 if (count <= 1)
3040 {
3041 ttyputusage(x_("defnode OPTIONS"));
3042 return;
3043 }
3044
3045 l = estrlen(pp = par[1]);
3046
3047 /* handle negation */
3048 if (namesamen(pp, x_("not"), l) == 0 && l >= 1)
3049 {
3050 negated = TRUE;
3051 count--;
3052 par++;
3053 l = estrlen(pp = par[1]);
3054 } else negated = FALSE;
3055
3056 if (namesamen(pp, x_("from-cell-library"), l) == 0)
3057 {
3058 if (np != NONODEPROTO && np->primindex != 0)
3059 {
3060 us_abortcommand(_("Cell library marking can only be done for cells"));
3061 return;
3062 }
3063 for(onp = el_curlib->firstnodeproto; onp != NONODEPROTO; onp = onp->nextnodeproto)
3064 {
3065 if (np != NONODEPROTO && np != onp) continue;
3066 if (!negated)
3067 {
3068 if ((onp->userbits&INCELLLIBRARY) != 0)
3069 {
3070 ttyputverbose(M_("Cell %s is already part of a cell library"),
3071 describenodeproto(onp));
3072 } else
3073 {
3074 ttyputverbose(M_("Cell %s is now part of a cell library"),
3075 describenodeproto(onp));
3076 }
3077 (void)setval((INTBIG)onp, VNODEPROTO, x_("userbits"),
3078 onp->userbits | INCELLLIBRARY, VINTEGER);
3079 } else
3080 {
3081 if ((onp->userbits&INCELLLIBRARY) == 0)
3082 {
3083 ttyputverbose(M_("Cell %s is already not part of a cell library"),
3084 describenodeproto(onp));
3085 } else
3086 {
3087 ttyputverbose(M_("Cell %s is now not part of a cell library"),
3088 describenodeproto(onp));
3089 }
3090 (void)setval((INTBIG)onp, VNODEPROTO, x_("userbits"),
3091 onp->userbits & ~INCELLLIBRARY, VINTEGER);
3092 }
3093 }
3094 return;
3095 }
3096
3097 if (namesamen(pp, x_("check-dates"), l) == 0 && l >= 2)
3098 {
3099 if (np != NONODEPROTO)
3100 {
3101 us_abortcommand(_("Date checking must be done for all cells (*)"));
3102 return;
3103 }
3104 if (!negated)
3105 {
3106 if ((us_useroptions&CHECKDATE) != 0)
3107 ttyputverbose(M_("Cell revision dates already being checked")); else
3108 ttyputverbose(M_("Cell revision date errors will be identified"));
3109 (void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3110 us_useroptions | CHECKDATE, VINTEGER);
3111 } else
3112 {
3113 if ((us_useroptions&CHECKDATE) == 0)
3114 ttyputverbose(M_("Cell revision dates already being ignored")); else
3115 ttyputverbose(M_("Cell revision date errors will be ignored"));
3116 (void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3117 us_useroptions & ~CHECKDATE, VINTEGER);
3118 }
3119 return;
3120 }
3121
3122 if (namesamen(pp, x_("centered-primitives"), l) == 0 && l >= 2)
3123 {
3124 if (np != NONODEPROTO)
3125 {
3126 us_abortcommand(_("Primitive centering must be done for all nodes (*)"));
3127 return;
3128 }
3129 if (!negated)
3130 {
3131 if ((us_useroptions&CENTEREDPRIMITIVES) != 0)
3132 ttyputverbose(M_("Primitives are already being placed by their center")); else
3133 ttyputverbose(M_("Primitives will be placed by their center"));
3134 (void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3135 us_useroptions | CENTEREDPRIMITIVES, VINTEGER);
3136 } else
3137 {
3138 if ((us_useroptions&CENTEREDPRIMITIVES) == 0)
3139 ttyputverbose(M_("Primitives are already being placed by edges")); else
3140 ttyputverbose(M_("Primitives will be placed by edges"));
3141 (void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3142 us_useroptions & ~CENTEREDPRIMITIVES, VINTEGER);
3143 }
3144 return;
3145 }
3146
3147 if (namesamen(pp, x_("copy-ports"), l) == 0 && l >= 2)
3148 {
3149 if (np != NONODEPROTO)
3150 {
3151 us_abortcommand(_("Port copying must be done for all nodes (*)"));
3152 return;
3153 }
3154 if (!negated)
3155 {
3156 if ((us_useroptions&DUPCOPIESPORTS) != 0)
3157 ttyputverbose(M_("Ports are already being copied by duplicate/array/yanknode")); else
3158 ttyputverbose(M_("Ports will be copied by duplicate/array/yanknode"));
3159 (void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3160 us_useroptions | DUPCOPIESPORTS, VINTEGER);
3161 } else
3162 {
3163 if ((us_useroptions&DUPCOPIESPORTS) == 0)
3164 ttyputverbose(M_("Ports are already not being copied by duplicate/array/yanknode")); else
3165 ttyputverbose(M_("Ports will not be copied by duplicate/array/yanknode"));
3166 (void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3167 us_useroptions & ~DUPCOPIESPORTS, VINTEGER);
3168 }
3169 return;
3170 }
3171
3172 if (namesamen(pp, x_("alterable"), l) == 0 && l >= 1)
3173 {
3174 if (np != NONODEPROTO)
3175 {
3176 /* set alterability of cells */
3177 if (!negated)
3178 {
3179 if ((np->userbits&NPLOCKED) == 0)
3180 {
3181 ttyputverbose(M_("Contents of cell %s are already able to be freely altered"),
3182 describenodeproto(np));
3183 } else
3184 {
3185 ttyputverbose(M_("Contents of cell %s may now be freely edited"),
3186 describenodeproto(np));
3187 }
3188 (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3189 np->userbits & ~NPLOCKED, VINTEGER);
3190 } else
3191 {
3192 if ((np->userbits&NPLOCKED) != 0)
3193 {
3194 ttyputverbose(M_("Contents of cell %s are already locked"),
3195 describenodeproto(np));
3196 } else
3197 {
3198 ttyputverbose(M_("Contents of cell %s will not be allowed to change"),
3199 describenodeproto(np));
3200 }
3201 (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3202 np->userbits | NPLOCKED, VINTEGER);
3203 }
3204 } else
3205 {
3206 us_abortcommand(_("Must set alterability for a specific cell"));
3207 }
3208 return;
3209 }
3210
3211 if (namesamen(pp, x_("instances-locked"), l) == 0 && l >= 1)
3212 {
3213 if (np == NONODEPROTO)
3214 {
3215 us_abortcommand(_("Cell instance locking cannot be done for all prototypes (*)"));
3216 return;
3217 }
3218
3219 /* set alterability of cell instances */
3220 if (negated)
3221 {
3222 if ((np->userbits&NPILOCKED) == 0)
3223 {
3224 ttyputverbose(M_("Instances in cell %s are already able to be freely altered"),
3225 describenodeproto(np));
3226 } else
3227 {
3228 ttyputverbose(M_("Instances in cell %s may now be freely edited"),
3229 describenodeproto(np));
3230 }
3231 (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3232 np->userbits & ~NPILOCKED, VINTEGER);
3233 } else
3234 {
3235 if ((np->userbits&NPILOCKED) != 0)
3236 {
3237 ttyputverbose(M_("Instances in cell %s are already locked"),
3238 describenodeproto(np));
3239 } else
3240 {
3241 ttyputverbose(M_("Instances in cell %s will not be allowed to change"),
3242 describenodeproto(np));
3243 }
3244 (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3245 np->userbits | NPILOCKED, VINTEGER);
3246 }
3247 return;
3248 }
3249
3250 if (namesamen(pp, x_("locked-primitives"), l) == 0 && l >= 1)
3251 {
3252 if (np != NONODEPROTO)
3253 {
3254 us_abortcommand(_("Primitive lock must be done for all prototypes (*)"));
3255 return;
3256 }
3257 if (negated)
3258 {
3259 if ((us_useroptions&NOPRIMCHANGES) == 0)
3260 ttyputverbose(M_("Locked primitives are already able to be freely altered")); else
3261 ttyputverbose(M_("Locked primitives may now be freely edited"));
3262 (void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3263 us_useroptions & ~NOPRIMCHANGES, VINTEGER);
3264 } else
3265 {
3266 if ((us_useroptions&NOPRIMCHANGES) != 0)
3267 ttyputverbose(M_("Locked primitive changes are already being disallowed")); else
3268 ttyputverbose(M_("Locked primitive changes will not be allowed"));
3269 (void)setvalkey((INTBIG)us_tool, VTOOL, us_optionflagskey,
3270 us_useroptions | NOPRIMCHANGES, VINTEGER);
3271 }
3272 return;
3273 }
3274
3275 if (namesamen(pp, x_("expanded"), l) == 0 && l >= 1)
3276 {
3277 if (np == NONODEPROTO)
3278 {
3279 for(np = el_curlib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
3280 {
3281 if (!negated) (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3282 np->userbits | WANTNEXPAND, VINTEGER); else
3283 (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3284 np->userbits & ~WANTNEXPAND, VINTEGER);
3285 }
3286 } else
3287 {
3288 if (np->primindex != 0)
3289 {
3290 if (!negated) us_abortcommand(_("Primitives are expanded by definition")); else
3291 us_abortcommand(_("Cannot un-expand primitives"));
3292 return;
3293 }
3294 if (!negated) (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3295 np->userbits | WANTNEXPAND, VINTEGER); else
3296 (void)setval((INTBIG)np, VNODEPROTO, x_("userbits"),
3297 np->userbits & ~WANTNEXPAND, VINTEGER);
3298 }
3299 ttyputverbose(M_("%s node prototypes will be %sexpanded on creation"), nname, (negated ? _("un-") : x_("")));
3300 return;
3301 }
3302
3303 if (namesamen(pp, x_("size"), l) == 0 && l >= 1)
3304 {
3305 if (np == NONODEPROTO)
3306 {
3307 us_abortcommand(_("Must change size on a single node"));
3308 return;
3309 }
3310 if (np->primindex == 0)
3311 {
3312 us_abortcommand(_("Can only change default size on primitives"));
3313 return;
3314 }
3315 if (count <= 2)
3316 {
3317 count = ttygetparam(_("X size: "), &us_defnodexsp, MAXPARS-2, &par[2]) + 2;
3318 if (count == 2)
3319 {
3320 us_abortedmsg();
3321 return;
3322 }
3323 }
3324 pp = par[2];
3325 i = atola(pp, 0);
3326 if (i&1) i++;
3327 if (count <= 3)
3328 {
3329 count = ttygetparam(_("Y size: "), &us_defnodeysp, MAXPARS-3, &par[3]) + 3;
3330 if (count == 3)
3331 {
3332 us_abortedmsg();
3333 return;
3334 }
3335 }
3336 pp = par[3];
3337 j = atola(pp, 0);
3338 if (j&1) j++;
3339 if (i < 0 || j < 0)
3340 {
3341 us_abortcommand(_("Sizes must not be negative"));
3342 return;
3343 }
3344 nodeprotosizeoffset(np, &plx, &ply, &phx, &phy, NONODEPROTO);
3345 nodesize[0] = i+plx+phx;
3346 nodesize[1] = j+ply+phy;
3347 nodesize[0] = nodesize[0] * WHOLE / el_curlib->lambda[np->tech->techindex];
3348 nodesize[1] = nodesize[1] * WHOLE / el_curlib->lambda[np->tech->techindex];
3349 (void)setvalkey((INTBIG)np, VNODEPROTO, el_node_size_default_key,
3350 (INTBIG)nodesize, VINTEGER|VISARRAY|(2<<VLENGTHSH));
3351 ttyputverbose(M_("%s nodes will be created %sx%s in size"), describenodeproto(np),
3352 latoa(i, 0), latoa(j, 0));
3353 return;
3354 }
3355
3356 if (namesamen(pp, x_("placement"), l) == 0 && l >= 1)
3357 {
3358 if (np != NONODEPROTO)
3359 {
3360 /* get placement angle for this node */
3361 var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, us_placement_angle_key);
3362 if (var == NOVARIABLE) pangle = 0; else pangle = var->addr;
3363
3364 if (count > 2)
3365 {
3366 pangle = (atofr(par[2])*10/WHOLE) % 3600;
3367 if (pangle < 0) pangle += 3600;
3368 if (namesame(&par[2][estrlen(par[2])-1], x_("t")) == 0) pangle += 3600;
3369 } else if (pangle >= 6300) pangle = 0; else
3370 pangle += 900;
3371 (void)setvalkey((INTBIG)np, VNODEPROTO, us_placement_angle_key, pangle, VINTEGER);
3372 } else
3373 {
3374 /* get placement angle for all nodes */
3375 var = getvalkey((INTBIG)us_tool, VTOOL, VINTEGER, us_placement_angle_key);
3376 if (var == NOVARIABLE) pangle = 0; else pangle = var->addr;
3377
3378 if (count > 2)
3379 {
3380 pangle = (atofr(par[2])*10/WHOLE) % 3600;
3381 if (pangle < 0) pangle += 3600;
3382 if (namesame(&par[2][estrlen(par[2])-1], x_("t")) == 0) pangle += 3600;
3383 } else if (pangle >= 6300) pangle = 0; else
3384 pangle += 900;
3385 (void)setvalkey((INTBIG)us_tool, VTOOL, us_placement_angle_key, pangle, VINTEGER);
3386 }
3387 return;
3388 }
3389
3390 ttyputbadusage(x_("defnode"));
3391 }
3392
us_duplicate(INTBIG count,CHAR * par[])3393 void us_duplicate(INTBIG count, CHAR *par[])
3394 {
3395 REGISTER NODEPROTO *np;
3396 REGISTER GEOM **list;
3397 REGISTER BOOLEAN interactiveplace;
3398
3399 /* get object */
3400 np = us_needcell();
3401 if (np == NONODEPROTO) return;
3402 list = us_gethighlighted(WANTNODEINST | WANTARCINST, 0, 0);
3403 if (list[0] == NOGEOM)
3404 {
3405 us_abortcommand(_("First select objects to duplicate"));
3406 return;
3407 }
3408
3409 if ((us_useroptions&NOMOVEAFTERDUP) != 0) interactiveplace = FALSE; else
3410 interactiveplace = TRUE;
3411 us_copylisttocell(list, np, np, TRUE, interactiveplace, TRUE);
3412 }
3413
3414 #if 0 /* test code for John Wood */
3415
3416 #define NUMTRANSISTOR 5
3417 #define DEFTRANSISTORWIDTH 3
3418 #define TRANSISTORWIDTH 30
3419 #define CELLNAME x_("multifingertransistor{lay}")
3420
3421 void us_debugjohn(void)
3422 {
3423 NODEPROTO *cell, *tra, *contact;
3424 NODEINST *transni, *contactni, *lastcontactni;
3425 PORTPROTO *topport, *botport, *conport;
3426 ARCPROTO *active;
3427 ARCINST *ai;
3428 CHAR *par[2];
3429 INTBIG lx, hx, ly, hy, sizex, sizey, sep, lambda, sizeycontact, bits,
3430 tpx, tpy, cpx, cpy, wid, i;
3431
3432 lambda = el_curlib->lambda[el_curtech->techindex];
3433 cell = newnodeproto(CELLNAME, el_curlib);
3434 if (cell == NONODEPROTO) return;
3435
3436 /* get the objects we need */
3437 tra = getnodeproto(x_("mocmos:N-Transistor"));
3438 if (tra == NONODEPROTO) return;
3439 contact = getnodeproto(x_("mocmos:Metal-1-N-Active-Con"));
3440 conport = contact->firstportproto;
3441 topport = getportproto(tra, x_("n-trans-diff-top"));
3442 botport = getportproto(tra, x_("n-trans-diff-bottom"));
3443 active = getarcproto(x_("mocmos:N-Active"));
3444
3445 /* get information for layout */
3446 sizex = tra->highx - tra->lowx;
3447 sizey = tra->highy - tra->lowy;
3448 sizeycontact = contact->highy - contact->lowy;
3449 sep = sizey * 2 - 32 * lambda;
3450 bits = us_makearcuserbits(active);
3451 wid = active->nominalwidth;
3452
3453 /* lay down the transistors */
3454 for(i=0; i<NUMTRANSISTOR; i++)
3455 {
3456 lx = 0; hx = sizex + (TRANSISTORWIDTH - DEFTRANSISTORWIDTH) * lambda;
3457 ly = i*sep; hy = ly + sizey;
3458 transni = newnodeinst(tra, lx, hx, ly, hy, 0, 0, cell);
3459 endobjectchange((INTBIG)transni, VNODEINST);
3460 if (i < NUMTRANSISTOR-1)
3461 {
3462 ly = hy - lambda * 29 / 2; hy = ly + sizeycontact;
3463 contactni = newnodeinst(contact, lx, hx, ly, hy, 0, 0, cell);
3464 endobjectchange((INTBIG)contactni, VNODEINST);
3465
3466 /* wire to the transistor */
3467 portposition(transni, topport, &tpx, &tpy);
3468 portposition(contactni, conport, &cpx, &cpy);
3469 ai = newarcinst(active, wid, bits, transni, topport, tpx, tpy,
3470 contactni, conport, cpx, cpy, cell);
3471 endobjectchange((INTBIG)ai, VARCINST);
3472 }
3473 if (i > 0)
3474 {
3475 portposition(transni, botport, &tpx, &tpy);
3476 portposition(lastcontactni, conport, &cpx, &cpy);
3477 ai = newarcinst(active, wid, bits, transni, botport, tpx, tpy,
3478 lastcontactni, conport, cpx, cpy, cell);
3479 endobjectchange((INTBIG)ai, VARCINST);
3480 }
3481 lastcontactni = contactni;
3482 }
3483
3484 /* display the result */
3485 par[0] = CELLNAME;
3486 us_editcell(1, par);
3487 }
3488 #endif
3489