An educational 8-bit CPU simulator with interactive visualization
Tiny8 is a lightweight and educational toolkit for exploring the fundamentals of computer architecture through hands-on assembly programming and real-time visualization. Designed for learning and experimentation, it features an AVR-inspired 8-bit CPU with 32 registers, a rich instruction set, and powerful debugging tools โ all with zero heavy dependencies.
- Vim-style navigation: Step through execution with intuitive keyboard controls
- Change highlighting: See exactly what changed at each step (registers, flags, memory)
- Advanced search: Find instructions, track register/memory changes, locate PC addresses
- Marks and bookmarks: Set and jump to important execution points
- Vertical scrolling: Handle programs with large memory footprints
- Generate high-quality GIF/MP4 videos of program execution
- Visualize register evolution, memory access patterns, and flag changes
- Perfect for presentations, documentation, and learning materials
- 32 general-purpose registers (R0-R31)
- 8-bit ALU with arithmetic, logical, and bit manipulation operations
- Status register (SREG) with 8 condition flags
- 2KB address space for unified memory and I/O
- Stack operations with dedicated stack pointer
- AVR-inspired instruction set with 60+ instructions
- Clean, readable Python implementation
- Comprehensive examples (Fibonacci, bubble sort, factorial, and more)
- Step-by-step execution traces for debugging
- Full API documentation and instruction set reference
pip install tiny8Create fibonacci.asm:
; Fibonacci Sequence Calculator
; Calculates the 10th Fibonacci number (F(10) = 55)
; F(0) = 0, F(1) = 1, F(n) = F(n-1) + F(n-2)
;
; Results stored in registers:
; R16 and R17 hold the two most recent Fibonacci numbers
ldi r16, 0 ; F(0) = 0
ldi r17, 1 ; F(1) = 1
ldi r18, 9 ; Counter: 9 more iterations to reach F(10)
loop:
add r16, r17 ; F(n) = F(n-1) + F(n-2)
mov r19, r16 ; Save result temporarily
mov r16, r17 ; Shift: previous = current
mov r17, r19 ; Shift: current = new result
dec r18 ; Decrement counter
brne loop ; Continue if counter != 0
done:
jmp done ; Infinite loop at endRun it:
tiny8 fibonacci.asm # Interactive debugger
tiny8 fibonacci.asm -m ani -o fibonacci.gif # Generate animationfrom tiny8 import CPU, assemble_file
asm = assemble_file("fibonacci.asm")
cpu = CPU()
cpu.load_program(asm)
cpu.run(max_steps=1000)
print(f"Result: R17 = {cpu.read_reg(17)}") # Final Fibonacci numberFor Students โ Write assembly, see immediate results with visual feedback. Understand how each instruction affects CPU state without abstractions.
For Educators โ Interactive demonstrations, easy assignment creation, and generate animations for lectures.
For Hobbyists โ Rapid algorithm prototyping at the hardware level with minimal overhead and an extensible, readable codebase.
- Full Documentation โ Complete API reference and guides
- Instruction Set Reference โ All 60+ instructions
- CLI Guide โ Terminal debugger keyboard shortcuts
- Examples โ Sample programs with explanations
- Contributing โ Guidelines for contributors
The terminal-based debugger provides powerful navigation and inspection capabilities.
l/horโ/โโ Step forward/backwardw/bโ Jump ยฑ10 steps0/$โ Jump to first/last stepSpaceโ Play/pause auto-execution[/]โ Decrease/increase playback speed
rโ Toggle register display (all/changed only)Mโ Toggle memory display (all/non-zero only)=โ Show detailed step informationj/kโ Scroll memory view up/down
:123โ Jump to step 123:+50/:-20โ Relative jumps:/ldiโ Search forward for instruction "ldi":?addโ Search backward for "add":@0x100โ Jump to PC address 0x100:r10โ Find next change to register R10:r10=42โ Find where R10 equals 42:m100โ Find next change to memory[100]:fZโ Find next change to flag Z
maโ Set mark 'a' at current step'aโ Jump to mark 'a'/โ Show help screenqorESCโ Quit
The examples/ directory contains programs demonstrating key concepts:
| Example | Description |
|---|---|
fibonacci.asm |
Fibonacci sequence using registers |
bubblesort.asm |
Sorting algorithm with memory visualization |
factorial.asm |
Recursive factorial calculation |
find_max.asm |
Finding maximum value in array |
is_prime.asm |
Prime number checking algorithm |
gcd.asm |
Greatest common divisor (Euclidean algorithm) |
Sort 32 bytes in memory:
tiny8 examples/bubblesort.asm -ms 0x60 -me 0x80 # Watch live
tiny8 examples/bubblesort.asm -m ani -o sort.gif -ms 0x60 -me 0x80 # Create GIFfrom tiny8 import CPU, assemble_file
cpu = CPU()
cpu.load_program(assemble_file("examples/bubblesort.asm"))
cpu.run()
print("Sorted:", [cpu.read_ram(i) for i in range(0x60, 0x80)])tiny8 FILE [OPTIONS]| Option | Description |
|---|---|
-m, --mode {cli,ani} |
Visualization mode: cli for interactive debugger (default), ani for animation |
-v, --version |
Show version and exit |
--max-steps N |
Maximum execution steps (default: 15000) |
| Option | Description |
|---|---|
-ms, --mem-start ADDR |
Starting memory address (decimal or 0xHEX, default: 0x00) |
-me, --mem-end ADDR |
Ending memory address (decimal or 0xHEX, default: 0xFF) |
| Option | Description |
|---|---|
-d, --delay SEC |
Initial playback delay in seconds (default: 0.15) |
| Option | Description |
|---|---|
-o, --output FILE |
Output filename (.gif, .mp4, .png) |
-f, --fps FPS |
Frames per second (default: 60) |
-i, --interval MS |
Update interval in milliseconds (default: 1) |
-pe, --plot-every N |
Update plot every N steps (default: 100, higher = faster) |
Windows: CLI debugger requires WSL or
windows-curses. Animation works natively.
Tiny8 implements an AVR-inspired instruction set with 62 instructions organized into logical categories. All mnemonics are case-insensitive. Registers are specified as R0-R31, immediates support decimal, hex ($FF or 0xFF), and binary (0b11111111) notation.
| Instruction | Description | Example |
|---|---|---|
LDI Rd, K |
Load 8-bit immediate into register | ldi r16, 42 |
MOV Rd, Rr |
Copy register to register | mov r17, r16 |
LD Rd, Rr |
Load from RAM at address in Rr | ld r18, r16 |
ST Rr, Rs |
Store Rs to RAM at address in Rr | st r16, r18 |
IN Rd, port |
Read from I/O port into register | in r16, 0x3F |
OUT port, Rr |
Write register to I/O port | out 0x3F, r16 |
PUSH Rr |
Push register onto stack | push r16 |
POP Rd |
Pop from stack into register | pop r16 |
| Instruction | Description | Example |
|---|---|---|
ADD Rd, Rr |
Add registers | add r16, r17 |
ADC Rd, Rr |
Add with carry | adc r16, r17 |
SUB Rd, Rr |
Subtract registers | sub r16, r17 |
SUBI Rd, K |
Subtract immediate | subi r16, 10 |
SBC Rd, Rr |
Subtract with carry | sbc r16, r17 |
SBCI Rd, K |
Subtract immediate with carry | sbci r16, 5 |
INC Rd |
Increment register | inc r16 |
DEC Rd |
Decrement register | dec r16 |
MUL Rd, Rr |
Multiply (result in Rd:Rd+1) | mul r16, r17 |
DIV Rd, Rr |
Divide (quotientโRd, remainderโRd+1) | div r16, r17 |
NEG Rd |
Two's complement negation | neg r16 |
ADIW Rd, K |
Add immediate to word (16-bit) | adiw r24, 1 |
SBIW Rd, K |
Subtract immediate from word | sbiw r24, 1 |
| Instruction | Description | Example |
|---|---|---|
AND Rd, Rr |
Logical AND | and r16, r17 |
ANDI Rd, K |
AND with immediate | andi r16, 0x0F |
OR Rd, Rr |
Logical OR | or r16, r17 |
ORI Rd, K |
OR with immediate | ori r16, 0x80 |
EOR Rd, Rr |
Exclusive OR | eor r16, r17 |
EORI Rd, K |
XOR with immediate | eori r16, 0xFF |
COM Rd |
One's complement | com r16 |
CLR Rd |
Clear register (XOR with self) | clr r16 |
SER Rd |
Set register to 0xFF | ser r16 |
TST Rd |
Test for zero or negative | tst r16 |
SWAP Rd |
Swap nibbles (high/low 4 bits) | swap r16 |
SBI port, bit |
Set bit in I/O register | sbi 0x18, 3 |
CBI port, bit |
Clear bit in I/O register | cbi 0x18, 3 |
| Instruction | Description | Example |
|---|---|---|
LSL Rd |
Logical shift left | lsl r16 |
LSR Rd |
Logical shift right | lsr r16 |
ROL Rd |
Rotate left through carry | rol r16 |
ROR Rd |
Rotate right through carry | ror r16 |
| Instruction | Description | Example |
|---|---|---|
JMP label |
Unconditional jump | jmp loop |
RJMP offset |
Relative jump | rjmp -5 |
CALL label |
Call subroutine | call function |
RCALL offset |
Relative call | rcall -10 |
RET |
Return from subroutine | ret |
RETI |
Return from interrupt | reti |
BRNE label |
Branch if not equal (Z=0) | brne loop |
BREQ label |
Branch if equal (Z=1) | breq done |
BRCS label |
Branch if carry set (C=1) | brcs overflow |
BRCC label |
Branch if carry clear (C=0) | brcc no_carry |
BRGE label |
Branch if greater/equal | brge positive |
BRLT label |
Branch if less than | brlt negative |
BRMI label |
Branch if minus (N=1) | brmi negative |
BRPL label |
Branch if plus (N=0) | brpl positive |
| Instruction | Description | Example |
|---|---|---|
CP Rd, Rr |
Compare registers (Rd - Rr) | cp r16, r17 |
CPI Rd, K |
Compare with immediate | cpi r16, 42 |
CPSE Rd, Rr |
Compare, skip if equal | cpse r16, r17 |
| Instruction | Description | Example |
|---|---|---|
SBRS Rd, bit |
Skip if bit in register is set | sbrs r16, 7 |
SBRC Rd, bit |
Skip if bit in register is clear | sbrc r16, 7 |
SBIS port, bit |
Skip if bit in I/O register is set | sbis 0x16, 3 |
SBIC port, bit |
Skip if bit in I/O register is clear | sbic 0x16, 3 |
| Instruction | Description | Example |
|---|---|---|
NOP |
No operation | nop |
SEI |
Set global interrupt enable | sei |
CLI |
Clear global interrupt enable | cli |
The 8-bit status register contains condition flags updated by instructions:
| Bit | Flag | Description |
|---|---|---|
| 7 | I | Global interrupt enable |
| 6 | T | Bit copy storage |
| 5 | H | Half carry (BCD arithmetic) |
| 4 | S | Sign bit (N โ V) |
| 3 | V | Two's complement overflow |
| 2 | N | Negative |
| 1 | Z | Zero |
| 0 | C | Carry/borrow |
Flags are used for conditional branching and tracking arithmetic results.
- Comments: Use
;for line comments - Labels: Must end with
:(e.g.,loop:) - Registers: Case-insensitive R0-R31 (r16, R16 equivalent)
- Immediates: Decimal (42), hex ($2A, 0x2A), binary (0b00101010)
- Whitespace: Flexible indentation, spaces/tabs interchangeable
- 32 General-Purpose Registers (R0-R31) โ 8-bit working registers
- Program Counter (PC) โ 16-bit, addresses up to 64KB
- Stack Pointer (SP) โ 16-bit, grows downward from high memory
- Status Register (SREG) โ 8 condition flags (I, T, H, S, V, N, Z, C)
- 64KB Address Space โ Unified memory for RAM and I/O
0x0000 - 0x001F Memory-mapped I/O (optional)
0x0020 - 0xFFFF Available RAM (stack grows downward from top)
pytest # Run all tests
pytest --cov=src/tiny8 --cov-report=html # With coverage
pytest tests/test_arithmetic.py # Specific test fileContributions welcome! See CONTRIBUTING.md for guidelines.
Areas for contribution: New instructions, example programs, documentation, visualizations, performance optimizations.
MIT License โ see LICENSE for details.
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: sql-hkr.github.io/tiny8
Made with โค๏ธ for learners, educators, and curious minds
Star โญ the repo if you find it useful!
