(1) ral环境搭建

class test_env extends uvm_env;
  ral  ral_model;
  
  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    ral_model = ral::type_id::create("ral_model");
    ral_model.configure(null,"");
    ral_model.build();
    ral_model.lock_model();
    ral_model.set_coverage(UVM_CVR_FILED_VALS);
    ral_model.default_map.set_auto_predict(1);
    cfg.ral_model = ral_model;
  endfunction

  virtual function void connect_phase(uvm_phase phase);
    ral_model.default_map.set_sequencer(this.vseqr.seqr, reg_adapter);
  endfunction

  virtual task reset_phase(uvm_phase phase);
    phase.raise_objection(phase);
    ral_model.reset();
    phase.drop_objection(phase)
  endtask
endclass

(2) adapter的写法,以axi接口的adapter为例

class reg2axi_adapter extends uvm_reg_adapter;

  `uvm_object_utils(reg2axi_adapter)

  function new(string name="reg2axi_adapter");
    super.new(name);
    provides_responses = 1;
  endfunction

  virtual function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
    global_cfg glb_cfg;
    svt_axi_port_configuration cfg;
    svt_axi_master_transaction reg_item;
    uvm_reg_addr_t addr_i;
  
    glb_cfg = global_cfg::get_instance();
    reg_item = svt_axi_master_transaction::type_id::create("axi_reg_item");
    reg_item.port_cfg = glb_cfg.axi_sys_cfg.master_cfg[1];
    addr_i = rw.addr;

    reg_item.randomize() with {
      xact_type = (rw.kind == UVM_WRITE)?svt_axi_master_transaction::WRITE:svt_axi_master_transaction::READ;
      addr == addr_i;
      burst_length == 1;
      id == 'h0;
      burst_size == svt_axi_master_transaction::BURST_SIZE_32BIT;
      burst_type == svt_axi_master_transaction::INCR;
    };

    reg_item.wstrb[0] = 'hf;
    reg_item.data[0] = (rw.kind == UVM_WRITE)? rw.data:'h0;
    return reg_item;
  endfunction

  virtual function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
    svt_axi_master_transaction reg_item;
    if(!$cast(reg_item, bus_item)) begin
      `uvm_fatal(get_full_name(), "NOT AXI MASTER TRANSACTION")
      return;
    end

    rw.kind = (reg_item.xact_type == svt_axi_master_transaction::WRITE)?UVM_WRITE:(reg_item.xact_type == svt_axi_master_transaction::READ)? UVM_READ:UVM_READ;
    rw.addr = reg_item.addr;
    rw.data = (ret_item.xact_type == svt_axi_master_transaction:WRITE)?'h0:(reg_item.xact_type == svt_axi_master_transaction::READ)?reg_item.data[0]:0;
    rw.status = (reg_item.rresp[0][1] == 0)?UVM_IS_K:UVM_NOT_OK;

  endfunction
endclass

(3) 使用uvm自带的seq来验证寄存器模型

     如下code中可以对某个reg进行操作NO_REG_TESTS.

class ral_sequence extends vum_sequence;
  task body();
    uvm_reg_hw_reset_seq  hw_rst;
    uvm_reg_bit_bash_seq  bit_bash_seq;
    uvm_reg_access_seq    acc_seq;

    uvm_resource_db#(bit)::set({"REG::", cfg.ral_model.fpga_reg_file.xxx_reg.get_full_name()}, "NO_REG_TESTS", 1, this);

    hw_rst = uvm_reg_hw_reset_seq::type_id::create("hw_rst");
    bit_bash_seq = uvm_reg_bit_bash_seq::type_id::create("bit_bash_seq");
    acc_seq      = uvm_reg_access_seq::type_id::create("acc_seq");

    hw_rst.model = cfg.ral_model.reg_file1;
    hw_rst.start(p_sequencer.seqr);
    bit_bash_seq.model = cfg.ral_model.reg_file1;
    bit_bash_seq.start(p_sequencer.seqr);
    acc_seq.model = cfg.ral_model.reg_file1;
    acc_seq.start(p_sequencer.seqr);    
  endtask
enclass

(4)中的reg_file1是寄存器模型中的block 块.

class ral_model extends uvm_reg_block;
  rand ral_reg_file reg_file;

  function void build();
    this.default_map = create_map("", 0, 4, UVM_LITLE_ENDIAN, 0);
    this.reg_file.configure(this, "");//TODO add path
    this.reg_file.build();
    this.default_map.add_submap(this.reg_file.default_map, UVM_REG_ADDR_WIDTH'h0);
  endfunction
enclass

(5) 读写单个reg的方法

task write_reg(string core_id, string module_name, string reg_name, uvm_reg_data_t val, string subsys_name = "APU0", uvm_verbosity verb=UVM_LOW);
  uvm_reg_block ralmdl;
  uvm_reg_block subsys_reg_blk
  uvm_reg_block module_reg_blk;
  uvm_reg  reg_i;
  uvm_status_e  status;
  uvm_reg_data_t rdata;
  apu_glb_cfg.cr_cfg.core_id = core_id;
  ralmdl = glb_cfg.ral_model;
  subsys_reg_blk = ralmdl.get_block_by_name(subsys_name);
  modeule_reg_blk= subsys_reg_blk.get_block_by_name(module_name);
  reg_i = module_reg_blk.get_reg_by_name(reg_name);
  reg_i.write(status, val);
endtask

task read_reg(string core_id, string module_name, string reg_name, uvm_reg_data_t val, string subsys_name = "APU0", uvm_verbosity verb=UVM_LOW);
  uvm_reg_block ralmdl;
  uvm_reg_block subsys_reg_blk
  uvm_reg_block module_reg_blk;
  uvm_reg  reg_i;
  uvm_status_e  status;
  uvm_reg_data_t rdata;
  apu_glb_cfg.cr_cfg.core_id = core_id;
  ralmdl = glb_cfg.ral_model;
  subsys_reg_blk = ralmdl.get_block_by_name(subsys_name);
  modeule_reg_blk= subsys_reg_blk.get_block_by_name(module_name);
  reg_i = module_reg_blk.get_reg_by_name(reg_name);
  reg_i.read(status, val);
endtask

(6) 如何验证寄存器

  (3)中能够验证寄存器的读写正确性,但是不能验证reg到module之间的正确传递,所以可以把(3)中case关闭,跑验证中已经写好的case,看code coverage,来查看哪些reg没有验到从reg到module,然后再逐个去验证,这样寄存器的验证就比较完善

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐