tiny8 package¶
Submodules¶
Module contents¶
tiny8 - a tiny AVR-like 8-bit CPU simulator package.
Provides a compact CPU implementation, assembler and visualization helpers for experimentation and teaching.
- class tiny8.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.- 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.
- 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_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_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_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_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_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_clr(rd)[source]¶
Clear register (Rd := 0). Behaves like EOR Rd,Rd for flags.
- 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_dec(rd)[source]¶
Decrement (Rd := Rd - 1) — updates V,N,S,Z; does not change C/H.
- 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_inc(rd)[source]¶
Increment (Rd := Rd + 1) — updates V,N,S,Z; does not change C/H.
- Parameters:
rd (int) – Destination register index.
- 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_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_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_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_neg(rd)[source]¶
Two’s complement (negate): Rd := 0 - Rd. Flags as subtraction from 0.
- Parameters:
rd (int) – Destination register index.
- 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_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_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_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.
- 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_sbiw(rd_word_low, imm_word)[source]¶
Subtract immediate from word register pair (Rd:Rd+1) — simplified.
- op_ser(rd)[source]¶
Set register all ones (Rd := 0xFF). Update flags conservatively.
- 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.
- 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.
- 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:
- 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.
- 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.
- class tiny8.AsmResult(program=<factory>, labels=<factory>, pc_to_line=<factory>, source_lines=<factory>)[source]¶
Bases:
objectResult of assembling source code.
- Parameters:
- __init__(program=<factory>, labels=<factory>, pc_to_line=<factory>, source_lines=<factory>)¶
- tiny8.assemble(text)[source]¶
Parse assembly source text and return parsed instructions and label map.
- Parameters:
text (str) – Assembly source code as a single string. May contain multiple lines, labels and comments.
- Returns:
AsmResult object containing program, labels, source line mapping, and original source text.
- Raises:
Exception – Propagates parsing errors from the underlying parser.
- Return type:
Example
>>> src = "start: MOV R1, 5\nJMP start" >>> result = assemble(src) >>> result.labels {'start': 0}
- tiny8.assemble_file(path)[source]¶
Assemble the contents of a source file.
- Parameters:
path (str) – Path to the source file to assemble.
- Returns:
The result produced by calling assemble(source_text).
- Raises:
FileNotFoundError – If the specified file does not exist.
OSError – For other I/O related errors when opening or reading the file.
Exception – Any exception raised by assemble(…) will be propagated.
- Return type:
Note
The file is opened in text mode and read entirely into memory.
Example
>>> result = assemble_file("program.asm")
- class tiny8.Visualizer(cpu)[source]¶
Bases:
object- animate_execution(mem_addr_start=96, mem_addr_end=127, filename=None, interval=200, fps=30, fontsize=9, cmap='inferno', plot_every=1)[source]¶
Animate SREG bits, registers (R0..R31), and a memory range as three stacked subplots.
- Parameters:
mem_addr_start (int) – Start memory address for memory subplot.
mem_addr_end (int) – End memory address for memory subplot.
filename (str | None) – Optional output filename for saving animation.
interval (int) – Milliseconds between frames.
fps (int) – Frames per second for saving output.
fontsize – Font size for labels and ticks.
cmap – Matplotlib colormap name for the heatmaps.
plot_every (int) – Plot every N steps (downsampling).
- show_flag_history(figsize=(14, 6))[source]¶
Plot SREG flag changes over execution time.
- Parameters:
figsize – Figure size as (width, height).
- show_memory_access(mem_addr_start=0, mem_addr_end=255, figsize=(12, 8))[source]¶
Plot a heatmap showing memory access patterns over time.
- tiny8.run_cli(cpu, mem_addr_start=0, mem_addr_end=31, delay=0.15, source_lines=None)[source]¶
Run interactive CLI visualizer in terminal.
Displays CPU state, registers, memory, and assembly source in a curses-based interface with keyboard navigation and playback controls.
- Parameters:
cpu – CPU instance with step_trace attribute containing execution history.
mem_addr_start (int) – Starting memory address to display (default: 0).
mem_addr_end (int) – Ending memory address to display (default: 31).
delay (float) – Initial playback delay in seconds (default: 0.15).
source_lines (list[str] | None) – Optional list of original assembly source lines for display.
- Raises:
RuntimeError – If cpu.step_trace is empty or missing.
- Return type:
None
- class tiny8.ProgressBar(total=None, desc='', disable=False, ncols=None, mininterval=0.1)[source]¶
Bases:
objectA simple tqdm-like progress bar for Tiny8 CPU execution.
- Usage:
- with ProgressBar(total=1000, desc=”Running”) as pb:
- for i in range(1000):
# do work pb.update(1)
- Or:
pb = ProgressBar(total=1000) for i in range(1000):
# do work pb.update(1)
pb.close()
- __init__(total=None, desc='', disable=False, ncols=None, mininterval=0.1)[source]¶
Initialize progress bar.
- Parameters:
total (int | None) – Total number of iterations (None for indeterminate)
desc (str) – Description prefix for the progress bar
disable (bool) – If True, disable the progress bar completely
ncols (int | None) – Width of the progress bar in characters (None for auto-detect)
mininterval (float) – Minimum time between updates in seconds