From 114b9a59f7d1673caec662304c36bccbe76920de Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Thu, 25 Feb 2021 13:37:31 -0500 Subject: [PATCH] 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. --- VERSION | 2 +- database/DBio.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 243 insertions(+), 8 deletions(-) diff --git a/VERSION b/VERSION index 7f0c6553..72b47869 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.133 +8.3.134 diff --git a/database/DBio.c b/database/DBio.c index 56874065..e9026ef8 100644 --- a/database/DBio.c +++ b/database/DBio.c @@ -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)