3

I have a wire called input and I want to detect the number of leading I am trying to create a module which uses the case statement below to change the output data depending on the number of leading zeros. However the size of the input is parameterizable.

If X was a fixed value of 4, I would just create a case statement,

case (input)
  4'b0001  : o_data = {i_data[0]};
  4'b001x  : o_data = {i_data[1],1'b0};
  4'b01xx  : o_data = {i_data[2],2'b0};
  4'b1xxx  : o_data = {i_data[3],3'b0};
  default  : o_data = 4'b0000;
endcase

But with variable X, how do I define all cases?

This question is similar to this one: How to define a parameterized multiplexer using SystemVerilog

Community
  • 1
  • 1
Veridian
  • 3,531
  • 12
  • 46
  • 80
  • o_data is assigned a different number of bits on each case condition. Do we have to assume that not assigned bits are zero? – mcleod_ideafix Mar 28 '15 at 20:23

3 Answers3

3

You can't really parameterize a case statement like that, but you can use a for loop instead:

module lead_detector #(parameter int WIDTH = 4) (
  input logic[WIDTH - 1:0] in,
  output logic[WIDTH - 1:0] out
);
  always_comb begin
    out = '0;
    for (int i = WIDTH - 1; i >= 0; i--)
      if (in[i] == 1'b1) begin
        out[i] = 1;
        break;
      end
  end
endmodule

This is the kind of code I see my designers write all the time (albeit in VHDL), but it should be synthesizable.

Tudor Timi
  • 7,453
  • 1
  • 24
  • 53
  • This should also work in Verilog if you change `always_comb` to `always @(in)`. – Tudor Timi Mar 28 '15 at 22:52
  • 1
    I have a doubt that whether above code is synthesizable? Will `break` statement effect synthesis? – Jithin Mar 30 '15 at 18:50
  • @Jithin : Yes the above code synthesizes. At least it does on Altera Quartus and Cadence Genus. Though I have noticed that Cadence Xcelium xprop checks will get disabled on any always_(comb|ff) blocks that have break statements in them since its not fully supported yet. – Pulimon Jan 22 '20 at 20:17
0

The OP is trying to design some sort of parametrized priority encoder, if I have understood well. I've come with this design that synthesizes well

module priority_encoder #(parameter WIDTH=4) (
    input wire [WIDTH-1:0] i,  // input data
    input wire [WIDTH-1:0] c,  // input control
    output reg [WIDTH-1:0] o   // output data
    );
        
    // Deal with the most significant bit case apart
    always @* begin
        if (c[WIDTH-1]==1'b1)
            o[WIDTH-1] = i[WIDTH-1];
        else
            o[WIDTH-1] = 1'b0;
    end
    
    // Deal with the rest of bits
    genvar idx;
    generate
    for (idx = WIDTH-2; idx >=0; idx = idx-1) begin :gen_cases
        always @* begin
            if (c[idx]==1'b1 && c[WIDTH-1:idx+1]=='b0)
                o[idx] = i[idx];
            else
                o[idx] = 1'b0;
        end
     end
     endgenerate
endmodule

The testbench module I've created for this design is as follows:

module tb_prioencoder;
    parameter WIDTH=3;
    // Inputs
    reg [WIDTH-1:0] i;
    reg [WIDTH-1:0] c;

    // Outputs
    wire [WIDTH-1:0] o;

    // Instantiate the Unit Under Test (UUT)
    priority_encoder #(WIDTH) uut (
        .i(i), 
        .c(c[WIDTH-1:0]), 
        .o(o)
    );

    initial begin
        i = {WIDTH{1'b1}};
        c = {WIDTH{1'b0}};
        repeat (2**WIDTH) begin
            #10;
            c = c + 1;
        end
    end      
endmodule

Which leads me to this chronogram (for WIDTH = 3): Chronogram for above testbench

Community
  • 1
  • 1
mcleod_ideafix
  • 11,128
  • 2
  • 24
  • 32
0

The case statement cannot be parameterized like that. A for loop as others mentioned is a good solution for your problem.

Here is a different solution: if you were looking to solve the reverse problem, i.e., finding the leading 1 from the right side, you could just bitwise-and in with its two's complement. Therefore, for finding the leading 1 from left, you can first bit-reverse in, bitwise-and it with its two's complement, and then bit-reverse the result:

logic [X - 1:0] reverse_in, reverse_out;
always_comb 
begin 
  reverse_in = { << {in} }; //Bit-reverse of input (using stream operator)
  reverse_out = (~(reverse_in) + 1) & reverse_in; //And with two's complement
  out = { << {reverse_out} };  //Bit-reverse of output
end

In synthesis, bit reversing does not have any cost since it is just rewiring.

Ari
  • 7,251
  • 11
  • 40
  • 70