cartridge
A program of Cartridges.
main.ngp
include "atari/xegs128.ngp"
modules { "print.asm" "intro.asm" "level.asm" }
panes in switched { level }
resident { print }
phase intro { needs intro then level entry introStart }
phase level { needs level entry levelStart }
entry intro
container car "xegs128"
xegs128.ngp project
; An Atari 800XL holding a 128 KB XEGS cartridge: sixteen banks of eight
; kilobytes, of which the last is the fixed part the CPU always sees at
; $A000-$BFFF and the other fifteen are storage, brought into $8000-$9FFF one at
; a time by the byte written to $D5FF. A cartridge is ROM the CPU reads where it
; lies, so nothing is loaded and there is no DOS: the machine's whole RAM below
; the cartridge is the program's, $0700 included.
target {
cpu "6502"
; The one Container a machine holding a cartridge takes. A `.xex` needs a DOS
; to load it, and this machine has none.
containers car
; Fifteen and not sixteen: the sixteenth bank is the fixed part under another
; name, and one set of bytes with two names is one too many.
units banks 15
window switched $8000 .. $9FFF views banks
}
storage { units banks }
target {
region ram $0000 .. $7FFF ram
region stack $0100 .. $01FF reserved
region io $D000 .. $D7FF register
; The part of the cartridge no switch takes away, which is where the solver
; puts everything nothing writes. $8000-$9FFF is in no Region at all: it is
; the window, it shows one Bank at a time, and only a Pane or storage stands
; there — as the boot record's page is in no Region of the diskette's variant.
region cart $A000 .. $BFFF rom
; What the driver writes. Any address of $D500-$D5FF is the same register.
register CARTSEL $D5FF
; 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
holder cartinit ; $BFFE: called in the middle of the cold start, and on every reset
}
; The OS, the driver for this storage and the decoders the tool ships. Every
; Transition calls the driver and the decoders, so they are resident; a decoder
; nothing uses is dropped.
modules {
"atari/osram.asm" "atari/osrom.asm" "atari/mathpack.asm"
"atari/charsets.asm" "atari/cart.asm" "stream/zx0.asm"
}
resident { osram, osrom, mathpack, charsets, cart, zx0 }
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
cart.asm cart
; The storage driver for a XEGS cartridge: the units are the Banks of the
; variant's `banks`, which the **byte written to `$D5FF`** brings into the
; $8000-$9FFF window — `switched` 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 decoders and the tool's
; own Procs expand where they use it as `nga.open`, `nga.read`, `nga.show` and
; `nga.showAt`.
;
; A state of `switched` **is** a Bank number, so this driver holds no table
; where `portb.asm` holds one: the window has no named state to number before
; the Banks, since a cartridge of this kind cannot be switched off, and the
; board wires the byte written straight to the address lines above the window.
; Which is also why `show` is two instructions and nothing else.
;
; The register is written and never read — the board decodes an address and
; latches the data, and gives nothing back — so the bank a Transition left in
; is in this driver's own byte and nowhere else.
;
; Resident, and outside the window: the variant lists this Module in `resident`,
; and the tool holds it outside the window the stream reads through, since code
; that switched the window from inside it would switch itself away.
cartSelect = $D5FF ; any address of $D500-$D5FF; the data is the bank
cartWindow = $8000
cartWindowEnd = cartWindow + $2000 ; one past the window: the high byte of the first address outside it
cartUnitPages = $20 ; a unit, in pages: what an offset carries by
.driver open cartOpen
.driver read cartRead
.driver unit cartUnit
.driver offset cartPtr
.driver stream switched
.driver show switched cartShow
.driver showAt switched cartShowAt
.transform copy cartCopy
.macro cartOpen
jsr cartOpenStream
.endm
.macro cartRead
jsr cartReadByte
.endm
; The state to show, which is the Bank: the window shows nothing else.
.macro cartShow state
lda #state
sta cartSelect
.endm
; X = the state to show.
.macro cartShowAt
stx cartSelect
.endm
; 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, `cartPtr` the
; offset and `cartUnit` the unit.
.section zeropage
cartPtr .res 2
cartUnit .res 1
.ends
; The stream to the position in cartUnit and cartPtr. 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 $2000 bytes, so the
; offset's top three bits are units.
.proc cartOpenStream
lda cartPtr+1
@carry
cmp #cartUnitPages
bcc @within
sbc #cartUnitPages
inc cartUnit
jmp @carry
@within
clc
adc #>cartWindow
sta cartPtr+1
lda cartUnit
sta cartSelect
rts
.endp
; A = the next byte of the stream. X and Y are not preserved.
.proc cartReadByte
ldy #0
lda (cartPtr),y
inc cartPtr
bne @done
inc cartPtr+1
ldy cartPtr+1
cpy #>cartWindowEnd
bne @done
pha
jsr cartNextUnit
pla
@done
rts
.endp
; The window's end: the next unit in, and the pointer back at its start.
.proc cartNextUnit
inc cartUnit
lda cartUnit
sta cartSelect
lda #0
sta cartPtr
lda #>cartWindow
sta cartPtr+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
; cartReadByte, 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.
cartDst .ztemp 2
cartSize .ztemp 2
cartRun .ztemp 1 ; bytes in the run, zero for 256
.proc cartCopy
stx cartDst
sty cartDst+1
jsr cartReadByte
sta cartSize
jsr cartReadByte
sta cartSize+1
@run
lda cartSize
ora cartSize+1
beq @done
lda cartPtr ; to the end of the source's page
eor #$FF
clc
adc #1
sta cartRun
lda cartSize+1
bne @copy ; at least a page left: the run stands
lda cartRun
beq @cap ; a whole page, and less than one left
cmp cartSize
bcc @copy
@cap
lda cartSize
sta cartRun
@copy
ldy cartRun
@byte
dey
lda (cartPtr),y
sta (cartDst),y
tya
bne @byte
ldx cartRun ; the run, as 256 where it is zero
bne @counted
inc cartPtr+1
inc cartDst+1
dec cartSize+1
jmp @crossed
@counted
txa
clc
adc cartPtr
sta cartPtr
bcc @source
inc cartPtr+1
@source
txa
clc
adc cartDst
sta cartDst
bcc @destination
inc cartDst+1
@destination
sec
lda cartSize
stx cartRun
sbc cartRun
sta cartSize
bcs @crossed
dec cartSize+1
@crossed
lda cartPtr+1
cmp #>cartWindowEnd
bne @run
jsr cartNextUnit ; the window's end: the next unit in
jmp @run
@done
rts
.endp
zx0.asm zx0
; The decoder of `zx0` over any driver's stream: Einar Saukas's ZX0, version
; 2's standard forward stream, decoded as the reference dzx0.c does, driven
; by the stream's own end marker. Written here from the format, not ported:
; nothing of the reference's text is in it, and it is licensed as everything
; under lib/ is, see lib/LICENSE. Entered with X/Y = the destination and the
; stream at the stored size, which it reads past. A match is copied a byte
; at a time, forward, from what was written, which is what makes an offset
; shorter than its length — the run — come out right. Resident, and outside
; the driver's window.
;
; zx0Bits the bit buffer, a sentinel one above the bits still unread
; zx0Offset the last offset
; zx0Length the length in hand, or an offset's MSB while one is read
; zx0Invert one while an offset's MSB is read, whose data bits the
; stream carries complemented; zero otherwise
.transform zx0 zx0Decode
zx0Dst .ztemp 2
zx0Src .ztemp 2
zx0Bits .ztemp 1
zx0Offset .ztemp 2
zx0Length .ztemp 2
zx0Invert .ztemp 1
; The next bit of the stream, in A as zero or one and in the Z flag. The
; buffer holds a sentinel above the unread bits, so shifting it to nothing is
; the signal to fetch the next byte and put the sentinel back below it.
.proc zx0Bit
asl zx0Bits
bne @have
nga.read
sec ; the sentinel the asl shifted out, which `read` may not keep
rol
sta zx0Bits
@have
lda #0
rol
rts
.endp
; An interlaced Elias gamma value into zx0Length: a control bit says whether
; a data bit follows, and the value begins at one. Three Procs chained by
; `then` because the value after an offset is entered with its first control
; bit already read, at zx0EliasData: the first falls through into the
; second, and the second branches into the third, which the chain is what
; allows.
.proc zx0Elias
lda #1
sta zx0Length
lda #0
sta zx0Length+1
.endp then zx0EliasMore
.proc zx0EliasMore
jsr zx0Bit
beq zx0EliasData ; zero: a data bit follows
rts
.endp then zx0EliasData
.proc zx0EliasData
jsr zx0Bit
eor zx0Invert
lsr
rol zx0Length
rol zx0Length+1
jmp zx0EliasMore
.endp
; One byte written: the destination moves on and the length in hand comes
; down, leaving Z set when it reaches zero.
.proc zx0Step
inc zx0Dst
bne @moved
inc zx0Dst+1
@moved
lda zx0Length
bne @low
dec zx0Length+1
@low
dec zx0Length
lda zx0Length
ora zx0Length+1
rts
.endp
; The length in hand copied from zx0Dst less the last offset to zx0Dst.
.proc zx0Copy
sec
lda zx0Dst
sbc zx0Offset
sta zx0Src
lda zx0Dst+1
sbc zx0Offset+1
sta zx0Src+1
@byte
ldy #0
lda (zx0Src),y
sta (zx0Dst),y
inc zx0Src
bne @from
inc zx0Src+1
@from
jsr zx0Step
bne @byte
rts
.endp
.proc zx0Decode
stx zx0Dst
sty zx0Dst+1
nga.read ; the stored size, which the end marker makes unnecessary
nga.read
lda #$80
sta zx0Bits ; an empty buffer: the sentinel alone
lda #1
sta zx0Offset
lda #0
sta zx0Offset+1 ; the last offset begins at one
sta zx0Invert
@literals
jsr zx0Elias
@literal
nga.read
ldy #0
sta (zx0Dst),y
jsr zx0Step
bne @literal
jsr zx0Bit
bne @offset
jsr zx0Elias ; a match at the last offset
jsr zx0Copy
jsr zx0Bit
beq @literals
@offset
lda #1
sta zx0Invert
jsr zx0Elias ; the new offset's MSB, complemented in the stream
lda #0
sta zx0Invert
lda zx0Length
beq @done ; 256 is the end marker, and the one value with a low byte of zero
lsr ; offset = MSB * 128 - LSB / 2
sta zx0Offset+1
lda #0
ror
sta zx0Offset
nga.read
lsr ; the LSB's low bit is the length's first control bit
php
eor #$FF
sec
adc zx0Offset
sta zx0Offset
bcs @subtracted
dec zx0Offset+1
@subtracted
plp
lda #1
sta zx0Length
lda #0
sta zx0Length+1
bcs @counted ; a control bit of one: the value is one
jsr zx0EliasData
@counted
inc zx0Length ; a match at a new offset is one longer than written
bne @copy
inc zx0Length+1
@copy
jsr zx0Copy
jsr zx0Bit
bne @offset
jmp @literals
@done
rts
.endp
print.asm
; The one thing both Phases need: a line on the screen, through the character
; I/O the OS opens on channel 0 before a program starts. `PUTREC` writes a
; record, so it ends the line itself.
CIOV = $E456
ICCOM = $0342
ICBAL = $0344
ICBLL = $0348
PUTREC = 9
; Both Phases call it, so both have to see the name.
.export printLine
; Where the line stands, and how long it is. Declaring where the two arguments
; are is what lets a Module of C call this one as a function.
.proc printLine
.declare arg xy
.declare arg a
stx ICBAL
sty ICBAL+1
sta ICBLL
lda #0
sta ICBLL+1
lda #PUTREC
sta ICCOM
ldx #0
jsr CIOV
rts
.endp
intro.asm
.section
introText
.byte "INTRO"
introTextEnd
.ends
.proc introStart
ldx #<introText
ldy #>introText
lda #introTextEnd - introText
jsr printLine
.transition level
.endp
level.asm
; What the Phase is for: a map of ten rows, which is what waits in storage
; while the program is in `intro`. Thirty-seven characters is what a row of
; the screen holds once the OS's left margin is taken off.
;
; It lives in the Pane `level`, so it stands in a Bank and is read there.
levelWidth = 37
; tag section
.section in level
levelMap
.byte "#####################################"
.byte "#...................................#"
.byte "#...................................#"
.byte "#......########.....................#"
.byte "#......#......#.....................#"
.byte "#......#......#.....................#"
.byte "#......########.....................#"
.byte "#...................................#"
.byte "#...................................#"
.byte "#####################################"
levelMapEnd
.ends
; end section
; tag draw
; A Trampoline: it stands outside the Window, but runs with `level` shown —
; which is what lets it name what the Pane holds. Chapter five's loop, moved
; here whole.
.proc drawMap, under level
at .ztemp 2
left .ztemp 1
lda #<levelMap
sta at
lda #>levelMap
sta at+1
lda #( levelMapEnd - levelMap ) / levelWidth
sta left
@row
ldx at
ldy at+1
lda #levelWidth
jsr printLine
clc
lda at
adc #levelWidth
sta at
bcc @counted
inc at+1
@counted
dec left
bne @row
rts
.endp
.proc levelStart
.with level
jsr drawMap
@stop jmp @stop
.endp
; end draw
transition.asm nga.transition
ngaFramesHeld = 0
ngaUnitBytes = 1
ngaEntrySize = 4
ngaBlockSize = 6
ngaFrameHeader = 3 + ngaSelects
; The Transition routine. Called by `jsr` from a `.transition`, with the
; statement's list right behind the call: the Phase to enter, and per Phase
; the code may be in, the unit and offset where the edge's Frame waits.
; nga.open and nga.read are the driver's roles, macros of the driver's
; Module expanded here, and nga.unit and nga.offset the cells its stream
; stands in, which open reads the position from; and ngaCurrentPhase is the
; Cell the tool generates. Everything else the edge has to say waits in the
; Frame, in storage. See docs/spec/transition.md.
;
; Its zero page is Temporaries: nothing of it is needed once the routine has
; jumped to the entered Phase's entry, and a `.transition` is a jump into the
; routine, so whatever the statement's Section had on the zero page is dead by
; then too. Two Temporaries never live at once share an address — see
; docs/decisions/0034-trace.md.
.export ngaTransition
ngaPtr .ztemp 2
ngaEntry .ztemp 2
ngaDst .ztemp 2
ngaValue .ztemp 2
ngaOffset .ztemp 2
ngaFrameAt .ztemp 2 + ngaUnitBytes ; where the Frame's stream stands: the offset, then the unit
ngaWanted .ztemp 1
ngaCount .ztemp 1
ngaUnit .ztemp ngaUnitBytes
.proc ngaTransition
pla
sta ngaPtr
pla
sta ngaPtr+1 ; the return address: one below the statement's list
ldy #1
lda (ngaPtr),y
sta ngaWanted ; the Phase to enter
iny
lda (ngaPtr),y
sta ngaCount ; entries that follow
lda ngaPtr
clc
adc #3
sta ngaPtr
bcc @scan
inc ngaPtr+1
@scan
lda ngaCount
bne @check
brk ; no entry for the current Phase: unreachable while the static rule holds
@check
ldy #0
lda (ngaPtr),y
cmp ngaCurrentPhase
beq @found
lda ngaPtr ; the next entry
clc
adc #ngaEntrySize
sta ngaPtr
bcc @skipped
inc ngaPtr+1
@skipped
dec ngaCount
jmp @scan
@found
iny
lda (ngaPtr),y
sta ngaFrameAt+2 ; the unit the Frame waits in
.if ngaUnitBytes > 1
iny
lda (ngaPtr),y
sta ngaFrameAt+3
.endif
iny
lda (ngaPtr),y
sta ngaFrameAt
iny
lda (ngaPtr),y
sta ngaFrameAt+1 ; and where in it
.endp then ngaEnter
; The rest of it, and the way in for a Container that has no current Phase to
; look one up by: ngaWanted holds the Phase to enter and ngaFrameAt where
; its Frame waits. The cold start comes here — see
; docs/decisions/0216-a-car-names-its-format-and-the-cold-start-is-an-edge.md.
.export ngaEnter
.proc ngaEnter
jsr ngaFrameOpen
.if ngaFramesHeld
nga.read
sta ngaPtr
nga.read
sta ngaPtr+1 ; where the descriptors are to be held, or zero
.endif
nga.read
sta ngaEntry
nga.read
sta ngaEntry+1
nga.read
sta ngaCount ; blocks that follow
.if ngaSelects
nga.read ; the ROMs the entered Phase needs, switched
nga.select ; before a byte of it lands
.endif
lda #ngaFrameHeader
jsr ngaFrameSkip
.if ngaFramesHeld
lda ngaPtr
ora ngaPtr+1
beq @block ; nowhere to hold them: one open a block
; A block's bytes, read in one pass from where the stream already stands. The
; write pointer, the counter and the index are Temporaries of the routine's own
; that nothing is keeping here: ngaValue belongs to the Cell writes, which come
; after the blocks, and ngaUnit and ngaDst to a block being loaded, which has
; not begun. Only ngaPtr is really spent, being live across the whole of the
; block loop and so no longer able to share with what a driver declares — which
; is the two bytes of zero page this way of fetching costs.
lda ngaPtr
sta ngaValue
lda ngaPtr+1
sta ngaValue+1
lda ngaCount
sta ngaUnit ; blocks still to hold
@hold
lda ngaUnit
beq @heldBlock
lda #0
sta ngaDst ; the index, which a read may take out of Y
@six
nga.read
ldy ngaDst
sta (ngaValue),y
iny
sty ngaDst
cpy #ngaBlockSize
bne @six
lda #ngaBlockSize
jsr ngaFrameSkip ; so the Frame stands past them at the end
lda ngaValue
clc
adc #ngaBlockSize
sta ngaValue
bcc @counted
inc ngaValue+1
@counted
dec ngaUnit
jmp @hold
; Then a block at a time out of memory, and the Frame opened once more at the
; end rather than once for every one of them.
@heldBlock
lda ngaCount
beq @cells
ldy #0
lda (ngaPtr),y
sta nga.unit ; straight into the driver's cells: the
iny ; descriptors are in memory, and nothing
.if ngaUnitBytes > 1 ; reads the stream before it is opened
lda (ngaPtr),y
sta nga.unit+1
iny
.endif
lda (ngaPtr),y
sta nga.offset
iny
lda (ngaPtr),y
sta nga.offset+1
iny
lda (ngaPtr),y
sta ngaDst
iny
lda (ngaPtr),y
sta ngaDst+1
iny
lda (ngaPtr),y
pha ; the decoder's number
lda ngaPtr
clc
adc #ngaBlockSize
sta ngaPtr
bcc @heldLoad
inc ngaPtr+1
@heldLoad
nga.open
pla
ldx ngaDst
ldy ngaDst+1
jsr ngaTransform
dec ngaCount
jmp @heldBlock
.endif
@block
lda ngaCount
beq @cells
jsr ngaFrameOpen ; back to the Frame: a block's stream replaced it
nga.read
sta ngaUnit
.if ngaUnitBytes > 1
nga.read
sta ngaUnit+1
.endif
nga.read
sta ngaOffset
nga.read
sta ngaOffset+1
nga.read
sta ngaDst
nga.read
sta ngaDst+1
nga.read
pha ; the decoder's number
lda #ngaBlockSize
jsr ngaFrameSkip
lda ngaUnit ; only now: the driver reads the Frame through
sta nga.unit ; these very cells, and writing them while it
.if ngaUnitBytes > 1 ; did would move the stream
lda ngaUnit+1
sta nga.unit+1
.endif
lda ngaOffset
sta nga.offset
lda ngaOffset+1
sta nga.offset+1
nga.open ; the block's stream: its stored size, then its bytes
pla
ldx ngaDst
ldy ngaDst+1
jsr ngaTransform
dec ngaCount
jmp @block
@cells
jsr ngaFrameOpen
nga.read
sta ngaCount ; Cell writes that follow, read in one stream
@cell
lda ngaCount
beq @enter
nga.read
sta ngaDst
nga.read
sta ngaDst+1
nga.read
sta ngaValue
nga.read
sta ngaValue+1
ldy #0
lda ngaValue
sta (ngaDst),y ; a Cell stands outside the driver's window
iny
lda ngaValue+1
sta (ngaDst),y
dec ngaCount
jmp @cell
@enter
lda ngaWanted
sta ngaCurrentPhase ; the Phase the program is in from here on
jmp (ngaEntry)
.endp
; The Frame's stream, from where the routine last left it.
.proc ngaFrameOpen
lda ngaFrameAt
sta nga.offset
lda ngaFrameAt+1
sta nga.offset+1
lda ngaFrameAt+2
sta nga.unit
.if ngaUnitBytes > 1
lda ngaFrameAt+3
sta nga.unit+1
.endif
nga.open
rts
.endp
; A bytes on in the Frame, which is where its stream is opened next. The
; offset carries into the unit, so that a Frame running past the last offset
; a unit's number can reach goes on into the next.
.proc ngaFrameSkip
clc
adc ngaFrameAt
sta ngaFrameAt
bcc @done
inc ngaFrameAt+1
bne @done
inc ngaFrameAt+2
.if ngaUnitBytes > 1
bne @done
inc ngaFrameAt+3
.endif
@done
rts
.endp
; Where the cold start's Frame waits: a unit and an offset in it, which the
; Container writes here once PlaceStorage has put it somewhere. `readonly`
; because nothing writes it and it belongs in the ROM a cartridge is.
.export ngaColdFrame
.section absolute, readonly
ngaColdFrame
.byte 0 ; the unit
.if ngaUnitBytes > 1
.byte 0
.endif
.word 0 ; and where in it
.ends
; What a cartridge's run vector points at, and what the OS therefore jumps to:
; the entry Phase is entered as any Phase is entered, by the routine, from a
; Frame. `root`, since the hardware reaches it and no Chunk of the program does,
; and exported because the Container writes its address into the run vector.
.export ngaStart
.proc ngaStart, root
lda #0
sta ngaWanted
lda ngaColdFrame
sta ngaFrameAt+2
.if ngaUnitBytes > 1
lda ngaColdFrame+1
sta ngaFrameAt+3
.endif
lda ngaColdFrame+ngaUnitBytes
sta ngaFrameAt
lda ngaColdFrame+ngaUnitBytes+1
sta ngaFrameAt+1
jmp ngaEnter
.endp
cell nga.cell
ngaCurrentPhasecart.asm nga.cart
; The cartridge header: the six bytes at $BFFA the OS reads before it runs
; anything of a cartridge. $BFFC being zero is what says one is there, and the
; OS then tests that $BFFB cannot be written, which it cannot, being ROM. See
; docs/spec/car.md.
.export ngaCartStart
.section absolute at $BFFA, root, readonly
ngaCartStart
.word 0 ; the program's start, which the Container
; patches once addresses exist: the OS jumps
; through it after E: is open on IOCB 0, and
; again on every reset
.byte 0 ; $BFFC: a cartridge is here
.byte $04 ; $BFFD: started through $BFFA, no disk boot,
; and not the diagnostic cartridge bit 7 would
; make it
.root cartinit
.word ngaCartInit ; $BFFE: called in the middle of the cold start
.ends
; The init vector points here and here does nothing on purpose: it is called
; before the OS has finished its own cold start and before E: exists, so
; anything run there would run in a machine half set up.
.proc ngaCartInit
rts
.endp
transforms.asm nga.transforms
; The dispatcher over the decoders the program declared, in the order the
; tool numbered them. See docs/spec/transition.md.
.export ngaSelects
ngaSelects = 0
.export ngaTransform
.proc ngaTransform
cmp #0
bne @not0
jmp cartCopy
@not0
brk
.endp
Memory map
- intro143 zero page, 15622 bytes
- level143 zero page, 15617 bytes
| Address | Bytes | Section | Module | Kind | Phases | Waits |
|---|---|---|---|---|---|---|
| $0000–$007F | 128 | osZero | osram | section | 0..1 | |
| $0080–$0082 | 3 | cartPtr | cart | section | 0..1 | |
| $0083–$0084 | 2 | cartDst | cart | temporary | 0..1 | |
| $0083–$0084 | 2 | ngaDst | nga.transition | temporary | 0..1 | |
| $0083–$0084 | 2 | ngaPtr | nga.transition | temporary | 0..1 | |
| $0085–$0086 | 2 | cartSize | cart | temporary | 0..1 | |
| $0085–$0086 | 2 | ngaOffset | nga.transition | temporary | 0..1 | |
| $0085–$0086 | 2 | ngaValue | nga.transition | temporary | 0..1 | |
| $0087–$0087 | 1 | cartRun | cart | temporary | 0..1 | |
| $0087–$0087 | 1 | ngaUnit | nga.transition | temporary | 0..1 | |
| $0088–$0089 | 2 | ngaEntry | nga.transition | temporary | 0..1 | |
| $008A–$008C | 3 | ngaFrameAt | nga.transition | temporary | 0..1 | |
| $008D–$008D | 1 | ngaWanted | nga.transition | temporary | 0..1 | |
| $008E–$008E | 1 | ngaCount | nga.transition | temporary | 0..1 | |
| $0200–$06FF | 1280 | osRam | osram | section | 0..1 | |
| $0700–$0704 | 5 | introText | intro | section | 0 | bank 0 +$0014 (copy, 7 B) |
| $0705–$0705 | 1 | ngaCurrentPhase | nga.cell | section | 0..1 | bank 0 +$001B (copy, 3 B) |
| $8000–$8171 | 370 | levelMap | level | section | 0..1 | |
| $A000–$A017 | 24 | cartOpenStream | cart | proc | 0..1 | |
| $A018–$A02D | 22 | cartReadByte | cart | proc | 0..1 | |
| $A02E–$A03D | 16 | cartNextUnit | cart | proc | 0..1 | |
| $A03E–$A0AF | 114 | cartCopy | cart | proc | 0..1 | |
| $A0B0–$A0C8 | 25 | printLine | proc | 0..1 | ||
| $A0C9–$A0DA | 18 | introStart | intro | proc | 0 | |
| $A10B–$A153 | 73 | ngaTransition | nga.transition | proc | 0..1 | |
| $A154–$A1E7 | 148 | ngaEnter | nga.transition | proc | 0..1 | |
| $A1E8–$A1F7 | 16 | ngaFrameOpen | nga.transition | proc | 0..1 | |
| $A1F8–$A205 | 14 | ngaFrameSkip | nga.transition | proc | 0..1 | |
| $A206–$A208 | 3 | ngaColdFrame | nga.transition | section | 0..1 | |
| $A209–$A21E | 22 | ngaStart | nga.transition | proc | 0..1 | |
| $A21F–$A21F | 1 | ngaCartInit | nga.cart | proc | 0..1 | |
| $A220–$A227 | 8 | ngaTransform | nga.transforms | proc | 0..1 | |
| $BFFA–$BFFF | 6 | ngaCartStart | nga.cart | section | 0..1 | |
| $C000–$CFFF | 4096 | osRomLow | osrom | section | 0..1 | |
| $D800–$DFFF | 2048 | mathPack | mathpack | section | 0..1 | |
| $E000–$FFFF | 8192 | osRomHigh | osrom | section | 0..1 | |
| $0083–$0084 | 2 | drawMap.at | level | temporary | 1 | |
| $0085–$0085 | 1 | drawMap.left | level | temporary | 1 | |
| $A0DB–$A0FF | 37 | drawMap | level | proc | 1 | |
| $A100–$A10A | 11 | levelStart | level | proc | 1 |
The car
131088 bytes, 2 segments, 0 unaccounted.
| 0 | 16 | container header | |
| 46 | 114658 | erased | |
| 115074 | 7822 | erased |
Storage 5 images at 16
| $0000 | 16 | frame | |
| $0000 | 4 | frame | |
| $0000 | 7 | payload, copy | |
| $0000 | 3 | payload, copy | |
| $8000 | 370 | pane |
$A000–$BFFF 8192 bytes at 122896
| $A000 | 2 | cart.cartOpenStream | cart.asm |
| $A002 | 2 | cart.cartOpenStream | cart.asm |
| $A004 | 2 | cart.cartOpenStream | cart.asm |
| $A006 | 2 | cart.cartOpenStream | cart.asm |
| $A008 | 2 | cart.cartOpenStream | cart.asm |
| $A00A | 3 | cart.cartOpenStream | cart.asm |
| $A00D | 1 | cart.cartOpenStream | cart.asm |
| $A00E | 2 | cart.cartOpenStream | cart.asm |
| $A010 | 2 | cart.cartOpenStream | cart.asm |
| $A012 | 2 | cart.cartOpenStream | cart.asm |
| $A014 | 3 | cart.cartOpenStream | cart.asm |
| $A017 | 1 | cart.cartOpenStream | cart.asm |
| $A018 | 2 | cart.cartReadByte | cart.asm |
| $A01A | 2 | cart.cartReadByte | cart.asm |
| $A01C | 2 | cart.cartReadByte | cart.asm |
| $A01E | 2 | cart.cartReadByte | cart.asm |
| $A020 | 2 | cart.cartReadByte | cart.asm |
| $A022 | 2 | cart.cartReadByte | cart.asm |
| $A024 | 2 | cart.cartReadByte | cart.asm |
| $A026 | 2 | cart.cartReadByte | cart.asm |
| $A028 | 1 | cart.cartReadByte | cart.asm |
| $A029 | 3 | cart.cartReadByte | cart.asm |
| $A02C | 1 | cart.cartReadByte | cart.asm |
| $A02D | 1 | cart.cartReadByte | cart.asm |
| $A02E | 2 | cart.cartNextUnit | cart.asm |
| $A030 | 2 | cart.cartNextUnit | cart.asm |
| $A032 | 3 | cart.cartNextUnit | cart.asm |
| $A035 | 2 | cart.cartNextUnit | cart.asm |
| $A037 | 2 | cart.cartNextUnit | cart.asm |
| $A039 | 2 | cart.cartNextUnit | cart.asm |
| $A03B | 2 | cart.cartNextUnit | cart.asm |
| $A03D | 1 | cart.cartNextUnit | cart.asm |
| $A03E | 2 | cart.cartCopy | cart.asm |
| $A040 | 2 | cart.cartCopy | cart.asm |
| $A042 | 3 | cart.cartCopy | cart.asm |
| $A045 | 2 | cart.cartCopy | cart.asm |
| $A047 | 3 | cart.cartCopy | cart.asm |
| $A04A | 2 | cart.cartCopy | cart.asm |
| $A04C | 2 | cart.cartCopy | cart.asm |
| $A04E | 2 | cart.cartCopy | cart.asm |
| $A050 | 2 | cart.cartCopy | cart.asm |
| $A052 | 2 | cart.cartCopy | cart.asm |
| $A054 | 2 | cart.cartCopy | cart.asm |
| $A056 | 1 | cart.cartCopy | cart.asm |
| $A057 | 2 | cart.cartCopy | cart.asm |
| $A059 | 2 | cart.cartCopy | cart.asm |
| $A05B | 2 | cart.cartCopy | cart.asm |
| $A05D | 2 | cart.cartCopy | cart.asm |
| $A05F | 2 | cart.cartCopy | cart.asm |
| $A061 | 2 | cart.cartCopy | cart.asm |
| $A063 | 2 | cart.cartCopy | cart.asm |
| $A065 | 2 | cart.cartCopy | cart.asm |
| $A067 | 2 | cart.cartCopy | cart.asm |
| $A069 | 2 | cart.cartCopy | cart.asm |
| $A06B | 2 | cart.cartCopy | cart.asm |
| $A06D | 1 | cart.cartCopy | cart.asm |
| $A06E | 2 | cart.cartCopy | cart.asm |
| $A070 | 2 | cart.cartCopy | cart.asm |
| $A072 | 1 | cart.cartCopy | cart.asm |
| $A073 | 2 | cart.cartCopy | cart.asm |
| $A075 | 2 | cart.cartCopy | cart.asm |
| $A077 | 2 | cart.cartCopy | cart.asm |
| $A079 | 2 | cart.cartCopy | cart.asm |
| $A07B | 2 | cart.cartCopy | cart.asm |
| $A07D | 2 | cart.cartCopy | cart.asm |
| $A07F | 3 | cart.cartCopy | cart.asm |
| $A082 | 1 | cart.cartCopy | cart.asm |
| $A083 | 1 | cart.cartCopy | cart.asm |
| $A084 | 2 | cart.cartCopy | cart.asm |
| $A086 | 2 | cart.cartCopy | cart.asm |
| $A088 | 2 | cart.cartCopy | cart.asm |
| $A08A | 2 | cart.cartCopy | cart.asm |
| $A08C | 1 | cart.cartCopy | cart.asm |
| $A08D | 1 | cart.cartCopy | cart.asm |
| $A08E | 2 | cart.cartCopy | cart.asm |
| $A090 | 2 | cart.cartCopy | cart.asm |
| $A092 | 2 | cart.cartCopy | cart.asm |
| $A094 | 2 | cart.cartCopy | cart.asm |
| $A096 | 1 | cart.cartCopy | cart.asm |
| $A097 | 2 | cart.cartCopy | cart.asm |
| $A099 | 2 | cart.cartCopy | cart.asm |
| $A09B | 2 | cart.cartCopy | cart.asm |
| $A09D | 2 | cart.cartCopy | cart.asm |
| $A09F | 2 | cart.cartCopy | cart.asm |
| $A0A1 | 2 | cart.cartCopy | cart.asm |
| $A0A3 | 2 | cart.cartCopy | cart.asm |
| $A0A5 | 2 | cart.cartCopy | cart.asm |
| $A0A7 | 2 | cart.cartCopy | cart.asm |
| $A0A9 | 3 | cart.cartCopy | cart.asm |
| $A0AC | 3 | cart.cartCopy | cart.asm |
| $A0AF | 1 | cart.cartCopy | cart.asm |
| $A0B0 | 3 | print.printLine | print.asm |
| $A0B3 | 3 | print.printLine | print.asm |
| $A0B6 | 3 | print.printLine | print.asm |
| $A0B9 | 2 | print.printLine | print.asm |
| $A0BB | 3 | print.printLine | print.asm |
| $A0BE | 2 | print.printLine | print.asm |
| $A0C0 | 3 | print.printLine | print.asm |
| $A0C3 | 2 | print.printLine | print.asm |
| $A0C5 | 3 | print.printLine | print.asm |
| $A0C8 | 1 | print.printLine | print.asm |
| $A0C9 | 2 | intro.introStart | intro.asm |
| $A0CB | 2 | intro.introStart | intro.asm |
| $A0CD | 2 | intro.introStart | intro.asm |
| $A0CF | 3 | intro.introStart | intro.asm |
| $A0D2 | 9 | intro.introStart | intro.asm |
| $A0DB | 48 | storage image | |
| $A10B | 1 | nga.transition.ngaTransition | transition.asm |
| $A10C | 2 | nga.transition.ngaTransition | transition.asm |
| $A10E | 1 | nga.transition.ngaTransition | transition.asm |
| $A10F | 2 | nga.transition.ngaTransition | transition.asm |
| $A111 | 2 | nga.transition.ngaTransition | transition.asm |
| $A113 | 2 | nga.transition.ngaTransition | transition.asm |
| $A115 | 2 | nga.transition.ngaTransition | transition.asm |
| $A117 | 1 | nga.transition.ngaTransition | transition.asm |
| $A118 | 2 | nga.transition.ngaTransition | transition.asm |
| $A11A | 2 | nga.transition.ngaTransition | transition.asm |
| $A11C | 2 | nga.transition.ngaTransition | transition.asm |
| $A11E | 1 | nga.transition.ngaTransition | transition.asm |
| $A11F | 2 | nga.transition.ngaTransition | transition.asm |
| $A121 | 2 | nga.transition.ngaTransition | transition.asm |
| $A123 | 2 | nga.transition.ngaTransition | transition.asm |
| $A125 | 2 | nga.transition.ngaTransition | transition.asm |
| $A127 | 2 | nga.transition.ngaTransition | transition.asm |
| $A129 | 2 | nga.transition.ngaTransition | transition.asm |
| $A12B | 1 | nga.transition.ngaTransition | transition.asm |
| $A12C | 2 | nga.transition.ngaTransition | transition.asm |
| $A12E | 2 | nga.transition.ngaTransition | transition.asm |
| $A130 | 3 | nga.transition.ngaTransition | transition.asm |
| $A133 | 2 | nga.transition.ngaTransition | transition.asm |
| $A135 | 2 | nga.transition.ngaTransition | transition.asm |
| $A137 | 1 | nga.transition.ngaTransition | transition.asm |
| $A138 | 2 | nga.transition.ngaTransition | transition.asm |
| $A13A | 2 | nga.transition.ngaTransition | transition.asm |
| $A13C | 2 | nga.transition.ngaTransition | transition.asm |
| $A13E | 2 | nga.transition.ngaTransition | transition.asm |
| $A140 | 2 | nga.transition.ngaTransition | transition.asm |
| $A142 | 3 | nga.transition.ngaTransition | transition.asm |
| $A145 | 1 | nga.transition.ngaTransition | transition.asm |
| $A146 | 2 | nga.transition.ngaTransition | transition.asm |
| $A148 | 2 | nga.transition.ngaTransition | transition.asm |
| $A14A | 1 | nga.transition.ngaTransition | transition.asm |
| $A14B | 2 | nga.transition.ngaTransition | transition.asm |
| $A14D | 2 | nga.transition.ngaTransition | transition.asm |
| $A14F | 1 | nga.transition.ngaTransition | transition.asm |
| $A150 | 2 | nga.transition.ngaTransition | transition.asm |
| $A152 | 2 | nga.transition.ngaTransition | transition.asm |
| $A154 | 3 | nga.transition.ngaEnter | transition.asm |
| $A157 | 3 | nga.transition.ngaEnter | transition.asm |
| $A15A | 2 | nga.transition.ngaEnter | transition.asm |
| $A15C | 3 | nga.transition.ngaEnter | transition.asm |
| $A15F | 2 | nga.transition.ngaEnter | transition.asm |
| $A161 | 3 | nga.transition.ngaEnter | transition.asm |
| $A164 | 2 | nga.transition.ngaEnter | transition.asm |
| $A166 | 2 | nga.transition.ngaEnter | transition.asm |
| $A168 | 3 | nga.transition.ngaEnter | transition.asm |
| $A16B | 2 | nga.transition.ngaEnter | transition.asm |
| $A16D | 2 | nga.transition.ngaEnter | transition.asm |
| $A16F | 3 | nga.transition.ngaEnter | transition.asm |
| $A172 | 3 | nga.transition.ngaEnter | transition.asm |
| $A175 | 2 | nga.transition.ngaEnter | transition.asm |
| $A177 | 3 | nga.transition.ngaEnter | transition.asm |
| $A17A | 2 | nga.transition.ngaEnter | transition.asm |
| $A17C | 3 | nga.transition.ngaEnter | transition.asm |
| $A17F | 2 | nga.transition.ngaEnter | transition.asm |
| $A181 | 3 | nga.transition.ngaEnter | transition.asm |
| $A184 | 2 | nga.transition.ngaEnter | transition.asm |
| $A186 | 3 | nga.transition.ngaEnter | transition.asm |
| $A189 | 2 | nga.transition.ngaEnter | transition.asm |
| $A18B | 3 | nga.transition.ngaEnter | transition.asm |
| $A18E | 1 | nga.transition.ngaEnter | transition.asm |
| $A18F | 2 | nga.transition.ngaEnter | transition.asm |
| $A191 | 3 | nga.transition.ngaEnter | transition.asm |
| $A194 | 2 | nga.transition.ngaEnter | transition.asm |
| $A196 | 2 | nga.transition.ngaEnter | transition.asm |
| $A198 | 2 | nga.transition.ngaEnter | transition.asm |
| $A19A | 2 | nga.transition.ngaEnter | transition.asm |
| $A19C | 2 | nga.transition.ngaEnter | transition.asm |
| $A19E | 2 | nga.transition.ngaEnter | transition.asm |
| $A1A0 | 3 | nga.transition.ngaEnter | transition.asm |
| $A1A3 | 1 | nga.transition.ngaEnter | transition.asm |
| $A1A4 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1A6 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1A8 | 3 | nga.transition.ngaEnter | transition.asm |
| $A1AB | 2 | nga.transition.ngaEnter | transition.asm |
| $A1AD | 3 | nga.transition.ngaEnter | transition.asm |
| $A1B0 | 3 | nga.transition.ngaEnter | transition.asm |
| $A1B3 | 3 | nga.transition.ngaEnter | transition.asm |
| $A1B6 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1B8 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1BA | 2 | nga.transition.ngaEnter | transition.asm |
| $A1BC | 3 | nga.transition.ngaEnter | transition.asm |
| $A1BF | 2 | nga.transition.ngaEnter | transition.asm |
| $A1C1 | 3 | nga.transition.ngaEnter | transition.asm |
| $A1C4 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1C6 | 3 | nga.transition.ngaEnter | transition.asm |
| $A1C9 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1CB | 3 | nga.transition.ngaEnter | transition.asm |
| $A1CE | 2 | nga.transition.ngaEnter | transition.asm |
| $A1D0 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1D2 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1D4 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1D6 | 1 | nga.transition.ngaEnter | transition.asm |
| $A1D7 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1D9 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1DB | 2 | nga.transition.ngaEnter | transition.asm |
| $A1DD | 3 | nga.transition.ngaEnter | transition.asm |
| $A1E0 | 2 | nga.transition.ngaEnter | transition.asm |
| $A1E2 | 3 | nga.transition.ngaEnter | transition.asm |
| $A1E5 | 3 | nga.transition.ngaEnter | transition.asm |
| $A1E8 | 2 | nga.transition.ngaFrameOpen | transition.asm |
| $A1EA | 2 | nga.transition.ngaFrameOpen | transition.asm |
| $A1EC | 2 | nga.transition.ngaFrameOpen | transition.asm |
| $A1EE | 2 | nga.transition.ngaFrameOpen | transition.asm |
| $A1F0 | 2 | nga.transition.ngaFrameOpen | transition.asm |
| $A1F2 | 2 | nga.transition.ngaFrameOpen | transition.asm |
| $A1F4 | 3 | nga.transition.ngaFrameOpen | transition.asm |
| $A1F7 | 1 | nga.transition.ngaFrameOpen | transition.asm |
| $A1F8 | 1 | nga.transition.ngaFrameSkip | transition.asm |
| $A1F9 | 2 | nga.transition.ngaFrameSkip | transition.asm |
| $A1FB | 2 | nga.transition.ngaFrameSkip | transition.asm |
| $A1FD | 2 | nga.transition.ngaFrameSkip | transition.asm |
| $A1FF | 2 | nga.transition.ngaFrameSkip | transition.asm |
| $A201 | 2 | nga.transition.ngaFrameSkip | transition.asm |
| $A203 | 2 | nga.transition.ngaFrameSkip | transition.asm |
| $A205 | 1 | nga.transition.ngaFrameSkip | transition.asm |
| $A206 | 1 | nga.transition.ngaColdFrame | transition.asm |
| $A207 | 2 | nga.transition.ngaColdFrame | transition.asm |
| $A209 | 2 | nga.transition.ngaStart | transition.asm |
| $A20B | 2 | nga.transition.ngaStart | transition.asm |
| $A20D | 3 | nga.transition.ngaStart | transition.asm |
| $A210 | 2 | nga.transition.ngaStart | transition.asm |
| $A212 | 3 | nga.transition.ngaStart | transition.asm |
| $A215 | 2 | nga.transition.ngaStart | transition.asm |
| $A217 | 3 | nga.transition.ngaStart | transition.asm |
| $A21A | 2 | nga.transition.ngaStart | transition.asm |
| $A21C | 3 | nga.transition.ngaStart | transition.asm |
| $A21F | 1 | nga.cart.ngaCartInit | cart.asm |
| $A220 | 2 | nga.transforms.ngaTransform | transforms.asm |
| $A222 | 2 | nga.transforms.ngaTransform | transforms.asm |
| $A224 | 3 | nga.transforms.ngaTransform | transforms.asm |
| $A227 | 1 | nga.transforms.ngaTransform | transforms.asm |
| $A228 | 7634 | storage image | |
| $BFFA | 2 | nga.cart.ngaCartStart | cart.asm |
| $BFFC | 1 | nga.cart.ngaCartStart | cart.asm |
| $BFFD | 1 | nga.cart.ngaCartStart | cart.asm |
| $BFFE | 2 | nga.cart.ngaCartStart | cart.asm |