EECS 31L EX-601 Arithmetic Logic Unit (ALU)

Part A: Behavioral Modeling

Someone wrote the following code claiming that it is the next generation of 16-bit adders where we just don’t care about carry bits anymore.

module adder_16bit (
  input [15:0] A,  input [15:0] B,  output [15:0] Y
  );
   assign Y = A + B;
endmodule

Q1. Rewrite the above module using behavioral modeling.

Solution:

module adder_16bit (
  input [15:0] A, input [15:0] B, output reg [15:0] Y
  );
  always @(*) begin
    Y = A + B;
  end
endmodule

Q2. True or False: The original module models a combinational circuit, and the behavioral version can still model a combinational circuit.
Solution: True; the always @(*) block can model combinational logic circuits like the adder in this exercise.

Q3. True or False: The bit width of the output Y is 16 or 17, depending on the actual values of A and B.
Solution: False — The output width is fixed at 16 bits by the port declaration, regardless of the actual values of A and B.

Q4. Suppose that the instructor has asked to use your code to instantiate an adder in his own ALU module. but he can’t make up his mind about the bit width of the adder ports. Now it is 16 bits. Tomorrow it is 32 bits. Rewrite the module header so that the instructor can set the number of bits N to whatever value he wants when instantiating adder_Nbit. Rename the module to adder_Nbit, obviously.

Solution:

module adder_Nbit #(parameter N = 16) (input [N-1:0] A, input [N-1:0] B, output [N-1:0] Y);
  assign Y = A + B;
endmodule

It is important to remember the correct syntax:

module MODULE_NAME #(parameter PARAM_NAME = DEFAULT_VALUE) ( PORT_LIST );

Part B: The ALU and You

Q5. True or False: In a typical combinational ALU, the logic circuit for each operation continuously computes its result regardless of the ALU control signal values.
Solution: True; they are all combinational circuits, they do compute their results continuously. The multiplexer at the very end selects which results to show.

Q6. True or False: In a typical combinational ALU, some operations may have a different number of operands than others.
Solution: True; for example, a NOT operation has only one operand while an ADD has two.

Q7. True or False: In a typical combinational ALU, a decoder selects the output of exactly one operation to be the ALU output.
Solution: False; a multiplexer (MUX), not a decoder, selects the output.

Q8. True or False: An ALU with 5-bit opcode can still support 6 operations.
Solution: True; a 5-bit opcode can encode up to 32 operations, and 6 is less than 32 if I recall correctly.

Q9. True or False: In a typical combinational ALU, its output may depend on both the value of its input operands and the value of the opcode.
Solution: True; operands determine the result of each operation, and the opcode determines which one of those results to output.


Part C: ALU Design

Alleged ALU design

Alleged ALU design

Based on the above design, answer the following questions:

Q10. Write down the opcode values in binary for each of the 5 operations.
Solution:
From the figure, we can tell that the opcode is a 4-bit value. The opcode value for an operation is the index of the MUX input line that is connected to the output of that operation.

- Opcode for ADD: 0010 (2 in decimal)
- Opcode for SUB: 0110 (6 in decimal)
- Opcode for MUL: 1000 (8 in decimal)
- Opcode for DIV: 1001 (9 in decimal)
- Opcode for PAR: 1010 (10 in decimal)

Q11. Using behavioral modeling, write a Verilog module for the ALU shown above. The following are the specifications:

Solution:

module alu #(parameter N = 16) ( // module name, parameter name and default value
  input  [N-1:0]  A,    // N-bit input has a range of [N-1:0]
  input  [N-1:0]  B,    // Same
  input  [3:0]    Op,   // From Q10
  output reg [N-1:0] Y, // N-bit output
  output Z,  // flags are single-bit outputs
  output NF  // I realized that the name "N" was already taken by the parameter,
             // so we have to use a different name... my bad.
);

  always @(*) begin
    case (Op)  // Case statements don't need a begin-end block
      4'b0010 : Y = A + B; // If Op=2, perform addition
      4'b0110 : Y = A - B; // etc.
      4'b1000 : Y = A * B; // s a m e
      4'b1001 : Y = A / B; // s  a  m  e
      4'b1010 : Y = ^{A, B}; // Don't forget: XOR "^" returns 1 if the total number of 1's is odd
      default: Y = {N{1'b0}};
    endcase
  end

  // Assign flag values
  assign Z  = (Y == 0); // Straightforward
  assign NF = Y[N-1];   // MSB of Y is at index N-1

endmodule // over and out