Memory maps

This page covers both volatile memory (the SRAM layout the kernel lays out by hand) and the on-disk format of the EEPROM filesystem.

SRAM startup

The AVR does not clear RAM on reset, so the compiler emits a small crt0-style routine that zeroes the whole SRAM before @main runs. That makes a program start from the same controlled state on real silicon as it does in the simulator (whose RAM is already zero), so every global begins life at zero.

The SRAM map

kernel/memory.ik lays out SRAM by hand. The map is chosen to fit both the ATmega32 (RAM 0x00600x085F) and the ATmega328p (0x01000x08FF): kernel state sits at 0x0340 — above the compiler’s statics on either part — and process stacks fill up to 0x07FF, leaving 0x0800–RAMEND for the scheduler/reset stack on whichever device.

Range

Contents

..0x033F

compiler statics (ATmega32 from 0x0060)

0x0340..0x0565

kernel state (zeroed at boot; BSS_LEN = 0x0226)

0x0566..0x07FF

process stacks (no overlap with kernel state)

0x0800..RAMEND

scheduler / reset stack

Kernel state

The kernel data region holds, in order: the process table (state, saved SP, and wake tick per pid), the ls tree renderer’s per-depth connector flags, the scheduler’s saved SP / current-pid / tick counter, the 26 script variables and the lazy bus-init and redirection flags, the shell’s line and expansion buffers, the two-slot mount table, the script/working scratch buffers, and the per-pid background-job state.

Symbol

Address

Role

PROC_STATE

0x0340

per-pid state byte

PROC_SP

0x0344

per-pid saved stack pointer

PROC_WAKE

0x034C

per-pid wake tick while sleeping

TICKS

0x0364

tick counter from the Timer0 ISR (up)

VARS

0x0368

the 26 script variables az

CWD_LOC

0x039E

working directory as a packed (device, node)

LINE_BUF

0x03A0

current input line (64 bytes)

EXPAND

0x03E8

line after $var expansion (80 bytes)

MNT_*

0x0438

two-slot mount table (used / device / mountpoint)

SCRATCH

0x0440

script-line / file working buffer

BG_FILE

0x04E0

per-pid background script location

Process stacks

Each process gets a fixed stack that grows downward; pid 0 (the shell) gets the most room. The three tile 0x05660x07FF with no gaps and no overlap with the kernel state below:

Process

Top

Size

pid 0

0x07FF

320 B

pid 1

0x06BF

160 B

pid 2

0x061F

186 B

The EEPROM filesystem layout

Each block device holds the same tree, but file data is allocated dynamically from a shared cluster pool (a FAT-style allocator), so a file grows to whatever free space allows instead of a fixed per-file slot.

A node is 16 bytes:

Bytes

Field

[0]

type (0 free, 1 file, 2 dir)

[1]

parent node index

[2..3]

length (u16)

[4..11]

name (8 bytes, NUL-padded)

[12]

first cluster (0xFF = empty file)

The internal volume (device 0) uses the whole 1 KB on-chip EEPROM, laid out as the node table, then the FAT (one next-pointer byte per cluster; 0xFF free, 0xFE end-of-chain), then the data clusters:

Range (in device)

Contents

0x000..0x07F

node table (8 nodes × 16 B)

0x080..0x0B3

FAT (52 cluster pointers)

0x0B4..0x3F3

data (52 clusters × 16 B) — files up to ~832 B

The external I2C EEPROM (device 2) uses 64 nodes with fixed 256-byte slots.

A packed location

A filesystem location is a 16-bit value device * 256 + node. CWD_LOC and the mount table store locations this way, so a path can name a node on any device and crossing a mount point is just following the location to a different device. The helpers @loc, @loc_dev, and @loc_node pack and unpack them.