a-box
A program of Character sets.
main.ngp
include "atari/130xe.ngp"
modules { "box.asm" }
container xex
130xe.ngp project
; An Atari 130XE: five Banks as a unit set — the four of extended memory and,
; last, the machine's own memory under the Window — the Window PORTB brings
; one of them into, every Region of the address space, and the Modules a
; program on this machine needs. It declares no storage. A program that loads
; anything during a run includes `atari/extension.ngp` beside this, which makes
; the Banks its storage. What PORTB takes to show a state is the
; driver's and not here, and the OS is two Modules rather than a Region because
; it occupies memory for a while rather than being a truth about addresses: its
; variables for the whole of a program, its ROM in every Phase that does not
; say `without osrom` — see 0229. The same register switches the ROMs, so the
; driver is what declares them.
target {
cpu "6502"
; DOS loads a `.xex`, and a Project naming any other Container is refused
; here rather than at the writer.
containers xex
; No Window has a base, so the memory under this one is a Bank like the
; others and nothing of the program stands there but a Pane or storage — see
; docs/decisions/0229-no-window-has-a-base.md.
units extension 5
window ext $4000 .. $7FFF views extension
}
target {
region ram $0000 .. $CFFF ram
region $D800 .. $FFFF ram
region stack $0100 .. $01FF reserved
region io $D000 .. $D7FF register
; The RAM the OS ROM covers, named so that a Section may say `in underOsLow`
; and stand there: only in a Phase without `osrom`, or hidden under it where
; nothing needs it — see docs/decisions/0243-a-section-may-name-the-region-it-stands-in.md.
region underOsLow $C000 .. $CFFF ram
region underOsHigh $D800 .. $FFFF ram
; This machine takes a `.xex` and nothing else, and a `.xex` is loaded by a
; DOS, which stays where a DOS of the 2.x family stays. A Project whose DOS
; takes more says so with a `reserved` Region of its own, which narrows this
; one further.
region dos $0700 .. $1FFF reserved
; What the driver writes. A Project that wants more of the hardware by name
; declares it, as it declares the memory its DOS holds.
register PORTB $D301
; The hardware that holds a Section while a program has handed it one, by
; `.root NAME` before the taking of its address, until it hands another or
; `.release NAME`: what it holds stays where it is for that long. See
; docs/decisions/0247-the-hardware-holds-a-section-for-as-long-as-it-is-given-it.md.
holder dlist ; ANTIC's display list: SDLSTL, or DLISTL
holder dli ; the display list interrupt: VDSLST
holder vbi ; the immediate vertical blank: VVBLKI
holder vbd ; the deferred vertical blank: VVBLKD
holder nmi ; $FFFA, where the OS ROM is switched out
holder irq ; $FFFE, where the OS ROM is switched out
holder chbase ; the character set: CHBAS, or CHBASE
holder pmbase ; the player-missile memory: PMBASE
holder dosini ; DOSINI: called once a boot returns, and on every reset
}
; The OS and the driver, listed as a file of the Project's own would be. The
; driver is here and not beside the storage because it does more than read it:
; it shows a Pane's Bank and switches the ROMs, with or without storage. BASIC
; is not listed: a program that wants it lists `atari/basic.asm` and names it
; in a Phase's `needs`, and the driver switches it out everywhere else.
modules {
"atari/osram.asm" "atari/osrom.asm" "atari/mathpack.asm"
"atari/charsets.asm" "atari/portb.asm"
}
resident { osram, osrom, mathpack, charsets, portb }
osram.asm osram
; The memory the Atari OS keeps its variables in: half the zero page and the
; pages from $0200 to $06FF. Sections that hold no bytes, pinned where the OS
; keeps them, so the solver sees memory that is taken rather than a Region it may
; never allocate from. See 0038 for why what occupies memory for a while is a
; Module, and 0229 for why the OS is two of them.
;
; **Resident wherever the OS is used at all**, and not only in the Phases whose
; ROM is in: a Phase without `atari/osrom.asm` runs with the ROM switched out and
; the OS asleep, and the variables have to be as the OS left them when a later
; Phase switches it back in.
;
; Every Section here is `root`: the OS and the hardware reach them with no
; Reference in any Chunk, so nothing else would keep them. None holds bytes, so
; none has a Payload and no Transition loads one. This is the OS as an XL or XE
; ships it; a machine whose OS lives elsewhere declares a Module of its own.
.export RTCLOK, SDMCTL, SDLSTL, SDLSTH, CH
; The OS's half of the zero page. The program's own variables live above it,
; in the half the variant leaves to the solver.
.section zeropage at $0000, root
osZero
.res $12
RTCLOK .res 3 ; $0012: the frame counter, three bytes
.res $6B
.ends
; The OS's variables and buffers. The shadow registers are among them and
; are Labels here rather than registers of the variant: they are the OS's
; memory, which the OS copies to the hardware on every vertical blank, and
; a `register` Region inside this Section would be an address the Section
; may not cover.
.section absolute at $0200, root
osRam
.res $2F
SDMCTL .res 1 ; $022F: shadows DMACTL
SDLSTL .res 1 ; $0230: the display list address, low
SDLSTH .res 1 ; $0231: and high
.res $CA
CH .res 1 ; $02FC: the last key pressed, $FF for none
.res $403
.ends
osrom.asm osrom
; The Atari OS ROM, in the two ranges the hardware registers leave between them,
; and the entry points a program calls in the second. Sections that hold no
; bytes, pinned where the ROM is, so that a Phase that needs this Module has
; the ranges taken and one without it has the RAM underneath — see 0229.
;
; **A ROM the driver switches out.** A variant lists this Module in `resident`,
; so every Phase has the OS unless it says `without osrom`, which the driver's
; `.driver rom osrom` is what allows; a Phase without it has the RAM under the
; ROM, its own vectors at $FFFA to look after, and no call into the OS — a
; `jsr` to an entry point below is a Reference to a Section that Phase does not
; have, and refused as one.
;
; The high range begins at **$E000 and not at $D800**: $D800-$DFFF is the
; floating-point pack, which a device on the parallel bus maps its own ROM
; over once it is selected, so it is `atari/mathpack.asm` — a Module a variant
; may leave out, and one whose absence is a fact about the machine rather than
; an omission. A variant that lists this file lists that one too, unless it
; has something else to say about those addresses.
;
; Every Section is `root`, since the OS and the hardware reach them with no
; Reference in any Chunk. This is the ROM an XL or XE ships.
.export SETVBV, XITVBV
.section absolute at $C000, root
osRomLow
.res $1000
.ends
.section absolute at $E000, root
osRomHigh
.res $45C
SETVBV .res 3 ; $E45C: A = the stage, X/Y = the routine
.res 3
XITVBV .res 3 ; $E462: the end of a deferred routine
.res $1B9B
.ends
mathpack.asm mathpack
; The floating-point routines the OS keeps at $D800-$DFFF, as a Section that
; holds no bytes, so that the solver sees memory that is taken.
;
; **A Module of its own and not part of `atari/osrom.asm`**, because this is the
; one range of the OS that something else can take away. A device on the
; parallel bus maps its ROM over the whole of it once it is selected — the
; kernel's own PBI scan says so in as many words, and looks for a device's
; identifying bytes at $D803 and $D80B, which is why the math pack must not
; begin with them. A variant for a machine whose PBI device is selected for
; the life of the program therefore does not list this file, and says what
; stands there instead.
;
; **Switched out with the OS.** On an XL the one bit of PORTB that takes the OS
; ROM out takes this out too, so a driver that switches ROMs declares it as
; `.driver rom mathpack osrom`: a Phase that needs this needs the OS's ranges
; taken as well, and cannot do without `osrom` — see 0229.
;
; Nothing is exported. The pack's entry points are documented by Atari and a
; program that calls one declares it, as it declares any address of the OS
; `atari/osrom.asm` does not name; nothing the tool ships calls into it.
;
; `root`, because the OS reaches it with no Reference in any Chunk of the
; program, and holding no bytes it has no Payload and no Transition loads it.
.section absolute at $D800, root
mathPack
.res $800
.ends
charsets.asm charsets
; The Atari's two codes for the same letters, as Charsets.
;
; `atascii` is what the character I/O takes: the machine's own code, with the
; graphics characters where an ASCII machine keeps its control codes, and the
; letters where ASCII has them — which is why an unprefixed literal of plain
; letters has always worked and why nothing else has. `\n` is `$9B`, the end of
; line, and not `$0A`.
;
; `screen` is what the display reads out of screen memory, which is the same
; letters at other numbers. A program that writes where the display looks
; rather than through the OS wants this one.
;
; The graphics characters are written here as the Unicode the box-drawing and
; block characters have, so a picture drawn in the source is the picture the
; machine draws. A letter in inverse video is one of those too — Unicode squares
; them off in a negative, and `atascii"PRESS 🆂"` is seven bytes with the last
; one inverse. A whole line of inverse text is better asked of a Charset
; derived from this one, `.charset bright : atascii ^ $80`, which is what a
; derivation is for. Two of them have no exact Unicode: `$02` and `$0D` are a
; quarter of a cell where the nearest character is an eighth, and are written
; as `▕` and `▔`. Everything else, the inverse entries included, was read off
; the machine's own font and matches it.
;
; This Module emits nothing: it is two names and two tables.
.export atascii, screen
; tag atascii
.charset atascii
"♥├▕┘┤┐╱╲◢▗◣▝▘▔▂▖♣┌─┼●▄▎┬┴▌└" = $00
"↑↓←→" = $1C
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" = $20
"♦" = $60
"abcdefghijklmnopqrstuvwxyz" = $61
"♠" = $7B
"│" = $7C
"\n" = $9B
; Inverse video is the same glyph with the bits the other way round, which
; for the blocks and the triangles is another character Unicode draws. Every
; one of these was read off the machine's own font and is exact; the rest of
; the inverse half has no glyph to be written as, and is reached by adding
; $80 or by a Charset derived from this one.
"▊" = $82 ; ▕
"◤" = $88 ; ◢
"▛" = $89 ; ▗
"◥" = $8A ; ◣
"▙" = $8B ; ▝
"▟" = $8C ; ▘
"▆" = $8D ; ▔
"▜" = $8F ; ▖
"▀" = $95 ; ▄
"▐" = $99 ; ▌
"█" = $A0 ; the space
; And the letters, which Unicode squares off in a negative.
"🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽🅾🅿🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉" = $C1
.endch
; end atascii
.charset screen
" !\"#$%&'()*+,-./0123456789:;<=>?" = $00
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" = $20
"♥├▕┘┤┐╱╲◢▗◣▝▘▔▂▖♣┌─┼●▄▎┬┴▌└" = $40
"♦" = $60
"abcdefghijklmnopqrstuvwxyz" = $61
"♠" = $7B
"│" = $7C
; The same inverses, at the display's numbers.
"▊" = $C2
"◤" = $C8
"▛" = $C9
"◥" = $CA
"▙" = $CB
"▟" = $CC
"▆" = $CD
"▜" = $CF
"▀" = $D5
"▐" = $D9
"█" = $80
"🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽🅾🅿🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉" = $A1
.endch
portb.asm portb
; The storage driver for extended memory behind PORTB: the units are the
; Banks of the variant's `extension`, which a value written to PORTB brings
; into the $4000-$7FFF window — `ext` in the variant — and the stream is a
; pointer into that window that walks on to the next unit at its end. Each
; role is a macro declared with `.driver`, which the routine, the loader's
; glue, the decoders and the tool's own Procs expand where they use it as
; `nga.open`, `nga.read`, `nga.show` and `nga.showAt`. What the hardware
; calls each state of a Window is this Module's alone: `portbValues` holds
; a PORTB value per state of `ext`, one per Bank, as many as the variant's
; `extension` counts — the last of the 130XE's five being the machine's own
; memory, which no Window keeps as a base — see 0229. `PORTB` is the variant's
; register.
;
; **The same register holds the OS ROM and BASIC**, bits 0 and 1, so this
; driver is also what switches them: `.driver rom` names the Modules that are
; those ROMs, and `select` is handed the set a Phase needs and writes the two
; bits, which every switch of a Bank keeps as they are — see 0229.
;
; Resident, and outside the window — the variant lists this Module in
; `resident`, and the tool holds it outside the window the stream reads
; through.
portbWindow = $4000
portbWindowEnd = portbWindow + $4000 ; one past the window: the high byte of the first address outside it
portbUnitPages = $40 ; a unit, in pages: what an offset carries by
.driver open portbOpen
.driver read portbRead
.driver unit portbUnit
.driver offset portbPtr
.driver stream ext
.driver show ext portbShow
.driver showAt ext portbShowAt
.driver init portbInit
.driver finalize portbFinalize
.driver rom osrom ; bit 0 of the set
.driver rom mathpack osrom ; bit 1, which one bit of PORTB shows with the OS
.driver rom basic ; bit 2
.driver select portbRoms
.driver mask portbMask
.driver unmask portbUnmask
.transform copy portbCopy
; PORTB as the program found it, kept by `init` and put back by `finalize`: the
; bits of BASIC and of the self-test are the user's, whatever the program does
; with them meanwhile, and a DOS returned to expects its machine as it left it
; — see docs/decisions/0229-no-window-has-a-base.md.
.macro portbInit
lda PORTB
sta portbFound
.endm
.macro portbFinalize
lda portbFound
sta PORTB
.endm
.section
portbFound .res 1
.ends
; What the load wraps a switch of every ROM out in, while the DOS's interrupts
; are still on: with the OS out, $FFFA is RAM the load is writing. IRQ masked,
; and NMI, which `sei` does not reach, off at ANTIC; then back as the OS keeps
; it, the vertical blank on — see
; docs/decisions/0241-bytes-kept-for-a-later-phase-may-lie-hidden-under-a-rom.md.
NMIEN = $D40E
.macro portbMask
sei
lda #0
sta NMIEN
.endm
.macro portbUnmask
lda #$40
sta NMIEN
cli
.endm
.macro portbOpen
jsr portbOpenStream
.endm
.macro portbRead
jsr portbReadByte
.endm
; The state to show, as the tool numbers ext's states: Bank n is n.
.macro portbShow state
ldx #state
jsr portbBank
.endm
; X = the state to show.
.macro portbShowAt
jsr portbBank
.endm
; A = the set of ROMs the Phase needs.
.macro portbRoms
jsr portbSelectRoms
.endm
; PORTB per state of ext, one value per Bank. The list runs to the 130XE's
; five — four of extended memory, and then $FF, the machine's own with the
; self-test out — and the variant's count trims it, so that a variant with
; fewer Banks takes a prefix; one with more lists its values here. Every value
; has bits 0 and 1 set, which is what lets portbBank keep the ROMs' bits as
; they are with one `and` and no scratch byte.
.macro portbBankValues n, values...
.if n > 0
.match values
.case first, rest...
.byte first
portbBankValues n - 1, rest...
.endmatch
.endif
.endm
; The table portbBank indexes, in a Section of its own: what has an
; address stands in one, and a Proc holds code alone.
.section
portbValues
portbBankValues extension, $E3, $E7, $EB, $EF, $FF
.ends
; The stream: where the next byte is, and which unit is in. A plain zero-page
; Section rather than Temporaries, because the value has to survive between
; one call and the next while nothing here is running. They are also the
; cells the routine writes a position into before it opens the stream,
; `portbPtr` the offset and `portbUnit` the unit.
.section zeropage
portbPtr .res 2
portbUnit .res 1
.ends
; X = the state of ext to show: its PORTB value, with the bits of the OS ROM
; and of BASIC left as they are, since those are what `select` said. Writes no
; memory, so that a loader running it leaves nothing behind but the register.
.proc portbBank
lda PORTB
ora #$FC
and portbValues,x
sta PORTB
rts
.endp
; A = the set of ROMs the Phase entered needs: bit 0 `osrom`, bit 1 `mathpack`,
; bit 2 `basic`. Bit 0 of PORTB is set for the OS ROM and the floating-point
; pack, which one bit shows together, and bit 1 is clear for BASIC; the bank
; bits are left as they are. Writes no memory, the set waiting on the stack
; while the register is worked out.
.proc portbSelectRoms
pha
lda PORTB
ora #$03 ; the OS in and BASIC out, to begin with
tax
pla
pha
and #$03 ; neither osrom nor mathpack: the OS out
bne @os
txa
and #$FE
tax
@os
pla
and #$04 ; basic: BASIC in
beq @basic
txa
and #$FD
tax
@basic
stx PORTB
rts
.endp
; The stream to the position in portbUnit and portbPtr. An offset past the
; unit's end carries into the units after, since the routine counts on in a
; Frame without knowing where a unit ends: a unit is $4000 bytes, so the
; offset's top two bits are units.
.proc portbOpenStream
lda portbPtr+1
@carry
cmp #portbUnitPages
bcc @within
sbc #portbUnitPages
inc portbUnit
jmp @carry
@within
clc
adc #>portbWindow
sta portbPtr+1
ldx portbUnit
jsr portbBank
rts
.endp
; A = the next byte of the stream. X and Y are not preserved.
.proc portbReadByte
ldy #0
lda (portbPtr),y
inc portbPtr
bne @done
inc portbPtr+1
ldy portbPtr+1
cpy #>portbWindowEnd
bne @done
pha
jsr portbNextUnit
pla
@done
rts
.endp
; The window's end: the next unit in, and the pointer back at its start.
.proc portbNextUnit
inc portbUnit
ldx portbUnit
jsr portbBank
lda #0
sta portbPtr
lda #>portbWindow
sta portbPtr+1
rts
.endp
; The decoder of `copy`: X/Y = the destination, the stream at the stored
; size and then the bytes. Reads the window through the pointer rather than
; through portbReadByte, which is what a driver's own decoder is for: a run at a
; time, where a run ends at the source's page end or at the size, so that
; the inner loop is `(zp),y` down to zero — the window's end is a page end,
; so a unit is never crossed inside a run.
portbDst .ztemp 2
portbSize .ztemp 2
portbRun .ztemp 1 ; bytes in the run, zero for 256
.proc portbCopy
stx portbDst
sty portbDst+1
jsr portbReadByte
sta portbSize
jsr portbReadByte
sta portbSize+1
@run
lda portbSize
ora portbSize+1
beq @done
lda portbPtr ; to the end of the source's page
eor #$FF
clc
adc #1
sta portbRun
lda portbSize+1
bne @copy ; at least a page left: the run stands
lda portbRun
beq @cap ; a whole page, and less than one left
cmp portbSize
bcc @copy
@cap
lda portbSize
sta portbRun
@copy
ldy portbRun
@byte
dey
lda (portbPtr),y
sta (portbDst),y
tya
bne @byte
ldx portbRun ; the run, as 256 where it is zero
bne @counted
inc portbPtr+1
inc portbDst+1
dec portbSize+1
jmp @crossed
@counted
txa
clc
adc portbPtr
sta portbPtr
bcc @source
inc portbPtr+1
@source
txa
clc
adc portbDst
sta portbDst
bcc @destination
inc portbDst+1
@destination
sec
lda portbSize
stx portbRun
sbc portbRun
sta portbSize
bcs @crossed
dec portbSize+1
@crossed
lda portbPtr+1
cmp #>portbWindowEnd
bne @run
jsr portbNextUnit ; the window's end: the next unit in
jmp @run
@done
rts
.endp
box.asm
CIOV = $E456
ICCOM = $0342
ICBAL = $0344
ICBLL = $0348
PUTCHR = $0B
; tag box
; The picture is the source. Every character here is the Unicode the Atari's
; own glyph is drawn as, and `atascii` is where the two are put side by side.
; `▄` and `▀` are one glyph and its inverse, which is the same byte with bit
; seven set — and Unicode draws both, so neither is a number here. So is a
; letter in inverse video: `🆂` is `S` with the bit set, and stands in a line of
; ordinary text without the line being cut in two.
.section
box
.byte atascii"┌───────┐\n"
.byte atascii"│ HELLO │\n"
.byte atascii"└───────┘\n"
.byte atascii"▄▀▄▀▄▀▄▀▄\n"
.byte atascii"PRESS 🆂\n"
boxEnd
.ends
; end box
.proc entry
lda #<box
sta ICBAL
lda #>box
sta ICBAL+1
lda #<( boxEnd - box )
sta ICBLL
lda #>( boxEnd - box )
sta ICBLL+1
lda #PUTCHR ; the bytes as they are, end of line included
sta ICCOM
ldx #0
jsr CIOV
@stop jmp @stop
.endp
load.asm nga.load
; What a `.xex` decodes with while it loads: without storage its transformed
; Sections, and compressed its segments. See
; docs/decisions/0235-a-xex-decodes-in-place-while-it-loads.md and
; docs/decisions/0259-a-xex-may-be-compressed-segment-by-segment.md.
ngaLoadPtr .ztemp 2
.macro ngaLoadRead
ldy #0
lda (ngaLoadPtr),y
inc ngaLoadPtr
bne @same
inc ngaLoadPtr+1
@same
.endm
; Where the loader puts the form it has just written, and the destination.
.export ngaUnpackFrom, ngaUnpackTo
.section root
ngaUnpackFrom .res 2
ngaUnpackTo .res 2
.ends
; What lies hidden under a ROM is written into memory nothing holds yet with a
; table in front of it — how many pieces, the ROMs to put back, then where each
; is, where it goes and how long it is — and moved with every ROM out and the
; interrupts masked. See
; docs/decisions/0241-bytes-kept-for-a-later-phase-may-lie-hidden-under-a-rom.md.
.export ngaUnder, ngaUnderTable, ngaUnderPutBack
.section root
ngaUnderTable .res 2
.ends
.section root
ngaUnderPutBack .res 1
.ends
ngaUnderAt .ztemp 2
ngaUnderFrom .ztemp 2
ngaUnderTo .ztemp 2
ngaUnderLeft .ztemp 2
ngaUnderCount .ztemp 1
ngaUnderRoms .ztemp 1
.proc ngaUnder, root
nga.mask
lda #0
nga.select
lda ngaUnderTable
sta ngaUnderAt
lda ngaUnderTable+1
sta ngaUnderAt+1
ldy #0
lda (ngaUnderAt),y
sta ngaUnderCount
iny
lda (ngaUnderAt),y
sta ngaUnderRoms
ldx #2
piece jsr take
sta ngaUnderFrom
jsr take
sta ngaUnderFrom+1
jsr take
sta ngaUnderTo
jsr take
sta ngaUnderTo+1
jsr take
sta ngaUnderLeft
jsr take
sta ngaUnderLeft+1
ldy #0
move lda ngaUnderLeft
ora ngaUnderLeft+1
beq moved
lda (ngaUnderFrom),y
sta (ngaUnderTo),y
inc ngaUnderFrom
bne from
inc ngaUnderFrom+1
from inc ngaUnderTo
bne to
inc ngaUnderTo+1
to lda ngaUnderLeft
bne left
dec ngaUnderLeft+1
left dec ngaUnderLeft
jmp move
moved dec ngaUnderCount
bne piece
lda ngaUnderRoms
nga.select
nga.unmask
rts
; The next byte of the table, which X walks from its third.
take txa
tay
lda (ngaUnderAt),y
inx
rts
.endp
init.asm nga.init
; The driver's `init`, wrapped so that a Container has an address to call.
; See docs/spec/transition.md and docs/spec/xex.md.
.export ngaInit
.proc ngaInit, root
nga.init
rts
.endp
finish.asm nga.finish
; Where a program that returns ends: the driver's `finalize`, then back to
; what started it. See docs/decisions/0229-no-window-has-a-base.md.
.export ngaFinish
.proc ngaFinish, root
nga.finalize
rts
.endp
run.asm nga.run
; How the program is started: the ROMs its entry Phase needs selected, and
; where it ends left on the stack, so that its return lands on ngaFinish
; from whichever Phase it returns. See
; docs/decisions/0229-no-window-has-a-base.md.
.export ngaRun
.proc ngaRun, root
lda #3
nga.select
.own ; followed by the rts the program returns with
lda #>( ngaFinish - 1 )
pha
.own
lda #<( ngaFinish - 1 )
pha
jmp nga.entry
.endp
Memory map
- (implicit)128 zero page, 15756 bytes
| Address | Bytes | Section | Module | Kind | Phases | Waits |
|---|---|---|---|---|---|---|
| $0000–$007F | 128 | osZero | osram | section | 0 | |
| $0200–$06FF | 1280 | osRam | osram | section | 0 | |
| $2000–$2000 | 1 | portbFound | portb | section | 0 | |
| $2001–$201E | 30 | portbSelectRoms | portb | proc | 0 | |
| $201F–$204E | 48 | box | box | section | 0 | |
| $204F–$206F | 33 | entry | box | proc | 0 | |
| $2070–$2076 | 7 | ngaInit | nga.init | proc | 0 | |
| $2077–$207D | 7 | ngaFinish | nga.finish | proc | 0 | |
| $207E–$208B | 14 | ngaRun | nga.run | proc | 0 | |
| $C000–$CFFF | 4096 | osRomLow | osrom | section | 0 | |
| $D800–$DFFF | 2048 | mathPack | mathpack | section | 0 | |
| $E000–$FFFF | 8192 | osRomHigh | osrom | section | 0 |
The xex
157 bytes, 3 segments, 0 unaccounted.
| 0 | 2 | container header |
$2001–$208B 139 bytes at 2
| $2001 | 1 | portb.portbSelectRoms | portb.asm |
| $2002 | 3 | portb.portbSelectRoms | portb.asm |
| $2005 | 2 | portb.portbSelectRoms | portb.asm |
| $2007 | 1 | portb.portbSelectRoms | portb.asm |
| $2008 | 1 | portb.portbSelectRoms | portb.asm |
| $2009 | 1 | portb.portbSelectRoms | portb.asm |
| $200A | 2 | portb.portbSelectRoms | portb.asm |
| $200C | 2 | portb.portbSelectRoms | portb.asm |
| $200E | 1 | portb.portbSelectRoms | portb.asm |
| $200F | 2 | portb.portbSelectRoms | portb.asm |
| $2011 | 1 | portb.portbSelectRoms | portb.asm |
| $2012 | 1 | portb.portbSelectRoms | portb.asm |
| $2013 | 2 | portb.portbSelectRoms | portb.asm |
| $2015 | 2 | portb.portbSelectRoms | portb.asm |
| $2017 | 1 | portb.portbSelectRoms | portb.asm |
| $2018 | 2 | portb.portbSelectRoms | portb.asm |
| $201A | 1 | portb.portbSelectRoms | portb.asm |
| $201B | 3 | portb.portbSelectRoms | portb.asm |
| $201E | 1 | portb.portbSelectRoms | portb.asm |
| $201F | 10 | box.box | box.asm |
| $2029 | 10 | box.box | box.asm |
| $2033 | 10 | box.box | box.asm |
| $203D | 10 | box.box | box.asm |
| $2047 | 8 | box.box | box.asm |
| $204F | 2 | box.entry | box.asm |
| $2051 | 3 | box.entry | box.asm |
| $2054 | 2 | box.entry | box.asm |
| $2056 | 3 | box.entry | box.asm |
| $2059 | 2 | box.entry | box.asm |
| $205B | 3 | box.entry | box.asm |
| $205E | 2 | box.entry | box.asm |
| $2060 | 3 | box.entry | box.asm |
| $2063 | 2 | box.entry | box.asm |
| $2065 | 3 | box.entry | box.asm |
| $2068 | 2 | box.entry | box.asm |
| $206A | 3 | box.entry | box.asm |
| $206D | 3 | box.entry | box.asm |
| $2070 | 6 | nga.init.ngaInit | init.asm |
| $2076 | 1 | nga.init.ngaInit | init.asm |
| $2077 | 6 | nga.finish.ngaFinish | finish.asm |
| $207D | 1 | nga.finish.ngaFinish | finish.asm |
| $207E | 2 | nga.run.ngaRun | run.asm |
| $2080 | 3 | nga.run.ngaRun | run.asm |
| $2083 | 2 | nga.run.ngaRun | run.asm |
| $2085 | 1 | nga.run.ngaRun | run.asm |
| $2086 | 2 | nga.run.ngaRun | run.asm |
| $2088 | 1 | nga.run.ngaRun | run.asm |
| $2089 | 3 | nga.run.ngaRun | run.asm |
$02E2–$02E3 2 bytes at 145
| $02E2 | 2 | initad |
$02E0–$02E1 2 bytes at 151
| $02E0 | 2 | runad |