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