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 blocktop_reg_block的引用,registermodel就是在這個層次實例化的。
bus_env引用該agent的register modelbus_reg_block,并實例化adapter和predictor,該adapter和predictor將該registermodel連接到agent。
uvm代碼生成器在使用registermodel的default sequence中向相應registermodel中的每個寄存器寫入一個隨機值。
Filenamebus_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:
Filenamebus_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:
Filenamebus.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
審核編輯:劉清
-
寄存器
+關注
關注
31文章
5608瀏覽量
129998 -
UVM
+關注
關注
0文章
183瀏覽量
20018 -
生成器
+關注
關注
7文章
322瀏覽量
22715 -
DUT
+關注
關注
0文章
194瀏覽量
13453
原文標題:Easier UVM Code Generator Part 3:添加Register Layer
文章出處:【微信號:芯片驗證工程師,微信公眾號:芯片驗證工程師】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
如何在IAR Embedded Workbench中配置生成對應代碼區域的CRC校驗碼
如何在simv sim_opts中使用uvm_set_verbosity
UVM sequence分層有哪幾種方式呢
UVM sequence分層的幾種體現
基于UVM的代碼生成器的開發設計
如何在生產時防止代碼泄漏
如何在生成的代碼中使用UVM Register Layer?
評論