Verilog/SystemVerilog 在 case 语句中推断闩锁
Verilog/SystemVerilog inferred latch in case statement
我无法理解为什么我的代码有锁存器
logic [1:0] lru_list [0:3];
always_comb begin
if(reset) begin
lru_list[0] = 0;
lru_list[1] = 0;
lru_list[2] = 0;
lru_list[3] = 0;
end
else begin
case({access, update, access_index_i < 4})
3'b101: begin
lru_list[0] = lru_list[0] + 1;
lru_list[1] = lru_list[1] + 1;
lru_list[2] = lru_list[2] + 1;
lru_list[3] = lru_list[3] + 1;
lru_list[access_index_i] = 0;
end
3'b011: begin
lru_list[0] = lru_list[0];
lru_list[1] = lru_list[1];
lru_list[2] = lru_list[2];
lru_list[3] = lru_list[3];
lru_list[access_index_i] = 0;
end
default: begin
lru_list[0] = lru_list[0];
lru_list[1] = lru_list[1];
lru_list[2] = lru_list[2];
lru_list[3] = lru_list[3];
end
endcase
end
end // always_comb
在 case 语句中,我有一个默认 case,它将捕获所有不匹配的值。我还为数组中的每个索引设置了一个值。我不明白我在哪里隐式地将我的数组设置为隐式值。
我认为这可能与 lru_list[access_index_i] = 0;
有关,但注释掉这两行仍然会出现保存错误。
这是我要开始的。
首先在 always 语句中添加一个敏感列表。你有一个 "reset" if 在那里,所以听起来你想要 always @(posedge clk 或 posedge reset)。我知道您正在使用 always_comb,但我很想知道这是否确实解决了问题。它会告诉。
编辑:所以我刚刚意识到您正在使用 RHS 上的相同变量对 LHS 变量进行操作。你需要计时。否则当你组合进入计数状态时,它永远无法解决,因为它总是在无限循环中添加。总是@(posedge clk 或 posedge reset)我认为你会得到更好的结果。
其次,可能更重要的是,您似乎正在使用 access_index_i < 4 并试图从中提取一些位来构成串联向量的最低有效位 {access, update, access_index_i < 4}。如果你向右移动,我认为逻辑会在结果中插入 4'b0000,我猜它并不是真正的开始,所以我想知道在 3'b101 案例中实际使用了什么位作为它将由 {bit,bit,vector} 寻址。似乎您想说 {bit,bit,vector[4]} 或类似的东西。您实际上可能正在使用 access_index_i 的最低有效 3 位来处理您的组合语句。
编辑:回复您在下方的评论。你可以,(这就是我所做的)将问题分成两部分,组合和时钟。
reg [3:0] my_sig;
wire [3:0] my_sig_wire;
always @ (posedge clk)
begin
my_sig <= my_sig_wire;
end
always (*)
begin
if(reset)
begin
my_sig_wire = 4'b0000; // This will also reset the clocked version
end
else
begin
my_sig_wire = my_sig; // This is okay, because no matter
// how much I alter my_sig_wire, my_sig will
// only change on the clock pulse. So
// we avoid the infinite loop problem
my_sig_wire[index] = 1'b0; // Tweak one of the signals for fun.
// on the next clock, my_sig is updated!
end
end
组合块定义了纯粹基于输入的输出,没有状态。
时序元件(触发器)包含状态,因此输出可以基于输入和状态,或仅基于状态。
您的默认语句:
default: begin
lru_list[0] = lru_list[0];
通过保存一个值来维持状态,因此不能组合。您尚未定义触发器 (@(posedge clk)
),因此推断出一个锁存器来保持状态。
我无法理解为什么我的代码有锁存器
logic [1:0] lru_list [0:3];
always_comb begin
if(reset) begin
lru_list[0] = 0;
lru_list[1] = 0;
lru_list[2] = 0;
lru_list[3] = 0;
end
else begin
case({access, update, access_index_i < 4})
3'b101: begin
lru_list[0] = lru_list[0] + 1;
lru_list[1] = lru_list[1] + 1;
lru_list[2] = lru_list[2] + 1;
lru_list[3] = lru_list[3] + 1;
lru_list[access_index_i] = 0;
end
3'b011: begin
lru_list[0] = lru_list[0];
lru_list[1] = lru_list[1];
lru_list[2] = lru_list[2];
lru_list[3] = lru_list[3];
lru_list[access_index_i] = 0;
end
default: begin
lru_list[0] = lru_list[0];
lru_list[1] = lru_list[1];
lru_list[2] = lru_list[2];
lru_list[3] = lru_list[3];
end
endcase
end
end // always_comb
在 case 语句中,我有一个默认 case,它将捕获所有不匹配的值。我还为数组中的每个索引设置了一个值。我不明白我在哪里隐式地将我的数组设置为隐式值。
我认为这可能与 lru_list[access_index_i] = 0;
有关,但注释掉这两行仍然会出现保存错误。
这是我要开始的。
首先在 always 语句中添加一个敏感列表。你有一个 "reset" if 在那里,所以听起来你想要 always @(posedge clk 或 posedge reset)。我知道您正在使用 always_comb,但我很想知道这是否确实解决了问题。它会告诉。
编辑:所以我刚刚意识到您正在使用 RHS 上的相同变量对 LHS 变量进行操作。你需要计时。否则当你组合进入计数状态时,它永远无法解决,因为它总是在无限循环中添加。总是@(posedge clk 或 posedge reset)我认为你会得到更好的结果。
其次,可能更重要的是,您似乎正在使用 access_index_i < 4 并试图从中提取一些位来构成串联向量的最低有效位 {access, update, access_index_i < 4}。如果你向右移动,我认为逻辑会在结果中插入 4'b0000,我猜它并不是真正的开始,所以我想知道在 3'b101 案例中实际使用了什么位作为它将由 {bit,bit,vector} 寻址。似乎您想说 {bit,bit,vector[4]} 或类似的东西。您实际上可能正在使用 access_index_i 的最低有效 3 位来处理您的组合语句。
编辑:回复您在下方的评论。你可以,(这就是我所做的)将问题分成两部分,组合和时钟。
reg [3:0] my_sig;
wire [3:0] my_sig_wire;
always @ (posedge clk)
begin
my_sig <= my_sig_wire;
end
always (*)
begin
if(reset)
begin
my_sig_wire = 4'b0000; // This will also reset the clocked version
end
else
begin
my_sig_wire = my_sig; // This is okay, because no matter
// how much I alter my_sig_wire, my_sig will
// only change on the clock pulse. So
// we avoid the infinite loop problem
my_sig_wire[index] = 1'b0; // Tweak one of the signals for fun.
// on the next clock, my_sig is updated!
end
end
组合块定义了纯粹基于输入的输出,没有状态。
时序元件(触发器)包含状态,因此输出可以基于输入和状态,或仅基于状态。
您的默认语句:
default: begin
lru_list[0] = lru_list[0];
通过保存一个值来维持状态,因此不能组合。您尚未定义触发器 (@(posedge clk)
),因此推断出一个锁存器来保持状态。