This is part 2 of my projects called Getting Started with FPGAs. Part 1 is basically a prerequisite to this project, as it tells you have to get the Alchitry Au FPGA board and its associated software up and running.
In this project, we are only dealing with combinational logic, i.e. it's all pure static logic. We aren't dealing with clocks, counters, flip-flops, etc. We are going to build an 8 bit ALU or arithmetic logic unit. It's the place in a CPU or microcontroller where all the math and logic operations are performed. They aren't as complicated as you might think. They perform all the operations required in parallel, using simple combinational logic, and then use a multiplexer to select the desired result and present it as the output.
Building the PiecesWe could construct all of the required logic from scratch. For example, to add our two 8 bit numbers, we first need the Lucid code to build a 1- bit full-adder:
And then we could use our 1 bit full_adder module to build an 8 bit full_adder module, like this:
But HDL languages and software tools like Vivado are so powerful, we don't need to tell our software how to build an 8 bit full-adder - it already knows. If we define registers A and B as 8 bits wide, and then say: regOut = regA + regB, the software tools will build the 8 bit adder for us.
So let's start with a list of operations we want our ALU to perform:
- opcode 0 - Add A and B
- opcode 1 - Subtract B from A
- opcode 2 - AND A and B
- opcode 3 - OR A and B
- opcode 4 - XOR A and B
- opcode 5 - Shift A left
- opcode 6 - Shift A right
- opcode 7 - NOT A
- opcode 8 - Increment A
- opcode 9 - Decrement A
We need our Lucid programming language, Alchitry Labs, and Vivado to build all the hardware to do all these operations, and then we need a multiplexer, that uses the opcode to select the answer we want.
Building Our ALUAs it turns out, all of this is surprisingly easy. Here is the entire ALU module:
There is quite a bit to talk about here. These very few lines of code generate a lot of hardware logic. Each math or logic operation requires building some logic circuits capable of generating that result. And the multiplexer is another complicated piece of logic, but we are able to easily create it by using "case", which selects for us which result is output.
We have even added two additional opcodes, just for fun - multiply and divide. An actual CPU uses a sequence of smaller steps for both multiplication and division, not combinational logic. But our design tools know how to do both with combinational logic. Multiplication works pretty well, but division done this way is somewhat problematic. I didn't even know division was possible with combinational logic, until I tried it here. It does yield a good approximation for integer division, but is sometimes slightly off.
Putting It All Together in an Alchitry Labs ProjectWe are going to implement our ALU on the Alchitry Au board and use Alchitry's IO Element board to interface with it.
Let's begin by creating a new project called "eight_bit_ALU" in Achitry Labs. We need to select the Alchitry Au board, Lucid language, and from Example: the IO Element Base. Then we need to create a new Lucid source file: alu.luc, and paste our alu module code into it.
Alchitry Labs has already created our au_top file. We just need to make a couple of changes to it to connect our ALU module to the IO hardware are the IO board.
First, just below
.clk(clk) {// The reset conditioner is used to synchronize the reset signal to the FPGA// clock. This ensures the entire FPGA comes out of reset at the same time.reset_conditioner reset_cond;}
and above "always", add the line:
alu myALU; // an instance of alu
This line creates an instance of the ALU hardware module.
Now, inside the always brackets, add the lines:
myALU.opCode = io_dip[2]; // dip 2 inputs op code
myALU.regA = io_dip[0]; // dip 0 inputs reg A
myALU.regB = io_dip[1]; // dip 1 inputs reg B
io_led[1] = myALU.regOut[15-:8]; // io LEDs 1 display MSBs of output
io_led[0] = myALU.regOut[7-:8]; // io LEDs 0 display LSBs of output
These 5 lines connect the inputs of the ALU to the DIP switches on the IO board, and display the output of the ALU on the IO board's right two LED banks.
We can now build our hardware and download it to the FPGA on the Alchitry Au board.
Using the ALUWe can now use the two DIP switches on the right of the IO board to input two binary numbers, A and B, and then with the left DIP switches specify an op code. The LEDs will display the requested result, again in binary.
Our cover photo is the first example. Here it is again:
Our two inputs are 3 and 6. The opcode is 0, which says add, and the output displays 9.
Above, we have changed the opcode to 4, which selects EOR as our output The inputs are 0011 and 0110, so our EOR result is 0101.
Here A = 27 and the opcode is 5 for Shift Left. The result is 27 * 2 or 54.
And finally, above is an example of division by combinational logic. 92 / 7 = 13.14286. It has given us the correct integer answer of 13. It usually did, though I found a couple of times it was off by ± 1.
What's NextHere in Part 2, we have really been able to see the power of HDL languages and the software tools developed to help design logic circuits. They have been able to make a beginner like me actually look like I know what I am doing.
The next project will be a little more challenging. I am going to start using the 4 digit, 7 segment display on the IO board, and I am going to interface a keypad to the Alchitry Au board through the Br Prototype board. Both of these efforts will require clocks and counters, which we were able to avoid with a ALU project.
Comments
Please log in or sign up to comment.