gsch2pcb: Make --m4-file and -m4-pcbdir arguments work again.
[geda-gaf/peter-b.git] / utils / scripts / gnet_hier_verilog.sh
blob45ef4395148af61a188ca5d7076936105776ebfa
1 #!/bin/bash
2 # gEDA - GPL Electronic Design Automation
3 # Copyright (C) 2007-2008 Paul Tan (pt75234 at users.sourceforge.net)
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 # ========================================================
19 # Description:
20 # Generate non-flatten hierarchical Verilog netlist
21 # gnet_hier_verilog.sh
22 # version 0.0.2
23 # Usage:
24 # [path]gnet_hier_verilog.sh [path]FileName.sch
25 # Requires gawk and gEDA's gnetlist gnet-verilog.scm
26 # Please set tab = 2 for readability
27 # Written by Paul Tan
28 # ========================================================
29 # 1) This is a simple draft bash script to produce a
30 # hierarchical verilog netlist in a single file.
31 # It gathers hierarchical information from a list of
32 # unique symbols/schematics originating from the top level
33 # schematic all the way down to the lowest level of the
34 # design hierarchy. It then successively invokes the
35 # existing gEDA verilog netlister to produce each single
36 # level netlists, and concatinates all the unique
37 # module netlists into one single hierarchical netlist
38 # file.
39 # 2) Currently, it assumes that one or more hierarchical symbol
40 # can be represented by a single schematic file. If needed,
41 # feature for mutiple schematic files mapped to a single symbol
42 # can be easily added. In that case, multiple source attrib
43 # are used in that symbol.
44 # 3) It checks the follwoing errors while traversing down
45 # the hierarchy and terminates the netlisting if error
46 # is found.
47 # a) if a symbol's source attribute indicated schematic can not
48 # be found in the search paths defined by gafrc.
49 # b) if a symbol's device attribute value does not match its
50 # corresponding schematic's module_name attribute value.
51 # 4) This script assumes that there are no other errors in the
52 # entire hierarchy, and that the user has already run the
53 # DRC. Moreover, it assumes that the user has run the single
54 # level verilog netlister on each schematic in the hierarchy
55 # without any error. it also assumes that the hierarchy-traverse
56 # is disabled in gnetlistrc, thus disables flatten hierarchical
57 # netlist generation.
58 # 5) Netlist of modules are listed from top down, can easily be
59 # changed to do bottom up.
60 # 6) Symbol must contain "source=????.sch" attribute to have its
61 # schematic netlisted. Otherwise, symbol is treated just as
62 # primitive instances in the netlist.
63 # 7) It only uses the gafrc file in the folder where the top level
64 # schematic resides. The search path for the symbols and
65 # schematics should be defined in that gafrc file. The
66 # current implementation searches from the beginning
67 # of the file, it will be changed to conform to the gEDA
68 # practice of searching from the bottom first.
69 # 8) Hierarchy info is output to a report file for reference.
70 # 9)This script is optimized for readability only, I hope.
71 # 10)Array variables are suffixed with A, e,g,, HLineA[]
72 # ========================================================
73 # To do list
74 # -------------------------------------------------------
75 # 1) Multi-page sch per symbol support
76 # 2) Use the "file" attrib to include user defined netlist
77 # 3) Include .gnetlistrc and other config files info to search
78 # 4) Change search order for sym/sch libs to LIFO (last in fisrt out)
79 # 5) Recode the script in C or scheme ?
80 # 6) Add CL args to support VHDL and Spice hier netlist
81 # 7) Add error checks:
82 # a) add ERC (Electrical_Rule_Check) if not already checked
83 # by gnetlist DRC.
84 # ========================================================
86 # Notes
88 # ========================================================
89 # First we create a master list in a record array HierListA[].
90 # HierListA[] will contain a list of records of all unique symbols
91 # under the top schematics and all its underlying schematics.
92 # This master record list will be output to a text file
93 # for reference.
94 # Then we'll invoke the gnetlist program to netlist each of
95 # the schematics representing the symbols on the list,
96 # concatinating each netlist into the top level netlist.
98 # Each record of HierListA[] has 5 or more fields:
99 # 0 1 2 3 4 [5] ...
100 # ItemNum Flag Sym_Name Sch_Dir Sch_Name [Sch_Name] ..
101 # -------------------------------------------------------
102 # Corresponding variables declared in this script
103 # $iN $iFlag $iSym $iSchDir $iSch
104 # $CurIndex $CurFlag $CurSym $CurDir $CurSch ; In master
105 # $EndIndex $Tflag $Tsym $TschDir $Tsch ; To add
106 # -------------------------------------------------------
107 # The Flag is used to indicate if a schematic needs to
108 # be netlisted.
109 # Flag = 0 means NOT to netlist the schematic.
110 # Flag = 1 means to netlist the schematic.
111 # Flag = 2 means NOT to netlist, since other symbol already
112 # has the same schematic listed.
113 # ----------------------------------------------
114 # For multiple pages(files) schematic, use more than 5 fields
115 # in a record.
116 # ========================================================
118 # Script starts here
120 # ========================================================
121 # Configurable items
122 # ---------------------------------------
123 # Define the symbol's attribute to be used for its
124 # associated schematic.
125 src_attrib="source"
126 # ---------------------------------------
127 # version
128 ver=0.0.2
129 My_Debug=0
130 # ========================================================
131 my_error=0
132 my_ext=""
133 echo
134 if [ -z $1 ]
135 then my_error=1
137 # ---------------------------------------
138 # To be changed: loop thru multiple sch files from CL's args
139 if [ $my_error == 0 ]; then
140 TopSchFile=$1
141 my_ext=${TopSchFile#*.}
142 if [ "$my_ext" != "sch" ]; then
143 my_error=1
146 # ---------------------------------------
147 if [ $my_error == 1 ]; then
148 echo "Error:"
149 echo -n "Please include a gEDA schematic file"
150 echo " as its argument."
151 echo " Usage:"
152 echo " [path]gnet_hier_verilog.sh [path]FileName.sch"
153 exit 1
155 # ---------------------------------------
156 TopDir=$(dirname $1)
157 cd $TopDir
158 TopDir=$PWD
159 TopBaseFile=$(basename $1 .sch)
160 CurSchFile=$1
161 TopVFile="${TopBaseFile}.v"
162 ReportFile="${TopBaseFile}_Report.txt"
163 TemptFile="hier_temp.v"
164 # ---------------------------------------
165 echo
166 echo "Starting Hierarchical Verilog Netlister version ${ver} ....."
167 # ===============================================
168 if [ $My_Debug == 1 ]
169 then
170 echo
171 echo '======== Start Debug ==========='
172 echo "TopDir = $TopDir"
173 echo "TopBaseFile = $TopBaseFile"
174 echo "CurSchFile = $CurSchFile"
175 echo "ReportFile = $ReportFile"
177 # ----------------------------------------------
179 # Init all indices:
180 # Fields position in a record
181 iN=0; iFlag=1; iSym=2; iSchDir=3; iSch=4
182 # ----------------------------------------------
183 # Initialize master list HierListA[]'s first record
184 CurIndex=0
185 EndIndex=0
186 Tflag=1
187 Tsym="${TopBaseFile}.sym"
188 Tsch="${TopBaseFile}.sch"
189 TschDir="."
190 # Fields in each row of record
191 HLineA[$iN]=$EndIndex
192 HLineA[$iSym]=$Tsym
193 HLineA[$iSch]=$Tsch
194 HLineA[$iSchDir]=$TschDir
195 HLineA[$iFlag]=$Tflag
196 # First row of record in master list
197 HierListA[0]=`echo ${HLineA[@]:0}`
198 # ----------------------------------------------
199 # Initialize other lists
200 # ----------------------------------------------
201 # Get gEDA gafrc's symbol and schematic search paths
202 # into their respective list arrays
203 SymDirListA=( `
204 gawk 'BEGIN {FS="\""}
205 (NF >= 1)&&($1 == "(component-library ") {
206 printf("%s\n",$2);
207 }' gafrc` )
208 # ----------------------------------------------
209 SrcDirListA=( `
210 gawk 'BEGIN {FS="\""}
211 (NF >= 1)&&($1 == "(source-library ") {
212 printf("%s\n",$2);
213 }' gafrc` )
215 # ===============================================
216 if [ $My_Debug == 1 ]; then
217 echo "---------------------------"
218 echo -n "SymDirList n = "
219 echo ${#SymDirListA[*]}
220 for i in "${SymDirListA[@]}"; do echo "$i"; done
221 echo "---------------------------"
222 echo -n "SrcDirList n = "
223 echo ${#SrcDirListA[*]}
224 for i in "${SrcDirListA[@]}"; do echo "$i"; done
225 echo "---------------------------"
227 # ###############################################
228 # Process each record from the master list
229 while (("$CurIndex" <= "$EndIndex"))
231 # Get a record from the master list
232 CurA=( ${HierListA[$CurIndex]} )
233 CurFlag=${CurA[$iFlag]}
234 CurSchFile=${CurA[$iSch]}
235 CurSchDir=${CurA[$iSchDir]}
236 if [ "$CurSchDir" == "." ]
237 then CurSchPath=$CurSchFile
238 else CurSchPath=`echo "$CurSchDir/$CurSchFile"`
240 CurSchBase=$(basename $CurSchFile .sch)
241 # --------------------------------
242 # Only Flag=1 entry will get netlisted and processed
243 # down the hierarchy
244 if [ "$CurFlag" != 1 ]; then
245 let "++CurIndex"
246 continue
248 # ----------------------------------------------
249 # if needed, this is the place to generate netlist
250 # for each record. For now, we netlist at the end
251 # after we have generated all the records
252 # ----------------------------------------------
253 # To be changed: loop thru pages of schs
254 # ----------------------------------------------
255 # Get all instances of any symbols from current schematic
256 # into TempSymListA[]
257 TempSymListA=( `
258 gawk '(NF==7)&&($1=="C") {printf("%s\n",$7)}' $CurSchPath
260 # ----------------------------------------------
261 # Make a unique symbol list from it
262 TSymListA[0]=${TempSymListA[0]}
263 found=0
264 let "k = 0"
265 for i in "${TempSymListA[@]}"; do
266 found=0
267 for j in "${TSymListA[@]}"; do
268 if [ "$i" == "$j" ]; then
269 found=1
270 break
272 done # for j
273 if [ $found == 1 ]; then continue
275 let "++k"
276 TSymListA[$k]=$i
277 done # for i
278 unset TempSymListA
279 # ===============================================
280 # Check if Tsym already exist in the master list
281 # if not on list, add to the list
282 found=0
283 for Tsym in "${TSymListA[@]}"; do
284 found=0
285 for HLineA in "${HierListA[@]}"; do
286 HierA=( `echo $HLineA` )
287 HierSym=${HierA[$iSym]}
289 if [ "$Tsym" == "$HierSym" ]; then
290 found=1
291 break
293 done
295 if [ $found == 1 ]; then continue
297 # ===================================
298 # Find the Symbol file and its folder
299 found=0
300 for i in "${SymDirListA[@]}"; do
301 TsymPath=`echo "$i/$Tsym"`
302 if [ -e $TsymPath ]; then
303 found=1
304 TsymDir=$i
305 break
307 done
309 if [ $found == 0 ]; then
310 echo "Error: "
311 echo " $Tsym file not found. Please check the search path"
312 echo " defined in the gafrc file."
313 exit 1
315 # ---------------------------------
316 # Find the schematic file name for the symbol from:
317 # 1) The "source" attribute in the symbol file of
318 # the $TsymDir folder.
319 # 2) If no "source", use the symbol basename as the schematic
320 # basename? For now, must use "source".
321 # 3) Note that the sch file must contain "module_name"
322 # attrubute whose value must match the value of the
323 # "device" attribute from the sym file. This script
324 # checks for this condition.
325 # Given the schematic file name, search its folder path in:
326 # 1) Source folders specified in the gEDA rc file
327 # ---------------------------------
328 TsymBase=$(basename $Tsym .sym)
329 TschDir=$TsymDir
330 Tflag=0
331 # ---------------------------------
332 # Get "source" and "device" attributes from sym file
333 # and store them in SymAttribListA[]
334 SymAttribListA=( `
335 gawk -v src=$src_attrib 'BEGIN {FS="="}
336 (NF==2)&&($1 == src) {print $0};
337 (NF==2)&&($1 == "device") {print $0}
338 ' $TsymPath` )
339 # ---------------------------------
340 # To be changed: add a list of sources SymSrcList[]
341 # to support multi-page
342 # ---------------------------------
343 # Check if source exist in SymAttribListA[]
344 Tsch=""
345 for i in "${SymAttribListA[@]}"; do
346 if [ "${i%=*}" == "$src_attrib" ]; then
347 Tsch=${i#*=}; break
349 done
350 # ---------------------------------
351 if [ "$Tsch" == "" ]; then
352 Tsch="None"; Tflag=0
353 else
354 # ---------------------------------
355 # Found sch name, check if already on master list
356 found=0
357 for HLineA in "${HierListA[@]}"; do
358 HierA=( `echo $HLineA` )
359 HierSch=${HierA[$iSch]}
360 if [ "$Tsch" == "$HierSch" ]; then
361 found=1
362 break
364 done
365 # If sch not on master list, need further check
366 if [ $found == 0 ]; then
367 Tflag=2
370 # ---------------------------------
371 # if sch not on list, search for sch path
372 if [ $Tflag == 2 ]; then
373 found=0
374 for i in "${SrcDirListA[@]}"; do
375 TschPath=`echo "$i/$Tsch"`
376 if [ -e $TschPath ]; then
377 found=1
378 TschDir=$i
379 break
381 done
382 # if can't find sch path, error and exit
383 if [ $found == 0 ]; then
384 echo -n "Error: $Tsch is the $src_attrib attribute in "
385 echo -n "$Tsym but NOT in the gafrc "
386 echo "source-directory path."
387 Tflag=3
388 exit 1
390 # ---------------------------------
391 # Found sch path, check if sch's
392 # sch's module_name attribute = sym's device attribute
393 # ---------------------------------
394 # Get module_name attrib from sch file
395 TModule=""
396 TModule=( `
397 gawk 'BEGIN {FS="="}
398 (NF == 2)&&($1 == "module_name") {
399 printf("%s\n", $2); exit}' $TschPath` )
400 # ---------------------------------
401 # Check if module_name = device from SymAttribListA[]
402 # ---------------------------------
403 Tdev=""
404 for i in "${SymAttribListA[@]}"; do
405 if [ "${i%=*}" == "device" ]; then
406 Tdev=${i#*=}; break
408 done
409 # ---------------------------------
410 if [[ "$TModule" != "" ]] && [[ "$TModule" == "$Tdev" ]]
411 then Tflag=1
412 else
413 echo "Error: "
414 echo " $Tsym Symbol's device attribute $Tdev does not match"
415 echo " $Tsch schematic's module_name attribute $TModule."
416 exit 1
418 # ---------------------------------
420 # ===================================
421 # Add a new record into the master list HierListA[]
422 let "++EndIndex"
423 HLineA[$iN]=$EndIndex
424 HLineA[$iFlag]=$Tflag
425 HLineA[$iSym]=$Tsym
426 HLineA[$iSchDir]=$TschDir
427 HLineA[$iSch]=$Tsch
428 HierListA[$EndIndex]=`echo ${HLineA[@]:0}`
429 # ---------------------------------
430 if [ $My_Debug == 3 ]; then
431 echo "Added new record"
432 echo ${HierListA[$EndIndex]}
433 echo
435 # ---------------------------------
436 done # done. for Tsym
437 unset TSymListA
438 # ===============================================
439 let "++CurIndex"
440 done # done generating master list
442 # ###############################################
443 # Generate a report file
444 echo "# Hierarchical netlist report for:" >$ReportFile
445 echo "# $TopSchFile" >>$ReportFile
446 echo "# ------------------------">>$ReportFile
447 # comments fields
448 HLineA[$iN]="Index"
449 HLineA[$iFlag]="Flag"
450 HLineA[$iSym]="Sym"
451 HLineA[$iSch]="Sch"
452 HLineA[$iSchDir]="Sch_Dir"
453 echo "# ${HLineA[@]:0}" >>$ReportFile
454 echo "# ------------------------">>$ReportFile
455 for i in "${HierListA[@]}"; do
456 echo $i >>$ReportFile
457 done
459 # ###############################################
460 # Generate netlist from record in the master list
461 # Only Flag=1 record will be netlisted
462 # ###############################################
463 echo
464 echo "Generating hierarchical netlist ...... "
465 let "CurIndex=0"
466 let "EndIndex=${#HierListA[@]}-1"
467 # -----------------------------------
468 if [ $My_Debug == 2 ]; then
469 echo
470 echo "CurIndex = $CurIndex"
471 echo "EndIndex = $EndIndex"
472 echo
474 # -----------------------------------
475 while (("$CurIndex" <= "$EndIndex"))
477 # Get a record from the master list
478 CurA=( ${HierListA[$CurIndex]} )
479 # Get fields of the selected record
480 CurFlag=${CurA[$iFlag]}
481 CurSchFile=${CurA[$iSch]}
482 CurSchDir=${CurA[$iSchDir]}
483 if [ "$CurSchDir" == "." ]
484 then CurSchPath=$CurSchFile
485 else CurSchPath=`echo "$CurSchDir/$CurSchFile"`
487 CurSchBase=$(basename $CurSchFile .sch)
488 # --------------------------------
489 # Only Flag=1 entry will get netlisted
490 if [ $CurFlag != 1 ]; then
491 let "++CurIndex"
492 continue
494 # --------------------------------
495 # To be changed: add multi-page netlist
496 # --------------------------------
497 if [ "$CurIndex" -eq 0 ]
498 then
499 gnetlist -g verilog -o $TopVFile $TopSchFile
500 else
501 gnetlist -g verilog -o $TemptFile $CurSchPath
502 # Skip header portion of each netlist
503 gawk 'BEGIN{found = 0}
504 (NF >= 1)&&($1 == "module")&&(found == 0){
505 found = 1;
506 printf("\n/* --------------------------------- */\n");
508 (NR > 0)&&(found == 1){
509 print $0;
511 ' $TemptFile >>$TopVFile
513 # --------------------------------
514 let "++CurIndex"
515 done
516 echo
517 echo "Hierarchical Verilog netlist successfully completed."
518 echo