【问题标题】:Verilog case statementVerilog 案例陈述
【发布时间】:2014-01-28 09:25:20
【问题描述】:

我们是否可以有任何语法使 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语句之外,还有其他方法可以使用语法来实现吗?

欢迎任何反馈。 问候

【问题讨论】:

  • 右边的数据(位模式)从哪里来?如果它是已知的常规模式,那么创建它的方法可能比查找表更好。
  • 右边的数据是正则模式,除1外所有位都是1,这个位置和select值一样。例如。 case[0] 将 select[0] 设为零,case [4] 将 select[4] 设为零。

标签: verilog case-statement


【解决方案1】:

如果是你之后的行走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 所建议的那样。 Shift 创建步行 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() 强制转换为有符号数以允许 &gt;&gt;&gt; 通过符号扩展进行移位。这也可以写成:

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);

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

【讨论】:

  • Verilog 在 2009 年成为 SystemVerilog,因为不会有新的 Verilog 标准。因此,在不指定版本 (95,2001,2005) 的情况下寻求 Verilog 帮助时,我认为包含可合成的部分 SystemVerilog 是合理的,它本质上是 Verilog 2009, 2012。
  • 我建议out = ~(OUT_W'(1'b1 &lt;&lt; shift)) 更具可读性。移位一个 1,然后将所有位取反得到一个移位的 0。
  • @nguthrie 我什至没有考虑过使用反转。这当然更简洁,更易读!
  • @Morgan - 如您所知,Verilog 和 SyetemVerilog 完全不同;一个松散地基于另一个的事实是不相关的。 SystemVerilog 从第一天起就受到政治驱动,决定不维护 V-2005 标准也是如此。而一个简单的事实是,很多人会继续使用 Verilog,并没有使用 SystemVerilog 的打算。如果有人发布带有C 标签的问题,那么提供C++ 答案肯定没有意义吗?
  • Verilog-2001 的相应变化是什么?
【解决方案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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2015-01-24
      • 1970-01-01
      • 1970-01-01
      • 2023-04-10
      • 2010-10-30
      • 2016-05-13
      • 2016-02-21
      • 2012-09-08
      • 2013-10-14
      相关资源
      最近更新 更多