【问题标题】:How to remove latches in code of 1-bit ALU?如何删除 1 位 ALU 代码中的锁存器?
【发布时间】:2021-11-17 18:55:43
【问题描述】:

我正在尝试在 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 语句?

【问题讨论】:

    标签: verilog


    【解决方案1】:

    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    
    

    还有其他方法可以做到这一点,但这是一种常见的方法。

    【讨论】:

      【解决方案2】:

      问题在于您在逻辑中编写了一个锁存器。考虑以下几点:

      aways @*
         if(en)
            a <= b;
      

      在上述方案中,如果en 为高电平,则a 会随着b 的变化而变化。但是,如果en 较低,即使b 发生变化,a 也会保持其旧值。这是一种闩锁行为,综合工具会识别特定模式以生成闩锁。

      从算法上讲,闩锁是从未完全指定的条件语句派生的,例如上面的if 没有else,其中a 在某些情况下不被驱动。

      要表达组合逻辑,您需要确保a 在所有情况下都被驱动。下面展示了一个简单的组合二路复用器

      always @*
         if (en)
            a = b;
         else
            a = c;
      

      在上面的a 中被驱动在if 语句的所有分支中。顺便说一句,=&lt;= 的使用不定义类型或编码设备。但是,&lt;= 推荐用于顺序逻辑,如锁存器,= 应用于组合设备。

      确保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 的 答案中所示。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多