学习了一些Python的基础语法之后,确实被Python优美的表达方式所吸引,所以想用Python来干点什么,之前一直想用MATLAB脚本来完成TestBench的自动生成,这里正好用Python来完成。
该TestBench主要包含以下三个部分:
- 基本的时钟clk和复位rst的生成
- 读取一个文件中的数据
- 提取一个模块的接口信号并将其实例化
前两个部分使用普通的文件写入操作就可以完成,第三个部分稍微复杂一点,需要用到正则表达式提取模块的名字、信号的名字和位宽等。总的来说,这是一段很简单的代码。
另外:可将第三部分用作Verilog子模块的顶层文件自动生成,省去复制粘贴连线的麻烦。
贴一个分分钟学会Python的链接:http://www.code123.cc/1049.html
该程序有三个文件。
主文件 | 字符串文件 | 模块提取函数文件 |
---|---|---|
verilog_tb_gen.py | config.py | extract_interface.py |
_
按1.2的流程:
1. 打开、关闭、及写入等文件操作与其他语言基本一致,详细可参考链接:http://blog.csdn.net/qq_16923717/article/details/77716137
2. 2、3、4步就是基本的打印和文本替换,与一般的print一样;
3. 模块接口信息提取用到的操作及参考链接如下:
正则表达式说明:
下面是该程序中最长的正则表达式
re_interface = re.compile('(input|output)(\s+|\[\d+:0\]|\s+\[\d+:0\]|\[\d+:0\]\s+|\s+\[\d+:0\]\s+)\w+(,(\s+|)\w+){0,10}')
该正则表达式匹配的是输入和输出信号的名字和位宽信息,因为考虑了Verilog书写的各种情况,所以该正则表达式才那么长,如果接口很规范,其实很短就可以了。
先注意正则表达式中的三个符号:’\’ ‘|’ ‘()’
Verilog输入输出的可能写法有以下几种:
// 第一个括号中匹配的情况
input sig_1;
output sig_2;
// 第二个括号中匹配的情况,按从左到右的顺序
input signal_1; // 位宽为1,中间只有空格
input[1:0]signal_2; // 完全没有空格
input [1:0]signal_3; // 左边有空格
input[1:0] signal_4; // 右边有空格
input [1:0] signal_5; // 两边都有空格
// 第二个括号和第三个括号中间的 '\w+' 是匹配第一个信号的名字
// 第三个括号匹配的是多个信号中第一个信号后面的情况,如 ', signal_7',花括号里数字表示最多匹配10个
input signal_6, signal_7; // 一行有多个信号,信号间有逗号和空格
input signal_8,signal_9; // 信号间只有逗号
verilog_tb_gen.py代码
'''
Verilog testbench generator
'''
import re
import config
import extract_interface
# parameter
NAME = 'fir_sim' # tb name
PERIOD = 10 # clock period: ns
RST_DELAY = 200 # reset delay : ns
DATA_WIDTH = 32 # rom data width
DATA_LEN = 301 # rom data length
PATH = r'D:\my_prj\my_filter_hdl_1\my_filter_hdl_1.srcs\msg.dat'
# memory path
# open and truncate file
fp = open('%s.v' % NAME, 'w')
fp.truncate()
# print clk and rst
fp.write(config.mod_clk_rst % (NAME, PERIOD, RST_DELAY))
fp.write(config.divide)
# print rom
fp.write(config.memory % (DATA_WIDTH - 1, DATA_LEN, PATH.replace('\\','/')))
fp.write(config.divide)
# print source data
fp.write(config.src_data % (DATA_WIDTH - 1, DATA_LEN))
fp.write(config.divide)
fp.write(config.divide)
'''
Extract module interface
'''
extract_interface.extract_print('fir_hdl.v', 0, fp) # Extract file1
extract_interface.extract_print('fir.v', 1, fp) # Extract file2
# The end, close the file
fp.write('\n\nendmodule')
fp.close()
config.py代码
'''
Verilog testbench generator
String
'''
# module clk rst
mod_clk_rst = 'module %s;\n\
parameter PERIOD = %d;\n\
reg clk = 1;\n\
reg rst = 1;\n\n\
initial begin\n\
forever\n\
#(PERIOD/2) clk = ~clk;\n\
end\n\n\
initial begin\n\
#%d\n\
rst = 0;\n\
end\n\n\
'
# divide
divide = '//------------------------------------------------------------\n'
# memory
memory = 'reg [%d:0] datain[0:%d];\n\
initial begin\n\
$readmemb("%s", datain);\n\
end\n\n\
'
# source data
src_data = "reg\t[15:0]\t\ti;\n\
reg\t[%d:0]\t\tsource_data;\n\
reg\t\t\t\tsource_data_vld;\n\n\
always @ (posedge clk) begin\n\
if (rst) begin\n\
i <= 'd0;\n\
source_data <= 'd0;\n\
source_data_vld <= 'd0;\n\
end\n\
else if (i < %d) begin\n\
i <= i + 1;\n\
source_data <= datain[i];\n\
source_data_vld <= 1;\n\
end\n\
else begin\n\
i <= i;\n\
source_data <= 'd0;\n\
source_data_vld <= 'd0;\n\
end\n\
end\n\n\
"
extract_interface.py代码
'''
Verilog testbench generator
Extract module interface
'''
import re
def extract_print( path, u, fp ): # u是例化模块时的编号
with open(path, 'r') as dotv:
split_as_lines = dotv.read().splitlines()
# Extract output wire
re_wire = re.compile('output(\s+|\[\d+:0\]|\s+\[\d+:0\]|\[\d+:0\]\s+|\s+\[\d+:0\]\s+)\w+(,(\s+|)\w+){0,10}')
for i in range(len(split_as_lines)):
x = re_wire.search(split_as_lines[i])
if x:
wire_list = re.split(r'[\s\,]+', x.group(0))
if re.match('\[', wire_list[1]):
width_info = wire_list[1]
indx = 2
else:
width_info = '\t'
indx = 1
for j in range(len(wire_list) - indx):
fp.write('wire\t%s\t\t%-20s;\n' % (width_info, wire_list[j + indx]))
fp.write('\n')
# Extract module name
re_module_name = re.compile('module\s+\w+') # 预编译正则表达式
for i in range(len(split_as_lines)):
y = re_module_name.search(split_as_lines[i])
if y:
module_name = re.split('\s+', y.group(0))[1]
fp.write('%-19su%-6d(\n' % (module_name, u)) # 打印module name
# Extract interface
re_interface = re.compile('(input|output)(\s+|\[\d+:0\]|\s+\[\d+:0\]|\[\d+:0\]\s+|\s+\[\d+:0\]\s+)\w+(,(\s+|)\w+){0,10}')
k = 0
for i in range(len(split_as_lines)):
z = re_interface.search(split_as_lines[i])
if z:
interface_string = re.sub(r'\[\d+:0\]', ' ', z.group(0))
interface_list = re.split(r'[\s\,]+', interface_string)
for j in range(len(interface_list) - 1):
if (k == 0):
fp.write('\t.%-21s( %-20s)\n' % (interface_list[j+1], interface_list[j+1]))
else:
fp.write('\t,.%-20s( %-20s)\n' % (interface_list[j+1], interface_list[j+1]))
k += 1
fp.write('\t);\n\n')
return
生成的tb文件
注意该tb还不是一个完整的tb
module fir_sim;
parameter PERIOD = 10;
reg clk = 1;
reg rst = 1;
initial begin
forever
#(PERIOD/2) clk = ~clk;
end
initial begin
#200
rst = 0;
end
//------------------------------------------------------------
reg [31:0] datain[0:301];
initial begin
$readmemb("D:/my_prj/my_filter_hdl_1/my_filter_hdl_1.srcs/msg.dat", datain);
end
//------------------------------------------------------------
reg [15:0] i;
reg [31:0] source_data;
reg source_data_vld;
always @ (posedge clk) begin
if (rst) begin
i <= 'd0;
source_data <= 'd0;
source_data_vld <= 'd0;
end
else if (i < 301) begin
i <= i + 1;
source_data <= datain[i];
source_data_vld <= 1;
end
else begin
i <= i;
source_data <= 'd0;
source_data_vld <= 'd0;
end
end
//------------------------------------------------------------
//------------------------------------------------------------
wire [31:0] fir_out ;
fir_hdl u0 (
.clk ( clk )
,.fir_in ( fir_in )
,.fir_out ( fir_out )
);
wire [31:0] fir_out_TDATA ;
wire fir_in_TREADY ;
wire fir_out_TVALID ;
fir u1 (
.fir_in_TDATA ( fir_in_TDATA )
,.fir_out_TDATA ( fir_out_TDATA )
,.ap_clk ( ap_clk )
,.ap_rst_n ( ap_rst_n )
,.fir_in_TVALID ( fir_in_TVALID )
,.fir_in_TREADY ( fir_in_TREADY )
,.fir_out_TVALID ( fir_out_TVALID )
,.fir_out_TREADY ( fir_out_TREADY )
);
endmodule
提取的源文件接口
fir.v
module fir (
fir_in_TDATA,
fir_out_TDATA,
ap_clk,
ap_rst_n,
fir_in_TVALID,
fir_in_TREADY,
fir_out_TVALID,
fir_out_TREADY
);
input [31:0] fir_in_TDATA;
output [31:0] fir_out_TDATA;
input ap_clk;
input ap_rst_n;
input fir_in_TVALID;
output fir_in_TREADY;
output fir_out_TVALID;
input fir_out_TREADY;
fir_hdl.v
module fir_hdl(
input clk,
input [31:0] fir_in,
output [31:0] fir_out
);