How to force dut internal signals in UVM environment

Hi,
I want to force some internal signals in DUT. If I put the internal signals in a interface, can I use like " assign if.internal = 1’b1 " ? Does this value have a conflict with real internal value? I mean the signal “internal” will have two drives.
Thank you so much!

Jun

I want to force some internal signals in DUT. If I put the internal signals in a interface, can I use like " assign if.internal = 1’b1 " ? Does this value have a conflict with real internal value? I mean the signal “internal” will have two drives.

What you are suggesting would work, but the internal signal would have to be a wire.
The problem with your approach is that it makes your DUT unclean since it inserts TB signals into your synthesizable design.

A better approach would be to have the assign into that internal signal from the interface under the control of the testbench. I demonstrate that below. The “cntrl_enb” and “cntrl_data” are issued by the testbench (e.g., the driver).

interface dut_if(input bit clk);
    bit cntrl_enb;       // from control 
    logic [7:0] cntrl_data; // from control 
     
    assign top.dut1.data= cntrl_enb ? cntrl_data : 'Z; 

endinterface 

module dut(input bit clk); 
    wire[7:0] data;
endmodule : dut

module top; 
    bit clk;
    dut dut1(.*); 
    dut_if dut_if1(clk); 
endmodule

Ben Cohen SystemVerilog.us

In reply to ben@SystemVerilog.us:

Another option is to use the force. Maybe more of what you want

interface dut_if(input bit clk);
    bit cntrl_enb;       // from control 
    logic [7:0] cntrl_data; // from control 
     
    //assign top.dut1.data= cntrl_enb ? cntrl_data : 'Z; 
    always @ (posedge clk)
        if(cntrl_enb)
          force top.dut1.data= cntrl_data;  // cntrl_enb ? cntrl_data : 'Z;
        else release top.dut1.data;

endinterface 

module dut(input bit clk); 
    // wire [7:0] data;
    logic [7:0] data;
endmodule : dut

module top; 
    bit clk;
    dut dut1(.*); 
    dut_if dut_if1(clk); 
endmodule

Ben SystemVerilog.us

In reply to ben@SystemVerilog.us:

Hi Ben,
Thank you so much for helping with this problem.
Your second way is working. The first one seems have problem, because if cntrl_enb = 1’b1, then the internal signal “top.dut1.data” still has two drive.

Thank you again.

Jun

In reply to Jun LI:

I have a similar problem but can not use the absolute path for the force. Is there any other way?

I would be very grateful if anyone could help me …

Ben’s Solution is perfect.
I had the same issue and tackled it almost similarly.
Create an interface with the same signals you want to force in DUT. Create some sort of control signals that you could drive from the driver or testcase. You can do that by getting a virtual handle in the testcase

Code like :

interface dut_if()
 logic ctrl;
 wire logic dut_pin;
 logic dut_pin_desired_val;
 always @ (*) begin
  if(ctrl) begin
     force dut_pin = dut_pin_desired_val;
  end
 end

In TB,

dut_if if_instance();
dut dut_instance(.dut_pin(.if_instance.dut_pin)); //connect if to DUT
//do a uvm config db set in TB for dut_if here

**make sure you have a virtual handle declared somehwre in top pkg(typedef virtual dut_if dut_vif)

In testcase,

dut_vif vif;//declare a vif instance.
//do a uvm config db "get" of the dut_vif;

Now in testcase you can drive, vif.ctrl and vif.dut_pin_desired_val any way you want and see the same reflected on DUT.

Hello, I am facing a similar issue. The “force” solution works for me but since the force and the clocking edge arrive at the same time, this leads to a race-condition in the design. I tried fixing that by adding default output skew to the clocking block but that didn’t help. Should the skew be applied to the force statement? Or it is only applicable to non-blocking assignments?

Here is the code,

interface drv_sig(input bit clk);

bit force_enable;
bit drv_sig;

clocking drv_cb @(posed clk);
  input force_enable;
  output drv_sig;
endclocking

modport driver(
  clocking drv_cb,
  input clk,
  input force_enable,
output drv_sig);


always @(posedge clk) 
   if(force_enable != $past(force_enable)) begin
      if(force_enable == 1)
         force top.dut.data = drv_sig;
      else
         release top.dut.data;
    end

endinterface

Appreciate any input.

In reply to cooltoad:
Below is a link that I once used in a training class. I’ll emphasize certain points below.
I see this approach as a good way to drive interface signals.
http://systemverilog.us/vf/test_if_class.sv


interface dut_if(input logic clk);  // DO NOT USE!!!!!
	parameter hold_time   =3;  // 3ns  
	parameter setup_time  = 5;
	wire[31:0] data;
	logic[31:0] address;
	logic rd, wr; 
	clocking driver_cb @(posedge clk);
		default input #setup_time output #hold_time;
		output address;
		output rd, wr; 
		inout data;
	endclocking
	modport dut_mp(inout data, input clk, rd, wr, address);
	modport driver_mp(clocking driver_cb);
	ap_rdwr: assert property(@ (driver_cb)
		not(rd && wr));
	ap_addr_not0: assume property(@(driver_cb) $time> 20ns |-> address != 'h0);
endinterface : dut_if

class driver;
	virtual interface dut_if.driver_mp v_if; 
	transaction tx        =new(); 
	// driver
	task automatic drive();
		if(!randomize(tx))  $error("randomization failure"); 
		@ (v_if.driver_cb) begin
			if(!randomize(tx))  $error("randomization failure"); 
			v_if.driver_cb.rd                                  <= tx.rd; 
			v_if.driver_cb.wr                                  <= tx.wr; 
			v_if.driver_cb.address                             <= tx.address; 
			if(tx.wr)  v_if.driver_cb.data  <= tx.data_dr;   
			else  v_if.driver_cb.data  <=  'hZ; 
		end
	endtask : drive
endclass : driver
Notice the 3 ns delays in the outputs. 
http://systemverilog.us/vf/noforce.png

// ***** On the force, I tried 
task automatic drive();
		if(!randomize(tx))  $error("randomization failure"); 
		@ (v_if.driver_cb) begin
			if(!randomize(tx))  $error("randomization failure"); 
			...
			if(tx.wr)  
				//v_if.driver_cb.data  <= tx.data_dr;  
			    force v_if.driver_cb.data  = tx.data_dr;  
			else  v_if.driver_cb.data  <=  'hZ; 
		end
	endtask : drive 
// **** ERROR MESSAGE
 Variables accessed through virtual interface cannot be used in continuous assignments.
 

Thus, go over my example and see if that works for you. I feel it is a better and cleaner approach, and more a la UVM.
Ben Cohen
http://www.systemverilog.us/ ben@systemverilog.us
For training, consulting, services: contact Home - My cvcblr


In reply to Jun LI:

Just my two cents,
If you want to create an interface for internal signals there is a DVCon paper from Dave which shows how to integrate a UVM testbench with a bound interface. See this too.

When you use the force statement on a wire, that overrides all the drivers on the network until encountering another force or release statement.

For example

module test;  
    reg a, b, c, d;
    wire e;
    and and1 (e, a, b, c);

    initial begin
      $monitor("%d d=%b,e=%b", $stime, d, e);
      assign d = a & b & c;
      a = 1;
      b = 0;
      c = 1;
      #10;
      force d = (a | b | c);
      force e = (a | b | c);
      #10;
      release d;
      release e;
      #10 $finish;
    end
endmodule

In the example above and gate and1 is patched to work as or gate. If you simulate it, you’d get following results:

Results:
00 d=0,e=0
10 d=1,e=1
20 d=0,e=0

Without force statement, for t = 10, e should be equal to 0 (since 1 & 0 & 1 = 0). Using force statement overrides result of and1 and force e = 1. But as soon as release is applied to e, the value is change to 0 (the functionality of and gate is restored).

In the example above you can also see that force/release can be applied both to regs (d) and wires (e). This statements are used in testbenches, when you want to force determined value in reg or wire.

In case you want to force an interface using a variable, then that variable must not be transient. From Dave’s comment:
“A force statement many not contain any expressions made with automatic variables. That is because the lifetime of the effect of a force statement may go beyond the lifetime the the automatic variables. When you exit the task a, the automatic variable c disappears and there is no longer a valid expression for the force to use.
This is easy to fix on the RHS of the force by using an intermediate static variable.”
See verilog - Automatic variable may not be used in non-procedural constructs - Stack Overflow

Lastly, if you want to force /release an intern signal from an UVM class, then you will have to create a task in your interface to do the force/release, then call the task from your UVM class using virtual interfaces. If the DUT signal is unrelated to any existing interface, you may need to create a separate interface and use bind to instantiate the interface inside your DUT.
Notice that the SV force command CANNOT be used directly with virtual interfaces, therefore the need for the separated force tasks inside the interface.


interface blabla;

.....


  task force_reg_rn_1(logic [31:0] value);
         `ifdef VCS
             $hdl_xmr_force("secure_core_tb_top.u_secure_core_wrp.SR_REG_RN_1", "value", "0 ps", "freeze",  , 0);
         `else
             //QUESTA
             force secure_core_tb_top.u_secure_core_wrp.SR_REG_RN_1 = value;//direct force DUT intern signal
         `endif
    endtask
    task release_reg_rn_1();
         `ifdef VCS
             $hdl_xmr_release("secure_core_tb_top.u_secure_core_wrp.SR_REG_RN_1", 0);
         `else
             //QUESTA
             release secure_core_tb_top.u_secure_core_wrp.SR_REG_RN_1;//direct release DUT intern signal
         `endif
    endtask

endinterface

In reply to ben@SystemVerilog.us:

This worked for me also. Thanks Ben !!

Hi,

Suppose I have a design which gives error at 60,000 clock cycles. For example, variable A value changes from 1 to 0 at t = 60,000 clock time only. I don’t want to run the test-case this much cycles long to save simulation time and to check condition. How can I use force and release statements for this?

In reply to Vaishali:

BTW 60000 clock cycles might not be so much simulation time.
Forcing internal signals is always a dangerous game. If you want to be correct you had to force all internal nodes to adequate values. This is not practicable and you might want to check with asequence a lot more of functionality and not only the change of 1 explicit signal.
The simulators are supporting situations like your scenario. You can store the internal sates for a time prior to the interesting time. You can then load this state and continue from this time with your simulation.