Skip to content

PIOC-OS - Memory management

Image: encos-ser-all-banks-68k.bin Date: 2026-07-26 Status: three allocators identified. Heap free-list node format is PARTIAL.


1. Three separate allocators - do not confuse them

Allocator Region Freed? Used for
General heap 0x1300-0x1A00 yes, first-fit free list process descriptors, port structures, list nodes
PLANC frame arena separate, bump-allocated never routine activation frames
Fixed pools statically placed returned to their own free list RX buffers, XTRB / COBF / RbRcv / RbCmd / connection records

The frame arena being non-reclaiming is the single most surprising property of this firmware and is covered in detail in the ghidra-planc skill. It is why a caller can legitimately read results out of a callee's frame after that callee has returned.


2. The general heap

Address Role
0x1300-0x1A00 heap body
0x0D00-0x0D0A heap control words
HeapInitFreeList 0x35BE build the initial free list
HeapAllocateBlock 0x36A4 first-fit allocation

The heap top is computed at boot from the board configuration record: (0x04CA)+0x30 gives the DRAM size in 2KB pages, and the heap ceiling is derived from it (02-BOOT-AND-INIT.md section 4). So the usable heap depends on what the ND-100 host declared, not on anything in the ROM. An emulator that leaves the board config zero will produce a zero-sized or wrongly-sized heap.

Note the control words at 0x0D00-0x0D0A sit immediately below the module directory record at 0x0D0C - adjacent but unrelated structures. Do not read 0x0D00 as part of the directory.

NOT ESTABLISHED: the free-list node layout, the allocation granularity, and whether there is a coalescing free.


3. The PLANC frame arena

Frames are bump-allocated from a separate arena and never popped. Only the pair (saved A6, return address) lives on the CPU stack.

Two allocators exist, and they differ in skip distance - which matters because the bytes after the call are data, not code:

Allocator Skip distance Inline descriptor
0x4492 4 one longword = the frame size. Used by essentially every PLANC routine, including all 27 trap handlers
0x4456 8 8 bytes. Used by the trap #2 dispatcher at 0x3498

There are three copies of the leaf runtime, one per linked bank (around 0x134xx, 0x44xx and 0x6BCF0-0x6BF8B), each with its own frame allocator. 0x4478 is byte-identical to 0x13524. Check which bank a caller sits in before assuming which copy it uses.

Frame layout is documented in the ghidra-planc skill; the field that matters for memory purposes is +0x00 STP, the next-free cursor - the prologue follows it to reach its own frame and republishes it for its callee. The arena is therefore a simple stack of frames that only ever grows during a call chain, unwound wholesale rather than per-frame.


4. Fixed pools

Each has its own init and free-list routine. Identified so far:

Pool Init Free
RX buffer pool rxpool_init 0x5512, maybe_init_buffer_pool_188da 0x5322 drain_freehead_to_readyring 0x51D0
XTRB LNCNInitFreeXtrbPool 0x8342
COBF LNCNInitFreeCobfPool 0x83E8
RbRcv LNCNInitFreeRbRcvPool 0x84EA LNCNFreeRbRcv 0x84BC
RbCmd LNCNInitFreeRbCmdPool 0x8586 LNCNFreeRbCmd 0x855A
Connection records LNCNInitConnPool 0x8694 LNCNClearAndFreeConn 0x85F4
POCS message buffers PocsInitMessageBufferPool 0xC4AC
POCS session descriptors PocsInitSessionDescriptorPool 0xC7B8 PocsReleaseSessionDescriptor 0xCBCC
XGate free list XGateFreeListInit 0xC31E XGateFreeListAppendEntry 0xC2F0

The behaviour that matters for emulation

RX pool exhaustion is a SILENT drop. When no free node is available the frame is discarded and the counter at 0x188A0 is bumped, and the host is never notified. An implementation that reports an error here is being more helpful than the real card and will diverge from it.


5. The port pools

Covered in 06-IPC-AND-MESSAGING.md, repeated here because they are allocators: two port pools at 0x2D472 (classes 0 and 1) and 0x2D4F4 (class 2), plus the name registry at 0x2D354. All three carry a word 0xAAAA at offset +4 as an "initialised" signature; a mismatch makes the port calls return -2.


6. Open

  • Heap free-list node format, granularity, and whether frees coalesce
  • Sizes of every fixed pool (element count x element size)
  • Where the frame arena physically lives and how large it is
  • Whether the arena is ever reset other than by unwinding

Provenance

The allocator inventory and the two frame allocators are established. The heap-top dependency on board config is a prior finding. Section 6 is what static reading has not answered.