-
-
Notifications
You must be signed in to change notification settings - Fork 52
Investigation: The Apple IIgs Memory Manager
As of the first draft of this document, all parts are present for Apple IIgs emulation but bugs remain. At least one of those manifests as the in-ROM memory manager not responding as expected; in particular:
- titles including Airball, Bouncing Bluster and Crystal Quest meet an unexpected
BRK
during startup, somewhere in the 00:BB or 00:BC page, dropping the user into the monitor; and - titles such as Defender of the Crown, Block Out and Bubble Ghost stop completely on an error of 'Unable to reserve memory segment $0201'.
The second set would appear overtly to be memory manager related; the former also seems to be.
Digging down on Airball, the immediate progenitor of the error is this routine in the ROM's MoveUp
(from mm.asm):
lda Count+2
adc Dest+2 ;A = 00bank
xba ;A = bank00
ora #$44 ;MVP opcode
pha
bra muFirst
i.e. the ROM is intending to assemble the sequence MVP
, RTS
on the stack, to which it later jumps. An ORA
is used because a single-byte load isn't available. In my emulator the value at Dest+2
originates from whatever the contents of RAM were at power up rather than necessarily being 00
and as a result the generated opcode isn't MVP
and the on-stack sequence that is jumped to runs off the rails.
Specifically the value at Dest+2
at that point in the code is 7f15
.
By the time MoveUp
is reached, the value is in Dest+2
(i.e. 00bcb1
and 00bcb2
).
(Aside on cycle times below: they are relative to the 14Mhz bus, and depend on things like the exact disk rotation speeds I currently have, so should not be expected necessarily to be accurate in the future)
It was placed there by a STY
at fc0d5f
, 502081910 cycles since the machine launched. That immediately follows a load from 00bcc5/6
.
The value was put into 00bcc5/6
by a STY
at fc0d5f
, 502078270 cycles since the machine launched. The value had been picked up by a LDY [$21]
at fc0cb2
, which read the value from 00bcc9/a
.
It had been placed into 00bcc9/a
by a STA
at fc0fcb
, 502077180 cycles since the machine launched. It picked the value up from from a LDA [$13],y
with y=2
at fc0fc9
, which read the value from e11806/7
.
In context, that is likely to be the upper word of the block of memory pointed to by a memory handle; see précis on memory manager handles below.
The value was written to e11806/7
by a STA [$17],y
at fc0dac
with y=2
, 497930810 cycles since machine launch. Its origin then was one instruction earlier, a LDA $03,x
with x=2
and d=$bca4
at fc0daa
, which accessed bca9/a
.
7f15
had been stored to bca9/a
at fc0da4
by a STA [$05]
, 497929740 cycles since machine launch, having been read from 00bcc1/2
one instruction earlier by a LDA [$1d]
.
It had been stored there by a STY [$1d]
at fc0d5f
, 497928970 cycles since machine launch, having been fetched by a LDY [$21]
at fc0cb2
, 497928450 cycles since machine launched, which fetched from 00bcc5/6
.
That value was left by a STA [$21]
at fc0fcb
, 497927880 cycles since machine launch. It was fetched one instruction earlier by a LDA [$13], y
with y=2
, and d=$bca4
yielding a base for the long address of bcb7
which gave e119a8
; that plus y leads to a two-byte fetch from e119aa/b
.
Digging down on e119ab
, logging reads and writes to it since launch until its relevant access at 497927875 cycles since launch shows:
e119ab <- 00 [15775430]
e119ab -> 00 [141578780]
e119ab -> 00 [141579715]
e119ab <- 00 [469272795]
e119ab -> 00 [469274435]
e119ab -> 00 [469274490]
e119ab -> 00 [473880845]
e119ab -> 00 [473881875]
e119ab -> 00 [473920325]
e119ab <- 00 [480022440]
e119ab <- 7f [495809345]
e119ab -> 7f [495811040]
e119ab -> 7f [495811095]
e119ab -> 7f [495820535]
e119ab -> 7f [495820590]
e119ab -> 7f [497927875]
Therefore: it looks like the handle map is properly cleared at startup, which at least takes guesses around detecting a cold start and with loop lengths off the table.
Digging down on cycle 495809345 after machine launch returns us to fc0dac
, the same location that wrote to e11806/7
above; that instruction begins 495809310 cycles after machine launch.
The memory manager uses the region between e11700
and e11aff
for a list of handles. Each handle is 20 bytes long and has the format:
- 0–3: address of held memory;
- 4–5: attributes;
- 6–7: segment owner ID;
- 8–11: size of held memory;
- 12–15: pointer to next;
- 16–19: pointer to previous.
e119aa/b
is 682 bytes into the full list of handles; it is therefore the high two bytes of the first field — the address of the memory held — of the 34th handle.