`default_nettype none
typedef enum { M_proc, M_iter, M_tree, M_iter_sol, M_tree_sol } M_Type;
typedef enum
{ Char_0 = 48, Char_9 = 57,
Char_A = 65, Char_Z = 90, Char_a = 97, Char_z = 122 }
Chars_Special;
function int atoi1_func( input logic [7:0] char, input int r );
automatic int char_uc =
char >= Char_a && char <= Char_z ? char - Char_a + Char_A : char;
automatic int val_09 = char - Char_0;
automatic int val_az = 10 + char_uc - Char_A;
automatic bit is_09 = char>=Char_0 && char <= Char_9 && char < Char_0 + r;
automatic bit is_az = char_uc >= Char_A && char_uc < Char_A + r - 10;
atoi1_func = is_09 ? val_09 : is_az ? val_az : -1;
endfunction
module atoi1
#( int r = 32, w = 10 )
( output logic [w-1:0] val,
output logic is_digit,
input uwire [7:0] char );
always_comb begin
automatic int valr = atoi1_func(char,r);
is_digit = valr >= 0;
val = is_digit ? valr : 0;
end
endmodule
module mux2
#( int w = 3 )
( output uwire [w-1:0] x,
input uwire s,
input uwire [w-1:0] a0, a1 );
assign x = s ? a1 : a0;
endmodule
module mult_by_c
#( int w_in = 8, int c = 16, int w_out = w_in+$clog2(c) )
( output uwire [w_out-1:0] prod, input uwire [w_in-1:0] a );
assign prod = a * c;
endmodule
module add
#( int w = 5 )
( output uwire [w-1:0] s, input uwire [w-1:0] a, b );
assign s = a + b;
endmodule
module atoi_it
#( int r = 11, n = 5, wv = $clog2( r**n ), wd = $clog2(n+1) )
( output logic [wv-1:0] val,
output logic [wd-1:0] nd,
input uwire [7:0] str [n-1:0] );
uwire [wv-1:0] vali[n-1:-1];
uwire is_valid[n-1:-1];
uwire [wd-1:0] ndi[n-1:-1];
assign is_valid[-1] = 1;
assign ndi[-1] = 0;
assign vali[-1] = 0;
assign nd = ndi[n-1];
assign val = vali[n-1];
localparam int wcv = $clog2(r);
for ( genvar i=0; i<n; i++ ) begin
uwire [wcv-1:0] valdr;
uwire is_digit;
atoi1 #(r,wcv) a( valdr, is_digit, str[i] );
assign is_valid[i] = is_digit && is_valid[i-1];
uwire [wcv-1:0] vald = is_valid[i] ? valdr : 0;
uwire [wv-1:0] vals;
mult_by_c #( .w_in(wcv), .c(r**i), .w_out(wv) ) mc( vals, vald );
add #(wv) a1( vali[i], vali[i-1], vals );
assign ndi[i] = is_valid[i] ? i+1 : ndi[i-1];
end
endmodule
module atoi_pr
#( int r = 11, n = 5, wv = $clog2( r**n ), wd = $clog2(n+1) )
( output logic [wv-1:0] val,
output logic [wd-1:0] nd,
input uwire [7:0] str [n-1:0] );
always_comb begin
val = 0; nd = 0;
for ( int i=0; i<n; i++ ) begin
automatic int dval = atoi1_func(str[i],r);
if ( dval < 0 ) break;
val += dval * r**i;
nd++;
end
end
endmodule
module atoi_tr
#( int r = 11, n = 5, wv = $clog2( r**n ), wd = $clog2(n+1) )
( output uwire [wv-1:0] val,
output var logic [wd-1:0] nd,
input uwire [7:0] str [n-1:0] );
if ( n == 1 ) begin
uwire is_dd;
uwire [wv-1:0] valr;
atoi1 #(r,wv) a( valr, is_dd, str[0] );
assign val = is_dd ? valr : 0;
assign nd = is_dd;
end else begin
localparam int nlo = n/2;
localparam int nhi = n - nlo;
localparam int vwh = $clog2( r**nhi );
localparam int dwh = $clog2( nhi+1 );
uwire [vwh-1:0] vallo, valhi;
uwire [dwh-1:0] ndlo, ndhi;
atoi_tr #(r,nlo,vwh,dwh) alo( vallo, ndlo, str[nlo-1:0] );
atoi_tr #(r,nhi,vwh,dwh) ahi( valhi, ndhi, str[n-1:nlo] );
uwire hitoo = ndlo == nlo;
uwire [vwh-1:0] valhid = hitoo ? valhi : 0;
uwire [wv-1:0] valhis; mult_by_c #(vwh,r**nlo,wv) mc( valhis, valhid );
assign val = vallo + valhis;
assign nd = hitoo ? nlo + ndhi : ndlo;
end
endmodule
cadence
module testbench;
localparam int nnsets = 7;
localparam int nset[nnsets] = '{ 1, 2, 3, 4, 7, 8, 9 };
localparam int npsets = 2;
localparam int pset[npsets] = '{ 10, 16 };
localparam int nmsets = 2;
localparam M_Type mset[nmsets] = '{ M_tree, M_iter };
string mtype_str[M_Type] =
'{ M_proc:"atoi_pr", M_tree:"atoi_tr", M_iter:"atoi_it",
M_tree_sol:"a_tr_sol", M_iter_sol:"a_it_sol" };
int t_errs_len_mod[M_Type];
int t_errs_val_mod[M_Type];
int t_errs_len_r[int];
int t_errs_val_r[int];
int t_errs_len_n[int];
int t_errs_val_n[int];
int t_errs; initial t_errs = 0;
final begin
for ( int i=0; i<npsets; i++ )
$write("Total errors for radix %2d: %5d len, %5d val\n",
pset[i], t_errs_len_r[pset[i]],
t_errs_val_r[pset[i]]);
for ( int i=0; i<nnsets; i++ )
$write("Total errors for string length %2d: %5d len, %5d val\n",
nset[i], t_errs_len_n[nset[i]],
t_errs_val_n[nset[i]]);
for ( int i=0; i<nmsets; i++ )
$write("Total errors for mod %4s: %5d len, %5d val\n",
mtype_str[mset[i]], t_errs_len_mod[mset[i]],
t_errs_val_mod[mset[i]]);
$write("Total number of errors: %0d\n",t_errs);
end
localparam int nsets = nnsets * npsets * nmsets;
uwire d[nsets:-1]; assign d[-1] = 1;
for ( genvar m=0; m<nmsets; m++ )
for ( genvar n=0; n<nnsets; n++ )
for ( genvar i=0; i<npsets; i++ )
begin
localparam int idx = m * npsets * nnsets + n * npsets + i;
testbench_r #(pset[i],nset[n],mset[m])
t2( .done(d[idx]), .tstart(d[idx-1]) );
end
endmodule
module testbench_r
#( int r = 16, n = 3,
M_Type mtype = M_proc )
( output logic done, input uwire tstart );
localparam int w = $clog2(r**n);
localparam int ntests = 500;
localparam int wd = $clog2(n+1);
uwire [wd-1:0] nd;
uwire [w-1:0] val;
logic [7:0] str[n-1:0];
string mtype_str[M_Type] =
'{ M_proc:"atoi_pr", M_tree:"atoi_tr", M_iter:"atoi_it",
M_tree_sol:"a_tr_sol", M_iter_sol:"a_it_sol" };
case ( mtype )
M_proc: atoi_pr #(r,n,w) a8( val, nd, str );
M_tree: atoi_tr #(r,n,w) a8( val, nd, str );
M_iter: atoi_it #(r,n,w) a8( val, nd, str );
M_tree_sol: atoi_tr_sol #(r,n,w) a8( val, nd, str );
M_iter_sol: atoi_it_sol #(r,n,w) a8( val, nd, str );
endcase
logic [7:0] non_digit[256];
function string to_string(input logic [w-1:0] val);
automatic string result = "";
if ( val == 0 ) result = "0";
while ( val ) begin
automatic int d = val % r;
automatic int v = d < 10 ? d + Char_0 : d - 10 + Char_A;
val = val / r;
result = { string'(v), result };
end
to_string = result;
endfunction
initial begin
automatic int nd_size = 0;
automatic int rm10 = r > 10 ? 10 : r;
automatic bit err_silent = testbench.t_errs > 10;
for ( int i=32; i<128; i++ ) begin
if ( i >= Char_0 && i < Char_0 + rm10 ) continue;
if ( i >= Char_A && i < Char_A + r - 10 ) continue;
if ( i >= Char_a && i < Char_a + r - 10 ) continue;
non_digit[nd_size++] = i;
end
wait( tstart );
for ( int tt=0; tt<3; tt++ ) begin
automatic bit single_char = tt == 0;
automatic bit space_pad = single_char || tt == 1;
automatic int nttests = single_char ? r : ntests;
automatic int n_err = 0, n_lerr = 0;
automatic string ttype =
single_char ? "Single_Char (SC)"
: space_pad ? "Space_Pad (SP)" : "General (GE)";
automatic string abbrev =
single_char ? "SC" : space_pad ? "SP" : "GE";
for ( int i=0; i<nttests; i++ ) begin
automatic int len = single_char ? 1 : 1 + {$random} % n;
automatic logic [w-1:0] sval = 0;
for ( int j=0; j<len; j++ ) begin
automatic int d = {$random} % r;
automatic int char_a = {$random} % 1 ? Char_A : Char_a;
if ( d == 0 && j == len - 1 ) d = 1;
if ( single_char ) d = i;
str[j] = d < 10 ? Char_0 + d : char_a + d - 10;
sval += d * r ** j;
end
str[len] = space_pad ? " " : non_digit[{$random}%nd_size];
for ( int j=len+1; j<n; j++ )
str[j] = space_pad ? 32 : 32 + {$random}%(128-32);
#1;
if ( sval !== val ) begin
n_err++;
if ( !err_silent && n_err < 5 )
$write("Mod-%s R-%2d n-%2d Ty-%s Error val %s != %s (correct) for string \"%s\"\n",
mtype_str[mtype], r, n, abbrev, to_string(val), to_string(sval), string'(str));
end
if ( !single_char && len !== nd ) begin
n_lerr++;
if ( !err_silent && n_lerr < 10 )
$write("Mod-%s R-%2d n-%2d Ty-%s Error len %0d != %0d (correct) for string \"%s\"\n",
mtype_str[mtype],
r, n, abbrev, nd, len, string'(str) );
end
#1;
end
$write("Mod-%s Radix-%2d n-%2d Ty-%s, done with %0d tests, %0d val errors, %0d len errors.\n",
mtype_str[mtype],
r, n, abbrev, nttests, n_err, n_lerr);
testbench.t_errs += n_err + n_lerr;
testbench.t_errs_len_mod[mtype] += n_lerr;
testbench.t_errs_val_mod[mtype] += n_err;
testbench.t_errs_len_r[r] += n_lerr;
testbench.t_errs_val_r[r] += n_err;
testbench.t_errs_len_n[n] += n_lerr;
testbench.t_errs_val_n[n] += n_err;
if ( n_err + n_lerr ) err_silent = 1;
end
done = 1;
end
endmodule
cadence