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