如何删除 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语句的所有分支中驱动ResultCount .换句话说,您缺少 default:。您可以将其添加为

always @*
  case ...
   default: begin
     Result = 0;
     Cout = 0;
   end
 endcase
 ...

或者您可以使用第二种方案,预先初始化并在 case 语句之前分配它们,如 toolic 的 答案。