How to remove latches in code of 1-bit ALU?

Viewed 92

I am trying to build a 32-bit ALU in Verilog. I've implemented a 1-bit ALU at the beginning. The ALU should have only 4 functions, not all of them: add, sub, and, or. This is my code:

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

The problem here is that it generates unnecessary LATCH gates. I already know it's because I'm not covering all cases in my case statement; however, these are the only cases that I have. What should I do to fix my case statement?

2 Answers

At the top of the always block, but before the case statement, set initial values to all the signals being assigned in the always block. In your code, this means:

      Result = 0;
      Cout = 0;

Since combinational logic uses blocking assignments, the initial values will be properly overwritten when one of your 4 opcodes is selected. Here is the full always block:

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    

There are other ways to do this as well, but this is a common approach.

The issue is that you coded a latch in your logic. Consider the following:

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

In the above scheme, if en is high, then a changes as soon as b changes. But, if en is low, a will keep its old value even if b changes. This is a latch behavior and synthesis tools recognize the specific pattern in order to generate latches.

Algorithmically, a latch is derived from a not fully-specified conditional statement, like the above if without else, where a is not driven in some cases.

To express a combinatorial logic, you need to make sure that a is driven in all cases. The following shows a simple combinatorial two-way mux

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

In the above a is driven in all branches of the if statement. BTW, use of = or <= does not define the type or the coded device. However, <= is recommended for sequential logic, like latches and = should be used for combinatorial devices.

The other way to make sure that a is always driven is to assign a certain value to it before the conditional statement, like here:

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

This is a well recognized design pattern which works with all synthesis tools.

So, your code is similar to the above, and you do not drive Result and Count in all branches of the case statement. In other words you are missing default:. You can add it as

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

Or you can use the second scheme with initialization upfront and assign them before the case statement, as in toolic's answer.

Related