一个用 Python 编写的微型 CPU 模拟器
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.
pip install tiny8
Create fibonacci.asm:
…
Run it:
tiny8 fibonacci.asm # Interactive debugger
tiny8 fibonacci.asm -m ani -o fibonacci.gif # Generate animation
from 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 number
For 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.
The terminal-based debugger provides powerful navigation and inspection capabilities.
l / h or → / ← — Step forward/backwardw / b — Jump ±10 steps0 / $ — Jump to first/last stepSpace — Play/pause auto-execution[ / ] — Decrease/increase playback speedr — 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 Zma — Set mark 'a' at current step'a — Jump to mark 'a'/ — Show help screenq or ESC — QuitThe examples/ directory contains programs demonstrating key concepts:
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 GIF
from 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]
-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)
-ms, --mem-start ADDR
Starting memory address (decimal or 0xHEX, default: 0x00)
-me, --mem-end ADDR
Ending memory address (decimal or 0xHEX, default: 0xFF)
-d, --delay SEC
Initial playback delay in seconds (default: 0.15)
-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.
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
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
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
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
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
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
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
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/borrowFlags are used for conditional branching and tracking arithmetic results.
; for line comments: (e.g., loop:)暂无开放 Issues,或尚未同步最近议题。