Overview of the Project
A basic CPU implementation, designed in Verilog. The CPU has enough opcodes to allow for the execution of pretty much any algorithm.
The CPU has three states that it will cycle through for each instruction. To make programming more practical, I also created a custom assembly language with a Python parser that converts the assembly code into 16-bit machine code for the CPU to execute.
This is my final project for Digital System Design (ELEC 4200), and is on GitHub
Software Used for Development
- Xilinx Vivado for Verilog RTL design and simulation
- Python for the custom assembly language parser
Features
Architecture
- 32-bit registers
- 16-bit instruction width
- 16 general-purpose registers
The block diagram of the CPU is shown below:
Opcodes
With only these opcodes, almost any algorithm can be executed.
Limitations
- Maximum program size is 256 lines
LOAD
instruction can only input 8-bit values (despite 32-bit registers)
CPU States
The CPU cycles through three states:
FETCH: The current_instruction
register is set, based on the program counter.
EXECUTE: The current instruction is executed. This is basically a case
statement that executes based on the opcode.
UPDATE: This state increments the program counter and sets outputs (such as 7-segment display).
This means it takes 3 clock cycles per instruction. This could probably be optimized through pipelining.
Custom Assembly Langauge
The CPU takes in 16-bit instructions. The first bits, 15-13, are the opcode.
To make programming the CPU easier, I made a Python script to parse the assembly language to machine code:
This program will output the fibonacci sequence.
Registers 0 and 1 hold the numbers to be added together. We can see these registers advance through the fibonacci sequence. This program will loop forever.
ALU
The ALU is a separate module that is instantiated by the CPU:
The ALU has many modes:
- Addition
- Subtraction
- Multiplication
And logic operations: - Equals
I'm going to add more ALU modes later
The ALU can be interfaced with assembly code:
The output can then be saved to a register:
After these two assembly lines, the sum of registers 0 and 1 will be saved to register 4.
FPGA Integration
For the final project, I also am required to run this CPU on hardware. Testing the CPU operation on the FPGA required significant debugging due to how Vivado synthesizes and implements Verilog code. One major challenge was configuring the 7-segment display clock. The display cycles through digits rapidly to appear continuously lit, which required creating a separate clock divider to control the switching speed.
Vivado's synthesis process initially caused unexpected issues with the display's operation. After resolving these, the CPU worked flawlessly, successfully running programs like a counter, the Fibonacci sequence, and addition using switch inputs. Below, the 7-segment display shows the 11th Fibonacci number, 55, as proof of the working design.
Final Project Report
The final project required a report to summarize my work.