在 Verilog 中参数化不完整的 case 语句

Parameterizing an incomplete case statement in Verilog

我正在尝试参数化我编写的一些代码。下面的非参数化版本是为 WIDTH = 4 编写的。我有一个循环零的 reg digits。基于这个零的位置,我想从我的数组 SS 输出一个特定的向量到 segments (我在别处给它赋值)。

reg [6:0] SS [3:0];    

always @(posedge clk)
    if (reset) digits <= 4'b1110;
    else       digits <= { digits[2:0], digits[3] };

always @(*)
    if (reset) segments <= ~7'h0;
    else case(~digits)
        4'b1    : segments[6:0] <= ~SS[0];
        4'b10   : segments[6:0] <= ~SS[1];
        4'b100  : segments[6:0] <= ~SS[2];
        4'b1000 : segments[6:0] <= ~SS[3];
        default : segments[6:0] <=  7'h0;
    endcase

如何为 digits 的不同宽度参数化此 case 语句?我试过使用 for 循环而不是像这样的 case 语句:

for (genvar i = 0; i < WIDTH; i = i+1) begin
    if (~digits[i]) segments[6:0] <= ~SS[i];
end

但它不会合成,因为它说 segments 有多个驱动程序,如果我像下面那样以不同的方式进行合成,它会说 digits 不是常数,所以它无法合成:

for (genvar i = 0; i < WIDTH; i = i+1) begin
    if (~digits == (1 << i)) segments[6:0] <= ~SS[i];
end

我该怎么做?我想过取 ~digits 的对数基数 2 并在循环中检查它是否等于 i 但我不确定如何在硬件中执行此操作。有没有更好的方法?

你可以做一个循环并利用 "last assignment wins"。见下文。我在这里使用了一些 SystemVerilog 语法,但没有它你也可以做到。

PARAMETER SS_SIZE = 4
logic [6:0] SS [SS_SIZE];
logic [SS_SIZE-1:0] digits;

always_ff @(posedge clk or posedge reset)
    if (reset) digits <= {{(SS_SIZE-1){1'b1}},1'b0};
    else       digits <= { digits[SS_SIZEE-2:0], digits[SS_SIZE-1] };

always_comb begin
    segments = '0;
    for(int i=0; i<SS_SIZE; i++) begin
       if(digits[i]==1'b0) begin
          segments = ~SS[i];
       end
    end
 end

我会更进一步,用二进制计数器替换移位寄存器:

PARAMETER SS_SIZE = 4
logic [6:0] SS [SS_SIZE];
logic [$clog2(SS_SIZE)-1:0] count;

always_ff @(posedge clk or posedge reset)
    if (reset) count <= '0;
    else if(count == (SS_SIZE-1)) count <= '0
    else       count <= count+1;

assign segments = ~SS[count];