A fully functional 32-bit RISC pipelined processor implemented in VHDL, featuring a 5-stage pipeline with hazard detection, data forwarding, interrupt support and a Von-Neumman architecture (one memory space for instructions and data). This project is designed for educational purposes and ModelSim simulation.
- 5-Stage Pipeline: Fetch → Decode → Execute → Memory → Writeback
- 32-bit Architecture with 20-bit address space (1MB addressable memory)
- 8 General Purpose Registers (R0–R7)
- 27+ Instructions covering ALU, Memory, I/O, and Control Flow
- Data Hazard Handling: Forwarding unit with EX-EX and MEM-EX paths
- Control Hazard Handling: Pipeline stalling and flushing
- Hardware & Software Interrupts: INT0, INT1 with automatic CCR/PC save-restore
- Stack Operations: PUSH/POP with dedicated Stack Pointer
- Custom Assembler: Python-based assembler for
.asm→.memconversion
pipelined-processor/
├── src/
│ ├── processor.vhd # Top-level processor entity
│ ├── pkg/
│ │ └── cpu_defs_pkg.vhd # Constants, opcodes, type definitions
│ ├── stages/
│ │ ├── fetch.vhd # Instruction Fetch stage
│ │ ├── decode.vhd # Instruction Decode stage
│ │ ├── execute.vhd # Execute stage
│ │ ├── memory.vhd # Memory Access stage
│ │ └── writeback.vhd # Write Back stage
│ ├── buffers/
│ │ ├── if_id_reg.vhd # IF/ID pipeline register
│ │ ├── id_ex_reg.vhd # ID/EX pipeline register
│ │ ├── ex_mem_reg.vhd # EX/MEM pipeline register
│ │ └── mem_wb_reg.vhd # MEM/WB pipeline register
│ ├── components/
│ │ ├── alu.vhd # Arithmetic Logic Unit
│ │ ├── control_unit.vhd # Main control unit with FSM
│ │ ├── register_file.vhd # 8x32-bit register file
│ │ ├── forwarding_unit.vhd # Data forwarding logic
│ │ ├── hazard_detection_unit.vhd # Hazard detection
│ │ ├── priority_pc_mux.vhd # PC source selection
│ │ └── generic_mux.vhd # Parameterized multiplexer
│ └── memory/
│ └── ram.vhd # Unified memory (256KB)
├── testbench/
│ ├── processor_tb.vhd # Main processor testbench
│ ├── branch_test_tb.vhd # Branch instruction tests
│ ├── memory_test_tb.vhd # Memory operation tests
│ └── two_operand_tb.vhd # ALU operation tests
├── TestCases/
│ ├── Branch.asm / Branch.mem
│ ├── Memory.asm / Memory.mem
│ ├── TwoOperand.asm / TwoOperand.mem
│ └── ...
├── assembler/
│ └── assembler.py # Python assembler
├── simulation/
│ └── scripts/ # ModelSim compile/run scripts
└── Makefile # Build automation
| Stage | Description |
|---|---|
| Fetch (IF) | Reads instruction from memory using PC, computes PC+1, handles reset vector loading |
| Decode (ID) | Decodes opcode, reads register file, generates control signals, handles immediate fetching |
| Execute (EX) | Performs ALU operations, evaluates branch conditions, computes memory addresses |
| Memory (MEM) | Handles load/store operations, stack operations (PUSH/POP), manages stack pointer |
| Writeback (WB) | Writes results back to register file, selects between ALU result, memory data, or I/O port |
31 27 26 24 23 21 20 18 17 0
+-------+------+------+------+-------------+
| OPCODE| Rdst | Rsrc1| Rsrc2| unused |
+-------+------+------+------+-------------+
5b 3b 3b 3b 18b
For instructions with immediate values, a second 32-bit word follows containing the immediate.
| Instruction | Opcode | Description |
|---|---|---|
ADD Rd, Rs1, Rs2 |
00000 | Rd = Rs1 + Rs2 |
SUB Rd, Rs1, Rs2 |
00001 | Rd = Rs1 - Rs2 |
AND Rd, Rs1, Rs2 |
00110 | Rd = Rs1 AND Rs2 |
NOT Rd |
00100 | Rd = NOT Rd |
INC Rd |
00010 | Rd = Rd + 1 |
MOV Rd, Rs |
00101 | Rd = Rs |
SWAP Rs1, Rs2 |
00011 | Exchange Rs1 ↔ Rs2 |
SETC |
00111 | Set carry flag |
| Instruction | Opcode | Description |
|---|---|---|
NOP |
01000 | No operation |
HLT |
01001 | Halt processor |
IN Rd |
01011 | Rd = Input port |
OUT Rs |
01010 | Output port = Rs |
LDM Rd, Imm |
01101 | Rd = Immediate (32-bit) |
IADD Rd, Rs, Imm |
01100 | Rd = Rs + Immediate |
| Instruction | Opcode | Description |
|---|---|---|
LDD Rd, offset(Rs) |
10000 | Rd = Memory[Rs + offset] |
STD Rs, offset(Rb) |
10001 | Memory[Rb + offset] = Rs |
PUSH Rs |
10101 | Push Rs onto stack |
POP Rd |
10100 | Pop from stack to Rd |
| Instruction | Opcode | Description |
|---|---|---|
JMP addr |
11011 | Unconditional jump |
JZ addr |
11000 | Jump if Zero flag set |
JN addr |
11001 | Jump if Negative flag set |
JC addr |
11010 | Jump if Carry flag set |
CALL addr |
11100 | Call subroutine (pushes PC+2) |
RET |
11101 | Return from subroutine |
INT index |
11110 | Software interrupt (0-3) |
RTI |
11111 | Return from interrupt |
The forwarding unit resolves RAW (Read After Write) hazards by forwarding data from:
- EX/MEM stage → Execute stage inputs (EX-EX forwarding)
- MEM/WB stage → Execute stage inputs (MEM-EX forwarding)
Priority order: Immediate > EX/MEM Forward > MEM/WB Forward > Register File
The hazard detection unit handles:
- Load-Use Hazards: Stalls pipeline when a load is followed by an instruction that uses the loaded value
- Memory Structural Hazards: Stalls during memory read/write operations
- Control Hazards: Flushes pipeline on branch mispredictions and jump instructions
- Interrupt vectors: Stored at memory addresses 0x0 (Reset), 0x1 (Empty Stack), 0x2 (INT0), 0x3 (INT1)
- INT sequence: Push PC → Push CCR → Jump to handler
- RTI sequence: Pop CCR → Pop PC → Resume execution
| Address | Purpose |
|---|---|
| 0x00000 | Reset Vector |
| 0x00001 | Stack Exception Handler |
| 0x00002 | INT0 Handler Address |
| 0x00003 | INT1 Handler Address |
| 0x3FFFF | Stack Pointer Initial Value |
- ModelSim (or compatible VHDL simulator)
- Python 3 (for the assembler)
- Make (optional, for automation)
-
Assemble your program:
python3 assembler/assembler.py TestCases/Branch.asm TestCases/Branch.mem
-
Compile VHDL sources (using ModelSim):
cd simulation vlib work vsim -c -do "do scripts/compile.do; quit"
-
Run simulation:
vsim -gui -do "do scripts/run.do"
# Full build and simulation
make all
# Assemble a specific program
make asm ASM_SOURCE=TestCases/Memory.asm
# Compile VHDL
make compile
# Run simulation (GUI)
make sim SIM_SCRIPT=[scripts/example.do]
# Clean generated files
make cleanThe Python assembler converts assembly .asm files to memory .mem files.
python3 assembler/assembler.py <input.asm> <output.mem># Comments start with #, ;, or //
.ORG 0 # Set origin address (hex)
200 # Raw data word
.ORG 200
LDM R1, FFFF # R1 = 0xFFFF
ADD R2, R1, R0 # R2 = R1 + R0
PUSH R2 # Push R2 to stack
JZ 300 # Jump if zero flag set
CALL 500 # Call subroutine at 0x500
RET # ReturnNote: All numbers are in hexadecimal format by default.
| Test Case | Description |
|---|---|
Branch.asm |
Tests JMP, JZ, JN, JC, CALL, RET, INT, RTI, flag forwarding |
Memory.asm |
Tests LDM, LDD, STD, PUSH, POP operations |
TwoOperand.asm |
Tests ADD, SUB, AND, MOV, SWAP |
OneOperand.asm |
Tests NOT, INC, IN, OUT and flag updates |
BranchPrediction.asm |
Tests branch behavior and pipeline flushing |
| Parameter | Value |
|---|---|
| Data Width | 32 bits |
| Address Width | 20 bits (1MB) |
| Memory Size | 256K words (1MB) |
| Register Count | 8 (R0–R7) |
| Pipeline Stages | 5 |
| Instruction Count | 27+ |
| Clock | Configurable (simulation) |
This project is for educational purposes. Feel free to use, modify, and distribute.
Omar Gamal |
Mostafa Abdelgelel |
Omar Hassan |
Mostafa Hassan |
