tiny8 Documentation

repository·main·Indexed 23 days ago

https://github.com/sql-hkr/tiny8

An educational 8-bit CPU simulator (v0.2.0) featuring an AVR-inspired architecture with 32 general-purpose registers and a 64KB address space. It includes a CLI with an interactive terminal debugger for stepping through assembly code, real-time visualization tools for memory and registers, and the ability to generate execution animations in GIF, MP4, or PNG formats.

Tokens
15.3K
Snippets
33
Records
104
Agent score
80%

What's inside tiny8

  1. Understand the Tiny8 CPU Architecture

    main

    Tiny8 is a simplified 8-bit CPU architecture inspired by the AVR (ATmega) family, designed for educational clarity. It uses a Von Neumann architecture where program instructions and data share the same memory space.

    Key Specifications:

    • Word size: 8 bits
    • Registers: 32 general-purpose 8-bit registers (R0-R31)
    • Memory: Configurable RAM (default 2KB)
    • Stack: Grows downward from high memory
    • Instruction set: ~60 AVR-inspired instructions
    • Status register: 8-bit SREG with condition flags
  2. Tiny8 Architecture Overview

    main

    Tiny8 is an AVR-inspired 8-bit CPU simulator with the following architectural specifications:

    • Registers: 32 general-purpose registers (R0-R31).
    • ALU: 8-bit Arithmetic Logic Unit supporting arithmetic, logical, and bit manipulation.
    • Status Register (SREG): Contains 8 condition flags.
    • Memory: 2KB unified address space for memory and I/O.
    • Stack: Dedicated stack pointer for stack operations.
    • Instruction Set: 60+ AVR-inspired instructions.
  3. Understand the Instruction Execution and Format

    main

    Tiny8 follows a Fetch-Decode-Execute-Update cycle. Instructions are stored in memory as tuples.

    Instruction Format (Python representation): (mnemonic, (operand1, operand2, ...))

    Operand Types:

    • Register: ("reg", N) where N is 0-31
    • Immediate: Integer value
    • Label: String referring to a program location
    • Address: Memory address (integer)

    Examples of instruction tuples:

    ("ldi", (("reg", 16), 42))      # ldi r16, 42
    ("add", (("reg", 16), ("reg", 17)))  # add r16, r17
    ("jmp", ("loop",))              # jmp loop
  4. Trace CPU Execution

    main

    The CPU automatically records traces during execution, which can be used for debugging and animation:

    • Register Trace: Records all register changes as (step, register, new_value).
    • Memory Trace: Records all memory writes as (step, address, new_value).
    • Step Trace: Records full CPU state snapshots for visualization.
  5. Perform register shifting for state management

    main

    When calculating sequences or managing state transitions, you often need to move values between registers. This is typically done using a temporary register to prevent overwriting data before it has been moved.

    mov r19, r16        ; Temporary save
    mov r16, r17        ; Shift values
    mov r17, r19        ; Update with new value
  6. Implement a loop structure in Tiny8 assembly

    main

    A standard pattern for implementing loops in Tiny8 assembly involves initializing a counter register, performing the loop body, decrementing the counter, and using a conditional branch (brne) to jump back to the start of the loop if the counter is not zero.

    ldi r18, N          ; Initialize counter
    loop:
        ; ... loop body ...
        dec r18         ; Decrement counter
        brne loop       ; Branch if not equal to zero
  7. Understand the Tiny8 Architecture

    main

    Tiny8 is an 8-bit architecture with the following components:

    CPU Components

    • 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.

    Memory Map

    • 0x0000 - 0x001F: Memory-mapped I/O (optional).
    • 0x0020 - 0xFFFF: Available RAM (stack grows downward from the top).
  8. Define and use Labels in Tiny8

    main

    Labels mark specific locations in your program and are used as targets for jumps, branches, or subroutine calls.

    Rules for Labels:

    • Must end with a colon (:).
    • Names are case-sensitive.
    • Valid characters: letters, digits, and underscores.
    • Cannot start with a digit.
    • Cannot be a reserved instruction mnemonic.

    Usage Examples:

    ; Label on its own line
    start:               
        ldi r16, 0
    
    ; Label before instruction
    loop: dec r16        
        brne loop
    
    ; Using labels with control flow
        jmp start
        breq equal_case
        call subroutine
    
    subroutine:
        ; ... code ...
        ret
    start:               
        ldi r16, 0
    
    loop: dec r16        
        brne loop
    
        jmp start
        breq equal_case
        call subroutine
    
    subroutine:
        ; ... code ...
        ret
  9. Use General-Purpose and Special Registers

    main

    Tiny8 provides 32 general-purpose 8-bit registers labeled R0 through R31. While all are general-purpose, certain instructions have constraints:

    • LDI (Load Immediate): Only works with registers R16-R31.
    • Arithmetic/Logic: Most instructions work with any register R0-R31.

    Special Registers:

    • Program Counter (PC): Points to the current instruction; automatically increments.
    • Stack Pointer (SP): Points to the top of the stack in memory. Initialized to the end of RAM (e.g., 0x07FF for 2KB RAM). It decrements on PUSH and increments on POP.
    • Status Register (SREG): An 8-bit register containing condition flags updated by arithmetic and logic operations.
  10. Configure and Use Tiny8 Memory

    main

    Tiny8 uses a byte-addressable memory model. The RAM size is configurable via the Memory(ram_size=...) parameter.

    Default Configuration (2KB):

    • Address range: 0x0000 to 0x07FF
    • Stack Pointer (SP) initialization: 0x07FF (the last address in RAM).

    Memory Layout:

    • Stack Area: Located at high memory; grows downward (towards 0x0000) as PUSH decrements the SP.
    • Data Area: Located at low memory; grows upward.
    • Note: There are no fixed boundaries between stack and data; collisions can occur if they grow toward each other.

    Memory Access Patterns:

    Register-indirect addressing:

    ; Load from memory
    ldi r26, 0x00        ; Set address low byte
    ldi r27, 0x02        ; Set address high byte (address = 0x0200)
    ld r16, r26          ; Load byte from address in R26 into R16
    
    ; Store to memory  
    ldi r26, 0x50        ; Address = 0x50
    ldi r16, 42          ; Value to store
    st r26, r16          ; Store R16 to memory[R26]

    Stack Operations:

    push r16             ; Push R16 onto stack (SP decrements)
    pop r17              ; Pop from stack into R17 (SP increments)
    
    call my_function     ; Pushes return address, then jumps
    ret                  ; Pops return address, then returns

    I/O Operations:

    in r16, 0x3F         ; Read from I/O port 0x3F into R16
    out 0x3F, r16        ; Write R16 to I/O port 0x3F
  11. Navigate the Interactive Terminal Debugger

    main

    The CLI debugger uses Vim-style and custom keyboard controls for stepping through code and inspecting state.

    • l / h or / : Step forward/backward
    • w / b: Jump ±10 steps
    • 0 / $: Jump to first/last step
    • Space: Play/pause auto-execution
    • [ / ]: Decrease/increase playback speed

    Display & Inspection

    • r: Toggle register display (all/changed only)
    • M: Toggle memory display (all/non-zero only)
    • =: Show detailed step information
    • j / k: Scroll memory view up/down

    Search & Navigation (press :)

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

    Marks & Help

    • ma: Set mark 'a' at current step
    • 'a: Jump to mark 'a'
    • /: Show help screen
    • q or ESC: Quit
  12. Run an assembly program with the interactive debugger

    main

    To execute an assembly file (.asm) using the interactive terminal debugger, pass the filename as an argument to the tiny8 command. The debugger supports Vim-style navigation, change highlighting for registers and memory, and advanced search capabilities.

    tiny8 fibonacci.asm