【问题标题】:How to parameterize a case statement with don't cares?如何参数化不关心的case语句?
【发布时间】:2015-03-28 05:12:07
【问题描述】:

我有一个叫输入的线,我想检测前导数 我正在尝试创建一个模块,该模块使用下面的 case 语句根据前导零的数量更改输出数据。但是输入的大小是可参数化的。

如果 X 是固定值 4,我会创建一个 case 语句,

case (input)
  4'b0001  : o_data = {i_data[0]};
  4'b001x  : o_data = {i_data[1],1'b0};
  4'b01xx  : o_data = {i_data[2],2'b0};
  4'b1xxx  : o_data = {i_data[3],3'b0};
  default  : o_data = 4'b0000;
endcase

但是对于变量 X,我如何定义所有情况?

这个问题和这个问题类似:How to define a parameterized multiplexer using SystemVerilog

【问题讨论】:

  • o_data 在每种情况下都被分配了不同的位数。我们是否必须假设未分配的位为零?

标签: verilog system-verilog


【解决方案1】:

你不能像这样真正参数化 case 语句,但你可以使用 for 循环代替:

module lead_detector #(parameter int WIDTH = 4) (
  input logic[WIDTH - 1:0] in,
  output logic[WIDTH - 1:0] out
);
  always_comb begin
    out = '0;
    for (int i = WIDTH - 1; i >= 0; i--)
      if (in[i] == 1'b1) begin
        out[i] = 1;
        break;
      end
  end
endmodule

这是我看到我的设计师一直编写的那种代码(尽管是用 VHDL 编写的),但它应该是可综合的。

【讨论】:

  • 如果您将 always_comb 更改为 always @(in),这在 Verilog 中也应该可以工作。
  • 我怀疑上面的代码是否可以合成? break语句会影响合成吗?
  • @Jithin :是的,上面的代码合成了。至少在 Altera Quartus 和 Cadence Genus 上是这样。虽然我注意到 Cadence Xcelium xprop 检查将在任何包含 break 语句的 always_(comb|ff) 块上被禁用,因为它尚未完全支持。
【解决方案2】:

如果我理解得很好,OP 正在尝试设计某种参数化优先级编码器。我带来了这种合成良好的设计

module priority_encoder #(parameter WIDTH=4) (
    input wire [WIDTH-1:0] i,  // input data
    input wire [WIDTH-1:0] c,  // input control
    output reg [WIDTH-1:0] o   // output data
    );
        
    // Deal with the most significant bit case apart
    always @* begin
        if (c[WIDTH-1]==1'b1)
            o[WIDTH-1] = i[WIDTH-1];
        else
            o[WIDTH-1] = 1'b0;
    end
    
    // Deal with the rest of bits
    genvar idx;
    generate
    for (idx = WIDTH-2; idx >=0; idx = idx-1) begin :gen_cases
        always @* begin
            if (c[idx]==1'b1 && c[WIDTH-1:idx+1]=='b0)
                o[idx] = i[idx];
            else
                o[idx] = 1'b0;
        end
     end
     endgenerate
endmodule

我为此设计创建的测试平台模块如下:

module tb_prioencoder;
    parameter WIDTH=3;
    // Inputs
    reg [WIDTH-1:0] i;
    reg [WIDTH-1:0] c;

    // Outputs
    wire [WIDTH-1:0] o;

    // Instantiate the Unit Under Test (UUT)
    priority_encoder #(WIDTH) uut (
        .i(i), 
        .c(c[WIDTH-1:0]), 
        .o(o)
    );

    initial begin
        i = {WIDTH{1'b1}};
        c = {WIDTH{1'b0}};
        repeat (2**WIDTH) begin
            #10;
            c = c + 1;
        end
    end      
endmodule

这让我看到了这个计时码表(WIDTH = 3):

【讨论】:

    【解决方案3】:

    case 语句不能这样参数化。其他人提到的 for 循环是解决您问题的好方法。

    这是一个不同的解决方案:如果您想解决相反的问题,即从右侧找到前导 1,您可以按位和 in 及其二进制补码。因此,为了从左边找到前导的 1,您可以先对 in 进行位反转,然后将其与二进制补码进行位反转,然后对结果进行位反转:

    logic [X - 1:0] reverse_in, reverse_out;
    always_comb 
    begin 
      reverse_in = { << {in} }; //Bit-reverse of input (using stream operator)
      reverse_out = (~(reverse_in) + 1) & reverse_in; //And with two's complement
      out = { << {reverse_out} };  //Bit-reverse of output
    end
    

    在综合中,位反转没有任何成本,因为它只是重新布线。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多