A fully functional 8-bit CPU designed and simulated in Verilog from scratch. Implements the complete fetch-decode-execute cycle with a custom instruction set, ALU, register file, RAM, and control unit — all simulated using Icarus Verilog and EPWave on EDA Playground.
The CPU is built from 4 modules wired together: RAM → IR → Control Unit → control signals ↓ B Reg → ALU → A Reg ↓ Output
| Module | Description |
|---|---|
| ALU | Performs ADD, SUB, AND, OR operations |
| Registers | Holds A, B, PC, IR values |
| RAM | 16x8-bit memory storing program and data |
| Control Unit | Decodes instructions and drives control signals |
| Instruction | Opcode (4-bit) | Description |
|---|---|---|
| LDA | 0001 | Load value from memory address into A register |
| ADD | 0010 | Add value from memory address to A register |
| SUB | 0011 | Subtract value from memory address from A register |
| OUT | 1110 | Output current value of A register |
| HLT | 1111 | Halt the CPU |
Each instruction is 8 bits — top 4 bits are the opcode, bottom 4 bits are the memory address.
Example: 00010101 = LDA 5 (load value at address 5 into A)
Every instruction goes through 3 clock cycles: Cycle 1 — FETCH : Load instruction from RAM[PC] into IR, increment PC Cycle 2 — DECODE : Control unit reads opcode from IR Cycle 3 — EXECUTE : Perform the operation (ADD takes an extra cycle)
- Inputs: 8-bit A, 8-bit B, 3-bit operation select
- Outputs: 8-bit result, zero flag
- Operations: ADD (000), SUB (001), AND (010), OR (011)
- Combinational logic — result updates instantly on input change
- A register — accumulator, holds main working value
- B register — holds second operand for ALU
- PC (Program Counter) — tracks next instruction address, can increment or load
- IR (Instruction Register) — holds current instruction being executed
- All registers are clock-driven (update on rising clock edge)
- Synchronous reset clears all registers to 0
- 16 memory locations, each 8 bits wide
- Address space: 0x0 to 0xF
- Read is combinational (instant)
- Write is sequential (on clock edge, when write enable is high)
- Program is preloaded at startup using initial block
- Reads opcode from top 4 bits of IR
- Generates all control signals: load_a, load_b, load_ir, inc_pc, alu_sel, halt
- Tracks current step (fetch/decode/execute) using internal step counter
- ADD and SUB use an extra execute cycle to correctly stage B load then ALU result
The following program is preloaded into RAM and executed by the CPU: Address 0: 00010101 → LDA 5 (load value at address 5 into A) Address 1: 00100110 → ADD 6 (add value at address 6 to A) Address 2: 11100000 → OUT (output A register) Address 3: 11110000 → HLT (halt CPU) Address 5: 00001110 → data: 14 Address 6: 00001010 → data: 10
Expected execution: LDA 5 → A = 14 ADD 6 → A = 14 + 10 = 24 OUT → Output = 24 HLT → CPU stopped
--- CPU Starting ---
Program: LDA 5, ADD 6, OUT, HLT
Expected: 14 + 10 = 24
--------------------
cycle=0 | PC=0 | IR=00000000 | A=0 | out=0 | halt=0
cycle=1 | PC=1 | IR=00010101 | A=0 | out=0 | halt=0
cycle=2 | PC=1 | IR=00010101 | A=0 | out=0 | halt=0
cycle=3 | PC=1 | IR=00010101 | A=14 | out=0 | halt=0
cycle=4 | PC=2 | IR=00100110 | A=14 | out=14 | halt=0
cycle=5 | PC=2 | IR=00100110 | A=14 | out=14 | halt=0
cycle=6 | PC=2 | IR=00100110 | A=14 | out=14 | halt=0
cycle=7 | PC=2 | IR=00100110 | A=24 | out=14 | halt=0
cycle=8 | PC=3 | IR=11100000 | A=24 | out=24 | halt=0
cycle=9 | PC=3 | IR=11100000 | A=24 | out=24 | halt=0
cycle=10 | PC=3 | IR=11100000 | A=24 | out=24 | halt=0
cycle=11 | PC=4 | IR=11110000 | A=24 | out=24 | halt=0
cycle=12 | PC=4 | IR=11110000 | A=24 | out=24 | halt=1
--------------------
CPU HALTED!
Final Output = 24
| Tool | Purpose |
|---|---|
| EDA Playground | Online Verilog IDE |
| Icarus Verilog 12.0 | Verilog compiler and simulator |
| EPWave | Online waveform viewer |
| VS Code | Local code editor |
| Git + GitHub | Version control |
8bit-cpu/
├── alu.v # ALU module
├── alu_tb.v # ALU testbench
├── registers.v # Register file module
├── registers_tb.v # Register file testbench
├── ram.v # RAM module
├── ram_tb.v # RAM testbench
├── control_unit.v # Control unit module
├── control_unit_tb.v # Control unit testbench
├── cpu.v # Top-level CPU module
├── cpu_tb.v # Top-level CPU testbench
└── README.md # This file
- Go to edaplayground.com
- Paste design file in left box
- Paste testbench in right box
- Select Icarus Verilog 12.0, enable EPWave
- Hit Run
# Install tools
sudo apt install iverilog gtkwave
# Compile and simulate
iverilog -o cpu_sim cpu.v cpu_tb.v
vvp cpu_sim
# View waveform
gtkwave dump.vcd- Verilog HDL and hardware description
- CPU architecture and datapath design
- Fetch-decode-execute pipeline
- Combinational vs sequential logic
- Control unit and FSM design
- ALU design and operation
- Memory addressing and RAM interfacing
- Clock-driven register updates
- Hardware simulation and waveform analysis
Muniem Amjad Computer Engineering Student