`default_nettype none
module shift_fixed
#( int wid_lg = 4,
int amt = 1,
int wid = 1 << wid_lg )
( output uwire [wid-1:0] shifted,
input uwire [wid-1:0] unshifted,
input uwire shift );
assign shifted = shift ? unshifted << amt : unshifted;
endmodule
module shift_lt_behav
#( int wid_lg = 4,
int wid = 1 << wid_lg )
( output uwire [wid-1:0] shifted,
input uwire [wid-1:0] unshifted,
input uwire [wid_lg-1:0] amt );
assign shifted = unshifted << amt;
endmodule
module shift_lt_comb
#( int wid_lg = 4,
int wid = 1 << wid_lg )
( output uwire [wid-1:0] shifted,
input uwire [wid-1:0] unshifted,
input uwire [wid_lg-1:0] amt );
uwire [wid-1:0] step[wid_lg-1:-1];
assign step[-1] = unshifted;
assign shifted = step[wid_lg-1];
for ( genvar i=0; i<wid_lg; i++ )
shift_fixed #(wid_lg,1<<i) sf( step[i], step[i-1], amt[i] );
endmodule
module shift_lt_seq
#( int wid_lg = 4,
int wid = 1 << wid_lg )
( output logic [wid-1:0] shifted,
output uwire ready,
input uwire [wid-1:0] unshifted,
input uwire [wid_lg-1:0] amt,
input uwire start,
input uwire clk );
logic [wid_lg-1:0] cnt;
uwire [wid-1:0] sf_out;
shift_fixed #(wid_lg,1) sf( sf_out, shifted, 1'b1 );
always_ff @( posedge clk ) begin
if ( start == 1 ) begin
shifted = unshifted;
cnt = amt;
end else if ( cnt > 0 ) begin
shifted = sf_out;
cnt--;
end
end
assign ready = cnt == 0;
endmodule
module shift_lt_seq_d
#( int wid_lg = 4,
int num_shifters = 2,
int wid = 1 << wid_lg )
( output logic [wid-1:0] shifted,
output uwire ready,
input uwire [wid-1:0] unshifted,
input uwire [wid_lg-1:0] amt,
input uwire start,
input uwire clk );
localparam int cnt_bits = ( wid_lg + num_shifters - 1 ) / num_shifters;
logic [num_shifters-1:0][cnt_bits-1:0] cnt;
uwire [wid-1:0] inter_sh[num_shifters-1:-1];
assign inter_sh[-1] = shifted;
for ( genvar i = 0; i < num_shifters; i++ ) begin
localparam int shift_amt = 1 << i * cnt_bits;
uwire shift = cnt[i] != 0;
shift_fixed #(wid_lg,shift_amt) sf( inter_sh[i], inter_sh[i-1], shift );
end
always_ff @( posedge clk )
if ( start == 1 ) begin
shifted = unshifted;
cnt = amt;
end else if ( cnt > 0 ) begin
shifted = inter_sh[num_shifters-1];
for ( int i=0; i<num_shifters; i++ ) if ( cnt[i] ) cnt[i]--;
end
assign ready = cnt == 0;
endmodule
module shift_lt_seq_d_sol
#( int wid_lg = 4,
int num_shifters = 2,
int wid = 1 << wid_lg )
( output logic [wid-1:0] shifted,
output logic ready,
input uwire [wid-1:0] unshifted,
input uwire [wid_lg-1:0] amt,
input uwire start,
input uwire clk );
logic [num_shifters-1:0] shift;
uwire [wid-1:0] shin[num_shifters-1:-1];
localparam int bits_per_seg = wid_lg / num_shifters;
for ( genvar i=0; i<num_shifters; i++ ) begin
localparam int fs_amt = 2 ** ( i * bits_per_seg );
shift_fixed #( wid_lg, fs_amt ) sf( shin[i], shin[i-1], shift[i] );
end
assign shin[-1] = shifted;
logic [num_shifters-1:0][bits_per_seg-1:0] cnt;
logic [wid-1:0] next_shifted;
logic next_ready;
logic [num_shifters-1:0] next_shift;
logic [num_shifters-1:0][bits_per_seg-1:0] next_cnt;
always_comb begin
if ( start == 1 ) begin
next_cnt = amt;
next_shift = 0;
end else begin
for ( int i=0; i<num_shifters; i++ ) begin
next_shift[i] = cnt[i] > 0;
next_cnt[i] = next_shift[i] ? cnt[i] - 1 : cnt[i];
end
end
end
assign next_ready = start ? 0 : cnt == 0 ? 1 : ready;
assign next_shifted = start ? unshifted : shin[num_shifters-1];
always_ff @( posedge clk ) begin
shifted = next_shifted;
ready = next_ready;
shift = next_shift;
cnt = next_cnt;
end
endmodule
module shift_lt_seq_d_live
#( int wid_lg = 6,
int num_shifters = 1,
int wid = 1 << wid_lg )
( output logic [wid-1:0] shifted,
output logic ready,
input uwire [wid-1:0] unshifted,
input uwire [wid_lg-1:0] amt,
input uwire start,
input uwire clk );
localparam int bits_per_seg = wid_lg / num_shifters;
logic [num_shifters-1:0] shift;
uwire [wid-1:0] shin[num_shifters-1:-1];
assign shin[-1] = shifted;
for ( genvar i=0; i<num_shifters; i++ ) begin
localparam int fs_amt = 2 ** ( i * bits_per_seg );
shift_fixed #( wid_lg, fs_amt ) sf( shin[i], shin[i-1], shift[i] );
end
logic [num_shifters-1:0][bits_per_seg-1:0] cnt;
always_ff @( posedge clk ) begin
if ( start == 1 ) begin
ready = 0;
cnt = amt;
shift = 0;
shifted = unshifted;
end else begin
if ( cnt == 0 ) ready = 1;
for ( int i=0; i<num_shifters; i++ ) begin
shift[i] = cnt[i] > 0;
if ( cnt[i] != 0 ) cnt[i]--;
end
shifted = shin[num_shifters-1];
end
end
endmodule
module shift_lt_seq_d_p2
#( int wid_lg = 6,
int num_shifters = 1,
int wid = 1 << wid_lg )
( output logic [wid-1:0] shifted,
output logic ready,
input uwire [wid-1:0] unshifted,
input uwire [wid_lg-1:0] amt,
input uwire start,
input uwire clk );
localparam int bits_per_seg = wid_lg / num_shifters;
logic [num_shifters-1:0] shift;
uwire [wid-1:0] shin[num_shifters-1:-1];
assign shin[-1] = shifted;
for ( genvar i=0; i<num_shifters; i++ ) begin
localparam int fs_amt = 2 ** ( i * bits_per_seg );
shift_fixed #( wid_lg, fs_amt ) sf( shin[i], shin[i-1], shift[i] );
end
logic [num_shifters-1:0][bits_per_seg-1:0] cnt;
always_ff @( posedge clk ) begin
if ( start == 1 ) begin
ready = 0;
cnt = amt;
shifted = unshifted;
end else begin
shifted = shin[num_shifters-1];
end
if ( cnt == 0 ) ready = 1;
for ( int i=0; i<num_shifters; i++ ) begin
shift[i] = cnt[i] > 0;
if ( cnt[i] != 0 ) cnt[i]--;
end
end
endmodule
cadence
program reactivate(output uwire clk_reactive, input uwire clk);
assign clk_reactive = clk;
endprogram
module testbench;
localparam int wid_lg = 6;
localparam int wid = 1 << wid_lg;
localparam int max_units = 20;
logic clk;
bit done;
int cycle;
uwire [wid-1:0] sout[max_units];
uwire ready[max_units];
logic [wid-1:0] sin;
logic [wid_lg-1:0] amt;
logic start;
typedef struct { int idx; int err_count = 0; bit seq = 0;
logic [wid-1:0] sout = 'h111; int cyc_tot = 0; } Info;
Info pi[string];
shift_lt_seq_d #(wid_lg,1) my_sld4(sout[4], ready[4], sin, amt, start, clk);
initial begin
automatic string m = "Degree 1";
pi[m].idx = 4; pi[m].seq = 1;
end
shift_lt_seq_d #(wid_lg,3) my_sld5(sout[5], ready[5], sin, amt, start, clk);
initial begin
automatic string m = "Degree 3";
pi[m].idx = 5; pi[m].seq = 1;
end
shift_lt_seq_d_live #(wid_lg,1) my_sld9(sout[9], ready[9], sin, amt, start, clk);
initial begin
automatic string m = "Degree 1 live";
pi[m].idx = 9; pi[m].seq = 1;
end
shift_lt_seq_d_live #(wid_lg,3) my_sld2(sout[2], ready[2], sin, amt, start, clk);
initial begin
automatic string m = "Degree 3 live";
pi[m].idx = 2; pi[m].seq = 1;
end
shift_lt_seq_d_sol #(wid_lg,1) my_sld1(sout[1], ready[1], sin, amt, start, clk);
initial begin
automatic string m = "Degree 1 sol";
pi[m].idx = 1; pi[m].seq = 1;
end
shift_lt_seq_d_sol #(wid_lg,3) my_sld10(sout[10], ready[10], sin, amt, start, clk);
initial begin
automatic string m = "Degree 3 sol";
pi[m].idx = 10; pi[m].seq = 1;
end
shift_lt_seq_d_p2 #(wid_lg,1) my_sld3(sout[3], ready[3], sin, amt, start, clk);
initial begin
automatic string m = "Degree 1 P2";
pi[m].idx = 3; pi[m].seq = 1;
end
shift_lt_seq_d_p2 #(wid_lg,3) my_sld6(sout[6], ready[6], sin, amt, start, clk);
initial begin
automatic string m = "Degree 3 P2";
pi[m].idx = 6; pi[m].seq = 1;
end
localparam int tests_per_sa = 50;
localparam int num_tests = wid * tests_per_sa;
localparam int cycle_limit = num_tests * wid * 2;
uwire clk_reactive;
reactivate ra(clk_reactive,clk);
initial begin
clk = 0;
cycle = 0;
fork
forever #10 cycle += clk++;
wait( done );
wait( cycle >= cycle_limit )
$write("*** Cycle limit exceeded, ending.\n");
join_any;
$finish();
end
initial begin
automatic int test_count = 0;
done = 0;
start = 1;
@( posedge clk_reactive ); @( posedge clk_reactive );
for ( int i=0; i<num_tests; i++ ) begin
automatic int cyc_start = cycle;
automatic int cyc_timeout = cycle + wid * 2;
logic [wid-1:0] shadow_sout;
int awaiting;
automatic logic [wid_lg-1:0] amt_1 = i / tests_per_sa;
amt = { amt_1[1:0], amt_1[wid_lg-1:2] };
test_count++;
for ( int p=0; p<wid; p+=32 ) sin[p+:32] = $random;
shadow_sout = sin << amt;
start = 1;
@( posedge clk_reactive );
start = 0;
awaiting = pi.num();
foreach ( pi[muti] ) begin
automatic string mut = muti; fork begin
while ( pi[mut].seq
&& ready[pi[mut].idx] !== 1
&& cycle < cyc_timeout )
@( posedge clk_reactive );
awaiting--;
pi[mut].sout = sout[pi[mut].idx];
pi[mut].cyc_tot += cycle - cyc_start;
end join_none;
end
wait ( awaiting == 0 );
foreach ( pi[ mut ] )
if ( shadow_sout !== pi[mut].sout ) begin
pi[mut].err_count++;
if ( pi[mut].err_count < 5 )
$write
("%-20s wrong result for 0x%0h << %0d: 0x%0h != 0x%0h (correct)\n",
mut, sin, amt, pi[mut].sout, shadow_sout);
end
end
done = 1;
foreach ( pi[ mut ] )
$write("Ran %4d tests for %-15s, %4d errors found. Avg cyc %.1f\n",
test_count, mut, pi[mut].err_count,
pi[mut].seq ? real'(pi[mut].cyc_tot) / test_count : 1
);
end
endmodule
cadence