GBHawk: start C++ifying mappers

This commit is contained in:
alyosha-tas 2020-03-26 09:39:44 -04:00
parent 31c41f6279
commit 649f96b617
21 changed files with 3402 additions and 8 deletions

View File

@ -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

View File

@ -157,6 +157,24 @@
<ClInclude Include="GBC_PPU.h" />
<ClInclude Include="GBHawk.h" />
<ClInclude Include="GB_PPU.h" />
<ClInclude Include="Mapper_Base.h" />
<ClInclude Include="Mapper_Camera.h" />
<ClInclude Include="Mapper_Default.h" />
<ClInclude Include="Mapper_HuC1.h" />
<ClInclude Include="Mapper_HuC3.h" />
<ClInclude Include="Mapper_MBC1.h" />
<ClInclude Include="Mapper_MBC1_Multi.h" />
<ClInclude Include="Mapper_MBC2.h" />
<ClInclude Include="Mapper_MBC3.h" />
<ClInclude Include="Mapper_MBC5.h" />
<ClInclude Include="Mapper_MBC6.h" />
<ClInclude Include="Mapper_MBC7.h" />
<ClInclude Include="Mapper_MMM01.h" />
<ClInclude Include="Mapper_RockMan8.h" />
<ClInclude Include="Mapper_Sachen_MMC1.h" />
<ClInclude Include="Mapper_Sachen_MMC2.h" />
<ClInclude Include="Mapper_TAMA5.h" />
<ClInclude Include="Mapper_WisdomTree.h" />
<ClInclude Include="SerialPort.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="Memory.h" />

View File

@ -0,0 +1,83 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
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);
}
*/
};
}

View File

@ -0,0 +1,167 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,87 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,197 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,311 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,203 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,199 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,124 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,295 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,167 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,87 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,488 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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;
}
};
}

View File

@ -0,0 +1,87 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,96 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,190 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,226 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,292 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -0,0 +1,81 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
#include <math.h>
#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);
}
};
}

View File

@ -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;