diff --git a/round_robin_performance_enc.sv b/round_robin_performance_enc.sv new file mode 100755 index 0000000..93549e6 --- /dev/null +++ b/round_robin_performance_enc.sv @@ -0,0 +1,113 @@ +//------------------------------------------------------------------------------ +// round_robin_performance_enc.sv +// Konstantin Pavlov, pavlovconst@gmail.com +//------------------------------------------------------------------------------ + +// INFO ------------------------------------------------------------------------- +// VErsion of round robin combinational encoder to select only one bit from +// the input bus. Feature of this particular version is a performance boost +// motivated by skipping inactive inputs while performing round_robin. +// +// In contrast to priority encoder, every input bit (on average) has equal +// chance to get to the output when all inputs are equally probable +// +// See also round_robin_enc.sv +// See also priority_enc.sv +// + + +/* --- INSTANTIATION TEMPLATE BEGIN --- + +round_robin_performance_enc #( + .WIDTH( 32 ) +) RE1 ( + .clk( clk ), + .nrst( nrst ), + .id( ), + .od_valid( ), + .od_filt( ), + .od_bin( ) +); + +--- INSTANTIATION TEMPLATE END ---*/ + + +module round_robin_performance_enc #( parameter + WIDTH = 32, + WIDTH_W = $clog2(WIDTH) +)( + input clk, // clock + input nrst, // inversed reset, synchronous + + input [WIDTH-1:0] id, // input data bus + output od_valid, // output valid (some bits are active) + output logic [WIDTH-1:0] od_filt, // filtered data (only one priority bit active) + output logic [WIDTH_W-1:0] od_bin // priority bit binary index +); + + +// current bit selector +logic [WIDTH_W-1:0] priority_bit = '0; + +// prepare double width buffer with LSB bits masked out +logic [2*WIDTH-1:0] mask; +logic [2*WIDTH-1:0] id_buf; +always_comb begin + integer i; + for ( i=0; i<2*WIDTH; i++ ) begin + if( i>priority_bit[WIDTH_W-1:0] ) begin + mask[i] = 1'b1; + end else begin + mask[i] = 1'b0; + end + end + id_buf[2*WIDTH-1:0] = {2{id[WIDTH-1:0]}} & mask[2*WIDTH-1:0]; +end + +logic [2*WIDTH-1:0] id_buf_filt; +leave_one_hot #( + .WIDTH( 2*WIDTH ) +) one_hot_b ( + .in( id_buf[2*WIDTH-1:0] ), + .out( id_buf_filt[2*WIDTH-1:0] ) +); + +logic [(WIDTH_W+1)-1:0] id_buf_bin; // one more bit to decode double width input + +logic err_no_hot; +assign od_valid = ~err_no_hot; + +pos2bin #( + .BIN_WIDTH( (WIDTH_W+1) ) +) pos2bin_b ( + .pos( id_buf_filt[2*WIDTH-1:0] ), + .bin( id_buf_bin[(WIDTH_W+1)-1:0] ), + + .err_no_hot( err_no_hot ), + .err_multi_hot( ) +); + +always_comb begin + if( od_valid ) begin + od_bin[WIDTH_W-1:0] = id_buf_bin[(WIDTH_W+1)-1:0] % WIDTH; + od_filt[WIDTH-1:0] = 1'b1 << od_bin[WIDTH_W-1:0]; + end else begin + od_bin[WIDTH_W-1:0] = '0; + od_filt[WIDTH-1:0] = '0; + end +end + +// latching current +always_ff @(posedge clk) begin + if( ~nrst ) begin + priority_bit[WIDTH_W-1:0] <= '0; + end else begin + if( od_valid ) begin + priority_bit[WIDTH_W-1:0] <= od_bin[WIDTH_W-1:0]; + end else begin + // nop, + end // if + end // if nrst +end + +endmodule diff --git a/round_robin_performance_enc_tb.sv b/round_robin_performance_enc_tb.sv new file mode 100755 index 0000000..05c462b --- /dev/null +++ b/round_robin_performance_enc_tb.sv @@ -0,0 +1,121 @@ +//------------------------------------------------------------------------------ +// round_robin_performance_enc_tb.sv +// Konstantin Pavlov, pavlovconst@gmail.com +//------------------------------------------------------------------------------ + +// INFO ------------------------------------------------------------------------ +// testbench for round_robin_performance_enc.sv module +// + +`timescale 1ns / 1ps + +module round_robin_performance_enc_tb(); + +logic clk200; +initial begin + #0 clk200 = 1'b0; + forever + #2.5 clk200 = ~clk200; +end + +// external device "asynchronous" clock +logic clk33a; +initial begin + #0 clk33a = 1'b0; + forever + #7 clk33a = ~clk33a; +end + +logic clk33; +//assign clk33 = clk33a; +always @(*) begin + clk33 = #($urandom_range(0, 2000)*10ps) clk33a; +end + +logic rst; +initial begin + #0 rst = 1'b0; + #10.2 rst = 1'b1; + #5 rst = 1'b0; + //#10000; + forever begin + #9985 rst = ~rst; + #5 rst = ~rst; + end +end + +logic nrst; +assign nrst = ~rst; + +logic rst_once; +initial begin + #0 rst_once = 1'b0; + #10.2 rst_once = 1'b1; + #5 rst_once = 1'b0; +end + +logic nrst_once; +assign nrst_once = ~rst_once; + +logic [31:0] DerivedClocks; +clk_divider #( + .WIDTH( 32 ) +) cd1 ( + .clk( clk200 ), + .nrst( nrst_once ), + .ena( 1'b1 ), + .out( DerivedClocks[31:0] ) +); + +logic [31:0] E_DerivedClocks; +edge_detect ed1[31:0] ( + .clk( {32{clk200}} ), + .nrst( {32{nrst_once}} ), + .in( DerivedClocks[31:0] ), + .rising( E_DerivedClocks[31:0] ), + .falling( ), + .both( ) +); + +logic [15:0] RandomNumber1; +c_rand rng1 ( + .clk(clk200), + .rst(rst_once), + .reseed(1'b0), + .seed_val(DerivedClocks[31:0]), + .out( RandomNumber1[15:0] ) +); + +logic start; +initial begin + #0 start = 1'b0; + #100 start = 1'b1; + #20 start = 1'b0; +end + +// Module under test ========================================================== + +`define WIDTH_W 3 +`define WIDTH (2**`WIDTH_W) + +logic [`WIDTH-1:0] pos; +bin2pos #( + .BIN_WIDTH( `WIDTH_W ) +) BP1 ( + .bin( RandomNumber1[`WIDTH_W-1:0] ), + .pos( pos[`WIDTH-1:0] ) +); + +round_robin_performance_enc #( + .WIDTH( `WIDTH ) +) RE1 ( + .clk( clk200 ), + .nrst( nrst_once ), + .id( RandomNumber1[`WIDTH-1:0] ), //pos[`WIDTH-1:0] ), + .od_valid( ), + .od_filt( ), + .od_bin( ) +); + + +endmodule