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: object

In-memory 8-bit AVR-like CPU model.

The CPU implements a compact instruction-dispatch model. Handlers are methods named op_<mnemonic> and are invoked by step() for the currently-loaded program.

Parameters:

memory (Memory | None)

regs

32 8-bit general purpose registers (R0..R31).

Type:

list[int]

pc

Program counter (index into program).

Type:

int

sp

Stack pointer (index into RAM in the associated tiny8.memory.Memory).

Type:

int

sreg

Status register bits stored in a single integer (I, T, H, S, V, N, Z, C).

Type:

int

step_count

Instruction execution counter.

Type:

int

reg_trace

Per-step register change trace entries of the form (step, reg, new_value).

Type:

list[tuple[int, int, int]]

mem_trace

Per-step memory change trace entries of the form (step, addr, new_value).

Type:

list[tuple[int, int, int]]

step_trace

Full per-step snapshots useful for visualization and debugging.

Type:

list[dict]

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.

__init__(memory=None)[source]
Parameters:

memory (Memory | None)

get_flag(bit)[source]

Return the boolean value of a specific SREG flag bit.

Parameters:

bit (int) – Integer bit index (0..7).

Returns:

True if the bit is set, False otherwise.

Return type:

bool

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_adc(rd, rr)[source]

Add with carry (Rd := Rd + Rr + C) and update flags.

Parameters:
  • rd (int) – Destination register index.

  • rr (int) – Source register index.

op_add(rd, rr)[source]

Add register rr to rd (Rd := Rd + Rr) and update flags.

Parameters:
  • rd (int) – Destination register index.

  • rr (int) – Source register index.

Note

Sets C, H, N, V, S, Z per AVR semantics.

op_adiw(rd_word_low, imm_word)[source]

Add immediate to word register pair (Rd:Rd+1) - simplified.

Parameters:
  • rd_word_low (int) – Low register of the pair (even register index).

  • imm_word (int) – 16-bit immediate to add.

op_and(rd, rr)[source]

Logical AND (Rd := Rd & Rr) — updates N, Z, V=0, C=0, H=0, S.

Parameters:
  • rd (int) – Destination register index.

  • rr (int) – Source register index.

op_andi(rd, imm)[source]

Logical AND with immediate (Rd := Rd & K).

Parameters:
  • rd (int) – Destination register index.

  • imm (int) – Immediate value.

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_brge(label)[source]

Branch if Greater or Equal (Signed).

Parameters:

label (str | int) – Destination label or address to jump to if the condition is met.

op_brlt(label)[source]

Branch if Less Than (Signed).

Parameters:

label (str | int) – Destination label or address to jump to if the condition is met.

op_brmi(label)[source]

Branch if Minus (Negative flag set).

Parameters:

label (str | int) – Destination label or address to jump to if the condition is met.

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_brpl(label)[source]

Branch if Plus (Negative flag clear).

Parameters:

label (str | int) – Destination label or address to jump to if the condition is met.

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_cbi(io_addr, bit)[source]

Clear a bit in an I/O/memory-mapped address (use RAM area).

Parameters:
  • io_addr (int) – I/O or RAM address to modify.

  • bit (int) – Bit index to clear (0..7).

op_cli()[source]

Clear Global Interrupt Enable (I bit).

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_cp(rd, rr)[source]

Compare two registers (sets flags but doesn’t modify registers).

Parameters:
  • rd (int) – First register index.

  • rr (int) – Second register index.

op_cpi(rd, imm)[source]

Compare register with immediate (sets flags but doesn’t modify register).

Parameters:
  • rd (int) – Register index to compare.

  • imm (int) – Immediate value to compare against.

op_cpse(rd, rr)[source]

Compare and Skip if Equal: compare Rd,Rr; if equal, skip next instruction.

Parameters:
  • rd (int) – First register index.

  • rr (int) – Second 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.

Parameters:
  • rd (int) – Destination register index for quotient.

  • rr (int) – Divisor register index.

Note

If divisor is zero, sets C and Z flags to indicate error.

op_eor(rd, rr)[source]

Exclusive OR (Rd := Rd ^ Rr) — updates N, Z, V=0, C=0, H=0, S.

Parameters:
  • rd (int) – Destination register index.

  • rr (int) – Source register index.

op_eori(rd, imm)[source]

Logical EOR with immediate (Rd := Rd ^ K).

Parameters:
  • rd (int) – Destination register index.

  • imm (int) – Immediate value.

op_in(rd, port)[source]

Read from I/O port into register.

Parameters:
  • rd (int) – Destination register index.

  • port (int) – Port address to read from.

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_ld(rd, addr_reg)[source]

Load from RAM at address contained in register addr_reg into rd.

Parameters:
  • rd (int) – Destination register index.

  • addr_reg (int) – Register index containing the RAM address to load from.

op_ldi(reg_idx, imm)[source]

Load an immediate value into a register.

Parameters:
  • reg_idx (int) – Destination register index.

  • imm (int) – Immediate value to load.

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_mov(rd, rr)[source]

Copy the value from register rr into rd.

Parameters:
  • rd (int) – Destination register index.

  • rr (int) – Source register index.

op_mul(rd, rr)[source]

Multiply 8x8 -> 16: store low in Rd, high in Rd+1.

Parameters:
  • rd (int) – Destination register index for low byte.

  • rr (int) – Source register index.

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_nop()[source]

No-operation: does nothing for one step.

op_or(rd, rr)[source]

Logical OR (Rd := Rd | Rr) — updates N, Z, V=0, C=0, H=0, S.

Parameters:
  • rd (int) – Destination register index.

  • rr (int) – Source register index.

op_ori(rd, imm)[source]

Logical OR with immediate (Rd := Rd | K).

Parameters:
  • rd (int) – Destination register index.

  • imm (int) – Immediate value.

op_out(port, rr)[source]

Write register value to I/O port.

Parameters:
  • port (int) – Port address to write to.

  • rr (int) – Source 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 rr is 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_reti()[source]

Return from interrupt: pop return address and set I flag.

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_rol(rd)[source]

Rotate left through carry.

Parameters:

rd (int) – Destination register index.

op_ror(rd)[source]

Rotate right through carry.

Parameters:

rd (int) – Destination register index.

op_sbc(rd, rr)[source]

Subtract with carry (Rd := Rd - Rr - C).

Parameters:
  • rd (int) – Destination register index.

  • rr (int) – Source register index.

op_sbci(rd, imm)[source]

Subtract immediate with carry: Rd := Rd - K - C.

Parameters:
  • rd (int) – Destination register index.

  • imm (int) – Immediate value.

op_sbi(io_addr, bit)[source]

Set a bit in an I/O/memory-mapped address (use RAM area).

Parameters:
  • io_addr (int) – I/O or RAM address to modify.

  • bit (int) – Bit index to set (0..7).

op_sbic(io_addr, bit)[source]

Skip if bit in IO/RAM-mapped address is clear.

Parameters:
  • io_addr (int) – I/O or RAM address.

  • bit (int) – Bit position to test.

op_sbis(io_addr, bit)[source]

Skip if bit in IO/RAM-mapped address is set.

Parameters:
  • io_addr (int) – I/O or RAM address.

  • bit (int) – Bit position to test.

op_sbiw(rd_word_low, imm_word)[source]

Subtract immediate from word register pair (Rd:Rd+1) — simplified.

Parameters:
  • rd_word_low (int) – Low register of the pair (even register index).

  • imm_word (int) – 16-bit immediate to subtract.

op_sbrc(rd, bit)[source]

Skip next if bit in register is clear.

Parameters:
  • rd (int) – Register index.

  • bit (int) – Bit position to test.

op_sbrs(rd, bit)[source]

Skip next if bit in register is set.

Parameters:
  • rd (int) – Register index.

  • bit (int) – Bit position to test.

op_sei()[source]

Set Global Interrupt Enable (I bit).

op_ser(rd)[source]

Set register all ones (Rd := 0xFF). Update flags conservatively.

Parameters:

rd (int) – Destination register index.

op_st(addr_reg, rr)[source]

Store register rr into RAM at address contained in register addr_reg.

Parameters:
  • addr_reg (int) – Register index containing the RAM address to write to.

  • rr (int) – Source register index to store.

op_sub(rd, rr)[source]

Subtract (Rd := Rd - Rr) and set flags C,H,N,V,S,Z.

Parameters:
  • rd (int) – Destination register index.

  • rr (int) – Source register index.

op_subi(rd, imm)[source]

Subtract immediate (Rd := Rd - K).

Parameters:
  • rd (int) – Destination register index.

  • imm (int) – Immediate value.

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.

read_ram(addr)[source]

Read a byte from RAM at the given address.

Parameters:

addr (int) – RAM address to read.

Returns:

Byte value stored at addr (0..255).

Return type:

int

read_reg(r)[source]

Return the 8-bit value from register r.

Parameters:

r (int) – Register index (0..31).

Returns:

The 8-bit value (0..255) stored in the register.

Return type:

int

run(max_steps=100000, show_progress=True)[source]

Run instructions until program end or max_steps is reached.

Parameters:
  • max_steps (int) – Maximum number of instruction steps to execute (default 100000).

  • show_progress (bool) – If True, display a progress bar during execution (default True).

Return type:

None

Note

This repeatedly calls step() until it returns False or the maximum step count is reached.

set_flag(bit, value)[source]

Set or clear a specific SREG flag bit.

Parameters:
  • bit (int) – Integer bit index (0..7) representing the flag position.

  • value (bool) – True to set the bit, False to clear it.

Return type:

None

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 to step_trace.

Returns:

True if an instruction was executed; False if the PC is out of range and execution should stop.

Return type:

bool

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 to vector_addr.

write_ram(addr, val)[source]

Write an 8-bit value to RAM at addr and record the trace.

Parameters:
  • addr (int) – RAM address to write.

  • val (int) – Value to write; will be truncated to 8 bits.

Return type:

None

Note

The underlying Memory object stores the value; a (step, addr, val) tuple is appended to mem_trace for visualizers/tests.

write_reg(r, val)[source]

Write an 8-bit value to register r and record the change.

Parameters:
  • r (int) – Register index (0..31).

  • val (int) – Value to write; will be truncated to 8 bits.

Return type:

None

Note

A trace entry is appended only when the register value actually changes to avoid noisy traces.

class tiny8.AsmResult(program=<factory>, labels=<factory>, pc_to_line=<factory>, source_lines=<factory>)[source]

Bases: object

Result of assembling source code.

Parameters:
program

List of instruction tuples (mnemonic, operands).

Type:

list[tuple[str, tuple]]

labels

Mapping from label names to program counter addresses.

Type:

dict[str, int]

pc_to_line

Mapping from program counter to original source line number.

Type:

dict[int, int]

source_lines

Original source text split into lines for display.

Type:

list[str]

__init__(program=<factory>, labels=<factory>, pc_to_line=<factory>, source_lines=<factory>)
Parameters:
Return type:

None

program: list[tuple[str, tuple]]
labels: dict[str, int]
pc_to_line: dict[int, int]
source_lines: list[str]
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:

AsmResult

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:

AsmResult

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

__init__(cpu)[source]
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.

Parameters:
  • mem_addr_start (int) – Start memory address.

  • mem_addr_end (int) – End memory address.

  • figsize – Figure size as (width, height).

show_register_history(registers=None, figsize=(14, 8))[source]

Plot timeline of register value changes over execution.

Parameters:
  • registers (list[int]) – List of register indices to plot (default: R0-R7).

  • figsize – Figure size as (width, height).

show_statistics(top_n=10)[source]

Plot execution summary statistics.

Parameters:

top_n (int) – Number of top memory addresses to show in access frequency.

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: object

A 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()

Parameters:
__enter__()[source]

Context manager entry.

__exit__(exc_type, exc_val, exc_tb)[source]

Context manager exit.

__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

close()[source]

Close the progress bar and print newline.

reset()[source]

Reset the progress bar to initial state.

set_description(desc)[source]

Update the description.

Parameters:

desc (str) – New description string

update(n=1)[source]

Update progress by n steps.

Parameters:

n (int) – Number of steps to increment