diff --git a/VERSION b/VERSION index 245451db..24ae6434 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.3.635 +8.3.636 diff --git a/dbwind/DBWbuttons.c b/dbwind/DBWbuttons.c index 49080da5..fbb34aaa 100644 --- a/dbwind/DBWbuttons.c +++ b/dbwind/DBWbuttons.c @@ -131,8 +131,11 @@ DBWAddButtonHandler( for (i = 0; i < MAXBUTTONHANDLERS; i++) { if (dbwButtonHandlers[i] != NULL) continue; - (void) StrDup(&dbwButtonHandlers[i], name); - (void) StrDup(&dbwButtonDoc[i], doc); + StrDup(&dbwButtonHandlers[i], name); + if (doc != NULL) + StrDup(&dbwButtonDoc[i], doc); + else + dbwButtonDoc[i] = (char *)NULL; dbwButtonProcs[i] = proc; dbwButtonCursors[i] = cursor; return; @@ -273,6 +276,37 @@ DBWGetButtonHandler() return dbwButtonHandlers[dbwButtonCurrentIndex]; } +/* + * ---------------------------------------------------------------------------- + * + * DBWButtonHandlerIndex() + * + * Given a string, return the index of the button handler. If the + * string does not correspond to any button handler name, then + * return -1. + * + * Results: + * Index of button handler, if it exists; -1 otherwise. + * + * Side effects: + * None. + * + * ---------------------------------------------------------------------------- + */ + +int +DBWButtonHandlerIndex(char *toolName) +{ + int i; + + for (i = 0; i < MAXBUTTONHANDLERS; i++) + { + if (dbwButtonHandlers[i] == NULL) return -1; + else if (!strcmp(toolName, dbwButtonHandlers[i])) return i; + } + return -1; +} + /* * ---------------------------------------------------------------------------- * @@ -294,7 +328,10 @@ DBWGetButtonHandler() void DBWPrintButtonDoc() { - TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]); + if (dbwButtonDoc[dbwButtonCurrentIndex]) + TxPrintf("%s", dbwButtonDoc[dbwButtonCurrentIndex]); + else + TxPrintf("(no usage information)\n"); } diff --git a/dbwind/dbwind.h b/dbwind/dbwind.h index 860b52a4..8faf1891 100644 --- a/dbwind/dbwind.h +++ b/dbwind/dbwind.h @@ -152,6 +152,7 @@ extern void DBWAddButtonHandler(const char *name, const cb_database_buttonhandle int cursor, const char *doc); extern char *DBWGetButtonHandler(); extern char *DBWChangeButtonHandler(); +extern int DBWButtonHandlerIndex(); extern void DBWPrintButtonDoc(); extern void DBWBoxHandler(); diff --git a/extract/ExtBasic.c b/extract/ExtBasic.c index 1b41f115..31fe2c30 100644 --- a/extract/ExtBasic.c +++ b/extract/ExtBasic.c @@ -2755,6 +2755,56 @@ extOutputDevices(def, transList, outFile) /* get corrected by extComputeEffectiveLW(). */ length = (extTransRec.tr_gatelen - width) / 2; } + + if ((n == 1) && (length == 0) && (extTransRec.tr_gatelen == 0)) + { + /* If a one-terminal device has not recorded any + * gate length, then get W and L from the bounding + * box of the device. This routine could be much + * better optimized but it is probably not worth + * the effort. Just reusing the code from above + * for creating extSpecialDevice, a list of device + * tiles. Note that W and L are not distinguishable + * and hopefully the PDK defines the device by area + * and perimeter. + */ + LinkedTile *lt; + Rect devbbox, ltbox; + + extSpecialDevice = (LinkedTile *)NULL; + + arg.fra_uninit = (ClientData)extTransRec.tr_gatenode; + arg.fra_region = (ExtRegion *)reg; + arg.fra_each = extSDTileFunc; + ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo, + arg.fra_pNum, &arg); + + arg.fra_uninit = (ClientData) reg; + arg.fra_region = (ExtRegion *) extTransRec.tr_gatenode; + arg.fra_each = (int (*)()) NULL; + ExtFindNeighbors(reg->treg_tile, reg->treg_dinfo, + arg.fra_pNum, &arg); + + lt = extSpecialDevice; + if (lt) + { + TiToRect(lt->t, &devbbox); + for (; lt; lt = lt->t_next) + { + TiToRect(lt->t, <box); + GeoInclude(<box, &devbbox); + } + free_magic1_t mm1 = freeMagic1_init(); + for (lt = extSpecialDevice; lt; lt = lt->t_next) + freeMagic1(&mm1, (char *)lt); + freeMagic1_end(&mm1); + } + length = devbbox.r_xtop - devbbox.r_xbot; + /* Width was likely a perimeter value and will + * be recalculated as the actual device width. + */ + width = devbbox.r_ytop - devbbox.r_ybot; + } } /*------------------------------------------------------*/ diff --git a/tcltk/tools.tcl b/tcltk/tools.tcl index 5e9cc666..b3ac5d7e 100644 --- a/tcltk/tools.tcl +++ b/tcltk/tools.tcl @@ -534,8 +534,11 @@ proc magic::enable_tools {} { # The user can change these bindings at will by using the # "macro" command when the tool is active. + # NOTE: Do not name a tool "netlist" because it will get + # confused with the "netlist" window. + magic::macro copy wiring - magic::macro copy netlist + magic::macro copy nettool magic::macro copy pick magic::tool wiring @@ -549,7 +552,7 @@ proc magic::enable_tools {} { macro Button4 "wire incr width ; wire show" macro Button5 "wire decr width ; wire show" - magic::tool netlist + magic::tool nettool macro Button1 "netlist select" macro Button2 "netlist join" macro Button3 "netlist terminal" @@ -704,8 +707,8 @@ proc magic::tool {{type next}} { if {$type == "next"} { switch $Opts(tool) { box { set type wiring } - wiring { set type netlist } - netlist { set type pick } + wiring { set type nettool } + nettool { set type pick } pick { set type box } } } @@ -761,9 +764,9 @@ proc magic::tool {{type next}} { set Opts(tool) wiring cursor 19 ;# sets the cursor } - netlist { + nettool { puts stdout {Switching to NETLIST tool.} - set Opts(tool) netlist + set Opts(tool) nettool cursor 18 ;# sets the cursor } pick { diff --git a/windows/windCmdAM.c b/windows/windCmdAM.c index a7d76dcb..88eef6ed 100644 --- a/windows/windCmdAM.c +++ b/windows/windCmdAM.c @@ -1056,6 +1056,7 @@ windDoMacro(w, cmd, interactive) bool do_help = FALSE; bool do_reverse = FALSE; char *searchterm = NULL; + char *clientName = NULL; macrodef *cMacro; HashTable *clienttable; HashEntry *h; @@ -1073,9 +1074,25 @@ windDoMacro(w, cmd, interactive) argstart = 1; if (cmd->tx_argc == 1) - wc = DBWclientID; /* Added by NP 11/15/04 */ + wc = DBWclientID; /* Default client */ else if (cmd->tx_argc > 1) + { wc = WindGetClient(cmd->tx_argv[1], TRUE); + if (wc != NULL) + { + clientName = cmd->tx_argv[1]; + argstart++; + } + else + { + /* Check if argument is a known layout button handler */ + if (DBWButtonHandlerIndex(cmd->tx_argv[1]) != -1) + { + clientName = cmd->tx_argv[1]; + argstart++; + } + } + } while (cmd->tx_argc > argstart) { @@ -1116,6 +1133,15 @@ windDoMacro(w, cmd, interactive) wc = DBWclientID; } MacroCopy(wc, cmd->tx_argv[argstart]); + + /* If tool name did not previously exist, then add + * it to the list of known tool names, so that it + * can be found later by the "macro" command. + */ + if (DBWButtonHandlerIndex(cmd->tx_argv[argstart]) == -1) + DBWAddButtonHandler(cmd->tx_argv[argstart], + (const cb_database_buttonhandler_t)NULL, + 0, (const char *)NULL); } return; } @@ -1147,26 +1173,53 @@ windDoMacro(w, cmd, interactive) if (MacroKey(cmd->tx_argv[argstart], &verbose) == 0) if (MacroKey(cmd->tx_argv[argstart + 1], &verbose) != 0) - { - wc = 0; - argstart++; return; - } } } - else - argstart++; + + /* If a clientName wasn't given, but wc is DBWclientID, then get + * the clientName from the default button handler. + */ + + if ((clientName == NULL) && (wc == DBWclientID)) + clientName = DBWGetButtonHandler(); if (cmd->tx_argc == argstart) { - if (wc == (WindClient)0) + if (clientName == NULL) + h = NULL; + else + h = HashLookOnly(&MacroClients, (char *)clientName); + + if (h == NULL) { - TxError("No such client.\n"); +#ifdef MAGIC_WRAPPER + Tcl_Obj *lobj; + lobj = Tcl_NewListObj(0, NULL); +#endif + TxError("Cannot get macro list from current window.\n"); +#ifndef MAGIC_WRAPPER + TxError("List of known macro clients:\n"); +#endif + /* If clientName was not in MacroClients, then what is? */ + HashStartSearch(&hs); + while ((h = HashNext(&MacroClients, &hs)) != NULL) + { + char *clientName = h->h_key.h_name; +#ifdef MAGIC_WRAPPER + Tcl_ListObjAppendElement(magicinterp, lobj, + Tcl_NewStringObj(clientName, -1)); +#else + TxError("%s ", clientName); +#endif + } +#ifdef MAGIC_WRAPPER + Tcl_SetObjResult(magicinterp, lobj); +#else + TxError("\n"); +#endif return; } - h = HashLookOnly(&MacroClients, (char *)wc); - if (h == NULL) - return; else { clienttable = (HashTable *)HashGetValue(h);