From VHDL Code to Real Hardware: Designing an 8-bit ALU
In this project we create an 8-bit arithmetic logic unit (ALU) in the VHDL language and run it on an Altera CPLD development board connected to a custom PCB with input switches and LED display.
Developing electronic systems using a hardware-based approach doesn’t always have to involve physically connecting various transistors and logic gates onto a breadboard or a PCB. It is possible to build an arithmetic logic unit (ALU) using discrete logic, but as logic complexity increases, there are better options. Through programmable logic devices and hardware description languages (HDL), anything from a simple circuit to a highly specialized processing unit can be implemented within a single chip.
ALU Project Overview
In this project, I will walk through the creation of the 8-bit ALU circuit with input DIP switches and output LEDs demonstrated in operation in Figure 1. I used the VHDL language to code the ALU and ran it on a Complex Programmable Logic Device (CPLD) development board. My goal was to give an introduction to programmable logic and open the door for working with real hardware rather than just diagrams and computer simulations.
Figure 1. The 8-bit ALU project in operation (GIF). Image used courtesy of Kristijan Nelkovski
For this project, I built a custom printed circuit board (PCB) with All About Circuits branding, as illustrated in Figure 2. The CPLD is a more affordable but less powerful programmable logic device than the more well-known Field Programmable Gate Array (FPGA). Both devices can be used to create custom electronic designs with dedicated inputs and outputs.
Figure 2. The completed ALU project includes a custom PCB. Image used courtesy of Kristijan Nelkovski
Internally, these CPLD and FPGA components contain arrays of reconfigurable logic blocks and come packaged as standalone ICs for embedding into your own designs. Manufacturers offer development boards for learning, testing, and experimenting using their technologies and software environments. I used a development board for my CPLD.
What Is an ALU?
At the core of every processor lies a combinational logic circuit that executes arithmetic and bitwise operations on integer binary numbers called an Arithmetic Logic Unit. The circuit that we’re going to be building in this project is an 8-bit ALU that contains two 8-bit operands (inputs), one 8-bit result (output), and a 4-bit opcode (input) that defines what operation is going to be executed (Figure 3)
Figure 3. A symbolic representation of an ALU. Image used courtesy of Jim Lamberson, Wikimedia Commons
An ALU will typically contain status bits (both as inputs and as outputs) that give important information to a processor about the last executed operation. This status info can include whether the result was zero or whether the result overflowed outside of the most significant bit (MSB). However, our circuit doesn’t need them and, as such, will not contain any.
The ALU provides an excellent starting point for learning about VHDL coding and CPLD programming operations. Once you complete this project, you can easily expand to more difficult applications.
Project Details and References
In this project, we will create an 8-bit arithmetic logic unit (ALU) in the VHDL language and run it on an Altera Max II EPM240 CPLD development board using Intel’s Quartus Prime Lite Edition software (Altera is now part of Intel). The code for this circuit is built upon lab exercise designs published by the University of California, Riverside.
Note: Although I created a “shield” type board for use in this project, everything covered here is completely breadboard and perfboard friendly.
Setting up a New Project With Quartus Prime for the Altera MAX II Dev Board
To start working on our project, we need to download and install the Quartus Prime Lite Edition and create a folder to store all of our projects. I downloaded the software from Intel’s website and created a folder called “quartus” in the “Windows Documents” directory.
When we run Quartus, the first thing we need to do is set up a new project via the “New Project Wizard,” which can be found under “File -> New Project Wizard.” Then, we need to click “Next” on the first screen called “Introduction”.
As illustrated in Figure 4, on the second screen called “Directory, Name, Top-Level Entity,” we need to select the folder we created earlier as the working directory and give the current project an adequate name. I named this project “ALU”.
Figure 4. Quartus “Directory, Name, Top-Level Entity” screen. Image used courtesy of Kristijan Nelkovski (Click image to enlarge)
For the “Project Type” screen, we need to select “Empty project” and leave the next screen called “Add Files” empty (Figure 5).
Figure 5. Quartus “Project Type” screen. Image used courtesy of Kristijan Nelkovski (Click image to enlarge)
On the “Family, Device & Board Settings” screen, we need to select “MAX II” from the drop-down menu in the “Device family” section (Figure 6). Then, from the “Available devices” section, select “EPM240T100C5”, as this is the chip onboard the Altera MAX II EPM240.
Figure 6. Quartus filled “Family, Device & Board Settings” screen. Image used courtesy of Kristijan Nelkovski (Click image to enlarge)
Next, we need to change “Verilog HDL” to “VHDL” on the “EDA Tool Settings” screen, click next, and check if everything is done correctly in the “Summary” (Figure 7). After this, we can click on the “Finish” button, and our new project will be created.
Figure 7. Quartus “EDA Tool Settings” screen. Image used courtesy of Kristijan Nelkovski (Click image to enlarge)
Once this project opens, we need to click on the name of our entity in the “Project Navigator: Hierarchy” window and create a new VHDL file by pressing “CTRL+N” and selecting “VHDL File.”
After this file opens, we have to save it as the VHDL file for our entity by going into “File -> Save As.” When all of this is done, we can start writing the code for our ALU.
Declaring the VHDL Libraries
So as with all programming languages, the first thing that we need to do at the top of the VHDL code is to declare the libraries that will be used in the project.
LIBRARY ieee; USE ieee.std_logic_1164.ALL; USE ieee.std_logic_unsigned.ALL; USE ieee.std_logic_arith.ALL;
Creating the ALU Circuit Entity
Next, we will create an ALU entity that defines all of its input and output ports. Here we have defined ports A and B as “IN STD_LOGIC_VECTOR(7 DOWNTO 0)” which means that each of these inputs is actually an 8-bit bus with its bits numbered from 7 down to 0 where the seventh bit is the MSB. Similarly, the SEL port is defined as a 4-bit input, and the RES port is defined as an 8-bit output.
ENTITY ALU IS PORT ( A : IN STD_LOGIC_VECTOR(7 DOWNTO 0); B : IN STD_LOGIC_VECTOR(7 DOWNTO 0); SEL: IN STD_LOGIC_VECTOR(3 DOWNTO 0); RES: OUT STD_LOGIC_VECTOR(7 DOWNTO 0) ); END ALU;
Creating a VHDL Behavioral Architecture of the ALU Circuit
Now we need to design the architecture or behavior of our circuit. We will create a process using the three inputs or ports A, B, and Sel.
Inside this process, we can call a “case-when” statement (similar to “switch-case” in other programming languages) where we check the state of the port SEL. The SEL value is the opcode for our ALU and determines which operation needs to be executed between the two 8-bit numbers that are received on ports A and B.
This is done within the “when XXXX =>” portions of the statement where XXXX represents the binary state of SEL (a position between 0000 and 1111). Each state is assigned to a corresponding ALU operation being executed using the values received on ports A and B. The output is written out on port RES.
After this, we can end the “case” statement, the process, and the behavioral architecture, and with that, end the code portion of our project.
ARCHITECTURE behv OF alu IS BEGIN PROCESS (A, B, Sel) BEGIN CASE Sel IS WHEN "0000" => RES <= "00000000"; -- no operation WHEN "0001" => RES <= A + B; -- addition WHEN "0010" => RES <= A + (NOT B) + 1; -- subtraction WHEN "0011" => RES <= A + 1; -- add one to operand A WHEN "0100" => RES <= A - 1; -- subtract one from operand A WHEN "0101" => RES <= A(6 DOWNTO 0) & '0'; -- shift operand A to the left WHEN "0110" => RES <= '0' & A(7 DOWNTO 1); -- shift operand A to the right WHEN "0111" => RES <= NOT A; -- one's complement of operand A WHEN "1000" => RES <= NOT A + 1; -- two's complement of operand A WHEN "1001" => RES <= A AND B; -- logical and WHEN "1010" => RES <= A OR B; -- logical or WHEN "1011" => RES <= A NAND B; -- logical nand WHEN "1100" => RES <= A NOR B; -- logical nor WHEN "1101" => RES <= A XOR B; -- logical xor WHEN "1110" => RES <= (NOT A) + (NOT B); -- random operation WHEN "1111" => RES <= (A + B) AND (A OR B); -- another random operation WHEN OTHERS => RES <= "00000000"; END CASE; END PROCESS; END behv;
In the code above, I’ve included some of the most common arithmetic and logic operations as well as some random ones, commenting on what each of them does. Here you can replace and include any arbitrary arithmetic or logic operation that you’d like!
After our code is finished, the first thing that we need to do is compile it. This can be done by going into “Processing -> Start Compilation.” If everything compiles correctly, we shouldn't get any error messages, although we’ll probably get some warnings that we can ignore.
Next, we need to connect the ports we defined earlier for our entity to physical pins located on the Altera development board. We’re going to do this through Quartus’ Pin Planner tool which is accessible through “Assignments -> Pin Planner.”
The pin planner tool contains:
- A visual representation of the chip in use (the EPM240 in this case.
- A pin legend describing each pin type.
- A table containing each individual node from our entity’s ports. Inside this table, we can connect every node to a dedicated pin by writing it out in the corresponding row of the “Location” column.
Table 1 contains my resulting pinout table.
Table 1. Quartus pin mapping table for the ALU
|ALU PORT NAME||EPM240 PIN||ALU PORT NAME||EPM240 PIN|
Uploading Code to the Altera Dev Board
Once we’ve assigned every input and output to a pin, we need to compile the code again. If no error messages pop up, we can proceed uploading it to the Altera MAX II.
In order to do so, we first have to connect the board itself to a 5 V power source through the onboard barrel jack. Next, we have to connect it to the USB Blaster via the JTAG port and then connect the USB Blaster to our computer using the mini USB jack (Figure 8).
Figure 8. Altera board and USB Blaster connections. Image used courtesy of Kristijan Nelkovski
Afterward, we can run the programmer by going into “Tools -> Programmer” and checking “Program/Configure,” as shown in Figure 9. Then we need to open “Hardware Setup” and select “USB Blaster” as our “available hardware item” (our programmer) and then click “Start” for our code to be uploaded to the Altera MAX II.
Figure 9. Quartus programmer screen. Image used courtesy of Kristijan Nelkovski (Click image to enlarge)
PCB Circuit Diagram
The schematic of Figure 10 depicts our circuit diagram. Each LED is connected to an output pin through a current-limiting resistor. Each contact from a DIP switch that is connected to an input pin is also pulled down to the ground with resistor networks (on the custom PCB, these are hidden underneath the DIP switches).
Figure 10. Circuit diagram for the custom PCB wih switch inputs and LED outputs. Image used courtesy of Kristijan Nelkovski (Click image to enlarge)
After wiring everything up and powering the Altera board with 5 V, we can see the ALU spring into action by inputting numbers on our operand ports and switching the operation mode to any operation we like. The LEDs display the result as illustrated above in Figure 1.
BOM for the ALU Project
Table 2 contains the bill of materials for this project.
Table 2. VHDL ALU bill of materials
|Altera Max II EPM240 development board and USB Blaster bundle (with a barrel jack and mini USB cable)||1||You need the main Altera board plus the USB blaster for uploading code through Quartus via JTAG.|
|LEDs||8||Here we represent each bit using an LED, so 8 bits for the ALU give us a total of 8 LEDs.|
|Resistors (R_0 to R_7)||8||Current limiting resistors for our LEDs (220 Ω to 1 kΩ).|
|DIP Switch - 8-position||2||Two 8-bit inputs for our ALU.|
|Resistor network of 8 resistors (RESISTOR NETWORK_A and RESISTOR NETWORK_B)||2||Pull-down resistor network for the 8 position switches (4.7 kΩ and up).|
|DIP Switch - 4 position||1||A 4-bit mode select input for the ALU.|
|Resistor network of 4 resistors (RESISTOR NETWORK_MODE)||1||Pull-down resistor network for the 4 position switches (4.7 kΩ and up).|
|Male-to-female jumper wires (or a custom IDC cable for the full PCB version)||30||Jumper wires from the Altera board to the breadboard or perfboard.|
In this project, we created an 8-bit ALU circuit in the VHDL language and ran it on a CPLD development board. Here, my goal was to give an introduction to programmable logic and open the door for working with FPGA components with real hardware components instead of diagrams and computer simulations.
If you duplicate this project, you can easily add additional opcodes to the VHDL operation of the ALU. You could also modify the circuit design to output and display status codes. Share your ideas or projects in the comments below!