GBHawk: start C++ifying mappers
This commit is contained in:
parent
31c41f6279
commit
649f96b617
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
*/
|
||||
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue