Made an enhancement to the code that automatically tries to figure
out where to find the technology corresponding to a file given on the command line: (1) Changed the default search location from /usr/share/pdk to /usr/local/share/pdk, which is the actual default for open_pdks (can still be overridden by environment variable PDK_ROOT). (2) Made the PDK name by itself preferable to the PDK name plus any extension when searching (e.g., "sky130A" is preferred over "sky130A_backup"). (3) Check the located directory for any file <tech_name>.tcl and source it if it exists. (4) Run any tag callbacks on the "tech load" command, which rebuilds the tool icons.
This commit is contained in:
parent
a8cc403e4b
commit
68a088943f
112
database/DBio.c
112
database/DBio.c
|
|
@ -106,6 +106,11 @@ bool dbReadElements();
|
|||
bool dbReadProperties();
|
||||
bool dbReadUse();
|
||||
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* Used to make a tag callback after loading a techfile */
|
||||
extern int TagCallback();
|
||||
#endif /* MAGIC_WRAPPER */
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -151,6 +156,13 @@ file_is_not_writeable(name)
|
|||
return(0);
|
||||
}
|
||||
|
||||
/* Linked string record used to hold directory contents */
|
||||
|
||||
typedef struct _linkedDirent {
|
||||
struct dirent *ld_dirent;
|
||||
struct _linkedDirent *ld_next;
|
||||
} LinkedDirent;
|
||||
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
*
|
||||
|
|
@ -168,18 +180,27 @@ file_is_not_writeable(name)
|
|||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* Notes:
|
||||
* Algorithm refined 9/12/2023. A directory which has the exact name of
|
||||
* the technology is preferred (put at the front of the list) to any other
|
||||
* directory name. e.g., for techname "sky130A.tech", directory "sky130A"
|
||||
* would be preferred to "sky130A_orig".
|
||||
*
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
char *
|
||||
DBSearchForTech(techname, pathroot, level)
|
||||
DBSearchForTech(techname, techroot, pathroot, level)
|
||||
char *techname;
|
||||
char *techroot; /* techname without the ".tech" suffix */
|
||||
char *pathroot;
|
||||
int level;
|
||||
{
|
||||
char *newpath, *found;
|
||||
char *newpath, *found, *dptr;
|
||||
struct dirent *tdent;
|
||||
DIR *tdir;
|
||||
LinkedDirent *dlist = NULL, *ld, *ldlast = NULL;
|
||||
int dlen;
|
||||
|
||||
/* Avoid potential infinite looping. Any tech file should not be very */
|
||||
/* far down the path. 10 levels is already excessive. */
|
||||
|
|
@ -189,25 +210,58 @@ DBSearchForTech(techname, pathroot, level)
|
|||
if (tdir) {
|
||||
|
||||
/* Read the directory contents of tdir */
|
||||
/* If any entry of tdir is equal to techroot, put it at the front */
|
||||
/* of the list. */
|
||||
|
||||
while ((tdent = readdir(tdir)) != NULL)
|
||||
{
|
||||
ld = (LinkedDirent *)mallocMagic(sizeof(LinkedDirent));
|
||||
ld->ld_dirent = tdent;
|
||||
|
||||
if (!strcmp(tdent->d_name, techroot))
|
||||
{
|
||||
/* Put at front of list */
|
||||
ld->ld_next = dlist;
|
||||
dlist = ld;
|
||||
if (ldlast == NULL)
|
||||
ldlast = ld;
|
||||
}
|
||||
else if (strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, ".."))
|
||||
{
|
||||
/* Put at end of list */
|
||||
ld->ld_next = NULL;
|
||||
if (ldlast == NULL)
|
||||
dlist = ld;
|
||||
else
|
||||
ldlast->ld_next = ld;
|
||||
ldlast = ld;
|
||||
}
|
||||
}
|
||||
|
||||
for (ld = dlist; ld; ld = ld->ld_next)
|
||||
{
|
||||
tdent = ld->ld_dirent;
|
||||
if (tdent->d_type != DT_DIR)
|
||||
{
|
||||
if (!strcmp(tdent->d_name, techname))
|
||||
{
|
||||
closedir(tdir);
|
||||
for (ld = dlist; ld; ld = ld->ld_next)
|
||||
freeMagic(ld);
|
||||
return pathroot;
|
||||
}
|
||||
}
|
||||
else if (strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, ".."))
|
||||
else
|
||||
{
|
||||
newpath = mallocMagic(strlen(pathroot) + strlen(tdent->d_name) + 3);
|
||||
sprintf(newpath, "%s/%s", pathroot, tdent->d_name);
|
||||
found = DBSearchForTech(techname, newpath, level + 1);
|
||||
found = DBSearchForTech(techname, techroot, newpath, level + 1);
|
||||
if (found != newpath) freeMagic(newpath);
|
||||
if (found)
|
||||
{
|
||||
closedir(tdir);
|
||||
for (ld = dlist; ld; ld = ld->ld_next)
|
||||
freeMagic(ld);
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
|
@ -215,6 +269,9 @@ DBSearchForTech(techname, pathroot, level)
|
|||
closedir(tdir);
|
||||
}
|
||||
|
||||
for (ld = dlist; ld; ld = ld->ld_next)
|
||||
freeMagic(ld);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -492,7 +549,7 @@ dbCellReadDef(f, cellDef, ignoreTech, dereference)
|
|||
/* 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
|
||||
* default install path /usr/local/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
|
||||
|
|
@ -506,28 +563,29 @@ dbCellReadDef(f, cellDef, ignoreTech, dereference)
|
|||
|
||||
string = getenv("PDK_PATH");
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
found = DBSearchForTech(techfullname, tech, string, 0);
|
||||
if (!found)
|
||||
{
|
||||
string = getenv("PDKPATH");
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
found = DBSearchForTech(techfullname, tech, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = getenv("PDK_ROOT");
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
found = DBSearchForTech(techfullname, tech, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = getenv("PDKROOT");
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
found = DBSearchForTech(techfullname, tech, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
found = DBSearchForTech(techfullname, "/usr/share/pdk", 0);
|
||||
found = DBSearchForTech(techfullname, tech,
|
||||
"/usr/local/share/pdk", 0);
|
||||
}
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* Additional checks for PDK_PATH, etc., as Tcl variables. */
|
||||
|
|
@ -539,31 +597,46 @@ dbCellReadDef(f, cellDef, ignoreTech, dereference)
|
|||
string = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
found = DBSearchForTech(techfullname, tech, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = (char *)Tcl_GetVar(magicinterp, "PDKROOT",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
found = DBSearchForTech(techfullname, tech, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = (char *)Tcl_GetVar(magicinterp, "PDK_PATH",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
found = DBSearchForTech(techfullname, tech, string, 0);
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string = (char *)Tcl_GetVar(magicinterp, "PDKPATH",
|
||||
TCL_GLOBAL_ONLY);
|
||||
if (string)
|
||||
found = DBSearchForTech(techfullname, string, 0);
|
||||
found = DBSearchForTech(techfullname, tech, string, 0);
|
||||
}
|
||||
|
||||
/* Experimental---check for a ".tcl" file in the same */
|
||||
/* directory as ".tech" and source it instead of */
|
||||
/* loading the tech file. */
|
||||
|
||||
if (found)
|
||||
{
|
||||
char *tclpath;
|
||||
|
||||
tclpath = (char *)mallocMagic(strlen(found) + strlen(tech)
|
||||
+ 6);
|
||||
sprintf(tclpath, "%s/%s.tcl", found, tech);
|
||||
Tcl_EvalFile(magicinterp, tclpath);
|
||||
freeMagic(tclpath);
|
||||
}
|
||||
#endif
|
||||
|
||||
freeMagic(techfullname);
|
||||
if (found)
|
||||
{
|
||||
|
|
@ -586,6 +659,17 @@ dbCellReadDef(f, cellDef, ignoreTech, dereference)
|
|||
TxPrintf("Cell path is now \"%s\"\n", CellLibPath);
|
||||
}
|
||||
freeMagic(found);
|
||||
#ifdef MAGIC_WRAPPER
|
||||
/* Apply tag callbacks for "tech load" command */
|
||||
{
|
||||
char *argv[2];
|
||||
argv[0] = StrDup((char **)NULL, "tech");
|
||||
argv[1] = StrDup((char **)NULL, "load");
|
||||
TagCallback(magicinterp, NULL, 2, argv);
|
||||
freeMagic(argv[1]);
|
||||
freeMagic(argv[0]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (strcmp(DBTechName, tech))
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ TagVerify(keyword)
|
|||
/* Find any tags associated with a command and execute them. */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
static int
|
||||
int
|
||||
TagCallback(interp, tkpath, argc, argv)
|
||||
Tcl_Interp *interp;
|
||||
char *tkpath;
|
||||
|
|
|
|||
Loading…
Reference in New Issue