diff --git a/commands/CmdCD.c b/commands/CmdCD.c index 6fdcb4ad..712b0ae4 100644 --- a/commands/CmdCD.c +++ b/commands/CmdCD.c @@ -3182,7 +3182,6 @@ CmdDrc(w, cmd) bool doforall = FALSE; bool dolist = FALSE; int count_total; - DRCCountList *dcl, *dclsrch; int argc = cmd->tx_argc; char **argv = cmd->tx_argv; #ifdef MAGIC_WRAPPER @@ -3199,7 +3198,7 @@ CmdDrc(w, cmd) "check recheck area under box in all cells", "count count error tiles in each cell under box", "euclidean on|off enable/disable Euclidean geometry checking", - "find [nth] locate next (or nth) error in the layout", + "find [nth] locate next (or nth) error in the layout", "help print this help information", "off turn off background checker", "on reenable background checker", @@ -3305,15 +3304,6 @@ CmdDrc(w, cmd) break; case COUNT: - count_total = -1; - if (argc == 3) - if (!strncmp(argv[2], "total", 5)) - count_total = 0; - -#ifdef MAGIC_WRAPPER - if (count_total == -1) lobj = Tcl_NewListObj(0, NULL); -#endif - if ((window = w) == NULL) { window = ToolGetBoxWindow(&rootArea, (int *) NULL); @@ -3323,61 +3313,44 @@ CmdDrc(w, cmd) rootArea = w->w_surfaceArea; rootUse = (CellUse *) window->w_surfaceID; - dcl = DRCCount(rootUse, &rootArea); - while (dcl != NULL) - { - if (count_total >= 0) - count_total += dcl->dcl_count; - else - { -#ifdef MAGIC_WRAPPER - if (dolist) - { - Tcl_Obj *pobj = Tcl_NewListObj(0, NULL); - Tcl_ListObjAppendElement(magicinterp, pobj, - Tcl_NewStringObj(dcl->dcl_def->cd_name, -1)); - Tcl_ListObjAppendElement(magicinterp, pobj, - Tcl_NewIntObj(dcl->dcl_count)); - Tcl_ListObjAppendElement(magicinterp, lobj, pobj); - } - else - { -#endif - - if (dcl->dcl_count > 1) - TxPrintf("Cell %s has %d error tiles.\n", - dcl->dcl_def->cd_name, dcl->dcl_count); - else if (dcl->dcl_count == 1) - TxPrintf("Cell %s has just one error tile.\n", - dcl->dcl_def->cd_name); -#ifdef MAGIC_WRAPPER - } -#endif - } - freeMagic((char *)dcl); - dcl = dcl->dcl_next; - } + count_total = DRCCount(rootUse, &rootArea); #ifdef MAGIC_WRAPPER - if (count_total >= 0) + if (dolist) + { + lobj = Tcl_NewListObj(0, NULL); + Tcl_ListObjAppendElement(magicinterp, lobj, + Tcl_NewStringObj(rootUse->cu_def->cd_name, -1)); + Tcl_ListObjAppendElement(magicinterp, lobj, + Tcl_NewIntObj(count_total)); + } + else + { +#endif + + if (count_total > 1) + TxPrintf("Cell %s has %d error tiles.\n", + rootUse->cu_def->cd_name, count_total); + else if (count_total == 1) + TxPrintf("Cell %s has just one error tile.\n", + rootUse->cu_def->cd_name); + +#ifdef MAGIC_WRAPPER + } +#endif + +#ifdef MAGIC_WRAPPER + if (doforall) + Tcl_SetObjResult(magicinterp, lobj); + else if (count_total >= 0) { if (dolist) Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(count_total)); else - { - if ((DRCBackGround != DRC_SET_OFF) && (count_total == -1)) - count_total = 0; - if (count_total >= 0) - TxPrintf("Total DRC errors found: %d\n", count_total); - } + TxPrintf("Total DRC errors found: %d\n", count_total); } - else if (dolist) - Tcl_SetObjResult(magicinterp, lobj); #else - if ((DRCBackGround != DRC_SET_OFF) && (count_total == -1)) - count_total = 0; - if (count_total >= 0) - TxPrintf("Total DRC errors found: %d\n", count_total); + TxPrintf("Total DRC errors found: %d\n", count_total); #endif break; diff --git a/drc/DRCmain.c b/drc/DRCmain.c index b1906713..29ab5e8f 100644 --- a/drc/DRCmain.c +++ b/drc/DRCmain.c @@ -343,7 +343,7 @@ drcListallError (celldef, rect, cptr, scx) area = &scx->scx_area; if ((area != NULL) && (!GEO_OVERLAP(area, rect))) return; DRCErrorCount += 1; - h = HashFind(&DRCErrorTable, cptr->drcc_why); + h = HashFind(&DRCErrorTable, drcSubstitute(cptr)); lobj = (Tcl_Obj *) HashGetValue(h); if (lobj == NULL) lobj = Tcl_NewListObj(0, NULL); @@ -747,111 +747,42 @@ drcCheckFunc(scx, cdarg) * ---------------------------------------------------------------------------- */ -DRCCountList * +int DRCCount(use, area) CellUse *use; /* Top-level use of hierarchy. */ Rect *area; /* Area in which violations are counted. */ { - DRCCountList *dcl, *newdcl; - HashTable dupTable; - HashEntry *he; - HashSearch hs; int count; SearchContext scx; - extern int drcCountFunc(); /* Forward reference. */ - - /* Use a hash table to make sure that we don't output information - * for any cell more than once. - */ - - HashInit(&dupTable, 16, HT_WORDKEYS); + CellDef *def; + extern int drcCountFunc2(); scx.scx_use = use; scx.scx_x = use->cu_xlo; scx.scx_y = use->cu_ylo; scx.scx_area = *area; scx.scx_trans = GeoIdentityTransform; - (void) drcCountFunc(&scx, &dupTable); - /* Create the list from the hash table */ - - dcl = NULL; - if (dupTable.ht_table != (HashEntry **) NULL) - { - HashStartSearch(&hs); - while ((he = HashNext(&dupTable, &hs)) != (HashEntry *)NULL) - { - count = (spointertype)HashGetValue(he); - if (count > 1) - { - newdcl = (DRCCountList *)mallocMagic(sizeof(DRCCountList)); - newdcl->dcl_count = count - 1; - newdcl->dcl_def = (CellDef *)he->h_key.h_ptr; - newdcl->dcl_next = dcl; - dcl = newdcl; - } - } - } - HashKill(&dupTable); - return dcl; -} - -int -drcCountFunc(scx, dupTable) - SearchContext *scx; - HashTable *dupTable; /* Passed as client data, used to - * avoid searching any cell twice. - */ -{ - int count; - HashEntry *h; - CellDef *def; - extern int drcCountFunc2(); - - /* If we've already seen this cell definition before, then skip it - * now. - */ - - def = scx->scx_use->cu_def; - h = HashFind(dupTable, (char *)def); - if (HashGetValue(h) != 0) goto done; - HashSetValue(h, 1); + def = use->cu_def; /* Count errors in this cell definition by scanning the error plane. */ count = 0; (void) DBSrPaintArea((Tile *) NULL, def->cd_planes[PL_DRC_ERROR], - &def->cd_bbox, &DBAllButSpaceBits, drcCountFunc2, (ClientData) &count); - HashSetValue(h, (spointertype)count + 1); + &def->cd_bbox, &DBAllButSpaceBits, drcCountFunc2, (ClientData)(&count)); - /* Ignore children that have not been loaded---we will only report */ - /* errors that can be seen. This avoids immediately loading and */ - /* drc processing large layouts simply because we asked for an */ - /* error count. When the cell is loaded, drc will be checked */ - /* anyway, and the count can be updated in response to that check. */ - - if ((scx->scx_use->cu_def->cd_flags & CDAVAILABLE) == 0) return 0; - - /* New behavior: Don't search children, instead propagate errors up. */ - /* (void) DBCellSrArea(scx, drcCountFunc, (ClientData) dupTable); */ - - /* As a special performance hack, if the complete cell area is - * handled here, don't bother to look at any more array elements. - */ - - done: if (GEO_SURROUND(&scx->scx_area, &def->cd_bbox)) return 2; - else return 0; + return count; } int -drcCountFunc2(tile, pCount) - Tile *tile; /* Tile found in error plane. */ - int *pCount; /* Address of count word. */ +drcCountFunc2(tile, countptr) + Tile *tile; /* Tile found in error plane. */ + int *countptr; /* Address of count word. */ { - if (TiGetType(tile) != (TileType) TT_SPACE) *pCount += 1; + if (TiGetType(tile) != (TileType) TT_SPACE) (*countptr)++; return 0; } - + /* * ---------------------------------------------------------------------------- * diff --git a/drc/drc.h b/drc/drc.h index e2dea941..99bf0d28 100644 --- a/drc/drc.h +++ b/drc/drc.h @@ -125,15 +125,6 @@ typedef struct drcpendingcookie struct drcpendingcookie *dpc_next; } DRCPendingCookie; -/* Structure used to pass back lists of cell definitions and error tile counts */ - -typedef struct drccountlist -{ - CellDef *dcl_def; - int dcl_count; - struct drccountlist *dcl_next; -} DRCCountList; - /* Structure used to keep information about the current DRC style */ typedef struct drckeep @@ -267,7 +258,7 @@ extern void DRCPrintRulesTable(); extern void DRCWhy(); extern void DRCPrintStats(); extern void DRCCheck(); -extern DRCCountList *DRCCount(); +extern int DRCCount(); extern int DRCFind(); extern void DRCCatchUp(); extern bool DRCFindInteractions(); diff --git a/tcltk/Makefile b/tcltk/Makefile index ac45c270..db00d511 100644 --- a/tcltk/Makefile +++ b/tcltk/Makefile @@ -18,6 +18,7 @@ TCL_FILES = \ console.tcl \ techbuilder.tcl \ cellmgr.tcl \ + drcmgr.tcl \ libmgr.tcl \ texthelper.tcl \ tools.tcl \ diff --git a/tcltk/drcmgr.tcl b/tcltk/drcmgr.tcl new file mode 100644 index 00000000..abf9277f --- /dev/null +++ b/tcltk/drcmgr.tcl @@ -0,0 +1,195 @@ +#------------------------------------------------------ +# Script for generating the "DRC manager" window. +# +# Written by Tim Edwards, November 2019 +#------------------------------------------------------ + +global Opts + +if {$::tk_version >= 8.5} { + +set Opts(drcmgr) 0 + +magic::tag addpath "magic::drcmanager" +magic::tag path "magic::drcmanager" + +# Callback to the DRC manager + +proc magic::drccallback {command} { + global Opts + + set fid [.drcmgr.box.view selection] + if {[.drcmgr.box.view parent $fid] == {}} { + set value {} + } else { + set value [.drcmgr.box.view item $fid -text] + } + + if { $Opts(target) == "default" } { + set winlist [magic::windownames layout] + set winname [lindex $winlist 0] + } else { + set winname $Opts(target) + } + + switch $command { + update { + magic::drcmanager update + } + last { + .drcmgr.box.view selection set [.drcmgr.box.view prev $fid] + magic::drccallback zoom + } + next { + .drcmgr.box.view selection set [.drcmgr.box.view next $fid] + magic::drccallback zoom + } + zoom { + if {$value != {}} { + set snaptype [snap] + snap internal + box values {*}$value + magic::suspendall + magic::findbox zoom + magic::zoom 2 + magic::resumeall + snap $snaptype + } + } + } +} + +#---------------------------------------------- +# Create the DRC manager window +#---------------------------------------------- + +proc magic::makedrcmanager { mgrpath } { + global filtered + + set filtered 1 + toplevel ${mgrpath} + wm withdraw ${mgrpath} + frame ${mgrpath}.actionbar + frame ${mgrpath}.box + frame ${mgrpath}.target + + ttk::treeview ${mgrpath}.box.view -selectmode browse \ + -yscrollcommand "${mgrpath}.box.vert set" \ + -xscrollcommand "${mgrpath}.box.vert set" \ + -columns 0 + scrollbar ${mgrpath}.box.vert -orient vertical -command "${mgrpath}.box.view yview" + ${mgrpath}.box.view heading #0 -text "DRC Rule" + ${mgrpath}.box.view heading 0 -text "Error Number" + ${mgrpath}.box.view column #0 -stretch true -anchor w -minwidth 350 + ${mgrpath}.box.view column 0 -stretch false -anchor center -minwidth 50 + + grid columnconfigure ${mgrpath}.box 0 -weight 1 -minsize 500 + grid columnconfigure ${mgrpath}.box 1 -weight 0 + grid rowconfigure ${mgrpath}.box 0 -weight 1 + grid ${mgrpath}.box.view -row 0 -column 0 -sticky news + grid ${mgrpath}.box.vert -row 0 -column 1 -sticky news + + grid rowconfigure ${mgrpath} 0 -weight 0 + grid rowconfigure ${mgrpath} 1 -weight 1 + grid rowconfigure ${mgrpath} 2 -weight 0 + grid columnconfigure ${mgrpath} 0 -weight 1 + grid ${mgrpath}.actionbar -row 0 -column 0 -sticky news + grid ${mgrpath}.box -row 1 -column 0 -sticky news + grid ${mgrpath}.target -row 2 -column 0 -sticky news + + button ${mgrpath}.actionbar.update -text "Update" \ + -command {magic::drccallback update} + button ${mgrpath}.actionbar.last -text "Last" -command {magic::drccallback last} + button ${mgrpath}.actionbar.next -text "Next" -command {magic::drccallback next} + button ${mgrpath}.actionbar.zoom -text "Zoom" -command {magic::drccallback zoom} + + pack ${mgrpath}.actionbar.update -side left + pack ${mgrpath}.actionbar.last -side left + pack ${mgrpath}.actionbar.next -side left + pack ${mgrpath}.actionbar.zoom -side right + + label ${mgrpath}.target.name -text "Target window:" + menubutton ${mgrpath}.target.list -text "default" \ + -menu ${mgrpath}.target.list.winmenu + + pack ${mgrpath}.target.name -side left -padx 2 + pack ${mgrpath}.target.list -side left + + #Withdraw the window when the close button is pressed + wm protocol ${mgrpath} WM_DELETE_WINDOW "set Opts(drcmgr) 0 ; \ + wm withdraw ${mgrpath}" + + #------------------------------------------------- + # Callback when a treeview item is opened + #------------------------------------------------- + + bind .drcmgr <> { + set s [.drcmgr.box.view selection] + foreach i [.drcmgr.box.view children $s] { + # NOTE: not hierarchical + .drcmgr.box.view item $i -open false + } + } + + bind .drcmgr <> { + set s [.drcmgr.box.view selection] + foreach i [.drcmgr.box.view children $s] { + foreach j [.drcmgr.box.view children $i] { + .drcmgr.box.view delete $j + } + } + } +} + +proc magic::adddrcentry {key valuelist} { + set id [.drcmgr.box.view insert {} end -text ${key}] + set i 0 + foreach value $valuelist { + .drcmgr.box.view insert $id end -text "$value" + incr i + } +} + + +#-------------------------------------------------------------- +# The cell manager window main callback function +#-------------------------------------------------------------- + +proc magic::drcmanager {{option "update"}} { + global editstack + global CAD_ROOT + + # Check for existence of the manager widget + if {[catch {wm state .drcmgr}]} { + if {$option == "create"} { + magic::makedrcmanager .drcmgr + } else { + return + } + } elseif { $option == "create"} { + return + } + + magic::suspendall + + # Get existing list of error classes and remove them + set currules [.drcmgr.box.view children {}] + foreach rule $currules { + .drcmgr.box.view delete ${rule} + } + + # Run DRC + select top cell + set drcdict [dict create {*}[drc listall why]] + + # set first true + dict for {key value} $drcdict { + magic::adddrcentry ${key} ${value} + # .drcmgr.box.view item ${key} -open $first + # set first false + } + magic::resumeall +} + +} ;# (if Tk version 8.5) + diff --git a/tcltk/wrapper.tcl b/tcltk/wrapper.tcl index cb1f1e73..563778d5 100644 --- a/tcltk/wrapper.tcl +++ b/tcltk/wrapper.tcl @@ -367,6 +367,10 @@ catch {source ${CAD_ROOT}/magic/tcl/cellmgr.tcl} catch {source ${CAD_ROOT}/magic/tcl/libmgr.tcl} +# Generate the DRC manager + +catch {source ${CAD_ROOT}/magic/tcl/drcmgr.tcl} + # Generate the text helper catch {source ${CAD_ROOT}/magic/tcl/texthelper.tcl} @@ -1404,6 +1408,13 @@ proc magic::openwrapper {{cell ""} {framename ""}} { } else { \ wm withdraw .techmgr } }] + $m add check -label "DRC Manager" -variable Opts(drcmgr) \ + -command [subst { magic::drcmanager create; \ + if { \$Opts(drcmgr) } { \ + wm deiconify .drcmgr ; raise .drcmgr \ + } else { \ + wm withdraw .drcmgr } }] + $m add check -label "Netlist Window" -variable Opts(netlist) \ -command [subst { if { \[windownames netlist\] != {}} { \ set Opts(netlist) 0 ; closewindow \[windownames netlist\] \