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 0x0060–0x085F) and the ATmega328p
(0x0100–0x08FF): 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 |
|---|---|
|
compiler statics (ATmega32 from |
|
kernel state (zeroed at boot; |
|
process stacks (no overlap with kernel state) |
|
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 |
|---|---|---|
|
|
per-pid state byte |
|
|
per-pid saved stack pointer |
|
|
per-pid wake tick while sleeping |
|
|
tick counter from the Timer0 ISR ( |
|
|
the 26 script variables |
|
|
working directory as a packed |
|
|
current input line (64 bytes) |
|
|
line after |
|
|
two-slot mount table (used / device / mountpoint) |
|
|
script-line / file working buffer |
|
|
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 0x0566–0x07FF with no gaps and no overlap with
the kernel state below:
Process |
Top |
Size |
|---|---|---|
pid 0 |
|
320 B |
pid 1 |
|
160 B |
pid 2 |
|
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 |
|---|---|
|
type (0 free, 1 file, 2 dir) |
|
parent node index |
|
length (u16) |
|
name (8 bytes, NUL-padded) |
|
first cluster ( |
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 |
|---|---|
|
node table (8 nodes × 16 B) |
|
FAT (52 cluster pointers) |
|
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.