A complete, compilable C project for a software CPU (instruction-set simulator) suitable for electronics/CS labs. This project delivers high-quality code, documentation, and tests for a deterministic, reproducible CPU simulator.
- Registers: A,B,C,D general 8-bit; X,Y 16-bit index; SP 16; PC 16; FLAGS (Z,N,C,V,I)
- Addressing: immediate, register, [absolute], [X+offset], [Y+offset], [SP+offset], relative branch
- Core Operations: Load/Store, Arithmetic, Logical, Shift/Rotate, Jump/Call, Branch, Stack, System
- Instruction Format: 1-byte opcode + 0-2 operand bytes with cycle-accurate timing
- 64 KiB address space
- 0x0000–0x7FFF: RAM
- 0x8000–0xFEFF: MMIO window
- 0xFF00–0xFFFF: Reset/ISR vectors
- UART: TX at 0x8000, RX at 0x8001, STATUS at 0x8002
- GPIO: 8-bit port at 0x8003
- TIMER: 0x8004..0x8007 (latch, ctrl, count, irq flag)
- Single-step and run modes with cycle-accurate tick()
- Reset(), IRQ(), NMI() lines and interrupt handling
- Disassembler for any memory range
- Optional clock throttling (instructions/second)
- Assembler: Supports labels, .org, .byte/.word, constants, comments, include
- Monitor: CLI with load, run, step, regs, mem dump, breakpoints, watchpoints, disasm, save snapshot
- Scriptable REPL commands
- Self-test suite with golden traces
- ISA tests per instruction (flags, edge cases)
- Integration tests: UART echo, timer-driven blink, IRQ nesting
- Deterministic seeds with PASS/FAIL summary
examples/hello.asm: Prints "HELLO"examples/addloop.asm: Sums 1..N and prints resultexamples/gpio_blink.asm: Toggles GPIO via timer IRQ
make# Build examples
make examples
# Run CPU simulator
./build/cpu-sim examples/hello.bin --addr 0x0200 --run
# Interactive mode
./build/cpu-sim
# Monitor/debugger
./build/monitormake test├── src/ # Source code
│ ├── cpu.h/c # CPU core implementation
│ ├── isa.h/c # Instruction set architecture
│ ├── memory.h/c # Memory system
│ ├── devices.h/c # Device implementations
│ ├── assembler.h/c # Assembler
│ ├── cpu-sim.c # Main CPU simulator
│ ├── asm.c # Assembler program
│ ├── disasm.c # Disassembler
│ └── monitor.c # Monitor/debugger
├── tests/ # Test suite
│ └── test_runner.c # Test suite runner
├── examples/ # Example programs
│ ├── hello.asm # Hello world
│ ├── addloop.asm # Add loop
│ └── gpio_blink.asm # GPIO blink
├── docs/ # Documentation
├── build/ # Build output
├── Makefile # Build system
└── README.md # This file
| Mnemonic | Opcode | Bytes | Cycles | Description |
|---|---|---|---|---|
| LDI #val | 0x00 | 2 | 2 | Load immediate |
| LDA [addr] | 0x01 | 3 | 3 | Load from memory |
| STA [addr] | 0x02 | 3 | 3 | Store to memory |
| MOV r,r | 0x03 | 2 | 1 | Move register |
| Mnemonic | Opcode | Bytes | Cycles | Description |
|---|---|---|---|---|
| ADD #val | 0x10 | 2 | 2 | Add immediate |
| SUB #val | 0x11 | 2 | 2 | Subtract immediate |
| CMP #val | 0x14 | 2 | 2 | Compare |
| INC r | 0x15 | 1 | 1 | Increment register |
| DEC r | 0x16 | 1 | 1 | Decrement register |
| Mnemonic | Opcode | Bytes | Cycles | Description |
|---|---|---|---|---|
| AND #val | 0x20 | 2 | 2 | Logical AND |
| OR #val | 0x21 | 2 | 2 | Logical OR |
| XOR #val | 0x22 | 2 | 2 | Logical XOR |
| Mnemonic | Opcode | Bytes | Cycles | Description |
|---|---|---|---|---|
| JMP addr | 0x40 | 3 | 3 | Jump absolute |
| JSR addr | 0x41 | 3 | 6 | Jump to subroutine |
| RTS | 0x42 | 1 | 6 | Return from subroutine |
| Mnemonic | Opcode | Bytes | Cycles | Description |
|---|---|---|---|---|
| BEQ addr | 0x50 | 2 | 2 | Branch if equal (Z=1) |
| BNE addr | 0x51 | 2 | 2 | Branch if not equal (Z=0) |
| BCS addr | 0x52 | 2 | 2 | Branch if carry set (C=1) |
| BCC addr | 0x53 | 2 | 2 | Branch if carry clear (C=0) |
| BMI addr | 0x54 | 2 | 2 | Branch if minus (N=1) |
| BPL addr | 0x55 | 2 | 2 | Branch if plus (N=0) |
| BVS addr | 0x56 | 2 | 2 | Branch if overflow set (V=1) |
| BVC addr | 0x57 | 2 | 2 | Branch if overflow clear (V=0) |
| Mnemonic | Opcode | Bytes | Cycles | Description |
|---|---|---|---|---|
| PHA | 0x60 | 1 | 3 | Push accumulator |
| PLA | 0x61 | 1 | 4 | Pull accumulator |
| PHP | 0x62 | 1 | 3 | Push processor status |
| PLP | 0x63 | 1 | 4 | Pull processor status |
| PUSH r | 0x64 | 2 | 3 | Push register |
| POP r | 0x65 | 2 | 4 | Pull register |
| Mnemonic | Opcode | Bytes | Cycles | Description |
|---|---|---|---|---|
| SEI | 0x70 | 1 | 2 | Set interrupt disable |
| CLI | 0x71 | 1 | 2 | Clear interrupt disable |
| NOP | 0x72 | 1 | 1 | No operation |
| HLT | 0x73 | 1 | 1 | Halt |
- Format:
#value - Example:
LDI #0x42 - Loads the value directly into the accumulator
- Format:
[address] - Example:
LDA [0x1000] - Uses the address as an absolute memory location
- Format:
[X+offset],[Y+offset] - Example:
LDA [X+0x10] - Uses index register plus offset as address
- Format:
offset - Example:
BEQ loop - Used for branch instructions, calculates target from PC + offset
| Address Range | Description |
|---|---|
| 0x0000-0x7FFF | RAM (32KB) |
| 0x8000-0xFEFF | MMIO Window |
| 0xFF00-0xFFFF | Vector Table |
| Address | Device | Description |
|---|---|---|
| 0x8000 | UART TX | Transmit data |
| 0x8001 | UART RX | Receive data |
| 0x8002 | UART STATUS | Status register |
| 0x8003 | GPIO PORT | GPIO port data |
| 0x8004 | TIMER LATCH | Timer latch low |
| 0x8005 | TIMER LATCH | Timer latch high |
| 0x8006 | TIMER CTRL | Timer control |
| 0x8007 | TIMER IRQ | Timer interrupt flag |
# Load and run a program
./build/cpu-sim examples/hello.bin --addr 0x0200 --run
# Interactive mode with tracing
./build/cpu-sim --trace --break 0x0300
# Run with frequency limit
./build/cpu-sim examples/addloop.bin --freq 1000000 --cycles 10000# Assemble a program
./build/asm examples/hello.asm -o hello.bin
# Generate listing
./build/asm examples/hello.asm -o hello.bin -l hello.lst
# Verbose output
./build/asm examples/hello.asm -o hello.bin -v# Interactive monitor
./build/monitor
# Run script
./build/monitor -s commands.txt
# Monitor commands
monitor> load examples/hello.bin 0x0200
monitor> run
monitor> step
monitor> regs
monitor> mem 0x0200 16
monitor> disasm 0x0200 16
monitor> break 0x0300
monitor> watch 0x8000
monitor> trace on
monitor> quit- C99 compatible compiler (GCC, Clang, MSVC)
- Make
- No external dependencies beyond libc
# Build all tools
make
# Build specific tool
make cpu-sim
make asm
make disasm
make monitor
make tests
# Build examples
make examples
# Run tests
make test
# Clean build
make clean
# Debug build
make debug
# Install (optional)
make installThe project includes a comprehensive test suite:
# Run all tests
make test
# Run specific test categories
./build/tests
# Test output
Software CPU Simulator Test Suite
=================================
Running test: CPU Creation... PASS
Running test: CPU Reset... PASS
Running test: CPU Registers... PASS
Running test: CPU Flags... PASS
Running test: CPU Memory... PASS
Running test: CPU Instructions... PASS
Running test: CPU Interrupts... PASS
Running test: Memory System... PASS
Running test: Device System... PASS
Running test: ISA Instructions... PASS
Running test: Assembler Basic... PASS
Running test: Integration Hello... PASS
Running test: Integration AddLoop... PASS
Running test: Integration GPIO Blink... PASS
Test Results Summary:
===================
Total tests: 14
Passed: 14
Failed: 0
Success rate: 100.0%
ALL TESTS PASSED!This project is provided as-is for educational purposes. Feel free to use, modify, and distribute according to your needs.
This is a complete, self-contained project. All components are implemented and tested. The codebase follows C99 standards and is designed to be portable across different platforms.