From our previous part, we added the SRAM and tested the battery backup was working correctly. In this part, I was hoping to look into the FRAM but instead when the PCBs arrived, I started testing games, found a few that didn’t work and was able to get some to work by adding some MBC1 support via a few little detection hacks.
I was laying out the PCB, was almost done, then I looked at an actual cart and realised there was a hole in the board, this screw hole would go straight through the ROM. I didn’t want to re-layout the board having already spent hours on it but happened to notice that some clone carts had the hole at the top. After moving the CPLD a little bit, it worked out fine.
The prototype HASL PCBs arrived a little while later, they sort of fit the cart but I’ll need to move the screw hole down just a tad. At the time, I didn’t have any CR2025 SMD tabbed batteries so I just put in a through-hole coin cell holder. You might also notice that the board is quite thick; I didn’t measure the thickness and left it as 1.6mm when it’s really 0.8mm. Another little issue is that R1/R2 resistors are too close to the bottom of the board, so I’ll move them up. I brought out the clock and audio in lines to the CPLD just in case I ever wanted to play around with those.
Little problems aside, the PCB worked well, loaded up a couple games and played them without any issues so I made the little changes to the PCB and had it done with ENIG, gold fingers with a 45 degree bevel and ordered 50 of them.
Current consumption
I wanted to see how much current the cart was taking compared to other carts so I measured the current of the whole GBA – running Pokemon Silver start screen it was reading 139/141mA while regular carts were 83mA. It’s quite a bit actually but most of it is due to the CPLD (even unprogrammed ones draw 30mA!).
Just for testing, I removed the RAM side of the CPLD code and the current did drop a bit. I tried removing the latch dependency, quickly made it clock based (it didn’t work as you might have guessed) but the current still stayed the same. I happened to stumble upon an option in the Altera software which allows you to select if it should generate the circuit based on speed, balanced or area. I had it set to speed so I changed it to area and it seemed to drop just a little bit to 133mA, I’ll take any reduction I can have. The whole cart takes 50mA and the games I tested still seemed to without issues.
Adding MBC1 0x3000-3FFF reading ROM support to solve corrupted games
After testing a couple more games, I tested Super Mario Land 2 – 6 Golden Coins however when the map screen loaded, it was all corrupted. You could still load the level and that played through fine but sometimes you could end up loading the wrong stage. If you try this game on a chinese clone cart, you see the same thing, so just like I did, they must only have implemented MBC5.
SML2 runs on MBC1 and taking a look at the MBC1 specs, they looked to be pretty similar to MBC5 except that the ROM banks are accessible from 0x2000-3FFF where MBC5 is 0x2000-2FFF for the lower bank and 0x3000-3FFF for the high bit of the bank.
// 0x2000-3FFF - Low 7 bits of ROM Bank Number (Write Only) with little MBC1 support if (((inputAddress == 4'd2) || inputAddress == 4'd3) && !inputWR && inputRD && inputCE) begin
We don’t have to worry about the MBC5 high bit of the ROM bank on 0x3000-3FFF since it’s just a 2MB cart and all we need to look out for is 7 bits of the lower bank. I modified the code to be like MBC1 – look for 0x2000-3FFF and treat that as the lower bank, it worked!
Adding MBC1 switching bank 0 to bank 1 support to solve white screen
Making my way through a couple of more games when I reached Mega Man 5 (MBC1), once it loads the Nintendo logo it just white screens, odd but I kept going through the list. I decided to implement another MBC1 part, the bank switching of 0 at 0x4000 gives bank 1. It’s pretty strange because switching to bank 1 also gives bank 1 so really why would any cart ever switch to bank 0?
Well after implementing it, Mega Man 5 worked and so did some others like Duke Nukem, Game & Watch Gallery, Gameboy Gallery 2 and Turok – Rage Wars (UE).
Waiting for MBC1 bank 0 switching before enabling 0x3000-3FFF reading
After each change in the CPLD code, you basically have to re-test all the previous games that you know are working, just in case. In this case, Tony Hawk’s Pro Skater 2 (MBC5) didn’t work, it’s a a 2MB game, it would just white screen and taking out the listening address of 0x3000-3FFF made it work again, looks like it could be trying to set the high bit of the bank switching low just in case.
if (((inputAddress == 4'd2) || inputAddress == 4'd3 && mbc1Detect303FOn) && !inputWR && inputRD && inputCE) begin if (inputData == 7'd0) begin romBank <= 1'b1; mbc1Detect303FOn <= 1'b1; end
We need a way to detect whether a game is MBC1 or 5, a toggle switch on the board itself would be nice but not convenient, if we had a larger pin count CPLD we could perhaps read the MBC type if the GBA requests it (would have to check if it does) but I came up with a little hack that seems to work but could potentially break some MBC5 games. The only games I found so far that switched to bank 0 were MBC1 so why not add a little check for that, if the game switches to bank 0, we’ll start to check for the 0x3000-3FFF address.
We kind of have to hope that they will write to 0x2000-2FFFF early on otherwise it might not work. A quick test and Tony Hawk’s Pro Skater 2 along with Megaman Xtreme 2, International Karate and Dragon Ball Z – Legendary Super Warriors now work and all the existing MBC1 games I tried kept working too, a win.
Blocking access to RAM banking for MBC1 games to solve corrupted games
I was just playing Donkey Kong Land 3 (MBC1) for a bit longer than the normal 20-30 seconds when I noticed something odd on the first level, two barrels were next to each other, weird, then in another play through I bumped into the DK character and the game crashed, something’s not right. The same thing as you guessed it, happens to the chinese clone carts.
After some quick testing, if I disabled the switching of RAM banks then it worked fine. Another feature of MBC1 is that you can switch between ROM banking mode (up to 8KByte RAM, 2MByte ROM) which is the default and also RAM banking mode (up to 32KByte RAM, 512KByte ROM) at 0x6000-7FFF.
DKL3 is only a 512KByte ROM with 8KByte save so it shouldn’t ever had to switch the upper bits of the ROM or switch any RAM banks either. ROM banking mode is the default, maybe they are trying to set the upper bits of the ROM bank at 0x4000-4FFF or something else is going on but for our MBC5 it represents all the RAM banks.
// 0x6000-7FFF - ROM/RAM Mode Detection if ((inputAddress == 4'd6 || inputAddress == 4'd7) && !inputWR && inputRD && inputCE) begin mbc1Detected607F <= 1'b1; end // 0x4000-5FFF - RAM Bank Number (Write Only) if ((inputAddress == 4'd4 || inputAddress == 4'd5) && !inputWR && inputRD && inputCE) begin if ((mbc1Detect303FOn && mbc1Detected607F)) begin // Ignore RAM banking requests end else begin ramBank <= inputData[3:0]; end end
The solution is another little hack, if 0x6000-7FFF is detected and if 0x3000-3FFF is also detected, lock down the RAM banking, so the maximum is 8KBytes though that will affect the few MBC1 games that use RAM banking.
I made it so it would only lock the RAM if it detected both sorts of MBC1 because if we only detect either one and lock it down, then games like Wario Land 2 doesn’t work as that switches to bank 0 for some reason and games like Pokemon that have an RTC at 0x6000-7FFF would trip the detection too.
// 0x2000-3FFF - Low 7 bits of ROM Bank Number (Write Only) with little MBC1 detection hack if (((inputAddress == 4'd2) || inputAddress == 4'd3 && mbc1Detect303FOn) && !inputWR && inputRD && inputCE) begin if (inputData == 7'd0) begin romBank <= 1'b1; mbc1Detect303FOn <= 1'b1; end else begin if (inputData >= 7'd32) begin mbc3or5Locked <= 1'b1; end romBank <= inputData; end end // 0x4000-5FFF - RAM Bank Number (Write Only) if ((inputAddress == 4'd4 || inputAddress == 4'd5) && !inputWR && inputRD && inputCE) begin if ((mbc1Detect303FOn && mbc1Detected607F) && !mbc3or5Locked) begin // Ignore RAM banking requests end else begin ramBank <= inputData[3:0]; end end
Just in case an MBC3/5 carts somehow gets locked into MBC1 mode, I added a little solution, if a game tries to access more than 512KB of the ROM at 0x2000-3FFF we’ll lock the cart to MBC5 mode so then all RAM banks are allowed. MBC1 games shouldn’t write anything higher than 512KB (5 bits).
MBC1 implementation not quite complete
The MBC1 implementation isn’t quite complete, we don’t allow for any carts with higher than 512KB ROM or that use more than 8KB of RAM, there doesn’t seem to be that many games like that, so it will be harder to test it if works right or not, I was a bit hesitant to add support for it. Never the less, I did start working on it, just to see, the few games I quickly tried all worked. I reverted all the code and even if I didn’t do any bank switching above 512KB, they still worked, but for how long, I need a to find a game I can easily test with but for now I will skip the implementation.
I re-tested the current consumption after adding all the MBC1 code, unfortunately it looks like we are back up to 139/141mA on the Pokemon Silver start screen – 56/58mA for the cart.
Here’s how the schematic looks and here’s the Verilog CPLD code: GB MBC5-1 Hybrid v1.0 or check it out on Github: Gameboy-MBC5-MBC1-Hybrid
So I think it’s pretty much ready to be sold, just waiting for the flash chips and stencils to arrive. While I wait I’ll just test a lot more games and update the game compatibility list. I’ve set the item in the shop to coming soon – GB 2MB 128KB SRAM Flash Cart. Edit: It’s now available!
Parts:
Part 1: CPLD as the MBC and adding Flash as our ROM
Part 2: Adding the SRAM
Part 3: PCBs arrived, Adding some MBC1 support and troubleshooting a few games
Part 4: Adding Multi-game support
Part 5: Using 32KB FRAM and Adding MBC1 2MB ROM Support