Illegal Ancilla Dossier

Illegal ancillae are those with IDs greater $43. Through various means, these values can be placed into the ancilla array; however, there is no vector corresponding to these values. As such, they begin executing mostly garbage code.

The following section headers will name each entry as IAx##, where IA abbreviates Illegal Ancilla; x indicates a hexadecimal value; ## is the hexadecimal ID of the ancilla.

The results are fully unpredictable.

IAx44

IAx44_entry
080702
BRK #$00
BREAK
00FFFF
BRL $0702
000704
BRK #$00
BREAK
00FFFF
BRL $0702

This entry points to a location in WRAM. The address is seemingly unused, so it will most likely have $0000, which will execute the break vector. This vector jumps to $00FFFF, which has a BRL that wraps around and reads $0000 as the argument to the opcode, which is a relative distance to branch from the byte after the argument. $0000 is expected to have the original illegal pointer, so execution resumes at $000704, more unused space. This begins a long loop of repeated break vectors. Eventually, the stack will overwrite $0000, resulting in unpredictable effects.

IAx45

IAx45_entry
080106
BRK ??
BREAK
00FFFF
BRL $0106
000108
????

This entry points to a location in WRAM. The low byte of the address is unused, so it will contain the value $00. The next byte is not predictable, but the argument to BRK is generally ignorable. The break vector leads to a jump to $000108. From here, the results are not predictable.

IAx46

IAx46_entry
080701
BRK #$00
BREAK
00FFFF
BRL $0701
000703
BRK #$00
BREAK
00FFFF
BRL $0701

This entry points to a location in WRAM. The high byte of the address is technically used, but always has a value of $00. This leads to a similar BRK loop as IAx44.

IAx47

IAx47_entry
080107
????

This entry points to a location in WRAM. The results are fully unpredictable.

IAx48

IAx48_entry
080700
????

This entry points to a location in WRAM. The low byte (which will determine the first opcode used) is technically predictable, as it is determined by Link's coordinates; however, with 7 consecutive $00 bytes following, there is not much useful that can be done besides returning from the routine safely with an RTS ($60).

IAx49

IAx49_entry
080108
????

This entry points to a location in WRAM. The results are fully unpredictable.

IAx4A

IAx4A_entry
080904
????
IAx4A_entry
080904
BRK #$F0
BREAK
00FFFF
BRL $0904
000906
BRK #$F0
BREAK
00FFFF
BRL $0904

This entry points to a location in WRAM, specifically the OAM buffer. The results are fully unpredictable.

IAx4B

IAx4B_entry
08FF04
0B
PHD
; Doctor to stack
08FF05
FC 0E FC
JSR ($FC0E,X)
; X<10

This entry points to a location in ROM. Specifically, it is executing data that is part of the quake draw routine's tables. Depending on the slot, different code from another table will be executed. Regardless, the game will crash.

IAx4C

IAx4C_entry
080302
BRK ??
IAx4C_entry
080302
ORA (??,X)

This entry points to a location in WRAM. The address $0302 only takes on values of $00 or $01. In the case of $00, the BRK vector will lead to unpredictable results. When ORA (dp,X) is executed, the inevitable crash is merely delayed.

IAx4D

IAx4D_entry
080708
????

This entry points to a location in WRAM. The results are fully unpredictable.

IAx4E

IAx4E_entry
080101
????

This entry points to a location in WRAM. The results are fully unpredictable.

IAx4F

IAx4F_entry
080707
BRK ??
BREAK
00FFFF
BRL $0707
000709
????

This entry points to a location in WRAM. The addresses containing the opcode is unused, resulting in a BRK, but it is followed by overworld screen properties, resulting in unpredictable code.

IAx50

IAx50_entry
080001
BRK ??
BREAK
00FFFF
BRL $0001
000003
????

This entry points to a location in WRAM. The high byte of the address will be the opcode (BRK); after the break vector, the results are unpredictable.

IAx51

IAx51_entry
080807
????

This entry points to a location in WRAM, specifically the OAM buffer. The results are fully unpredictable.

IAx52

IAx52_entry
0804FF
BRK ??
BREAK
00FFFF
BRL $04FF
000501
????

This entry points to a location in WRAM, specifically the last slot in the torch timer array. This array has 16 slots, but in practice, this slot is never used. A BRK will occur, but it will then jump to $0501 for execution. The results are fully unpredictable.

IAx53

IAx53_entry
080409
BRK ??
BREAK
00FFFF
BRL $0409
00040B
BRK ??
BREAK
00FFFF
BRL $0409

This entry points to a location in WRAM, specifically the high byte of the quadrant visits flag for the current underworld tile. This byte is unused, so it will result in a BRK. The address branched to after the BRK is also unused, resulting in a BRK loop.

IAx54

IAx55

IAx54_entry
088383
52 88
EOR ($88)
088385
19 8D FC
ORA $FC8D,Y
; Y=$A6 so [$08FD33]:$C4
088388
90 E8
BCC $E8
; Carry will be cleared
088366
BC 68 0C
LDY $0C86,X
; We've been here before

IAx54 and IAx55 share the same entry point.

This entry points to a location in ROM. Funnily enough, it is pointing straight to another pointer from the jump table we just used, specifically the pointer for the unused ancilla with an ID of $03. Quite quickly, this routine converges into actual code; in fact, it's the code just run to find out which ancilla subroutine to execute. Unfortunately, this returns to a point in the code after a stack push was meant to occur. When a value assumed to be the ancilla ID is recovered from the stack, it will rip off the low byte of our return address ($37). This results in it executing the routine for the ancilla with ID $02, the fire rod shot. When it's finished, the unbalanced stack will eventually cause the game to crash. Forever.

IAx56

IAx57

IAx56_entry
0880B6
00 22
BRK #$22
00FFFF
82 B6 80
BRL $80B6
0080B8
61 80
ADC ($80,X)
0080BA
85 03
STA $03
0080BC
B9 7D 80
LDA $807D,Y
; Y=$AA; so [$8127]:$8D
0080BF
85 04
STA $04
0080C1
B9 99 80
LDA $8099,Y
; Y=$AA; so [$8143]:$83
0080C4
85 05
STA $05
0080C6
DC 03 00
JMP [$0003]

IAx56 and IAx57 share the same entry point.

This entry points to a location in ROM, specifically the routine AncillaAdd_FireRodShot; however, its entry point does not align with the code, and it treats the parameter of an STA dp as the opcode, resulting in a BRK being executed. The break vector leads to the middle of the topmost subroutine, RunModule. The entry point does not align with the code, but it recovers after one instruction. From here, the result is mostly unpredictable.

However, $80 is in the middle of some unused RAM. If this illegal ancilla is in slots 0, 1, or 2, then the ADC will look at the word in addresses $80, $81, or $82, respectively, all of which contain the value $0000. In these cases, the accumulator, which currently contains the high byte of our pointer, will have the value of $0000 added to it, which contains the low byte of our pointer. The carry is always clear, so we know that we will get $36 as our result, with the carry flag set. This results in a jump to a known address in bank83, of which bank03 is a mirror. This bank is filled entirely with overworld tile32 data, so, needless to say, the results are garbage. But we can follow along for a bit:

838D36
01 00
ORA ($00,X)
838D38
D5 2D
CMP ($2D,X)
838D3A
0A 0C
LDY #$0C
838D3C
21 00
AND ($00,X)
838D3E
7E 2D 1D
ROR $122D,X
838D41
CC 01 02
CPY $0201
838D44
CC CC 4C
CPY $4CCC
; Open bus
838D47
4E 22 44
LSR $4422
; More open bus
838D4A
4F 4E 4D 51
EOR $514D4E
838D4E
44 44 FF
MVP $FF, $44
; Nice
838D51
A2 57
LDX #$57
838D53
59 23 44
EOR $4423,Y
; Speed 5: Open Bus
838D56
59 5B 5D
EOR $5D5B,Y
838D59
59 44 44
EOR $4444
838D5C
5F 58 60 37
EOR $376058,X
838D60
44 42 37
MVP $37, $42
838D63
A8
TAY
838D64
6B
RTL

The game crashes because the stack is unbalanced after this RTL.

For all other indices, the results are fully unpredictable.

IAx58

IAx59

IAx5A

IAx5B

IAx58_entry
08B6B7
RTS

IAx58, IAx59, IAx5A, and IAx5B all share the same entry point.

This entry points to a location in ROM, specifically one of the exit points of Ancilla_QuakeSpell. The entry point aligns perfectly with the code, an RTS that allows the ancilla to exit safely, without doing anything.

IAx5C

IAx5C_entry
0868BD
68
PLA
0868BE
37 37
AND [$37],Y
0868BF
00 00
BRK #$00
00FFFF
82 BD 68
BRL $68BD
0068BF
68
PLA
0068C0
32 32
AND ($32)

This entry points to a location in open bus. The results are fully unpredictable.

IAx5D

IAx5D_entry
08D00C
BNE $13
; Z=0 because we last loaded $D0
08D021
JSR $F6B6
; Ancilla_PrepAdjustedOamCoord
.Adjust_OAM
08F6B6
LDY $0C7C,X
08F6B9
LDA $F67F,Y
; Y=$B8; [$08F737]:$05
08F6BC
STA $65
; Expected legal values: $10, $20, $30
08F6BE
STZ $64
08F6C0
LDA $0BFA,X
; All values of X when this code runs
08F6C3
STA $00
; should be <10
08F6C5
LDA $0C0E,X
; So I wouldn't expect any corruption
08F6C8
STA $01
08F6CA
LDA $0C04,X
08F6CD
STA $02
08F6CF
LDA $0C18,X
08F6D2
STA $03
08F6D4
REP #$20
08F6D6
LDA $00
08F6D8
SEC
08F6D9
SBC $0122
08F6DC
STA $00
08F6DE
LDA $02
08F6E0
SEC
08F6E1
SBC $011E
08F6E4
STA $02
08F6E6
STA $04
08F6E8
SEP #$20
08F6EA
RTS

This entry points to a location in ROM, specifically part of the flute ancilla's consumption code. The entry point aligns perfectly with the code. The branch is always taken, as the Z flag will always be unset from reading the high byte of the pointer.

This creates a glitchy object (often the item get sprite) on screen, but beyond that, it does not appear to have any interesting consequences in and of itself. If the object ends up being off screen, it will just delete itself from the array.

IAx5E

009E05
15 78
ORA $78,X
009E07
15 79
ORA $79,X
009E09
15 76
ORA $76,X
009E0B
15 77
ORA $77,X
009E0D
15 76
ORA $76,X
009E0F
15 77
ORA $77,X
009E11
15 78
ORA $78,X
009E13
15 79
ORA $79,X
009E15
15 78
ORA $78,X
009E17
15 79
ORA $79,X
009E19
15 92
ORA $92,X
009E1B
08
PHP
009E1C
98
TYA
009E1D
08
PHP
009E1E
A4 08
LDY $08
009E20
AD 0C 93
LDA $930C
; DB is still $08
009E23
08
PHP
009E24
99 08 A5
STA $A508,Y
; This does nothing
009E27
08
PHP
009E28
AD 8C AD
LDA $AD8C
009E2B
4C A4 48
JMP $48A4
; Open bus
0048A4
48
PHA
0048A5
64 64
STZ $64
0048A7
00 00
BRK #$00
BREAK
00FFFF
82 0E 9E
BRL $9E03

This entry points to a location in ROM, specifically part of the bomb draw routine's data table. The first instruction is a BRK. Eventually, this leads to open bus, making the results crashdictable.

IAx5F

IAx5F_entry
080C4A
????

This entry points to a location in WRAM, specifically the start of the ancilla ID array. This array is easily manipulable; it can, and has, been used for arbitrary code execution.

IAx60

IAx60_entry
0811A5
????

This entry points to a location in WRAM, specifically a general purpose DMA buffer. The results are fully unpredictable.

IAx61

IAx61_entry
0806D0
????

This entry points to a location in WRAM, specifically an array of shutter door location values. Results will vary based on the position and order of doors, but most of the results are fully unpredictable..

IAx62

IAx62_entry
088020
JSR $8035
; Ancilla_SetSfxPan
088023
STA $012D
088026
RTS

This entry points to a location in ROM, specifically the Ancilla_SFX1_Pan routine. The entry point aligns with the code perfectly and results in a stable return. Because the sound effect attempted is $80, this will only cause the ambient sound effect (if any) to fade away, as negative values flag this behavior for those sound effects specifically.

IAx63

IAx63_entry
082090
20 20 20
JSR $2020
; Open bus
082020
92 92
STA.b ($92)
082022
20 20 20
JSR $2020
082020
24 24
BIT.b $24
082022
???

This entry points to a location in open bus. The results are fully unpredictable. And then some.

IAx64

IAx64_entry
08908B
LDA $0C22,X
; Ancilla_Move_Y

This entry points to a location in ROM, specifically the Ancilla_Move_Y routine. The entry point is exactly the beginning of the routine, so the code runs perfectly and without fault. Thus, this ancilla will be in a constant state of vertical movement. Every array used by this routine is 10 entries long, so there is no potential for corruption.

IAx65

IAx65_entry
082A20
ROL A
082A21
ROL A
082A22
ROL A
082A23
ROL A
; Let's skip ahead
082A59
SED
082A5A
SED
082A5B
SED
082A5C
SED
; Let's skip ahead again…
0833B6
SED
0833B7
SED
0833B8
SED
; Just a little more…
084014
SED
084015
SED
084016
????

This entry points to a location in open bus. In general, the results are fully unpredictable.

In many cases, the same instructions are used ad nauseum, but eventually, execution lands on the controller ports, allowing for full control arbitrary code execution in a TAS. This can make this illegal ancilla predictable and usable; however, other CPU operations will clobber the value in open bus.

IAx66

IAx66_entry
08A086
60
RTS

This entry points to a location in ROM, specifically part of the door debris draw routine's data table. It just so happens to land on the value $60, which is the opcode for RTS, causing the ancilla's routine to exit immediately.

IAx67

IAx67_entry
08A904
92 FA
STA ($FA)
; A=$A9
08A906
60
RTS

This entry points to a location in ROM, specifically the end of the jump splash draw routine. The entry point does not align perfectly with the code, but it recovers quickly. This code takes the value of the accumulator, which currently holds the high byte of the pointer ($A9), and stores it with an indirect write to the 16-bit address present in $FA. This address holds the player 1 joypad input from the previous frame: AXLR..... $FB is the same for player 2, but the code for writing it is unreachable; thus, the high byte of the indirect address is always $00.

Effectively, this means we can write $A9 to 16 different addresses using a standard SNES controller; within the address range $00$F0, for low nibbles of $0. The bottom nibble is the controller's signature, which is %0000 for a regular controller.

Controller input Address Effect
%0000      $00 Scratch space Useless
%0001    R $10 Game module Crash
%0010   L  $20 Link's Y-coordinate low byte Funny teleport
%0011   LR $30 Link's Y velocity Nothing; overwritten before use
%0100  X   $40 Temp variable for coordinates Nothing; overwritten before use
%0101  X R $50 Change direction flag Link cannot turn anymore
%0110  XL  $60 Attract mode sequence counter Nothing; zeroed every frame as collateral damage
%0111  XLR $70 Free RAM Nothing
%1000 A    $80 Free RAM Nothing
%1001 A  R $90 OAM buffer location pointer Nothing; overwritten before use
%1010 A L  $A0 Room ID Repointed to EP big chest room or a nonexistent room
ID $01A9 corresponds to cape and mirror in SRAM
%1011 A LR $B0 Subsubmodule Game will crash during transitions
%1100 AX   $C0 Tilemap buffer pointer Nothing; overwritten before use
%1101 AX R $D0 Room load pointers Nothing; overwritten before use
%1110 AXL  $E0 BG1 horizontal scroll low byte Nothing; corrected every frame
%1111 AXLR $F0 Joypad 1 inputs Changes input for joypad 1 to B+Select+Up+Right

With a non-standard controller, we can write to any address on page zero. That's a bit too much to document here, but I will note that Yuzuhara was able to write to Link's speed variable.

IAx68

IAx68_entry
08D90B
STA $0C0E,X
; A=$D9
08D90E
LDA $02
; Could be anything
08D910
STA $0C04,X
08D913
LDA $03
08D915
STA $0C18,X
08D918
BRA +7
; Ancilla_SpinSpark

This entry points to a location in ROM, specifically the end of a routine that transmutes ancilla $2A into ancilla $2B. The low byte of the Y-coordinate will remain at its current value, and the high byte will take the value $D9. The low and high bytes of the X-coordinate will be garbage data.

After the coordinates are set each frame, this illegal ancilla will behave like a normal spin spark. The ID rewrite of the routine is not performed, so this ancilla will remain with the illegal ID.

IAx69

This illegal ancilla shares the same pointer and effect as IAx5F.

IAx6A

IAx6A_entry
0803F0
????

This entry points to a location in location in WRAM, specifically the flute cooldown timer. This results in fully unpredictable results or a BRK (followed by fully unpredictable results).

IAx6B

IAx6B_entry
081088
????

This entry points to a location in WRAM, specifically the arbitrary DMA buffer. The results are fully unpredictable.

IAx6C

IAx6C_entry
08B9F8
01 00
ORA ($00,X)
08B9FA
FA
PLX
08B9FB
FF FA FF F4
SBC $F4FFFA,X
08B9FF
FF 01 00 FA
SBC $FA0001,X
08B903
FF FA FF F4
SBC $F4FFFA,X
08B907
FF 01 00 FA
SBC $FA0001,X
08B90B
FF FA FF F4
SBC $F4FFFA,X
08B90F
FF 01 00 FA
SBC $FA0001,X
boring…
08BA53
FF FD FF F3
SBC $F3FFFD,X
08BA57
FF FF FF F8
SBC $F8FFFF,X
08BA5B
FF 09 00 0F
SBC $0F0009,X
08BA5F
00 06
BRK #$06
BREAK
00FFFF
82 F8 B9
BRL $B9F8
00B9FA
61 71
ADC ($71,X)
00B9FC
AA
TAX
00B9FD
71 EC
ADC ($EC),Y
00B9FF
01 EC
ORA ($EC,X)
00BA01
01 70
ORA ($70,X)
00BA03
31 71
AND ($71),Y
00BA05
31 72
AND ($72),Y
00BA07
31 7E
AND ($7E),Y
Not worth looking at…
00BA87
71 AB
ADC ($AB),Y
00BA89
71 AA
ADC ($AA),Y
00BA8B
71 CF
ADC ($CF),Y
00BA8D
0D CF 8D
ORA $8DCF
00BA90
CF 4D CF CD
CMP $CDCF4D
00BA94
1F 0D 1F 8D
ORA $8D1F0D,X
00BA98
1F 4D 1F CD
ORA $CD1F4D,X
00BA9C
01 0D
ORA ($0D,X)
00BA9E
01 8D
ORA ($8D,X)
00BAA0
01 4D
ORA ($4D,X)
00BAA2
01 CD
ORA ($CD,X)
00BAA4
D0 19
BNE $19

This entry points to a location in ROM, specifically part of the magic powder draw routine's table. After doing a bunch of subtraction, a BRK is hit and execution resumes in the middle of a large data table. Given the onslaught of indirect addressing, results are fully unpredictable. A number of branch instructions can potentially occur, but overall almost all outcomes will be a crash.

IAx6D

IAx6D_entry
080280
????

This entry points to a location in WRAM, specifically an array of ancillae OAM priority values. Results are, you guessed it, fully unpredictable.

IAx6E

IAx6E_entry
0804F0
????

This entry points to a location in WRAM, specifically the torch timer array. Unlike IAx52, this points to the beginning of the array, which is actually used in practice. Unfortunately, this still results in unpredictable code or a BRK.

IAx6F

IAx6F_entry
0830A9
30 30
BMI $30
IAx6F_entry
0830AB
30 30
BMI $30
IAx6F_entry
0830AD
30 30
BMI $30
IAx6F_entry
0830AF
30 30
BMI $30

This entry points to a location in open bus. It will constantly not branch on negatives until it reaches CPU registers. Afterwards, the results are fully unpredictable.

IAx70

IAx70_entry
080485
????

This entry points to a location in WRAM, specifically the last byte in an array that counts the number spiral staircases. The results are fully unpredictable.

IAx71

IAx71_entry
0810A9
????

This entry points to a location in WRAM, specifically part of the arbitrary DMA buffer. The results are fully unpredictable.

IAx72

08B3A4
PHX
; Code before entry for reference
08B3A5
LDA $7F5810,X
08B3A9
CMP #$0D
08B3AB
BEQ $76
; Does not align with below
IAx72_entry
08B3AC
ROR $0A,X
08B3AE
CLC
08B3AF
ADC $7F5810,X
08B3B3
CLC
08B3B4
ADC #$02

This entry points to a location in ROM, specifically part of the bombos spell draw routine. The entry point does not align perfectly with the code, but it recovers after one instruction. Unfortunately, the entry is after where a stack push was meant to occur, so at the end of this routine, the stack will become unbalanced, resulting in a crash. I mean... The results are fully unpredictable.

IAx73

IAx73_entry
08F00F
E2 85
SEP #$85
08F011
00 E2
BRK #$E2
BREAK
00FFFF
82 0F F0
BRL $F00F
00F011
C5 7E
CMP $7E
00F013
A8
TAY
00F014
29 E0
AND #$E0
00F016
03 F0
ORA $F0,S
00F018
06 98
ASL $98
00F01A
38
SEC
00F01B
E9 20
SBC #$20
00F01D
00 A8
BRK #$A8
BREAK
00FFFF
82 0F F0
BRL $F00F

This entry points to a location in ROM, specifically part of the Skull Woods flame routine. The entry point does not align with the code and ends up executing a BRK. Interestingly, the SEP instruction sets the interrupt-disable flag; however, this flag has no effect on a software interrupt.

The location branched to does not align perfectly with the code. It recovers after 1 instruction; however, the routine entered expects both the accumulator and index registers to be in 16-bit mode. Having entered with both in 8-bit mode, the CPU fails to stay aligned with the intended code. This is irrelevant, as the code eventually enters a BRK loop.

IAx74

IAx74_entry
08BC11
00 99
BRK #$99
BREAK
00FFFF
82 11 BC
BRL $BC11
00BC13
51 85
EOR ($85),Y
etc.

This entry points to a location in ROM, specifically the end of the dash tremor code. The break vector hit leads to a data table, where endless direct page instructions are executed. They're not worth documenting, and I hope the game eventually crashes.

IAx75

IAx75_entry
080C7C
????

This entry points to a location in WRAM, specifically the ancilla layer array. Without using other misslots to write different values here, only $00 or $01 will be present. The results are fully unpredictable.

IAx76

This illegal ancilla shares the same pointer and effect as IAx61.

IAx77

IAx77_entry
088C22
STA $0C0E,X
088C25
PLA
088C26
STA $0BFA,X
088C29
PLA
088C2A
STA $0C18,X
088C2D
PLA
088C2E
STA $0C04,X

This entry points to a location in ROM, specifically part of an ancilla hitbox routine. The entry point aligns perfectly with the code; however, it skips over several stack pushes that were meant to occur. This leaves the stack unbalanced, causing the game to eventually crash.

IAx78

IAx78_entry
080DBA
????

This entry points to a location in WRAM, specifically a general purpose property of sprites. Predictably, the results are fully unpredictable.

IAx79

IAx79_entry
080A80
????

This entry points to a location in WRAM, specifically part of the OAM buffer. The results are fully unpredictable.

IAx7A

IAx7A_entry
089022
0C 91 90
TSB $9091
; Write to ROM ignored
089025
LDA $01
089027
SEC
089028
SBC #$04
08905A
LDX $0FAC
08905D
LDA $8F82,X
089060
LDY #$02
08907F
RTS

This entry points to a location in ROM, specifically the tink spark draw routine. The entry point does not align perfectly with the code, but it recovers after 1 instruction. Eventually the routine returns cleanly.

Of particular interest is the instruction at $08:905A, which loads the X register with the value of $0FAC. The tink spark is not a slotted ancilla, so it does not have any recovery of slot after this. Thus, this instruction will determine the next slot executed −1. Normally, this address only takes on values from 0–5; however, if we found a way to modify this address, we could execute ancillae in the illegal slots from $0A$7F.

This also comes with the potential to hardlock the game in an infinite loop. For example, if IAx7A is in slot 0 and $0FAC has a value of $02, then the next ancilla executed will be slot 1, followed by slot 0 again. This will repeat ad infinitum.

Less interestingly, this illegal ancilla should also result in some broken objects on screen.

IAx7B

This illegal ancilla shares the same pointer and effect as IAx78.

IAx7C

IAx7C_entry
080480
????

This entry points to a location in WRAM, specifically a variable that counts spiral staircases. The results are fully unpredictable.

IAx7D

IAx7D_entry
088022
80 8D
BRA $7FB1
087FB1
8D 8D 8D
STA $8D8D
087FB3
80 80
BRA $7F36
087F36
80 80
BRA $7EB8

This entry points to a location in ROM, specifically an ancilla sound effects routine. The entry point does not align with code, causing it to branch to open bus. It will keep branching backwards until it reaches CPU registers or the A bus is clobbered. These results are fully unpredictable.

Under most circumstances, HDMA will indeed clobber the A register, and the CPU should eventually reach $08:8000, where it will put a broken sound effect into SFX set 1 and allow this ancilla to recover cleanly.

IAx7E

This illegal ancilla shares the same pointer and effect as IAx78.

IAx7F

IAx7F_entry
0800A0
????

This entry points to a location in WRAM, specifically the current underworld room ID. The high byte located in $A1 can only ever contain $00 or $01. These results are fully unpredictable, though being in room $60 can return safely.

IAx80

IAx80_entry
0803A9
????

This entry points to a location in WRAM, specifically a general purpose property of F-slot ancillae. The results are fully unpredictable.

Further illegal ancilla

Due to the left shift when calculating the index into the pointer table, illegal ancillae with an ID of $81 and higher will behave as the ancilla with an ID $80 lower. This is because the top bit is discarded after decrementing, resulting in the same index.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.

The results are fully unpredictable.