Domanda

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

È stato utile?

Soluzione

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.

Altri suggerimenti

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

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)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top