void CPU::WriteByte(ushort address, uchar data) { // writing to cartridge ROM; swaps ROM banks if (address < 0x8000) { cartridge->WriteToMemory(address, data); } // writing to cartridge RAM else if (address >= 0xA000 && address < 0xC000) { ushort adjustedAddress = address - 0xA000; cartridge->WriteToRAM(adjustedAddress, data); } // writing to ECHO; also write to RAM else if (address >= 0xE000 && address < 0xFE00) { memory->WriteByte(address, data); memory->WriteByte(address - 0x2000, data); } // restricted else if (address >= 0xFEA0 && address < 0xFEFF) { // do nothing } // writing to TMC else if (address == TMC) { memory->WriteByte(address, data); SetClockFrequency(); } // writing to DIV else if (address == 0xFF04) { memory->WriteByte(address, 0); } // writing to scanline register else if (address == 0xFF44) { memory->WriteByte(address, 0); } // writing to DMA trigger else if (address == 0xff46) { DMATransfer(data); } else { memory->WriteByte(address, data); } }
void MMU::WriteByte(unsigned _int16 address, uint8 value){ switch (address & 0xF000){ //TODO: support for (MBC5), not that its used much anyway case 0x0000: case 0x1000: switch (type){ //(MBC1)Enable RAM Bank if XXXX1010_2 (0x0A) is written, disable if anything else is written //(MBC2)Toggle cart RAM if the LSB of the upper address byte is 0 and same test as MBC1 case MBC2: if ((address & 0x10u) > 0){ break; }//if 0, just fall through //(MBC3)Same as MBC1, also enables read/writes to clock registers on cart case MBC1: case MBC3: case MBC5: if ((value & 0xFu) == 0xAu) ramWriteEnable = true; else ramWriteEnable = false; break; } break; case 0x2000: //(MBC5)Lower 8 bits of ROM bank number //(MBC5)Unlike others, writing 0 actually gives rom bank 0 if (type == MBC5){ currentROMBank &= ~(0xFF); currentROMBank |= (value); } case 0x3000: switch (type){ //(MBC1)Switch bank to XXXBBBBB_2, where X=don't care (0x00-0x1F) //(MBC1)Values of B=1 and B=0 are functionally equivalent, bank#0 is accessible from 0x0000-0x3FFF //(MBC1)Values of 0x20, 0x40, and 0x60 will result in 0x21, 0x41, 0x61 respectively case MBC1: currentROMBank &= 0xE0u; //set lower 5 bits to 0; currentROMBank |= (value & 0x1F); if (currentROMBank == 0 || currentROMBank == 0x20u || currentROMBank == 0x40u || currentRAMBank == 0x60u) currentROMBank++; std::cout << std::hex << "Switch to " << currentROMBank << std::endl; break; //(MBC2)Switch ROM bank to XXXXBBBB_2, where X=don't care //(MBC2)Address must have the LSB of the upper address byte = 1 (X1XX,X3XX,X5XX,etc.) case MBC2: currentROMBank &= 0xF0u; currentROMBank |= (value & 0xFu); if (currentROMBank == 0) currentROMBank++; break; //(MBC3)Writing a value of XBBBBBBB_2 selects the appropriate ROM bank (value of 0 is a value of 1 again) case MBC3: currentROMBank &= 0x80u; currentROMBank |= (value & 0x7Fu); if (currentROMBank == 0) currentROMBank++; break; //(MBC5) Write the MSB (bit 9) of the rom bank from the LSB of value case MBC5: currentROMBank &= ~(0x100u); currentROMBank |= (value & 0x01u); } break; case 0x4000: case 0x5000: switch (type){ //(MBC1)If in 4/32 Mode, switch RAM bank XXXXXXBB_2 (0x00-0x03) //(MBC1)If in 16/8 Mode, set the two most significant ROM address lines to XXXXXXBB_2 (Bits 5 and 6) case MBC1: if (type == romSwitch){ currentROMBank &= 0x1Fu; //turn off bits 5 and 6 currentROMBank |= ((value & 0x03) << 5); if (currentROMBank == 0 || currentROMBank == 0x20u || currentROMBank == 0x40u || currentRAMBank == 0x60u) currentROMBank++; std::cout << std::hex << "Switch to " << currentROMBank << std::endl; } else{ //RAM switching currentRAMBank = (value & 0x03u); } case MBC2: break; //(MBC3)If a value of 0x00-0x03 is written, select that RAM bank //(MBC3)If a value of 0x08-0x0C is written, select that RTC register case MBC3: if (value <= 0x03u){ currentRAMBank = value & 0x03u; } else if (value >= 0x08u && value <= 0x0cu){ currentRTCRegister = getRTCReg(value); } case MBC5: currentRAMBank = (value & 0x0Fu); } break; case 0x6000: case 0x7000: switch (type){ //(MBC1)Switch to memory mode specified by XXXXXXXB_2, where X= don't care //(MBC1)B=0 -> 16Mb ROM/8Kb RAM, B=1 -> 4Mb ROM/32Kb RAM case MBC1: if ((value & 0x01u) == 0){ mode = romSwitch; } else{ mode = ramSwitch; currentRAMBank = 0; //no ram switching } case MBC5: case MBC2: break; //(MBC3)Latch clock data if 0x00 then 0x01 is written (write current time to RTC registers) case MBC3: if (value == 0x00u){ RTCLatchPossible = true; } if (RTCLatchPossible && (value == 0x01u)){ //TODO: RTC Latch here RTCLatchPossible = false; } } break; case 0x8000: case 0x9000: vram[address & 0x1FFFu] = value; break; case 0xA000: case 0xB000: if (eram == nullptr) break; //(MBC2) only addressable from 0xA000 to 0xA1FF //(MBC2) only write lower 4 bits of value (512 x 4bit values) if (!ramWriteEnable) break; if (type == MBC2){ if (address <= 0xA1FFu){ eram[address & 0x1FFFu] = value & 0x0001u; } } else eram[address & 0x1FFFu] = value; break; case 0xC000: case 0xD000: case 0xE000: wram[address & 0x1FFFu] = value; break; case 0xF000: switch (address & 0x0F00u) { // Echo RAM case 0x000: case 0x100: case 0x200: case 0x300: case 0x400: case 0x500: case 0x600: case 0x700: case 0x800: case 0x900: case 0xA00: case 0xB00: case 0xC00: case 0xD00: wram[address & 0x1FFFu] = value; break; // OAM case 0xE00: if ((address & 0xFF)<0xA0) //anything after A0 should be 0s oam[address & 0xFFu] = value; break; // Zeropage RAM, I/O case 0xF00: if (address > 0xFF7F) zram[address & 0x7Fu] = value; else{ if (address == 0xFF00u){ //change which column of keys we are looking at keyColumn = value & 0x30u; } else if (address == 0xFF04u){ //writes to the DIV register reset the DIV timer io[0x04] = 0; } else if (address == 0xFF07){ uint8 currentTMC = io[0x07]; uint8 newTMC = value; io[0x07] = value; if ((currentTMC & 0x03) != (newTMC & 0x03)){ //clock frequency has changed, so reset the counter for it switch (newTMC & 0x03){ case 0x0u: c->timerPeriod = 1024; break; case 0x1u: c->timerPeriod = 16; break; case 0x2u: c->timerPeriod = 64; break; case 0x3u: c->timerPeriod = 256; break; } } } else if (address == 0xFF44){ io[0x44] = 0; } else if (address == 0xFF46){ DMATransfer(value); } else{ io[address & 0x7Fu] = value; } } } break; } }