Search code examples
verilogsystem-verilogfpgahdlencoder-decoder

How do i make a synthesizable parameterized encoder on Verilog?


I have tried to do it this way:

module encoder 
#(
    parameter WIDTH = 4
 )
(
    input wire [WIDTH-1: 0] in,
    output reg [$clog2(WIDTH)-1: 0] out
);

  genvar i; 
  generate
    for (i = 0;i < WIDTH;i = i+1) 
    begin :gen_block
      always @* 
      begin
        if (in[i]==1'b1) 
          out = i;
      end
    end
  endgenerate
endmodule

It works well in the simulation, but I'm not sure if this can be synthesized. The generate block will produce multiple copies of the always block, and I'm guessing there will be a race condition between the previous value of out and the updated value of out.

Am I correct about assuming that this code can't be synthesized? If so, What do I change to make it synthesize correctly?


Solution

  • Yes, you do have a race condition in simulation and it is not synthesizable. You cannot have multiple always blocks making assignments to the same variable in parallel( happens when more than one bit in in is set). You want a regular procedural-for loop, not a generate-for loop.

    module encoder 
    #(
        parameter WIDTH = 4
     )
    (
        input wire [WIDTH-1: 0] in,
        output logic [$clog2(WIDTH)-1: 0] out
    );
          always_comb begin
            out = 'x; // don't care if no 'in' bits set
            for (int i = 0;i < WIDTH;i++)
                if (in[i]==1'b1) begin
                   out = i;
                   break; // priority goes from LSB-to-MSB
            end
        end
    endmodule
    

    Edit: For tools that do not support break yet

    always_comb begin
            bit Break;
            Break = 0;
            out = 'x; // don't care if no 'in' bits set
            for (int i = 0;i < WIDTH;i++)
                if (in[i]==1'b1 && !Break) begin
                   out = i;
                   Break = 1;
            end
        end