ASIC DV

搞定数字IC中的寄存器文件

2020-07-02  本文已影响0人  sarai_c7eb

寄存器File在SOC中的应用非常普遍;
CPU通过控制寄存器从而控制IC逻辑的功能,软件的SDK开发几乎都是针对这些寄存器的开发;
然而寄存器的设计无论从文档角度还是代码角度都是一堆重复的工作;这些工作繁琐而易于出错;给开发过程带来了不少的困难;

本文利用excel完成寄存器文档的开发,然后通过VBA将表格转JSON格式:

  1. 对设计工作而言,可以开发脚本从JSON转verilog文件
  2. 对验证工作而言,可以开发脚本从JSON转ralf文件

1. PART1:EXCEL转JSON

EXCEL表单

EXCEL表单如上图,需要注意的是:

  1. Width内容一定要填写正确,即表示除最高位的Reserved filed外的寄存器实际宽度;
  2. Field部分也要填写正确,即不能不填写,只支持单个数字或a:b的格式;
  3. TYPE部分只支持reg(寄存器)和mem(RAM)
    • mem通常用于RALF生成,RTL不会产生mem类代码;
    • 建议将mem类型和reg类型分开;
    • mem类型的Foffset属性带边mem的宽度,WIDTH则代码mem bit width;
  4. 目前只支持ro,rw,rc,wc,w1p,cnt,int类型;
  5. 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
整体思路:

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"))

上一篇下一篇

猜你喜欢

热点阅读