0

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?

  • I doubt that it works in simulation. You did not test it enough. The code just generates WIDTH number of latch drivers for a single signal 'out'. it is not synthesizable for this reason. – Serge Apr 29 '21 at 01:23
  • @Serge it does work in the simulation. Can you check this picture once? All the outputs are properly generated. Link: https://imgur.com/02bx3ei – Abhishek Revinipati Apr 29 '21 at 17:36
  • Your model causes undefined behavior in simulation. If it worked for you, it means that either you did not check it with sufficient number of cases or you were just lucky. It will probably work correctly if `in` has only a single bit set. With multiple bits set you can have unexpected results. – Serge Apr 29 '21 at 20:12

2 Answers2

2

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
dave_59
  • 39,096
  • 3
  • 24
  • 63
0

you can avoid break by initializing i = N-1

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 = N-1 ;i >=0;i--)
            if (in[i]) begin
               out = i;
        end
    end
endmodule