Oya, I've heard of mega-ROMs
Tags: computer msx homemade-hardware
Konami made some of the best games for the MSX computer platform. Unfortunately, the market being what it is, those cartridges have become expensive collectibles rather than cheap games, which takes all the fun out of it. Before we can build a bootleg cart, we need to understand Konami’s unique mapper.
My goal for this project was to make a functional cartridge that could play Konami’s Knightmare II: The Maze of Galious. Although I think the game is interesting and ambitious, this was mostly because blog friend famiclone loved the game, and I owed him an MSX in exchange for the lovely ColecoVision and busted 48k Spectrum he sent me.
Failure to Launch
For a couple years now, I’ve wanted to play The Maze of Galious on an MSX. Galious is a side-scrolling action-adventure game with some long gameplay, multiple characters, and some fiendish puzzles. Blog friend famiclone has been really interested in it, and I wanted to see what all the fuss is about, too.
At first, I looked at the used market to see if I could buy a cartridge. The absolute lowest I’ve seen a (very worn) cartridge listed for over the years is ¥4800. In retrospect, after all this adventure, that doesn’t seem like much, but “spending fifty bucks instead of learning something” is not the name of this blog.
As you have probably inferred, the obstacle was understanding the mapping scheme in use. I’d soldered together a bunch of homebrew MSX cartridges before, but they were always a simple “bare ROM” on a pre-made board that is keyed off of slot-select. No fancy mappers, and limited to 64k at most. I certainly did not program the software on those cartridges – MSX programming is an experience I am saving for the future!
I set about trying to figure out the paging scheme in use, by piecing together MSX.org wikis and squinting at pictures of other mega-ROM boards. But everything was very confusing, and it seemed like with every step forward, I’d end up having to pull the design apart and redo it from scratch, or end up with way too many parts.
So what changed? I got talking to bsittler, a huge MSX fan, about the MSX.
When he heard about the project, blog friend bsittler sent me some Konami-style cases from Retro Game Restore that he had lying around the property. This act of generosity was the spark that motivated me to actually finish this project up enough to send it to fab. Thank you!
I made Microchip send me a sample DIP32 SST39SF040 EEPROM, which was very nice of them to provide. Thank you, too, Microchip!
For my initial run I decided to try Galious. I could also have done Metal Gear, but I only wanted to have MSX1 games on this initial cart.
Mapping for These Territories
What is a cartridge mapper, and why do we need one?
A lot of early MSX games are similar to most ColecoVision cartridges: a bare ROM on a PCB, without any fancy logic.
As cartridges got bigger, they no longer fit entirely into the Z80 CPU’s 64k of address space. Some page-switching had to be added. It’s just what it sounds like: instead of looking at a whole book’s worth of information laid out on a table all at once, we cut that information into pages, and then flip the book to look at one page at a time.
In other words, one address in the Z80 space could now point to multiple different addresses on the ROM. This was an inevitable development: anyone who knows programmers can tell you that they always need more memory (both ROM and RAM!)
Long-time readers will remember that we’ve delved into cartridge page-switching routines before, such as the explanation of how UNROM cartridges worked on the NES.
Page switching was built into the MSX standard’s design from the start. ASCII Corporation, which originated the standard, had a whole lot of programmers on staff and they got what they wanted. MSX’s basic “slot” scheme makes it easy to access two 64k cartridges while still keeping BIOS ROM and RAM available.
MSX Slot Mapping
Because the MSX came relatively late in 1983, the design of the standard benefited from seeing the limitations of other Z80-based systems. Many parts were inspired by my beloved NEC PC-6001, but ASCII picked and chose some reasonably sane choices. For our purposes at the moment, one of the more significant features of the MSX design is the slot system, which allows manufacturers to specify a huge memory map that can be “paged” in and out at runtime.
I had tried to fit the slot system into my head on many previous occasions. It is hard to go into any discussion of the MSX hardware standard without seeing words like “slot,” “mapper,” “page,” and “segment” thrown around, often interchangeably. Things made more sense once I talked to bsittler, who has had a long history tinkering with the MSX and features a near-infinite amount of patience for my dumb questions.
Here, then, are the basic rules as I understand them:
- The MSX divides the 64kB Z80 address space into four 16kB “pages.”
- Each page can choose between one of four “slots” to point to, which usually (but not always) correspond to “built in,” “cartridge slot 1,” “cartridge slot 2,” and “miscellaneous.”
- To set the pages, you write a byte to I/O port $a8 to tell it what slot to display at which page1. Page 3 ($c0000 to $ffff ) is the most significant half-nibble of that byte.
I wrote a quick example, based on my 16kB Sony HB-101, that you can play with on your own to see what I mean:
Click on slots on the left-side table in order to map them into the MSX's Z80 address space on the right.
Assign MSX Slots
Slot 0 | Slot 1 | Slot 2 | Slot 3 | |
---|---|---|---|---|
Page $C000 - $FFFF | 16k RAM | Cart Slot 1 | Cart Slot 2 | Nothing |
Page $8000 - $BFFF | Nothing | Cart Slot 1 | Cart Slot 2 | Nothing |
Page $4000 - $7FFF | Main ROM (top) | Cart Slot 1 | Cart Slot 2 | Hit-Bit Organizer |
Page $0000 - $3FFF | Main ROM (bottom) | Cart Slot 1 | Cart Slot 2 | Nothing |
Current Memory Map
Page | Mapped to... |
---|---|
Page $C000 - $FFFF | ... |
Page $8000 - $BFFF | ... |
Page $4000 - $7FFF | ... |
Page $0000 - $3FFF | ... |
Slot-Changing Instructions
The critical point I didn’t get on previous attempts was that each page can only use slots in its row. For example, on this example of the Sony HB-101, you can’t map the main ROM into high memory. I had been confused before why everything seemed to still be in the same order, despite there seemingly being a lot of flexibility in the design of an MSX-standard computer.
If you put the above example into the configuration where RAM, the BIOS ROM, and the cartridge are all assigned into the memory map at the same time (i.e. OUT ($a8), 0b00010100
), you’ll find that the lowest address available to the cartridge is $4000 . This is why MSX ROM cartridges decode their initialization code at $4000 . It’s where the MSX BIOS will look for it when it mounts the slot.
There is a “slot-expander” peripheral to further subdivide these slots if you need more space. The MSX2 has a lot of additional fancy mapper schemes built into the standard as well, but I don’t understand those yet, so we’re not going to cover those in this article.
Under the standard MSX scheme, a cartridge is split into four 16k slots, which means that your theoretical game can be a whopping 64 kilobytes without requiring any additional fancy mapping schemes, which add cost to every cartridge. That’s a huge amount of space, if you’re used to the Nintendo NROM, which limited cartridges to a measly 32k of program space.
Konami Bon Ami
Unfortunately for the MSX planners, games kept getting bigger and bigger… When Konami started making 128-kilobyte games, they had to implement an extra mapping scheme of their own.
That’s where the “MegaROM” mapper comes in: it lets you page-switch one megabit (128 kilo bytes) of cartridge ROM so that it can be fully accessed by the MSX through the 64k of slots that it makes available to the cartridge.
Under the Konami scheme, we divide the 1Mbit ROM into eight 16k segments.
Each 16k slot of the MSX cartridge’s slot space can now choose to point to one of eight 16k segments of the ROM on the cartridge. This design is very similar to that of the MSX’s own mapper!
There is just one caveat: on the early Konami mappers, the $4000 to $7fff slot is always mapped to the first segment of the ROM. This is because the MSX will look at this slot first in order to boot a cartridge, so it has to contain the boot code for the game when the MSX turns on.
Why is this fixed, then? Why not make it configurable and just default to segment zero? It’s probably because Konami would otherwise have to add logic to detect when the MSX is starting up, and reset all these registers to zero2. I’m glad they didn’t do this, because it would have made it much harder for me to implement, but more on that in a bit.
The Guts of Page Switching
Now that we know logically how things are supposed to work from the software side of the MSX, how do we actually implement a mapper in hardware?
At the most basic level, a page-switching scheme controls the upper address bits of the RAM or ROM that we want to switch. For instance, you can think of a 32k RAM chip as being four chunks of 8k, arranged in a line.
Instead of being driven directly by the CPU, we instead drive those lines from some sort of latch. When we want to look at a different chunk of the RAM, we change the latch’s settings, and it changes how it’s driving the mapped RAM/ROM’s address lines.
The Konami mapper needs a pretty fancy latch, but it’s still a part we can just get off the shelf. Let’s ditch the generalities and get down to how it specifically works..
The Magic 74LS670
Most of the homebrew MegaROM cartridges are based around the 74LS670. That part is called a “4x4 register file,” which is a very Texas Instruments name for what is basically four 4-bit latches stuck together in one teeny tiny chip.
To use the ‘670, you set two address pins (22 = 4 registers) and then can enable read or write. Enabling write sets the registers inside the chip for the given address, and enabling read expresses the content of that register on the output pins.
It’s a pretty useful part, especially when you realize that you can write to a different register than you’re reading from at the same time. You can almost think of it as a crude, very small dual-port SRAM.
Unfortunately, it’s a little harder to get these days: Digi-Key is asking over $11 for it in HCT DIP, and most varieties are simply discontinued. My supplies all came from salvage. I think it could be a cool project to try and build one of these using a PLD.
The Struggle
I had tried making one of these before, because I figured it was something simple like the UNROM mapper. Previously, I had started figuring it out from the MSX.org description of the mapper’s addresses, but I kept making very complex decode circuits.
This time around, I looked at this thread complaining about a non-working MegaROM schematic and decided to take a peek. I was surprised to find that they didn’t route A14 at all, and started to puzzle that out on paper.
Eventually, I figured out that A14 doesn’t usefully distinguish any access. Here, let me show you:
Address | Segment | A13 | A14 | A15 |
---|---|---|---|---|
$4000 | Always 0 | 0 | 1 | 0 |
$6000 | Variable | 1 | 1 | 0 |
$8000 | Variable | 0 | 0 | 1 |
$a000 | Variable | 1 | 0 | 1 |
As you can see from the table, A14 isn’t needed to decide between “paged” and “unpaged” access.
If A13 or A15 are high, then we know it’s trying to read a paged segment, and we should activate the 74LS670 to set the upper address lines to whatever it has set.
Otherwise, the ‘670 doesn’t turn on, and the upper address lines on the ROM would be left low (more on this in a second.) A14 is just not necessary to know. Once I figured this out, the penny dropped on the decoding.
Although it’s not my design, I figure it’s okay to crib from other designs as long as I’m actually learning from them.
Now that I know how it works, it would be easy to expand to a “Konami 16” mapper (for 256k games) or even something more complicated.
Arrival
In order to rough out the PCB dimensions, I measured a Gerber of another MSX cartridge using the KiCad Gerber viewer. However, I got the hole diameter slightly wrong for the case: I measured 4mm, but the cases provided were 4.5-ish mm when they arrived.
Even so, the edge connector was correct and fit properly into the system, so we can still test it!
For testing, I grabbed the closest MSX to hand: a black Sony HB-101 that I knew to have exceptionally dirty and glitchy cartridge slots. Perfect!
Unfortunately, the HB-101 didn’t want to boot my new cartridge, even after repeatedly cleaning those slots. Instead, the BIOS would just jump to the built-in Sony HitBit organizer menu every time, indicating it couldn’t read the cart, or just didn’t like what was going on there.
I decided that I would grab my copy of Tiny Slot Checker and see if anything legible was coming back from the cart.
Tiny Slot Checked
Tiny Slot Checker is a fantastic MSX utility written by Tiny Yarou, a Japanese hobbyist. Basically, it scans the MSX’s memory space and displays what it thinks is installed in each of the MSX’s slots.
Critically, for our purposes, it includes a hex viewer. My plan was to use this hex viewer to inspect the cartridge slot containing my prototype Oyanami. That way, I’d be able to see if the cartridge is able to be read at all. And if the paging scheme was wrong, I’d maybe even be able to figure out what segment of the ROM it was looking at instead of the one containing the boot code.
Tiny Slot Checker reported that slot 2 was populated. It tries to make an educated guess about the contents of the slot, and can fingerprint many games and BIOS ROMs. In this case, it had no idea what was in that slot, so it just displayed ?
.
Page 0 | Page 1 | Page 2 | Page 3 | |
---|---|---|---|---|
Slot 0 | Main (BIOS) | Main | Empty | Empty |
Slot 1 (Tiny Slot Checker) | Empty | This Tool | Empty | Empty |
Slot 2 (our cart) | Empty | ? | ? | Empty |
Slot 3 | Empty | HitBit Tools | Empty | RAM |
Every MSX cartridge must start with ASCII "AB"
($41 $42 ) in order to be identified by the BIOS as a bootable ROM. We also know that this magic string must be mounted at $4000 on the cartridge, because that’s where the MSX looks to boot a cart.
I inspected Page 1, Slot 2 of the cartridge with Tiny Slot Checker’s hex viewer. Instead of AB
, I saw $C1 $84 $21 $C1 !
I went back to my modern computer, and plugged that string into the search function in my favourite hex editor, Hex Fiend. The only place in the entire 4Mbit ROM where that byte string could be found was at the address $72000 , which means that when we accessed the ROM on the cart, A13, A16, A17, and A18 are all stuck high.
Don’t be a DIP
For starters, that meant that my DIP-switch for choosing games also wasn’t working, because it’s the only thing that controls A17 and A18 on the ROM.
Oh, did I forget to mention that DIP switch earlier? I added it when I realized that it was the same price to get a 4-megabit SST39SF040 as it is a 1-megabit SST39SF010. This way, I could put four Konami MegaROM games on the same cart, which I think everyone agrees is more.
The DIP switch is its own kind of mapper, in that it controls the A17 and A18 lines of the ROM, splitting the 4Mbit ROM into four equal 1Mbit chunks (remember again that 22 = 4.) It’s just that it’s actuated with my greasy human fingers instead of an efficient, perfect machine.
Once I checked my schematic, I realized I had wired the switch up backward. When the ROM switch is closed, it will short A17 and A18 low, defeating two 10k pullups. Unfortunately, it’s only closed when it’s “on,” which is the opposite of what you’d expect.
So that’s one bug found. I turned off the computer and flipped both DIP-switches to “ON.” If my theory was correct, I should now only see A13 and A16 high in page 1, or $12000 .
That’s not what I got. The byte string $5b , $68 , $67 , $61 was found at $1e000 – which sets A13, A14, A15 and A16. Where did A14 and A15 come from all of a sudden? Page 2 was decoding to the segment at $18000 , which shouldn’t be possible, because it’s supposed to be a fixed mapping to $00000 !
Wild Pointers Could Not Drag Me Away From Boot
Momentarily devoid of higher-order thought, I decided to power cycle the system and see if the pages moved around. If it was randomly changing, I could assume something was uninitialized or being driven by a floating pin. After letting the machine sit for awhile, I turned it back on to find that the same pages were shown in the same spots. What was going on, I asked the heavens, but they refused to bestow me with any better insights.
With my sanity returning, I decided to look at pictures of other MegaROM cartridges. I found a picture of a MegaFlashROM PCB, which stirred some memories. Surprising myself, I found a 512K Konami MegaFlashROM cartridge PCB that I had forgotten about in my MSX cartridges box. Whoops. I could’ve just built this in the first place.
With more luck, I immediately noticed that the 512K FlashMegaROM has a pretty prominent resistor network. Through the magic of datasheets and the continuity test, I determined that the FlashMegaROM cartridge is in fact pulling the segmented lines (all the high address outputs from the ‘670s) low!
It was only now that I remembered the datasheet for the ‘670 said it was tri-state: it can output true, false, or nothing at all. If I don’t select the ‘670, it doesn’t drive the output lines at all, leaving the ROM’s input address lines floating, and picking up whatever cosmic radio-frequency strangeness that also tells my cat what to do.
In other words, all the segmented address lines on my ROM were floating whenever I did an access to the “fixed” segment. You know, the segment that contains the boot code for the cart. By adding the pull-downs, those address lines are driven low by default, which keeps things consistent.
Normally, I would expect floating address pins to be completely random, but this was very consistent. My best guess is that, because Tiny Slot Checker is reading the ROM sequentially, quick enough to prevent decay of any internally latched matrix addresses, and always in the same order, there is some aspect of the ROM’s internal addressing logic that makes this fairly deterministic (if still useless.) If you have a better theory, please let me know.
I bodged a 10k onto the paged-A13 output of the 670, and suddenly I was now reading from $1c000 – A14, A15, and A16 high, but not A13. Progress!
Okay, let’s bodge ‘em all.
After some creative routing of 10ks to avoid shorts, I had wired up all four of the paged address pins. I turned on the system to see what Tiny Slot Checker would make of it, but I was surprised to see… a Konami logo3!
The MSX was booting into Salamander!
And with a quick adjustment of the DIP-switches, Galious!
Finishing Touches
There’s one thing missing, as long as you ignore the fact that the PCB doesn’t work properly out of the box: a cartridge label. Form over function, that’s what I always say.
I decided to try and get a custom sticker made, and I went to a Canadian manufacturer, Sticker Beaver. I’ve been meaning to use this shop for something for quite some time now, and I figure this was as good as a time as any.
After a lot of learning curve in Inkscape, and a little bit of back-and-forth with the proofs, I had these holographic glitter stickers cut and sent to me. Even on the free shipping plan, it only took about three business days to arrive, but it was like waiting for Christmas morning.
While I was waiting for the stickers, I had time to debug the board. Now that I knew what was wrong, I made some tweaks to the cartridge PCB. I added a resistor network to provide the pull-downs (rolling the DIP-switch resistors into it in the process,) and fixed the mounting holes. Then I reordered it from JLCPCB, this time choosing ENIG gold plating.
These new Oyanami Gold cartridges cost more money to make because of the ENIG, but I think we can all agree that they look pretty cool. And now they fit in the case!
That is, as long as you don’t want to socket your ROMs; there’s not quite enough height, a common complaint about MSX cartridges. This one is soldered down.
Maze of Galious
Ah, the part of the project where I get to play a game for five minutes! I did a quick check to make sure the game was bootable, then spent thirty minutes digging out my AV capture/splitter rig and its hydra of cables and messing with OBS to record a short clip.
Although Galious involves a lot of keyboard action (for instance, F1 to open the sub-screen menu,) all the movement, combat, and tricky platforming is easier with a d-pad. That’s where the FM2AND6 comes in:
Made by blog friend OMPeaRetro, the FM2AND6 is a familiar controller layout that’s got a new PCB inside. It offers a no-brainer setup for 2-button games on old Japanese PCs, including the MSX, and 6-button games on the FM Towns. You’ll hear more about it later, but for now it’s going to help Popolon and Aphrodite dole out the harshness.
Conclusion
This was a fun project to do! It all came together fairly quickly, thanks to the help of some smart friends. And playing these old Konami games is a lot of fun.
You can download the cartridge KiCad files for yourself from the GitHub repository. There’s also a bunch of Gerbers on the release page, which can be sent directly to fabrication.
Now if only I could reflash this cart on the fly… and load games from a host PC… and… and… and…
-
The MSX standard frowns upon programmers writing directly to that port as opposed to using the MSX-builder’s BIOS wrapper functions, as you’re not really guaranteed to have the page-switching port at that location. ↩
-
There are a couple other homemade cartridges with “universal” mappers that implement this functionality, and have a CPLD or other programmable logic in order to handle the initialization hurdles. I wanted to keep things simple for now. As you can probably sympathize, my head was already swimming with pages and segments and slots by now. ↩
-
Tiny Slot Checker is pretty clever, and will step aside at boot time if another cartridge is installed, regardless of which physical slot it’s in! Normally, the MSX will boot off of cartridge slot 1 first. It does so using a similar mechanism to the
ret
BIOS bail-out that I used when I wrote my PC-6001 cartridge loader. You can hold Shift at startup to keep it from bailing out, so that you can inspect the contents of bootable cartridges with impunity. ↩