Gambatte: Merge improvements from gifvex(mcmaeve)
Restores Bios support and loading GB games into GBC Accuracy imrpovements
This commit is contained in:
parent
c6bdae916f
commit
e5ded9b139
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
@ -109,7 +113,7 @@ public:
|
||||||
void setTraceCallback(void (*callback)(void *));
|
void setTraceCallback(void (*callback)(void *));
|
||||||
void setScanlineCallback(void (*callback)(), int sl);
|
void setScanlineCallback(void (*callback)(), int sl);
|
||||||
void setRTCCallback(std::uint32_t (*callback)());
|
void setRTCCallback(std::uint32_t (*callback)());
|
||||||
void setLinkCallback(void (*callback)());
|
void setLinkCallback(void(*callback)());
|
||||||
|
|
||||||
/** Returns true if the currently loaded ROM image is treated as having CGB support. */
|
/** Returns true if the currently loaded ROM image is treated as having CGB support. */
|
||||||
bool isCgb() const;
|
bool isCgb() const;
|
||||||
|
@ -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:
|
||||||
|
|
|
@ -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" />
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -109,7 +121,7 @@ GBEXPORT void gambatte_setrtccallback(GB *g, unsigned int (*callback)())
|
||||||
g->setRTCCallback(callback);
|
g->setRTCCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
GBEXPORT void gambatte_setlinkcallback(GB *g, void (*callback)())
|
GBEXPORT void gambatte_setlinkcallback(GB *g, void(*callback)())
|
||||||
{
|
{
|
||||||
g->setLinkCallback(callback);
|
g->setLinkCallback(callback);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 *);
|
||||||
|
@ -96,7 +100,7 @@ public:
|
||||||
memory.setRTCCallback(callback);
|
memory.setRTCCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLinkCallback(void (*callback)()) {
|
void setLinkCallback(void(*callback)()) {
|
||||||
memory.setLinkCallback(callback);
|
memory.setLinkCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,10 +1215,11 @@ 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) {
|
||||||
state.ppu.bgpData.ptr[i] = 0xFF;
|
state.ppu.bgpData.ptr[i ] = 0xFF;
|
||||||
state.ppu.bgpData.ptr[i + 1] = 0x7F;
|
state.ppu.bgpData.ptr[i + 1] = 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -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_);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -61,7 +63,7 @@ public:
|
||||||
unsigned char * wmem(unsigned area) const { return wmem_[area]; }
|
unsigned char * wmem(unsigned area) const { return wmem_[area]; }
|
||||||
unsigned char * vramdata() const { return rambankdata_ - 0x4000; }
|
unsigned char * vramdata() const { return rambankdata_ - 0x4000; }
|
||||||
unsigned char * vramdataend() const { return rambankdata_; }
|
unsigned char * vramdataend() const { return rambankdata_; }
|
||||||
unsigned char * romdata() const { return memchunk_ + 0x4000;}
|
unsigned char * romdata() const { return memchunk_ + 0x4000; }
|
||||||
unsigned char * romdata(unsigned area) const { return romdata_[area]; }
|
unsigned char * romdata(unsigned area) const { return romdata_[area]; }
|
||||||
unsigned char * romdataend() const { return rambankdata_ - 0x4000; }
|
unsigned char * romdataend() const { return rambankdata_ - 0x4000; }
|
||||||
unsigned char * wramdata(unsigned area) const { return wramdata_[area]; }
|
unsigned char * wramdata(unsigned area) const { return wramdata_[area]; }
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,12 +36,20 @@ 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);
|
||||||
void (*execCallback)(unsigned);
|
void (*execCallback)(unsigned);
|
||||||
CDCallback cdCallback;
|
CDCallback cdCallback;
|
||||||
void (*linkCallback)();
|
void(*linkCallback)();
|
||||||
|
|
||||||
unsigned (*getInput)();
|
unsigned (*getInput)();
|
||||||
unsigned long divLastUpdate;
|
unsigned long divLastUpdate;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +306,7 @@ public:
|
||||||
cart.setRTCCallback(callback);
|
cart.setRTCCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLinkCallback(void (*callback)()) {
|
void setLinkCallback(void(*callback)()) {
|
||||||
this->linkCallback = callback;
|
this->linkCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
Loading…
Reference in New Issue