美文网首页ASIC DV
搞定数字IC中的寄存器文件

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

作者: sarai_c7eb | 来源:发表于2020-07-02 20:13 被阅读0次

    寄存器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
    整体思路:

    • 根据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"))
    
    

    相关文章

      网友评论

        本文标题:搞定数字IC中的寄存器文件

        本文链接:https://www.haomeiwen.com/subject/gqcdqktx.html