Contra Spirits hacking

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Post Reply
krzysiobal
Posts: 712
Joined: Sun Jun 12, 2011 12:06 pm
Location: Poland

Contra Spirits hacking

Post by krzysiobal » Wed May 27, 2020 12:40 pm

I was trying to make physical cartridge of Contra Spirits (Mapper 90 / Jy Company), but all I got was just a momental hang of game after power-up. Maybe one in 50 power-up worked. I triple checked the mapper design in FPGA (PRG/CHR banking) and it was OK, other games using this mapper (Super Mario World, Final Fight 3) worked fine. Maybe my IRQ implementation was not accurate, but still SMW and FF3 worked fine and Contra Spirits did not even use IRQs at title screen.

Image Image Image

Deep analysis shown that Contra Spirits just after power-up calculates some kind of CRC of its CHR data (every $4d'th byte) and PRG code (every $21th byte).

The above calculated values (which should be equal to 49 A4 and 5B 6B respectively are checked not only during start, but in many places during game (for example - on each frame). If they don't match, game hangs. Simple fix would be to disable all the checks (replace TXS with NOP), but I was not sure if I could cover all the places, so safer idea was to overwrite beginning of the calculation routine with the function that always returns corect values

After that solution, game works and even launches faster, because the CRC calculating routine took around 1second on boot.

I really wonder why the un-patched game worked so randomly. If the PRG/CHR reading would fail, the game would hang during game randomly, but it works fine now.

Code: Select all

--Detailed algorithms--
How it calculates:
$00, $01 - chr-rom addr ptr (lo, hi)
$02      - there is stored value read from chr-rom
$04      - 1k chr-rom bank at $9000
$49, $4a - crc of chr-rom values (each $4d'th value from 0 up to $7d2
           are taken into account) [should be: 49 A4]

$4b, $4c - crc of prg-rom values (each $21'th value from $8000 up to
           $bfff are taken into account) [should be: 5B 6B]
$4d <- 00
$2b <- 01

CHR-ROM CRC calculation start routine:
	0F:D057: A5 04     LDA $0004 = #$00 
	0F:D059: 8D 00 90  STA $9000 = #$8A
	0F:D05C: 18        CLC
	0F:D05D: 69 01     ADC #$01
	0F:D05F: 8D 01 90  STA $9001 = #$02
	0F:D062: A9 00     LDA #$00
	0F:D064: 85 00     STA $0000 = #$00
	0F:D066: A9 00     LDA #$00
	0F:D068: 85 01     STA $0001 = #$00
	0F:D06A: A5 01     LDA $0001 = #$00
	0F:D06C: 8D 06 20  STA $2006 = #$00
	0F:D06F: A5 00     LDA $0000 = #$00
	0F:D071: 8D 06 20  STA $2006 = #$00
	0F:D074: AD 07 20  LDA $2007 = #$00
	0F:D077: AD 07 20  LDA $2007 = #$00
	0F:D07A: 85 02     STA $0002 = #$00
	0F:D07C: A5 49     LDA $0049 = #$00
	0F:D07E: 18        CLC
	0F:D07F: 65 02     ADC $0002 = #$00
	0F:D081: 85 49     STA $0049 = #$00
	0F:D083: 90 02     BCC $D087
	0F:D085: E6 4A     INC $004A = #$00
	0F:D087: 06 49     ASL $0049 = #$00
	0F:D089: 26 4A     ROL $004A = #$00
	0F:D08B: 90 06     BCC $D093
	0F:D08D: E6 49     INC $0049 = #$00
	0F:D08F: D0 02     BNE $D093
	0F:D091: E6 4A     INC $004A = #$00
	0F:D093: A5 00     LDA $0000 = #$00
	0F:D095: 18        CLC
	0F:D096: 69 4D     ADC #$4D
	0F:D098: 85 00     STA $0000 = #$00
	0F:D09A: 90 02     BCC $D09E
	0F:D09C: E6 01     INC $0001 = #$00
	0F:D09E: A5 00     LDA $0000 = #$00
	0F:D0A0: 38        SEC
	0F:D0A1: E9 00     SBC #$00
	0F:D0A3: A5 01     LDA $0001 = #$00
	0F:D0A5: E9 08     SBC #$08
	0F:D0A7: 90 C1     BCC $D06A
	0F:D0A9: E6 04     INC $0004 = #$00
	0F:D0AB: E6 04     INC $0004 = #$00
	0F:D0AD: A5 04     LDA $0004 = #$00
	0F:D0AF: D0 A6     BNE $D057
PRG-ROM CRC calculation start routine:
	0F:D0B1: A9 00     LDA #$00
	0F:D0B3: 85 04     STA $0004 = #$00
	0F:D0B5: A5 04     LDA $0004 = #$00
	0F:D0B7: 8D 00 80  STA $8000 = #$4C
	0F:D0BA: 18        CLC
	0F:D0BB: 69 01     ADC #$01
	0F:D0BD: 8D 01 80  STA $8001 = #$2A
	0F:D0C0: A9 00     LDA #$00
	0F:D0C2: 85 00     STA $0000 = #$1F
	0F:D0C4: A9 80     LDA #$80
	0F:D0C6: 85 01     STA $0001 = #$08
	0F:D0C8: A0 00     LDY #$00
	0F:D0CA: B1 00     LDA ($00),Y @ $081F = #$00
	0F:D0CC: 85 02     STA $0002 = #$00
	0F:D0CE: A5 4B     LDA $004B = #$00
	0F:D0D0: 18        CLC
	0F:D0D1: 65 02     ADC $0002 = #$00
	0F:D0D3: 85 4B     STA $004B = #$00
	0F:D0D5: 90 02     BCC $D0D9
	0F:D0D7: E6 4C     INC $004C = #$00
	0F:D0D9: 06 4B     ASL $004B = #$00
	0F:D0DB: 26 4C     ROL $004C = #$00
	0F:D0DD: 90 06     BCC $D0E5
	0F:D0DF: E6 4B     INC $004B = #$00
	0F:D0E1: D0 02     BNE $D0E5
	0F:D0E3: E6 4C     INC $004C = #$00
	0F:D0E5: A5 00     LDA $0000 = #$1F
	0F:D0E7: 18        CLC
	0F:D0E8: 69 21     ADC #$21
	0F:D0EA: 85 00     STA $0000 = #$1F
	0F:D0EC: 90 02     BCC $D0F0
	0F:D0EE: E6 01     INC $0001 = #$08
	0F:D0F0: A5 00     LDA $0000 = #$1F
	0F:D0F2: 38        SEC
	0F:D0F3: E9 00     SBC #$00
	0F:D0F5: A5 01     LDA $0001 = #$08
	0F:D0F7: E9 A0     SBC #$A0
	0F:D0F9: 90 CD     BCC $D0C8
	0F:D0FB: E6 04     INC $0004 = #$00
	0F:D0FD: A5 04     LDA $0004 = #$00
	0F:D0FF: C9 20     CMP #$20
	0F:D101: 90 B2     BCC $D0B5
Some remaiting stuff:
	0F:D103: 20 AB C3  JSR $C3AB
	0F:D106: A9 00     LDA #$00
	0F:D108: 85 4D     STA $004D = #$01
	0F:D10A: A9 01     LDA #$01
	0F:D10C: 85 2B     STA $002B = #$00
	0F:D10E: 78        SEI

---
How it checks:

03CFDB: A5 4A     LDA $004A = #$A4   
03CFDD: C9 A4     CMP #$A4           
03CFDF: F0 01     BEQ $CFD2          
03CFE1: 9A        TXS                
                                     
03D13C: A5 4B     LDA $004B = #$5B   
03D13E: CD A2 FF  CMP $FFA2 = #$5B   
03D141: F0 01     BEQ $D134          
03D143: 9A        TXS                

03D147: A5 4C     LDA $004C = #$6B   
03D149: CD A0 FF  CMP $FFA0 = #$6B   
03D14C: F0 01     BEQ $D13F          
03D14E: 9A        TXS                

00244D: A5 4A     LDA $004A = #$A4
00244F: C9 A4     CMP #$A4
002451: F0 01     BEQ $A444
002453: 9A        TXS

Fix - write at ROM offset $3d067 those values: a9498549a9a4854aa95b854ba96b854c4c03d1
which corresponds to
lda #$49   
sta $49
lda #$a4
sta $4a
lda #$5b
sta $4b
lda #$6b
sta $4c
jmp D103

Post Reply