Acorn BBC BASIC II Memory Map

← Acorn BBC BASIC

Addresses outside the ROM used by Acorn BBC BASIC II at run time — zero-page workspace, RAM buffers, and memory-mapped I/O. For the ROM code itself (&8000&BFFF), see the disassembly listing.

Access: R read, W write, B indexing base — the address is named as base,X/,Y, so the byte actually touched is base + index and the literal byte at this address is never itself accessed.

Zero page

Address Name Access Description
&0000–&0001 zp_lomem R/W/B

LOMEM: the start of variable storage. Defaults to TOP when a program is run and grows upward as variables are created (tracked by VARTOP); settable with LOMEM=.

&0002–&0003 zp_vartop R/W/B

VARTOP: the address just past the last allocated variable — where the next new variable goes. Runs from LOMEM up toward zp_stack_ptr; the two meeting is "No room".

&0004–&0005 zp_stack_ptr R/W/B

Pointer to the top of BASIC's value stack, which grows downward from HIMEM. The stack carries expression temporaries, strings pushed during evaluation, and — across a PROC/FN call — a saved copy of the 6502 hardware stack. "No room" is raised if it descends to meet VARTOP.

&0006–&0007 zp_himem R/W

HIMEM: the top of memory available to BASIC. The value stack (zp_stack_ptr) grows down from here; settable with HIMEM=. Read from the MOS (OSBYTE &84) at startup.

&0008–&0009 zp_erl R

ERL: the line number in which the last error occurred, set by the error handler and read by the ERL function (0 in immediate mode).

&000A zp_text_ptr_off R/W

PtrA offset: the offset of the next character within the program line addressed by zp_text_ptr. The interpreter reads the tokenised program through this pointer/offset pair.

&000B–&000C zp_text_ptr R/W

PtrA: the primary program/text pointer — the base address of the line currently being interpreted. Combined with zp_text_ptr_off to fetch tokens.

&000D–&0011 zp_rnd_seed R/W/B

RND state: the 33-bit linear-feedback shift register behind RND. &0D-&10 are a little-endian 32-bit value (bits 0-31); bit 0 of &11 is bit 32. Advanced 32 steps per RND call; reseeded by RND(-n).

&0012–&0013 zp_top R/W

TOP: the address just past the end of the tokenised program text (and the default for LOMEM). Read by the TOP pseudo-variable and set when the program is edited.

&0014 zp_print_bytes R/W

Print field width: the @%-derived field width used while formatting a number for PRINT, counting the characters emitted so far in the current field.

&0015 zp_print_flag R/W

Number-base flag for output: 0 selects decimal, negative selects hexadecimal (set by STR$~ and PRINT ~).

&0016–&0017 zp_error_vec R/W

ON ERROR handler address: where the interpreter jumps when an error is trapped. Reset to the default handler (&B433) at the start of each statement line; set by ON ERROR.

&0018 zp_page R

PAGE high byte: the start of the BASIC program as a page number (PAGE = this × 256). Read from OSHWM at startup; the PAGE pseudo-variable exposes it.

&0019–&001A zp_text_ptr2 R/W

PtrB: the secondary text pointer, used by the expression evaluator and the tokeniser while zp_text_ptr (PtrA) is preserved. Paired with zp_text_ptr2_off.

&001B zp_text_ptr2_off R/W

PtrB offset: the offset of the next character for the secondary text pointer zp_text_ptr2.

&001C–&001D zp_data_ptr R/W

DATA pointer: the address of the next DATA item to be READ. Set to the program start by RESTORE (or a line by RESTORE n) and advanced as items are read.

&001E zp_count R/W

COUNT: the number of characters printed since the last newline (the print column). Used for , field alignment and the WIDTH auto-newline; read by the COUNT function.

&001F zp_listo R/W

LISTO flags: the listing-indent options set by LISTO n. Control whether LIST indents FOR/REPEAT bodies and spaces tokens.

&0020 zp_trace_flag R/W

TRACE flag: &00 = tracing off, &FF = on (TRACE ON/TRACE OFF). When on, executed line numbers are printed in brackets up to zp_trace_max.

&0021–&0022 zp_trace_max R/W

TRACE ceiling: the highest line number that TRACE reports (TRACE n). Lines above it are not traced.

&0023 zp_width R/W

WIDTH: the print line width for the auto-newline (WIDTH n). &FF (the default) means no automatic wrap; compared against zp_count.

&0024 zp_repeat_level R/W

REPEAT stack depth: how many REPEAT loops are open, indexing repeat_stack. Not saved across a PROC/FN call, so leaving a loop via ENDPROC/GOTO leaks its entry.

&0025 zp_gosub_level R/W

GOSUB stack depth: how many GOSUB calls are open, indexing gosub_stack. Not saved across a PROC/FN call.

&0026 zp_for_level R/W

FOR stack depth: how many FOR loops are open (×15 gives the byte offset into for_stack). Not saved across a PROC/FN call.

&0027 zp_var_type R/W

Value type of the most recently fetched/evaluated value: 0 = string, positive (&40) = integer, negative = real. Drives the type dispatch throughout the evaluator.

&0028 zp_opt_flag R/W

Inline-assembler OPT flags (OPT n): bit 0 prints a listing, bit 1 enables error reporting, bit 2 assembles to the offset address O% instead of P%. &FF outside [ ] marks "not assembling".

&0029 zp_asm_opcode R/W/B

Inline assembler: the opcode byte being built for the instruction currently being assembled, before its operand bytes are appended.

&002A–&002D zp_iwa R/W/B

IWA — the 32-bit integer work accumulator. Holds the integer operand/result of the evaluator and the integer arithmetic primitives, and doubles as a pointer to a variable’s value during a fetch.

&002E–&0035 zp_fwa_sign R/W

FWA — floating-point work accumulator A (&2E-&35): sign (&2E), overflow/guard (&2F), excess-128 exponent (&30), 32-bit mantissa MSB-first (&31-&34) and a rounding byte (&35). The main register for real arithmetic; see zp_fwb_sign.

&0036 zp_strbuf_len R/W

Length of the string currently in the string work area at string_work.

&0037–&0038 zp_general R/W/B

General-purpose work pointer (&37-&3A). Reused widely — the tokeniser/line scanner, the variable-chain walk, the program editor — as a scratch 16-bit pointer.

&0039–&003A zp_fileblk R/W

Filing-system control block (&39 onward): the OSFILE / load-save parameter block. Filing is not active during arithmetic, so this overlaps the FP workspace below (zp_fwb_sign onward).

&003B–&0042 zp_fwb_sign R/W

FWB — floating-point work accumulator B (&3B-&42), same layout as zp_fwa_sign. Supplies the second operand for binary floating-point operations (add, multiply, divide).

&003C zp_fwb_ovf

FWB overflow byte (&3C), part of zp_fwb_sign. A much-reused scratch location: outside floating point it serves as the tokeniser's line-number-arming flag (&FF after GOTO etc. means encode the next number as a line number), a variable-chain walk pointer, an array dimension-descriptor offset, and LIST's REPEAT/UNTIL indent counter. Read each use in its own context rather than assuming a single global meaning.

&0043–&0047 zp_fp_temp R/W

Floating-point temporary / scratch (&43-&47). Holds spill bytes for the FP routines and serves as the quotient build area for integer DIV/MOD.

&0048 zp_dp_flag R/W

Decimal-point-seen flag, set while parsing a number literal so a second . is rejected and the fractional digits are scaled.

&0049 zp_dec_exp R/W

Decimal exponent accumulated while parsing the E part of a real literal.

&004A zp_int_exp R/W

Integer-part / exponent scratch: holds the integer exponent during number parsing and the integer part of a value in EXP and the int/fraction split.

&004B–&004C zp_fp_ptr R/W

Pointer to a packed 5-byte floating-point value (a variable or an FP temporary) for the pack/unpack routines.

&004D–&004E zp_coeff_ptr R/W

Pointer to the current coefficient table, used while evaluating the continued-fraction approximations in the trig functions.

&00FD–&00FE zp_error_ptr R/W

Pointer to the error block currently being reported (the bytes after a BRK): the error number and message the handler is processing.

&00FF zp_escflg R/W

ESCFLG — the MOS escape flag. Its top bit is set when Escape is pressed; BASIC polls it between statements, acknowledges it via OSBYTE, and raises the "Escape" error.

6502 hardware stack

Address Name Access Description
&0100–&01FF hw_stack R/W/B

The 6502 hardware stack (page 1), used normally for JSR/RTS and register saves. A PROC/FN call copies a snapshot of the live stack onto the BASIC value stack and restores it on return, so call nesting is bounded by free stack space rather than a fixed table.

&0106 frame_local_count B

Base for the PROC/FN call frame's LOCAL/parameter restore count: frame_local_count,X with X = the running body's stack pointer (&F5) addresses the count byte at &01FB. stmt_local bumps it as each LOCAL or parameter is saved; call_proc_fn replays that many saved values on =/ENDPROC.

Resident integers & FP workspace

Address Name Access Description
&0400–&046B resint_at R/W/B

The resident integer variables, four bytes each: @% here at &0400, then A%-Z% at &0404-&046B. @% sets the PRINT/STR$ number format. Two slots double as the inline assembler's counters — O% (the 'O' slot, &043C) is the offset-assembly address and P% (the 'P' slot, &0440) the program counter.

&046C–&047F fp_temp1 R/W/B

Four 5-byte packed floating-point temporaries: TEMP1 (&046C), TEMP2 (&0471), TEMP3 (&0476) and TEMP4 (&047B). The maths routines stash intermediate reals here while reusing FWA / FWB.

&047F var_table_base B

The −1 base for the variable chain-head table var_ptr_table: the clear loop stores var_table_base,X for X = &80…1, zeroing &0480-&04FF.

&0480–&04FF var_ptr_table R/W

The dynamic-variable chain-head table: a two-byte head pointer per initial-character class (A-Z, a-z, _, @), addressed as &0400 + 2×char. find_variable walks the linked list of variables sharing an initial character; create_variable links a new one in at the head.

FOR / REPEAT / GOSUB stacks

Address Name Access Description
&04F1 for_var_lo B

Current FOR frame, control-variable address low (offset +0): the ,X read base (X = zp_for_level) NEXT uses to match and reload the loop variable.

&04F2 for_var_hi B

Current FOR frame, control-variable address high (offset +1).

&04F3 for_type B

Current FOR frame, control-variable type (offset +2): 5 = real, otherwise integer.

&04F4 for_step0 B

Current FOR frame, STEP byte 0 (offset +3): NEXT adds the STEP to the control variable. An integer STEP uses bytes 0-3; a real STEP adds a fifth byte at +7.

&04F5 for_step1 B

Current FOR frame, STEP byte 1 (offset +4).

&04F6 for_step2 B

Current FOR frame, STEP byte 2 (offset +5).

&04F7 for_step3 B

Current FOR frame, STEP byte 3 (offset +6).

&04F9 for_limit0 B

Current FOR frame, loop-limit byte 0 (offset +8): NEXT compares the control variable against it. An integer limit uses bytes 0-3; a real limit adds a fifth byte at +C.

&04FA for_limit1 B

Current FOR frame, loop-limit byte 1 (offset +9).

&04FB for_limit2 B

Current FOR frame, loop-limit byte 2 (offset +A).

&04FC for_limit3 B

Current FOR frame, loop-limit byte 3 (offset +B).

&04FE for_loopback_lo B

Current FOR frame, loop-body text pointer low (offset +D): where NEXT resumes each iteration.

&04FF for_loopback_hi B

Current FOR frame, loop-body text pointer high (offset +E).

&0500–&0595 for_stack B

The FOR stack: up to 10 frames of 15 bytes each (&0500-&0595; depth in zp_for_level). Each frame holds the control-variable address and type, the STEP and limit values, and the loop-back text pointer — pushed by FOR, consulted and updated by NEXT.

&0501 for_set_ptr_hi B

Write base FOR uses to stack a new for_stack frame: control-variable address high (offset +1). The low byte goes to for_stack itself; the read-side counterpart is for_var_hi.

&0502 for_set_type B

New-frame write base: control-variable type (offset +2).

&0503 for_set_step0 B

New-frame write base: STEP byte 0 (offset +3).

&0504 for_set_step1 B

New-frame write base: STEP byte 1 (offset +4).

&0505 for_set_step2 B

New-frame write base: STEP byte 2 (offset +5).

&0506 for_set_step3 B

New-frame write base: STEP byte 3 (offset +6).

&0508 for_set_limit0 B

New-frame write base: loop-limit byte 0 (offset +8).

&0509 for_set_limit1 B

New-frame write base: loop-limit byte 1 (offset +9).

&050A for_set_limit2 B

New-frame write base: loop-limit byte 2 (offset +A).

&050B for_set_limit3 B

New-frame write base: loop-limit byte 3 (offset +B).

&050D for_set_loop_lo B

New-frame write base: loop-body text pointer low (offset +D).

&050E for_set_loop_hi B

New-frame write base: loop-body text pointer high (offset +E).

&05A3 repeat_loop_lo B

The −1 read base for the REPEAT stack low bytes: UNTIL loads repeat_loop_lo,X (X = zp_repeat_level) to reload the current loop-start pointer.

&05A4–&05B7 repeat_stack B

REPEAT loop-start text pointers, low bytes — up to 20 nested (depth in zp_repeat_level); high bytes in repeat_stack_hi. UNTIL reloads the pointer to re-test its condition.

&05B7 repeat_loop_hi B

The −1 read base for the REPEAT stack high bytes (repeat_stack_hi); pairs with repeat_loop_lo.

&05B8–&05CB repeat_stack_hi B

High bytes of the REPEAT loop-start pointers; low bytes in repeat_stack.

&05CB gosub_return_lo B

The −1 read base for the GOSUB stack low bytes: RETURN loads gosub_return_lo,X (X = zp_gosub_level) to recover the return position.

&05CC–&05E5 gosub_stack B

GOSUB return text pointers, low bytes — up to 26 nested (depth in zp_gosub_level); high bytes in gosub_stack_hi. RETURN pops the top entry.

&05E5 gosub_return_hi B

The −1 read base for the GOSUB stack high bytes (gosub_stack_hi); pairs with gosub_return_lo.

&05E6–&05FF gosub_stack_hi B

High bytes of the GOSUB return pointers; low bytes in gosub_stack.

String and line buffers

Address Name Access Description
&05FF strbuf_base B

The −1 base for the string work area string_work: strbuf_base,X (X = 1…length) addresses the buffer, so index 1 is the first character — the string routines fill and read it one-based.

&0600–&06FF string_work R/W/B

The string work area / CALL parameter block. BASIC builds string results here — the text of STR$, the digits of a number conversion, a popped string for comparison — with the length in zp_strbuf_len. CALL also assembles its parameter block here.

&0700–&07FF line_input_buf R/W

The line input buffer. The line editor reads a typed line (at the > prompt or for INPUT) into here via OSWORD 0; the tokeniser then processes it in place.