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:
Tim Edwards 2023-09-12 11:12:00 -04:00
parent a8cc403e4b
commit 68a088943f
3 changed files with 100 additions and 16 deletions

View File

@ -1 +1 @@
8.3.428 8.3.429

View File

@ -106,6 +106,11 @@ bool dbReadElements();
bool dbReadProperties(); bool dbReadProperties();
bool dbReadUse(); 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); 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: * Side effects:
* None. * 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 * char *
DBSearchForTech(techname, pathroot, level) DBSearchForTech(techname, techroot, pathroot, level)
char *techname; char *techname;
char *techroot; /* techname without the ".tech" suffix */
char *pathroot; char *pathroot;
int level; int level;
{ {
char *newpath, *found; char *newpath, *found, *dptr;
struct dirent *tdent; struct dirent *tdent;
DIR *tdir; DIR *tdir;
LinkedDirent *dlist = NULL, *ld, *ldlast = NULL;
int dlen;
/* Avoid potential infinite looping. Any tech file should not be very */ /* Avoid potential infinite looping. Any tech file should not be very */
/* far down the path. 10 levels is already excessive. */ /* far down the path. 10 levels is already excessive. */
@ -189,25 +210,58 @@ DBSearchForTech(techname, pathroot, level)
if (tdir) { if (tdir) {
/* Read the directory contents of 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) 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 (tdent->d_type != DT_DIR)
{ {
if (!strcmp(tdent->d_name, techname)) if (!strcmp(tdent->d_name, techname))
{ {
closedir(tdir); closedir(tdir);
for (ld = dlist; ld; ld = ld->ld_next)
freeMagic(ld);
return pathroot; return pathroot;
} }
} }
else if (strcmp(tdent->d_name, ".") && strcmp(tdent->d_name, "..")) else
{ {
newpath = mallocMagic(strlen(pathroot) + strlen(tdent->d_name) + 3); newpath = mallocMagic(strlen(pathroot) + strlen(tdent->d_name) + 3);
sprintf(newpath, "%s/%s", pathroot, tdent->d_name); 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 != newpath) freeMagic(newpath);
if (found) if (found)
{ {
closedir(tdir); closedir(tdir);
for (ld = dlist; ld; ld = ld->ld_next)
freeMagic(ld);
return found; return found;
} }
} }
@ -215,6 +269,9 @@ DBSearchForTech(techname, pathroot, level)
closedir(tdir); closedir(tdir);
} }
for (ld = dlist; ld; ld = ld->ld_next)
freeMagic(ld);
return NULL; return NULL;
} }
@ -492,7 +549,7 @@ dbCellReadDef(f, cellDef, ignoreTech, dereference)
/* Places to check for a technology: In the PDK_ROOT /* Places to check for a technology: In the PDK_ROOT
* (PDKROOT) directory, PDK_PATH (PDKPATH) from environment * (PDKROOT) directory, PDK_PATH (PDKPATH) from environment
* variables, and CAD_ROOT from Tcl variables; the open_pdks * 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 * path. For CAD_ROOT the variable is expected to point to
* a path containing the techfile. For PDK_PATH and PDK_ROOT, * a path containing the techfile. For PDK_PATH and PDK_ROOT,
* search the directory tree for any subdirectory called * search the directory tree for any subdirectory called
@ -506,28 +563,29 @@ dbCellReadDef(f, cellDef, ignoreTech, dereference)
string = getenv("PDK_PATH"); string = getenv("PDK_PATH");
if (string) if (string)
found = DBSearchForTech(techfullname, string, 0); found = DBSearchForTech(techfullname, tech, string, 0);
if (!found) if (!found)
{ {
string = getenv("PDKPATH"); string = getenv("PDKPATH");
if (string) if (string)
found = DBSearchForTech(techfullname, string, 0); found = DBSearchForTech(techfullname, tech, string, 0);
} }
if (!found) if (!found)
{ {
string = getenv("PDK_ROOT"); string = getenv("PDK_ROOT");
if (string) if (string)
found = DBSearchForTech(techfullname, string, 0); found = DBSearchForTech(techfullname, tech, string, 0);
} }
if (!found) if (!found)
{ {
string = getenv("PDKROOT"); string = getenv("PDKROOT");
if (string) if (string)
found = DBSearchForTech(techfullname, string, 0); found = DBSearchForTech(techfullname, tech, string, 0);
} }
if (!found) if (!found)
{ {
found = DBSearchForTech(techfullname, "/usr/share/pdk", 0); found = DBSearchForTech(techfullname, tech,
"/usr/local/share/pdk", 0);
} }
#ifdef MAGIC_WRAPPER #ifdef MAGIC_WRAPPER
/* Additional checks for PDK_PATH, etc., as Tcl variables. */ /* 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", string = (char *)Tcl_GetVar(magicinterp, "PDK_ROOT",
TCL_GLOBAL_ONLY); TCL_GLOBAL_ONLY);
if (string) if (string)
found = DBSearchForTech(techfullname, string, 0); found = DBSearchForTech(techfullname, tech, string, 0);
} }
if (!found) if (!found)
{ {
string = (char *)Tcl_GetVar(magicinterp, "PDKROOT", string = (char *)Tcl_GetVar(magicinterp, "PDKROOT",
TCL_GLOBAL_ONLY); TCL_GLOBAL_ONLY);
if (string) if (string)
found = DBSearchForTech(techfullname, string, 0); found = DBSearchForTech(techfullname, tech, string, 0);
} }
if (!found) if (!found)
{ {
string = (char *)Tcl_GetVar(magicinterp, "PDK_PATH", string = (char *)Tcl_GetVar(magicinterp, "PDK_PATH",
TCL_GLOBAL_ONLY); TCL_GLOBAL_ONLY);
if (string) if (string)
found = DBSearchForTech(techfullname, string, 0); found = DBSearchForTech(techfullname, tech, string, 0);
} }
if (!found) if (!found)
{ {
string = (char *)Tcl_GetVar(magicinterp, "PDKPATH", string = (char *)Tcl_GetVar(magicinterp, "PDKPATH",
TCL_GLOBAL_ONLY); TCL_GLOBAL_ONLY);
if (string) 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 #endif
freeMagic(techfullname); freeMagic(techfullname);
if (found) if (found)
{ {
@ -586,6 +659,17 @@ dbCellReadDef(f, cellDef, ignoreTech, dereference)
TxPrintf("Cell path is now \"%s\"\n", CellLibPath); TxPrintf("Cell path is now \"%s\"\n", CellLibPath);
} }
freeMagic(found); 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)) if (strcmp(DBTechName, tech))

View File

@ -93,7 +93,7 @@ TagVerify(keyword)
/* Find any tags associated with a command and execute them. */ /* Find any tags associated with a command and execute them. */
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
static int int
TagCallback(interp, tkpath, argc, argv) TagCallback(interp, tkpath, argc, argv)
Tcl_Interp *interp; Tcl_Interp *interp;
char *tkpath; char *tkpath;