#------------------------------------------------------ # 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.save -text "Save" -command {magic::drc_save_report} 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.save -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) #--------------------------------------------------- # Alternative way to view/save DRC errors in magic. # Dump a text file of errors and positions. Note # that the dump, using "drc listall why", enumerates # every single edge check and is therefore more # detailed than the areas declared by "drc count" # or enumerated in "drc find". #--------------------------------------------------- proc magic::drc_save_report {{cellname ""} {outfile ""}} { if {$outfile == ""} {set outfile "drc.out"} set fout [open $outfile w] set oscale [cif scale out] # magic::suspendall if {$cellname == ""} { select top cell set cellname [cellname list self] set origname "" } else { set origname [cellname list self] puts stdout "loading $cellname\n" flush stdout load $cellname select top cell } drc check set count [drc list count] puts $fout "$cellname $count" puts $fout "----------------------------------------" set drcresult [drc listall why] foreach {errtype coordlist} $drcresult { puts $fout $errtype puts $fout "----------------------------------------" foreach coord $coordlist { set bllx [expr {$oscale * [lindex $coord 0]}] set blly [expr {$oscale * [lindex $coord 1]}] set burx [expr {$oscale * [lindex $coord 2]}] set bury [expr {$oscale * [lindex $coord 3]}] set coords [format " %.3f %.3f %.3f %.3f" $bllx $blly $burx $bury] puts $fout "$coords" } puts $fout "----------------------------------------" } puts $fout "" if {$origname != ""} { load $origname } # magic::resumeall close $fout puts stdout "done with $outfile\n" flush stdout } #--------------------------------------------------- # Read back a dumped file of DRC errors. This is of # limited use, as any layout should have DRC errors # already marked. This routine loads errors into # "feedback" areas, which is redundant to the error # tiles. However, feedback areas are more precise, # as they mark the error area at each checked edge #--------------------------------------------------- proc magic::drc_load_report {{drc_file ""}} { if {$drc_file == ""} { set drc_file "drc.out" } set fin [open $drc_file r] puts stdout "Reading $drc_file\n" flush stdout magic::suspendall set error_text "" while {[gets $fin line] >= 0} { if {[string first " " $line] == 0} { if [regexp { ([^ ]+) ([^ ]+) ([^ ]+) ([^ ]+)} $line lmatch llx lly urx ury] { feedback add "$error_text" vert_highlights ${llx}um ${lly}um \ ${llx}um ${ury}um ${urx}um ${ury}um ${urx}um ${lly}um } } elseif {[string first "-" $line] != 0} { set error_text $line } } magic::resumeall close $fin puts stdout "Done.\n" puts stdout "Use \"feedback find\" to enumerate errors.\n" flush stdout }