UVM has the facility of doing backdoor reads from HDL paths via DPI/PLI interface.
Consider a simple design hierarchy shown below for illustration purposes. We also need a testbench to instantiate the design and start the test.
module B;
reg [3:0] cfg;
endmodule
module A;
B b;
endmodule
// Testbench module
module tb;
A a();
initial
run_test("base_test");
endmodule
uvm_hdl_check_path
import "DPI-C" context function int uvm_hdl_check_path (string path);
This method returns 1 if the given HDL path exists, else it returns a 0.
class base_test extends uvm_test;
...
virtual function void build_phase (uvm_phase phase);
if (uvm_hdl_check_path ("tb.a.b.cfg"))
`uvm_info ("TEST", "Path tb.a.b.cfg exists", UVM_MEDIUM)
if (!uvm_hdl_check_path ("tb.a.def"))
`uvm_info ("TEST", "Path tb.a.def does not exist", UVM_MEDIUM)
endfunction
endclass
uvm_hdl_deposit
import "DPI-C" context function int uvm_hdl_deposit (string path, uvm_hdl_data_t value);
This method deposits the given value onto the HDL path and returns 1 if successful, else 0.
class base_test extends uvm_test;
...
virtual task run_phase (uvm_phase phase);
if (! uvm_hdl_deposit("tb.a.b.cfg", 4'h9))
`uvm_error ("TEST", "Deposit on tb.a.b.cfg failed", UVM_MEDIUM)
endtask
endclass
uvm_hdl_force
import "DPI-C" context function int uvm_hdl_force (string path, uvm_hdl_data_t value);
This method forces the value on the given path and returns 1 if successful, else it returns 0. The difference between uvm_hdl_force
and uvm_hdl_deposit
is that the former has to be released at some point later in time for the original net to be able to drive the signal. For uvm_hdl_deposit
, the value is simply placed onto the net and will persist until the original net drives some other value onto it.
class base_test extends uvm_test;
...
virtual task run_phase (uvm_phase phase);
if (! uvm_hdl_force("tb.a.b.cfg", 4'h9))
`uvm_error ("TEST", "Force on tb.a.b.cfg failed", UVM_MEDIUM)
endtask
endclass
uvm_hdl_force_time
task uvm_hdl_force_time (string path, uvm_hdl_data_t value, time force_time = 0);
Forces the given value onto the HDL path for the specified amount of time. If force_time is 0, uvm_hdl_deposit
will be called. Again, this method returns 1 if successful, else 0. The difference between this method and uvm_hdl_force
is that the latter has to be released some time later, while this method automatically releases the force after the given time.
class base_test extends uvm_test;
...
virtual task run_phase (uvm_phase phase);
if (! uvm_hdl_force_time("tb.a.b.cfg", 4'h9, 30))
`uvm_error ("TEST", "Force on tb.a.b.cfg failed", UVM_MEDIUM)
endtask
endclass
uvm_hdl_release_and_read
import "DPI-C" context function int uvm_hdl_release_and_read (string path, inout uvm_hdl_data_t value);
This releases the value previously set by uvm_hdl_force
and returns 1 if it is successful, else 0. The value provided as an argument to this method is applied to the HDL after it is released.
class base_test extends uvm_test;
...
virtual task run_phase (uvm_phase phase);
if (! uvm_hdl_release_and_read("tb.a.b.cfg", 4'hE))
`uvm_error ("TEST", "Release on tb.a.b.cfg failed", UVM_MEDIUM)
endtask
endclass
uvm_hdl_release
import "DPI-C" context function int uvm_hdl_release (string path);
This method will release the value previously forced on the given HDL path with uvm_hdl_force
and returns 1 if successful, else 0.
class base_test extends uvm_test;
...
virtual task run_phase (uvm_phase phase);
if (! uvm_hdl_release("tb.a.b.cfg"))
`uvm_error ("TEST", "Release on tb.a.b.cfg failed", UVM_MEDIUM)
endtask
endclass
uvm_hdl_read
import "DPI-C" context function int uvm_hdl_read (string path, output uvm_hdl_data_t value);
Reads the current value on the given HDL path and returns 1 if successful, else 0.
class base_test extends uvm_test;
...
virtual task run_phase (uvm_phase phase);
int rdata;
if (! uvm_hdl_read("tb.a.b.cfg", rdata))
`uvm_error ("TEST", "Read from tb.a.b.cfg failed", UVM_MEDIUM)
endtask
endclass