搞定数字IC中的寄存器文件
2020-07-02 本文已影响0人
sarai_c7eb
寄存器File在SOC中的应用非常普遍;
CPU通过控制寄存器从而控制IC逻辑的功能,软件的SDK开发几乎都是针对这些寄存器的开发;
然而寄存器的设计无论从文档角度还是代码角度都是一堆重复的工作;这些工作繁琐而易于出错;给开发过程带来了不少的困难;
本文利用excel完成寄存器文档的开发,然后通过VBA将表格转JSON格式:
- 对设计工作而言,可以开发脚本从JSON转verilog文件
- 对验证工作而言,可以开发脚本从JSON转ralf文件
1. PART1:EXCEL转JSON
EXCEL表单EXCEL表单如上图,需要注意的是:
- Width内容一定要填写正确,即表示除最高位的Reserved filed外的寄存器实际宽度;
- Field部分也要填写正确,即不能不填写,只支持单个数字或a:b的格式;
- TYPE部分只支持reg(寄存器)和mem(RAM)
- mem通常用于RALF生成,RTL不会产生mem类代码;
- 建议将mem类型和reg类型分开;
- mem类型的Foffset属性带边mem的宽度,WIDTH则代码mem bit width;
- 目前只支持ro,rw,rc,wc,w1p,cnt,int类型;
- reserved命名的F那么对应的Ftype一定要设置为ro
'Version 1.0
Sub json_gen()
'row number cacluate
Dim row_num As Integer
row_num = Range("A" & 65535).End(xlUp).Row
Do While Range("A" & row_num).MergeCells Or Trim(Range("A" & row_num)) = ""
row_num = row_num - 1
Loop
'global char
QM = Chr(34)
CR = Chr(10)
'the file name and location
Module_name = ActiveSheet.Name
File_name = LCase(Module_name) & ".json"
filepath = Application.ActiveWorkbook.Path & "\" & File_name
Dim a_range As Range
Set a_range = Range("A3", Range("A" & row_num))
Dim FN As Integer
FN = FreeFile
Open filepath For Output As #FN
Print #FN, "{" & CR;
Print #FN, String(2, " ") & QM & "BLOCK_NAME" & QM & ":" & QM & [B1] & QM & "," & CR;
Print #FN, String(2, " ") & QM & "BLOCK_BASE" & QM & ":" & QM & [D1] & QM & "," & CR;
Print #FN, String(2, " ") & QM & "BLOCK_REGS" & QM & ":[" & CR;
For Each tcell In a_range
If (Trim(tcell) <> "") Then
Print #FN, String(4, " ") & "{" & CR;
Print #FN, String(6, " ") & QM & "REG_NAME" & QM & ":" & QM & tcell.Offset(0, 0) & QM & "," & CR;
Print #FN, String(6, " ") & QM & "REG_TYPE" & QM & ":" & QM & tcell.Offset(0, 1) & QM & "," & CR;
Print #FN, String(6, " ") & QM & "REG_ADDR" & QM & ":" & QM & tcell.Offset(0, 2) & QM & "," & CR;
Print #FN, String(6, " ") & QM & "REG_WIDTH" & QM & ":" & QM & tcell.Offset(0, 3) & QM & "," & CR;
Print #FN, String(6, " ") & QM & "REG_FIELDS" & QM & ":" & "[" & CR;
'fields generation
Dim i As Integer
Dim j As Integer
i = 0
Do
j = i + 1
Dim pre_end As Boolean
pre_end = Trim(tcell.Offset(j, 0)) <> "" Or Trim(tcell.Offset(j, 4)) = ""
If (pre_end) Then
Print #FN, String(8, " ") & "{" & QM & "FLD_OS" & QM & ":" & QM & tcell.Offset(i, 4) & QM & "," & _
QM & "FLD_TYPE" & QM & ":" & QM & tcell.Offset(i, 5) & QM & "," & _
QM & "FLD_RST" & QM & ":" & QM & tcell.Offset(i, 6) & QM & "," & _
QM & "FLD_NAME" & QM & ":" & QM & tcell.Offset(i, 7) & QM & "}" & CR;
Else
Print #FN, String(8, " ") & "{" & QM & "FLD_OS" & QM & ":" & QM & tcell.Offset(i, 4) & QM & "," & _
QM & "FLD_TYPE" & QM & ":" & QM & tcell.Offset(i, 5) & QM & "," & _
QM & "FLD_RST" & QM & ":" & QM & tcell.Offset(i, 6) & QM & "," & _
QM & "FLD_NAME" & QM & ":" & QM & tcell.Offset(i, 7) & QM & "}," & CR;
End If
i = i + 1
Loop Until pre_end
Print #FN, String(6, " ") & "]" & CR;
If (tcell.Row >= row_num) Then
Print #FN, String(4, " ") & "}" & CR;
Else
Print #FN, String(4, " ") & "}," & CR;
End If
Print #FN, CR; 'interleaver
End If
Next
Print #FN, String(2, " ") & "]" & CR;
Print #FN, "}" & CR;
Close #FN
MsgBox (filepath & " generated ok!")
End Sub
2 PART2:JSON转VERILOG
使用方法:python json2vlog.py xxx.json
整体思路:
- 根据JSON包将JSON文件读入;
- 产生REG CLASS和FLD CLASS;
- REG CLASS将FLD CLASS收集到list中;
- REG CLASS的各种方法对应打印RTL的不同部分(需要调用FLD的方法);
Python3代码如下所示:
import json
import sys
#versio 1.0
#read the json file
#-------------------------------------------------------------------------------
if len(sys.argv)==2:
json_file=sys.argv[1]
else:
print("Please input your json file\n")
f=open("modulea.json",'r')
#f=open(json_file,'r')
json =json.load(f)
block_name=json["BLOCK_NAME"]
f.close()
#register class
#-------------------------------------------------------------------------------
class my_reg:
def __init__(self,reg_name,reg_type,reg_addr,reg_width,reg_flds,reg_aw):
self.reg_name =reg_name.lower()
self.reg_type =reg_type
self.reg_addr =reg_addr.replace("0x","'h")
self.reg_width=reg_width
self.reg_flds =reg_flds
self.reg_aw =reg_aw
self.fld_class_lst=[]
def reg_wire_dec(self):
#declare the reg defination with 'wire'
if self.reg_width=="1":
wire_tmp_dec=" "
else:
wire_tmp_dec="[%d:0]"%(int(self.reg_width)-1)
wire_dec="wire %-12s %-30s;\n"%(wire_tmp_dec,self.reg_name.lower())
return wire_dec
def reg_assign_dec(self):
#assign the reg={fields};
fld_name_list=[]
for fld in self.fld_class_lst:
wd=str(fld.calc_wd())
if fld.fld_name=='reserved' and fld.fld_type=='ro':
fld_tmp_name="{%s{1'b0}}"%wd
else:
fld_tmp_name=self.reg_name.lower()+"_"+fld.fld_name.lower()
fld_name_list.append(fld_tmp_name)
fld_tmp_str=",".join(fld_name_list)
if len(fld_name_list)==1:
assign_tmp_dec="assign %s=%s;\n"%(self.reg_name,fld_tmp_str)
else:
assign_tmp_dec="assign %s={%s};\n"%(self.reg_name,fld_tmp_str)
return assign_tmp_dec
def reg_rdata_dec(self):
#to fill the rdata part,the reg_width must be accurated!!
if int(self.reg_width)==32:
rdata_tmp_dec=" %-10s: cfg_rdata <= %s;\n"%(self.reg_addr,self.reg_name)
else:
rdata_pf = "{"+str(32-int(self.reg_width))+"{1'b0}}"
rdata_tmp_dec=" %-10s: cfg_rdata <= {%s,%s};\n"%(self.reg_addr,rdata_pf,self.reg_name)
return rdata_tmp_dec
def reg_err_dec(self):
#to fill the err part
err_tmp=" cfg_addr != %-9s |\n"%(self.reg_addr)
return err_tmp
def fld_class_collection(self):
#collect the fileds in a reg to a list
self.reg_addr=self.reg_aw+self.reg_addr
tmp_lst=self.reg_flds
#filter the first field w/ 'reserved'
if tmp_lst[0]["FLD_NAME"]=='reserved' and tmp_lst[0]["FLD_TYPE"]=='ro':
tmp_lst.pop(0)
for fld in tmp_lst:
fld_c=my_fld(self.reg_name,
self.reg_addr,
fld["FLD_OS"],
fld["FLD_TYPE"],
fld["FLD_RST"],
fld["FLD_NAME"])
self.fld_class_lst.append(fld_c)
#return self.fld_class_lst
def reg_io_dec(self,fo):
#self.fld_class_collection()
for reg_fld in self.fld_class_lst:
if(reg_fld.io_dec()):
fo.write(reg_fld.io_dec())
def reg_reg_dec(self,fo):
#self.fld_class_collection()
for reg_fld in self.fld_class_lst:
if(reg_fld.reg_dec()):
fo.write(reg_fld.reg_dec())
def reg_func_dec(self,fo):
#self.fld_class_collection()
for reg_fld in self.fld_class_lst:
if(reg_fld.func_dec()):
fo.write(reg_fld.func_dec())
#field class
#-------------------------------------------------------------------------------
class my_fld:
def __init__(self,reg_name,reg_addr,fld_os,fld_type,fld_rst,fld_name):
self.reg_name=reg_name
self.reg_addr=reg_addr
self.fld_os =fld_os
self.fld_type=fld_type
self.fld_rst =fld_rst
self.fld_name=fld_name
self.fname_in1 =""
self.fname_in2 =""
self.fname_out =""
self.fname_reg =""
self.wd =1
def calc_wd(self):
#cacualte the field width
if ":" in self.fld_os:
hi,lo=self.fld_os.split(":")
self.wd=int(hi)-int(lo)+1
else:
self.wd=1
return self.wd
def wd_dec(self):
#generate the width declaration
wd=self.calc_wd()
wd_dec=" "
if wd!=1:
th=wd-1
wd_dec="[%d:0]"%th
return wd_dec
def io_gen(self):
#generat the IO defination
self.fname_out=self.reg_name.lower() + "_"+self.fld_name.lower()
if self.fld_type=='int':
self.fname_in1=self.reg_name.lower() + "_"+self.fld_name.lower() + "_int_set"
self.fname_in2=self.reg_name.lower() + "_"+self.fld_name.lower() + "_int_clr"
elif self.fld_type=='w1p':
self.fname_in1=self.reg_name.lower() + "_"+self.fld_name.lower() + "_trig"
self.fname_reg=self.reg_name.lower() + "_"+self.fld_name.lower()+"_ff1"
elif self.fld_type=='cnt':
self.fname_in1=self.reg_name.lower() + "_"+self.fld_name.lower() + "_inc"
elif self.fld_type=='rc' or self.fld_type=='wc':
self.fname_in1=self.reg_name.lower() + "_"+self.fld_name.lower() + "_in"
elif self.fld_type=='ro':
self.fname_in1=self.reg_name.lower() + "_"+self.fld_name.lower()
def io_dec(self):
#declare the IO in the io part
self.io_gen()
wd_dec=self.wd_dec()
tmp_io1=" output reg %-12s %-30s ,\n"%(wd_dec,self.fname_out)
if self.fld_type=='int':
tmp_io3=" input %-12s %-30s ,\n"%(wd_dec,self.fname_in2)
tmp_io2=" input %-12s %-30s ,\n"%(wd_dec,self.fname_in1)
return tmp_io3+tmp_io2+tmp_io1
elif self.fld_type=='w1p':
tmp_io2=" input %-12s %-30s ,\n"%(wd_dec,self.fname_in1)
return tmp_io2+tmp_io1
elif self.fld_type=='cnt':
tmp_io2=" input %-12s %-30s ,\n"%(wd_dec,self.fname_in1)
return tmp_io2+tmp_io1
elif self.fld_type=='rc' or self.fld_type=='wc':
tmp_io2=" input %-12s %-30s ,\n"%(wd_dec,self.fname_in1)
return tmp_io2+tmp_io1
elif self.fld_type=='ro' and self.fld_name!='reserved' :
tmp_io2=" input %-12s %-30s ,\n"%(wd_dec,self.fname_in1)
return tmp_io2
elif self.fld_type=='rw':
return tmp_io1
else:
return None
def reg_dec(self):
#declare the reg defination in the reg part
self.io_gen()
wd_dec=self.wd_dec()
if self.fld_type=='w1p':
fld_reg="reg %-12s %-30s;\n"%(wd_dec,self.fname_reg)
return fld_reg
else:
return None
def func_dec(self):
#declare the fucntion part in the main verilog
wd=str(self.calc_wd())
wd_dec="["+self.fld_os+"]"
self.io_gen()
if self.fld_type=='int':
func_line0="always@(posedge clk or negedge rst_n) begin\n"
func_line1=" if(rst_n==1'b0)\n"
func_line2=" %s <= %s;\n"%(self.fname_out,wd+"'h"+self.fld_rst.replace("0x",""))
func_line3=" else\n"
func_line4=" %s <= %s & ( ~ %s) | %s;\n" %(self.fname_out,self.fname_out,self.fname_in2,self.fname_in1)
func_line5="end\n"
return func_line0+func_line1+func_line2+func_line3+func_line4+func_line5
elif self.fld_type=='w1p':
func_line0="always@(posedge clk or negedge rst_n) begin\n"
func_line1=" if(rst_n==1'b0) begin\n"
func_line2=" %s <= %s;\n"%(self.fname_reg,wd+"'h"+self.fld_rst.replace("0x",""))
func_line3=" %s <= %s;\n"%(self.fname_out,wd+"'h"+self.fld_rst.replace("0x",""))
func_line4=" end\n"
func_line5=" else begin\n"
func_line6=" %s <= %s ;\n" %(self.fname_reg,self.fname_in1)
func_line7=" %s <= %s &(~%s);\n" %(self.fname_out,self.fname_in1,self.fname_reg)
func_line8=" end\n"
func_line9="end\n"
return func_line0+func_line1+func_line2+func_line3+func_line4+func_line5+func_line6+func_line7+func_line8+func_line9
elif self.fld_type=='cnt':
func_line0="always@(posedge clk or negedge rst_n) begin\n"
func_line1=" if(rst_n==1'b0)\n"
func_line2=" %s <= %s;\n"%(self.fname_out,wd+"'h"+self.fld_rst.replace("0x",""))
func_line3=" else if(cfg_vld && cfg_wr && cfg_addr==%s && cfg_wdata%s==%s'b0)\n"%(self.reg_addr,wd_dec,wd)
func_line4=" %s <= %s ;\n" %(self.fname_out,self.fname_in1)
func_line5=" else if(%s)\n"%self.fname_in1
func_line6=" %s <= %s + 1'b1 ;\n" %(self.fname_out,self.fname_out)
func_line7="end\n"
return func_line0+func_line1+func_line2+func_line3+func_line4+func_line5+func_line6+func_line7
elif self.fld_type=='wc':
func_line0="always@(posedge clk or negedge rst_n) begin\n"
func_line1=" if(rst_n==1'b0)\n"
func_line2=" %s <= %s;\n"%(self.fname_out,wd+"'h"+self.fld_rst.replace("0x",""))
func_line3=" else if(cfg_vld && cfg_wr && cfg_addr==%s)\n"%(self.reg_addr)
func_line4=" %s <= %s & cfg_wdata%s | %s;\n" %(self.fname_out,self.fname_out,wd_dec,self.fname_in1)
func_line5=" else \n"
func_line6=" %s <= %s | %s;\n" %(self.fname_out,self.fname_out,self.fname_in1)
func_line7="end\n"
return func_line0+func_line1+func_line2+func_line3+func_line4+func_line5+func_line6+func_line7
elif self.fld_type=='rc':
func_line0="always@(posedge clk or negedge rst_n) begin\n"
func_line1=" if(rst_n==1'b0)\n"
func_line2=" %s <= %s;\n"%(self.fname_out,wd+"'h"+self.fld_rst.replace("0x",""))
func_line3=" else if(cfg_vld && cfg_rd && cfg_addr==%s)\n"%(self.reg_addr)
func_line4=" %s <= %s;\n" %(self.fname_out,self.fname_in1)
func_line5=" else \n"
func_line6=" %s <= %s | %s;\n" %(self.fname_out,self.fname_out,self.fname_in1)
func_line7="end\n"
return func_line0+func_line1+func_line2+func_line3+func_line4+func_line5+func_line6+func_line7
elif self.fld_type=='rw':
func_line0="always@(posedge clk or negedge rst_n) begin\n"
func_line1=" if(rst_n==1'b0)\n"
func_line2=" %s <= %s;\n"%(self.fname_out,wd+"'h"+self.fld_rst.replace("0x",""))
func_line3=" else if(cfg_vld && cfg_wr && cfg_addr==%s)\n"%(self.reg_addr)
func_line4=" %s <= cfg_wdata%s;\n" %(self.fname_out,wd_dec)
func_line5="end\n"
return func_line0+func_line1+func_line2+func_line3+func_line4+func_line5
else:
return None
#main
#-------------------------------------------------------------------------------
f_hdr_1='''//============================================================
// Copyright (c) 2013 All rights reserved.
// Author : xxx
// Project : V50
// Description: %s
// date : xxx
//============================================================
module %s #(
parameter DW = 32 ,
parameter AW = 16 )
(
//cfg bus connection
input clk ,
input rst_n ,
input cfg_vld ,
input cfg_wr ,
input cfg_rd ,
input [AW-1:0] cfg_addr ,
input [DW-1:0] cfg_wdata ,
//logic connection
'''%(block_name,block_name.upper()+"_RF")
f_hdr_2='''//cofig bus conenction
output reg [DW-1:0] cfg_rdata ,
output reg cfg_ack ,
output reg cfg_err
);'''
r_hdr='''
//---------------------------------------
// REGs Declaration
//---------------------------------------\n'''
w_hdr='''
//---------------------------------------
// WIREs Declaration
//---------------------------------------\n'''
f_hdr='''
//---------------------------------------
// Function Declaration
//---------------------------------------\n'''
rdata_hdr_1='''
//read back
//------------------------------------------------------------------------
always@(posedge clk or negedge rst_n) begin
if(rst_n==1'b0)
cfg_rdata <= {DW{1'b0}};
else if(cfg_vld && cfg_rd) begin
case(cfg_addr)\n'''
rdata_hdr_2=''' default : cfg_rdata <= {DW{1'b0}};
endcase
end
end
always@(posedge clk or negedge rst_n) begin
if(rst_n==1'b0)
cfg_ack <= 1'b0;
else
cfg_ack <= cfg_vld & (cfg_wr | cfg_rd);
end
always@(posedge clk or negedge rst_n) begin
if(rst_n==1'b0)
cfg_err <= 1'b0;
else
cfg_err <= cfg_vld & (\n'''
rdata_hdr_3=''' 1'b0 );
end
'''
t_hdr='''
endmodule'''
#------------------------------------------------------------
reg_class_list=[]
for reg_tmp in json["BLOCK_REGS"]:
if reg_tmp["REG_TYPE"]=='reg':
reg_c=my_reg(reg_tmp["REG_NAME"],
reg_tmp["REG_TYPE"],
reg_tmp["REG_ADDR"],
reg_tmp["REG_WIDTH"],
reg_tmp["REG_FIELDS"],
"16")
reg_class_list.append(reg_c)
fo=open("%s.v"%(block_name.lower()+"_rf"),"w")
fo.write(f_hdr_1)
for reg_c in reg_class_list:
reg_c.fld_class_collection()
reg_c.reg_io_dec(fo)
fo.write(f_hdr_2)
fo.write(r_hdr)
for reg_c in reg_class_list:
reg_c.reg_reg_dec(fo)
fo.write(w_hdr)
for reg_c in reg_class_list:
fo.write(reg_c.reg_wire_dec())
fo.write(f_hdr)
for reg_c in reg_class_list:
fo.write("\n")
fo.write("//%s\n"%reg_c.reg_name)
fo.write("//-----------------------------------------\n")
reg_c.reg_func_dec(fo)
fo.write(reg_c.reg_assign_dec())
fo.write(rdata_hdr_1)
for reg_c in reg_class_list:
fo.write(reg_c.reg_rdata_dec())
fo.write(rdata_hdr_2)
for reg_c in reg_class_list:
fo.write(reg_c.reg_err_dec())
fo.write(rdata_hdr_3)
fo.write(t_hdr)
fo.close()
print("the file %s is generated!!!"%(block_name.lower()+"_rf"))
产生的RTL一瞥:
image.png
PART3:JSON转RALF
使用方法:python json2ralf.py xxx.json
思路和产生RTL的类似,只不过方法更简单
import json
import sys
#version 1.0
#read the json file
#-------------------------------------------------------------------------------
if len(sys.argv)==2:
json_file=sys.argv[1]
else:
print("Please input your json file\n")
f=open("modulea.json",'r')
#f=open(json_file,'r')
json =json.load(f)
block_name=json["BLOCK_NAME"]
f.close()
#register class
#-------------------------------------------------------------------------------
class my_reg:
def __init__(self,reg_name,reg_type,reg_addr,reg_width,reg_flds,reg_aw):
self.reg_name =reg_name.lower()
self.reg_type =reg_type
self.reg_addr =reg_addr.replace("0x","'h")
self.reg_width=reg_width
self.reg_flds =reg_flds
self.reg_aw =reg_aw
self.fld_class_lst=[]
def fld_class_collection(self):
#collect the fileds in a reg to a list
tmp_lst=self.reg_flds
#filter the first field w/ 'reserved'
if tmp_lst[0]["FLD_NAME"]=='reserved' and tmp_lst[0]["FLD_TYPE"]=='ro':
tmp_lst.pop(0)
for fld in tmp_lst:
fld_c=my_fld(self.reg_name,
self.reg_addr,
fld["FLD_OS"],
fld["FLD_TYPE"],
fld["FLD_RST"],
fld["FLD_NAME"])
self.fld_class_lst.append(fld_c)
#return self.fld_class_lst
def reg_func_dec(self,fo):
#self.fld_class_collection()
if self.reg_type=='reg':
reg_line0=" "*4+"register %s @%s {\n"%(self.reg_name,self.reg_aw+self.reg_addr)
#reg_line1=" "*8+"bytes %s;\n"%self.reg_aw
fo.write(reg_line0)
for reg_fld in self.fld_class_lst:
if(reg_fld.func_dec()):
fo.write(reg_fld.func_dec())
reg_line2=" "*4+"}\n"
fo.write(reg_line2)
elif self.reg_type=='mem':
reg_line0=" "*4+"memory %s {\n"%self.reg_name
reg_line1=" "*8+"size %s;\n"%self.fld_class_lst[0].fld_os
reg_line2=" "*8+"bits %s;\n"%self.reg_width
reg_line3=" "*8+"access %s;\n"%self.fld_class_lst[0].fld_type
reg_line4=" "*4+"}\n"
fo.write(reg_line0+reg_line1+reg_line2+reg_line3+reg_line4)
#field class
#-------------------------------------------------------------------------------
class my_fld:
def __init__(self,reg_name,reg_addr,fld_os,fld_type,fld_rst,fld_name):
self.reg_name=reg_name
self.reg_addr=reg_addr
self.fld_os =fld_os
self.fld_type=fld_type
self.fld_rst =fld_rst
self.fld_name=fld_name
self.fname_in1 =""
self.fname_in2 =""
self.fname_out =""
self.fname_reg =""
self.wd =1
def calc_wd(self):
#cacualte the field width
if ":" in self.fld_os:
hi,lo=self.fld_os.split(":")
self.wd=int(hi)-int(lo)+1
return hi,lo,str(self.wd)
else:
self.wd=1
return self.fld_os,self.fld_os,str(self.wd)
def func_dec(self):
#declare the fucntion part in the main verilog
if self.fld_name=='reserved' and self.fld_type=='ro':
return None
else:
hi,lo,wd=self.calc_wd()
fld_line0=" "*8+"field %s @%s {\n"%(self.fld_name,str((int(lo))))
fld_line1=" "*12+"bits %s;\n"%wd
#fld_line2=" "*12+"access %s;\n"%self.fld_type
fld_line2=" "*12+"access %s;\n"%"rw"
fld_line3=" "*12+"hard_reset %s;\n"%self.fld_rst.replace("0x",wd+"'h")
fld_line4=" "*8+"}\n"
return fld_line0+fld_line1+fld_line2+fld_line3+fld_line4
#main
#-------------------------------------------------------------------------------
reg_class_list=[]
for reg_tmp in json["BLOCK_REGS"]:
reg_c=my_reg(reg_tmp["REG_NAME"],
reg_tmp["REG_TYPE"],
reg_tmp["REG_ADDR"],
reg_tmp["REG_WIDTH"],
reg_tmp["REG_FIELDS"],
"16")
reg_class_list.append(reg_c)
fo=open("%s.ralf"%(block_name.lower()+"_rf"),"w")
block_hdr_start='''block %s {
cover +a+b+f;
endian little;
bytes %s;\n'''%(block_name.upper(),"2")
block_hdr_end="}"
fo.write(block_hdr_start)
for reg_c in reg_class_list:
reg_c.fld_class_collection()
reg_c.reg_func_dec(fo)
fo.write(block_hdr_end)
fo.close()
print("the %s.ralf is generated!!!"%(block_name.lower()+"rf"))
产生的RALF文件一瞥:
image.png
JSON转SV
也可以直接从JSON转为UVM的REG_BLOCK和REG CLASS;
代码如下:
import json
import sys
#version 1.0
#read the json file
#-------------------------------------------------------------------------------
if len(sys.argv)==2:
json_file=sys.argv[1]
else:
print("Please input your json file\n")
f=open("modulea.json",'r')
#f=open(json_file,'r')
json =json.load(f)
block_name=json["BLOCK_NAME"].lower()
f.close()
#register class
#-------------------------------------------------------------------------------
class my_reg:
def __init__(self,reg_name,reg_type,reg_addr,reg_width,reg_flds,reg_aw):
self.reg_name =reg_name.lower()
self.reg_type =reg_type
self.reg_addr =reg_addr.replace("0x","'h")
self.reg_width=reg_width
self.reg_flds =reg_flds
self.reg_aw =reg_aw
self.ins_name=self.reg_name.lower()+("_ins")
self.fld_class_lst=[]
def reg_dec(self,fo):
reg_dec_tmp="class %s extends uvm_reg;\n"%self.reg_name
fo.write(reg_dec_tmp)
def reg_new(self,fo):
rn_tmp1=" "*4+"`uvm_object_utils(%s)\n"%self.reg_name
rn_tmp2="\n"
rn_tmp3=" "*4+'function new(input string name="%s");\n'%self.reg_name
rn_tmp4=" "*8+"super.new(name,%s,UVM_NO_COVERAGE);\n"%self.reg_aw
rn_tmp5=" "*4+"endfunction\n"
rn_tmp6="endclass\n\n"
fo.write(rn_tmp1+rn_tmp2+rn_tmp3+rn_tmp4+rn_tmp5+rn_tmp6)
def reg_blk_dec(self,fo):
reg_blk_dec_tmp=" "*4+"rand %s %s;\n"%(self.reg_name,self.ins_name)
fo.write(reg_blk_dec_tmp)
def reg_blk_build(self,fo):
#to fill the rdata part,the reg_width must be accurated!!
reg_build_tmp1=' '*8+'%s=%s::type_id::create("%s",,get_full_name());\n'%(self.ins_name,self.reg_name,self.ins_name)
reg_build_tmp2=' '*8+'%s.configure(this,null,"%s");\n'%(self.ins_name,self.reg_name)
reg_build_tmp3=' '*8+'%s.build();\n'%self.ins_name
reg_build_tmp4=' '*8+'default_map.add_reg(%s,%s,"RW");\n'%(self.ins_name,self.reg_addr)
reg_build_tmp5='\n'
fo.write(reg_build_tmp1+reg_build_tmp2+reg_build_tmp3+reg_build_tmp4+reg_build_tmp5)
def fld_class_collection(self):
#collect the fileds in a reg to a list
self.reg_addr=self.reg_aw+self.reg_addr
tmp_lst=self.reg_flds
#filter the first field w/ 'reserved'
if tmp_lst[0]["FLD_NAME"]=='reserved' and tmp_lst[0]["FLD_TYPE"]=='ro':
tmp_lst.pop(0)
for fld in tmp_lst:
fld_c=my_fld(self.reg_name,
self.reg_addr,
fld["FLD_OS"],
fld["FLD_TYPE"],
fld["FLD_RST"],
fld["FLD_NAME"])
self.fld_class_lst.append(fld_c)
#return self.fld_class_lst
def reg_fld_dec(self,fo):
#self.fld_class_collection()
for reg_fld in self.fld_class_lst:
if(reg_fld.fld_dec()):
fo.write(reg_fld.fld_dec())
def reg_fld_build(self,fo):
#self.fld_class_collection()
fo.write("\n")
fo.write(" virtual function void build();\n")
for reg_fld in self.fld_class_lst:
if(reg_fld.fld_build()):
fo.write(reg_fld.fld_build())
fo.write(" endfunction\n")
fo.write("\n")
#field class
#-------------------------------------------------------------------------------
class my_fld:
def __init__(self,reg_name,reg_addr,fld_os,fld_type,fld_rst,fld_name):
self.reg_name=reg_name
self.reg_addr=reg_addr
self.fld_os =fld_os
self.fld_type=fld_type
self.fld_rst =fld_rst
self.fld_name=fld_name
self.wd =1
def calc_wd(self):
#cacualte the field width
if ":" in self.fld_os:
hi,lo=self.fld_os.split(":")
self.wd=int(hi)-int(lo)+1
return str(self.wd),str(lo)
else:
self.wd=1
return str(self.wd),str(self.fld_os)
def fld_dec(self):
#declare the IO in the io part
tmp_io1=" "*4+"rand uvm_reg_field %s;\n"%self.fld_name.lower()
return tmp_io1
def fld_build(self):
#declare the reg defination in the reg part
wd,os=self.calc_wd()
tmp_io1=" "*8+'%s=uvm_reg_field::type_id::create("%s");\n'%(self.fld_name.lower(),self.fld_name.lower())
tmp_io2=" "*8+'%s.configure(this,%s,%s,"RW",1,0,1,1,0);\n'%(self.fld_name.lower(),wd,os)
return tmp_io1+tmp_io2
#main
#-------------------------------------------------------------------------------
block_byte_aw=4
blk1='''
virtual function void build();
default_map=create_map("default_map",0,%d,UVM_LITTLE_ENDIAN,0);
\n'''%block_byte_aw
blk2=''' endfunction
`uvm_object_utils(%s)
function new(input string name="%s");
super.new(name,UVM_NO_COVERAGE);
endfunction\n
endclass\n'''%(block_name+"_blk",block_name+"_blk")
#------------------------------------------------------------
reg_class_list=[]
for reg_tmp in json["BLOCK_REGS"]:
if reg_tmp["REG_TYPE"]=='reg':
reg_c=my_reg(reg_tmp["REG_NAME"],
reg_tmp["REG_TYPE"],
reg_tmp["REG_ADDR"],
reg_tmp["REG_WIDTH"],
reg_tmp["REG_FIELDS"],
"16")
reg_class_list.append(reg_c)
fo=open("%s.sv"%(block_name.lower()+"_blk"),"w")
for reg_c in reg_class_list:
reg_c.reg_dec(fo)
reg_c.fld_class_collection()
reg_c.reg_fld_dec(fo)
reg_c.reg_fld_build(fo)
reg_c.reg_new(fo)
reg_model_name=block_name+"_blk"
fo.write("class %s extends uvm_reg_block;\n"%reg_model_name)
for reg_c in reg_class_list:
reg_c.reg_blk_dec(fo)
fo.write(blk1)
for reg_c in reg_class_list:
reg_c.reg_blk_build(fo)
fo.write(blk2)
fo.close()
print("the file %s is generated!!!"%(block_name.lower()+"_rf.sv"))