Verilog case statement

user1495523 picture user1495523 · Jan 28, 2014 · Viewed 10.3k times · Source

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

Answer

Morgan picture Morgan · Jan 28, 2014

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.