CPS1 is an arcade system board developed by Capcom that ran game software stored on removable ROM cartridges. There are some classic games release on it, such as Final Fight, Street Fighter II': Champion Edition, Cadillacs and Dinosaurs. There are some emulators to emulate it: MAME, WinKawaks, Nebula, FBA...
The sound of CPS1 is amazing too. I have found the only software named M1 to reproduce the music of arcade games. M1 lets you enjoy music from over 1400 arcade games. But M1 is not a open source software.
MAME is strictly a non-profit project. Its main purpose is to be a reference to the inner workings of the emulated arcade machines. You can do anything about arcade games with MAME source code. To show the detail of decrypting CPS1 game audio, I programmed this software named M1.NET (for CPS1).
How It Works?
For CPS1 audio, there are two different boards. I named them CPS-1 and Capcom QSound (CPS version).
For CPS-1, the Z-80 CPU runs at 3579545 Hz, and there are two sound chips: Yamaha YM2151, Oki OKI6295. The program load the file "audiocpu.rom" as the Z-80 ROM, file "oki.rom" as the OKI6295 ROM. Then the Z-80 CPU runs. When you double click the track or click the play button, the function
CStop is triggered.
For Capcom QSound (CPS version), the Z-80 CPU runs at 8000000 Hz with Kabuki encrypted code, and there is a Q-Sound chip. The program loads the file "audiocpu.rom" as the Z-80 ROM for
ReadMemory only, file "audiocpuop.rom" as the Z-80 ROM for
ReadOp only, and file "qsound.rom" as the Q-Sound chip ROM. Then the Z-80 CPU runs. When you double click the track or click the play button, the function
QStop is triggered.
public static void CPlay(ushort ID)
Sound.latched_value = (byte)ID;
public static void CStop(ushort ID)
Sound.latched_value = (byte)ID;
public static void QPlay(ushort ID)
public static void QStop(ushort ID)
qsound_sharedram1_w(0x00, (ushort)(ID >> 8));
The program uses the same .lst file as
BridgeM, and it uses the truncated format of the file "m1.xml" of
BridgeM1. You should install Microsoft .NET Framework 3.5 or higher before running the program. The UI is simple and it has the similar function as
BridgeM1. I've added the file "wofhfh.lst". Since "
wofhfh" is a bootleg, I have some problem in stopping voice. You can edit "m1.xml", add .lst file and make ROMs for any CPS1 game to get its audio.
M1.NET (for CPS1) user interface
Make the ROMs
Now I explain how to make the roms for both boards.
For CPS-1 game "
ffight", I will make the following files: "audiocpu.rom", "oki.rom". From the MAME CPS1 code:
Find the following code:
ROM_START( ffight )
ROM_REGION( 0x18000, "audiocpu", 0 )
ROM_LOAD( "ff_09.12b", 0x00000, 0x08000,
CRC(b8367eb5) SHA1(ec3db29fdd6200e9a8f4f8073a7e34aef731354f) )
ROM_CONTINUE( 0x10000, 0x08000 )
ROM_REGION( 0x40000, "oki", 0 )
ROM_LOAD( "ff_18.11c", 0x00000, 0x20000,
CRC(375c66e7) SHA1(36189e23209ce4ae5d9cbabd1574540d0591e7b3) )
ROM_LOAD( "ff_19.12c", 0x20000, 0x20000,
CRC(1ef137f9) SHA1(974b5e72aa28b87ebfa7438efbdfeda769dedf5e) )
Insert 0x8000 zero bytes at offset 0x8000 of file "ff_09.12b" (or other name in previous version, just check the CRC32 b8367eb5 to confirm the file), and save it as file "audiocpu.rom" with the length 0x18000. Simply sequentially concatenate the files "ff_18.11c", "ff_19.12c" to a file "oki.rom" with the length 0x40000. You can do it with WinHex easily.
Insert 0x8000 (32768) bytes of 0x00 at the offset 0x8000
Sequently concatenate the files "ff_18.11c", "ff_19.12c"
For Capcom QSound (CPS version) game "
wof", so I will make the following files: "audiocpu.rom", "audiocpuop.rom", "qsound.rom". Find the following code from the MAME CPS1 code:
ROM_START( wof )
ROM_REGION( 0x28000, "audiocpu", 0 )
ROM_LOAD( "tk2_qa.5k", 0x00000, 0x08000,
CRC(c9183a0d) SHA1(d8b1d41c572f08581f8ab9eb878de77d6ea8615d) )
ROM_CONTINUE( ; 0x10000, 0x18000 )
ROM_REGION( 0x200000, "qsound", 0 )
ROM_LOAD( "tk2-q1.1k", 0x000000, 0x80000,
CRC(611268cf) SHA1(83ab059f2110fb25fdcff928d56b790fc1f5c975) )
ROM_LOAD( "tk2-q2.2k", 0x080000, 0x80000,
CRC(20f55ca9) SHA1(90134e9a9c4749bb65c728b66ea4dac1fd4d88a4) )
ROM_LOAD( "tk2-q3.3k", 0x100000, 0x80000,
CRC(bfcf6f52) SHA1(2a85ff3fc89b4cbabd20779ec12da2e116333c7c) )
ROM_LOAD( "tk2-q4.4k", 0x180000, 0x80000,
CRC(36642e88) SHA1(8ab25b19e2b67215a5cb1f3aa81b9d26009cfeb8) )
Simply sequentially concatenate the files "tk2-q1.1k", "tk2-q2.2k", "tk2-q3.3k", "tk2-q4.4k" to a file "qsound.rom" with the length 0x200000. By debugging MAME, you can set a breakpoint at the end of function "
kabuki_decode" in source file "src\mame\machine\kabuki.c" and find the start address, then dump the memory to file:
Dump memory by MAME debugging
Or you can do the same as type CPS-1 for file "audiocpu.rom". Then dump memory from running process (for example:
BridgeM1…) when ROMs loaded by finding key bytes and replace the first 0x8000 bytes of file "audiocpu.rom". And dump memory for "audiocpuop.rom" with the length 0x8000.
Dump memory from running Nebula by finding key bytes
I've finished M1.NET (for CPS1). It figures out how the audio ROMs work. You can make any other CPS1 games supported. By the translation from C to C#, there is no unsafe code and the code is much more readable. I've preserved the main architecture of MAME. Programmers can refer more to this. For example: make it support other sound chips, program an emulator like WinKawaks...
- MAME-Multiple Arcade Machine Emulator - http://www.mamedev.org/source/
- MSDN - http://msdn.microsoft.com
- bizhawk Z80 code - http://code.google.com/p/bizhawk/source/browse/trunk/BizHawk.Emulation/CPUs/Z80/
- VCMAME detail by Bryan McPhail - http://www.codeproject.com/Articles/4923/VCMAME-Multiple-Arcade-Machine-Emulator-for-Visual
- MAME and MAMEUI Visual C Project Files - http://www.mikesarcade.com/arcade/vcmame.html
- BridgeM1 - http://www.e2j.net/downloads.html
- WinHex - http://www.x-ways.net/winhex/