Introduction

An arithmetic and logic unit (ALU) is a combinational circuit that performs various Boolean and arithmetic operations on a pair of n-bit operands. In this homework, you will create a 32-bit ALU that can perform the operations of most MIPS arithmetic and logical instructions.

Design

We will start by constructing a 1-bit ALU and then create the desired 32-bit ALU by connecting 32 1-bit ALUs. As Figure 1 shows, a 1-bit ALU can be constructed using a full-adder, two multiplexors and a few gates. The two 1-bit data inputs are named a and b, and the 1-bit output is named Result. This ALU can perform addition, subtraction, AND, OR on the two data inputs according to an operation code supplied to the ALU. The two-bit control input named Operation partially specifies the operation code. Figure 2 specifies the functionality of this ALU.

Figure 1: A 1-bit ALU.

Operation Binvert CarryIn Result Function

00 0 X a AND b Logical AND
01 0 X a OR b Logical OR
10 0 0 a + b Addition
10 1 1 a - b Subtraction
11 1 1 Less Sets on less than

Figure 2: The functionality of the ALU.

In Figure 2, X means don't care, + means arithmetic addition, and - means arithmetic subtraction. Note that the four-input multiplexor on the right in Figure 1 has its 2-bit select input connected to the Operation line. The output of this multiplexer is the 1-bit output of the ALU named Result. Recall that subtracting b from a is the same as adding the 2's complement of b to a. The two-input multiplexor on the left selects b or its inverted value, depending on the 1-bit select input named Binvert. This input is set to 0 for addition, AND, and OR, and set to 1 for subtraction. The CarryIn input is set to 0 for addition and set to 1 for subtraction.
The design of the ALU is incomplete. You will extend the design in a later lab so that more instructions can be performed by the ALU. For example, the input Less will be used to support the MIPS set on less than instruction (slt).


VHDL code

We start by specifying the entity declaration for the 1-bit ALU:

library ieee;
use ieee.std_logic_1164.all;
entity ALU1 is
port (a, b, Less, CarryIn, Binvert: in std_logic;
Operation: in std_logic_vector (1 downto 0);
Result, CarryOut: out std_logic);
end ALU1;

Figure 3: Entity declaration for 1-bit ALU.

The input port Operation is declared to be of the predefined type std_logic_vector. This type provides an easy way to declare a signal to be a group or string of conceptually related bits, more commonly called a bit vector. The declaration defines Operation as a 2-bit std_logic_vector signal with a descending index range 1 downto 0. Individual bits of Operation can then be accessed by the indexed named notations, Operation(1) and Operation(0), with the highest index used for the most-significant bit.
We can define the architecture for the 1-bit ALU as the interconnection of the building blocks shown in Figure 1. In the previous homework, you already wrote the code for a full-adder entity named full_adder. (You may need to modify the full_adder code to use the gate library given in this homework, but let’s worry about this after we finish the whole thing.) We will use this full_adder entity as a component within the architecture of ALU1. The other components needed are a two-input multiplexer and a four-input multiplexer. One way to model a multiplexer at the behavioral level is with a VHDL statement known as selected signal assignment. A selected signal assignment allows a signal to be assigned one of several values, based on a selection criteria. (This statement operates very much like a case statement in conventional programming languages.) Figure 4 shows how it can be used to describe a 4-to-1 multiplexer. The entity is called mux4to1. The data inputs to the mux4to1 entity are the 1-bit signals named I0, I1, I2 and I3, and the select inputs are the two-bit signal named S. The output is named f. The selected signal assignment begins with the keyword with and specifies that S is to be used for the selection criterion. The four when clauses set f to the value of one of the inputs I0, ..., I3, depending on the value of S. Note that VHDL requires that multibit values such as "01" be enclosed in double quotes and bit values such as '0' and '1' be enclosed in single quotes.

library ieee;
use ieee.std_logic_1164.all;
entity mux4to1 is
port (I0, I1, I2, I3: in std_logic;
S: in std_logic_vector (1 downto 0);
f: out std_logic);
end mux4to1;

architecture behavioral of mux4to1 is
begin
with S select
f <= I0 when "00",
I1 when "01",
I2 when "10",
I3 when others;
end behavioral;

Figure 4: VHDL code for a 4-to-1 multiplexer.

Once we have completed the 1-bit ALU, the full 32-bit ALU can be constructed from 32 1-bit ALUs as shown in Figure 5.

Figure 5: A 32-bit ALU.

To write the VHDL code for the 32-bit ALU, we first declare the 32-bit ALU as an entity. Since the data inputs and the result output are 32 bits wide, we declare them as std_logic_vectors, which are dimensioned 31 downto 0.

library ieee;
use ieee.std_logic_1164.all;
entity ALU32 is
port (a, b: in std_logic_vector (31 downto 0);
CarryIn, Binvert: in std_logic;
Operation: in std_logic_vector (1 downto 0);
Result: out std_logic_vector (31 downto 0);
CarryOut: out std_logic);
end ALU32;

Figure 6: Entity declaration for 32-bit ALU.

One approach to specifying the architecture for the 32-bit ALU is to include a component declaration for the ALU1 entity and instantiate 32 copies of the ALU1 subcircuit. One would expect that it could be written in a more compact form using a loop. VHDL provides a feature called the for generate statement for describing regularly structured hierarchical code. Fig. 7 shows the architecture for the ALU32 entity written using a for generate statement.

architecture structural of ALU32 is
component ALU1 is
port (a, b, Less, CarryIn, Binvert: in std_logic;
Operation: in std_logic_vector (1 downto 0);
Result, CarryOut: out std_logic);
end component;

signal c: std_logic_vector (30 downto 0);
signal Less: std_logic;
begin
Less <= '0';
A1: ALU1 port map (a(0), b(0), Less, CarryIn, Binvert, Operation, Result(0), c(0));
G1: for i in 1 to 30 generate
ALUs: ALU1 port map (
a(i), b(i), Less, c(i - 1), Binvert, Operation, Result(i), c(i));
end generate;
A32: ALU1 port map (a(31), b(31), Less, c(30), Binvert, Operation, Result(31), CarryOut);
end structural;

Figure 7: Architecture for the 32-bit ALU .


What you need to do

  1. create a file using the name “ALU32.vhd”. All the entities and architectures you write will be in this one single file.
  2. For component 4-to-1 multiplexer, you can type (or paste) the code in Figure 4.
  3. Write VHDL code for a 2-to-1 multiplexer, which will be very similar to 4-to-1 multiplexer.
  4. For component 1-bit ALU, type (or paste) the entity declaration for the 1-bit ALU entity given in Figure 3. Write the architecture code for this entity. Remember that you need to include three components (1-bit full_adder, 4-to-1 multiplexer, 2-to-1 multiplexer) and some gates in this architecture.
  5. The entity and architecture for ALU32 are given above. You can just type (or paste) the code in Figures 6 and 7.


Useful Tips

·  As soon as you finish coding the entity/architecture for one small component, compile the file. Do not finish coding all at once, and try to compile the big file.

·  Similarly, you need to simulate/debug your vhdl file one step a time. Say, you can debug after you finish coding one-bit full-adder, one-bit ALU, and 32-bit ALU respectively.

·  How to debug your VHDL program?

  1. Write the VHDL code first
  2. Calculate when the outputs will settle based on your design.
  3. Change your inputs (note that your inputs cannot change faster than the time you calculated from step 2), and observe the waveform of the outputs. Then verify your outputs from the simulation by comparing them with the results calculated by hand.