Gambatte: Merge improvements from gifvex(mcmaeve)

Restores Bios support and loading GB games into GBC
Accuracy imrpovements
This commit is contained in:
alyosha-tas 2018-01-15 07:45:15 -05:00
parent c6bdae916f
commit e5ded9b139
57 changed files with 7492 additions and 7244 deletions

View File

@ -93,6 +93,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
throw new InvalidOperationException("gambatte_load() returned non-zero (is this not a gb or gbc rom?)"); throw new InvalidOperationException("gambatte_load() returned non-zero (is this not a gb or gbc rom?)");
} }
if ((flags & LibGambatte.LoadFlags.FORCE_DMG) == LibGambatte.LoadFlags.FORCE_DMG)
{
byte[] Bios = comm.CoreFileProvider.GetFirmware("GB", "World", false, "BIOS Not Found, Cannot Load");
if (LibGambatte.gambatte_loaddmgbios(GambatteState, Bios) != 0)
{
throw new InvalidOperationException("gambatte_loaddmgbios() returned non-zero (bios error)");
}
}
else
{
byte[] Bios = comm.CoreFileProvider.GetFirmware("GBC", "World", false, "BIOS Not Found, Cannot Load");
if (LibGambatte.gambatte_loadgbcbios(GambatteState, Bios) != 0)
{
throw new InvalidOperationException("gambatte_loadgbcbios() returned non-zero (bios error)");
}
}
// set real default colors (before anyone mucks with them at all) // set real default colors (before anyone mucks with them at all)
PutSettings((GambatteSettings)settings ?? new GambatteSettings()); PutSettings((GambatteSettings)settings ?? new GambatteSettings());

View File

@ -59,6 +59,24 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int gambatte_load(IntPtr core, byte[] romdata, uint length, long now, LoadFlags flags); public static extern int gambatte_load(IntPtr core, byte[] romdata, uint length, long now, LoadFlags flags);
/// <summary>
/// Load GB BIOS image.
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="biosdata">the bios data, can be disposed of once this function returns</param>
/// <returns>0 on success, negative value on failure.</returns>
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int gambatte_loaddmgbios(IntPtr core, byte[] biosdata);
/// <summary>
/// Load GBC BIOS image.
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="biosdata">the bios data, can be disposed of once this function returns</param>
/// <returns>0 on success, negative value on failure.</returns>
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int gambatte_loadgbcbios(IntPtr core, byte[] biosdata);
/// <summary> /// <summary>
/// Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer, /// Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer,
/// or until a video frame has been drawn. /// or until a video frame has been drawn.

View File

@ -51,7 +51,8 @@ public:
enum LoadFlag { enum LoadFlag {
FORCE_DMG = 1, /**< Treat the ROM as not having CGB support regardless of what its header advertises. */ FORCE_DMG = 1, /**< Treat the ROM as not having CGB support regardless of what its header advertises. */
GBA_CGB = 2, /**< Use GBA intial CPU register values when in CGB mode. */ GBA_CGB = 2, /**< Use GBA intial CPU register values when in CGB mode. */
MULTICART_COMPAT = 4 /**< Use heuristics to detect and support some multicart MBCs disguised as MBC1. */ MULTICART_COMPAT = 4, /**< Use heuristics to detect and support some multicart MBCs disguised as MBC1. */
TRUE_COLOR = 8 /**< Use GBP color conversion instead of GBC-screen approximation */
}; };
/** Load ROM image. /** Load ROM image.
@ -62,6 +63,9 @@ public:
*/ */
int load(const char *romfiledata, unsigned romfilelength, std::uint32_t now, unsigned flags = 0); int load(const char *romfiledata, unsigned romfilelength, std::uint32_t now, unsigned flags = 0);
int loadGBCBios(const char* biosfiledata);
int loadDMGBios(const char* biosfiledata);
/** Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer, /** Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer,
* or until a video frame has been drawn. * or until a video frame has been drawn.
* *
@ -135,6 +139,9 @@ public:
void GetRegs(int *dest); void GetRegs(int *dest);
void SetInterruptAddresses(int *addrs, int numAddrs);
int GetHitInterruptAddress();
template<bool isReader>void SyncState(NewState *ns); template<bool isReader>void SyncState(NewState *ns);
private: private:

View File

@ -5,14 +5,14 @@
<Configuration>Debug</Configuration> <Configuration>Debug</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32"> <ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>Win32</Platform> <Platform>Win32</Platform>
</ProjectConfiguration> </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64"> <ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<Platform>x64</Platform> <Platform>x64</Platform>
@ -22,47 +22,50 @@
<ProjectGuid>{5D630682-7BDA-474D-B387-0EB420DDC199}</ProjectGuid> <ProjectGuid>{5D630682-7BDA-474D-B387-0EB420DDC199}</ProjectGuid>
<Keyword>Win32Proj</Keyword> <Keyword>Win32Proj</Keyword>
<RootNamespace>libgambatte</RootNamespace> <RootNamespace>libgambatte</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries> <UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset> <PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType> <ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries> <UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization> <WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet> <CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup> </PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"> <ImportGroup Label="ExtensionSettings">
</ImportGroup> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ImportGroup Label="Shared">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
@ -92,9 +95,6 @@
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
<PostBuildEvent>
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile> <ClCompile>
@ -110,9 +110,6 @@
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
<PostBuildEvent>
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile> <ClCompile>
@ -128,13 +125,10 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
<PostBuildEvent>
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile> <ClCompile>
@ -150,13 +144,10 @@
</ClCompile> </ClCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding> <EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link> </Link>
<PostBuildEvent>
<Command>copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\output\dll\$(TargetFileName)</Command>
</PostBuildEvent>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="include\gambatte.h" /> <ClInclude Include="include\gambatte.h" />

View File

@ -35,6 +35,18 @@ GBEXPORT int gambatte_load(GB *g, const char *romfiledata, unsigned romfilelengt
return ret; return ret;
} }
GBEXPORT int gambatte_loadgbcbios(GB* g, const char* biosfiledata)
{
int ret = g->loadGBCBios(biosfiledata);
return ret;
}
GBEXPORT int gambatte_loaddmgbios(GB* g, const char* biosfiledata)
{
int ret = g->loadDMGBios(biosfiledata);
return ret;
}
GBEXPORT int gambatte_runfor(GB *g, short *soundbuf, unsigned *samples) GBEXPORT int gambatte_runfor(GB *g, short *soundbuf, unsigned *samples)
{ {
unsigned sampv = *samples; unsigned sampv = *samples;
@ -60,7 +72,7 @@ GBEXPORT void gambatte_reset(GB *g, long long now)
GBEXPORT void gambatte_setdmgpalettecolor(GB *g, unsigned palnum, unsigned colornum, unsigned rgb32) GBEXPORT void gambatte_setdmgpalettecolor(GB *g, unsigned palnum, unsigned colornum, unsigned rgb32)
{ {
g->setDmgPaletteColor(palnum, colornum, rgb32); //g->setDmgPaletteColor(palnum, colornum, rgb32);
} }
GBEXPORT void gambatte_setcgbpalette(GB *g, unsigned *lut) GBEXPORT void gambatte_setcgbpalette(GB *g, unsigned *lut)
@ -201,3 +213,13 @@ GBEXPORT void gambatte_getregs(GB *g, int *dest)
{ {
g->GetRegs(dest); g->GetRegs(dest);
} }
GBEXPORT void gambatte_setinterruptaddresses(GB *g, int *addrs, int numAddrs)
{
g->SetInterruptAddresses(addrs, numAddrs);
}
GBEXPORT int gambatte_gethitinterruptaddress(GB *g)
{
return g->GetHitInterruptAddress();
}

View File

@ -23,7 +23,7 @@
namespace gambatte { namespace gambatte {
CPU::CPU() CPU::CPU()
: memory(Interrupter(SP, PC)), : memory(Interrupter(SP, PC), SP, PC),
cycleCounter_(0), cycleCounter_(0),
PC(0x100), PC(0x100),
SP(0xFFFE), SP(0xFFFE),
@ -39,6 +39,7 @@ CPU::CPU()
H(0x01), H(0x01),
L(0x4D), L(0x4D),
skip(false), skip(false),
numInterruptAddresses(),
tracecallback(0) tracecallback(0)
{ {
} }
@ -111,6 +112,7 @@ void CPU::loadState(const SaveState &state) {
#define HL() ( H << 8 | L ) #define HL() ( H << 8 | L )
#define READ(dest, addr) do { (dest) = memory.read(addr, cycleCounter); cycleCounter += 4; } while (0) #define READ(dest, addr) do { (dest) = memory.read(addr, cycleCounter); cycleCounter += 4; } while (0)
#define PEEK(dest, addr) do { (dest) = memory.read(addr, cycleCounter); } while(0)
// #define PC_READ(dest, addr) do { (dest) = memory.pc_read(addr, cycleCounter); cycleCounter += 4; } while (0) // #define PC_READ(dest, addr) do { (dest) = memory.pc_read(addr, cycleCounter); cycleCounter += 4; } while (0)
#define PC_READ(dest) do { (dest) = memory.read_excb(PC, cycleCounter, false); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0) #define PC_READ(dest) do { (dest) = memory.read_excb(PC, cycleCounter, false); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
#define PC_READ_FIRST(dest) do { (dest) = memory.read_excb(PC, cycleCounter, true); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0) #define PC_READ_FIRST(dest) do { (dest) = memory.read_excb(PC, cycleCounter, true); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; } while (0)
@ -298,7 +300,6 @@ void CPU::loadState(const SaveState &state) {
HF2 = u8; \ HF2 = u8; \
ZF = CF = A + HF2; \ ZF = CF = A + HF2; \
A = ZF & 0xFF; \ A = ZF & 0xFF; \
calcHF(HF1, HF2); \
} while (0) } while (0)
//adc a,r (4 cycles): //adc a,r (4 cycles):
@ -309,7 +310,6 @@ void CPU::loadState(const SaveState &state) {
HF2 = (CF & 0x100) | (u8); \ HF2 = (CF & 0x100) | (u8); \
ZF = CF = (CF >> 8 & 1) + (u8) + A; \ ZF = CF = (CF >> 8 & 1) + (u8) + A; \
A = ZF & 0xFF; \ A = ZF & 0xFF; \
calcHF(HF1, HF2); \
} while (0) } while (0)
//sub a,r (4 cycles): //sub a,r (4 cycles):
@ -321,7 +321,6 @@ void CPU::loadState(const SaveState &state) {
ZF = CF = A - HF2; \ ZF = CF = A - HF2; \
A = ZF & 0xFF; \ A = ZF & 0xFF; \
HF2 |= 0x400; \ HF2 |= 0x400; \
calcHF(HF1, HF2); \
} while (0) } while (0)
//sbc a,r (4 cycles): //sbc a,r (4 cycles):
@ -332,7 +331,6 @@ void CPU::loadState(const SaveState &state) {
HF2 = 0x400 | (CF & 0x100) | (u8); \ HF2 = 0x400 | (CF & 0x100) | (u8); \
ZF = CF = A - ((CF >> 8) & 1) - (u8); \ ZF = CF = A - ((CF >> 8) & 1) - (u8); \
A = ZF & 0xFF; \ A = ZF & 0xFF; \
calcHF(HF1, HF2); \
} while (0) } while (0)
//and a,r (4 cycles): //and a,r (4 cycles):
@ -371,7 +369,6 @@ void CPU::loadState(const SaveState &state) {
HF2 = u8; \ HF2 = u8; \
ZF = CF = A - HF2; \ ZF = CF = A - HF2; \
HF2 |= 0x400; \ HF2 |= 0x400; \
calcHF(HF1, HF2); \
} while (0) } while (0)
//inc r (4 cycles): //inc r (4 cycles):
@ -380,7 +377,6 @@ void CPU::loadState(const SaveState &state) {
HF2 = (r) | 0x800; \ HF2 = (r) | 0x800; \
ZF = (r) + 1; \ ZF = (r) + 1; \
(r) = ZF & 0xFF; \ (r) = ZF & 0xFF; \
calcHF(HF1, HF2); \
} while (0) } while (0)
//dec r (4 cycles): //dec r (4 cycles):
@ -389,7 +385,6 @@ void CPU::loadState(const SaveState &state) {
HF2 = (r) | 0xC00; \ HF2 = (r) | 0xC00; \
ZF = (r) - 1; \ ZF = (r) - 1; \
(r) = ZF & 0xFF; \ (r) = ZF & 0xFF; \
calcHF(HF1, HF2); \
} while (0) } while (0)
//16-BIT ARITHMETIC //16-BIT ARITHMETIC
@ -412,7 +407,6 @@ void CPU::loadState(const SaveState &state) {
CF = H + (CF >> 8) + (rh); \ CF = H + (CF >> 8) + (rh); \
H = CF & 0xFF; \ H = CF & 0xFF; \
cycleCounter += 4; \ cycleCounter += 4; \
calcHF(HF1, HF2); \
} while (0) } while (0)
//inc rr (8 cycles): //inc rr (8 cycles):
@ -444,7 +438,6 @@ void CPU::loadState(const SaveState &state) {
ZF = 1; \ ZF = 1; \
cycleCounter += 4; \ cycleCounter += 4; \
(sumout) = sp_plus_n_var_sum & 0xFFFF; \ (sumout) = sp_plus_n_var_sum & 0xFFFF; \
calcHF(HF1, HF2); \
} while (0) } while (0)
//JUMPS: //JUMPS:
@ -498,6 +491,7 @@ void CPU::loadState(const SaveState &state) {
void CPU::process(const unsigned long cycles) { void CPU::process(const unsigned long cycles) {
memory.setEndtime(cycleCounter_, cycles); memory.setEndtime(cycleCounter_, cycles);
hitInterruptAddress = 0;
memory.updateInput(); memory.updateInput();
//unsigned char A = A_; //unsigned char A = A_;
@ -512,8 +506,23 @@ void CPU::process(const unsigned long cycles) {
cycleCounter += cycles + (-cycles & 3); cycleCounter += cycles + (-cycles & 3);
} }
} else while (cycleCounter < memory.nextEventTime()) { } else while (cycleCounter < memory.nextEventTime()) {
unsigned char opcode; unsigned char opcode = 0x00;
int FullPC = PC;
if (PC >= 0x4000 && PC <= 0x7FFF)
FullPC |= memory.curRomBank() << 16;
for (int i = 0; i < numInterruptAddresses; i++) {
if (FullPC == interruptAddresses[i]) {
hitInterruptAddress = interruptAddresses[i];
memory.setEndtime(cycleCounter, 0);
break;
}
}
if (!hitInterruptAddress)
{
if (tracecallback) { if (tracecallback) {
int result[14]; int result[14];
result[0] = cycleCounter; result[0] = cycleCounter;
@ -541,6 +550,7 @@ void CPU::process(const unsigned long cycles) {
PC = (PC - 1) & 0xFFFF; PC = (PC - 1) & 0xFFFF;
skip = false; skip = false;
} }
}
switch (opcode) { switch (opcode) {
//nop (4 cycles): //nop (4 cycles):
@ -622,15 +632,23 @@ void CPU::process(const unsigned long cycles) {
//stop (4 cycles): //stop (4 cycles):
//Halt CPU and LCD display until button pressed: //Halt CPU and LCD display until button pressed:
case 0x10: case 0x10:
{
unsigned char followingByte;
PEEK(followingByte, PC);
PC = (PC + 1) & 0xFFFF; PC = (PC + 1) & 0xFFFF;
//if (followingByte != 0x00) {
//memory.di();
//memory.blackScreen();
//}
cycleCounter = memory.stop(cycleCounter); cycleCounter = memory.stop(cycleCounter);
if (cycleCounter < memory.nextEventTime()) { if (cycleCounter < memory.nextEventTime()) {
const unsigned long cycles = memory.nextEventTime() - cycleCounter; const unsigned long cycles = memory.nextEventTime() - cycleCounter;
cycleCounter += cycles + (-cycles & 3); cycleCounter += cycles + (-cycles & 3);
} }
}
break; break;
case 0x11: case 0x11:
ld_rr_nn(D, E); ld_rr_nn(D, E);
@ -886,7 +904,6 @@ void CPU::process(const unsigned long cycles) {
ZF = HF2 + 1; ZF = HF2 + 1;
WRITE(addr, ZF & 0xFF); WRITE(addr, ZF & 0xFF);
HF2 |= 0x800; HF2 |= 0x800;
calcHF(HF1, HF2);
} }
break; break;
@ -900,7 +917,6 @@ void CPU::process(const unsigned long cycles) {
ZF = HF2 - 1; ZF = HF2 - 1;
WRITE(addr, ZF & 0xFF); WRITE(addr, ZF & 0xFF);
HF2 |= 0xC00; HF2 |= 0xC00;
calcHF(HF1, HF2);
} }
break; break;
@ -943,7 +959,6 @@ void CPU::process(const unsigned long cycles) {
CF += H; CF += H;
H = CF & 0xFF; H = CF & 0xFF;
cycleCounter += 4; cycleCounter += 4;
calcHF(HF1, HF2);
break; break;
//ldd a,(hl) (8 cycles): //ldd a,(hl) (8 cycles):
@ -1440,7 +1455,6 @@ void CPU::process(const unsigned long cycles) {
case 0xBF: case 0xBF:
CF = ZF = 0; CF = ZF = 0;
HF2 = 0x400; HF2 = 0x400;
calcHF(HF1, HF2); \
break; break;
//ret nz (20;8 cycles): //ret nz (20;8 cycles):
@ -2870,6 +2884,17 @@ void CPU::GetRegs(int *dest)
dest[9] = L; dest[9] = L;
} }
void CPU::SetInterruptAddresses(int *addrs, int numAddrs)
{
interruptAddresses = addrs;
numInterruptAddresses = numAddrs;
}
int CPU::GetHitInterruptAddress()
{
return hitInterruptAddress;
}
SYNCFUNC(CPU) SYNCFUNC(CPU)
{ {
SSS(memory); SSS(memory);

View File

@ -38,6 +38,10 @@ class CPU {
bool skip; bool skip;
int *interruptAddresses;
int numInterruptAddresses;
int hitInterruptAddress;
void process(unsigned long cycles); void process(unsigned long cycles);
void (*tracecallback)(void *); void (*tracecallback)(void *);
@ -120,6 +124,10 @@ public:
memory.setCgbPalette(lut); memory.setCgbPalette(lut);
} }
unsigned char* cgbBiosBuffer() { return memory.cgbBiosBuffer(); }
unsigned char* dmgBiosBuffer() { return memory.dmgBiosBuffer(); }
bool gbIsCgb() { return memory.gbIsCgb(); }
//unsigned char ExternalRead(unsigned short addr) { return memory.read(addr, cycleCounter_); } //unsigned char ExternalRead(unsigned short addr) { return memory.read(addr, cycleCounter_); }
unsigned char ExternalRead(unsigned short addr) { return memory.peek(addr); } unsigned char ExternalRead(unsigned short addr) { return memory.peek(addr); }
void ExternalWrite(unsigned short addr, unsigned char val) { memory.write_nocb(addr, val, cycleCounter_); } void ExternalWrite(unsigned short addr, unsigned char val) { memory.write_nocb(addr, val, cycleCounter_); }
@ -128,6 +136,9 @@ public:
void GetRegs(int *dest); void GetRegs(int *dest);
void SetInterruptAddresses(int *addrs, int numAddrs);
int GetHitInterruptAddress();
template<bool isReader>void SyncState(NewState *ns); template<bool isReader>void SyncState(NewState *ns);
}; };

View File

@ -26,12 +26,12 @@
namespace gambatte { namespace gambatte {
struct GB::Priv { struct GB::Priv {
CPU cpu; CPU cpu;
bool gbaCgbMode; unsigned loadflags;
unsigned layersMask; unsigned layersMask;
uint_least32_t vbuff[160*144]; uint_least32_t vbuff[160*144];
Priv() : gbaCgbMode(false), layersMask(LAYER_MASK_BG | LAYER_MASK_OBJ) Priv() : loadflags(0), layersMask(LAYER_MASK_BG | LAYER_MASK_OBJ)
{ {
} }
@ -94,8 +94,7 @@ void GB::reset(const std::uint32_t now) {
SaveState state; SaveState state;
p_->cpu.setStatePtrs(state); p_->cpu.setStatePtrs(state);
setInitState(state, !(p_->loadflags & FORCE_DMG), p_->loadflags & GBA_CGB, p_->loadflags & TRUE_COLOR, now);
setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode, now);
p_->cpu.loadState(state); p_->cpu.loadState(state);
if (length > 0) if (length > 0)
{ {
@ -150,7 +149,8 @@ int GB::load(const char *romfiledata, unsigned romfilelength, const std::uint32_
if (!failed) { if (!failed) {
SaveState state; SaveState state;
p_->cpu.setStatePtrs(state); p_->cpu.setStatePtrs(state);
setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode = flags & GBA_CGB, now); p_->loadflags = flags;
setInitState(state, !(flags & FORCE_DMG), flags & GBA_CGB, flags & TRUE_COLOR, now);
p_->cpu.loadState(state); p_->cpu.loadState(state);
//p_->cpu.loadSavedata(); //p_->cpu.loadSavedata();
} }
@ -158,6 +158,16 @@ int GB::load(const char *romfiledata, unsigned romfilelength, const std::uint32_
return failed; return failed;
} }
int GB::loadGBCBios(const char* biosfiledata) {
memcpy(p_->cpu.cgbBiosBuffer(), biosfiledata, 0x900);
return 0;
}
int GB::loadDMGBios(const char* biosfiledata) {
memcpy(p_->cpu.dmgBiosBuffer(), biosfiledata, 0x100);
return 0;
}
bool GB::isCgb() const { bool GB::isCgb() const {
return p_->cpu.isCgb(); return p_->cpu.isCgb();
} }
@ -228,10 +238,20 @@ void GB::GetRegs(int *dest) {
p_->cpu.GetRegs(dest); p_->cpu.GetRegs(dest);
} }
void GB::SetInterruptAddresses(int *addrs, int numAddrs)
{
p_->cpu.SetInterruptAddresses(addrs, numAddrs);
}
int GB::GetHitInterruptAddress()
{
return p_->cpu.GetHitInterruptAddress();
}
SYNCFUNC(GB) SYNCFUNC(GB)
{ {
SSS(p_->cpu); SSS(p_->cpu);
NSS(p_->gbaCgbMode); NSS(p_->loadflags);
NSS(p_->vbuff); NSS(p_->vbuff);
} }

View File

@ -1041,11 +1041,11 @@ static void setInitialCgbIoamhram(unsigned char *const ioamhram) {
}; };
static const unsigned char ffxxDump[0x100] = { static const unsigned char ffxxDump[0x100] = {
0xCF, 0x00, 0x7C, 0xFF, 0x44, 0x00, 0x00, 0xF8, 0xCF, 0x00, 0x7C, 0xFF, 0x00, 0x00, 0x00, 0xF8,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1,
0x80, 0xBF, 0xF3, 0xFF, 0xBF, 0xFF, 0x3F, 0x00, 0x80, 0x3F, 0x00, 0xFF, 0xBF, 0xFF, 0x3F, 0x00,
0xFF, 0xBF, 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, 0xFF, 0xFF, 0xBF, 0x7F, 0xFF, 0x9F, 0xFF, 0xBF, 0xFF,
0xFF, 0x00, 0x00, 0xBF, 0x77, 0xF3, 0xF1, 0xFF, 0xFF, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x70, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF,
@ -1146,7 +1146,7 @@ static void setInitialDmgIoamhram(unsigned char *const ioamhram) {
} // anon namespace } // anon namespace
void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode, const std::uint32_t now) { void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode, const bool trueColors, const std::uint32_t now) {
static const unsigned char cgbObjpDump[0x40] = { static const unsigned char cgbObjpDump[0x40] = {
0x00, 0x00, 0xF2, 0xAB, 0x00, 0x00, 0xF2, 0xAB,
0x61, 0xC2, 0xD9, 0xBA, 0x61, 0xC2, 0xD9, 0xBA,
@ -1166,39 +1166,36 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
0x83, 0x40, 0x0B, 0x77 0x83, 0x40, 0x0B, 0x77
}; };
state.cpu.PC = 0x100; state.cpu.cycleCounter = 8;
state.cpu.SP = 0xFFFE; state.cpu.PC = 0;
state.cpu.A = cgb * 0x10 | 0x01; state.cpu.SP = 0;
state.cpu.B = cgb & gbaCgbMode; state.cpu.A = 0;
state.cpu.C = 0x13; state.cpu.B = 0;
state.cpu.D = 0x00; state.cpu.C = 0;
state.cpu.E = 0xD8; state.cpu.D = 0;
state.cpu.F = 0xB0; state.cpu.E = 0;
state.cpu.H = 0x01; state.cpu.F = 0;
state.cpu.L = 0x4D; state.cpu.H = 0;
state.cpu.L = 0;
state.cpu.skip = false; state.cpu.skip = false;
setInitialVram(state.mem.vram.ptr, cgb); state.mem.biosMode = true;
state.cpu.cycleCounter = cgb ? 0x102A0 : 0x102A0 + 0x8D2C; state.mem.cgbSwitching = false;
state.mem.agbMode = gbaCgbMode;
std::memset(state.mem.sram.ptr, 0xFF, state.mem.sram.getSz()); std::memset(state.mem.sram.ptr, 0xFF, state.mem.sram.getSz());
if (cgb) { setInitialVram(state.mem.vram.ptr, cgb);
setInitialCgbWram(state.mem.wram.ptr);
}
else {
setInitialDmgWram(state.mem.wram.ptr);
}
if (cgb) { if (cgb) {
setInitialCgbWram(state.mem.wram.ptr);
setInitialCgbIoamhram(state.mem.ioamhram.ptr); setInitialCgbIoamhram(state.mem.ioamhram.ptr);
} } else {
else { setInitialDmgWram(state.mem.wram.ptr);
setInitialDmgIoamhram(state.mem.ioamhram.ptr); setInitialDmgIoamhram(state.mem.ioamhram.ptr);
} }
state.mem.ioamhram.ptr[0x140] = 0x91; state.mem.ioamhram.ptr[0x104] = 0;
state.mem.ioamhram.ptr[0x104] = 0x1C; state.mem.ioamhram.ptr[0x140] = 0;
state.mem.ioamhram.ptr[0x144] = 0x00; state.mem.ioamhram.ptr[0x144] = 0x00;
state.mem.divLastUpdate = 0; state.mem.divLastUpdate = 0;
@ -1218,6 +1215,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
state.mem.enableRam = false; state.mem.enableRam = false;
state.mem.rambankMode = false; state.mem.rambankMode = false;
state.mem.hdmaTransfer = false; state.mem.hdmaTransfer = false;
state.mem.gbIsCgb = cgb;
for (unsigned i = 0x00; i < 0x40; i += 0x02) { for (unsigned i = 0x00; i < 0x40; i += 0x02) {
@ -1240,7 +1238,7 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
std::memset(state.ppu.spAttribList, 0, sizeof(state.ppu.spAttribList)); std::memset(state.ppu.spAttribList, 0, sizeof(state.ppu.spAttribList));
std::memset(state.ppu.spByte0List, 0, sizeof(state.ppu.spByte0List)); std::memset(state.ppu.spByte0List, 0, sizeof(state.ppu.spByte0List));
std::memset(state.ppu.spByte1List, 0, sizeof(state.ppu.spByte1List)); std::memset(state.ppu.spByte1List, 0, sizeof(state.ppu.spByte1List));
state.ppu.videoCycles = cgb ? 144 * 456ul + 164 : 153 * 456ul + 396; state.ppu.videoCycles = 0;
state.ppu.enableDisplayM0Time = state.cpu.cycleCounter; state.ppu.enableDisplayM0Time = state.cpu.cycleCounter;
state.ppu.winYPos = 0xFF; state.ppu.winYPos = 0xFF;
state.ppu.xpos = 0; state.ppu.xpos = 0;
@ -1263,30 +1261,33 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
state.ppu.nextM0Irq = 0; state.ppu.nextM0Irq = 0;
state.ppu.oldWy = state.mem.ioamhram.get()[0x14A]; state.ppu.oldWy = state.mem.ioamhram.get()[0x14A];
state.ppu.pendingLcdstatIrq = false; state.ppu.pendingLcdstatIrq = false;
state.ppu.isCgb = cgb;
state.ppu.trueColors = !trueColors;
state.spu.cycleCounter = 0x1000 | (state.cpu.cycleCounter >> 1 & 0xFFF); // spu.cycleCounter >> 12 & 7 represents the frame sequencer position.
state.spu.cycleCounter = 0; // spu.cycleCounter >> 12 & 7 represents the frame sequencer position.
state.spu.ch1.sweep.counter = SoundUnit::COUNTER_DISABLED; state.spu.ch1.sweep.counter = SoundUnit::COUNTER_DISABLED;
state.spu.ch1.sweep.shadow = 0; state.spu.ch1.sweep.shadow = 0;
state.spu.ch1.sweep.nr0 = 0; state.spu.ch1.sweep.nr0 = 0;
state.spu.ch1.sweep.negging = false; state.spu.ch1.sweep.negging = false;
state.spu.ch1.duty.nextPosUpdate = (state.spu.cycleCounter & ~1) + 2048 * 2; state.spu.ch1.duty.nextPosUpdate = (state.spu.cycleCounter & ~1ul) + 37 * 2;
state.spu.ch1.duty.nr3 = 0; state.spu.ch1.duty.nr3 = 0;
state.spu.ch1.duty.pos = 0; state.spu.ch1.duty.pos = 0;
state.spu.ch1.env.counter = SoundUnit::COUNTER_DISABLED; state.spu.ch1.env.counter = SoundUnit::COUNTER_DISABLED;
state.spu.ch1.env.volume = 0; state.spu.ch1.env.volume = 0;
state.spu.ch1.lcounter.counter = SoundUnit::COUNTER_DISABLED; state.spu.ch1.lcounter.counter = SoundUnit::COUNTER_DISABLED;
state.spu.ch1.lcounter.lengthCounter = 0x40; state.spu.ch1.lcounter.lengthCounter = 0;
state.spu.ch1.nr4 = 0; state.spu.ch1.nr4 = 0;
state.spu.ch1.master = true; state.spu.ch1.master = true;
state.spu.ch2.duty.nextPosUpdate = (state.spu.cycleCounter & ~1) + 2048 * 2; state.spu.ch2.duty.nextPosUpdate = SoundUnit::COUNTER_DISABLED;
state.spu.ch2.duty.nr3 = 0; state.spu.ch2.duty.nr3 = 0;
state.spu.ch2.duty.pos = 0; state.spu.ch2.duty.pos = 0;
state.spu.ch2.env.counter = state.spu.cycleCounter - ((state.spu.cycleCounter - 0x1000) & 0x7FFF) + 8ul * 0x8000; state.spu.ch2.env.counter = SoundUnit::COUNTER_DISABLED;
state.spu.ch2.env.volume = 0; state.spu.ch2.env.volume = 0;
state.spu.ch2.lcounter.counter = SoundUnit::COUNTER_DISABLED; state.spu.ch2.lcounter.counter = SoundUnit::COUNTER_DISABLED;
state.spu.ch2.lcounter.lengthCounter = 0x40; state.spu.ch2.lcounter.lengthCounter = 0;
state.spu.ch2.nr4 = 0; state.spu.ch2.nr4 = 0;
state.spu.ch2.master = false; state.spu.ch2.master = false;
@ -1305,10 +1306,10 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
state.spu.ch4.lfsr.counter = state.spu.cycleCounter + 4; state.spu.ch4.lfsr.counter = state.spu.cycleCounter + 4;
state.spu.ch4.lfsr.reg = 0xFF; state.spu.ch4.lfsr.reg = 0xFF;
state.spu.ch4.env.counter = state.spu.cycleCounter - ((state.spu.cycleCounter - 0x1000) & 0x7FFF) + 8ul * 0x8000; state.spu.ch4.env.counter = SoundUnit::COUNTER_DISABLED;
state.spu.ch4.env.volume = 0; state.spu.ch4.env.volume = 0;
state.spu.ch4.lcounter.counter = SoundUnit::COUNTER_DISABLED; state.spu.ch4.lcounter.counter = SoundUnit::COUNTER_DISABLED;
state.spu.ch4.lcounter.lengthCounter = 0x40; state.spu.ch4.lcounter.lengthCounter = 0;
state.spu.ch4.nr4 = 0; state.spu.ch4.nr4 = 0;
state.spu.ch4.master = false; state.spu.ch4.master = false;

View File

@ -22,7 +22,7 @@
#include <cstdint> #include <cstdint>
namespace gambatte { namespace gambatte {
void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode, std::uint32_t now); void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode, bool trueColors, std::uint32_t now);
} }
#endif #endif

View File

@ -62,6 +62,7 @@ public:
void resetCc(unsigned long oldCc, unsigned long newCc); void resetCc(unsigned long oldCc, unsigned long newCc);
unsigned ifreg() const { return ifreg_; } unsigned ifreg() const { return ifreg_; }
unsigned iereg() const { return iereg_; }
unsigned pendingIrqs() const { return ifreg_ & iereg_; } unsigned pendingIrqs() const { return ifreg_ & iereg_; }
bool ime() const { return intFlags.ime(); } bool ime() const { return intFlags.ime(); }
bool halted() const { return intFlags.halted(); } bool halted() const { return intFlags.halted(); }

View File

@ -18,10 +18,10 @@
***************************************************************************/ ***************************************************************************/
#include "cartridge.h" #include "cartridge.h"
#include "../savestate.h" #include "../savestate.h"
#include <algorithm>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>
#include <algorithm>
namespace gambatte { namespace gambatte {
@ -615,8 +615,7 @@ int Cartridge::loadROM(const char *romfiledata, unsigned romfilelength, const bo
break; break;
} }
cgb = header[0x0143] >> 7 & (1 ^ forceDmg); cgb = !forceDmg;
//cgb = forceDmg ? false : true;
std::printf("cgb: %d\n", cgb); std::printf("cgb: %d\n", cgb);
} }
@ -627,13 +626,11 @@ int Cartridge::loadROM(const char *romfiledata, unsigned romfilelength, const bo
std::printf("rombanks: %u\n", static_cast<unsigned>(filesize / 0x4000)); std::printf("rombanks: %u\n", static_cast<unsigned>(filesize / 0x4000));
mbc.reset(); mbc.reset();
memptrs.reset(rombanks, rambanks, cgb ? 8 : 2); memptrs.reset(rombanks, rambanks, cgb ? 8 : 2);
rtc.set(false, 0); rtc.set(false, 0);
//rom->rewind(); //rom->rewind();
//rom->read(reinterpret_cast<char*>(memptrs.romdata()), (filesize / 0x4000) * 0x4000ul); //rom->read(reinterpret_cast<char*>(memptrs.romdata()), (filesize / 0x4000) * 0x4000ul);
std::memcpy(memptrs.romdata(), romfiledata, (filesize / 0x4000) * 0x4000ul); std::memcpy(memptrs.romdata(), romfiledata, (filesize / 0x4000) * 0x4000ul);
std::memset(memptrs.romdata() + (filesize / 0x4000) * 0x4000ul, 0xFF, (rombanks - filesize / 0x4000) * 0x4000ul); std::memset(memptrs.romdata() + (filesize / 0x4000) * 0x4000ul, 0xFF, (rombanks - filesize / 0x4000) * 0x4000ul);
enforce8bit(memptrs.romdata(), rombanks * 0x4000ul); enforce8bit(memptrs.romdata(), rombanks * 0x4000ul);

View File

@ -79,6 +79,7 @@ public:
unsigned char * wsrambankptr() const { return memptrs.wsrambankptr(); } unsigned char * wsrambankptr() const { return memptrs.wsrambankptr(); }
unsigned char * vrambankptr() const { return memptrs.vrambankptr(); } unsigned char * vrambankptr() const { return memptrs.vrambankptr(); }
OamDmaSrc oamDmaSrc() const { return memptrs.oamDmaSrc(); } OamDmaSrc oamDmaSrc() const { return memptrs.oamDmaSrc(); }
unsigned curRomBank() const { return memptrs.curRomBank(); }
void setVrambank(unsigned bank) { memptrs.setVrambank(bank); } void setVrambank(unsigned bank) { memptrs.setVrambank(bank); }
void setWrambank(unsigned bank) { memptrs.setWrambank(bank); } void setWrambank(unsigned bank) { memptrs.setWrambank(bank); }

View File

@ -25,6 +25,7 @@ namespace gambatte {
MemPtrs::MemPtrs() MemPtrs::MemPtrs()
: rmem_(), wmem_(), romdata_(), wramdata_(), vrambankptr_(0), rsrambankptr_(0), : rmem_(), wmem_(), romdata_(), wramdata_(), vrambankptr_(0), rsrambankptr_(0),
wsrambankptr_(0), memchunk_(0), rambankdata_(0), wramdataend_(0), oamDmaSrc_(OAM_DMA_SRC_OFF), wsrambankptr_(0), memchunk_(0), rambankdata_(0), wramdataend_(0), oamDmaSrc_(OAM_DMA_SRC_OFF),
curRomBank_(1),
memchunk_len(0) memchunk_len(0)
{ {
} }
@ -35,12 +36,10 @@ MemPtrs::~MemPtrs() {
void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsigned wrambanks) { void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsigned wrambanks) {
delete []memchunk_; delete []memchunk_;
memchunk_len = 0x4000 + rombanks * 0x4000ul + 0x4000 + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000; memchunk_len = 0x4000 + rombanks * 0x4000ul + 0x4000 + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000;
memchunk_ = new unsigned char[memchunk_len]; memchunk_ = new unsigned char[memchunk_len];
romdata_[0] = romdata(); romdata_[0] = romdata();
rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000; rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000;
wramdata_[0] = rambankdata_ + rambanks * 0x2000ul; wramdata_[0] = rambankdata_ + rambanks * 0x2000ul;
wramdataend_ = wramdata_[0] + wrambanks * 0x1000ul; wramdataend_ = wramdata_[0] + wrambanks * 0x1000ul;
@ -62,17 +61,14 @@ void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsi
} }
void MemPtrs::setRombank0(const unsigned bank) { void MemPtrs::setRombank0(const unsigned bank) {
romdata_[0] = romdata() + bank * 0x4000ul; romdata_[0] = romdata() + bank * 0x4000ul;
rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0]; rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
disconnectOamDmaAreas(); disconnectOamDmaAreas();
} }
void MemPtrs::setRombank(const unsigned bank) { void MemPtrs::setRombank(const unsigned bank) {
curRomBank_ = bank;
romdata_[1] = romdata() + bank * 0x4000ul - 0x4000; romdata_[1] = romdata() + bank * 0x4000ul - 0x4000;
rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1]; rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
disconnectOamDmaAreas(); disconnectOamDmaAreas();
} }
@ -221,6 +217,7 @@ SYNCFUNC(MemPtrs)
MSS(rambankdata_); MSS(rambankdata_);
MSS(wramdataend_); MSS(wramdataend_);
NSS(oamDmaSrc_); NSS(oamDmaSrc_);
NSS(curRomBank_);
} }
} }

View File

@ -41,6 +41,8 @@ class MemPtrs {
OamDmaSrc oamDmaSrc_; OamDmaSrc oamDmaSrc_;
unsigned curRomBank_;
int memchunk_len; int memchunk_len;
int memchunk_saveoffs; int memchunk_saveoffs;
int memchunk_savelen; int memchunk_savelen;
@ -73,6 +75,7 @@ public:
unsigned char * wsrambankptr() const { return wsrambankptr_; } unsigned char * wsrambankptr() const { return wsrambankptr_; }
unsigned char * vrambankptr() const { return vrambankptr_; } unsigned char * vrambankptr() const { return vrambankptr_; }
OamDmaSrc oamDmaSrc() const { return oamDmaSrc_; } OamDmaSrc oamDmaSrc() const { return oamDmaSrc_; }
unsigned curRomBank() const { return curRomBank_; }
void setRombank0(unsigned bank); void setRombank0(unsigned bank);
void setRombank(unsigned bank); void setRombank(unsigned bank);

View File

@ -24,7 +24,7 @@
namespace gambatte { namespace gambatte {
Memory::Memory(const Interrupter &interrupter_in) Memory::Memory(const Interrupter &interrupter_in, unsigned short &sp, unsigned short &pc)
: readCallback(0), : readCallback(0),
writeCallback(0), writeCallback(0),
execCallback(0), execCallback(0),
@ -41,7 +41,9 @@ Memory::Memory(const Interrupter &interrupter_in)
serialCnt(0), serialCnt(0),
blanklcd(false), blanklcd(false),
LINKCABLE(false), LINKCABLE(false),
linkClockTrigger(false) linkClockTrigger(false),
SP(sp),
PC(pc)
{ {
intreq.setEventTime<BLIT>(144*456ul); intreq.setEventTime<BLIT>(144*456ul);
intreq.setEventTime<END>(0); intreq.setEventTime<END>(0);
@ -61,6 +63,10 @@ static inline int serialCntFrom(const unsigned long cyclesUntilDone, const bool
} }
void Memory::loadState(const SaveState &state) { void Memory::loadState(const SaveState &state) {
biosMode = state.mem.biosMode;
cgbSwitching = state.mem.cgbSwitching;
agbMode = state.mem.agbMode;
gbIsCgb_ = state.mem.gbIsCgb;
sound.loadState(state); sound.loadState(state);
display.loadState(state, state.mem.oamDmaPos < 0xA0 ? cart.rdisabledRam() : ioamhram); display.loadState(state, state.mem.oamDmaPos < 0xA0 ? cart.rdisabledRam() : ioamhram);
tima.loadState(state, TimaInterruptRequester(intreq)); tima.loadState(state, TimaInterruptRequester(intreq));
@ -260,7 +266,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
break; break;
case INTERRUPTS: case INTERRUPTS:
if (halted()) { if (halted()) {
if (isCgb()) if (gbIsCgb_)
cycleCounter += 4; cycleCounter += 4;
intreq.unhalt(); intreq.unhalt();
@ -269,17 +275,33 @@ unsigned long Memory::event(unsigned long cycleCounter) {
if (ime()) { if (ime()) {
unsigned address; unsigned address;
const unsigned pendingIrqs = intreq.pendingIrqs();
cycleCounter += 12;
display.update(cycleCounter);
SP = (SP - 2) & 0xFFFF;
write(SP + 1, PC >> 8, cycleCounter);
unsigned ie = intreq.iereg();
cycleCounter += 4;
display.update(cycleCounter);
write(SP, PC & 0xFF, cycleCounter);
const unsigned pendingIrqs = ie & intreq.ifreg();
cycleCounter += 4;
display.update(cycleCounter);
const unsigned n = pendingIrqs & -pendingIrqs; const unsigned n = pendingIrqs & -pendingIrqs;
if (n < 8) { if (n == 0) {
address = 0;
}
else if (n < 8) {
static const unsigned char lut[] = { 0x40, 0x48, 0x48, 0x50 }; static const unsigned char lut[] = { 0x40, 0x48, 0x48, 0x50 };
address = lut[n-1]; address = lut[n-1];
} else } else
address = 0x50 + n; address = 0x50 + n;
intreq.ackIrq(n); intreq.ackIrq(n);
cycleCounter = interrupter.interrupt(address, cycleCounter, *this); PC = address;
} }
break; break;
@ -306,10 +328,19 @@ unsigned long Memory::stop(unsigned long cycleCounter) {
// when switching speed, it seems that the CPU spontaneously restarts soon? // when switching speed, it seems that the CPU spontaneously restarts soon?
// otherwise, the cpu should be allowed to stay halted as long as needed // otherwise, the cpu should be allowed to stay halted as long as needed
// so only execute this line when switching speed // so only execute this line when switching speed
intreq.halt();
intreq.setEventTime<UNHALT>(cycleCounter + 0x20000 + isDoubleSpeed() * 8); intreq.setEventTime<UNHALT>(cycleCounter + 0x20000 + isDoubleSpeed() * 8);
} }
else {
if ((ioamhram[0x100] & 0x30) == 0x30) {
di();
intreq.halt(); intreq.halt();
}
else {
intreq.halt();
intreq.setEventTime<UNHALT>(cycleCounter + 0x20000 + isDoubleSpeed() * 8);
}
}
return cycleCounter; return cycleCounter;
} }
@ -861,7 +892,11 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
case 0x4B: case 0x4B:
display.wxChange(data, cycleCounter); display.wxChange(data, cycleCounter);
break; break;
case 0x4C:
if (biosMode) {
//flagClockReq(&intreq);
}
break;
case 0x4D: case 0x4D:
if (isCgb()) if (isCgb())
ioamhram[0x14D] = (ioamhram[0x14D] & ~1u) | (data & 1); return; ioamhram[0x14D] = (ioamhram[0x14D] & ~1u) | (data & 1); return;
@ -873,8 +908,12 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
return; return;
case 0x50: case 0x50:
// this is the register that turns off the bootrom biosMode = false;
// it can only ever be written to once (with 1) once boot rom finishes if (cgbSwitching) {
display.copyCgbPalettesToDmg();
display.setCgb(false);
cgbSwitching = false;
}
return; return;
case 0x51: case 0x51:
dmaSource = data << 8 | (dmaSource & 0xFF); dmaSource = data << 8 | (dmaSource & 0xFF);
@ -945,8 +984,8 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
return; return;
case 0x6C: case 0x6C:
if (isCgb())
ioamhram[0x16C] = data | 0xFE; ioamhram[0x16C] = data | 0xFE;
cgbSwitching = true;
return; return;
case 0x70: case 0x70:
@ -1098,6 +1137,10 @@ SYNCFUNC(Memory)
NSS(ioamhram); NSS(ioamhram);
NSS(divLastUpdate); NSS(divLastUpdate);
NSS(lastOamDmaUpdate); NSS(lastOamDmaUpdate);
NSS(biosMode);
NSS(cgbSwitching);
NSS(agbMode);
NSS(gbIsCgb_);
SSS(intreq); SSS(intreq);
SSS(tima); SSS(tima);

View File

@ -19,6 +19,8 @@
#ifndef MEMORY_H #ifndef MEMORY_H
#define MEMORY_H #define MEMORY_H
static unsigned char const agbOverride[0xD] = { 0xFF, 0x00, 0xCD, 0x03, 0x35, 0xAA, 0x31, 0x90, 0x94, 0x00, 0x00, 0x00, 0x00 };
#include "mem/cartridge.h" #include "mem/cartridge.h"
#include "video.h" #include "video.h"
#include "sound.h" #include "sound.h"
@ -34,6 +36,14 @@ class FilterInfo;
class Memory { class Memory {
Cartridge cart; Cartridge cart;
unsigned char ioamhram[0x200]; unsigned char ioamhram[0x200];
unsigned char cgbBios[0x900];
unsigned char dmgBios[0x100];
bool biosMode;
bool cgbSwitching;
bool agbMode;
bool gbIsCgb_;
unsigned short &SP;
unsigned short &PC;
void (*readCallback)(unsigned); void (*readCallback)(unsigned);
void (*writeCallback)(unsigned); void (*writeCallback)(unsigned);
@ -83,9 +93,10 @@ class Memory {
bool isDoubleSpeed() const { return display.isDoubleSpeed(); } bool isDoubleSpeed() const { return display.isDoubleSpeed(); }
public: public:
explicit Memory(const Interrupter &interrupter); explicit Memory(const Interrupter &interrupter, unsigned short &sp, unsigned short &pc);
bool loaded() const { return cart.loaded(); } bool loaded() const { return cart.loaded(); }
unsigned curRomBank() const { return cart.curRomBank(); }
const char * romTitle() const { return cart.romTitle(); } const char * romTitle() const { return cart.romTitle(); }
int debugGetLY() const { return display.debugGetLY(); } int debugGetLY() const { return display.debugGetLY(); }
@ -97,6 +108,10 @@ public:
void saveSavedata(char *dest) { cart.saveSavedata(dest); } void saveSavedata(char *dest) { cart.saveSavedata(dest); }
void updateInput(); void updateInput();
unsigned char* cgbBiosBuffer() { return (unsigned char*)cgbBios; }
unsigned char* dmgBiosBuffer() { return (unsigned char*)dmgBios; }
bool gbIsCgb() { return gbIsCgb_; }
bool getMemoryArea(int which, unsigned char **data, int *length); // { return cart.getMemoryArea(which, data, length); } bool getMemoryArea(int which, unsigned char **data, int *length); // { return cart.getMemoryArea(which, data, length); }
unsigned long stop(unsigned long cycleCounter); unsigned long stop(unsigned long cycleCounter);
@ -179,6 +194,16 @@ public:
} }
unsigned readBios(const unsigned P) {
if (gbIsCgb_) {
if (agbMode && P >= 0xF3 && P < 0x100) {
return (agbOverride[P - 0xF3] + cgbBios[P]) & 0xFF;
}
return cgbBios[P];
}
return dmgBios[P];
}
unsigned read(const unsigned P, const unsigned long cycleCounter) { unsigned read(const unsigned P, const unsigned long cycleCounter) {
if (readCallback) if (readCallback)
readCallback(P); readCallback(P);
@ -188,6 +213,9 @@ public:
if(map.type != eCDLog_AddrType_None) if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,eCDLog_Flags_Data); cdCallback(map.addr,map.type,eCDLog_Flags_Data);
} }
if (biosMode && ((!gbIsCgb_ && P < 0x100) || (gbIsCgb_ && P < 0x900 && (P < 0x100 || P >= 0x200)))) {
return readBios(P);
}
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter); return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
} }
@ -200,10 +228,16 @@ public:
if(map.type != eCDLog_AddrType_None) if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand); cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand);
} }
if (biosMode && ((!gbIsCgb_ && P < 0x100) || (gbIsCgb_ && P < 0x900 && (P < 0x100 || P >= 0x200)))) {
return readBios(P);
}
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter); return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
} }
unsigned peek(const unsigned P) { unsigned peek(const unsigned P) {
if (biosMode && ((!gbIsCgb_ && P < 0x100) || (gbIsCgb_ && P < 0x900 && (P < 0x100 || P >= 0x200)))) {
return readBios(P);
}
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_peek(P); return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_peek(P);
} }
@ -288,6 +322,10 @@ public:
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32); void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
void setCgbPalette(unsigned *lut); void setCgbPalette(unsigned *lut);
void blackScreen() {
display.blackScreen();
}
int LinkStatus(int which); int LinkStatus(int which);
template<bool isReader>void SyncState(NewState *ns); template<bool isReader>void SyncState(NewState *ns);

View File

@ -38,7 +38,7 @@ struct SaveState {
void set(T *ptr, const unsigned long sz) { this->ptr = ptr; this->sz = sz; } void set(T *ptr, const unsigned long sz) { this->ptr = ptr; this->sz = sz; }
friend class SaverList; friend class SaverList;
friend void setInitState(SaveState &, bool, bool, std::uint32_t); friend void setInitState(SaveState &, bool, bool, bool, std::uint32_t);
}; };
struct CPU { struct CPU {
@ -78,6 +78,10 @@ struct SaveState {
bool enableRam; bool enableRam;
bool rambankMode; bool rambankMode;
bool hdmaTransfer; bool hdmaTransfer;
bool biosMode;
bool cgbSwitching;
bool agbMode;
bool gbIsCgb;
} mem; } mem;
struct PPU { struct PPU {
@ -113,6 +117,8 @@ struct SaveState {
unsigned char wscx; unsigned char wscx;
bool weMaster; bool weMaster;
bool pendingLcdstatIrq; bool pendingLcdstatIrq;
bool isCgb;
bool trueColors;
} ppu; } ppu;
struct SPU { struct SPU {

View File

@ -36,7 +36,14 @@ void LCD::setCgbPalette(unsigned *lut) {
refreshPalettes(); refreshPalettes();
} }
unsigned long LCD::gbcToRgb32(const unsigned bgr15) { unsigned long LCD::gbcToRgb32(const unsigned bgr15, bool trueColor) {
unsigned long const r = bgr15 & 0x1F;
unsigned long const g = bgr15 >> 5 & 0x1F;
unsigned long const b = bgr15 >> 10 & 0x1F;
if (trueColor)
return (r << 19) | (g << 11) | (b << 3);
return cgbColorsRgb32[bgr15 & 0x7FFF]; return cgbColorsRgb32[bgr15 & 0x7FFF];
} }
@ -66,6 +73,10 @@ void LCD::reset(const unsigned char *const oamram, const unsigned char *vram, co
refreshPalettes(); refreshPalettes();
} }
void LCD::setCgb(bool cgb) {
ppu.setCgb(cgb);
}
static unsigned long mode2IrqSchedule(const unsigned statReg, const LyCounter &lyCounter, const unsigned long cycleCounter) { static unsigned long mode2IrqSchedule(const unsigned statReg, const LyCounter &lyCounter, const unsigned long cycleCounter) {
if (!(statReg & 0x20)) if (!(statReg & 0x20))
return DISABLED_TIME; return DISABLED_TIME;
@ -140,8 +151,8 @@ void LCD::loadState(const SaveState &state, const unsigned char *const oamram) {
void LCD::refreshPalettes() { void LCD::refreshPalettes() {
if (ppu.cgb()) { if (ppu.cgb()) {
for (unsigned i = 0; i < 8 * 8; i += 2) { for (unsigned i = 0; i < 8 * 8; i += 2) {
ppu.bgPalette()[i >> 1] = gbcToRgb32( bgpData[i] | bgpData[i + 1] << 8); ppu.bgPalette()[i >> 1] = gbcToRgb32( bgpData[i] | bgpData[i + 1] << 8, isTrueColors());
ppu.spPalette()[i >> 1] = gbcToRgb32(objpData[i] | objpData[i + 1] << 8); ppu.spPalette()[i >> 1] = gbcToRgb32(objpData[i] | objpData[i + 1] << 8, isTrueColors());
} }
} else { } else {
setDmgPalette(ppu.bgPalette() , dmgColorsRgb32 , bgpData[0]); setDmgPalette(ppu.bgPalette() , dmgColorsRgb32 , bgpData[0]);
@ -150,6 +161,32 @@ void LCD::refreshPalettes() {
} }
} }
void LCD::copyCgbPalettesToDmg() {
for (unsigned i = 0; i < 4; i++) {
dmgColorsRgb32[i] = gbcToRgb32(bgpData[i * 2] | bgpData[i * 2 + 1] << 8, isTrueColors());
}
for (unsigned i = 0; i < 8; i++) {
dmgColorsRgb32[i + 4] = gbcToRgb32(objpData[i * 2] | objpData[i * 2 + 1] << 8, isTrueColors());
}
}
void LCD::blackScreen() {
if (ppu.cgb()) {
for (unsigned i = 0; i < 8 * 8; i += 2) {
ppu.bgPalette()[i >> 1] = 0;
ppu.spPalette()[i >> 1] = 0;
}
}
else {
for (unsigned i = 0; i < 4; i++) {
dmgColorsRgb32[i] = 0;
}
for (unsigned i = 0; i < 8; i++) {
dmgColorsRgb32[i + 4] = 0;
}
}
}
namespace { namespace {
template<typename T> template<typename T>
@ -168,7 +205,7 @@ void LCD::updateScreen(const bool blanklcd, const unsigned long cycleCounter) {
update(cycleCounter); update(cycleCounter);
if (blanklcd && ppu.frameBuf().fb()) { if (blanklcd && ppu.frameBuf().fb()) {
const unsigned long color = ppu.cgb() ? gbcToRgb32(0xFFFF) : dmgColorsRgb32[0]; const unsigned long color = ppu.cgb() ? gbcToRgb32(0xFFFF, isTrueColors()) : dmgColorsRgb32[0];
clear(ppu.frameBuf().fb(), color, ppu.frameBuf().pitch()); clear(ppu.frameBuf().fb(), color, ppu.frameBuf().pitch());
} }
} }
@ -282,23 +319,23 @@ bool LCD::cgbpAccessible(const unsigned long cycleCounter) {
} }
void LCD::doCgbColorChange(unsigned char *const pdata, void LCD::doCgbColorChange(unsigned char *const pdata,
unsigned long *const palette, unsigned index, const unsigned data) { unsigned long *const palette, unsigned index, const unsigned data, bool trueColor) {
pdata[index] = data; pdata[index] = data;
index >>= 1; index >>= 1;
palette[index] = gbcToRgb32(pdata[index << 1] | pdata[(index << 1) + 1] << 8); palette[index] = gbcToRgb32(pdata[index << 1] | pdata[(index << 1) + 1] << 8, trueColor);
} }
void LCD::doCgbBgColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) { void LCD::doCgbBgColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
if (cgbpAccessible(cycleCounter)) { if (cgbpAccessible(cycleCounter)) {
update(cycleCounter); update(cycleCounter);
doCgbColorChange(bgpData, ppu.bgPalette(), index, data); doCgbColorChange(bgpData, ppu.bgPalette(), index, data, isTrueColors());
} }
} }
void LCD::doCgbSpColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) { void LCD::doCgbSpColorChange(unsigned index, const unsigned data, const unsigned long cycleCounter) {
if (cgbpAccessible(cycleCounter)) { if (cgbpAccessible(cycleCounter)) {
update(cycleCounter); update(cycleCounter);
doCgbColorChange(objpData, ppu.spPalette(), index, data); doCgbColorChange(objpData, ppu.spPalette(), index, data, isTrueColors());
} }
} }

View File

@ -147,8 +147,8 @@ class LCD {
static void setDmgPalette(unsigned long *palette, const unsigned long *dmgColors, unsigned data); static void setDmgPalette(unsigned long *palette, const unsigned long *dmgColors, unsigned data);
void setDmgPaletteColor(unsigned index, unsigned long rgb32); void setDmgPaletteColor(unsigned index, unsigned long rgb32);
unsigned long gbcToRgb32(const unsigned bgr15); unsigned long gbcToRgb32(const unsigned bgr15, bool trueColor);
void doCgbColorChange(unsigned char *const pdata, unsigned long *const palette, unsigned index, const unsigned data); void doCgbColorChange(unsigned char *const pdata, unsigned long *const palette, unsigned index, const unsigned data, bool trueColor);
void refreshPalettes(); void refreshPalettes();
void setDBuffer(); void setDBuffer();
@ -175,6 +175,9 @@ public:
void setCgbPalette(unsigned *lut); void setCgbPalette(unsigned *lut);
void setVideoBuffer(uint_least32_t *videoBuf, int pitch); void setVideoBuffer(uint_least32_t *videoBuf, int pitch);
void setLayers(unsigned mask) { ppu.setLayers(mask); } void setLayers(unsigned mask) { ppu.setLayers(mask); }
void setCgb(bool cgb);
void copyCgbPalettesToDmg();
void blackScreen();
int debugGetLY() const { return ppu.lyCounter().ly(); } int debugGetLY() const { return ppu.lyCounter().ly(); }
@ -267,6 +270,7 @@ public:
bool isCgb() const { return ppu.cgb(); } bool isCgb() const { return ppu.cgb(); }
bool isDoubleSpeed() const { return ppu.lyCounter().isDoubleSpeed(); } bool isDoubleSpeed() const { return ppu.lyCounter().isDoubleSpeed(); }
bool isTrueColors() const { return ppu.trueColors(); }
unsigned long *bgPalette() { return ppu.bgPalette(); } unsigned long *bgPalette() { return ppu.bgPalette(); }
unsigned long *spPalette() { return ppu.spPalette(); } unsigned long *spPalette() { return ppu.spPalette(); }

View File

@ -1630,6 +1630,8 @@ void PPU::loadState(const SaveState &ss, const unsigned char *const oamram) {
p_.weMaster = ss.ppu.weMaster; p_.weMaster = ss.ppu.weMaster;
p_.winDrawState = ss.ppu.winDrawState & (WIN_DRAW_START | WIN_DRAW_STARTED); p_.winDrawState = ss.ppu.winDrawState & (WIN_DRAW_START | WIN_DRAW_STARTED);
p_.lastM0Time = p_.now - ss.ppu.lastM0Time; p_.lastM0Time = p_.now - ss.ppu.lastM0Time;
p_.cgb = ss.ppu.isCgb;
p_.trueColors = ss.ppu.trueColors;
loadSpriteList(p_, ss); loadSpriteList(p_, ss);
if (m3loopState && videoCycles < 144 * 456L && p_.xpos < 168 if (m3loopState && videoCycles < 144 * 456L && p_.xpos < 168
@ -1802,6 +1804,7 @@ SYNCFUNC(PPU)
NSS(p_.endx); NSS(p_.endx);
NSS(p_.cgb); NSS(p_.cgb);
NSS(p_.trueColors);
NSS(p_.weMaster); NSS(p_.weMaster);
} }

View File

@ -92,6 +92,7 @@ struct PPUPriv {
unsigned char endx; unsigned char endx;
bool cgb; bool cgb;
bool trueColors;
bool weMaster; bool weMaster;
PPUPriv(NextM0Time &nextM0Time, const unsigned char *oamram, const unsigned char *vram); PPUPriv(NextM0Time &nextM0Time, const unsigned char *oamram, const unsigned char *vram);
@ -107,6 +108,7 @@ public:
unsigned long * bgPalette() { return p_.bgPalette; } unsigned long * bgPalette() { return p_.bgPalette; }
bool cgb() const { return p_.cgb; } bool cgb() const { return p_.cgb; }
bool trueColors() const { return p_.trueColors; }
void doLyCountEvent() { p_.lyCounter.doEvent(); } void doLyCountEvent() { p_.lyCounter.doEvent(); }
unsigned long doSpriteMapEvent(unsigned long time) { return p_.spriteMapper.doEvent(time); } unsigned long doSpriteMapEvent(unsigned long time) { return p_.spriteMapper.doEvent(time); }
const PPUFrameBuf & frameBuf() const { return p_.framebuf; } const PPUFrameBuf & frameBuf() const { return p_.framebuf; }
@ -133,6 +135,8 @@ public:
unsigned long * spPalette() { return p_.spPalette; } unsigned long * spPalette() { return p_.spPalette; }
void update(unsigned long cc); void update(unsigned long cc);
void setLayers(unsigned mask) { p_.layersMask = mask; } void setLayers(unsigned mask) { p_.layersMask = mask; }
void setCgb(bool cgb) { p_.cgb = cgb; }
void setTrueColors(bool trueColors) { p_.trueColors = trueColors; }
template<bool isReader>void SyncState(NewState *ns); template<bool isReader>void SyncState(NewState *ns);
}; };

Binary file not shown.