tiny8.cpu module¶
A simplified AVR-like 8-bit CPU simulator.
This module provides a lightweight CPU model inspired by the ATmega family.
The CPU class is the primary export and implements a small, extensible instruction-dispatch model.
The implementation favors readability over step-accurate emulation. Add
instruction handlers by defining methods named op_<mnemonic> on CPU.
- class tiny8.cpu.CPU(memory=None)[source]¶
Bases:
objectIn-memory 8-bit AVR-like CPU model.
The CPU implements a compact instruction-dispatch model. Handlers are methods named
op_<mnemonic>and are invoked bystep()for the currently-loaded program.- Parameters:
memory (Memory | None)
- sp¶
Stack pointer (index into RAM in the associated
tiny8.memory.Memory).- Type:
- reg_trace¶
Per-step register change trace entries of the form
(step, reg, new_value).
- mem_trace¶
Per-step memory change trace entries of the form
(step, addr, new_value).
Note
This implementation simplifies many AVR specifics (flag semantics, exact step counts, IO mapping) in favor of clarity. Extend or replace individual
op_handlers to increase fidelity.- write_reg(r, val)[source]¶
Write an 8-bit value to register
rand record the change.- Parameters:
- Return type:
None
Note
A trace entry is appended only when the register value actually changes to avoid noisy traces.
- write_ram(addr, val)[source]¶
Write an 8-bit value to RAM at
addrand record the trace.- Parameters:
- Return type:
None
Note
The underlying
Memoryobject stores the value; a(step, addr, val)tuple is appended tomem_tracefor visualizers/tests.
- load_program(program, labels=None, pc_to_line=None, source_lines=None)[source]¶
Load an assembled program into the CPU.
- Parameters:
program (list[tuple[str, tuple]] | AsmResult) – Either a list of
(mnemonic, operands)tuples or an AsmResult object. If AsmResult, other params are ignored.labels (dict[str, int] | None) – Mapping of label strings to instruction indices (ignored if program is AsmResult).
pc_to_line (dict[int, int] | None) – Optional mapping from PC to source line number for tracing (ignored if program is AsmResult).
source_lines (list[str] | None) – Optional original assembly source lines for display (ignored if program is AsmResult).
Note
After loading the program, the program counter is reset to zero.
- step()[source]¶
Execute a single instruction at the current program counter.
Performs one fetch-decode-execute step. A pre-step snapshot of registers and non-zero RAM is recorded, the instruction handler (
op_<mnemonic>) is invoked, and a post-step trace entry is appended tostep_trace.- Returns:
True if an instruction was executed; False if the PC is out of range and execution should stop.
- Return type:
- run(max_steps=100000, show_progress=True)[source]¶
Run instructions until program end or
max_stepsis reached.- Parameters:
- Return type:
None
Note
This repeatedly calls
step()until it returns False or the maximum step count is reached.
- op_ldi(reg_idx, imm)[source]¶
Load an immediate value into a register.
Note
The AVR LDI instruction is normally restricted to R16..R31; this simplified implementation accepts any register index.
- op_add(rd, rr)[source]¶
Add register
rrtord(Rd := Rd + Rr) and update flags.Note
Sets C, H, N, V, S, Z per AVR semantics.
- op_inc(rd)[source]¶
Increment (Rd := Rd + 1) — updates V,N,S,Z; does not change C/H.
- Parameters:
rd (int) – Destination register index.
- op_dec(rd)[source]¶
Decrement (Rd := Rd - 1) — updates V,N,S,Z; does not change C/H.
- Parameters:
rd (int) – Destination register index.
- op_mul(rd, rr)[source]¶
Multiply 8x8 -> 16: store low in Rd, high in Rd+1.
Note
Updates Z and C flags. Z set if product == 0; C set if high != 0.
- op_clr(rd)[source]¶
Clear register (Rd := 0). Behaves like EOR Rd,Rd for flags.
- Parameters:
rd (int) – Destination register index.
- op_ser(rd)[source]¶
Set register all ones (Rd := 0xFF). Update flags conservatively.
- Parameters:
rd (int) – Destination register index.
- op_div(rd, rr)[source]¶
Unsigned divide convenience instruction: quotient -> Rd, remainder -> Rd+1.
Note
If divisor is zero, sets C and Z flags to indicate error.
- op_jmp(label)[source]¶
Jump to a given label or numeric address by updating the program counter.
- Parameters:
label (str | int) – The jump target. If a string, it is treated as a symbolic label and looked up in self.labels. If an int, it is used directly as the numeric address.
Note
Sets PC to target - 1 because the instruction dispatcher will increment PC after the current instruction completes.
- op_lsl(rd)[source]¶
Logical shift left (Rd := Rd << 1).
- Parameters:
rd (int) – Destination register index.
- op_lsr(rd)[source]¶
Logical shift right (Rd := Rd >> 1).
- Parameters:
rd (int) – Destination register index.
- op_com(rd)[source]¶
One’s complement: Rd := ~Rd. Updates N,V,S,Z,C per AVR-ish semantics.
- Parameters:
rd (int) – Destination register index.
- op_neg(rd)[source]¶
Two’s complement (negate): Rd := 0 - Rd. Flags as subtraction from 0.
- Parameters:
rd (int) – Destination register index.
- op_swap(rd)[source]¶
Swap nibbles in register: Rd[7:4] <-> Rd[3:0]. Does not affect SREG.
- Parameters:
rd (int) – Destination register index.
- op_tst(rd)[source]¶
Test: perform AND Rd,Rd and update flags but do not store result.
- Parameters:
rd (int) – Register index to test.
- op_sbiw(rd_word_low, imm_word)[source]¶
Subtract immediate from word register pair (Rd:Rd+1) — simplified.
- op_rjmp(label)[source]¶
Relative jump — label may be an int or string label.
- Parameters:
label (str) – Jump target (label name or relative offset).
- op_rcall(label)[source]¶
Relative call — push return address and jump relatively or to label.
- Parameters:
label (str) – Call target (label name or relative offset).
- op_brne(label)[source]¶
Branch to label if Zero flag is not set (BRNE).
- Parameters:
label (str) – Destination label to jump to if Z flag is not set.
- op_breq(label)[source]¶
Branch to label if Zero flag is set (BREQ).
- Parameters:
label (str) – Destination label to jump to if Z flag is set.
- op_brcs(label)[source]¶
Branch to a label if the carry flag is set.
- Parameters:
label (str) – Destination label to jump to if the carry flag is set.
- op_brcc(label)[source]¶
Branch to a label if the carry flag is clear.
- Parameters:
label (str) – Destination label to jump to if the carry flag is clear.
- op_push(rr)[source]¶
Push a register value onto the stack.
- Parameters:
rr (int) – Source register index to push.
Note
The value of register
rris written to RAM at the current stack pointer, and the stack pointer is then decremented.
- op_pop(rd)[source]¶
Pop a value from the stack into a register.
- Parameters:
rd (int) – Destination register index to receive the popped value.
Note
The stack pointer is incremented, the byte at the new stack pointer is read from RAM, and the value is written into register
rd.
- op_call(label)[source]¶
Call a subroutine by pushing the return address and jumping to label.
- Parameters:
label (str) – Label to call.
Note
The return address (pc+1) is pushed as two bytes (high then low) onto the stack, decrementing the stack pointer after each write.
- op_ret()[source]¶
Return from subroutine by popping the return address and setting PC.
Note
Two bytes are popped from the stack (low then high) to reconstruct the return address, which is then loaded into the program counter.
- trigger_interrupt(vector_addr)[source]¶
Trigger an interrupt vector if it is enabled.
- Parameters:
vector_addr (int) – Interrupt vector address to jump to.
Note
If the interrupt vector is enabled in
self.interrupts, the current PC+1 is pushed onto the stack (high then low byte) and control jumps tovector_addr.