Synthesizing a neo-geo game from scratch (ish)

I recently decided to take on a project building a neo-geo MVS cart of a rather rare game, Twinkle Star Sprites. It is possible to buy this game for cheaper on the PS2 or Dreamcast, but why hack one of those into an arcade cabinet when you already have a Neo-Geo? When I started this project the prices on MVS carts on ebay started at around $1200 and went up from there, so it seems like a worthy effort. I’m gonna buzz through the easy stuff and focus on the things I had to do that you cannot easily figure out by googling or reading the silkscreen.

First step is acquiring parts. I needed a cartrige shell, they are reproduced in whatever color you want at RetroModding. I did find that the PCBs fit a bit tight so I shaved some of the plastic tabs with a hobby knife so it was snug but not bowing out. The PCBs I determined by looking at MVS Scans and then getting the bare circuit boards from ebay. You can also compare what games used each PCB and buy a game with compatible boards and pull the ROMs yourself. I did not have enough confidence in this project to try buying cheaper games with boards that MIGHT be compatible and start hacking on them, so to give myself the best chance at this working I got the PROGBK1 and the CHA256B boards. You also need to be sure to get the right chips on your PROGBK1 board, I bought the fully populated one and pulled the bottom chip off just to be sure I would have it if I needed it as I didn’t have the complete plan for how this would work at the time I bought these parts.

The ROMs are a whole other thing, looking at the PCB silkscreen I got this:

P1, V1, V2, TC5316200

C1-C4, KM23C32000

S1, TC531000

M1, TC531001

Looking these chips up and googling for equivalents or people replacing ROMs in neo geo carts I came up with this table:

big roms
small roms

So, it looks like I just need to get some of these UV erasable EPROMs to replace the mask ROMs in this game, that won’t be that hard. Programming them, however, is a bit of a challenge. I can program the 27C101 with my TL866A, but none of the others. The 27C301 is no big deal, I just made a passive adapter swapping /OE and A16 and pretend it’s a ‘101 (this difference is between standard JEDEC pinouts and non-JEDEC and I don’t know why they laid this board out with both, it seems really dumb). The bigger 16-bit ROMs will take some more doing, and I ended up buying one of these: E2R16v2.1 – 27C400/800/160/322 programming adapter for Minipro TL866. There are a bunch out there, but GGlabs does lots of other cool stuff and I like them.

Now that I have established that I have all the parts, how do I set up the boards I just bought? The easy answer is to copy the jumper positions on MVS Scans, but that flies in the face (a little) of the documentation on the Neo Geo Development wiki. I read up on these boards and added some stuff, cleaned up some red links and made some page redirects so the information I needed was all nice and organized on the wiki. There’s still plenty to be done, but largely what I needed that wasn’t already up there has been put up there. There is still an outstanding issue for me about ROM size nomenclature, however. Some of these roms are 16 bits wide, so do you talk in terms of 16bit words? or perhaps if the rom is being used in byte mode and accessed in 8bit bytes you use that? With all this confusion do you just refer to them in bits? Sometimes I find it unclear since there’s no units and that can be frustrating.

The first questionable thing is on the CHA256B board (which is supposedly just a slightly different layout of the CHA256 board). The scan of the OEM board has jumpers J2, J3, J9, J10, J11, and J16 set. According to the wiki the combination of J9/J10 means the board is set for 4MiB (the largest) C-ROMs, J2/J3 means it uses a 128KiB M-ROM (also, the bigger of the two available configurations), but J11/J16 seems to be an invalid configuration. There isn’t a fully reverse engineered schematic of this section of the board so I can’t check it but here’s my thoughts. If the ROMs in C1/C2 are less than 4MiB then you set J15, if they are 4MiB you set J11. If the ROMs in C3/C4 are less than 4MiB then you set J16, if they are 4MiB you set J12, and so on… After checking the MAME source I can see that C3/C4 are indeed smaller than C1/C2 which makes sense why the jumper would be set differently. This game does not use C5-C8 so that also makes sense why those jumpers are just not present.

Programming these chips was as easy as finding the ROMs on the internet (this was even easier than it usually is, they were hosted somewhere halfway-legitimate) and burning them. S1 and M1 burned ok, after using my adapter to program S1. The S1 spot on the board helpfully has power and ground run so that when you put in the 32pin EPROM the /OE line is grounded and power goes to the Vcc pin, even though with the mask ROM those pins on the board aren’t connected to anything. I programmed the C-ROMs using 27C322s even for C3/C4 and just put more copies of the code in the empty space so it would simulate the mirroring of code into upper memory that would happen if smaller ROMs were installed there. To use the adapter I bought you need to split the ROMs into chunks, a friend wrote some scripts to make that easy.

The next board was easier in some ways and harder in others. The PROGBK1 has the chip enable schematics traced out, but I had some shenanigans to perform to make this one work right. Looking at the PCB on MVS Scans I moved all the jumpers and removed the un-needed bank switching chip. Now I want to understand what is actually going on so I can know which chips to install here.

stock Twinkle Star Sprites configuration

Here is the stock configuration, it uses half of the 74ls139 to decode the A21 and A22 lines to chip select lines for each of the 4 chip positions. What is of particular interest to me is the stuff going on with JV11 and JV8. JV11 sends A20 to a pin on V1, JV8 grounds that pin on V2. I know V2 is half the size of V2 so this makes some sense, but look at what the pin is labeled: A20 or /BYTE. Now when I was looking for equivalent chips I found that the 27C160 has what is known as byte mode where the contents of the chip can be read out in 8bit bytes instead of 16bit words. One of the unused data lines is used as another address line and that’s how the chip can be 1Mx16 OR 2Mx8. Looking closer at the traces on the board I can see that NO V-ROM uses all 16 data lines, so they are all operating in BYTE mode all the time. This is making me sweat a little because the 27C322 that I THOUGHT could be an equivalent for the larger rom here does not have that mode. Looking at the V-ROM page on the wiki reveals that little oversight of mine:

The TC5332204 mask ROMs have a similar pinout to the 27C322 EPROMs. The only difference is that they’re set to byte mode only: half of the data output pins are unused. Pin 30 (Q15) is used as the address lowest bit.

some of those traces don’t go anywhere…

Oops. It looks like there are no easy solutions for how to get a TC5332204 equivalent EPROM. But where did that come from, I thought these were TC5316200 ROMs? Turns out the silkscreen only covers one possible ROM that can fill that spot, MAME has a listing of the actual ROM types in the comments (differences from above in bold):

P1, TC5316200

V1, TC5332204

V2, TC5316200

C1, C2, TC5332205

C3, C4, TC538200

S1, TC531000

M1, TC531001

So how do I make this work with parts I can get? One solution I saw involved a couple 74LS245 gates to ‘make’ a byte mode for the 27C322. That seemed like a lot of work and not much fun. My next thought was to do some of my own address decoding to split the memory space of V1 into two chips. Turns out that is exactly what this board is FOR!

my new configuration

I decided that because A22 is unused (the top half of the available memory that is being decoded) then I would just remap the available 4 chips into the range of memory I care about. JV7, JV8, and JV9 now set the V1, V2, and V3 chip locations to 27C160s in BYTE mode. JV3 and JV4 now decode the memory range into chunks half the size they were before, which lets me use chips half the size (but twice as many) and all is well.

There are some differences between this memory map and the original. In the original case since A20 was not wired to v2 at all that means if you access the memory region from 0x300000 through 0x3FFFFF you get the same data that was from 0x200000 to 0x2FFFFF, what MAME calls a mirror. I checked and MAME doesn’t implement the mirror even though the original game has it, that means to me that the game will work without it. Also when accessing memory above 0x400000 you get noise (probably all 0 actually) because there are physically no chips at those locations, so when the 74ls139 enables that socket, nothing happens. The difference now is that the way I rewired it reading from 0x300000 through 0x3FFFFF gives you nothing instead of that mirror and reading from 0x400000 to 0x7FFFFF gives you a mirror of what’s on 0x000000 to 0x3FFFFF. This is because now A22 is hooked to nothing so the decoder just happily routes those requests to V1 and 2 again since it doesn’t know the requests are actually for higher addresses because the only difference is A22 going high.

In the case of this game it doesn’t matter, but for some games they use tricks where they access the same information from different locations because it’s faster in code to do that, they use the mirroring intentionally to save instructions. Also, some security checks in games check for mirroring because inexact implementations like mine can be detected by looking at higher memory that’s supposed to be empty and finding data. It would get a bit more complicated if I wanted to get around that, basically I’d add a 74ls138 that is like the 139 but uses 3 bits to decode to 4 chip locations instead of 2 bits to 4 chip locations, then I’d use A22 on that and have it route to 4 unconnected chips (I may actually do this to make a metal slug 3 cart and stack chips to give me 8 V-ROMs decoded using a 74ls138 instead of the ‘139 that’s in there).

To finish off the cart there are replacement labels available for download in various places. I use Irfanview for my images because it was nice like a decade ago and this is an old windows installation. The print dialog in that program lets you pick the image size in X and Y (or just one and preserve the aspect ratio). for my printer and the specific label it took some tweaking as I printed test pieces on regular paper but once it was just right I ran a sheet of inkjet printable photo sticker paper and cut it out. Now I only realized that the original labels are not nearly that shiny after printing it, but it’ll probably be fine.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: