mirror of
https://github.com/RTimothyEdwards/magic.git
synced 2026-08-28 17:15:13 +02:00
This seems like it has 2 use cases. Internal console management around reprinting command prompt, but many modes of operation delegate the prompt processing to tkcon or readline. Process termination to restore the termios.
1295 lines
33 KiB
C
1295 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 <sys/types.h>
|
|
#include <sys/times.h>
|
|
#include <sys/time.h>
|
|
|
|
#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
|
|
#include "lisp/lisp.h"
|
|
#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. ([email protected]) */
|
|
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 ([email protected]) */
|
|
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();
|
|
}
|
|
|
|
|
|
|