Skip to content

Memory map

Every data address P8X software uses, as generators/gen_memmap.py defines it: memory regions, I/O ports and the scratch areas of the BIOS, the OS and the commands. The same generator writes memmap.inc for the assembler and memmap.h for C, and the printable memory map is generated from it too. This page is built from its Python output, generators/memmap.py, so it cannot disagree with it.

In short: ROM $0000-$17FF (6 KB, the monitor and BIOS), RAM $1800-$FEFF, I/O $FF00-$FFFF. The OS loads at $2000; programs run from $5900.

Memory-region anchors

Name Value Notes
RAMBASE $1800 first RAM address (ROM shrunk 8K->6K 2026-09-14; $1800-$1FFF is a low RAM island)
IOBASE $FF00 memory-mapped I/O page
ROMSIZE $1800 6K firmware ROM $0000-$17FF (monitor uses ~5.2K)
RAMSIZE $E700 RAM span $1800-$FEFF (IOBASE-RAMBASE)
OSORG $2000 OS load/link address (still $2000; the $1800-$1FFF RAM island holds relocated scratch)
TPABASE $5900 transient program area base (RUNnable programs load here)
CSTACKTOP $F800 compiler C-stack top (grows down; p8cc __csp init)

I/O ports ($FF00-$FFFF)

Name Value Notes
SWITCHES $FF00 read: DIP/switch input (I/O card port 0; emulator -s)
LEDS $FF02 write: LED output latch (emulator -L stamps; POKE 65282)
IRQGEN $FF06 write (any value): assert a maskable IRQ (emulator device-IRQ model; hardware IRQ comes from the IRQ-controller card)
ACIAS $FF04 ACIA status (rd) / control (wr)
ACIAD $FF05 ACIA data
ACIA2S $FF08 2nd ACIA status (rd) / control (wr) -- the Kermit/serial-terminal port
ACIA2D $FF09 2nd ACIA data
CFDATA $FF10 CF task file
CFFEAT $FF11
CFSCNT $FF12
CFLBA0 $FF13
CFLBA1 $FF14
CFLBA2 $FF15
CFHEAD $FF16 $E0 = LBA mode, drive 0
CFCMD $FF17 command (wr) / status (rd)
CFSTAT $FF17
MDA $FF30 MDU operand a, low byte (write clears the high byte)
MDB $FF31 MDU operand b, low byte
MDC $FF32 MDU divisor c, low byte
MDQ $FF33 read: MDU result (a*b)/c, low byte (poll MDSTAT first)
MDGO $FF34 write (any value): start the MDU operation
MDSTAT $FF35 read: bit7 BUSY
MDID $FF36 read: $4D 'M' -- MDU-presence probe
GLDATA $FF50 GL: write one command-stream byte into the FIFO
GLSTAT $FF51 read: bit7 FIFO full, bit6 busy, bit1 error pending, bit0 read-back pending
GLRB $FF52 read: pop one read-back FIFO byte
GLERR $FF53 read: pop one error FIFO byte (0 = empty)
GLID $FF54 read: $47 'G' -- graphics-language presence probe
PSADAT $FF58 read: port A (keyboard) byte, ready cleared on read (raw Set-2)
PSAST $FF59 port A status: r bit0 ready/bit1 overrun/bit2 parity; w bit0 CLK-low/bit1 DATA-low
PSBDAT $FF5A read: port B (mouse) byte, ready cleared on read
PSBST $FF5B port B status: as PSAST
PSLINE $FF5C read: live line states (bit0 Aclk/bit1 Adat/bit2 Bclk/bit3 Bdat) for the bit-banged transmit
PSID $FF5E read: $4B 'K' -- PS/2-card presence probe (absent floats $FF)
MDAH $FF39 MDU operand a, high byte (write AFTER MDA)
MDBH $FF3A MDU operand b, high byte
MDCH $FF3B MDU divisor c, high byte
MDQH $FF3C read: MDU result, high byte

BIOS / FS scratch (moved to $1F00-$1FFF island)

Name Value Notes
LBUF $1F00 input line buffer
ADDRL $1F40 parsed address
ADDRH $1F41
HEXL $1F42 hex accumulator
HEXH $1F43
LBA $1F47 current LBA, byte 0 (bits 7:0)
LBA1 $1F48 LBA byte 1 (bits 15:8) — 0 after CFINIT unless set
LBA2 $1F49 LBA byte 2 (bits 23:16) — 0 after CFINIT unless set
FNAME $1F4A 12-byte filename (space-padded) — in for both calls
FSRC $1F56 FCREATE: source address of the file data (2 bytes)
FLEN $1F58 file length in bytes (3 bytes): FCREATE in, FFIND out
FSAV $1F5B FCREATE scratch: requested length saved across FFIND (3)
ROLBA $1F5E next sector LBA to read (3)
ROREM $1F61 bytes remaining in the file (3)
ROBUF $1F64 caller's 512-byte sector buffer address (2)
ROPTR $1F66 read cursor within ROBUF (2)
ROCNT $1F68 bytes left in ROBUF; 0 -> refill (3)
WOLBA $1F6B current output sector LBA (3)
WOPOS $1F6E byte offset within SBUF; 512 -> flush (2)
WOTOT $1F70 total bytes written (-> FLEN at close) (3)
DIRLBA $1F73 current directory start LBA, low byte (16-bit: +DIRLBA1)
DIRN $1F74 current directory sector count (1)
FFLAG $1F75 flag of the entry FSCAN matched (file $01 / dir $02)
RPATH $1F76 FRESOLVE path cursor (2)
DILBA $1F78 iteration: current directory sector LBA (1)
DICNT $1F79 iteration: sectors remaining (1)
DIIDX $1F7A iteration: entry index within the sector (0..15)
FLAREM $1F7B FLOADAT remaining-bytes counter (CFRDSEC clobbers TMP) (3)
DIBUFH $1F7E FNEXT directory-buffer page (high byte; low byte 0).
DILBA1 $1F7F FNEXT iteration sector LBA, high byte
DIRLBA1 $1F80 current directory start LBA, high byte (pairs DIRLBA)
FCDH $1F81 FCREATE directory-sector scan cursor, high byte (HEXL)
DRVSEL $1F82 current CF drive for sector I/O (0/1); ORed into CFHEAD
CFTOL $1F83 CF bounded-wait timeout counter, low byte
CFTOH $1F84 CF bounded-wait timeout counter, high byte
ROSDRV $1F85 read-stream drive (captured by FOPEN, re-asserted by FG_FILL)
WOSDRV $1F86 write-stream drive (captured by FWOPEN, re-asserted by FW_FLUSH)
CFIMASK $1F87 bit N set = drive N has been CFINIT'd this session
REMW $1F88 FCOM_CORE ceil(FLEN/512): 24-bit remaining counter (3)
CNTW $1F8B FCOM_CORE sector count, 16-bit (files may span >255 sectors)
ROSTAT $1F5E read-stream state base (ROLBA..ROCNT, 11 bytes)

Shared sector buffer

Name Value Notes
SBUF $1D00 sector buffer

Hardware stack

Name Value Notes
STKTOP $FEFF

OS scratch (top moved to the $1800-$1FFF island)

Name Value Notes
LINEBUF $5700 shell input line (64 bytes)
CMDBUF $5740 parsed command word (16 bytes)
NAMEBUF $5750 12-byte filename (search key / DIR scratch)
ECNT $5763 entries-left-in-sector counter
FLAGS $5764 current entry flag byte
MATCH $5765 1 = name matched / strings equal
LENLO $5766 entry length, low 16 bits
LENHI $5767
STARTLO $5768 entry start LBA (low byte)
LOADLO $5769 entry load address
LOADHI $576A
EXECLO $576B entry exec address
EXECHI $576C
DLBA $576D directory sector being scanned
SECCNT $576E sectors left to transfer
CURLBA $576F current data LBA
ENTPL $5770 pointer to a directory entry (in SBUF):
ENTPH $5771 flag byte for DEL, entry start for SAVE
ARGPL $5772 saved arg position in LINEBUF
ARGPH $5773
HXLO $5774 GETHEX result
HXHI $5775
DIGIT $5776 HEXVAL digit value
SHCNT $5777 shift counter
SVSTLO $5778 SAVE source start address
SVSTHI $5779
FREELO $577A boot-block free pointer (next data LBA)
FREEHI $577B
SRCLO $577C running source pointer during the copy
SRCHI $577D
REM $577E sectors remaining in the SAVE write loop
NF $5780 running next-free LBA
PFOUND $5781 1 if this pass found an unpacked extent
MINSTRT $5782 smallest start LBA >= NF this pass
MINSEC $5783 that extent's sector count
MINPL $5784 pointer to that entry's start-LBA field (in SBUF)
MINPH $5785
MINDL $5786 that entry's directory sector LBA
ESTART $5787 current entry start LBA (low byte)
SRCL $5788 copy source LBA
DSTL $5789 copy dest LBA
CPYN $578A sectors left to copy
CANDL $578B current entry's start-field pointer
CANDH $578C
ROOTN $578D root directory sector count (4)
DATABASE $578E first data LBA (37)
CWDL $578F current directory: start LBA
CWDN $5790 sector count
SDIRL $5791 directory being scanned this op (start LBA)
SDIRN $5792 sector count
SCNT $5793 sectors-left counter while scanning a directory
LSL $5794 SETPATH: pointer to the last '/' in CWDPATH
LSH $5795
PATHL $5796 saved path cursor across DESCEND (FINDENT clobbers P2)
PATHH $5797
NEWLBA $5798 MKDIR: LBA of the new directory extent
PSL $5799 MKDIR: parent dir start LBA / sector count
PSN $579A
EFLAG $579B flag byte WRENT stamps (F_FILE for SAVE, F_DIR for MKDIR)
RMDL $579C RMDIR: parent directory sector holding the entry
CDST $579D current directory: start LBA / sectors / entry index
CDSC $579E
CIDX $579F
REDIRF $57A0 0 = console, 1 = capturing to RBUF
RCH $57A1 OUTCH: byte being emitted
RS2L $57A2 OUTCH: saved caller P2
RS2H $57A3
RPTRL $57A4 OUTCH: next free byte in the capture buffer
RPTRH $57A5
RHX $57A6 OPHEX8 scratch
REDNAME $57A7 redirect target filename (null-terminated, <=48): $63A7..$63D6
FNDIR $57D7 directories counted
FNFIL $57D8 files counted
FNDEL $57D9 deleted slots counted
FMAXE $57DA highest extent end LBA seen (data area only)
FUSED $57DB data sectors occupied by live extents
FERR $57DC problems found (0 = clean)
FCHILD $57DD CHKDD: directory whose '..' is being checked
FEXP $57DE CHKDD: expected parent LBA
TSP $57E0 tree stack depth (0 = at root level)
TI $57E1 scratch loop counter for the frame stack
LENHI2 $57E2 entry length, bits 16..23 (the BIOS FLEN 3rd byte)
SECCH $57E3 SECCOUNT sector-count high byte (files >255 sectors)
MINSECH $57E4 PACK: chosen extent's sector count, high byte
CPYNH $57E5 PK2MOVE: sectors-to-copy counter, high byte
TFRAME $58B7 8 frames x 4 bytes (dst_lo,dst_hi,dsc,idx): $64B7..$64D6
PPSEC $57FA chosen extent's parent-entry: dir sector LBA / slot
PPSLOT $57FB
CANDSEC $57FC candidate entry's location during the find walk
CANDSLOT $57FD
PARST $57FE PK2FIX: parent directory start LBA (for '..')
CWDPATH $5800 textual CWD path for the prompt (up to 48 bytes)
INMODE $5830 SYS_GETC source: 0 = console, 1 = the read stream
INARM $5831 shell armed a '< file' for the next RUN
INNAME $5832 '< file' name (null-terminated, <=48): $6432..$6461
PIPEF $5862 pipe stage: 0 none, 1 left ran, 2 right ran
PIPEBUF $5863 saved right-hand command of a 'cmd | cmd' ($6463..$64A2)
CWDLH $58A3 CWDL high byte (current working directory start LBA)
SDIRLH $58A4 SDIRL high byte (directory being scanned this op)
STARTHI $58A5 STARTLO high byte (entry start LBA from FINDENT)
DLBAH $58A6 DLBA high byte (directory-sector scan cursor)
NEWLBAH $58A7 NEWLBA high byte (MKDIR new extent)
PSLH $58A8 PSL high byte (MKDIR parent extent)
PARSTH $58A9 PARST high byte (PACK '..' parent fix)
RMDLH $58AA RMDL high byte (RMDIR parent sector)
CURLBAH $58AB CURLBA high byte (SAVE data-write LBA, 16-bit)
NFH $58AC NF high byte (PACK next-free target)
MINSTRTH $58AD MINSTRT high byte (smallest start LBA this pass)
CDSTH $58AE CDST high byte (current directory in the walk)
CANDSECH $58AF CANDSEC high byte (candidate entry's dir sector)
PPSECH $58B0 PPSEC high byte (chosen extent's parent-entry sector)
SRCH $58B1 SRCL high byte (PK2MOVE copy source)
DSTH $58B2 DSTL high byte (PK2MOVE copy dest)
FCHILDH $58B3 FCHILD high byte (CHKDD child dir)
FEXPH $58B4 FEXP high byte (CHKDD expected parent)
FMAXEH $58B5 FMAXE high byte (FSCK highest extent end)
FUSEDH $58B6 FUSED high byte (FSCK live data sectors)
REDAPP $58D7 >> append redirect: 1 = prepend the existing file
APHAVE $58D8 >> : 1 = an existing file to prepend was found
APLBA $58D9 >> : old file's start LBA (2 bytes)
APREM $58DB >> : old file bytes left to copy (2 bytes)
APCHK $58DD >> : bytes to emit from the current sector (2 bytes)
SCRIPTM $58E0 1 = the shell is running lines from a sh script
SCRSAVE $58E1 saved script read-stream state (ROSTATE 13 + ROSDRV = 14: $64E1..$64EE)
SCRCNT $58EF byte counter for SAVESCR/RESTSCR (1)
APBUF $1B00 >> prepend sector buffer (512B, below the TPA); also the
IBUF $1800 512-byte buffer for the stdin read stream
PATHBUF $1A00 search path, ';'-separated dirs; default '/BIN' ($6700..$673F)
RUNPATH $1A40 scratch: candidate program path built during a lookup ($6740..$679F)
RUNSKIP $1AA0 DORUN: 1 = skip the program-name word for the arg pointer
PSCANL $1AA1 PATH search cursor into PATHBUF (low)
PSCANH $1AA2 PATH search cursor into PATHBUF (high)
GPLF $1AA3 SYS_GETC console: 1 = a LF is pending after a CR keypress
CURDRIVE $1AA4 derived: 1 if the CWD is under /d1 (drive 1), else 0
DRVINIT $1AA5 bitmask: bit N set = drive N has been CFINIT'd this session
MPSAV $1AA6 MNTPFX: saved P2 (2 bytes) while sniffing a 'd1' prefix

TPA (transient programs)

Name Value Notes
RBUF $5900 capture buffer = the TPA (free during a built-in cmd)

Shell history

Name Value Notes
HISTST $1F8E history ring: index where the next entry is written (0..HISTN-1)
HISTCT $1F8F history ring: number of stored entries (0..HISTN)
HISTNV $1F90 history ring: recall cursor (0 = not navigating; N = N lines back)
HISTRING $F800 history ring buffer base: HISTN x HISTLEN bytes ($F800..$F9FF, the free 512 B above CSTACKTOP; $FA00 = glob page, $FC00 = RDBUF, $FE00 = stack)

Shell completion

Name Value Notes
CMPPFX $1B00 tab-complete: leaf prefix being completed (NUL-term, 64; aliases APBUF)
CMPLCP $1B40 tab-complete: longest common prefix of the matches (NUL-term, 16; aliases APBUF)
CMPDIR $1B50 tab-complete: directory-part path string, for CDPATH (NUL-term, 64; aliases APBUF)
CMPPL $1F91 tab-complete: length of the typed leaf prefix
CMPCNT $1F92 tab-complete: number of matches (saturates at 255)
CMPFW $1F93 tab-complete: 1 = completing the command word (first word)
CMPTABF $1F94 tab-complete: 1 = the previous key was a no-progress Tab
CMPISD $1F95 tab-complete: 1 = the sole match is a directory
CMPLM $1F96 tab-complete: 1 = scan in list mode (print matches)
CMPDL $1F97 tab-complete: target directory start LBA, low byte
CMPDLH $1F98 tab-complete: target directory start LBA, high byte
CMPDN $1F99 tab-complete: target directory sector count
CMPCUR $1F9A tab-complete: saved line length (cursor) across the scan
CMPSAV $1F9B tab-complete: saved SBUF entry cursor across a candidate (2)
CMPWLB $1F9D tab-complete: directory-walk running sector LBA (2)
CMPWSC $1F9F tab-complete: directory-walk sectors remaining
CMPIX $1FA0 tab-complete: KWTAB index during the built-in scan

Console tty state

Name Value Notes
TTYRAW $1FA1 0 = expand a bare LF to CR LF on console output; nonzero = pass bytes through untouched (for binary over the serial link, like stty raw)
TTYLST $1FA2 last byte PUTC transmitted, so an LF that already follows a CR is not doubled
TTYCH $1FA3 PUTC's saved character (PUTC must preserve A)

Graphics presence

Name Value Notes
GFXPRES $1FA4 1 = GL card fitted (screen is the display); 0 = headless serial console

Glass tty

Name Value Notes
GTCOL $1FA5 glass TTY cursor column (0..GTCOLS-1)
GTROW $1FA6 glass TTY cursor row (0..GTROWS-1)
GTSUSP $1FA7 nonzero = glass TTY suspended (a full-screen GL app owns the screen; CONOUT is serial-only)
GCONEN $1FAF 1 = glass TTY console ENABLED (CONOUT mirrors to the GL screen); 0 = off (serial-only, the default -- screen on enables it)
GTXL $1FA8 glass TTY cursor pixel x, low byte (0..474, step 6)
GTXH $1FA9 glass TTY cursor pixel x, high byte
GTYL $1FAA glass TTY text-baseline pixel y (window, y-up), low byte
GTYH $1FAB glass TTY text-baseline pixel y, high byte
GTCH $1FAC glass TTY: the byte currently being drawn
GTTMP $1FAD glass TTY: FIFO-push scratch (holds the byte across the backpressure wait)
GTCNT $1FAE glass TTY: table-stream byte counter