Search code examples
verilogsystem-verilogtest-bench

Why does the force statement get stuck? And how to force a single bit in an array of bits?


module dut_top;
    wire [31:0] ctrl_32bit;
    wire        ctrl_1bit;
    assign ctrl_32bit = 0;
    assign ctrl_1bit=0;
    
    initial begin #1000ns; end
endmodule

program automatic test;
    initial begin
        repeat(5) begin
            #100ns;
            force dut_top.ctrl_32bit[0] =~ dut_top.ctrl_32bit[0]; //LINE 1
            force dut_top.ctrl_1bit     =~ dut_top.ctrl_1bit;     //LINE 2
            force dut_top.ctrl_32bit[0] =  dut_top.ctrl_1bit;     //LINE 3
        end
    end
endprogram

My code is shown above. LINE 1 gets stuck. But after commenting out LINE 1, LINE 2 and LINE 3 work fine.

  1. What is the reason? I think it is related to timeslot, but I can't explain it myself.
  2. How should I solve this requirement?

I want to force a single bit in an array of bits every once in a while.


Solution

  • The force statement does not deposit the value, it forcefully applies the expression to the target. It behaves similar to the concurrent assignment of an assign statement. Therefore force dut_top.ctrl_32bit[0] = ~dut_top.ctrl_32bit[0]; has zero-time feedback to itself.

    To understand how force works when the right-hand-side is a variable, consider the following:

    module force_example;
      reg [3:0] a,b;
      initial begin
        $monitor("a:%b b:%b @ %2t", $time);
        force b = a;
        for(a=0; a<5; a=a+1) #1;
        #1 $finish();
      end
    endmodule
    

    b will equal a even as a changes. Regardless of the simulator, it will will display the following:

    a:0000 b:0000 @  0
    a:0001 b:0001 @  1
    a:0010 b:0010 @  2
    a:0011 b:0011 @  3
    a:0100 b:0100 @  4
    a:0101 b:0101 @  5
    

    You need to break the feedback loop to resolve your force issue. There are two ways to do this:

    1. Conditional logic and force to a constant:

      program automatic test;
          initial begin
              repeat(5) begin
                  #100ns;
                  if (dut_top.ctrl_32bit[0])
                      force dut_top.ctrl_32bit[0] = 1'b0;
                  else
                      force dut_top.ctrl_32bit[0] = 1'b1;
                  if (dut_top.ctrl_1bit)
                      force dut_top.ctrl_1bit     = 1'b0;
                  else
                      force dut_top.ctrl_1bit     = 1'b1;
                  force dut_top.ctrl_32bit[0] =  dut_top.ctrl_1bit; // This is okay
              end
          end
      endprogram
      
    2. Intermediate variables:

      program automatic test;
          logic [31:0] tb_ctrl_32bit;
          logic        tb_ctrl_1bit;
          initial begin
              tb_ctrl_32bit = dut_top.ctrl_32bit;
              tb_ctrl_1bit  = dut_top.ctrl_1bit;
              force dut_top.ctrl_32bit[0] =~ tb_ctrl_32bit[0]; //LINE 1
              force dut_top.ctrl_1bit     =~ tb_ctrl_1bit;     //LINE 2
              force dut_top.ctrl_32bit[0] =  tb_ctrl_1bit;     //LINE 3
              repeat(5) begin
                  #100ns;
                  tb_ctrl_32bit[0] =~ dut_top.ctrl_32bit[0];
                  tb_ctrl_1bit     =~ dut_top.ctrl_1bit;
                  tb_ctrl_32bit[0] =  dut_top.ctrl_1bit;
              end
          end
      endprogram