458
`default_nettype none
typedef enum logic [1:0]
{ tr_both = 3, tr_incr = 2, tr_decr = 1, tr_equal = 0 } Trend;
module ist_compare
#( int w = 15 )
( output uwire [1:0] gl, input uwire [w-1:0] a, b );
assign gl = { a < b, a > b };
endmodule
module trend2
#( int wd = 20, wi = 10 )
( output logic [1:0] prev_trend,
output logic [wi-1:0] prev_length,
output logic [1:0] curr_trend, last_2_trend,
output logic [wi-1:0] curr_idx_start,
input uwire [wd-1:0] samp,
input uwire reset, clk );
uwire [wi-1:0] debug_val;
endmodule
cadence
program reactivate
(output uwire clk_reactive, output int cycle_reactive,
input uwire clk, input var int cycle);
assign clk_reactive = clk;
assign cycle_reactive = cycle;
endprogram
string trend_str[int] =
'{ tr_both: "Bth", tr_incr: "Inc", tr_decr: "Dec", tr_equal: "Eql" };
function string trend_str_get( logic [1:0] trend );
trend_str_get = $isunknown(trend) ? "Unk" : trend_str[trend];
endfunction
function logic[1:0] func_compare( int unsigned a, b );
func_compare = { a < b, a > b };
endfunction
function string eob( bit is_error, string err_msg, string debug_msg );
localparam bit debug = 0;
eob = is_error ? err_msg : ( debug ? debug_msg : " " );
endfunction
function int min( int a, int b );
min = a <= b ? a : b;
endfunction
module testbench;
localparam int trace_lines_n_wanted = 10;
localparam int n_errors_show = 20;
logic done;
localparam int wd = 10;
localparam int wi = 12;
localparam int max_idx = ( 1 << wi ) - 1;
localparam int limit_val = ( 1 << wd ) - 1;
localparam int n_tests = 20000;
localparam int cyc_max = n_tests + 100;
int seed;
initial seed = 475501;
function automatic bit rand_bern( int period );
rand_bern = $dist_uniform(seed,1,period) == 1;
endfunction
function automatic int rand_n( int n );
rand_n = $dist_uniform(seed,0,n-1);
endfunction
bit clk;
int cycle, cycle_limit;
logic clk_reactive;
int cycle_reactive;
reactivate ra(clk_reactive,cycle_reactive,clk,cycle);
string event_trace;
string ev_trace[$];
initial begin
clk = 0;
cycle = 0;
event_trace = "";
done = 0;
cycle_limit = cyc_max;
fork
while ( !done ) #1 cycle += clk++;
wait( cycle >= cycle_limit )
$write("Exit from clock loop at cycle %0d, limit %0d. %s\n %s\n",
cycle, cycle_limit, "** CYCLE LIMIT EXCEEDED **",
event_trace);
join_any;
done = 1;
end
logic [wd-1:0] din;
logic reset;
uwire [wi-1:0] curr_idx_start, prev_length;
uwire [1:0] curr_trend, prev_trend, last_2_trend;
trend2 #(wd,wi) mut_trend2
( prev_trend, prev_length, curr_trend, last_2_trend,
curr_idx_start, din, reset, clk );
initial begin
automatic int n_err_trend = 0, n_err_last_2_trend = 0;
automatic int n_err_idx_start = 0, n_err_prev_length = 0;
automatic int n_err_prev_trend = 0;
automatic int n_resets = 0, n_changes = 0;
automatic int heading_shown_cyc = -1000;
automatic Trend shadow_curr_trend = tr_equal;
string tr_entry, err_text, heading;
int shadow_idx, idx_last_change;
int shadow_prev_length, shadow_idx_start;
Trend shadow_prev_trend;
reset = 1;
din = 0;
@( negedge clk );
@( negedge clk );
for ( int i=0; i<n_tests; i++ ) begin
automatic logic [wd-1:0] din_prev = din;
automatic Trend shadow_last_2_trend;
bit err_idx_start, err_prev_length, err_prev_trend;
bit err_trend, err_last_2_trend, show_errs, have_errs;
if ( i == 0 || shadow_idx >= max_idx || rand_bern( n_tests/5 ) ) begin
reset = 1;
n_resets++;
din = rand_n( 1 << wd );
din_prev = din;
shadow_prev_trend = tr_equal;
shadow_prev_length = 0;
shadow_curr_trend = tr_equal;
shadow_idx = 0;
shadow_idx_start = shadow_idx;
idx_last_change = 0;
end else begin
shadow_idx++;
end
if ( reset ) begin ; end else if ( !shadow_curr_trend ) begin
automatic int dir = rand_bern( 2 );
automatic int abs_delta = 1 + $abs($dist_normal(seed,4,10));
automatic int delta = dir ? abs_delta : -abs_delta;
din += delta;
if ( din > din_prev ) shadow_curr_trend = tr_incr;
if ( din < din_prev ) shadow_curr_trend = tr_decr;
shadow_idx_start = idx_last_change;
end else if ( rand_bern( 3 ) ) begin
automatic int abs_delta = 1 + $abs($dist_normal(seed,4,10));
n_changes++;
if ( shadow_prev_trend === shadow_curr_trend )
$fatal(1, "Benchmark Error: should have switched trends %h %h.",
shadow_prev_trend, shadow_curr_trend);
shadow_prev_trend = shadow_curr_trend;
shadow_prev_length = idx_last_change - shadow_idx_start;
shadow_idx_start = idx_last_change;
if ( shadow_curr_trend == tr_incr ) begin
din = din - min(din, abs_delta);
shadow_curr_trend = tr_decr;
end else begin
din = min(din + abs_delta,(1<<wd)-1);
shadow_curr_trend = tr_incr;
end
end else if ( rand_bern( 3 ) == 0 ) begin
automatic int delta = 1 + $abs($dist_normal(seed,4,10));
automatic int d_try =
shadow_curr_trend == tr_incr ? din + delta : din - delta;
din = d_try < 0 ? 0 : d_try > limit_val ? limit_val : d_try;
end else begin
end
if ( din != din_prev ) idx_last_change = shadow_idx;
shadow_last_2_trend =
din > din_prev ? tr_incr : din < din_prev ? tr_decr : tr_equal;
@( negedge clk );
err_prev_trend = shadow_prev_trend !== prev_trend;
err_prev_length = shadow_prev_length !== prev_length;
err_trend = shadow_curr_trend !== curr_trend;
err_last_2_trend = shadow_last_2_trend !== last_2_trend;
err_idx_start = shadow_idx_start !== curr_idx_start;
heading = $sformatf
(" %5s c %4s %4s TrLst2 TrCurr %5s TrPrev %4s %12s %5s",
"Cyc", "Idx","Samp", "IdxSt", "LenP", " ", "Debug");
tr_entry =
$sformatf
({"Tr %5d %s %4d %4d %2b-%3s ",
"%2b-%3s %5d %2b-%3s %4d <- Correct %5d "},
cycle, reset ? "R" : " ",
shadow_idx,
din,
shadow_last_2_trend,
trend_str[shadow_last_2_trend],
shadow_curr_trend,
trend_str[shadow_curr_trend],
shadow_idx_start,
shadow_prev_trend,
trend_str[shadow_prev_trend],
shadow_prev_length,
mut_trend2.debug_val
);
err_text =
$sformatf("Er %5s %13s %6s %6s %5s %6s %4s <- Mod Errors",
" ", " ",
eob( err_last_2_trend,
$sformatf("%2b-%s",last_2_trend,
trend_str_get(last_2_trend)), "2t2t2t" ),
eob( err_trend,
$sformatf("%2b-%s",curr_trend,
trend_str_get(curr_trend)), "ctctct"),
eob( err_idx_start,
$sformatf("%0d",curr_idx_start), "ist" ),
eob( err_prev_trend,
$sformatf("%2b-%s",prev_trend,
trend_str_get(prev_trend)), "------"),
eob( err_prev_length,
$sformatf("%0d",prev_length), "len" )
);
ev_trace.push_back(tr_entry);
while ( ev_trace.size() > 10 ) tr_entry = ev_trace.pop_front();
show_errs = 0;
if ( err_prev_trend && n_err_prev_trend++ < n_errors_show )
show_errs = 1;
if ( err_prev_length && n_err_prev_length++ < n_errors_show )
show_errs = 1;
if ( err_idx_start && n_err_idx_start++ < n_errors_show )
show_errs = 1;
if ( err_trend && n_err_trend++ < n_errors_show ) show_errs = 1;
if ( err_last_2_trend && n_err_last_2_trend++ < n_errors_show )
show_errs = 1;
have_errs = err_prev_trend || err_prev_length ||
err_idx_start || err_trend || err_last_2_trend;
if ( show_errs || cycle < trace_lines_n_wanted ) begin
automatic bit show_heading = cycle - heading_shown_cyc > 12;
if ( show_heading ) begin
$write("\n%s\n",heading);
heading_shown_cyc = cycle;
end
while ( ev_trace.size() ) $write("%s\n",ev_trace.pop_front());
if ( have_errs )
$write("%s\n",err_text);
end
reset = 0;
end
$write("\nErrors last-2-trend: %0d\n", n_err_last_2_trend);
$write("Errors current trend, idx start: %0d, %0d\n",
n_err_trend, n_err_idx_start);
$write("Errors previ trend, length: %0d, %0d\n",
n_err_prev_trend, n_err_prev_length);
$write("%s",
$sformatf({ "Done. Summary: %0d resets, %0d changes, errs: ",
"(pt,pl,ct,is,lt) %0d,%0d,%0d,%0d,%0d\n"},
n_resets, n_changes,
n_err_prev_trend, n_err_prev_length,
n_err_trend, n_err_idx_start,
n_err_last_2_trend));
done = 1;
end
endmodule
cadence