简介
能让电脑完成的就不要手写了,自动生成寄存器模块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 signal
wire wr_base_w ;
wire wr_test_w ;
// reg
reg [31:0] reg_base_r ;
reg [31:0] reg_test_r ;
// read data
wire [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;
end
end
assign 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;
end
end
assign 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;
end
end
//==========================================================
// 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 signal
wire wr_base_w ;
wire wr_test_w ;
// reg
reg [31:0] reg_base_r ;
reg [31:0] reg_test_r ;
// read data
wire [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;
end
end
assign 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;
end
end
这里恒简单,因为前面已经将信号拼接好了,这里直接使用即可
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 python
import os
import 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