diff --git a/rtl/priority_encoder.v b/rtl/priority_encoder.v index 730306302..8735a0e37 100644 --- a/rtl/priority_encoder.v +++ b/rtl/priority_encoder.v @@ -42,57 +42,43 @@ module priority_encoder # output wire [WIDTH-1:0] output_unencoded ); -// power-of-two width -parameter W1 = 2**$clog2(WIDTH); -parameter W2 = W1/2; +parameter LEVELS = WIDTH > 2 ? $clog2(WIDTH) : 1; +parameter W = 2**LEVELS; + +// pad input to even power of two +wire [W-1:0] input_padded = {{W-WIDTH{1'b0}}, input_unencoded}; + +wire [W/2-1:0] stage_valid[LEVELS-1:0]; +wire [W/2-1:0] stage_enc[LEVELS-1:0]; generate - if (WIDTH == 1) begin - // one input - assign output_valid = input_unencoded; - assign output_encoded = 0; - end else if (WIDTH == 2) begin - // two inputs - just an OR gate - assign output_valid = |input_unencoded; + genvar l, n; + + // process input bits; generate valid bit and encoded bit for each pair + for (n = 0; n < W/2; n = n + 1) begin : loop_in + assign stage_valid[0][n] = |input_padded[n*2+1:n*2]; if (LSB_PRIORITY == "LOW") begin - assign output_encoded = input_unencoded[1]; + assign stage_enc[0][n] = input_padded[n*2+1]; end else begin - assign output_encoded = ~input_unencoded[0]; + assign stage_enc[0][n] = !input_padded[n*2+0]; end - end else begin - // more than two inputs - split into two parts and recurse - // also pad input to correct power-of-two width - wire [$clog2(W2)-1:0] out1, out2; - wire valid1, valid2; - priority_encoder #( - .WIDTH(W2), - .LSB_PRIORITY(LSB_PRIORITY) - ) - priority_encoder_inst1 ( - .input_unencoded(input_unencoded[W2-1:0]), - .output_valid(valid1), - .output_encoded(out1) - ); - priority_encoder #( - .WIDTH(W2), - .LSB_PRIORITY(LSB_PRIORITY) - ) - priority_encoder_inst2 ( - .input_unencoded({{W1-WIDTH{1'b0}}, input_unencoded[WIDTH-1:W2]}), - .output_valid(valid2), - .output_encoded(out2) - ); - // multiplexer to select part - assign output_valid = valid1 | valid2; - if (LSB_PRIORITY == "LOW") begin - assign output_encoded = valid2 ? {1'b1, out2} : {1'b0, out1}; - end else begin - assign output_encoded = valid1 ? {1'b0, out1} : {1'b1, out2}; + end + + // compress down to single valid bit and encoded bus + for (l = 1; l < LEVELS; l = l + 1) begin : loop_levels + for (n = 0; n < W/(2*2**l); n = n + 1) begin : loop_compress + assign stage_valid[l][n] = |stage_valid[l-1][n*2+1:n*2]; + if (LSB_PRIORITY == "LOW") begin + assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+1] ? {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]} : {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]}; + end else begin + assign stage_enc[l][(n+1)*(l+1)-1:n*(l+1)] = stage_valid[l-1][n*2+0] ? {1'b0, stage_enc[l-1][(n*2+1)*l-1:(n*2+0)*l]} : {1'b1, stage_enc[l-1][(n*2+2)*l-1:(n*2+1)*l]}; + end end end endgenerate -// unencoded output +assign output_valid = stage_valid[LEVELS-1]; +assign output_encoded = stage_enc[LEVELS-1]; assign output_unencoded = 1 << output_encoded; endmodule