From 649f96b6174cd2f18095861a1d3e7ab6011e69f8 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Thu, 26 Mar 2020 09:39:44 -0400 Subject: [PATCH] GBHawk: start C++ifying mappers --- libHawk/GBHawk/GBHawk/Core.h | 10 +- libHawk/GBHawk/GBHawk/GBHawk.vcxproj | 18 + libHawk/GBHawk/GBHawk/Mapper_Base.h | 83 ++++ libHawk/GBHawk/GBHawk/Mapper_Camera.h | 167 +++++++ libHawk/GBHawk/GBHawk/Mapper_Default.h | 87 ++++ libHawk/GBHawk/GBHawk/Mapper_HuC1.h | 197 +++++++++ libHawk/GBHawk/GBHawk/Mapper_HuC3.h | 311 +++++++++++++ libHawk/GBHawk/GBHawk/Mapper_MBC1.h | 203 +++++++++ libHawk/GBHawk/GBHawk/Mapper_MBC1_Multi.h | 199 +++++++++ libHawk/GBHawk/GBHawk/Mapper_MBC2.h | 124 ++++++ libHawk/GBHawk/GBHawk/Mapper_MBC3.h | 295 +++++++++++++ libHawk/GBHawk/GBHawk/Mapper_MBC5.h | 167 +++++++ libHawk/GBHawk/GBHawk/Mapper_MBC6.h | 87 ++++ libHawk/GBHawk/GBHawk/Mapper_MBC7.h | 488 +++++++++++++++++++++ libHawk/GBHawk/GBHawk/Mapper_MMM01.h | 87 ++++ libHawk/GBHawk/GBHawk/Mapper_RockMan8.h | 96 ++++ libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC1.h | 190 ++++++++ libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC2.h | 226 ++++++++++ libHawk/GBHawk/GBHawk/Mapper_TAMA5.h | 292 ++++++++++++ libHawk/GBHawk/GBHawk/Mapper_WisdomTree.h | 81 ++++ libHawk/GBHawk/GBHawk/Memory.h | 2 + 21 files changed, 3402 insertions(+), 8 deletions(-) create mode 100644 libHawk/GBHawk/GBHawk/Mapper_Base.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_Camera.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_Default.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_HuC1.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_HuC3.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_MBC1.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_MBC1_Multi.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_MBC2.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_MBC3.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_MBC5.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_MBC6.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_MBC7.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_MMM01.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_RockMan8.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC1.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC2.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_TAMA5.h create mode 100644 libHawk/GBHawk/GBHawk/Mapper_WisdomTree.h diff --git a/libHawk/GBHawk/GBHawk/Core.h b/libHawk/GBHawk/GBHawk/Core.h index c03d4118ef..ccaebb7377 100644 --- a/libHawk/GBHawk/GBHawk/Core.h +++ b/libHawk/GBHawk/GBHawk/Core.h @@ -9,6 +9,7 @@ #include "Memory.h" #include "Timer.h" #include "SerialPort.h" +#include "Mapper_Base.h" namespace GBHawk { @@ -51,8 +52,6 @@ namespace GBHawk psg.is_GBC = &MemMap.is_GBC; psg.double_speed = &MemMap.double_speed; psg.timer_div_reg = &timer.divider_reg; - - sl_case = 0; }; PPU ppu; @@ -61,8 +60,7 @@ namespace GBHawk MemoryManager MemMap; Timer timer; SerialPort serialport; - - uint8_t sl_case = 0; + Mapper mapper; void Load_BIOS(uint8_t* bios, bool GBC_console) { @@ -121,8 +119,6 @@ namespace GBHawk saver = cpu.SaveState(saver); saver = psg.SaveState(saver); saver = MemMap.SaveState(saver); - - *saver = sl_case; saver++; } void LoadState(uint8_t* loader) @@ -131,8 +127,6 @@ namespace GBHawk loader = cpu.LoadState(loader); loader = psg.LoadState(loader); loader = MemMap.LoadState(loader); - - sl_case = *loader; loader++; } #pragma endregion diff --git a/libHawk/GBHawk/GBHawk/GBHawk.vcxproj b/libHawk/GBHawk/GBHawk/GBHawk.vcxproj index e0a6fa1e09..bcadc24fba 100644 --- a/libHawk/GBHawk/GBHawk/GBHawk.vcxproj +++ b/libHawk/GBHawk/GBHawk/GBHawk.vcxproj @@ -157,6 +157,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/libHawk/GBHawk/GBHawk/Mapper_Base.h b/libHawk/GBHawk/GBHawk/Mapper_Base.h new file mode 100644 index 0000000000..1f4fac5e2a --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_Base.h @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +using namespace std; + +namespace GBHawk +{ + class MemoryManager; + + class Mapper + { + public: + + Mapper() + { + + } + + uint32_t* + + virtual uint8_t ReadMemory(uint32_t addr) + { + return 0; + } + + virtual uint8_t PeekMemory(uint32_t addr) + { + return 0; + } + + virtual void WriteMemory(uint32_t addr, uint8_t value) + { + } + + virtual void PokeMemory(uint32_t addr, uint8_t value) + { + } + + virtual uint8_t* SaveState(uint8_t* saver) + { + return nullptr; + } + + virtual uint8_t* LoadState(uint8_t* loader) + { + return nullptr; + } + + virtual void Dispose() + { + } + + virtual void Reset() + { + } + + virtual void Mapper_Tick() + { + } + + virtual void RTC_Get(int value, int index) + { + } + /* + virtual void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + } + + protected void SetCDLROM(LR35902.eCDLogMemFlags flags, int cdladdr) + { + Core.SetCDL(flags, "ROM", cdladdr); + } + + protected void SetCDLRAM(LR35902.eCDLogMemFlags flags, int cdladdr) + { + Core.SetCDL(flags, "CartRAM", cdladdr); + } + */ + + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_Camera.h b/libHawk/GBHawk/GBHawk/Mapper_Camera.h new file mode 100644 index 0000000000..67f618ff51 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_Camera.h @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_Camera : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t RAM_bank; + bool RAM_enable; + uint32_t ROM_mask; + uint32_t RAM_mask; + bool regs_enable; + uint8_t regs[0x80] = {}; + + void Reset() + { + ROM_bank = 1; + RAM_bank = 0; + RAM_enable = false; + ROM_mask = Core._rom.Length / 0x4000 - 1; + + RAM_mask = Core.cart_RAM.Length / 0x2000 - 1; + + regs_enable = false; + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + return Core._rom[addr]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + if (regs_enable) + { + if ((addr & 0x7F) == 0) + { + return 0;// regs[0]; + } + else + { + return 0; + } + } + else + { + if (/*RAM_enable && */(((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; + } + else + { + return 0xFF; + } + } + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + // lowest bank is fixed, but is still effected by mode + SetCDLROM(flags, addr); + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else + { + if (!regs_enable) + { + if ((((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); + } + else + { + return; + } + } + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + if (addr < 0x2000) + { + RAM_enable = (value & 0xF) == 0xA; + } + else if (addr < 0x4000) + { + ROM_bank = value; + ROM_bank &= ROM_mask; + //Console.WriteLine(addr + " " + value + " " + ROM_mask + " " + ROM_bank); + } + else if (addr < 0x6000) + { + if ((value & 0x10) == 0x10) + { + regs_enable = true; + } + else + { + regs_enable = false; + RAM_bank = value & RAM_mask; + } + } + } + else + { + if (regs_enable) + { + regs[(addr & 0x7F)] = (uint8_t)(value & 0x7); + } + else + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; + } + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_mask), ref RAM_mask); + ser.Sync(nameof(RAM_enable), ref RAM_enable); + ser.Sync(nameof(regs_enable), ref regs_enable); + ser.Sync(nameof(regs), ref regs, false); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_Default.h b/libHawk/GBHawk/GBHawk/Mapper_Default.h new file mode 100644 index 0000000000..bf5024658a --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_Default.h @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_Default : Mapper + { + public: + + void Reset() + { + // nothing to initialize + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x8000) + { + return Core._rom[addr]; + } + else + { + if (Core.cart_RAM != null) + { + return Core.cart_RAM[addr - 0xA000]; + } + else + { + return 0; + } + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x8000) + { + SetCDLROM(flags, addr); + } + else + { + if (Core.cart_RAM != null) + { + SetCDLRAM(flags, addr - 0xA000); + } + else + { + return; + } + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + // no mapping hardware available + } + else + { + if (Core.cart_RAM != null) + { + Core.cart_RAM[addr - 0xA000] = value; + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_HuC1.h b/libHawk/GBHawk/GBHawk/Mapper_HuC1.h new file mode 100644 index 0000000000..ef938e57c4 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_HuC1.h @@ -0,0 +1,197 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_HuC1 : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t RAM_bank; + bool RAM_enable; + uint32_t ROM_mask; + uint32_t RAM_mask; + bool IR_signal; + + void Reset() + { + ROM_bank = 0; + RAM_bank = 0; + RAM_enable = false; + ROM_mask = Core._rom.Length / 0x4000 - 1; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + + RAM_mask = 0; + if (Core.cart_RAM != null) + { + RAM_mask = Core.cart_RAM.Length / 0x2000 - 1; + if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; } + } + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + return Core._rom[addr]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else if ((addr >= 0xA000) && (addr < 0xC000)) + { + if (RAM_enable) + { + if (Core.cart_RAM != null) + { + if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) + { + return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; + } + else + { + return 0xFF; + } + } + else + { + return 0xFF; + } + } + else + { + // when RAM isn't enabled, reading from this area will return IR sensor reading + // for now we'll assume it never sees light (0xC0) + return 0xC0; + } + } + else + { + return 0xFF; + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + SetCDLROM(flags, addr); + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else if ((addr >= 0xA000) && (addr < 0xC000)) + { + if (RAM_enable) + { + if (Core.cart_RAM != null) + { + if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) + { + SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); + } + else + { + return; + } + } + else + { + return; + } + } + else + { + return; + } + } + else + { + return; + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + if (addr < 0x2000) + { + RAM_enable = (value & 0xF) != 0xE; + } + else if (addr < 0x4000) + { + value &= 0x3F; + + ROM_bank &= 0xC0; + ROM_bank |= value; + ROM_bank &= ROM_mask; + } + else if (addr < 0x6000) + { + RAM_bank = value & 3; + RAM_bank &= RAM_mask; + } + } + else + { + if (RAM_enable) + { + if (Core.cart_RAM != null) + { + if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) + { + Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; + } + } + } + else + { + // I don't know if other bits here have an effect + if (value == 1) + { + IR_signal = true; + } + else if (value == 0) + { + IR_signal = false; + } + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_mask), ref RAM_mask); + ser.Sync(nameof(RAM_enable), ref RAM_enable); + ser.Sync(nameof(IR_signal), ref IR_signal); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_HuC3.h b/libHawk/GBHawk/GBHawk/Mapper_HuC3.h new file mode 100644 index 0000000000..a117533705 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_HuC3.h @@ -0,0 +1,311 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_HuC3 : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t RAM_bank; + bool RAM_enable; + uint32_t ROM_mask; + uint32_t RAM_mask; + bool IR_signal; + uint8_t control; + uint8_t chip_read; + bool timer_read; + uint32_t time_val_shift; + uint32_t time; + uint32_t RTC_timer; + uint32_t RTC_low_clock; + uint32_t RTC_seconds; + + void Reset() + { + ROM_bank = 0; + RAM_bank = 0; + RAM_enable = false; + ROM_mask = Core._rom.Length / 0x4000 - 1; + control = 0; + chip_read = 1; + timer_read = false; + time_val_shift = 0; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + + RAM_mask = 0; + if (Core.cart_RAM != null) + { + RAM_mask = Core.cart_RAM.Length / 0x2000 - 1; + if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; } + } + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + return Core._rom[addr]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else if ((addr >= 0xA000) && (addr < 0xC000)) + { + if ((control >= 0xB) && (control < 0xE)) + { + if (control == 0xD) + { + return 1; + } + return chip_read; + } + + if (RAM_enable) + { + if (Core.cart_RAM != null) + { + if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) + { + return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; + } + else + { + return 0xFF; + } + } + else + { + return 0xFF; + } + } + else + { + // what to return if RAM not enabled and controller not selected? + return 0xFF; + } + } + else + { + return 0xFF; + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + SetCDLROM(flags, addr); + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else if ((addr >= 0xA000) && (addr < 0xC000)) + { + if (RAM_enable) + { + if (Core.cart_RAM != null) + { + if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) + { + SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); + } + else + { + return; + } + } + else + { + return; + } + } + else + { + return; + } + } + else + { + return; + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + if (addr < 0x2000) + { + RAM_enable = (value & 0xA) == 0xA; + control = value; + } + else if (addr < 0x4000) + { + if (value == 0) { value = 1; } + + ROM_bank = value; + ROM_bank &= ROM_mask; + } + else if (addr < 0x6000) + { + RAM_bank = value; + RAM_bank &= 0xF; + RAM_bank &= RAM_mask; + } + } + else + { + if (RAM_enable && ((control < 0xB) || (control > 0xE))) + { + if (Core.cart_RAM != null) + { + if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) + { + Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; + } + } + } + + if (control == 0xB) + { + switch (value & 0xF0) + { + case 0x10: + if (timer_read) + { + // return timer value + chip_read = (uint8_t)((time >> time_val_shift) & 0xF); + time_val_shift += 4; + if (time_val_shift == 28) { time_val_shift = 0; } + } + break; + case 0x20: + break; + case 0x30: + if (!timer_read) + { + // write to timer + if (time_val_shift == 0) { time = 0; } + if (time_val_shift < 28) + { + time |= (uint)((value & 0x0F) << time_val_shift); + time_val_shift += 4; + if (time_val_shift == 28) { timer_read = true; } + } + } + break; + case 0x40: + // other commands + switch (value & 0xF) + { + case 0x0: + time_val_shift = 0; + break; + case 0x3: + timer_read = false; + time_val_shift = 0; + break; + case 0x7: + timer_read = true; + time_val_shift = 0; + break; + case 0xF: + break; + } + break; + case 0x50: + break; + case 0x60: + timer_read = true; + break; + } + } + else if (control == 0xC) + { + // maybe IR + } + else if (control == 0xD) + { + // maybe IR + } + } + } + + void RTC_Get(uint32_t value, uint32_t index) + { + time |= (uint)((value & 0xFF) << index); + } + + void Mapper_Tick() + { + RTC_timer++; + + if (RTC_timer == 128) + { + RTC_timer = 0; + + RTC_low_clock++; + + if (RTC_low_clock == 32768) + { + RTC_low_clock = 0; + + RTC_seconds++; + if (RTC_seconds > 59) + { + RTC_seconds = 0; + time++; + if ((time & 0xFFF) > 1439) + { + time -= 1440; + time += (1 << 12); + if ((time >> 12) > 365) + { + time -= (365 << 12); + time += (1 << 24); + } + } + } + } + } + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_mask), ref RAM_mask); + ser.Sync(nameof(RAM_enable), ref RAM_enable); + ser.Sync(nameof(IR_signal), ref IR_signal); + ser.Sync(nameof(control), ref control); + ser.Sync(nameof(chip_read), ref chip_read); + ser.Sync(nameof(timer_read), ref timer_read); + ser.Sync(nameof(time_val_shift), ref time_val_shift); + ser.Sync(nameof(time), ref time); + ser.Sync(nameof(RTC_timer), ref RTC_timer); + ser.Sync(nameof(RTC_low_clock), ref RTC_low_clock); + ser.Sync(nameof(RTC_seconds), ref RTC_seconds); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_MBC1.h b/libHawk/GBHawk/GBHawk/Mapper_MBC1.h new file mode 100644 index 0000000000..a33ab11738 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_MBC1.h @@ -0,0 +1,203 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_MBC1 : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t RAM_bank; + bool RAM_enable; + bool sel_mode; + uint32_t ROM_mask; + uint32_t RAM_mask; + + void Reset() + { + ROM_bank = 1; + RAM_bank = 0; + RAM_enable = false; + sel_mode = false; + ROM_mask = Core._rom.Length / 0x4000 - 1; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + + RAM_mask = 0; + if (Core.cart_RAM != null) + { + RAM_mask = Core.cart_RAM.Length / 0x2000 - 1; + if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; } + } + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + // lowest bank is fixed, but is still effected by mode + if (sel_mode) + { + return Core._rom[(ROM_bank & 0x60) * 0x4000 + addr]; + } + else + { + return Core._rom[addr]; + } + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + if (Core.cart_RAM != null) + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; + } + else + { + return 0xFF; + } + + } + else + { + return 0xFF; + } + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + // lowest bank is fixed, but is still effected by mode + if (sel_mode) + { + SetCDLROM(flags, (ROM_bank & 0x60) * 0x4000 + addr); + } + else + { + SetCDLROM(flags, addr); + } + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else + { + if (Core.cart_RAM != null) + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); + } + else + { + return; + } + + } + else + { + return; + } + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + if (addr < 0x2000) + { + RAM_enable = (value & 0xF) == 0xA; + } + else if (addr < 0x4000) + { + value &= 0x1F; + + // writing zero gets translated to 1 + if (value == 0) { value = 1; } + + ROM_bank &= 0xE0; + ROM_bank |= value; + ROM_bank &= ROM_mask; + } + else if (addr < 0x6000) + { + if (sel_mode && Core.cart_RAM != null) + { + RAM_bank = value & 3; + RAM_bank &= RAM_mask; + } + else + { + ROM_bank &= 0x1F; + ROM_bank |= ((value & 3) << 5); + ROM_bank &= ROM_mask; + } + } + else + { + sel_mode = (value & 1) > 0; + + if (sel_mode && Core.cart_RAM != null) + { + ROM_bank &= 0x1F; + ROM_bank &= ROM_mask; + } + else + { + RAM_bank = 0; + } + } + } + else + { + if (Core.cart_RAM != null) + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; + } + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_mask), ref RAM_mask); + ser.Sync(nameof(RAM_enable), ref RAM_enable); + ser.Sync(nameof(sel_mode), ref sel_mode); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_MBC1_Multi.h b/libHawk/GBHawk/GBHawk/Mapper_MBC1_Multi.h new file mode 100644 index 0000000000..64440f131f --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_MBC1_Multi.h @@ -0,0 +1,199 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_MBC1_Multi : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t RAM_bank; + bool RAM_enable; + bool sel_mode; + uint32_t ROM_mask; + uint32_t RAM_mask; + + void Reset() + { + ROM_bank = 1; + RAM_bank = 0; + RAM_enable = false; + sel_mode = false; + ROM_mask = (Core._rom.Length / 0x4000 * 2) - 1; // due to how mapping works, we want a 1 bit higher mask + RAM_mask = 0; + if (Core.cart_RAM != null) + { + RAM_mask = Core.cart_RAM.Length / 0x2000 - 1; + if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; } + } + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + // lowest bank is fixed, but is still effected by mode + if (sel_mode) + { + return Core._rom[((ROM_bank & 0x60) >> 1) * 0x4000 + addr]; + } + else + { + return Core._rom[addr]; + } + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + (((ROM_bank & 0x60) >> 1) | (ROM_bank & 0xF)) * 0x4000]; + } + else + { + if (Core.cart_RAM != null) + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; + } + else + { + return 0xFF; + } + + } + else + { + return 0; + } + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + // lowest bank is fixed, but is still effected by mode + if (sel_mode) + { + SetCDLROM(flags, ((ROM_bank & 0x60) >> 1) * 0x4000 + addr); + } + else + { + SetCDLROM(flags, addr); + } + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + (((ROM_bank & 0x60) >> 1) | (ROM_bank & 0xF)) * 0x4000); + } + else + { + if (Core.cart_RAM != null) + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); + } + else + { + return; + } + + } + else + { + return; + } + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + if (addr < 0x2000) + { + RAM_enable = ((value & 0xA) == 0xA); + } + else if (addr < 0x4000) + { + value &= 0x1F; + + // writing zero gets translated to 1 + if (value == 0) { value = 1; } + + ROM_bank &= 0xE0; + ROM_bank |= value; + ROM_bank &= ROM_mask; + } + else if (addr < 0x6000) + { + if (sel_mode && Core.cart_RAM != null) + { + RAM_bank = value & 3; + RAM_bank &= RAM_mask; + } + else + { + ROM_bank &= 0x1F; + ROM_bank |= ((value & 3) << 5); + ROM_bank &= ROM_mask; + } + } + else + { + sel_mode = (value & 1) > 0; + + if (sel_mode && Core.cart_RAM != null) + { + ROM_bank &= 0x1F; + ROM_bank &= ROM_mask; + } + else + { + RAM_bank = 0; + } + } + } + else + { + if (Core.cart_RAM != null) + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; + } + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_mask), ref RAM_mask); + ser.Sync(nameof(RAM_enable), ref RAM_enable); + ser.Sync(nameof(sel_mode), ref sel_mode); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_MBC2.h b/libHawk/GBHawk/GBHawk/Mapper_MBC2.h new file mode 100644 index 0000000000..571c096a66 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_MBC2.h @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_MBC2 : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t RAM_bank; + bool RAM_enable; + uint32_t ROM_mask; + + void Reset() + { + ROM_bank = 1; + RAM_bank = 0; + RAM_enable = false; + ROM_mask = Core._rom.Length / 0x4000 - 1; + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + return Core._rom[addr]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else if ((addr >= 0xA000) && (addr < 0xA200)) + { + if (RAM_enable) + { + return Core.cart_RAM[addr - 0xA000]; + } + return 0xFF; + } + else + { + return 0xFF; + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + SetCDLROM(flags, addr); + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else if ((addr >= 0xA000) && (addr < 0xA200)) + { + if (RAM_enable) + { + SetCDLRAM(flags, addr - 0xA000); + } + return; + } + else + { + return; + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x2000) + { + if ((addr & 0x100) == 0) + { + RAM_enable = ((value & 0xA) == 0xA); + } + } + else if (addr < 0x4000) + { + if ((addr & 0x100) > 0) + { + ROM_bank = value & 0xF & ROM_mask; + if (ROM_bank==0) { ROM_bank = 1; } + } + } + else if ((addr >= 0xA000) && (addr < 0xA200)) + { + if (RAM_enable) + { + Core.cart_RAM[addr - 0xA000] = (uint8_t)(value & 0xF); + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_enable), ref RAM_enable); + } + }; +} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Mapper_MBC3.h b/libHawk/GBHawk/GBHawk/Mapper_MBC3.h new file mode 100644 index 0000000000..6ab1a848c1 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_MBC3.h @@ -0,0 +1,295 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_MBC3 : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t RAM_bank; + bool RAM_enable; + uint32_t ROM_mask; + uint32_t RAM_mask; + uint8_t[] RTC_regs = new uint8_t[5]; + uint8_t[] RTC_regs_latch = new uint8_t[5]; + bool RTC_regs_latch_wr; + uint32_t RTC_timer; + uint32_t RTC_low_clock; + bool halt; + uint32_t RTC_offset; + + void Reset() + { + ROM_bank = 1; + RAM_bank = 0; + RAM_enable = false; + ROM_mask = Core._rom.Length / 0x4000 - 1; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + + RAM_mask = 0; + if (Core.cart_RAM != null) + { + RAM_mask = Core.cart_RAM.Length / 0x2000 - 1; + if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; } + } + + RTC_regs_latch[0] = 0; + RTC_regs_latch[1] = 0; + RTC_regs_latch[2] = 0; + RTC_regs_latch[3] = 0; + RTC_regs_latch[4] = 0; + + RTC_regs_latch_wr = true; + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + return Core._rom[addr]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + if (RAM_enable) + { + if ((Core.cart_RAM != null) && (RAM_bank <= RAM_mask)) + { + if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) + { + return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; + } + else + { + return 0xFF; + } + } + + if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) + { + //Console.WriteLine("reg: " + (RAM_bank - 8) + " value: " + RTC_regs_latch[RAM_bank - 8] + " cpu: " + Core.cpu.TotalExecutedCycles); + return RTC_regs_latch[RAM_bank - 8]; + } + else + { + return 0x0; + } + } + else + { + return 0x0; + } + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + SetCDLROM(flags, addr); + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else + { + if (RAM_enable) + { + if ((Core.cart_RAM != null) && (RAM_bank <= RAM_mask)) + { + if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) + { + SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); + } + else + { + return; + } + } + + if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) + { + return; + } + else + { + return; + } + } + else + { + return; + } + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + if (addr < 0x2000) + { + RAM_enable = ((value & 0xA) == 0xA); + } + else if (addr < 0x4000) + { + value &= 0x7F; + + // writing zero gets translated to 1 + if (value == 0) { value = 1; } + + ROM_bank = value; + ROM_bank &= ROM_mask; + } + else if (addr < 0x6000) + { + RAM_bank = value; + } + else + { + if (!RTC_regs_latch_wr && ((value & 1) == 1)) + { + for (uint32_t i = 0; i < 5; i++) + { + RTC_regs_latch[i] = RTC_regs[i]; + } + } + + RTC_regs_latch_wr = (value & 1) > 0; + } + } + else + { + if (RAM_enable) + { + if ((Core.cart_RAM != null) && (RAM_bank <= RAM_mask)) + { + if (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length) + { + Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; + } + } + else if ((RAM_bank >= 8) && (RAM_bank <= 0xC)) + { + RTC_regs[RAM_bank - 8] = value; + + if ((RAM_bank - 8) == 0) { RTC_low_clock = RTC_timer = 0; } + + halt = (RTC_regs[4] & 0x40) > 0; + } + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void RTC_Get(uint32_t value, uint32_t index) + { + if (index < 5) + { + RTC_regs[index] = (uint8_t)value; + } + else + { + RTC_offset = value; + } + } + + void Mapper_Tick() + { + if (!halt) + { + RTC_timer++; + + if (RTC_timer == 128) + { + RTC_timer = 0; + + RTC_low_clock++; + + if (RTC_low_clock == 32768) + { + RTC_low_clock = 0; + RTC_timer = RTC_offset; + + RTC_regs[0]++; + + if (RTC_regs[0] > 59) + { + RTC_regs[0] = 0; + RTC_regs[1]++; + if (RTC_regs[1] > 59) + { + RTC_regs[1] = 0; + RTC_regs[2]++; + if (RTC_regs[2] > 23) + { + RTC_regs[2] = 0; + if (RTC_regs[3] < 0xFF) + { + RTC_regs[3]++; + } + else + { + RTC_regs[3] = 0; + + if ((RTC_regs[4] & 1) == 0) + { + RTC_regs[4] |= 1; + } + else + { + RTC_regs[4] &= 0xFE; + RTC_regs[4] |= 0x80; + } + } + } + } + } + } + } + } + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_mask), ref RAM_mask); + ser.Sync(nameof(RAM_enable), ref RAM_enable); + ser.Sync(nameof(halt), ref halt); + ser.Sync(nameof(RTC_regs), ref RTC_regs, false); + ser.Sync(nameof(RTC_regs_latch), ref RTC_regs_latch, false); + ser.Sync(nameof(RTC_regs_latch_wr), ref RTC_regs_latch_wr); + ser.Sync(nameof(RTC_timer), ref RTC_timer); + ser.Sync(nameof(RTC_low_clock), ref RTC_low_clock); + ser.Sync(nameof(RTC_offset), ref RTC_offset); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_MBC5.h b/libHawk/GBHawk/GBHawk/Mapper_MBC5.h new file mode 100644 index 0000000000..b0ae64d2f5 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_MBC5.h @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_MBC5 : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t RAM_bank; + bool RAM_enable; + uint32_t ROM_mask; + uint32_t RAM_mask; + + void Reset() + { + ROM_bank = 1; + RAM_bank = 0; + RAM_enable = false; + ROM_mask = Core._rom.Length / 0x4000 - 1; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + if (ROM_mask > 0x100) { ROM_mask |= 0xFF; } + + RAM_mask = 0; + if (Core.cart_RAM != null) + { + RAM_mask = Core.cart_RAM.Length / 0x2000 - 1; + if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; } + } + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + return Core._rom[addr]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + if (Core.cart_RAM != null) + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + return Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000]; + } + else + { + return 0xFF; + } + + } + else + { + return 0xFF; + } + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + SetCDLROM(flags, addr); + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else + { + if (Core.cart_RAM != null) + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + SetCDLRAM(flags, (addr - 0xA000) + RAM_bank * 0x2000); + } + else + { + return; + } + + } + else + { + return; + } + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + if (addr < 0x2000) + { + RAM_enable = (value & 0xF) == 0xA; + } + else if (addr < 0x3000) + { + value &= 0xFF; + + ROM_bank &= 0x100; + ROM_bank |= value; + ROM_bank &= ROM_mask; + } + else if (addr < 0x4000) + { + value &= 1; + + ROM_bank &= 0xFF; + ROM_bank |= (value << 8); + ROM_bank &= ROM_mask; + } + else if (addr < 0x6000) + { + RAM_bank = value & 0xF; + RAM_bank &= RAM_mask; + } + } + else + { + if (Core.cart_RAM != null) + { + if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Core.cart_RAM.Length)) + { + Core.cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value; + } + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_mask), ref RAM_mask); + ser.Sync(nameof(RAM_enable), ref RAM_enable); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_MBC6.h b/libHawk/GBHawk/GBHawk/Mapper_MBC6.h new file mode 100644 index 0000000000..40b5288d9b --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_MBC6.h @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_MBC6 : Mapper + { + public: + + void Reset() + { + // nothing to initialize + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x8000) + { + return Core._rom[addr]; + } + else + { + if (Core.cart_RAM != null) + { + return Core.cart_RAM[addr - 0xA000]; + } + else + { + return 0; + } + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x8000) + { + SetCDLROM(flags, addr); + } + else + { + if (Core.cart_RAM != null) + { + SetCDLRAM(flags, addr - 0xA000); + } + else + { + return; + } + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + // no mapping hardware available + } + else + { + if (Core.cart_RAM != null) + { + Core.cart_RAM[addr - 0xA000] = value; + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_MBC7.h b/libHawk/GBHawk/GBHawk/Mapper_MBC7.h new file mode 100644 index 0000000000..c4f96b82ba --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_MBC7.h @@ -0,0 +1,488 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_MBC7 : Mapper + { + public: + + uint32_t ROM_bank; + bool RAM_enable_1, RAM_enable_2; + uint32_t ROM_mask; + uint8_t acc_x_low; + uint8_t acc_x_high; + uint8_t acc_y_low; + uint8_t acc_y_high; + bool is_erased; + + // EEPROM related + bool CS_prev; + bool CLK_prev; + bool DI_prev; + bool DO; + bool instr_read; + bool perf_instr; + uint32_t instr_bit_counter; + uint32_t instr; + bool WR_EN; + uint32_t EE_addr; + uint32_t instr_case; + uint32_t instr_clocks; + uint32_t EE_value; + uint32_t countdown; + bool countdown_start; + + + void Reset() + { + ROM_bank = 1; + RAM_enable_1 = RAM_enable_2 = false; + ROM_mask = Core._rom.Length / 0x4000 - 1; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + + acc_x_low = 0; + acc_x_high = 0x80; + acc_y_low = 0; + acc_y_high = 0x80; + + // reset acceerometer + is_erased = false; + + // EEPROM related + CS_prev = CLK_prev = DI_prev = DO = instr_read = perf_instr = WR_EN = countdown_start = false; + instr_bit_counter = instr = EE_addr = instr_case = instr_clocks = EE_value = countdown = 0; + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + return Core._rom[addr]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else if (addr < 0xA000) + { + return 0xFF; + } + else if (addr < 0xB000) + { + if (RAM_enable_1 && RAM_enable_2) + { + return Register_Access_Read(addr); + } + else + { + return 0xFF; + } + } + else + { + return 0xFF; + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + SetCDLROM(flags, addr); + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else if (addr < 0xA000) + { + return; + } + else if (addr < 0xB000) + { + if (RAM_enable_1 && RAM_enable_2) + { + return; + } + else + { + return; + } + } + else + { + return; + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0xA000) + { + if (addr < 0x2000) + { + RAM_enable_1 = (value & 0xF) == 0xA; + } + else if (addr < 0x4000) + { + value &= 0xFF; + + //Console.WriteLine(Core.cpu.TotalExecutedCycles); + //Console.WriteLine(value); + + ROM_bank &= 0x100; + ROM_bank |= value; + ROM_bank &= ROM_mask; + } + else if (addr < 0x6000) + { + RAM_enable_2 = (value & 0xF0) == 0x40; + } + } + else + { + if (RAM_enable_1 && RAM_enable_2) + { + Register_Access_Write(addr, value); + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_enable_1), ref RAM_enable_1); + ser.Sync(nameof(RAM_enable_2), ref RAM_enable_2); + ser.Sync(nameof(acc_x_low), ref acc_x_low); + ser.Sync(nameof(acc_x_high), ref acc_x_high); + ser.Sync(nameof(acc_y_low), ref acc_y_low); + ser.Sync(nameof(acc_y_high), ref acc_y_high); + ser.Sync(nameof(is_erased), ref is_erased); + + ser.Sync(nameof(CS_prev), ref CS_prev); + ser.Sync(nameof(CLK_prev), ref CLK_prev); + ser.Sync(nameof(DI_prev), ref DI_prev); + ser.Sync(nameof(DO), ref DO); + ser.Sync(nameof(instr_read), ref instr_read); + ser.Sync(nameof(perf_instr), ref perf_instr); + ser.Sync(nameof(instr_bit_counter), ref instr_bit_counter); + ser.Sync(nameof(instr), ref instr); + ser.Sync(nameof(WR_EN), ref WR_EN); + ser.Sync(nameof(EE_addr), ref EE_addr); + ser.Sync(nameof(instr_case), ref instr_case); + ser.Sync(nameof(instr_clocks), ref instr_clocks); + ser.Sync(nameof(EE_value), ref EE_value); + ser.Sync(nameof(countdown), ref countdown); + ser.Sync(nameof(countdown_start), ref countdown_start); + } + + uint8_t Register_Access_Read(uint32_t addr) + { + if ((addr & 0xA0F0) == 0xA000) + { + return 0xFF; + } + else if ((addr & 0xA0F0) == 0xA010) + { + return 0xFF; + } + else if ((addr & 0xA0F0) == 0xA020) + { + return acc_x_low; + } + else if ((addr & 0xA0F0) == 0xA030) + { + return acc_x_high; + } + else if ((addr & 0xA0F0) == 0xA040) + { + return acc_y_low; + } + else if ((addr & 0xA0F0) == 0xA050) + { + return acc_y_high; + } + else if ((addr & 0xA0F0) == 0xA060) + { + return 0xFF; + } + else if ((addr & 0xA0F0) == 0xA070) + { + return 0xFF; + } + else if ((addr & 0xA0F0) == 0xA080) + { + return (uint8_t)((CS_prev ? 0x80 : 0) | + (CLK_prev ? 0x40 : 0) | + (DI_prev ? 2 : 0) | + (DO ? 1 : 0)); + } + else + { + return 0xFF; + } + } + + void Register_Access_Write(uint32_t addr, uint8_t value) + { + if ((addr & 0xA0F0) == 0xA000) + { + if (value == 0x55) + { + //Console.WriteLine("Erasing ACC"); + + is_erased = true; + acc_x_low = 0x00; + acc_x_high = 0x80; + acc_y_low = 0x00; + acc_y_high = 0x80; + } + } + else if ((addr & 0xA0F0) == 0xA010) + { + if ((value == 0xAA) && is_erased) + { + // latch new accelerometer values + //Console.WriteLine("Latching ACC"); + acc_x_low = (uint8_t)(Core.Acc_X_state & 0xFF); + acc_x_high = (uint8_t)((Core.Acc_X_state & 0xFF00) >> 8); + acc_y_low = (uint8_t)(Core.Acc_Y_state & 0xFF); + acc_y_high = (uint8_t)((Core.Acc_Y_state & 0xFF00) >> 8); + } + } + else if ((addr & 0xA0F0) == 0xA080) + { + // EEPROM writes + EEPROM_write(value); + } + } + + private void EEPROM_write(uint8_t value) + { + bool CS = value.Bit(7); + bool CLK = value.Bit(6); + bool DI = value.Bit(1); + + // if we deselect the chip, complete instructions or countdown and stop + if (!CS) + { + CS_prev = CS; + CLK_prev = CLK; + DI_prev = DI; + + DO = true; + countdown_start = false; + perf_instr = false; + instr_read = false; + + //Console.Write("Chip De-selected: "); + //Console.WriteLine(Core.cpu.TotalExecutedCycles); + } + + if (!instr_read && !perf_instr) + { + // if we aren't performing an operation or reading an incoming instruction, we are waiting for one + // this is signalled by CS and DI both being 1 while CLK goes from 0 to 1 + if (CLK && !CLK_prev && DI && CS) + { + instr_read = true; + instr_bit_counter = 0; + instr = 0; + DO = false; + //Console.Write("Initiating command: "); + //Console.WriteLine(Core.cpu.TotalExecutedCycles); + } + } + else if (instr_read && CLK && !CLK_prev) + { + // all instructions are 10 bits long + instr = (instr << 1) | ((value & 2) >> 1); + + instr_bit_counter++; + if (instr_bit_counter == 10) + { + instr_read = false; + instr_clocks = 0; + EE_addr = instr & 0x7F; + EE_value = 0; + + switch (instr & 0x300) + { + case 0x0: + switch (instr & 0xC0) + { + case 0x0: // disable writes + instr_case = 0; + WR_EN = false; + DO = true; + break; + case 0x40: // fill mem with value + instr_case = 1; + perf_instr = true; + break; + case 0x80: // fill mem with FF + instr_case = 2; + if (WR_EN) + { + for (uint32_t i = 0; i < 256; i++) + { + Core.cart_RAM[i] = 0xFF; + } + } + DO = true; + break; + case 0xC0: // enable writes + instr_case = 3; + WR_EN = true; + DO = true; + break; + } + break; + case 0x100: // write to address + instr_case = 4; + perf_instr = true; + break; + case 0x200: // read from address + instr_case = 5; + perf_instr = true; + break; + case 0x300: // set address to FF + instr_case = 6; + if (WR_EN) + { + Core.cart_RAM[EE_addr * 2] = 0xFF; + Core.cart_RAM[EE_addr * 2 + 1] = 0xFF; + } + DO = true; + break; + } + + //Console.Write("Selected Command: "); + //Console.Write(instr_case); + //Console.Write(" "); + //Console.WriteLine(Core.cpu.TotalExecutedCycles); + } + } + else if (perf_instr && CLK && !CLK_prev) + { + //Console.Write("Command In progress, Cycle: "); + //Console.Write(instr_clocks); + //Console.Write(" "); + //Console.WriteLine(Core.cpu.TotalExecutedCycles); + + // for commands that require additional clocking + switch (instr_case) + { + case 1: + EE_value = (EE_value << 1) | ((value & 2) >> 1); + + if (instr_clocks == 15) + { + if (WR_EN) + { + for (uint32_t i = 0; i < 128; i++) + { + Core.cart_RAM[i * 2] = (uint8_t)(EE_value & 0xFF); + Core.cart_RAM[i * 2 + 1] = (uint8_t)((EE_value & 0xFF00) >> 8); + } + } + instr_case = 7; + countdown = 8; + } + break; + + case 4: + EE_value = (EE_value << 1) | ((value & 2) >> 1); + + if (instr_clocks == 15) + { + if (WR_EN) + { + Core.cart_RAM[EE_addr * 2] = (uint8_t)(EE_value & 0xFF); + Core.cart_RAM[EE_addr * 2 + 1] = (uint8_t)((EE_value & 0xFF00) >> 8); + } + instr_case = 7; + countdown = 8; + } + break; + + case 5: + if ((instr_clocks >= 0) && (instr_clocks <= 7)) + { + DO = ((Core.cart_RAM[EE_addr * 2 + 1] >> (7 - instr_clocks)) & 1) == 1; + } + else if ((instr_clocks >= 8) && (instr_clocks <= 15)) + { + DO = ((Core.cart_RAM[EE_addr * 2] >> (15 - instr_clocks)) & 1) == 1; + } + + if (instr_clocks == 15) + { + instr_case = 7; + countdown = 8; + } + break; + + case 6: + + instr_case = 7; + countdown = 8; + break; + + case 7: + // completed operations take time, so countdown a bit here. + // not cycle accurate for operations like writing to all of the EEPROM, but good enough + + break; + } + + if (instr_case == 7) + { + perf_instr = false; + countdown_start = true; + } + + instr_clocks++; + } + else if (countdown_start) + { + countdown--; + if (countdown == 0) + { + countdown_start = false; + DO = true; + + //Console.Write("Command Complete: "); + //Console.WriteLine(Core.cpu.TotalExecutedCycles); + } + } + + CS_prev = CS; + CLK_prev = CLK; + DI_prev = DI; + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_MMM01.h b/libHawk/GBHawk/GBHawk/Mapper_MMM01.h new file mode 100644 index 0000000000..fe608640fa --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_MMM01.h @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_MMM01 : Mapper + { + public: + + void Reset() + { + // nothing to initialize + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x8000) + { + return Core._rom[addr]; + } + else + { + if (Core.cart_RAM != null) + { + return Core.cart_RAM[addr - 0xA000]; + } + else + { + return 0; + } + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x8000) + { + SetCDLROM(flags, addr); + } + else + { + if (Core.cart_RAM != null) + { + SetCDLRAM(flags, addr - 0xA000); + } + else + { + return; + } + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x8000) + { + // no mapping hardware available + } + else + { + if (Core.cart_RAM != null) + { + Core.cart_RAM[addr - 0xA000] = value; + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_RockMan8.h b/libHawk/GBHawk/GBHawk/Mapper_RockMan8.h new file mode 100644 index 0000000000..9cbd4bda86 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_RockMan8.h @@ -0,0 +1,96 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_RM8 : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t ROM_mask; + + void Reset() + { + ROM_bank = 1; + ROM_mask = Core._rom.Length / 0x4000 - 1; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + // lowest bank is fixed + return Core._rom[addr]; + + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + return 0xFF; + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + // lowest bank is fixed + SetCDLROM(flags, addr); + + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else + { + return; + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if ((addr >= 0x2000) && (addr < 0x4000)) + { + value &= 0x1F; + + if (value == 0) { value = 1; } + + // in hhugboy they just subtract 8, but to me looks like bits 4 and 5 are just swapped (and bit 4 is unused?) + ROM_bank = ((value & 0xF) | ((value & 0x10) >> 1))& ROM_mask; + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC1.h b/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC1.h new file mode 100644 index 0000000000..6f619b927c --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC1.h @@ -0,0 +1,190 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_Sachen1 : Mapper + { + public: + + uint32_t ROM_bank; + bool locked; + uint32_t ROM_mask; + uint32_t ROM_bank_mask; + uint32_t BASE_ROM_Bank; + bool reg_access; + uint32_t addr_last; + uint32_t counter; + + void Reset() + { + ROM_bank = 1; + ROM_mask = Core._rom.Length / 0x4000 - 1; + BASE_ROM_Bank = 0; + ROM_bank_mask = 0xFF; + locked = true; + reg_access = false; + addr_last = 0; + counter = 0; + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + if (locked) + { + // header is scrambled + if ((addr >= 0x100) && (addr < 0x200)) + { + uint32_t temp0 = (addr & 1); + uint32_t temp1 = (addr & 2); + uint32_t temp4 = (addr & 0x10); + uint32_t temp6 = (addr & 0x40); + + temp0 = temp0 << 6; + temp1 = temp1 << 3; + temp4 = temp4 >> 3; + temp6 = temp6 >> 6; + + addr &= 0x1AC; + addr |= (uint32_t)(temp0 | temp1 | temp4 | temp6); + } + addr |= 0x80; + } + + return Core._rom[addr + BASE_ROM_Bank * 0x4000]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + return 0xFF; + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + if (locked) + { + // header is scrambled + if ((addr >= 0x100) && (addr < 0x200)) + { + uint32_t temp0 = (addr & 1); + uint32_t temp1 = (addr & 2); + uint32_t temp4 = (addr & 0x10); + uint32_t temp6 = (addr & 0x40); + + temp0 = temp0 << 6; + temp1 = temp1 << 3; + temp4 = temp4 >> 3; + temp6 = temp6 >> 6; + + addr &= 0x1AC; + addr |= (uint32_t)(temp0 | temp1 | temp4 | temp6); + } + addr |= 0x80; + } + + SetCDLROM(flags, addr + BASE_ROM_Bank * 0x4000); + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else + { + return; + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x2000) + { + if (reg_access) + { + BASE_ROM_Bank = value; + } + } + else if (addr < 0x4000) + { + ROM_bank = (value > 0) ? value : 1; + + if ((value & 0x30) == 0x30) + { + reg_access = true; + } + else + { + reg_access = false; + } + } + else if (addr < 0x6000) + { + if (reg_access) + { + ROM_bank_mask = value; + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void Mapper_Tick() + { + if (locked) + { + if (((Core.addr_access & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (Core.addr_access >= 0x100)) + { + counter++; + Console.WriteLine(Core.cpu.TotalExecutedCycles); + } + + if (Core.addr_access >= 0x100) + { + addr_last = Core.addr_access; + } + + if (counter == 0x30) + { + locked = false; + Console.WriteLine("Unlocked"); + } + } + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(locked), ref locked); + ser.Sync(nameof(ROM_bank_mask), ref ROM_bank_mask); + ser.Sync(nameof(BASE_ROM_Bank), ref BASE_ROM_Bank); + ser.Sync(nameof(reg_access), ref reg_access); + ser.Sync(nameof(addr_last), ref addr_last); + ser.Sync(nameof(counter), ref counter); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC2.h b/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC2.h new file mode 100644 index 0000000000..a349b8a797 --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_Sachen_MMC2.h @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_Sachen2 : Mapper + { + public: + + uint32_t ROM_bank; + bool locked, locked_GBC, finished; + uint32_t ROM_mask; + uint32_t ROM_bank_mask; + uint32_t BASE_ROM_Bank; + bool reg_access; + uint32_t addr_last; + uint32_t counter; + + void Reset() + { + ROM_bank = 1; + ROM_mask = Core._rom.Length / 0x4000 - 1; + BASE_ROM_Bank = 0; + ROM_bank_mask = 0; + locked = true; + locked_GBC = false; + finished = false; + reg_access = false; + addr_last = 0; + counter = 0; + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + // header is scrambled + if ((addr >= 0x100) && (addr < 0x200)) + { + uint32_t temp0 = (addr & 1); + uint32_t temp1 = (addr & 2); + uint32_t temp4 = (addr & 0x10); + uint32_t temp6 = (addr & 0x40); + + temp0 = temp0 << 6; + temp1 = temp1 << 3; + temp4 = temp4 >> 3; + temp6 = temp6 >> 6; + + addr &= 0x1AC; + addr |= (uint32_t)(temp0 | temp1 | temp4 | temp6); + } + + if (locked_GBC) { addr |= 0x80; } + + return Core._rom[addr + BASE_ROM_Bank * 0x4000]; + } + else if (addr < 0x8000) + { + uint32_t temp_bank = (ROM_bank & ~ROM_bank_mask) | (ROM_bank_mask & BASE_ROM_Bank); + temp_bank &= ROM_mask; + + return Core._rom[(addr - 0x4000) + temp_bank * 0x4000]; + } + else + { + return 0xFF; + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + // header is scrambled + if ((addr >= 0x100) && (addr < 0x200)) + { + uint32_t temp0 = (addr & 1); + uint32_t temp1 = (addr & 2); + uint32_t temp4 = (addr & 0x10); + uint32_t temp6 = (addr & 0x40); + + temp0 = temp0 << 6; + temp1 = temp1 << 3; + temp4 = temp4 >> 3; + temp6 = temp6 >> 6; + + addr &= 0x1AC; + addr |= (uint32_t)(temp0 | temp1 | temp4 | temp6); + } + + if (locked_GBC) { addr |= 0x80; } + + SetCDLROM(flags, addr + BASE_ROM_Bank * 0x4000); + } + else if (addr < 0x8000) + { + uint32_t temp_bank = (ROM_bank & ~ROM_bank_mask) | (ROM_bank_mask & BASE_ROM_Bank); + temp_bank &= ROM_mask; + + SetCDLROM(flags, (addr - 0x4000) + temp_bank * 0x4000); + } + else + { + return; + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x2000) + { + if (reg_access) + { + BASE_ROM_Bank = value; + } + } + else if (addr < 0x4000) + { + ROM_bank = (value > 0) ? (value) : 1; + + if ((value & 0x30) == 0x30) + { + reg_access = true; + } + else + { + reg_access = false; + } + } + else if (addr < 0x6000) + { + if (reg_access) + { + ROM_bank_mask = value; + } + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void Mapper_Tick() + { + if (locked) + { + if (((Core.addr_access & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (Core.addr_access >= 0x100)) + { + counter++; + } + + if (Core.addr_access >= 0x100) + { + addr_last = Core.addr_access; + } + + if (counter == 0x30) + { + locked = false; + locked_GBC = true; + counter = 0; + } + } + else if (locked_GBC) + { + if (((Core.addr_access & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (Core.addr_access >= 0x100)) + { + counter++; + } + + if (Core.addr_access >= 0x100) + { + addr_last = Core.addr_access; + } + + if (counter == 0x30) + { + locked_GBC = false; + finished = true; + Console.WriteLine("Finished"); + Console.WriteLine(Core.cpu.TotalExecutedCycles); + } + + // The above condition seems to never be reached as described in the mapper notes + // so for now add this one + + if ((Core.addr_access == 0x133) && (counter == 1)) + { + locked_GBC = false; + finished = true; + Console.WriteLine("Unlocked"); + } + } + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(locked), ref locked); + ser.Sync(nameof(locked_GBC), ref locked_GBC); + ser.Sync(nameof(finished), ref finished); + ser.Sync(nameof(ROM_bank_mask), ref ROM_bank_mask); + ser.Sync(nameof(BASE_ROM_Bank), ref BASE_ROM_Bank); + ser.Sync(nameof(reg_access), ref reg_access); + ser.Sync(nameof(addr_last), ref addr_last); + ser.Sync(nameof(counter), ref counter); + } + }; +} \ No newline at end of file diff --git a/libHawk/GBHawk/GBHawk/Mapper_TAMA5.h b/libHawk/GBHawk/GBHawk/Mapper_TAMA5.h new file mode 100644 index 0000000000..1f21ebd72c --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_TAMA5.h @@ -0,0 +1,292 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_TAMA5 : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t RAM_bank; + uint32_t ROM_mask; + uint32_t RAM_mask; + uint8_t[] RTC_regs = new uint8_t[10]; + uint32_t RTC_timer; + uint32_t RTC_low_clock; + bool halt; + uint32_t RTC_offset; + uint32_t ctrl; + uint32_t RAM_addr_low; + uint32_t RAM_addr_high; + uint32_t RAM_val_low; + uint32_t RAM_val_high; + uint8_t Chip_return_low; + uint8_t Chip_return_high; + + void Reset() + { + ROM_bank = 0; + RAM_bank = 0; + ROM_mask = Core._rom.Length / 0x4000 - 1; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + + RAM_mask = 0; + if (Core.cart_RAM != null) + { + RAM_mask = Core.cart_RAM.Length / 0x2000 - 1; + if (Core.cart_RAM.Length == 0x800) { RAM_mask = 0; } + } + + RAM_addr_low = RAM_addr_high = RAM_val_low = RAM_val_high = 0; + Chip_return_low = Chip_return_high = 0; + halt = false; + + ctrl = 0; + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x4000) + { + return Core._rom[addr]; + } + else if (addr < 0x8000) + { + return Core._rom[(addr - 0x4000) + ROM_bank * 0x4000]; + } + else + { + + switch (ctrl) + { + case 0xA: + // The game won't proceed unless this value (anded with 3) is 1 + // see bank 0: 0x1A7D to 0x1A89 + return 1; + case 0xC: + //Console.WriteLine("read low: " + Chip_return_low); + return Chip_return_low; + case 0xD: + //Console.WriteLine("read high: " + Chip_return_high); + return Chip_return_high; + } + + return 0x0; + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x4000) + { + SetCDLROM(flags, addr); + } + else if (addr < 0x8000) + { + SetCDLROM(flags, (addr - 0x4000) + ROM_bank * 0x4000); + } + else + { + + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr == 0xA000) + { + switch (ctrl) + { + case 0: + ROM_bank &= 0xF0; + ROM_bank |= (value & 0xF); + break; + case 1: + ROM_bank &= 0x0F; + ROM_bank |= ((value & 0x1) << 4); + break; + case 4: + RAM_val_low = (value & 0xF); + break; + case 5: + RAM_val_high = (value & 0xF); + //Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] = (uint8_t)((RAM_val_high << 4) | RAM_val_low); + break; + case 6: + RAM_addr_high = (value & 1); + + switch ((value & 0xE) >> 1) + { + case 0: + // write to RAM + Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] = (uint8_t)((RAM_val_high << 4) | RAM_val_low); + break; + case 1: + // read from RAM + Chip_return_high = (uint8_t)(Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] >> 4); + Chip_return_low = (uint8_t)(Core.cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] & 0xF); + break; + case 2: + // read from RTC registers + if (RAM_addr_low == 3) + { + Chip_return_high = RTC_regs[2]; + Chip_return_low = RTC_regs[1]; + } + else if (RAM_addr_low == 6) + { + Chip_return_high = RTC_regs[4]; + Chip_return_low = RTC_regs[3]; + } + else + { + Chip_return_high = 1; + Chip_return_low = 1; + } + break; + case 3: + // write to RTC registers (probably wrong, not well tested) + if (RAM_addr_low == 3) + { + RTC_regs[2] = (uint8_t)(RAM_val_high & 0xF); + RTC_regs[1] = (uint8_t)(RAM_val_low & 0xF); + } + else if (RAM_addr_low == 6) + { + RTC_regs[4] = (uint8_t)(RAM_val_high & 0xF); + RTC_regs[3] = (uint8_t)(RAM_val_low & 0xF); + } + else + { + + } + break; + case 4: + // read from seconds register (time changes are checked when it rolls over) + Chip_return_low = (uint8_t)(RTC_regs[0] & 0xF); + break; + } + + //Console.WriteLine("CTRL: " + (value >> 1) + " RAM_high:" + RAM_addr_high + " RAM_low: " + RAM_addr_low + " val: " + (uint8_t)((RAM_val_high << 4) | RAM_val_low) + " Cpu: " + Core.cpu.TotalExecutedCycles); + break; + case 7: + RAM_addr_low = (value & 0xF); + + //Console.WriteLine(" RAM_low:" + RAM_addr_low + " Cpu: " + Core.cpu.TotalExecutedCycles); + break; + } + } + else if (addr == 0xA001) + { + ctrl = value; + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void RTC_Get(uint32_t value, uint32_t index) + { + if (index < 10) + { + RTC_regs[index] = (uint8_t)value; + } + else + { + RTC_offset = value; + } + } + + void Mapper_Tick() + { + if (!halt) + { + RTC_timer++; + + if (RTC_timer == 128) + { + RTC_timer = 0; + + RTC_low_clock++; + + if (RTC_low_clock == 32768) + { + RTC_low_clock = 0; + RTC_timer = RTC_offset; + + RTC_regs[0]++; + + if (RTC_regs[0] > 59) + { + RTC_regs[0] = 0; + RTC_regs[1]++; + // 1's digit of minutes + if (RTC_regs[1] > 9) + { + RTC_regs[1] = 0; + RTC_regs[2]++; + // 10's digit of minutes + if (RTC_regs[2] > 5) + { + RTC_regs[2] = 0; + RTC_regs[3]++; + // 1's digit of hours + if (RTC_regs[3] > 9) + { + RTC_regs[3] = 0; + RTC_regs[4]++; + // 10's digit of hours + if (RTC_regs[4] > 2) + { + RTC_regs[4] = 0; + RTC_regs[5]++; + } + } + } + } + } + } + } + } + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + ser.Sync(nameof(RAM_bank), ref RAM_bank); + ser.Sync(nameof(RAM_mask), ref RAM_mask); + ser.Sync(nameof(halt), ref halt); + ser.Sync(nameof(RTC_regs), ref RTC_regs, false); + ser.Sync(nameof(RTC_timer), ref RTC_timer); + ser.Sync(nameof(RTC_low_clock), ref RTC_low_clock); + ser.Sync(nameof(RTC_offset), ref RTC_offset); + ser.Sync(nameof(ctrl), ref ctrl); + ser.Sync(nameof(RAM_addr_low), ref RAM_addr_low); + ser.Sync(nameof(RAM_addr_high), ref RAM_addr_high); + ser.Sync(nameof(RAM_val_low), ref RAM_val_low); + ser.Sync(nameof(RAM_val_high), ref RAM_val_high); + ser.Sync(nameof(Chip_return_low), ref Chip_return_low); + ser.Sync(nameof(Chip_return_high), ref Chip_return_high); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Mapper_WisdomTree.h b/libHawk/GBHawk/GBHawk/Mapper_WisdomTree.h new file mode 100644 index 0000000000..74ce6e112d --- /dev/null +++ b/libHawk/GBHawk/GBHawk/Mapper_WisdomTree.h @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include + +#include "Mapper_Base.h" + +using namespace std; + +namespace GBHawk +{ + class Mapper_WT : Mapper + { + public: + + uint32_t ROM_bank; + uint32_t ROM_mask; + + void Reset() + { + ROM_bank = 0; + ROM_mask = Core._rom.Length / 0x8000 - 1; + + // some games have sizes that result in a degenerate ROM, account for it here + if (ROM_mask > 4) { ROM_mask |= 3; } + if (ROM_mask > 0x100) { ROM_mask |= 0xFF; } + } + + uint8_t ReadMemory(uint32_t addr) + { + if (addr < 0x8000) + { + return Core._rom[ROM_bank * 0x8000 + addr]; + } + else + { + return 0xFF; + } + } + + /* + void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags) + { + if (addr < 0x8000) + { + SetCDLROM(flags, ROM_bank * 0x8000 + addr); + } + else + { + return; + } + } + */ + + uint8_t PeekMemory(uint32_t addr) + { + return ReadMemory(addr); + } + + void WriteMemory(uint32_t addr, uint8_t value) + { + if (addr < 0x4000) + { + ROM_bank = ((addr << 1) & 0x1ff) >> 1; + ROM_bank &= ROM_mask; + } + } + + void PokeMemory(uint32_t addr, uint8_t value) + { + WriteMemory(addr, value); + } + + void SyncState(Serializer ser) + { + ser.Sync(nameof(ROM_bank), ref ROM_bank); + ser.Sync(nameof(ROM_mask), ref ROM_mask); + } + }; +} diff --git a/libHawk/GBHawk/GBHawk/Memory.h b/libHawk/GBHawk/GBHawk/Memory.h index bcd0477b7f..532b623fbb 100644 --- a/libHawk/GBHawk/GBHawk/Memory.h +++ b/libHawk/GBHawk/GBHawk/Memory.h @@ -12,6 +12,7 @@ namespace GBHawk class PPU; class GBAudio; class SerialPort; + class Mapper; class MemoryManager { @@ -33,6 +34,7 @@ namespace GBHawk LR35902* cpu_pntr = nullptr; Timer* timer_pntr = nullptr; SerialPort* serialport_pntr = nullptr; + Mapper* mapper_pntr = nullptr; uint8_t* rom_1 = nullptr; uint8_t* rom_2 = nullptr; uint8_t* bios_rom = nullptr;