3---Python初体验之简单TestBench自动生成+Verilog模块信号提取
2017-08-31 14:53
1341 查看
学习了一些Python的基础语法之后,确实被Python优美的表达方式所吸引,所以想用Python来干点什么,之前一直想用MATLAB脚本来完成TestBench的自动生成,这里正好用Python来完成。
该TestBench主要包含以下三个部分:
基本的时钟clk和复位rst的生成
读取一个文件中的数据
提取一个模块的接口信号并将其实例化
前两个部分使用普通的文件写入操作就可以完成,第三个部分稍微复杂一点,需要用到正则表达式提取模块的名字、信号的名字和位宽等。总的来说,这是一段很简单的代码。
另外:可将第三部分用作Verilog子模块的顶层文件自动生成,省去复制粘贴连线的麻烦。
贴一个分分钟学会Python的链接:http://www.code123.cc/1049.html
_
字符串文件中存着一些固定的打印信息
模块提取函数文件中则完成了整个模块接口信息的提取和打印
主文件完成调度管理
从config中提取生成时钟和复位的字符串并写入sim文件中;
同上:提取memory初始化字符串;
同上:提取memory数据读取的always块字符串;
调用模块提取函数提取指定文件的接口信息并写入sim文件;
关闭文件。
_
模块提取函数流程:
该函数有三个部分,每个部分的流程基本一致。
将提取文件中的字符按行分离为一个字符串列表,并赋给一个变量;
预编译含有接口信息的正则表达式;
利用for循环在每一行里面去搜索该正则表达式,如果搜索到了则进入下一步;
将搜索到的字符串按照空格或者逗号分离成一个个单独的字符串,这样就可以根据下标提取接口的信息;
将提取到的信息写入sim文件。
1. 打开、关闭、及写入等文件操作与其他语言基本一致,详细可参考链接:http://blog.csdn.net/qq_16923717/article/details/77716137
2. 2、3、4步就是基本的打印和文本替换,与一般的print一样;
3. 模块接口信息提取用到的操作及参考链接如下:
读取并分行,用到了read()和splitlines():http://blog.csdn.net/nanjunxiao/article/details/9086079
正则表达式,注意re.match和re.search的区别,以及为什么要预编译正则表达式
菜鸟教程正则表达式
廖雪峰Python教程正则表达式
正则表达式说明:
下面是该程序中最长的正则表达式
该正则表达式匹配的是输入和输出信号的名字和位宽信息,因为考虑了Verilog书写的各种情况,所以该正则表达式才那么长,如果接口很规范,其实很短就可以了。
先注意正则表达式中的三个符号:’\’ ‘|’ ‘()’
反斜杠’\’:用作转义字符,如表达式中的\s+表示匹配至少一个空格,\w+匹配至少一个字母、数字或下划线,\d+匹配至少一个数字;
竖线’|’:表示或操作,如(input|output)即可匹配输入也可匹配输出;
圆括号()”:逻辑分离
Verilog输入输出的可能写法有以下几种:
config.py代码
extract_interface.py代码
生成的tb文件
注意该tb还不是一个完整的tb
提取的源文件接口
fir.v
fir_hdl.v
该TestBench主要包含以下三个部分:
基本的时钟clk和复位rst的生成
读取一个文件中的数据
提取一个模块的接口信号并将其实例化
前两个部分使用普通的文件写入操作就可以完成,第三个部分稍微复杂一点,需要用到正则表达式提取模块的名字、信号的名字和位宽等。总的来说,这是一段很简单的代码。
另外:可将第三部分用作Verilog子模块的顶层文件自动生成,省去复制粘贴连线的麻烦。
贴一个分分钟学会Python的链接:http://www.code123.cc/1049.html
1. 程序结构和运行流程
1.1 程序结构
该程序有三个文件。主文件 | 字符串文件 | 模块提取函数文件 |
---|---|---|
verilog_tb_gen.py | config.py | extract_interface.py |
字符串文件中存着一些固定的打印信息
模块提取函数文件中则完成了整个模块接口信息的提取和打印
主文件完成调度管理
1.2 运行流程
打开或新建一个sim文件;从config中提取生成时钟和复位的字符串并写入sim文件中;
同上:提取memory初始化字符串;
同上:提取memory数据读取的always块字符串;
调用模块提取函数提取指定文件的接口信息并写入sim文件;
关闭文件。
_
模块提取函数流程:
该函数有三个部分,每个部分的流程基本一致。
将提取文件中的字符按行分离为一个字符串列表,并赋给一个变量;
预编译含有接口信息的正则表达式;
利用for循环在每一行里面去搜索该正则表达式,如果搜索到了则进入下一步;
将搜索到的字符串按照空格或者逗号分离成一个个单独的字符串,这样就可以根据下标提取接口的信息;
将提取到的信息写入sim文件。
2. 流程中用到的操作说明
按1.2的流程:1. 打开、关闭、及写入等文件操作与其他语言基本一致,详细可参考链接:http://blog.csdn.net/qq_16923717/article/details/77716137
2. 2、3、4步就是基本的打印和文本替换,与一般的print一样;
3. 模块接口信息提取用到的操作及参考链接如下:
读取并分行,用到了read()和splitlines():http://blog.csdn.net/nanjunxiao/article/details/9086079
正则表达式,注意re.match和re.search的区别,以及为什么要预编译正则表达式
菜鸟教程正则表达式
廖雪峰Python教程正则表达式
正则表达式说明:
下面是该程序中最长的正则表达式
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书写的各种情况,所以该正则表达式才那么长,如果接口很规范,其实很短就可以了。
先注意正则表达式中的三个符号:’\’ ‘|’ ‘()’
反斜杠’\’:用作转义字符,如表达式中的\s+表示匹配至少一个空格,\w+匹配至少一个字母、数字或下划线,\d+匹配至少一个数字;
竖线’|’:表示或操作,如(input|output)即可匹配输入也可匹配输出;
圆括号()”:逻辑分离
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; // 信号间只有逗号
3. 附录
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 );
相关文章推荐
- python模块win32com 实现数据库表结构自动生成word表格
- C#自动给据sql中的带@的变量提取变量名称在从简单数据对象中取得生成SqlParameter数组进行数据插入(利用反射完成)
- 使用Sphinx为你的python模块自动生成文档
- C#自动给据sql中的带@的变量提取变量名称在从简单数据对象中取得生成SqlParameter数组进行数据插入(利用反射完成)
- Appium跑python脚本自动生成简单测试结果报告
- Python实现简单生成验证码功能【基于random模块】
- 使用Sphinx为你的python模块自动生成文档
- 简单使用Python自动生成文章
- 使用Sphinx为你的python模块自动生成文档
- 神奇的模块--谷歌开源 Python Fire:自动生成命令行接口
- Sphinx--python模块自动生成文档
- 简单使用Python自动生成文章
- Python自动生成sql语句
- Python中random模块生成随机数详解
- 使用python自动生成docker nginx反向代理配置
- Python简单的爬取网页信息并生成json文件与乱码解决小记
- Python 模块paramiko简单使用方法
- Python 的 MySQLdb 模块插入数据没有成功与 autocommit(自动提交)的关系
- 使用Python生成随机简单的验证码
- android自动更新新版模块(简单,实用)