uvm register model
1.基本概念
uvm_reg_field:寄存器模型中最小单位
uvm_reg:由uvm_reg_field组成
1 class reg_invert extends uvm_reg; 2 3 rand uvm_reg_field reg_data; 4 5 virtual function void build(); 6 reg_data = uvm_reg_field::type_id::create("reg_data"); 7 // parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, individually accessible 8 reg_data.configure(this, 1, 0, "RW", 1, 0, 1, 1, 0); 9 endfunction 10 11 `uvm_object_utils(reg_invert) 12 13 function new(input string name="reg_invert"); 14 //parameter: name, size, has_coverage 15 super.new(name, 16, UVM_NO_COVERAGE); 16 endfunction 17 endclass
uvm_reg_block:由uvm_reg组成,也可加入其他uvm_reg_block
uvm_reg_map:存储各个寄存器的地址映射关系
1 class reg_model extends uvm_reg_block; 2 rand reg_invert invert; 3 4 virtual function void build(); 5 default_map = create_map("default_map", 0, 2, UVM_BIG_ENDIAN, 0);//系统声明的uvm_reg_map 6 7 invert = reg_invert::type_id::create("invert", , get_full_name()); 8 invert.configure(this, null, "invert");//后面两个参数是reg_file和后门访问路径 9 invert.build(); 10 default_map.add_reg(invert, 'h9, "RW");//后两个参数是地址和access方式 11 endfunction 12 13 `uvm_object_utils(reg_model) 14 15 function new(input string name="reg_model"); 16 super.new(name, UVM_NO_COVERAGE); 17 endfunction 18 19 endclass
2.应用
寄存器模型前门访问会通过sequence产生一个uvm_reg_bus_op的变量,此变量要经过adapter转换后交给sequencer,随后交给driver
register model --> sequence --> adapter --> sequencer --> driver
1 class my_adapter extends uvm_reg_adapter; 2 string tID = get_type_name(); 3 4 `uvm_object_utils(my_adapter) 5 6 function new(string name="my_adapter"); 7 super.new(name); 8 endfunction : new 9 10 function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw); 11 bus_transaction tr; 12 tr = new("tr"); 13 tr.addr = rw.addr; 14 tr.bus_op = (rw.kind == UVM_READ) ? BUS_RD: BUS_WR; 15 if (tr.bus_op == BUS_WR) 16 tr.wr_data = rw.data; 17 return tr; 18 endfunction : reg2bus 19 20 function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw); 21 bus_transaction tr; 22 if(!$cast(tr, bus_item)) begin 23 `uvm_fatal(tID, 24 "Provided bus_item is not of the correct type. Expecting bus_transaction") 25 return; 26 end 27 rw.kind = (tr.bus_op == BUS_RD) ? UVM_READ : UVM_WRITE; 28 rw.addr = tr.addr; 29 rw.byte_en = 'h3; 30 rw.data = (tr.bus_op == BUS_RD) ? tr.rd_data : tr.wr_data; 31 rw.status = UVM_IS_OK; 32 endfunction : bus2reg 33 34 endclass : my_adapter
在uvm test中instance和connect
1 class base_test extends uvm_test; 2 3 my_env env; 4 my_vsqr v_sqr; 5 reg_model rm; 6 my_adapter reg_sqr_adapter; 7 ... 16 endclass 17 18 19 function void base_test::build_phase(uvm_phase phase); 20 super.build_phase(phase); 21 env = my_env::type_id::create("env", this); 22 v_sqr = my_vsqr::type_id::create("v_sqr", this); 23 rm = reg_model::type_id::create("rm", this); 24 rm.configure(null, "");//parent和后门访问路径 25 rm.build(); 26 rm.lock_model(); 27 rm.reset();
rm.set_hdl_path_root("top_tb.my_dut"); //设置后门的根目录 28 reg_sqr_adapter = new("reg_sqr_adapter"); 29 env.p_rm = this.rm; 30 endfunction 31 32 function void base_test::connect_phase(uvm_phase phase); 33 super.connect_phase(phase); 34 v_sqr.p_my_sqr = env.i_agt.sqr; 35 v_sqr.p_bus_sqr = env.bus_agt.sqr; 36 v_sqr.p_rm = this.rm; 37 rm.default_map.set_sequencer(env.bus_agt.sqr, reg_sqr_adapter); 38 rm.default_map.set_auto_predict(1); 39 endfunction
在ref model中使用
1 class my_model extends uvm_component; ... 3 reg_model p_rm; ... 5 endclass
1 function void my_env::connect_phase(uvm_phase phase); ... 9 mdl.p_rm = this.p_rm; 10 endfunction
1 task my_model::main_phase(uvm_phase phase); 2 my_transaction tr; 3 my_transaction new_tr; 4 uvm_status_e status; 5 uvm_reg_data_t value; 6 super.main_phase(phase); 7 p_rm.invert.read(status, value, UVM_FRONTDOOR); 8 while(1) begin 9 port.get(tr); 10 new_tr = new("new_tr"); 11 new_tr.copy(tr); 12 //`uvm_info("my_model", "get one transaction, copy and print it:", UVM_LOW) 13 //new_tr.print(); 14 if(value) 15 invert_tr(new_tr); 16 ap.write(new_tr); 17 end 18 endtask
在sequence中使用
1 class case0_cfg_vseq extends uvm_sequence; ... 10 virtual task body(); 11 uvm_status_e status; 12 uvm_reg_data_t value; ... 15 p_sequencer.p_rm.invert.read(status, value, UVM_FRONTDOOR); 16 `uvm_info("case0_cfg_vseq", $sformatf("invert's initial value is %0h", value), UVM_LOW) 17 p_sequencer.p_rm.invert.write(status, 1, UVM_FRONTDOOR); 18 p_sequencer.p_rm.invert.read(status, value, UVM_FRONTDOOR); ... 22 endtask 23 24 endclass
3.register model常用api
write/read:可通过前门或后门方式读写DUT,寄存器模型会相应更新期望值和镜像值,符合寄存器读写属性要求
peek/poke:通过后门方式读写DUT,寄存器模型会相应更新期望值和镜像值,无视寄存器读写属性要求
set:更新寄存器模型期望值,镜像值不变
get:返回寄存器模型期望值
update:检查寄存器模型期望值和镜像值是否一致,如果不一致,就会将期望值写入DUT并更新镜像值
randomize:寄存器模型期望值变为随机值,镜像值不变,通常后接update操作
mirror:读取DUT中寄存器值更新到寄存器模型,如发现与镜像值不一致可选择是否报错,UVM_CHECK报错,UVM_NO_CHECK不报错
predict:更新镜像值并且不对DUT操作
uvm_reg_block::get_root_blocks(blks):blks为整个验证平台的最顶层reg_block队列句柄
uvm_reg_map的函数get_reg_by_offset(addr):可根据地址addr获得改地址所对应寄存器句柄