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?
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:
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.