Verilog案例陈述

时间:2014-01-28 09:25:20

标签: verilog case-statement

我们可以使用case语句可扩展的语法吗? 让我用一个例子来解释:Mux

如果只有2条选择线

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 

3条选择线

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 

我的问题:

  • 是否有一种编写代码的通用方法可以解决具有任意数量选择线的多路复用器? 2,3,4 ...

  • 除了case语句之外,还有其他方法可以实现这个吗?

欢迎任何反馈。 问候

3 个答案:

答案 0 :(得分:2)

如果是步行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'(1'b1 << shift));
  end

根据nguthrie 的建议。移动以创建步行1,然后反转以创建步行0。


我的原始建议(有点冗长)使用SystemVerilog直接创建一个步行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`()投射到正确的宽度以停止LHS RHS宽度不匹配警告。 $signed()投射到已签名的号码,以允许>>>按符号扩展进行转换。这也可以写成:

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

对于Verilog-2001,您将获得LHS RHS宽度不匹配警告:

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

这已经消除了在轮班期间签名扩展的需要。

答案 1 :(得分:2)

由于给定的标准是二进制到一冷解码器,因此可以使用for循环。与位移位器相比,它的典型性为合成提供了更好的时序和面积;从我的经验来看。您应该进行自己的比较,因为它取决于您的标准单元库以及合成器的优化程度。

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

答案 2 :(得分:1)

这将为您提供一个简洁的通用多路复用器,其中所有输入都聚合在一个名为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

你想要的是有点不同,in的值已经知道并且可以在内部生成。因此,我的代码中的generate / endgenerate块可以被其他人描述的方法之一替换。

    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

(不确定这是纯粹的Verilog还是SystemVerilog)