1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: drc.c
6 * Design-rule check tool
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 "config.h"
33 #if DRCTOOL
34
35 #include "global.h"
36 #include "egraphics.h"
37 #include "drc.h"
38 #include "efunction.h"
39 #include "tech.h"
40 #include "tecgen.h"
41 #include "tecschem.h"
42 #include "edialogs.h"
43 #include "usr.h"
44 #include "usrdiacom.h"
45
46 /* the DRC tool table */
47 static COMCOMP dr_drccp = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
48 INPUTOPT, x_(" \t"), M_("cell to be rechecked"), M_("check current cell")};
49 static KEYWORD drcnotopt[] =
50 {
51 {x_("verbose"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
52 {x_("reasonable"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
53 TERMKEY
54 };
55 static COMCOMP drcnotp = {drcnotopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
56 INPUTOPT, x_(" \t"), M_("Design Rule Checker negative action"), 0};
57 static COMCOMP drcfip = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
58 INPUTOPT, x_(" \t"), M_("cell to ignored for short check DRC"), 0};
59 static COMCOMP drcfup = {NOKEYWORD, topofcells, nextcells, NOPARAMS,
60 INPUTOPT, x_(" \t"), M_("cell to un-ignored for short check DRC"), 0};
61 static KEYWORD drcfopt[] =
62 {
63 {x_("select-run"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
64 {x_("run"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
65 {x_("ignore"), 1,{&drcfip,NOKEY,NOKEY,NOKEY,NOKEY}},
66 {x_("unignore"), 1,{&drcfup,NOKEY,NOKEY,NOKEY,NOKEY}},
67 TERMKEY
68 };
69 static COMCOMP drcfp = {drcfopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
70 INPUTOPT, x_(" \t"), M_("Short Detecting Design Rule Checker action"), 0};
71 static KEYWORD drcnopt[] =
72 {
73 {x_("run"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
74 {x_("select-run"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
75 {x_("reset-check-dates"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
76 {x_("just-1-error"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
77 {x_("all-errors"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
78 TERMKEY
79 };
80 static COMCOMP drcbatchp = {drcnopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
81 INPUTOPT, x_(" \t"), M_("Batch Design Rule Checker action"), 0};
82 static KEYWORD drcopt[] =
83 {
84 {x_("check"), 1,{&dr_drccp,NOKEY,NOKEY,NOKEY,NOKEY}},
85 {x_("forget-ignored-errors"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
86 {x_("not"), 1,{&drcnotp,NOKEY,NOKEY,NOKEY,NOKEY}},
87 {x_("verbose"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
88 {x_("batch"), 1,{&drcbatchp,NOKEY,NOKEY,NOKEY,NOKEY}},
89 {x_("shortcheck"), 1,{&drcfp,NOKEY,NOKEY,NOKEY,NOKEY}},
90 {x_("ecadcheck"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
91 {x_("reasonable"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
92 {x_("quick-check"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
93 {x_("quick-select-check"), 0,{NOKEY,NOKEY,NOKEY,NOKEY,NOKEY}},
94 TERMKEY
95 };
96 COMCOMP dr_drcp = {drcopt, NOTOPLIST, NONEXTLIST, NOPARAMS,
97 0, x_(" \t"), M_("Design Rule Checker action"), M_("show defaults")};
98
99 /* dcheck modules */
100 #define NODCHECK ((DCHECK *)-1)
101
102 #define NODENEW 1 /* this nodeinst was created */
103 #define ARCNEW 2 /* this arcinst was created */
104 #define NODEMOD 3 /* this nodeinst was modified */
105 #define ARCMOD 4 /* this arcinst was modified */
106 #define NODEKILL 5 /* this nodeinst was deleted */
107 #define ARCKILL 6 /* this arcinst was deleted */
108
109 typedef struct Idcheck
110 {
111 NODEPROTO *cell; /* cell containing object to be checked */
112 INTBIG entrytype; /* type of check */
113 void *entryaddr; /* object being checked */
114 struct Idcheck *nextdcheck; /* next in list */
115 } DCHECK;
116 static DCHECK *dr_firstdcheck;
117 static DCHECK *dr_dcheckfree;
118
119 static INTBIG dr_verbosekey; /* key for "DRC_verbose" */
120 INTBIG dr_ignore_listkey; /* key for "DRC_ignore_list" */
121 INTBIG dr_lastgooddrckey; /* key for "DRC_last_good_drc" */
122 static INTBIG dr_incrementalonkey; /* key for "DRC_incrementalon" */
123 static INTBIG dr_optionskey; /* key for "DRC_options" */
124 INTBIG dr_max_distanceskey; /* key for "DRC_max_distances" */
125 INTBIG dr_wide_limitkey; /* key for "DRC_wide_limit" */
126 INTBIG dr_min_widthkey; /* key for "DRC_min_width" */
127 INTBIG dr_min_width_rulekey; /* key for "DRC_min_width_rule" */
128 INTBIG dr_min_node_sizekey; /* key for "DRC_min_node_size" */
129 INTBIG dr_min_node_size_rulekey; /* key for "DRC_min_node_size_rule" */
130 INTBIG dr_connected_distanceskey; /* key for "DRC_min_connected_distances" */
131 INTBIG dr_connected_distances_rulekey; /* key for "DRC_min_connected_distances_rule" */
132 INTBIG dr_unconnected_distanceskey; /* key for "DRC_min_unconnected_distances" */
133 INTBIG dr_unconnected_distances_rulekey; /* key for "DRC_min_unconnected_distances_rule" */
134 INTBIG dr_connected_distancesWkey; /* key for "DRC_min_connected_distances_wide" */
135 INTBIG dr_connected_distancesW_rulekey; /* key for "DRC_min_connected_distances_wide_rule" */
136 INTBIG dr_unconnected_distancesWkey; /* key for "DRC_min_unconnected_distances_wide" */
137 INTBIG dr_unconnected_distancesW_rulekey; /* key for "DRC_min_unconnected_distances_wide_rule" */
138 INTBIG dr_connected_distancesMkey; /* key for "DRC_min_connected_distances_multi" */
139 INTBIG dr_connected_distancesM_rulekey; /* key for "DRC_min_connected_distances_multi_rule" */
140 INTBIG dr_unconnected_distancesMkey; /* key for "DRC_min_unconnected_distances_multi" */
141 INTBIG dr_unconnected_distancesM_rulekey; /* key for "DRC_min_unconnected_distances_multi_rule" */
142 INTBIG dr_edge_distanceskey; /* key for "DRC_min_edge_distances" */
143 INTBIG dr_edge_distances_rulekey; /* key for "DRC_min_edge_distances_rule" */
144 #ifdef SURROUNDRULES
145 INTBIG dr_surround_layer_pairskey; /* key for "DRC_surround_layer_pairs" */
146 INTBIG dr_surround_distanceskey; /* key for "DRC_surround_distances" */
147 INTBIG dr_surround_rulekey; /* key for "DRC_surround_rule" */
148 #endif
149 BOOLEAN dr_logerrors; /* TRUE to log errors in error reporting system */
150 TOOL *dr_tool; /* the DRC tool object */
151
152 CHAR *dr_variablenames[] =
153 {
154 x_("DRC_max_distances"),
155 x_("DRC_wide_limit"),
156 x_("DRC_min_width"),
157 x_("DRC_min_width_rule"),
158 x_("DRC_min_node_size"),
159 x_("DRC_min_node_size_rule"),
160 x_("DRC_min_connected_distances"),
161 x_("DRC_min_connected_distances_rule"),
162 x_("DRC_min_unconnected_distances"),
163 x_("DRC_min_unconnected_distances_rule"),
164 x_("DRC_min_connected_distances_wide"),
165 x_("DRC_min_connected_distances_wide_rule"),
166 x_("DRC_min_unconnected_distances_wide"),
167 x_("DRC_min_unconnected_distances_wide_rule"),
168 x_("DRC_min_connected_distances_multi"),
169 x_("DRC_min_connected_distances_multi_rule"),
170 x_("DRC_min_unconnected_distances_multi"),
171 x_("DRC_min_unconnected_distances_multi_rule"),
172 x_("DRC_min_edge_distances"),
173 x_("DRC_min_edge_distances_rule"),
174 0
175 };
176
177 /* prototypes for local routines */
178 static DCHECK *dr_allocdcheck(void);
179 static NODEPROTO *dr_checkthiscell(INTBIG, CHAR*);
180 static void dr_freedcheck(DCHECK*);
181 static void dr_optionsdlog(void);
182 static void dr_rulesdloghook(void);
183 static void dr_queuecheck(void*, NODEPROTO*, INTBIG);
184 static void dr_unignore(NODEPROTO*, BOOLEAN, void*);
185 static void dr_unqueuecheck(LIBRARY *lib);
186 static INTBIG dr_examinecell(NODEPROTO *np, BOOLEAN report);
187 static void dr_schdocheck(GEOM *geom);
188 static void dr_checkentirecell(NODEPROTO *cell, INTBIG count, NODEINST **nodestocheck,
189 BOOLEAN *validity, BOOLEAN justarea);
190 static BOOLEAN dr_schcheckcolinear(ARCINST *ai, ARCINST *oai);
191 static void dr_schcheckobjectvicinity(GEOM *topgeom, GEOM *geom, XARRAY trans);
192 static void dr_checkschematiccell(NODEPROTO *cell, BOOLEAN justthis);
193 static void dr_checkschematiccellrecursively(NODEPROTO *cell);
194 static BOOLEAN dr_schcheckpoly(GEOM *geom, POLYGON *poly, GEOM *otopgeom, GEOM *ogeom, XARRAY otrans, BOOLEAN cancross);
195 static BOOLEAN dr_schcheckpolygonvicinity(GEOM *geom, POLYGON *poly);
196 static BOOLEAN dr_checkpolyagainstpoly(GEOM *geom, POLYGON *poly, GEOM *ogeom, POLYGON *opoly, BOOLEAN cancross);
197
198 /******************** CONTROL ********************/
199
dr_init(INTBIG * argc,CHAR1 * argv[],TOOL * thistool)200 void dr_init(INTBIG *argc, CHAR1 *argv[], TOOL *thistool)
201 {
202 /* only initialize during pass 1 */
203 if (thistool == NOTOOL || thistool == 0) return;
204
205 dr_tool = thistool;
206
207 /* initialize the design-rule checker lists */
208 dr_dcheckfree = NODCHECK;
209 dr_firstdcheck = NODCHECK;
210 dr_logerrors = TRUE;
211
212 dr_verbosekey = makekey(x_("DRC_verbose"));
213 dr_ignore_listkey = makekey(x_("DRC_ignore_list"));
214 dr_lastgooddrckey = makekey(x_("DRC_last_good_drc"));
215 dr_incrementalonkey = makekey(x_("DRC_incrementalon"));
216 dr_optionskey = makekey(x_("DRC_options"));
217 DiaDeclareHook(x_("drcopt"), &dr_drcp, dr_optionsdlog);
218 DiaDeclareHook(x_("drcrules"), &dr_drccp, dr_rulesdloghook);
219 }
220
dr_done(void)221 void dr_done(void)
222 {
223 #ifdef DEBUGMEMORY
224 REGISTER DCHECK *d;
225
226 while (dr_firstdcheck != NODCHECK)
227 {
228 d = dr_firstdcheck;
229 dr_firstdcheck = dr_firstdcheck->nextdcheck;
230 dr_freedcheck(d);
231 }
232 while (dr_dcheckfree != NODCHECK)
233 {
234 d = dr_dcheckfree;
235 dr_dcheckfree = dr_dcheckfree->nextdcheck;
236 efree((CHAR *)d);
237 }
238 drcb_term();
239 dr_quickterm();
240 #endif
241 }
242
dr_set(INTBIG count,CHAR * par[])243 void dr_set(INTBIG count, CHAR *par[])
244 {
245 REGISTER BOOLEAN negate;
246 REGISTER INTBIG l, i, errs, options;
247 REGISTER CHAR *pp;
248 REGISTER FILE *f;
249 REGISTER NODEPROTO *np;
250 REGISTER VARIABLE *var;
251 REGISTER TECHNOLOGY *tech;
252 CHAR *newpar[3], *truename, *abortseq;
253 static INTBIG filetypedrac = -1;
254 REGISTER void *infstr;
255
256 if (count == 0)
257 {
258 var = getvalkey((INTBIG)dr_tool, VTOOL, VINTEGER, dr_verbosekey);
259 if (var == NOVARIABLE) i = 0; else i = var->addr;
260 if (i == 0) ttyputmsg(M_("Design rule checker is brief")); else
261 ttyputmsg(M_("Design rule checker is verbose"));
262 return;
263 }
264
265 options = dr_getoptionsvalue();
266 l = estrlen(pp = par[0]);
267 negate = FALSE;
268 if (namesamen(pp, x_("not"), l) == 0)
269 {
270 negate = TRUE;
271 if (count <= 1)
272 {
273 count = ttygetparam(M_("DRC negate option:"), &drcnotp, MAXPARS-1, &par[1]) + 1;
274 if (count <= 1)
275 {
276 ttyputerr(M_("Aborted"));
277 return;
278 }
279 }
280 l = estrlen(pp = par[1]);
281 }
282
283 if (namesamen(pp, x_("forget-ignored-errors"), l) == 0)
284 {
285 np = dr_checkthiscell(count, par[1]);
286 if (np == NONODEPROTO) return;
287
288 /* erase all ignore lists on all objects */
289 var = getvalkey((INTBIG)np, VNODEPROTO, VGEOM|VISARRAY, dr_ignore_listkey);
290 if (var != NOVARIABLE)
291 (void)delvalkey((INTBIG)np, VNODEPROTO, dr_ignore_listkey);
292
293 ttyputmsg(M_("Ignored violations turned back on."));
294 return;
295 }
296 if (namesamen(pp, x_("check"), l) == 0)
297 {
298 /* make sure network tool is on */
299 if ((net_tool->toolstate&TOOLON) == 0)
300 {
301 ttyputerr(M_("Network tool must be running...turning it on"));
302 toolturnon(net_tool);
303 ttyputerr(M_("...now reissue the DRC command"));
304 return;
305 }
306
307 np = dr_checkthiscell(count, par[1]);
308 if (np == NONODEPROTO) return;
309 errs = dr_examinecell(np, TRUE);
310 return;
311 }
312
313 if (namesamen(pp, x_("ecadcheck"), l) == 0)
314 {
315 np = getcurcell();
316 if (np == NONODEPROTO)
317 {
318 ttyputerr(_("Must be editing a cell to check with ECAD's Dracula"));
319 return;
320 }
321 tech = np->tech;
322 var = getval((INTBIG)tech, VTECHNOLOGY, VSTRING|VISARRAY, x_("DRC_ecad_deck"));
323 if (var == NOVARIABLE)
324 {
325 ttyputerr(_("Cannot find an ECAD deck in the %s technology"), tech->techname);
326 return;
327 }
328
329 /* create the file */
330 if (filetypedrac < 0)
331 filetypedrac = setupfiletype(x_("rul"), x_("*.map"), MACFSTAG('TEXT'), FALSE, x_("drac"), _("Dracula"));
332 f = xcreate(x_("ecaddrc.RUL"), filetypedrac, _("ECAD DRC Control File"), &truename);
333 if (f == NULL)
334 {
335 if (truename != 0) ttyputerr(_("Cannot write %s"), truename);
336 return;
337 }
338
339 /* write the deck */
340 l = getlength(var);
341 for(i=0; i<l; i++)
342 {
343 pp = ((CHAR **)var->addr)[i];
344 if (estrncmp(pp, x_(" PRIMARY ="), 10) == 0)
345 {
346 xprintf(f, x_(" PRIMARY = %s\n"), np->protoname);
347 continue;
348 }
349 if (estrncmp(pp, x_(" INDISK ="), 9) == 0)
350 {
351 xprintf(f, x_(" INDISK = %s.cif\n"), np->protoname);
352 continue;
353 }
354 xprintf(f, x_("%s\n"), pp);
355 }
356
357 /* finished with control deck */
358 xclose(f);
359 ttyputverbose(M_("Wrote 'ecaddrc.RUL'. Now generating CIF for cell %s"), describenodeproto(np));
360
361 /* tell I/O to write CIF */
362 newpar[0] = x_("cif");
363 newpar[1] = x_("output");
364 newpar[2] = x_("include-cloak-layer");
365 telltool(io_tool, 3, newpar);
366 (void)asktool(io_tool, x_("write"), (INTBIG)np->lib, (INTBIG)x_("cif"));
367 newpar[0] = x_("cif");
368 newpar[1] = x_("output");
369 newpar[2] = x_("ignore-cloak-layer");
370 telltool(io_tool, 3, newpar);
371 return;
372 }
373
374 if (namesamen(pp, x_("batch"), l) == 0)
375 {
376 if (count == 1)
377 {
378 ttyputusage(x_("telltool drc batch OPTIONS"));
379 return;
380 }
381 l = estrlen(pp = par[1]);
382 if (namesamen(pp, x_("run"), l) == 0)
383 {
384 /* make sure network tool is on */
385 if ((net_tool->toolstate&TOOLON) == 0)
386 {
387 ttyputerr(M_("Network tool must be running...turning it on"));
388 toolturnon(net_tool);
389 ttyputerr(M_("...now reissue the DRC command"));
390 return;
391 }
392
393 /* make sure there is a cell to check */
394 np = getcurcell();
395 if (np == NONODEPROTO)
396 {
397 ttyputerr(_("No current cell"));
398 return;
399 }
400
401 /* see if a dialog should be displayed */
402 infstr = initinfstr();
403 addstringtoinfstr(infstr, _("Checking hierarchically..."));
404 abortseq = getinterruptkey();
405 if (abortseq != 0)
406 formatinfstr(infstr, _(" (type %s to abort)"), abortseq);
407 ttyputmsg(returninfstr(infstr));
408 (void)drcb_check(np, TRUE, FALSE);
409 return;
410 }
411 if (namesamen(pp, x_("select-run"), l) == 0)
412 {
413 /* make sure network tool is on */
414 if ((net_tool->toolstate&TOOLON) == 0)
415 {
416 ttyputerr(M_("Network tool must be running...turning it on"));
417 toolturnon(net_tool);
418 ttyputerr(M_("...now reissue the DRC command"));
419 return;
420 }
421
422 /* make sure there is a cell to check */
423 np = getcurcell();
424 if (np == NONODEPROTO)
425 {
426 ttyputerr(_("No current cell"));
427 return;
428 }
429
430 /* see if a dialog should be displayed */
431 infstr = initinfstr();
432 addstringtoinfstr(infstr, _("Checking selected area hierarchically..."));
433 abortseq = getinterruptkey();
434 if (abortseq != 0)
435 formatinfstr(infstr, _(" (type %s to abort)"), abortseq);
436 ttyputmsg(returninfstr(infstr));
437 (void)drcb_check(np, TRUE, TRUE);
438 return;
439 }
440 if (namesamen(pp, x_("just-1-error"), l) == 0)
441 {
442 (void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey,
443 options | DRCFIRSTERROR, VINTEGER);
444 ttyputmsg(M_("Hierarchical DRC will stop after first error in a cell"));
445 return;
446 }
447 if (namesamen(pp, x_("all-errors"), l) == 0)
448 {
449 (void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey,
450 options & ~DRCFIRSTERROR, VINTEGER);
451 ttyputmsg(M_("Hierarchical DRC will find all errors in a cell"));
452 return;
453 }
454 if (namesamen(pp, x_("reset-check-dates"), l) == 0)
455 {
456 dr_reset_dates();
457 ttyputmsg(M_("All date information about valid DRC is reset"));
458 return;
459 }
460 ttyputbadusage(x_("telltool drc batch"));
461 return;
462 }
463
464 if (namesamen(pp, x_("quick-check"), l) == 0 && l >= 7)
465 {
466 /* get the current cell */
467 np = getcurcell();
468 if (np == NONODEPROTO)
469 {
470 ttyputerr(_("No current cell"));
471 return;
472 }
473 dr_checkentirecell(np, 0, 0, 0, FALSE);
474 return;
475 }
476
477 if (namesamen(pp, x_("quick-select-check"), l) == 0 && l >= 7)
478 {
479 /* get the current cell */
480 np = getcurcell();
481 if (np == NONODEPROTO)
482 {
483 ttyputerr(_("No current cell"));
484 return;
485 }
486 dr_checkentirecell(np, 0, 0, 0, TRUE);
487 return;
488 }
489
490 if (namesamen(pp, x_("shortcheck"), l) == 0)
491 {
492 if (count < 2)
493 {
494 ttyputusage(x_("telltool drc shortcheck (run|ignore|unignore)"));
495 return;
496 }
497 l = estrlen(pp = par[1]);
498 if (namesamen(pp, x_("run"), l) == 0)
499 {
500 /* make sure network tool is on */
501 if ((net_tool->toolstate&TOOLON) == 0)
502 {
503 ttyputerr(M_("Network tool must be running...turning it on"));
504 toolturnon(net_tool);
505 ttyputerr(M_("...now reissue the DRC command"));
506 return;
507 }
508 dr_flatwrite(getcurcell());
509 return;
510 }
511 if (namesamen(pp, x_("ignore"), l) == 0)
512 {
513 if (count < 3)
514 {
515 ttyputusage(x_("telltool drc shortcheck ignore CELL"));
516 return;
517 }
518 dr_flatignore(par[2]);
519 return;
520 }
521 if (namesamen(pp, x_("unignore"), l) == 0)
522 {
523 if (count < 3)
524 {
525 ttyputusage(x_("telltool drc shortcheck unignore CELL"));
526 return;
527 }
528 dr_flatunignore(par[2]);
529 return;
530 }
531 ttyputbadusage(x_("telltool drc shortcheck"));
532 return;
533 }
534
535 if (namesamen(pp, x_("verbose"), l) == 0)
536 {
537 if (!negate)
538 {
539 (void)setvalkey((INTBIG)dr_tool, VTOOL, dr_verbosekey, 1, VINTEGER|VDONTSAVE);
540 ttyputverbose(M_("DRC verbose"));
541 } else
542 {
543 if (getvalkey((INTBIG)dr_tool, VTOOL, VINTEGER, dr_verbosekey) != NOVARIABLE)
544 (void)delvalkey((INTBIG)dr_tool, VTOOL, dr_verbosekey);
545 ttyputverbose(M_("DRC brief"));
546 }
547 return;
548 }
549
550 if (namesamen(pp, x_("reasonable"), l) == 0)
551 {
552 if (!negate)
553 {
554 (void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey,
555 options | DRCREASONABLE, VINTEGER);
556 ttyputverbose(M_("DRC will consider only reasonable number of polygons"));
557 } else
558 {
559 (void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey,
560 options & ~DRCREASONABLE, VINTEGER);
561 ttyputverbose(M_("DRC will consider all polygons"));
562 }
563 return;
564 }
565 ttyputbadusage(x_("telltool drc"));
566 }
567
568 /*
569 * make request of the DRC tool:
570 * "check-instances" TAKES: CELL, COUNT, NODEINST array, BOOLEAN validity-array
571 */
dr_request(CHAR * command,va_list ap)572 INTBIG dr_request(CHAR *command, va_list ap)
573 {
574 REGISTER NODEPROTO *cell;
575 REGISTER NODEINST **nodelist;
576 REGISTER BOOLEAN *validity;
577 REGISTER INTBIG arg1, arg2, arg3, arg4, count;
578
579 if (namesame(command, x_("check-instances")) == 0)
580 {
581 /* get the arguments */
582 arg1 = va_arg(ap, INTBIG);
583 arg2 = va_arg(ap, INTBIG);
584 arg3 = va_arg(ap, INTBIG);
585 arg4 = va_arg(ap, INTBIG);
586
587 cell = (NODEPROTO *)arg1;
588 count = arg2;
589 nodelist = (NODEINST **)arg3;
590 validity = (BOOLEAN *)arg4;
591 dr_checkentirecell(cell, count, nodelist, validity, FALSE);
592 return(0);
593 }
594 return(0);
595 }
596
dr_examinenodeproto(NODEPROTO * np)597 void dr_examinenodeproto(NODEPROTO *np)
598 {
599 REGISTER INTBIG i, errs;
600 REGISTER CHAR *pt;
601 if (dr_examinecell(np, FALSE) != 0)
602 {
603 errs = numerrors();
604 for(i=0; i<errs; i++)
605 {
606 pt = reportnexterror(0, 0, 0);
607 ttyputmsg(x_("%s"), pt);
608 }
609
610 /* reset error pointers to start of list */
611 termerrorlogging(FALSE);
612 }
613 }
614
615 /*
616 * Routine to examine cell "np" nonhierarchically and return the number of errors found.
617 */
dr_examinecell(NODEPROTO * np,BOOLEAN report)618 INTBIG dr_examinecell(NODEPROTO *np, BOOLEAN report)
619 {
620 REGISTER NODEINST *ni;
621 REGISTER ARCINST *ai;
622 REGISTER INTBIG errorcount;
623
624 if (stopping(STOPREASONDRC)) return(0);
625
626 /* do not check things in hidden libraries (such as the clipboard) */
627 if ((np->lib->userbits&HIDDENLIBRARY) != 0) return(0);
628
629 /* make sure network tool is on */
630 if ((net_tool->toolstate&TOOLON) == 0) return(0);
631
632 /* handle schematics separately */
633 if (np->cellview == el_schematicview || np->tech == sch_tech)
634 {
635 dr_checkschematiccell(np, TRUE);
636 return(0);
637 }
638
639 /* clear errors */
640 initerrorlogging(_("DRC"));
641
642 drcb_initincrementalcheck(np);
643 for(ni = np->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
644 (void)drcb_checkincremental(ni->geom, TRUE);
645 for(ai = np->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
646 (void)drcb_checkincremental(ai->geom, TRUE);
647 errorcount = numerrors();
648 if (report)
649 ttyputmsg(_("Cell %s checked at this level only (%ld errors)"),
650 describenodeproto(np), errorcount);
651 termerrorlogging(TRUE);
652 return(errorcount);
653 }
654
dr_slice(void)655 void dr_slice(void)
656 {
657 REGISTER DCHECK *d, *nextd;
658 REGISTER NODEPROTO *np;
659 REGISTER BOOLEAN didcheck;
660 REGISTER VARIABLE *var;
661
662 /* see if the tool should be off */
663 var = getvalkey((INTBIG)dr_tool, VTOOL, VINTEGER, dr_incrementalonkey);
664 if (var != NOVARIABLE && var->addr == 0)
665 {
666 toolturnoff(dr_tool, FALSE);
667 return;
668 }
669
670 if (dr_firstdcheck == NODCHECK) return;
671
672 /* make sure network tool is on */
673 if ((net_tool->toolstate&TOOLON) == 0)
674 {
675 ttyputerr(M_("Network tool must be running...turning it on"));
676 toolturnon(net_tool);
677 return;
678 }
679
680 /* mark this activity */
681 setactivity(_("DRC"));
682
683 /* first clear the ignore information on any objects that changed */
684 for(d = dr_firstdcheck; d != NODCHECK; d = d->nextdcheck)
685 {
686 if (d->entrytype == NODEMOD || d->entrytype == NODEKILL)
687 dr_unignore(d->cell, TRUE, d->entryaddr);
688 if (d->entrytype == ARCMOD || d->entrytype == ARCKILL)
689 dr_unignore(d->cell, FALSE, d->entryaddr);
690 }
691
692 /* clear errors */
693 dr_logerrors = FALSE;
694
695 np = NONODEPROTO;
696 didcheck = FALSE;
697 for(d = dr_firstdcheck; d != NODCHECK; d = nextd)
698 {
699 nextd = d->nextdcheck;
700 if (!stopping(STOPREASONDRC))
701 {
702 if (d->entrytype == NODEMOD || d->entrytype == NODENEW)
703 {
704 NODEINST *ni;
705
706 ni = (NODEINST *)d->entryaddr;
707 if ((ni->userbits&DEADN) == 0)
708 {
709 if (d->cell != np)
710 {
711 np = ni->parent;
712 drcb_initincrementalcheck(np);
713 didcheck = TRUE;
714 }
715 (void)drcb_checkincremental(ni->geom, FALSE);
716 }
717 }
718 if (d->entrytype == ARCMOD || d->entrytype == ARCNEW)
719 {
720 ARCINST *ai;
721
722 ai = (ARCINST *)d->entryaddr;
723 if ((ai->userbits&DEADA) == 0)
724 {
725 if (d->cell != np)
726 {
727 np = ai->parent;
728 drcb_initincrementalcheck(np);
729 didcheck = TRUE;
730 }
731 (void)drcb_checkincremental(ai->geom, FALSE);
732 }
733 }
734 }
735 dr_freedcheck(d);
736 }
737 dr_firstdcheck = NODCHECK;
738 dr_logerrors = TRUE;
739 }
740
741 /******************** DATABASE CHANGES ********************/
742
dr_modifynodeinst(NODEINST * ni,INTBIG oldlx,INTBIG oldly,INTBIG oldhx,INTBIG oldhy,INTBIG oldrot,INTBIG oldtran)743 void dr_modifynodeinst(NODEINST *ni,INTBIG oldlx,INTBIG oldly,INTBIG oldhx,INTBIG oldhy,
744 INTBIG oldrot,INTBIG oldtran)
745 {
746 dr_queuecheck(ni, ni->parent, NODEMOD);
747 }
748
dr_modifyarcinst(ARCINST * ai,INTBIG oldxA,INTBIG oldyA,INTBIG oldxB,INTBIG oldyB,INTBIG oldwid,INTBIG oldlen)749 void dr_modifyarcinst(ARCINST *ai,INTBIG oldxA, INTBIG oldyA, INTBIG oldxB, INTBIG oldyB,
750 INTBIG oldwid, INTBIG oldlen)
751 {
752 dr_queuecheck(ai, ai->parent, ARCMOD);
753 }
754
dr_newobject(INTBIG addr,INTBIG type)755 void dr_newobject(INTBIG addr, INTBIG type)
756 {
757 REGISTER NODEINST *ni;
758 REGISTER ARCINST *ai;
759
760 if ((type&VTYPE) == VNODEINST)
761 {
762 ni = (NODEINST *)addr;
763 dr_queuecheck(ni, ni->parent, NODENEW);
764 } else if ((type&VTYPE) == VARCINST)
765 {
766 ai = (ARCINST *)addr;
767 dr_queuecheck(ai, ai->parent, ARCNEW);
768 }
769 }
770
dr_killobject(INTBIG addr,INTBIG type)771 void dr_killobject(INTBIG addr, INTBIG type)
772 {
773 REGISTER DCHECK *d, *lastd, *nextd;
774 REGISTER NODEINST *ni;
775 REGISTER ARCINST *ai;
776
777 /* remove any others in the list that point to this deleted object */
778 lastd = NODCHECK;
779 for(d = dr_firstdcheck; d != NODCHECK; d = nextd)
780 {
781 nextd = d->nextdcheck;
782 if (d->entryaddr == (void *)addr)
783 {
784 if (lastd == NODCHECK) dr_firstdcheck = nextd; else
785 lastd->nextdcheck = nextd;
786 dr_freedcheck(d);
787 continue;
788 }
789 lastd = d;
790 }
791
792 if ((type&VTYPE) == VNODEINST)
793 {
794 ni = (NODEINST *)addr;
795 dr_queuecheck(ni, ni->parent, NODEKILL);
796 } else if ((type&VTYPE) == VARCINST)
797 {
798 ai = (ARCINST *)addr;
799 dr_queuecheck(ai, ai->parent, ARCKILL);
800 }
801 }
802
dr_eraselibrary(LIBRARY * lib)803 void dr_eraselibrary(LIBRARY *lib)
804 {
805 dr_unqueuecheck(lib);
806 }
807
dr_newvariable(INTBIG addr,INTBIG type,INTBIG key,INTBIG newtype)808 void dr_newvariable(INTBIG addr, INTBIG type, INTBIG key, INTBIG newtype)
809 {
810 if (type == VTECHNOLOGY)
811 {
812 if (key == el_techstate_key)
813 {
814 /* code cannot be called by multiple procesors: uses globals */
815 NOT_REENTRANT;
816
817 dr_curtech = NOTECHNOLOGY;
818 }
819 }
820 }
821
822 /******************** SUPPORT ROUTINES ********************/
823
824 /*
825 * routine to allocate a new dcheck module from the pool (if any) or memory
826 */
dr_allocdcheck(void)827 DCHECK *dr_allocdcheck(void)
828 {
829 REGISTER DCHECK *d;
830
831 if (dr_dcheckfree == NODCHECK)
832 {
833 d = (DCHECK *)emalloc(sizeof (DCHECK), dr_tool->cluster);
834 if (d == 0) return(NODCHECK);
835 } else
836 {
837 /* take module from free list */
838 d = dr_dcheckfree;
839 dr_dcheckfree = (DCHECK *)d->nextdcheck;
840 }
841 return(d);
842 }
843
844 /*
845 * routine to return dcheck module "d" to the pool of free modules
846 */
dr_freedcheck(DCHECK * d)847 void dr_freedcheck(DCHECK *d)
848 {
849 d->nextdcheck = dr_dcheckfree;
850 dr_dcheckfree = d;
851 }
852
dr_queuecheck(void * addr,NODEPROTO * cell,INTBIG function)853 void dr_queuecheck(void *addr, NODEPROTO *cell, INTBIG function)
854 {
855 REGISTER DCHECK *d;
856
857 /* do not examine anything in a hidden library (such as the clipboard) */
858 if ((cell->lib->userbits&HIDDENLIBRARY) != 0) return;
859
860 d = dr_allocdcheck();
861 if (d == NODCHECK)
862 {
863 ttyputnomemory();
864 return;
865 }
866 d->entrytype = function;
867 d->cell = cell;
868 d->entryaddr = addr;
869 d->nextdcheck = dr_firstdcheck;
870 dr_firstdcheck = d;
871 }
872
873 /*
874 * Routine to remove all check objects that are in library "lib"
875 * (because the library has been deleted)
876 */
dr_unqueuecheck(LIBRARY * lib)877 void dr_unqueuecheck(LIBRARY *lib)
878 {
879 REGISTER DCHECK *d, *nextd, *lastd;
880
881 lastd = NODCHECK;
882 for(d = dr_firstdcheck; d != NODCHECK; d = nextd)
883 {
884 nextd = d->nextdcheck;
885 if (d->cell == NONODEPROTO || d->cell->lib == lib)
886 {
887 if (lastd == NODCHECK) dr_firstdcheck = nextd; else
888 lastd->nextdcheck = nextd;
889 dr_freedcheck(d);
890 continue;
891 }
892 lastd = d;
893 }
894 }
895
896 /*
897 * routine to delete DRC ignore information on object "pos"
898 */
dr_unignore(NODEPROTO * np,BOOLEAN objisnode,void * addr)899 void dr_unignore(NODEPROTO *np, BOOLEAN objisnode, void *addr)
900 {
901 REGISTER GEOM **ignorelist, *p1, *p2, *geom;
902 REGISTER VARIABLE *var;
903 REGISTER INTBIG i, len, pt;
904
905 var = getvalkey((INTBIG)np, VNODEPROTO, VGEOM|VISARRAY, dr_ignore_listkey);
906
907 /* if the list is empty there is nothing to do */
908 if (var == NOVARIABLE) return;
909
910 /* see if this entry is mentioned in the list */
911 len = getlength(var);
912 for(i=0; i<len; i++)
913 {
914 geom = ((GEOM **)var->addr)[i];
915 if (geom->entryisnode == objisnode && geom->entryaddr.blind == addr) break;
916 }
917 if (i >= len) return;
918
919 /* create a new list without the entry */
920 ignorelist = (GEOM **)emalloc((len * (sizeof (GEOM *))), el_tempcluster);
921 if (ignorelist == 0)
922 {
923 ttyputnomemory();
924 return;
925 }
926
927 /* search list and remove entries that mention this module */
928 pt = 0;
929 for(i=0; i<len; i += 2)
930 {
931 p1 = ((GEOM **)var->addr)[i];
932 p2 = ((GEOM **)var->addr)[i+1];
933 if (p1->entryisnode == objisnode && p1->entryaddr.blind == addr) continue;
934 if (p2->entryisnode == objisnode && p2->entryaddr.blind == addr) continue;
935 ignorelist[pt++] = p1; ignorelist[pt++] = p2;
936 }
937
938 /* set the list back in place */
939 if (pt > 0) (void)setvalkey((INTBIG)np, VNODEPROTO, dr_ignore_listkey,
940 (INTBIG)ignorelist, (INTBIG)(VGEOM|VISARRAY|(pt<<VLENGTHSH)|VDONTSAVE)); else
941 (void)delvalkey((INTBIG)np, VNODEPROTO, dr_ignore_listkey);
942 efree((CHAR *)ignorelist);
943 }
944
945 /*
946 * routine to determine the node prototype specified in "name" (given that
947 * there were "count" parameters to the command and that "name" should be in
948 * the second). Returns NONODEPROTO if there is an error.
949 */
dr_checkthiscell(INTBIG count,CHAR * name)950 NODEPROTO *dr_checkthiscell(INTBIG count, CHAR *name)
951 {
952 REGISTER NODEPROTO *np;
953
954 if (count < 2)
955 {
956 np = getcurcell();
957 if (np == NONODEPROTO) ttyputerr(_("No current cell"));
958 return(np);
959 }
960 np = getnodeproto(name);
961 if (np == NONODEPROTO)
962 {
963 ttyputerr(_("No cell named %s"), name);
964 return(NONODEPROTO);
965 }
966 if (np->primindex != 0)
967 {
968 ttyputerr(_("Can only check cells, not primitives"));
969 return(NONODEPROTO);
970 }
971 return(np);
972 }
973
974 /*
975 * Routine to obtain the current value of the DRC options.
976 * Note that this cannot be automatically maintained by the "newvariable()" hook
977 * because the DRC isn't always on.
978 */
dr_getoptionsvalue(void)979 INTBIG dr_getoptionsvalue(void)
980 {
981 REGISTER VARIABLE *var;
982
983 var = getvalkey((INTBIG)dr_tool, VTOOL, VINTEGER, dr_optionskey);
984 if (var == NOVARIABLE) return(0);
985 return(var->addr);
986 }
987
988 /*
989 * Turns off all saved date information about valid DRC.
990 */
dr_reset_dates(void)991 void dr_reset_dates(void)
992 {
993 REGISTER LIBRARY *lib;
994 REGISTER NODEPROTO *np;
995 REGISTER VARIABLE *var;
996
997 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
998 {
999 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1000 {
1001 var = getvalkey((INTBIG)np, VNODEPROTO, VINTEGER, dr_lastgooddrckey);
1002 if (var == NOVARIABLE) continue;
1003 nextchangequiet();
1004 (void)delvalkey((INTBIG)np, VNODEPROTO, dr_lastgooddrckey);
1005 }
1006 }
1007 }
1008
1009 /*
1010 * Routine to check all of cell "cell". Returns number of errors found.
1011 */
dr_checkentirecell(NODEPROTO * cell,INTBIG count,NODEINST ** nodestocheck,BOOLEAN * validity,BOOLEAN justarea)1012 void dr_checkentirecell(NODEPROTO *cell, INTBIG count, NODEINST **nodestocheck, BOOLEAN *validity,
1013 BOOLEAN justarea)
1014 {
1015 REGISTER LIBRARY *lib;
1016 REGISTER NODEPROTO *np;
1017 REGISTER INTBIG errorcount;
1018
1019 if (cell->cellview == el_schematicview || cell->tech == sch_tech)
1020 {
1021 /* hierarchical check of schematics */
1022 for(lib = el_curlib; lib != NOLIBRARY; lib = lib->nextlibrary)
1023 for(np = lib->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
1024 np->temp1 = 0;
1025 initerrorlogging(_("Schematic DRC"));
1026 dr_checkschematiccellrecursively(cell);
1027 errorcount = numerrors();
1028 if (errorcount != 0) ttyputmsg(_("TOTAL OF %ld ERRORS FOUND"), errorcount);
1029 termerrorlogging(TRUE);
1030 return;
1031 }
1032 dr_quickcheck(cell, count, nodestocheck, validity, justarea);
1033 }
1034
1035 /****************************** SCHEMATIC DRC ******************************/
1036
dr_checkschematiccellrecursively(NODEPROTO * cell)1037 void dr_checkschematiccellrecursively(NODEPROTO *cell)
1038 {
1039 REGISTER NODEINST *ni;
1040 REGISTER NODEPROTO *cnp;
1041
1042 cell->temp1 = 1;
1043 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1044 {
1045 if (ni->proto->primindex != 0) continue;
1046 cnp = contentsview(ni->proto);
1047 if (cnp == NONODEPROTO) cnp = ni->proto;
1048 if (cnp->temp1 != 0) continue;
1049
1050 /* ignore documentation icon */
1051 if (isiconof(ni->proto, cell)) continue;
1052
1053 dr_checkschematiccellrecursively(cnp);
1054 }
1055
1056 /* now check this cell */
1057 ttyputmsg(_("Checking schematic cell %s"), describenodeproto(cell));
1058 dr_checkschematiccell(cell, FALSE);
1059 }
1060
dr_checkschematiccell(NODEPROTO * cell,BOOLEAN justthis)1061 void dr_checkschematiccell(NODEPROTO *cell, BOOLEAN justthis)
1062 {
1063 REGISTER NODEINST *ni;
1064 REGISTER ARCINST *ai;
1065 REGISTER INTBIG errorcount, initialerrorcount, thiserrors;
1066 REGISTER CHAR *indent;
1067
1068 if (justthis) initerrorlogging(_("Schematic DRC"));
1069 initialerrorcount = numerrors();
1070 for(ni = cell->firstnodeinst; ni != NONODEINST; ni = ni->nextnodeinst)
1071 dr_schdocheck(ni->geom);
1072 for(ai = cell->firstarcinst; ai != NOARCINST; ai = ai->nextarcinst)
1073 dr_schdocheck(ai->geom);
1074 errorcount = numerrors();
1075 thiserrors = errorcount - initialerrorcount;
1076 if (justthis) indent = x_(""); else
1077 indent = x_(" ");
1078 if (thiserrors == 0) ttyputmsg(_("%sNo errors found"), indent); else
1079 ttyputmsg(_("%s%ld errors found"), indent, thiserrors);
1080 if (justthis) termerrorlogging(TRUE);
1081 }
1082
1083 /*
1084 * Routine to check schematic object "geom".
1085 */
dr_schdocheck(GEOM * geom)1086 void dr_schdocheck(GEOM *geom)
1087 {
1088 REGISTER NODEPROTO *cell, *np;
1089 REGISTER NODEINST *ni;
1090 REGISTER ARCINST *ai;
1091 ARCINST **thearcs;
1092 REGISTER PORTARCINST *pi;
1093 REGISTER PORTPROTO *pp;
1094 REGISTER VARIABLE *var, *fvar;
1095 REGISTER BOOLEAN checkdangle;
1096 REGISTER INTBIG i, j, fun, signals, portwidth, nodesize;
1097 INTBIG x, y;
1098 void *err, *infstr;
1099 UINTBIG descript[TEXTDESCRIPTSIZE];
1100
1101 cell = geomparent(geom);
1102 if (geom->entryisnode)
1103 {
1104 ni = geom->entryaddr.ni;
1105
1106 /* check for bus pins that don't connect to any bus arcs */
1107 if (ni->proto == sch_buspinprim)
1108 {
1109 /* proceed only if it has no exports on it */
1110 if (ni->firstportexpinst == NOPORTEXPINST)
1111 {
1112 /* must not connect to any bus arcs */
1113 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1114 if (pi->conarcinst->proto == sch_busarc) break;
1115 if (pi == NOPORTARCINST)
1116 {
1117 err = logerror(_("Bus pin does not connect to any bus arcs"), cell, 0);
1118 addgeomtoerror(err, geom, TRUE, 0, 0);
1119 return;
1120 }
1121 }
1122
1123 /* flag bus pin if more than 1 wire is connected */
1124 i = 0;
1125 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1126 if (pi->conarcinst->proto == sch_wirearc) i++;
1127 if (i > 1)
1128 {
1129 err = logerror(_("Wire arcs cannot connect through a bus pin"), cell, 0);
1130 addgeomtoerror(err, geom, TRUE, 0, 0);
1131 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1132 if (pi->conarcinst->proto == sch_wirearc)
1133 addgeomtoerror(err, pi->conarcinst->geom, TRUE, 0, 0);
1134 return;
1135 }
1136 }
1137
1138 /* check all pins */
1139 if ((ni->proto->userbits&NFUNCTION) >> NFUNCTIONSH == NPPIN)
1140 {
1141 /* may be stranded if there are no exports or arcs */
1142 if (ni->firstportexpinst == NOPORTEXPINST && ni->firstportarcinst == NOPORTARCINST)
1143 {
1144 /* see if the pin has displayable variables on it */
1145 for(i=0; i<ni->numvar; i++)
1146 {
1147 var = &ni->firstvar[i];
1148 if ((var->type&VDISPLAY) != 0) break;
1149 }
1150 if (i >= ni->numvar)
1151 {
1152 err = logerror(_("Stranded pin (not connected or exported)"), cell, 0);
1153 addgeomtoerror(err, geom, TRUE, 0, 0);
1154 return;
1155 }
1156 }
1157
1158 if (isinlinepin(ni, &thearcs))
1159 {
1160 err = logerror(_("Unnecessary pin (between 2 arcs)"), cell, 0);
1161 addgeomtoerror(err, geom, TRUE, 0, 0);
1162 return;
1163 }
1164
1165 if (invisiblepinwithoffsettext(ni, &x, &y, FALSE))
1166 {
1167 err = logerror(_("Invisible pin has text in different location"), cell, 0);
1168 addgeomtoerror(err, geom, TRUE, 0, 0);
1169 addlinetoerror(err, (ni->lowx+ni->highx)/2, (ni->lowy+ni->highy)/2, x, y);
1170 return;
1171 }
1172 }
1173
1174 /* check parameters */
1175 if (ni->proto->primindex == 0)
1176 {
1177 np = contentsview(ni->proto);
1178 if (np == NONODEPROTO) np = ni->proto;
1179
1180 /* ensure that this node matches the parameter list */
1181 for(i=0; i<ni->numvar; i++)
1182 {
1183 var = &ni->firstvar[i];
1184 if (TDGETISPARAM(var->textdescript) == 0) continue;
1185 fvar = NOVARIABLE;
1186 for(j=0; j<np->numvar; j++)
1187 {
1188 fvar = &np->firstvar[j];
1189 if (TDGETISPARAM(fvar->textdescript) == 0) continue;
1190 if (namesame(makename(var->key), makename(fvar->key)) == 0) break;
1191 }
1192 if (j >= np->numvar)
1193 {
1194 /* this node's parameter is no longer on the cell: delete from instance */
1195 infstr = initinfstr();
1196 formatinfstr(infstr, _("Parameter '%s' on node %s is invalid and has been deleted"),
1197 truevariablename(var), describenodeinst(ni));
1198 err = logerror(returninfstr(infstr), cell, 0);
1199 addgeomtoerror(err, geom, TRUE, 0, 0);
1200 startobjectchange((INTBIG)ni, VNODEINST);
1201 (void)delvalkey((INTBIG)ni, VNODEINST, var->key);
1202 endobjectchange((INTBIG)ni, VNODEINST);
1203 i--;
1204 } else
1205 {
1206 /* this node's parameter is still on the cell: make sure units are OK */
1207 if (TDGETUNITS(var->textdescript) != TDGETUNITS(fvar->textdescript))
1208 {
1209 infstr = initinfstr();
1210 formatinfstr(infstr, _("Parameter '%s' on node %s had incorrect units (now fixed)"),
1211 truevariablename(var), describenodeinst(ni));
1212 err = logerror(returninfstr(infstr), cell, 0);
1213 addgeomtoerror(err, geom, TRUE, 0, 0);
1214 startobjectchange((INTBIG)ni, VNODEINST);
1215 TDCOPY(descript, var->textdescript);
1216 TDSETUNITS(descript, TDGETUNITS(fvar->textdescript));
1217 modifydescript((INTBIG)ni, VNODEINST, var, descript);
1218 endobjectchange((INTBIG)ni, VNODEINST);
1219 }
1220
1221 /* make sure visibility is OK */
1222 if (TDGETINTERIOR(fvar->textdescript) != 0)
1223 {
1224 if ((var->type&VDISPLAY) != 0)
1225 {
1226 infstr = initinfstr();
1227 formatinfstr(infstr, _("Parameter '%s' on node %s should not be visible (now fixed)"),
1228 truevariablename(var), describenodeinst(ni));
1229 err = logerror(returninfstr(infstr), cell, 0);
1230 addgeomtoerror(err, geom, TRUE, 0, 0);
1231 startobjectchange((INTBIG)ni, VNODEINST);
1232 var->type &= ~VDISPLAY;
1233 endobjectchange((INTBIG)ni, VNODEINST);
1234 }
1235 } else
1236 {
1237 if ((var->type&VDISPLAY) == 0)
1238 {
1239 infstr = initinfstr();
1240 formatinfstr(infstr, _("Parameter '%s' on node %s should be visible (now fixed)"),
1241 truevariablename(var), describenodeinst(ni));
1242 err = logerror(returninfstr(infstr), cell, 0);
1243 addgeomtoerror(err, geom, TRUE, 0, 0);
1244 startobjectchange((INTBIG)ni, VNODEINST);
1245 var->type |= VDISPLAY;
1246 endobjectchange((INTBIG)ni, VNODEINST);
1247 }
1248 }
1249 }
1250 }
1251 }
1252 } else
1253 {
1254 ai = geom->entryaddr.ai;
1255
1256 /* check for being floating if it does not have a visible name on it */
1257 var = getvalkey((INTBIG)ai, VARCINST, -1, el_arc_name_key);
1258 if (var == NOVARIABLE || (var->type&VDISPLAY) == 0) checkdangle = TRUE; else
1259 checkdangle = FALSE;
1260 if (checkdangle)
1261 {
1262 /* do not check for dangle when busses are on named networks */
1263 if (ai->proto == sch_busarc)
1264 {
1265 if (ai->network->namecount > 0 && ai->network->tempname == 0) checkdangle = FALSE;
1266 }
1267 }
1268 if (checkdangle)
1269 {
1270 /* check to see if this arc is floating */
1271 for(i=0; i<2; i++)
1272 {
1273 ni = ai->end[i].nodeinst;
1274
1275 /* OK if not a pin */
1276 fun = nodefunction(ni);
1277 if (fun != NPPIN) continue;
1278
1279 /* OK if it has exports on it */
1280 if (ni->firstportexpinst != NOPORTEXPINST) continue;
1281
1282 /* OK if it connects to more than 1 arc */
1283 if (ni->firstportarcinst == NOPORTARCINST) continue;
1284 if (ni->firstportarcinst->nextportarcinst != NOPORTARCINST) continue;
1285
1286 /* the arc dangles */
1287 err = logerror(_("Arc dangles"), cell, 0);
1288 addgeomtoerror(err, geom, TRUE, 0, 0);
1289 return;
1290 }
1291 }
1292
1293
1294 /* check to see if its width is sensible */
1295 if (ai->network == NONETWORK) signals = 1; else
1296 {
1297 signals = ai->network->buswidth;
1298 if (signals < 1) signals = 1;
1299 }
1300 for(i=0; i<2; i++)
1301 {
1302 ni = ai->end[i].nodeinst;
1303 if (ni->proto->primindex != 0) continue;
1304 np = contentsview(ni->proto);
1305 if (np == NONODEPROTO) np = ni->proto;
1306 pp = equivalentport(ni->proto, ai->end[i].portarcinst->proto, np);
1307 if (pp == NOPORTPROTO)
1308 {
1309 infstr = initinfstr();
1310 formatinfstr(infstr, _("Arc %s connects to port %s of node %s, but there is no equivalent port in cell %s"),
1311 describearcinst(ai), ai->end[i].portarcinst->proto->protoname, describenodeinst(ni), describenodeproto(np));
1312 err = logerror(returninfstr(infstr), cell, 0);
1313 addgeomtoerror(err, geom, TRUE, 0, 0);
1314 addgeomtoerror(err, ni->geom, TRUE, 0, 0);
1315 continue;
1316 }
1317 portwidth = pp->network->buswidth;
1318 if (portwidth < 1) portwidth = 1;
1319 nodesize = ni->arraysize;
1320 if (nodesize <= 0) nodesize = 1;
1321 if (signals != portwidth && signals != portwidth*nodesize)
1322 {
1323 infstr = initinfstr();
1324 formatinfstr(infstr, _("Arc %s (%ld wide) connects to port %s of node %s (%ld wide)"),
1325 describearcinst(ai), signals, pp->protoname, describenodeinst(ni), portwidth);
1326 err = logerror(returninfstr(infstr), cell, 0);
1327 addgeomtoerror(err, geom, TRUE, 0, 0);
1328 addgeomtoerror(err, ni->geom, TRUE, 0, 0);
1329 }
1330 }
1331 }
1332
1333 /* check for overlap */
1334 dr_schcheckobjectvicinity(geom, geom, el_matid);
1335 }
1336
1337 /*
1338 * Routine to check whether object "geom" has a DRC violation with a neighboring object.
1339 */
dr_schcheckobjectvicinity(GEOM * topgeom,GEOM * geom,XARRAY trans)1340 void dr_schcheckobjectvicinity(GEOM *topgeom, GEOM *geom, XARRAY trans)
1341 {
1342 REGISTER INTBIG i, total;
1343 REGISTER NODEINST *ni, *subni;
1344 REGISTER ARCINST *ai, *subai;
1345 XARRAY xformr, xformt, subrot, localtrans;
1346 static POLYGON *poly = NOPOLYGON;
1347
1348 needstaticpolygon(&poly, 4, dr_tool->cluster);
1349 if (geom->entryisnode)
1350 {
1351 ni = geom->entryaddr.ni;
1352 makerot(ni, xformr);
1353 transmult(xformr, trans, localtrans);
1354 if (ni->proto->primindex == 0)
1355 {
1356 if ((ni->userbits&NEXPAND) != 0)
1357 {
1358 /* expand the instance */
1359 maketrans(ni, xformt);
1360 transmult(xformt, localtrans, subrot);
1361 for(subni = ni->proto->firstnodeinst; subni != NONODEINST; subni = subni->nextnodeinst)
1362 dr_schcheckobjectvicinity(topgeom, subni->geom, subrot);
1363 for(subai = ni->proto->firstarcinst; subai != NOARCINST; subai = subai->nextarcinst)
1364 dr_schcheckobjectvicinity(topgeom, subai->geom, subrot);
1365 }
1366 } else
1367 {
1368 /* primitive */
1369 total = nodepolys(ni, 0, NOWINDOWPART);
1370 for(i=0; i<total; i++)
1371 {
1372 shapenodepoly(ni, i, poly);
1373 xformpoly(poly, localtrans);
1374 (void)dr_schcheckpolygonvicinity(topgeom, poly);
1375 }
1376 }
1377 } else
1378 {
1379 ai = geom->entryaddr.ai;
1380 total = arcpolys(ai, NOWINDOWPART);
1381 for(i=0; i<total; i++)
1382 {
1383 shapearcpoly(ai, i, poly);
1384 xformpoly(poly, trans);
1385 (void)dr_schcheckpolygonvicinity(topgeom, poly);
1386 }
1387 }
1388 }
1389
1390 /*
1391 * Routine to check whether polygon "poly" from object "geom" has a DRC violation
1392 * with a neighboring object. Returns TRUE if an error was found.
1393 */
dr_schcheckpolygonvicinity(GEOM * geom,POLYGON * poly)1394 BOOLEAN dr_schcheckpolygonvicinity(GEOM *geom, POLYGON *poly)
1395 {
1396 REGISTER NODEINST *ni, *oni;
1397 REGISTER ARCINST *ai, *oai;
1398 REGISTER NODEPROTO *cell;
1399 REGISTER GEOM *ogeom;
1400 REGISTER PORTARCINST *pi;
1401 REGISTER NETWORK *net;
1402 REGISTER BOOLEAN connected;
1403 REGISTER INTBIG i, sea;
1404
1405 /* don't check text */
1406 if (poly->style == TEXTCENT || poly->style == TEXTTOP ||
1407 poly->style == TEXTBOT || poly->style == TEXTLEFT ||
1408 poly->style == TEXTRIGHT || poly->style == TEXTTOPLEFT ||
1409 poly->style == TEXTBOTLEFT || poly->style == TEXTTOPRIGHT ||
1410 poly->style == TEXTBOTRIGHT || poly->style == TEXTBOX ||
1411 poly->style == GRIDDOTS) return(FALSE);
1412
1413 cell = geomparent(geom);
1414 if (geom->entryisnode) ni = geom->entryaddr.ni; else ai = geom->entryaddr.ai;
1415 sea = initsearch(geom->lowx, geom->highx, geom->lowy, geom->highy, cell);
1416 for(;;)
1417 {
1418 ogeom = nextobject(sea);
1419 if (ogeom == NOGEOM) break;
1420
1421 /* canonicalize so that errors are found only once */
1422 if ((INTBIG)geom <= (INTBIG)ogeom) continue;
1423
1424 /* what type of object was found in area */
1425 if (ogeom->entryisnode)
1426 {
1427 /* found node nearby */
1428 oni = ogeom->entryaddr.ni;
1429 if (geom->entryisnode)
1430 {
1431 /* this is node, nearby is node: see if two nodes touch */
1432 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1433 net->temp1 = 0;
1434 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1435 pi->conarcinst->network->temp1 |= 1;
1436 for(pi = oni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1437 pi->conarcinst->network->temp1 |= 2;
1438 for(net = cell->firstnetwork; net != NONETWORK; net = net->nextnetwork)
1439 if (net->temp1 == 3) break;
1440 if (net != NONETWORK) continue;
1441 } else
1442 {
1443 /* this is arc, nearby is node: see if electrically connected */
1444 for(pi = oni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1445 if (pi->conarcinst->network == ai->network) break;
1446 if (pi != NOPORTARCINST) continue;
1447 }
1448
1449 /* no connection: check for touching another */
1450 if (dr_schcheckpoly(geom, poly, ogeom, ogeom, el_matid, FALSE))
1451 {
1452 termsearch(sea);
1453 return(TRUE);
1454 }
1455 } else
1456 {
1457 /* found arc nearby */
1458 oai = ogeom->entryaddr.ai;
1459 if (geom->entryisnode)
1460 {
1461 /* this is node, nearby is arc: see if electrically connected */
1462 for(pi = ni->firstportarcinst; pi != NOPORTARCINST; pi = pi->nextportarcinst)
1463 if (pi->conarcinst->network == oai->network) break;
1464 if (pi != NOPORTARCINST) continue;
1465
1466 if (dr_schcheckpoly(geom, poly, ogeom, ogeom, el_matid, FALSE))
1467 {
1468 termsearch(sea);
1469 return(TRUE);
1470 }
1471 } else
1472 {
1473 /* this is arc, nearby is arc: check for colinearity */
1474 if (dr_schcheckcolinear(ai, oai))
1475 {
1476 termsearch(sea);
1477 return(TRUE);
1478 }
1479
1480 /* if not connected, check to see if they touch */
1481 connected = FALSE;
1482 if (ai->network == oai->network) connected = TRUE; else
1483 {
1484 if (ai->network->buswidth > 1 && oai->network->buswidth <= 1)
1485 {
1486 for(i=0; i<ai->network->buswidth; i++)
1487 if (ai->network->networklist[i] == oai->network) break;
1488 if (i < ai->network->buswidth) connected = TRUE;
1489 } else if (oai->network->buswidth > 1 && ai->network->buswidth <= 1)
1490 {
1491 for(i=0; i<oai->network->buswidth; i++)
1492 if (oai->network->networklist[i] == ai->network) break;
1493 if (i < oai->network->buswidth) connected = TRUE;
1494 }
1495 }
1496 if (!connected)
1497 {
1498 if (dr_schcheckpoly(geom, poly, ogeom, ogeom, el_matid, TRUE))
1499 {
1500 termsearch(sea);
1501 return(TRUE);
1502 }
1503 }
1504 }
1505 }
1506 }
1507 return(TRUE);
1508 }
1509
1510 /*
1511 * Check polygon "poly" from object "geom" against
1512 * geom "ogeom" transformed by "otrans" (and really on top-level object "otopgeom").
1513 * Returns TRUE if an error was found.
1514 */
dr_schcheckpoly(GEOM * geom,POLYGON * poly,GEOM * otopgeom,GEOM * ogeom,XARRAY otrans,BOOLEAN cancross)1515 BOOLEAN dr_schcheckpoly(GEOM *geom, POLYGON *poly, GEOM *otopgeom, GEOM *ogeom, XARRAY otrans,
1516 BOOLEAN cancross)
1517 {
1518 REGISTER INTBIG i, total;
1519 REGISTER NODEINST *ni, *subni;
1520 REGISTER ARCINST *ai, *subai;
1521 XARRAY xformr, xformt, thistrans, subrot;
1522 static POLYGON *opoly = NOPOLYGON;
1523
1524 needstaticpolygon(&opoly, 4, dr_tool->cluster);
1525 if (ogeom->entryisnode)
1526 {
1527 ni = ogeom->entryaddr.ni;
1528 makerot(ni, xformr);
1529 transmult(xformr, otrans, thistrans);
1530 if (ni->proto->primindex == 0)
1531 {
1532 maketrans(ni, xformt);
1533 transmult(xformt, thistrans, subrot);
1534 for(subni = ni->proto->firstnodeinst; subni != NONODEINST; subni = subni->nextnodeinst)
1535 {
1536 if (dr_schcheckpoly(geom, poly, otopgeom, subni->geom, subrot, cancross))
1537 return(TRUE);
1538 }
1539 for(subai = ni->proto->firstarcinst; subai != NOARCINST; subai = subai->nextarcinst)
1540 {
1541 if (dr_schcheckpoly(geom, poly, otopgeom, subai->geom, subrot, cancross))
1542 return(TRUE);
1543 }
1544 } else
1545 {
1546 total = nodepolys(ni, 0, NOWINDOWPART);
1547 for(i=0; i<total; i++)
1548 {
1549 shapenodepoly(ni, i, opoly);
1550 xformpoly(opoly, thistrans);
1551 if (dr_checkpolyagainstpoly(geom, poly, otopgeom, opoly, cancross))
1552 return(TRUE);
1553 }
1554 }
1555 } else
1556 {
1557 ai = ogeom->entryaddr.ai;
1558 total = arcpolys(ai, NOWINDOWPART);
1559 for(i=0; i<total; i++)
1560 {
1561 shapearcpoly(ai, i, opoly);
1562 xformpoly(opoly, otrans);
1563 if (dr_checkpolyagainstpoly(geom, poly, otopgeom, opoly, cancross))
1564 return(TRUE);
1565 }
1566 }
1567 return(FALSE);
1568 }
1569
1570 /*
1571 * Check polygon "poly" from object "geom" against
1572 * polygon "opoly" from object "ogeom".
1573 * If "cancross" is TRUE, they can cross each other (but an endpoint cannot touch).
1574 * Returns TRUE if an error was found.
1575 */
dr_checkpolyagainstpoly(GEOM * geom,POLYGON * poly,GEOM * ogeom,POLYGON * opoly,BOOLEAN cancross)1576 BOOLEAN dr_checkpolyagainstpoly(GEOM *geom, POLYGON *poly, GEOM *ogeom, POLYGON *opoly, BOOLEAN cancross)
1577 {
1578 REGISTER void *err;
1579 REGISTER INTBIG i;
1580
1581 if (cancross)
1582 {
1583 for(i=0; i<poly->count; i++)
1584 {
1585 if (polydistance(opoly, poly->xv[i], poly->yv[i]) <= 0) break;
1586 }
1587 if (i >= poly->count)
1588 {
1589 /* none in "poly" touched one in "opoly", try other way */
1590 for(i=0; i<opoly->count; i++)
1591 {
1592 if (polydistance(poly, opoly->xv[i], opoly->yv[i]) <= 0) break;
1593 }
1594 if (i >= opoly->count) return(FALSE);
1595 }
1596 } else
1597 {
1598 if (!polyintersect(poly, opoly)) return(FALSE);
1599 }
1600
1601 /* report the error */
1602 err = logerror(_("Objects touch"), geomparent(geom), 0);
1603 addgeomtoerror(err, geom, TRUE, 0, 0);
1604 addgeomtoerror(err, ogeom, TRUE, 0, 0);
1605 return(TRUE);
1606 }
1607
1608 /*
1609 * Routine to check whether arc "ai" is colinear with another.
1610 * Returns TRUE if an error was found.
1611 */
dr_schcheckcolinear(ARCINST * ai,ARCINST * oai)1612 BOOLEAN dr_schcheckcolinear(ARCINST *ai, ARCINST *oai)
1613 {
1614 REGISTER INTBIG lowx, highx, lowy, highy, olow, ohigh, ang, oang, fx, fy, tx, ty,
1615 ofx, ofy, otx, oty, dist, gdist, frx, fry, tox, toy, ca, sa;
1616 REGISTER void *err;
1617
1618 /* get information about the other line */
1619 fx = ai->end[0].xpos; fy = ai->end[0].ypos;
1620 tx = ai->end[1].xpos; ty = ai->end[1].ypos;
1621 ofx = oai->end[0].xpos; ofy = oai->end[0].ypos;
1622 otx = oai->end[1].xpos; oty = oai->end[1].ypos;
1623 if (ofx == otx && ofy == oty) return(FALSE);
1624
1625 /* see if they are colinear */
1626 lowx = mini(fx, tx);
1627 highx = maxi(fx, tx);
1628 lowy = mini(fy, ty);
1629 highy = maxi(fy, ty);
1630 if (fx == tx)
1631 {
1632 /* vertical line */
1633 olow = mini(ofy, oty);
1634 ohigh = maxi(ofy, oty);
1635 if (ofx != fx || otx != fx) return(FALSE);
1636 if (lowy >= ohigh || highy <= olow) return(FALSE);
1637 ang = 900;
1638 } else if (fy == ty)
1639 {
1640 /* horizontal line */
1641 olow = mini(ofx, otx);
1642 ohigh = maxi(ofx, otx);
1643 if (ofy != fy || oty != fy) return(FALSE);
1644 if (lowx >= ohigh || highx <= olow) return(FALSE);
1645 ang = 0;
1646 } else
1647 {
1648 /* general case */
1649 ang = figureangle(fx, fy, tx, ty);
1650 oang = figureangle(ofx, ofy, otx, oty);
1651 if (ang != oang && mini(ang, oang) + 1800 != maxi(ang, oang)) return(FALSE);
1652 if (muldiv(ofx-fx, ty-fy, tx-fx) != ofy-fy) return(FALSE);
1653 if (muldiv(otx-fx, ty-fy, tx-fx) != oty-fy) return(FALSE);
1654 olow = mini(ofy, oty);
1655 ohigh = maxi(ofy, oty);
1656 if (lowy >= ohigh || highy <= olow) return(FALSE);
1657 olow = mini(ofx, otx);
1658 ohigh = maxi(ofx, otx);
1659 if (lowx >= ohigh || highx <= olow) return(FALSE);
1660 }
1661 err = logerror(_("Arcs overlap"), ai->parent, 0);
1662 addgeomtoerror(err, ai->geom, TRUE, 0, 0);
1663 addgeomtoerror(err, oai->geom, TRUE, 0, 0);
1664
1665 /* add information that shows the arcs */
1666 ang = (ang + 900) % 3600;
1667 dist = ai->parent->lib->lambda[ai->parent->tech->techindex] * 2;
1668 gdist = dist / 2;
1669 ca = cosine(ang); sa = sine(ang);
1670 frx = fx + mult(dist, ca);
1671 fry = fy + mult(dist, sa);
1672 tox = tx + mult(dist, ca);
1673 toy = ty + mult(dist, sa);
1674 fx = fx + mult(gdist, ca);
1675 fy = fy + mult(gdist, sa);
1676 tx = tx + mult(gdist, ca);
1677 ty = ty + mult(gdist, sa);
1678 addlinetoerror(err, frx, fry, tox, toy);
1679 addlinetoerror(err, frx, fry, fx, fy);
1680 addlinetoerror(err, tx, ty, tox, toy);
1681
1682 frx = ofx - mult(dist, ca);
1683 fry = ofy - mult(dist, sa);
1684 tox = otx - mult(dist, ca);
1685 toy = oty - mult(dist, sa);
1686 ofx = ofx - mult(gdist, ca);
1687 ofy = ofy - mult(gdist, sa);
1688 otx = otx - mult(gdist, ca);
1689 oty = oty - mult(gdist, sa);
1690 addlinetoerror(err, frx, fry, tox, toy);
1691 addlinetoerror(err, frx, fry, ofx, ofy);
1692 addlinetoerror(err, otx, oty, tox, toy);
1693 return(TRUE);
1694 }
1695
1696 /****************************** DIALOGS ******************************/
1697
1698 /* DRC: Options */
1699 static DIALOGITEM dr_optionsdialogitems[] =
1700 {
1701 /* 1 */ {0, {304,184,328,248}, BUTTON, N_("OK")},
1702 /* 2 */ {0, {304,44,328,108}, BUTTON, N_("Cancel")},
1703 /* 3 */ {0, {144,8,160,224}, MESSAGE, N_("Incremental and hierarchical:")},
1704 /* 4 */ {0, {272,32,288,160}, BUTTON, N_("Edit Rules Deck")},
1705 /* 5 */ {0, {32,32,48,117}, CHECK, N_("On")},
1706 /* 6 */ {0, {192,216,208,272}, EDITTEXT, x_("")},
1707 /* 7 */ {0, {8,8,24,169}, MESSAGE, N_("Incremental DRC:")},
1708 /* 8 */ {0, {64,8,80,169}, MESSAGE, N_("Hierarchical DRC:")},
1709 /* 9 */ {0, {248,8,264,169}, MESSAGE, N_("Dracula DRC Interface:")},
1710 /* 10 */ {0, {112,32,128,192}, BUTTON, N_("Clear valid DRC dates")},
1711 /* 11 */ {0, {88,32,104,228}, CHECK, N_("Just 1 error per cell")},
1712 /* 12 */ {0, {216,32,232,296}, CHECK, N_("Ignore center cuts in large contacts")},
1713 /* 13 */ {0, {192,48,208,212}, MESSAGE, N_("Number of processors:")},
1714 /* 14 */ {0, {168,32,184,217}, CHECK, N_("Use multiple processors")},
1715 /* 15 */ {0, {56,8,57,296}, DIVIDELINE, x_("")},
1716 /* 16 */ {0, {136,8,137,296}, DIVIDELINE, x_("")},
1717 /* 17 */ {0, {240,8,241,296}, DIVIDELINE, x_("")},
1718 /* 18 */ {0, {296,8,297,296}, DIVIDELINE, x_("")}
1719 };
1720 static DIALOG dr_optionsdialog = {{50,75,387,381}, N_("DRC Options"), 0, 18, dr_optionsdialogitems, 0, 0};
1721
1722 /* special items for the "DRC Options" dialog: */
1723 #define DDRO_DRACULADECK 4 /* Edit dracula rules (button) */
1724 #define DDRO_DRCON 5 /* Incremental DRC is on (check) */
1725 #define DDRO_NUMPROC 6 /* Number of processors to use (edit text) */
1726 #define DDRO_CLEARDATES 10 /* Clear valid DRC dates (button) */
1727 #define DDRO_JUST1ERROR 11 /* Find 1 error per cell (check) */
1728 #define DDRO_FEWERCUTS 12 /* Ignore center cuts in large contacts (check) */
1729 #define DDRO_USEMULTIPROC 14 /* Use multiple processors (check) */
1730
dr_optionsdlog(void)1731 void dr_optionsdlog(void)
1732 {
1733 REGISTER INTBIG itemHit, options, oldoptions, i, l, numproc, orignumproc;
1734 REGISTER CHAR *qual;
1735 INTBIG dummy, clearvaliddrcdates;
1736 CHAR header[200], *dummyfile[1];
1737 REGISTER VARIABLE *var;
1738 REGISTER WINDOWPART *w;
1739 REGISTER EDITOR *ed;
1740 REGISTER void *infstr, *dia;
1741
1742 dia = DiaInitDialog(&dr_optionsdialog);
1743 if (dia == 0) return;
1744 DiaUnDimItem(dia, DDRO_CLEARDATES);
1745
1746 oldoptions = dr_getoptionsvalue();
1747 if ((oldoptions&DRCFIRSTERROR) != 0) DiaSetControl(dia, DDRO_JUST1ERROR, 1);
1748 if ((oldoptions&DRCREASONABLE) != 0) DiaSetControl(dia, DDRO_FEWERCUTS, 1);
1749 if ((dr_tool->toolstate & TOOLON) != 0) DiaSetControl(dia, DDRO_DRCON, 1);
1750 if (graphicshas(CANDOTHREADS))
1751 {
1752 DiaUnDimItem(dia, DDRO_USEMULTIPROC);
1753 orignumproc = numproc = (oldoptions&DRCNUMPROC) >> DRCNUMPROCSH;
1754 if (numproc == 0) numproc = enumprocessors();
1755 esnprintf(header, 200, x_("%ld"), numproc);
1756 DiaSetText(dia, DDRO_NUMPROC, header);
1757 if ((oldoptions&DRCMULTIPROC) != 0)
1758 {
1759 DiaSetControl(dia, DDRO_USEMULTIPROC, 1);
1760 DiaUnDimItem(dia, DDRO_NUMPROC);
1761 } else
1762 {
1763 DiaDimItem(dia, DDRO_NUMPROC);
1764 }
1765 } else
1766 {
1767 DiaDimItem(dia, DDRO_USEMULTIPROC);
1768 DiaDimItem(dia, DDRO_NUMPROC);
1769 }
1770
1771 /* loop until done */
1772 for(;;)
1773 {
1774 itemHit = DiaNextHit(dia);
1775 if (itemHit == OK || itemHit == CANCEL || itemHit == DDRO_DRACULADECK) break;
1776 if (itemHit == DDRO_DRCON || itemHit == DDRO_JUST1ERROR ||
1777 itemHit == DDRO_FEWERCUTS || itemHit == DDRO_USEMULTIPROC)
1778 {
1779 i = 1 - DiaGetControl(dia, itemHit);
1780 DiaSetControl(dia, itemHit, i);
1781 if (itemHit == DDRO_USEMULTIPROC)
1782 {
1783 if (i != 0) DiaUnDimItem(dia, DDRO_NUMPROC); else
1784 DiaDimItem(dia, DDRO_NUMPROC);
1785 }
1786 continue;
1787 }
1788 if (itemHit == DDRO_CLEARDATES)
1789 {
1790 clearvaliddrcdates = 1;
1791 DiaDimItem(dia, DDRO_CLEARDATES);
1792 continue;
1793 }
1794 }
1795
1796 if (itemHit != CANCEL)
1797 {
1798 options = 0;
1799 if (DiaGetControl(dia, DDRO_JUST1ERROR) != 0) options |= DRCFIRSTERROR;
1800 if (DiaGetControl(dia, DDRO_FEWERCUTS) != 0) options |= DRCREASONABLE;
1801 if (graphicshas(CANDOTHREADS))
1802 {
1803 if (DiaGetControl(dia, DDRO_USEMULTIPROC) != 0) options |= DRCMULTIPROC;
1804 numproc = eatoi(DiaGetText(dia, DDRO_NUMPROC));
1805 if (DiaGetControl(dia, DDRO_USEMULTIPROC) == 0)
1806 numproc = orignumproc;
1807 options = (options & ~DRCNUMPROC) | (numproc << DRCNUMPROCSH);
1808 }
1809 if (options != oldoptions)
1810 (void)setvalkey((INTBIG)dr_tool, VTOOL, dr_optionskey, options, VINTEGER);
1811
1812 /* change state of DRC */
1813 if (DiaGetControl(dia, DDRO_DRCON) != 0)
1814 {
1815 if ((dr_tool->toolstate & TOOLON) == 0)
1816 {
1817 toolturnon(dr_tool);
1818 setvalkey((INTBIG)dr_tool, VTOOL, dr_incrementalonkey, 1, VINTEGER);
1819 }
1820 } else
1821 {
1822 if ((dr_tool->toolstate & TOOLON) != 0)
1823 {
1824 toolturnoff(dr_tool, FALSE);
1825 setvalkey((INTBIG)dr_tool, VTOOL, dr_incrementalonkey, 0, VINTEGER);
1826 }
1827 }
1828
1829 /* clear valid DRC dates if requested */
1830 if (clearvaliddrcdates != 0) dr_reset_dates();
1831 }
1832 DiaDoneDialog(dia);
1833
1834 if (itemHit == DDRO_DRACULADECK)
1835 {
1836 /* now edit the dracula */
1837 qual = x_("DRC_ecad_deck");
1838 esnprintf(header, 200, _("ECAD deck for technology %s"), el_curtech->techname);
1839
1840 var = getval((INTBIG)el_curtech, VTECHNOLOGY, -1, qual);
1841 if (var == NOVARIABLE)
1842 {
1843 dummyfile[0] = x_("");
1844 var = setval((INTBIG)el_curtech, VTECHNOLOGY, qual, (INTBIG)dummyfile,
1845 VSTRING|VISARRAY|(1<<VLENGTHSH));
1846 if (var == NOVARIABLE)
1847 {
1848 ttyputerr(_("Cannot create DRC_ecad_deck on the technology"));
1849 return;
1850 }
1851 } else
1852 var->type &= ~VDONTSAVE;
1853
1854 /* get a new window, put an editor in it */
1855 w = us_wantnewwindow(0);
1856 if (w == NOWINDOWPART) return;
1857 if (us_makeeditor(w, header, &dummy, &dummy) == NOWINDOWPART) return;
1858 ed = w->editor;
1859 ed->editobjqual = qual;
1860 ed->editobjaddr = (CHAR *)el_curtech;
1861 ed->editobjtype = VTECHNOLOGY;
1862 ed->editobjvar = var;
1863 us_suspendgraphics(w);
1864
1865 l = getlength(var);
1866 for(i=0; i<l; i++)
1867 {
1868 infstr = initinfstr();
1869 addstringtoinfstr(infstr, describevariable(var, i, -1));
1870 us_addline(w, i, returninfstr(infstr));
1871 }
1872 us_resumegraphics(w);
1873 w->changehandler = us_varchanges;
1874 }
1875 }
1876
1877 /*
1878 * Routine to invoke the Design Rule Editing dialog on the current technology.
1879 */
dr_rulesdloghook(void)1880 void dr_rulesdloghook(void)
1881 {
1882 REGISTER INTBIG i, changed, truelen, truelenR, truelencon, truelenuncon, truelenconW, truelenunconW,
1883 truelenconM, truelenunconM, truelenedge, truelenconR, truelenunconR, truelenconWR, truelenunconWR,
1884 truelenconMR, truelenunconMR, truelenedgeR;
1885 REGISTER VARIABLE *varcon, *varuncon, *varconW, *varunconW, *varconM, *varunconM,
1886 *varedge, *varconR, *varunconR, *varconWR, *varunconWR, *varconMR, *varunconMR,
1887 *varedgeR, *varmindist, *varmindistR, *var, *varminsize, *varminsizeR;
1888 REGISTER DRCRULES *rules;
1889
1890 /* create a RULES structure */
1891 rules = dr_allocaterules(el_curtech->layercount, el_curtech->nodeprotocount, el_curtech->techname);
1892 if (rules == NODRCRULES) return;
1893
1894 /* fill in the technology name and layer names */
1895 for(i=0; i<rules->numlayers; i++)
1896 (void)allocstring(&rules->layernames[i], layername(el_curtech, i), el_tempcluster);
1897
1898 /* get the distances */
1899 varmindist = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1900 dr_min_widthkey);
1901 varmindistR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1902 dr_min_width_rulekey);
1903 varcon = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1904 dr_connected_distanceskey);
1905 varuncon = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1906 dr_unconnected_distanceskey);
1907 varconW = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1908 dr_connected_distancesWkey);
1909 varunconW = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1910 dr_unconnected_distancesWkey);
1911 varconM = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1912 dr_connected_distancesMkey);
1913 varunconM = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1914 dr_unconnected_distancesMkey);
1915 varedge = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1916 dr_edge_distanceskey);
1917 varminsize = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT|VISARRAY,
1918 dr_min_node_sizekey);
1919 varconR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1920 dr_connected_distances_rulekey);
1921 varunconR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1922 dr_unconnected_distances_rulekey);
1923 varconWR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1924 dr_connected_distancesW_rulekey);
1925 varunconWR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1926 dr_unconnected_distancesW_rulekey);
1927 varconMR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1928 dr_connected_distancesM_rulekey);
1929 varunconMR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1930 dr_unconnected_distancesM_rulekey);
1931 varedgeR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1932 dr_edge_distances_rulekey);
1933 varminsizeR = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VSTRING|VISARRAY,
1934 dr_min_node_size_rulekey);
1935
1936 /* put the distances into the rules structure */
1937 if (varmindist == NOVARIABLE) truelen = 0; else
1938 truelen = getlength(varmindist);
1939 if (varmindistR == NOVARIABLE) truelenR = 0; else
1940 truelenR = getlength(varmindistR);
1941 for(i=0; i<rules->numlayers; i++)
1942 {
1943 if (i < truelen)
1944 rules->minwidth[i] = ((INTBIG *)varmindist->addr)[i];
1945 if (i < truelenR && ((CHAR **)varmindistR->addr)[i][0] != 0)
1946 (void)reallocstring(&rules->minwidthR[i], ((CHAR **)varmindistR->addr)[i], el_tempcluster);
1947 }
1948 if (varcon == NOVARIABLE) truelencon = 0; else
1949 truelencon = getlength(varcon);
1950 if (varuncon == NOVARIABLE) truelenuncon = 0; else
1951 truelenuncon = getlength(varuncon);
1952 if (varconW == NOVARIABLE) truelenconW = 0; else
1953 truelenconW = getlength(varconW);
1954 if (varunconW == NOVARIABLE) truelenunconW = 0; else
1955 truelenunconW = getlength(varunconW);
1956 if (varconM == NOVARIABLE) truelenconM = 0; else
1957 truelenconM = getlength(varconM);
1958 if (varunconM == NOVARIABLE) truelenunconM = 0; else
1959 truelenunconM = getlength(varunconM);
1960 if (varedge == NOVARIABLE) truelenedge = 0; else
1961 truelenedge = getlength(varedge);
1962
1963 if (varconR == NOVARIABLE) truelenconR = 0; else
1964 truelenconR = getlength(varconR);
1965 if (varunconR == NOVARIABLE) truelenunconR = 0; else
1966 truelenunconR = getlength(varunconR);
1967 if (varconWR == NOVARIABLE) truelenconWR = 0; else
1968 truelenconWR = getlength(varconWR);
1969 if (varunconWR == NOVARIABLE) truelenunconWR = 0; else
1970 truelenunconWR = getlength(varunconWR);
1971 if (varconMR == NOVARIABLE) truelenconMR = 0; else
1972 truelenconMR = getlength(varconMR);
1973 if (varunconMR == NOVARIABLE) truelenunconMR = 0; else
1974 truelenunconMR = getlength(varunconMR);
1975 if (varedgeR == NOVARIABLE) truelenedgeR = 0; else
1976 truelenedgeR = getlength(varedgeR);
1977
1978 for(i=0; i<rules->utsize; i++)
1979 {
1980 if (i < truelencon)
1981 rules->conlist[i] = ((INTBIG *)varcon->addr)[i];
1982 if (i < truelenuncon)
1983 rules->unconlist[i] = ((INTBIG *)varuncon->addr)[i];
1984 if (i < truelenconW)
1985 rules->conlistW[i] = ((INTBIG *)varconW->addr)[i];
1986 if (i < truelenunconW)
1987 rules->unconlistW[i] = ((INTBIG *)varunconW->addr)[i];
1988 if (i < truelenconM)
1989 rules->conlistM[i] = ((INTBIG *)varconM->addr)[i];
1990 if (i < truelenunconM)
1991 rules->unconlistM[i] = ((INTBIG *)varunconM->addr)[i];
1992 if (i < truelenedge)
1993 rules->edgelist[i] = ((INTBIG *)varedge->addr)[i];
1994
1995 if (i < truelenconR && ((CHAR **)varconR->addr)[i][0] != 0)
1996 (void)reallocstring(&rules->conlistR[i], ((CHAR **)varconR->addr)[i], el_tempcluster);
1997 if (i < truelenunconR && ((CHAR **)varunconR->addr)[i][0] != 0)
1998 (void)reallocstring(&rules->unconlistR[i], ((CHAR **)varunconR->addr)[i], el_tempcluster);
1999 if (i < truelenconWR && ((CHAR **)varconWR->addr)[i][0] != 0)
2000 (void)reallocstring(&rules->conlistWR[i], ((CHAR **)varconWR->addr)[i], el_tempcluster);
2001 if (i < truelenunconWR && ((CHAR **)varunconWR->addr)[i][0] != 0)
2002 (void)reallocstring(&rules->unconlistWR[i], ((CHAR **)varunconWR->addr)[i], el_tempcluster);
2003 if (i < truelenconMR && ((CHAR **)varconMR->addr)[i][0] != 0)
2004 (void)reallocstring(&rules->conlistMR[i], ((CHAR **)varconMR->addr)[i], el_tempcluster);
2005 if (i < truelenunconMR && ((CHAR **)varunconMR->addr)[i][0] != 0)
2006 (void)reallocstring(&rules->unconlistMR[i], ((CHAR **)varunconMR->addr)[i], el_tempcluster);
2007 if (i < truelenedgeR && ((CHAR **)varedgeR->addr)[i][0] != 0)
2008 (void)reallocstring(&rules->edgelistR[i], ((CHAR **)varedgeR->addr)[i], el_tempcluster);
2009 }
2010 var = getvalkey((INTBIG)el_curtech, VTECHNOLOGY, VFRACT, dr_wide_limitkey);
2011 if (var != NOVARIABLE) rules->widelimit = var->addr;
2012
2013 /* get the node minimum size information */
2014 if (varminsize == NOVARIABLE) truelen = 0; else
2015 truelen = getlength(varminsize);
2016 if (varminsizeR == NOVARIABLE) truelenR = 0; else
2017 truelenR = getlength(varminsizeR);
2018 for(i=0; i<rules->numnodes; i++)
2019 {
2020 rules->nodenames[i] = el_curtech->nodeprotos[i]->nodename;
2021 if (i < truelen)
2022 {
2023 rules->minnodesize[i*2] = ((INTBIG *)varminsize->addr)[i*2];
2024 rules->minnodesize[i*2+1] = ((INTBIG *)varminsize->addr)[i*2+1];
2025 }
2026 if (i < truelenR && ((CHAR **)varminsizeR->addr)[i][0] != 0)
2027 (void)reallocstring(&rules->minnodesizeR[i], ((CHAR **)varminsizeR->addr)[i], el_tempcluster);
2028 }
2029
2030 /* run the DRC editing dialog */
2031 changed = dr_rulesdlog(el_curtech, rules);
2032
2033 /* if values changed, update variables */
2034 if (changed != 0)
2035 {
2036 if ((changed&RULECHANGEMINWID) != 0)
2037 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_min_widthkey,
2038 (INTBIG)rules->minwidth, VFRACT|VISARRAY|(rules->numlayers<<VLENGTHSH));
2039 if ((changed&RULECHANGEMINWIDR) != 0)
2040 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_min_width_rulekey,
2041 (INTBIG)rules->minwidthR, VSTRING|VISARRAY|(rules->numlayers<<VLENGTHSH));
2042 if ((changed&RULECHANGECONSPA) != 0)
2043 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distanceskey,
2044 (INTBIG)rules->conlist, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2045 if ((changed&RULECHANGEUCONSPA) != 0)
2046 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distanceskey,
2047 (INTBIG)rules->unconlist, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2048 if ((changed&RULECHANGECONSPAW) != 0)
2049 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distancesWkey,
2050 (INTBIG)rules->conlistW, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2051 if ((changed&RULECHANGEUCONSPAW) != 0)
2052 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distancesWkey,
2053 (INTBIG)rules->unconlistW, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2054 if ((changed&RULECHANGECONSPAM) != 0)
2055 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distancesMkey,
2056 (INTBIG)rules->conlistM, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2057 if ((changed&RULECHANGEUCONSPAM) != 0)
2058 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distancesMkey,
2059 (INTBIG)rules->unconlistM, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2060 if ((changed&RULECHANGEEDGESPA) != 0)
2061 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_edge_distanceskey,
2062 (INTBIG)rules->edgelist, VFRACT|VISARRAY|(rules->utsize<<VLENGTHSH));
2063 if ((changed&RULECHANGECONSPAR) != 0)
2064 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distances_rulekey,
2065 (INTBIG)rules->conlistR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2066 if ((changed&RULECHANGEUCONSPAR) != 0)
2067 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distances_rulekey,
2068 (INTBIG)rules->unconlistR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2069 if ((changed&RULECHANGECONSPAWR) != 0)
2070 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distancesW_rulekey,
2071 (INTBIG)rules->conlistWR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2072 if ((changed&RULECHANGEUCONSPAWR) != 0)
2073 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distancesW_rulekey,
2074 (INTBIG)rules->unconlistWR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2075 if ((changed&RULECHANGECONSPAMR) != 0)
2076 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_connected_distancesM_rulekey,
2077 (INTBIG)rules->conlistMR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2078 if ((changed&RULECHANGEUCONSPAMR) != 0)
2079 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_unconnected_distancesM_rulekey,
2080 (INTBIG)rules->unconlistMR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2081 if ((changed&RULECHANGEEDGESPAR) != 0)
2082 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_edge_distances_rulekey,
2083 (INTBIG)rules->edgelistR, VSTRING|VISARRAY|(rules->utsize<<VLENGTHSH));
2084 if ((changed&RULECHANGEWIDLIMIT) != 0)
2085 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_wide_limitkey,
2086 rules->widelimit, VFRACT);
2087
2088 if ((changed&RULECHANGEMINSIZE) != 0)
2089 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_min_node_sizekey,
2090 (INTBIG)rules->minnodesize, VFRACT|VISARRAY|((rules->numnodes*2)<<VLENGTHSH));
2091 if ((changed&RULECHANGEMINSIZER) != 0)
2092 setvalkey((INTBIG)el_curtech, VTECHNOLOGY, dr_min_node_size_rulekey,
2093 (INTBIG)rules->minnodesizeR, VSTRING|VISARRAY|(rules->numnodes<<VLENGTHSH));
2094
2095 /* reset valid DRC dates */
2096 dr_reset_dates();
2097 }
2098
2099 /* free the rules structure */
2100 dr_freerules(rules);
2101 }
2102
2103 /*
2104 * Routine to allocate the space for a DRC rules object that describes "layercount" layers.
2105 * Returns NODRCRULES on error.
2106 */
dr_allocaterules(INTBIG layercount,INTBIG nodecount,CHAR * techname)2107 DRCRULES *dr_allocaterules(INTBIG layercount, INTBIG nodecount, CHAR *techname)
2108 {
2109 DRCRULES *rules;
2110 REGISTER INTBIG i;
2111
2112 rules = (DRCRULES *)emalloc(sizeof (DRCRULES), el_tempcluster);
2113 if (rules == 0) return(NODRCRULES);
2114
2115 (void)allocstring(&rules->techname, techname, el_tempcluster);
2116
2117 /* cache the spacing rules for this technology */
2118 rules->numlayers = layercount;
2119 rules->utsize = (layercount * layercount - layercount) / 2 + layercount;
2120 rules->layernames = (CHAR **)emalloc(rules->numlayers * (sizeof (CHAR *)), el_tempcluster);
2121 if (rules->layernames == 0) return(NODRCRULES);
2122 rules->minwidth = (INTBIG *)emalloc(rules->numlayers * SIZEOFINTBIG, el_tempcluster);
2123 if (rules->minwidth == 0) return(NODRCRULES);
2124 rules->minwidthR = (CHAR **)emalloc(rules->numlayers * (sizeof (CHAR *)), el_tempcluster);
2125 if (rules->minwidthR == 0) return(NODRCRULES);
2126 rules->conlist = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2127 if (rules->conlist == 0) return(NODRCRULES);
2128 rules->unconlist = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2129 if (rules->unconlist == 0) return(NODRCRULES);
2130 rules->conlistW = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2131 if (rules->conlistW == 0) return(NODRCRULES);
2132 rules->unconlistW = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2133 if (rules->unconlistW == 0) return(NODRCRULES);
2134 rules->conlistM = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2135 if (rules->conlistM == 0) return(NODRCRULES);
2136 rules->unconlistM = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2137 if (rules->unconlistM == 0) return(NODRCRULES);
2138 rules->edgelist = (INTBIG *)emalloc(rules->utsize * SIZEOFINTBIG, el_tempcluster);
2139 if (rules->edgelist == 0) return(NODRCRULES);
2140
2141 rules->conlistR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2142 if (rules->conlistR == 0) return(NODRCRULES);
2143 rules->unconlistR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2144 if (rules->unconlistR == 0) return(NODRCRULES);
2145 rules->conlistWR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2146 if (rules->conlistWR == 0) return(NODRCRULES);
2147 rules->unconlistWR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2148 if (rules->unconlistWR == 0) return(NODRCRULES);
2149 rules->conlistMR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2150 if (rules->conlistMR == 0) return(NODRCRULES);
2151 rules->unconlistMR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2152 if (rules->unconlistMR == 0) return(NODRCRULES);
2153 rules->edgelistR = (CHAR **)emalloc(rules->utsize * (sizeof (CHAR *)), el_tempcluster);
2154 if (rules->edgelistR == 0) return(NODRCRULES);
2155
2156 for(i=0; i<rules->numlayers; i++)
2157 {
2158 rules->minwidth[i] = XX;
2159 (void)allocstring(&rules->minwidthR[i], x_(""), el_tempcluster);
2160 rules->layernames[i] = 0;
2161 }
2162 for(i=0; i<rules->utsize; i++)
2163 {
2164 rules->conlist[i] = XX;
2165 rules->unconlist[i] = XX;
2166 rules->conlistW[i] = XX;
2167 rules->unconlistW[i] = XX;
2168 rules->conlistM[i] = XX;
2169 rules->unconlistM[i] = XX;
2170 rules->edgelist[i] = XX;
2171 (void)allocstring(&rules->conlistR[i], x_(""), el_tempcluster);
2172 (void)allocstring(&rules->unconlistR[i], x_(""), el_tempcluster);
2173 (void)allocstring(&rules->conlistWR[i], x_(""), el_tempcluster);
2174 (void)allocstring(&rules->unconlistWR[i], x_(""), el_tempcluster);
2175 (void)allocstring(&rules->conlistMR[i], x_(""), el_tempcluster);
2176 (void)allocstring(&rules->unconlistMR[i], x_(""), el_tempcluster);
2177 (void)allocstring(&rules->edgelistR[i], x_(""), el_tempcluster);
2178 }
2179 rules->widelimit = K10;
2180
2181 /* allocate space for node rules */
2182 rules->numnodes = nodecount;
2183 if (nodecount > 0)
2184 {
2185 rules->nodenames = (CHAR **)emalloc(nodecount * (sizeof (CHAR *)), el_tempcluster);
2186 if (rules->nodenames == 0) return(NODRCRULES);
2187 rules->minnodesize = (INTBIG *)emalloc(nodecount * 2 * SIZEOFINTBIG, el_tempcluster);
2188 if (rules->minnodesize == 0) return(NODRCRULES);
2189 rules->minnodesizeR = (CHAR **)emalloc(nodecount * (sizeof (CHAR *)), el_tempcluster);
2190 if (rules->minnodesizeR == 0) return(NODRCRULES);
2191 for(i=0; i<nodecount; i++)
2192 {
2193 rules->minnodesize[i*2] = XX;
2194 rules->minnodesize[i*2+1] = XX;
2195 (void)allocstring(&rules->minnodesizeR[i], x_(""), el_tempcluster);
2196 }
2197 }
2198 return(rules);
2199 }
2200
2201 /*
2202 * Routine to free the DRCRULES structure in "rules".
2203 */
dr_freerules(DRCRULES * rules)2204 void dr_freerules(DRCRULES *rules)
2205 {
2206 REGISTER INTBIG i;
2207
2208 efree((CHAR *)rules->techname);
2209 efree((CHAR *)rules->conlist);
2210 efree((CHAR *)rules->unconlist);
2211 efree((CHAR *)rules->conlistW);
2212 efree((CHAR *)rules->unconlistW);
2213 efree((CHAR *)rules->conlistM);
2214 efree((CHAR *)rules->unconlistM);
2215 efree((CHAR *)rules->edgelist);
2216 efree((CHAR *)rules->minwidth);
2217 for(i=0; i<rules->utsize; i++)
2218 {
2219 efree((CHAR *)rules->conlistR[i]);
2220 efree((CHAR *)rules->unconlistR[i]);
2221 efree((CHAR *)rules->conlistWR[i]);
2222 efree((CHAR *)rules->unconlistWR[i]);
2223 efree((CHAR *)rules->conlistMR[i]);
2224 efree((CHAR *)rules->unconlistMR[i]);
2225 efree((CHAR *)rules->edgelistR[i]);
2226 }
2227 for(i=0; i<rules->numlayers; i++)
2228 {
2229 efree((CHAR *)rules->minwidthR[i]);
2230 if (rules->layernames[i] != 0)
2231 efree((CHAR *)rules->layernames[i]);
2232 }
2233 for(i=0; i<rules->numnodes; i++)
2234 efree((CHAR *)rules->minnodesizeR[i]);
2235 if (rules->numnodes > 0)
2236 {
2237 efree((CHAR *)rules->nodenames);
2238 efree((CHAR *)rules->minnodesize);
2239 efree((CHAR *)rules->minnodesizeR);
2240 }
2241 efree((CHAR *)rules->conlistR);
2242 efree((CHAR *)rules->unconlistR);
2243 efree((CHAR *)rules->conlistWR);
2244 efree((CHAR *)rules->unconlistWR);
2245 efree((CHAR *)rules->conlistMR);
2246 efree((CHAR *)rules->unconlistMR);
2247 efree((CHAR *)rules->edgelistR);
2248 efree((CHAR *)rules->minwidthR);
2249 efree((CHAR *)rules->layernames);
2250 }
2251
2252 /****************************** DESIGN-RULE EDITING DIALOG ******************************/
2253
2254 /* DRC: Rules */
2255 static DIALOGITEM dr_rulesdialogitems[] =
2256 {
2257 /* 1 */ {0, {8,516,32,580}, BUTTON, N_("OK")},
2258 /* 2 */ {0, {40,516,64,580}, BUTTON, N_("Cancel")},
2259 /* 3 */ {0, {32,100,188,278}, SCROLL, x_("")},
2260 /* 4 */ {0, {32,8,48,95}, RADIO, N_("Layers:")},
2261 /* 5 */ {0, {212,8,435,300}, SCROLL, x_("")},
2262 /* 6 */ {0, {8,100,24,294}, MESSAGE|INACTIVE, x_("")},
2263 /* 7 */ {0, {8,8,24,95}, MESSAGE, N_("Technology:")},
2264 /* 8 */ {0, {192,8,208,88}, MESSAGE, N_("To Layer:")},
2265 /* 9 */ {0, {88,452,104,523}, MESSAGE, N_("Size")},
2266 /* 10 */ {0, {88,528,104,583}, MESSAGE, N_("Rule")},
2267 /* 11 */ {0, {112,308,128,424}, MESSAGE, N_("Minimum Width:")},
2268 /* 12 */ {0, {112,454,128,502}, EDITTEXT, x_("")},
2269 /* 13 */ {0, {112,514,128,596}, EDITTEXT, x_("")},
2270 /* 14 */ {0, {180,308,196,387}, MESSAGE, N_("Normal:")},
2271 /* 15 */ {0, {204,324,220,450}, MESSAGE, N_("When connected:")},
2272 /* 16 */ {0, {204,454,220,502}, EDITTEXT, x_("")},
2273 /* 17 */ {0, {204,514,220,595}, EDITTEXT, x_("")},
2274 /* 18 */ {0, {232,324,248,450}, MESSAGE, N_("Not connected:")},
2275 /* 19 */ {0, {232,454,248,502}, EDITTEXT, x_("")},
2276 /* 20 */ {0, {232,514,248,595}, EDITTEXT, x_("")},
2277 /* 21 */ {0, {288,308,304,520}, MESSAGE, N_("Wide (when bigger than this):")},
2278 /* 22 */ {0, {312,324,328,450}, MESSAGE, N_("When connected:")},
2279 /* 23 */ {0, {312,454,328,502}, EDITTEXT, x_("")},
2280 /* 24 */ {0, {312,514,328,595}, EDITTEXT, x_("")},
2281 /* 25 */ {0, {340,324,356,450}, MESSAGE, N_("Not connected:")},
2282 /* 26 */ {0, {340,454,356,502}, EDITTEXT, x_("")},
2283 /* 27 */ {0, {340,514,356,595}, EDITTEXT, x_("")},
2284 /* 28 */ {0, {368,308,384,448}, MESSAGE, N_("Multiple cuts:")},
2285 /* 29 */ {0, {392,324,408,450}, MESSAGE, N_("When connected:")},
2286 /* 30 */ {0, {392,454,408,502}, EDITTEXT, x_("")},
2287 /* 31 */ {0, {392,514,408,595}, EDITTEXT, x_("")},
2288 /* 32 */ {0, {420,324,436,450}, MESSAGE, N_("Not connected:")},
2289 /* 33 */ {0, {420,454,436,502}, EDITTEXT, x_("")},
2290 /* 34 */ {0, {420,514,436,595}, EDITTEXT, x_("")},
2291 /* 35 */ {0, {180,452,196,523}, MESSAGE, N_("Distance")},
2292 /* 36 */ {0, {180,528,196,583}, MESSAGE, N_("Rule")},
2293 /* 37 */ {0, {24,328,48,488}, BUTTON, N_("Factory Reset of Rules")},
2294 /* 38 */ {0, {288,526,304,574}, EDITTEXT, x_("")},
2295 /* 39 */ {0, {260,324,276,450}, MESSAGE, N_("Edge:")},
2296 /* 40 */ {0, {260,454,276,502}, EDITTEXT, x_("")},
2297 /* 41 */ {0, {260,514,276,595}, EDITTEXT, x_("")},
2298 /* 42 */ {0, {192,104,208,300}, CHECK, N_("Show only lines with rules")},
2299 /* 43 */ {0, {56,8,72,95}, RADIO, N_("Nodes:")},
2300 /* 44 */ {0, {136,308,152,424}, MESSAGE, N_("Minimum Height:")},
2301 /* 45 */ {0, {136,454,152,502}, EDITTEXT, x_("")}
2302 };
2303 static DIALOG dr_rulesdialog = {{50,75,495,681}, N_("Design Rules"), 0, 45, dr_rulesdialogitems, 0, 0};
2304
2305 static void dr_loaddrcdialog(DRCRULES *rules, INTBIG *validlayers, void *dia);
2306 static void dr_loaddrcruleobjects(DRCRULES *rules, INTBIG *validlayers, void *dia);
2307 static void dr_loaddrcdistance(DRCRULES *rules, void *dia);
2308 static CHAR *dr_loadoptlistline(DRCRULES *rules, INTBIG dindex, INTBIG lindex, INTBIG onlyvalid);
2309 static INTBIG dr_rulesdialoggetlayer(DRCRULES *rules, INTBIG item, void *dia);
2310
2311 /* special items for the "DRC Rules" dialog: */
2312 #define DDRR_FROMLAYER 3 /* From layer (scroll) */
2313 #define DDRR_SHOWLAYERS 4 /* Show layers in upper list (check) */
2314 #define DDRR_TOLAYER 5 /* To layer (scroll) */
2315 #define DDRR_TECHNAME 6 /* Technology name (stat text) */
2316 #define DDRR_TOLAYER_L 8 /* To layer label (message) */
2317 #define DDRR_MINWIDTH 12 /* Minimum width (edit text) */
2318 #define DDRR_MINWIDTHR 13 /* Minimum width rule (edit text) */
2319 #define DDRR_NORMDIST_L 14 /* Normal distance label (message) */
2320 #define DDRR_CONDIST_L 15 /* Connected distance label (message) */
2321 #define DDRR_CONDIST 16 /* Connected distance (edit text) */
2322 #define DDRR_CONDISTR 17 /* Connected distance rule (edit text) */
2323 #define DDRR_UCONDIST_L 18 /* Unconnected distance label (message) */
2324 #define DDRR_UCONDIST 19 /* Unconnected distance (edit text) */
2325 #define DDRR_UCONDISTR 20 /* Unconnected distance rule (edit text) */
2326 #define DDRR_WIDEDIST_L 21 /* Wide distance label (message) */
2327 #define DDRR_CONDISTW_L 22 /* Connected wide distance label (message) */
2328 #define DDRR_CONDISTW 23 /* Connected wide distance (edit text) */
2329 #define DDRR_CONDISTWR 24 /* Connected wide distance rule (edit text) */
2330 #define DDRR_UCONDISTW_L 25 /* Unconnected wide distance label (message) */
2331 #define DDRR_UCONDISTW 26 /* Unconnected wide distance (edit text) */
2332 #define DDRR_UCONDISTWR 27 /* Unconnected wide distance rule (edit text) */
2333 #define DDRR_MULTIDIST_L 28 /* Multicut distance label (message) */
2334 #define DDRR_CONDISTM_L 29 /* Connected multi distance label (message) */
2335 #define DDRR_CONDISTM 30 /* Connected multi distance (edit text) */
2336 #define DDRR_CONDISTMR 31 /* Connected multi distance rule (edit text) */
2337 #define DDRR_UCONDISTM_L 32 /* Unconnected multi distance label (message) */
2338 #define DDRR_UCONDISTM 33 /* Unconnected multi distance (edit text) */
2339 #define DDRR_UCONDISTMR 34 /* Unconnected multi distance rule (edit text) */
2340 #define DDRR_DIST_L 35 /* Spacing distance label (message) */
2341 #define DDRR_DISTR_L 36 /* Spacing rule label (message) */
2342 #define DDRR_FACTORYRST 37 /* Factor Reset (button) */
2343 #define DDRR_WIDELIMIT 38 /* Wide limit (edit text) */
2344 #define DDRR_EDGEDIST_L 39 /* Edge distance label (message) */
2345 #define DDRR_EDGEDIST 40 /* Edge distance (edit text) */
2346 #define DDRR_EDGEDISTR 41 /* Edge distance rule (edit text) */
2347 #define DDRR_VALIDRULES 42 /* Only show lines with rules (check) */
2348 #define DDRR_SHOWNODES 43 /* Show nodes in upper list (check) */
2349 #define DDRR_MINHEIGHT_L 44 /* Minimum height label (message) */
2350 #define DDRR_MINHEIGHT 45 /* Minimum height (edit text) */
2351
2352 /*
2353 * Routine to implement a dialog for design rule editing. This is called from the design-rule checker
2354 * to edit current rules, and it is called by the technology editor to edit rules from technologies
2355 * under construction. Takes a technology name ("techname"), number of layers ("numlayers"), and
2356 * the layer names ("layernames"). Takes all of the design-rule tables:
2357 * "minwidth" and "minwidthR", the minimum width and rule for each layer
2358 * "conlist" and "conlistR", the distances and rules between connected layers
2359 * "unconlist" and "unconlistR", the distances and rules between unconnected layers
2360 * "conlistW" and "conlistWR", the distances and rules between connected layers that are wide
2361 * "unconlistW" and "unconlistWR", the distances and rules between unconnected layers that are wide
2362 * "conlistM" and "conlistMR", the distances and rules between connected layers on multi-cut contacts
2363 * "unconlistM" and "unconlistMR", the distances and rules between unconnected layers on multi-cut contacts
2364 * Returns bits that indicate which values changed.
2365 */
dr_rulesdlog(TECHNOLOGY * tech,DRCRULES * rules)2366 INTBIG dr_rulesdlog(TECHNOLOGY *tech, DRCRULES *rules)
2367 {
2368 REGISTER INTBIG itemHit, i, j, dist, layer1, layer2, temp, dindex, *validlayers, changed;
2369 REGISTER NODEINST *ni;
2370 REGISTER ARCINST *ai;
2371 REGISTER NODEPROTO *np;
2372 NODEINST node;
2373 ARCINST arc;
2374 REGISTER ARCPROTO *ap;
2375 REGISTER CHAR *pt, *varname;
2376 REGISTER POLYGON *poly;
2377 REGISTER void *dia;
2378
2379 /* determine which layers are valid */
2380 validlayers = (INTBIG *)emalloc(rules->numlayers * SIZEOFINTBIG, dr_tool->cluster);
2381 if (validlayers == 0) return(0);
2382 if (tech == NOTECHNOLOGY)
2383 {
2384 /* designing rules in technology edit: all layers are valid */
2385 for(i=0; i<rules->numlayers; i++) validlayers[i] = 1;
2386 } else
2387 {
2388 /* editing rules for technology: find used layers only */
2389 poly = allocpolygon(4, dr_tool->cluster);
2390 for(i=0; i<rules->numlayers; i++) validlayers[i] = 0;
2391 for(np = tech->firstnodeproto; np != NONODEPROTO; np = np->nextnodeproto)
2392 {
2393 if ((np->userbits&NNOTUSED) != 0) continue;
2394 ni = &node; initdummynode(ni);
2395 ni->proto = np;
2396 ni->lowx = np->lowx; ni->highx = np->highx;
2397 ni->lowy = np->lowy; ni->highy = np->highy;
2398 j = nodepolys(ni, 0, NOWINDOWPART);
2399 for(i=0; i<j; i++)
2400 {
2401 shapenodepoly(ni, i, poly);
2402 if (poly->tech != tech) continue;
2403 validlayers[poly->layer] = 1;
2404 }
2405 }
2406 for(ap = tech->firstarcproto; ap != NOARCPROTO; ap = ap->nextarcproto)
2407 {
2408 if ((ap->userbits&ANOTUSED) != 0) continue;
2409 ai = &arc; initdummyarc(ai);
2410 ai->proto = ap;
2411 ai->width = ap->nominalwidth;
2412 j = arcpolys(ai, NOWINDOWPART);
2413 for(i=0; i<j; i++)
2414 {
2415 shapearcpoly(ai, i, poly);
2416 if (poly->tech != tech) continue;
2417 validlayers[poly->layer] = 1;
2418 }
2419 }
2420 freepolygon(poly);
2421 }
2422
2423 dia = DiaInitDialog(&dr_rulesdialog);
2424 if (dia == 0) return(0);
2425 DiaInitTextDialog(dia, DDRR_FROMLAYER, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
2426 SCSELMOUSE|SCREPORT);
2427 DiaInitTextDialog(dia, DDRR_TOLAYER, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0,
2428 SCSELMOUSE|SCREPORT);
2429 if (tech == NOTECHNOLOGY) DiaDimItem(dia, DDRR_FACTORYRST); else
2430 DiaUnDimItem(dia, DDRR_FACTORYRST);
2431
2432 /* make the layer list */
2433 DiaSetControl(dia, DDRR_SHOWLAYERS, 1);
2434 dr_loaddrcruleobjects(rules, validlayers, dia);
2435
2436 DiaSetText(dia, DDRR_TECHNAME, rules->techname);
2437 DiaSetText(dia, DDRR_WIDELIMIT, frtoa(rules->widelimit));
2438
2439 dr_loaddrcdialog(rules, validlayers, dia);
2440 dr_loaddrcdistance(rules, dia);
2441 changed = 0;
2442
2443 /* loop until done */
2444 for(;;)
2445 {
2446 itemHit = DiaNextHit(dia);
2447 if (itemHit == OK || itemHit == CANCEL || itemHit == DDRR_FACTORYRST) break;
2448 if (itemHit == DDRR_SHOWLAYERS || itemHit == DDRR_SHOWNODES)
2449 {
2450 DiaSetControl(dia, DDRR_SHOWLAYERS, 0);
2451 DiaSetControl(dia, DDRR_SHOWNODES, 0);
2452 DiaSetControl(dia, itemHit, 1);
2453 dr_loaddrcruleobjects(rules, validlayers, dia);
2454 dr_loaddrcdialog(rules, validlayers, dia);
2455 continue;
2456 }
2457 if (itemHit == DDRR_CONDIST || itemHit == DDRR_UCONDIST ||
2458 itemHit == DDRR_CONDISTW || itemHit == DDRR_UCONDISTW ||
2459 itemHit == DDRR_CONDISTM || itemHit == DDRR_UCONDISTM ||
2460 itemHit == DDRR_EDGEDIST)
2461 {
2462 /* typed into distance field */
2463 i = dr_rulesdialoggetlayer(rules, DDRR_TOLAYER, dia);
2464 if (i < 0) continue;
2465 pt = DiaGetText(dia, itemHit);
2466 while (*pt == ' ' || *pt == '\t') pt++;
2467 if (*pt == 0) dist = -WHOLE; else
2468 dist = atofr(pt);
2469 layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2470 if (layer1 < 0) continue;
2471 layer2 = i;
2472 if (layer1 > layer2) { temp = layer1; layer1 = layer2; layer2 = temp; }
2473 dindex = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
2474 dindex = layer2 + rules->numlayers * layer1 - dindex;
2475 if (itemHit == DDRR_CONDIST)
2476 {
2477 if (rules->conlist[dindex] != dist) changed |= RULECHANGECONSPA;
2478 rules->conlist[dindex] = dist;
2479 } else if (itemHit == DDRR_UCONDIST)
2480 {
2481 if (rules->unconlist[dindex] != dist) changed |= RULECHANGEUCONSPA;
2482 rules->unconlist[dindex] = dist;
2483 } else if (itemHit == DDRR_CONDISTW)
2484 {
2485 if (rules->conlistW[dindex] != dist) changed |= RULECHANGECONSPAW;
2486 rules->conlistW[dindex] = dist;
2487 } else if (itemHit == DDRR_UCONDISTW)
2488 {
2489 if (rules->unconlistW[dindex] != dist) changed |= RULECHANGEUCONSPAW;
2490 rules->unconlistW[dindex] = dist;
2491 } else if (itemHit == DDRR_CONDISTM)
2492 {
2493 if (rules->conlistM[dindex] != dist) changed |= RULECHANGECONSPAM;
2494 rules->conlistM[dindex] = dist;
2495 } else if (itemHit == DDRR_UCONDISTM)
2496 {
2497 if (rules->unconlistM[dindex] != dist) changed |= RULECHANGEUCONSPAM;
2498 rules->unconlistM[dindex] = dist;
2499 } else if (itemHit == DDRR_EDGEDIST)
2500 {
2501 if (rules->edgelist[dindex] != dist) changed |= RULECHANGEEDGESPA;
2502 rules->edgelist[dindex] = dist;
2503 }
2504
2505 pt = dr_loadoptlistline(rules, dindex, i, 0);
2506 DiaSetScrollLine(dia, DDRR_TOLAYER, DiaGetCurLine(dia, DDRR_TOLAYER), pt);
2507 continue;
2508 }
2509 if (itemHit == DDRR_CONDISTR || itemHit == DDRR_UCONDISTR ||
2510 itemHit == DDRR_CONDISTWR || itemHit == DDRR_UCONDISTWR ||
2511 itemHit == DDRR_CONDISTMR || itemHit == DDRR_UCONDISTMR ||
2512 itemHit == DDRR_EDGEDISTR)
2513 {
2514 /* typed into rule field */
2515 i = dr_rulesdialoggetlayer(rules, DDRR_TOLAYER, dia);
2516 if (i < 0) continue;
2517 pt = DiaGetText(dia, itemHit);
2518 layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2519 if (layer1 < 0) continue;
2520 layer2 = i;
2521 if (layer1 > layer2) { temp = layer1; layer1 = layer2; layer2 = temp; }
2522 dindex = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
2523 dindex = layer2 + rules->numlayers * layer1 - dindex;
2524 if (itemHit == DDRR_CONDISTR)
2525 {
2526 if (estrcmp(rules->conlistR[dindex], pt) != 0) changed |= RULECHANGECONSPAR;
2527 (void)reallocstring(&rules->conlistR[dindex], pt, el_tempcluster);
2528 } else if (itemHit == DDRR_UCONDISTR)
2529 {
2530 if (estrcmp(rules->unconlistR[dindex], pt) != 0) changed |= RULECHANGEUCONSPAR;
2531 (void)reallocstring(&rules->unconlistR[dindex], pt, el_tempcluster);
2532 } else if (itemHit == DDRR_CONDISTWR)
2533 {
2534 if (estrcmp(rules->conlistWR[dindex], pt) != 0) changed |= RULECHANGECONSPAWR;
2535 (void)reallocstring(&rules->conlistWR[dindex], pt, el_tempcluster);
2536 } else if (itemHit == DDRR_UCONDISTWR)
2537 {
2538 if (estrcmp(rules->unconlistWR[dindex], pt) != 0) changed |= RULECHANGEUCONSPAWR;
2539 (void)reallocstring(&rules->unconlistWR[dindex], pt, el_tempcluster);
2540 } else if (itemHit == DDRR_CONDISTMR)
2541 {
2542 if (estrcmp(rules->conlistMR[dindex], pt) != 0) changed |= RULECHANGECONSPAMR;
2543 (void)reallocstring(&rules->conlistMR[dindex], pt, el_tempcluster);
2544 } else if (itemHit == DDRR_UCONDISTMR)
2545 {
2546 if (estrcmp(rules->unconlistMR[dindex], pt) != 0) changed |= RULECHANGEUCONSPAMR;
2547 (void)reallocstring(&rules->unconlistMR[dindex], pt, el_tempcluster);
2548 } else if (itemHit == DDRR_EDGEDISTR)
2549 {
2550 if (estrcmp(rules->edgelistR[dindex], pt) != 0) changed |= RULECHANGEEDGESPAR;
2551 (void)reallocstring(&rules->edgelistR[dindex], pt, el_tempcluster);
2552 }
2553 continue;
2554 }
2555 if (itemHit == DDRR_WIDELIMIT)
2556 {
2557 pt = DiaGetText(dia, DDRR_WIDELIMIT);
2558 dist = atofr(pt);
2559 if (rules->widelimit != dist) changed |= RULECHANGEWIDLIMIT;
2560 rules->widelimit = dist;
2561 continue;
2562 }
2563 if (itemHit == DDRR_MINWIDTH)
2564 {
2565 /* typed into min-width field */
2566 pt = DiaGetText(dia, DDRR_MINWIDTH);
2567 while (*pt == ' ' || *pt == '\t') pt++;
2568 if (*pt == 0) dist = -WHOLE; else
2569 dist = atofr(pt);
2570 if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2571 {
2572 /* set the node minimum width */
2573 i = DiaGetCurLine(dia, DDRR_FROMLAYER);
2574 if (rules->minnodesize[i*2] != dist) changed |= RULECHANGEMINSIZE;
2575 rules->minnodesize[i*2] = dist;
2576 } else
2577 {
2578 /* set the layer minimum width */
2579 layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2580 if (rules->minwidth[layer1] != dist) changed |= RULECHANGEMINWID;
2581 rules->minwidth[layer1] = dist;
2582 }
2583 continue;
2584 }
2585 if (itemHit == DDRR_MINHEIGHT)
2586 {
2587 /* typed into min-width field */
2588 pt = DiaGetText(dia, DDRR_MINHEIGHT);
2589 while (*pt == ' ' || *pt == '\t') pt++;
2590 if (*pt == 0) dist = -WHOLE; else
2591 dist = atofr(pt);
2592
2593 /* set the node minimum height */
2594 i = DiaGetCurLine(dia, DDRR_FROMLAYER);
2595 if (rules->minnodesize[i*2+1] != dist) changed |= RULECHANGEMINSIZE;
2596 rules->minnodesize[i*2+1] = dist;
2597 continue;
2598 }
2599 if (itemHit == DDRR_MINWIDTHR)
2600 {
2601 /* typed into min-width rule field */
2602 pt = DiaGetText(dia, DDRR_MINWIDTHR);
2603 while (*pt == ' ' || *pt == '\t') pt++;
2604 if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2605 {
2606 /* set the node minimum width */
2607 i = DiaGetCurLine(dia, DDRR_FROMLAYER);
2608 if (estrcmp(rules->minnodesizeR[i], pt) != 0) changed |= RULECHANGEMINSIZER;
2609 (void)reallocstring(&rules->minnodesizeR[i], pt, el_tempcluster);
2610 } else
2611 {
2612 /* set the layer minimum width */
2613 layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2614 if (estrcmp(rules->minwidthR[layer1], pt) != 0) changed |= RULECHANGEMINWIDR;
2615 (void)reallocstring(&rules->minwidthR[layer1], pt, el_tempcluster);
2616 }
2617 continue;
2618 }
2619 if (itemHit == DDRR_FROMLAYER)
2620 {
2621 /* changed layer popup */
2622 dr_loaddrcdialog(rules, validlayers, dia);
2623 dr_loaddrcdistance(rules, dia);
2624 continue;
2625 }
2626 if (itemHit == DDRR_TOLAYER)
2627 {
2628 /* clicked on new entry in scroll list of "to" layers */
2629 dr_loaddrcdistance(rules, dia);
2630 continue;
2631 }
2632 if (itemHit == DDRR_VALIDRULES)
2633 {
2634 DiaSetControl(dia, itemHit, 1-DiaGetControl(dia, itemHit));
2635 dr_loaddrcdialog(rules, validlayers, dia);
2636 dr_loaddrcdistance(rules, dia);
2637 continue;
2638 }
2639 }
2640
2641 DiaDoneDialog(dia);
2642
2643 if (itemHit != OK) changed = 0;
2644 if (itemHit == DDRR_FACTORYRST)
2645 {
2646 /* "factory reset" was clicked, start by deleting all DRC variables */
2647 for(j=0; dr_variablenames[j] != 0; j++)
2648 {
2649 if (getval((INTBIG)tech, VTECHNOLOGY, -1, dr_variablenames[j]) == NOVARIABLE) continue;
2650 (void)delval((INTBIG)tech, VTECHNOLOGY, dr_variablenames[j]);
2651 }
2652
2653 /* set all technology-defined DRC variables */
2654 for(i=0; tech->variables[i].name != 0; i++)
2655 {
2656 varname = tech->variables[i].name;
2657 for(j=0; dr_variablenames[j] != 0; j++)
2658 if (namesame(varname, dr_variablenames[j]) == 0) break;
2659 if (dr_variablenames[j] == 0) continue;
2660
2661 /* reset the variable */
2662 if (setval((INTBIG)tech, VTECHNOLOGY, tech->variables[i].name,
2663 (INTBIG)tech->variables[i].value, tech->variables[i].type & ~VDONTSAVE) == NOVARIABLE) break;
2664 }
2665
2666 /* call the technology-specific routine to do any extra work */
2667 (void)asktech(tech, x_("factory-reset"));
2668
2669 /* also clear valid DRC dates */
2670 dr_reset_dates();
2671 }
2672 efree((CHAR *)validlayers);
2673 return(changed);
2674 }
2675
dr_loaddrcruleobjects(DRCRULES * rules,INTBIG * validlayers,void * dia)2676 void dr_loaddrcruleobjects(DRCRULES *rules, INTBIG *validlayers, void *dia)
2677 {
2678 REGISTER INTBIG i;
2679
2680 DiaLoadTextDialog(dia, DDRR_FROMLAYER, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0);
2681 if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2682 {
2683 /* list the nodes */
2684 for(i=0; i<rules->numnodes; i++)
2685 DiaStuffLine(dia, DDRR_FROMLAYER, rules->nodenames[i]);
2686 DiaUnDimItem(dia, DDRR_MINHEIGHT_L);
2687 DiaUnDimItem(dia, DDRR_MINHEIGHT);
2688
2689 DiaDimItem(dia, DDRR_CONDIST);
2690 DiaDimItem(dia, DDRR_CONDISTR);
2691 DiaDimItem(dia, DDRR_UCONDIST);
2692 DiaDimItem(dia, DDRR_UCONDISTR);
2693 DiaDimItem(dia, DDRR_CONDISTW);
2694 DiaDimItem(dia, DDRR_CONDISTWR);
2695 DiaDimItem(dia, DDRR_UCONDISTW);
2696 DiaDimItem(dia, DDRR_UCONDISTWR);
2697 DiaDimItem(dia, DDRR_CONDISTM);
2698 DiaDimItem(dia, DDRR_CONDISTMR);
2699 DiaDimItem(dia, DDRR_UCONDISTM);
2700 DiaDimItem(dia, DDRR_UCONDISTMR);
2701 DiaDimItem(dia, DDRR_WIDELIMIT);
2702 DiaDimItem(dia, DDRR_EDGEDIST);
2703 DiaDimItem(dia, DDRR_EDGEDISTR);
2704 DiaDimItem(dia, DDRR_VALIDRULES);
2705 DiaDimItem(dia, DDRR_NORMDIST_L);
2706 DiaDimItem(dia, DDRR_CONDIST_L);
2707 DiaDimItem(dia, DDRR_UCONDIST_L);
2708 DiaDimItem(dia, DDRR_EDGEDIST_L);
2709 DiaDimItem(dia, DDRR_WIDEDIST_L);
2710 DiaDimItem(dia, DDRR_CONDISTW_L);
2711 DiaDimItem(dia, DDRR_UCONDISTW_L);
2712 DiaDimItem(dia, DDRR_MULTIDIST_L);
2713 DiaDimItem(dia, DDRR_CONDISTM_L);
2714 DiaDimItem(dia, DDRR_UCONDISTM_L);
2715 DiaDimItem(dia, DDRR_DIST_L);
2716 DiaDimItem(dia, DDRR_DISTR_L);
2717 DiaDimItem(dia, DDRR_TOLAYER_L);
2718 DiaDimItem(dia, DDRR_TOLAYER);
2719 } else
2720 {
2721 /* list the layers */
2722 for(i=0; i<rules->numlayers; i++)
2723 {
2724 if (validlayers[i] == 0) continue;
2725 DiaStuffLine(dia, DDRR_FROMLAYER, rules->layernames[i]);
2726 }
2727 DiaDimItem(dia, DDRR_MINHEIGHT_L);
2728 DiaDimItem(dia, DDRR_MINHEIGHT);
2729
2730 DiaUnDimItem(dia, DDRR_CONDIST);
2731 DiaUnDimItem(dia, DDRR_CONDISTR);
2732 DiaUnDimItem(dia, DDRR_UCONDIST);
2733 DiaUnDimItem(dia, DDRR_UCONDISTR);
2734 DiaUnDimItem(dia, DDRR_CONDISTW);
2735 DiaUnDimItem(dia, DDRR_CONDISTWR);
2736 DiaUnDimItem(dia, DDRR_UCONDISTW);
2737 DiaUnDimItem(dia, DDRR_UCONDISTWR);
2738 DiaUnDimItem(dia, DDRR_CONDISTM);
2739 DiaUnDimItem(dia, DDRR_CONDISTMR);
2740 DiaUnDimItem(dia, DDRR_UCONDISTM);
2741 DiaUnDimItem(dia, DDRR_UCONDISTMR);
2742 DiaUnDimItem(dia, DDRR_WIDELIMIT);
2743 DiaUnDimItem(dia, DDRR_EDGEDIST);
2744 DiaUnDimItem(dia, DDRR_EDGEDISTR);
2745 DiaUnDimItem(dia, DDRR_VALIDRULES);
2746 DiaUnDimItem(dia, DDRR_NORMDIST_L);
2747 DiaUnDimItem(dia, DDRR_CONDIST_L);
2748 DiaUnDimItem(dia, DDRR_UCONDIST_L);
2749 DiaUnDimItem(dia, DDRR_EDGEDIST_L);
2750 DiaUnDimItem(dia, DDRR_WIDEDIST_L);
2751 DiaUnDimItem(dia, DDRR_CONDISTW_L);
2752 DiaUnDimItem(dia, DDRR_UCONDISTW_L);
2753 DiaUnDimItem(dia, DDRR_MULTIDIST_L);
2754 DiaUnDimItem(dia, DDRR_CONDISTM_L);
2755 DiaUnDimItem(dia, DDRR_UCONDISTM_L);
2756 DiaUnDimItem(dia, DDRR_DIST_L);
2757 DiaUnDimItem(dia, DDRR_DISTR_L);
2758 DiaUnDimItem(dia, DDRR_TOLAYER_L);
2759 DiaUnDimItem(dia, DDRR_TOLAYER);
2760 }
2761 DiaSelectLine(dia, DDRR_FROMLAYER, 0);
2762 }
2763
2764 /*
2765 * Routine to show the detail on the selected layer/node in the upper scroll area.
2766 */
dr_loaddrcdialog(DRCRULES * rules,INTBIG * validlayers,void * dia)2767 void dr_loaddrcdialog(DRCRULES *rules, INTBIG *validlayers, void *dia)
2768 {
2769 REGISTER INTBIG i, j, layer1, layer2, temp, dindex, onlyvalid, count;
2770 REGISTER CHAR *line;
2771
2772 if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2773 {
2774 /* show node information */
2775 j = DiaGetCurLine(dia, DDRR_FROMLAYER);
2776 if (j < 0) return;
2777 DiaSetText(dia, DDRR_MINWIDTH, frtoa(rules->minnodesize[j*2]));
2778 DiaSetText(dia, DDRR_MINHEIGHT, frtoa(rules->minnodesize[j*2+1]));
2779 DiaSetText(dia, DDRR_MINWIDTHR, rules->minnodesizeR[j]);
2780 } else
2781 {
2782 /* show layer information */
2783 onlyvalid = DiaGetControl(dia, DDRR_VALIDRULES);
2784 j = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2785 if (rules->minwidth[j] < 0) DiaSetText(dia, DDRR_MINWIDTH, x_("")); else
2786 DiaSetText(dia, DDRR_MINWIDTH, frtoa(rules->minwidth[j]));
2787 DiaSetText(dia, DDRR_MINWIDTHR, rules->minwidthR[j]);
2788 DiaLoadTextDialog(dia, DDRR_TOLAYER, DiaNullDlogList, DiaNullDlogItem, DiaNullDlogDone, 0);
2789 count = 0;
2790 for(i=0; i<rules->numlayers; i++)
2791 {
2792 if (validlayers[i] == 0) continue;
2793 layer1 = j;
2794 layer2 = i;
2795 if (layer1 > layer2) { temp = layer1; layer1 = layer2; layer2 = temp; }
2796 dindex = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
2797 dindex = layer2 + rules->numlayers * layer1 - dindex;
2798
2799 line = dr_loadoptlistline(rules, dindex, i, onlyvalid);
2800 if (*line == 0) continue;
2801 DiaStuffLine(dia, DDRR_TOLAYER, line);
2802 count++;
2803 }
2804 if (count > 0) DiaSelectLine(dia, DDRR_TOLAYER, 0);
2805 }
2806 }
2807
dr_loadoptlistline(DRCRULES * rules,INTBIG dindex,INTBIG lindex,INTBIG onlyvalid)2808 CHAR *dr_loadoptlistline(DRCRULES *rules, INTBIG dindex, INTBIG lindex, INTBIG onlyvalid)
2809 {
2810 REGISTER CHAR *condist, *uncondist, *wcondist, *wuncondist,
2811 *mcondist, *muncondist, *edgedist;
2812 REGISTER void *infstr;
2813
2814 if (rules->conlist[dindex] < 0) condist = x_(""); else
2815 condist = frtoa(rules->conlist[dindex]);
2816 if (rules->unconlist[dindex] < 0) uncondist = x_(""); else
2817 uncondist = frtoa(rules->unconlist[dindex]);
2818 if (rules->conlistW[dindex] < 0) wcondist = x_(""); else
2819 wcondist = frtoa(rules->conlistW[dindex]);
2820 if (rules->unconlistW[dindex] < 0) wuncondist = x_(""); else
2821 wuncondist = frtoa(rules->unconlistW[dindex]);
2822 if (rules->conlistM[dindex] < 0) mcondist = x_(""); else
2823 mcondist = frtoa(rules->conlistM[dindex]);
2824 if (rules->unconlistM[dindex] < 0) muncondist = x_(""); else
2825 muncondist = frtoa(rules->unconlistM[dindex]);
2826 if (rules->edgelist[dindex] < 0) edgedist = x_(""); else
2827 edgedist = frtoa(rules->edgelist[dindex]);
2828 if (onlyvalid != 0)
2829 {
2830 if (*condist == 0 && *uncondist == 0 && *wcondist == 0 &&
2831 *wuncondist == 0 && *mcondist == 0 && *muncondist == 0 &&
2832 *edgedist == 0) return(x_(""));
2833 }
2834 infstr = initinfstr();
2835 formatinfstr(infstr, x_("%s (%s/%s/%s/%s/%s/%s/%s)"), rules->layernames[lindex],
2836 condist, uncondist, wcondist, wuncondist, mcondist, muncondist, edgedist);
2837 return(returninfstr(infstr));
2838 }
2839
dr_rulesdialoggetlayer(DRCRULES * rules,INTBIG item,void * dia)2840 INTBIG dr_rulesdialoggetlayer(DRCRULES *rules, INTBIG item, void *dia)
2841 {
2842 REGISTER INTBIG i, layer;
2843 REGISTER CHAR *lname, save, *endpos;
2844
2845 i = DiaGetCurLine(dia, item);
2846 if (i < 0) return(-1);
2847 lname = DiaGetScrollLine(dia, item, i);
2848 for(endpos = lname; *endpos != 0; endpos++)
2849 if (endpos[0] == ' ' && endpos[1] == '(') break;
2850 save = *endpos;
2851 *endpos = 0;
2852 for(layer=0; layer<rules->numlayers; layer++)
2853 if (namesame(lname, rules->layernames[layer]) == 0) break;
2854 *endpos = save;
2855 if (layer >= rules->numlayers) return(-1);
2856 return(layer);
2857 }
2858
dr_loaddrcdistance(DRCRULES * rules,void * dia)2859 void dr_loaddrcdistance(DRCRULES *rules, void *dia)
2860 {
2861 REGISTER INTBIG layer1, layer2, temp, dindex;
2862
2863 if (DiaGetControl(dia, DDRR_SHOWLAYERS) == 0)
2864 {
2865 /* show node information */
2866 } else
2867 {
2868 /* show layer information */
2869 DiaSetText(dia, DDRR_CONDIST, x_("")); DiaSetText(dia, DDRR_CONDISTR, x_(""));
2870 DiaSetText(dia, DDRR_UCONDIST, x_("")); DiaSetText(dia, DDRR_UCONDISTR, x_(""));
2871 DiaSetText(dia, DDRR_CONDISTW, x_("")); DiaSetText(dia, DDRR_CONDISTWR, x_(""));
2872 DiaSetText(dia, DDRR_UCONDISTW, x_("")); DiaSetText(dia, DDRR_UCONDISTWR, x_(""));
2873 DiaSetText(dia, DDRR_CONDISTM, x_("")); DiaSetText(dia, DDRR_CONDISTMR, x_(""));
2874 DiaSetText(dia, DDRR_UCONDISTM, x_("")); DiaSetText(dia, DDRR_UCONDISTMR, x_(""));
2875 DiaSetText(dia, DDRR_EDGEDIST, x_("")); DiaSetText(dia, DDRR_EDGEDISTR, x_(""));
2876
2877 layer1 = dr_rulesdialoggetlayer(rules, DDRR_FROMLAYER, dia);
2878 if (layer1 < 0) return;
2879 layer2 = dr_rulesdialoggetlayer(rules, DDRR_TOLAYER, dia);
2880 if (layer2 < 0) return;
2881
2882 if (layer1 > layer2) { temp = layer1; layer1 = layer2; layer2 = temp; }
2883 dindex = (layer1+1) * (layer1/2) + (layer1&1) * ((layer1+1)/2);
2884 dindex = layer2 + rules->numlayers * layer1 - dindex;
2885
2886 if (rules->conlist[dindex] >= 0)
2887 DiaSetText(dia, DDRR_CONDIST, frtoa(rules->conlist[dindex]));
2888 if (rules->unconlist[dindex] >= 0)
2889 DiaSetText(dia, DDRR_UCONDIST, frtoa(rules->unconlist[dindex]));
2890 if (rules->conlistW[dindex] >= 0)
2891 DiaSetText(dia, DDRR_CONDISTW, frtoa(rules->conlistW[dindex]));
2892 if (rules->unconlistW[dindex] >= 0)
2893 DiaSetText(dia, DDRR_UCONDISTW, frtoa(rules->unconlistW[dindex]));
2894 if (rules->conlistM[dindex] >= 0)
2895 DiaSetText(dia, DDRR_CONDISTM, frtoa(rules->conlistM[dindex]));
2896 if (rules->unconlistM[dindex] >= 0)
2897 DiaSetText(dia, DDRR_UCONDISTM, frtoa(rules->unconlistM[dindex]));
2898 if (rules->edgelist[dindex] >= 0)
2899 DiaSetText(dia, DDRR_EDGEDIST, frtoa(rules->edgelist[dindex]));
2900
2901 DiaSetText(dia, DDRR_CONDISTR, rules->conlistR[dindex]);
2902 DiaSetText(dia, DDRR_UCONDISTR, rules->unconlistR[dindex]);
2903 DiaSetText(dia, DDRR_CONDISTWR, rules->conlistWR[dindex]);
2904 DiaSetText(dia, DDRR_UCONDISTWR, rules->unconlistWR[dindex]);
2905 DiaSetText(dia, DDRR_CONDISTMR, rules->conlistMR[dindex]);
2906 DiaSetText(dia, DDRR_UCONDISTMR, rules->unconlistMR[dindex]);
2907 DiaSetText(dia, DDRR_EDGEDISTR, rules->edgelistR[dindex]);
2908 }
2909 }
2910
2911 #endif /* DRCTOOL - at top */
2912