Fixing ROMs for EMS 64 GB Smart Card USB

Discussion of programming and development for the original Game Boy and Game Boy Color.
Post Reply
Great Hierophant
Posts: 780
Joined: Tue Nov 23, 2004 9:35 pm

Fixing ROMs for EMS 64 GB Smart Card USB

Post by Great Hierophant »

I have an EMS 64 GB Smart Card USB, and while almost all Gameboy & Gameboy Color games work in it, there are a few that do not. The list is here:

Super Mario Land 2 (see BF)
Megaman V (blank screen)
Who Framed Roger Rabbit (garbled copyright screen, resets)
Gargoyle's Quest (see BF)
Donkey Kong Land 3 (blank screen)
Game & Watch Gallery (wrong music, graphical garbage, resetting)
Asteroids & Missile Command (mostly blank screen, random lines)
Kung Fu Master
Pyrmaids of Ra
RoboCop v. the Terminator (see BF)
SeaQuest DSV (see BF)
Spiderman and the X-Men: Arcade's Revenge (see BF)
Gauntlet II (garbled initial screen)
Pokemon Red/Blue (garbled "Ed" tile in name select screen)

I can only think of three reasons why these games would not work:
1. Improper Bankswitch Emulation in the cart
2. Flash is too slow
3. Cart's setup conflicts with Game code

The Bung Fixes solve the Super Mario Land 2 problem (garbled map screen) and makes Gargoyle's Quest, (blank screen), SeaQuest (garbled screen) Spider-Man & X-Men (ditto) & RoboCop v. Terminator (ditto). It improves Who Framed Roger Rabbit (first copyright screen visible, will go no further) but not Pyramids or Kung Fu Master. However, the Fixes only change one string starting with EA 00 (other than the global checksum). What does this do and how can I improve and fix the other ROMs?
Last edited by Great Hierophant on Sun Dec 06, 2009 9:50 am, edited 3 times in total.
User avatar
kyuusaku
Posts: 1665
Joined: Mon Sep 27, 2004 2:13 pm

Post by kyuusaku »

1.
Great Hierophant
Posts: 780
Joined: Tue Nov 23, 2004 9:35 pm

Post by Great Hierophant »

kyuusaku wrote:1.
That would make sense. I would suggest that the Card is emulating an MCB5, which can cause some difficulty for older games. If an MCB1-3 game writes to somewhere in the 3000-3FFF range to switch banks, it may likely end up with something very different that what it expects. How does one figure out which bytes are used for bankswitching?
User avatar
kyuusaku
Posts: 1665
Joined: Mon Sep 27, 2004 2:13 pm

Post by kyuusaku »

You'd have to put breakpoints on MBC writes, determine what write breaks what, then fix it.
Great Hierophant
Posts: 780
Joined: Tue Nov 23, 2004 9:35 pm

Post by Great Hierophant »

Or if the Game uses a value greater than what the MBC originally would have expected, then it may change to a random bank.
Great Hierophant
Posts: 780
Joined: Tue Nov 23, 2004 9:35 pm

Post by Great Hierophant »

I can confirm that it is the MBC that is causing the trouble here. In every case, if you switch the 0x147 from an MBC1/2/3 type to an MCB5 type and play them in an emulator like bgb, you will encounter the exact same problems with each ROM as on the Gameboy.

Now on MBC5, there are three instances where the problem can occur:
1. Game writes to 3000-3FFF to perform a bankswitch
2. Game writes a 00 value to perform a bankswitch, seeking to select bank 1 on an MBC1/2/3, but selects bank 0 on an MBC5.
3. Game writes a value greater than 1F (MBC1), F (MBC2), 7F (MBC3) to switch a bank on MBC5, the upper bits selecting some random bank.

In many cases, it seems like number #2 is occuring. The Bung Fixes are supposed to address #1, and if they cannot do so alone, then one must adjust for #2.
User avatar
Dwedit
Posts: 4921
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

Zelda Oracles uses mirrored banks, so I doubt it's number 3.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
User avatar
MottZilla
Posts: 2837
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

If it's the bank switching numbering you should be able to do a minor ASM hack to fix the number on the fly. You just need to find the mapper writes and patch them so if the write is going to be zero to write 1 instead. Shouldn't be hard at all.
Great Hierophant
Posts: 780
Joined: Tue Nov 23, 2004 9:35 pm

Post by Great Hierophant »

This is where I need help. A typical bankswitch command is sometimes as simple as

Code: Select all

ld (2100), a
where register a contains the number of the bank to which the program wants to access. In these cases, a contains 00 and the MBC1/2/3 understands that to switch to bank 1 while the MCB5 will switch to bank 0.

My trouble is trying to figure out where previously in the code the program set register a to 00 and how to tell it to write a 01 without breaking anything else. Also, I would need to figure out all instances where this would occur.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Great Hierophant wrote:My trouble is trying to figure out where previously in the code the program set register a to 00 and how to tell it to write a 01 without breaking anything else.
Instead of worrying about what happened before, it would be much easier to replace the actual write by a call to a subroutine, which you'll place wherever you can. In this routine you can modify the value as desired and then write it. Just save and restore whatever flags or registers you mess with and you should be OK.
Also, I would need to figure out all instances where this would occur.
I don't know much about the GB scene, but there's an emulator with good debugging capabilities you can just trap all writes to the registers in question so you know where they happen. You can also search the ROM for the 2 bytes that represent the address of the register and check if each instance of it is actually a bankswitch command, and replace by the call to the subroutine.
User avatar
MottZilla
Posts: 2837
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

This is exactly what you want to do. I'm not particularly good with Z80 type ASM since I have rarely been involved with it but you should be able to replace the actual write opcode to the register with a JSR type command to some free space in the Fixed ROM bank. All you need here is to check the contents of the value to be written for being 0 which should probably be easily determined by a CMP or perhaps just a BNE type command so that you can load the value with 1 if it was 0 and do nothing if it was not 0 and then do the write you replaced with the JSR followed by a RTS.

Again I'm not experienced with Z80 type ASM so I can't really be specific. But it really should't be that hard to do. Not unless the fixed bank is jam packed and you have no free rom space.
User avatar
tokumaru
Posts: 12427
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

I don't know much Z80 either, but from what I've read "ld (2100), a" can easily be replaced by "call XXXX" (XXXX is the location you found to place your subroutine), because both instructions occupy the same amount of bytes (3).

Then, if all you need is turn 0's into 1's, the routine can be something like this (note that I never coded Z80 before, so I don't know if this is the best way to do it or if it works at all):

Code: Select all

	push af ;save the flags and a
	cp 0 ;compare a to 0
	jr nz, skip ;skip if not equal
	inc a ;correct the value
skip:
	ld (2100), a ;switch the bank
	pop af ;restore the flags and a
	ret ;return
User avatar
Dwedit
Posts: 4921
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

Pretty much correct, except people would usually use a one byte flag update instruction (like OR A or AND A) instead of CP 0.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
Great Hierophant
Posts: 780
Joined: Tue Nov 23, 2004 9:35 pm

Post by Great Hierophant »

tokumaru wrote:I don't know much Z80 either, but from what I've read "ld (2100), a" can easily be replaced by "call XXXX" (XXXX is the location you found to place your subroutine), because both instructions occupy the same amount of bytes (3).

Then, if all you need is turn 0's into 1's, the routine can be something like this (note that I never coded Z80 before, so I don't know if this is the best way to do it or if it works at all):

Code: Select all

	push af ;save the flags and a
	cp 0 ;compare a to 0
	jr nz, skip ;skip if not equal
	inc a ;correct the value
skip:
	ld (2100), a ;switch the bank
	pop af ;restore the flags and a
	ret ;return
This code will fix the problems in:
Megaman V
Game & Watch Gallery
Pokemon Red/Blue
Kung Fu Master
Pyrmaids of Ra
Asteroids & Missile Command
Last edited by Great Hierophant on Tue Dec 08, 2009 9:30 pm, edited 3 times in total.
User avatar
MottZilla
Posts: 2837
Joined: Wed Dec 06, 2006 8:18 pm

Post by MottZilla »

So are you asking a question or telling us you did that and it fixed those? I'm not sure what you are saying exactly.
Post Reply