1

Quite often I have to simulate a situation, where an input signal entering the FPGA is either heavily glitching, or just has very slow rise/fall times, which in the real design might result in metastability, and signal glitching. To clean the signal, I have designed a 'debouncing' module, which I use whenever such a situation happens, and I simulate my design using ideal behaviour of the signal.

My question here is related to the simulation of such a situation. In particular - how to take any test-bench generated signal (in a driver class), and make it randomly glitching at rising and falling edges. All within a specification I give. For example, I'd like to simulate a 'clean' push-button signal, and make it randomly bounce between low and high whenever any transition happens, for anywhere between 1 and 5 milliseconds, up to 30 times.

Is there a way how to simulate such behaviour effectively in System Verilog?

2
  • I'm talking about how to generate noise in the form of spurious transitions on a single 1-bit signal. I believe this is perfectly possible to do. Commented Dec 6, 2024 at 14:15
  • Verilog simulation is done in delta-cycles. There two ways to think about glitches there: (1) while a base signal period takes many cycles, a glitch can be simulated as a much shorter deviation of a signal value, say one delta cycle. (2) there are also parasitic glitches which happens during a single delta cycle. There are ways to generate those too. Which one are you interested in? The first one is easy to control, the other is not. Commented Dec 6, 2024 at 14:28

2 Answers 2

1

I can show you how you can set up random constraints to meet your glitch specifications. If you have a classed based testbench (maybe UVM) you can extend your driver with the overridden behaviors from the example below. We would need to see how your testbench works before we could show you exactly how to do it. Hopefully this is enough information for you:

module top;
  timeunit 1ps/1ps;
  logic dut_signal;
  bit clk;
  
  initial repeat (50) #50ms clk = !clk;
  initial begin $dumpfile("dump.vcd"); $dumpvars; end
  class transaction;
    rand bit signal;
    rand int unsigned bounces;
    rand int unsigned delays[]; // in ns
    
    constraint c {
      bounces <=30;
      delays.size() == bounces*2; // each bounce needs high/low delay
      if (bounces > 0)
        delays.sum() inside {[ 1ms/1ns : 5ms/1ns ]}; // all delays must be within 1-5ms (normalized to ns)
    }
  endclass
  
  transaction tx = new;
  
  always @(posedge clk)
    begin
      assert(tx.randomize);
      $display("%p",tx);
      if (dut_signal !== tx.signal) begin // only glitch when changing the value
        dut_signal <= tx.signal;
        foreach(tx.delays[i])
          #(tx.delays[i]*1ns) dut_signal <= ! dut_signal;
      end
    end
endmodule
Sign up to request clarification or add additional context in comments.

Comments

0

thank you, for your clear answer. I managed to come with the following solution, it is a bit less elaborate than yours, but works as well:

Here is the generator class:

    class bouncer #(parameter int max_num_transactions = 30,
        // in nanoseconds:
        parameter int max_collective_time = 10000);


        rand int               num_transactions;
        // we cannot randomize time as it requires svrnm license,
        // so we do in integer. These are in nanoseconds as it is expected
        // to have triggering max in milliseconds range
        rand int               wait_times[2*max_num_transactions];
        rand int               lastwait;
        // this is somewhat of a guess, having max num transactions
        // and collective time we have to guess on maximum allowable space
        // to be able to generate proper vector:
        parameter int         maxval = integer'(max_collective_time / max_num_transactions * 1.5);


       constraint m_num_transactions {num_transactions > 6;
          num_transactions < 2*max_num_transactions;};

       // 100ns - 5us, all here in nanoseconds
       constraint waits {foreach(wait_times[i]) wait_times[i] > 100 &&
          wait_times[i] < maxval && wait_times.sum() < max_collective_time;};

       constraint lw {lastwait > 100; lastwait < 2500;};

       function void post_randomize();
           $display("Total delay: %.2f us", (wait_times.sum() * 1e-3));
           $display("Max per tick delay: ", maxval);
       endfunction // post_randomize

       // generates 'bouncing' according to randomly generated
       // spoiling of the signal by transactions
       task generate_spoiled_signal(logic final_state,
                    ref logic tospoil);
       // spoiling procedure:
       foreach (wait_times[i]) begin
           #(wait_times[i] * 1ns);
           tospoil = ~tospoil;
       end
       #(lastwait * 1ns);
       tospoil = final_state;
      endtask // generate_spoiled_signal
    endclass // bouncer

And this is how I generate the bouncing in the driver class:

    class motor_driver;
        virtual t_motor motor_x;
        bouncer B;
        ....
        task run();
           ....
           B = new;
           assert(B.randomize());
           B.generate_spoiled_signal('1, motor_x.motor_pg_i);
           #1ms;
           B.generate_spoiled_signal('0, motor_x.motor_pg_i);
        endtask
    endclass

It generated the desired bouncing: enter image description here

I have to say that I like how you tackled the dynamic array resizing and total sum. I did not know about these methods. What I have posted respects the total time as well, but until I have introduced 'maxval' to constraint a single transaction to a meaningful value it failed occasionally the randomization. Probably it could not find correct values.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.