1#!/usr/local/bin/tclsh8.6
2#---------------------------------------------------------------------------
3# annotate.tcl ---
4#
5# Read a file "antenna.out" produced by qrouter, and use this to
6# back-annotate the <project>.v verilog structural netlist for input
7# to static timing analysis.
8#
9# The "antenna.out" file contains connections made by the router to
10# antenna anchoring cells.  It is solely a product of the routing and
11# should not permanently affect any netlist that becomes input to any
12# stage prior to routing (e.g., the .blif or .cel files used for
13# placement).
14#
15# The output is written to the filename specified.  Input and output
16# files are opened at the same time, so do not specify the same file to
17# be overwritten.
18#
19# 5/18/2018:  A file "fillcells.txt" containing all the fill cells added
20# to the design may be appended to the "antenna.out" file.  Add these to
21# the netlist as well.  However, antenna entries in "antenna.out" also
22# appear in "fillcells.txt", so ignore redundant entries.
23#---------------------------------------------------------------------------
24
25namespace path {::tcl::mathop ::tcl::mathfunc}
26
27if {$argc != 3 && $argc != 4} {
28   puts stdout "Usage:  annotate.tcl <antenna_file> <verilog_file> <verilog_out> [<pwrgnd_file>]"
29   exit 0
30}
31
32puts stdout "Running annotate.tcl"
33
34set antennaname [lindex $argv 0]
35set vlogname [lindex $argv 1]
36set vlogoutname [lindex $argv 2]
37
38# If an additional file name is given, it should point to the file
39# that sets vddnet and gndnet in the design (picked up from the LEF
40# files, so no need to re-parse them.
41
42if {$argc == 4} {
43   set pwrgndfile [lindex $argv 3]
44
45   if [catch {open $pwrgndfile r} fpwr] {
46      puts stderr "Can't open file $pwrgndfile for input, assuming standard names."
47      set vddnet false
48      set gndnet false
49   } else {
50
51      # Read file and evaluate the same way the other shell script files are
52      # in other of the qflow Tcl scripts (e.g., ypostproc.tcl).
53
54      while {[gets $fpwr line] >= 0} {
55         set tcmd [string map {= \ } $line]
56         eval $tcmd
57      }
58      close $fpwr
59   }
60} else {
61   set vddnet false
62   set gndnet false
63}
64
65set debug false
66
67#-----------------------------------------------------------------
68# Open antenna file for reading
69#-----------------------------------------------------------------
70
71if [catch {open $antennaname r} fant] {
72   puts stderr "Error: can't open file $antennaname for input"
73   exit 1
74}
75
76#-----------------------------------------------------------------
77# Read the antenna update file.
78#-----------------------------------------------------------------
79
80set added 0
81set changelist [dict create]
82set instlist [dict create]
83
84# NOTE:  Lines in section "Unfixed antenna errors" are not nets to be
85# annotated, but a list of nets that are creating DRC antenna errors.
86# These nets are ignored.
87
88set in_unfix false
89while {[gets $fant line] >= 0} {
90   if {$in_unfix == false} {
91      if [regexp {[ \t]*Net=([^ \t]+)[ \t]+Instance=([^ \t]+)[ \t]+Cell=([^ \t]+)[ \t]+Pin=([^ \t]+)} $line lmatch netname instname cellname pinname] {
92         # Keep instances seen in a dictionary and ignore redundant entries
93         if [catch {dict get $instlist $instname}] {
94            incr added
95            dict set changelist $instname [list $netname $cellname $pinname]
96	    dict set instlist $instname true
97         }
98      }
99   }
100   if [regexp {[ \t]*Unfixed antenna errors:} $line lmatch] {
101      set in_unfix true
102   } elseif [regexp {[ \t]*# Fill cell instances} $line lmatch] {
103      set in_unfix false
104   }
105}
106if {$added == 0} {
107   puts stdout "No nets needed annotating."
108   exit 0
109}
110
111close $fant	;# Done with antenna input file
112
113#-----------------------------------------------------------------
114# Open verilog files for reading and writing
115#-----------------------------------------------------------------
116
117if [catch {open $vlogname r} fvlog] {
118   puts stderr "Error: can't open file $vlogname for input"
119   exit 1
120}
121
122if [catch {open $vlogoutname w} fvout] {
123   puts stderr "Error: can't open file $vlogoutname for output"
124   exit 1
125}
126
127while {[gets $fvlog line] >= 0} {
128   if [regexp {[ \t]*endmodule} $line lmatch] {
129      # Insert the list here
130      dict for {instname netchange} $changelist {
131	 set netname [lindex $netchange 0]
132	 set cellname [lindex $netchange 1]
133	 set pinname [lindex $netchange 2]
134	 if {${pinname} != "-" && ${pinname} != ""} {
135	    puts $fvout "${cellname} ${instname} ( .${pinname}(${netname}) );"
136	 } else {
137	    puts $fvout "${cellname} ${instname} ( );"
138	 }
139      }
140   }
141   puts $fvout $line
142}
143
144close $fvlog
145close $fvout
146
147puts stdout "Done with annotate.tcl"
148exit 0
149