The Wonderful World of NES/Fami Cart Copy Protection ---------------------------------------------------- 10/26/05 Version 1.0 Written by: Kevin Horton --- I'm about to describe how the copy protection works and was broken on the Earthworm Jim 2 "pirate original" cartridge. The cartridge itself isn't too special; inside the cheap plastic Fami shell is a board with 3 gloptops on it like many other pirate cartridges. What makes this one special, however, is the great lengths they went to to.. 1) prevent reverse-engineering the code 2) used things like "open bus" to get values needed for later use 3) make it difficult to convert the game to use another mapper Today, we're going to focus on parts 1 and 2. --- This description assumes the reader knows all the standard Nintendo/Fami nomenclature, but the term "open bus" may not be widely known. See the appendix for info on how open bus works. Also, I fully decode the "invalid" opcodes for the 6502 in my disassemblies, so don't be scared if you see some unfamiliar 6502 opcodes!!! On with the show! --- There seems to be several layers of protection on the code. The programmers obviously spent a great deal of time devising these protections to make it as difficult as possible to trace the code. Without seeing the code execute step by step, it'd be nearly impossible. There were many "traps" in the code designed to crash the CPU or get hung up if things were not JUST right. They also performed bankswitches in the middle of routines, causing the CPU to fall into the *middle* of another routine. This makes tracing through the code via disassembly literally impossible. All the code was laid out bare on my disassembly, but there literally was just NO way to trace through the strings of spaghetti code without seeing the code execute from the cartridge. And this is where Microbug and CopyNES come in. I recently developed a powerful on-NES 6502 "emulator" that allowed me to actually single step the code ON the cartridge, ON the NES and see the registers, a disassembly, and all the other stuff I needed to know at one time. This was my first actual real "live" test with the new software and it seems to work. All disassemblies and other things are directly cut and pasted from Microbug. Overview of the protection: The layers of protection are many: they are arranged like so: 1) Bogus writes to registers that don't exist. 2) Reading open bus values and using them later. 3) Bankswitching in the middle of a routine, which drops you into the middle of another. 4) Use of what looks like "junk" code that really executes 5) Using "deterministic" code (see below) to write instructions into RAM 6) Writing seeming "junk" into RAM, then using it as an address to write to which performs a bankswitch 7) Using 2 types of hash functions on PRG ROM banks to get values which are then fed back into the hash to generate new values and code(!) 8) Manufacturing a jumptable and critical mapper write routines in the RAM using said deterministic code 9) Piping all bankswitch and other critical functions into RAM, and/or the jumptable in RAM 10) Putting traps in the code so that if a value is not right, it hangs up the CPU or crashes it. 11) Using JMP() and PHA:PHA:RTS to generate impossible to follow branch points all over the code. 12) Using mapper register mirrors to mask writes to the mapper, and to mask how many registers there really are. --- Starting out. Resetting the CPU drops us at... FF84: 20 38 78 JSR $7838 FF87: D8 CLD FF88: A9 00 LDA #$00 ;<-- Reset drops us into the "middle" of some code FF8A: 8D 00 20 STA $2000 FF8D: 8D 01 20 STA $2001 ;turn the PPU off here FF90: 8D 80 67 STA $6780 ;this write does absolutely nothing FF93: A9 03 LDA #$03 FF95: 8D 81 67 STA $6781 ;this write does absolutely nothing FF98: AD 81 57 LDA $5781 ;Read open bus! Acc will hold 57h FF9B: 0A ASL FF9C: 0A ASL FF9D: 0A ASL FF9E: 18 CLC FF9F: E9 24 SBC #$24 FFA1: 8D FF 07 STA $07FF ;store 93h into 7ffh (this will be used later) FFA4: A9 E4 LDA #$E4 FFA6: 8D 80 56 STA $5680 ;useless write FFA9: A9 78 LDA #$78 FFAB: 8D 81 56 STA $5681 ;useless write FFAE: 8D 00 A0 STA $A000 ;set up mirroring FFB1: A9 C4 LDA #$C4 FFB3: 8D FC 5F STA $5FFC ;BANKSWITCH! Writing here changes banks! FFB6: A9 C5 LDA #$C5 ;---------------------------------------------- FFB8: 8D FD 5F STA $5FFD ;Trap #1 FFBB: A9 80 LDA #$80 ;the rest of this code is misdirection FFBD: 8D FE 5F STA $5FFE ;it is never used! FFC0: A9 81 LDA #$81 FFC2: 8D FF 5F STA $5FFF Right out of the starting gate, we can see that two tricky things have been done. First, they read open bus and store it for later use, and then they hide an "active" bankswitch right in the MIDDLE of what looks like a string of code to init the mapper. If you continue running this code, it will LOOK like it's doing something useful for a while, but it will then crash when it jumps into la-la land. That's trap #1 Here's a closer examination of what happens because of the bankswitch: FFB1: A9 C4 LDA #$C4 FFB3: 8D FC 5F STA $5FFC ;BANKSWITCH! Writing here changes banks! FFB6: A9 80 LDA #$80 ;this is code in the NEW bank FFB8: 78 SEI ;turn off interrupts FFB9: 8D A8 F0 STA $F0A8 ;turn off IRQs FFBC: 8D A8 70 STA $70A8 ;does nothing FFBF: 8D A8 60 STA $60A8 ;does nothing FFC2: 8D A8 50 STA $50A8 ;does nothing FFC5: 8D A8 50 STA $50A8 ;does nothing FFC8: 8D A8 8D STA $8DA8 ;Selects a CHR bank (useless) FFCB: A9 C5 LDA #$C5 FFCD: 8D A8 7F STA $7FA8 ;does nothing FFD0: 8D A8 6F STA $6FA8 ;does nothing FFD3: 8D A8 5F STA $5FA8 ;BANKSWITCH! FFD6: 8D A8 4F STA $4FA8 ;--------------------------------------------- FFD9: 8D A8 3F STA $3FA8 ;Trap #2 FFDC: 8D A8 2F STA $2FA8 ;continuing execution here leads to invalid opcodes FFDF: 8D A8 1F STA $1FA8 ;and crashination FFE2: 8D A8 0F STA $0FA8 FFE5: 8E A8 0F STX $0FA8 FFE8: 80 NOP FFE9: A8 TAY This part is VERY interesting, because it looks JUST like you hit an address pointer table or something, rather than code. There is a big run of STA's above the entry point that look just like table entries. Even the LDA #$80 and SEI look like similar "address" entries! The "pointer table" continues past the STX at the end into undocumented opcodes and other crashy things. As before, they bankswitch right in the "middle" of the code. FFD0: 8D A8 6F STA $6FA8 ;does nothing FFD3: 8D A8 5F STA $5FA8 ;BANKSWITCH! FFD6: 49 00 EOR #$00 ;this does nothing FFD8: A8 TAY FFD9: 85 00 STA $00 ;store C5h at 0000h FFDB: A9 5C LDA #$5C FFDD: 85 01 STA $01 ;store 5Ch at 0001h FFDF: A9 CD LDA #$CD FFE1: 91 00 STA ($00),Y ;BANKSWITCH! store CDh at 5D8Ah (!) FFE3: C8 INY ;------------------------------------------ FFE4: A9 48 LDA #$48 ;Trap #3 FFE6: 91 00 STA ($00),Y ;this code is worthless and running it will FFE8: AD 49 00 LDA $0049 ;cause the thing to crash FFEB: 8D E0 04 STA $04E0 FFEE: 06 AD ASL $AD FFF0: 79 06 29 ADC $2906,Y They are getting a bit more devious with their protection scheme now. They are indexing a write using seemingly "random" numbers which when calculated out, equal the bankswitch register. As before, this code is just smack-dab in the middle of other code so that it looks like it's part of a larger innocuous subroutine! FFDF: A9 CD LDA #$CD FFE1: 91 00 STA ($00),Y ;BANKSWITCH! store CDh at 5D8Ah (!) FFE3: D8 CLD ;clear the decimal flag (finally :-) FFE4: A9 00 LDA #$00 FFE6: 8D 15 40 STA $4015 ;shut the sound up FFE9: 8D 17 40 STA $4017 ;set up IRQ thing FFEC: A9 4C LDA #$4C FFEE: 85 40 STA $40 ;write a JMP opcode to 0040h FFF0: AD FC FF LDA $FFFC FFF3: 85 41 STA $41 ;write lower byte of "reset vector" FFF5: AD FD FF LDA $FFFD FFF8: 85 42 STA $42 ;write upper byte of "reset vector" FFFA: 4C 40 00 JMP $0040 ;jump to our JMP instruction in RAM OK, things are starting to get a bit more complicated. They are now writing code into RAM which will just jump back into ROM when executed: 0040: 4C 00 FF JMP $FF00 This jumps us right back into the ROM, and the entire exercise was just a waste of time and cycles... However, in the ROM, there are several places which do similar things to this and JMP to 0040h, so knowing which one is right is very difficult to determine from a disassembly. FEFA: A5 49 LDA $49 FEFC: F0 09 BEQ $FF07 FEFE: A9 00 LDA #$00 FF00: A9 3F LDA #$3F ;<-------- we get dropped back into here FF02: 8D 06 20 STA $2006 ;our subroutine is "already in progress" ! FF05: A9 00 LDA #$00 FF07: 8D 06 20 STA $2006 ;point PPU addy to palette FF0A: A2 20 LDX #$20 ;32 palette bytes FF0C: A9 0E LDA #$0E ;black FF0E: 8D 07 20 STA $2007 ;write palette entry FF11: CA DEX FF12: D0 FA BNE $FF0E ;clear out the entire palette FF14: A5 00 LDA $00 ;copy our little 5CC5h address over FF16: 85 02 STA $02 FF18: A5 01 LDA $01 FF1A: 85 03 STA $03 FF1C: A9 C4 LDA #$C4 FF1E: 91 02 STA ($02),Y ;BANKSWITCH! store C4h at 5D8Ah FF20: 8D E0 6F STA $6FE0 ;-------------------------------------------- FF23: 8D FE 07 STA $07FE ;Trap #4 FF26: A9 50 LDA #$50 ;note how this code looks very "promising" FF28: 8D 80 6E STA $6E80 ;from a bankswitching perspective! FF2B: A9 76 LDA #$76 We get dropped in what looks like the middle of a routine, but all that code above FF00h is just crap and is never used. It's merely some more misdirection to make life hard. Here, they clear out the palette which essentially blanks the screen since all the palette entries are now black. Then, they copy the 5CC5h pointer over (loaded in earlier) and use it to peform a bankswitch. Note that Y was not changed and is still C5h. This again writes to 5D8Ah as before. Notice how the code after the bankswitch looks very "promising"... like those writes are really initializing the mapper registers or something useful like that. Of course they are just bullshit and are never meant to be executed. Executing the code there will cause the CPU to crash. FF1C: A9 C4 LDA #$C4 FF1E: 91 02 STA ($02),Y ;BANKSWITCH! store C4h at 5D8Ah FF20: AD 02 20 LDA $2002 FF23: 30 FB BMI $FF20 ;wait 1 PPU frame FF25: AD 02 20 LDA $2002 ;reset PPU latch select (not too useful) FF28: A0 00 LDY #$00 FF2A: A9 5E LDA #$5E FF2C: A2 7F LDX #$7F ;initialize all CPU registers here for the next FF2E: 8E FE 07 STX $07FE ;part, and write 7Fh to 07FEh FF31: 8E 80 5F STX $5F80 ;BANKSWITCH! FF34: A2 8D LDX #$8D ;------------------------------------------- FF36: 8E FF 07 STX $07FF ;Trap #5 FF39: 8E 81 5F STX $5F81 ;more promising code. though 7FF gets overwritten FF3C: A9 90 LDA #$90 ;which would be bad... and the code crashes FF3E: 95 C6 STA $C6,X They bankswitch this time wasn't hidden a whole lot. This section of code (again dropped in the middle of other seemingly "normal" code) waits 1 frame on the PPU and loads up the CPU registers, writes a value to 7FEh which will be used later, and bankswitches. FF2E: 8E FE 07 STX $07FE ;part, and write 7Fh to 07FEh FF31: 8E 80 5F STX $5F80 ;BANKSWITCH! FF34: 9A TXS ;set stack to 7Fh FF35: 9D E2 06 STA $06E2,X FF38: 95 00 STA $00,X ;store 5Eh into 761h and 07fh FF3A: CA DEX FF3B: 95 00 STA $00,X ;store 5Eh into 07eh FF3D: 91 7E STA ($7E),Y ;BANKSWITCH! store 5Eh into 5E5Eh FF3F: 91 80 STA ($80),Y ;------------------------------------------ FF41: 91 00 STA ($00),Y ;Trap #6 FF43: 60 RTS ;that RTS sure is a nice touch :-) Things continue to get tricker. If you did not know where the code "ended" from the previous segment to this segment, you would not know where the bank write occured, since it relies on the values of A,X, and Y on entry. In fact, if the bankswitch register was not written to, then the RTS (cute) would've been executed, crashing the CPU. FF3B: 95 00 STA $00,X ;store 5Eh into 07eh FF3D: 91 7E STA ($7E),Y ;BANKSWITCH! store 5Eh into 5E5Eh FF30: A9 07 LDA #$07 ;I kept this code up here to show the type of FF32: A2 30 LDX #$30 ;misdirection they are doing... it is NOT FF34: 85 7F STA $7F ;executed! FF36: 86 7E STX $7E FF38: A9 4C LDA #$4C FF3A: 9D E7 06 STA $06E7,X FF3D: A2 34 LDX #$34 FF3F: BD E3 06 LDA $06E3,X ;<--- We get dropped in right here FF42: A8 TAY ;Acc holds 5Eh FF43: AA TAX FF44: 09 31 ORA #$31 ;Acc holds 7Fh FF46: 18 CLC FF47: 69 81 ADC #$81 ;Acc holds 00h FF49: 95 0A STA $0A,X ;Store 00h at 005eh FF4B: E8 INX FF4C: 9D 0D 06 STA $060D,X ;All these writes do absolutely nothing FF4F: E8 INX FF50: 95 0B STA $0B,X FF52: E8 INX FF53: 9D 0F 70 STA $700F,X FF56: E8 INX FF57: 95 10 STA $10,X FF59: E8 INX FF5A: 9D 11 60 STA $6011,X FF5D: E8 INX FF5E: 95 0C STA $0C,X FF60: E8 INX FF61: 95 0E STA $0E,X FF63: A9 00 LDA #$00 ;because, we are going to clear RAM out! FF65: AA TAX FF66: 95 00 STA $00,X FF68: 9D 00 03 STA $0300,X FF6B: 9D 00 04 STA $0400,X FF6E: 9D 00 05 STA $0500,X FF71: 9D 00 06 STA $0600,X FF74: 9D 00 07 STA $0700,X FF77: E8 INX FF78: D0 EC BNE $FF66 ;clear out zeropage, page 3,4,5,6, and 7 FF7A: 98 TYA ;Get Y and put it into A (unchanged from before) FF7B: A8 TAY ;dunno what this is for... doesn't do anything FF7C: EA NOP ;A holds 5Eh FF7D: 18 CLC FF7E: 69 4B ADC #$4B ;A holds A9h... aha! This is LDA #$. FF80: 9D F0 07 STA $07F0,X ;Store it at 07F0h FF83: 98 TYA ;This is the start of our "deterministic" code FF84: 0A ASL FF85: 0A ASL FF86: 29 EF AND #$EF ;A holds 68h FF88: E8 INX FF89: 9D F0 07 STA $07F0,X ;store at 07F1h FF8C: E8 INX FF8D: 18 CLC FF8E: 69 25 ADC #$25 ;this code is writing 6502 instructions into RAM FF90: 9D F0 07 STA $07F0,X FF93: E8 INX FF94: 98 TYA FF95: 9D F0 07 STA $07F0,X FF98: E8 INX FF99: 9D F0 07 STA $07F0,X FF9C: E8 INX FF9D: 29 ED AND #$ED FF9F: 9D F0 07 STA $07F0,X FFA2: E8 INX FFA3: 38 SEC FFA4: E9 2C SBC #$2C FFA6: 9D F0 07 STA $07F0,X FFA9: E8 INX FFAA: 18 CLC FFAB: 69 DA ADC #$DA FFAD: 9D F0 07 STA $07F0,X FFB0: E8 INX FFB1: AD F5 07 LDA $07F5 FFB4: 09 20 ORA #$20 FFB6: 9D F0 07 STA $07F0,X FFB9: E8 INX FFBA: AD F5 07 LDA $07F5 FFBD: 9D F0 07 STA $07F0,X FFC0: E8 INX FFC1: 29 33 AND #$33 FFC3: 9D F0 07 STA $07F0,X FFC6: 98 TYA FFC7: 29 BF AND #$BF FFC9: AA TAX FFCA: AD FA 07 LDA $07FA FFCA: AD FA 07 LDA $07FA FFCD: 09 F0 ORA #$F0 FFCF: 95 2E STA $2E,X ;store F0h at 004ch FFD1: E8 INX FFD2: 8A TXA FFD3: 29 E7 AND #$E7 FFD5: 95 2E STA $2E,X ;store 07h at 004dh FFD7: 4C F8 07 JMP $07F8 ;jump into the code we just manufactured! OK, things are starting to heat up! We're headed into the portion of the code that I like to call "deterministic". This basically means that the outputs are dependant on the previous input, and because of this, the output will always be a fixed value no matter how complex your code is, so long as your input doesn't change. i.e. there is no way to return a truly random result from a deterministic machine, since everything starts at a known value, and a string of known operations occurs. What all this means, is if one calculation fails for some reason, the entire house of cards falls, and the CPU crashes! We're really playing with fire now- using the previous values of A, X, and Y to write the code we're about to execute! This is the big guns for sure. The long string of instructions up there generates the following code: 07F0: A9 68 LDA #$68 07F2: 8D 5E 5E STA $5E5E ;Bankswitch! 07F5: 4C 20 FA JMP $FA20 ;jump back into ROM 07F8: 6C 4C 00 JMP ($004C) ;<--- We enter here. 4ch points to 07F0h So, ALLLLL that code up there was used to generate this short snippet. We drop down into the indirect JMP, and we can see that 07F0h was written to 004ch right before the JMP into RAM. As you can see, if ANY of the CPU registers was wrong, the code would've been "rendered" improperly, resulting in a crash. Each write depends on the value of the data before it for proper code generation. This is the "big guns" Jumping back into ROM (yes, in a new bank from the old) FA1D: B5 40 LDA $40,X FA1F: AA TAX FA20: 9D 42 07 STA $0742,X ;<--- we jump back in here FA23: 0A ASL FA24: 9D 33 07 STA $0733,X ;riiight into the middle of more code that FA27: 9D 3C 07 STA $073C,X ;manufactures code and puts it into RAM. FA2A: AA TAX ;the results of this 100% rely on the values FA2B: BD 22 07 LDA $0722,X ;in the CPU registers! FA2E: 9D 7B 06 STA $067B,X FA31: 18 CLC FA32: 69 01 ADC #$01 FA34: 9D 8D 06 STA $068D,X FA37: BD 20 07 LDA $0720,X FA3A: 9D 70 06 STA $0670,X FA3D: 9D 90 06 STA $0690,X FA40: 29 FE AND #$FE FA42: 9D 72 06 STA $0672,X FA45: AA TAX FA46: 09 02 ORA #$02 FA48: 9D 9B 06 STA $069B,X FA4B: 29 F5 AND #$F5 FA4D: 9D 9E 06 STA $069E,X FA50: AA TAX FA51: 9D C2 06 STA $06C2,X FA54: 09 04 ORA #$04 FA56: 9D B6 06 STA $06B6,X FA59: BD 55 07 LDA $0755,X FA5C: 09 01 ORA #$01 FA5E: 9D AA 06 STA $06AA,X FA61: 18 CLC FA62: 69 01 ADC #$01 FA64: 9D B5 06 STA $06B5,X FA67: 9D B7 06 STA $06B7,X FA6A: BD 5A 07 LDA $075A,X FA6D: 9D 5F 07 STA $075F,X FA70: 9D A1 06 STA $06A1,X FA73: 9D A7 06 STA $06A7,X FA76: 9D C3 06 STA $06C3,X FA79: 09 01 ORA #$01 FA7B: 9D AF 06 STA $06AF,X FA7E: 09 06 ORA #$06 FA80: 9D AD 06 STA $06AD,X FA83: 9D BA 06 STA $06BA,X FA86: 9D BF 06 STA $06BF,X FA89: BD A2 06 LDA $06A2,X FA8C: AA TAX FA8D: 09 41 ORA #$41 FA8F: 9D B4 06 STA $06B4,X FA92: 29 FE AND #$FE FA94: 9D A8 06 STA $06A8,X FA97: 29 F7 AND #$F7 FA99: 9D B6 06 STA $06B6,X FA9C: 29 7F AND #$7F FA9E: 9D BE 06 STA $06BE,X FAA1: 0A ASL FAA2: 09 0C ORA #$0C FAA4: 9D B0 06 STA $06B0,X FAA7: 29 FB AND #$FB FAA9: 9D A9 06 STA $06A9,X FAAC: AA TAX FAAD: 38 SEC FAAE: E9 B0 SBC #$B0 FAB0: 9D 80 06 STA $0680,X FAB3: 18 CLC FAB4: 69 59 ADC #$59 FAB6: 9D 81 06 STA $0681,X FAB9: 09 0C ORA #$0C FABB: 9D 7D 06 STA $067D,X FABE: 9D 9D 06 STA $069D,X FAC1: AA TAX FAC2: BD C4 06 LDA $06C4,X FAC5: 95 00 STA $00,X FAC7: BD 76 07 LDA $0776,X FACA: AA TAX FACB: 95 20 STA $20,X FACD: 18 CLC FACE: 69 33 ADC #$33 FAD0: 9D E6 06 STA $06E6,X FAD3: 9D 06 07 STA $0706,X FAD6: 29 FE AND #$FE FAD8: 9D F0 06 STA $06F0,X FADB: AA TAX FADC: 18 CLC FADD: 69 51 ADC #$51 FADF: 9D BC 06 STA $06BC,X FAE2: 18 CLC FAE3: 69 05 ADC #$05 FAE5: 9D C4 06 STA $06C4,X FAE8: 18 CLC FAE9: 69 0E ADC #$0E FAEB: 9D C3 06 STA $06C3,X FAEE: 09 0B ORA #$0B FAF0: 9D C9 06 STA $06C9,X FAF3: BD BA 06 LDA $06BA,X FAF6: AA TAX FAF7: BD F4 06 LDA $06F4,X FAFA: 95 00 STA $00,X ;store 00h into 4dh FAFC: AA TAX FAFD: BD 51 07 LDA $0751,X FB00: 29 F7 AND #$F7 FB02: 95 4E STA $4E,X ;store c0h into 4eh FB04: AA TAX FB05: BD 92 06 LDA $0692,X FB08: 09 06 ORA #$06 FB0A: 9D 37 07 STA $0737,X FB0D: AA TAX FB0E: 38 SEC FB0F: E9 86 SBC #$86 FB11: 9D 20 07 STA $0720,X FB14: BD 7E 06 LDA $067E,X FB17: 29 7D AND #$7D FB19: 9D 1B 07 STA $071B,X FB1C: 4C F0 07 JMP $07F0 ;jump back into RAM The Big Guns are now officially out! This insanely huge string of CRAP writes the following two pieces of code: 0740: A9 00 LDA #$00 0742: A8 TAY 0743: AA TAX ;init A,X,Y 0744: 91 7D STA ($7D),Y ;bankswitch! 0746: A0 00 LDY #$00 0748: 18 CLC 0749: 71 4D ADC ($4D),Y 074B: 8D E1 07 STA $07E1 ;this code around here performs a convoluted 074E: 90 01 BCC $0751 ;sumcheck and changes around X and Y 0750: E8 INX 0751: C8 INY 0752: D0 F4 BNE $0748 0754: E6 4E INC $4E 0756: A4 4E LDY $4E 0758: CC FF 07 CPY $07FF ;it finally terminates at a hard to determine 075B: D0 E9 BNE $0746 ;point based on the data in the selected bank 075D: 8E E0 07 STX $07E0 ;leaving X in a seemingly random state. 0760: A9 68 LDA #$68 0762: A0 00 LDY #$00 0764: 91 7D STA ($7D),Y ;bankswitch again 0766: 60 RTS ;back to ROM (in a different bank!) You will be seeing ALOT of this latter routine. From now on, I will call it the "0740 hash function". It also updates this piece of code, which is where execution continues: 07F0: A9 64 LDA #$64 ;<--- we drop in here, skipping the JMP() 07F2: 8D 5E 5E STA $5E5E ;bankswitch 07F5: 4C 50 D6 JMP $D650 ;back to ROM 07F8: 6C 4C 00 JMP ($004C) Back to the ROM: D650: BD 1B 07 LDA $071B,X ; D653: AA TAX ;X is 64h D654: 9D FD 06 STA $06FD,X D657: BD DD 06 LDA $06DD,X D65A: 95 04 STA $04,X D65C: 09 01 ORA #$01 D65E: 95 07 STA $07,X D660: A8 TAY D661: C8 INY D662: 98 TYA D663: 95 05 STA $05,X D665: C8 INY D666: 98 TYA D667: 95 09 STA $09,X D669: C8 INY D66A: 98 TYA D66B: 95 0A STA $0A,X D66D: C8 INY D66E: 98 TYA D66F: 95 0B STA $0B,X D671: C8 INY D672: 98 TYA D673: 95 06 STA $06,X D675: C8 INY D676: 98 TYA D677: 95 08 STA $08,X D679: 20 40 07 JSR $0740 ;call the 0740 hash function D67C: AD 54 07 LDA $0754 D67F: AA TAX ;X is E6h D680: BD 0F 07 LDA $070F,X D683: 38 SEC D684: E9 0C SBC #$0C D686: 9D 0B 07 STA $070B,X D689: 18 CLC D68A: 69 38 ADC #$38 D68C: 9D 10 07 STA $0710,X D68F: 18 CLC D690: 69 60 ADC #$60 D692: AA TAX D693: 9D 1F 07 STA $071F,X D696: A9 EA LDA #$EA D698: 9D 17 07 STA $0717,X D69B: AA TAX D69C: BD 78 03 LDA $0378,X D69F: 9D 75 04 STA $0475,X D6A2: 18 CLC D6A3: 69 20 ADC #$20 D6A5: 9D F4 12 STA $12F4,X ;write to a RAM mirror! (not used tho) D6A8: 9D 35 04 STA $0435,X D6AB: 29 F5 AND #$F5 D6AD: 9D E0 03 STA $03E0,X D6B0: AA TAX D6B1: BD 57 03 LDA $0357,X D6B4: 9D 10 04 STA $0410,X D6B7: 29 EF AND #$EF D6B9: 9D 32 04 STA $0432,X D6BC: 20 EF 07 JSR $07EF ;Jump back into RAM D6BF: AA TAX ;------------------------------------ D6C0: BD 00 03 LDA $0300,X ;Trap #7 D6C3: 9D 38 04 STA $0438,X ;the JSR never returns! D6C6: BD E0 06 LDA $06E0,X D6C9: 9D 60 07 STA $0760,X D6CC: BD 70 04 LDA $0470,X D6CF: 18 CLC It then jumps into this code in RAM which it manufactured... 07EF: EA NOP 07F0: A9 40 LDA #$40 07F2: 8D 5E 5E STA $5E5E ;BANKSWITCH! 07F5: 4C 78 D8 JMP $D878 ;jump back into ROM 07F8: 6C 4C 00 JMP ($004C) As you can see... like before, they JSR into RAM and make it LOOK like the routine returns, but that's just another trap which leads to the usual CPU crashing and all that. Execution starts back up here, and it is now starting to write a JMP table in RAM, among other things. D878: AA TAX ;X holds 40h D879: BD A0 07 LDA $07A0,X D87C: 18 CLC D87D: 7D 16 07 ADC $0716,X ;we're getting deeper now.. the math ops are D880: 9D A2 07 STA $07A2,X ;getting even more insane now! D883: BD A1 07 LDA $07A1,X ;indexed ADC's and SBCs and stuff! D886: 38 SEC D887: FD 17 07 SBC $0717,X D88A: 9D A3 07 STA $07A3,X D88D: BD 19 07 LDA $0719,X D890: AA TAX D891: BD 56 06 LDA $0656,X D894: A8 TAY D895: BD E1 06 LDA $06E1,X D898: 18 CLC D899: 69 A5 ADC #$A5 D89B: F0 03 BEQ $D8A0 D89D: 4C 35 D9 JMP $D935 ;Trap #8 (going here crashes) D8A0: B9 93 07 LDA $0793,Y ;and it gets worse! using X *and* Y indexes! D8A3: 49 D6 EOR #$D6 D8A5: F0 03 BEQ $D8AA D8A7: 4C B8 D9 JMP $D9B8 ;Trap #9 D8AA: BD F3 06 LDA $06F3,X D8AD: 9D F8 06 STA $06F8,X D8B0: 9D ED 06 STA $06ED,X D8B3: BD 5E 06 LDA $065E,X D8B6: AA TAX D8B7: 9D 6A 07 STA $076A,X D8BA: 9D 6B 07 STA $076B,X D8BD: 9D 5F 07 STA $075F,X D8C0: 9D 60 07 STA $0760,X D8C3: 9D 6D 07 STA $076D,X D8C6: 9D 6E 07 STA $076E,X D8C9: FE 6E 07 INC $076E,X ;indexed incs too, sheesh! D8CC: FE 5F 07 INC $075F,X D8CF: 9D 6F 07 STA $076F,X D8D2: BD D8 06 LDA $06D8,X D8D5: 99 AC 07 STA $07AC,Y D8D8: 99 B0 07 STA $07B0,Y D8DB: 99 A1 07 STA $07A1,Y D8DE: AA TAX D8DF: BD FC 06 LDA $06FC,X D8E2: 38 SEC D8E3: E9 A0 SBC #$A0 D8E5: 99 A3 07 STA $07A3,Y D8E8: BD FE 06 LDA $06FE,X D8EB: 9D 08 07 STA $0708,X D8EE: 18 CLC D8EF: 69 19 ADC #$19 D8F1: 9D 96 07 STA $0796,X D8F4: BD 95 07 LDA $0795,X D8F7: 9D 94 07 STA $0794,X D8FA: 99 72 07 STA $0772,Y D8FD: 99 75 07 STA $0775,Y D900: 99 78 07 STA $0778,Y D903: 99 7B 07 STA $077B,Y D906: 99 7E 07 STA $077E,Y D909: 99 81 07 STA $0781,Y D90C: 99 84 07 STA $0784,Y D90F: 99 87 07 STA $0787,Y D912: 99 8A 07 STA $078A,Y D915: BD 04 07 LDA $0704,X D918: 99 A4 07 STA $07A4,Y D91B: BD 05 07 LDA $0705,X D91E: 99 A5 07 STA $07A5,Y D921: 18 CLC D922: 69 35 ADC #$35 D924: 9D 07 07 STA $0707,X D927: 38 SEC D928: E9 62 SBC #$62 D92A: 9D 95 07 STA $0795,X D92D: A0 00 LDY #$00 D92F: 68 PLA ;pop off the return addy we never used D930: 68 PLA ;when we JSR'd into RAM and JMP'd back D931: 20 F0 07 JSR $07F0 ;JSR into RAM but don't come back! D934: 60 RTS ;------------------------------------------ D935: BD 1A 06 LDA $061A,X ;Trap #10 D938: AA TAX ;this code of course never gets run D939: BD 20 07 LDA $0720,X ;the RTS is a nice touch again D93C: 99 1A 00 STA $001A,Y D93F: BD 21 07 LDA $0721,X D942: 99 1B 00 STA $001B,Y D945: BD 22 07 LDA $0722,X D948: 99 20 00 STA $0020,Y D94B: BD 23 07 LDA $0723,X D94E: 99 21 00 STA $0021,Y And it manufactured the following code: 07C3: 4C 00 00 JMP $0000 07C6: 4C 00 00 JMP $0000 07C9: 4C 00 00 JMP $0000 07CC: 4C 00 00 JMP $0000 07CF: 4C 00 00 JMP $0000 07D2: 4C 00 00 JMP $0000 07D5: 4C 00 00 JMP $0000 07D8: 4C 00 00 JMP $0000 07DB: 00 00 BRK #$00 07DD: 00 00 BRK #$00 07DF: 00 5B BRK #$5B 07E1: D6 FF DEC $FF,X 07E3: 88 DEY 07E4: 00 00 BRK #$00 This doesn't look like much right now, but it's slowly building up a JMP table that will be VERY VERY important later on. The following code was also manufactured, and execution starts at the top: 07F0: A9 49 LDA #$49 ;start execution here 07F2: 91 7D STA ($7D),Y 07F4: 4C 50 F9 JMP $F950 ;back into ROM 07F7: 8D 8E 8E STA $8E8E ;these bankswitch routines will be used later 07FA: 60 RTS 07FB: 8E 8F 8E STX $8E8F ;by the game code 07FE: 60 RTS Execution then continues... in a different bank of course. F950: E8 INX ;X is 61h F951: BD E7 06 LDA $06E7,X F954: 38 SEC F955: E9 05 SBC #$05 F957: 9D 60 07 STA $0760,X F95A: 29 FC AND #$FC F95C: 9D 63 07 STA $0763,X F95F: BD EB 06 LDA $06EB,X ;there's a huuuuuuge string of this crap F962: 9D 64 07 STA $0764,X ;so skip to the bottom... :-) F965: 9D 67 07 STA $0767,X F968: 9D 6D 07 STA $076D,X F96B: 9D 70 07 STA $0770,X F96E: 9D 79 07 STA $0779,X F971: 09 02 ORA #$02 F973: 9D 61 07 STA $0761,X F976: BD EC 06 LDA $06EC,X F979: 29 FE AND #$FE F97B: 9D 66 07 STA $0766,X F97E: BD F4 06 LDA $06F4,X F981: 09 01 ORA #$01 F983: 9D 69 07 STA $0769,X F986: BD F7 06 LDA $06F7,X F989: 29 F7 AND #$F7 F98B: 9D 6A 07 STA $076A,X F98E: 38 SEC F98F: E9 3E SBC #$3E F991: 9D 6C 07 STA $076C,X F994: BD 6E 07 LDA $076E,X F997: 9D 77 07 STA $0777,X F99A: 9D 7A 07 STA $077A,X F99D: 38 SEC F99E: E9 10 SBC #$10 F9A0: 9D 6F 07 STA $076F,X F9A3: AA TAX F9A4: 38 SEC F9A5: E9 1C SBC #$1C F9A7: 9D 96 07 STA $0796,X F9AA: BD 06 07 LDA $0706,X F9AD: 38 SEC F9AE: E9 40 SBC #$40 F9B0: 9D 97 07 STA $0797,X F9B3: BD 22 07 LDA $0722,X F9B6: 9D 98 07 STA $0798,X F9B9: B5 2C LDA $2C,X F9BB: 9D 9A 07 STA $079A,X F9BE: BD 26 07 LDA $0726,X F9C1: 9D 9B 07 STA $079B,X F9C4: BD 04 07 LDA $0704,X F9C7: 9D AA 07 STA $07AA,X F9CA: 38 SEC F9CB: E9 44 SBC #$44 F9CD: 9D B5 07 STA $07B5,X F9D0: BD 12 07 LDA $0712,X F9D3: 38 SEC F9D4: E9 60 SBC #$60 F9D6: 9D B9 07 STA $07B9,X F9D9: BD 2C 07 LDA $072C,X F9DC: 18 CLC F9DD: 69 0B ADC #$0B F9DF: 9D BA 07 STA $07BA,X F9E2: BD 2C 07 LDA $072C,X F9E5: AA TAX F9E6: BD 61 06 LDA $0661,X F9E9: 9D 91 06 STA $0691,X F9EC: 9D 93 06 STA $0693,X F9EF: 9D 9F 06 STA $069F,X F9F2: 9D A1 06 STA $06A1,X F9F5: 9D A9 06 STA $06A9,X F9F8: 9D 07 07 STA $0707,X F9FB: BD 82 06 LDA $0682,X F9FE: 9D 92 06 STA $0692,X FA01: 9D A0 06 STA $06A0,X FA04: 09 02 ORA #$02 FA06: 9D 90 06 STA $0690,X FA09: AA TAX FA0A: BD 9E 06 LDA $069E,X FA0D: 9D D2 06 STA $06D2,X FA10: 9D DC 06 STA $06DC,X FA13: 9D FA 06 STA $06FA,X FA16: 9D FF 06 STA $06FF,X FA19: 9D 04 07 STA $0704,X FA1C: 9D 08 07 STA $0708,X FA1F: A9 41 LDA #$41 FA21: 9D D3 06 STA $06D3,X FA24: BD C2 06 LDA $06C2,X FA27: 9D D4 06 STA $06D4,X FA2A: 9D E0 06 STA $06E0,X FA2D: 9D 46 07 STA $0746,X FA30: AA TAX FA31: BD D4 06 LDA $06D4,X FA34: 9D E6 06 STA $06E6,X FA37: 9D F2 06 STA $06F2,X FA3A: 9D 58 07 STA $0758,X FA3D: BD CC 06 LDA $06CC,X FA40: 29 FB AND #$FB FA42: 9D E7 06 STA $06E7,X FA45: 9D F3 06 STA $06F3,X FA48: 9D 4B 07 STA $074B,X FA4B: DE 4B 07 DEC $074B,X FA4E: BD B1 06 LDA $06B1,X FA51: 9D E8 06 STA $06E8,X FA54: 9D F4 06 STA $06F4,X FA57: A9 B1 LDA #$B1 FA59: 9D E9 06 STA $06E9,X FA5C: 9D F5 06 STA $06F5,X FA5F: BD B9 06 LDA $06B9,X FA62: 9D EA 06 STA $06EA,X FA65: BD 39 07 LDA $0739,X FA68: 9D EC 06 STA $06EC,X FA6B: 9D FA 06 STA $06FA,X FA6E: A9 85 LDA #$85 FA70: 9D EB 06 STA $06EB,X FA73: 9D 17 07 STA $0717,X FA76: 9D 1B 07 STA $071B,X FA79: A9 66 LDA #$66 FA7B: 9D F6 06 STA $06F6,X FA7E: 9D 1A 07 STA $071A,X FA81: BD C9 06 LDA $06C9,X FA84: 9D 08 07 STA $0708,X FA87: 9D 0F 07 STA $070F,X FA8A: 9D 14 07 STA $0714,X FA8D: AA TAX FA8E: E8 INX FA8F: E8 INX FA90: 8A TXA FA91: 9D 7F 07 STA $077F,X FA94: BD C2 07 LDA $07C2,X FA97: 9D 81 07 STA $0781,X FA9A: FE 81 07 INC $0781,X FA9D: AA TAX FA9E: BD 8E 06 LDA $068E,X FAA1: 9D C8 06 STA $06C8,X FAA4: 9D CB 06 STA $06CB,X FAA7: 9D D6 06 STA $06D6,X FAAA: BD 8C 06 LDA $068C,X FAAD: 9D CA 06 STA $06CA,X FAB0: BD 0E 07 LDA $070E,X FAB3: 9D C9 06 STA $06C9,X FAB6: BD 0D 07 LDA $070D,X FAB9: 9D CC 06 STA $06CC,X FABC: 18 CLC FABD: 69 01 ADC #$01 FABF: 9D 19 07 STA $0719,X FAC2: 09 04 ORA #$04 FAC4: 9D CD 06 STA $06CD,X FAC7: 9D CF 06 STA $06CF,X FACA: 29 FD AND #$FD FACC: 9D DB 06 STA $06DB,X FACF: 9D E0 06 STA $06E0,X FAD2: FE E0 06 INC $06E0,X FAD5: BD 36 07 LDA $0736,X FAD8: 9D E3 06 STA $06E3,X FADB: 9D EA 06 STA $06EA,X FADE: 18 CLC FADF: 69 07 ADC #$07 FAE1: 9D CE 06 STA $06CE,X FAE4: BD 91 06 LDA $0691,X FAE7: 9D D0 06 STA $06D0,X FAEA: 9D D2 06 STA $06D2,X FAED: 18 CLC FAEE: 69 57 ADC #$57 FAF0: 9D D1 06 STA $06D1,X FAF3: 18 CLC FAF4: 69 06 ADC #$06 FAF6: 9D 15 07 STA $0715,X FAF9: BD 94 06 LDA $0694,X FAFC: 09 01 ORA #$01 FAFE: 9D D3 06 STA $06D3,X FB01: BD 95 06 LDA $0695,X FB04: 9D D4 06 STA $06D4,X FB07: 18 CLC FB08: 69 D7 ADC #$D7 FB0A: 9D D7 06 STA $06D7,X FB0D: AA TAX FB0E: BD 21 07 LDA $0721,X FB11: 9D C7 06 STA $06C7,X FB14: 9D C8 06 STA $06C8,X FB17: 9D CD 06 STA $06CD,X FB1A: 18 CLC FB1B: 69 01 ADC #$01 FB1D: 9D CC 06 STA $06CC,X FB20: 38 SEC FB21: E9 14 SBC #$14 FB23: 9D D3 06 STA $06D3,X FB26: 09 01 ORA #$01 FB28: 9D D7 06 STA $06D7,X FB2B: 18 CLC FB2C: 69 6F ADC #$6F FB2E: 9D 98 06 STA $0698,X FB31: 9D 99 06 STA $0699,X FB34: 9D D9 06 STA $06D9,X FB37: 8A TXA FB38: 18 CLC FB39: 69 AA ADC #$AA FB3B: AA TAX FB3C: BD E8 06 LDA $06E8,X FB3F: 09 01 ORA #$01 FB41: 9D EC 06 STA $06EC,X FB44: 9D 6C 07 STA $076C,X FB47: BD 40 07 LDA $0740,X FB4A: 9D EA 06 STA $06EA,X FB4D: 9D 6A 07 STA $076A,X FB50: 18 CLC FB51: 69 22 ADC #$22 FB53: 9D EB 06 STA $06EB,X FB56: 9D 6B 07 STA $076B,X FB59: 68 PLA ;pull return address since we JSR'd into RAM FB5A: 68 PLA ;and JMP'd back into ROM FB5B: BD 40 07 LDA $0740,X FB5E: 9D 26 07 STA $0726,X FB61: 9D 2A 07 STA $072A,X FB64: BD E6 06 LDA $06E6,X FB67: 9D 27 07 STA $0727,X FB6A: 18 CLC FB6B: 69 86 ADC #$86 FB6D: 9D 2B 07 STA $072B,X FB70: BD CD 06 LDA $06CD,X FB73: 9D 28 07 STA $0728,X FB76: 9D 2C 07 STA $072C,X FB79: 18 CLC FB7A: 69 42 ADC #$42 FB7C: 9D E1 06 STA $06E1,X FB7F: BD 08 07 LDA $0708,X FB82: 09 20 ORA #$20 FB84: 9D 08 07 STA $0708,X FB87: BD C5 06 LDA $06C5,X FB8A: 9D 09 07 STA $0709,X FB8D: BD C8 06 LDA $06C8,X FB90: 09 04 ORA #$04 FB92: 9D 0D 07 STA $070D,X FB95: A5 68 LDA $68 FB97: 9D 64 07 STA $0764,X FB9A: 9D 65 07 STA $0765,X FB9D: BD C8 06 LDA $06C8,X FBA0: 18 CLC FBA1: 69 50 ADC #$50 FBA3: 9D F5 06 STA $06F5,X FBA6: BD C8 06 LDA $06C8,X FBA9: AA TAX FBAA: B5 50 LDA $50,X FBAC: 95 35 STA $35,X FBAE: 95 5E STA $5E,X FBB0: BD 40 07 LDA $0740,X FBB3: 09 01 ORA #$01 FBB5: 95 36 STA $36,X FBB7: BD 46 07 LDA $0746,X FBBA: 95 4F STA $4F,X FBBC: 38 SEC FBBD: E9 03 SBC #$03 FBBF: 9D E7 07 STA $07E7,X FBC2: 20 6E 07 JSR $076E ;JSR back into RAM The following stuff was manufactured in RAM... 0760: A9 49 LDA #$49 0762: A0 00 LDY #$00 0764: 91 7D STA ($7D),Y ;bankswitch 0766: 60 RTS ;and return 0767: B2 HLT 0768: E0 00 CPX #$00 076A: 4C 6E E1 JMP $E16E 076D: 00 --- 076E: EA NOP ;<--- exeuction picks up here in RAM 076F: EA NOP 0770: A2 00 LDX #$00 ;this is another, more complex hashing 0772: A0 00 LDY #$00 ;function. 0774: A9 68 LDA #$68 0776: 91 7D STA ($7D),Y 0778: 8A TXA 0779: A8 TAY 077A: B1 4D LDA ($4D),Y 077C: 85 4F STA $4F 077E: A9 00 LDA #$00 0780: A0 00 LDY #$00 0782: 91 7D STA ($7D),Y 0784: 8A TXA 0785: A8 TAY 0786: B1 66 LDA ($66),Y 0788: 29 7D AND #$7D 078A: C5 4F CMP $4F 078C: D0 1C BNE $07AA 078E: E8 INX 078F: D0 E1 BNE $0772 0791: E6 67 INC $67 0793: E6 4E INC $4E 0795: A5 4E LDA $4E 0797: CD FF 07 CMP $07FF 079A: D0 D6 BNE $0772 ;wait for some hard to predict thing to 079C: A9 8D LDA #$8D ;happen 079E: 8D E4 07 STA $07E4 07A1: A9 8E LDA #$8E 07A3: 8D E5 07 STA $07E5 07A6: 4C 60 07 JMP $0760 ;jmp to the top of this block of code 07A9: 7A NOP 07AA: 4C E6 07 JMP $07E6 07AD: 7B 60 EA RRA $EA60,Y Our JMP table is coming along nicely!! 07C0: 4C 13 E3 JMP $E313 07C3: 4C 10 E1 JMP $E110 07C6: 4C 06 E1 JMP $E106 07C9: 4C 4F C4 JMP $C44F 07CC: 4C 86 E1 JMP $E186 07CF: 4C 3C E1 JMP $E13C 07D2: 20 68 E0 JSR $E068 07D5: 4C 00 A0 JMP $A000 07D8: 4C AB E1 JMP $E1AB 07DB: 4C 89 E2 JMP $E289 And some other RAM is half-initialized and holds some crap right now 07DE: 00 00 BRK #$00 07E0: 5B D6 FF SRE $FFD6,Y 07E3: 88 DEY 07E4: 00 00 BRK #$00 07E6: A9 00 LDA #$00 07E8: 91 7D STA ($7D),Y 07EA: 4C 6E E1 JMP $E16E 07ED: 8F 8E 60 SAX $608E 07F0: A9 65 LDA #$65 07F2: 91 7D STA ($7D),Y 07F4: 4C 30 EB JMP $EB30 07F7: 8D 8E 8E STA $8E8E 07FA: 60 RTS 07FB: 8E 8F 8E STX $8E8F 07FE: 60 RTS 07FF: DD 00 00 CMP $0000,X 0802: 00 00 BRK #$00 Once the RAM code returns, execution picks up in ROM where it left off before the JSR. FBC5: AE 48 07 LDX $0748 ;X is 18h FBC8: BD CC 07 LDA $07CC,X FBCB: 9D DF 07 STA $07DF,X FBCE: BD CD 07 LDA $07CD,X FBD1: 9D E3 07 STA $07E3,X FBD4: 8A TXA FBD5: 18 CLC FBD6: 69 49 ADC #$49 FBD8: 9D 5D 07 STA $075D,X FBDB: 18 CLC FBDC: 69 8A ADC #$8A FBDE: 95 36 STA $36,X FBE0: 18 CLC FBE1: 69 05 ADC #$05 FBE3: 95 4F STA $4F,X FBE5: 18 CLC FBE6: 69 0B ADC #$0B FBE8: 9D E7 07 STA $07E7,X FBEB: B5 50 LDA $50,X FBED: 9D CC 07 STA $07CC,X FBF0: 9D CD 07 STA $07CD,X FBF3: 20 6F 07 JSR $076F ;Run our hashing function again FBF6: AE 66 07 LDX $0766 FBF9: BD 84 07 LDA $0784,X FBFC: 18 CLC FBFD: 69 D3 ADC #$D3 FBFF: 9D 8F 07 STA $078F,X FC02: BD 85 07 LDA $0785,X FC05: 9D 9B 07 STA $079B,X FC08: 8A TXA FC09: 18 CLC FC0A: 69 0C ADC #$0C FC0C: 9D 15 07 STA $0715,X FC0F: 9D 1F 07 STA $071F,X FC12: BD 72 07 LDA $0772,X FC15: AA TAX FC16: 18 CLC FC17: 69 B0 ADC #$B0 FC19: 95 2E STA $2E,X FC1B: 29 EF AND #$EF FC1D: 95 47 STA $47,X FC1F: BD 3E 07 LDA $073E,X FC22: 9D DF 07 STA $07DF,X FC25: B5 48 LDA $48,X FC27: 9D C4 07 STA $07C4,X FC2A: 9D C5 07 STA $07C5,X FC2D: 20 6E 07 JSR $076E ;Run hashing function again FC30: AE 66 07 LDX $0766 ;X is 60h FC33: BD 84 07 LDA $0784,X FC36: 18 CLC FC37: 69 BF ADC #$BF FC39: 9D 60 07 STA $0760,X FC3C: BD 85 07 LDA $0785,X FC3F: 18 CLC FC40: 69 1B ADC #$1B FC42: 9D 90 07 STA $0790,X FC45: 8A TXA FC46: 18 CLC FC47: 69 0C ADC #$0C FC49: BD E9 06 LDA $06E9,X FC4C: 29 CF AND #$CF FC4E: 9D 15 07 STA $0715,X FC51: BD 60 07 LDA $0760,X FC54: AA TAX FC55: 18 CLC FC56: 69 7E ADC #$7E FC58: 95 02 STA $02,X FC5A: 18 CLC FC5B: 69 16 ADC #$16 FC5D: 95 1B STA $1B,X FC5F: 38 SEC FC60: E9 01 SBC #$01 FC62: AA TAX FC63: 9D 20 07 STA $0720,X FC66: BD 62 06 LDA $0662,X FC69: 9D 05 07 STA $0705,X FC6C: 9D 06 07 STA $0706,X FC6F: 20 6F 07 JSR $076F ;call hashing function FC72: AE 66 07 LDX $0766 ;X is 60h FC75: BD 84 07 LDA $0784,X FC78: 18 CLC FC79: 69 54 ADC #$54 FC7B: 9D 71 07 STA $0771,X FC7E: BD 85 07 LDA $0785,X FC81: 18 CLC FC82: 69 78 ADC #$78 FC84: 95 0A STA $0A,X FC86: 8A TXA FC87: 9D 15 07 STA $0715,X FC8A: BD E1 06 LDA $06E1,X FC8D: 9D 84 07 STA $0784,X FC90: 9D 85 07 STA $0785,X FC93: BD EF 06 LDA $06EF,X FC96: AA TAX FC97: BD 51 07 LDA $0751,X FC9A: 18 CLC FC9B: 69 09 ADC #$09 FC9D: 95 4D STA $4D,X FC9F: 18 CLC FCA0: 69 1C ADC #$1C FCA2: 95 66 STA $66,X FCA4: 38 SEC FCA5: E9 17 SBC #$17 FCA7: AA TAX FCA8: 9D 21 07 STA $0721,X FCAB: 20 6F 07 JSR $076F ;call hashing function FCAE: AE 66 07 LDX $0766 ;X is 60h FCB1: BD 84 07 LDA $0784,X FCB4: 18 CLC FCB5: 69 56 ADC #$56 FCB7: 9D 62 07 STA $0762,X FCBA: BD 85 07 LDA $0785,X FCBD: 18 CLC FCBE: 69 85 ADC #$85 FCC0: 9D 61 07 STA $0761,X FCC3: 8A TXA FCC4: B5 08 LDA $08,X FCC6: 9D 1F 07 STA $071F,X FCC9: BD E1 06 LDA $06E1,X FCCC: 9D 84 07 STA $0784,X FCCF: 9D 85 07 STA $0785,X FCD2: BD EF 06 LDA $06EF,X FCD5: AA TAX FCD6: BD 50 07 LDA $0750,X FCD9: 29 F7 AND #$F7 FCDB: 95 66 STA $66,X FCDD: BD 5B 07 LDA $075B,X FCE0: 09 10 ORA #$10 FCE2: 95 4D STA $4D,X FCE4: BD 58 07 LDA $0758,X FCE7: AA TAX FCE8: 9D 00 07 STA $0700,X FCEB: 20 6F 07 JSR $076F ;call hashing function FCEE: AE 66 07 LDX $0766 ;X is 60h FCF1: BD 84 07 LDA $0784,X FCF4: 18 CLC FCF5: 69 54 ADC #$54 FCF7: 9D 65 07 STA $0765,X FCFA: BD 85 07 LDA $0785,X FCFD: 18 CLC FCFE: 69 82 ADC #$82 FD00: 9D 64 07 STA $0764,X FD03: 8A TXA FD04: FE 15 07 INC $0715,X FD07: BD E1 06 LDA $06E1,X FD0A: 9D 84 07 STA $0784,X FD0D: 9D 85 07 STA $0785,X FD10: BD 64 07 LDA $0764,X FD13: AA TAX FD14: 18 CLC FD15: 69 B6 ADC #$B6 FD17: 95 57 STA $57,X FD19: 18 CLC FD1A: 69 13 ADC #$13 FD1C: 95 3E STA $3E,X FD1E: 18 CLC FD1F: 69 06 ADC #$06 FD21: AA TAX FD22: 9D 20 07 STA $0720,X FD25: 20 6F 07 JSR $076F ;call hashing function FD28: AE 66 07 LDX $0766 ;X is 60h FD2B: BD 84 07 LDA $0784,X FD2E: 38 SEC FD2F: E9 25 SBC #$25 FD31: 9D 73 07 STA $0773,X FD34: BD 85 07 LDA $0785,X FD37: 18 CLC FD38: 69 92 ADC #$92 FD3A: 9D 72 07 STA $0772,X FD3D: 8A TXA FD3E: BD E1 06 LDA $06E1,X FD41: 9D 84 07 STA $0784,X FD44: 9D 85 07 STA $0785,X FD47: BD 64 07 LDA $0764,X FD4A: AA TAX FD4B: 18 CLC FD4C: 69 BC ADC #$BC FD4E: 95 57 STA $57,X FD50: 18 CLC FD51: 69 2F ADC #$2F FD53: 95 3E STA $3E,X FD55: BD 88 07 LDA $0788,X FD58: AA TAX FD59: 9D 00 07 STA $0700,X FD5C: 20 6F 07 JSR $076F ;call hashing function FD5F: AE 66 07 LDX $0766 ;X is 60h FD62: BD 84 07 LDA $0784,X FD65: 18 CLC FD66: 69 53 ADC #$53 FD68: 9D 74 07 STA $0774,X FD6B: BD 85 07 LDA $0785,X FD6E: 18 CLC FD6F: 69 12 ADC #$12 FD71: 9D 77 07 STA $0777,X FD74: 8A TXA FD75: 18 CLC FD76: 69 09 ADC #$09 FD78: 9D 15 07 STA $0715,X FD7B: BD E1 06 LDA $06E1,X FD7E: 9D 84 07 STA $0784,X FD81: 9D 85 07 STA $0785,X FD84: BD 70 07 LDA $0770,X FD87: AA TAX FD88: BD 53 07 LDA $0753,X FD8B: 95 2B STA $2B,X FD8D: 18 CLC FD8E: 69 08 ADC #$08 FD90: 95 12 STA $12,X FD92: 09 07 ORA #$07 FD94: AA TAX FD95: 9D 20 07 STA $0720,X FD98: 20 6F 07 JSR $076F ;call hashing function FD9B: AE 66 07 LDX $0766 ;X is 60h FD9E: BD 84 07 LDA $0784,X FDA1: 18 CLC FDA2: 69 BF ADC #$BF FDA4: 9D 75 07 STA $0775,X FDA7: BD 85 07 LDA $0785,X FDAA: 18 CLC FDAB: 69 72 ADC #$72 FDAD: 9D 76 07 STA $0776,X FDB0: 8A TXA FDB1: BD 60 07 LDA $0760,X FDB4: 29 F7 AND #$F7 FDB6: 9D 1F 07 STA $071F,X FDB9: AA TAX FDBA: DE 31 07 DEC $0731,X FDBD: B5 24 LDA $24,X FDBF: 9D A0 07 STA $07A0,X FDC2: 9D A1 07 STA $07A1,X FDC5: BD 53 07 LDA $0753,X FDC8: 18 CLC FDC9: 69 31 ADC #$31 FDCB: 95 23 STA $23,X FDCD: BD 53 07 LDA $0753,X FDD0: 09 10 ORA #$10 FDD2: 95 0A STA $0A,X FDD4: 20 6F 07 JSR $076F ;call hashing function FDD7: AE 66 07 LDX $0766 ;X is 60h FDDA: BD 84 07 LDA $0784,X FDDD: 9D 8C 07 STA $078C,X FDE0: BD 85 07 LDA $0785,X FDE3: 18 CLC FDE4: 69 1D ADC #$1D FDE6: 9D 79 07 STA $0779,X FDE9: AD 66 07 LDA $0766 FDEC: 18 CLC FDED: 69 20 ADC #$20 FDEF: AA TAX FDF0: BD C0 06 LDA $06C0,X FDF3: 9D 26 07 STA $0726,X FDF6: 9D 2A 07 STA $072A,X FDF9: A9 7B LDA #$7B FDFB: 9D 29 07 STA $0729,X FDFE: A9 7C LDA #$7C FE00: 9D 2D 07 STA $072D,X FE03: BD E6 06 LDA $06E6,X FE06: 18 CLC FE07: 69 06 ADC #$06 FE09: 9D 2B 07 STA $072B,X FE0C: 18 CLC FE0D: 69 1F ADC #$1F FE0F: 9D 28 07 STA $0728,X FE12: 9D 2C 07 STA $072C,X FE15: 18 CLC FE16: 69 BC ADC #$BC FE18: 9D F5 06 STA $06F5,X FE1B: A5 68 LDA $68 FE1D: 9D E1 06 STA $06E1,X FE20: 9D 09 07 STA $0709,X FE23: 9D FF 06 STA $06FF,X FE26: 38 SEC FE27: E9 01 SBC #$01 FE29: 9D 7F 07 STA $077F,X FE2C: BD 08 07 LDA $0708,X FE2F: 29 DF AND #$DF FE31: 9D 08 07 STA $0708,X FE34: BD C8 06 LDA $06C8,X FE37: 18 CLC FE38: 69 08 ADC #$08 FE3A: 9D 0D 07 STA $070D,X FE3D: 8A TXA FE3E: 18 CLC FE3F: 69 56 ADC #$56 FE41: AA TAX FE42: 4C F0 07 JMP $07F0 ;jump into RAM, bankswitch, jump back to ROM After this unholy mess, 0740-07ffh now contains one giant stretch of code. This code is all presented here. Some of it is used in the game as routines that get called all the time... So without the RAM, the game will not function at all... and figuring out what does what will be impossible. 0740: A9 00 LDA #$00 0742: A8 TAY 0743: AA TAX 0744: 91 7D STA ($7D),Y 0746: A0 00 LDY #$00 0748: 18 CLC 0749: 71 4D ADC ($4D),Y 074B: 8D E1 07 STA $07E1 074E: 90 01 BCC $0751 0750: E8 INX 0751: C8 INY 0752: D0 F4 BNE $0748 0754: E6 4E INC $4E 0756: A4 4E LDY $4E 0758: CC FF 07 CPY $07FF 075B: D0 E9 BNE $0746 075D: 8E E0 07 STX $07E0 0760: A9 00 LDA #$00 0762: A0 00 LDY #$00 0764: 91 7D STA ($7D),Y 0766: 60 RTS 0767: B2 HLT 0768: E0 00 CPX #$00 076A: 4C 6E E1 JMP $E16E 076D: 00 EA BRK #$EA 076F: EA NOP 0770: A2 00 LDX #$00 0772: A0 00 LDY #$00 0774: A9 41 LDA #$41 0776: 91 7D STA ($7D),Y 0778: 8A TXA 0779: A8 TAY 077A: B1 4D LDA ($4D),Y 077C: 85 4F STA $4F 077E: A9 00 LDA #$00 0780: A0 00 LDY #$00 0782: 91 7D STA ($7D),Y 0784: 8A TXA 0785: A8 TAY 0786: B1 66 LDA ($66),Y 0788: 09 00 ORA #$00 078A: C5 4F CMP $4F 078C: D0 20 BNE $07AE 078E: E8 INX 078F: D0 E1 BNE $0772 0791: E6 67 INC $67 0793: E6 4E INC $4E 0795: A5 4E LDA $4E 0797: CD FF 07 CMP $07FF 079A: D0 D6 BNE $0772 079C: A9 8D LDA #$8D 079E: 8D E4 07 STA $07E4 07A1: A9 8E LDA #$8E 07A3: 8D E5 07 STA $07E5 07A6: A9 60 LDA #$60 07A8: 85 7B STA $7B 07AA: A9 66 LDA #$66 07AC: 85 7C STA $7C 07AE: 60 RTS 07AF: EA NOP 07B0: 00 00 BRK #$00 07B2: 00 00 BRK #$00 07B4: 00 00 BRK #$00 07B6: 00 00 BRK #$00 07B8: 00 00 BRK #$00 07BA: 00 00 BRK #$00 07BC: 00 00 BRK #$00 07BE: 00 00 BRK #$00 07C0: 4C 13 E3 JMP $E313 ;here's our critical jumptable! 07C3: 4C 10 E1 JMP $E110 07C6: 4C 06 E1 JMP $E106 07C9: 4C 4F C4 JMP $C44F 07CC: 4C 86 E1 JMP $E186 07CF: 4C 3C E1 JMP $E13C 07D2: 20 68 E0 JSR $E068 07D5: 4C 00 A0 JMP $A000 07D8: 4C AB E1 JMP $E1AB 07DB: 4C 89 E2 JMP $E289 07DE: 00 00 BRK #$00 07E0: 5B --- 07E1: D6 FF DEC $FF,X 07E3: 88 DEY 07E4: 8D 8E A9 STA $A98E 07E7: 00 91 BRK #$91 07E9: 7D 4C 6E ADC $6E4C,X 07EC: 8D 8F 8E STA $8E8F 07EF: 60 RTS 07F0: A9 65 LDA #$65 ;<--- we jump into here from the ROM 07F2: 91 7D STA ($7D),Y ;bankswitch 07F4: 4C 30 EB JMP $EB30 ;JMP back into ROM 07F7: 8D 8E 8E STA $8E8E 07FA: 60 RTS 07FB: 8E 8F 8E STX $8E8F 07FE: 60 RTS 07FF: FF --- The code picks up here from RAM... EB28: A5 30 LDA $30 EB2A: D0 04 BNE $EB30 EB2C: A2 A8 LDX #$A8 EB2E: A0 40 LDY #$40 EB30: 8A TXA ;<---- exeuction continues here EB31: 38 SEC ;our routine is "already in progress" EB32: E9 56 SBC #$56 EB34: AA TAX EB35: 9D 31 07 STA $0731,X EB38: 18 CLC EB39: 69 39 ADC #$39 EB3B: 9D 30 07 STA $0730,X ;continue to manufacture more code EB3E: AA TAX EB3F: BD DF 06 LDA $06DF,X EB42: 9D F9 06 STA $06F9,X EB45: BD 8F 06 LDA $068F,X EB48: 9D FA 06 STA $06FA,X EB4B: 18 CLC EB4C: 69 51 ADC #$51 EB4E: 9D FB 06 STA $06FB,X EB51: BD 08 07 LDA $0708,X EB54: 29 FD AND #$FD EB56: 9D FC 06 STA $06FC,X EB59: BD A2 06 LDA $06A2,X EB5C: 9D 00 07 STA $0700,X EB5F: 9D 04 07 STA $0704,X EB62: 18 CLC EB63: 69 0D ADC #$0D EB65: 9D FD 06 STA $06FD,X EB68: 38 SEC EB69: E9 5E SBC #$5E EB6B: 9D FE 06 STA $06FE,X EB6E: BD 9B 06 LDA $069B,X EB71: 09 01 ORA #$01 EB73: 9D FF 06 STA $06FF,X EB76: AA TAX EB77: 18 CLC EB78: 69 14 ADC #$14 EB7A: 9D D3 06 STA $06D3,X EB7D: BD 6A 06 LDA $066A,X EB80: 9D D4 06 STA $06D4,X EB83: 8A TXA EB84: 38 SEC EB85: E9 1D SBC #$1D EB87: 9D D5 06 STA $06D5,X EB8A: BD CE 06 LDA $06CE,X EB8D: 09 E1 ORA #$E1 EB8F: 9D D7 06 STA $06D7,X EB92: BD 13 07 LDA $0713,X EB95: 9D D8 06 STA $06D8,X EB98: 18 CLC EB99: 69 20 ADC #$20 EB9B: AA TAX EB9C: BD F1 06 LDA $06F1,X EB9F: 9D 71 07 STA $0771,X EBA2: BD E5 06 LDA $06E5,X EBA5: 9D 75 07 STA $0775,X EBA8: BD E8 06 LDA $06E8,X EBAB: 9D 76 07 STA $0776,X EBAE: 09 0A ORA #$0A EBB0: 9D 2F 07 STA $072F,X EBB3: BD E8 06 LDA $06E8,X EBB6: 09 01 ORA #$01 EBB8: 9D EC 06 STA $06EC,X EBBB: BD 40 07 LDA $0740,X EBBE: 9D EA 06 STA $06EA,X EBC1: 18 CLC EBC2: 69 22 ADC #$22 EBC4: 9D EB 06 STA $06EB,X EBC7: 4C F0 07 JMP $07F0 ;jump back into RAM RAM looks like... 07F0: A9 00 LDA #$00 07F2: 91 7D STA ($7D),Y ;reset the sub-mapper, revert to MMC3-like mode 07F4: 4C 7D E0 JMP $E07D ;go back to ROM And ROM picks back up... E06D: 20 FB 07 JSR $07FB E070: EC FF BF CPX $BFFF E073: D0 F3 BNE $E068 E075: 60 RTS E076: AD 30 68 LDA $6830 E079: 85 68 STA $68 ;gotta love the seemingly "good" code here E07B: A2 30 LDX #$30 ;and we just return into the middle of it E07D: A0 00 LDY #$00 ;<---- return here E07F: 20 B0 07 JSR $07B0 ;then back into RAM Oho! Look at the code the last set of writes to RAM made... This part of the RAM was all 0's before... and now it's this! It is yet another hash routine... if the hash fails, it gets hung up and execution stops! Kinda clever, that. 07B0: B9 80 FF LDA $FF80,Y 07B3: 18 CLC 07B4: 69 11 ADC #$11 07B6: DD 7F E7 CMP $E77F,X 07B9: D0 FB BNE $07B6 07BB: C8 INY 07BC: CA DEX 07BD: D0 F1 BNE $07B0 07BF: 60 RTS After we DON'T crash in the check routine, we continue here... E082: 8D 80 60 STA $6080 ;ALL of the following writes do not do anything E085: A9 00 LDA #$00 ;there aren't even registers or RAM here. E087: 8D 81 60 STA $6081 E08A: A9 38 LDA #$38 E08C: 8D 82 60 STA $6082 E08F: A9 3F LDA #$3F E091: 8D 83 60 STA $6083 E094: A9 4C LDA #$4C E096: 8D 84 60 STA $6084 E099: A9 7F LDA #$7F E09B: 8D 85 60 STA $6085 E09E: A9 4E LDA #$4E E0A0: 8D 85 60 STA $6085 E0A3: A9 30 LDA #$30 E0A5: 8D 00 50 STA $5000 E0A8: A9 48 LDA #$48 E0AA: 8D 01 50 STA $5001 E0AD: A9 47 LDA #$47 E0AF: 8D 02 50 STA $5002 E0B2: A0 00 LDY #$00 E0B4: B9 4E E0 LDA $E04E,Y ;load code into 0101h (see below) E0B7: 99 01 01 STA $0101,Y E0BA: C8 INY E0BB: C0 0A CPY #$0A E0BD: 90 F5 BCC $E0B4 It just loaded the following code into 0101h: 0101: AD 00 01 LDA $0100 0104: 20 E4 FF JSR $FFE4 0107: 20 FB 07 JSR $07FB 010A: 60 RTS E0BF: A9 40 LDA #$40 E0C1: 8D 17 40 STA $4017 ;set up IRQ mode E0C4: A9 00 LDA #$00 E0C6: 8D 00 A0 STA $A000 ;set up mirroring E0C9: 58 CLI ;turn IRQ's on E0CA: A9 01 LDA #$01 E0CC: 85 C0 STA $C0 E0CE: A9 08 LDA #$08 E0D0: 85 09 STA $09 E0D2: A9 00 LDA #$00 E0D4: 85 C1 STA $C1 E0D6: 85 77 STA $77 E0D8: 85 0F STA $0F E0DA: A9 01 LDA #$01 E0DC: 85 0B STA $0B E0DE: A5 0B LDA $0B E0E0: F0 09 BEQ $E0EB E0E2: 20 C0 07 JSR $07C0 ;our JMP table is now in full effect! 07C0: 4C 13 E3 JMP $E313 E313: 8D 00 E0 STA $E000 ;clear IRQ flag E316: A5 68 LDA $68 ;acc = 00h E318: 8D 00 20 STA $2000 ;clear PPU E31B: 8D 01 20 STA $2001 E31E: 85 0C STA $0C E320: 85 0D STA $0D E322: 85 16 STA $16 E324: 85 0A STA $0A E326: 85 0B STA $0B E328: 85 0F STA $0F E32A: 85 ED STA $ED ;clear out various things E32C: A9 FF LDA #$FF E32E: 8D 00 C0 STA $C000 ;set IRQ reload E331: 8D 00 07 STA $0700 E334: 8D 01 07 STA $0701 E337: 8D 02 07 STA $0702 E33A: 8D 03 07 STA $0703 E33D: 20 E7 E2 JSR $E2E7 ;push sprites off the screen E340: 20 F9 E2 JSR $E2F9 ;clear out the nametables on the PPU E343: A5 09 LDA $09 E345: 0A ASL E346: AA TAX ;X holds 10h E347: BD 54 E3 LDA $E354,X E34A: 85 47 STA $47 E34C: BD 55 E3 LDA $E355,X E34F: 85 48 STA $48 ;store E753h E351: 6C 47 00 JMP ($0047) ;go there E753: AE C1 07 LDX $07C1 E756: A4 69 LDY $69 E758: 20 D2 07 JSR $07D2 ;our JMP table is in effect! E75B: 60 RTS 07D2: 20 68 E0 JSR $E068 E068: A5 6F LDA $6F E06A: 20 F7 07 JSR $07F7 ;do a write to 8000h E06D: 20 FB 07 JSR $07FB ;do a write to 8001h E070: EC FF BF CPX $BFFF E073: D0 F3 BNE $E068 ;crash if not right! E075: 60 RTS 07D5: 4C 00 A0 JMP $A000 ;JMP table is in play again A000: 98 TYA A001: 0A ASL A002: AA TAX ;X is 4 A003: BD 0D A0 LDA $A00D,X ;oh wow that's cute... calculated RTS A006: 48 PHA A007: BD 0C A0 LDA $A00C,X A00A: 48 PHA A00B: 60 RTS ;this leads us to... A088: A9 7D LDA #$7D A08A: 85 47 STA $47 A08C: A9 A2 LDA #$A2 A08E: 85 48 STA $48 A090: A9 20 LDA #$20 A092: 85 2B STA $2B A094: A9 00 LDA #$00 A096: 85 2A STA $2A A098: 20 7A A1 JSR $A17A ;init PPU nametable A09B: A9 F8 LDA #$F8 A09D: 85 40 STA $40 A09F: A9 FA LDA #$FA A0A1: 85 41 STA $41 A0A3: A9 FF LDA #$FF A0A5: 85 60 STA $60 A0A7: A9 00 LDA #$00 A0A9: 85 08 STA $08 A0AB: A9 00 LDA #$00 A0AD: 85 3E STA $3E A0AF: 85 3F STA $3F A0B1: 85 1A STA $1A A0B3: 85 1C STA $1C A0B5: 85 1B STA $1B A0B7: 85 1D STA $1D A0B9: A9 1E LDA #$1E A0BB: 85 01 STA $01 A0BD: A9 A8 LDA #$A8 A0BF: 85 3D STA $3D A0C1: 8D 00 20 STA $2000 ;turn PPU on A0C4: 60 RTS E75B: 60 RTS E0E5: 20 C3 07 JSR $07C3 07C3: 4C 10 E1 JMP $E110 E110: 20 CF 07 JSR $07CF ;set up some sprite things E113: A5 3D LDA $3D ;init some things E115: 85 00 STA $00 E117: A5 3E LDA $3E E119: 85 02 STA $02 E11B: A5 3F LDA $3F E11D: 85 03 STA $03 E11F: A5 40 LDA $40 E121: 85 10 STA $10 E123: A5 41 LDA $41 E125: 85 11 STA $11 E127: A5 42 LDA $42 E129: 85 12 STA $12 E12B: A5 42 LDA $42 E12D: 85 12 STA $12 E12F: A5 43 LDA $43 E131: 85 13 STA $13 E133: A5 44 LDA $44 E135: 85 14 STA $14 E137: A5 45 LDA $45 E139: 85 15 STA $15 E13B: 60 RTS E0E8: 4C C6 07 JMP $07C6 ;JMP into RAM again 07C6: 4C 06 E1 JMP $E106 E0DE: A5 0B LDA $0B E0E0: F0 09 BEQ $E0EB E0E2: 20 C0 07 JSR $07C0 ;sprite/bankswitching routines E0E5: 20 C3 07 JSR $07C3 E0E8: 4C C6 07 JMP $07C6 E0EB: E6 46 INC $46 E0ED: A5 17 LDA $17 E0EF: F0 FA BEQ $E0EB E0F1: 20 C3 07 JSR $07C3 ;more sprite/bankswitching routines E0F4: 20 C9 07 JSR $07C9 E0F7: 20 CC 07 JSR $07CC E0FA: A5 0F LDA $0F E0FC: F0 08 BEQ $E106 E0FE: E6 46 INC $46 E100: A5 17 LDA $17 E102: C5 69 CMP $69 E104: 90 F8 BCC $E0FE E106: E6 16 INC $16 ;<--- code gets dropped down into here E108: A5 68 LDA $68 E10A: 85 17 STA $17 E10C: 85 19 STA $19 E10E: F0 CE BEQ $E0DE E110: 20 CF 07 JSR $07CF E113: A5 3D LDA $3D E115: 85 00 STA $00 Well, that's about all I'm going to show. Most of the protection is now done at this point, and the game code is commencing. From this point on, the code continuously calls the routines and JMP vectors in RAM to do all the "important" things such as bankswitching and sprite loading and such. Hope it was as informatitive and amusing to you as I thought it was! The lengths they went to protect this game were quite extreme, and I don't think I have ever seen anything like it before. Though, in the end, a little work and perserverence opened up its secrets and got it running. This game now runs on Nintendulator, and I hope it'll soon be running on my FPGA NES. ------------------------------------------------------------------- Appendix- How Open Bus Works: Basically, open bus is what you get if you try to read an "unimplemented" memory location, such as 5000h or 4800h. Generally, you will read the last byte that was present on the CPU's data lines, which is *usually* the last byte of the read instruction. The data "stays" on the data lines due to stray bus capacitance, forming a rudimentary "dynamic RAM" type situation. Examining a few instructions reveals why the byte returned is usually the upper 8 bits of the address bus: AD 00 50 : LDA $5000 The last byte on the databus was 50h, which happens to be the upper 8 bits of the address we looked at, so this is what the LDA instruction will return into the accumulator. This is the reason that reading the controller ports (at 4016h and 4017h) returns 40 or 41... not all 8 bits are connected, and bit 6 just happens to be one that isn't connected, so the "1" bit "bleeds through".