Search code examples
verilogcase-statement

Verilog case statement


Could we have any syntax where case statement is scalable? Let me explain with an example: Mux

If there were only 2 select lines

always @(A[1:0]) begin
 case (A[1:0])
  2'b00 : select = 4'b1110;
  2'b01 : select = 4'b1101;
  2'b10 : select = 4'b1011;
  2'b11 : select = 4'b0111;
 endcase
end 

For 3 select lines

always @(A[2:0]) begin
 case (A[2:0])
  3'b000 : select = 8'b1111_1110;
  3'b001 : select = 8'b1111_1101;
  3'b010 : select = 8'b1111_1011;
  3'b011 : select = 8'b1111_0111;
  3'b100 : select = 8'b1110_1111;
  3'b101 : select = 8'b1101_1111;
  3'b110 : select = 8'b1011_1111;
  3'b111 : select = 8'b0111_1111;
 endcase
end 

My questions:

  • Is there a generic way of writing code that could address a mux with any number of select lines? 2,3,4...

  • Is there any other way of achieving this using syntax other than case statement?

Any feedback is welcome. regards


Solution

  • If it is the walking 0's pattern that your after how about:

      localparam SHIFT_W = 3;
      localparam OUT_W   = 2**SHIFT_W;
      reg [SHIFT_W-1:0] shift;
      reg   [OUT_W-1:0] out;
    
      always_comb begin
        out = ~(OUT_W'(1'b1 << shift));
      end
    

    As suggested by nguthrie. Shift to create a walking 1, then invert to create a walking 0.


    My original suggestion (which was a bit verbose) using SystemVerilog to directly create a walking 0:

      localparam SHIFT_W = 3;
      localparam OUT_W   = 2**SHIFT_W;
      reg [SHIFT_W-1:0] shift;
      reg   [OUT_W-1:0] out;
      always_comb begin
        out = OUT_W'( $signed{ 1'b1, 1'b0, {OUT_W{1'b1}} }) >>> (OUT_W-shift) );
      end
    

    WIDTH`() Casts to the correct width to stop LHS RHS width mismatch warnings. $signed() Casts to a signed number to allow >>> to shift by sign extending. This could also be written as:

    out = OUT_W'( { {OUT_W{1'b1}}, 1'b0, {OUT_W{1'b1}} } >> (OUT_W-shift) );
    

    For Verilog-2001, you will just get LHS RHS width mismatch warnings:

    out = { {OUT_W{1'b1}}, 1'b0, {OUT_W{1'b1}} } >> (OUT_W-shift);
    

    Which has removed the need to sign extend during shift.