Hacking Soccer Kings for Free Play

Here are some of my notes from adding a "Free Play" option to Soccer Kings.

If you read my notes on Farfalla, this is a continuation of that effort.

ROM Layout (3 x 2532)

Again, the first step is figuring out where everyhing is. Unlike the 2 x 2764, for this I had to go back to the schematics. Fortunately, it doesn't take long to work through the possible addresses and figure out which device is at what address.

Start Address End Address Device Bank
0x0000 0x07FF ROM1 Bank 1
0x0800 0x0FFF ROM2 Bank 1
0x1000 0x17FF ROM3 Bank 1
0x1800 0x1FFF RAM (Mine)
0x2000 0x27FF ROM1 Bank 2
0x2800 0x2FFF ROM2 Bank 2
0x3000 0x37FF ROM3 Bank 2
0x3800 0x3FFF RAM (Theirs)

Memory Map / Layout (3 x 2532)

ROM 1
Bank 1
ROM 2
Bank 1
ROM 3
Bank 1
RAM
(Mine)
ROM 1
Bank 1
ROM 2
Bank 1
ROM 3
Bank 1
RAM
(Theirs)
0x0000
0x07FF
0x0800
0x0FFF
0x1000
0x17FF
0x1800
0x1FFF
0x2000
0x27FF
0x2800
0x2FFF
0x3000
0x37FF
0x3800
0x3FFF

The addresses 0x1800 0x1C00 0x3800 and 0x3C00 are all equivalent. In the hardware, they all end up at the same location (RAM). I'm used to using 0x1800 for the base of RAM.

Building Memory Image for Disassembly


dd bs=2048 count=1 if=cpurom1.bin of=Rom1Bank1 skip=0
dd bs=2048 count=1 if=cpurom1.bin of=Rom1Bank2 skip=1

dd bs=2048 count=1 if=cpurom2.bin of=Rom2Bank1 skip=0
dd bs=2048 count=1 if=cpurom2.bin of=Rom2Bank2 skip=1

dd bs=2048 count=1 if=cpurom3.bin of=Rom3Bank1 skip=0
dd bs=2048 count=1 if=cpurom3.bin of=Rom3Bank2 skip=1

dd bs=2048 count=1 if=/dev/zero of=RAM skip=0

cat Rom1Bank1 Rom2Bank1 Rom3Bank1 RAM Rom1Bank2 Rom2Bank2 Rom3Bank2 RAM > SoccerKings.bin

Hex dump of images does not reveal any free space.

Possibility: conversion to a 2x2764 setup. Re-arrange the image blocks to fit. If possible, this would also provide free space in the ROMs for hacking.

Memory Map / Layout (2 x 2764)

ROM 1
Bank 1
ROM 2
Bank 1
ROM 2
Bank 2
RAM
(Mine)
ROM 1
Bank 2
ROM 2
Bank 3
ROM 2
Bank 4
RAM
(Theirs)
ROM 1
Bank 3
Hole ROM 1
Bank 4
Hole
0x0000
0x07FF
0x0800
0x0FFF
0x1000
0x17FF
0x1800
0x1FFF
0x2000
0x27FF
0x2800
0x2FFF
0x3000
0x37FF
0x3800
0x3FFF
0x4000
0x47FF
0x4800
0x4FFF
0x6000
0x67FF
0x6800
0x6FFF

Memory Map / Layout (3 x 2532)

ROM 1
Bank 1
ROM 2
Bank 1
ROM 3
Bank 1
RAM
(Mine)
ROM 1
Bank 1
ROM 2
Bank 1
ROM 3
Bank 1
RAM
(Theirs)
0x0000
0x07FF
0x0800
0x0FFF
0x1000
0x17FF
0x1800
0x1FFF
0x2000
0x27FF
0x2800
0x2FFF
0x3000
0x37FF
0x3800
0x3FFF

ROM1 Bank1 - Stays the same (ROM1 Bank1)
ROM2 Bank1 - Stays the same (ROM2 Bank1)
ROM3 Bank1 - Moves to ROM2 Bank2
ROM1 Bank2 - Stays the same (ROM1 Bank2)
ROM2 Bank2 - Moves to ROM2 Bank3
ROM3 Bank2 - Moves to ROM2 Bank4
RAM - Stays at 1800 / 3800
Holes @ 4000 - 47FF, 4800 - 4FFF, 5000 - 57FF, 5800 - 5FFF, 6000 - 67FF, 6800 - 6FFF

ROM1 has free space.
ROM2 is full.
Put hacking code @ 6000, 6040 (ROM1 Bank4)

Credits are stored @ 0x1F22 in RAM (0x18)
Credits are also stored bit-flipped @ 0x1F4D (0xE7)

Setting 30 is stored @ 0x1F98 in RAM (0x00)
Setting 30 is also stored bit-flipped @ 0x1FC8 (0xFF)

Does not work. Game does not boot.

Have not figured out why the 3 x 2532 to 2 x 2764 image rearranging won't work. After two-pass disassembly of the ROMs, nothing is standing out as being a problem. RAM is being accessed at 0x1C00 in this game, but that maps down to the same as 0x1800 or 0x3800 as far as the hardware is concerned.

After several attempts to make sense of this, I abandoned the idea of making a 2 x 2764 Soccer Kings, at least for now. I may re-visit this idea later.

Some minor source code changes to the patches to shrink them slightly get them down to a total of 48 bytes of code + data.

There are 50 bytes of data at 0x2000 (0x0800 in ROM1) in the hex dump, most likely only used for the never-used feature of printing the audits on a serial printer.

00002000  43 4f 49 4e 53 20 23 20  50 4c 41 59 45 44 20 47  |COINS # PLAYED G| 
00002010  57 49 4e 4e 45 44 20 47  53 4f 43 43 45 52 20 4b  |WINNED GSOCCER K| 
00002020  49 4e 47 20 53 53 45 52  49 41 4c 20 4e 20 30 37  |ING SSERIAL N 07| 
00002030  33 30 20 cc 1c a7 05 00  3f 10 92 18 03 3f 24 3d  |30 .....?....?$=| 

Using this space for code loses the ability to have a custom serial number and glamour space to put a URL in the image, but it might make for a much faster effort to get a Free Play ROM image that works, since it eliminates the need to rearrange the images in to larger ROMs to make space. Also might make this easier to do to other games in the future, since all of them have this same block of text.

Found credit decrement code. Is somewhat obscured in this ROM, unlike the simple plain code in Farfalla.


1154 : C8 FA		strr,r0 *X1150		; Credit decrement happens here.

*1150 contains 0x1F22 credits address in RAM

12EC:			loda r0 [0x1f22]	; Load credits value from RAM
...
12F6: A4 01		sub, r0 0x01		; Credit decrement
12F8: 3F 11 54		bsta, 0x1154		; Store updated credits

Patches:

Disables "Coin Meter" check
Patch [07 FF] to [07 00] @0x2B56 (ROM2 Bank2) 0x0B56 in ROM2 image

Disable credit = 0? check
Patch [0C 1F 22] to [1F 20 00] @0x12CA (ROM3 Bank1) 0x02CA in ROM3 image

Prevent credit decrement less than 0
Patch [A4 01] to [C0 C0] @0x12F6 (ROM3 Bank1) 0x02F6 in ROM3 image
Patch to [0C 1F 22] to [1F 20 18] @0x12EC (ROM3 Bank1) 0x02EC in ROM3 image


Patch1:                                 ; (24 bytes) 
        loda    r0,[Setting30]          ; Get value of setting 30 
        andi    r0,#0x0F                ; Strip off high order bits 
        comi    r0,#0x00                ; Is Setting 30 =?= 0 
        bctr    .eq.,Patch1Done         ; Yes: continue with original code 
        lodi    r0,#0x01                ; No: disable credit check 
        bctr    .un.,[Patch1Return]     ; Return from patch 
Patch1Done: 
        loda    r0,[Credits]            ; Original code 
        bctr    .un.,[Patch1Return] 
Patch1Return: 
        .dw     #0x12CD                 ; Return from patch 
Credits: 
        .dw     #0x3f22                 ; Credits in RAM 
Setting30: 
        .dw     #0x1f98                 ; Setting 30 in RAM 


Patch2:                                 ; (25 bytes) 
        loda    r0,[Setting30]          ; Get value of setting 30 
        andi    r0,#0x0F                ; Strip off high order bits 
        comi    r0,#0x00                ; Is Setting 30 =?= 0 
        bctr    .eq.,Patch2Done         ; Yes: continue with original code 
        loda    r0,[Credits]            ; No: disable credit decrement below 0 
        bctr    .gt.,Patch2Done         ; Credit=0? – allow credit decrement 
        bctr    .un.,[Patch2Return]     ; Return from patch 
Patch2Done: 
        loda    r0,[Credits] 
        subi    r0,#0x01                ; Decrement credits 
        bctr    .un.,[Patch2Return]     ; Return from patch 
Patch2Return: 
        .dw     #0x12EF                 ; Return from patch 

Patch code in ROM1 @ 0x0800


00002000  0c 80 16 44 0f e4 00 18  04 04 01 1b 85 0c 80 14  |...D............| 
00002010  1b 80 12 cd 3f 22 1f 0c  80 16 44 0f e4 00 18 07  |....?"....D.....| 
00002020  0c 80 14 19 02 1b 87 0c  80 14 a4 01 1b 80 12 ef  |................| 

Testing (PinMAME)

Disable of Coin Meter - patch works.
Credit Increment / Decrement - works.
Start (Credits > 0) - works
Start (Credits == 0) - does not work, game does not start

Bug found. In the FreePlay.asm source, the second patch ".org" statement was off by one byte. This overwrote the last byte of the first patch. The missing byte was the second half of the address of Setting 30 in RAM. So instead of reading the value for Setting 30, some other address was read, leading to wrong behaviour.

PinMAME tested - OK 12 February 2011
Game tested - OK 12 February 2011


David Gersic

Copyright © 2011. All rights reserved.

This document may be freely distributed so long as the content is not modified.

Last updated 15 February 2011