电力电子转战数字IC20220824day68——uvm实战3

 寄存器模型的自动化生成

 编写excel文件,后缀为csv;编写python脚本

才cmd中输入这两个文件的路径和命名就可以自动生成寄存器模型rgm

 

 

 寄存器模型的更新

最开始的寄存器模型是这样的

 

 

 在reg_pkg中,这些接口信号作为uvm_sequence_item定义为reg_trans类。约束,注册,域的自动化,new函数,一个不要落。

  class reg_trans extends uvm_sequence_item;
    rand bit[7:0] addr;
    rand bit[1:0] cmd;
    rand bit[31:0] data;
    bit rsp;

    constraint cstr {
      soft cmd inside {`WRITE, `READ, `IDLE};
      soft addr inside {`SLV0_RW_ADDR, `SLV1_RW_ADDR, `SLV2_RW_ADDR, `SLV0_R_ADDR, `SLV1_R_ADDR, `SLV2_R_ADDR};
      addr[7:4]==0 && cmd==`WRITE -> soft data[31:6]==0;
      soft addr[7:5]==0;
      addr[4]==1 -> soft cmd == `READ;
    };

    `uvm_object_utils_begin(reg_trans)
      `uvm_field_int(addr, UVM_ALL_ON)
      `uvm_field_int(cmd, UVM_ALL_ON)
      `uvm_field_int(data, UVM_ALL_ON)
      `uvm_field_int(rsp, UVM_ALL_ON)
    `uvm_object_utils_end

    function new (string name = "reg_trans");
      super.new(name);
    endfunction
  endclass

 

 item由driver驱动

  class reg_driver extends uvm_driver #(reg_trans);
    local virtual reg_intf intf;

    `uvm_component_utils(reg_driver)
  
    function new (string name = "reg_driver", uvm_component parent);
      super.new(name, parent);
    endfunction
  
    function void set_interface(virtual reg_intf intf);
      if(intf == null)
        $error("interface handle is NULL, please check if target interface has been intantiated");
      else
        this.intf = intf;
    endfunction

    task run_phase(uvm_phase phase);
      fork
        this.do_drive();
        this.do_reset();
      join
    endtask

    task do_reset();
      forever begin
        @(negedge intf.rstn);
        intf.cmd_addr <= 0;
        intf.cmd <= `IDLE;
        intf.cmd_data_m2s <= 0;
      end
    endtask

    task do_drive();
      reg_trans req, rsp;
      @(posedge intf.rstn);
      forever begin
        seq_item_port.get_next_item(req);
        this.reg_write(req);
        void'($cast(rsp, req.clone()));
        rsp.rsp = 1;
        rsp.set_sequence_id(req.get_sequence_id());
        seq_item_port.item_done(rsp);
      end
    endtask
  
    task reg_write(reg_trans t);
      @(posedge intf.clk iff intf.rstn);
      case(t.cmd)
        `WRITE: begin 
                  intf.drv_ck.cmd_addr <= t.addr; 
                  intf.drv_ck.cmd <= t.cmd; 
                  intf.drv_ck.cmd_data_m2s <= t.data; 
                end
        `READ:  begin 
                  intf.drv_ck.cmd_addr <= t.addr; 
                  intf.drv_ck.cmd <= t.cmd; 
                  repeat(2) @(negedge intf.clk);
                  t.data = intf.cmd_data_s2m; 
                end
        `IDLE:  begin 
                  this.reg_idle(); 
                end
        default: $error("command %b is illegal", t.cmd);
      endcase
      `uvm_info(get_type_name(), $sformatf("sent addr %2x, cmd %2b, data %8x", t.addr, t.cmd, t.data), UVM_HIGH)
    endtask
    
    task reg_idle();
      @(posedge intf.clk);
      intf.drv_ck.cmd_addr <= 0;
      intf.drv_ck.cmd <= `IDLE;
      intf.drv_ck.cmd_data_m2s <= 0;
    endtask
  endclass

 

 

 一共6个寄存器对应的csv文档如下

 更新后的结构图如下,寄存器被换成了APB总线?

寄存器接口如下

 

 根据v1.csv和寄存器图,以及寄存器接口中的信号,更新寄存器为v2

 这是自己的傻逼更新,需要更改的地方是:预留区域reserved为RO只读,id的重置值不是全部为0;域不是信号名;free slot的重置值时'd32

 用相同的操作获得rgm.pkg。寄存器模型每个reg为一个类,最后多一个类mcdf_reg

 每个寄存器类的结构都是相似的:注册,声明域,域的覆盖组;new函数中有条件例化覆盖组;build_phase完成域的例化和配置;与覆盖组相对应的采样函数。

在最后的mcdf_rgm中,所有寄存器class被作为随机变量,声明寄存器map,build_phase中对每个寄存器进行例化、配置、调用build、例化map+每个寄存器偏移地址,预留了后门访问的添加路径。最后是lock_model,这部分要再复习一下uvm的寄存器模型。

  class mcdf_rgm extends uvm_reg_block;
    `uvm_object_utils(mcdf_rgm)
    rand slv_en_reg slv_en;
    rand parity_err_clr_reg parity_err_clr;
    rand slv_id_reg slv_id;
    rand slv_len_reg slv_len;
    rand slv0_free_slot_reg slv0_free_slot;
    rand slv1_free_slot_reg slv1_free_slot;
    rand slv2_free_slot_reg slv2_free_slot;
    rand slv3_free_slot_reg slv3_free_slot;
    rand slv0_parity_err_reg slv0_parity_err;
    rand slv1_parity_err_reg slv1_parity_err;
    rand slv2_parity_err_reg slv2_parity_err;
    rand slv3_parity_err_reg slv3_parity_err;
    uvm_reg_map map;
    function new(string name = "mcdf_rgm");
      super.new(name, UVM_NO_COVERAGE);
    endfunction
    virtual function void build();
      slv_en = slv_en_reg::type_id::create("slv_en");
      slv_en.configure(this);
      slv_en.build();
      parity_err_clr = parity_err_clr_reg::type_id::create("parity_err_clr");
      parity_err_clr.configure(this);
      parity_err_clr.build();
      slv_id = slv_id_reg::type_id::create("slv_id");
      slv_id.configure(this);
      slv_id.build();
      slv_len = slv_len_reg::type_id::create("slv_len");
      slv_len.configure(this);
      slv_len.build();
      slv0_free_slot = slv0_free_slot_reg::type_id::create("slv0_free_slot");
      slv0_free_slot.configure(this);
      slv0_free_slot.build();
      slv1_free_slot = slv1_free_slot_reg::type_id::create("slv1_free_slot");
      slv1_free_slot.configure(this);
      slv1_free_slot.build();
      slv2_free_slot = slv2_free_slot_reg::type_id::create("slv2_free_slot");
      slv2_free_slot.configure(this);
      slv2_free_slot.build();
      slv3_free_slot = slv3_free_slot_reg::type_id::create("slv3_free_slot");
      slv3_free_slot.configure(this);
      slv3_free_slot.build();
      slv0_parity_err = slv0_parity_err_reg::type_id::create("slv0_parity_err");
      slv0_parity_err.configure(this);
      slv0_parity_err.build();
      slv1_parity_err = slv1_parity_err_reg::type_id::create("slv1_parity_err");
      slv1_parity_err.configure(this);
      slv1_parity_err.build();
      slv2_parity_err = slv2_parity_err_reg::type_id::create("slv2_parity_err");
      slv2_parity_err.configure(this);
      slv2_parity_err.build();
      slv3_parity_err = slv3_parity_err_reg::type_id::create("slv3_parity_err");
      slv3_parity_err.configure(this);
      slv3_parity_err.build();
      map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
      map.add_reg(slv_en, 32'h00, "RW");
      map.add_reg(parity_err_clr, 32'h04, "RW");
      map.add_reg(slv_id, 32'h08, "RW");
      map.add_reg(slv_len, 32'h0C, "RW");
      map.add_reg(slv0_free_slot, 32'h80, "RO");
      map.add_reg(slv1_free_slot, 32'h84, "RO");
      map.add_reg(slv2_free_slot, 32'h88, "RO");
      map.add_reg(slv3_free_slot, 32'h8C, "RO");
      map.add_reg(slv0_parity_err, 32'h90, "RO");
      map.add_reg(slv1_parity_err, 32'h94, "RO");
      map.add_reg(slv2_parity_err, 32'h98, "RO");
      map.add_reg(slv3_parity_err, 32'h9C, "RO");
      //slv_en.add_hdl_path_slice("???", 0, 32);
      //parity_err_clr.add_hdl_path_slice("???", 0, 32);
      //slv_id.add_hdl_path_slice("???", 0, 32);
      //slv_len.add_hdl_path_slice("???", 0, 32);
      //slv0_free_slot.add_hdl_path_slice("???", 0, 32);
      //slv1_free_slot.add_hdl_path_slice("???", 0, 32);
      //slv2_free_slot.add_hdl_path_slice("???", 0, 32);
      //slv3_free_slot.add_hdl_path_slice("???", 0, 32);
      //slv0_parity_err.add_hdl_path_slice("???", 0, 32);
      //slv1_parity_err.add_hdl_path_slice("???", 0, 32);
      //slv2_parity_err.add_hdl_path_slice("???", 0, 32);
      //slv3_parity_err.add_hdl_path_slice("???", 0, 32);
      //add_hdl_path("???");
      lock_model();
    endfunction
  endclass


版权声明:本文为weixin_39668316原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。