Sunteți pe pagina 1din 8

codeslinger.co.

uk
H o mB e a s Zi u c k sM o e g a D r M i a v e s /t G e re n S e y s Cs i ht s ie Bpm l 8 o Gamebo y g

codeslinger.co.uk
Gamebo y - Ro m and Ram Banking.

Detecting Rom Bank Mode:


There are two types o f ROM banking that I have emulated, MBC1 and MBC2. The majo rity o f the games (8 0 %) are MBC1 so to have a decent emulato r this is a must to emulate. So me games like Tetris and Bubble Gho st do nt use ROM banking at all. They just lo ad the entire game into memo ry regio n 0 x0 0 x8 0 0 0 and never need to swap memo ry in and o ut. To detect what ROM mo de the game is yo u have to read memo ry 0 x147 after the game has been lo aded into memo ry. If 0 x147 is 0 then the game has no memo ry banking (like tetris), ho wever if it is 1,2 o r 3 then it is MBC1 and if it is 5 o r 6 then it is MBC2. This gives the fo llo wing co de:

Gameboy Emulation:
Getting Started The Hardware Memory Control and Map ROM and RAM Banking The Timers Interupts LCD DMA Transfer Graphic Emulation Joypad Emulation Opcode Examples PDFmyURL.com

m_MBC1 = false ; m_MBC2 = false ; switch (m_CartridgeMemory[0x147]) { case 1 : m_MBC1 = true ; break case 2 : m_MBC1 = true ; break case 3 : m_MBC1 = true ; break case 5 : m_MBC2 = true ; break case 6 : m_MBC2 = true ; break

case 6 : m_MBC2 = true ; break default : break ; }

Finished Product

We also need a variable declaratio n to specify which ROM bank is currently lo aded into internal memo ry address 0 x40 0 0 -0 x7FFF. As ROM Bank 0 is fixed into memo ry address 0 x0 -0 x3FFF this variable sho uld never be 0 , it sho uld be at least 1. We need to initialize this variable o n emulato r lo ad to 1. m_CurrentROMBank = 1 ; // this is type BYTE

Detecting RAM Banking:


Cartridge memo ry address 0 x148 tells ho w much RAM banks the game has. The maximum is 4. The size o f 1 RAM bank is 0 x20 0 0 bytes so if we have an array o f size 0 x8 0 0 0 this is eno ugh space fo r all the RAM banks. Like ROM banking we also need a variable to po int at which RAM bank the game is using between values o f 0 -3. This gives us the fo llo wing declaratio ns.

BYTE m_RAMBanks[0x8000] ; BYTE m_CurrentRAMBank ;

We then need to initialize these like so : memset(&m_RAMBanks,0,sizeof(m_RAMBanks) ; m_CurrentRAMBank=0;

RAM Banking is no t use d in MBC2! T he re f o re m _Curre nt RAMBank will always be 0 !

Controlling reading from ROM and RAM:


As stated in the sectio n called Memo ry Co ntro l and Map we need to co ntro l Reading and Writing to the internal memo ry. The main reaso n to co ntro l the reading is to make sure everything reads fro m the co rrect ROM and RAM banks. This will give us the fo llo wing functio n:

// read memory should never modify member variables hence const BYTE Emulator::ReadMemory(WORD address) const { // are we reading from the rom memory bank?
PDFmyURL.com

if ((address>=0x4000) && (address <= 0x7FFF)) { WORD newAddress = address - 0x4000 ; return m_CartridgeMemory[newAddress + (m_CurrentROMBank*0x4000)] ; } // are we reading from ram memory bank? else if ((address >= 0xA000) && (address <= 0xBFFF)) { WORD newAddress = address - 0xA000 ; return m_RAMBanks[newAddress + (m_CurrentRAMBank*0x2000)] ; } // else return memory return m_Rom[address] ; }

That was actually pretty easy wasn't it? Ho pefully no w yo u can see why yo u must ALWAYS yo u ReadMemo ry and WriteMemo ry when accessing internal gamebo y memo ry

Changing the current ROM and RAM Banks:


No w we kno w ho w to read fro m the co rrect memo ry banks but ho w do es the game request the banks to be changed? In my o pinio n this is o ne o f the mo st difficult parts o f the gamebo y emulatio n. It isnt difficult to co de but it is difficult to make sense o f what yo u have to do . The way it wo rks is the gamebo y attempts to write directy to ROM but o ur WriteMemo ry functio n will trap it and decypher why it is trying to write to ROM. Depending o n the memo ry address o f where it is trying to write to ROM we need to take different actio n. If the address is between 0 x20 0 0 -0 x40 0 0 then it is a ROM bank change. If the address is 0 x40 0 0 -0 x6 0 0 0 then it is a RAM bank change o r a ROM bank change depending o n what current ROM/RAM mo de is selected (explained in a minute). If the value is between 0 x0 -0 x20 0 0 then it enables RAM bank writing (also explained in a minute). We can no w change the ROM part o f o ur WriteMemo ry functio n to this:

void Emulator::WriteMemory(WORD address, BYTE data) { if (address < 0x8000) { HandleBanking(address,data) ;


PDFmyURL.com

} else if ((address >= 0xA000) && (address < 0xC000)) { if (m_EnableRAM) { WORD newAddress = address - 0xA000 ; m_RAMBanks[newAddress + (m_CurrentRAMBank*0x2000)] = data ; } } // the rest of this function carries on as before } ///////////////////////////////////////////////////////////////// void Emulator::HandleBanking(WORD address, BYTE data) { // do RAM enabling if (address < 0x2000) { if (m_MBC1 || m_MBC2) { DoRamBankEnable(address,data) ; } } // do ROM bank change else if ((address >= 0x200) && (address < 0x4000)) { if (m_MBC1 || m_MBC2) { DoChangeLoROMBank(data) ; } } // do ROM or RAM bank change else if ((address >= 0x4000) && (address < 0x6000)) {
PDFmyURL.com

// there is no rambank in mbc2 so always use rambank 0 if (m_MBC1) { if(m_ROMBanking) { DoChangeHiRomBank(data) ; } else { DoRAMBankChange(data) ; } } } // this will change whether we are doing ROM banking // or RAM banking with the above if statement else if ((address >= 0x6000) && (address < 0x8000)) { if (m_MBC1) DoChangeROMRAMMode(data) ; } }

Read o n fo r a full explanatio n o f what the abo ve co de means

Enabling RAM:
In o rder to write to RAM banks the game must specifically request that ram bank writing is enabled. It do es this by attempting to write to internal ROM address between 0 and 0 x20 0 0 . Fo r MBC1 if the lo wer nibble o f the data the game is writing to memo ry is 0 xA then ram bank writing is enabled else if the lo wer nibble is 0 then ram bank writing is disabled. MBC2 is exactly the same except there is an additio nal clause that bit 4 o f the address byte must be 0 . This gives the fo llo wing functio n:

void Emulator::DoRAMBankEnable(WORD address, BYTE data) { if (m_MBC2) {


PDFmyURL.com

if (TestBit(address,4) == 1) return ; } BYTE testData = data & 0xF ; if (testData == 0xA) m_EnableRAM = true ; else if (testData == 0x0) m_EnableRAM = false ; }

Changing ROM Banks Part 1:


If the memo ry bank is MBC1 then there is two parts to changing the current ro m bank. The first way is if the game writes to memo ry address 0 x20 0 0 -0 x3FFF then it changes the lo wer 5 bits o f the current ro m bank but no t bits 5 and 6 . The seco nd way is writing to memo ry address 0 x40 0 0 -0 x5FFF during ro mbanking mo de (explained later) which o nly changes bits 5 and 6 no t bits 0 -4. So co mbining these two metho ds yo u can change bits 0 -6 o f which ro m bank is currently in use. Ho wever if the game is using MBC2 then this is much easier. If the game writes to address 0 x20 0 0 -0 x3FFF then the current ram bank changes bits 0 -3 and bits 5-6 are never set. This means writing to address 0 x40 0 0 -0 x5FFF in MBC2 mo de do es no thing. This sectio n explains what happens when the game writes to memo ry address 0 x20 0 0 -0 x3FFF.

void Emulator::DoChangeLoROMBank(BYTE data) { if (m_MBC2) { m_CurrentROMBank = data & 0xF ; if (m_CurrentROMBank == 0) m_CurrentROMBank++ ; return ; } BYTE lower5 = data & 31 ; m_CurrentROMBank &= 224; // turn off the lower 5 m_CurrentROMBank |= lower5 ; if (m_CurrentROMBank == 0) m_CurrentROMBank++ ; }

So if we're using MBC2 then the current ro m bank beco mes the lo wer nibble o f data. Ho wever if we are
PDFmyURL.com

using MBC1 then we must set the lo wer 5 bits o f current ro m bank to the lo wer 5 bits o f data whilst keeping the upper 3 bits the same. Yo u may be wo ndering why I increment m_CurrentROMBank if it is set to 0 . The reaso n is that ro m bank 0 is static and can always be fo und in memo ry address 0 x0 0 0 -0 x40 0 0 so ro m bank 0 sho uld never be lo aded into memo ry 0 x40 0 0 -0 x8 0 0 0 . If m_CurrentROMBank is ever set to 0 then it is treated as ro mbank 1 so ro mbank 1 o r greater will reside in the bank regio n 0 x40 0 0 0 x8 0 0 0 .

Changing ROM Banks Part 2:


As just stated there are two ways to change the current ro m bank in MBC1 mo de. This sho ws ho w to change the bits 5 and 6 when writing to memo ry address 0 x40 0 0 -0 x6 0 0 0 and m_Ro mBanking is true (explained later)

void Emulator::DoChangeHiRomBank(BYTE data) { // turn off the upper 3 bits of the current rom m_CurrentROMBank &= 31 ; // turn off the lower 5 bits of the data data &= 224 ; m_CurrentROMBank |= data ; if (m_CurrentROMBank == 0) m_CurrentROMBank++ ; }

Changing RAM Banks:


Yo u canno t change RAM Banks in MBC2 as that has external ram o n the cartridge. To change RAM Banks in MBC1 the game must again write to memo ry address 0 x40 0 0 -0 x6 0 0 0 but this time m_Ro mBanking must be false (explained later). The current ram bank gets set to the lo wer 2 bits o f the data like so :

void Emulator::DoRAMBankChange(BYTE data) { m_CurrentRAMBank = data & 0x3 ; }

Selecting either ROM or RAM banking mode:


Finally the last part o f this banking maratho n is this m_Ro mBanking I keep go ing o n abo ut. This variable
PDFmyURL.com

is respo nsible fo r ho w to act when the game writes to memo ry address 0 x40 0 0 -0 x6 0 0 0 . This variable defaults to true but is changes during MBC1 mo de when the game writes to memo ry address 0 x6 0 0 0 0 x8 0 0 0 . If the least significant bit o f the data being written to this address range is 0 then m_Ro mBanking is set to true, o therwise it is set to false meaning there is abo ut to be a ram bank change. It is impo rtant to set m_CurrentRAMBank to 0 whenever yo u set m_Ro mBanking to true because the gamebo y can o nly use rambank 0 in this mo de.

void Emulator::DoChangeROMRAMMode(BYTE data) { BYTE newData = data & 0x1 ; m_RomBanking = (newData == 0)?true:false ; if (m_RomBanking) m_CurrentRAMBank = 0 ; }

That is the end o f the banking sectio n. Next is The Timers sectio n which is easier than this!

Copyright 2008 codeslinger.co.uk

PDFmyURL.com

S-ar putea să vă placă și