电子说
一、前言
之前写过一篇关于利用Python生成module instance的文章,现直接在这篇文章基础上修改完善。作为一名IC验证工程师在公司经常写些脚本,自己在这方面的功底也提高了不少,再者有网友评论之前的脚本有不足之处,所以本文编写了一个进阶版的脚本,扩展性也比较强,方便大家使用。
二、代码设计
新添加的功能特性包括:
1 支持inout端口
2 支持多module文件中指定module的instance生成(不指定则默认与文件名一致)
3 检查注释行
4 生成Instance同时提供端口参数注释,包括端口方向和位宽
5 可选同时生成端口连接信号及其声明
因为提供了上述特性,代码逻辑较基础版更为复杂点。整个生成过程分为三个阶段:获得指定module的代码段,从中提取出端口信息以及按照指定工作模式生成instance文件。先上代码再加以说明:
基础版:
1 #!/usr/bin/python23 import re4 import os56 #regex compile7 regex_module = re.compile('(module)(s+)(w+)')89 regex_ports = re.compile('''10 (input|output) #011 (s+) #112 (wire|regs+)? #213 ([w+-1:0]s+)? #314 (w+) #415 ''',re.VERBOSE)1617 directory = os.getcwd()18 #open the design file19 file_design = input('Please enter the file name:')20 with open(directory+'/'+file_design,'r') as file_obj:21 comment = file_obj.read()2223 #regex match module name24 module_obj = regex_module.search(comment)25 print(module_obj.group())26 #regex match ports name27 groups_ports = regex_ports.findall(comment)28 print(' number of ports:',len(groups_ports))2930 #write the instantiation templete to an assigned file31 file_tb = input('Please enter the top file name:')32 with open(directory+'/'+file_tb,'a') as file_obj2:33 if module_obj is not None:34 file_obj2.write(module_obj.group(3)+' uut ( ')3536 num = len(groups_ports)37 for i in range(num):38 if i == num-1:39 file_obj2.write('.'+groups_ports[i][4]+' () ')40 else:41 file_obj2.write('.'+groups_ports[i][4]+' (), ')42 file_obj2.write('); ')
python_inst.py进阶版:
1 import re2 import argparse3 import os45 class Rtl_generator:6 def __init__(self):7 self.extract_list=[]8 self.info_list=[]9 self.module_name = None1011 @staticmethod12 def display_list_for_test(list_name):13 print('list : ')14 for unit in list_name:15 print(unit)1617 def get_module_specified_lines(self,regex,file_name):18 print('input function: get_module_specified ')19 with open(file_name,'r') as file_obj:20 add_flag = 021 for line in file_obj:22 line = line.strip()23 if not line.startswith('//'):24 re_head_obj = re.match(regex,line)25 re_tail_obj = re.match(r'endmodule',line)26 if re_head_obj is not None:27 add_flag = 128 elif add_flag == 1 and re_tail_obj is not None:29 add_flag = 030 break31 else:32 continue3334 if add_flag == 1:35 self.extract_list.append(line)3637 def extract_ports_info(self,regex_ports, regex_width):38 print('input function: get_ports_info ')39 for unit in self.extract_list:40 re_ports_obj = re.search(regex_ports,unit)41 if re_ports_obj is not None:42 port_name = re_ports_obj.group(6)43 port_direction = re_ports_obj.group(1)44 port_width_str = re_ports_obj.group(4)45 if port_width_str is None:46 port_width = 147 else:48 #port_width = port_width_str49 width_str = re.search(regex_width,port_width_str).group(2)50 width_info_list = width_str.split(":")51 high_str = width_info_list[0]52 low_str = width_info_list[1]53 if '-1' in high_str:54 port_width = high_str.split("-")[0]55 else:56 high = int(high_str)57 low = int(low_str)58 port_width = high - low + 1 if high >= low else low - high + 159 port_info = {'name':port_name,'direct':port_direction,'width':port_width}60 self.info_list.append(port_info)616263 def gen_module_instance(self,filename,mode):64 print('input function: gen_module_instance')65 ports_num = len(self.info_list)66 line_list = []67 line_list.append('module wrapper();')68 if mode == 'gen_inst_wc':69 for i in range(ports_num):70 var_type = 'reg' if self.info_list[i]['direct'] == 'input' else 'wire'71 line_list.append('{:<5} [{}-1:0] {};'.format(var_type,72 self.info_list[i]['width'],73 self.info_list[i]['name']))74 line_list.append(' ')75 line_list.append('{} inst_name'.format(self.module_name))76 line_list.append('(')77 index = 07879 for unit in self.info_list:80 if index == ports_num - 1:81 post_fix = '//{:<15}width:{}'.format(unit['direct'], unit['width'])82 else:83 post_fix = ',//{:<15}width:{}'.format(unit['direct'], unit['width'])84 index+=18586 if mode == 'gen_inst_wc':87 line_list.append('.{:<30}{:<30}{}'.format(unit['name'], '('+unit['name']+')', post_fix))88 elif mode == 'gen_inst_only':89 line_list.append('.{:<30}{:<5}{}'.format(unit['name'], '(' + ')', post_fix))90 line_list.append(');')91 line_list.append('endmodule ')92 with open(filename,'w') as file_obj:93 for line in line_list:94 file_obj.write(line)95 file_obj.write(' ')96 print('generate instance finish')rtl_generator.py
1 from rtl_generator import *2 #import rtl_generator34 mode_list = ['gen_inst_only','gen_inst_wc']56 def create_arg_parser():7 parser = argparse.ArgumentParser()8 parser.add_argument("-filename",required=True)9 parser.add_argument("-target",default='wrapper.v')10 parser.add_argument("-modulename")11 parser.add_argument("-mode",choices=mode_list,default=mode_list[0])1213 options = parser.parse_args()14 return options1516 def get_arg(options,option):17 if hasattr(options,option):18 arg = getattr(options,option)19 return arg20 else:21 return None2223 def compile_regex(**key_args):24 regex_dict={}25 if 'module_head' in key_args.keys():26 regex_module_head = re.compile(r'''27 (modules+)28 (%s)29 ''' %(key_args['module_head']),re.VERBOSE)30 regex_dict['module_head'] = regex_module_head3132 if 'module_ports' in key_args.keys():33 regex_module_ports = re.compile(r'''34 (output|input|inout) #1 direction35 (s+) #236 (wire|reg)? #337 ([[w-:]+])? #4 width38 (s+)? #539 (w+) #6 port name40 ''',re.VERBOSE)41 regex_dict['module_ports'] = regex_module_ports4243 if 'width' in key_args.keys():44 regex_width = re.compile(r'''45 ([)46 ([w-:]+)47 (])48 ''',re.VERBOSE)49 regex_dict['width'] = regex_width5051 return regex_dict5253 rg = Rtl_generator()5455 if __name__ == "__main__":56 options = create_arg_parser()57 #print(options)58 file_name_arg = get_arg(options,"filename")59 module_name_arg=get_arg(options,"modulename")60 work_mode_arg = get_arg(options,"mode")61 target_file_arg = get_arg(options,"target")6263 (filepath,filename_we) = os.path.split(file_name_arg)64 (filename,ext) = os.path.splitext(filename_we)6566 rg.module_name = filename if module_name_arg is None else module_name_arg67 print('file name:{} module name:{}'.format(filename_we,rg.module_name))6869 regex_dict = compile_regex(module_head=rg.module_name,module_ports=True,width=True)70 rg.get_module_specified_lines(regex_dict['module_head'],file_name_arg)71 #rg.display_list_for_test(rg.extract_list)7273 rg.extract_ports_info(regex_dict['module_ports'],regex_dict['width'])74 #rg.display_list_for_test(rg.info_list)7576 rg.gen_module_instance(target_file_arg,work_mode_arg)inst_gen_app.py
在进阶版的脚本中采用了OOP特性,将相关的数据结构和function封装为Rtl_generator class。把命令行选项参数提取和正则表达式部分放在了inst_gen_app.py中完成。
根据生成逻辑中的三个阶段详细阐述内部原理:获取指定module代码段过程中,首先检测是否为注释行,若是则利用continue跳过,为有效行才进一步分析。利用add_flag指示是否检测到module头,若检测到则将代码行添加在extract_list里直至遇到endmodule停止。从module代码段中提取端口信息,使用regex_ports的各个group分离出端口名称、位宽以及方向部分字符串。其中位宽部分再次使用regex_width以及运算得到真实的位宽数值,很简单一看就懂不再赘述了。之后以字典的形式存储在info_list中。最后是生成Instance的部分,判断工作模式,若是默认的gen_inst_only则只产生Instance,若是gen_inst_wc,也就是generate instance with connections,那么在instance的端口上添加同名的连接信号以及该信号的声明,有木有太方便!
三、运行结果
最后我们来看下运行结果,这次在WINDOW的Pycharm环境下开发的,terminal和LINUX中的命令行用起来一样:
> python inst_gen_app.py -filename video_system_wrapper.v -mode gen_inst_wc -target testbench.sv
设计原文件与生成文件如下:
1 //Copyright 1986-2017 Xilinx, Inc. All Rights Reserved.2 //--------------------------------------------------------------------------------3 //Tool Version: Vivado v.2017.4 (win64) Build 2086221 Fri Dec 15 2039 MST 20174 //Date : Sun Mar 22 1233 20205 //Host : DESKTOP-CE32R3P running 64-bit major release (build 9200)6 //Command : generate_target video_system_wrapper.bd7 //Design : video_system_wrapper8 //Purpose : IP block netlist9 //--------------------------------------------------------------------------------10 `timescale 1 ps / 1 ps1112 module video_system_wrapper13 (aclk_0,14 aresetn_0,15 camera_rstn,16 din_0,17 en_capture_0,18 href_0,19 locked_0,20 m_axis_video_0_tdata,21 m_axis_video_0_tlast,22 m_axis_video_0_tready,23 m_axis_video_0_tuser,24 m_axis_video_0_tvalid,25 overflow_0,26 pclk_0,27 s_axis_video_0_tdata,28 s_axis_video_0_tlast,29 s_axis_video_0_tready,30 s_axis_video_0_tuser,31 s_axis_video_0_tvalid,32 status_0,33 underflow_0,34 vga_clk,35 vid_io_out_0_active_video,36 vid_io_out_0_data,37 vid_io_out_0_field,38 vid_io_out_0_hblank,39 vid_io_out_0_hsync,40 vid_io_out_0_vblank,41 vid_io_out_0_vsync,42 vid_io_out_reset_0,43 vsync_0,44 vtc_ctrl_araddr,45 vtc_ctrl_arready,46 vtc_ctrl_arvalid,47 vtc_ctrl_awaddr,48 vtc_ctrl_awready,49 vtc_ctrl_awvalid,50 vtc_ctrl_bready,51 vtc_ctrl_bresp,52 vtc_ctrl_bvalid,53 vtc_ctrl_rdata,54 vtc_ctrl_rready,55 vtc_ctrl_rresp,56 vtc_ctrl_rvalid,57 vtc_ctrl_wdata,58 vtc_ctrl_wready,59 vtc_ctrl_wstrb,60 vtc_ctrl_wvalid);61 input aclk_0;62 input aresetn_0;63 output camera_rstn;64 input [7:0]din_0;65 input en_capture_0;66 input href_0;67 output locked_0;68 output [23:0]m_axis_video_0_tdata;69 output m_axis_video_0_tlast;70 input m_axis_video_0_tready;71 output m_axis_video_0_tuser;72 output m_axis_video_0_tvalid;73 output overflow_0;74 input pclk_0;75 input [23:0]s_axis_video_0_tdata;76 input s_axis_video_0_tlast;77 output s_axis_video_0_tready;78 input s_axis_video_0_tuser;79 input s_axis_video_0_tvalid;80 output [31:0]status_0;81 output underflow_0;82 input vga_clk;83 output vid_io_out_0_active_video;84 output [23:0]vid_io_out_0_data;85 output vid_io_out_0_field;86 output vid_io_out_0_hblank;87 output vid_io_out_0_hsync;88 output vid_io_out_0_vblank;89 output vid_io_out_0_vsync;90 input vid_io_out_reset_0;91 input vsync_0;92 input [8:0]vtc_ctrl_araddr;93 output vtc_ctrl_arready;94 input vtc_ctrl_arvalid;95 input [8:0]vtc_ctrl_awaddr;96 output vtc_ctrl_awready;97 input vtc_ctrl_awvalid;98 input vtc_ctrl_bready;99 output [1:0]vtc_ctrl_bresp;100 output vtc_ctrl_bvalid;101 output [31:0]vtc_ctrl_rdata;102 input vtc_ctrl_rready;103 output [1:0]vtc_ctrl_rresp;104 output vtc_ctrl_rvalid;105 input [31:0]vtc_ctrl_wdata;106 output vtc_ctrl_wready;107 input [3:0]vtc_ctrl_wstrb;108 input vtc_ctrl_wvalid;109110 wire aclk_0;111 wire aresetn_0;112 wire camera_rstn;113 wire [7:0]din_0;114 wire en_capture_0;115 wire href_0;116 wire locked_0;117 wire [23:0]m_axis_video_0_tdata;118 wire m_axis_video_0_tlast;119 wire m_axis_video_0_tready;120 wire m_axis_video_0_tuser;121 wire m_axis_video_0_tvalid;122 wire overflow_0;123 wire pclk_0;124 wire [23:0]s_axis_video_0_tdata;125 wire s_axis_video_0_tlast;126 wire s_axis_video_0_tready;127 wire s_axis_video_0_tuser;128 wire s_axis_video_0_tvalid;129 wire [31:0]status_0;130 wire underflow_0;131 wire vga_clk;132 wire vid_io_out_0_active_video;133 wire [23:0]vid_io_out_0_data;134 wire vid_io_out_0_field;135 wire vid_io_out_0_hblank;136 wire vid_io_out_0_hsync;137 wire vid_io_out_0_vblank;138 wire vid_io_out_0_vsync;139 wire vid_io_out_reset_0;140 wire vsync_0;141 wire [8:0]vtc_ctrl_araddr;142 wire vtc_ctrl_arready;143 wire vtc_ctrl_arvalid;144 wire [8:0]vtc_ctrl_awaddr;145 wire vtc_ctrl_awready;146 wire vtc_ctrl_awvalid;147 wire vtc_ctrl_bready;148 wire [1:0]vtc_ctrl_bresp;149 wire vtc_ctrl_bvalid;150 wire [31:0]vtc_ctrl_rdata;151 wire vtc_ctrl_rready;152 wire [1:0]vtc_ctrl_rresp;153 wire vtc_ctrl_rvalid;154 wire [31:0]vtc_ctrl_wdata;155 wire vtc_ctrl_wready;156 wire [3:0]vtc_ctrl_wstrb;157 wire vtc_ctrl_wvalid;158159 video_system video_system_i160 (.aclk_0(aclk_0),161 .aresetn_0(aresetn_0),162 .camera_rstn(camera_rstn),163 .din_0(din_0),164 .en_capture_0(en_capture_0),165 .href_0(href_0),166 .locked_0(locked_0),167 .m_axis_video_0_tdata(m_axis_video_0_tdata),168 .m_axis_video_0_tlast(m_axis_video_0_tlast),169 .m_axis_video_0_tready(m_axis_video_0_tready),170 .m_axis_video_0_tuser(m_axis_video_0_tuser),171 .m_axis_video_0_tvalid(m_axis_video_0_tvalid),172 .overflow_0(overflow_0),173 .pclk_0(pclk_0),174 .s_axis_video_0_tdata(s_axis_video_0_tdata),175 .s_axis_video_0_tlast(s_axis_video_0_tlast),176 .s_axis_video_0_tready(s_axis_video_0_tready),177 .s_axis_video_0_tuser(s_axis_video_0_tuser),178 .s_axis_video_0_tvalid(s_axis_video_0_tvalid),179 .status_0(status_0),180 .underflow_0(underflow_0),181 .vga_clk(vga_clk),182 .vid_io_out_0_active_video(vid_io_out_0_active_video),183 .vid_io_out_0_data(vid_io_out_0_data),184 .vid_io_out_0_field(vid_io_out_0_field),185 .vid_io_out_0_hblank(vid_io_out_0_hblank),186 .vid_io_out_0_hsync(vid_io_out_0_hsync),187 .vid_io_out_0_vblank(vid_io_out_0_vblank),188 .vid_io_out_0_vsync(vid_io_out_0_vsync),189 .vid_io_out_reset_0(vid_io_out_reset_0),190 .vsync_0(vsync_0),191 .vtc_ctrl_araddr(vtc_ctrl_araddr),192 .vtc_ctrl_arready(vtc_ctrl_arready),193 .vtc_ctrl_arvalid(vtc_ctrl_arvalid),194 .vtc_ctrl_awaddr(vtc_ctrl_awaddr),195 .vtc_ctrl_awready(vtc_ctrl_awready),196 .vtc_ctrl_awvalid(vtc_ctrl_awvalid),197 .vtc_ctrl_bready(vtc_ctrl_bready),198 .vtc_ctrl_bresp(vtc_ctrl_bresp),199 .vtc_ctrl_bvalid(vtc_ctrl_bvalid),200 .vtc_ctrl_rdata(vtc_ctrl_rdata),201 .vtc_ctrl_rready(vtc_ctrl_rready),202 .vtc_ctrl_rresp(vtc_ctrl_rresp),203 .vtc_ctrl_rvalid(vtc_ctrl_rvalid),204 .vtc_ctrl_wdata(vtc_ctrl_wdata),205 .vtc_ctrl_wready(vtc_ctrl_wready),206 .vtc_ctrl_wstrb(vtc_ctrl_wstrb),207 .vtc_ctrl_wvalid(vtc_ctrl_wvalid));208 endmodulevideo_system_wrapper.v
1 module wrapper();2 reg [1-1:0] aclk_0;3 reg [1-1:0] aresetn_0;4 wire [1-1:0] camera_rstn;5 reg [8-1:0] din_0;6 reg [1-1:0] en_capture_0;7 reg [1-1:0] href_0;8 wire [1-1:0] locked_0;9 wire [24-1:0] m_axis_video_0_tdata;10 wire [1-1:0] m_axis_video_0_tlast;11 reg [1-1:0] m_axis_video_0_tready;12 wire [1-1:0] m_axis_video_0_tuser;13 wire [1-1:0] m_axis_video_0_tvalid;14 wire [1-1:0] overflow_0;15 reg [1-1:0] pclk_0;16 reg [24-1:0] s_axis_video_0_tdata;17 reg [1-1:0] s_axis_video_0_tlast;18 wire [1-1:0] s_axis_video_0_tready;19 reg [1-1:0] s_axis_video_0_tuser;20 reg [1-1:0] s_axis_video_0_tvalid;21 wire [32-1:0] status_0;22 wire [1-1:0] underflow_0;23 reg [1-1:0] vga_clk;24 wire [1-1:0] vid_io_out_0_active_video;25 wire [24-1:0] vid_io_out_0_data;26 wire [1-1:0] vid_io_out_0_field;27 wire [1-1:0] vid_io_out_0_hblank;28 wire [1-1:0] vid_io_out_0_hsync;29 wire [1-1:0] vid_io_out_0_vblank;30 wire [1-1:0] vid_io_out_0_vsync;31 reg [1-1:0] vid_io_out_reset_0;32 reg [1-1:0] vsync_0;33 reg [9-1:0] vtc_ctrl_araddr;34 wire [1-1:0] vtc_ctrl_arready;35 reg [1-1:0] vtc_ctrl_arvalid;36 reg [9-1:0] vtc_ctrl_awaddr;37 wire [1-1:0] vtc_ctrl_awready;38 reg [1-1:0] vtc_ctrl_awvalid;39 reg [1-1:0] vtc_ctrl_bready;40 wire [2-1:0] vtc_ctrl_bresp;41 wire [1-1:0] vtc_ctrl_bvalid;42 wire [32-1:0] vtc_ctrl_rdata;43 reg [1-1:0] vtc_ctrl_rready;44 wire [2-1:0] vtc_ctrl_rresp;45 wire [1-1:0] vtc_ctrl_rvalid;46 reg [32-1:0] vtc_ctrl_wdata;47 wire [1-1:0] vtc_ctrl_wready;48 reg [4-1:0] vtc_ctrl_wstrb;49 reg [1-1:0] vtc_ctrl_wvalid;505152 video_system_wrapper inst_name53 (54 .aclk_0 (aclk_0) ,//input width:155 .aresetn_0 (aresetn_0) ,//input width:156 .camera_rstn (camera_rstn) ,//output width:157 .din_0 (din_0) ,//input width:858 .en_capture_0 (en_capture_0) ,//input width:159 .href_0 (href_0) ,//input width:160 .locked_0 (locked_0) ,//output width:161 .m_axis_video_0_tdata (m_axis_video_0_tdata) ,//output width:2462 .m_axis_video_0_tlast (m_axis_video_0_tlast) ,//output width:163 .m_axis_video_0_tready (m_axis_video_0_tready) ,//input width:164 .m_axis_video_0_tuser (m_axis_video_0_tuser) ,//output width:165 .m_axis_video_0_tvalid (m_axis_video_0_tvalid) ,//output width:166 .overflow_0 (overflow_0) ,//output width:167 .pclk_0 (pclk_0) ,//input width:168 .s_axis_video_0_tdata (s_axis_video_0_tdata) ,//input width:2469 .s_axis_video_0_tlast (s_axis_video_0_tlast) ,//input width:170 .s_axis_video_0_tready (s_axis_video_0_tready) ,//output width:171 .s_axis_video_0_tuser (s_axis_video_0_tuser) ,//input width:172 .s_axis_video_0_tvalid (s_axis_video_0_tvalid) ,//input width:173 .status_0 (status_0) ,//output width:3274 .underflow_0 (underflow_0) ,//output width:175 .vga_clk (vga_clk) ,//input width:176 .vid_io_out_0_active_video (vid_io_out_0_active_video) ,//output width:177 .vid_io_out_0_data (vid_io_out_0_data) ,//output width:2478 .vid_io_out_0_field (vid_io_out_0_field) ,//output width:179 .vid_io_out_0_hblank (vid_io_out_0_hblank) ,//output width:180 .vid_io_out_0_hsync (vid_io_out_0_hsync) ,//output width:181 .vid_io_out_0_vblank (vid_io_out_0_vblank) ,//output width:182 .vid_io_out_0_vsync (vid_io_out_0_vsync) ,//output width:183 .vid_io_out_reset_0 (vid_io_out_reset_0) ,//input width:184 .vsync_0 (vsync_0) ,//input width:185 .vtc_ctrl_araddr (vtc_ctrl_araddr) ,//input width:986 .vtc_ctrl_arready (vtc_ctrl_arready) ,//output width:187 .vtc_ctrl_arvalid (vtc_ctrl_arvalid) ,//input width:188 .vtc_ctrl_awaddr (vtc_ctrl_awaddr) ,//input width:989 .vtc_ctrl_awready (vtc_ctrl_awready) ,//output width:190 .vtc_ctrl_awvalid (vtc_ctrl_awvalid) ,//input width:191 .vtc_ctrl_bready (vtc_ctrl_bready) ,//input width:192 .vtc_ctrl_bresp (vtc_ctrl_bresp) ,//output width:293 .vtc_ctrl_bvalid (vtc_ctrl_bvalid) ,//output width:194 .vtc_ctrl_rdata (vtc_ctrl_rdata) ,//output width:3295 .vtc_ctrl_rready (vtc_ctrl_rready) ,//input width:196 .vtc_ctrl_rresp (vtc_ctrl_rresp) ,//output width:297 .vtc_ctrl_rvalid (vtc_ctrl_rvalid) ,//output width:198 .vtc_ctrl_wdata (vtc_ctrl_wdata) ,//input width:3299 .vtc_ctrl_wready (vtc_ctrl_wready) ,//output width:1100 .vtc_ctrl_wstrb (vtc_ctrl_wstrb) ,//input width:4101 .vtc_ctrl_wvalid (vtc_ctrl_wvalid) //input width:1102 );103 endmoduletestbench.sv
总结下Usage:
-filename module所在文件的文件名
-modulename 指定要产生instance的module名称(可选项,默认与文件同名)
-mode 工作模式,包括gen_inst_only和gen_inst_wc(可选项,默认为gen_inst_only)
-target 指定生成文件的文件名(可选项,默认为wrapper.v)
测试还不太充分,若有问题后续会在这篇文章基础上继续改进。下面会传到GITHUB上方便更新!
全部0条评论
快来发表一下你的评论吧 !