I've been hacking around with Taito F2 hardware for a while now. One conversion I've recently complete is converting Ah Eikou no Koshien (a Japanese Baseball Game) into Gun & Frontier (A vertical SHMUP). I wanted to post up a log of this process as I utilized and learned a wide breadth of different tools and techniques and honestly I think the process is more interesting than the end result.
Part 1 Determining Feasibility
I didn't start out thinking "lets convert koshien to gunfront". Rather I looked at the MAME driver with the thought of "are there any games on this hardware similar enough to be conversion candidates?" I like MAME drivers with a lot of comments describing what the hardware is doing or what the different features, are it helps to clarify a lot of things instead of having to analyze the code to figure it out. The Taito F2 driver doesn't disappoint and it has this nice chart of which games use which Taito Customs and what those customs do:
So right off the bat we see that there are a lot of variations in this hardware. it's not like CPS1 or System 16 where every game uses nearly identical hardware. HOWEVER going through this list we can see that some games DO share the same collection of customs. Here is where I found that koshien uses "TC0510NIO TC0360PRI TC0260DAR" for IO, priority, and pallet and gunfront uses "TC0510NIO TC0360PRI TC0260DAR" for IO, priority, and pallet also. koshien is a cheaper sports game and gunfront looks like a cool shmup that sounds like something interesting so lets look deeper into the MAME driver and see what other differences there are.
The next thing I look at is the "Address Map", this is the part of the MAME driver that explains the location of the different hardware features in terms of how the CPU accesses them. You really need this to match between the two games because if it's different then that could be a deal breaker or a lot of work to fix. If your lucky a different address map can be fixed by swapping or modifying a PAL, or jumpers, if you're unlucky it could mean hundreds of patches to the game code (like trying to convert CPS1.5 games to CPS2) or in some cases differences could mean it's not possible at all, or simply not worth the effort. Of course the best scenario is when games use the same exact address map.
So what do we see here?
if you look at each of the "map(" entries the first number is the location of the hardware feature and the second number is the size, the rest of it tells you what that entry is for. ROM and RAM locations are the most important things you want to match perfectly.
At first glance this is very good news because the location of everything is exactly the same but there are some differences:
Now that we know the address map looks decent lets look at the ROM definition, this tells us the size and location of all the ROMs that the game uses.
So Here we can see all of the ROM files for each of these games, the "ROM_REGION" lines tell us the total amount of space used by all the ROMs in that group (often this matches what's in the address map), and the "ROM_LOAD" tells us how the ROM is loaded into memory. the first number after the file name is the location, and the second number is the size... just like on the address map.
if we notice some of the program ROMs are loaded with "ROM_LOAD16_BYTE" and every other address location ends with 1. What this is telling us is that we have 2 8-bit ROMs that are being "interleaved" together to form a single 16-bit ROM. You can think of it like each ROM is a stack of paper so it reads a page from the left stack (the "lower" ROM), then a page from the stack (the "upper" ROM) then the left, then the right, and so on. You can think of a 16-bit ROM as simply being a double-wide page, but some games used pairs of 8-bit ROMs to the same effect.
This is important because we can see that on gunfront it uses 3 pairs of interleaved ROMs , and on koshien it uses 1 pair of interleaved ROMs and then a normal 16-bit ROM. So one of the things we're going to have to do is interleave some of the gun front ROM data before we can write it to that 16-bit ROM. There are some bigger problems here though, most notably there is a gap in the koshien ROM space. The first two ROMs are 0x20000 in size meaning together they form a 0x40000 sized 16-bit ROM. But the third ROM doesn't start until 0x80000... that means there is no ROM space from 0x40000 to 0x80000 gunfront has data in this region, so that's something that will need to be fixed if this conversion is going to be possible.
The other problem here is the ADPCM (Audio Samples) ROM. gunfront uses one that's twice the size of koshien (sizes are in hex so 0x100000 is twice the size of 0x080000). Everything else seems ok as the sizes are either the same or koshien has larger ROM space that gunfront simply wont need
It's entirely possible that the PCB is already setup to fill these gaps, maybe they even use the same PCB? lets track down some photos of the hardware...
Ok, so it's not what I was hoping, clearly these are two completely different PCBs, but we can see that they do have essentially the same hardware features. The F2 hardware had some games on single board PCBs and other games with 2-board stacks that use a generic mother board and a sub-board that is game specific (That's what these are). Weirdly the game specific board is where the JAMMA edge is located but you can tell an F2 2-board version from the 3 large connectors labeled T, C, and B. gunfront was released as both a 2-board and a single board version, but I believe koshien was only ever released as a 2-board version.
Normally at this point I would perform a "virtual conversion" in MAME by renaming all of the gunfront ROM files to the names used by koshen, and then loading koshien in MAME with gunfront data to see if runs. Unfortunately the gap in the program ROM space means that's not possible (at least not without modifying the MAME source and recompiling)
I happen to already own a koshien PCB that I bought as part of an F2 bundle. so since we can't test in MAME lets test on hardware.
Part 1 Determining Feasibility
I didn't start out thinking "lets convert koshien to gunfront". Rather I looked at the MAME driver with the thought of "are there any games on this hardware similar enough to be conversion candidates?" I like MAME drivers with a lot of comments describing what the hardware is doing or what the different features, are it helps to clarify a lot of things instead of having to analyze the code to figure it out. The Taito F2 driver doesn't disappoint and it has this nice chart of which games use which Taito Customs and what those customs do:
Code:
I/O Priority / Palette Additional gfx Other
--------- ------------------- ----------------------- ----------------------------
finalb TC0220IOC TC0110PCR TC0070RGB
dondokod TC0220IOC TC0360PRI TC0260DAR TC0280GRD(x2)(zoom/rot)
megab TC0220IOC TC0360PRI TC0260DAR TC0030CMD(C-Chip protection)
thundfox TC0220IOC TC0360PRI TC0260DAR TC0100SCN (so it has two)
cameltry TC0220IOC TC0360PRI TC0260DAR TC0280GRD(x2)(zoom/rot)
qtorimon TC0220IOC TC0110PCR TC0070RGB
liquidk TC0220IOC TC0360PRI TC0260DAR
quizhq TMP82C265 TC0110PCR TC0070RGB
ssi TC0510NIO TC0260DAR
gunfront TC0510NIO TC0360PRI TC0260DAR
growl TMP82C265 TC0360PRI TC0260DAR TC0190FMC(sprite banking?)
mjnquest TC0110PCR TC0070RGB
footchmp TE7750 TC0360PRI TC0260DAR TC0480SCP(tilemaps) TC0190FMC(sprite banking?)
koshien TC0510NIO TC0360PRI TC0260DAR
yuyugogo TC0510NIO TC0260DAR
ninjak TE7750 TC0360PRI TC0260DAR TC0190FMC(sprite banking?)
solfigtr TMP82C265 TC0360PRI TC0260DAR TC0190FMC(sprite banking?)
qzquest TC0510NIO TC0260DAR
pulirula TC0510NIO TC0360PRI TC0260DAR TC0430GRW(zoom/rot)
metalb TC0510NIO TC0360PRI TC0260DAR TC0480SCP(tilemaps)
qzchikyu TC0510NIO TC0260DAR
yesnoj TMP82C265 TC0260DAR TC8521AP(RTC)
deadconx TE7750 TC0360PRI TC0260DAR TC0480SCP(tilemaps) TC0190FMC(sprite banking?)
dinorex TC0510NIO TC0360PRI TC0260DAR
qjinsei TC0510NIO TC0360PRI TC0260DAR
qcrayon TC0510NIO TC0360PRI TC0260DAR
qcrayon2 TC0510NIO TC0360PRI TC0260DAR
driftout TC0510NIO TC0360PRI TC0260DAR TC0430GRW(zoom/rot)
The next thing I look at is the "Address Map", this is the part of the MAME driver that explains the location of the different hardware features in terms of how the CPU accesses them. You really need this to match between the two games because if it's different then that could be a deal breaker or a lot of work to fix. If your lucky a different address map can be fixed by swapping or modifying a PAL, or jumpers, if you're unlucky it could mean hundreds of patches to the game code (like trying to convert CPS1.5 games to CPS2) or in some cases differences could mean it's not possible at all, or simply not worth the effort. Of course the best scenario is when games use the same exact address map.
Code:
void taitof2_state::koshien_map(address_map &map)
{
map(0x000000, 0x0fffff).rom();
map(0x100000, 0x10ffff).ram();
map(0x200000, 0x201fff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette");
map(0x300000, 0x30000f).rw(m_tc0510nio, FUNC(tc0510nio_device::halfword_r), FUNC(tc0510nio_device::halfword_w));
map(0x320000, 0x320000).w("tc0140syt", FUNC(tc0140syt_device::master_port_w));
map(0x320002, 0x320002).rw("tc0140syt", FUNC(tc0140syt_device::master_comm_r), FUNC(tc0140syt_device::master_comm_w));
map(0x800000, 0x80ffff).rw(m_tc0100scn[0], FUNC(tc0100scn_device::ram_r), FUNC(tc0100scn_device::ram_w)); /* tilemaps */
map(0x820000, 0x82000f).rw(m_tc0100scn[0], FUNC(tc0100scn_device::ctrl_r), FUNC(tc0100scn_device::ctrl_w));
map(0x900000, 0x90ffff).ram().share("spriteram");
map(0xa20000, 0xa20001).w(FUNC(taitof2_state::koshien_spritebank_w));
map(0xb00000, 0xb0001f).w(m_tc0360pri, FUNC(tc0360pri_device::write)).umask16(0xff00);
}
Code:
void taitof2_state::gunfront_map(address_map &map)
{
map(0x000000, 0x0bffff).rom();
map(0x100000, 0x10ffff).ram();
map(0x200000, 0x201fff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette");
map(0x300000, 0x30000f).rw(m_tc0510nio, FUNC(tc0510nio_device::halfword_wordswap_r), FUNC(tc0510nio_device::halfword_wordswap_w));
map(0x320000, 0x320000).w("tc0140syt", FUNC(tc0140syt_device::master_port_w));
map(0x320002, 0x320002).rw("tc0140syt", FUNC(tc0140syt_device::master_comm_r), FUNC(tc0140syt_device::master_comm_w));
map(0x800000, 0x80ffff).rw(m_tc0100scn[0], FUNC(tc0100scn_device::ram_r), FUNC(tc0100scn_device::ram_w)); /* tilemaps */
map(0x820000, 0x82000f).rw(m_tc0100scn[0], FUNC(tc0100scn_device::ctrl_r), FUNC(tc0100scn_device::ctrl_w));
map(0x900000, 0x90ffff).ram().share("spriteram");
// map(0xa00000, 0xa00001).nopw(); /* ?? */
map(0xb00000, 0xb0001f).w(m_tc0360pri, FUNC(tc0360pri_device::write)).umask16(0x00ff); /* ?? */
}
if you look at each of the "map(" entries the first number is the location of the hardware feature and the second number is the size, the rest of it tells you what that entry is for. ROM and RAM locations are the most important things you want to match perfectly.
At first glance this is very good news because the location of everything is exactly the same but there are some differences:
- I do see that the SIZE of the ROM space for koshien is LARGER than gun-front, this is ok, because it just means that gunfront wont use up all the available space (had koshien been smaller than gunfront it might be a problem).
- Next I see that on line 866 koshien uses some kind of sprite banking feature that is absent from gunfront. Since gunfront doesn't use it it's safe to say it will never try to access this memory location so it probably wont be a problem.
- The last difference I notice is some minor differences related to the tc0510nio chip, the location and size is the same but how it's accessed is different. We know from the chart at the beginning that this is the IO chip, hopefully this is a non-issue so lets keep going.
Now that we know the address map looks decent lets look at the ROM definition, this tells us the size and location of all the ROMs that the game uses.
Code:
ROM_START( koshien ) /* Ah Eikou no Koshien */
ROM_REGION( 0x100000, "maincpu", 0 ) /* 256k for 68000 code */
ROM_LOAD16_BYTE( "c81-11.bin", 0x000000, 0x020000, CRC(b44ea8c9) SHA1(f1d19f531b7a653f1c4244d612a339d95ce8cc7c) )
ROM_LOAD16_BYTE( "c81-10.bin", 0x000001, 0x020000, CRC(8f98c40a) SHA1(f9471306c47ced10a56c09794954e55fdb6f6b85) )
ROM_LOAD16_WORD_SWAP( "c81-04.bin", 0x080000, 0x080000, CRC(1592b460) SHA1(d42514b4d588d0376914832f0e07ce626d1cdee0) ) /* data rom */
ROM_REGION( 0x100000, "tc0100scn_1", 0 ) /* SCR */
ROM_LOAD16_WORD_SWAP( "c81-03.bin", 0x000000, 0x100000, CRC(29bbf492) SHA1(bd370b1de256a432821b443a6653aab8507fb3a7) )
ROM_REGION( 0x200000, "sprites", 0 ) /* OBJ */
ROM_LOAD( "c81-01.bin", 0x000000, 0x100000, CRC(64b15d2a) SHA1(18b3b405f77ad80781e3fce4ef021ba49f707ed6) )
ROM_LOAD( "c81-02.bin", 0x100000, 0x100000, CRC(962461e8) SHA1(cb0313b00681c36110eed50eae41ad98eb22205d) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound cpu */
ROM_LOAD( "c81-12.bin", 0x00000, 0x10000, CRC(6e8625b6) SHA1(212d384aa6ed43f5389739863afecbf0ad68af14) )
ROM_REGION( 0x080000, "ymsnd", 0 ) /* ADPCM samples */
ROM_LOAD( "c81-05.bin", 0x00000, 0x80000, CRC(9c3d71be) SHA1(79f1bb40d8356d9fc93b569c20be15e7fbf34580) )
ROM_REGION( 0x080000, "ymsnd.deltat", 0 ) /* Delta-T samples */
ROM_LOAD( "c81-06.bin", 0x00000, 0x80000, CRC(927833b4) SHA1(c09240e4885d2eace1c64fa6425faeeea0296d98) )
ROM_REGION( 0x0600, "plds", 0 )
ROM_LOAD( "pal16l8b-c81-07.bin", 0x0000, 0x0104, CRC(46341732) SHA1(af652621cb96f656fd1f9ed20daeb076641aeb08) )
ROM_LOAD( "pal16l8b-c81-08.bin", 0x0200, 0x0104, CRC(e7d2d300) SHA1(20a1a258230d5be73381c97509437a9e76de958c) )
ROM_LOAD( "pal16l8b-c81-09.bin", 0x0400, 0x0104, CRC(e4c012a1) SHA1(56746ce42fd64bf04e17132811de291a1bfa5451) )
ROM_END
Code:
ROM_START( gunfront )
ROM_REGION( 0xc0000, "maincpu", 0 ) /* 768k for 68000 code */
ROM_LOAD16_BYTE( "c71-09.ic42", 0x00000, 0x20000, CRC(10a544a2) SHA1(3b46bbd494b432d36aed3fd4b429cef074050c1d) )
ROM_LOAD16_BYTE( "c71-08.ic41", 0x00001, 0x20000, CRC(c17dc0a0) SHA1(f84e0d1afb403bb06480e8687558cd320d60099e) )
ROM_LOAD16_BYTE( "c71-10.ic40", 0x40000, 0x20000, CRC(f39c0a06) SHA1(8217f0dd855d6e15756349d47f327742ab50db15) )
ROM_LOAD16_BYTE( "c71-14.ic39", 0x40001, 0x20000, CRC(312da036) SHA1(44215c64ad9f8a4566cc9f407a7b38799a08d485) )
ROM_LOAD16_BYTE( "c71-16.ic38", 0x80000, 0x20000, CRC(1bbcc2d4) SHA1(fe664f8d2b6d902f034cf51f42378cc68c970b53) )
ROM_LOAD16_BYTE( "c71-15.ic37", 0x80001, 0x20000, CRC(df3e00bb) SHA1(9fe2ece7289945692099eba92f02e5a97a4d148c) )
ROM_REGION( 0x100000, "tc0100scn_1", 0 ) /* SCR */
ROM_LOAD16_WORD_SWAP( "c71-02.ic59", 0x000000, 0x100000, CRC(2a600c92) SHA1(38a08ade2c6fa005a402d04fabf87ff10236d4c6) )
ROM_REGION( 0x100000, "sprites", 0 ) /* OBJ */
ROM_LOAD( "c71-03.ic19", 0x000000, 0x100000, CRC(9133c605) SHA1(fa10c60cd4ca439a273c644bbf3810824a0ca523) )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* sound cpu */
ROM_LOAD( "c71-12.ic49", 0x00000, 0x10000, CRC(0038c7f8) SHA1(405def36e67949219b6f9394333278ec60ad5783) )
ROM_REGION( 0x100000, "ymsnd", 0 ) /* ADPCM samples */
ROM_LOAD( "c71-01.ic29", 0x000000, 0x100000, CRC(0e73105a) SHA1(c5c9743f68a43273e16f5e5179557f2392505a1e) )
/* no Delta-T samples */
// Pals c71-16.28 c71-07.27
ROM_END
if we notice some of the program ROMs are loaded with "ROM_LOAD16_BYTE" and every other address location ends with 1. What this is telling us is that we have 2 8-bit ROMs that are being "interleaved" together to form a single 16-bit ROM. You can think of it like each ROM is a stack of paper so it reads a page from the left stack (the "lower" ROM), then a page from the stack (the "upper" ROM) then the left, then the right, and so on. You can think of a 16-bit ROM as simply being a double-wide page, but some games used pairs of 8-bit ROMs to the same effect.
This is important because we can see that on gunfront it uses 3 pairs of interleaved ROMs , and on koshien it uses 1 pair of interleaved ROMs and then a normal 16-bit ROM. So one of the things we're going to have to do is interleave some of the gun front ROM data before we can write it to that 16-bit ROM. There are some bigger problems here though, most notably there is a gap in the koshien ROM space. The first two ROMs are 0x20000 in size meaning together they form a 0x40000 sized 16-bit ROM. But the third ROM doesn't start until 0x80000... that means there is no ROM space from 0x40000 to 0x80000 gunfront has data in this region, so that's something that will need to be fixed if this conversion is going to be possible.
The other problem here is the ADPCM (Audio Samples) ROM. gunfront uses one that's twice the size of koshien (sizes are in hex so 0x100000 is twice the size of 0x080000). Everything else seems ok as the sizes are either the same or koshien has larger ROM space that gunfront simply wont need
It's entirely possible that the PCB is already setup to fill these gaps, maybe they even use the same PCB? lets track down some photos of the hardware...
Ok, so it's not what I was hoping, clearly these are two completely different PCBs, but we can see that they do have essentially the same hardware features. The F2 hardware had some games on single board PCBs and other games with 2-board stacks that use a generic mother board and a sub-board that is game specific (That's what these are). Weirdly the game specific board is where the JAMMA edge is located but you can tell an F2 2-board version from the 3 large connectors labeled T, C, and B. gunfront was released as both a 2-board and a single board version, but I believe koshien was only ever released as a 2-board version.
Normally at this point I would perform a "virtual conversion" in MAME by renaming all of the gunfront ROM files to the names used by koshen, and then loading koshien in MAME with gunfront data to see if runs. Unfortunately the gap in the program ROM space means that's not possible (at least not without modifying the MAME source and recompiling)
I happen to already own a koshien PCB that I bought as part of an F2 bundle. so since we can't test in MAME lets test on hardware.
Attachments
Last edited: