Implemented more automation for attempting to find a tech file

based on the contents of a .mag file being read in, assuming
compatibility with principles of open_pdks.  The search paths
are not meddled with unless a file is read for which the technology
cannot be found (and a technology has not already been read, or at
least no database file exists in memory using any technology that
has already been read).  If so, then variables PDK_PATH and PDK_ROOT
are searched for in both the shell environment and the local Tcl
environment.  Also, if open_pdks has installed PDKs in the path
/usr/share/pdk/, then that path will be searched.  If a corresponding
technology file is found, it will be loaded.  If the path corresponds
to an open_pdks-style path, then the library paths in libs.ref will
also be added to the search paths for cells.
This commit is contained in:
Tim Edwards 2021-02-25 13:37:31 -05:00
parent 2bb3580f3e
commit 114b9a59f7
2 changed files with 243 additions and 8 deletions

View File

@ -1 +1 @@
8.3.133
8.3.134

View File

@ -135,6 +135,132 @@ file_is_not_writeable(name)
return(0);
}
/*
* ----------------------------------------------------------------------------
*
* DBSearchForTech --
*
* Helper function for automatically discovering a technology used in a
* .mag file when reading. This function will recursively search all
* directories rooted at "pathroot" looking for a file "techname" which
* must include the ".tech" extension. If found, the path name is returned.
*
* Results:
* Pointer to a string containing the path name. This is allocated so as
* not to be lost, and must be freed by the caller.
*
* Side effects:
* None.
*
* ----------------------------------------------------------------------------
*/
char *
DBSearchForTech(techname, pathroot, level)
char *techname;
char *pathroot;
int level;
{
char *newpath, *found;
struct dirent *tdent;
DIR *tdir;
/* Avoid potential infinite looping. Any tech file should not be very */
/* far down the path. 10 levels is already excessive. */
if (level > 10) return NULL;
tdir = opendir(pathroot);
if (tdir) {
/* Read the directory contents of tdir */
while ((tdent = readdir(tdir)) != NULL)
{
if (tdent->d_type != DT_DIR)
{
if (!strcmp(tdent->d_name, techname))
return pathroot;
}
else if (strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, ".."))
{
newpath = mallocMagic(strlen(pathroot) + strlen(tdent->d_name) + 3);
sprintf(newpath, "%s/%s", pathroot, tdent->d_name);
found = DBSearchForTech(techname, newpath, level + 1);
if (found != newpath) freeMagic(newpath);
if (found) return found;
}
}
closedir(tdir);
}
else
return NULL;
}
/*
* ----------------------------------------------------------------------------
*
* DBAddStandardCellPaths --
*
* Search for .mag files in any directory below "pathptr", for any
* directory found containing .mag files, add that path to the search
* path for cells.
*
* Results:
* Number of paths added to CellLibPath.
*
* Side effects:
* May add paths to the CellLibPath.
*
* ----------------------------------------------------------------------------
*/
int
DBAddStandardCellPaths(pathptr, level)
char *pathptr;
int level;
{
int paths = 0;
struct dirent *tdent;
char *newpath;
DIR *tdir;
bool magfound = FALSE;
/* Avoid potential infinite looping. Any tech file should not be very */
/* far down the path. 10 levels is already excessive. */
if (level > 10) return 0;
tdir = opendir(pathptr);
if (tdir) {
while ((tdent = readdir(tdir)) != NULL)
{
if ((tdent->d_type == DT_DIR) &&
(strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, "..")))
{
/* Scan the directory contents of tdir for more subdirectories */
newpath = mallocMagic(strlen(pathptr) + strlen(tdent->d_name) + 3);
sprintf(newpath, "%s/%s", pathptr, tdent->d_name);
paths += DBAddStandardCellPaths(newpath, level + 1);
freeMagic(newpath);
}
else if (tdent->d_type != DT_DIR)
{
/* Scan the directory contents of tdir for .mag files */
if (!strcmp(tdent->d_name + strlen(tdent->d_name) - 4, ".mag"))
{
if (magfound == FALSE)
{
PaAppend(&CellLibPath, pathptr);
paths++;
magfound = TRUE;
}
}
}
}
closedir(tdir);
}
return paths;
}
/*
* ----------------------------------------------------------------------------
*
@ -335,13 +461,122 @@ dbCellReadDef(f, cellDef, name, ignoreTech, dereference)
TxPrintf("Will attempt to read cell anyway.\n");
else
{
TxError("Use command \"tech load\" if you want to switch"
" technologies, or use\n");
TxError("\"cellname delete %s\" and \"load %s -force\" to"
" force the cell to load as technology %s\n",
cellDef->cd_name, cellDef->cd_name, DBTechName);
SigEnableInterrupts();
return (FALSE);
/* If no cells are currently in memory, then make an
* attempt to find the technology associated with the
* layout and load it.
*/
if (!CmdCheckForPaintFunc())
{
/* Places to check for a technology: In the PDK_ROOT
* (PDKROOT) directory, PDK_PATH (PDKPATH) from environment
* variables, and CAD_ROOT from Tcl variables; the open_pdks
* default install path /usr/share/pdk/, and magic's install
* path. For CAD_ROOT the variable is expected to point to
* a path containing the techfile. For PDK_PATH and PDK_ROOT,
* search the directory tree for any subdirectory called
* magic/ and look for a compatible techfile there.
*/
char *found = NULL;
char *string, *techfullname;
techfullname = mallocMagic(strlen(tech) + 6);
sprintf(techfullname, "%s.tech", tech);
string = getenv("PDK_PATH");
if (string)
found = DBSearchForTech(techfullname, string, 0);
if (!found)
{
string = getenv("PDKPATH");
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = getenv("PDK_ROOT");
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = getenv("PDKROOT");
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
found = DBSearchForTech(techfullname, "/usr/share/pdk", 0);
}
#ifdef MAGIC_WRAPPER
/* Additional checks for PDK_PATH, etc., as Tcl variables. */
/* This is unlikely, as they would have to be set in a */
/* startup file, and a startup file is likely to just load */
/* the technology itself. */
if (!found)
{
string = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT",
TCL_GLOBAL_ONLY);
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = (char *)Tcl_GetVar(magicinterp, "PDKROOT",
TCL_GLOBAL_ONLY);
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = (char *)Tcl_GetVar(magicinterp, "PDK_PATH",
TCL_GLOBAL_ONLY);
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
if (!found)
{
string = (char *)Tcl_GetVar(magicinterp, "PDKPATH",
TCL_GLOBAL_ONLY);
if (string)
found = DBSearchForTech(techfullname, string, 0);
}
#endif
freeMagic(techfullname);
if (found)
{
char *sptr;
PaAppend(&SysLibPath, found);
TxError("Loading technology %s\n", tech);
if (!TechLoad(tech, 0))
TxError("Error in loading technology file\n");
else if ((sptr = strstr(found, "libs.tech")) != NULL)
{
int paths = 0;
/* Additional automatic handling of open_pdks- */
/* style PDKs. Append the libs.ref libraries */
/* to the cell search path. */
strcpy(sptr + 5, "ref");
paths = DBAddStandardCellPaths(found, 0);
if (paths > 0)
TxPrintf("Cell path is now \"%s\"\n", CellLibPath);
}
freeMagic(found);
}
}
if (strcmp(DBTechName, tech))
{
TxError("Use command \"tech load\" if you want to switch"
" technologies, or use\n");
TxError("\"cellname delete %s\" and \"load %s -force\" to"
" force the cell to load as technology %s\n",
cellDef->cd_name, cellDef->cd_name, DBTechName);
SigEnableInterrupts();
return (FALSE);
}
}
}
if (dbFgets(line, sizeof line, f) == NULL)