It is said that uvm backdoor access support routines like uvm_hdl_deposit, etc provide an interface to the DPI/PLI implementation of backdoor access used by registers. Could someone explain what that means and how it actually works? Do calls like add_hdl_path, add_hdl_path_slice also work in a similar way?
Also, for a reg_block of given structure, how would one add the hdl path to enable backdoor writes?
EX:
class reg_block extends uvm_reg_block;
function void build();
A = A_t::type_id::create("A");
A.configure()
A.build()
****how do I add the hdl path here for the reg A? would it be add_hdl_path(.path("top.dut"),) ?
//similarly for B and C
endfunction
endclass
class A extend uvm_reg;
function void build();
x1 = uvm_reg_field::type_id("x1");
x1.configure()
add_hdl_path_slice(.name("x1"), .offset(0), .size(1));
//similarly for the rest of the fields
endfunction
endclass
In reply to Vaishnavi Balasubramanian:
Hey, basically the uvm_hdl_force is a routine capable to force some values into a net with a specific pathname evaluated at runtime by calling the uvm_hdl_path_check. This works only with constant values rather than variables. There is no scenario that brights in mind why you should be calling it in the BACKDOOR.
By calling the HDL_PATH_SLICE you are just providing the path to that specific register into your RTL. It will ending up calling the uvm_hdl_deposit:
task uvm_reg::backdoor_write(uvm_reg_item rw);
uvm_hdl_path_concat paths[$];
bit ok=1;
get_full_hdl_path(paths,rw.bd_kind);
foreach (paths[i]) begin
uvm_hdl_path_concat hdl_concat = paths[i];
foreach (hdl_concat.slices[j]) begin
`uvm_info("RegMem", {"backdoor_write to ",
hdl_concat.slices[j].path},UVM_DEBUG)
if (hdl_concat.slices[j].offset < 0) begin
ok &= uvm_hdl_deposit(hdl_concat.slices[j].path,rw.value[0]);
continue;
end
begin
uvm_reg_data_t slice;
slice = rw.value[0] >> hdl_concat.slices[j].offset;
slice &= (1 << hdl_concat.slices[j].size)-1;
ok &= uvm_hdl_deposit(hdl_concat.slices[j].path, slice);
end
end
end
rw.status = (ok ? UVM_IS_OK : UVM_NOT_OK);
endtask
You can add the paths in different ways like:
// check if the register has already the path slice
if(register_target.has_hdl_path() == 0) begin
// add the RTL path slice
register_target.add_hdl_path_slice(
.name (path),
.offset(0),
.size (register_target.get_n_bits()),
.first (~register_target.has_hdl_path()),
.kind ("RTL"));
end
or alternatively, you could add that in the test or in env where you buil/configure/lock the model.
your_reg_block.configure( .hdl_path( "top.<dut_name_instance>" ) );
your_reg_block.build();
Remember that the add_hdl_path will work by storing a into a queue pool labeled by a KEY in our case is RTL and by placing the string to the path (called path slice) in there which then will be popped and concatenated to the HDL_PATH to create the final path.
Hope this clarifies. regards
In reply to Rsignori92:
Hi Rsignori92, thanks for the response. So, say I’ve linked the registers and its individual fields to the corresponding hdl path. Now, if I want to do a backdoor write calling the backdoor_write method, is there a way to do it without having to mention the path again? (like uvm_hdl_deposit takes the path as an argument)? I’m confused as to how to define backdoor_write to write into DUT corresponding to all the reg fields of a given register?
In reply to Vaishnavi Balasubramanian:
Firstly so sorry I did not notice you replied. So once the paths have been added you can simply do:
register_target.write(your_value, UVM_BACKDOOR, status);
the UVM_BACKDOOR as uvm_path_e enum allows you to perform the backdoor the backdoor_write I believe it calls the USER_DEFINED backdoor meaning you should be calling set_backdoor previously where you called the configure.
regards
In reply to Rsignori92:
No problem at all, thank you so much!