2

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

user1495523
  • 475
  • 2
  • 7
  • 17
  • Where will the data (bit patterns) on the right come from? If it is a known regular pattern then there is likely a better way to create it than a look up table. – Morgan Jan 28 '14 at 10:07
  • The data on the right is regular pattern, all bits are one except one, this is at the position same as select value. eg. case[0] would have select[0] as zero, and case [4] would have select[4] as zero. – user1495523 Jan 28 '14 at 10:27

3 Answers3

2

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.

Community
  • 1
  • 1
Morgan
  • 19,934
  • 8
  • 58
  • 84
  • 2
    Verilog became SystemVerilog in 2009, as there will be no new Verilog standards. Therefore when asking for Verilog help with out specifying the version (95,2001,2005) I think it is reasonable to include syhtesizable parts SystemVerilog which is essentially Verilog 2009, 2012. – Morgan Jan 28 '14 at 14:56
  • I would suggest `out = ~(OUT_W'(1'b1 << shift))` is more readable. Shift a 1 and then invert all of the bits to get a shifted 0. – nguthrie Jan 28 '14 at 17:32
  • @nguthrie I did not even think about using an invert. That certainly is more succinct, and readable! – Morgan Jan 28 '14 at 18:51
  • @Morgan - Verilog and SyetemVerilog are completely different, as you know; the fact that one is loosely based on the other is not relevant. SystemVerilog was politically driven from day #1, as was the decision not to maintain the V-2005 standard. And the simple fact is that many people will continue to use Verilog, and have no intention of using SystemVerilog. If someone posted a quetion with a `C` tag, surely it wouldn't make sense to provide a `C++` answer? – EML Jan 29 '14 at 09:09
  • What would be the corresponding chage for Verilog-2001? – user1495523 Jan 29 '14 at 10:26
  • The only SystemVerilog section is the width casting operation, ```WIDTH`()``` which will leave you with LHS RHS width mismatch warning, in this scenario it is safe. – Morgan Jan 29 '14 at 12:18
  • @EML I do not think comparing `c` to `c++` is quite the same as `Verilog` to the [synthesisable sections of `SystemVerilog`](http://www.sutherland-hdl.com/papers/2013-SNUG-SV_Synthesizable-SystemVerilog_paper.pdf). I would agree with you when it comes to the class based verification but not for RTL. SystemVerilog is the new standard which current tools are based on, people asking for help under the verilog tag are often pointed in the direction of [SystemVerilog LRM IEEE 1800-2012](http://standards.ieee.org/getieee/1800/download/1800-2012.pdf). – Morgan Jan 29 '14 at 12:30
2

Since the given criteria is for a binary to one-cold decoder, a for-loop can be used. It typicality gives better timing and area for synthesize compared to a bit-shifter; from my experience. You should do your own comparison as it depends your standard cell library and how well your synthesizer can optimize.

module bin2cold #(parameter WIDTH=4) (
  output reg [2**WIDTH-1:0] cold,
  input      [   WIDTH-1:0] bin );

integer idx;
always @* begin
  for(idx = 0; idx < 2**WIDTH; idx=idx+1) begin
    cold[idx] = (bin != idx);
  end
end

endmodule
Greg
  • 18,111
  • 5
  • 46
  • 68
1

This will give you a succinct generic mux, where all inputs are aggregated in a vector called in, and then they get separated in input_array:

module mux #(parameter  DW  = 32,
            parameter   N   = 2) 
(

 input   [(DW*N)-1:0]           in,
 input   [$clog2(N)-1:0]    sel,   

 output  logic [DW-1:0]       out
);

genvar ig;

logic    [DW-1:0] input_array [0:N-1];

assign  out = input_array[sel];

//separating inputs
generate
    for(ig=0; ig<N; ig=ig+1) begin: array_assignments
        assign  input_array[ig] = in[(ig*DW)+:DW];
    end
endgenerate

endmodule

What you want is a bit different in that, the value of in is already known and can internally be generated. Therefore, the generate/endgenerate block in my code, can be replaced by one of the methods described by others.

    module mux #(parameter  DW  = 32,
            parameter   N   = 2) 
(

 input   [(DW*N)-1:0]           in, //not used anymore
 input   [$clog2(N)-1:0]    sel,   

 output  logic [DW-1:0]       out
);

genvar ig;

logic    [DW-1:0] input_array [0:N-1];

assign  out = input_array[sel];

generate
    for(ig=0; ig<N; ig=ig+1) begin: array_assignments
        assign  input_array[ig] = ~( 2**ig );
    end
endgenerate

endmodule

(not sure of this is purely Verilog or SystemVerilog)

Ari
  • 7,251
  • 11
  • 40
  • 70