GBHawk: Clean up files and definitions

This commit is contained in:
alyosha-tas 2020-03-27 20:16:24 -04:00
parent b8233666ac
commit 98265cd066
31 changed files with 8709 additions and 8435 deletions

View File

@ -0,0 +1,188 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace BizHawk.Emulation.Cores.Nintendo.GBHawk
{
/// <summary>
/// static bindings into GBHawk.dll
/// </summary>
public static class LibGBHawk
{
# region Core
/// <returns>opaque state pointer</returns>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GB_create();
/// <param name="core">opaque state pointer</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_destroy(IntPtr core);
/// <summary>
/// Load BIOS and BASIC image. each must be 16K in size
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="bios">the rom data, can be disposed of once this function returns</param>
/// <param name="is_GBC">is it GBC console</param>
/// <param name="GBC_as_GBA">is it in GBA mode</param>
/// <returns>0 on success, negative value on failure.</returns>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int GB_load_bios(IntPtr core, byte[] bios, bool is_GBC, bool GBC_as_GBA);
/// <summary>
/// Load ROM image.
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="romdata_1">the rom data, can be disposed of once this function returns</param>
/// <param name="length_1">length of romdata in bytes</param>
/// <returns>0 on success, negative value on failure.</returns>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int GB_load(IntPtr core, byte[] romdata_1, uint length_1, uint RTC_init, uint RTC_offset);
/// <summary>
/// Advance a frame and send controller data.
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="ctrl1">controller data for player 1</param>
/// <param name="ctrl2">controller data for player 2</param>
/// <param name="render">length of romdata in bytes</param>
/// <param name="sound">Mapper number to load core with</param>
/// <returns>0 on success, negative value on failure.</returns>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool GB_frame_advance(IntPtr core, byte ctrl1, byte ctrl2, byte[] kbrows, bool render, bool sound);
/// <summary>
/// Get Video data
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="videobuf">where to send video to</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_get_video(IntPtr core, int[] videobuf);
/// <summary>
/// Get Video data
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="aud_buf">where to send left audio to</param>
/// <param name="n_samp">number of left samples</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint GB_get_audio(IntPtr core, int[] aud_buf, ref uint n_samp);
#endregion
#region State Save / Load
/// <summary>
/// Save State
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="saver">save buffer</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_save_state(IntPtr core, byte[] saver);
/// <summary>
/// Load State
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="loader">load buffer</param>
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_load_state(IntPtr core, byte[] loader);
#endregion
#region Memory Domain Functions
/// <summary>
/// Read the system bus
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="addr">system bus address</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte GB_getsysbus(IntPtr core, int addr);
/// <summary>
/// Read the VRAM
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="addr">vram address</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte GB_getvram(IntPtr core, int addr);
/// <summary>
/// Read the RAM
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="addr">ram address</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte GB_getram(IntPtr core, int addr);
#endregion
#region Tracer
/// <summary>
/// type of the cpu trace callback
/// </summary>
/// <param name="t">type of event</param>
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TraceCallback(int t);
/// <summary>
/// set a callback for trace logging
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="callback">null to clear</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_settracecallback(IntPtr core, TraceCallback callback);
/// <summary>
/// get the trace logger header length
/// </summary>
/// <param name="core">opaque state pointer</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int GB_getheaderlength(IntPtr core);
/// <summary>
/// get the trace logger disassembly length, a constant
/// </summary>
/// <param name="core">opaque state pointer</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int GB_getdisasmlength(IntPtr core);
/// <summary>
/// get the trace logger register string length, a constant
/// </summary>
/// <param name="core">opaque state pointer</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int GB_getregstringlength(IntPtr core);
/// <summary>
/// get the trace logger header
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="h">pointer to const char *</param>
/// <param name="callback">null to clear</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_getheader(IntPtr core, StringBuilder h, int l);
/// <summary>
/// get the register state from the cpu
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="r">pointer to const char *</param>
/// <param name="t">call type</param>
/// <param name="l">copy length, must be obtained from appropriate get legnth function</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_getregisterstate(IntPtr core, StringBuilder h, int t, int l);
/// <summary>
/// get the register state from the cpu
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="d">pointer to const char *</param>
/// <param name="t">call type</param>
/// <param name="l">copy length, must be obtained from appropriate get legnth function</param>
[DllImport("GBHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GB_getdisassembly(IntPtr core, StringBuilder h, int t, int l);
#endregion
}
}

View File

@ -5,11 +5,11 @@
#include "LR35902.h"
#include "GBAudio.h"
#include "PPU_Base.h"
#include "Memory.h"
#include "Timer.h"
#include "SerialPort.h"
#include "Mapper_Base.h"
#include "Mappers.h"
#include "PPU.h"
namespace GBHawk
{
@ -18,27 +18,74 @@ namespace GBHawk
public:
GBCore()
{
};
PPU* ppu;
LR35902 cpu;
GBAudio psg;
MemoryManager MemMap;
Timer timer;
SerialPort serialport;
Mapper* mapper;
void Load_BIOS(uint8_t* bios, bool GBC_console, bool GBC_as_GBA)
{
MemMap.Load_BIOS(bios, GBC_console, GBC_as_GBA);
}
void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, string MD5, uint32_t RTC_initial, uint32_t RTC_offset)
{
MemMap.Load_ROM(ext_rom_1, ext_rom_size_1);
// After we load the ROM we need to initialize the rest of the components (ppu and mapper)
// tell the cpu the console type
cpu.is_GBC = MemMap.is_GBC;
//initialize system components
// initialize the proper ppu
if (MemMap.is_GBC)
{
if ((MemMap.header[0x43] != 0x80) && (MemMap.header[0x43] != 0xC0))
{
ppu = new GBC_GB_PPU();
}
else
{
ppu = new GBC_PPU();
}
}
else
{
ppu = new GB_PPU();
}
MemMap.ppu_pntr = &ppu[0];
// initialize the proper mapper
Setup_Mapper(MD5, RTC_initial, RTC_offset);
// set up pointers
MemMap.cpu_pntr = &cpu;
MemMap.ppu_pntr = &ppu;
MemMap.psg_pntr = &psg;
MemMap.timer_pntr = &timer;
MemMap.serialport_pntr = &serialport;
cpu.mem_ctrl = &MemMap;
ppu.FlagI = &cpu.FlagI;
ppu.in_vblank = &MemMap.in_vblank;
ppu.cpu_LY = &cpu.LY;
ppu.REG_FFFF = &MemMap.REG_FFFF;
ppu.REG_FF0F = &MemMap.REG_FF0F;
ppu._scanlineCallbackLine = &MemMap._scanlineCallbackLine;
ppu.OAM = &MemMap.OAM[0];
ppu.VRAM = &MemMap.VRAM[0];
ppu.VRAM_Bank = &MemMap.VRAM_Bank;
ppu.cpu_halted = &cpu.halted;
ppu._vidbuffer = &MemMap._vidbuffer[0];
ppu.color_palette = &MemMap.color_palette[0];
ppu.HDMA_transfer = &MemMap.HDMA_transfer;
ppu.GBC_compat = &MemMap.GBC_compat;
MemMap.ppu_pntr->FlagI = &cpu.FlagI;
MemMap.ppu_pntr->in_vblank = &MemMap.in_vblank;
MemMap.ppu_pntr->cpu_LY = &cpu.LY;
MemMap.ppu_pntr->REG_FFFF = &MemMap.REG_FFFF;
MemMap.ppu_pntr->REG_FF0F = &MemMap.REG_FF0F;
MemMap.ppu_pntr->_scanlineCallbackLine = &MemMap._scanlineCallbackLine;
MemMap.ppu_pntr->OAM = &MemMap.OAM[0];
MemMap.ppu_pntr->VRAM = &MemMap.VRAM[0];
MemMap.ppu_pntr->VRAM_Bank = &MemMap.VRAM_Bank;
MemMap.ppu_pntr->cpu_halted = &cpu.halted;
MemMap.ppu_pntr->_vidbuffer = &MemMap._vidbuffer[0];
MemMap.ppu_pntr->color_palette = &MemMap.color_palette[0];
MemMap.ppu_pntr->HDMA_transfer = &MemMap.HDMA_transfer;
MemMap.ppu_pntr->GBC_compat = &MemMap.GBC_compat;
timer.FlagI = &cpu.FlagI;
timer.REG_FFFF = &MemMap.REG_FFFF;
@ -53,31 +100,13 @@ namespace GBHawk
psg.double_speed = &MemMap.double_speed;
psg.timer_div_reg = &timer.divider_reg;
mapper.addr_access = &MemMap.addr_access;
mapper.Acc_X_state = &MemMap.Acc_X_state;
mapper.Acc_Y_state = &MemMap.Acc_Y_state;
mapper.ROM_Length = &MemMap.ROM_Length;
mapper.Cart_RAM_Length = &MemMap.Cart_RAM_Length;
mapper.ROM = &MemMap.ROM[0];
mapper.Cart_RAM = &MemMap.Cart_RAM[0];
};
PPU ppu;
LR35902 cpu;
GBAudio psg;
MemoryManager MemMap;
Timer timer;
SerialPort serialport;
Mapper mapper;
void Load_BIOS(uint8_t* bios, bool GBC_console)
{
MemMap.Load_BIOS(bios, GBC_console);
}
void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, uint32_t ext_rom_mapper_1, uint8_t* ext_rom_2, uint32_t ext_rom_size_2, uint32_t ext_rom_mapper_2)
{
MemMap.Load_ROM(ext_rom_1, ext_rom_size_1, ext_rom_mapper_1, ext_rom_2, ext_rom_size_2, ext_rom_mapper_2);
MemMap.mapper_pntr->addr_access = &MemMap.addr_access;
MemMap.mapper_pntr->Acc_X_state = &MemMap.Acc_X_state;
MemMap.mapper_pntr->Acc_Y_state = &MemMap.Acc_Y_state;
MemMap.mapper_pntr->ROM_Length = &MemMap.ROM_Length;
MemMap.mapper_pntr->Cart_RAM_Length = &MemMap.Cart_RAM_Length;
MemMap.mapper_pntr->ROM = &MemMap.ROM[0];
MemMap.mapper_pntr->Cart_RAM = &MemMap.Cart_RAM[0];
}
bool FrameAdvance(uint8_t controller_1, uint8_t controller_2, uint8_t* kb_rows_ptr, bool render, bool rendersound)
@ -86,7 +115,6 @@ namespace GBHawk
MemMap.controller_byte_1 = controller_1;
MemMap.controller_byte_2 = controller_2;
MemMap.kb_rows = kb_rows_ptr;
MemMap.start_pressed = (controller_1 & 0x80) > 0;
MemMap.lagged = true;
uint32_t scanlinesPerFrame = 262;
@ -119,11 +147,226 @@ namespace GBHawk
return psg.master_audio_clock;
}
void Setup_Mapper(string MD5, uint32_t RTC_initial, uint32_t RTC_offset)
{
// setup up mapper based on header entry
string mppr;
switch (MemMap.header[0x47])
{
case 0x0: mapper = new Mapper_Default(); mppr = "NROM"; break;
case 0x1: mapper = new Mapper_MBC1(); mppr = "MBC1"; break;
case 0x2: mapper = new Mapper_MBC1(); mppr = "MBC1"; break;
case 0x3: mapper = new Mapper_MBC1(); mppr = "MBC1"; MemMap.has_bat = true; break;
case 0x5: mapper = new Mapper_MBC2(); mppr = "MBC2"; break;
case 0x6: mapper = new Mapper_MBC2(); mppr = "MBC2"; MemMap.has_bat = true; break;
case 0x8: mapper = new Mapper_Default(); mppr = "NROM"; break;
case 0x9: mapper = new Mapper_Default(); mppr = "NROM"; MemMap.has_bat = true; break;
case 0xB: mapper = new Mapper_MMM01(); mppr = "MMM01"; break;
case 0xC: mapper = new Mapper_MMM01(); mppr = "MMM01"; break;
case 0xD: mapper = new Mapper_MMM01(); mppr = "MMM01"; MemMap.has_bat = true; break;
case 0xF: mapper = new Mapper_MBC3(); mppr = "MBC3"; MemMap.has_bat = true; break;
case 0x10: mapper = new Mapper_MBC3(); mppr = "MBC3"; MemMap.has_bat = true; break;
case 0x11: mapper = new Mapper_MBC3(); mppr = "MBC3"; break;
case 0x12: mapper = new Mapper_MBC3(); mppr = "MBC3"; break;
case 0x13: mapper = new Mapper_MBC3(); mppr = "MBC3"; MemMap.has_bat = true; break;
case 0x19: mapper = new Mapper_MBC5(); mppr = "MBC5"; break;
case 0x1A: mapper = new Mapper_MBC5(); mppr = "MBC5"; MemMap.has_bat = true; break;
case 0x1B: mapper = new Mapper_MBC5(); mppr = "MBC5"; break;
case 0x1C: mapper = new Mapper_MBC5(); mppr = "MBC5"; break;
case 0x1D: mapper = new Mapper_MBC5(); mppr = "MBC5"; break;
case 0x1E: mapper = new Mapper_MBC5(); mppr = "MBC5"; MemMap.has_bat = true; break;
case 0x20: mapper = new Mapper_MBC6(); mppr = "MBC6"; break;
case 0x22: mapper = new Mapper_MBC7(); mppr = "MBC7"; MemMap.has_bat = true; break;
case 0xFC: mapper = new Mapper_Camera(); mppr = "CAM"; MemMap.has_bat = true; break;
case 0xFD: mapper = new Mapper_TAMA5(); mppr = "TAMA5"; MemMap.has_bat = true; break;
case 0xFE: mapper = new Mapper_HuC3(); mppr = "HuC3"; break;
case 0xFF: mapper = new Mapper_HuC1(); mppr = "HuC1"; break;
// Bootleg mappers
// NOTE: Sachen mapper selection does not account for scrambling, so if another bootleg mapper
// identifies itself as 0x31, this will need to be modified
case 0x31: mapper = new Mapper_Sachen2(); mppr = "Schn2"; break;
case 0x4:
case 0x7:
case 0xA:
case 0xE:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
case 0x18:
case 0x1F:
case 0x21:
default:
// mapper not implemented
mapper = nullptr;
}
// special case for multi cart mappers
if ((MD5 == "97122B9B183AAB4079C8D36A4CE6E9C1") ||
(MD5 == "9FB9C42CF52DCFDCFBAD5E61AE1B5777") ||
(MD5 == "CF1F58AB72112716D3C615A553B2F481")
)
{
mapper = new Mapper_MBC1_Multi();
}
// Wisdom Tree does not identify their mapper, so use hash instead
if ((MD5 == "2C07CAEE51A1F0C91C72C7C6F380B0F6") || // Joshua
(MD5 == "37E017C8D1A45BAB609FB5B43FB64337") || // Spiritual Warfare
(MD5 == "AB1FA0ED0207B1D0D5F401F0CD17BEBF") || // Exodus
(MD5 == "BA2AC3587B3E1B36DE52E740274071B0") || // Bible - KJV
(MD5 == "8CDDB8B2DCD3EC1A3FDD770DF8BDA07C") // Bible - NIV
)
{
mapper = new Mapper_WT();
mppr = "Wtree";
}
// special case for bootlegs
if ((MD5 == "CAE0998A899DF2EE6ABA8E7695C2A096"))
{
mapper = new Mapper_RM8();
}
if ((MD5 == "D3C1924D847BC5D125BF54C2076BE27A"))
{
mapper = new Mapper_Sachen1();
mppr = "Schn1";
}
MemMap.Cart_RAM = nullptr;
switch (MemMap.header[0x49])
{
case 1:
MemMap.Cart_RAM = new uint8_t[0x800];
break;
case 2:
MemMap.Cart_RAM = new uint8_t[0x2000];
break;
case 3:
MemMap.Cart_RAM = new uint8_t[0x8000];
break;
case 4:
MemMap.Cart_RAM = new uint8_t[0x20000];
break;
case 5:
MemMap.Cart_RAM = new uint8_t[0x10000];
break;
case 0:
MemMap.has_bat = false;
break;
}
// Sachen maper not known to have RAM
if ((mppr == "Schn1") || (mppr == "Schn2"))
{
MemMap.Cart_RAM = nullptr;
MemMap.Use_MT = true;
}
// mbc2 carts have built in RAM
if (mppr == "MBC2")
{
MemMap.Cart_RAM = new uint8_t[0x200];
}
// mbc7 has 256 bytes of RAM, regardless of any header info
if (mppr == "MBC7")
{
MemMap.Cart_RAM = new uint8_t[0x100];
MemMap.has_bat = true;
}
// TAMA5 has 0x1000 bytes of RAM, regardless of any header info
if (mppr == "TAMA5")
{
MemMap.Cart_RAM = new uint8_t[0x20];
MemMap.has_bat = true;
}
MemMap.Cart_RAM_Length = sizeof(MemMap.Cart_RAM);
if (MemMap.Cart_RAM != nullptr && (mppr != "MBC7"))
{
for (uint32_t i = 0; i < MemMap.Cart_RAM_Length; i++)
{
MemMap.Cart_RAM[i] = 0xFF;
}
}
// Extra RTC initialization for mbc3, HuC3, and TAMA5
if (mppr == "MBC3")
{
MemMap.Use_MT = true;
mapper->RTC_Get(RTC_offset, 5);
int days = (int)floor(RTC_initial / 86400.0);
int days_upper = ((days & 0x100) >> 8) | ((days & 0x200) >> 2);
mapper->RTC_Get(days_upper, 4);
mapper->RTC_Get(days & 0xFF, 3);
int remaining = RTC_initial - (days * 86400);
int hours = (int)floor(remaining / 3600.0);
mapper->RTC_Get(hours & 0xFF, 2);
remaining = remaining - (hours * 3600);
int minutes = (int)floor(remaining / 60.0);
mapper->RTC_Get(minutes & 0xFF, 1);
remaining = remaining - (minutes * 60);
mapper->RTC_Get(remaining & 0xFF, 0);
}
if (mppr == "HuC3")
{
MemMap.Use_MT = true;
int years = (int)floor(RTC_initial / 31536000.0);
mapper->RTC_Get(years, 24);
int remaining = RTC_initial - (years * 31536000);
int days = (int)floor(remaining / 86400.0);
int days_upper = (days >> 8) & 0xF;
mapper->RTC_Get(days_upper, 20);
mapper->RTC_Get(days & 0xFF, 12);
remaining = remaining - (days * 86400);
int minutes = (int)floor(remaining / 60.0);
int minutes_upper = (minutes >> 8) & 0xF;
mapper->RTC_Get(minutes_upper, 8);
mapper->RTC_Get(remaining & 0xFF, 0);
}
if (mppr == "TAMA5")
{
MemMap.Use_MT = true;
// currently no date / time input for TAMA5
}
}
#pragma region State Save / Load
void SaveState(uint8_t* saver)
{
saver = ppu.SaveState(saver);
saver = ppu->SaveState(saver);
saver = cpu.SaveState(saver);
saver = psg.SaveState(saver);
saver = MemMap.SaveState(saver);
@ -131,7 +374,7 @@ namespace GBHawk
void LoadState(uint8_t* loader)
{
loader = ppu.LoadState(loader);
loader = ppu->LoadState(loader);
loader = cpu.LoadState(loader);
loader = psg.LoadState(loader);
loader = MemMap.LoadState(loader);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -26,16 +26,18 @@ GBHawk_EXPORT void GB_destroy(GBCore* p)
std::free(p);
}
// load bios and basic into the core
GBHawk_EXPORT void GB_load_bios(GBCore* p, uint8_t* bios, bool GBC_console)
// load bios into the core
GBHawk_EXPORT void GB_load_bios(GBCore* p, uint8_t* bios, bool GBC_console, bool GBC_as_GBA)
{
p->Load_BIOS(bios, GBC_console);
p->Load_BIOS(bios, GBC_console, GBC_as_GBA);
}
// load a rom into the core
GBHawk_EXPORT void GB_load(GBCore* p, uint8_t* rom_1, uint32_t size_1, uint32_t mapper_1, uint8_t* rom_2, uint32_t size_2, uint8_t mapper_2)
GBHawk_EXPORT void GB_load(GBCore* p, uint8_t* rom_1, uint32_t size_1, uint32_t RTC_initial, uint32_t RTC_offset)
{
p->Load_ROM(rom_1, size_1, mapper_1, rom_2, size_2, mapper_2);
string MD5;
p->Load_ROM(rom_1, size_1, MD5, RTC_initial, RTC_offset);
}
// advance a frame

View File

@ -153,39 +153,19 @@
<ItemGroup>
<ClInclude Include="GBAudio.h" />
<ClInclude Include="Core.h" />
<ClInclude Include="GBC_GB_PPU.h" />
<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="Mappers.h" />
<ClInclude Include="SerialPort.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="Memory.h" />
<ClInclude Include="PPU_Base.h" />
<ClInclude Include="PPU.h" />
<ClInclude Include="LR35902.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="GBHawk.cpp" />
<ClCompile Include="Memory.cpp" />
<ClCompile Include="LR35902.cpp" />
<ClCompile Include="PPU_Base.cpp" />
<ClCompile Include="PPU.cpp" />
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />

File diff suppressed because it is too large Load Diff

View File

@ -1,350 +0,0 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
using namespace std;
namespace GBHawk
{
class MemoryManager;
class Mapper
{
public:
Mapper()
{
}
uint8_t* ROM = nullptr;
uint8_t* Cart_RAM = nullptr;
uint32_t* ROM_Length = nullptr;
uint32_t* Cart_RAM_Length = nullptr;
uint32_t* addr_access = nullptr;
uint32_t* Acc_X_state = nullptr;
uint32_t* Acc_Y_state = nullptr;
// Generic Mapper Variables
bool RAM_enable;
bool sel_mode;
bool IR_signal;
uint32_t ROM_bank;
uint32_t RAM_bank;
uint32_t ROM_mask;
uint32_t RAM_mask;
// Common
bool halt;
uint32_t RTC_timer;
uint32_t RTC_low_clock;
// HuC3
bool timer_read;
uint8_t control;
uint8_t chip_read;
uint32_t time_val_shift;
uint32_t time;
uint32_t RTC_seconds;
// MBC3
uint8_t RTC_regs[5] = {};
uint8_t RTC_regs_latch[5] = {};
bool RTC_regs_latch_wr;
uint32_t RTC_offset;
// camera
bool regs_enable;
uint8_t regs_cam[0x80] = {};
// sachen
bool locked, locked_GBC, finished, reg_access;
uint32_t ROM_bank_mask;
uint32_t BASE_ROM_Bank;
uint32_t addr_last;
uint32_t counter;
// TAMA5
uint8_t RTC_regs_TAMA[10] = {};
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;
// MBC7
bool RAM_enable_1, RAM_enable_2, is_erased;
uint8_t acc_x_low;
uint8_t acc_x_high;
uint8_t acc_y_low;
uint8_t acc_y_high;
// EEPROM related
bool CS_prev;
bool CLK_prev;
bool DI_prev;
bool DO;
bool instr_read;
bool perf_instr;
bool WR_EN;
bool countdown_start;
uint32_t instr_bit_counter;
uint32_t instr;
uint32_t EE_addr;
uint32_t instr_case;
uint32_t instr_clocks;
uint32_t EE_value;
uint32_t countdown;
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 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);
}
*/
#pragma region State Save / Load
uint8_t* SaveState(uint8_t* saver)
{
saver = bool_saver(RAM_enable, saver);
saver = bool_saver(sel_mode, saver);
saver = bool_saver(IR_signal, saver);
saver = int_saver(ROM_bank, saver);
saver = int_saver(RAM_bank, saver);
saver = int_saver(ROM_mask, saver);
saver = int_saver(RAM_mask, saver);
saver = bool_saver(halt, saver);
saver = int_saver(RTC_timer, saver);
saver = int_saver(RTC_low_clock, saver);
saver = bool_saver(timer_read, saver);
saver = byte_saver(control, saver);
saver = byte_saver(chip_read, saver);
saver = int_saver(time_val_shift, saver);
saver = int_saver(time, saver);
saver = int_saver(RTC_seconds, saver);
for (int i = 0; i < 5; i++) { saver = byte_saver(RTC_regs[i], saver); }
for (int i = 0; i < 5; i++) { saver = byte_saver(RTC_regs_latch[i], saver); }
saver = bool_saver(RTC_regs_latch_wr, saver);
saver = int_saver(RTC_offset, saver);
saver = bool_saver(regs_enable, saver);
for (int i = 0; i < 5; i++) { saver = byte_saver(regs_cam[i], saver); }
saver = bool_saver(locked, saver);
saver = bool_saver(locked_GBC, saver);
saver = bool_saver(finished, saver);
saver = bool_saver(reg_access, saver);
saver = int_saver(ROM_bank_mask, saver);
saver = int_saver(BASE_ROM_Bank, saver);
saver = int_saver(addr_last, saver);
saver = int_saver(counter, saver);
for (int i = 0; i < 10; i++) { saver = byte_saver(RTC_regs_TAMA[i], saver); }
saver = byte_saver(Chip_return_low, saver);
saver = byte_saver(Chip_return_high, saver);
saver = int_saver(ctrl, saver);
saver = int_saver(RAM_addr_low, saver);
saver = int_saver(RAM_addr_high, saver);
saver = int_saver(RAM_val_low, saver);
saver = int_saver(RAM_val_high, saver);
saver = bool_saver(RAM_enable_1, saver);
saver = bool_saver(RAM_enable_2, saver);
saver = bool_saver(is_erased, saver);
saver = byte_saver(acc_x_low, saver);
saver = byte_saver(acc_x_high, saver);
saver = byte_saver(acc_y_low, saver);
saver = byte_saver(acc_y_high, saver);
// EEPROM related
saver = bool_saver(CS_prev, saver);
saver = bool_saver(CLK_prev, saver);
saver = bool_saver(DI_prev, saver);
saver = bool_saver(DO, saver);
saver = bool_saver(instr_read, saver);
saver = bool_saver(perf_instr, saver);
saver = bool_saver(WR_EN, saver);
saver = bool_saver(countdown_start, saver);
saver = int_saver(instr_bit_counter, saver);
saver = int_saver(instr, saver);
saver = int_saver(EE_addr, saver);
saver = int_saver(instr_case, saver);
saver = int_saver(instr_clocks, saver);
saver = int_saver(EE_value, saver);
saver = int_saver(countdown, saver);
return saver;
}
uint8_t* LoadState(uint8_t* loader)
{
loader = bool_loader(&RAM_enable, loader);
loader = bool_loader(&sel_mode, loader);
loader = bool_loader(&IR_signal, loader);
loader = int_loader(&ROM_bank, loader);
loader = int_loader(&RAM_bank, loader);
loader = int_loader(&ROM_mask, loader);
loader = int_loader(&RAM_mask, loader);
loader = bool_loader(&halt, loader);
loader = int_loader(&RTC_timer, loader);
loader = int_loader(&RTC_low_clock, loader);
loader = bool_loader(&timer_read, loader);
loader = byte_loader(&control, loader);
loader = byte_loader(&chip_read, loader);
loader = int_loader(&time_val_shift, loader);
loader = int_loader(&time, loader);
loader = int_loader(&RTC_seconds, loader);
for (int i = 0; i < 5; i++) { loader = byte_loader(&RTC_regs[i], loader); }
for (int i = 0; i < 5; i++) { loader = byte_loader(&RTC_regs_latch[i], loader); }
loader = bool_loader(&RTC_regs_latch_wr, loader);
loader = int_loader(&RTC_offset, loader);
loader = bool_loader(&regs_enable, loader);
for (int i = 0; i < 5; i++) { loader = byte_loader(&regs_cam[i], loader); }
loader = bool_loader(&locked, loader);
loader = bool_loader(&locked_GBC, loader);
loader = bool_loader(&finished, loader);
loader = bool_loader(&reg_access, loader);
loader = int_loader(&ROM_bank_mask, loader);
loader = int_loader(&BASE_ROM_Bank, loader);
loader = int_loader(&addr_last, loader);
loader = int_loader(&counter, loader);
for (int i = 0; i < 10; i++) { loader = byte_loader(&RTC_regs_TAMA[i], loader); }
loader = byte_loader(&Chip_return_low, loader);
loader = byte_loader(&Chip_return_high, loader);
loader = int_loader(&ctrl, loader);
loader = int_loader(&RAM_addr_low, loader);
loader = int_loader(&RAM_addr_high, loader);
loader = int_loader(&RAM_val_low, loader);
loader = int_loader(&RAM_val_high, loader);
loader = bool_loader(&RAM_enable_1, loader);
loader = bool_loader(&RAM_enable_2, loader);
loader = bool_loader(&is_erased, loader);
loader = byte_loader(&acc_x_low, loader);
loader = byte_loader(&acc_x_high, loader);
loader = byte_loader(&acc_y_low, loader);
loader = byte_loader(&acc_y_high, loader);
// EEPROM related
loader = bool_loader(&CS_prev, loader);
loader = bool_loader(&CLK_prev, loader);
loader = bool_loader(&DI_prev, loader);
loader = bool_loader(&DO, loader);
loader = bool_loader(&instr_read, loader);
loader = bool_loader(&perf_instr, loader);
loader = bool_loader(&WR_EN, loader);
loader = bool_loader(&countdown_start, loader);
loader = int_loader(&instr_bit_counter, loader);
loader = int_loader(&instr, loader);
loader = int_loader(&EE_addr, loader);
loader = int_loader(&instr_case, loader);
loader = int_loader(&instr_clocks, loader);
loader = int_loader(&EE_value, loader);
loader = int_loader(&countdown, loader);
return loader;
}
uint8_t* bool_saver(bool to_save, uint8_t* saver)
{
*saver = (uint8_t)(to_save ? 1 : 0); saver++;
return saver;
}
uint8_t* byte_saver(uint8_t to_save, uint8_t* saver)
{
*saver = to_save; saver++;
return saver;
}
uint8_t* int_saver(uint32_t to_save, uint8_t* saver)
{
*saver = (uint8_t)(to_save & 0xFF); saver++; *saver = (uint8_t)((to_save >> 8) & 0xFF); saver++;
*saver = (uint8_t)((to_save >> 16) & 0xFF); saver++; *saver = (uint8_t)((to_save >> 24) & 0xFF); saver++;
return saver;
}
uint8_t* bool_loader(bool* to_load, uint8_t* loader)
{
to_load[0] = *to_load == 1; loader++;
return loader;
}
uint8_t* byte_loader(uint8_t* to_load, uint8_t* loader)
{
to_load[0] = *loader; loader++;
return loader;
}
uint8_t* int_loader(uint32_t* to_load, uint8_t* loader)
{
to_load[0] = *loader; loader++; to_load[0] |= (*loader << 8); loader++;
to_load[0] |= (*loader << 16); loader++; to_load[0] |= (*loader << 24); loader++;
return loader;
}
#pragma endregion
};
}

View File

@ -1,148 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
RAM_bank = 0;
RAM_enable = false;
ROM_mask = ROM_Length[0] / 0x4000 - 1;
RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1;
regs_enable = false;
}
uint8_t ReadMemory(uint32_t addr)
{
if (addr < 0x4000)
{
return ROM[addr];
}
else if (addr < 0x8000)
{
return 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) < Cart_RAM_Length[0]))
{
return 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) < Cart_RAM_Length[0]))
{
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_cam[(addr & 0x7F)] = (uint8_t)(value & 0x7);
}
else
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value;
}
}
}
}
void PokeMemory(uint32_t addr, uint8_t value)
{
WriteMemory(addr, value);
}
};
}

View File

@ -1,87 +0,0 @@
#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 ROM[addr];
}
else
{
if (Cart_RAM_Length > 0)
{
return Cart_RAM[addr - 0xA000];
}
else
{
return 0;
}
}
}
/*
void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags)
{
if (addr < 0x8000)
{
SetCDLROM(flags, addr);
}
else
{
if (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 (Cart_RAM_Length > 0)
{
Cart_RAM[addr - 0xA000] = value;
}
}
}
void PokeMemory(uint32_t addr, uint8_t value)
{
WriteMemory(addr, value);
}
};
}

View File

@ -1,180 +0,0 @@
#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:
void Reset()
{
ROM_bank = 0;
RAM_bank = 0;
RAM_enable = false;
ROM_mask = ROM_Length[0] / 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 (Cart_RAM_Length[0] > 0)
{
RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1;
if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; }
}
}
uint8_t ReadMemory(uint32_t addr)
{
if (addr < 0x4000)
{
return ROM[addr];
}
else if (addr < 0x8000)
{
return ROM[(addr - 0x4000) + ROM_bank * 0x4000];
}
else if ((addr >= 0xA000) && (addr < 0xC000))
{
if (RAM_enable)
{
if (Cart_RAM_Length[0] > 0)
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])
{
return 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 (Cart_RAM != null)
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])
{
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 (Cart_RAM_Length[0] > 0)
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])
{
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);
}
};
}

View File

@ -1,278 +0,0 @@
#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:
void Reset()
{
ROM_bank = 0;
RAM_bank = 0;
RAM_enable = false;
ROM_mask = ROM_Length[0] / 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 (Cart_RAM_Length[0] > 0)
{
RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1;
if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; }
}
}
uint8_t ReadMemory(uint32_t addr)
{
if (addr < 0x4000)
{
return ROM[addr];
}
else if (addr < 0x8000)
{
return 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 (Cart_RAM_Length[0] > 0)
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])
{
return 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 (Cart_RAM != null)
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])
{
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 (Cart_RAM_Length[0] > 0)
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])
{
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 |= (uint32_t)((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 |= (uint32_t)((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);
}
}
}
}
}
}
};
}

View File

@ -1,186 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
RAM_bank = 0;
RAM_enable = false;
sel_mode = false;
ROM_mask = ROM_Length[0] / 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 (Cart_RAM_Length[0] > 0)
{
RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1;
if (Cart_RAM_Length[0] == 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 ROM[(ROM_bank & 0x60) * 0x4000 + addr];
}
else
{
return ROM[addr];
}
}
else if (addr < 0x8000)
{
return ROM[(addr - 0x4000) + ROM_bank * 0x4000];
}
else
{
if (Cart_RAM_Length[0] > 0)
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
return 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 (Cart_RAM != null)
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
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 && (Cart_RAM_Length[0] > 0))
{
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 && (Cart_RAM_Length[0] > 0))
{
ROM_bank &= 0x1F;
ROM_bank &= ROM_mask;
}
else
{
RAM_bank = 0;
}
}
}
else
{
if (Cart_RAM_Length[0] > 0)
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value;
}
}
}
}
void PokeMemory(uint32_t addr, uint8_t value)
{
WriteMemory(addr, value);
}
};
}

View File

@ -1,182 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
RAM_bank = 0;
RAM_enable = false;
sel_mode = false;
ROM_mask = (ROM_Length[0] / 0x4000 * 2) - 1; // due to how mapping works, we want a 1 bit higher mask
RAM_mask = 0;
if (Cart_RAM_Length[0] > 0)
{
RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1;
if (Cart_RAM_Length[0] == 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 ROM[((ROM_bank & 0x60) >> 1) * 0x4000 + addr];
}
else
{
return ROM[addr];
}
}
else if (addr < 0x8000)
{
return ROM[(addr - 0x4000) + (((ROM_bank & 0x60) >> 1) | (ROM_bank & 0xF)) * 0x4000];
}
else
{
if (Cart_RAM_Length[0] > 0)
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
return 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 (Cart_RAM != null)
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
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 && (Cart_RAM_Length[0] > 0))
{
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 && (Cart_RAM_Length[0] > 0))
{
ROM_bank &= 0x1F;
ROM_bank &= ROM_mask;
}
else
{
RAM_bank = 0;
}
}
}
else
{
if (Cart_RAM_Length[0] > 0)
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value;
}
}
}
}
void PokeMemory(uint32_t addr, uint8_t value)
{
WriteMemory(addr, value);
}
};
}

View File

@ -1,111 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
RAM_bank = 0;
RAM_enable = false;
ROM_mask = ROM_Length[0] / 0x4000 - 1;
}
uint8_t ReadMemory(uint32_t addr)
{
if (addr < 0x4000)
{
return ROM[addr];
}
else if (addr < 0x8000)
{
return ROM[(addr - 0x4000) + ROM_bank * 0x4000];
}
else if ((addr >= 0xA000) && (addr < 0xA200))
{
if (RAM_enable)
{
return 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)
{
Cart_RAM[addr - 0xA000] = (uint8_t)(value & 0xF);
}
}
}
void PokeMemory(uint32_t addr, uint8_t value)
{
WriteMemory(addr, value);
}
};
}

View File

@ -1,266 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
RAM_bank = 0;
RAM_enable = false;
ROM_mask = ROM_Length[0] / 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 (Cart_RAM_Length[0] > 0)
{
RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1;
if (Cart_RAM_Length[0] == 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 ROM[addr];
}
else if (addr < 0x8000)
{
return ROM[(addr - 0x4000) + ROM_bank * 0x4000];
}
else
{
if (RAM_enable)
{
if ((Cart_RAM_Length[0] > 0) && (RAM_bank <= RAM_mask))
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])
{
return 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 ((Cart_RAM != null) && (RAM_bank <= RAM_mask))
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])
{
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 ((Cart_RAM_Length[0] > 0) && (RAM_bank <= RAM_mask))
{
if (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0])
{
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;
}
}
}
}
}
}
}
}
}
};
}

View File

@ -1,152 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
RAM_bank = 0;
RAM_enable = false;
ROM_mask = ROM_Length[0] / 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 (Cart_RAM_Length[0] > 0)
{
RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1;
if (Cart_RAM_Length[0] == 0x800) { RAM_mask = 0; }
}
}
uint8_t ReadMemory(uint32_t addr)
{
if (addr < 0x4000)
{
return ROM[addr];
}
else if (addr < 0x8000)
{
return ROM[(addr - 0x4000) + ROM_bank * 0x4000];
}
else
{
if (Cart_RAM_Length[0] > 0)
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
return 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 (Cart_RAM != null)
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
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 (Cart_RAM_Length[0] > 0)
{
if (RAM_enable && (((addr - 0xA000) + RAM_bank * 0x2000) < Cart_RAM_Length[0]))
{
Cart_RAM[(addr - 0xA000) + RAM_bank * 0x2000] = value;
}
}
}
}
void PokeMemory(uint32_t addr, uint8_t value)
{
WriteMemory(addr, value);
}
};
}

View File

@ -1,87 +0,0 @@
#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 ROM[addr];
}
else
{
if (Cart_RAM_Length[0] > 0)
{
return Cart_RAM[addr - 0xA000];
}
else
{
return 0;
}
}
}
/*
void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags)
{
if (addr < 0x8000)
{
SetCDLROM(flags, addr);
}
else
{
if (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 (Cart_RAM_Length[0] > 0)
{
Cart_RAM[addr - 0xA000] = value;
}
}
}
void PokeMemory(uint32_t addr, uint8_t value)
{
WriteMemory(addr, value);
}
};
}

View File

@ -1,432 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
RAM_enable_1 = RAM_enable_2 = false;
ROM_mask = ROM_Length[0] / 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 ROM[addr];
}
else if (addr < 0x8000)
{
return 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);
}
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)(Acc_X_state[0] & 0xFF);
acc_x_high = (uint8_t)((Acc_X_state[0] & 0xFF00) >> 8);
acc_y_low = (uint8_t)(Acc_Y_state[0] & 0xFF);
acc_y_high = (uint8_t)((Acc_Y_state[0] & 0xFF00) >> 8);
}
}
else if ((addr & 0xA0F0) == 0xA080)
{
// EEPROM writes
EEPROM_write(value);
}
}
void EEPROM_write(uint8_t value)
{
bool CS = (value & 0x80) > 0;
bool CLK = (value & 0x40) > 0;
bool DI = (value & 0x2) > 0;
// 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++)
{
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)
{
Cart_RAM[EE_addr * 2] = 0xFF;
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++)
{
Cart_RAM[i * 2] = (uint8_t)(EE_value & 0xFF);
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)
{
Cart_RAM[EE_addr * 2] = (uint8_t)(EE_value & 0xFF);
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 = ((Cart_RAM[EE_addr * 2 + 1] >> (7 - instr_clocks)) & 1) == 1;
}
else if ((instr_clocks >= 8) && (instr_clocks <= 15))
{
DO = ((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

@ -1,87 +0,0 @@
#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 ROM[addr];
}
else
{
if (Cart_RAM_Length[0] > 0)
{
return Cart_RAM[addr - 0xA000];
}
else
{
return 0;
}
}
}
/*
void MapCDL(uint32_t addr, LR35902.eCDLogMemFlags flags)
{
if (addr < 0x8000)
{
SetCDLROM(flags, addr);
}
else
{
if (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 (Cart_RAM_Length[0] > 0)
{
Cart_RAM[addr - 0xA000] = value;
}
}
}
void PokeMemory(uint32_t addr, uint8_t value)
{
WriteMemory(addr, value);
}
};
}

View File

@ -1,87 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
ROM_mask = ROM_Length[0] / 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 ROM[addr];
}
else if (addr < 0x8000)
{
return 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);
}
};
}

View File

@ -1,167 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
ROM_mask = ROM_Length[0] / 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 ROM[addr + BASE_ROM_Bank * 0x4000];
}
else if (addr < 0x8000)
{
return 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 (((addr_access[0] & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (addr_access[0] >= 0x100))
{
counter++;
}
if (addr_access[0] >= 0x100)
{
addr_last = addr_access[0];
}
if (counter == 0x30)
{
locked = false;
}
}
}
};
}

View File

@ -1,200 +0,0 @@
#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:
void Reset()
{
ROM_bank = 1;
ROM_mask = ROM_Length[0] / 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 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 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 (((addr_access[0] & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (addr_access[0] >= 0x100))
{
counter++;
}
if (addr_access[0] >= 0x100)
{
addr_last = addr_access[0];
}
if (counter == 0x30)
{
locked = false;
locked_GBC = true;
counter = 0;
}
}
else if (locked_GBC)
{
if (((addr_access[0] & 0x8000) == 0) && ((addr_last & 0x8000) > 0) && (addr_access[0] >= 0x100))
{
counter++;
}
if (addr_access[0] >= 0x100)
{
addr_last = addr_access[0];
}
if (counter == 0x30)
{
locked_GBC = false;
finished = true;
}
// The above condition seems to never be reached as described in the mapper notes
// so for now add this one
if ((addr_access[0] == 0x133) && (counter == 1))
{
locked_GBC = false;
finished = true;
}
}
}
};
}

View File

@ -1,255 +0,0 @@
#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:
void Reset()
{
ROM_bank = 0;
RAM_bank = 0;
ROM_mask = ROM_Length[0] / 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 (Cart_RAM_Length[0] > 0)
{
RAM_mask = Cart_RAM_Length[0] / 0x2000 - 1;
if (Cart_RAM_Length[0] == 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 ROM[addr];
}
else if (addr < 0x8000)
{
return 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);
//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
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)(Cart_RAM[(RAM_addr_high << 4) | RAM_addr_low] >> 4);
Chip_return_low = (uint8_t)(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_TAMA[2];
Chip_return_low = RTC_regs_TAMA[1];
}
else if (RAM_addr_low == 6)
{
Chip_return_high = RTC_regs_TAMA[4];
Chip_return_low = RTC_regs_TAMA[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_TAMA[2] = (uint8_t)(RAM_val_high & 0xF);
RTC_regs_TAMA[1] = (uint8_t)(RAM_val_low & 0xF);
}
else if (RAM_addr_low == 6)
{
RTC_regs_TAMA[4] = (uint8_t)(RAM_val_high & 0xF);
RTC_regs_TAMA[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_TAMA[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_TAMA[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_TAMA[0]++;
if (RTC_regs_TAMA[0] > 59)
{
RTC_regs_TAMA[0] = 0;
RTC_regs_TAMA[1]++;
// 1's digit of minutes
if (RTC_regs_TAMA[1] > 9)
{
RTC_regs_TAMA[1] = 0;
RTC_regs_TAMA[2]++;
// 10's digit of minutes
if (RTC_regs_TAMA[2] > 5)
{
RTC_regs_TAMA[2] = 0;
RTC_regs_TAMA[3]++;
// 1's digit of hours
if (RTC_regs_TAMA[3] > 9)
{
RTC_regs_TAMA[3] = 0;
RTC_regs_TAMA[4]++;
// 10's digit of hours
if (RTC_regs_TAMA[4] > 2)
{
RTC_regs_TAMA[4] = 0;
RTC_regs_TAMA[5]++;
}
}
}
}
}
}
}
}
}
};
}

View File

@ -1,72 +0,0 @@
#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:
void Reset()
{
ROM_bank = 0;
ROM_mask = ROM_Length[0] / 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 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);
}
};
}

File diff suppressed because it is too large Load Diff

View File

@ -5,9 +5,9 @@
#include "Memory.h"
#include "LR35902.h"
#include "PPU_Base.h"
#include "PPU.h"
#include "GBAudio.h"
#include "Mapper_Base.h"
#include "Mappers.h"
#include "SerialPort.h"
#include "Timer.h"

View File

@ -28,7 +28,7 @@ namespace GBHawk
void WriteMemory(uint32_t addr, uint8_t value);
uint8_t Read_Registers(uint32_t addr);
void Write_Registers(uint32_t addr, uint8_t value);
#pragma region Declarations
PPU* ppu_pntr = nullptr;
@ -51,9 +51,7 @@ namespace GBHawk
uint8_t* kb_rows;
// State
bool PortDEEnabled = false;
bool lagged;
bool start_pressed;
bool is_GBC;
bool GBC_compat;
bool speed_switch, double_speed;
@ -61,6 +59,8 @@ namespace GBHawk
bool GB_bios_register;
bool HDMA_transfer;
bool _islag;
bool Use_MT;
bool has_bat;
uint8_t REG_FFFF, REG_FF0F, REG_FF0F_OLD;
uint8_t _scanlineCallbackLine;
@ -80,13 +80,14 @@ namespace GBHawk
uint8_t ZP_RAM[0x80] = {};
uint8_t RAM[0x8000] = {};
uint8_t VRAM[0x10000] = {};
uint8_t OAM[0x10000] = {};
uint8_t cart_ram[0x8000] = {};
uint8_t unmapped[0x400] = {};
uint8_t VRAM[0x4000] = {};
uint8_t OAM[0xA0] = {};
uint8_t header[0x50] = {};
uint32_t _vidbuffer[160 * 144] = {};
uint32_t color_palette[4] = { 0xFFFFFFFF , 0xFFAAAAAA, 0xFF555555, 0xFF000000 };
const uint8_t GBA_override[13] = { 0xFF, 0x00, 0xCD, 0x03, 0x35, 0xAA, 0x31, 0x90, 0x94, 0x00, 0x00, 0x00, 0x00 };
uint32_t FrameBuffer[160 * 144] = {};
#pragma endregion
@ -94,12 +95,25 @@ namespace GBHawk
#pragma region Functions
// NOTE: only called when checks pass that the files are correct
void Load_BIOS(uint8_t* bios, bool GBC_console)
void Load_BIOS(uint8_t* bios, bool GBC_console, bool GBC_as_GBA)
{
if (GBC_console)
{
bios_rom = new uint8_t[2304];
memcpy(bios_rom, bios, 2304);
is_GBC = true;
// set up IR variables if it's GBC
IR_mask = 0; IR_reg = 0x3E; IR_receive = 2; IR_self = 2; IR_signal = 2;
if (GBC_as_GBA)
{
for (int i = 0; i < 13; i++)
{
bios_rom[i + 0xF3] = (uint8_t)((GBA_override[i] + bios_rom[i + 0xF3]) & 0xFF);
}
IR_mask = 2;
}
}
else
{
@ -108,14 +122,15 @@ namespace GBHawk
}
}
void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, uint32_t ext_rom_mapper_1, uint8_t* ext_rom_2, uint32_t ext_rom_size_2, uint32_t ext_rom_mapper_2)
void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1)
{
ROM = new uint8_t[ext_rom_size_1];
memcpy(ROM, ext_rom_1, ext_rom_size_1);
ROM_Length = ext_rom_size_1;
ROM_Mapper = ext_rom_mapper_1;
std::memcpy(header, ext_rom_1 + 0x100, 0x50);
}
// Switch Speed (GBC only)
@ -163,24 +178,20 @@ namespace GBHawk
uint8_t* SaveState(uint8_t* saver)
{
*saver = (uint8_t)(PortDEEnabled ? 1 : 0); saver++;
*saver = (uint8_t)(lagged ? 1 : 0); saver++;
*saver = (uint8_t)(start_pressed ? 1 : 0); saver++;
std::memcpy(saver, &RAM, 0x10000); saver += 0x10000;
std::memcpy(saver, &cart_ram, 0x8000); saver += 0x8000;
//std::memcpy(saver, &cart_ram, 0x8000); saver += 0x8000;
return saver;
}
uint8_t* LoadState(uint8_t* loader)
{
PortDEEnabled = *loader == 1; loader++;
lagged = *loader == 1; loader++;
start_pressed = *loader == 1; loader++;
std::memcpy(&RAM, loader, 0x10000); loader += 0x10000;
std::memcpy(&cart_ram, loader, 0x8000); loader += 0x8000;
//std::memcpy(&cart_ram, loader, 0x8000); loader += 0x8000;
return loader;
}

View File

@ -3,7 +3,7 @@
#include <string>
#include "Memory.h"
#include "PPU_Base.h"
#include "PPU.h"
using namespace std;

5003
libHawk/GBHawk/GBHawk/PPU.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,577 +0,0 @@
#include <iostream>
#include <cstdint>
#include <iomanip>
#include <string>
using namespace std;
namespace GBHawk
{
class MemoryManager;
class PPU
{
public:
#pragma region PPU
PPU()
{
}
uint8_t ReadMemory(uint32_t);
MemoryManager* mem_ctrl;
// pointers not stated
bool* FlagI = nullptr;
bool* in_vblank = nullptr;
bool* cpu_halted = nullptr;
bool* HDMA_transfer = nullptr;
bool* GBC_compat = nullptr;
uint8_t* cpu_LY = nullptr;
uint8_t* REG_FFFF = nullptr;
uint8_t* REG_FF0F = nullptr;
uint8_t* _scanlineCallbackLine = nullptr;
uint8_t* OAM = nullptr;
uint8_t* VRAM = nullptr;
uint32_t* VRAM_Bank = nullptr;
uint32_t* _vidbuffer = nullptr;
uint32_t* color_palette = nullptr;
uint32_t BG_palette[32] = {};
uint32_t OBJ_palette[32] = {};
bool HDMA_active;
bool clear_screen;
// register variables
uint8_t LCDC;
uint8_t STAT;
uint8_t scroll_y;
uint8_t scroll_x;
uint8_t LY;
uint8_t LY_actual;
uint8_t LY_inc;
uint8_t LYC;
uint8_t DMA_addr;
uint8_t BGP;
uint8_t obj_pal_0;
uint8_t obj_pal_1;
uint8_t window_y;
uint8_t window_x;
bool DMA_start;
uint32_t DMA_clock;
uint32_t DMA_inc;
uint8_t DMA_byte;
// state variables
uint32_t cycle;
bool LYC_INT;
bool HBL_INT;
bool VBL_INT;
bool OAM_INT;
bool LCD_was_off;
bool stat_line;
bool stat_line_old;
// OAM scan
bool DMA_OAM_access;
bool OAM_access_read;
bool OAM_access_write;
uint32_t OAM_scan_index;
uint32_t SL_sprites_index;
uint32_t SL_sprites[40] = {};
uint32_t write_sprite;
bool no_scan;
// render
bool VRAM_access_read;
bool VRAM_access_write;
uint32_t read_case;
uint32_t internal_cycle;
uint32_t y_tile;
uint32_t y_scroll_offset;
uint32_t x_tile;
uint32_t x_scroll_offset;
uint32_t tile_byte;
uint32_t sprite_fetch_cycles;
bool fetch_sprite;
bool going_to_fetch;
bool first_fetch;
uint32_t sprite_fetch_counter;
uint8_t sprite_attr_list[160] = {};
uint8_t sprite_pixel_list[160] = {};
uint8_t sprite_present_list[160] = {};
uint32_t temp_fetch;
uint32_t tile_inc;
bool pre_render;
bool pre_render_2;
uint8_t tile_data[3] = {};
uint8_t tile_data_latch[3] = {};
uint32_t latch_counter;
bool latch_new_data;
uint32_t render_counter;
uint32_t render_offset;
uint32_t pixel_counter;
uint32_t pixel;
uint8_t sprite_data[2] = {};
uint8_t sprite_sel[2] = {};
uint32_t sl_use_index;
bool no_sprites;
uint32_t SL_sprites_ordered[40] = {}; // (x_end, data_low, data_high, attr)
uint32_t evaled_sprites;
uint32_t sprite_ordered_index;
bool blank_frame;
bool window_latch;
uint32_t consecutive_sprite;
uint32_t last_eval;
uint32_t total_counter;
// windowing state
uint32_t window_counter;
bool window_pre_render;
bool window_started;
bool window_is_reset;
uint32_t window_tile_inc;
uint32_t window_y_tile;
uint32_t window_x_tile;
uint32_t window_y_tile_inc;
uint32_t window_x_latch;
uint32_t window_y_latch;
uint32_t hbl_countdown;
// The following are GBC specific variables
// individual uint8_t used in palette colors
uint8_t BG_bytes[64] = {};
uint8_t OBJ_bytes[64] = {};
bool BG_bytes_inc;
bool OBJ_bytes_inc;
uint8_t BG_bytes_index;
uint8_t OBJ_bytes_index;
uint8_t BG_transfer_byte;
uint8_t OBJ_transfer_byte;
// HDMA is unique to GBC, do it as part of the PPU tick
uint8_t HDMA_src_hi;
uint8_t HDMA_src_lo;
uint8_t HDMA_dest_hi;
uint8_t HDMA_dest_lo;
uint32_t HDMA_tick;
uint8_t HDMA_byte;
// controls for tile attributes
uint32_t VRAM_sel;
bool BG_V_flip;
bool HDMA_mode;
bool HDMA_run_once;
uint32_t cur_DMA_src;
uint32_t cur_DMA_dest;
uint32_t HDMA_length;
uint32_t HDMA_countdown;
uint32_t HBL_HDMA_count;
uint32_t last_HBL;
bool HBL_HDMA_go;
bool HBL_test;
uint8_t LYC_t;
uint32_t LYC_cd;
// accessors for derived values (GBC only)
uint8_t BG_pal_ret() { return (uint8_t)(((BG_bytes_inc ? 1 : 0) << 7) | (BG_bytes_index & 0x3F)); }
uint8_t OBJ_pal_ret() { return (uint8_t)(((OBJ_bytes_inc ? 1 : 0) << 7) | (OBJ_bytes_index & 0x3F)); }
uint8_t HDMA_ctrl() { return (uint8_t)(((HDMA_active ? 0 : 1) << 7) | ((HDMA_length >> 4) - 1)); }
virtual uint8_t ReadReg(uint32_t addr)
{
return 0;
}
virtual void WriteReg(uint32_t addr, uint8_t value)
{
}
virtual void tick()
{
}
// might be needed, not sure yet
virtual void latch_delay()
{
}
virtual void render(uint32_t render_cycle)
{
}
virtual void process_sprite()
{
}
// normal DMA moves twice as fast in double speed mode on GBC
// So give it it's own function so we can seperate it from PPU tick
virtual void DMA_tick()
{
}
virtual void OAM_scan(uint32_t OAM_cycle)
{
}
virtual void Reset()
{
}
// order sprites according to x coordinate
// note that for sprites of equal x coordinate, priority goes to first on the list
virtual void reorder_and_assemble_sprites()
{
}
virtual void color_compute_BG()
{
}
void color_compute_OBJ()
{
}
#pragma endregion
#pragma region State Save / Load
uint8_t* SaveState(uint8_t* saver)
{
for (int i = 0; i < 32; i++) { saver = int_saver(BG_palette[i], saver); }
for (int i = 0; i < 32; i++) { saver = int_saver(OBJ_palette[i], saver); }
for (int i = 0; i < 40; i++) { saver = int_saver(SL_sprites[i], saver); }
for (int i = 0; i < 160; i++) { saver = byte_saver(sprite_attr_list[i], saver); }
for (int i = 0; i < 160; i++) { saver = byte_saver(sprite_pixel_list[i], saver); }
for (int i = 0; i < 160; i++) { saver = byte_saver(sprite_present_list[i], saver); }
for (int i = 0; i < 3; i++) { saver = byte_saver(tile_data[i], saver); }
for (int i = 0; i < 3; i++) { saver = byte_saver(tile_data_latch[i], saver); }
for (int i = 0; i < 2; i++) { saver = byte_saver(sprite_data[i], saver); }
for (int i = 0; i < 2; i++) { saver = byte_saver(sprite_sel[i], saver); }
for (int i = 0; i < 40; i++) { saver = int_saver(SL_sprites_ordered[i], saver); }
saver = bool_saver(HDMA_active, saver);
saver = bool_saver(clear_screen, saver);
saver = byte_saver(LCDC, saver);
saver = byte_saver(STAT, saver);
saver = byte_saver(scroll_y, saver);
saver = byte_saver(scroll_x, saver);
saver = byte_saver(LY, saver);
saver = byte_saver(LY_actual, saver);
saver = byte_saver(LY_inc, saver);
saver = byte_saver(LYC, saver);
saver = byte_saver(DMA_addr, saver);
saver = byte_saver(BGP, saver);
saver = byte_saver(obj_pal_0, saver);
saver = byte_saver(obj_pal_1, saver);
saver = byte_saver(window_y, saver);
saver = byte_saver(window_x, saver);
saver = bool_saver(DMA_start, saver);
saver = int_saver(DMA_clock, saver);
saver = int_saver(DMA_inc, saver);
saver = byte_saver(DMA_byte, saver);
saver = int_saver(cycle, saver);
saver = bool_saver(LYC_INT, saver);
saver = bool_saver(HBL_INT, saver);
saver = bool_saver(VBL_INT, saver);
saver = bool_saver(OAM_INT, saver);
saver = bool_saver(stat_line, saver);
saver = bool_saver(stat_line_old, saver);
saver = bool_saver(LCD_was_off, saver);
saver = int_saver(OAM_scan_index, saver);
saver = int_saver(SL_sprites_index, saver);
saver = int_saver(write_sprite, saver);
saver = bool_saver(no_scan, saver);
saver = bool_saver(DMA_OAM_access, saver);
saver = bool_saver(OAM_access_read, saver);
saver = bool_saver(OAM_access_write, saver);
saver = bool_saver(VRAM_access_read, saver);
saver = bool_saver(VRAM_access_write, saver);
saver = int_saver(read_case, saver);
saver = int_saver(internal_cycle, saver);
saver = int_saver(y_tile, saver);
saver = int_saver(y_scroll_offset, saver);
saver = int_saver(x_tile, saver);
saver = int_saver(x_scroll_offset, saver);
saver = int_saver(tile_byte, saver);
saver = int_saver(sprite_fetch_cycles, saver);
saver = bool_saver(fetch_sprite, saver);
saver = bool_saver(going_to_fetch, saver);
saver = bool_saver(first_fetch, saver);
saver = int_saver(sprite_fetch_counter, saver);
saver = int_saver(temp_fetch, saver);
saver = int_saver(tile_inc, saver);
saver = bool_saver(pre_render, saver);
saver = bool_saver(pre_render_2, saver);
saver = int_saver(latch_counter, saver);
saver = bool_saver(latch_new_data, saver);
saver = int_saver(render_counter, saver);
saver = int_saver(render_offset, saver);
saver = int_saver(pixel_counter, saver);
saver = int_saver(pixel, saver);
saver = int_saver(sl_use_index, saver);
saver = bool_saver(no_sprites, saver);
saver = int_saver(evaled_sprites, saver);
saver = int_saver(sprite_ordered_index, saver);
saver = bool_saver(blank_frame, saver);
saver = bool_saver(window_latch, saver);
saver = int_saver(consecutive_sprite, saver);
saver = int_saver(last_eval, saver);
saver = int_saver(window_counter, saver);
saver = bool_saver(window_pre_render, saver);
saver = bool_saver(window_started, saver);
saver = bool_saver(window_is_reset, saver);
saver = int_saver(window_tile_inc, saver);
saver = int_saver(window_y_tile, saver);
saver = int_saver(window_x_tile, saver);
saver = int_saver(window_y_tile_inc, saver);
saver = int_saver(window_x_latch, saver);
saver = int_saver(window_y_latch, saver);
saver = int_saver(hbl_countdown, saver);
// The following are GBC specific variables
for (int i = 0; i < 64; i++) { saver = byte_saver(BG_bytes[i], saver); }
for (int i = 0; i < 64; i++) { saver = byte_saver(OBJ_bytes[i], saver); }
saver = byte_saver(BG_transfer_byte, saver);
saver = byte_saver(OBJ_transfer_byte, saver);
saver = byte_saver(HDMA_src_hi, saver);
saver = byte_saver(HDMA_src_lo, saver);
saver = byte_saver(HDMA_dest_hi, saver);
saver = byte_saver(HDMA_dest_lo, saver);
saver = int_saver(HDMA_tick, saver);
saver = byte_saver(HDMA_byte, saver);
saver = int_saver(VRAM_sel, saver);
saver = bool_saver(BG_V_flip, saver);
saver = bool_saver(HDMA_mode, saver);
saver = bool_saver(HDMA_run_once, saver);
saver = int_saver(cur_DMA_src, saver);
saver = int_saver(cur_DMA_dest, saver);
saver = int_saver(HDMA_length, saver);
saver = int_saver(HDMA_countdown, saver);
saver = int_saver(HBL_HDMA_count, saver);
saver = int_saver(last_HBL, saver);
saver = bool_saver(HBL_HDMA_go, saver);
saver = bool_saver(HBL_test, saver);
saver = bool_saver(BG_bytes_inc, saver);
saver = bool_saver(OBJ_bytes_inc, saver);
saver = byte_saver(BG_bytes_index, saver);
saver = byte_saver(OBJ_bytes_index, saver);
saver = byte_saver(LYC_t, saver);
saver = int_saver(LYC_cd, saver);
return saver;
}
uint8_t* LoadState(uint8_t* loader)
{
for (int i = 0; i < 32; i++) { loader = int_loader(&BG_palette[i], loader); }
for (int i = 0; i < 32; i++) { loader = int_loader(&OBJ_palette[i], loader); }
for (int i = 0; i < 40; i++) { loader = int_loader(&SL_sprites[i], loader); }
for (int i = 0; i < 160; i++) { loader = byte_loader(&sprite_attr_list[i], loader); }
for (int i = 0; i < 160; i++) { loader = byte_loader(&sprite_pixel_list[i], loader); }
for (int i = 0; i < 160; i++) { loader = byte_loader(&sprite_present_list[i], loader); }
for (int i = 0; i < 3; i++) { loader = byte_loader(&tile_data[i], loader); }
for (int i = 0; i < 3; i++) { loader = byte_loader(&tile_data_latch[i], loader); }
for (int i = 0; i < 2; i++) { loader = byte_loader(&sprite_data[i], loader); }
for (int i = 0; i < 2; i++) { loader = byte_loader(&sprite_sel[i], loader); }
for (int i = 0; i < 40; i++) { loader = int_loader(&SL_sprites_ordered[i], loader); }
loader = bool_loader(&HDMA_active, loader);
loader = bool_loader(&clear_screen, loader);
loader = byte_loader(&LCDC, loader);
loader = byte_loader(&STAT, loader);
loader = byte_loader(&scroll_y, loader);
loader = byte_loader(&scroll_x, loader);
loader = byte_loader(&LY, loader);
loader = byte_loader(&LY_actual, loader);
loader = byte_loader(&LY_inc, loader);
loader = byte_loader(&LYC, loader);
loader = byte_loader(&DMA_addr, loader);
loader = byte_loader(&BGP, loader);
loader = byte_loader(&obj_pal_0, loader);
loader = byte_loader(&obj_pal_1, loader);
loader = byte_loader(&window_y, loader);
loader = byte_loader(&window_x, loader);
loader = bool_loader(&DMA_start, loader);
loader = int_loader(&DMA_clock, loader);
loader = int_loader(&DMA_inc, loader);
loader = byte_loader(&DMA_byte, loader);
loader = int_loader(&cycle, loader);
loader = bool_loader(&LYC_INT, loader);
loader = bool_loader(&HBL_INT, loader);
loader = bool_loader(&VBL_INT, loader);
loader = bool_loader(&OAM_INT, loader);
loader = bool_loader(&stat_line, loader);
loader = bool_loader(&stat_line_old, loader);
loader = bool_loader(&LCD_was_off, loader);
loader = int_loader(&OAM_scan_index, loader);
loader = int_loader(&SL_sprites_index, loader);
loader = int_loader(&write_sprite, loader);
loader = bool_loader(&no_scan, loader);
loader = bool_loader(&DMA_OAM_access, loader);
loader = bool_loader(&OAM_access_read, loader);
loader = bool_loader(&OAM_access_write, loader);
loader = bool_loader(&VRAM_access_read, loader);
loader = bool_loader(&VRAM_access_write, loader);
loader = int_loader(&read_case, loader);
loader = int_loader(&internal_cycle, loader);
loader = int_loader(&y_tile, loader);
loader = int_loader(&y_scroll_offset, loader);
loader = int_loader(&x_tile, loader);
loader = int_loader(&x_scroll_offset, loader);
loader = int_loader(&tile_byte, loader);
loader = int_loader(&sprite_fetch_cycles, loader);
loader = bool_loader(&fetch_sprite, loader);
loader = bool_loader(&going_to_fetch, loader);
loader = bool_loader(&first_fetch, loader);
loader = int_loader(&sprite_fetch_counter, loader);
loader = int_loader(&temp_fetch, loader);
loader = int_loader(&tile_inc, loader);
loader = bool_loader(&pre_render, loader);
loader = bool_loader(&pre_render_2, loader);
loader = int_loader(&latch_counter, loader);
loader = bool_loader(&latch_new_data, loader);
loader = int_loader(&render_counter, loader);
loader = int_loader(&render_offset, loader);
loader = int_loader(&pixel_counter, loader);
loader = int_loader(&pixel, loader);
loader = int_loader(&sl_use_index, loader);
loader = bool_loader(&no_sprites, loader);
loader = int_loader(&evaled_sprites, loader);
loader = int_loader(&sprite_ordered_index, loader);
loader = bool_loader(&blank_frame, loader);
loader = bool_loader(&window_latch, loader);
loader = int_loader(&consecutive_sprite, loader);
loader = int_loader(&last_eval, loader);
loader = int_loader(&window_counter, loader);
loader = bool_loader(&window_pre_render, loader);
loader = bool_loader(&window_started, loader);
loader = bool_loader(&window_is_reset, loader);
loader = int_loader(&window_tile_inc, loader);
loader = int_loader(&window_y_tile, loader);
loader = int_loader(&window_x_tile, loader);
loader = int_loader(&window_y_tile_inc, loader);
loader = int_loader(&window_x_latch, loader);
loader = int_loader(&window_y_latch, loader);
loader = int_loader(&hbl_countdown, loader);
// The following are GBC specific variables
for (int i = 0; i < 64; i++) { loader = byte_loader(&BG_bytes[i], loader); }
for (int i = 0; i < 64; i++) { loader = byte_loader(&OBJ_bytes[i], loader); }
loader = byte_loader(&BG_transfer_byte, loader);
loader = byte_loader(&OBJ_transfer_byte, loader);
loader = byte_loader(&HDMA_src_hi, loader);
loader = byte_loader(&HDMA_src_lo, loader);
loader = byte_loader(&HDMA_dest_hi, loader);
loader = byte_loader(&HDMA_dest_lo, loader);
loader = int_loader(&HDMA_tick, loader);
loader = byte_loader(&HDMA_byte, loader);
loader = int_loader(&VRAM_sel, loader);
loader = bool_loader(&BG_V_flip, loader);
loader = bool_loader(&HDMA_mode, loader);
loader = bool_loader(&HDMA_run_once, loader);
loader = int_loader(&cur_DMA_src, loader);
loader = int_loader(&cur_DMA_dest, loader);
loader = int_loader(&HDMA_length, loader);
loader = int_loader(&HDMA_countdown, loader);
loader = int_loader(&HBL_HDMA_count, loader);
loader = int_loader(&last_HBL, loader);
loader = bool_loader(&HBL_HDMA_go, loader);
loader = bool_loader(&HBL_test, loader);
loader = bool_loader(&BG_bytes_inc, loader);
loader = bool_loader(&OBJ_bytes_inc, loader);
loader = byte_loader(&BG_bytes_index, loader);
loader = byte_loader(&OBJ_bytes_index, loader);
loader = byte_loader(&LYC_t, loader);
loader = int_loader(&LYC_cd, loader);
return loader;
}
uint8_t* bool_saver(bool to_save, uint8_t* saver)
{
*saver = (uint8_t)(to_save ? 1 : 0); saver++;
return saver;
}
uint8_t* byte_saver(uint8_t to_save, uint8_t* saver)
{
*saver = to_save; saver++;
return saver;
}
uint8_t* int_saver(uint32_t to_save, uint8_t* saver)
{
*saver = (uint8_t)(to_save & 0xFF); saver++; *saver = (uint8_t)((to_save >> 8) & 0xFF); saver++;
*saver = (uint8_t)((to_save >> 16) & 0xFF); saver++; *saver = (uint8_t)((to_save >> 24) & 0xFF); saver++;
return saver;
}
uint8_t* bool_loader(bool* to_load, uint8_t* loader)
{
to_load[0] = *to_load == 1; loader++;
return loader;
}
uint8_t* byte_loader(uint8_t* to_load, uint8_t* loader)
{
to_load[0] = *loader; loader++;
return loader;
}
uint8_t* int_loader(uint32_t* to_load, uint8_t* loader)
{
to_load[0] = *loader; loader++; to_load[0] |= (*loader << 8); loader++;
to_load[0] |= (*loader << 16); loader++; to_load[0] |= (*loader << 24); loader++;
return loader;
}
#pragma endregion
};
}