Files
lopez-repo/blog-post-2.md
2026-03-09 16:53:27 -06:00

5.8 KiB
Raw Blame History

Blog Entry #2 — Registers, Addressing Modes & Type Size Modifiers

In this second entry I will cover three fundamental concepts of the Spider Virtual Machine: the register table, addressing modes, and type size modifiers. These three systems work together to define how every single instruction in Spider operates.


Registers

The Spider VM provides two categories of registers.

General Purpose Registers (16 total) are directly accessible from instructions using addressing modes. They can hold either integers or floats depending on the instruction being executed.

The 16 GP registers have defined roles by convention:

  • RA — First argument and return value of a function
  • RB, RC, RD — Second, third and fourth arguments
  • RX, RY — Free auxiliary registers with no rules
  • R0R3 — Caller-saved: the called function may overwrite them
  • R4R7 — Callee-saved: the called function must restore them
  • R8, R9 — Fifth and sixth function arguments

System Registers (8 total) cannot be accessed directly by addressing modes. They require dedicated instructions to read or modify them, and they are always integers.

The most important system registers are:

  • RF — Flag Register: holds the full state of the VM in 64 bits
  • RI — Instruction Register: points to the current instruction (program counter)
  • RS — Stack Register: tracks the current top of the stack
  • RZ — Stack Base Register: base reference for the current function frame
  • RE — Exception Register: holds the address of the active exception handler
  • RV — Interrupt Vector Register: used for both internal and external interrupts
  • RM — Memory Register: total RAM available to the VM

One of Spider's core design decisions is to prioritize registers over the stack. Since registers are always available and fast to access, a well-written Spider program can run with minimal stack usage. This is especially important on constrained hardware like the ATmega328p, which only has 2KB of RAM.


Addressing Modes

Each instruction in Spider operates on parameters. An addressing mode defines how to interpret those parameters. The same instruction can behave very differently depending on the mode.

Spider has 8 addressing modes:

Mode Syntax Meaning
Implied (none) No parameter needed, operand is implicit
Immediate 42i The value is a literal constant
Absolute 0x1000i The value is a fixed memory address
Register RA The value is stored in a register
Indirect [0x1000i] Go to that address and use what's stored there
Pointer [RA] The register holds a memory address, follow it
Indexed [RA + 8i] Base register plus a constant offset
Scaled [RA + RB * 4i] Base register plus scaled index register
Displaced [RA + RB*4i+2i] Full address calculation with two registers

Addressing modes are encoded in 5 bits inside each 2-byte instruction. When an instruction has two parameters, those 5 bits are split: 2 bits for the first parameter and 3 bits for the second.

A modifier suffix is used in assembly syntax to specify the mode explicitly: .imp, .imm, .abs, .reg, .ind, .ptr, .idx, .sca, .dis

For example:

MOV.reg  RA, RB         ; move value from RB into RA using registers
MOV.ptr  RA, [RB]       ; move value from address stored in RB into RA
MOV.idx  RA, [RB + 8i]  ; move value from address RB+8 into RA

Type Size Modifiers

Every instruction in Spider also carries a type size modifier encoded in the last 2 bits of the 2-byte instruction header. This tells the VM how many bytes to read or write when executing the instruction.

Type Modifier Size
Byte .B 1 byte
Short .S 2 bytes
Int .I 4 bytes
Long .L 8 bytes
Float .F 4 bytes
Double .D 8 bytes

The type modifier applies to the entire instruction, meaning both operands must be congruent. You cannot mix sizes in a single instruction.

This system is directly tied to Spider's philosophy of strong typing: the programmer always knows exactly how much memory an operation consumes. There are no hidden conversions or surprises.

Two important behaviors to understand:

Reading a smaller size ignores the top bits of the value. For example, reading a register containing 0x12345678 with .B gives you 0x78.

Writing a smaller size only modifies the lower bytes and leaves the top bits untouched. Writing 0xAB with .B into that same register gives you 0x123456AB.

A complete instruction combining all three systems looks like this:

MOV.I.reg  RA, RB    ; move a 4-byte integer from RB into RA
MOV.B.ptr  RA, [RB]  ; move 1 byte from the address in RB into RA
ADD.L.idx  RA, [RB + 8i] ; add 8-byte value at address RB+8 into RA

How these three systems connect

These three concepts are not independent. Every instruction in Spider uses all three simultaneously:

  • The op code (9 bits) says what to do
  • The addressing mode (5 bits) says where the data is
  • The type modifier (2 bits) says how big the data is

Together they fit in exactly 2 bytes per instruction, followed by the actual parameter data. This compact design is what makes Spider efficient enough to run on microcontrollers with very limited memory.