I've been designing digital logic in Verilog (and more recently SystemVerilog) since 1998 but I have never had much use for user-defined primitives (UDPs) as they're generally non-synthesizable. Well, as part of a testbench, I need to instantiate several UDPs, specifically, JK flip-flops with level sensitive asynchronous preset and clear.
Since it's been a while since I did anything with UDPs, I read some reference material and then coded the UDP, which I thought would be quite straightforward. Unfortunately, the UDP doesn't behave correctly in that its output is mostly undefined when it should be zero or one. I read more reference material and adjusted the UDP's table many times with no success. After just about pulling my hair out, I decided to just use the example code in the Verilog LRM. Unfortunately, even this doesn't work! Is there something wrong with the extremely simple testbench? Any insight would be appreciated. The code follows:
primitive jk_edge_ff (q, clock, j, k, preset, clear); //This is taken verbatim from the Verilog LRM
output q; reg q;
input clock, j, k, preset, clear;
table
// clock jk pc state output/next state
? ?? 01 : ? : 1 ; // preset logic
? ?? *1 : 1 : 1 ;
? ?? 10 : ? : 0 ; // clear logic
? ?? 1* : 0 : 0 ;
r 00 00 : 0 : 1 ; // normal clocking cases
r 00 11 : ? : - ;
r 01 11 : ? : 0 ;
r 10 11 : ? : 1 ;
r 11 11 : 0 : 1 ;
r 11 11 : 1 : 0 ;
f ?? ?? : ? : - ;
b *? ?? : ? : - ; // j and k transition cases
b ?* ?? : ? : - ;
endtable
endprimitive
module tb;
reg clock, j, k, preset, clear;
wire q;
jk_edge_ff jkff0(q, clock, j, k, preset, clear);
initial
begin
clock = 1;
forever #10 clock = ~clock;
end
initial
begin
$monitor("time = %t , q = %b , clock = %b , j = %b , k = %b , preset = %b , clear = %b", $time, q, clock, j, k, preset, clear);
#20; preset = 0; clear = 0; j = 0; k = 1;
#20 k = 0;
#20 preset = 1;
#20 preset = 0;
#20 clear = 1;
#20 clear = 0;
#20 j = 1;
#20 j = 0;
#20 k = 1;
#20 k = 0;
#20 j = 1;
#20 k = 1;
#200 $finish;
end
endmodule
In the second initial block, I've tested changing the phase (relative to the clock) of when the inputs to the flip-flop change by adjusting the first delay value in front of "preset = 0;" -- I've tried nothing, #5 , #10 , #15 and #20 with the same results.
Here is the output of the simulator, which in this case is Aldec Riviera Pro 2022.04:
# KERNEL: time = 0 , q = x , clock = 1 , j = x , k = x , preset = x , clear = x
# KERNEL: time = 10 , q = x , clock = 0 , j = x , k = x , preset = x , clear = x
# KERNEL: time = 20 , q = x , clock = 1 , j = 0 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 30 , q = x , clock = 0 , j = 0 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 40 , q = x , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 50 , q = x , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 60 , q = 0 , clock = 1 , j = 0 , k = 0 , preset = 1 , clear = 0
# KERNEL: time = 70 , q = 0 , clock = 0 , j = 0 , k = 0 , preset = 1 , clear = 0
# KERNEL: time = 80 , q = x , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 90 , q = x , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 100 , q = 1 , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 1
# KERNEL: time = 110 , q = 1 , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 1
# KERNEL: time = 120 , q = x , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 130 , q = x , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 140 , q = x , clock = 1 , j = 1 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 150 , q = x , clock = 0 , j = 1 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 160 , q = x , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 170 , q = x , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 180 , q = x , clock = 1 , j = 0 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 190 , q = x , clock = 0 , j = 0 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 200 , q = x , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 210 , q = x , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 220 , q = x , clock = 1 , j = 1 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 230 , q = x , clock = 0 , j = 1 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 240 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 250 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 260 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 270 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 280 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 290 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 300 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 310 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 320 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 330 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 340 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 350 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 360 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 370 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 380 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 390 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 400 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 410 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 420 , q = x , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 430 , q = x , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
Strangely, in the above I notice that preset and clear seem to have their behavior reversed.
The expected output would be:
# KERNEL: time = 0 , q = x , clock = 1 , j = x , k = x , preset = x , clear = x
# KERNEL: time = 10 , q = x , clock = 0 , j = x , k = x , preset = x , clear = x
# KERNEL: time = 20 , q = 0 , clock = 1 , j = 0 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 30 , q = 0 , clock = 0 , j = 0 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 40 , q = 0 , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 50 , q = 0 , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 60 , q = 1 , clock = 1 , j = 0 , k = 0 , preset = 1 , clear = 0
# KERNEL: time = 70 , q = 1 , clock = 0 , j = 0 , k = 0 , preset = 1 , clear = 0
# KERNEL: time = 80 , q = 1 , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 90 , q = 1 , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 100 , q = 0 , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 1
# KERNEL: time = 110 , q = 0 , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 1
# KERNEL: time = 120 , q = 0 , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 130 , q = 0 , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 140 , q = 1 , clock = 1 , j = 1 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 150 , q = 1 , clock = 0 , j = 1 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 160 , q = 1 , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 170 , q = 1 , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 180 , q = 0 , clock = 1 , j = 0 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 190 , q = 0 , clock = 0 , j = 0 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 200 , q = 0 , clock = 1 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 210 , q = 0 , clock = 0 , j = 0 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 220 , q = 1 , clock = 1 , j = 1 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 230 , q = 1 , clock = 0 , j = 1 , k = 0 , preset = 0 , clear = 0
# KERNEL: time = 240 , q = 0 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 250 , q = 0 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 260 , q = 1 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 270 , q = 1 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 280 , q = 0 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 290 , q = 0 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 300 , q = 1 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 310 , q = 1 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 320 , q = 0 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 330 , q = 0 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 340 , q = 1 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 350 , q = 1 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 360 , q = 0 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 370 , q = 0 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 380 , q = 1 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 390 , q = 1 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 400 , q = 0 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 410 , q = 0 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 420 , q = 1 , clock = 1 , j = 1 , k = 1 , preset = 0 , clear = 0
# KERNEL: time = 430 , q = 1 , clock = 0 , j = 1 , k = 1 , preset = 0 , clear = 0