1#!/usr/local/bin/tclsh8.6
2#
3# Usage:
4#	blif2sim.tcl <blif_filename> <dir> [<sim_filename>]
5#
6# If cel_filename is not specified, then name will be the root name
7# of the .blif file with the .sim extension.
8#
9# "dir" is the directory where .sim views of the standard cells are
10# located.  If .sim views are not available but .mag files are, the
11# .sim files will be generated automatically.
12#
13#------------------------------------------------------------
14# Written by Tim Edwards February 12, 2007
15# MultiGiG, Inc.
16#------------------------------------------------------------
17
18set bliffile [lindex $argv 0]
19set cellname [file rootname $bliffile]
20if {"$cellname" == "$bliffile"} {
21   set bliffile ${cellname}.blif
22}
23
24set prefix ""
25if {$argc > 2} {
26   if {[lindex $argv [expr {$argc - 2}]] == "-prefix"} {
27      set prefix [lindex $argv [expr {$argc - 1}]]/
28      incr argc -2
29   }
30}
31
32if {$argc > 1} {
33   set magdir [lindex $argv 1]
34} else {
35   set magdir /home/tim/projects/multigig/digital_flow/layout/digital2
36}
37
38if {$argc == 3} {
39   set simfile [lindex $argv 2]
40} else {
41   set simfile ${cellname}.sim
42}
43
44set scriptdir [file dirname $argv0]
45
46#-------------------------------------------------------------
47# Open files for read and write
48
49if [catch {open $bliffile r} fnet] {
50   puts stderr "Error: can't open file $bliffile for reading!"
51   exit 0
52}
53
54#----------------------------------------------------------------
55# First, parse the contents of the .blif file and get a list
56# of all macro names used.
57#----------------------------------------------------------------
58
59puts stdout "1st pass of blif file ${bliffile}. . ."
60flush stdout
61
62set macrolist {}
63while {[gets $fnet line] >= 0} {
64   if [regexp {^INSTANCE[ \t]+"([^"]+)"} $line lmatch macro] {
65      lappend macrolist $macro
66   }
67}
68set macrolist [lsort -unique $macrolist]
69close $fnet
70
71set needsims {}
72foreach macro $macrolist {
73   if {[glob -nocomplain ${magdir}/${macro}.sim] == {}} {
74      lappend needsims ${macro}
75   } elseif {[file size ${magdir}/${macro}.ext] == 0} {
76      lappend needsims ${macro}
77   }
78}
79
80if {$needsims != {}} {
81   puts stdout "Generating .sim views. . ."
82   flush stdout
83
84   foreach macro $needsims {
85      puts stdout "Generating ${macro}.sim"
86      flush stdout
87      catch {exec ${scriptdir}/makesim.sh ${magdir}/$macro}
88   }
89}
90
91if [catch {open $simfile w} fsim] {
92   puts stderr "Error: can't open file $simfile for writing!"
93   exit 0
94}
95
96puts $fsim "| SIM file $simfile generated by blif2sim"
97
98#----------------------------------------------------------------
99# Procedure to dump the contents of a subcircuit .sim file to the
100# top-level .sim file, replacing pin names with net names.
101#----------------------------------------------------------------
102
103proc dump_sim {fsim mode magdir prefix} {
104
105   # Pick up variable definition from top-level
106   upvar $mode mname
107
108   # Make VDD, VSS, and GND show up as globals
109   set mname(VDD)  VDD
110   set mname(VDD!) VDD
111   set mname(VSS)  VSS
112   set mname(VSS!) VSS
113   set mname(GND)  GND
114   set mname(GND!) GND
115
116   set fsub [open ${magdir}/${mode}.sim r]
117   while {[gets $fsub line] >= 0} {
118      set mtype [string index $line 0]
119
120      # Parse .sim file lines.  Ignore lumped "R", which is not used by IRSIM.
121
122      switch -exact $mtype {
123	 n -
124	 p { regexp {^[pn] ([^ ]+) ([^ ]+) ([^ ]+) (.*)} $line valid \
125			gate drain source rest
126	     puts -nonewline $fsim "$mtype "
127	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${gate}) "}]} {
128		puts -nonewline $fsim "${prefix}${mode}$mname(count)/$gate "
129	     }
130	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${drain}) "}]} {
131		puts -nonewline $fsim "${prefix}${mode}$mname(count)/$drain "
132	     }
133	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${source}) "}]} {
134		puts -nonewline $fsim "${prefix}${mode}$mname(count)/$source "
135	     }
136	     puts $fsim $rest
137	   }
138	 r { regexp {^r ([^ ]+) ([^ ]+) (.*)} $line valid r1 r2 rest
139	     puts -nonewline $fsim "r "
140	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${r1}) "}]} {
141		puts -nonewline $fsim "${prefix}${mode}$mname(count)/$r1 "
142	     }
143	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${r2}) "}]} {
144		puts -nonewline $fsim "${prefix}${mode}$mname(count)/$r2 "
145	     }
146	     puts $fsim $rest
147	   }
148	 C { regexp {^C ([^ ]+) ([^ ]+) (.*)} $line valid top bottom rest
149	     puts -nonewline $fsim "C "
150	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${top}) "}]} {
151		puts -nonewline $fsim "${prefix}${mode}$mname(count)/$top "
152	     }
153	     if {[catch {puts -nonewline $fsim "${prefix}$mname(${bottom}) "}]} {
154		puts -nonewline $fsim "${prefix}${mode}$mname(count)/$bottom "
155	     }
156	     puts $fsim $rest
157	   }
158	 | { puts $fsim $line }
159      }
160   }
161   close $fsub
162}
163
164#----------------------------------------------------------------
165# Parse the contents of the .blif file again and dump each cell
166# instance to the .sim file output.
167
168puts stdout "2nd pass of blif file. . ."
169flush stdout
170
171set fnet [open $bliffile r]
172set mode none
173while {[gets $fnet line] >= 0} {
174   if [regexp {^INSTANCE[ \t]+"([^"]+)"[ \t]*:[ \t]*"([^"]+)"} $line \
175		lmatch macroname macrotype] {
176      # New instance.  First dump the current instance to the sim file
177      if {$mode != "pins" && $mode != "none"} { dump_sim $fsim $mode $magdir $prefix}
178
179      # (There is now a valid mag/ext/sim file for TIELO and TIEHI)
180      # if [string equal $macroname TIELO] {gets $fnet line; continue}
181      # if [string equal $macroname TIEHI] {gets $fnet line; continue}
182      set mode $macroname
183      if {[catch {incr ${mode}(count)}]} {set ${mode}(count) 0}
184   } elseif [regexp {^ENDMODEL} $line lmatch] {
185      # Dump last "mode" output
186      if {$mode != "pins"} { dump_sim $fsim $mode $magdir $prefix}
187   } elseif [regexp {^INPUT} $line lmatch] {
188      set mode "pins"
189   } elseif [regexp {^OUTPUT} $line lmatch] {
190      set mode "pins"
191   } elseif [regexp {^MODEL[ \t]+"([^"]+)"} $line lmatch cellverify] {
192      if {"$cellname" != "$cellverify"} {
193	 puts -nonewline stderr "WARNING:  MODEL name ${cellverify} does not"
194	 puts stderr " match filename ${cellname}!"
195      }
196   } elseif {"$mode" == "pins"} {
197      if [regexp {"([^"]+)"[ \t]*:[ \t]*"([^"]+)"} $line lmatch pinname netname] {
198	 # Don't do anything with these.
199      }
200   } else {
201      # In the middle of parsing an instance;  mode = instance name (in lowercase).
202      if [regexp {"([^"]+)"[ \t]*:[ \t]*"([^"]+)"} $line lmatch pinname netname] {
203	 set ${mode}(${pinname}) $netname
204      }
205   }
206}
207# Dump the final instance to the sim file, if there was one.
208if {$mode != "pins" && $mode != "none"} { dump_sim $fsim $mode $magdir $prefix}
209close $fnet
210
211puts stdout "Done!"
212