1 /*
2 * main.c --
3 *
4 * The topmost module of the Magic VLSI tool. This module
5 * initializes the other modules and then calls the 'textio'
6 * module to read and execute commands.
7 *
8 * *********************************************************************
9 * * Copyright (C) 1985, 1990 Regents of the University of California. *
10 * * Permission to use, copy, modify, and distribute this *
11 * * software and its documentation for any purpose and without *
12 * * fee is hereby granted, provided that the above copyright *
13 * * notice appear in all copies. The University of California *
14 * * makes no representations about the suitability of this *
15 * * software for any purpose. It is provided "as is" without *
16 * * express or implied warranty. Export of this software outside *
17 * * of the United States of America may require an export license. *
18 * *********************************************************************
19 */
20
21 #ifndef lint
22 static char rcsid[] __attribute__ ((unused)) = "$Header: /usr/cvsroot/magic-8.0/utils/main.c,v 1.2 2008/02/07 17:33:19 tim Exp $";
23 #endif /* not lint */
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <sys/types.h>
30 #include <sys/times.h>
31 #include <sys/time.h>
32
33 #include "tcltk/tclmagic.h"
34 #include "utils/main.h"
35 #include "utils/magic.h"
36 #include "utils/malloc.h"
37 #include "utils/magsgtty.h"
38 #include "utils/hash.h"
39 #include "utils/macros.h"
40 #include "textio/textio.h"
41 #include "utils/geometry.h"
42 #include "textio/txcommands.h"
43 #include "tiles/tile.h"
44 #include "utils/tech.h"
45 #include "database/database.h"
46 #include "drc/drc.h"
47 #include "windows/windows.h"
48 #include "graphics/graphics.h"
49 #include "dbwind/dbwind.h"
50 #include "commands/commands.h"
51 #include "utils/signals.h"
52 #include "utils/utils.h"
53 #include "utils/runstats.h"
54 #include "cif/cif.h"
55 #ifdef ROUTE_MODULE
56 #include "router/router.h"
57 #endif
58 #ifdef LEF_MODULE
59 #include "lef/lef.h"
60 #endif
61 #include "extract/extract.h"
62 #include "utils/undo.h"
63 #include "netmenu/netmenu.h"
64 #include "plow/plow.h"
65 #include "utils/paths.h"
66 #include "wiring/wiring.h"
67 #ifdef PLOT_MODULE
68 #include "plot/plot.h"
69 #endif
70 #include "sim/sim.h"
71 #include "utils/list.h"
72 #ifdef ROUTE_MODULE
73 #include "mzrouter/mzrouter.h"
74 #endif
75 #include "lisp/lisp.h"
76 #ifdef THREE_D
77 #include "graphics/wind3d.h"
78 #endif
79
80
81 /*
82 * Global data structures
83 *
84 */
85
86 global char *Path = NULL; /* Search path */
87 global char *CellLibPath = NULL; /* Used to find cells. */
88 global char *SysLibPath = NULL; /* Used to find color maps, styles, */
89 /* technologies, etc. */
90
91 /*
92 * Flag that tells if various options have been set on the command line
93 * (see utils.h for explanation of individual flags).
94 */
95
96 global short RuntimeFlags = MAIN_MAKE_WINDOW;
97
98 /*
99 * See the file main.h for a description of the information kept
100 * pertaining to the edit cell.
101 */
102
103 global CellUse *EditCellUse = NULL;
104 global CellDef *EditRootDef = NULL;
105 global Transform EditToRootTransform;
106 global Transform RootToEditTransform;
107
108
109 /*
110 * data structures local to main.c
111 *
112 */
113
114 /* the filename specified on the command line */
115 static char *MainFileName = NULL;
116
117 /* RC file specified on the command line */
118 static char *RCFileName = NULL;
119
120 /* Definition of file types that magic can read */
121 #define FN_MAGIC_DB 0
122 #define FN_LEF_FILE 1
123 #define FN_DEF_FILE 2
124 #define FN_GDS_FILE 3
125 #define FN_CIF_FILE 4
126 #define FN_TCL_SCRIPT 5
127
128 /* List of filenames specified on the command line */
129 typedef struct filename {
130 char *fn;
131 unsigned char fn_type;
132 struct filename *fn_prev;
133 } FileName;
134 FileName *CurrentName;
135
136 /* tech name specified on the command line */
137 static char *TechDefault = NULL;
138
139 /* the filename for the graphics and mouse ports */
140 global char *MainGraphicsFile = NULL;
141 global char *MainMouseFile = NULL;
142
143 /* information about the color display. */
144 global char *MainDisplayType = NULL;
145 global char *MainMonType = NULL;
146
147
148 /* Copyright notice for the binary file. */
149 global char *MainCopyright = "\n--- MAGIC: Copyright (C) 1985, 1990 "
150 "Regents of the University of California. ---\n";
151
152 /* Forward declarations */
153 char *mainArg();
154
155
156 /*
157 * ----------------------------------------------------------------------------
158 * MainExit:
159 *
160 * Magic's own exit procedure
161 *
162 * Results:
163 * None.
164 *
165 * Side effects:
166 * We exit.
167 * ----------------------------------------------------------------------------
168 */
169
170 void
MainExit(errNum)171 MainExit(errNum)
172 int errNum;
173 {
174 #ifdef MOCHA
175 MochaExit(errNum);
176 #endif
177 if (GrClosePtr != NULL) /* We are not guarenteed that everthing will
178 * be initialized already!
179 */
180 GrClose();
181
182 DBRemoveBackup();
183
184 TxFlush();
185 TxResetTerminal();
186
187 #ifdef MAGIC_WRAPPER
188
189 // NOTE: This needs to be done in conjunction with the following
190 // commands in the console:
191 // (1) tkcon eval rename ::exit ::quit
192 // (2) tkcon eval proc::exit args {slave eval quit}
193 //
194 // The lines above redirect tkcon's "exit" routine to be named
195 // "quit" (in the console, not the slave!). Because the tkcon
196 // File->Exit callback is set to eval "exit", we then can create
197 // a new proc called "exit" in the console that runs "quit" in
198 // the slave (magic), and will therefore do the usual checks to
199 // save work before exiting; if all responses are to exit without
200 // saving, then it finally gets to here, where it runs the (renamed)
201 // "quit" command in tkcon. That will ensure that tkcon runs
202 // various cleanup activities such as saving the command-line
203 // history file before the final (!) exit.
204
205 if (TxTkConsole)
206 Tcl_Eval(magicinterp, "catch {tkcon eval quit}\n");
207 #endif
208
209 exit(errNum);
210 }
211
212 /*
213 * ----------------------------------------------------------------------------
214 *
215 * mainDoArgs:
216 *
217 * Process command line arguments
218 *
219 * Results:
220 * Return 0 on success, 1 on failure
221 *
222 * Side effects:
223 * Global variables are modified
224 *
225 * Notes:
226 * In order to work properly with the -F flag, we need to
227 * use StrDup() to make copies of any arguments we want
228 * to be visible when we restart a frozen file.
229 *
230 * ----------------------------------------------------------------------------
231 */
232
233 int
mainDoArgs(argc,argv)234 mainDoArgs(argc, argv)
235 int argc;
236 char **argv;
237 {
238 bool haveDashI = FALSE;
239 char *cp;
240
241 /* Startup filename (may be changed with the "-rcfile" option or */
242 /* the "-norcfile" option). */
243
244 RCFileName = StrDup((char **) NULL, ".magicrc");
245
246 while (--argc > 0)
247 {
248 argv++;
249 if (**argv == '-')
250 {
251 switch (argv[0][1])
252 {
253 case 'g':
254 if ((cp = mainArg(&argc, &argv, "tty name")) == NULL)
255 return 1;
256 MainGraphicsFile = StrDup((char **) NULL, cp);
257 if (!haveDashI)
258 MainMouseFile = MainGraphicsFile;
259 break;
260
261 case 'i':
262 haveDashI = TRUE;
263 if ((cp = mainArg(&argc, &argv, "tty name")) == NULL)
264 return 1;
265 MainMouseFile = StrDup((char **) NULL, cp);
266 break;
267
268 case 'd':
269 if ((cp = mainArg(&argc, &argv, "display type")) ==NULL)
270 return 1;
271 MainDisplayType = StrDup((char **) NULL, cp);
272 break;
273
274 case 'm':
275 if ((cp = mainArg(&argc, &argv, "monitor type")) ==NULL)
276 return 1;
277 MainMonType = StrDup((char **) NULL, cp);
278 break;
279
280 /*
281 * Declare the technology.
282 */
283 case 'T':
284 if ((cp = mainArg(&argc, &argv, "technology")) == NULL)
285 return 1;
286 TechDefault = StrDup((char **) NULL, cp);
287 TechOverridesDefault = TRUE;
288 break;
289
290 /*
291 * -r or -re or -recover: Recover a crash file.
292 * -rc or -rcfile: Declare a specific startup file to read.
293 */
294 case 'r':
295 if ((strlen(argv[0]) <= 2) || argv[0][2] == 'e')
296 RuntimeFlags |= MAIN_RECOVER;
297 else if ((argc > 1) && (argv[0][2] == 'c'))
298 {
299 argv[0][2] = '\0';
300 if ((cp = mainArg(&argc, &argv, "startup file")) == NULL)
301 return 1;
302 RCFileName = StrDup((char **) NULL, cp);
303 }
304 else
305 {
306 TxError("Unknown option: '%s'\n", *argv);
307 return 1;
308 }
309 break;
310
311 /*
312 * We are being debugged.
313 */
314 case 'D':
315 RuntimeFlags |= MAIN_DEBUG;
316 break;
317
318 #ifdef MAGIC_WRAPPER
319 /*
320 * "-w" for wrapper * implies -nowindow (no initial window)
321 */
322 case 'w':
323 RuntimeFlags &= ~MAIN_MAKE_WINDOW;
324 break;
325 /*
326 * No initial window / no console options / no startup file read.
327 */
328 case 'n':
329 if (strlen(argv[0]) < 4)
330 {
331 TxError("Ambiguous option %s: use -nowindow, -noconsole, "
332 "or -norcfile\n", argv[0]);
333 return 1;
334 }
335 else if (argv[0][3] == 'c')
336 RuntimeFlags &= ~MAIN_TK_CONSOLE;
337 else if (argv[0][3] == 'w')
338 RuntimeFlags &= ~MAIN_MAKE_WINDOW;
339 else if (argv[0][3] == 'r')
340 {
341 freeMagic(RCFileName);
342 RCFileName = NULL;
343 }
344 else
345 {
346 TxError("Unknown option: '%s'\n", *argv);
347 return 1;
348 }
349 break;
350 #endif
351 default:
352 TxError("Unknown option: '%s'\n", *argv);
353 TxError("Usage: magic [-g gPort] [-d devType] [-m monType] "
354 "[-i tabletPort] [-D] [-F objFile saveFile]\n"
355 "[-T technology] [-rcfile startupFile | -norcfile]"
356 #ifdef MAGIC_WRAPPER
357 "[-noconsole] [-nowindow] [-wrapper] "
358 #endif
359 "[file]\n");
360 return 1;
361 }
362 }
363 else if (MakeMainWindow)
364 {
365 if (MainFileName == NULL) {
366 MainFileName = StrDup((char **) NULL, *argv);
367 CurrentName = (FileName *) mallocMagic(sizeof(FileName));
368 CurrentName->fn = MainFileName;
369 CurrentName->fn_prev = (FileName *) NULL;
370 CurrentName->fn_type = FN_MAGIC_DB;
371 }
372 else
373 {
374 FileName *temporary;
375
376 temporary = (FileName *) mallocMagic(sizeof(FileName));
377 temporary->fn = StrDup((char **) NULL, *argv);
378 temporary->fn_prev = CurrentName;
379 temporary->fn_type = FN_MAGIC_DB;
380 CurrentName = temporary;
381 }
382
383 /* Remove suffix if the file name already has it */
384 {
385 char *c,*d;
386
387 for(c = CurrentName->fn; (*c) != '\0'; c++);
388 for(d = DBSuffix; (*d) != '\0'; d++);
389 while( (*c) == (*d) ) {
390 if (c == MainFileName) break;
391 if (d == DBSuffix) {
392 (*c) = '\0';
393 break;
394 }
395 c--;
396 d--;
397 }
398
399 // Additional checks
400 if ((c = strrchr(CurrentName->fn, '.')) != NULL)
401 {
402 #ifdef LEF_MODULE
403 if (!strcasecmp(c, ".lef"))
404 CurrentName->fn_type = FN_LEF_FILE;
405 else if (!strcasecmp(c, ".def"))
406 CurrentName->fn_type = FN_DEF_FILE;
407 #endif
408 #ifdef CIF_MODULE
409 if (!strcasecmp(c, ".cif"))
410 CurrentName->fn_type = FN_CIF_FILE;
411 else if (!strncasecmp(c, ".gds", 3))
412 CurrentName->fn_type = FN_GDS_FILE;
413 #endif
414 #ifdef MAGIC_WRAPPER
415 if (!strcasecmp(c, ".tcl"))
416 {
417 CurrentName->fn_type = FN_TCL_SCRIPT;
418 /* Behavior: If a .tcl file is passed on the
419 * command line, then all following arguments
420 * are assumed to be arguments of the script,
421 * and not to be processed as additional
422 * input file types.
423 */
424 break;
425 }
426 #endif
427 }
428 }
429 }
430 }
431
432 return 0;
433 }
434
435 /*
436 * ----------------------------------------------------------------------------
437 *
438 * mainArg --
439 *
440 * Pull off an argument from the (argc, argv) pair and also check
441 * to make sure it's not another flag (i.e, it doesn't begin with
442 * a '-').
443 *
444 * Results:
445 * Return pointer to the argument string.
446 *
447 * Side effects:
448 * See the comments in ArgStr() in the utils module -- they
449 * apply here.
450 *
451 * ----------------------------------------------------------------------------
452 */
453
454 char *
mainArg(pargc,pargv,mesg)455 mainArg(pargc, pargv, mesg)
456 int *pargc;
457 char ***pargv;
458 char *mesg;
459 {
460 char option, *cp;
461
462 option = (*pargv)[0][1];
463 cp = ArgStr(pargc, pargv, mesg);
464 if (cp == NULL)
465 return (char *) NULL;
466
467 if (*cp == '-')
468 {
469 TxError("Bad name after '-%c' option: '%s'\n", option, cp);
470 return (char *) NULL;
471 }
472 return cp;
473 }
474
475
476 /*
477 * ----------------------------------------------------------------------------
478 * mainInitBeforeArgs:
479 *
480 * Initializes things before argument processing.
481 *
482 * Results:
483 * 0 on success. As written, there are no failure modes.
484 *
485 * Side effects:
486 * All sorts of initialization. Most initialization, however, is done
487 * in 'mainInitAfterArgs'.
488 * ----------------------------------------------------------------------------
489 */
490
491 int
mainInitBeforeArgs(argc,argv)492 mainInitBeforeArgs(argc, argv)
493 int argc;
494 char *argv[];
495 {
496 TechOverridesDefault = FALSE;
497 if (Path == NULL)
498 Path = StrDup((char **) NULL, ".");
499
500 /* initialize text display */
501 TxInit();
502 TxSetTerminal();
503
504 #ifdef SCHEME_INTERPRETER
505 /* Initialize Lisp module. (rajit@cs.caltch.edu) */
506 LispInit();
507 #endif
508
509 /*
510 * Get preliminary info on the graphics display.
511 * This may be overriden later.
512 */
513 GrGuessDisplayType(&MainGraphicsFile, &MainMouseFile,
514 &MainDisplayType, &MainMonType);
515 FindDisplay((char *)NULL, "displays", CAD_LIB_PATH, &MainGraphicsFile,
516 &MainMouseFile, &MainDisplayType, &MainMonType);
517
518 return 0;
519 }
520
521
522 /*
523 * ----------------------------------------------------------------------------
524 * mainInitAfterArgs:
525 *
526 * Initializes things after argument processing.
527 *
528 * Results:
529 * Status: 0 = success, 1 = failure to set graphics display,
530 * 2 = failure to load technology file.
531 *
532 * Side effects:
533 * All sorts of initialization.
534 * ----------------------------------------------------------------------------
535 */
536
537 int
mainInitAfterArgs()538 mainInitAfterArgs()
539 {
540 int (*nullProc)() = 0;
541 SectionID sec_tech, sec_planes, sec_types, sec_aliases;
542 SectionID sec_styles;
543 SectionID sec_connect, sec_contact, sec_compose;
544 SectionID sec_cifinput, sec_cifoutput;
545 SectionID sec_drc, sec_extract, sec_wiring, sec_router;
546 SectionID sec_plow, sec_plot, sec_mzrouter;
547
548 DBTypeInit();
549 MacroInit();
550
551 #ifdef LEF_MODULE
552 /* Pre-techfile-loading intialization of the LEF module */
553 LefInit();
554 #endif
555
556 #ifdef OPENACCESS
557 OAInit();
558 #endif
559
560 /*
561 * Setup path names for system directory searches
562 */
563
564 StrDup(&SysLibPath, MAGIC_SYS_PATH);
565
566 /*
567 * Historic behavior: Expect to search for cells in a directory
568 * inside the install area with the same name as the technology.
569 * Deprecated but kept for backwards compatibility. If directory
570 * does not exist, it will be ignored.
571 */
572
573 if (TechFileName != NULL)
574 {
575 CellLibPath = (char *)mallocMagic(strlen(MAGIC_LIB_PATH_FORMAT)
576 + strlen(TechFileName) - 1);
577 sprintf(CellLibPath, MAGIC_LIB_PATH_FORMAT, TechFileName);
578 PaAppend(&CellLibPath, MAGIC_LIB_PATH_DEFAULT);
579 }
580 else if ((TechDefault != NULL) && TechOverridesDefault)
581 {
582 CellLibPath = (char *)mallocMagic(strlen(MAGIC_LIB_PATH_FORMAT)
583 + strlen(TechDefault) - 1);
584 sprintf(CellLibPath, MAGIC_LIB_PATH_FORMAT, TechDefault);
585 PaAppend(&CellLibPath, MAGIC_LIB_PATH_DEFAULT);
586 }
587 else
588 StrDup(&CellLibPath, MAGIC_LIB_PATH_DEFAULT);
589
590 if (MainGraphicsFile == NULL) MainGraphicsFile = "/dev/null";
591 if (MainMouseFile == NULL) MainMouseFile = MainGraphicsFile;
592
593 #ifdef MAGIC_WRAPPER
594 /* Check for batch mode operation and disable interrupts in */
595 /* batch mode by not calling SigInit(). */
596 if (Tcl_GetVar(magicinterp, "batch_mode", TCL_GLOBAL_ONLY) != NULL)
597 SigInit(1);
598 else
599 #endif
600
601 /* catch signals, must come after mainDoArgs & before SigWatchFile */
602 SigInit(0);
603
604 /* set up graphics */
605 if ( !GrSetDisplay(MainDisplayType, MainGraphicsFile, MainMouseFile) )
606 {
607 return 1;
608 }
609
610 /* initialize technology */
611 TechInit();
612 TechAddClient("tech", DBTechInit, DBTechSetTech, nullProc,
613 (SectionID) 0, &sec_tech, FALSE);
614 TechAddClient("version", DBTechInitVersion, DBTechSetVersion, nullProc,
615 (SectionID) 0, (int *)0, TRUE);
616 TechAddClient("planes", DBTechInitPlane, DBTechAddPlane, nullProc,
617 (SectionID) 0, &sec_planes, FALSE);
618 TechAddClient("types", DBTechInitType, DBTechAddType, DBTechFinalType,
619 sec_planes, &sec_types, FALSE);
620
621 TechAddClient("styles", nullProc, DBWTechAddStyle, nullProc,
622 sec_types, &sec_styles, FALSE);
623
624 TechAddClient("contact", DBTechInitContact,
625 DBTechAddContact, DBTechFinalContact,
626 sec_types|sec_planes, &sec_contact, FALSE);
627
628 TechAddAlias("contact", "images");
629 TechAddClient("aliases", nullProc, DBTechAddAlias, nullProc,
630 sec_planes|sec_types|sec_contact, &sec_aliases, TRUE);
631
632 TechAddClient("compose", DBTechInitCompose,
633 DBTechAddCompose, DBTechFinalCompose,
634 sec_types|sec_planes|sec_contact, &sec_compose, FALSE);
635
636 TechAddClient("connect", DBTechInitConnect,
637 DBTechAddConnect, DBTechFinalConnect,
638 sec_types|sec_planes|sec_contact, &sec_connect, FALSE);
639
640 #ifdef CIF_MODULE
641 TechAddClient("cifoutput", CIFTechStyleInit, CIFTechLine, CIFTechFinal,
642 (SectionID) 0, &sec_cifoutput, FALSE);
643
644 TechAddClient("cifinput", CIFReadTechStyleInit, CIFReadTechLine,
645 CIFReadTechFinal, (SectionID) 0, &sec_cifinput, FALSE);
646 #else
647 TechAddClient("cifoutput", nullProc,nullProc,nullProc,
648 (SectionID) 0, &sec_cifoutput, FALSE);
649
650 TechAddClient("cifinput", nullProc,nullProc,nullProc,
651 (SectionID) 0, &sec_cifinput, FALSE);
652 #endif
653 #ifdef ROUTE_MODULE
654 TechAddClient("mzrouter", MZTechInit, MZTechLine, MZTechFinal,
655 sec_types|sec_planes, &sec_mzrouter, TRUE);
656 #else
657 TechAddClient("mzrouter", nullProc,nullProc,nullProc,
658 sec_types|sec_planes, &sec_mzrouter, TRUE);
659 #endif
660 TechAddClient("drc", DRCTechStyleInit, DRCTechLine, DRCTechFinal,
661 sec_types|sec_planes, &sec_drc, FALSE);
662 /* Plow rules are generated from the same lines as the DRC rules */
663 TechAddClient("drc", PlowDRCInit, PlowDRCLine, PlowDRCFinal,
664 sec_types|sec_planes, &sec_drc, FALSE);
665
666 #ifdef LEF_MODULE
667 TechAddClient("lef", LefTechInit, LefTechLine, nullProc,
668 sec_types|sec_planes, (SectionID *) 0, TRUE);
669 #endif
670
671 #ifdef NO_EXT
672 TechAddClient("extract", nullProc, nullProc,nullProc,
673 sec_types|sec_connect, &sec_extract, FALSE);
674 #else
675 TechAddClient("extract", nullProc, ExtTechLine, ExtTechFinal,
676 sec_types|sec_connect, &sec_extract, FALSE);
677 #endif
678
679 TechAddClient("wiring", WireTechInit, WireTechLine, WireTechFinal,
680 sec_types, &sec_wiring, TRUE);
681
682 #ifdef ROUTE_MODULE
683 TechAddClient("router", RtrTechInit, RtrTechLine, RtrTechFinal,
684 sec_types, &sec_router, TRUE);
685 #else
686 TechAddClient("router", nullProc,nullProc,nullProc,
687 sec_types, &sec_router, TRUE);
688 #endif
689 TechAddClient("plowing", PlowTechInit, PlowTechLine, PlowTechFinal,
690 sec_types|sec_connect|sec_contact, &sec_plow, TRUE);
691 #ifdef PLOT_MODULE
692 TechAddClient("plot", PlotTechInit, PlotTechLine, PlotTechFinal,
693 sec_types, &sec_plot, TRUE);
694 #else
695 TechAddClient("plot", nullProc,nullProc,nullProc,
696 sec_types, &sec_plot, TRUE);
697 #endif
698
699 /* Load minimum technology file needed to keep things from */
700 /* crashing during initialization. */
701
702 if (!TechLoad("minimum", 0))
703 {
704 TxError("Cannot load technology \"minimum\" for initialization\n");
705 return 2;
706 }
707
708 /* The minimum tech has been loaded only to keep the database from */
709 /* becoming corrupted during initialization. Free the tech file */
710 /* name so that a "real" technology file can be forced to replace */
711 /* it in mainInitFinal(). */
712
713 if (TechFileName != NULL)
714 {
715 freeMagic(TechFileName);
716 TechFileName = NULL;
717 }
718
719 /* initialize the undo package */
720 (void) UndoInit((char *) NULL, (char *) NULL);
721
722 /* initialize windows */
723 WindInit();
724
725 /* initialize commands */
726 CmdInit();
727
728 /* Initialize the interface between windows and its clients */
729 DBWinit();
730 #ifdef USE_READLINE
731 TxInitReadline();
732 #endif
733 CMWinit();
734 #ifdef THREE_D
735 W3Dinit();
736 #endif
737
738 /* Initialize the circuit extractor */
739 #ifndef NO_EXT
740 ExtInit();
741 #endif
742
743 /* Initialize plowing */
744 PlowInit();
745
746 /* Initialize selection */
747 SelectInit();
748
749 /* Initialize the wiring module */
750 WireInit();
751
752 #ifdef ROUTE_MODULE
753 /* Initialize the netlist menu */
754 NMinit();
755 #endif
756
757 /* Initialize the design-rule checker */
758 DRCInit();
759
760 /* Initialize the maze router */
761 #ifdef ROUTE_MODULE
762 MZInit();
763
764 /* Initialize the interactive router -
765 * NOTE the mzrouter must be initialized prior to the irouter
766 * so that default parameters will be completely setup
767 */
768 IRDebugInit();
769 IRAfterTech();
770 #endif
771
772 /* Initialize the Sim Module (the part of it which involves (i)rsim) */
773 #if !defined(NO_SIM_MODULE) && defined(RSIM_MODULE)
774 SimInit();
775 #endif
776
777 TxSetPoint(GR_CURSOR_X, GR_CURSOR_Y, WIND_UNKNOWN_WINDOW);
778
779 return 0;
780 }
781
tcl_exit_hook(ClientData clientData)782 void tcl_exit_hook(ClientData clientData)
783 {
784 TxResetTerminal();
785 exit(0);
786 }
787
788 /*
789 * ----------------------------------------------------------------------------
790 * mainInitFinal:
791 *
792 * Final initialization; reads startup files and any initial file
793 * specified.
794 *
795 * Results:
796 * Return 0 on success. As written, there is no failure mode.
797 *
798 * Side effects:
799 * All sorts of initialization.
800 * ----------------------------------------------------------------------------
801 */
802
803 int
mainInitFinal()804 mainInitFinal()
805 {
806 char *home, cwd[512];
807 char startupFileName[256];
808 FILE *f;
809 char *rname;
810 int result;
811
812 /* Reset terminal if exit is called inside a TCL script */
813 Tcl_SetExitProc(tcl_exit_hook);
814
815 #ifdef MAGIC_WRAPPER
816
817 /* Read in system pre-startup file, if it exists. */
818
819 /* Use PaOpen first to perform variable substitutions, and */
820 /* return the actual filename in rname. */
821
822 f = PaOpen(MAGIC_PRE_DOT, "r", (char *) NULL, ".",
823 (char *) NULL, (char **) &rname);
824 if (f != NULL)
825 {
826 fclose(f);
827 result = Tcl_EvalFile(magicinterp, rname);
828 if (result != TCL_OK)
829 {
830 TxError("Error parsing pre-startup file \"%s\": %s\n", rname,
831 Tcl_GetStringResult(magicinterp));
832 Tcl_ResetResult(magicinterp);
833 }
834 }
835 #endif /* MAGIC_WRAPPER */
836
837 // Make a first attempt to load the technology if specified on the
838 // command line with the -T option. This will preempt most other
839 // ways that the technology file is determined. If the technology
840 // specified cannot be loaded, then the forced override is revoked.
841
842 if ((TechFileName == NULL) && (TechDefault != NULL) && TechOverridesDefault)
843 {
844 if (!TechLoad(TechDefault, -2))
845 {
846 TxError("Failed to load technology \"%s\"\n", TechDefault);
847 TechOverridesDefault = FALSE;
848 }
849 else if (!TechLoad(TechDefault, 0))
850 {
851 TxError("Error loading technology \"%s\"\n", TechDefault);
852 TechOverridesDefault = FALSE;
853 }
854 }
855
856 #ifndef MAGIC_WRAPPER
857
858 // Let the wrapper script be responsible for formatting and
859 // printing the technology file informaiton.
860
861 if (DBTechName != 0) {
862 TxPrintf("Using technology \"%s\"", DBTechName);
863 if (DBTechVersion != 0) TxPrintf(", version %s.", DBTechVersion);
864 TxPrintf("\n");
865 }
866 if (DBTechDescription != 0) TxPrintf("%s\n", DBTechDescription);
867 #endif
868
869 #ifdef MAGIC_WRAPPER
870 /* Read in system startup file, if it exists. */
871
872 /* Use PaOpen first to perform variable substitutions, and */
873 /* return the actual filename in rname. */
874
875 f = PaOpen(MAGIC_SYS_DOT, "r", (char *) NULL, ".",
876 (char *) NULL, (char **) &rname);
877 if (f != NULL)
878 {
879 fclose(f);
880 result = Tcl_EvalFile(magicinterp, rname);
881 if (result != TCL_OK)
882 {
883 TxError("Error parsing system startup file \"%s\": %s\n", rname,
884 Tcl_GetStringResult(magicinterp));
885 Tcl_ResetResult(magicinterp);
886 }
887 }
888
889 #else /* !MAGIC_WRAPPER */
890
891 f = PaOpen(MAGIC_SYS_DOT, "r", (char *) NULL, ".",
892 (char *) NULL, (char **) NULL);
893 if (f != NULL)
894 {
895 TxDispatch(f);
896 (void) fclose(f);
897 }
898
899 #endif /* !MAGIC_WRAPPER */
900
901 /*
902 * Strive for a wee bit more parallelism; let the graphics
903 * display run while we're reading in startup files & initial cell.
904 */
905
906 GrFlush();
907
908 /* Ignore this whole section if we have received the -norc option */
909 if (RCFileName != NULL)
910 {
911
912 /* Read in user's startup files, if there are any. */
913 /* If the "-rcfile" option has been used, and it doesn't specify */
914 /* a full path, then look for this file in the home directory too. */
915
916 home = getenv("HOME");
917
918 #ifdef MAGIC_WRAPPER
919
920 if (home != NULL && (RCFileName[0] != '/'))
921 {
922 Tcl_Channel fc;
923
924 (void) sprintf(startupFileName, "%s/%s", home, RCFileName);
925
926 fc = Tcl_OpenFileChannel(magicinterp, startupFileName, "r", 0);
927 if (fc != NULL)
928 {
929 Tcl_Close(magicinterp, fc);
930 result = Tcl_EvalFile(magicinterp, startupFileName);
931 if (result != TCL_OK)
932 {
933 TxError("Error parsing user \"%s\": %s\n", RCFileName,
934 Tcl_GetStringResult(magicinterp));
935 Tcl_ResetResult(magicinterp);
936 }
937 }
938 else
939 {
940 /* Try the (deprecated) name ".magic" */
941 (void) sprintf(startupFileName, "%s/.magic", home);
942 fc = Tcl_OpenFileChannel(magicinterp, startupFileName, "r", 0);
943 if (fc != NULL)
944 {
945 TxPrintf("Note: Use of the file name \"~/.magic\" is deprecated."
946 " Please change this to \"~/.magicrc\".\n");
947
948 Tcl_Close(magicinterp, fc);
949 result = Tcl_EvalFile(magicinterp, startupFileName);
950
951 if (result != TCL_OK)
952 {
953 TxError("Error parsing user \".magic\": %s\n",
954 Tcl_GetStringResult(magicinterp));
955 Tcl_ResetResult(magicinterp);
956 }
957 }
958 }
959 }
960
961 if (getcwd(cwd, 512) == NULL || strcmp(cwd, home) || (RCFileName[0] == '/'))
962 {
963 /* Read in the .magicrc file from the current directory, if */
964 /* different from HOME. */
965
966 Tcl_Channel fc;
967
968 fc = Tcl_OpenFileChannel(magicinterp, RCFileName, "r", 0);
969 if (fc != NULL)
970 {
971 Tcl_Close(magicinterp, fc);
972 result = Tcl_EvalFile(magicinterp, RCFileName);
973
974 if (result != TCL_OK)
975 {
976 // Print error message but continue anyway
977
978 TxError("Error parsing \"%s\": %s\n", RCFileName,
979 Tcl_GetStringResult(magicinterp));
980 Tcl_ResetResult(magicinterp);
981 TxPrintf("Bad local startup file \"%s\", continuing without.\n",
982 RCFileName);
983 }
984 }
985 else
986 {
987 /* Try the (deprecated) name ".magic" */
988
989 Tcl_ResetResult(magicinterp);
990 fc = Tcl_OpenFileChannel(magicinterp, ".magic", "r", 0);
991 if (fc != NULL)
992 {
993 Tcl_Close(magicinterp, fc);
994
995 TxPrintf("Note: Use of the file name \".magic\" is deprecated."
996 " Please change this to \".magicrc\".\n");
997
998 result = Tcl_EvalFile(magicinterp, ".magic");
999
1000 if (result != TCL_OK)
1001 {
1002 // Print error message but continue anyway
1003
1004 TxError("Error parsing local \".magic\": %s\n",
1005 Tcl_GetStringResult(magicinterp));
1006 Tcl_ResetResult(magicinterp);
1007 TxPrintf("Bad local startup file \".magic\","
1008 " continuing without.\n");
1009 }
1010 }
1011 else
1012 {
1013 /* Try the alternative name "magic_setup" */
1014
1015 Tcl_ResetResult(magicinterp);
1016
1017 fc = Tcl_OpenFileChannel(magicinterp, "magic_setup", "r", 0);
1018 if (fc != NULL)
1019 {
1020 Tcl_Close(magicinterp, fc);
1021
1022 result = Tcl_EvalFile(magicinterp, "magic_setup");
1023 if (result != TCL_OK)
1024 {
1025 TxError("Error parsing local \"magic_setup\": %s\n",
1026 Tcl_GetStringResult(magicinterp));
1027 TxError("%s\n", Tcl_GetStringResult(magicinterp));
1028 Tcl_ResetResult(magicinterp); // Still not an error
1029 TxPrintf("Bad local startup file \"magic_setup\","
1030 " continuing without.\n");
1031 }
1032 }
1033 }
1034 }
1035 }
1036
1037 #else /* !MAGIC_WRAPPER */
1038
1039 if (home != NULL && (RCFileName[0] != '/'))
1040 {
1041 (void) sprintf(startupFileName, "%s/%s", home, RCFileName);
1042
1043
1044 f = PaOpen(startupFileName, "r", (char *) NULL, ".",
1045 (char *) NULL, (char **) NULL);
1046
1047 if ((f == NULL) && (!strcmp(RCFileName, ".magicrc")))
1048 {
1049 /* Try the (deprecated) name ".magic" */
1050 (void) sprintf(startupFileName, "%s/.magic", home);
1051 f = PaOpen(startupFileName, "r", (char *) NULL, ".",
1052 (char *) NULL, (char **) NULL);
1053 if (f != NULL)
1054 TxPrintf("Note: Use of the file name \"~/.magic\" is deprecated."
1055 " Please change this to \"~/.magicrc\".\n");
1056 }
1057
1058 if (f != NULL)
1059 {
1060 TxDispatch(f);
1061 (void) fclose(f);
1062 }
1063 }
1064
1065 /* Read in any startup file in the current directory, or one that was */
1066 /* specified on the commandline by the "-rcfile <name>" option. */
1067
1068 f = PaOpen(RCFileName, "r", (char *) NULL, ".",
1069 (char *) NULL, (char **) NULL);
1070
1071 /* Again, check for the deprecated name ".magic" */
1072 if (f == NULL)
1073 {
1074 if (!strcmp(RCFileName, ".magicrc"))
1075 {
1076 f = PaOpen(".magic", "r", (char *) NULL, ".",
1077 (char *) NULL, (char **) NULL);
1078 if (f != NULL)
1079 TxPrintf("Note: Use of the file name \"./.magic\" is deprecated."
1080 " Please change this to \"./.magicrc\".\n");
1081
1082 else
1083 f = PaOpen("magic_setup", "r", (char *) NULL, ".",
1084 (char *) NULL, (char **) NULL);
1085 }
1086 else
1087 TxError("Startup file \"%s\" not found or unreadable!\n", RCFileName);
1088 }
1089
1090 if (f != NULL)
1091 {
1092 TxDispatch(f);
1093 fclose(f);
1094 }
1095
1096 #endif /* !MAGIC_WRAPPER */
1097
1098 }
1099
1100 /* We are done forcing the "tech load" command to be ignored */
1101 TechOverridesDefault = FALSE;
1102
1103 /* If no technology has been specified yet, try to read one from
1104 * the initial cell, or else assign a default.
1105 */
1106
1107 if ((TechFileName == NULL) && (TechDefault == NULL) && (MainFileName != NULL))
1108 StrDup(&TechDefault, DBGetTech(MainFileName));
1109
1110 /* Load the technology file. If any startup file loaded a */
1111 /* technology file, then "TechFileName" will be set, and we */
1112 /* should not override it. */
1113
1114 if ((TechFileName == NULL) && (TechDefault != NULL))
1115 {
1116 if (!TechLoad(TechDefault, -2))
1117 TxError("Failed to load technology \"%s\"\n", TechDefault);
1118 else if (!TechLoad(TechDefault, 0))
1119 TxError("Error loading technology \"%s\"\n", TechDefault);
1120 }
1121
1122 if (TechDefault != NULL)
1123 {
1124 freeMagic(TechDefault);
1125 TechDefault = NULL;
1126 }
1127
1128 /* If that failed, then load the "minimum" technology again and */
1129 /* keep it. It's not very useful, but it will keep everything */
1130 /* up and running. In the worst case, if site.pre has removed the */
1131 /* standard locations from the system path, then magic will exit. */
1132
1133 if (TechFileName == NULL)
1134 if (!TechLoad("minimum", 0))
1135 return -1;
1136
1137 #ifdef SCHEME_INTERPRETER
1138 /* Pass technology name to Lisp interpreter (rajit@cs.caltech.edu) */
1139 LispSetTech (TechFileName);
1140 #endif
1141
1142 /*
1143 * Recover crash files from the temp directory if we have specified
1144 * the -r option on the command line (non-tcl version. Tcl version
1145 * uses the command-line command crashrecover.
1146 */
1147
1148 if (mainRecover && MakeMainWindow)
1149 {
1150 DBFileRecovery();
1151 }
1152
1153 /*
1154 * Bring in a new cell or cells to start up if one was given
1155 * on the command line
1156 */
1157
1158 else if (MainFileName && MakeMainWindow)
1159 {
1160 FileName *temporary;
1161
1162 while(CurrentName != NULL)
1163 {
1164 temporary = CurrentName;
1165 CurrentName = temporary->fn_prev;
1166 TxPrintf("Loading \"%s\" from command line.\n", temporary->fn);
1167 switch (temporary->fn_type)
1168 {
1169 case FN_MAGIC_DB:
1170 DBWreload(temporary->fn);
1171 break;
1172 #ifdef LEF_MODULE
1173 case FN_LEF_FILE:
1174 LefRead(temporary->fn, FALSE, FALSE);
1175 break;
1176 case FN_DEF_FILE:
1177 DefRead(temporary->fn, FALSE);
1178 break;
1179 #endif
1180 #ifdef MAGIC_WRAPPER
1181 case FN_TCL_SCRIPT:
1182 result = Tcl_EvalFile(magicinterp, temporary->fn);
1183 if (result != TCL_OK)
1184 {
1185 TxError("Error parsing \"%s\": %s\n",
1186 temporary->fn,
1187 Tcl_GetStringResult(magicinterp));
1188 Tcl_ResetResult(magicinterp);
1189 }
1190 break;
1191 #endif
1192 }
1193 freeMagic(temporary);
1194 }
1195 }
1196
1197 /* Create an initial box. */
1198
1199 if (MakeMainWindow && EditCellUse)
1200 DBWSetBox(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox);
1201
1202 /* Set the initial fence for undo-ing: don't want to be able to
1203 * undo past this point.
1204 */
1205 UndoFlush();
1206 TxClearPoint();
1207
1208 Tcl_SetExitProc(NULL);
1209
1210 return 0;
1211 }
1212
1213
1214 /*
1215 * ----------------------------------------------------------------------------
1216 * mainFinish:
1217 *
1218 * Finish up things for Magic. This routine is NOT called on an
1219 * error exit.
1220 *
1221 * Results:
1222 * None.
1223 *
1224 * Side effects:
1225 * Various things, such as stopping measurement gathering.
1226 * ----------------------------------------------------------------------------
1227 */
1228
1229 void
mainFinished()1230 mainFinished()
1231 {
1232 /* Close up things */
1233 MainExit(0);
1234 }
1235
1236 /*---------------------------------------------------------------------------
1237 * magicMain:
1238 *
1239 * Top-level procedure of the Magic Layout System. There is purposely
1240 * not much in here so that we have more flexibility. Also, it is
1241 * not called 'main' so that other programs that use Magic may do
1242 * something else.
1243 *
1244 * Results:
1245 * None.
1246 *
1247 * Side Effects:
1248 * None.
1249 *
1250 * Note: Try not to add code to this procedure. Add it instead to one of the
1251 * procedures that it calls.
1252 *
1253 *----------------------------------------------------------------------------
1254 */
1255
1256 void
magicMain(argc,argv)1257 magicMain(argc, argv)
1258 int argc;
1259 char *argv[];
1260 {
1261 int rstatus;
1262
1263 if ((rstatus = mainInitBeforeArgs(argc, argv)) != 0) MainExit(rstatus);
1264 if ((rstatus = mainDoArgs(argc, argv)) != 0) MainExit(rstatus);
1265 if ((rstatus = mainInitAfterArgs()) != 0) MainExit(rstatus);
1266 if ((rstatus = mainInitFinal()) != 0) MainExit(rstatus);
1267 TxDispatch( (FILE *) NULL);
1268 mainFinished();
1269 }
1270
1271
1272
1273