A modular, multi-cycle, accumulator-based RISC processor implemented in Verilog HDL for computer architecture education and digital system design.
This repository contains a complete RTL implementation of a simple accumulator-based Reduced Instruction Set Computer (RISC) processor written in synthesizable Verilog HDL.
The project is designed for education and experimentation. It demonstrates:
- processor organization and RTL design;
- separation of datapath and control logic;
- multi-cycle instruction execution;
- finite-state-machine control;
- unified instruction and data memory;
- module-level and CPU integration verification;
- waveform-based debugging and architectural analysis.
The design prioritizes readability, modularity, and ease of extension rather than performance. Each hardware component is implemented as an independent RTL module.
- 8-bit accumulator-based datapath
- 8-bit instructions with a 3-bit opcode and 5-bit operand
- 32-address unified program and data memory
- Eight native instructions
- Multi-cycle finite-state-machine controller
- Modular and synthesizable Verilog RTL
- Automated regression and CPU integration tests
- VCD waveform generation for GTKWave
- Vivado RTL elaboration and synthesis support
| Feature | Description |
|---|---|
| Architecture | Accumulator-based RISC |
| Datapath width | 8 bits |
| Instruction width | 8 bits |
| Opcode width | 3 bits |
| Operand width | 5 bits |
| Address space | 32 memory locations |
| Memory organization | Unified program/data memory |
| Controller | Finite-state machine |
| Execution model | Multi-cycle |
| RTL language | Verilog HDL |
| Primary simulator | Icarus Verilog |
The processor consists of a compact datapath and a finite-state-machine controller. Because the architecture is accumulator-based, arithmetic and logical operations use a single general-purpose register: the accumulator (AC).
flowchart LR
PC[Program Counter]
IR[Instruction Register]
MUX[Address Multiplexer]
MEM[Unified Memory]
BUS[8-bit Data Bus]
AC[Accumulator]
ALU[Arithmetic Logic Unit]
CTRL[Controller FSM]
PC --> MUX
IR --> MUX
MUX --> MEM
MEM --> BUS
BUS --> IR
BUS --> ALU
AC --> ALU
ALU --> AC
CTRL --> PC
CTRL --> IR
CTRL --> MEM
CTRL --> AC
CTRL --> MUX
The controller coordinates memory access, register updates, ALU operations, and program-counter changes over multiple clock cycles.
Elaborated RTL schematic showing the program counter, instruction register, address multiplexer, accumulator, ALU, unified memory, and FSM controller.
Each instruction occupies one byte:
+-------------+----------------+
| Opcode (3) | Operand (5) |
+-------------+----------------+
7 5 4 0
- Opcode identifies the operation.
- Operand represents a memory address or jump destination.
| Opcode | Mnemonic | Operation |
|---|---|---|
000 |
HLT |
Stop processor execution |
001 |
SKZ |
Skip the next instruction when AC == 0 |
010 |
ADD addr |
AC ← AC + MEM[addr] |
011 |
AND addr |
AC ← AC AND MEM[addr] |
100 |
XOR addr |
AC ← AC XOR MEM[addr] |
101 |
LDA addr |
AC ← MEM[addr] |
110 |
STO addr |
MEM[addr] ← AC |
111 |
JMP addr |
PC ← addr |
Instructions are executed over multiple clock cycles so that datapath resources can be reused. A typical instruction passes through some or all of the following stages:
Instruction Address
│
▼
Instruction Fetch
│
▼
Instruction Load
│
▼
Decode / Idle
│
▼
Operand Address
│
▼
Operand Fetch
│
▼
Execute
│
▼
Write Back
The controller selects only the states required by the current instruction.
| State | Purpose |
|---|---|
INST_ADDR |
Select the instruction address |
INST_FETCH |
Read instruction memory |
INST_LOAD |
Load the instruction register |
IDLE |
Decode the current instruction |
OP_ADDR |
Select the operand address |
OP_FETCH |
Read the operand |
ALU_OP |
Execute an arithmetic, logical, or control operation |
STORE |
Write a result to memory |
| Signal | Description |
|---|---|
rd |
Memory read enable |
wr |
Memory write enable |
ld_ir |
Load the instruction register |
ld_ac |
Load the accumulator |
ld_pc |
Load the program counter |
inc_pc |
Increment the program counter |
sel |
Select the memory address source |
data_e |
Enable data-bus output |
| Module | Responsibility |
|---|---|
CPU.v |
Top-level processor and module integration |
Controller.v |
FSM sequencing and control-signal generation |
ALU.v |
Arithmetic and logical operations |
Memory.v |
Unified instruction and data memory |
PC.v |
Program counter |
IR.v |
Instruction register |
AC.v |
Accumulator register |
The top-level module connects the datapath and controller. It selects memory addresses, routes the shared data bus, forwards control signals, and coordinates complete instruction execution.
The controller sequences instruction states and generates the signals required for memory access, register loading, ALU operation, and program-counter updates.
The ALU supports:
- addition;
- bitwise AND;
- bitwise XOR;
- accumulator loading.
It also produces the zero condition used by SKZ.
The unified memory stores both instructions and data.
- 32 addressable locations
- 8-bit data width
- asynchronous read
- synchronous write
The program counter stores the address of the next instruction and supports:
- increment;
- loading a jump destination;
- synchronous reset.
The instruction register holds the current instruction so that its opcode and operand remain stable during execution.
The accumulator is the processor's only general-purpose register. It can load an ALU result, retain its current value, or reset synchronously.
A compact, accumulator-based RISC processor implemented in Verilog HDL. The design demonstrates the core principles of CPU organization, including instruction fetch, instruction decode, arithmetic and logic execution, memory access, program-counter control, and finite-state-machine-based control.
This repository contains the RTL source code, module-level testbenches, CPU integration testbenches, a Python-based simulation runner, waveform-oriented verification assets, and a LaTeX project report.
- Overview
- Architecture
- Instruction Set
- Repository Structure
- Modules
- Requirements
- Getting Started
- Running Tests
- Waveform Simulation
- Verification Coverage
- Documentation
- Limitations
- License
The processor uses an 8-bit instruction format composed of a 3-bit opcode and a 5-bit operand field. This format supports eight instructions and provides access to a 32-location memory space. The datapath is built around an 8-bit accumulator register, an 8-bit bidirectional data bus, a 5-bit program counter, and a 32 × 8-bit memory.
The CPU operates synchronously with a clock signal and an active-high reset signal. Program execution continues until the HLT instruction is decoded and the controller asserts the halt signal.
Key characteristics:
- 8-bit instruction width
- 3-bit opcode and 5-bit operand
- 8 supported instructions
- 32-address memory space
- 8-bit accumulator-based datapath
- Multi-cycle instruction execution
- 8-state controller finite state machine
- Modular RTL implementation
- Unit and integration testbenches
- Automated simulation runner for Icarus Verilog and Vivado Simulator
The top-level processor is implemented in src/CPU.v and integrates the following components:
+----------------+
| Controller |
+----------------+
| control signals
v
+------+ +-------------+ +----------+
| PC | --> | Address MUX | --> | Memory |
+------+ +-------------+ +----------+
^ |
| v
+----------------+
| Instruction IR |
+----------------+
| opcode / operand
v
+--------------+ +------+ +------------+
| Accumulator | --> | ALU | --> | Accumulator|
+--------------+ +------+ +------------+
The CPU execution flow is divided into two main phases:
-
Instruction Fetch Phase
INST_ADDRINST_FETCHINST_LOADIDLE
-
Execution Phase
OP_ADDROP_FETCHALU_OPSTORE
A standard instruction is executed over these eight controller states. Control-flow instructions such as SKZ, JMP, and HLT update the program counter or halt state according to the opcode and ALU zero flag.
| Opcode | Mnemonic | Description | ALU Output |
|---|---|---|---|
000 |
HLT |
Halt processor execution | inA |
001 |
SKZ |
Skip next instruction when the accumulator is zero | inA |
010 |
ADD |
Add memory operand to accumulator | inA + inB |
011 |
AND |
Bitwise AND between accumulator and memory operand | inA & inB |
100 |
XOR |
Bitwise XOR between accumulator and memory operand | inA ^ inB |
101 |
LDA |
Load memory operand into accumulator | inB |
110 |
STO |
Store accumulator value into memory | inA |
111 |
JMP |
Jump to operand address | inA |
Instruction format:
bit[7:5] opcode
bit[4:0] operand / address
Example program:
LDA 20 ; AC <- MEM[20]
ADD 21 ; AC <- AC + MEM[21]
STO 22 ; MEM[22] <- AC
HLT ; Stop executionVerilog-Simple-Risc-Processor/
├── src/
│ ├── CPU.v
│ ├── Controller.v
│ ├── ALU.v
│ ├── Memory.v
│ ├── PC.v
│ ├── IR.v
│ └── AC.v
├── testbench/
│ ├── test_001/
│ ├── test_002/
│ ├── ...
│ └── test_010/
├── docs/
│ └── images/
├── run_tests.py
├── LICENSE
.
├── src/
│ ├── AC.v
│ ├── ADD_MUX.v
│ ├── ALU.v
│ ├── CPU.v
│ ├── Controller.v
│ ├── IR.v
│ ├── Memory.v
│ └── PC.v
├── testbench/
│ ├── run_tests.py
│ ├── test_001/
│ │ ├── PC_tb.v
│ │ └── expected.txt
│ ├── test_002/
│ │ ├── AM_tb.v
│ │ └── expected.txt
│ ├── test_003/
│ │ ├── ALU_tb.v
│ │ └── expected.txt
│ ├── test_004/
│ │ ├── Controller_tb.v
│ │ └── expected.txt
│ ├── test_005/
│ │ ├── IR_tb.v
│ │ └── expected.txt
│ ├── test_006/
│ │ ├── AC_tb.v
│ │ └── expected.txt
│ ├── test_007/
│ │ ├── Memory_tb.v
│ │ └── expected.txt
│ ├── test_008/
│ │ ├── CPU_tb.v
│ │ └── expected.txt
│ ├── test_009/
│ │ ├── CPU2_tb.v
│ │ └── expected.txt
│ └── test_010/
│ └── CPU_tb_wave.v
├── report/
│ ├── chapters/
│ ├── figures/
│ ├── riscReport.tex
│ └── riscReport.pdf
├── flake.nix
├── flake.lock
├── run_tests.py
└── README.md
The project uses two complementary verification levels:
- Module-level verification checks individual RTL components.
- CPU integration verification checks complete program execution and interactions among processor components.
Tests are compiled with Icarus Verilog, executed with vvp, and evaluated against expected output.
RTL Source
│
▼
Compile with iverilog
│
▼
Simulate with vvp
│
▼
Compare Output
│
▼
PASS / FAIL
| Test | Description |
|---|---|
test_001 |
Program-counter verification |
test_002 |
Memory-module verification |
test_003 |
Instruction-register verification |
test_004 |
Accumulator verification |
test_005 |
ALU arithmetic and logical operations |
test_006 |
Controller FSM verification |
test_007 |
Datapath signal verification |
test_008 |
CPU instruction execution |
test_009 |
CPU integration test |
test_010 |
Waveform-oriented CPU integration |
All eight instructions are exercised by the integration tests:
| Instruction | Verified |
|---|---|
HLT |
✓ |
SKZ |
✓ |
ADD |
✓ |
AND |
✓ |
XOR |
✓ |
LDA |
✓ |
STO |
✓ |
JMP |
✓ |
Multi-cycle instruction execution showing datapath activity, controller sequencing, memory access, conditional skip, jump, and halt behavior.
Install:
- Python 3
- Icarus Verilog
- GTKWave for waveform inspection
python3 run_tests.py --src src --testbench testbench --sim icaruspython3 run_tests.py \
--src src \
--testbench testbench \
--sim icarus \
--filter test_010Replace test_010 with the required test name.
Running test_001 ... PASS
Running test_002 ... PASS
...
Running test_010 ... PASS
Summary
Passed : 10
Failed : 0
Skipped: 0
The waveform-oriented integration test produces a Value Change Dump (.vcd) file.
Open it with GTKWave:
gtkwave CPU_tb_wave.vcdUseful signals include:
- program counter;
- instruction register;
- accumulator;
- ALU output;
- memory address and data;
- controller state;
- internal data bus;
- zero flag;
- control signals.
A recommended debugging cycle is:
- Run the relevant test.
- Review the simulation output.
- Inspect the generated waveform.
- Locate incorrect datapath or controller behavior.
- Update the RTL.
- Run the full regression suite.
Synthesized processor schematic generated by Vivado, showing the main processor modules and FPGA-specific clock and I/O resources.
View detailed synthesized logic
Detailed gate-level view of the synthesized processor logic. This diagram illustrates how the RTL design is transformed into registers, multiplexers, combinational logic, and control circuitry.
The implementation intentionally favors clarity over performance:
- one hardware component per source file;
- explicit separation of datapath and control logic;
- a single accumulator instead of a register file;
- multi-cycle execution instead of pipelining;
- a compact instruction set;
- unified program and data memory;
- consistent signal naming;
- synthesizable Verilog constructs.
These choices make the project suitable for introductory computer architecture courses, digital-design laboratories, and architectural experiments.
The following features are intentionally omitted:
| Feature | Status |
|---|---|
| General-purpose register file | ✗ |
| Immediate instructions | ✗ |
| Pipeline | ✗ |
| Hazard detection | ✗ |
| Branch prediction | ✗ |
| Interrupt support | ✗ |
| Cache memory | ✗ |
| Separate instruction and data memory | ✗ |
| Memory-mapped I/O | ✗ |
| Exceptions | ✗ |
Possible extensions include:
SUBandOR- shift operations
- compare instructions
- immediate operands
- additional conditional branches
- register file
- barrel shifter
- status register and additional flags
- Harvard memory organization
- five-stage pipeline
- forwarding and hazard detection
- pipeline flushing
- interrupt controller
- functional coverage
- constrained-random testing
- SystemVerilog testbenches
- assertion-based verification
- continuous integration with GitHub Actions
The project provides practical experience with:
- register-transfer-level design;
- modular hardware development;
- datapath organization;
- finite-state-machine control;
- instruction decoding and execution;
- ALU, memory, and program-counter design;
- multi-cycle processor control;
- hardware simulation and verification;
- waveform analysis.
Contributions are welcome, including new instructions, additional testbenches, documentation improvements, RTL optimizations, and bug fixes.
- Fork the repository.
- Create a feature branch.
- Commit your changes.
- Confirm that all regression tests pass.
- Open a pull request.
Current version: 1.1
The project is functionally stable and suitable for educational use. The current release includes the modular RTL implementation, multi-cycle controller, complete original instruction set, automated regression tests, CPU integration tests, waveform debugging, and project documentation.
- M. Morris Mano -Computer System Architecture
- David A. Patterson and John L. Hennessy -Computer Organization and Design
- Stephen Brown and Zvonko Vranesic -Fundamentals of Digital Logic with Verilog Design
- IEEE Standard for the Verilog Hardware Description Language
- VinhTechiee -https://github.com/VinhTechiee
- ladonna-2511 -https://github.com/ladonna-2511
- lunaz27 -https://github.com/lunaz27
This project was developed as part of undergraduate coursework in digital logic and computer architecture.
Special thanks to the instructors and teaching assistants whose lectures and laboratory exercises inspired this educational processor.
The program counter stores the address of the current instruction. It supports reset, address loading, and increment operations.
Priority order:
rst > ld_pc > inc_pc > hold
The address multiplexer selects the source address for memory access:
sel = 1: select program counter addresssel = 0: select instruction operand address
The module is parameterized through WIDTH.
The memory module provides a 32 × 8-bit storage array with a single bidirectional data port. Read and write operations are controlled by rd and wr.
- Read:
rd = 1,wr = 0 - Write:
rd = 0,wr = 1 - High impedance: otherwise
The instruction register stores the current 8-bit instruction and separates it into:
opcode = instruction[7:5]operand = instruction[4:0]
The accumulator stores the main working data value of the CPU. It receives ALU output when ld_ac is asserted.
The ALU performs arithmetic, logic, and data-transfer operations based on the opcode. It also generates the zero flag based on whether the accumulator input is zero.
The controller is implemented as an 8-state finite state machine. It generates all datapath control signals, including memory read/write, instruction loading, accumulator loading, program-counter increment/loading, bus enable, and halt control.
The top-level CPU connects the datapath modules and controller into a complete processor system. It exposes the following interface:
module CPU (
input clk,
input rst,
output halt
);At least one Verilog simulator is required:
- Icarus Verilog for
iverilogandvvp - AMD/Xilinx Vivado Simulator for
xvlog,xelab, andxsim
Python is also required for the automated test runner.
Optional development environment:
- Nix with flakes enabled
- The provided
flake.nixdefines a development shell containing Verilog, Python, and LaTeX-related tooling.
Clone the repository:
git clone <repository-url>
cd Verilog-Simple-Risc-ProcessorIf Nix is available, enter the development shell:
nix develop .#riscAlternatively, install the required tools manually:
# Ubuntu/Debian example
sudo apt update
sudo apt install iverilog python3The repository includes an automated Python test runner that can use either Icarus Verilog or Vivado Simulator.
Run all testbenches with simulator auto-detection:
python run_tests.py --src src --testbench testbenchRun all tests with Icarus Verilog:
python run_tests.py --src src --testbench testbench --sim icarusRun all tests with Vivado Simulator:
python run_tests.py --src src --testbench testbench --sim vivadoRun selected tests only:
python run_tests.py --src src --testbench testbench --filter test_001 test_008Use loose output comparison:
python run_tests.py --src src --testbench testbench --looseFor Vivado installations that are not available through PATH, specify the Vivado binary directory:
python run_tests.py --src src --testbench testbench --sim vivado --vivado-bin "C:/Xilinx/Vivado/2024.2/bin"The waveform-oriented CPU integration testbench is located at:
testbench/test_010/CPU_tb_wave.v
This testbench is intended for signal inspection and waveform debugging. It exposes internal CPU signals as top-level aliases and generates waveform output.
Example using Icarus Verilog:
iverilog -g2005 -o CPU_tb_wave.vvp src/*.v testbench/test_010/CPU_tb_wave.v
vvp CPU_tb_wave.vvpOpen the generated waveform file with a waveform viewer such as GTKWave, Surfer, or another compatible tool.
Note:
test_010does not include anexpected.txtfile, so the automated test runner treats it as a waveform-oriented test rather than a standard output-comparison test.
The verification suite includes both module-level and CPU-level tests.
| Test | Target | Purpose |
|---|---|---|
test_001 |
Program Counter | Reset, increment, load, hold, priority, wrap-around |
test_002 |
Address MUX | Address selection, parameter override, stability |
test_003 |
ALU | Opcode behavior, zero flag, arithmetic and logic operations |
test_004 |
Controller | FSM state transitions and control signal generation |
test_005 |
Instruction Register | Reset, load, hold, opcode and operand extraction |
test_006 |
Accumulator | Reset, load, hold, boundary values |
test_007 |
Memory | Read, write, high impedance, conflict prevention |
test_008 |
CPU Integration | Basic program: LDA, ADD, STO, HLT |
test_009 |
CPU Integration | Extended instruction-flow verification |
test_010 |
CPU Waveform | Waveform inspection and full instruction demonstration |
The report/ directory contains the LaTeX source and compiled PDF report for the project. The report describes the design approach, implementation details, simulation results, RTL schematics, and waveform captures.
Main report files:
report/riscReport.tex
report/riscReport.pdf
report/chapters/
report/figures/
This processor is designed as an educational RTL project and intentionally remains compact. Current limitations include:
- Small instruction set
- 5-bit address space limited to 32 memory locations
- Fixed multi-cycle execution sequence
- No pipelining
- No interrupt support
- No general-purpose register file
- No separate instruction and data memories
This project is released under the MIT License. See the LICENSE file for details.
"The best way to understand a processor is to build one."



