From e1783a42a92e1e037009c6f2ce2bc07f632f0781 Mon Sep 17 00:00:00 2001 From: Tim Edwards Date: Fri, 15 Nov 2019 10:26:04 -0500 Subject: [PATCH] Added a "DRC manager" window option. This allows DRC errors to be categorized by error type and scrolled through conveniently. However, it needs work dealing with finding the actual error bounds. The "DRC count" counts tiles, which is tile-plane-geometry-specific, and "DRC listall why" fractures errors both over tiles and over the square areas that the interactive DRC splits the layout into, for performance. The DRC error plane needs to be changed to hold different types for each error class, so that errors can be scanned by boundary instead of by tile (work to be done). --- commands/CmdCD.c | 89 ++++++++------------- drc/DRCmain.c | 93 +++------------------- drc/drc.h | 11 +-- tcltk/Makefile | 1 + tcltk/drcmgr.tcl | 195 ++++++++++++++++++++++++++++++++++++++++++++++ tcltk/wrapper.tcl | 11 +++ 6 files changed, 251 insertions(+), 149 deletions(-) create mode 100644 tcltk/drcmgr.tcl 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\] \