A fully structural 32-bit CPU implemented in VHDL and synthesized for an Intel Cyclone IV E FPGA. The design uses a classic three-stage fetch–decode–execute datapath controlled by a finite-state machine, with a ripple-carry adder hierarchy built from first principles.
The CPU is composed of three top-level components instantiated inside cpu1:
Control_New— a 3-state Mealy FSM (T1/T2/T3) that decodes the instruction register and drives all register load/clear signals, MUX selects, ALU operation codes, and memory enables.data_path— the full datapath: program counter, instruction register, two general-purpose registers (A and B), an ALU, an internal data memory, and a network of MUXes connecting them via a shared data bus.reset_circuit— a power-on reset sequencer that holds the CPU in reset for one clock cycle and then assertsEnable_PDto start the control FSM.
External System Memory
│ dataIn[31:0]
▼
┌─────────────┐ data bus (32-bit)
│ DATA_MUX │◄──────────────────────────────────────┐
│ (4-to-1) │ sel: dataIn / data_mem / ALU / zero │
└──────┬──────┘ │
│ data_bus_s │
├──► IR (register32) ──► Control_New (INST) │
├──► A_Mux ──► Reg_A ──► IM_MUX1 ──► ALU ─────┘
└──► B_Mux ──► Reg_B ──► IM_MUX2 ──► ALU
PC ──► addrOut ──► External System Memory (address)
The following waveforms were captured in ModelSim during functional verification:
Reset circuit — full state sequence:
CPU FSM cycling through fetch → decode → execute → writeback states after reset
Reset circuit — zoomed timing:
Detailed timing showing register writes and PC increment per instruction
cpu1
├── reset_circuit
├── Control_New (3-state FSM, no sub-modules)
└── data_path
├── IR [register32]
├── PC0 [pc]
│ ├── addd [add] — increments PC by 1
│ ├── mux0 [mux2to1] — selects branch target or PC+1
│ └── reg32 [register32]
├── LZE_PC / LZE_A_Mux / LZE_B_Mux / LZE_IM_MUX2 [LZE] — lower-16 zero-extend
├── UZE_IM_MUX1 [UZE] — upper-16 zero-extend (for LUI)
├── RED_Data_Mem [RED] — extracts lower 8 bits as memory address
├── A_Mux0 [mux2to1] — data bus vs. immediate operand for Reg A
├── B_Mux0 [mux2to1] — data bus vs. immediate operand for Reg B
├── Reg_A [register32] — 32-bit accumulator A
├── Reg_B [register32] — 32-bit accumulator B
├── Reg_Mux0 [mux2to1] — selects A or B for memory write
├── Data_Mem0 [data_mem] — 256 × 32-bit synchronous RAM
├── IM_MUX1a [mux2to1] — ALU A-operand: Reg_A vs. immediate
├── IM_MUX2a [mux4to1] — ALU B-operand: Reg_B / immediate / 1 / 0
├── ALU0 [alu] — 8-operation 32-bit ALU
│ ├── add0 [adder32] — addition path
│ │ ├── stage0 [adder16]
│ │ │ └── 4× [adder4] — 4-bit ripple-carry adder (leaf cell)
│ │ └── stage1 [adder16]
│ └── sub0 [adder32] — subtraction path (NOT b + carry)
└── DATA_MUX0 [mux4to1] — selects result back onto data bus
The CPU supports 26 instructions encoded in a 32-bit word. The top 4 bits form the primary opcode; a subset use an 8-bit extended opcode in bits [31:24].
| Opcode | Mnemonic | Operation |
|---|---|---|
| 0000 | LDAI | Load immediate into A (lower 16 bits of IR, zero-extended) |
| 0001 | LDBI | Load immediate into B |
| 0010 | STA | Store A to data memory at address in IR[7:0] |
| 0011 | STB | Store B to data memory |
| 0100 | LUI | Load upper immediate into A (IR[15:0] shifted to upper half) |
| 0101 | JUMP | Unconditional branch (load PC from IR lower bits) |
| 0110 | BEQ | Branch if zero flag set |
| 1000 | BNE | Branch if zero flag clear |
| 1001 | LDA | Load A from data memory |
| 1010 | LDB | Load B from data memory |
| 0111 0000 | ADD | A ← A + B |
| 0111 0001 | ADDI | A ← A + immediate |
| 0111 0010 | SUB | A ← A − B |
| 0111 0011 | INCA | A ← A + 1 |
| 0111 0100 | ROL | A ← rotate A left by 1 |
| 0111 0101 | CLRA | Clear A |
| 0111 0110 | CLRB | Clear B |
| 0111 0111 | CLRC | Clear carry flag |
| 0111 1000 | CLRZ | Clear zero flag |
| 0111 1001 | ANDI | A ← A AND immediate |
| 0111 1010 | TSTZ | Skip next instruction if Z=1 |
| 0111 1011 | AND | A ← A AND B |
| 0111 1100 | TSTC | Skip next instruction if C=1 |
| 0111 1101 | ORI | A ← A OR immediate |
| 0111 1110 | DECA | A ← A − 1 |
| 0111 1111 | ROR | A ← rotate A right by 1 |
ALU_op |
Operation |
|---|---|
| 000 | AND |
| 001 | OR |
| 010 | ADD (via adder32) |
| 100 | Rotate Left (ROL) |
| 101 | Rotate Right (ROR) |
| 110 | Subtract (via adder32 with NOT b) |
| Port | Dir | Width | Description |
|---|---|---|---|
clk |
in | 1 | CPU clock |
mem_clk |
in | 1 | Memory clock (falling-edge triggered data_mem) |
rst |
in | 1 | Asynchronous reset |
dataIn |
in | 32 | Instruction/data from external system memory |
addrOut |
out | 32 | Program counter → memory address bus |
dataOut |
out | 32 | Internal data bus output |
dOutA / dOutB |
out | 32 | Register A / B debug outputs |
dOutIR |
out | 32 | Instruction register debug output |
dOutPC |
out | 32 | Program counter debug output |
dOutC / dOutZ |
out | 1 | Carry / zero flag debug outputs |
outT |
out | 3 | FSM state (one-hot: 001=T1, 010=T2, 100=T3) |
wen_mem / en_mem |
out | 1 | Write-enable / enable for internal data memory |
| File | Description |
|---|---|
cpu1.vhd |
Top-level entity — instantiates data_path, Control_New, reset_circuit |
data_path.vhd |
Full datapath structural implementation |
Control_New.vhd |
3-state instruction decoder FSM |
control.vhd |
Earlier version of the control unit (reference) |
alu.vhd |
8-operation ALU using adder32 |
adder32.vhd |
32-bit ripple-carry adder (2× adder16) |
adder16.vhd |
16-bit adder (4× adder4) |
adder4.vhd |
4-bit ripple-carry adder (4× fulladd) |
fulladd.vhd |
1-bit full adder (leaf cell) |
pc.vhd |
Program counter (register32 + add + mux2to1) |
register32.vhd |
32-bit D flip-flop register with synchronous load and clear |
mux2to1.vhd |
32-bit 2-to-1 MUX |
mux4to1.vhd |
32-bit 4-to-1 MUX |
LZE.vhd |
Lower zero-extend: zeros & IR[15:0] |
UZE.vhd |
Upper zero-extend: IR[15:0] & zeros |
RED.vhd |
Reduce to 8 bits: IR[7:0] |
data_mem.vhd |
256 × 32-bit synchronous RAM |
system_memory.vhd |
64 × 32-bit Altera altsyncram (instruction memory) |
add.vhd |
PC increment adder (+1) |
cpu_test_sim.vhd |
Simulation testbench |
Prerequisites: Intel Quartus Prime Lite (≥ 21.1) + ModelSim-Intel FPGA Edition
1. Open `src/Lab6.qpf` in Quartus Prime
2. Compile: Processing → Start Compilation
3. Simulate: Launch ModelSim via Tools → Run Simulation Tool → RTL Simulation
4. Program board: Programmer → Add .sof file → Start
(DE2-115 or compatible Cyclone IV E board)
Pin assignments are in the .qsf file.
- Multi-cycle FSM control (not pipelined) — a 3-state Mealy FSM (T1/T2/T3) drives all control signals; simpler hazard handling at the cost of throughput (one instruction per 3 cycles minimum).
- Accumulator-style architecture with 32-bit registers A and B — limits instruction-level parallelism but maps cleanly to a small register file and straightforward ISA encoding.
- Ripple-carry adder hierarchy — cascades 8 × 4-bit adders through 2 × 16-bit stages to reach 32 bits; convenient structural hierarchy but creates a long carry chain on the critical path, limiting Fmax.
- Harvard-style separate instruction/data memory —
system_memoryholds instructions (Altera altsyncram),data_memholds data (256 × 32-bit synchronous RAM); eliminates structural hazards between fetch and memory-access stages. - Single-clock FSM simplifies hazard handling at the cost of throughput — no forwarding logic or stall detection is needed since each state completes one micro-operation before advancing.
- Replace the ripple-carry adder with a carry-lookahead adder to cut the critical path and raise Fmax.
- Add a 5-stage pipeline (IF/ID/EX/MEM/WB) with operand forwarding and hazard detection to increase instruction throughput.
- Implement a branch predictor (start with static predict-not-taken) to reduce branch penalty in the pipelined version.
- Extend the ISA with multiply and divide instructions (currently absent from the 26-instruction set).
- Add a cache hierarchy (L1 I-cache + D-cache) in front of main memory to reduce average memory access latency.
VHDL · ISA design · multi-cycle control FSM · datapath design · ripple-carry adder · Quartus Prime · ModelSim · structural hierarchy · Cyclone IV E FPGA
MIT License — see LICENSE for details.