1300 lines
33 KiB
C
1300 lines
33 KiB
C
/*
|
|
* main.c --
|
|
*
|
|
* The topmost module of the Magic VLSI tool. This module
|
|
* initializes the other modules and then calls the 'textio'
|
|
* module to read and execute commands.
|
|
*
|
|
* *********************************************************************
|
|
* * Copyright (C) 1985, 1990 Regents of the University of California. *
|
|
* * Permission to use, copy, modify, and distribute this *
|
|
* * software and its documentation for any purpose and without *
|
|
* * fee is hereby granted, provided that the above copyright *
|
|
* * notice appear in all copies. The University of California *
|
|
* * makes no representations about the suitability of this *
|
|
* * software for any purpose. It is provided "as is" without *
|
|
* * express or implied warranty. Export of this software outside *
|
|
* * of the United States of America may require an export license. *
|
|
* *********************************************************************
|
|
*/
|
|
|
|
#ifndef lint
|
|
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 $";
|
|
#endif /* not lint */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/times.h>
|
|
#ifdef HAVE_SYS_TIME_H
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
#include "tcltk/tclmagic.h"
|
|
#include "utils/main.h"
|
|
#include "utils/magic.h"
|
|
#include "utils/malloc.h"
|
|
#include "utils/magsgtty.h"
|
|
#include "utils/hash.h"
|
|
#include "utils/macros.h"
|
|
#include "textio/textio.h"
|
|
#include "utils/geometry.h"
|
|
#include "textio/txcommands.h"
|
|
#include "tiles/tile.h"
|
|
#include "utils/tech.h"
|
|
#include "database/database.h"
|
|
#include "drc/drc.h"
|
|
#include "windows/windows.h"
|
|
#include "graphics/graphics.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "commands/commands.h"
|
|
#include "utils/signals.h"
|
|
#include "utils/utils.h"
|
|
#include "utils/runstats.h"
|
|
#include "cif/cif.h"
|
|
#ifdef ROUTE_MODULE
|
|
#include "router/router.h"
|
|
#endif
|
|
#ifdef LEF_MODULE
|
|
#include "lef/lef.h"
|
|
#endif
|
|
#include "extract/extract.h"
|
|
#include "utils/undo.h"
|
|
#include "netmenu/netmenu.h"
|
|
#include "plow/plow.h"
|
|
#include "utils/paths.h"
|
|
#include "wiring/wiring.h"
|
|
#ifdef PLOT_MODULE
|
|
#include "plot/plot.h"
|
|
#endif
|
|
#include "sim/sim.h"
|
|
#include "utils/list.h"
|
|
#ifdef ROUTE_MODULE
|
|
#include "mzrouter/mzrouter.h"
|
|
#endif
|
|
#ifdef SCHEME_INTERPRETER
|
|
#include "lisp/lisp.h"
|
|
#endif
|
|
#ifdef THREE_D
|
|
#include "graphics/wind3d.h"
|
|
#endif
|
|
|
|
/* C99 compat */
|
|
#include "utils/utils.h"
|
|
#include "utils/tech.h"
|
|
#include "commands/commands.h"
|
|
#include "dbwind/dbwind.h"
|
|
#include "cmwind/cmwind.h"
|
|
#include "extract/extract.h"
|
|
#include "plow/plow.h"
|
|
#include "select/select.h"
|
|
#include "irouter/irouter.h"
|
|
#include "lef/lefInt.h"
|
|
|
|
|
|
/*
|
|
* Global data structures
|
|
*
|
|
*/
|
|
|
|
global char *Path = NULL; /* Search path */
|
|
global char *CellLibPath = NULL; /* Used to find cells. */
|
|
global char *SysLibPath = NULL; /* Used to find color maps, styles, */
|
|
/* technologies, etc. */
|
|
|
|
/*
|
|
* Flag that tells if various options have been set on the command line
|
|
* (see utils.h for explanation of individual flags).
|
|
*/
|
|
|
|
global short RuntimeFlags = MAIN_MAKE_WINDOW;
|
|
|
|
/*
|
|
* See the file main.h for a description of the information kept
|
|
* pertaining to the edit cell.
|
|
*/
|
|
|
|
global CellUse *EditCellUse = NULL;
|
|
global CellDef *EditRootDef = NULL;
|
|
global Transform EditToRootTransform;
|
|
global Transform RootToEditTransform;
|
|
|
|
|
|
/*
|
|
* data structures local to main.c
|
|
*
|
|
*/
|
|
|
|
/* the filename specified on the command line */
|
|
static char *MainFileName = NULL;
|
|
|
|
/* RC file specified on the command line */
|
|
static char *RCFileName = NULL;
|
|
|
|
/* Definition of file types that magic can read */
|
|
#define FN_MAGIC_DB 0
|
|
#define FN_LEF_FILE 1
|
|
#define FN_DEF_FILE 2
|
|
#define FN_GDS_FILE 3
|
|
#define FN_CIF_FILE 4
|
|
#define FN_TCL_SCRIPT 5
|
|
|
|
/* List of filenames specified on the command line */
|
|
typedef struct filename {
|
|
char *fn;
|
|
unsigned char fn_type;
|
|
struct filename *fn_prev;
|
|
} FileName;
|
|
FileName *CurrentName;
|
|
|
|
/* tech name specified on the command line */
|
|
static char *TechDefault = NULL;
|
|
|
|
/* the filename for the graphics and mouse ports */
|
|
global char *MainGraphicsFile = NULL;
|
|
global char *MainMouseFile = NULL;
|
|
|
|
/* information about the color display. */
|
|
global char *MainDisplayType = NULL;
|
|
global char *MainMonType = NULL;
|
|
|
|
|
|
/* Copyright notice for the binary file. */
|
|
global char *MainCopyright = "\n--- MAGIC: Copyright (C) 1985, 1990 "
|
|
"Regents of the University of California. ---\n";
|
|
|
|
/* Forward declarations */
|
|
char *mainArg();
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* MainExit:
|
|
*
|
|
* Magic's own exit procedure
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* We exit.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
MainExit(errNum)
|
|
int errNum;
|
|
{
|
|
#ifdef MOCHA
|
|
MochaExit(errNum);
|
|
#endif
|
|
if (GrClosePtr != NULL) /* We are not guarenteed that everthing will
|
|
* be initialized already!
|
|
*/
|
|
GrClose();
|
|
|
|
DBRemoveBackup();
|
|
|
|
TxFlush();
|
|
TxResetTerminal(FALSE); /* set also atexit() handler */
|
|
|
|
#ifdef MAGIC_WRAPPER
|
|
|
|
// NOTE: This needs to be done in conjunction with the following
|
|
// commands in the console:
|
|
// (1) tkcon eval rename ::exit ::quit
|
|
// (2) tkcon eval proc::exit args {slave eval quit}
|
|
//
|
|
// The lines above redirect tkcon's "exit" routine to be named
|
|
// "quit" (in the console, not the slave!). Because the tkcon
|
|
// File->Exit callback is set to eval "exit", we then can create
|
|
// a new proc called "exit" in the console that runs "quit" in
|
|
// the slave (magic), and will therefore do the usual checks to
|
|
// save work before exiting; if all responses are to exit without
|
|
// saving, then it finally gets to here, where it runs the (renamed)
|
|
// "quit" command in tkcon. That will ensure that tkcon runs
|
|
// various cleanup activities such as saving the command-line
|
|
// history file before the final (!) exit.
|
|
|
|
if (TxTkConsole)
|
|
Tcl_Eval(magicinterp, "catch {tkcon eval quit}\n");
|
|
#endif
|
|
|
|
exit(errNum);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mainDoArgs:
|
|
*
|
|
* Process command line arguments
|
|
*
|
|
* Results:
|
|
* Return 0 on success, 1 on failure
|
|
*
|
|
* Side effects:
|
|
* Global variables are modified
|
|
*
|
|
* Notes:
|
|
* In order to work properly with the -F flag, we need to
|
|
* use StrDup() to make copies of any arguments we want
|
|
* to be visible when we restart a frozen file.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mainDoArgs(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
bool haveDashI = FALSE;
|
|
char *cp;
|
|
|
|
/* Startup filename (may be changed with the "-rcfile" option or */
|
|
/* the "-norcfile" option). */
|
|
|
|
RCFileName = StrDup((char **) NULL, ".magicrc");
|
|
|
|
while (--argc > 0)
|
|
{
|
|
argv++;
|
|
if (**argv == '-')
|
|
{
|
|
switch (argv[0][1])
|
|
{
|
|
case 'g':
|
|
if ((cp = mainArg(&argc, &argv, "tty name")) == NULL)
|
|
return 1;
|
|
MainGraphicsFile = StrDup((char **) NULL, cp);
|
|
if (!haveDashI)
|
|
MainMouseFile = MainGraphicsFile;
|
|
break;
|
|
|
|
case 'i':
|
|
haveDashI = TRUE;
|
|
if ((cp = mainArg(&argc, &argv, "tty name")) == NULL)
|
|
return 1;
|
|
MainMouseFile = StrDup((char **) NULL, cp);
|
|
break;
|
|
|
|
case 'd':
|
|
if ((cp = mainArg(&argc, &argv, "display type")) ==NULL)
|
|
return 1;
|
|
MainDisplayType = StrDup((char **) NULL, cp);
|
|
break;
|
|
|
|
case 'm':
|
|
if ((cp = mainArg(&argc, &argv, "monitor type")) ==NULL)
|
|
return 1;
|
|
MainMonType = StrDup((char **) NULL, cp);
|
|
break;
|
|
|
|
/*
|
|
* Declare the technology.
|
|
*/
|
|
case 'T':
|
|
if ((cp = mainArg(&argc, &argv, "technology")) == NULL)
|
|
return 1;
|
|
TechDefault = StrDup((char **) NULL, cp);
|
|
TechOverridesDefault = TRUE;
|
|
break;
|
|
|
|
/*
|
|
* -r or -re or -recover: Recover a crash file.
|
|
* -rc or -rcfile: Declare a specific startup file to read.
|
|
*/
|
|
case 'r':
|
|
if ((strlen(argv[0]) <= 2) || argv[0][2] == 'e')
|
|
RuntimeFlags |= MAIN_RECOVER;
|
|
else if ((argc > 1) && (argv[0][2] == 'c'))
|
|
{
|
|
argv[0][2] = '\0';
|
|
if ((cp = mainArg(&argc, &argv, "startup file")) == NULL)
|
|
return 1;
|
|
RCFileName = StrDup((char **) NULL, cp);
|
|
}
|
|
else
|
|
{
|
|
TxError("Unknown option: '%s'\n", *argv);
|
|
return 1;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* We are being debugged.
|
|
*/
|
|
case 'D':
|
|
RuntimeFlags |= MAIN_DEBUG;
|
|
break;
|
|
|
|
#ifdef MAGIC_WRAPPER
|
|
/*
|
|
* "-w" for wrapper * implies -nowindow (no initial window)
|
|
*/
|
|
case 'w':
|
|
RuntimeFlags &= ~MAIN_MAKE_WINDOW;
|
|
break;
|
|
/*
|
|
* No initial window / no console options / no startup file read.
|
|
*/
|
|
case 'n':
|
|
if (strlen(argv[0]) < 4)
|
|
{
|
|
TxError("Ambiguous option %s: use -nowindow, -noconsole, "
|
|
"or -norcfile\n", argv[0]);
|
|
return 1;
|
|
}
|
|
else if (argv[0][3] == 'c')
|
|
RuntimeFlags &= ~MAIN_TK_CONSOLE;
|
|
else if (argv[0][3] == 'w')
|
|
RuntimeFlags &= ~MAIN_MAKE_WINDOW;
|
|
else if (argv[0][3] == 'r')
|
|
{
|
|
freeMagic(RCFileName);
|
|
RCFileName = NULL;
|
|
}
|
|
else
|
|
{
|
|
TxError("Unknown option: '%s'\n", *argv);
|
|
return 1;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
TxError("Unknown option: '%s'\n", *argv);
|
|
TxError("Usage: magic [-g gPort] [-d devType] [-m monType] "
|
|
"[-i tabletPort] [-D] [-F objFile saveFile]\n"
|
|
"[-T technology] [-rcfile startupFile | -norcfile]"
|
|
#ifdef MAGIC_WRAPPER
|
|
"[-noconsole] [-nowindow] [-wrapper] "
|
|
#endif
|
|
"[file]\n");
|
|
return 1;
|
|
}
|
|
}
|
|
else if (MakeMainWindow)
|
|
{
|
|
if (MainFileName == NULL) {
|
|
MainFileName = StrDup((char **) NULL, *argv);
|
|
CurrentName = (FileName *) mallocMagic(sizeof(FileName));
|
|
CurrentName->fn = MainFileName;
|
|
CurrentName->fn_prev = (FileName *) NULL;
|
|
CurrentName->fn_type = FN_MAGIC_DB;
|
|
}
|
|
else
|
|
{
|
|
FileName *temporary;
|
|
|
|
temporary = (FileName *) mallocMagic(sizeof(FileName));
|
|
temporary->fn = StrDup((char **) NULL, *argv);
|
|
temporary->fn_prev = CurrentName;
|
|
temporary->fn_type = FN_MAGIC_DB;
|
|
CurrentName = temporary;
|
|
}
|
|
|
|
/* Remove suffix if the file name already has it */
|
|
{
|
|
char *c,*d;
|
|
|
|
for(c = CurrentName->fn; (*c) != '\0'; c++);
|
|
for(d = DBSuffix; (*d) != '\0'; d++);
|
|
while( (*c) == (*d) ) {
|
|
if (c == MainFileName) break;
|
|
if (d == DBSuffix) {
|
|
(*c) = '\0';
|
|
break;
|
|
}
|
|
c--;
|
|
d--;
|
|
}
|
|
|
|
// Additional checks
|
|
if ((c = strrchr(CurrentName->fn, '.')) != NULL)
|
|
{
|
|
#ifdef LEF_MODULE
|
|
if (!strcasecmp(c, ".lef"))
|
|
CurrentName->fn_type = FN_LEF_FILE;
|
|
else if (!strcasecmp(c, ".def"))
|
|
CurrentName->fn_type = FN_DEF_FILE;
|
|
#endif
|
|
#ifdef CIF_MODULE
|
|
if (!strcasecmp(c, ".cif"))
|
|
CurrentName->fn_type = FN_CIF_FILE;
|
|
else if (!strncasecmp(c, ".gds", 3))
|
|
CurrentName->fn_type = FN_GDS_FILE;
|
|
#endif
|
|
#ifdef MAGIC_WRAPPER
|
|
if (!strcasecmp(c, ".tcl"))
|
|
{
|
|
CurrentName->fn_type = FN_TCL_SCRIPT;
|
|
/* Behavior: If a .tcl file is passed on the
|
|
* command line, then all following arguments
|
|
* are assumed to be arguments of the script,
|
|
* and not to be processed as additional
|
|
* input file types.
|
|
*/
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* mainArg --
|
|
*
|
|
* Pull off an argument from the (argc, argv) pair and also check
|
|
* to make sure it's not another flag (i.e, it doesn't begin with
|
|
* a '-').
|
|
*
|
|
* Results:
|
|
* Return pointer to the argument string.
|
|
*
|
|
* Side effects:
|
|
* See the comments in ArgStr() in the utils module -- they
|
|
* apply here.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
char *
|
|
mainArg(pargc, pargv, mesg)
|
|
int *pargc;
|
|
char ***pargv;
|
|
char *mesg;
|
|
{
|
|
char option, *cp;
|
|
|
|
option = (*pargv)[0][1];
|
|
cp = ArgStr(pargc, pargv, mesg);
|
|
if (cp == NULL)
|
|
return (char *) NULL;
|
|
|
|
if (*cp == '-')
|
|
{
|
|
TxError("Bad name after '-%c' option: '%s'\n", option, cp);
|
|
return (char *) NULL;
|
|
}
|
|
return cp;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* mainInitBeforeArgs:
|
|
*
|
|
* Initializes things before argument processing.
|
|
*
|
|
* Results:
|
|
* 0 on success. As written, there are no failure modes.
|
|
*
|
|
* Side effects:
|
|
* All sorts of initialization. Most initialization, however, is done
|
|
* in 'mainInitAfterArgs'.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mainInitBeforeArgs(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
TechOverridesDefault = FALSE;
|
|
if (Path == NULL)
|
|
Path = StrDup((char **) NULL, ".");
|
|
|
|
/* initialize text display */
|
|
TxInit();
|
|
TxSetTerminal();
|
|
|
|
#ifdef SCHEME_INTERPRETER
|
|
/* Initialize Lisp module. (rajit@cs.caltch.edu) */
|
|
LispInit();
|
|
#endif
|
|
|
|
/*
|
|
* Get preliminary info on the graphics display.
|
|
* This may be overriden later.
|
|
*/
|
|
GrGuessDisplayType(&MainGraphicsFile, &MainMouseFile,
|
|
&MainDisplayType, &MainMonType);
|
|
FindDisplay((char *)NULL, "displays", CAD_LIB_PATH, &MainGraphicsFile,
|
|
&MainMouseFile, &MainDisplayType, &MainMonType);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* mainInitAfterArgs:
|
|
*
|
|
* Initializes things after argument processing.
|
|
*
|
|
* Results:
|
|
* Status: 0 = success, 1 = failure to set graphics display,
|
|
* 2 = failure to load technology file.
|
|
*
|
|
* Side effects:
|
|
* All sorts of initialization.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mainInitAfterArgs()
|
|
{
|
|
int (*nullProc)() = 0;
|
|
SectionID sec_tech, sec_planes, sec_types, sec_aliases;
|
|
SectionID sec_styles;
|
|
SectionID sec_connect, sec_contact, sec_compose;
|
|
SectionID sec_cifinput, sec_cifoutput;
|
|
SectionID sec_drc, sec_extract, sec_wiring, sec_router;
|
|
SectionID sec_plow, sec_plot, sec_mzrouter;
|
|
|
|
DBTypeInit();
|
|
MacroInit();
|
|
|
|
#ifdef LEF_MODULE
|
|
/* Pre-techfile-loading intialization of the LEF module */
|
|
LefInit();
|
|
#endif
|
|
|
|
#ifdef OPENACCESS
|
|
OAInit();
|
|
#endif
|
|
|
|
/*
|
|
* Setup path names for system directory searches
|
|
*/
|
|
|
|
StrDup(&SysLibPath, MAGIC_SYS_PATH);
|
|
|
|
/*
|
|
* Historic behavior: Expect to search for cells in a directory
|
|
* inside the install area with the same name as the technology.
|
|
* Deprecated but kept for backwards compatibility. If directory
|
|
* does not exist, it will be ignored.
|
|
*/
|
|
|
|
if (TechFileName != NULL)
|
|
{
|
|
CellLibPath = (char *)mallocMagic(strlen(MAGIC_LIB_PATH_FORMAT)
|
|
+ strlen(TechFileName) - 1);
|
|
sprintf(CellLibPath, MAGIC_LIB_PATH_FORMAT, TechFileName);
|
|
PaAppend(&CellLibPath, MAGIC_LIB_PATH_DEFAULT);
|
|
}
|
|
else if ((TechDefault != NULL) && TechOverridesDefault)
|
|
{
|
|
CellLibPath = (char *)mallocMagic(strlen(MAGIC_LIB_PATH_FORMAT)
|
|
+ strlen(TechDefault) - 1);
|
|
sprintf(CellLibPath, MAGIC_LIB_PATH_FORMAT, TechDefault);
|
|
PaAppend(&CellLibPath, MAGIC_LIB_PATH_DEFAULT);
|
|
}
|
|
else
|
|
StrDup(&CellLibPath, MAGIC_LIB_PATH_DEFAULT);
|
|
|
|
if (MainGraphicsFile == NULL) MainGraphicsFile = "/dev/null";
|
|
if (MainMouseFile == NULL) MainMouseFile = MainGraphicsFile;
|
|
|
|
#ifdef MAGIC_WRAPPER
|
|
/* Check for batch mode operation and disable interrupts in */
|
|
/* batch mode by not calling SigInit(). */
|
|
if (Tcl_GetVar(magicinterp, "batch_mode", TCL_GLOBAL_ONLY) != NULL)
|
|
SigInit(1);
|
|
else
|
|
#endif
|
|
|
|
/* catch signals, must come after mainDoArgs & before SigWatchFile */
|
|
SigInit(0);
|
|
|
|
/* set up graphics */
|
|
if ( !GrSetDisplay(MainDisplayType, MainGraphicsFile, MainMouseFile) )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/* initialize technology */
|
|
TechInit();
|
|
TechAddClient("tech", DBTechInit, DBTechSetTech, nullProc,
|
|
(SectionID) 0, &sec_tech, FALSE);
|
|
TechAddClient("version", DBTechInitVersion, DBTechSetVersion, nullProc,
|
|
(SectionID) 0, (int *)0, TRUE);
|
|
TechAddClient("planes", DBTechInitPlane, DBTechAddPlane, nullProc,
|
|
(SectionID) 0, &sec_planes, FALSE);
|
|
TechAddClient("types", DBTechInitType, DBTechAddType, DBTechFinalType,
|
|
sec_planes, &sec_types, FALSE);
|
|
|
|
TechAddClient("styles", nullProc, DBWTechAddStyle, nullProc,
|
|
sec_types, &sec_styles, FALSE);
|
|
|
|
TechAddClient("contact", DBTechInitContact,
|
|
DBTechAddContact, DBTechFinalContact,
|
|
sec_types|sec_planes, &sec_contact, FALSE);
|
|
|
|
TechAddAlias("contact", "images");
|
|
TechAddClient("aliases", nullProc, DBTechAddAlias, nullProc,
|
|
sec_planes|sec_types|sec_contact, &sec_aliases, TRUE);
|
|
|
|
TechAddClient("compose", DBTechInitCompose,
|
|
DBTechAddCompose, DBTechFinalCompose,
|
|
sec_types|sec_planes|sec_contact, &sec_compose, FALSE);
|
|
|
|
TechAddClient("connect", DBTechInitConnect,
|
|
DBTechAddConnect, DBTechFinalConnect,
|
|
sec_types|sec_planes|sec_contact, &sec_connect, FALSE);
|
|
|
|
#ifdef CIF_MODULE
|
|
TechAddClient("cifoutput", CIFTechStyleInit, CIFTechLine, CIFTechFinal,
|
|
(SectionID) 0, &sec_cifoutput, FALSE);
|
|
|
|
TechAddClient("cifinput", CIFReadTechStyleInit, CIFReadTechLine,
|
|
CIFReadTechFinal, (SectionID) 0, &sec_cifinput, FALSE);
|
|
#else
|
|
TechAddClient("cifoutput", nullProc,nullProc,nullProc,
|
|
(SectionID) 0, &sec_cifoutput, FALSE);
|
|
|
|
TechAddClient("cifinput", nullProc,nullProc,nullProc,
|
|
(SectionID) 0, &sec_cifinput, FALSE);
|
|
#endif
|
|
#ifdef ROUTE_MODULE
|
|
TechAddClient("mzrouter", MZTechInit, MZTechLine, MZTechFinal,
|
|
sec_types|sec_planes, &sec_mzrouter, TRUE);
|
|
#else
|
|
TechAddClient("mzrouter", nullProc,nullProc,nullProc,
|
|
sec_types|sec_planes, &sec_mzrouter, TRUE);
|
|
#endif
|
|
TechAddClient("drc", DRCTechStyleInit, DRCTechLine, DRCTechFinal,
|
|
sec_types|sec_planes, &sec_drc, FALSE);
|
|
/* Plow rules are generated from the same lines as the DRC rules */
|
|
TechAddClient("drc", PlowDRCInit, PlowDRCLine, PlowDRCFinal,
|
|
sec_types|sec_planes, &sec_drc, FALSE);
|
|
|
|
#ifdef LEF_MODULE
|
|
TechAddClient("lef", LefTechInit, LefTechLine, nullProc,
|
|
sec_types|sec_planes, (SectionID *) 0, TRUE);
|
|
#endif
|
|
|
|
#ifdef NO_EXT
|
|
TechAddClient("extract", nullProc, nullProc,nullProc,
|
|
sec_types|sec_connect, &sec_extract, FALSE);
|
|
#else
|
|
TechAddClient("extract", nullProc, ExtTechLine, ExtTechFinal,
|
|
sec_types|sec_connect, &sec_extract, FALSE);
|
|
#endif
|
|
|
|
TechAddClient("wiring", WireTechInit, WireTechLine, WireTechFinal,
|
|
sec_types, &sec_wiring, TRUE);
|
|
|
|
#ifdef ROUTE_MODULE
|
|
TechAddClient("router", RtrTechInit, RtrTechLine, RtrTechFinal,
|
|
sec_types, &sec_router, TRUE);
|
|
#else
|
|
TechAddClient("router", nullProc,nullProc,nullProc,
|
|
sec_types, &sec_router, TRUE);
|
|
#endif
|
|
TechAddClient("plowing", PlowTechInit, PlowTechLine, PlowTechFinal,
|
|
sec_types|sec_connect|sec_contact, &sec_plow, TRUE);
|
|
#ifdef PLOT_MODULE
|
|
TechAddClient("plot", PlotTechInit, PlotTechLine, PlotTechFinal,
|
|
sec_types, &sec_plot, TRUE);
|
|
#else
|
|
TechAddClient("plot", nullProc,nullProc,nullProc,
|
|
sec_types, &sec_plot, TRUE);
|
|
#endif
|
|
|
|
/* Load minimum technology file needed to keep things from */
|
|
/* crashing during initialization. */
|
|
|
|
if (!TechLoad("minimum", 0))
|
|
{
|
|
TxError("Cannot load technology \"minimum\" for initialization\n");
|
|
return 2;
|
|
}
|
|
|
|
/* The minimum tech has been loaded only to keep the database from */
|
|
/* becoming corrupted during initialization. Free the tech file */
|
|
/* name so that a "real" technology file can be forced to replace */
|
|
/* it in mainInitFinal(). */
|
|
|
|
if (TechFileName != NULL)
|
|
{
|
|
freeMagic(TechFileName);
|
|
TechFileName = NULL;
|
|
}
|
|
|
|
/* initialize the undo package */
|
|
(void) UndoInit((char *) NULL, (char *) NULL);
|
|
|
|
/* initialize windows */
|
|
WindInit();
|
|
|
|
/* initialize commands */
|
|
CmdInit();
|
|
|
|
/* Initialize the interface between windows and its clients */
|
|
DBWinit();
|
|
#ifdef USE_READLINE
|
|
TxInitReadline();
|
|
#endif
|
|
CMWinit();
|
|
#ifdef THREE_D
|
|
W3Dinit();
|
|
#endif
|
|
|
|
/* Initialize the circuit extractor */
|
|
#ifndef NO_EXT
|
|
ExtInit();
|
|
#endif
|
|
|
|
/* Initialize plowing */
|
|
PlowInit();
|
|
|
|
/* Initialize selection */
|
|
SelectInit();
|
|
|
|
/* Initialize the wiring module */
|
|
WireInit();
|
|
|
|
#ifdef ROUTE_MODULE
|
|
/* Initialize the netlist menu */
|
|
NMinit();
|
|
#endif
|
|
|
|
/* Initialize the design-rule checker */
|
|
DRCInit();
|
|
|
|
/* Initialize the maze router */
|
|
#ifdef ROUTE_MODULE
|
|
MZInit();
|
|
|
|
/* Initialize the interactive router -
|
|
* NOTE the mzrouter must be initialized prior to the irouter
|
|
* so that default parameters will be completely setup
|
|
*/
|
|
IRDebugInit();
|
|
IRAfterTech();
|
|
#endif
|
|
|
|
/* Initialize the Sim Module (the part of it which involves (i)rsim) */
|
|
#if !defined(NO_SIM_MODULE) && defined(RSIM_MODULE)
|
|
SimInit();
|
|
#endif
|
|
|
|
TxSetPoint(GR_CURSOR_X, GR_CURSOR_Y, WIND_UNKNOWN_WINDOW);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Tcl_SetExitProc() was removed in TCL9 and used to perform this function
|
|
* see: https://core.tcl-lang.org/tips/doc/trunk/tip/512.md
|
|
*
|
|
* Note this change will slightly alter the order, the termios restore will
|
|
* not longer be performed before exit() is called.
|
|
*
|
|
* The default Tcl_Exit() does manage calling exit(status) by default.
|
|
* This assumes TxResetTerminal() will only attempt a restore if state
|
|
* was saved.
|
|
* TxResetTerminal() does not do anything if TxTkConsole is set that appears
|
|
* to be the popup shell window.
|
|
*/
|
|
static void atexit_exit_hook(void)
|
|
{
|
|
TxResetTerminal(TRUE);
|
|
}
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* mainInitFinal:
|
|
*
|
|
* Final initialization; reads startup files and any initial file
|
|
* specified.
|
|
*
|
|
* Results:
|
|
* Return 0 on success. As written, there is no failure mode.
|
|
*
|
|
* Side effects:
|
|
* All sorts of initialization.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
int
|
|
mainInitFinal()
|
|
{
|
|
char *home, cwd[512];
|
|
char startupFileName[256];
|
|
FILE *f;
|
|
char *rname;
|
|
int result;
|
|
|
|
#ifdef MAGIC_WRAPPER
|
|
/* Reset terminal if exit is called inside a TCL script */
|
|
atexit(atexit_exit_hook);
|
|
|
|
/* Read in system pre-startup file, if it exists. */
|
|
|
|
/* Use PaOpen first to perform variable substitutions, and */
|
|
/* return the actual filename in rname. */
|
|
|
|
f = PaOpen(MAGIC_PRE_DOT, "r", (char *) NULL, ".",
|
|
(char *) NULL, (char **) &rname);
|
|
if (f != NULL)
|
|
{
|
|
fclose(f);
|
|
result = Tcl_EvalFile(magicinterp, rname);
|
|
if (result != TCL_OK)
|
|
{
|
|
TxError("Error parsing pre-startup file \"%s\": %s\n", rname,
|
|
Tcl_GetStringResult(magicinterp));
|
|
Tcl_ResetResult(magicinterp);
|
|
}
|
|
}
|
|
#endif /* MAGIC_WRAPPER */
|
|
|
|
// Make a first attempt to load the technology if specified on the
|
|
// command line with the -T option. This will preempt most other
|
|
// ways that the technology file is determined. If the technology
|
|
// specified cannot be loaded, then the forced override is revoked.
|
|
|
|
if ((TechFileName == NULL) && (TechDefault != NULL) && TechOverridesDefault)
|
|
{
|
|
if (!TechLoad(TechDefault, -2))
|
|
{
|
|
TxError("Failed to load technology \"%s\"\n", TechDefault);
|
|
TechOverridesDefault = FALSE;
|
|
}
|
|
else if (!TechLoad(TechDefault, 0))
|
|
{
|
|
TxError("Error loading technology \"%s\"\n", TechDefault);
|
|
TechOverridesDefault = FALSE;
|
|
}
|
|
}
|
|
|
|
#ifndef MAGIC_WRAPPER
|
|
|
|
// Let the wrapper script be responsible for formatting and
|
|
// printing the technology file informaiton.
|
|
|
|
if (DBTechName != 0) {
|
|
TxPrintf("Using technology \"%s\"", DBTechName);
|
|
if (DBTechVersion != 0) TxPrintf(", version %s.", DBTechVersion);
|
|
TxPrintf("\n");
|
|
}
|
|
if (DBTechDescription != 0) TxPrintf("%s\n", DBTechDescription);
|
|
#endif
|
|
|
|
#ifdef MAGIC_WRAPPER
|
|
/* Read in system startup file, if it exists. */
|
|
|
|
/* Use PaOpen first to perform variable substitutions, and */
|
|
/* return the actual filename in rname. */
|
|
|
|
f = PaOpen(MAGIC_SYS_DOT, "r", (char *) NULL, ".",
|
|
(char *) NULL, (char **) &rname);
|
|
if (f != NULL)
|
|
{
|
|
fclose(f);
|
|
result = Tcl_EvalFile(magicinterp, rname);
|
|
if (result != TCL_OK)
|
|
{
|
|
TxError("Error parsing system startup file \"%s\": %s\n", rname,
|
|
Tcl_GetStringResult(magicinterp));
|
|
Tcl_ResetResult(magicinterp);
|
|
}
|
|
}
|
|
|
|
#else /* !MAGIC_WRAPPER */
|
|
|
|
f = PaOpen(MAGIC_SYS_DOT, "r", (char *) NULL, ".",
|
|
(char *) NULL, (char **) NULL);
|
|
if (f != NULL)
|
|
{
|
|
TxDispatch(f);
|
|
(void) fclose(f);
|
|
}
|
|
|
|
#endif /* !MAGIC_WRAPPER */
|
|
|
|
/*
|
|
* Strive for a wee bit more parallelism; let the graphics
|
|
* display run while we're reading in startup files & initial cell.
|
|
*/
|
|
|
|
GrFlush();
|
|
|
|
/* Ignore this whole section if we have received the -norc option */
|
|
if (RCFileName != NULL)
|
|
{
|
|
|
|
/* Read in user's startup files, if there are any. */
|
|
/* If the "-rcfile" option has been used, and it doesn't specify */
|
|
/* a full path, then look for this file in the home directory too. */
|
|
|
|
home = getenv("HOME");
|
|
|
|
#ifdef MAGIC_WRAPPER
|
|
|
|
if (home != NULL && (RCFileName[0] != '/'))
|
|
{
|
|
Tcl_Channel fc;
|
|
|
|
(void) sprintf(startupFileName, "%s/%s", home, RCFileName);
|
|
|
|
fc = Tcl_OpenFileChannel(magicinterp, startupFileName, "r", 0);
|
|
if (fc != NULL)
|
|
{
|
|
Tcl_Close(magicinterp, fc);
|
|
result = Tcl_EvalFile(magicinterp, startupFileName);
|
|
if (result != TCL_OK)
|
|
{
|
|
TxError("Error parsing user \"%s\": %s\n", RCFileName,
|
|
Tcl_GetStringResult(magicinterp));
|
|
Tcl_ResetResult(magicinterp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Try the (deprecated) name ".magic" */
|
|
(void) sprintf(startupFileName, "%s/.magic", home);
|
|
fc = Tcl_OpenFileChannel(magicinterp, startupFileName, "r", 0);
|
|
if (fc != NULL)
|
|
{
|
|
TxPrintf("Note: Use of the file name \"~/.magic\" is deprecated."
|
|
" Please change this to \"~/.magicrc\".\n");
|
|
|
|
Tcl_Close(magicinterp, fc);
|
|
result = Tcl_EvalFile(magicinterp, startupFileName);
|
|
|
|
if (result != TCL_OK)
|
|
{
|
|
TxError("Error parsing user \".magic\": %s\n",
|
|
Tcl_GetStringResult(magicinterp));
|
|
Tcl_ResetResult(magicinterp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (getcwd(cwd, 512) == NULL || strcmp(cwd, home) || (RCFileName[0] == '/'))
|
|
{
|
|
/* Read in the .magicrc file from the current directory, if */
|
|
/* different from HOME. */
|
|
|
|
Tcl_Channel fc;
|
|
|
|
fc = Tcl_OpenFileChannel(magicinterp, RCFileName, "r", 0);
|
|
if (fc != NULL)
|
|
{
|
|
Tcl_Close(magicinterp, fc);
|
|
result = Tcl_EvalFile(magicinterp, RCFileName);
|
|
|
|
if (result != TCL_OK)
|
|
{
|
|
// Print error message but continue anyway
|
|
|
|
TxError("Error parsing \"%s\": %s\n", RCFileName,
|
|
Tcl_GetStringResult(magicinterp));
|
|
Tcl_ResetResult(magicinterp);
|
|
TxPrintf("Bad local startup file \"%s\", continuing without.\n",
|
|
RCFileName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Try the (deprecated) name ".magic" */
|
|
|
|
Tcl_ResetResult(magicinterp);
|
|
fc = Tcl_OpenFileChannel(magicinterp, ".magic", "r", 0);
|
|
if (fc != NULL)
|
|
{
|
|
Tcl_Close(magicinterp, fc);
|
|
|
|
TxPrintf("Note: Use of the file name \".magic\" is deprecated."
|
|
" Please change this to \".magicrc\".\n");
|
|
|
|
result = Tcl_EvalFile(magicinterp, ".magic");
|
|
|
|
if (result != TCL_OK)
|
|
{
|
|
// Print error message but continue anyway
|
|
|
|
TxError("Error parsing local \".magic\": %s\n",
|
|
Tcl_GetStringResult(magicinterp));
|
|
Tcl_ResetResult(magicinterp);
|
|
TxPrintf("Bad local startup file \".magic\","
|
|
" continuing without.\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Try the alternative name "magic_setup" */
|
|
|
|
Tcl_ResetResult(magicinterp);
|
|
|
|
fc = Tcl_OpenFileChannel(magicinterp, "magic_setup", "r", 0);
|
|
if (fc != NULL)
|
|
{
|
|
Tcl_Close(magicinterp, fc);
|
|
|
|
result = Tcl_EvalFile(magicinterp, "magic_setup");
|
|
if (result != TCL_OK)
|
|
{
|
|
TxError("Error parsing local \"magic_setup\": %s\n",
|
|
Tcl_GetStringResult(magicinterp));
|
|
TxError("%s\n", Tcl_GetStringResult(magicinterp));
|
|
Tcl_ResetResult(magicinterp); // Still not an error
|
|
TxPrintf("Bad local startup file \"magic_setup\","
|
|
" continuing without.\n");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#else /* !MAGIC_WRAPPER */
|
|
|
|
if (home != NULL && (RCFileName[0] != '/'))
|
|
{
|
|
(void) sprintf(startupFileName, "%s/%s", home, RCFileName);
|
|
|
|
|
|
f = PaOpen(startupFileName, "r", (char *) NULL, ".",
|
|
(char *) NULL, (char **) NULL);
|
|
|
|
if ((f == NULL) && (!strcmp(RCFileName, ".magicrc")))
|
|
{
|
|
/* Try the (deprecated) name ".magic" */
|
|
(void) sprintf(startupFileName, "%s/.magic", home);
|
|
f = PaOpen(startupFileName, "r", (char *) NULL, ".",
|
|
(char *) NULL, (char **) NULL);
|
|
if (f != NULL)
|
|
TxPrintf("Note: Use of the file name \"~/.magic\" is deprecated."
|
|
" Please change this to \"~/.magicrc\".\n");
|
|
}
|
|
|
|
if (f != NULL)
|
|
{
|
|
TxDispatch(f);
|
|
(void) fclose(f);
|
|
}
|
|
}
|
|
|
|
/* Read in any startup file in the current directory, or one that was */
|
|
/* specified on the commandline by the "-rcfile <name>" option. */
|
|
|
|
f = PaOpen(RCFileName, "r", (char *) NULL, ".",
|
|
(char *) NULL, (char **) NULL);
|
|
|
|
/* Again, check for the deprecated name ".magic" */
|
|
if (f == NULL)
|
|
{
|
|
if (!strcmp(RCFileName, ".magicrc"))
|
|
{
|
|
f = PaOpen(".magic", "r", (char *) NULL, ".",
|
|
(char *) NULL, (char **) NULL);
|
|
if (f != NULL)
|
|
TxPrintf("Note: Use of the file name \"./.magic\" is deprecated."
|
|
" Please change this to \"./.magicrc\".\n");
|
|
|
|
else
|
|
f = PaOpen("magic_setup", "r", (char *) NULL, ".",
|
|
(char *) NULL, (char **) NULL);
|
|
}
|
|
else
|
|
TxError("Startup file \"%s\" not found or unreadable!\n", RCFileName);
|
|
}
|
|
|
|
if (f != NULL)
|
|
{
|
|
TxDispatch(f);
|
|
fclose(f);
|
|
}
|
|
|
|
#endif /* !MAGIC_WRAPPER */
|
|
|
|
}
|
|
|
|
/* We are done forcing the "tech load" command to be ignored */
|
|
TechOverridesDefault = FALSE;
|
|
|
|
/* If no technology has been specified yet, try to read one from
|
|
* the initial cell, or else assign a default.
|
|
*/
|
|
|
|
if ((TechFileName == NULL) && (TechDefault == NULL) && (MainFileName != NULL))
|
|
StrDup(&TechDefault, DBGetTech(MainFileName));
|
|
|
|
/* Load the technology file. If any startup file loaded a */
|
|
/* technology file, then "TechFileName" will be set, and we */
|
|
/* should not override it. */
|
|
|
|
if ((TechFileName == NULL) && (TechDefault != NULL))
|
|
{
|
|
if (!TechLoad(TechDefault, -2))
|
|
TxError("Failed to load technology \"%s\"\n", TechDefault);
|
|
else if (!TechLoad(TechDefault, 0))
|
|
TxError("Error loading technology \"%s\"\n", TechDefault);
|
|
}
|
|
|
|
if (TechDefault != NULL)
|
|
{
|
|
freeMagic(TechDefault);
|
|
TechDefault = NULL;
|
|
}
|
|
|
|
/* If that failed, then load the "minimum" technology again and */
|
|
/* keep it. It's not very useful, but it will keep everything */
|
|
/* up and running. In the worst case, if site.pre has removed the */
|
|
/* standard locations from the system path, then magic will exit. */
|
|
|
|
if (TechFileName == NULL)
|
|
if (!TechLoad("minimum", 0))
|
|
return -1;
|
|
|
|
#ifdef SCHEME_INTERPRETER
|
|
/* Pass technology name to Lisp interpreter (rajit@cs.caltech.edu) */
|
|
LispSetTech (TechFileName);
|
|
#endif
|
|
|
|
/*
|
|
* Recover crash files from the temp directory if we have specified
|
|
* the -r option on the command line (non-tcl version. Tcl version
|
|
* uses the command-line command crashrecover.
|
|
*/
|
|
|
|
if (mainRecover && MakeMainWindow)
|
|
{
|
|
DBFileRecovery(NULL); /* automatic search most recent */
|
|
}
|
|
|
|
/*
|
|
* Bring in a new cell or cells to start up if one was given
|
|
* on the command line
|
|
*/
|
|
|
|
else if (MainFileName && MakeMainWindow)
|
|
{
|
|
FileName *temporary;
|
|
|
|
while(CurrentName != NULL)
|
|
{
|
|
temporary = CurrentName;
|
|
CurrentName = temporary->fn_prev;
|
|
TxPrintf("Loading \"%s\" from command line.\n", temporary->fn);
|
|
switch (temporary->fn_type)
|
|
{
|
|
case FN_MAGIC_DB:
|
|
DBWreload(temporary->fn);
|
|
break;
|
|
#ifdef LEF_MODULE
|
|
case FN_LEF_FILE:
|
|
LefRead(temporary->fn, FALSE, FALSE, -1);
|
|
break;
|
|
case FN_DEF_FILE:
|
|
DefRead(temporary->fn, FALSE, FALSE, FALSE);
|
|
break;
|
|
#endif
|
|
#ifdef MAGIC_WRAPPER
|
|
case FN_TCL_SCRIPT:
|
|
result = Tcl_EvalFile(magicinterp, temporary->fn);
|
|
if (result != TCL_OK)
|
|
{
|
|
TxError("Error parsing \"%s\": %s\n",
|
|
temporary->fn,
|
|
Tcl_GetStringResult(magicinterp));
|
|
Tcl_ResetResult(magicinterp);
|
|
}
|
|
break;
|
|
#endif
|
|
}
|
|
freeMagic(temporary);
|
|
}
|
|
}
|
|
|
|
/* Create an initial box. */
|
|
|
|
if (MakeMainWindow && EditCellUse)
|
|
DBWSetBox(EditCellUse->cu_def, &EditCellUse->cu_def->cd_bbox);
|
|
|
|
/* Set the initial fence for undo-ing: don't want to be able to
|
|
* undo past this point.
|
|
*/
|
|
UndoFlush();
|
|
TxClearPoint();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* ----------------------------------------------------------------------------
|
|
* mainFinish:
|
|
*
|
|
* Finish up things for Magic. This routine is NOT called on an
|
|
* error exit.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side effects:
|
|
* Various things, such as stopping measurement gathering.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
mainFinished()
|
|
{
|
|
/* Close up things */
|
|
MainExit(0);
|
|
}
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* magicMain:
|
|
*
|
|
* Top-level procedure of the Magic Layout System. There is purposely
|
|
* not much in here so that we have more flexibility. Also, it is
|
|
* not called 'main' so that other programs that use Magic may do
|
|
* something else.
|
|
*
|
|
* Results:
|
|
* None.
|
|
*
|
|
* Side Effects:
|
|
* None.
|
|
*
|
|
* Note: Try not to add code to this procedure. Add it instead to one of the
|
|
* procedures that it calls.
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*/
|
|
|
|
void
|
|
magicMain(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int rstatus;
|
|
|
|
if ((rstatus = mainInitBeforeArgs(argc, argv)) != 0) MainExit(rstatus);
|
|
if ((rstatus = mainDoArgs(argc, argv)) != 0) MainExit(rstatus);
|
|
if ((rstatus = mainInitAfterArgs()) != 0) MainExit(rstatus);
|
|
if ((rstatus = mainInitFinal()) != 0) MainExit(rstatus);
|
|
TxDispatch( (FILE *) NULL);
|
|
mainFinished();
|
|
}
|
|
|
|
|
|
|