Acquire a Register Model
寄存器模型一般可以使用工具生成或者从头开始编写,寄存器模型示例如下:
Filename regmodel.sv class dummy_reg extends uvm_reg; `uvm_object_utils(dummy_reg) rand uvm_reg_field F; ... virtual function void build(); F = uvm_reg_field::create("F"); F.configure(this, 8, 0, "RW", 1, 8'h00, 1, 1, 1); endfunction endclass class bus_reg_block extends uvm_reg_block; `uvm_object_utils(bus_reg_block) rand dummy_reg reg0; uvm_reg_map bus_map; ... virtual function void build(); reg0 = dummy_reg::create("reg0"); reg0.configure(this); reg0.build(); bus_map = create_map("bus_map", 'h0, 1, UVM_LITTLE_ENDIAN); default_map = bus_map; bus_map.add_reg(reg0, 'h0, "RW"); lock_model(); endfunction endclass class top_reg_block extends uvm_reg_block; `uvm_object_utils(top_reg_block) bus_reg_block bus; uvm_reg_map bus_map; ... virtual function void build(); bus = bus_reg_block::create("bus"); bus.configure(this); bus.build(); bus_map = create_map("bus_map", 'h0, 1, UVM_LITTLE_ENDIAN); default_map = bus_map; bus_map.add_submap(bus.bus_map, 'h0); lock_model(); endfunction endclass
Add Register Access to the Interface Template File
我们从interface template file的主要部分开始,其中指定了事务和接口中的变量。为了使示例简单,我们省略monitor和focv,只包含driver。
Filename bus.tpl agent_name = bus trans_item = bus_tx trans_var = rand bit cmd; trans_var = rand byte addr; trans_var = rand byte data; driver_inc = bus_do_drive.sv if_port = logic clk; if_port = bit cmd; if_port = byte addr; if_port = byte data; if_clock = clk
现在,我们通过指定register layer具有的访问类型以及寄存器层和agent之间的映射来扩展interface template file。这是通过标识register layer用于读取和写入 DUT 中的寄存器的command, address和data:
reg_access_mode = WR reg_access_block_type = bus_reg_block uvm_reg_kind = cmd uvm_reg_addr = addr uvm_reg_data = data
reg_access_mode指定是否允许register layer对寄存器进行写/读(WR)、只写 (WO) 或只读 (RO) 访问。
reg_access_block_type在寄存器模型文件中指定 uvm_reg_block 类型,该文件包含要读取或写入的寄存器。
Add Register Access to the Common Template File
top-level register model必须在 common template file中向uvm代码生成器描述:
Filename common.tpl regmodel_file = regmodel.sv top_reg_block_type = top_reg_block
top_reg_block_type 参数必须为top-level register model的类名。
Generate and Run
uvm代码生成器将创建以下结构:
top_tb (module) ↳ top_th (module instance) ↳ bus_if (interface instance) mydut (module instance) ↳ top_test (object, class uvm_test) ↳ top_config (created in build_phase, class uvm_object) top_env (uvm_env) ↳ bus_env_config (uvm_object) top_reg_block (uvm_reg_block) bus_env (uvm_env) ↳ bus_config (uvm_object) bus_reg_block (uvm_reg_block) reg2bus_adapter uvm_reg_predictor bus_agent (uvm_agent) ↳ bus_sequencer bus_driver (uvm_driver) bus_monitor (uvm_monitor) bus_coverage (uvm_subscriber) bus_env_coverage (uvm_subscriber) ↳ top_default_seq (created in run_phase, class uvm_sequence) ↳ bus_env_default_seq (uvm_sequence) ↳ registers.update()
实例化register model时,使用register model的每个agent都在其自己的 env 中实例化。在上面的结构中,可以看到:
top_test instantiates top_env instantiates bus_env instantiates bus_agent
top_env具有对top-level register block top_reg_block的引用,register model就是在这个层次实例化的。
bus_env引用该agent的register model bus_reg_block,并实例化adapter和predictor,该adapter和predictor将该register model连接到agent。
uvm代码生成器在使用register model的default sequence 中向相应register model中的每个寄存器写入一个随机值。
Filename bus_env_seq_lib.sv task bus_env_default_seq::body(); super.body(); `uvm_info(get_type_name(), "default sequence starting", UVM_HIGH) regmodel.get_registers(data_regs); data_regs.shuffle(); foreach(data_regs[i]) begin // Randomize register content and then update if(!data_regs[i].randomize()) `uvm_error(get_type_name(), $sformatf("Randomization error for data_regs[%0d]", i)) data_regs[i].update(status, .path(UVM_FRONTDOOR), .parent(this)); end `uvm_info(get_type_name(), "default sequence completed", UVM_HIGH) endtask : body
添加用户定义的寄存器sequence
与前面的文章一样,可以通过扩展uvm代码生成器创建的default sequence来创建自己的sequence。这次它是一个专门的register sequence:
Filename bus_env_reg_seq.sv class bus_env_reg_seq extends bus_env_default_seq; `uvm_object_utils(bus_env_reg_seq) ... task body(); regmodel.reg0.write(status, .value('hab), .parent(this)); assert(status == UVM_IS_OK); regmodel.reg0.write(status, .value('hcd), .parent(this)); assert(status == UVM_IS_OK); regmodel.reg0.write(status, .value('hef), .parent(this)); assert(status == UVM_IS_OK); regmodel.reg0.read(status, .value(data), .parent(this)); assert(status == UVM_IS_OK); endtask: body endclass : bus_env_reg_seq
同样需要在 interface template file添加 factory override:
Filename bus.tpl ... reg_seq_inc = bus_env_reg_seq.sv agent_factory_set = bus_env_default_seq bus_env_reg_seq
然后可以对生成的现成代码运行仿真,应该看到仿真日志中包含以下打印信息:
# @10000 mydut bus_cmd = W, bus_addr = 00, bus_data = ab # @30000 mydut bus_cmd = W, bus_addr = 00, bus_data = cd # @50000 mydut bus_cmd = W, bus_addr = 00, bus_data = ef # @70000 mydut bus_cmd = R, bus_addr = 00, bus_data = 00
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !