Synopsys数字前端工程自动产生脚本
随手弄了个Synopsys数字前端工程自动产生脚本,使用方式是在要创建工程的路径下python env_setup.py即可自动创建工程文件夹,随后进入prj子文件夹使用makefile调用工具即可。
写的比较仓促,有的功能没怎么测到,欢迎有bug或者修改意见在评论区反馈。
env_setup内容:
import os
# 定义文件树结构
file_tree = {
'lib': {},
'netlist': {},
'prj': {
'filelist.f': None,
'makefile': None
},
'src': {
'rtl': {},
'sdc': {}
},
'tb': {},
'work': {
'dc': {
'outputs': {},
'reports': {},
'scripts': {
'dc_post_syn.tcl': None,
'dc_read_design.tcl': None,
'dc_set_cons.tcl': None,
'dc_set_env.tcl': None,
'dc_setup.tcl': None,
'dc_syn.tcl': None,
'run_dc.tcl': None
}
},
'sg': {
'scripts': {}
},
'vcs': {},
'verdi': {}
}
}
# 创建文件树
def create_file_tree(base_path, tree, root_name):
for name, subtree in tree.items():
path = os.path.join(base_path, name)
if subtree is None:
# 创建文件
open(path, 'a').close()
else:
# 创建文件夹
os.makedirs(path, exist_ok=True)
create_file_tree(path, subtree, root_name)
# 在rtl文件夹下生成与root_dir同名的.v文件
if 'rtl' in tree:
rtl_file_path = os.path.join(base_path, 'rtl', f"{root_name}.v")
with open(rtl_file_path, 'w') as f:
rtl_content = f"""module {root_name} (
input clk,
input rst_n,
input [31:0] a,
input [31:0] b,
output reg [31:0] c
);
always @(posedge clk or negedge rst_n) begin
if (~rst_n)
c <= 32'h00000000;
else
c <= a + b;
end
endmodule
"""
f.write(rtl_content)
# 在tb文件夹下生成tb_{root_name}.v文件
if 'tb' in tree:
tb_file_path = os.path.join(base_path, 'tb', f"tb_{root_name}.v")
with open(tb_file_path, 'w') as f:
tb_content = f"""module tb_{root_name}();
reg clk;
reg rst_n;
reg [31:0] a;
reg [31:0] b;
wire [31:0] c;
always #10 clk = ~clk; //50MHz
initial begin
clk = 1'b0;
rst_n = 1'b0;
a = 32'h00000000;
b = 32'h00000000;
#10;
rst_n = 1'b1;
a = 32'h00001234;
b = 32'h00004321;
#100;
$finish;
end
{root_name} u_{root_name} (
.clk(clk),
.rst_n(rst_n),
.a(a),
.b(b),
.c(c)
);
`ifdef FSDB
initial begin
$fsdbDumpfile("tb_{root_name}.fsdb");
$fsdbDumpvars;
$fsdbDumpMDA();
end
`endif
endmodule
"""
f.write(tb_content)
# 在sdc文件夹下生成与root_dir同名的.sdc文件
if 'sdc' in tree:
sdc_file_path = os.path.join(base_path, 'sdc', f"{root_name}.sdc")
with open(sdc_file_path, 'w') as f:
sdc_content = f"""# Definition of Clock
set Tclk 20 ;#50MHz
set clk_name "clk"
set unc_perc 0.05
create_clock -name $clk_name -period $Tclk [get_ports clk]
set_clock_uncertainty -setup [expr $Tclk * $unc_perc] [get_clocks $clk_name]
set_clock_transition 0.4 [all_clocks]
# Set Ideal Network
set_dont_touch_network [get_ports clk]
set_ideal_network [get_port clk]
set_dont_touch_network [get_ports rst_n]
# Definition of IO
set_input_delay [expr $Tclk*1/5.0] -clock $clk_name [all_inputs]
remove_input_delay [get_ports clk]
set_output_delay [expr $Tclk*1/5.0] -clock $clk_name [all_outputs]
# Other Constraint
set_max_transition 0.6 [current_design]
set_max_fanout 64 [current_design]
set_max_capacitance 2 [current_design]
set_input_transition -max 0.5 [all_inputs]
set_load 2 [all_outputs]
set_max_leakage_power 0
set_max_area 0
"""
f.write(sdc_content)
# 在sdc文件夹下生成与root_dir同名的.sgdc文件
if 'sdc' in tree:
sgdc_file_path = os.path.join(base_path, 'sdc', f"{root_name}.sgdc")
with open(sgdc_file_path, 'w') as f:
sgdc_content = f"""current_design {root_name}
sdc_data -file ../../src/sdc/{root_name}.sdc
"""
f.write(sgdc_content)
# 在sg/scripts文件夹下生成run_sg.tcl文件
if 'scripts' in tree.get('sg', {}):
sg_script_path = os.path.join(base_path, 'sg', 'scripts', 'run_sg.tcl')
with open(sg_script_path, 'w') as f:
sg_script_content = f"""set design_name "{root_name}"
# read in files
read_file -type sourcelist ../../prj/filelist.f
# read_file -type gateslib ../../lib/
read_file -type sgdc ../../src/sdc/${{design_name}}.sgdc
# setup
set_option top ${{design_name}}
set_option sdc2sgdc yes
current_goal Design_Read -top ${{design_name}}
link_design -force
# run lint
current_goal lint/lint_rtl -top ${{design_name}}
run_goal
# save project
save_project -force
"""
f.write(sg_script_content)
# 在dc/scripts文件夹下生成多个tcl文件
if 'scripts' in tree.get('dc', {}):
dc_scripts = [
'dc_post_syn.tcl',
'dc_read_design.tcl',
'dc_set_cons.tcl',
'dc_set_env.tcl',
'dc_setup.tcl',
'dc_syn.tcl',
'run_dc.tcl'
]
for script in dc_scripts:
script_path = os.path.join(base_path, 'dc', 'scripts', script)
open(script_path, 'a').close()
# 获取用户输入的根目录
root_dir = input("请输入根目录路径: ")
# 获取根目录名称
root_name = os.path.basename(root_dir)
# 创建文件树
create_file_tree(root_dir, file_tree, root_name)
# 在makefile中生成内容
makefile_content = f""".PHONY:vcs verdi dc sg dve
OUTPUT = {root_name}
TIMESCALE = 1ns/1ps
#start vcs
vcs:
\tcd ../work/vcs && vcs -R -sverilog -full64 +v2k -debug_pp -timescale=${{TIMESCALE}} -cpp g++ -cc gcc -LDFLAGS -no-pie -LDFLAGS -Wl,--no-as-needed -CFLAGS -fPIE -fsdb -f ../../prj/filelist.f -o ${{OUTPUT}} -l compile.log
#start verdi
verdi:
\tcd ../work/verdi && verdi -sv -f ../../prj/filelist.f -ssf ../vcs/tb_${{OUTPUT}}.fsdb
#start dc
dc:
\tcd ../work/dc && dc_shell -f ./scripts/run_dc.tcl | tee ./syn.log && rm -r ~/synopsys_cache_O-2018.06-SP1
#start sg
sg:
\tcd ../work/sg && sg_shell -tcl ./scripts/run_sg.tcl
#start dve
dve:
\tcd ../work/vcs && ./${{OUTPUT}} -gui
"""
makefile_path = os.path.join(root_dir, 'prj', 'makefile')
with open(makefile_path, 'w') as f:
f.write(makefile_content)
# 在filelist.f中生成内容
filelist_content = f"""//Macro define
+define+FSDB
// pre_sim
../../src/rtl/{root_name}.v
// post_sim
//../../netlist/
// library
//../../lib/
// testbench
../../tb/tb_{root_name}.v
"""
filelist_path = os.path.join(root_dir, 'prj', 'filelist.f')
with open(filelist_path, 'w') as f:
f.write(filelist_content)
# 在run_dc.tcl中生成内容
run_dc_content = f""" # dc setup
source ./scripts/dc_setup.tcl
# read design
source ./scripts/dc_read_design.tcl
# define design environment
source ./scripts/dc_set_env.tcl
# set design constraints
source ./scripts/dc_set_cons.tcl
# synthesis and optimize design
source ./scripts/dc_syn.tcl
# analyze and resolve design problems
source ./scripts/dc_post_syn.tcl
"""
run_dc_path = os.path.join(root_dir, 'work', 'dc', 'scripts', 'run_dc.tcl')
with open(run_dc_path, 'w') as f:
f.write(run_dc_content)
# 在dc_syn.tcl中生成内容
dc_syn_content = f"""
check_design > $report_path/check_design_before_compile.rpt
check_timing > $report_path/check_timing_before_compile.rpt
compile_ultra
compile_ultra -incremental
"""
dc_syn_path = os.path.join(root_dir, 'work', 'dc', 'scripts', 'dc_syn.tcl')
with open(dc_syn_path, 'w') as f:
f.write(dc_syn_content)
# 在dc_setup.tcl中生成内容
dc_setup_content = f"""
set design_name "{root_name}"
# standard cell library
set stdcel_libs "
../../lib/
"
# memory library
set memory_libs "
../../lib/
"
# ip library
set ip_libs "
../../lib/
"
set target_library "$stdcel_libs"
set link_library "* $target_library $memory_libs $ip_libs"
sh mkdir -p ./reports
sh mkdir -p ./outputs
set report_path "./reports"
set output_path "./outputs"
set_svf $output_path/${{design_name}}.svf
"""
dc_setup_path = os.path.join(root_dir, 'work', 'dc', 'scripts', 'dc_setup.tcl')
with open(dc_setup_path, 'w') as f:
f.write(dc_setup_content)
# 在dc_set_env.tcl中生成内容
dc_set_env_content = f"""
set_operating_conditions "" -library ""
set_wire_load_model -name ""
set_wire_load_mode top
set_host_options -max_cores 16
set_dp_smartgen_options -all_options auto -optimize_for speed
set_critical_range 3 [current_design]
set_app_var enable_page_mode false
"""
dc_set_env_path = os.path.join(root_dir, 'work', 'dc', 'scripts', 'dc_set_env.tcl')
with open(dc_set_env_path, 'w') as f:
f.write(dc_set_env_content)
# 在dc_set_cons.tcl中生成内容
dc_set_cons_content = f"""
set sdc_path "../../src/sdc"
read_sdc "$sdc_path/${{design_name}}.sdc"
"""
dc_set_cons_path = os.path.join(root_dir, 'work', 'dc', 'scripts', 'dc_set_cons.tcl')
with open(dc_set_cons_path, 'w') as f:
f.write(dc_set_cons_content)
# 在dc_read_design.tcl中生成内容
dc_read_design_content = f"""
analyze -f verilog -vcs "-f ../../prj/filelist.f"
elaborate $design_name
current_design $design_name
link
"""
dc_read_design_path = os.path.join(root_dir, 'work', 'dc', 'scripts', 'dc_read_design.tcl')
with open(dc_read_design_path, 'w') as f:
f.write(dc_read_design_content)
# 在dc_post_syn.tcl中生成内容
dc_post_syn_content = f"""
write_sdf -version 2.1 $output_path/${{design_name}}_post_dc.sdf
write -f ddc -hier -output $output_path/${{design_name}}_post_dc.ddc
write -f verilog -hier -output $output_path/${{design_name}}_post_dc.v
write_sdc $output_path/${{design_name}}_post_dc.sdc
report_constraint -all_violators -verbose > $report_path/constraint.rpt
report_qor > $report_path/qor.rpt
report_power > $report_path/power.rpt
report_area > $report_path/area.rpt
report_cell > $report_path/cell.rpt
report_clock > $report_path/clk.rpt
report_hierarchy > $report_path/hierarchy.rpt
report_design > $report_path/design.rpt
report_reference > $report_path/reference.rpt
report_timing > $report_path/timing.rpt
check_design > $report_path/check_design_post_compile.rpt
check_timing > $report_path/check_timing_post_compile.rpt
"""
dc_post_syn_path = os.path.join(root_dir, 'work', 'dc', 'scripts', 'dc_post_syn.tcl')
with open(dc_post_syn_path, 'w') as f:
f.write(dc_post_syn_content)
print(f"模板工程已在 {root_dir} 生成")