1 /* -*- tab-width: 4 -*-
2 *
3 * Electric(tm) VLSI Design System
4 *
5 * File: dbcontrol.c
6 * Database system controller
7 * Written by: Steven M. Rubin, Static Free Software
8 *
9 * Copyright (c) 2000 Static Free Software.
10 *
11 * Electric(tm) is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Electric(tm) is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Electric(tm); see the file COPYING. If not, write to
23 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
24 * Boston, Mass 02111-1307, USA.
25 *
26 * Static Free Software
27 * 4119 Alpine Road
28 * Portola Valley, California 94028
29 * info@staticfreesoft.com
30 */
31
32 #include "global.h"
33 #include "database.h"
34 #include "tech.h"
35 #include "edialogs.h"
36 #include "usr.h"
37
38 #ifdef INTERNATIONAL
39 # ifdef MACOS
40 # define PACKAGE x_("macelectric")
41 # define LOCALEDIR x_("lib:international")
42 # else
43 # define PACKAGE x_("electric")
44 # define LOCALEDIR x_("lib/international")
45 # endif
46 #endif
47
48 /*
49 * The current Electric version.
50 * Version numbering consists of 3 parts: the major number, the minor number,
51 * and the detail. The detail part is optional lettering at the end which
52 * runs from "a" to "z", then "aa" to "az", then "ba" to "bz", etc.
53 * A released version has no detail, and is considered to be a HIGHER version
54 * than those with detail (which are prereleases). For example:
55 * version "6.04a" has major=6, minor=4, detail=1 ("a")
56 * version "6.05bc" has major=6, minor=5, detail=55 ("bc")
57 * version "6.03" has major=6, minor=3, and detail=1000
58 * The routine "io_getversion()" parses these version strings.
59 */
60 CHAR *el_version = x_("7.00");
61
62 BOOLEAN db_multiprocessing; /* true if multiprocessing */
63
64 /* prototypes for local routines */
65 static void db_freeallmemory(void);
66
67 /*
68 * the primary initialization of Electric
69 */
osprimaryosinit(void)70 void osprimaryosinit(void)
71 {
72 REGISTER INTBIG i;
73 REGISTER TECHNOLOGY *tech, *lasttech, *realtech;
74 REGISTER CONSTRAINT *constr;
75 REGISTER CLUSTER *clus;
76 REGISTER LIBRARY *lib;
77 CHAR libname[10], libfile[10];
78 extern TECHNOLOGY el_technologylist[];
79 REGISTER void *infstr;
80
81 #ifdef INTERNATIONAL
82 # if HAVE_SETLOCALE
83 setlocale(LC_ALL, x_(""));
84 # endif
85 bindtextdomain(PACKAGE, LOCALEDIR);
86 textdomain(PACKAGE);
87
88 /* a test */
89 estrcpy(libname, gettext(x_("Redo")));
90 #endif
91
92 /* initialize the memory allocation system */
93 db_multiprocessing = FALSE;
94 db_initclusters();
95
96 /* internal initialization of the constraint solvers */
97 el_curconstraint = &el_constraints[0];
98 for(i=0; el_constraints[i].conname != 0; i++)
99 {
100 constr = &el_constraints[i];
101 infstr = initinfstr();
102 addstringtoinfstr(infstr, x_("constraint:"));
103 addstringtoinfstr(infstr, constr->conname);
104 constr->cluster = alloccluster(returninfstr(infstr));
105 if (namesame(constr->conname, DEFCONSTR) == 0) el_curconstraint = constr;
106 }
107
108 /* internal initialization of the tools */
109 for(el_maxtools=0; el_tools[el_maxtools].toolname != 0; el_maxtools++)
110 {
111 infstr = initinfstr();
112 addstringtoinfstr(infstr, x_("tool:"));
113 addstringtoinfstr(infstr, el_tools[el_maxtools].toolname);
114 el_tools[el_maxtools].cluster = alloccluster(returninfstr(infstr));
115 el_tools[el_maxtools].toolindex = el_maxtools;
116 }
117
118 /* initialize the database */
119 db_initdatabase();
120 db_initgeometry();
121 db_initlanguages();
122 db_inittechnologies();
123
124 /* internal initialization of the technologies */
125 lasttech = NOTECHNOLOGY;
126 for(el_maxtech=0; el_technologylist[el_maxtech].techname != 0; el_maxtech++)
127 {
128 tech = &el_technologylist[el_maxtech];
129
130 /* create the real technology object */
131 infstr = initinfstr();
132 addstringtoinfstr(infstr, x_("tech:"));
133 addstringtoinfstr(infstr, tech->techname);
134 clus = alloccluster(returninfstr(infstr));
135 realtech = alloctechnology(clus);
136 if (realtech == NOTECHNOLOGY) error(_("No memory for technologies"));
137
138 /* link it in */
139 if (lasttech == NOTECHNOLOGY) el_technologies = realtech; else
140 lasttech->nexttechnology = realtech;
141 lasttech = realtech;
142
143 /* initialize the real technology object */
144 (void)allocstring(&realtech->techname, tech->techname, clus);
145 realtech->techindex = el_maxtech;
146 realtech->deflambda = tech->deflambda;
147 realtech->parse = tech->parse;
148 realtech->cluster = clus;
149 (void)allocstring(&realtech->techdescript, TRANSLATE(tech->techdescript), clus);
150 realtech->layercount = tech->layercount;
151 realtech->layers = tech->layers;
152 realtech->arcprotocount = tech->arcprotocount;
153 realtech->arcprotos = tech->arcprotos;
154 realtech->nodeprotocount = tech->nodeprotocount;
155 realtech->nodeprotos = tech->nodeprotos;
156 realtech->variables = tech->variables;
157 realtech->init = tech->init;
158 realtech->term = tech->term;
159 realtech->setmode = tech->setmode;
160 realtech->request = tech->request;
161 realtech->nodepolys = tech->nodepolys;
162 realtech->nodeEpolys = tech->nodeEpolys;
163 realtech->shapenodepoly = tech->shapenodepoly;
164 realtech->shapeEnodepoly = tech->shapeEnodepoly;
165 realtech->allnodepolys = tech->allnodepolys;
166 realtech->allnodeEpolys = tech->allnodeEpolys;
167 realtech->nodesizeoffset = tech->nodesizeoffset;
168 realtech->shapeportpoly = tech->shapeportpoly;
169 realtech->arcpolys = tech->arcpolys;
170 realtech->shapearcpoly = tech->shapearcpoly;
171 realtech->allarcpolys = tech->allarcpolys;
172 realtech->arcwidthoffset = tech->arcwidthoffset;
173 realtech->userbits = tech->userbits;
174 }
175
176 /* select a current technology */
177 el_curtech = el_technologies;
178 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
179 if (namesame(tech->techname, DEFTECH) == 0) el_curtech = tech;
180 el_curlayouttech = el_curtech;
181
182 /* setup a change batch for initialization work */
183 /* db_preparenewbatch(&el_tools[0]); */
184
185 /* pass 1 initialization of the constraint solvers */
186 for(i=0; el_constraints[i].conname != 0; i++)
187 (*el_constraints[i].init)(&el_constraints[i]);
188
189 /* pass 1 initialization of technologies */
190 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
191 {
192 if (tech->init != 0)
193 {
194 if ((*tech->init)(tech, 0))
195 error(_("User pass 1 error initializing %s technology"), tech->techname);
196 }
197 if (tech_doinitprocess(tech))
198 error(_("Pass 1 error initializing %s technology"), tech->techname);
199 }
200
201 /* pass 1 initialization of the tools */
202 for(i=0; i<el_maxtools; i++)
203 (*el_tools[i].init)(0, 0, &el_tools[i]);
204
205 /* create the first library */
206 el_curlib = NOLIBRARY;
207 estrcpy(libname, x_("noname"));
208 estrcpy(libfile, x_("noname"));
209 lib = newlibrary(libname, libfile);
210 selectlibrary(lib, TRUE);
211 }
212
213 /*
214 * the secondary initialization of Electric
215 */
ossecondaryinit(INTBIG argc,CHAR1 * argv[])216 void ossecondaryinit(INTBIG argc, CHAR1 *argv[])
217 {
218 REGISTER INTBIG i;
219 REGISTER TECHNOLOGY *tech;
220
221 /* pass 2 initialization of the constraint solvers */
222 for(i=0; el_constraints[i].conname != 0; i++)
223 (*el_constraints[i].init)(NOCONSTRAINT);
224
225 /* pass 2 initialization of technologies */
226 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
227 {
228 if (tech->init != 0)
229 {
230 if ((*tech->init)(tech, 1))
231 error(_("User pass 2 error initializing %s technology"), tech->techname);
232 }
233 if (tech_doaddportsandvars(tech))
234 error(_("Pass 2 error initializing %s technology"), tech->techname);
235 }
236
237 /* pass 2 initialization of the tools */
238 for(i=0; i<el_maxtools; i++) (*el_tools[i].init)(&argc, argv, NOTOOL);
239
240 /* pass 3 initialization of technologies */
241 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
242 {
243 if (tech->init != 0)
244 {
245 if ((*tech->init)(tech, 2))
246 error(_("User pass 3 error initializing %s technology"), tech->techname);
247 }
248 }
249
250 /* register and initialize technology-variable caching functions */
251 db_inittechcache();
252
253 /* pass 3 initialization of the tools */
254 for(i=0; i<el_maxtools; i++) (*el_tools[i].init)(&argc, argv, 0);
255
256 /* delete initialization change batches so it is ready for real changes */
257 noundoallowed();
258
259 /* make sure the integer sizes are correct */
260 if (sizeof(INTHUGE) < 8)
261 error(x_("INTHUGE must be 64 bits wide (fix 'global.h')\n"));
262 if (sizeof(INTBIG) < 4)
263 error(x_("INTBIG must be 32 bits wide (fix 'global.h')\n"));
264 if (sizeof(INTSML) < 2)
265 error(x_("INTSML must be 16 bits wide (fix 'global.h')\n"));
266 if (sizeof(INTBIG) < sizeof(CHAR *))
267 error(x_("INTBIG must be able to hold a pointer (%d bytes) bits wide (fix 'global.h')\n"),
268 sizeof(CHAR *));
269 }
270
271 /* the body of the main loop of Electric */
tooltimeslice(void)272 void tooltimeslice(void)
273 {
274 REGISTER INTBIG s;
275 REGISTER TOOL *tool;
276
277 for(s=0; s<el_maxtools; s++)
278 {
279 tool = &el_tools[s];
280 if ((tool->toolstate & TOOLON) == 0) continue;
281 if (tool->slice == 0) continue;
282
283 /* let the tool have a whack */
284 db_setcurrenttool(tool);
285 (*tool->slice)();
286
287 /* announce end of broadcast of changes */
288 db_endbatch();
289 }
290 }
291
telltool(TOOL * tool,INTBIG count,CHAR * par[])292 void telltool(TOOL *tool, INTBIG count, CHAR *par[])
293 {
294 if (tool->setmode == 0) return;
295 (*tool->setmode)(count, par);
296 }
297
asktool(TOOL * tool,CHAR * command,...)298 INTBIG asktool(TOOL *tool, CHAR *command, ...)
299 {
300 va_list ap;
301 INTBIG result;
302
303 if (tool->request == 0) return(0);
304 var_start(ap, command);
305 result = (*tool->request)(command, ap);
306 va_end(ap);
307 return(result);
308 }
309
310 /*
311 * routine to turn tool "tool" back on. The user interface will notice this change
312 * and inform the tool of each cell that changed while it was off (via "examinenodeproto").
313 */
toolturnon(TOOL * tool)314 void toolturnon(TOOL *tool)
315 {
316 /* turn on the tool */
317 (void)setval((INTBIG)tool, VTOOL, x_("toolstate"), tool->toolstate|TOOLON, VINTEGER);
318 }
319
320 /*
321 * routine to turn tool "tool" off. If "permanently" is true, this change
322 * will not be undoable
323 */
toolturnoff(TOOL * tool,BOOLEAN permanently)324 void toolturnoff(TOOL *tool, BOOLEAN permanently)
325 {
326 /* turn off the tool */
327 if (permanently) tool->toolstate &= ~TOOLON; else
328 (void)setval((INTBIG)tool, VTOOL, x_("toolstate"), tool->toolstate & ~TOOLON, VINTEGER);
329 }
330
331 /*
332 * shutdown the design tool
333 */
bringdown(void)334 void bringdown(void)
335 {
336 REGISTER INTBIG i;
337 REGISTER TECHNOLOGY *tech;
338 REGISTER TOOL *tool;
339 REGISTER CONSTRAINT *con;
340
341 /* go backwards through tools to shut down in proper order */
342 for(i = el_maxtools-1; i >= 0; i--)
343 {
344 tool = &el_tools[i];
345 if (tool->done != 0) (*tool->done)();
346 if (tool->numvar != 0) db_freevars(&tool->firstvar, &tool->numvar);
347 }
348
349 /* terminate technologies */
350 for(tech = el_technologies; tech != NOTECHNOLOGY; tech = tech->nexttechnology)
351 if (tech->term != 0) (*tech->term)();
352
353 /* terminate any language interpreters */
354 db_termlanguage();
355
356 /* shut down the constraint solvers */
357 for(i=0; el_constraints[i].conname != 0; i++)
358 {
359 con = &el_constraints[i];
360 (*con->term)();
361 if (con->numvar != 0) db_freevars(&con->firstvar, &con->numvar);
362 }
363
364 /* free up all memory */
365 db_freeallmemory();
366
367 /* check that there were no leaks */
368 db_checkallmemoryfree();
369
370 exitprogram();
371 }
372
db_freeallmemory(void)373 void db_freeallmemory(void)
374 {
375 #ifdef DEBUGMEMORY
376 REGISTER VIEW *v;
377 REGISTER TECHNOLOGY *tech, *nexttech;
378 REGISTER LIBRARY *lib;
379
380 noundoallowed();
381
382 /* free all views */
383 while (el_views != NOVIEW)
384 {
385 v = el_views;
386 el_views = el_views->nextview;
387 efree((CHAR *)v->viewname);
388 efree((CHAR *)v->sviewname);
389 freeview(v);
390 }
391
392 /* free all technologies */
393 for (tech = el_technologies; tech != NOTECHNOLOGY; tech = nexttech)
394 {
395 nexttech = tech->nexttechnology;
396 freetechnology(tech);
397 }
398
399 /* free all libraries */
400 while (el_curlib != NOLIBRARY)
401 {
402 lib = el_curlib;
403 el_curlib = el_curlib->nextlibrary;
404 eraselibrary(lib);
405 efree(lib->libfile);
406 efree(lib->libname);
407 freelibrary(lib);
408 }
409
410 /* free all database memory */
411 db_freetechnologymemory();
412 db_freechangememory();
413 db_freevariablememory();
414 db_freenoprotomemory();
415 db_freemathmemory();
416 db_freemergememory();
417 db_freegeomemory();
418 db_freeerrormemory();
419 db_freetextmemory();
420 initerrorlogging(x_(""));
421 # if LANGTCL
422 db_freetclmemory();
423 # endif
424 #endif
425 }
426
stopping(INTBIG reason)427 BOOLEAN stopping(INTBIG reason)
428 {
429 extern CHAR *db_stoppingreason[];
430 static UINTBIG lastchecktime = 0;
431 REGISTER UINTBIG curtime;
432
433 if ((us_tool->toolstate&TERMNOINTERRUPT) != 0) return(FALSE);
434
435 /* only check once per second */
436 curtime = ticktime();
437 if (curtime - lastchecktime < 60) return(FALSE);
438 lastchecktime = curtime;
439
440 checkforinterrupt();
441 if (el_pleasestop == 1)
442 {
443 flushscreen();
444 ttyputmsg(_("%s stopped"), db_stoppingreason[reason]);
445 el_pleasestop = 2;
446 }
447 return(el_pleasestop != 0);
448 }
449
450 /*
451 * Routine to enable multiprocessor locks in the database (if "on" is TRUE).
452 * Call this before firing-up threads so that database calls lock critical sections
453 * properly. Turn it off when thread usage has stopped.
454 */
setmultiprocesslocks(BOOLEAN on)455 void setmultiprocesslocks(BOOLEAN on)
456 {
457 static INTBIG threadcapability = 0; /* 1: can -1: can't */
458
459 if (on)
460 {
461 if (threadcapability == 0)
462 {
463 if (graphicshas(CANDOTHREADS)) threadcapability = 1; else
464 threadcapability = -1;
465 }
466 if (threadcapability < 0) return;
467 }
468 db_multiprocessing = on;
469 }
470
471 /*
472 * Checking routine to ensure that no multiprocessor code is running.
473 * Reports an error if so (because some non-reentrant code was called).
474 */
ensurenonparallel(CHAR * file,INTBIG line)475 void ensurenonparallel(CHAR *file, INTBIG line)
476 {
477 if (db_multiprocessing)
478 {
479 ttyputerr(_("ERROR: non-reentrant code (line %ld of module %s) called by multiple processors"),
480 line, file);
481 }
482 }
483
484 /*
485 * Routine to ensure that the mutual-exclusion lock at "mutex" is properly initialized
486 * and unlocked. If "showerror" is TRUE and an error occurs, display the error.
487 * Returns TRUE on error.
488 */
ensurevalidmutex(void ** mutex,BOOLEAN showerror)489 BOOLEAN ensurevalidmutex(void **mutex, BOOLEAN showerror)
490 {
491 if (*mutex == 0)
492 {
493 *mutex = emakemutex();
494 if (*mutex == 0)
495 {
496 if (!graphicshas(CANDOTHREADS)) return(FALSE);
497 if (showerror)
498 ttyputmsg(_("Error creating mutual-exclusion lock"));
499 return(TRUE);
500 }
501 }
502 emutexunlock(*mutex);
503 return(FALSE);
504 }
505