Memory and layouts

This page shows where the code, data and stacks of a program are in the 64 KiB of the //e. It tells how to select and change a linker layout, and how to read the memory report of the build. It also gives the cost of each part of the library.

Main memory

RangeUsed by
$0000-$007FOS and firmware zero page
$0080-$0099cc65 zero page. Startup saves it at entry and restores it before QUIT.
$009A-$00FFOS and firmware zero page
$0100-$013FThe ProDOS part of the hardware stack page. libtini does not change it.
$0140-$017FThe bank-transfer trampoline. Startup saves the original bytes and restores them at exit.
$0180-$01FFHardware stack: 128 bytes, with ProDOS interrupt dispatch
$0200-$03FFOS workspace and vectors. libtini does not change them.
$0400-$07FFText page 1. Fatal messages use it.
$0800-$1FFFNot used by cfg/libtini.cfg. Constants and low code in the full-game layout.
$2000-$BEFFThe program, its stacks, the near arena and the file buffer. See the layouts below.
$BF00-$BFFFProDOS global page and MLI entry. libtini does not change them.
$C000-$CFFFI/O and slot ROM. libtini does not change slot assignments.
$D000-$FFFFProDOS in the language card, and ROM. libtini does not change them and has no language-card code.

The two shared layouts

The two layouts make a raw ProDOS SYS file that ProDOS loads and starts at $2000. They link with the cc65 none.lib and the startup code of the project. A manifest selects one layout with config.

cfg/libtini.cfg (default)cfg/game.cfg
Used byThe diagnostic, tests, the starterLarger games
Code, data, BSSMAIN $2000-$9FFF, 32 KiBIMAGE from $2000; BSS in WORK, up to $AEFF
Constants and low codeWith the codeRODATA, AMEMCODE and LOWCODE run in LOW, $0800-$1FFF
C stack$A000-$A7FF$B700-$BEFF
Transfer staging$A800-$A87F$B400-$B47F
Near arena, NEARBSS$A900-$AEFF, 1,536 bytes$B480-$B6FF, 640 bytes
Guard$AF00-$AFFF$AF00-$AFFF
ProDOS file buffer, _ti_file_buffer$B000-$B3FF$B000-$B3FF

In cfg/game.cfg, startup copies the low segments one time from the end of the loaded image into $0800-$1FFF. It does this before it clears BSS. The code that runs one time at entry is in the ONCE segment. This layout puts ONCE at the addresses of BSS, so the clear of BSS makes these bytes available again. For the near-pointer checks, low memory is read-only.

A layout of your own

A game can link with its own copy of a layout file. Then it can use the memory that the library does not need. STARFALL makes no file calls. Thus examples/starfall/starfall.cfg does not define _ti_file_buffer.

That layout sets the end of WORK and of writable near memory, _ti_memory_end, to $B400. In the shared layouts this end is $AF00. Thus the guard page and the buffer give 1,280 more bytes of game memory. In that game, a file call does not link, so ProDOS cannot write over its variables.

Keep the checks of the build. The build rejects each segment outside the areas that the symbols of a layout give.

Read the memory report

starfall memory: LOW $0800-$1FFF 88 free; IMAGE $2000-$BEFF 1032 free; WORK $A26C-$B3FF 1110 free; NEAR $B480-$B6FF 1 free
starter memory: MAIN $2000-$9FFF 12321 free; NEAR $A900-$AEFF 1532 free

Each entry is a linker memory area with its free bytes. build/memory.json gives the same values and the used bytes for each program. When a segment does not fit, the build stops and gives the missing bytes:

starfall does not fit: segment BSS needs 50 more bytes in memory area WORK

IMAGE is the load image. It also holds the low segments until startup copies them. Thus its free bytes show how much more the SYS file can hold. WORK holds BSS while the program runs.

The near arena

Variables in the NEARBSS segment are in the near arena of the layout, outside the main area of the program. Startup sets them to zero, as for BSS. The linker rejects more data than the arena holds. All near API calls accept pointers into the arena. The library puts no data there.

#pragma bss-name (push, "NEARBSS")
static uint8_t level[512];
static uint16_t palette[16];
#pragma bss-name (pop)

STARFALL keeps its 547-byte simulation state, star columns, animated palette and two text buffers there. They use 639 of the 640 bytes.

Where code and data go

cc65 puts code in CODE, constants in RODATA, initialized variables in DATA and the other variables in BSS. Pragmas move a part of a file to a different segment:

/* Code that runs rarely, into low memory, in the full-game layout. */
#pragma code-name (push, "LOWCODE")
static void title_option(void) { /* ... */ }
#pragma code-name (pop)

/* Keep the constants of this file in main memory, where space is available. */
#pragma rodata-name (push, "CODE")
static const uint8_t table[64] = { /* ... */ };
#pragma rodata-name (pop)

Do not put code that runs after startup in ONCE. Use OSSTATE only for the startup code.

Auxiliary memory and banks

RangeUsed by
Selector 0, allThe OS and the display. It is never a resource bank.
Selector 0, $2000-$9FFFSHR pixels, scan-line bytes and palettes. ti_gfx_begin saves all 32,768 bytes.
Selectors 1-126, $0000-$01FFReserved. These are never resource bytes.
Granted selectors, $0200-$BFFF48,640 resource bytes for each bank
All selectors, $C000-$FFFFI/O, ROM and language card. Not used.

A resource continues from $BFFF of one granted bank to $0200 of the next bank. While auxiliary reads are mapped, only the page-one trampoline runs. Main memory and selector 0 come back before C code or interrupts continue. A grant of all selectors 1-126 gives 6,128,640 resource bytes.

The cost of each part of the library

A program links an archive member only when it uses one of its symbols. These sizes come from the CPU-only build. For your program, read build/<game>.map.

Archive membersLinked byCode and constantsState
memory, target_memory, target_hardwareAll resource and graphics calls3,977261
memory_nearti_near_move, ti_near_fill2710
memory_copyti_res_copy4340
errorti_error_*301
timingti_time_begin, ti_time_poll31611
timing_stepsti_steps_*33613
graphics, target_surfaceSurfaces, clear, rectangles1,769176
graphics_video, target_publishThe video session and ti_gfx_present1,31511
graphics_text, target_text, fontti_gfx_text, ti_gfx_text_opaque1,71144
target_digitsti_digits15012
graphics_rows, target_rowsti_gfx_present_rows7959
graphics_dotLines and bitmap fonts595136
graphics_lineti_gfx_line5460
graphics_fontti_gfx_text_font9250
graphics_blitBlits, sprites, maps, animation frames3,631288
scene, target_sceneSprite scenes, without TI_SCENE_STORAGE2,042197
audio, target_audioThe audio driver and speech5,075331
audio_musicti_music_start6327
target_songti_song_start1,120195
audio_envelopeti_audio_envelope*7130
audio_numbersti_speech_number5920
inputKeyboard and buttons26911
input_joystickti_joystick_read1,14635
input_stickti_stick_read47620
storage, target_storageFile calls and packs2,752236

The startup code adds 563 bytes. This includes 228 bytes of entry code, which the full-game layout uses again for BSS, and 98 bytes of saved OS state. The cc65 runtime routines that the program uses are added to this.

Save memory and time with cc65