一種帶Set、Clear、Mask功能的Register的驗證方案
前言:在DV工作中,我們經常會遇到如下圖所示的Register定義,例如RW類型的Register:demo,當我們把Register:demo_set設為1的時候,demo會變為1;當我們把demo_clear置為1的時候,demo會被清零;通過mask_demo_set,可以屏蔽掉set這個function;通過mask_clear_demo,可以屏蔽掉Clear功能。
reg set_mode;
reg clr_mode;
reg demo;
always @ (posedge clk or negedge fst_n) begin
if(!rst_n)
demo <= 'h0;
else if(set_demo & ~mask_set_demo)
demo <= 'h1;
esle if(clear_demo & ~mask_clr_demo)
demo <= 'h0;
end
一、基本策略
Override用predict()的回調函數:post_predict()去Update mirror value和desired value。
二、操作實例
2.1、先定義出Set、Clear、和Mask的Class
- 必須要繼承自uvm_reg_cbs
- 必須定義為virtual function
- 在這個class中實現post_predict()這個function。根據Spec,對mirror value做Update。
2.1.1、set_regs_callback的實現
class set_regs_callback extends uvm_reg_cbs;
function new(string name = "set_regs_callback");
super.new(mane);
endfunction
virtual function void post_predict(
input uvm_reg_field fld,
input uvm_reg_data_t previous,
inout uvm_reg_data_t value,
input uvm_predict_e kind,
input uvm_path_e path,
input uvm_reg_map map
);
if(kind == UVM_PREDICT_WRITE) begin
`uvm_info(get_full_name(), $sformatf("%s Current value: 0x%0h, Previous Mirror Value: 0x%0h",
fld.get_name(), value, previous), UVM_HIGH)
value = value | previous;
`uvm_info(get_full_name(), $sformatf("%s New Mirror value: 0x%0h, fld.get_name(), value), UVM_HIGH)
end
endfunction : post_predict
endclass : set_regs_callback
2.1.2、clear_regs_callback的實現
class clr_regs_callback extends uvm_reg_cbs;
function new(string name = "set_regs_callback");
super.new(mane);
endfunction
virtual function void post_predict(
input uvm_reg_field fld,
input uvm_reg_data_t previous,
inout uvm_reg_data_t value,
input uvm_predict_e kind,
input uvm_path_e path,
input uvm_reg_map map
);
if(kind == UVM_PREDICT_WRITE) begin
`uvm_info(get_full_name(), $sformatf("%s Current value: 0x%0h, Previous Mirror Value: 0x%0h",
fld.get_name(), value, previous), UVM_HIGH)
value = ~value & previous;
`uvm_info(get_full_name(), $sformatf("%s New Mirror value: 0x%0h, fld.get_name(), value), UVM_HIGH)
end
endfunction : post_predict
endclass : clr_regs_callback
2.13、gcr_prlv_ack_reg_callback的實現
class gcr_prlv_reg_callback extends uvm_reg_cbs;
function new(string name = "set_regs_callback");
super.new(mane);
endfunction
virtual function void post_predict(
input uvm_reg_field fld,
input uvm_reg_data_t previous,
inout uvm_reg_data_t value,
input uvm_predict_e kind,
input uvm_path_e path,
input uvm_reg_map map
);
if(kind == UVM_PREDICT_WRITE) begin
`uvm_info(get_full_name(), $sformatf("%s Current value: 0x%0h, Previous Mirror Value: 0x%0h",
fld.get_name(), value, previous), UVM_HIGH)
value = ~previous;
`uvm_info(get_full_name(), $sformatf("%s New Mirror value: 0x%0h, fld.get_name(), value), UVM_HIGH)
end
endfunction : post_predict
endclass : gcr_prlv_reg_callback
2.1.4、apb_ack_mask_callback的實現
class apb_ack_mask_callback extends uvm_reg_cbs;
function new(string name = "set_regs_callback");
super.new(mane);
endfunction
virtual function void pre_write(uvm_reg_item rw);
if(rw.path == UVM_BACKDOOR) return;
`uvm_info(get_full_name(), $sformatf("Start Writing with: 0x%0h", rw.Value[0]), UVM_LOW)
rw.value = value[0][0:0] = 'h0;
`uvm_info(get_full_name(), $sformatf("End Writing with: 0x%0h", rw.Value[0]), UVM_LOW)
endfunction : post_predict
endclass : apb_ack_mask_callback
2.2、在test_base中把需要Update的Register註冊到callback pool中
2.2.1、首先定義一個append_field的function
virtual function void append_field_callback(string reg_name, string sield_name, uvm_reg_cbs cb);
uvm_reg cb_reg;
uvm_reg_field cb_field;
cb_reg = ral_model.get_reg_by_name(reg_name);
cb_field = cb_reg.get_field_by_name(field_name);
uvm_callbacks#(uvm_reg_field, uvm_reg_cbs)::add(cb_field, cb);
endfunction : append_field_callback
2.2.2、將需要使用callback的Register都加入進來
virtual function void update_cirq_reg_callback(string ral_name);
set_regs_callback rg_set_cbs;
clr_regs_callback rg_clr_cbs;
apb_ack_mask_callback apb_ack_mask;
rg_set_cbs = new({ral_name, "_set_ral_callback"});
append_field_callback("R_CIRQ_IE_CHECK_MODE_SET", "VPE0_IE_CHECK_MODE_SET", rg_set_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_SET", "VPE1_IE_CHECK_MODE_SET", rg_set_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_SET", "VPE2_IE_CHECK_MODE_SET", rg_set_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_SET", "VPE3_IE_CHECK_MODE_SET", rg_set_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_SET", "VPE4_IE_CHECK_MODE_SET", rg_set_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_SET", "VPE5_IE_CHECK_MODE_SET", rg_set_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_SET", "VPE6_IE_CHECK_MODE_SET", rg_set_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_SET", "VPE7_IE_CHECK_MODE_SET", rg_set_cbs);
rg_clr_cbs = new({ral_name, "_clr_ral_callback"});
append_field_callback("R_CIRQ_IE_CHECK_MODE_CLR", "VPE0_IE_CHECK_MODE_CLR", rg_clr_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_CLR", "VPE1_IE_CHECK_MODE_CLR", rg_clr_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_CLR", "VPE3_IE_CHECK_MODE_CLR", rg_clr_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_CLR", "VPE3_IE_CHECK_MODE_CLR", rg_clr_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_CLR", "VPE4_IE_CHECK_MODE_CLR", rg_clr_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_CLR", "VPE5_IE_CHECK_MODE_CLR", rg_clr_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_CLR", "VPE6_IE_CHECK_MODE_CLR", rg_clr_cbs);
append_field_callback("R_CIRQ_IE_CHECK_MODE_CLR", "VPE7_IE_CHECK_MODE_CLR", rg_clr_cbs);
apb_ack_mask = new({ral_name, "_apb_ack_mask"});
append_field_callback("R_CIRQ_APB_ACK_MASK", "CIRG_PAB_ACK_MASK", apb_ack_mask);
endfunction : update_cirq_reg_callback
2.3、在run_phase中調用上述function
virtual task run_phase(uvm_phase phase);
reg_test_seq reg_test_seq_inst;
phase.raise_objection(this);
begin
reg_test_seq_inst = reg_test_seq::type_id::create("reg_test_seq_inst", this);
uvm_config_db#(uvm_reg_block)::set(null, "*", "__RAL_TEST_MODEL__", ral_model);
this.update_cirq_call_back("ral_CIRQ_TOP");
reg_test_seq_inst.start(my_env.apb_mst_inst[0].sequencer);
end
phase.drop_objection(this);
endtask : run_phase