rlm@1: #include "gbGlobals.h" rlm@1: #include "gbMemory.h" rlm@1: #include "../common/System.h" rlm@1: #include "../common/movie.h" rlm@1: rlm@1: mapperMBC1 gbDataMBC1 = { rlm@1: 0, // RAM enable rlm@1: 1, // ROM bank rlm@1: 0, // RAM bank rlm@1: 0, // memory model rlm@1: 0, // ROM high address rlm@1: 0 // RAM address rlm@1: }; rlm@1: rlm@1: // MBC1 ROM write registers rlm@1: void mapperMBC1ROM(u16 address, u8 value) rlm@1: { rlm@1: int tmpAddress = 0; rlm@1: rlm@1: switch (address & 0x6000) rlm@1: { rlm@1: case 0x0000: // RAM enable register rlm@1: gbDataMBC1.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); rlm@1: break; rlm@1: case 0x2000: // ROM bank select rlm@1: // value = value & 0x1f; rlm@1: if (value == 0) rlm@1: value = 1; rlm@1: if (value == gbDataMBC1.mapperROMBank) rlm@1: break; rlm@1: rlm@1: tmpAddress = value << 14; rlm@1: rlm@1: // check current model rlm@1: if (gbDataMBC1.mapperMemoryModel == 0) rlm@1: { rlm@1: // model is 16/8, so we have a high address in use rlm@1: tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; rlm@1: } rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbDataMBC1.mapperROMBank = value; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: break; rlm@1: case 0x4000: // RAM bank select rlm@1: if (gbDataMBC1.mapperMemoryModel == 1) rlm@1: { rlm@1: // 4/32 model, RAM bank switching provided rlm@1: value = value & 0x03; rlm@1: if (value == gbDataMBC1.mapperRAMBank) rlm@1: break; rlm@1: tmpAddress = value << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: gbMemoryMap[0x0a] = &gbRam[tmpAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; rlm@1: gbDataMBC1.mapperRAMBank = value; rlm@1: gbDataMBC1.mapperRAMAddress = tmpAddress; rlm@1: } rlm@1: else rlm@1: { rlm@1: // 16/8, set the high address rlm@1: gbDataMBC1.mapperROMHighAddress = value & 0x03; rlm@1: tmpAddress = gbDataMBC1.mapperROMBank << 14; rlm@1: tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: } rlm@1: break; rlm@1: case 0x6000: // memory model select rlm@1: gbDataMBC1.mapperMemoryModel = value & 1; rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: // MBC1 RAM write rlm@1: void mapperMBC1RAM(u16 address, u8 value) rlm@1: { rlm@1: if (gbDataMBC1.mapperRAMEnable) rlm@1: { rlm@1: if (gbRamSize) rlm@1: { rlm@1: gbWriteMemoryQuick(address, value); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void memoryUpdateMapMBC1() rlm@1: { rlm@1: int tmpAddress = gbDataMBC1.mapperROMBank << 14; rlm@1: rlm@1: // check current model rlm@1: if (gbDataMBC1.mapperMemoryModel == 1) rlm@1: { rlm@1: // model is 16/8, so we have a high address in use rlm@1: tmpAddress |= (gbDataMBC1.mapperROMHighAddress) << 19; rlm@1: } rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: rlm@1: if (gbRamSize) rlm@1: { rlm@1: gbMemoryMap[0x0a] = &gbRam[gbDataMBC1.mapperRAMAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[gbDataMBC1.mapperRAMAddress + 0x1000]; rlm@1: } rlm@1: } rlm@1: rlm@1: mapperMBC2 gbDataMBC2 = { rlm@1: 0, // RAM enable rlm@1: 1 // ROM bank rlm@1: }; rlm@1: rlm@1: // MBC2 ROM write registers rlm@1: void mapperMBC2ROM(u16 address, u8 value) rlm@1: { rlm@1: switch (address & 0x6000) rlm@1: { rlm@1: case 0x0000: // RAM enable rlm@1: if (!(address & 0x0100)) rlm@1: { rlm@1: gbDataMBC2.mapperRAMEnable = (value & 0x0f) == 0x0a; rlm@1: } rlm@1: break; rlm@1: case 0x2000: // ROM bank select rlm@1: if (address & 0x0100) rlm@1: { rlm@1: value &= 0x0f; rlm@1: rlm@1: if (value == 0) rlm@1: value = 1; rlm@1: if (gbDataMBC2.mapperROMBank != value) rlm@1: { rlm@1: gbDataMBC2.mapperROMBank = value; rlm@1: rlm@1: int tmpAddress = value << 14; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: } rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: // MBC2 RAM write rlm@1: void mapperMBC2RAM(u16 address, u8 value) rlm@1: { rlm@1: if (gbDataMBC2.mapperRAMEnable) rlm@1: { rlm@1: if (gbRamSize && address < 0xa200) rlm@1: { rlm@1: gbWriteMemoryQuick(address, value); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void memoryUpdateMapMBC2() rlm@1: { rlm@1: int tmpAddress = gbDataMBC2.mapperROMBank << 14; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: } rlm@1: rlm@1: mapperMBC3 gbDataMBC3 = { rlm@1: 0, // RAM enable rlm@1: 1, // ROM bank rlm@1: 0, // RAM bank rlm@1: 0, // RAM address rlm@1: 0, // timer clock latch rlm@1: 0, // timer clock register rlm@1: 0, // timer seconds rlm@1: 0, // timer minutes rlm@1: 0, // timer hours rlm@1: 0, // timer days rlm@1: 0, // timer control rlm@1: 0, // timer latched seconds rlm@1: 0, // timer latched minutes rlm@1: 0, // timer latched hours rlm@1: 0, // timer latched days rlm@1: 0, // timer latched control rlm@1: (time_t)-1 // last time rlm@1: }; rlm@1: rlm@1: void memoryUpdateMBC3Clock() rlm@1: { rlm@1: time_t now; rlm@1: rlm@1: if (VBAMovieActive() || VBAMovieLoading()) rlm@1: now = (time_t)(VBAMovieGetId() + VBAMovieGetFrameCounter()/60); /// FIXME: is /60 the right factor? rlm@1: else rlm@1: now = time(NULL); rlm@1: rlm@1: time_t diff = now - gbDataMBC3.mapperLastTime; rlm@1: if (diff > 0) rlm@1: { rlm@1: // update the clock according to the last update time rlm@1: gbDataMBC3.mapperSeconds += (int)(diff % 60); rlm@1: if (gbDataMBC3.mapperSeconds > 59) rlm@1: { rlm@1: gbDataMBC3.mapperSeconds -= 60; rlm@1: gbDataMBC3.mapperMinutes++; rlm@1: } rlm@1: rlm@1: diff /= 60; rlm@1: rlm@1: gbDataMBC3.mapperMinutes += (int)(diff % 60); rlm@1: if (gbDataMBC3.mapperMinutes > 60) rlm@1: { rlm@1: gbDataMBC3.mapperMinutes -= 60; rlm@1: gbDataMBC3.mapperHours++; rlm@1: } rlm@1: rlm@1: diff /= 60; rlm@1: rlm@1: gbDataMBC3.mapperHours += (int)(diff % 24); rlm@1: if (gbDataMBC3.mapperHours > 24) rlm@1: { rlm@1: gbDataMBC3.mapperHours -= 24; rlm@1: gbDataMBC3.mapperDays++; rlm@1: } rlm@1: diff /= 24; rlm@1: rlm@1: gbDataMBC3.mapperDays += (int)diff; rlm@1: if (gbDataMBC3.mapperDays > 255) rlm@1: { rlm@1: if (gbDataMBC3.mapperDays > 511) rlm@1: { rlm@1: gbDataMBC3.mapperDays %= 512; rlm@1: gbDataMBC3.mapperControl |= 0x80; rlm@1: } rlm@1: gbDataMBC3.mapperControl = (gbDataMBC3.mapperControl & 0xfe) | rlm@1: (gbDataMBC3.mapperDays > 255 ? 1 : 0); rlm@1: } rlm@1: } rlm@1: gbDataMBC3.mapperLastTime = now; rlm@1: } rlm@1: rlm@1: // MBC3 ROM write registers rlm@1: void mapperMBC3ROM(u16 address, u8 value) rlm@1: { rlm@1: int tmpAddress = 0; rlm@1: rlm@1: switch (address & 0x6000) rlm@1: { rlm@1: case 0x0000: // RAM enable register rlm@1: gbDataMBC3.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); rlm@1: break; rlm@1: case 0x2000: // ROM bank select rlm@1: value = value & 0x7f; rlm@1: if (value == 0) rlm@1: value = 1; rlm@1: if (value == gbDataMBC3.mapperROMBank) rlm@1: break; rlm@1: rlm@1: tmpAddress = value << 14; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbDataMBC3.mapperROMBank = value; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: rlm@1: break; rlm@1: case 0x4000: // RAM bank select rlm@1: if (value < 8) rlm@1: { rlm@1: if (value == gbDataMBC3.mapperRAMBank) rlm@1: break; rlm@1: tmpAddress = value << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: gbMemoryMap[0x0a] = &gbRam[tmpAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; rlm@1: gbDataMBC3.mapperRAMBank = value; rlm@1: gbDataMBC3.mapperRAMAddress = tmpAddress; rlm@1: } rlm@1: else rlm@1: { rlm@1: if (gbDataMBC3.mapperRAMEnable) rlm@1: { rlm@1: gbDataMBC3.mapperRAMBank = -1; rlm@1: rlm@1: gbDataMBC3.mapperClockRegister = value; rlm@1: } rlm@1: } rlm@1: break; rlm@1: case 0x6000: // clock latch rlm@1: if (gbDataMBC3.mapperClockLatch == 0 && value == 1) rlm@1: { rlm@1: memoryUpdateMBC3Clock(); rlm@1: gbDataMBC3.mapperLSeconds = gbDataMBC3.mapperSeconds; rlm@1: gbDataMBC3.mapperLMinutes = gbDataMBC3.mapperMinutes; rlm@1: gbDataMBC3.mapperLHours = gbDataMBC3.mapperHours; rlm@1: gbDataMBC3.mapperLDays = gbDataMBC3.mapperDays; rlm@1: gbDataMBC3.mapperLControl = gbDataMBC3.mapperControl; rlm@1: } rlm@1: if (value == 0x00 || value == 0x01) rlm@1: gbDataMBC3.mapperClockLatch = value; rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: // MBC3 RAM write rlm@1: void mapperMBC3RAM(u16 address, u8 value) rlm@1: { rlm@1: if (gbDataMBC3.mapperRAMEnable) rlm@1: { rlm@1: if (gbDataMBC3.mapperRAMBank != -1) rlm@1: { rlm@1: if (gbRamSize) rlm@1: { rlm@1: gbWriteMemoryQuick(address, value); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: time_t tmp; //Small kludge to get it working on some 64 bit systems. rlm@1: if (VBAMovieActive() || VBAMovieLoading()) rlm@1: gbDataMBC3.mapperLastTime = VBAMovieGetId() + VBAMovieGetFrameCounter()/60; rlm@1: else { rlm@1: time(&tmp); rlm@1: gbDataMBC3.mapperLastTime=(u32)tmp; rlm@1: } rlm@1: systemScreenMessage(ctime(&tmp), 4); rlm@1: gbDataMBC3.mapperLastTime=(u32)tmp; rlm@1: rlm@1: switch (gbDataMBC3.mapperClockRegister) rlm@1: { rlm@1: case 0x08: rlm@1: gbDataMBC3.mapperSeconds = value; rlm@1: break; rlm@1: case 0x09: rlm@1: gbDataMBC3.mapperMinutes = value; rlm@1: break; rlm@1: case 0x0a: rlm@1: gbDataMBC3.mapperHours = value; rlm@1: break; rlm@1: case 0x0b: rlm@1: gbDataMBC3.mapperDays = value; rlm@1: break; rlm@1: case 0x0c: rlm@1: if (gbDataMBC3.mapperControl & 0x80) rlm@1: gbDataMBC3.mapperControl = 0x80 | value; rlm@1: else rlm@1: gbDataMBC3.mapperControl = value; rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: // MBC3 read RAM rlm@1: u8 mapperMBC3ReadRAM(u16 address) rlm@1: { rlm@1: if (gbDataMBC3.mapperRAMEnable) rlm@1: { rlm@1: if (gbDataMBC3.mapperRAMBank != -1) rlm@1: { rlm@1: return gbReadMemoryQuick(address); rlm@1: } rlm@1: rlm@1: switch (gbDataMBC3.mapperClockRegister) rlm@1: { rlm@1: case 0x08: rlm@1: return gbDataMBC3.mapperLSeconds; rlm@1: break; rlm@1: case 0x09: rlm@1: return gbDataMBC3.mapperLMinutes; rlm@1: break; rlm@1: case 0x0a: rlm@1: return gbDataMBC3.mapperLHours; rlm@1: break; rlm@1: case 0x0b: rlm@1: return gbDataMBC3.mapperLDays; rlm@1: break; rlm@1: case 0x0c: rlm@1: return gbDataMBC3.mapperLControl; rlm@1: } rlm@1: } rlm@1: return 0; rlm@1: } rlm@1: rlm@1: void memoryUpdateMapMBC3() rlm@1: { rlm@1: int tmpAddress = gbDataMBC3.mapperROMBank << 14; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: rlm@1: if (gbDataMBC3.mapperRAMBank >= 0 && gbRamSize) rlm@1: { rlm@1: tmpAddress = gbDataMBC3.mapperRAMBank << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: gbMemoryMap[0x0a] = &gbRam[tmpAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; rlm@1: } rlm@1: } rlm@1: rlm@1: mapperMBC5 gbDataMBC5 = { rlm@1: 0, // RAM enable rlm@1: 1, // ROM bank rlm@1: 0, // RAM bank rlm@1: 0, // ROM high address rlm@1: 0, // RAM address rlm@1: 0 // is rumble cartridge? rlm@1: }; rlm@1: rlm@1: // MBC5 ROM write registers rlm@1: void mapperMBC5ROM(u16 address, u8 value) rlm@1: { rlm@1: int tmpAddress = 0; rlm@1: rlm@1: switch (address & 0x6000) rlm@1: { rlm@1: case 0x0000: // RAM enable register rlm@1: gbDataMBC5.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); rlm@1: break; rlm@1: case 0x2000: // ROM bank select rlm@1: if (address < 0x3000) rlm@1: { rlm@1: value = value & 0xff; rlm@1: if (value == gbDataMBC5.mapperROMBank) rlm@1: break; rlm@1: rlm@1: tmpAddress = (value << 14) | (gbDataMBC5.mapperROMHighAddress << 22) ; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbDataMBC5.mapperROMBank = value; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: } rlm@1: else rlm@1: { rlm@1: value = value & 1; rlm@1: if (value == gbDataMBC5.mapperROMHighAddress) rlm@1: break; rlm@1: rlm@1: tmpAddress = (gbDataMBC5.mapperROMBank << 14) | (value << 22); rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbDataMBC5.mapperROMHighAddress = value; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: } rlm@1: break; rlm@1: case 0x4000: // RAM bank select rlm@1: if (gbDataMBC5.isRumbleCartridge) rlm@1: value &= 0x07; rlm@1: else rlm@1: value &= 0x0f; rlm@1: if (value == gbDataMBC5.mapperRAMBank) rlm@1: break; rlm@1: tmpAddress = value << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: if (gbRamSize) rlm@1: { rlm@1: gbMemoryMap[0x0a] = &gbRam[tmpAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; rlm@1: rlm@1: gbDataMBC5.mapperRAMBank = value; rlm@1: gbDataMBC5.mapperRAMAddress = tmpAddress; rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: // MBC5 RAM write rlm@1: void mapperMBC5RAM(u16 address, u8 value) rlm@1: { rlm@1: if (gbDataMBC5.mapperRAMEnable) rlm@1: { rlm@1: if (gbRamSize) rlm@1: { rlm@1: gbWriteMemoryQuick(address, value); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void memoryUpdateMapMBC5() rlm@1: { rlm@1: int tmpAddress = (gbDataMBC5.mapperROMBank << 14) | rlm@1: (gbDataMBC5.mapperROMHighAddress << 22) ; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: rlm@1: if (gbRamSize) rlm@1: { rlm@1: tmpAddress = gbDataMBC5.mapperRAMBank << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: gbMemoryMap[0x0a] = &gbRam[tmpAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; rlm@1: } rlm@1: } rlm@1: rlm@1: mapperMBC7 gbDataMBC7 = { rlm@1: 0, // RAM enable rlm@1: 1, // ROM bank rlm@1: 0, // RAM bank rlm@1: 0, // RAM address rlm@1: 0, // chip select rlm@1: 0, // ?? rlm@1: 0, // mapper state rlm@1: 0, // buffer for receiving serial data rlm@1: 0, // idle state rlm@1: 0, // count of bits received rlm@1: 0, // command received rlm@1: 0, // address received rlm@1: 0, // write enable rlm@1: 0, // value to return on ram rlm@1: }; rlm@1: rlm@1: // MBC7 ROM write registers rlm@1: void mapperMBC7ROM(u16 address, u8 value) rlm@1: { rlm@1: int tmpAddress = 0; rlm@1: rlm@1: switch (address & 0x6000) rlm@1: { rlm@1: case 0x0000: rlm@1: break; rlm@1: case 0x2000: // ROM bank select rlm@1: value = value & 0x7f; rlm@1: if (value == 0) rlm@1: value = 1; rlm@1: rlm@1: if (value == gbDataMBC7.mapperROMBank) rlm@1: break; rlm@1: rlm@1: tmpAddress = (value << 14); rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbDataMBC7.mapperROMBank = value; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: break; rlm@1: case 0x4000: // RAM bank select/enable rlm@1: if (value < 8) rlm@1: { rlm@1: tmpAddress = (value&3) << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: gbMemoryMap[0x0a] = &gbMemory[0xa000]; rlm@1: gbMemoryMap[0x0b] = &gbMemory[0xb000]; rlm@1: rlm@1: gbDataMBC7.mapperRAMBank = value; rlm@1: gbDataMBC7.mapperRAMAddress = tmpAddress; rlm@1: gbDataMBC7.mapperRAMEnable = 0; rlm@1: } rlm@1: else rlm@1: { rlm@1: gbDataMBC7.mapperRAMEnable = 0; rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: // MBC7 read RAM rlm@1: u8 mapperMBC7ReadRAM(u16 address) rlm@1: { rlm@1: switch (address & 0xa0f0) rlm@1: { rlm@1: case 0xa000: rlm@1: case 0xa010: rlm@1: case 0xa060: rlm@1: case 0xa070: rlm@1: return 0; rlm@1: case 0xa020: rlm@1: // sensor X low byte rlm@1: return systemGetSensorX() & 255; rlm@1: case 0xa030: rlm@1: // sensor X high byte rlm@1: return systemGetSensorX() >> 8; rlm@1: case 0xa040: rlm@1: // sensor Y low byte rlm@1: return systemGetSensorY() & 255; rlm@1: case 0xa050: rlm@1: // sensor Y high byte rlm@1: return systemGetSensorY() >> 8; rlm@1: case 0xa080: rlm@1: return gbDataMBC7.value; rlm@1: } rlm@1: return 0xff; rlm@1: } rlm@1: rlm@1: // MBC7 RAM write rlm@1: void mapperMBC7RAM(u16 address, u8 value) rlm@1: { rlm@1: if (address == 0xa080) rlm@1: { rlm@1: // special processing needed rlm@1: int oldCs = gbDataMBC7.cs, oldSk = gbDataMBC7.sk; rlm@1: rlm@1: gbDataMBC7.cs = value>>7; rlm@1: gbDataMBC7.sk = (value>>6)&1; rlm@1: rlm@1: if (!oldCs && gbDataMBC7.cs) rlm@1: { rlm@1: if (gbDataMBC7.state == 5) rlm@1: { rlm@1: if (gbDataMBC7.writeEnable) rlm@1: { rlm@1: gbWriteMemoryQuick(0xa000+gbDataMBC7.address*2, gbDataMBC7.buffer>>8); rlm@1: gbWriteMemoryQuick(0xa000+gbDataMBC7.address*2+1, gbDataMBC7.buffer&0xff); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: } rlm@1: gbDataMBC7.state = 0; rlm@1: gbDataMBC7.value = 1; rlm@1: } rlm@1: else rlm@1: { rlm@1: gbDataMBC7.idle = true; rlm@1: gbDataMBC7.state = 0; rlm@1: } rlm@1: } rlm@1: rlm@1: if (!oldSk && gbDataMBC7.sk) rlm@1: { rlm@1: if (gbDataMBC7.idle) rlm@1: { rlm@1: if (value & 0x02) rlm@1: { rlm@1: gbDataMBC7.idle = false; rlm@1: gbDataMBC7.count = 0; rlm@1: gbDataMBC7.state = 1; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: switch (gbDataMBC7.state) rlm@1: { rlm@1: case 1: rlm@1: // receiving command rlm@1: gbDataMBC7.buffer <<= 1; rlm@1: gbDataMBC7.buffer |= (value & 0x02) ? 1 : 0; rlm@1: gbDataMBC7.count++; rlm@1: if (gbDataMBC7.count == 2) rlm@1: { rlm@1: // finished receiving command rlm@1: gbDataMBC7.state = 2; rlm@1: gbDataMBC7.count = 0; rlm@1: gbDataMBC7.code = gbDataMBC7.buffer & 3; rlm@1: } rlm@1: break; rlm@1: case 2: rlm@1: // receive address rlm@1: gbDataMBC7.buffer <<= 1; rlm@1: gbDataMBC7.buffer |= (value&0x02) ? 1 : 0; rlm@1: gbDataMBC7.count++; rlm@1: if (gbDataMBC7.count == 8) rlm@1: { rlm@1: // finish receiving rlm@1: gbDataMBC7.state = 3; rlm@1: gbDataMBC7.count = 0; rlm@1: gbDataMBC7.address = gbDataMBC7.buffer&0xff; rlm@1: if (gbDataMBC7.code == 0) rlm@1: { rlm@1: if ((gbDataMBC7.address>>6) == 0) rlm@1: { rlm@1: gbDataMBC7.writeEnable = 0; rlm@1: gbDataMBC7.state = 0; rlm@1: } rlm@1: else if ((gbDataMBC7.address>>6) == 3) rlm@1: { rlm@1: gbDataMBC7.writeEnable = 1; rlm@1: gbDataMBC7.state = 0; rlm@1: } rlm@1: } rlm@1: } rlm@1: break; rlm@1: case 3: rlm@1: gbDataMBC7.buffer <<= 1; rlm@1: gbDataMBC7.buffer |= (value&0x02) ? 1 : 0; rlm@1: gbDataMBC7.count++; rlm@1: rlm@1: switch (gbDataMBC7.code) rlm@1: { rlm@1: case 0: rlm@1: if (gbDataMBC7.count == 16) rlm@1: { rlm@1: if ((gbDataMBC7.address>>6) == 0) rlm@1: { rlm@1: gbDataMBC7.writeEnable = 0; rlm@1: gbDataMBC7.state = 0; rlm@1: } rlm@1: else if ((gbDataMBC7.address>>6) == 1) rlm@1: { rlm@1: if (gbDataMBC7.writeEnable) rlm@1: { rlm@1: for (int i = 0; i < 256; i++) rlm@1: { rlm@1: gbWriteMemoryQuick(0xa000+i*2, gbDataMBC7.buffer >> 8); rlm@1: gbWriteMemoryQuick(0xa000+i*2+1, gbDataMBC7.buffer & 0xff); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: } rlm@1: } rlm@1: gbDataMBC7.state = 5; rlm@1: } rlm@1: else if ((gbDataMBC7.address>>6) == 2) rlm@1: { rlm@1: if (gbDataMBC7.writeEnable) rlm@1: { rlm@1: for (int i = 0; i < 256; i++) rlm@1: WRITE16LE((u16 *)&gbMemory[0xa000+i*2], 0xffff); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: } rlm@1: gbDataMBC7.state = 5; rlm@1: } rlm@1: else if ((gbDataMBC7.address>>6) == 3) rlm@1: { rlm@1: gbDataMBC7.writeEnable = 1; rlm@1: gbDataMBC7.state = 0; rlm@1: } rlm@1: gbDataMBC7.count = 0; rlm@1: } rlm@1: break; rlm@1: case 1: rlm@1: if (gbDataMBC7.count == 16) rlm@1: { rlm@1: gbDataMBC7.count = 0; rlm@1: gbDataMBC7.state = 5; rlm@1: gbDataMBC7.value = 0; rlm@1: } rlm@1: break; rlm@1: case 2: rlm@1: if (gbDataMBC7.count == 1) rlm@1: { rlm@1: gbDataMBC7.state = 4; rlm@1: gbDataMBC7.count = 0; rlm@1: gbDataMBC7.buffer = (gbReadMemoryQuick(0xa000+gbDataMBC7.address*2)<<8)| rlm@1: (gbReadMemoryQuick(0xa000+gbDataMBC7.address*2+1)); rlm@1: } rlm@1: break; rlm@1: case 3: rlm@1: if (gbDataMBC7.count == 16) rlm@1: { rlm@1: gbDataMBC7.count = 0; rlm@1: gbDataMBC7.state = 5; rlm@1: gbDataMBC7.value = 0; rlm@1: gbDataMBC7.buffer = 0xffff; rlm@1: } rlm@1: break; rlm@1: } rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: if (oldSk && !gbDataMBC7.sk) rlm@1: { rlm@1: if (gbDataMBC7.state == 4) rlm@1: { rlm@1: gbDataMBC7.value = (gbDataMBC7.buffer & 0x8000) ? 1 : 0; rlm@1: gbDataMBC7.buffer <<= 1; rlm@1: gbDataMBC7.count++; rlm@1: if (gbDataMBC7.count == 16) rlm@1: { rlm@1: gbDataMBC7.count = 0; rlm@1: gbDataMBC7.state = 0; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void memoryUpdateMapMBC7() rlm@1: { rlm@1: int tmpAddress = (gbDataMBC5.mapperROMBank << 14); rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: } rlm@1: rlm@1: mapperHuC1 gbDataHuC1 = { rlm@1: 0, // RAM enable rlm@1: 1, // ROM bank rlm@1: 0, // RAM bank rlm@1: 0, // memory model rlm@1: 0, // ROM high address rlm@1: 0 // RAM address rlm@1: }; rlm@1: rlm@1: // HuC1 ROM write registers rlm@1: void mapperHuC1ROM(u16 address, u8 value) rlm@1: { rlm@1: int tmpAddress = 0; rlm@1: rlm@1: switch (address & 0x6000) rlm@1: { rlm@1: case 0x0000: // RAM enable register rlm@1: gbDataHuC1.mapperRAMEnable = ((value & 0x0a) == 0x0a ? 1 : 0); rlm@1: break; rlm@1: case 0x2000: // ROM bank select rlm@1: value = value & 0x3f; rlm@1: if (value == 0) rlm@1: value = 1; rlm@1: if (value == gbDataHuC1.mapperROMBank) rlm@1: break; rlm@1: rlm@1: tmpAddress = value << 14; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbDataHuC1.mapperROMBank = value; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: break; rlm@1: case 0x4000: // RAM bank select rlm@1: if (gbDataHuC1.mapperMemoryModel == 1) rlm@1: { rlm@1: // 4/32 model, RAM bank switching provided rlm@1: value = value & 0x03; rlm@1: if (value == gbDataHuC1.mapperRAMBank) rlm@1: break; rlm@1: tmpAddress = value << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: gbMemoryMap[0x0a] = &gbRam[tmpAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; rlm@1: gbDataHuC1.mapperRAMBank = value; rlm@1: gbDataHuC1.mapperRAMAddress = tmpAddress; rlm@1: } rlm@1: else rlm@1: { rlm@1: // 16/8, set the high address rlm@1: gbDataHuC1.mapperROMHighAddress = value & 0x03; rlm@1: tmpAddress = gbDataHuC1.mapperROMBank << 14; rlm@1: tmpAddress |= (gbDataHuC1.mapperROMHighAddress) << 19; rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: } rlm@1: break; rlm@1: case 0x6000: // memory model select rlm@1: gbDataHuC1.mapperMemoryModel = value & 1; rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: // HuC1 RAM write rlm@1: void mapperHuC1RAM(u16 address, u8 value) rlm@1: { rlm@1: if (gbDataHuC1.mapperRAMEnable) rlm@1: { rlm@1: if (gbRamSize) rlm@1: { rlm@1: gbWriteMemoryQuick(address, value); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void memoryUpdateMapHuC1() rlm@1: { rlm@1: int tmpAddress = gbDataHuC1.mapperROMBank << 14; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: rlm@1: if (gbRamSize) rlm@1: { rlm@1: tmpAddress = gbDataHuC1.mapperRAMBank << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: gbMemoryMap[0x0a] = &gbRam[tmpAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; rlm@1: } rlm@1: } rlm@1: rlm@1: mapperHuC3 gbDataHuC3 = { rlm@1: 0, // RAM enable rlm@1: 1, // ROM bank rlm@1: 0, // RAM bank rlm@1: 0, // RAM address rlm@1: 0, // RAM flag rlm@1: 0 // RAM read value rlm@1: }; rlm@1: rlm@1: // HuC3 ROM write registers rlm@1: void mapperHuC3ROM(u16 address, u8 value) rlm@1: { rlm@1: int tmpAddress = 0; rlm@1: rlm@1: switch (address & 0x6000) rlm@1: { rlm@1: case 0x0000: // RAM enable register rlm@1: gbDataHuC3.mapperRAMEnable = (value == 0x0a ? 1 : 0); rlm@1: gbDataHuC3.mapperRAMFlag = value; rlm@1: if (gbDataHuC3.mapperRAMFlag != 0x0a) rlm@1: gbDataHuC3.mapperRAMBank = -1; rlm@1: break; rlm@1: case 0x2000: // ROM bank select rlm@1: value = value & 0x7f; rlm@1: if (value == 0) rlm@1: value = 1; rlm@1: if (value == gbDataHuC3.mapperROMBank) rlm@1: break; rlm@1: rlm@1: tmpAddress = value << 14; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbDataHuC3.mapperROMBank = value; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: break; rlm@1: case 0x4000: // RAM bank select rlm@1: value = value & 0x03; rlm@1: if (value == gbDataHuC3.mapperRAMBank) rlm@1: break; rlm@1: tmpAddress = value << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: gbMemoryMap[0x0a] = &gbRam[tmpAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; rlm@1: gbDataHuC3.mapperRAMBank = value; rlm@1: gbDataHuC3.mapperRAMAddress = tmpAddress; rlm@1: break; rlm@1: case 0x6000: // nothing to do! rlm@1: break; rlm@1: } rlm@1: } rlm@1: rlm@1: // HuC3 read RAM rlm@1: u8 mapperHuC3ReadRAM(u16 address) rlm@1: { rlm@1: if (gbDataHuC3.mapperRAMFlag > 0x0b && rlm@1: gbDataHuC3.mapperRAMFlag < 0x0e) rlm@1: { rlm@1: if (gbDataHuC3.mapperRAMFlag != 0x0c) rlm@1: return 1; rlm@1: return gbDataHuC3.mapperRAMValue; rlm@1: } rlm@1: else rlm@1: return gbReadMemoryQuick(address); rlm@1: } rlm@1: rlm@1: // HuC3 RAM write rlm@1: void mapperHuC3RAM(u16 address, u8 value) rlm@1: { rlm@1: int32 *p; rlm@1: rlm@1: if (gbDataHuC3.mapperRAMFlag < 0x0b || rlm@1: gbDataHuC3.mapperRAMFlag > 0x0e) rlm@1: { rlm@1: if (gbDataHuC3.mapperRAMEnable) rlm@1: { rlm@1: if (gbRamSize) rlm@1: { rlm@1: gbWriteMemoryQuick(address, value); rlm@1: systemSaveUpdateCounter = SYSTEM_SAVE_UPDATED; rlm@1: } rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: if (gbDataHuC3.mapperRAMFlag == 0x0b) rlm@1: { rlm@1: if (value == 0x62) rlm@1: { rlm@1: gbDataHuC3.mapperRAMValue = 1; rlm@1: } rlm@1: else rlm@1: { rlm@1: switch (value & 0xf0) rlm@1: { rlm@1: case 0x10: rlm@1: p = &gbDataHuC3.mapperRegister2; rlm@1: gbDataHuC3.mapperRAMValue = *(p+gbDataHuC3.mapperRegister1++); rlm@1: if (gbDataHuC3.mapperRegister1 > 6) rlm@1: gbDataHuC3.mapperRegister1 = 0; rlm@1: break; rlm@1: case 0x30: rlm@1: p = &gbDataHuC3.mapperRegister2; rlm@1: *(p+gbDataHuC3.mapperRegister1++) = value & 0x0f; rlm@1: if (gbDataHuC3.mapperRegister1 > 6) rlm@1: gbDataHuC3.mapperRegister1 = 0; rlm@1: gbDataHuC3.mapperAddress = rlm@1: (gbDataHuC3.mapperRegister6 << 24) | rlm@1: (gbDataHuC3.mapperRegister5 << 16) | rlm@1: (gbDataHuC3.mapperRegister4 << 8) | rlm@1: (gbDataHuC3.mapperRegister3 << 4) | rlm@1: (gbDataHuC3.mapperRegister2); rlm@1: break; rlm@1: case 0x40: rlm@1: gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0xf0) | rlm@1: (value & 0x0f); rlm@1: gbDataHuC3.mapperRegister2 = (gbDataHuC3.mapperAddress & 0x0f); rlm@1: gbDataHuC3.mapperRegister3 = ((gbDataHuC3.mapperAddress>>4)&0x0f); rlm@1: gbDataHuC3.mapperRegister4 = ((gbDataHuC3.mapperAddress>>8)&0x0f); rlm@1: gbDataHuC3.mapperRegister5 = ((gbDataHuC3.mapperAddress>>16)&0x0f); rlm@1: gbDataHuC3.mapperRegister6 = ((gbDataHuC3.mapperAddress>>24)&0x0f); rlm@1: gbDataHuC3.mapperRegister7 = 0; rlm@1: gbDataHuC3.mapperRegister8 = 0; rlm@1: gbDataHuC3.mapperRAMValue = 0; rlm@1: break; rlm@1: case 0x50: rlm@1: gbDataHuC3.mapperRegister1 = (gbDataHuC3.mapperRegister1 & 0x0f) | rlm@1: ((value << 4)&0x0f); rlm@1: break; rlm@1: default: rlm@1: gbDataHuC3.mapperRAMValue = 1; rlm@1: break; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void memoryUpdateMapHuC3() rlm@1: { rlm@1: int tmpAddress = gbDataHuC3.mapperROMBank << 14; rlm@1: rlm@1: tmpAddress &= gbRomSizeMask; rlm@1: gbMemoryMap[0x04] = &gbRom[tmpAddress]; rlm@1: gbMemoryMap[0x05] = &gbRom[tmpAddress + 0x1000]; rlm@1: gbMemoryMap[0x06] = &gbRom[tmpAddress + 0x2000]; rlm@1: gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000]; rlm@1: rlm@1: if (gbRamSize) rlm@1: { rlm@1: tmpAddress = gbDataHuC3.mapperRAMBank << 13; rlm@1: tmpAddress &= gbRamSizeMask; rlm@1: gbMemoryMap[0x0a] = &gbRam[tmpAddress]; rlm@1: gbMemoryMap[0x0b] = &gbRam[tmpAddress + 0x1000]; rlm@1: } rlm@1: } rlm@1: