typedef enum
{ Char_escape = 128, Char_escape_stop = 200, Char_EOS = 255,
Char_A = 65, Char_Z = 90, Char_a = 97, Char_z = 122,
Char_0 = 48, Char_9 = 57,
Char_space = 32, Char_underscore = 95, Char_cr = 13
} Chars_Special;
`default_nettype none
module word_count
#( int wl = 5, wn = 6, n_avg_of = 10 )
( output logic word_start, word_part, word_ended,
output logic [wl-1:0] len_word,
output logic [wn-1:0] num_words,
output logic [wl-1:0] len_avg,
input uwire [7:0] char,
input uwire reset, clk );
uwire char_az = char >= Char_a && char <= Char_z
|| char >= Char_A && char <= Char_Z;
uwire char_09 = char >= Char_0 && char <= Char_9;
uwire char_wd_start = char_az;
uwire char_wd_part = char_wd_start || char_09 || char == Char_underscore;
logic prev_char_wd_part;
uwire next_word_start = char_wd_start && !prev_char_wd_part;
uwire next_word_part = word_part && char_wd_part || next_word_start;
uwire next_word_ended = word_part && !char_wd_part;
always_ff @( posedge clk ) begin
prev_char_wd_part <= reset ? 0 : char_wd_part;
word_start <= reset ? 0 : next_word_start;
word_part <= reset ? 0 : next_word_part;
word_ended <= reset ? 0 : next_word_ended;
end
logic [wl-1:0] len_recent[n_avg_of];
logic [wl+$clog2(n_avg_of):0] len_sum;
assign len_avg = len_recent[n_avg_of-1] ? len_sum / n_avg_of : 0;
always_ff @ ( posedge clk ) if ( reset ) begin
num_words <= 0;
len_word <= 0;
for ( int i=0; i<n_avg_of; i++ ) len_recent[i] = 0;
len_sum = 0;
end else begin
len_word <= next_word_start ? 1 : next_word_part ? len_word+1 : len_word;
num_words <= next_word_ended ? num_words + 1 : num_words;
if ( next_word_ended ) begin
len_sum -= len_recent[n_avg_of-1];
len_sum += len_word;
for ( int i=n_avg_of-1; i>0; i-- ) len_recent[i] = len_recent[i-1];
len_recent[0] = len_word;
end
end
endmodule
module word_count_blank
#( int wl = 5, wn = 6, n_avg_of = 10 )
( output logic word_start, word_part, word_ended,
output logic [wl-1:0] len_word,
output logic [wn-1:0] num_words,
output logic [wl-1:0] len_avg,
input uwire [7:0] char,
input uwire reset, clk );
uwire char_az = char >= Char_a && char <= Char_z
|| char >= Char_A && char <= Char_Z;
uwire char_09 = char >= Char_0 && char <= Char_9;
uwire char_wd_start = char_az;
uwire char_wd_part = char_wd_start || char_09 || char == Char_underscore;
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
module testbench;
localparam int npsets = 3;
localparam int pset[npsets][2] =
'{ { 2, 5 }, { 1, 6}, {9, 7 } };
int n_err_shown; int n_err_sh_nc, n_err_sh_nw, n_err_sh_avg, n_err_sh_state;
initial begin
n_err_sh_nc = 0;
n_err_sh_nw = 0;
n_err_sh_avg = 0;
n_err_sh_state = 0;
end
int t_errs; initial begin t_errs = 0; n_err_shown = 0; end
final $write("Total number of errors: %0d\n",t_errs);
uwire d[npsets:-1]; assign d[-1] = 1;
for ( genvar i=0; i<npsets; i++ )
testbench_n #(pset[i][0],pset[i][1]) t2( .done(d[i]), .tstart(d[i-1]) );
endmodule
module testbench_n
#( int win_sz = 10, wd_len_max = 5 )
( output logic done, input uwire tstart );
localparam int wl = $clog2(wd_len_max+1);
localparam int wn = $clog2(win_sz) + 5;
localparam int n_tests = 10000;
localparam int cyc_max = n_tests * 2;
localparam int tr_initial_lines = 12;
localparam int tr_err_context = 5;
int seed;
initial seed = 4755;
function string sample( input string str );
sample = str[ $dist_uniform( seed, 0, str.len()-1 ) ];
endfunction
function string fbit( input logic b, input string s );
fbit = b === 1 ? s : b === 0 ? "_" : b === 1'bx ? "x" : "z";
endfunction
bit clk;
int cycle, cycle_limit;
logic clk_reactive;
int cycle_reactive;
reactivate ra(clk_reactive,cycle_reactive,clk,cycle);
string event_trace;
initial begin
clk = 0;
cycle = 0;
event_trace = "";
done = 0;
cycle_limit = cyc_max;
wait( tstart );
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
uwire [wl-1:0] len, lavg;
uwire [wn-1:0] nw;
uwire w_start, w_part, w_ended;
logic [7:0] char;
logic reset;
string test_one = "I II III 2not o_wd four cinco a b c d ";
word_count #(wl,wn,win_sz) wd_cnt
(w_start, w_part, w_ended, len, nw, lavg, char,reset,clk);
bit char_wd_start[256];
bit char_wd_part[256];
string str_wd_start, str_wd_part, str_wd_notstart;
localparam string str_wd_not = " ,!.-";
int lens[$];
initial begin
automatic logic [wl-1:0] shadow_nc = 0;
automatic logic [wn-1:0] shadow_nw = 0;
automatic logic [wl-1:0] shadow_avg = 0;
automatic int len_sum = 0;
automatic int n_err_nc = 0, n_err_w_st=0, n_err_w_pa=0, n_err_w_en=0;
automatic logic shadow_w_st, shadow_w_pa, shadow_w_en;
automatic int n_err = 0, n_err_lavg = 0, n_err_nw = 0;
automatic int str_idx = 0;
automatic string str_win = {10{" "}};
automatic string test_str_buffer;
automatic int n_err_pre;
automatic logic pw_start, pw_part, pw_ended; automatic string tr_recent[$];
automatic bit need_reset = 0;
bit in_word, was_in_word, was_word_char;
for ( int i=0; i<256; i++ )
begin char_wd_start[i] = 0; char_wd_part[i] = 0; end
for ( int i=Char_a; i<=Char_z; i++ )
begin
char_wd_start[i] = 1; char_wd_part[i] = 1;
end
for ( int i=Char_A; i<=Char_Z; i++ )
begin
char_wd_start[i] = 1; char_wd_part[i] = 1;
end
for ( int i=Char_0; i<=Char_9; i++ ) char_wd_part[i] = 1;
char_wd_part[Char_underscore] = 1;
for ( int i=0; i<256; i++ ) begin
if ( !char_wd_start[i] && char_wd_part[i] )
str_wd_notstart = { str_wd_notstart, string'(byte'(i)) };
if ( char_wd_start[i] )
str_wd_start = { str_wd_start, string'(byte'(i)) };
if ( char_wd_part[i] )
str_wd_part = { str_wd_part, string'(byte'(i)) };
end
test_str_buffer = { test_one, test_one };
str_idx = 0;
in_word = 0;
was_in_word = 0;
was_word_char = 0;
char = Char_A;
reset = 1;
@( posedge clk_reactive ); @( posedge clk_reactive );
reset = 0;
for ( int i=0; i<n_tests; i++ ) begin
automatic int round = i / test_one.len();
automatic bit do_reset =
round == 1 && $dist_uniform(seed,1,7) == 1
|| round > 1 && $dist_uniform(seed,1,(wd_len_max+4)/2*win_sz*2)==1;
automatic bit show_err = 0;
@( negedge clk );
if ( str_idx >= test_str_buffer.len() ) begin
automatic int wd_sz = $dist_uniform(seed,1,wd_len_max);
automatic int wd_ws = $dist_uniform(seed,1,4);
automatic bit fake_word = $dist_uniform(seed,1,10) == 1;
test_str_buffer = "";
str_idx = 0;
if ( fake_word )
test_str_buffer = { test_str_buffer, sample( str_wd_notstart ) };
else
test_str_buffer = { test_str_buffer, sample( str_wd_start ) };
for ( int j=1; j<wd_sz; j++ )
test_str_buffer = { test_str_buffer, sample( str_wd_part ) };
for ( int j=0; j<wd_ws; j++ )
test_str_buffer = { test_str_buffer, sample( str_wd_not ) };
end
reset = do_reset;
char = test_str_buffer[str_idx++];
if ( round < 1 ) begin
end else begin
end
str_win = { str_win.substr(1,9), char };
pw_start = w_start;
pw_part = w_part;
pw_ended = w_ended;
@( posedge clk_reactive );
if ( do_reset ) begin
was_in_word = 0;
was_word_char = 0;
in_word = 0;
shadow_w_en = 0;
shadow_w_pa = 0;
shadow_w_st = 0;
end else begin
was_in_word = in_word;
shadow_w_st = !was_word_char && char_wd_start[char];
in_word =
was_in_word && char_wd_part[char] || shadow_w_st;
shadow_w_pa = in_word;
shadow_w_en = was_in_word && !in_word;
was_word_char = char_wd_part[char];
end
if ( do_reset ) begin
shadow_nc = 0;
shadow_nw = 0;
shadow_avg = 0;
lens.delete();
len_sum = 0;
end else if ( was_in_word && in_word ) begin
shadow_nc++;
end else if ( shadow_w_en ) begin
shadow_nw++;
len_sum += shadow_nc;
lens.push_front(shadow_nc);
if ( lens.size() > win_sz )
len_sum -= lens.pop_back();
if ( lens.size() == win_sz )
shadow_avg = len_sum / win_sz;
end else if ( shadow_w_st ) begin
shadow_nc = 1;
end
n_err_pre = n_err;
if ( w_start !== shadow_w_st ) begin
n_err_w_st++;
n_err++;
end
if ( w_part !== shadow_w_pa ) begin
n_err_w_pa++;
n_err++;
end
if ( w_ended !== shadow_w_en ) begin
n_err_w_en++;
n_err++;
end
if ( n_err_pre != n_err ) begin
if ( testbench.n_err_sh_state++ < 4 ) show_err = 1;
end
if ( shadow_nw !== nw )
begin
n_err_nw++; n_err++; need_reset = 1;
if ( testbench.n_err_sh_nw++ < 4 ) show_err = 1;
end
if ( shadow_avg !== lavg )
begin
n_err_lavg++; n_err++; need_reset = 1;
if ( testbench.n_err_sh_avg++ < 4 ) show_err = 1;
end
if ( shadow_nc !== len ) begin
n_err_nc++; n_err++;
if ( testbench.n_err_sh_nc++ < 4 ) show_err = 1;
end
begin
automatic string hd =
" W-M I Text---->| SPE L N A {D}";
automatic string item =
$sformatf
("Trace %2d-%1d %4d \"%10s\" %s %s%s%s %s%s%s %1d %2d %1d {%1d}",
win_sz, wd_len_max, i, str_win,
do_reset ? "R" : " ",
fbit(pw_start,"s"), fbit(pw_part,"p"), fbit(pw_ended,"e"),
fbit(w_start,"S"), fbit(w_part,"P"), fbit(w_ended,"E"),
len, nw, lavg,
wd_cnt.char_az
);
if ( n_err != n_err_pre )
item =
{ item,
$sformatf(" <-Error Correct-> %s%s%s %1d %2d %1d",
shadow_w_st ? "S" : "_", shadow_w_pa ? "P" : "_",
shadow_w_en ? "E" : "_",
shadow_nc, shadow_nw, shadow_avg) };
if ( i == 0 ) $write("%s\n",hd);
if ( i < tr_initial_lines )
$write("%s\n",item);
else begin
if ( tr_recent.size() > tr_err_context ) tr_recent.delete(0);
tr_recent.push_back(item);
end
end
if ( n_err != n_err_pre && show_err ) begin
while ( tr_recent.size() > 0 )
$write("%s\n",tr_recent.pop_front());
end
end
$write
("Done with n_avg_of=%0d, max wd len=%0d. Errors: st %0d, pa %0d, en %0d, nc %0d, nw %0d, av %0d\n",
win_sz, wd_len_max,
n_err_w_st, n_err_w_pa, n_err_w_en,
n_err_nc, n_err_nw, n_err_lavg);
testbench.t_errs += n_err;
done = 1;
end
endmodule
cadence