IC 设计工具篇 — 寄存器板块生成脚本设计过程(verilog 版)
简介
能让电脑完成的就不要手写了,自动生成寄存器板块verilog代码的脚本设计过程
不知道大家能否向我一样,需要快速的实现板块。
我大部分写的都是算法板块,而且算法每次修改都特别大,除了控制部分可以复用以外其余都需要重新设计。
但是有些板块还是有写规律可循的,比方寄存器部分。
不论算法如何改变寄存器的配置方式可以说都是差不多的,那即可以让电脑代替我来完成这部分工作了。
脚本功能
- 直接生成寄存器板块的verilog文件
- 配置接口采用apb接口,32bit数据和16bit地址
- 支持 RW、RO 类型的寄存器
- 支持地址自动分配
- 支持地址和bit位粘连检查
基础知识
- python
- verilog
python现在主要有两个大版本2.x 和 3.x ,linux 现在大部分默认还是python2,所以下面所有的都以python2为基础
python 2.x 和 3.x 有些许不同,请大家注意
建议使用2.7和3.4及其以上版本
代码格式
先定义下最后生成的代码风格(我就以我平常喜欢的风格来设计了)
代码中有下面两类寄存器
1.可读可写的寄存器:base,test
2.只读寄存器:dbg
module Mbase_reg_cfg( // clk / rst_n input i_clk ,input i_rst_n // apb port ,input i_psel ,input [15:0] i_paddr ,input i_penable ,input i_pwrite ,input [31:0] i_pwdata ,output [31:0] o_prdata // output port ,output o_sw_base_0 ,output [3:0] o_sw_base_1 ,output [3:0] o_sw_tt_dbg_1 ,output o_sw_tt_dbg_0 // input port ,input [3:0] i_ro_dbg_1 ,input [6:0] i_ro_dbg_0);//==========================================================// apb bus ctrl start/*{{{*///==========================================================wire wr ;wire rd ;wire [15:0] addr ;wire [31:0] wdata ;reg [31:0] rdata ;assign wr = i_psel & i_penable & i_pwrite ;assign rd = i_psel & ~i_penable & ~i_pwrite ;assign addr = i_paddr ;assign wdata = i_pwdata ;assign o_prdata = rdata ;//==========================================================// apb bus ctrl end/*}}}*///==========================================================//==========================================================// localparam start/*{{{*///==========================================================localparam BASE_ADDR = 16'h0000 ;localparam DBG_ADDR = 16'h0004 ;localparam TEST_ADDR = 16'h0008 ;//==========================================================// localparam end/*}}}*///==========================================================//==========================================================// reg and wire start/*{{{*///==========================================================// write signalwire wr_base_w ;wire wr_test_w ;// regreg [31:0] reg_base_r ;reg [31:0] reg_test_r ;// read datawire [31:0] rdata_base_w ;wire [31:0] rdata_dbg_w ;wire [31:0] rdata_test_w ;//==========================================================// reg and wire end/*}}}*///==========================================================//==========================================================// write signal gen start/*{{{*///==========================================================assign wr_base_w = wr & (addr == BASE_ADDR );assign wr_test_w = wr & (addr == TEST_ADDR );//==========================================================// write signal gen end/*}}}*///==========================================================//==========================================================// base start/*{{{*///==========================================================localparam BASE_VALID_BIT = 32'h00_00_00_f1;localparam BASE_DEFAULT = 32'h00_00_00_f1;always@(posedge i_clk) begin if(i_rst_n == 1'd0) begin reg_base_r <= BASE_DEFAULT; end else if(wr_base_w) begin reg_base_r <= wdata & BASE_VALID_BIT; endendassign o_sw_base_0 = reg_base_r[0];assign o_sw_base_1 = reg_base_r[7:4];assign rdata_base_w = { 24'd0 ,o_sw_base_1 ,3'd0 ,o_sw_base_0};//==========================================================// base end/*}}}*///==========================================================//==========================================================// dbg start/*{{{*///==========================================================assign rdata_dbg_w = { 14'd0 ,i_ro_dbg_0 ,3'd0 ,i_ro_dbg_1 ,4'd0};//==========================================================// dbg end/*}}}*///==========================================================//==========================================================// test start/*{{{*///==========================================================localparam TEST_VALID_BIT = 32'h80_00_00_f0;localparam TEST_DEFAULT = 32'h00_00_00_00;always@(posedge i_clk) begin if(i_rst_n == 1'd0) begin reg_test_r <= TEST_DEFAULT; end else if(wr_test_w) begin reg_test_r <= wdata & TEST_VALID_BIT; endendassign o_sw_tt_dbg_1 = reg_test_r[7:4];assign o_sw_tt_dbg_0 = reg_test_r[31];assign rdata_test_w = { o_sw_tt_dbg_0 ,23'd0 ,o_sw_tt_dbg_1 ,4'd0};//==========================================================// test end/*}}}*///==========================================================//==========================================================// rdata start/*{{{*///==========================================================always@(posedge i_clk) begin if(i_rst_n == 1'd0) begin rdata <= 32'd0; end else if(rd) begin case(addr) BASE_ADDR : rdata <= rdata_base_w ; DBG_ADDR : rdata <= rdata_dbg_w ; TEST_ADDR : rdata <= rdata_test_w ; default : rdata <= 32'd0 ; endcase end else begin rdata <= rdata; endend//==========================================================// rdata end/*}}}*///==========================================================endmodule
生成用列表文件内容
产生寄存器文件需要知道有那些寄存器和如何拼接
下面为产生上面寄存器文件所使用的列表文件格式
生成板块名M<name>_reg_cfg
列表文件名<name>_reg_list
列表列表名<name>_reg_list
- 假如列表文件和列表名不一致或者是不匹配会出现问题
base_reg_list = [{ "name" : "base", "addr" : 0x0000, "type" : "RW", # "RW" or "RO" "bit" : [ ["base_0", [0], 0x1], # [寄存器名称, 使用bit位, 默认值] ["base_1", [7,4], 0xf], # [寄存器名称, 使用bit位, 默认值] ]},{ "name" : "dbg", # "addr" : 0x0004, # 地址可以不显示指定,默认自增 "type" : "RO", "bit" : [ ["dbg_1", [7,4]], ["dbg_0", [17,11], 0x0], # 只读寄存器默认值不起作用 ]},{ "name" : "test", "addr" : 0x0008, # "type" : "RW", # 类型可以不显示指定,默认 "RW" "bit" : [ ["tt_dbg_1", [7,4]], # 默认值可以不显示指定,默认 "0" ["tt_dbg_0", [31], 0x0], ]},]
脚本解决步骤
1.读取寄存器列表
2.对没有制定默认值的地方进行增加,没有地址的使用前面进行累加
3.检查地址、bit位有无粘连
4.产生输入输出端口
5.产生localparam 地址内容
6.产生后续会使用到的信号定义
7.产生寄存器写使能逻辑
8.产生每个寄存器的写过程和输出信号拆分和读取信号合并内容
9.产生寄存器读逻辑
10.合并上述内容进行输出
脚本设计过程问题与关键点
1.读取寄存器列表
主要读取配置文件并生成脚本识别格式
为了省事,就不对寄存器列表进行语法解析,而是使用python的exec函数
exec : 执行字符串中的python语句
def get_reg_list(file_name): with open(file_name, "r") as f: data_str = f.readlines() data_str = "".join(data_str) _locals = locals() exec(data_str, globals(), _locals) data = _locals[file_name] return data
上面主要步骤
- 打开文件并读取一律内容,将文件列表拼接为一个大的字符串
- 执行字符串中内容,将字符串中的寄存器列表返回
2.对没有制定默认值的地方进行增加,没有地址的使用前面进行累加
为了后面代码不会每次还判读时候有指定,没有指定用默认值。
所以在给到后面解决时将没有显示指定的地方增加上默认值,简化后面代码解决
前面定义了地址默认自增,类型默认只读,默认值为0.
下面代码有相应的操作
def add_default(data): def_addr = 0x0000 def_type = "RW" def_value = 0x0 for reg in data: # add default addr try: def_addr = reg["addr"] + 4 except: reg["addr"] = def_addr def_addr = reg["addr"] + 4 # add default type try: reg["type"] except: reg["type"] = def_type for bit in reg["bit"]: # add default range if len(bit[1]) == 1: bit[1] = [bit[1][0],bit[1][0]] # add default value try: bit[2] except: bit.append(def_value)
上面代码中这两行不知道你有没有想到为什么这么做。
if len(bit[1]) == 1: bit[1] = [bit[1][0],bit[1][0]]
由于在寄存器只有一个bit的情况下,我们列表中只有一个值
为了将多bit和单bit统一,所以将单bit转为和多bit相同的方式
3.检查地址、bit位有无粘连
在设计过程中我一直有一个观点:人是最不靠谱的
在上面我们手动需要写的就是list文件
由于是手写,没有办法保证100%正确,所以需要增加适当的检查机制,确保正确性
常见的问题有几点:地址重叠、bit重叠、bit超出范围
下面代码就是针对这几点进行的检查
def check_overlap(data): err = 0 # addr overlap check addr_list = [] for reg in data: addr_list.append(reg["addr"]) set_addr_list = list(set(addr_list)) if len(addr_list) != len(set_addr_list): overlap_addr = [ addr for addr in set_addr_list if addr_list.count(addr) > 1] for addr in overlap_addr: print("Err : 0x%08x addr overlap !!!" % addr) err = 1 # bit overlap check for reg in data: bit_list = [] for bit in reg["bit"]: bit_start = bit[1][1] bit_end = bit[1][0] bit_list += range(bit_start,bit_end+1) set_bit_list = list(set(bit_list)) if len([bit for bit in set_bit_list if bit >= 32]) > 0: print("Err : reg %s addr 0x%08x bit out range !!!" % (reg['name'], reg['addr'])) err = 1 if len(bit_list) != len(set_bit_list): overlap_bit = [ bit for bit in set_bit_list if bit_list.count(bit) > 1] print("Err : 0x%08x bit %s overlap !!!" % (reg['addr'], str(overlap_bit))) err = 1 if err: sys.exit(1)
4.产生输入输出端口
接下来就该进入正式的verilog代码部分了
首先我们先确定需要产生的部分(下面内容为上面代码格式部分)
// output port ,output o_sw_base_0 ,output [3:0] o_sw_base_1 ,output [3:0] o_sw_tt_dbg_1 ,output o_sw_tt_dbg_0 // input port ,input [3:0] i_ro_dbg_1 ,input [6:0] i_ro_dbg_0
这部分是我们使用过程中需要的输入输出端口
所有的板块我们都需要配置相应的寄存器来确定工作模式或者是开关
上面输出口就是通过总线配置后的值
输入一般为运行后的输出,或者是debug用的
下面为详细的产生代码
def gen_io_port(data): io_str = [] rw_list = [ reg for reg in data if reg['type'] == 'RW'] ro_list = [ reg for reg in data if reg['type'] == 'RO'] # output port io_str.append(" // output port\n") for reg in rw_list: for bit in reg['bit']: bit_range = bit[1] bit_len = bit_range[0] - bit_range[1] if bit_len != 0: range_str = "[%d:0]" % bit_len else: range_str = "" bit_name_str = "o_sw_%s" % bit[0] io_str.append(" ,output %-17s %s\n" % (range_str, bit_name_str,)) io_str.append("\n"); # input port io_str.append(" // input port\n") for reg in ro_list: for bit in reg['bit']: bit_range = bit[1] bit_len = bit_range[0] - bit_range[1] if bit_len != 0: range_str = "[%d:0]" % bit_len else: range_str = "" bit_name_str = "i_ro_%s" % bit[0] io_str.append(" ,input %-17s %s\n" % (range_str, bit_name_str,)) io_str.append("\n"); return io_str
5.产生localparam 地址内容
接下来就改产生地址信息了,这里使用lcalparam定义地址,而后使用
所以这里就只产生定义,具体使用在后面的写逻辑生成
下面为需要产生的部分(下面内容为上面代码格式部分)
localparam BASE_ADDR = 16'h0000 ;localparam DBG_ADDR = 16'h0004 ;localparam TEST_ADDR = 16'h0008 ;
下面为产生代码。
这里没有什么难点
def gen_localparam(data): localparam_str = [] for reg in data: addr_name = "%s_ADDR" % reg['name'].upper() addr_str = "16'h%04x" % reg['addr'] localparam_str.append("localparam %-36s = %s ;\n" % (addr_name, addr_str,)) return localparam_str
6.产生后续会使用到的信号定义
下面就是信号的定义部分
这里主要定义了:写使能信号、寄存器信号、读数据信号
// write signalwire wr_base_w ;wire wr_test_w ;// regreg [31:0] reg_base_r ;reg [31:0] reg_test_r ;// read datawire [31:0] rdata_base_w ;wire [31:0] rdata_dbg_w ;wire [31:0] rdata_test_w ;
写使能和寄存器信号都是”RW”的才有,而读数据信号是所有类型的都有
主要是由于”RO”的不需要写,数据直接通过输入进来,只要要总线能读取就可
下面为相应产生部分
def gen_reg_wire(data): reg_wire_str = [] rw_list = [ reg for reg in data if reg['type'] == 'RW'] reg_wire_str.append("\n") # write signal reg_wire_str.append("// write signal\n") for reg in rw_list: wire_name = "wr_%s_w" % reg['name'] reg_wire_str.append("wire %-47s;\n" % wire_name) reg_wire_str.append("\n") # reg reg_wire_str.append("// reg\n") for reg in rw_list: reg_name = "reg_%s_r" % reg['name'] reg_wire_str.append("reg [31:0] %-47s;\n" % reg_name) reg_wire_str.append("\n") # read data reg_wire_str.append("// read data\n") for reg in data: wire_name = "rdata_%s_w" % reg['name'] reg_wire_str.append("wire [31:0] %-47s;\n" % wire_name) reg_wire_str.append("\n") return reg_wire_str
7.产生寄存器写使能逻辑
接下来就是产生写使能逻辑
assign wr_base_w = wr & (addr == BASE_ADDR );assign wr_test_w = wr & (addr == TEST_ADDR );
这里只要要产生RW类型的写使能就可,RO不需要
def gen_write_signal(data): write_signal_str = [] rw_list = [ reg for reg in data if reg['type'] == 'RW'] for reg in rw_list: wire_name = "wr_%s_w" % reg['name'] addr_name = "%s_ADDR" % reg['name'].upper() write_signal_str.append("assign %-20s = wr & (addr == %-14s);\n" % (wire_name, addr_name,)) return write_signal_str
8.产生每个寄存器的写过程和输出信号拆分和读取信号合并内容
接下来就是最主要的部分了
寄存器的读写、输出连接、读拼接都是在这里做的
下面为两类寄存器生成的最终生成内容(生成的注释中有vim识别的折叠,这是个人习惯)
//==========================================================// base start/*{{{*///==========================================================localparam BASE_VALID_BIT = 32'h00_00_00_f1;localparam BASE_DEFAULT = 32'h00_00_00_f1;always@(posedge i_clk) begin if(i_rst_n == 1'd0) begin reg_base_r <= BASE_DEFAULT; end else if(wr_base_w) begin reg_base_r <= wdata & BASE_VALID_BIT; endendassign o_sw_base_0 = reg_base_r[0];assign o_sw_base_1 = reg_base_r[7:4];assign rdata_base_w = { 24'd0 ,o_sw_base_1 ,3'd0 ,o_sw_base_0};//==========================================================// base end/*}}}*///==========================================================//==========================================================// dbg start/*{{{*///==========================================================assign rdata_dbg_w = { 14'd0 ,i_ro_dbg_0 ,3'd0 ,i_ro_dbg_1 ,4'd0};//==========================================================// dbg end/*}}}*///==========================================================
下面代码内容较多,对照上面生成内容看会更好
def gen_reg(data): reg_str = [] for reg in data: reg_str.append("//==========================================================\n") reg_str.append("// %-44s start/*{{{*/\n" % reg['name']) reg_str.append("//==========================================================\n") reg_name = "reg_%s_r" % reg['name'] value_bit_name = "%s_VALID_BIT" % reg['name'].upper() default_name = "%s_DEFAULT" % reg['name'].upper() write_name = "wr_%s_w" % reg['name'] rdata_name = "rdata_%s_w" % reg['name'] if reg['type'] == 'RW': # localparam value_bit = 0 default = 0 for bit in reg['bit']: bit_range = bit[1] bit_def = bit[2] bit_start = bit_range[1] bit_end = bit_range[0] bit_len = bit_end - bit_start + 1 value_bit |= (((2**bit_len) - 1) << bit_start) default |= bit_def << bit_start value_bit_str = "%08x" % value_bit default_str = "%08x" % default value_bit_str = "_".join([ value_bit_str[i*2:i*2+2] for i in range(4)]) default_str = "_".join([ default_str[i*2:i*2+2] for i in range(4)]) reg_str.append("localparam %-30s = 32'h%s;\n" % (value_bit_name, value_bit_str)) reg_str.append("localparam %-30s = 32'h%s;\n" % (default_name, default_str)) reg_str.append("\n") # reg function reg_str.append("always@(posedge i_clk) begin\n" ) reg_str.append(" if(i_rst_n == 1'd0) begin\n" ) reg_str.append(" %s <= %s;\n" % (reg_name, default_name,)) reg_str.append(" end\n" ) reg_str.append(" else if(%s) begin\n" % write_name) reg_str.append(" %s <= wdata & %s;\n" % (reg_name, value_bit_name,)) reg_str.append(" end\n" ) reg_str.append("end\n" ) reg_str.append("\n" ) # output for bit in reg['bit']: output_name = "o_sw_%s" % bit[0] bit_range = bit[1] bit_start = bit_range[1] bit_end = bit_range[0] bit_len = bit_end - bit_start + 1 if bit_len > 1: bit_range_str = "[%d:%d]" % (bit_end, bit_start) else: bit_range_str = "[%d]" % bit_start reg_str.append("assign %-16s = %s%s;\n" % (output_name, reg_name, bit_range_str,)) reg_str.append("\n") # rdata bit_index = 0 rdata_list = [] for bit in reg['bit']: bit_range = bit[1] bit_start = bit_range[1] bit_end = bit_range[0] if bit_index != bit_start: rdata_list.append("%d'd0" % (bit_start - bit_index)) if reg['type'] == "RW": rdata_list.append("o_sw_%s" % bit[0]) else: rdata_list.append("i_ro_%s" % bit[0]) bit_index = bit_end + 1 if bit_index != 32: rdata_list.append("%d'd0" % (32 - bit_index)) reg_str.append("assign %s = {\n" % rdata_name) reg_str.append(" " + "\n ,".join(rdata_list[::-1]) + "\n") reg_str.append("};\n") reg_str.append("//==========================================================\n") reg_str.append("// %-44s end/*}}}*/\n" % reg['name']) reg_str.append("//==========================================================\n") reg_str.append("\n") return reg_str
首先产生需要少量名称
产生默认值、可写bit 这两个localparam
产生寄存器写的always
产生输出信号的连接
产生输出信号的拼接,这里RW拼接的是o_sw_* 而RO拼接的是i_ro_*
9.产生寄存器读逻辑
这可以说已经是最后了
前面大部分逻辑都生成了,就差能让总线读取到的逻辑了
always@(posedge i_clk) begin if(i_rst_n == 1'd0) begin rdata <= 32'd0; end else if(rd) begin case(addr) BASE_ADDR : rdata <= rdata_base_w ; DBG_ADDR : rdata <= rdata_dbg_w ; TEST_ADDR : rdata <= rdata_test_w ; default : rdata <= 32'd0 ; endcase end else begin rdata <= rdata; endend
这里恒简单,由于前面已经将信号拼接好了,这里直接使用就可
def gen_rdata(data): rdata_str = [] for reg in data: addr_name = "%s_ADDR" % reg['name'].upper() rdata_name = "rdata_%s_w" % reg['name'] rdata_str.append(" %-22s : rdata <= %-21s;\n" % (addr_name, rdata_name,)) return rdata_str
10.合并上述内容进行输出
上面产生完所有逻辑内容,这里就只要要将所有内容拼接起来
下面代码尽管长,但其实没有什么内容。
def gen_reg_file( mode_name, io_str, localparam_str, reg_wire_str, write_signal_str, reg_str, rdata_str, ): with open("../reg_file/%s_reg_cfg.v" % mode_name, "w") as f: f.write("module M%s_reg_cfg\n" % mode_name ) f.write("(\n" ) f.write(" // clk / rst_n\n" ) f.write(" input i_clk\n" ) f.write(" ,input i_rst_n\n" ) f.write("\n" ) f.write(" // apb port\n" ) f.write(" ,input i_psel\n" ) f.write(" ,input [15:0] i_paddr\n" ) f.write(" ,input i_penable\n" ) f.write(" ,input i_pwrite\n" ) f.write(" ,input [31:0] i_pwdata\n" ) f.write(" ,output [31:0] o_prdata\n" ) f.write("\n" ) f.write("".join(io_str)) f.write(");\n" ) f.write("//==========================================================\n") f.write("// apb bus ctrl start/*{{{*/\n") f.write("//==========================================================\n") f.write("wire wr ;\n") f.write("wire rd ;\n") f.write("wire [15:0] addr ;\n") f.write("wire [31:0] wdata ;\n") f.write("reg [31:0] rdata ;\n") f.write("\n" ) f.write("assign wr = i_psel & i_penable & i_pwrite ;\n") f.write("assign rd = i_psel & ~i_penable & ~i_pwrite ;\n") f.write("assign addr = i_paddr ;\n") f.write("assign wdata = i_pwdata ;\n") f.write("assign o_prdata = rdata ;\n") f.write("//==========================================================\n") f.write("// apb bus ctrl end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("//==========================================================\n") f.write("// localparam start/*{{{*/\n") f.write("//==========================================================\n") f.write("".join(localparam_str)) f.write("//==========================================================\n") f.write("// localparam end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("//==========================================================\n") f.write("// reg and wire start/*{{{*/\n") f.write("//==========================================================\n") f.write("".join(reg_wire_str)) f.write("//==========================================================\n") f.write("// reg and wire end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("//==========================================================\n") f.write("// write signal gen start/*{{{*/\n") f.write("//==========================================================\n") f.write("".join(write_signal_str)) f.write("//==========================================================\n") f.write("// write signal gen end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("".join(reg_str)) f.write("//==========================================================\n") f.write("// rdata start/*{{{*/\n") f.write("//==========================================================\n") f.write("always@(posedge i_clk) begin\n" ) f.write(" if(i_rst_n == 1'd0) begin\n" ) f.write(" rdata <= 32'd0;\n" ) f.write(" end\n" ) f.write(" else if(rd) begin\n" ) f.write(" case(addr)\n" ) f.write("".join(rdata_str)) f.write(" default : rdata <= 32'd0 ;\n") f.write(" endcase\n" ) f.write(" end\n" ) f.write(" else begin\n" ) f.write(" rdata <= rdata;\n" ) f.write(" end\n" ) f.write("end\n" ) f.write("//==========================================================\n") f.write("// rdata end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("endmodule\n" ) f.close()
结尾
在工作过程中有许多的事,而且IC这一行容错率非常低,略微一个bug即可以是流片失败(FPGA的除外)
而我一直奉行<人是最不靠谱的>观点。而工作后会发现有很多的工具就是专门为了帮助人们找错误的,仿真就是其一。
然而工具使用的在熟练,也是需要花费不少时间的。
所以提高效率和精确性就是流程化,并且自动化
下面为完整的脚本
#!/bin/env pythonimport osimport sys# ==========================================================# get reg list start#{{{# ==========================================================def get_reg_list(file_name): try: with open(file_name, "r") as f: data_str = f.readlines() data_str = "".join(data_str) _locals = locals() exec(data_str, globals(), _locals) data = _locals[file_name] return data except: print("open file %s err" % file_name) sys.exit(1)# ==========================================================# get reg list end#}}}# ==========================================================# ==========================================================# add default start#{{{# ==========================================================def add_default(data): def_addr = 0x0000 def_type = "RW" def_value = 0x0 for reg in data: # add default addr try: def_addr = reg["addr"] + 4 except: reg["addr"] = def_addr def_addr = reg["addr"] + 4 # add default type try: reg["type"] except: reg["type"] = def_type for bit in reg["bit"]: # add default range if len(bit[1]) == 1: bit[1] = [bit[1][0],bit[1][0]] # add default value try: bit[2] except: bit.append(def_value)# ==========================================================# add default end#}}}# ==========================================================# ==========================================================# check overlap start#{{{# ==========================================================def check_overlap(data): err = 0 # addr overlap check addr_list = [] for reg in data: addr_list.append(reg["addr"]) set_addr_list = list(set(addr_list)) if len(addr_list) != len(set_addr_list): overlap_addr = [ addr for addr in set_addr_list if addr_list.count(addr) > 1] for addr in overlap_addr: print("Err : 0x%08x addr overlap !!!" % addr) err = 1 # bit overlap check for reg in data: bit_list = [] for bit in reg["bit"]: bit_start = bit[1][1] bit_end = bit[1][0] bit_list += range(bit_start,bit_end+1) set_bit_list = list(set(bit_list)) if len([bit for bit in set_bit_list if bit >= 32]) > 0: print("Err : reg %s addr 0x%08x bit out range !!!" % (reg['name'], reg['addr'])) err = 1 if len(bit_list) != len(set_bit_list): overlap_bit = [ bit for bit in set_bit_list if bit_list.count(bit) > 1] print("Err : 0x%08x bit %s overlap !!!" % (reg['addr'], str(overlap_bit))) err = 1 if err: sys.exit(1)# ==========================================================# check overlap end#}}}# ==========================================================# ==========================================================# gen io port start#{{{# ==========================================================def gen_io_port(data): io_str = [] rw_list = [ reg for reg in data if reg['type'] == 'RW'] ro_list = [ reg for reg in data if reg['type'] == 'RO'] # output port io_str.append(" // output port\n") for reg in rw_list: for bit in reg['bit']: bit_range = bit[1] bit_len = bit_range[0] - bit_range[1] if bit_len != 0: range_str = "[%d:0]" % bit_len else: range_str = "" bit_name_str = "o_sw_%s" % bit[0] io_str.append(" ,output %-17s %s\n" % (range_str, bit_name_str,)) io_str.append("\n"); # input port io_str.append(" // input port\n") for reg in ro_list: for bit in reg['bit']: bit_range = bit[1] bit_len = bit_range[0] - bit_range[1] if bit_len != 0: range_str = "[%d:0]" % bit_len else: range_str = "" bit_name_str = "i_ro_%s" % bit[0] io_str.append(" ,input %-17s %s\n" % (range_str, bit_name_str,)) io_str.append("\n"); return io_str# ==========================================================# gen io port end#}}}# ==========================================================# ==========================================================# gen localparam start#{{{# ==========================================================def gen_localparam(data): localparam_str = [] for reg in data: addr_name = "%s_ADDR" % reg['name'].upper() addr_str = "16'h%04x" % reg['addr'] localparam_str.append("localparam %-36s = %s ;\n" % (addr_name, addr_str,)) return localparam_str# ==========================================================# gen localparam end#}}}# ==========================================================# ==========================================================# gen reg wire start#{{{# ==========================================================def gen_reg_wire(data): reg_wire_str = [] rw_list = [ reg for reg in data if reg['type'] == 'RW'] reg_wire_str.append("\n") # write signal reg_wire_str.append("// write signal\n") for reg in rw_list: wire_name = "wr_%s_w" % reg['name'] reg_wire_str.append("wire %-47s;\n" % wire_name) reg_wire_str.append("\n") # reg reg_wire_str.append("// reg\n") for reg in rw_list: reg_name = "reg_%s_r" % reg['name'] reg_wire_str.append("reg [31:0] %-47s;\n" % reg_name) reg_wire_str.append("\n") # read data reg_wire_str.append("// read data\n") for reg in data: wire_name = "rdata_%s_w" % reg['name'] reg_wire_str.append("wire [31:0] %-47s;\n" % wire_name) reg_wire_str.append("\n") return reg_wire_str# ==========================================================# gen reg wire end#}}}# ==========================================================# ==========================================================# gen write signal start#{{{# ==========================================================def gen_write_signal(data): write_signal_str = [] rw_list = [ reg for reg in data if reg['type'] == 'RW'] for reg in rw_list: wire_name = "wr_%s_w" % reg['name'] addr_name = "%s_ADDR" % reg['name'].upper() write_signal_str.append("assign %-20s = wr & (addr == %-14s);\n" % (wire_name, addr_name,)) return write_signal_str# ==========================================================# gen write signal end#}}}# ==========================================================# ==========================================================# gen reg start#{{{# ==========================================================def gen_reg(data): reg_str = [] for reg in data: reg_str.append("//==========================================================\n") reg_str.append("// %-44s start/*{{{*/\n" % reg['name']) reg_str.append("//==========================================================\n") reg_name = "reg_%s_r" % reg['name'] value_bit_name = "%s_VALID_BIT" % reg['name'].upper() default_name = "%s_DEFAULT" % reg['name'].upper() write_name = "wr_%s_w" % reg['name'] rdata_name = "rdata_%s_w" % reg['name'] if reg['type'] == 'RW': # localparam value_bit = 0 default = 0 for bit in reg['bit']: bit_range = bit[1] bit_def = bit[2] bit_start = bit_range[1] bit_end = bit_range[0] bit_len = bit_end - bit_start + 1 value_bit |= (((2**bit_len) - 1) << bit_start) default |= bit_def << bit_start value_bit_str = "%08x" % value_bit default_str = "%08x" % default value_bit_str = "_".join([ value_bit_str[i*2:i*2+2] for i in range(4)]) default_str = "_".join([ default_str[i*2:i*2+2] for i in range(4)]) reg_str.append("localparam %-30s = 32'h%s;\n" % (value_bit_name, value_bit_str)) reg_str.append("localparam %-30s = 32'h%s;\n" % (default_name, default_str)) reg_str.append("\n") # reg function reg_str.append("always@(posedge i_clk) begin\n" ) reg_str.append(" if(i_rst_n == 1'd0) begin\n" ) reg_str.append(" %s <= %s;\n" % (reg_name, default_name,)) reg_str.append(" end\n" ) reg_str.append(" else if(%s) begin\n" % write_name) reg_str.append(" %s <= wdata & %s;\n" % (reg_name, value_bit_name,)) reg_str.append(" end\n" ) reg_str.append("end\n" ) reg_str.append("\n" ) # output for bit in reg['bit']: output_name = "o_sw_%s" % bit[0] bit_range = bit[1] bit_start = bit_range[1] bit_end = bit_range[0] bit_len = bit_end - bit_start + 1 if bit_len > 1: bit_range_str = "[%d:%d]" % (bit_end, bit_start) else: bit_range_str = "[%d]" % bit_start reg_str.append("assign %-16s = %s%s;\n" % (output_name, reg_name, bit_range_str,)) reg_str.append("\n") # rdata bit_index = 0 rdata_list = [] for bit in reg['bit']: bit_range = bit[1] bit_start = bit_range[1] bit_end = bit_range[0] if bit_index != bit_start: rdata_list.append("%d'd0" % (bit_start - bit_index)) if reg['type'] == "RW": rdata_list.append("o_sw_%s" % bit[0]) else: rdata_list.append("i_ro_%s" % bit[0]) bit_index = bit_end + 1 if bit_index != 32: rdata_list.append("%d'd0" % (32 - bit_index)) reg_str.append("assign %s = {\n" % rdata_name) reg_str.append(" " + "\n ,".join(rdata_list[::-1]) + "\n") reg_str.append("};\n") reg_str.append("//==========================================================\n") reg_str.append("// %-44s end/*}}}*/\n" % reg['name']) reg_str.append("//==========================================================\n") reg_str.append("\n") return reg_str# ==========================================================# gen reg end#}}}# ==========================================================# ==========================================================# gen rdata start#{{{# ==========================================================def gen_rdata(data): rdata_str = [] for reg in data: addr_name = "%s_ADDR" % reg['name'].upper() rdata_name = "rdata_%s_w" % reg['name'] rdata_str.append(" %-22s : rdata <= %-21s;\n" % (addr_name, rdata_name,)) return rdata_str# ==========================================================# gen rdata end#}}}# ==========================================================# ==========================================================# gen reg file start#{{{# ==========================================================def gen_reg_file( mode_name, io_str, localparam_str, reg_wire_str, write_signal_str, reg_str, rdata_str, ): with open("../reg_file/%s_reg_cfg.v" % mode_name, "w") as f: f.write("module M%s_reg_cfg\n" % mode_name ) f.write("(\n" ) f.write(" // clk / rst_n\n" ) f.write(" input i_clk\n" ) f.write(" ,input i_rst_n\n" ) f.write("\n" ) f.write(" // apb port\n" ) f.write(" ,input i_psel\n" ) f.write(" ,input [15:0] i_paddr\n" ) f.write(" ,input i_penable\n" ) f.write(" ,input i_pwrite\n" ) f.write(" ,input [31:0] i_pwdata\n" ) f.write(" ,output [31:0] o_prdata\n" ) f.write("\n" ) f.write("".join(io_str)) f.write(");\n" ) f.write("//==========================================================\n") f.write("// apb bus ctrl start/*{{{*/\n") f.write("//==========================================================\n") f.write("wire wr ;\n") f.write("wire rd ;\n") f.write("wire [15:0] addr ;\n") f.write("wire [31:0] wdata ;\n") f.write("reg [31:0] rdata ;\n") f.write("\n" ) f.write("assign wr = i_psel & i_penable & i_pwrite ;\n") f.write("assign rd = i_psel & ~i_penable & ~i_pwrite ;\n") f.write("assign addr = i_paddr ;\n") f.write("assign wdata = i_pwdata ;\n") f.write("assign o_prdata = rdata ;\n") f.write("//==========================================================\n") f.write("// apb bus ctrl end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("//==========================================================\n") f.write("// localparam start/*{{{*/\n") f.write("//==========================================================\n") f.write("".join(localparam_str)) f.write("//==========================================================\n") f.write("// localparam end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("//==========================================================\n") f.write("// reg and wire start/*{{{*/\n") f.write("//==========================================================\n") f.write("".join(reg_wire_str)) f.write("//==========================================================\n") f.write("// reg and wire end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("//==========================================================\n") f.write("// write signal gen start/*{{{*/\n") f.write("//==========================================================\n") f.write("".join(write_signal_str)) f.write("//==========================================================\n") f.write("// write signal gen end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("".join(reg_str)) f.write("//==========================================================\n") f.write("// rdata start/*{{{*/\n") f.write("//==========================================================\n") f.write("always@(posedge i_clk) begin\n" ) f.write(" if(i_rst_n == 1'd0) begin\n" ) f.write(" rdata <= 32'd0;\n" ) f.write(" end\n" ) f.write(" else if(rd) begin\n" ) f.write(" case(addr)\n" ) f.write("".join(rdata_str)) f.write(" default : rdata <= 32'd0 ;\n") f.write(" endcase\n" ) f.write(" end\n" ) f.write(" else begin\n" ) f.write(" rdata <= rdata;\n" ) f.write(" end\n" ) f.write("end\n" ) f.write("//==========================================================\n") f.write("// rdata end/*}}}*/\n") f.write("//==========================================================\n") f.write("\n" ) f.write("endmodule\n" ) f.close()# ==========================================================# gen reg file end#}}}# ==========================================================if __name__ == '__main__': if(len(sys.argv) < 2): print("not have input file") print(" %s reg_list" % sys.argv[0]) sys.exit(0) file_name = sys.argv[1] mode_name = file_name.split("_")[0] data = get_reg_list(file_name) add_default(data) check_overlap(data) io_str = gen_io_port(data) localparam_str = gen_localparam(data) reg_wire_str = gen_reg_wire(data) write_signal_str = gen_write_signal(data) reg_str = gen_reg(data) rdata_str = gen_rdata(data) gen_reg_file( mode_name, io_str, localparam_str, reg_wire_str, write_signal_str, reg_str, rdata_str, )
假如生成不了或者是错误可能是下面几点
1.列表文件名不是<name>_reg_list
2.列表文件中列表名和文件不一致
3.代码中生成目录为 “../reg_file/<name>_reg_cfg.v”,需要有相应的目录才能生成
4.是不是python版本问题
假如有问题或者是有想讨论的可以加我微信:anyuexiu
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » IC 设计工具篇 — 寄存器板块生成脚本设计过程(verilog 版)