如何删除 1 位 ALU 代码中的锁存器?
How to remove latches in code of 1-bit ALU?
我正在尝试在 Verilog 中构建一个 32 位 ALU。我一开始就实现了一个 1 位 ALU。
ALU 应该只有 4 个函数,而不是全部:add、sub、and、or。这是我的代码:
module ALU(
input wire [3:0] OPCode,
input wire Operand1,
input wire Operand2,
input wire cin,
output reg Result,
output reg Cout
);
always@(*)
begin
case(OPCode)
4'b0000: Result = Operand1&Operand2;
4'b0001: Result = Operand1|Operand2;
4'b0010:
begin
Result = cin ^(Operand1 ^ (Operand2 ^ cin));
Cout = ((Operand2 ^ cin) & Operand1) | ((Operand1 ^ (Operand2 ^ cin)) & cin);
end
4'b0110:
begin
Result = cin ^(Operand1 ^ (Operand2 ^ cin));
Cout = ((Operand2 ^ cin) & Operand1) | ((Operand1 ^ (Operand2 ^ cin)) & cin);
end
endcase
end
endmodule
这里的问题是它生成了不必要的 LATCH 门。我已经知道这是因为我没有在 case
声明中涵盖所有情况;但是,这些是我仅有的案例。
我应该怎么做才能修复我的 case
语句?
在 always
块的顶部,但在 case
语句之前,为 always
块中分配的所有信号设置初始值。在您的代码中,这意味着:
Result = 0;
Cout = 0;
由于组合逻辑使用阻塞分配,当您选择 4 个操作码之一时,初始值将被正确覆盖。这是完整的 always
块:
always@(*)
begin
Result = 0;
Cout = 0;
case(OPCode)
4'b0000: Result = Operand1&Operand2;
4'b0001: Result = Operand1|Operand2;
4'b0010:
begin
Result = cin ^(Operand1 ^ (Operand2 ^ cin));
Cout = ((Operand2 ^ cin) & Operand1) | ((Operand1 ^ (Operand2 ^ cin)) & cin);
end
4'b0110:
begin
Result = cin ^(Operand1 ^ (Operand2 ^ cin));
Cout = ((Operand2 ^ cin) & Operand1) | ((Operand1 ^ (Operand2 ^ cin)) & cin);
end
endcase
end
还有其他方法可以做到这一点,但这是一种常见的方法。
问题是您在逻辑中编写了锁存器。考虑以下因素:
aways @*
if(en)
a <= b;
在上面的方案中,如果en
是高电平,那么b
一变化,a
就变化。但是,如果 en
较低,即使 b
发生变化,a
也会保持其旧值。这是一个 latch 行为,综合工具识别特定模式以生成 latch。
从算法上讲,一个锁存器是从一个没有完全指定的条件语句派生的,就像上面的 if
没有 else
,其中 a
在某些情况下没有被驱动。
要表达组合逻辑,您需要确保 a
在所有情况下都被驱动。下面展示了一个简单的组合双向mux
always @*
if (en)
a = b;
else
a = c;
上面的a
是在if语句的所有分支中驱动的。顺便说一句,使用 =
或 <=
不定义类型或编码设备。但是,<=
推荐用于顺序逻辑,如锁存器,=
应用于组合设备。
确保 a
始终被驱动的另一种方法是在条件语句之前为其分配特定值,如下所示:
always @* begin
a = c;
if (en)
a = b;
end
这是一个公认的设计模式,适用于所有综合工具。
所以,你的代码和上面类似,你不在case语句的所有分支中驱动Result和Count .换句话说,您缺少 default:
。您可以将其添加为
always @*
case ...
default: begin
Result = 0;
Cout = 0;
end
endcase
...
或者您可以使用第二种方案,预先初始化并在 case 语句之前分配它们,如 toolic 的 答案。
我正在尝试在 Verilog 中构建一个 32 位 ALU。我一开始就实现了一个 1 位 ALU。 ALU 应该只有 4 个函数,而不是全部:add、sub、and、or。这是我的代码:
module ALU(
input wire [3:0] OPCode,
input wire Operand1,
input wire Operand2,
input wire cin,
output reg Result,
output reg Cout
);
always@(*)
begin
case(OPCode)
4'b0000: Result = Operand1&Operand2;
4'b0001: Result = Operand1|Operand2;
4'b0010:
begin
Result = cin ^(Operand1 ^ (Operand2 ^ cin));
Cout = ((Operand2 ^ cin) & Operand1) | ((Operand1 ^ (Operand2 ^ cin)) & cin);
end
4'b0110:
begin
Result = cin ^(Operand1 ^ (Operand2 ^ cin));
Cout = ((Operand2 ^ cin) & Operand1) | ((Operand1 ^ (Operand2 ^ cin)) & cin);
end
endcase
end
endmodule
这里的问题是它生成了不必要的 LATCH 门。我已经知道这是因为我没有在 case
声明中涵盖所有情况;但是,这些是我仅有的案例。
我应该怎么做才能修复我的 case
语句?
在 always
块的顶部,但在 case
语句之前,为 always
块中分配的所有信号设置初始值。在您的代码中,这意味着:
Result = 0;
Cout = 0;
由于组合逻辑使用阻塞分配,当您选择 4 个操作码之一时,初始值将被正确覆盖。这是完整的 always
块:
always@(*)
begin
Result = 0;
Cout = 0;
case(OPCode)
4'b0000: Result = Operand1&Operand2;
4'b0001: Result = Operand1|Operand2;
4'b0010:
begin
Result = cin ^(Operand1 ^ (Operand2 ^ cin));
Cout = ((Operand2 ^ cin) & Operand1) | ((Operand1 ^ (Operand2 ^ cin)) & cin);
end
4'b0110:
begin
Result = cin ^(Operand1 ^ (Operand2 ^ cin));
Cout = ((Operand2 ^ cin) & Operand1) | ((Operand1 ^ (Operand2 ^ cin)) & cin);
end
endcase
end
还有其他方法可以做到这一点,但这是一种常见的方法。
问题是您在逻辑中编写了锁存器。考虑以下因素:
aways @*
if(en)
a <= b;
在上面的方案中,如果en
是高电平,那么b
一变化,a
就变化。但是,如果 en
较低,即使 b
发生变化,a
也会保持其旧值。这是一个 latch 行为,综合工具识别特定模式以生成 latch。
从算法上讲,一个锁存器是从一个没有完全指定的条件语句派生的,就像上面的 if
没有 else
,其中 a
在某些情况下没有被驱动。
要表达组合逻辑,您需要确保 a
在所有情况下都被驱动。下面展示了一个简单的组合双向mux
always @*
if (en)
a = b;
else
a = c;
上面的a
是在if语句的所有分支中驱动的。顺便说一句,使用 =
或 <=
不定义类型或编码设备。但是,<=
推荐用于顺序逻辑,如锁存器,=
应用于组合设备。
确保 a
始终被驱动的另一种方法是在条件语句之前为其分配特定值,如下所示:
always @* begin
a = c;
if (en)
a = b;
end
这是一个公认的设计模式,适用于所有综合工具。
所以,你的代码和上面类似,你不在case语句的所有分支中驱动Result和Count .换句话说,您缺少 default:
。您可以将其添加为
always @*
case ...
default: begin
Result = 0;
Cout = 0;
end
endcase
...
或者您可以使用第二种方案,预先初始化并在 case 语句之前分配它们,如 toolic 的 答案。