( ESNUG 224 Item 4 ) ---------------------------------------------- [8/8/95]
From: wboeke@hzsda01.att.com (W. Boeke)
Subject: Scripting Hierarchical Compiles & Critiques Of The Scripting Language
Hi, John!
This letter serves 2 purposes. First I want to express my rejoice that I
finally managed to write a generic, robust Design Compiler script for
hierarchical designs. Second I want to criticize the semantics of the dc_shell
scripting language, and find out if my colleague ESNUG members share these
opinions.
My goal was to write a script that does a true hierarchical compile, such that
the user only has to supply the HDL entities that have been modified. The tool
then should leave the other designs in the hierarchy unmodified. The problem
is that the user does not know the names of subdesigns, because Design
Compiler gives fancy names to them during scan-chain insertion, uniquifying
and parameterizing of the subdesigns. The script exists in several varieties,
depending on how the scan-chains are specified: described in the source HDL or
inserted automatically. I give the version in which all scan-chains are
created by the tool. Here comes part of the script:
1 | Top_design = des_a
2 | Re_analyze = { des_b des_c }
3 | read db/ + Top_design + .db
4 | current_design Top_design
5 | check_design /* Needed for setting attributes */
6 | Sub_designs = find(reference "*")
| Sub_designs = filter(Sub_designs,"@is_hierarchical == true && \
@is_synlib_operator == false")
7 | foreach(Cur_design, Sub_designs) {
8 | current_design find(design,Cur_design)
9 | Name = get_attribute(find(design,Cur_design),hdl_template)
10 | foreach(Name,Name) {
11 | rename_design find(design,Cur_design) Name
12 | if (dc_shell_status == 0) { remove_design find(design,Cur_design)
| }
| }
| }
Variable Re_analyze in line 2 determines the HDL files that must be
(re)analyzed. In line 3 the hierarchical design is read from the database. In
line 6, a list of all relevant subdesigns is assigned to variable Sub_designs.
In line 7, a tric starts: all subdesigns get a name equal to the original name
as specified in the HDL source text. Designs with duplicate names are removed.
The foreach loop in line 10 has one purpose: in line 9 variable Name has value
{xxx}, whereas in line 11 a value xxx (without curly braces) is needed.
13 | foreach(Cur_design, Re_analyze) {
14 | Parameter = ""
15 | if (Cur_design == xx) { File = { xx xx-bhv }; Parameter = "width=>4"
16 | } else { File = Cur_design
| }
17 | foreach(File,File) { File = vhdl/ + File + .vhd
18 | analyze -f vhdl File
| }
19 | if (Cur_design != Top_design) {
20 | remove_design find(design Cur_design)
21 | elaborate Cur_design -par Parameter
| }
| }
Starting line 13, dedicated HDL files are re-analyzed. By the if statement in
line 15, file names and VHDL generics are specified. Before elaboration in
line 21, the old subdesign must be removed, because else it would be placed in
memory 2 times, which would yield an error later-on.
22 | remove_design find(design Top_design)
23 | elaborate Top_design
24 | check_design /* Needed for setting attributes */
In line 23 the toplevel design is elaborated. Apart from unmapped subdesigns,
this toplevel design now contains old, already compiled subdesigns, named by
their original name. This means that during compilation of the toplevel these
subdesigns can be resolved. The check_design command in line 24 is needed
because else some attributes are not properly set.
25 | Sub_designs = find(reference "*")
| Sub_designs = filter(Sub_designs,"@is_hierarchical == true && \
@is_synlib_operator == false && @is_mapped == false")
26 | foreach(Cur_design, Sub_designs + Top_design) {
27 | current_design find(design Cur_design)
| /* timing constraints ... */
28 | remove_clock -all
29 | derive_clocks
30 | Clock = find(port,all_clocks())
31 | if (Clock != {}) {
32 | create_clock -name CK -period Ckperiod Clock
| /* timing constraints ... */
33 | set_scan_style multiplexed_flip_flop
34 | } else {
35 | set_max_delay Combdelay -from all_inputs() -to all_outputs()
| }
37 | uniquify
38 | compile -incremental_mapping
| }
In the lines starting 26 the new subdesigns and the toplevel are compiled. In
lines 28 - 31 the sequential subdesigns are separated from the non-sequential,
because they need different timing constraints. In line 37 subdesigns might
get new names. In line 38 they are compiled for the first time.
39 | current_design Top_design
| /* Define test ports ... */
40 | insert_test
In line 40 remarkable things happen. The toplevel now contains a mix of
subdesigns with and without scan-chains. The tool manages to recognize the
subdesigns that it can leave unmodified, it only gives them a new name,
containing the string "_test". Finally it completes the scan-chains.
| /* More timing constraints ... */
41 | Sub_designs = filter(find(reference "*"),"@is_hierarchical == true")
42 | set_dont_touch Sub_designs
43 | foreach(Cur_design, Sub_designs) {
44 | current_design Top_design
45 | Instance = filter(find(cell,"*"), "@ref_name == Cur_design")
46 | characterize -constraints Instance
47 | current_design find(design Cur_design)
48 | compile -incremental_mapping
| }
49 | current_design Top_design
50 | compile -incremental_mapping
51 | write -hier -out db/ + Top_design + .db
52 | check_test
53 | report_test -scan_path >> Report_file
Starting line 43 all subdesigns are constrained automatically. Notice the
transition from design name towards instance name in lines 45 and 46. The rest
is straight-forward. Line 52 is needed else line 53 won't work. The whole
script works only one level deep, and a flaw occurs if identical subdesigns
exist that are parameterized differently.
If somebody has comments, or knows better solutions, please let him react. The
script emerged thanks to 2 courses, manuals reading, experimenting and sending
emails to the hotline. This last sentence is meant as a transition to my next
point: I rather disagree with the semantics of the Synopsys scripting
language.
// synopsys esnug_soapbox_mode on
Designers nowadays are accustomed to well-structured, strongly typed languages
like VHDL and Verilog. But for their dc_shell scripts, they are forced to use
a language that is not very perfect. The typing rules are complex and obscure.
The correct working of commands is sometimes a matter of try-and-error, even
for the hotline staff. The understanding of some types is difficult, e.g. can
somebody tell the exact distinction between a design, a cell and a reference?
Attributes are indispensable for making scripts do what you want, but it is
often unclear at what moment they are set by the tool. Is an attribute set
after reading the database, after elaboration or after compilation? If it is
set for a reference, is it also set for a cell? Some attributes appear to be
set only after seamingly unrelated commands (e.g. line 5). User-defined
variables often must be type cast by a find command, but if this is obligatory
again is a matter of try-and-error. Between different versions of the tool the
rules appear to change, so my scripts maybe will not work in the next release.
Some decades of programming language development has revealed rules that every
computer language should adhere to. The Synopsys scripting language serves to
control very complicated and sophisticated machinery, but has syntax and
semantics that is unclear, ill-documented and error-prone. Ladies and
gentlemen, software developers at Synopsys, may I give some suggestions?
1. Commands must do what they promise. E.g. the "find" command in line 30 only
works if preceeded by derive_clocks, and this command only works in all
circumstances if preceeded by the command in line 28 (remove_clock -all).
Also, report_test only works if preceeded by check_test. Command
report_attribute yields an incomplete list of attributes. Many more
examples of unclear behaviour exist.
2. The scope of commands is unclear. Why is the result of find(design,"*") all
designs in memory, and find(reference,"*") only the references in the
current design?
3. What is the use of a design placed in memory more then once? It is a burden
for the designer, because he is forced to clean this up explicitly.
4. Names in scripts are case sensitive, whereas VHDL is not. So VHDL code that
has been beautyfied by somebody may not work with an old script. At that,
the case of component names in libraries often is unknown. Please find a
solution for this.
5. The tool should take the consequences of found errors earlier, it is not
useful to go on after a real error. The tool should stop then, and release
its licence.
6. User-defined variables should be declared, complete with their type, before
they can be used, for the sake of safety. Also, all predefined variables
should have a type. The exact type of all command and function parameters
should be documented. If types do not match, the find command could perform
the necessary type casts. As it is now, if e.g. an addition of 2 variables
is needed (like: xx + yy), then it seems to be a question of luck how this
is interpreted by the tool (will it be: xxyy, or: { xx yy }).
7. Forget about the following types: design, reference, cell and lib_cell.
Replace them by 2 types: generic and instance. An instance should inherit
all attributes and mappings from its generic, whereas attributes and
mappings of instances can be added or modified. Thus, the uniquify command
would not be needed anymore. If a generic is (re)compiled, all its
instances get the same mapping. After this, the instances could be modified
by a command like
re_compile find(instance,"*")
// synopsys esnug_soapbox_mode off
I would like to close with a request to proceed with the good work: all tools,
from Behavioural Compiler up to Test Compiler controlled by one language, in
one environment.
- W. Boeke
AT&T
|
|