我正在尝试参数化我编写的一些代码。下面的非参数化版本是针对WIDTH = 4编写的。我有一个循环为零的reg digits
。根据这个零的位置,我想从我的数组segments
向SS
输出一个特定的向量(我在别处为它赋值)。
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
循环而不是像这样的案例陈述:
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
,但我不确定如何在硬件中执行此操作。还有更好的方法吗?
答案 0 :(得分:1)
你可以做一个循环并利用&#34;最后一次分配获胜&#34;。见下文。我在这里使用了一些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];