diff --git a/BizHawk.Emulation.Cores/Computers/MSX/LibMSX.cs b/BizHawk.Emulation.Cores/Computers/MSX/LibMSX.cs
index e5d298a588..3137f4e5aa 100644
--- a/BizHawk.Emulation.Cores/Computers/MSX/LibMSX.cs
+++ b/BizHawk.Emulation.Cores/Computers/MSX/LibMSX.cs
@@ -12,23 +12,36 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
{
# region Core
/// opaque state pointer
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr MSX_create();
/// opaque state pointer
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MSX_destroy(IntPtr core);
+ ///
+ /// Load BIOS and BASIC image. each must be 16K in size
+ ///
+ /// opaque state pointer
+ /// the rom data, can be disposed of once this function returns
+ /// length of romdata in bytes
+ /// 0 on success, negative value on failure.
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int MSX_load_bios(IntPtr core, byte[] bios, byte[] basic);
+
///
/// Load ROM image.
///
/// opaque state pointer
- /// the rom data, can be disposed of once this function returns
- /// length of romdata in bytes
- /// Mapper number to load core with
+ /// the rom data, can be disposed of once this function returns
+ /// length of romdata in bytes
+ /// Mapper number to load core with
+ /// the rom data, can be disposed of once this function returns
+ /// length of romdata in bytes
+ /// Mapper number to load core with
/// 0 on success, negative value on failure.
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern int MSX_load(IntPtr core, byte[] romdata, uint length, int mapper);
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
+ public static extern int MSX_load(IntPtr core, byte[] romdata_1, uint length_1, int mapper_1, byte[] romdata_2, uint length_2, int mapper_2);
///
/// Advance a frame and send controller data.
@@ -39,7 +52,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
/// length of romdata in bytes
/// Mapper number to load core with
/// 0 on success, negative value on failure.
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool MSX_frame_advance(IntPtr core, byte ctrl1, byte ctrl2, bool render, bool sound);
///
@@ -47,7 +60,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
///
/// opaque state pointer
/// where to send video to
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MSX_get_video(IntPtr core, int[] videobuf);
///
@@ -58,7 +71,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
/// where to send right audio to
/// number of left samples
/// number of right samples
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint MSX_get_audio(IntPtr core, uint[] aud_buf_L, uint[] aud_buf_R, ref uint n_samp_L, ref uint n_samp_R);
#endregion
@@ -70,7 +83,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
///
/// opaque state pointer
/// save buffer
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MSX_save_state(IntPtr core, byte[] saver);
///
@@ -90,7 +103,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
///
/// opaque state pointer
/// system bus address
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte MSX_getsysbus(IntPtr core, int addr);
///
@@ -98,7 +111,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
///
/// opaque state pointer
/// vram address
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern byte MSX_getvram(IntPtr core, int addr);
@@ -117,28 +130,28 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
///
/// opaque state pointer
/// null to clear
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MSX_settracecallback(IntPtr core, TraceCallback callback);
///
/// get the trace logger header length
///
/// opaque state pointer
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int MSX_getheaderlength(IntPtr core);
///
/// get the trace logger disassembly length, a constant
///
/// opaque state pointer
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int MSX_getdisasmlength(IntPtr core);
///
/// get the trace logger register string length, a constant
///
/// opaque state pointer
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int MSX_getregstringlength(IntPtr core);
///
@@ -147,7 +160,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
/// opaque state pointer
/// pointer to const char *
/// null to clear
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MSX_getheader(IntPtr core, StringBuilder h, int l);
///
@@ -157,7 +170,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
/// pointer to const char *
/// call type
/// copy length, must be obtained from appropriate get legnth function
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MSX_getregisterstate(IntPtr core, StringBuilder h, int t, int l);
///
@@ -167,7 +180,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
/// pointer to const char *
/// call type
/// copy length, must be obtained from appropriate get legnth function
- [DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
+ [DllImport("MSXHawk.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MSX_getdisassembly(IntPtr core, StringBuilder h, int t, int l);
#endregion
}
diff --git a/BizHawk.Emulation.Cores/Computers/MSX/MSX.IEmulator.cs b/BizHawk.Emulation.Cores/Computers/MSX/MSX.IEmulator.cs
index bd2be731d3..821df02750 100644
--- a/BizHawk.Emulation.Cores/Computers/MSX/MSX.IEmulator.cs
+++ b/BizHawk.Emulation.Cores/Computers/MSX/MSX.IEmulator.cs
@@ -149,7 +149,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
#region Video
public int _frameHz = 60;
- public int[] _vidbuffer = new int[160 * 144];
+ public int[] _vidbuffer = new int[192 * 256];
public int[] GetVideoBuffer()
{
diff --git a/BizHawk.Emulation.Cores/Computers/MSX/MSX.cs b/BizHawk.Emulation.Cores/Computers/MSX/MSX.cs
index 1d34cbb1ce..4f72453bae 100644
--- a/BizHawk.Emulation.Cores/Computers/MSX/MSX.cs
+++ b/BizHawk.Emulation.Cores/Computers/MSX/MSX.cs
@@ -27,8 +27,15 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
Array.Resize(ref RomData, ((RomData.Length / BankSize) + 1) * BankSize);
}
+ byte[] Bios = null;
+ byte[] Basic = null;
+ Bios = comm.CoreFileProvider.GetFirmware("MSX", "bios", true, "BIOS Not Found, Cannot Load");
+ Basic = comm.CoreFileProvider.GetFirmware("MSX", "basic", true, "BIOS Not Found, Cannot Load");
+
MSX_Pntr = LibMSX.MSX_create();
- LibMSX.MSX_load(MSX_Pntr, RomData, (uint)RomData.Length, 0);
+
+ LibMSX.MSX_load_bios(MSX_Pntr, Bios, Basic);
+ LibMSX.MSX_load(MSX_Pntr, RomData, (uint)RomData.Length, 0, RomData, (uint)RomData.Length, 0);
blip_L.SetRates(3579545, 44100);
blip_R.SetRates(3579545, 44100);
@@ -61,6 +68,8 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
IntPtr MSX_Pntr { get; set; } = IntPtr.Zero;
byte[] MSX_core = new byte[0x20000];
+ public byte[] _bios;
+ public byte[] _basic;
// Constants
private const int BankSize = 16384;
diff --git a/libHawk/MSXHawk/MSXHawk/Core.h b/libHawk/MSXHawk/MSXHawk/Core.h
index b1583b5152..7eebad0aa9 100644
--- a/libHawk/MSXHawk/MSXHawk/Core.h
+++ b/libHawk/MSXHawk/MSXHawk/Core.h
@@ -5,7 +5,7 @@
#include "Z80A.h"
#include "PSG.h"
-#include "VDP.h"
+#include "TMS9918A.h"
#include "Memory.h"
namespace MSXHawk
@@ -24,14 +24,19 @@ namespace MSXHawk
psg.Clock_Divider = 16;
};
- VDP vdp;
+ TMS9918A vdp;
Z80A cpu;
SN76489sms psg;
MemoryManager MemMap;
- void Load_ROM(uint8_t* ext_rom, uint32_t ext_rom_size, uint32_t ext_rom_mapper)
+ void Load_BIOS(uint8_t* bios, uint8_t* basic)
{
- MemMap.Load_ROM(ext_rom, ext_rom_size, ext_rom_mapper);
+ MemMap.Load_BIOS(bios, basic);
+ }
+
+ void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, uint32_t ext_rom_mapper_1, uint8_t* ext_rom_2, uint32_t ext_rom_size_2, uint32_t ext_rom_mapper_2)
+ {
+ MemMap.Load_ROM(ext_rom_1, ext_rom_size_1, ext_rom_mapper_1, ext_rom_2, ext_rom_size_2, ext_rom_mapper_2);
}
bool FrameAdvance(uint8_t controller_1, uint8_t controller_2, bool render, bool rendersound)
@@ -41,23 +46,28 @@ namespace MSXHawk
MemMap.start_pressed = (controller_1 & 0x80) > 0;
MemMap.lagged = true;
- int scanlinesPerFrame = 262;
+ uint32_t scanlinesPerFrame = 262;
vdp.SpriteLimit = true;
psg.num_samples_L = 0;
psg.num_samples_R = 0;
psg.sampleclock = 0;
- for (int i = 0; i < scanlinesPerFrame; i++)
+ for (uint32_t i = 0; i < scanlinesPerFrame; i++)
{
vdp.ScanLine = i;
- vdp.RenderCurrentScanline(render);
+ vdp.RenderScanline(i);
- vdp.ProcessFrameInterrupt();
- vdp.ProcessLineInterrupt();
+ if (vdp.ScanLine == 192)
+ {
+ vdp.InterruptPendingSet(true);
- for (int j = 0; j < vdp.IPeriod; j++)
+ if (vdp.EnableInterrupts())
+ cpu.NonMaskableInterruptset(true);
+ }
+
+ for (uint32_t j = 0; j < vdp.IPeriod; j++)
{
cpu.ExecuteOne();
@@ -69,27 +79,16 @@ namespace MSXHawk
}
psg.sampleclock++;
}
-
- if (vdp.ScanLine == scanlinesPerFrame - 1)
- {
- vdp.ProcessGGScreen();
- //vdp.ProcessOverscan();
- }
}
return MemMap.lagged;
}
void GetVideo(uint32_t* dest) {
- uint32_t* src = vdp.GameGearFrameBuffer;
+ uint32_t* src = vdp.FrameBuffer;
uint32_t* dst = dest;
- for (int i = 0; i < 144; i++)
- {
- std::memcpy(dst, src, sizeof uint32_t * 160);
- src += 160;
- dst += 160;
- }
+ std::memcpy(dst, src, sizeof uint32_t * 256 * 192);
}
uint32_t GetAudio(uint32_t* dest_L, uint32_t* dest_R, uint32_t* n_samp_L, uint32_t* n_samp_R)
diff --git a/libHawk/MSXHawk/MSXHawk/MSXHawk.cpp b/libHawk/MSXHawk/MSXHawk/MSXHawk.cpp
index 692eb7cbbb..a7753893df 100644
--- a/libHawk/MSXHawk/MSXHawk/MSXHawk.cpp
+++ b/libHawk/MSXHawk/MSXHawk/MSXHawk.cpp
@@ -13,37 +13,43 @@ using namespace MSXHawk;
#pragma region Core
// Create pointer to a core instance
-MSXHAWK_EXPORT MSXCore* MSX_create()
+MSXHawk_EXPORT MSXCore* MSX_create()
{
return new MSXCore();
}
// free the memory from the core pointer
-MSXHAWK_EXPORT void MSX_destroy(MSXCore* p)
+MSXHawk_EXPORT void MSX_destroy(MSXCore* p)
{
std::free(p);
}
-// load a rom into the core
-MSXHAWK_EXPORT void MSX_load(MSXCore* p, uint8_t* rom, unsigned int size, int mapper)
+// load bios and basic into the core
+MSXHawk_EXPORT void MSX_load_bios(MSXCore* p, uint8_t* bios, uint8_t* basic)
{
- p->Load_ROM(rom, size, mapper);
+ p->Load_BIOS(bios, basic);
+}
+
+// load a rom into the core
+MSXHawk_EXPORT void MSX_load(MSXCore* p, uint8_t* rom_1, uint32_t size_1, uint32_t mapper_1, uint8_t* rom_2, uint32_t size_2, uint8_t mapper_2)
+{
+ p->Load_ROM(rom_1, size_1, mapper_1, rom_2, size_2, mapper_2);
}
// advance a frame
-MSXHAWK_EXPORT void MSX_frame_advance(MSXCore* p, uint8_t ctrl1, uint8_t ctrl2, bool render, bool sound)
+MSXHawk_EXPORT void MSX_frame_advance(MSXCore* p, uint8_t ctrl1, uint8_t ctrl2, bool render, bool sound)
{
p->FrameAdvance(ctrl1, ctrl2, render, sound);
}
// send video data to external video provider
-MSXHAWK_EXPORT void MSX_get_video(MSXCore* p, uint32_t* dest)
+MSXHawk_EXPORT void MSX_get_video(MSXCore* p, uint32_t* dest)
{
p->GetVideo(dest);
}
// send audio data to external audio provider
-MSXHAWK_EXPORT uint32_t MSX_get_audio(MSXCore* p, uint32_t* dest_L, uint32_t* dest_R, uint32_t* n_samp_L, uint32_t* n_samp_R)
+MSXHawk_EXPORT uint32_t MSX_get_audio(MSXCore* p, uint32_t* dest_L, uint32_t* dest_R, uint32_t* n_samp_L, uint32_t* n_samp_R)
{
return p->GetAudio(dest_L, dest_R, n_samp_L, n_samp_R);
}
@@ -51,13 +57,13 @@ MSXHAWK_EXPORT uint32_t MSX_get_audio(MSXCore* p, uint32_t* dest_L, uint32_t* de
#pragma region State Save / Load
// save state
-MSXHAWK_EXPORT void MSX_save_state(MSXCore* p, uint8_t* saver)
+MSXHawk_EXPORT void MSX_save_state(MSXCore* p, uint8_t* saver)
{
p->SaveState(saver);
}
// load state
-MSXHAWK_EXPORT void MSX_load_state(MSXCore* p, uint8_t* loader)
+MSXHawk_EXPORT void MSX_load_state(MSXCore* p, uint8_t* loader)
{
p->LoadState(loader);
}
@@ -66,11 +72,11 @@ MSXHAWK_EXPORT void MSX_load_state(MSXCore* p, uint8_t* loader)
#pragma region Memory Domain Functions
-MSXHAWK_EXPORT uint8_t MSX_getsysbus(MSXCore* p, uint32_t addr) {
+MSXHawk_EXPORT uint8_t MSX_getsysbus(MSXCore* p, uint32_t addr) {
return p->GetSysBus(addr);
}
-MSXHAWK_EXPORT uint8_t MSX_getvram(MSXCore* p, uint32_t addr) {
+MSXHawk_EXPORT uint8_t MSX_getvram(MSXCore* p, uint32_t addr) {
return p->GetVRAM(addr);
}
#pragma endregion
@@ -79,37 +85,37 @@ MSXHAWK_EXPORT uint8_t MSX_getvram(MSXCore* p, uint32_t addr) {
#pragma region Tracer
// set tracer callback
-MSXHAWK_EXPORT void MSX_settracecallback(MSXCore* p, void (*callback)(int)) {
+MSXHawk_EXPORT void MSX_settracecallback(MSXCore* p, void (*callback)(int)) {
p->SetTraceCallback(callback);
}
// return the cpu trace header length
-MSXHAWK_EXPORT int MSX_getheaderlength(MSXCore* p) {
+MSXHawk_EXPORT int MSX_getheaderlength(MSXCore* p) {
return p->GetHeaderLength();
}
// return the cpu disassembly length
-MSXHAWK_EXPORT int MSX_getdisasmlength(MSXCore* p) {
+MSXHawk_EXPORT int MSX_getdisasmlength(MSXCore* p) {
return p->GetDisasmLength();
}
// return the cpu register string length
-MSXHAWK_EXPORT int MSX_getregstringlength(MSXCore* p) {
+MSXHawk_EXPORT int MSX_getregstringlength(MSXCore* p) {
return p->GetRegStringLength();
}
// return the cpu trace header
-MSXHAWK_EXPORT void MSX_getheader(MSXCore* p, char* h, int l) {
+MSXHawk_EXPORT void MSX_getheader(MSXCore* p, char* h, int l) {
p->GetHeader(h, l);
}
// return the cpu register state
-MSXHAWK_EXPORT void MSX_getregisterstate(MSXCore* p, char* r, int t, int l) {
+MSXHawk_EXPORT void MSX_getregisterstate(MSXCore* p, char* r, int t, int l) {
p->GetRegisterState(r, t, l);
}
// return the cpu disassembly
-MSXHAWK_EXPORT void MSX_getdisassembly(MSXCore* p, char* d, int t, int l) {
+MSXHawk_EXPORT void MSX_getdisassembly(MSXCore* p, char* d, int t, int l) {
p->GetDisassembly(d, t, l);
}
diff --git a/libHawk/MSXHawk/MSXHawk/MSXHawk.h b/libHawk/MSXHawk/MSXHawk/MSXHawk.h
index dbb02a9ed1..37cb5e0c27 100644
--- a/libHawk/MSXHawk/MSXHawk/MSXHawk.h
+++ b/libHawk/MSXHawk/MSXHawk/MSXHawk.h
@@ -1,5 +1,5 @@
#ifdef _WIN32
-#define MSXHAWK_EXPORT extern "C" __declspec(dllexport)
+#define MSXHawk_EXPORT extern "C" __declspec(dllexport)
#elif __linux__
-#define MSXHAWK_EXPORT extern "C"
+#define MSXHawk_EXPORT extern "C"
#endif
diff --git a/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj b/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj
index c08927af6e..b1dfcdac86 100644
--- a/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj
+++ b/libHawk/MSXHawk/MSXHawk/MSXHawk.vcxproj
@@ -71,19 +71,19 @@
- MSXHAWK
+ MSXHawk
true
- MSXHAWK
+ MSXHawk
true
- MSXHAWK
+ MSXHawk
false
- MSXHAWK
+ MSXHawk
false
@@ -91,7 +91,7 @@
Use
Level3
true
- WIN32;_DEBUG;MSXHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ WIN32;_DEBUG;MSXHawk_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
pch.h
@@ -106,7 +106,7 @@
Use
Level3
true
- _DEBUG;MSXHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ _DEBUG;MSXHawk_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
pch.h
@@ -123,7 +123,7 @@
true
true
true
- WIN32;NDEBUG;MSXHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ WIN32;NDEBUG;MSXHawk_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
pch.h
@@ -142,7 +142,7 @@
true
true
true
- NDEBUG;MSXHAWK_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ NDEBUG;MSXHawk_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
true
pch.h
@@ -160,7 +160,7 @@
-
+
diff --git a/libHawk/MSXHawk/MSXHawk/Memory.cpp b/libHawk/MSXHawk/MSXHawk/Memory.cpp
index 23c6cc4ba8..ae8af780dd 100644
--- a/libHawk/MSXHawk/MSXHawk/Memory.cpp
+++ b/libHawk/MSXHawk/MSXHawk/Memory.cpp
@@ -5,7 +5,7 @@
#include "Memory.h"
#include "Z80A.h"
-#include "VDP.h"
+#include "TMS9918A.h"
#include "PSG.h"
using namespace std;
@@ -15,143 +15,172 @@ namespace MSXHawk
uint8_t MemoryManager::HardwareRead(uint32_t port)
{
port &= 0xFF;
- if (port < 0x40) // General IO ports
- {
- switch (port)
- {
- case 0x00: return ReadPort0();
- case 0x01: return Port01;
- case 0x02: return Port02;
- case 0x03: return Port03;
- case 0x04: return Port04;
- case 0x05: return Port05;
- case 0x06: return 0xFF;
- case 0x3E: return Port3E;
- default: return 0xFF;
- }
- }
- if (port < 0x80) // VDP Vcounter/HCounter
- {
- if ((port & 1) == 0)
- return vdp_pntr->ReadVLineCounter();
- else
- return vdp_pntr->ReadHLineCounter();
- }
- if (port < 0xC0) // VDP data/control ports
+ if (port >= 0xA0 && port < 0xC0) // VDP data/control ports
{
if ((port & 1) == 0)
return vdp_pntr->ReadData();
else
return vdp_pntr->ReadVdpStatus();
}
- switch (port)
- {
- case 0xC0:
- case 0xDC: return ReadControls1();
- case 0xC1:
- case 0xDD: return ReadControls2();
- case 0xDE: return PortDEEnabled ? PortDE : 0xFF;
- case 0xF2: return 0xFF;
- default: return 0xFF;
- }
+
+ return 0xFF;
}
void MemoryManager::HardwareWrite(uint32_t port, uint8_t value)
{
port &= 0xFF;
- if (port < 0x40) // general IO ports
+
+ if (port == 0x98) // VDP
{
- switch (port & 0xFF)
- {
- case 0x01: Port01 = value; break;
- case 0x02: Port02 = value; break;
- case 0x03: Port03 = value; break;
- case 0x04: /*Port04 = value*/; break; // receive port, not sure what writing does
- case 0x05: Port05 = (uint8_t)(value & 0xF8); break;
- case 0x06: psg_pntr->Set_Panning(value); break;
- case 0x3E: Port3E = value; break;
- case 0x3F: Port3F = value; break;
- }
- }
- else if (port < 0x80) // PSG
+ vdp_pntr->WriteVdpData(value);
+ }
+ else if(port == 0x99) // VDP
+ {
+ vdp_pntr->WriteVdpControl(value);
+ }
+ else if (port == 0xA1)
{
psg_pntr->WriteReg(value);
}
- else if (port < 0xC0) // VDP
+ else if (port == 0xA8)
{
- if ((port & 1) == 0)
- {
- vdp_pntr->WriteVdpData(value);
- }
- else
- {
- vdp_pntr->WriteVdpControl(value);
- }
+ PortA8 = value;
+ remap();
}
- else if (port == 0xDE && PortDEEnabled) PortDE = value;
}
- void MemoryManager::remap_ROM_0()
+ void MemoryManager::remap()
{
- // 0x0000 - 0x03FF always maps to start of ROM
- cpu_pntr->MemoryMap[0] = &rom[0];
- cpu_pntr->MemoryMapMask[0] = 0;
-
- for (uint32_t i = 1; i < 16; i++)
- {
- cpu_pntr->MemoryMap[i] = &rom[(reg_FFFD % rom_size) * 0x4000 + (0x400 * i)];
- cpu_pntr->MemoryMapMask[i] = 0;
- }
- }
-
- void MemoryManager::remap_ROM_1()
- {
- for (uint32_t i = 0; i < 16; i++)
- {
- cpu_pntr->MemoryMap[i + 16] = &rom[(reg_FFFE % rom_size) * 0x4000 + (0x400 * i)];
- cpu_pntr->MemoryMapMask[i + 16] = 0;
- }
- }
-
- void MemoryManager::remap_ROM_2()
- {
- if ((reg_FFFC & 0x8) > 0)
+ if ((PortA8 & 3) == 0)
{
for (uint32_t i = 0; i < 16; i++)
{
- cpu_pntr->MemoryMap[i + 32] = &cart_ram[((reg_FFFC >> 2) & 0x1) * 0x4000 + (0x400 * i)];
- cpu_pntr->MemoryMapMask[i + 32] = 0xFF;
+ cpu_pntr->MemoryMap[i] = &bios_rom[(0x400 * i)];
+ cpu_pntr->MemoryMapMask[i] = 0;
}
}
- else
+ else if ((PortA8 & 3) == 1)
{
- for (int i = 0; i < 16; i++)
+ for (uint32_t i = 0; i < 16; i++)
{
- cpu_pntr->MemoryMap[i + 32] = &rom[(reg_FFFF % rom_size) * 0x4000 + (0x400 * i)];
+ cpu_pntr->MemoryMap[i] = &rom_1[(0x400 * i)];
+ cpu_pntr->MemoryMapMask[i] = 0;
+ }
+ }
+ else if ((PortA8 & 3) == 2)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i] = &rom_2[(0x400 * i)];
+ cpu_pntr->MemoryMapMask[i] = 0;
+ }
+ }
+ else if ((PortA8 & 3) == 3)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i] = &ram[0xC000 + (0x400 * i)];
+ cpu_pntr->MemoryMapMask[i] = 0xFF;
+ }
+ }
+
+ if (((PortA8 >> 2) & 3) == 0)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 16] = &basic_rom[(0x400 * i)];
+ cpu_pntr->MemoryMapMask[i + 16] = 0;
+ }
+ }
+ else if (((PortA8 >> 2) & 3) == 1)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 16] = &rom_1[04000 + (0x400 * i)];
+ cpu_pntr->MemoryMapMask[i + 16] = 0;
+ }
+ }
+ else if (((PortA8 >> 2) & 3) == 2)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 16] = &rom_2[04000 + (0x400 * i)];
+ cpu_pntr->MemoryMapMask[i + 16] = 0;
+ }
+ }
+ else if (((PortA8 >> 2) & 3) == 3)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 16] = &ram[0x8000 + (0x400 * i)];
+ cpu_pntr->MemoryMapMask[i + 16] = 0xFF;
+ }
+ }
+
+ if (((PortA8 >> 4) & 3) == 0)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 32] = &unmapped[0];
cpu_pntr->MemoryMapMask[i + 32] = 0;
}
}
- }
-
- void MemoryManager::remap_RAM()
- {
- if ((reg_FFFC & 0x10) > 0)
+ else if (((PortA8 >> 4) & 3) == 1)
{
for (uint32_t i = 0; i < 16; i++)
{
- cpu_pntr->MemoryMap[i + 48] = &cart_ram[(0x400 * i)];
- cpu_pntr->MemoryMapMask[i + 48] = 0xFF;
+ cpu_pntr->MemoryMap[i + 32] = &rom_1[0x8000 + (0x400 * i)];
+ cpu_pntr->MemoryMapMask[i + 32] = 0;
}
}
- else
+ else if (((PortA8 >> 4) & 3) == 2)
{
- for (uint32_t i = 0; i < 8; i++)
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 32] = &rom_2[0x8000 + (0x400 * i)];
+ cpu_pntr->MemoryMapMask[i + 32] = 0;
+ }
+ }
+ else if (((PortA8 >> 4) & 3) == 3)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 32] = &ram[0x4000 + (0x400 * i)];
+ cpu_pntr->MemoryMapMask[i + 32] = 0xFF;
+ }
+ }
+
+ if (((PortA8 >> 6) & 3) == 0)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 48] = &unmapped[0];
+ cpu_pntr->MemoryMapMask[i + 48] = 0;
+ }
+ }
+ else if (((PortA8 >> 6) & 3) == 1)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 48] = &rom_1[0xC000 + (0x400 * i)];
+ cpu_pntr->MemoryMapMask[i + 48] = 0;
+ }
+ }
+ else if (((PortA8 >> 6) & 3) == 2)
+ {
+ for (uint32_t i = 0; i < 16; i++)
+ {
+ cpu_pntr->MemoryMap[i + 48] = &rom_2[0xC000 + (0x400 * i)];
+ cpu_pntr->MemoryMapMask[i + 48] = 0;
+ }
+ }
+ else if (((PortA8 >> 6) & 3) == 3)
+ {
+ for (uint32_t i = 0; i < 16; i++)
{
cpu_pntr->MemoryMap[i + 48] = &ram[(0x400 * i)];
- cpu_pntr->MemoryMap[i + 48 + 8] = &ram[(0x400 * i)];
cpu_pntr->MemoryMapMask[i + 48] = 0xFF;
- cpu_pntr->MemoryMapMask[i + 48 + 8] = 0xFF;
}
}
}
diff --git a/libHawk/MSXHawk/MSXHawk/Memory.h b/libHawk/MSXHawk/MSXHawk/Memory.h
index 307c74a7e2..83dbf9089b 100644
--- a/libHawk/MSXHawk/MSXHawk/Memory.h
+++ b/libHawk/MSXHawk/MSXHawk/Memory.h
@@ -8,21 +8,26 @@ using namespace std;
namespace MSXHawk
{
class Z80A;
- class VDP;
+ class TMS9918A;
class SN76489sms;
class MemoryManager
{
public:
- VDP* vdp_pntr = nullptr;
+ TMS9918A* vdp_pntr = nullptr;
SN76489sms* psg_pntr = nullptr;
Z80A* cpu_pntr = nullptr;
- uint8_t* rom = nullptr;
+ uint8_t* rom_1 = nullptr;
+ uint8_t* rom_2 = nullptr;
+ uint8_t* bios_rom = nullptr;
+ uint8_t* basic_rom = nullptr;
// initialized by core loading, not savestated
- uint32_t rom_size;
- uint32_t rom_mapper;
+ uint32_t rom_size_1;
+ uint32_t rom_mapper_1;
+ uint32_t rom_size_2;
+ uint32_t rom_mapper_2;
// State
bool PortDEEnabled = false;
@@ -30,17 +35,11 @@ namespace MSXHawk
bool start_pressed;
uint8_t controller_byte_1, controller_byte_2;
- uint8_t Port01 = 0xFF;
- uint8_t Port02 = 0xFF;
- uint8_t Port03 = 0x00;
- uint8_t Port04 = 0xFF;
- uint8_t Port05 = 0x00;
- uint8_t Port3E = 0xAF;
- uint8_t Port3F = 0xFF;
- uint8_t PortDE = 0x00;
+ uint8_t PortA8 = 0x00;
uint8_t reg_FFFC, reg_FFFD, reg_FFFE, reg_FFFF;
- uint8_t ram[0x2000] = {};
+ uint8_t ram[0x10000] = {};
uint8_t cart_ram[0x8000] = {};
+ uint8_t unmapped[0x400] = {};
MemoryManager()
{
@@ -51,53 +50,32 @@ namespace MSXHawk
void HardwareWrite(uint32_t addr, uint8_t value);
- void remap_ROM_0();
+ void remap();
- void remap_ROM_1();
-
- void remap_ROM_2();
-
- void remap_RAM();
-
- void Load_ROM(uint8_t* ext_rom, uint32_t ext_rom_size, uint32_t ext_rom_mapper)
+ void Load_BIOS(uint8_t* bios, uint8_t* basic)
{
- rom = ext_rom;
- rom_size = ext_rom_size / 0x4000;
- rom_mapper = ext_rom_mapper;
+ bios_rom = bios;
+ basic_rom = basic;
+ }
+
+ void Load_ROM(uint8_t* ext_rom_1, uint32_t ext_rom_size_1, uint32_t ext_rom_mapper_1, uint8_t* ext_rom_2, uint32_t ext_rom_size_2, uint32_t ext_rom_mapper_2)
+ {
+ rom_1 = ext_rom_1;
+ rom_size_1 = ext_rom_size_1 / 0x4000;
+ rom_mapper_1 = ext_rom_mapper_1;
+ rom_2 = ext_rom_2;
+ rom_size_2 = ext_rom_size_2 / 0x4000;
+ rom_mapper_2 = ext_rom_mapper_2;
// default memory map setup
- reg_FFFC = 0;
- reg_FFFD = 0;
- reg_FFFE = 1;
- reg_FFFF = 2;
- remap_ROM_0();
- remap_ROM_1();
- remap_ROM_2();
- remap_RAM();
+ PortA8 = 0;
+
+ remap();
}
void MemoryWrite(uint32_t addr, uint8_t value)
{
- switch (addr)
- {
- case 0xFFFC:
- reg_FFFC = value;
- remap_ROM_2();
- remap_RAM();
- break;
- case 0xFFFD:
- reg_FFFD = value;
- remap_ROM_0();
- break;
- case 0xFFFE:
- reg_FFFE = value;
- remap_ROM_1();
- break;
- case 0xFFFF:
- reg_FFFF = value;
- remap_ROM_2();
- break;
- }
+
}
uint8_t ReadPort0()
@@ -131,19 +109,6 @@ namespace MSXHawk
value &= ~(controller_byte_2 & 0xF);
- if ((Port3F & 0x0F) == 5)
- {
- if (Port3F >> 4 == 0x0F)
- {
- value |= 0xC0;
- }
-
- else
- {
- value &= 0x3F;
- }
- }
-
return value;
}
@@ -157,14 +122,7 @@ namespace MSXHawk
*saver = controller_byte_1; saver++;
*saver = controller_byte_2; saver++;
- *saver = Port01; saver++;
- *saver = Port02; saver++;
- *saver = Port03; saver++;
- *saver = Port04; saver++;
- *saver = Port05; saver++;
- *saver = Port3E; saver++;
- *saver = Port3F; saver++;
- *saver = PortDE; saver++;
+ *saver = PortA8; saver++;
*saver = reg_FFFC; saver++;
*saver = reg_FFFD; saver++;
*saver = reg_FFFE; saver++;
@@ -184,26 +142,16 @@ namespace MSXHawk
controller_byte_1 = *loader; loader++;
controller_byte_2 = *loader; loader++;
- Port01 = *loader; loader++;
- Port02 = *loader; loader++;
- Port03 = *loader; loader++;
- Port04 = *loader; loader++;
- Port05 = *loader; loader++;
- Port3E = *loader; loader++;
- Port3F = *loader; loader++;
- PortDE = *loader; loader++;
+ PortA8 = *loader; loader++;
reg_FFFC = *loader; loader++;
reg_FFFD = *loader; loader++;
reg_FFFE = *loader; loader++;
reg_FFFF = *loader; loader++;
- std::memcpy(&ram, loader, 0x2000); loader += 0x2000;
- std::memcpy(&cart_ram, loader, 0x2000); loader += 0x2000;
+ std::memcpy(&ram, loader, 0x10000); loader += 0x10000;
+ std::memcpy(&cart_ram, loader, 0x8000); loader += 0x8000;
- remap_ROM_0();
- remap_ROM_1();
- remap_ROM_2();
- remap_RAM();
+ remap();
return loader;
}
diff --git a/libHawk/MSXHawk/MSXHawk/TMS9918A.h b/libHawk/MSXHawk/MSXHawk/TMS9918A.h
new file mode 100644
index 0000000000..33c9d033e1
--- /dev/null
+++ b/libHawk/MSXHawk/MSXHawk/TMS9918A.h
@@ -0,0 +1,523 @@
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+namespace MSXHawk
+{
+ class TMS9918A
+ {
+ public:
+ #pragma region VDP
+
+ TMS9918A()
+ {
+
+ }
+
+ // external pointers to CPU
+ bool* INT_FLAG = nullptr;
+ // external flags to display background or sprites
+ bool SHOW_BG, SHOW_SPRITES;
+ bool SpriteLimit;
+
+ // VDP State
+ bool VdpWaitingForLatchInt = true;
+ bool VdpWaitingForLatchByte = true;
+ bool VIntPending;
+ bool HIntPending;
+
+ uint8_t StatusByte;
+ uint8_t VdpLatch;
+ uint8_t VdpBuffer;
+ uint8_t Registers[8] = {};
+ uint8_t VRAM[0x4000]; //16kb video RAM
+
+ int32_t ScanLine;
+ uint32_t IPeriod = 228;
+ uint32_t VdpAddress;
+ uint32_t TmsMode;
+ uint32_t ColorTableBase;
+ uint32_t PatternGeneratorBase;
+ uint32_t SpritePatternGeneratorBase;
+ uint32_t TmsPatternNameTableBase;
+ uint32_t TmsSpriteAttributeBase;
+
+ uint32_t FrameBuffer[192 * 256] = {};
+
+ uint32_t BackgroundColor = 0;
+
+ uint32_t PaletteTMS9918[16] =
+ {
+ 0xFF000000,
+ 0xFF000000,
+ 0xFF47B73B,
+ 0xFF7CCF6F,
+ 0xFF5D4EFF,
+ 0xFF8072FF,
+ 0xFFB66247,
+ 0xFF5DC8ED,
+ 0xFFD76B48,
+ 0xFFFB8F6C,
+ 0xFFC3CD41,
+ 0xFFD3DA76,
+ 0xFF3E9F2F,
+ 0xFFB664C7,
+ 0xFFCCCCCC,
+ 0xFFFFFFFF
+ };
+
+ bool Mode1Bit() { return (Registers[1] & 16) > 0; }
+ bool Mode2Bit() { return (Registers[0] & 2) > 0; }
+ bool Mode3Bit() { return (Registers[1] & 8) > 0; }
+ bool EnableDoubledSprites() { return (Registers[1] & 1) > 0; }
+ bool EnableLargeSprites() { return (Registers[1] & 2) > 0; }
+ bool EnableInterrupts() { return (Registers[1] & 32) > 0; }
+ bool DisplayOn() { return (Registers[1] & 64) > 0; }
+ bool Mode16k() { return (Registers[1] & 128) > 0; }
+
+ bool InterruptPendingGet() { return (StatusByte & 0x80) != 0; }
+ void InterruptPendingSet(bool value) { StatusByte = (uint8_t)((StatusByte & ~0x02) | (value ? 0x80 : 0x00)); }
+
+ void WriteVdpControl(uint8_t value)
+ {
+ if (VdpWaitingForLatchByte)
+ {
+ VdpLatch = value;
+ VdpWaitingForLatchByte = false;
+ VdpAddress = (uint32_t)((VdpAddress & 0x3F00) | value);
+ return;
+ }
+
+ VdpWaitingForLatchByte = true;
+ VdpAddress = (uint32_t)(((value & 63) << 8) | VdpLatch);
+ VdpAddress &= 0x3FFF;
+ switch (value & 0xC0)
+ {
+ case 0x00: // read VRAM
+ VdpBuffer = VRAM[VdpAddress];
+ VdpAddress++;
+ VdpAddress &= 0x3FFF;
+ break;
+ case 0x40: // write VRAM
+ break;
+ case 0x80: // VDP register write
+ uint32_t reg = value & 0x0F;
+ WriteRegister(reg, VdpLatch);
+ break;
+ }
+ }
+
+ void WriteVdpData(uint8_t value)
+ {
+ VdpWaitingForLatchByte = true;
+ VdpBuffer = value;
+
+ VRAM[VdpAddress] = value;
+ //if (!Mode16k)
+ // Console.WriteLine("VRAM written while not in 16k addressing mode!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ VdpAddress++;
+ VdpAddress &= 0x3FFF;
+ }
+
+ void WriteRegister(uint32_t reg, uint8_t data)
+ {
+ if (reg >= 8) return;
+
+ Registers[reg] = data;
+ switch (reg)
+ {
+ case 0: // Mode Control Register 1
+ CheckVideoMode();
+ break;
+ case 1: // Mode Control Register 2
+ CheckVideoMode();
+ INT_FLAG[0] = (EnableInterrupts() && InterruptPendingGet());
+ break;
+ case 2: // Name Table Base Address
+ TmsPatternNameTableBase = (Registers[2] << 10) & 0x3C00;
+ break;
+ case 3: // Color Table Base Address
+ ColorTableBase = (Registers[3] << 6) & 0x3FC0;
+ break;
+ case 4: // Pattern Generator Base Address
+ PatternGeneratorBase = (Registers[4] << 11) & 0x3800;
+ break;
+ case 5: // Sprite Attribute Table Base Address
+ TmsSpriteAttributeBase = (Registers[5] << 7) & 0x3F80;
+ break;
+ case 6: // Sprite Pattern Generator Base Adderss
+ SpritePatternGeneratorBase = (Registers[6] << 11) & 0x3800;
+ break;
+ }
+ }
+
+ uint8_t ReadVdpStatus()
+ {
+ VdpWaitingForLatchByte = true;
+ uint8_t returnValue = StatusByte;
+ StatusByte &= 0x1F;
+ INT_FLAG[0] = false;
+
+ return returnValue;
+ }
+
+ uint8_t ReadData()
+ {
+ VdpWaitingForLatchByte = true;
+ uint8_t value = VdpBuffer;
+ VdpBuffer = VRAM[VdpAddress];
+ VdpAddress++;
+ VdpAddress &= 0x3FFF;
+ return value;
+ }
+
+ void CheckVideoMode()
+ {
+ if (Mode1Bit()) TmsMode = 1;
+ else if (Mode2Bit()) TmsMode = 2;
+ else if (Mode3Bit()) TmsMode = 3;
+ else TmsMode = 0;
+ }
+
+ void RenderScanline(int32_t scanLine)
+ {
+ if (scanLine >= 192)
+ return;
+
+ if (TmsMode == 2)
+ {
+ RenderBackgroundM2(scanLine);
+ RenderTmsSprites(scanLine);
+ }
+ else if (TmsMode == 0)
+ {
+ RenderBackgroundM0(scanLine);
+ RenderTmsSprites(scanLine);
+ }
+ else if (TmsMode == 3)
+ {
+ RenderBackgroundM3(scanLine);
+ RenderTmsSprites(scanLine);
+ }
+ else if (TmsMode == 1)
+ {
+ RenderBackgroundM1(scanLine);
+ // no sprites (text mode)
+ }
+ }
+
+ void RenderBackgroundM0(uint32_t scanLine)
+ {
+ if (DisplayOn() == false)
+ {
+ for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; };
+ return;
+ }
+
+ uint32_t yc = scanLine / 8;
+ uint32_t yofs = scanLine % 8;
+ uint32_t FrameBufferOffset = scanLine * 256;
+ uint32_t PatternNameOffset = TmsPatternNameTableBase + (yc * 32);
+ uint32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
+
+ for (uint32_t xc = 0; xc < 32; xc++)
+ {
+ uint32_t pn = VRAM[PatternNameOffset++];
+ uint32_t pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs];
+ uint32_t colorEntry = VRAM[ColorTableBase + (pn / 8)];
+ uint32_t fgIndex = (colorEntry >> 4) & 0x0F;
+ uint32_t bgIndex = colorEntry & 0x0F;
+ uint32_t fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex];
+ uint32_t bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex];
+
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x20) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x10) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x08) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x04) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x02) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x01) > 0) ? fgColor : bgColor;
+ }
+ }
+
+ void RenderBackgroundM1(uint32_t scanLine)
+ {
+ if (DisplayOn() == false)
+ {
+ for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; };
+ return;
+ }
+
+ uint32_t yc = scanLine / 8;
+ uint32_t yofs = scanLine % 8;
+ uint32_t FrameBufferOffset = scanLine * 256;
+ uint32_t PatternNameOffset = TmsPatternNameTableBase + (yc * 40);
+ uint32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
+
+ for (uint32_t xc = 0; xc < 40; xc++)
+ {
+ uint32_t pn = VRAM[PatternNameOffset++];
+ uint32_t pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs];
+ uint32_t colorEntry = Registers[7];
+ uint32_t fgIndex = (colorEntry >> 4) & 0x0F;
+ uint32_t bgIndex = colorEntry & 0x0F;
+ uint32_t fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex];
+ uint32_t bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex];
+
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x20) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x10) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x08) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x04) > 0) ? fgColor : bgColor;
+ }
+ }
+
+ void RenderBackgroundM2(uint32_t scanLine)
+ {
+ if (DisplayOn() == false)
+ {
+ for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; };
+ return;
+ }
+
+ uint32_t yrow = scanLine / 8;
+ uint32_t yofs = scanLine % 8;
+ uint32_t FrameBufferOffset = scanLine * 256;
+ uint32_t PatternNameOffset = TmsPatternNameTableBase + (yrow * 32);
+ uint32_t PatternGeneratorOffset = (((Registers[4] & 4) << 11) & 0x2000);
+ uint32_t ColorOffset = (ColorTableBase & 0x2000);
+ uint32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
+
+ for (uint32_t xc = 0; xc < 32; xc++)
+ {
+ uint32_t pn = VRAM[PatternNameOffset++] + ((yrow / 8) * 0x100);
+ uint32_t pv = VRAM[PatternGeneratorOffset + (pn * 8) + yofs];
+ uint32_t colorEntry = VRAM[ColorOffset + (pn * 8) + yofs];
+ uint32_t fgIndex = (colorEntry >> 4) & 0x0F;
+ uint32_t bgIndex = colorEntry & 0x0F;
+ uint32_t fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex];
+ uint32_t bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex];
+
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x80) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x40) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x20) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x10) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x08) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x04) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x02) > 0) ? fgColor : bgColor;
+ FrameBuffer[FrameBufferOffset++] = ((pv & 0x01) > 0) ? fgColor : bgColor;
+ }
+ }
+
+ void RenderBackgroundM3(uint32_t scanLine)
+ {
+ if (DisplayOn() == false)
+ {
+ for (int i = 0; i < 256; i++) { FrameBuffer[scanLine * 256 + i] = 0; };
+ return;
+ }
+
+ uint32_t yc = scanLine / 8;
+ bool top = (scanLine & 4) == 0; // am I in the top 4 pixels of an 8-pixel character?
+ uint32_t FrameBufferOffset = scanLine * 256;
+ uint32_t PatternNameOffset = TmsPatternNameTableBase + (yc * 32);
+ uint32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
+
+ for (uint32_t xc = 0; xc < 32; xc++)
+ {
+ uint32_t pn = VRAM[PatternNameOffset++];
+ uint32_t pv = VRAM[PatternGeneratorBase + (pn * 8) + ((yc & 3) * 2) + (top ? 0 : 1)];
+
+ uint32_t lColorIndex = pv & 0xF;
+ uint32_t rColorIndex = pv >> 4;
+ uint32_t lColor = lColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[lColorIndex];
+ uint32_t rColor = rColorIndex == 0 ? ScreenBGColor : PaletteTMS9918[rColorIndex];
+
+ FrameBuffer[FrameBufferOffset++] = lColor;
+ FrameBuffer[FrameBufferOffset++] = lColor;
+ FrameBuffer[FrameBufferOffset++] = lColor;
+ FrameBuffer[FrameBufferOffset++] = lColor;
+ FrameBuffer[FrameBufferOffset++] = rColor;
+ FrameBuffer[FrameBufferOffset++] = rColor;
+ FrameBuffer[FrameBufferOffset++] = rColor;
+ FrameBuffer[FrameBufferOffset] = rColor;
+ }
+ }
+
+ uint8_t ScanlinePriorityBuffer[256] = {};
+ uint8_t SpriteCollisionBuffer[256] = {};
+
+ void RenderTmsSprites(int32_t scanLine)
+ {
+ if (EnableDoubledSprites() == false)
+ {
+ RenderTmsSpritesStandard(scanLine);
+ }
+ else
+ {
+ RenderTmsSpritesDouble(scanLine);
+ }
+ }
+
+ void RenderTmsSpritesStandard(int32_t scanLine)
+ {
+ if (DisplayOn() == false) return;
+
+ for (uint32_t i = 0; i < 256; i++)
+ {
+ ScanlinePriorityBuffer[i] = 0;
+ SpriteCollisionBuffer[i] = 0;
+ };
+
+ bool LargeSprites = EnableLargeSprites();
+
+ int32_t SpriteSize = 8;
+ if (LargeSprites) SpriteSize *= 2;
+ const int32_t OneCellSize = 8;
+
+ int32_t NumSpritesOnScanline = 0;
+ for (int32_t i = 0; i < 32; i++)
+ {
+ int32_t SpriteBase = TmsSpriteAttributeBase + (i * 4);
+ int32_t y = VRAM[SpriteBase++];
+ int32_t x = VRAM[SpriteBase++];
+ int32_t Pattern = VRAM[SpriteBase++];
+ int32_t Color = VRAM[SpriteBase];
+
+ if (y == 208) break; // terminator sprite
+ if (y > 224) y -= 256; // sprite Y wrap
+ y++; // inexplicably, sprites start on Y+1
+ if (y > scanLine || y + SpriteSize <= scanLine) continue; // sprite is not on this scanline
+ if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment
+
+ if (++NumSpritesOnScanline == 5)
+ {
+ StatusByte &= 0xE0; // Clear FS0-FS4 bits
+ StatusByte |= (uint8_t)i; // set 5th sprite index
+ StatusByte |= 0x40; // set overflow bit
+ break;
+ }
+
+ if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-uint8_t alignment
+ int32_t SpriteLine = scanLine - y;
+
+ // pv contains the VRAM uint8_t holding the pattern data for this character at this scanline.
+ // each uint8_t contains the pattern data for each the 8 pixels on this line.
+ // the bit-shift further down on PV pulls out the relevant horizontal pixel.
+
+ int8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine];
+
+ for (int32_t xp = 0; xp < SpriteSize && x + xp < 256; xp++)
+ {
+ if (x + xp < 0) continue;
+ if (LargeSprites && xp == OneCellSize)
+ pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16];
+
+ if (Color != 0 && (pv & (1 << (7 - (xp & 7)))) > 0)
+ {
+ if (SpriteCollisionBuffer[x + xp] != 0)
+ StatusByte |= 0x20; // Set sprite collision flag
+
+ if (ScanlinePriorityBuffer[x + xp] == 0)
+ {
+ ScanlinePriorityBuffer[x + xp] = 1;
+ SpriteCollisionBuffer[x + xp] = 1;
+ FrameBuffer[(scanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F];
+ }
+ }
+ }
+ }
+ }
+
+ void RenderTmsSpritesDouble(int32_t scanLine)
+ {
+ if (DisplayOn() == false) return;
+
+ for (uint32_t i = 0; i < 256; i++)
+ {
+ ScanlinePriorityBuffer[i] = 0;
+ SpriteCollisionBuffer[i] = 0;
+ };
+
+ bool LargeSprites = EnableLargeSprites();
+
+ int32_t SpriteSize = 8;
+ if (LargeSprites) SpriteSize *= 2;
+ SpriteSize *= 2; // because sprite magnification
+ const int32_t OneCellSize = 16; // once 8-pixel cell, doubled, will take 16 pixels
+
+ int32_t NumSpritesOnScanline = 0;
+ for (int32_t i = 0; i < 32; i++)
+ {
+ int32_t SpriteBase = TmsSpriteAttributeBase + (i * 4);
+ int32_t y = VRAM[SpriteBase++];
+ int32_t x = VRAM[SpriteBase++];
+ int32_t Pattern = VRAM[SpriteBase++];
+ int32_t Color = VRAM[SpriteBase];
+
+ if (y == 208) break; // terminator sprite
+ if (y > 224) y -= 256; // sprite Y wrap
+ y++; // inexplicably, sprites start on Y+1
+ if (y > scanLine || y + SpriteSize <= scanLine) continue; // sprite is not on this scanline
+ if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment
+
+ if (++NumSpritesOnScanline == 5)
+ {
+ StatusByte &= 0xE0; // Clear FS0-FS4 bits
+ StatusByte |= (uint8_t)i; // set 5th sprite index
+ StatusByte |= 0x40; // set overflow bit
+ break;
+ }
+
+ if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-byte alignment
+ int32_t SpriteLine = scanLine - y;
+ SpriteLine /= 2; // because of sprite magnification
+
+ int8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine];
+
+ for (int32_t xp = 0; xp < SpriteSize && x + xp < 256; xp++)
+ {
+ if (x + xp < 0) continue;
+ if (LargeSprites && xp == OneCellSize)
+ pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16];
+
+ if (Color != 0 && (pv & (1 << (7 - ((xp / 2) & 7)))) > 0) // xp/2 is due to sprite magnification
+ {
+ if (SpriteCollisionBuffer[x + xp] != 0)
+ StatusByte |= 0x20; // Set sprite collision flag
+
+ if (ScanlinePriorityBuffer[x + xp] == 0)
+ {
+ ScanlinePriorityBuffer[x + xp] = 1;
+ SpriteCollisionBuffer[x + xp] = 1;
+ FrameBuffer[(scanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F];
+ }
+ }
+ }
+ }
+ }
+
+ #pragma endregion
+
+ #pragma region State Save / Load
+
+ uint8_t* SaveState(uint8_t* saver)
+ {
+
+ return saver;
+ }
+
+ uint8_t* LoadState(uint8_t* loader)
+ {
+
+ return loader;
+ }
+
+ #pragma endregion
+ };
+}
diff --git a/libHawk/MSXHawk/MSXHawk/VDP.h b/libHawk/MSXHawk/MSXHawk/VDP.h
deleted file mode 100644
index b8081f74af..0000000000
--- a/libHawk/MSXHawk/MSXHawk/VDP.h
+++ /dev/null
@@ -1,1314 +0,0 @@
-#include
-#include
-#include
-#include
-
-using namespace std;
-
-namespace MSXHawk
-{
- class VDP
- {
- public:
- #pragma region VDP
-
- // external pointers to CPU
- bool* INT_FLAG = nullptr;
- // external flags to display background or sprites
- bool SHOW_BG, SHOW_SPRITES;
- bool SpriteLimit;
-
- // VDP State
- bool VdpWaitingForLatchInt = true;
- bool VIntPending;
- bool HIntPending;
-
- uint8_t VRAM[0x4000]; //16kb video RAM
- uint8_t CRAM[64]; // SMS = 32 uint8_ts, GG = 64 uint8_ts CRAM
- uint8_t Registers[16] = { 0x06, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xF0, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00 };
- uint8_t StatusInt;
- uint8_t VdpLatch;
- uint8_t VdpBuffer;
- uint8_t VdpCommand;
- uint8_t HCounter = 0x90;
- uint8_t TmsMode = 4;
- uint8_t lineIntLinesRemaining;
- uint8_t mode_sys;
- uint8_t DisplayType;
-
- uint16_t VdpAddress;
-
- uint32_t NameTableBase;
- uint32_t ColorTableBase;
- uint32_t PatternGeneratorBase;
- uint32_t SpritePatternGeneratorBase;
- uint32_t TmsPatternNameTableBase;
- uint32_t TmsSpriteAttributeBase;
-
- int32_t IPeriod = 228;
- int32_t FrameHeight = 192;
- int32_t ScanLine;
-
- // not savestated, only effected on frame boundaries
- uint32_t FrameBuffer[256 * 244];
- uint32_t GameGearFrameBuffer[160 * 144];
-
- // preprocessed state assist stuff, don't need to savestate if saving only on frame boundaries
- uint8_t PatternBuffer[0x8000];
- uint8_t ScanlinePriorityBuffer[256];
- uint8_t SpriteCollisionBuffer[256];
-
- uint32_t Palette[32];
-
- const uint32_t Command_VramRead = 0x00;
- const uint32_t Command_VramWrite = 0x40;
- const uint32_t Command_RegisterWrite = 0x80;
- const uint32_t Command_CramWrite = 0xC0;
-
- const uint8_t MODE_SMS = 1;
- const uint8_t MODE_GG = 2;
-
- const uint8_t DISP_TYPE_NTSC = 1;
- const uint8_t DISP_TYPE_PAL = 2;
-
- const uint8_t pow2[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
- const uint8_t SMSPalXlatTable[4] = { 0, 85, 170, 255 };
- const uint8_t GGPalXlatTable[16] = { 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255 };
-
- VDP()
- {
- mode_sys = MODE_GG;
-
- DisplayType = DISP_TYPE_NTSC;
- NameTableBase = CalcNameTableBase();
- }
-
- inline bool Mode1Bit() { return (Registers[1] & 16) > 0; }
- inline bool Mode2Bit() { return (Registers[0] & 2) > 0; }
- inline bool Mode3Bit() { return (Registers[1] & 8) > 0; }
- inline bool Mode4Bit() { return (Registers[0] & 4) > 0; }
- inline bool ShiftSpritesLeft8Pixels() { return (Registers[0] & 8) > 0; }
- inline bool EnableLineInterrupts() { return (Registers[0] & 16) > 0; }
- inline bool LeftBlanking() { return (Registers[0] & 32) > 0; }
- inline bool HorizScrollLock() { return (Registers[0] & 64) > 0; }
- inline bool VerticalScrollLock() { return (Registers[0] & 128) > 0; }
- inline bool EnableDoubledSprites() { return (Registers[1] & 1) > 0; }
- inline bool EnableLargeSprites() { return (Registers[1] & 2) > 0; }
- inline bool EnableFrameInterrupts() { return (Registers[1] & 32) > 0; }
- inline bool DisplayOn() { return (Registers[1] & 64) > 0; }
-
- uint32_t SpriteAttributeTableBase() { return ((Registers[5] >> 1) << 8) & 0x3FFF; }
- uint32_t SpriteTileBase() { return (Registers[6] & 4) > 0 ? 256 : 0; }
- uint8_t BackdropColor() { return (uint8_t)(16 + (Registers[7] & 15)); }
-
- uint8_t ReadData()
- {
- VdpWaitingForLatchInt = true;
- uint8_t value = VdpBuffer;
- VdpBuffer = VRAM[VdpAddress & 0x3FFF];
- VdpAddress++;
- return value;
- }
-
- uint8_t ReadVdpStatus()
- {
- VdpWaitingForLatchInt = true;
- uint8_t returnValue = StatusInt;
- StatusInt &= 0x1F;
- HIntPending = false;
- VIntPending = false;
- INT_FLAG[0] = false;
- return returnValue;
- }
-
- uint8_t ReadVLineCounter()
- {
- if (DisplayType == DISP_TYPE_NTSC)
- {
- if (FrameHeight == 192)
- return VLineCounterTableNTSC192[ScanLine];
- if (FrameHeight == 224)
- return VLineCounterTableNTSC224[ScanLine];
- return VLineCounterTableNTSC240[ScanLine];
- }
- else
- { // PAL
- if (FrameHeight == 192)
- return VLineCounterTablePAL192[ScanLine];
- if (FrameHeight == 224)
- return VLineCounterTablePAL224[ScanLine];
- return VLineCounterTablePAL240[ScanLine];
- }
- }
-
- uint8_t ReadHLineCounter()
- {
- return HCounter;
- }
-
- void WriteVdpControl(uint8_t value)
- {
- if (VdpWaitingForLatchInt)
- {
- VdpLatch = value;
- VdpWaitingForLatchInt = false;
- VdpAddress = (uint16_t)((VdpAddress & 0xFF00) | value);
- return;
- }
-
- VdpWaitingForLatchInt = true;
- VdpAddress = (uint16_t)(((value & 63) << 8) | VdpLatch);
- switch (value & 0xC0)
- {
- case 0x00: // read VRAM
- VdpCommand = Command_VramRead;
- VdpBuffer = VRAM[VdpAddress & 0x3FFF];
- VdpAddress++;
- break;
- case 0x40: // write VRAM
- VdpCommand = Command_VramWrite;
- break;
- case 0x80: // VDP register write
- VdpCommand = Command_RegisterWrite;
- WriteRegister(value & 0x0F, VdpLatch);
- break;
- case 0xC0: // write CRAM / modify palette
- VdpCommand = Command_CramWrite;
- break;
- }
- }
-
- void WriteVdpData(uint8_t value)
- {
- VdpWaitingForLatchInt = true;
- VdpBuffer = value;
- if (VdpCommand == Command_CramWrite)
- {
- // Write Palette / CRAM
- uint32_t mask = mode_sys == MODE_SMS ? 0x1F : 0x3F;
- CRAM[VdpAddress & mask] = value;
- UpdatePrecomputedPalette();
- }
- else
- {
- // Write VRAM and update pre-computed pattern buffer.
- UpdatePatternBuffer((uint16_t)(VdpAddress & 0x3FFF), value);
- VRAM[VdpAddress & 0x3FFF] = value;
- }
- VdpAddress++;
- }
-
- void UpdatePrecomputedPalette()
- {
- if (mode_sys == MODE_SMS)
- {
- for (uint32_t i = 0; i < 32; i++)
- {
- uint8_t value = CRAM[i];
- uint8_t r = SMSPalXlatTable[(value & 0x03)];
- uint8_t g = SMSPalXlatTable[(value & 0x0C) >> 2];
- uint8_t b = SMSPalXlatTable[(value & 0x30) >> 4];
- Palette[i] = ARGB(r, g, b);
- }
- }
- else
- { // GameGear
- for (uint32_t i = 0; i < 32; i++)
- {
- uint16_t value = (uint16_t)((CRAM[(i * 2) + 1] << 8) | CRAM[(i * 2) + 0]);
- uint8_t r = GGPalXlatTable[(value & 0x000F)];
- uint8_t g = GGPalXlatTable[(value & 0x00F0) >> 4];
- uint8_t b = GGPalXlatTable[(value & 0x0F00) >> 8];
- Palette[i] = ARGB(r, g, b);
- }
- }
- }
-
- uint32_t ARGB(uint8_t red, uint8_t green, uint8_t blue)
- {
- return (uint32_t)((red << 0x10) | (green << 8) | blue | (0xFF << 0x18));
- }
-
- uint32_t CalcNameTableBase()
- {
- if (FrameHeight == 192)
- return 1024 * (Registers[2] & 0x0E);
- return (1024 * (Registers[2] & 0x0C)) + 0x0700;
- }
-
- void CheckVideoMode()
- {
- if (Mode4Bit() == false) // check old TMS modes
- {
- if (Mode1Bit()) TmsMode = 1;
- else if (Mode2Bit()) TmsMode = 2;
- else if (Mode3Bit()) TmsMode = 3;
- else TmsMode = 0;
- }
-
- else if (Mode4Bit() && Mode2Bit()) // if Mode4 and Mode2 set, then check extension modes
- {
- TmsMode = 4;
- switch (Registers[1] & 0x18)
- {
- case 0x00:
- case 0x18: // 192-line mode
- if (FrameHeight != 192)
- {
- FrameHeight = 192;
- NameTableBase = CalcNameTableBase();
- }
- break;
- case 0x10: // 224-line mode
- if (FrameHeight != 224)
- {
- FrameHeight = 224;
- NameTableBase = CalcNameTableBase();
- }
- break;
- case 0x08: // 240-line mode
- if (FrameHeight != 240)
- {
- FrameHeight = 240;
- NameTableBase = CalcNameTableBase();
- }
- break;
- }
- }
-
- else
- { // default to standard 192-line mode4
- TmsMode = 4;
- if (FrameHeight != 192)
- {
- FrameHeight = 192;
- NameTableBase = CalcNameTableBase();
- }
- }
- }
-
- void WriteRegister(uint32_t reg, uint8_t data)
- {
- Registers[reg] = data;
-
- switch (reg)
- {
- case 0: // Mode Control Register 1
- CheckVideoMode();
- INT_FLAG[0] = (EnableLineInterrupts() && HIntPending);
- INT_FLAG[0] |= (EnableFrameInterrupts() && VIntPending);
- break;
- case 1: // Mode Control Register 2
- CheckVideoMode();
- INT_FLAG[0] = (EnableFrameInterrupts() && VIntPending);
- INT_FLAG[0] |= (EnableLineInterrupts() && HIntPending);
- break;
- case 2: // Name Table Base Address
- NameTableBase = CalcNameTableBase();
- TmsPatternNameTableBase = (Registers[2] << 10) & 0x3C00;
- break;
- case 3: // Color Table Base Address
- ColorTableBase = (Registers[3] << 6) & 0x3FC0;
- break;
- case 4: // Pattern Generator Base Address
- PatternGeneratorBase = (Registers[4] << 11) & 0x3800;
- break;
- case 5: // Sprite Attribute Table Base Address
- // ??? should I move from my property to precalculated?
- TmsSpriteAttributeBase = (Registers[5] << 7) & 0x3F80;
- break;
- case 6: // Sprite Pattern Generator Base Adderss
- SpritePatternGeneratorBase = (Registers[6] << 11) & 0x3800;
- break;
- }
-
- }
-
- void UpdatePatternBuffer(uint16_t address, uint8_t value)
- {
- // writing one uint8_t affects 8 pixels due to stupid planar storage.
- for (uint32_t i = 0; i < 8; i++)
- {
- uint8_t colorBit = pow2[address % 4];
- uint8_t sourceBit = pow2[7 - i];
- uint16_t dest = (uint16_t)(((address & 0xFFFC) * 2) + i);
- if ((value & sourceBit) > 0) // setting bit
- PatternBuffer[dest] |= colorBit;
- else // clearing bit
- PatternBuffer[dest] &= (uint8_t)~colorBit;
- }
- }
-
- void ProcessFrameInterrupt()
- {
- if (ScanLine == FrameHeight + 1)
- {
- StatusInt |= 0x80;
- VIntPending = true;
- }
-
- if (VIntPending && EnableFrameInterrupts())
- {
- INT_FLAG[0] = true;
- }
-
- }
-
- void ProcessLineInterrupt()
- {
- if (ScanLine <= FrameHeight)
- {
- if (lineIntLinesRemaining-- <= 0)
- {
- HIntPending = true;
- if (EnableLineInterrupts())
- {
- INT_FLAG[0] = true;
- }
- lineIntLinesRemaining = Registers[0x0A];
- }
- return;
- }
- // else we're outside the active display period
- lineIntLinesRemaining = Registers[0x0A];
- }
-
- void RenderCurrentScanline(bool render)
- {
- // only mode 4 supports frameskip. deal with it
- if (TmsMode == 4)
- {
- if (render)
- RenderBackgroundCurrentLine(SHOW_BG);
-
- if (EnableDoubledSprites())
- RenderSpritesCurrentLineDoubleSize(SHOW_SPRITES & render);
- else
- RenderSpritesCurrentLine(SHOW_SPRITES & render);
-
- RenderLineBlanking(render);
- }
- else if (TmsMode == 2)
- {
- RenderBackgroundM2(SHOW_BG);
- RenderTmsSprites(SHOW_SPRITES);
- }
- else if (TmsMode == 0)
- {
- RenderBackgroundM0(SHOW_BG);
- RenderTmsSprites(SHOW_SPRITES);
- }
- }
-
- #pragma endregion
-
- #pragma region Mode4
-
- int32_t OverscanFrameWidth, OverscanFrameHeight;
- int32_t overscanTop;
- int32_t overscanBottom;
- int32_t overscanLeft;
- int32_t overscanRight;
-
- void RenderBackgroundCurrentLine(bool show)
- {
- if (ScanLine >= FrameHeight)
- return;
-
- if (DisplayOn() == false)
- {
- for (uint32_t x = 0; x < 256; x++)
- FrameBuffer[(ScanLine * 256) + x] = Palette[BackdropColor()];
- return;
- }
-
- // Clear the priority buffer for this scanline
- for (uint32_t i = 0; i < 256; i++)
- {
- ScanlinePriorityBuffer[i] = 0;
- }
-
- uint32_t mapBase = NameTableBase;
-
- uint32_t vertOffset = ScanLine + Registers[9];
- if (FrameHeight == 192)
- {
- if (vertOffset >= 224)
- vertOffset -= 224;
- }
- else
- {
- if (vertOffset >= 256)
- vertOffset -= 256;
- }
- uint8_t horzOffset = (HorizScrollLock() && ScanLine < 16) ? (uint8_t)0 : Registers[8];
-
- uint32_t yTile = vertOffset / 8;
-
- for (uint32_t xTile = 0; xTile < 32; xTile++)
- {
- if (xTile == 24 && VerticalScrollLock())
- {
- vertOffset = ScanLine;
- yTile = vertOffset / 8;
- }
-
- uint8_t PaletteBase = 0;
- uint32_t tileInfo = VRAM[mapBase + ((yTile * 32) + xTile) * 2] | (VRAM[mapBase + (((yTile * 32) + xTile) * 2) + 1] << 8);
- uint32_t tileNo = tileInfo & 0x01FF;
- if ((tileInfo & 0x800) != 0)
- PaletteBase = 16;
- bool Priority = (tileInfo & 0x1000) != 0;
- bool VFlip = (tileInfo & 0x400) != 0;
- bool HFlip = (tileInfo & 0x200) != 0;
-
- uint32_t yOfs = vertOffset & 7;
- if (VFlip)
- yOfs = 7 - yOfs;
-
- if (HFlip == false)
- {
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 0] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 1] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 2] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 3] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 4] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 5] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 6] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 7] + PaletteBase] : Palette[BackdropColor()];
-
- if (Priority)
- {
- horzOffset -= 8;
- for (uint32_t k = 0; k < 8; k++)
- {
- if (PatternBuffer[(tileNo * 64) + (yOfs * 8) + k] != 0)
- ScanlinePriorityBuffer[horzOffset] = 1;
- horzOffset++;
- }
- }
- }
- else // Flipped Horizontally
- {
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 7] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 6] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 5] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 4] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 3] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 2] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 1] + PaletteBase] : Palette[BackdropColor()];
- FrameBuffer[(ScanLine * 256) + horzOffset++] = show ? Palette[PatternBuffer[(tileNo * 64) + (yOfs * 8) + 0] + PaletteBase] : Palette[BackdropColor()];
-
- if (Priority)
- {
- horzOffset -= 8;
- for (int32_t k = 7; k >= 0; k--)
- {
- if (PatternBuffer[(tileNo * 64) + (yOfs * 8) + k] != 0)
- ScanlinePriorityBuffer[horzOffset] = 1;
- horzOffset++;
- }
- }
- }
- }
- }
-
- void RenderSpritesCurrentLine(bool show)
- {
- bool overflowHappens = true;
- bool collisionHappens = true;
- bool renderHappens = show;
-
- if (!DisplayOn())
- {
- renderHappens = false;
- collisionHappens = false;
- }
- if (ScanLine >= FrameHeight)
- {
- renderHappens = false;
- overflowHappens = false;
- }
-
- int32_t SpriteBase = SpriteAttributeTableBase();
- int32_t SpriteHeight = EnableLargeSprites() ? 16 : 8;
-
- // Clear the sprite collision buffer for this scanline
- for (int32_t i = 0; i < 256; i++)
- {
- SpriteCollisionBuffer[i] = 0;
- }
-
- // Loop through these sprites and render the current scanline
- int32_t SpritesDrawnThisScanline = 0;
- for (int32_t i = 0; i < 64; i++)
- {
- int32_t x = VRAM[SpriteBase + 0x80 + (i * 2)];
- if (ShiftSpritesLeft8Pixels())
- x -= 8;
-
- int32_t y = VRAM[SpriteBase + i] + 1;
- if (y == 209 && FrameHeight == 192)
- break; // 208 is special terminator sprite (in 192-line mode)
- if (y >= (EnableLargeSprites() ? 240 : 248))
- y -= 256;
-
- if (y + SpriteHeight <= ScanLine || y > ScanLine)
- continue;
-
- if (SpritesDrawnThisScanline >= 8)
- {
- collisionHappens = false; // technically the VDP stops processing sprite past this so we would never set the collision bit for sprites past this
- if (overflowHappens)
- StatusInt |= 0x40; // Set Overflow bit
- if (SpriteLimit)
- renderHappens = false; // should be able to break/return, but to ensure this has no effect on sync we keep processing and disable rendering
- }
-
- int32_t tileNo = VRAM[SpriteBase + 0x80 + (i * 2) + 1];
- if (EnableLargeSprites())
- tileNo &= 0xFE;
- tileNo += SpriteTileBase();
-
- int32_t ys = ScanLine - y;
-
- for (int32_t xs = 0; xs < 8 && x + xs < 256; xs++)
- {
- uint8_t color = PatternBuffer[(tileNo * 64) + (ys * 8) + xs];
- if (color != 0 && x + xs >= 0)
- {
- if (SpriteCollisionBuffer[x + xs] != 0)
- {
- if (collisionHappens)
- StatusInt |= 0x20; // Set Collision bit
- }
- else if (renderHappens && ScanlinePriorityBuffer[x + xs] == 0)
- {
- FrameBuffer[(ys + y) * 256 + x + xs] = Palette[(color + 16)];
- }
- SpriteCollisionBuffer[x + xs] = 1;
- }
- }
- SpritesDrawnThisScanline++;
- }
- }
-
- void RenderSpritesCurrentLineDoubleSize(bool show)
- {
- bool overflowHappens = true;
- bool collisionHappens = true;
- bool renderHappens = show;
-
- if (!DisplayOn())
- {
- renderHappens = false;
- collisionHappens = false;
- }
- if (ScanLine >= FrameHeight)
- {
- renderHappens = false;
- overflowHappens = false;
- }
-
- int32_t SpriteBase = SpriteAttributeTableBase();
- int32_t SpriteHeight = EnableLargeSprites() ? 16 : 8;
-
- // Clear the sprite collision buffer for this scanline
- for (uint32_t i = 0; i < 256; i++)
- {
- SpriteCollisionBuffer[i] = 0;
- }
-
- // Loop through these sprites and render the current scanline
- int32_t SpritesDrawnThisScanline = 0;
- for (int32_t i = 0; i < 64; i++)
- {
- int32_t x = VRAM[SpriteBase + 0x80 + (i * 2)];
- if (ShiftSpritesLeft8Pixels())
- x -= 8;
-
- int32_t y = VRAM[SpriteBase + i] + 1;
- if (y == 209 && FrameHeight == 192)
- break; // terminator sprite
- if (y >= (EnableLargeSprites() ? 240 : 248))
- y -= 256;
-
- if (y + (SpriteHeight * 2) <= ScanLine || y > ScanLine)
- continue;
-
- if (SpritesDrawnThisScanline >= 8)
- {
- collisionHappens = false; // technically the VDP stops processing sprite past this so we would never set the collision bit for sprites past this
- if (overflowHappens)
- StatusInt |= 0x40; // Set Overflow bit
- if (SpriteLimit)
- renderHappens = false; // should be able to break/return, but to ensure this has no effect on sync we keep processing and disable rendering
- }
-
- int32_t tileNo = VRAM[SpriteBase + 0x80 + (i * 2) + 1];
- if (EnableLargeSprites())
- tileNo &= 0xFE;
- tileNo += SpriteTileBase();
-
- int32_t ys = ScanLine - y;
-
- for (int32_t xs = 0; xs < 16 && x + xs < 256; xs++)
- {
- uint8_t color = PatternBuffer[(tileNo * 64) + ((ys / 2) * 8) + (xs / 2)];
- if (color != 0 && x + xs >= 0)
- {
- if (SpriteCollisionBuffer[x + xs] != 0)
- {
- if (collisionHappens)
- StatusInt |= 0x20; // Set Collision bit
- }
- else if (renderHappens && ScanlinePriorityBuffer[x + xs] == 0)
- {
- FrameBuffer[(ys + y) * 256 + x + xs] = Palette[(color + 16)];
- }
- SpriteCollisionBuffer[x + xs] = 1;
- }
- }
- SpritesDrawnThisScanline++;
- }
- }
-
- // Renders left-blanking. Should be done per scanline, not per-frame.
- void RenderLineBlanking(bool render)
- {
- if (!LeftBlanking() || ScanLine >= FrameHeight || !render)
- return;
-
- int32_t ofs = ScanLine * 256;
- for (int32_t x = 0; x < 8; x++)
- FrameBuffer[ofs++] = Palette[BackdropColor()];
- }
-
- /*
- void ProcessOverscan()
- {
- if (Sms.Settings.DisplayOverscan == false)
- return;
-
- if (OverscanFrameBuffer == null)
- {
- if (Sms.Region == Common.DisplayType.NTSC)
- {
- overscanLeft = 13;
- overscanRight = 15;
- overscanTop = 27;
- overscanBottom = 24;
- }
- else // PAL
- {
- overscanLeft = 13;
- overscanRight = 15;
- overscanTop = 48;
- overscanBottom = 48;
- }
-
- OverscanFrameWidth = overscanLeft + 256 + overscanRight;
- OverscanFrameHeight = overscanTop + 192 + overscanBottom;
- OverscanFrameBuffer = new int[OverscanFrameHeight * OverscanFrameWidth];
- }
-
- // Top overscan
- for (uint32_t y = 0; y < overscanTop; y++)
- for (uint32_t x = 0; x < OverscanFrameWidth; x++)
- OverscanFrameBuffer[(y * OverscanFrameWidth) + x] = BackgroundColor();
-
- // Bottom overscan
- for (uint32_t y = overscanTop + 192; y < OverscanFrameHeight; y++)
- for (uint32_t x = 0; x < OverscanFrameWidth; x++)
- OverscanFrameBuffer[(y * OverscanFrameWidth) + x] = BackgroundColor();
-
- // Left overscan
- for (uint32_t y = overscanTop; y < overscanTop + 192; y++)
- for (uint32_t x = 0; x < overscanLeft; x++)
- OverscanFrameBuffer[(y * OverscanFrameWidth) + x] = BackgroundColor();
-
- // Right overscan
- for (uint32_t y = overscanTop; y < overscanTop + 192; y++)
- for (uint32_t x = overscanLeft + 256; x < OverscanFrameWidth; x++)
- OverscanFrameBuffer[(y * OverscanFrameWidth) + x] = BackgroundColor();
-
- // Active display area
- for (uint32_t y = 0; y < 192; y++)
- for (uint32_t x = 0; x < 256; x++)
- OverscanFrameBuffer[((y + overscanTop) * OverscanFrameWidth) + overscanLeft + x] = FrameBuffer[y * 256 + x];
- }
- */
-
-
- // Handles GG clipping or highlighting
- void ProcessGGScreen()
- {
- uint32_t yStart = (FrameHeight - 144) / 2;
- for (uint32_t y = 0; y < 144; y++)
- for (uint32_t x = 0; x < 160; x++)
- GameGearFrameBuffer[(y * 160) + x] = FrameBuffer[((y + yStart) * 256) + x + 48];
- /*
- if (Sms.Settings.HighlightActiveDisplayRegion && Sms.Settings.ShowClippedRegions)
- {
- // Top 24 scanlines
- for (uint32_t y = 0; y < 24; y++)
- {
- for (uint32_t x = 0; x < 256; x++)
- {
- uint32_t frameOffset = (y * 256) + x;
- uint32_t p = (FrameBuffer[frameOffset] >> 1) & 0x7F7F7F7F;
- FrameBuffer[frameOffset] = (uint32_t)(p | 0x80000000);
- }
- }
-
- // Bottom 24 scanlines
- for (uint32_t y = 168; y < 192; y++)
- {
- for (uint32_t x = 0; x < 256; x++)
- {
- uint32_t frameOffset = (y * 256) + x;
- uint32_t p = (FrameBuffer[frameOffset] >> 1) & 0x7F7F7F7F;
- FrameBuffer[frameOffset] = (uint32_t)(p | 0x80000000);
- }
- }
-
- // Left 48 pixels
- for (uint32_t y = 24; y < 168; y++)
- {
- for (uint32_t x = 0; x < 48; x++)
- {
- uint32_t frameOffset = (y * 256) + x;
- uint32_t p = (FrameBuffer[frameOffset] >> 1) & 0x7F7F7F7F;
- FrameBuffer[frameOffset] = (uint32_t)(p | 0x80000000);
- }
- }
-
- // Right 48 pixels
- for (uint32_t y = 24; y < 168; y++)
- {
- for (uint32_t x = 208; x < 256; x++)
- {
- uint32_t frameOffset = (y * 256) + x;
- uint32_t p = (FrameBuffer[frameOffset] >> 1) & 0x7F7F7F7F;
- FrameBuffer[frameOffset] = (uint32_t)(p | 0x80000000);
- }
- }
- }
- */
- }
- #pragma endregion
-
- #pragma region ModeTMS
-
- uint32_t PaletteTMS9918[16] =
- {
- 0xFF000000,
- 0xFF000000,
- 0xFF47B73B,
- 0xFF7CCF6F,
- 0xFF5D4EFF,
- 0xFF8072FF,
- 0xFFB66247,
- 0xFF5DC8ED,
- 0xFFD76B48,
- 0xFFFB8F6C,
- 0xFFC3CD41,
- 0xFFD3DA76,
- 0xFF3E9F2F,
- 0xFFB664C7,
- 0xFFCCCCCC,
- 0xFFFFFFFF
- };
-
- void RenderBackgroundM0(bool show)
- {
- if (ScanLine >= FrameHeight)
- return;
-
- if (DisplayOn() == false)
- {
- for (int32_t i = ScanLine * 256; i < (ScanLine * 256 + 256); i++)
- {
- FrameBuffer[i] = 0;
- }
- return;
- }
-
- int32_t yc = ScanLine / 8;
- int32_t yofs = ScanLine % 8;
- int32_t FrameBufferOffset = ScanLine * 256;
- int32_t PatternNameOffset = TmsPatternNameTableBase + (yc * 32);
- int32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
-
- for (int32_t xc = 0; xc < 32; xc++)
- {
- int32_t pn = VRAM[PatternNameOffset++];
- int32_t pv = VRAM[PatternGeneratorBase + (pn * 8) + yofs];
- int32_t colorEntry = VRAM[ColorTableBase + (pn / 8)];
- int32_t fgIndex = (colorEntry >> 4) & 0x0F;
- int32_t bgIndex = colorEntry & 0x0F;
- int32_t fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex];
- int32_t bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex];
-
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x80) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x40) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x20) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x10) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x08) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x04) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x02) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x01) > 0) ? fgColor : bgColor) : 0;
- }
- }
-
- void RenderBackgroundM2(bool show)
- {
- if (ScanLine >= FrameHeight)
- return;
-
- if (DisplayOn() == false)
- {
- for (int32_t i = ScanLine * 256; i < (ScanLine * 256 + 256); i++)
- {
- FrameBuffer[i] = 0;
- }
- return;
- }
-
- int32_t yrow = ScanLine / 8;
- int32_t yofs = ScanLine % 8;
- int32_t FrameBufferOffset = ScanLine * 256;
- int32_t PatternNameOffset = TmsPatternNameTableBase + (yrow * 32);
- int32_t PatternGeneratorOffset = (((Registers[4] & 4) << 11) & 0x2000);// +((yrow / 8) * 0x100);
- int32_t ColorOffset = (ColorTableBase & 0x2000);// +((yrow / 8) * 0x100);
- int32_t ScreenBGColor = PaletteTMS9918[Registers[7] & 0x0F];
-
- for (int32_t xc = 0; xc < 32; xc++)
- {
- int32_t pn = VRAM[PatternNameOffset++] + ((yrow / 8) * 0x100);
- int32_t pv = VRAM[PatternGeneratorOffset + (pn * 8) + yofs];
- int32_t colorEntry = VRAM[ColorOffset + (pn * 8) + yofs];
- int32_t fgIndex = (colorEntry >> 4) & 0x0F;
- int32_t bgIndex = colorEntry & 0x0F;
- int32_t fgColor = fgIndex == 0 ? ScreenBGColor : PaletteTMS9918[fgIndex];
- int32_t bgColor = bgIndex == 0 ? ScreenBGColor : PaletteTMS9918[bgIndex];
-
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x80) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x40) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x20) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x10) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x08) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x04) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x02) > 0) ? fgColor : bgColor) : 0;
- FrameBuffer[FrameBufferOffset++] = show ? (((pv & 0x01) > 0) ? fgColor : bgColor) : 0;
- }
- }
-
- void RenderTmsSprites(bool show)
- {
- if (ScanLine >= FrameHeight || DisplayOn() == false)
- return;
-
- if (EnableDoubledSprites() == false)
- RenderTmsSpritesStandard(show);
- else
- RenderTmsSpritesDouble(show);
- }
-
- void RenderTmsSpritesStandard(bool show)
- {
- for (uint32_t i = 0; i < 256; i++)
- {
- ScanlinePriorityBuffer[i] = 0;
- }
- for (uint32_t i = 0; i < 256; i++)
- {
- SpriteCollisionBuffer[i] = 0;
- }
-
- bool LargeSprites = EnableLargeSprites();
-
- int32_t SpriteSize = 8;
- if (LargeSprites) SpriteSize *= 2;
- const int32_t OneCellSize = 8;
-
- int32_t NumSpritesOnScanline = 0;
- for (int32_t i = 0; i < 32; i++)
- {
- int32_t SpriteBase = TmsSpriteAttributeBase + (i * 4);
- int32_t y = VRAM[SpriteBase++];
- int32_t x = VRAM[SpriteBase++];
- int32_t Pattern = VRAM[SpriteBase++];
- int32_t Color = VRAM[SpriteBase];
-
- if (y == 208) break; // terminator sprite
- if (y > 224) y -= 256; // sprite Y wrap
- y++; // inexplicably, sprites start on Y+1
- if (y > ScanLine || y + SpriteSize <= ScanLine) continue; // sprite is not on this scanline
- if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment
-
- if (++NumSpritesOnScanline == 5)
- {
- StatusInt &= 0xE0; // Clear FS0-FS4 bits
- StatusInt |= (int8_t)i; // set 5th sprite index
- StatusInt |= 0x40; // set overflow bit
- break;
- }
-
- if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-uint8_t alignment
- int32_t SpriteLine = ScanLine - y;
-
- // pv contains the VRAM uint8_t holding the pattern data for this character at this scanline.
- // each uint8_t contains the pattern data for each the 8 pixels on this line.
- // the bit-shift further down on PV pulls out the relevant horizontal pixel.
-
- uint8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine];
-
- for (int32_t xp = 0; xp < SpriteSize && x + xp < 256; xp++)
- {
- if (x + xp < 0) continue;
- if (LargeSprites && xp == OneCellSize)
- pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16];
-
- if (Color != 0 && (pv & (1 << (7 - (xp & 7)))) > 0)
- {
- if (SpriteCollisionBuffer[x + xp] != 0)
- StatusInt |= 0x20; // Set sprite collision flag
-
- if (ScanlinePriorityBuffer[x + xp] == 0)
- {
- ScanlinePriorityBuffer[x + xp] = 1;
- SpriteCollisionBuffer[x + xp] = 1;
- if (show)
- FrameBuffer[(ScanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F];
- }
- }
- }
- }
- }
-
- void RenderTmsSpritesDouble(bool show)
- {
- for (uint32_t i = 0; i < 256; i++)
- {
- ScanlinePriorityBuffer[i] = 0;
- }
- for (uint32_t i = 0; i < 256; i++)
- {
- SpriteCollisionBuffer[i] = 0;
- }
-
- bool LargeSprites = EnableLargeSprites();
-
- int32_t SpriteSize = 8;
- if (LargeSprites) SpriteSize *= 2;
- SpriteSize *= 2; // because sprite magnification
- const int32_t OneCellSize = 16; // once 8-pixel cell, doubled, will take 16 pixels
-
- int32_t NumSpritesOnScanline = 0;
- for (int32_t i = 0; i < 32; i++)
- {
- int32_t SpriteBase = TmsSpriteAttributeBase + (i * 4);
- int32_t y = VRAM[SpriteBase++];
- int32_t x = VRAM[SpriteBase++];
- int32_t Pattern = VRAM[SpriteBase++];
- int32_t Color = VRAM[SpriteBase];
-
- if (y == 208) break; // terminator sprite
- if (y > 224) y -= 256; // sprite Y wrap
- y++; // inexplicably, sprites start on Y+1
- if (y > ScanLine || y + SpriteSize <= ScanLine) continue; // sprite is not on this scanline
- if ((Color & 0x80) > 0) x -= 32; // Early Clock adjustment
-
- if (++NumSpritesOnScanline == 5)
- {
- StatusInt &= 0xE0; // Clear FS0-FS4 bits
- StatusInt |= (uint8_t)i; // set 5th sprite index
- StatusInt |= 0x40; // set overflow bit
- break;
- }
-
- if (LargeSprites) Pattern &= 0xFC; // 16x16 sprites forced to 4-uint8_t alignment
- int32_t SpriteLine = ScanLine - y;
- SpriteLine /= 2; // because of sprite magnification
-
- uint8_t pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine];
-
- for (int32_t xp = 0; (xp < SpriteSize) && ((x + xp) < 256); xp++)
- {
- if (x + xp < 0) continue;
- if (LargeSprites && xp == OneCellSize)
- pv = VRAM[SpritePatternGeneratorBase + (Pattern * 8) + SpriteLine + 16];
-
- if (Color != 0 && (pv & (1 << (7 - ((xp / 2) & 7)))) > 0) // xp/2 is due to sprite magnification
- {
- if (SpriteCollisionBuffer[x + xp] != 0)
- StatusInt |= 0x20; // Set sprite collision flag
-
- if (ScanlinePriorityBuffer[x + xp] == 0)
- {
- ScanlinePriorityBuffer[x + xp] = 1;
- SpriteCollisionBuffer[x + xp] = 1;
- if (show)
- FrameBuffer[(ScanLine * 256) + x + xp] = PaletteTMS9918[Color & 0x0F];
- }
- }
- }
- }
- }
- #pragma endregion
-
- #pragma region Tables
-
- // TODO: HCounter
- const uint8_t VLineCounterTableNTSC192[262] =
- {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
- 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
- 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
- 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
- 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
- 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
- };
-
- const uint8_t VLineCounterTableNTSC224[262] =
- {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
- 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
- 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
- 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
- 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
- 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
- };
-
- const uint8_t VLineCounterTableNTSC240[262] =
- {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
- 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
- 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
- 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
- 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05
- };
-
- const uint8_t VLineCounterTablePAL192[313] =
- {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
- 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
- 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
- 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
- 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
- 0xF0, 0xF1, 0xF2,
- 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
- 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
- 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
- 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
- };
-
- const uint8_t VLineCounterTablePAL224[313] =
- {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
- 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
- 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
- 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
- 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
- 0x00, 0x01, 0x02,
- 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
- 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
- 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
- };
-
- const uint8_t VLineCounterTablePAL240[313] =
- {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
- 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
- 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
- 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
- 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
- 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
- 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
- 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
- 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
- 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
- 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
- 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
- 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
- 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
- };
- #pragma endregion
-
- #pragma region State Save / Load
-
- uint8_t* SaveState(uint8_t* saver)
- {
- *saver = (uint8_t)(VdpWaitingForLatchInt ? 1 : 0); saver++;
- *saver = (uint8_t)(VIntPending ? 1 : 0); saver++;
- *saver = (uint8_t)(HIntPending ? 1 : 0); saver++;
-
- for (int i = 0; i < 0x4000; i++) { *saver = VRAM[i]; saver++; }
- for (int i = 0; i < 64; i++) { *saver = CRAM[i]; saver++; }
- for (int i = 0; i < 16; i++) { *saver = Registers[i]; saver++; }
-
- *saver = StatusInt; saver++;
- *saver = VdpLatch; saver++;
- *saver = VdpBuffer; saver++;
- *saver = VdpCommand; saver++;
- *saver = HCounter; saver++;
- *saver = TmsMode; saver++;
- *saver = lineIntLinesRemaining; saver++;
- *saver = mode_sys; saver++;
- *saver = DisplayType; saver++;
-
- *saver = (uint8_t)(VdpAddress & 0xFF); saver++; *saver = (uint8_t)((VdpAddress >> 8) & 0xFF); saver++;
-
- *saver = (uint8_t)(NameTableBase & 0xFF); saver++; *saver = (uint8_t)((NameTableBase >> 8) & 0xFF); saver++;
- *saver = (uint8_t)((NameTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((NameTableBase >> 24) & 0xFF); saver++;
-
- *saver = (uint8_t)(ColorTableBase & 0xFF); saver++; *saver = (uint8_t)((ColorTableBase >> 8) & 0xFF); saver++;
- *saver = (uint8_t)((ColorTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((ColorTableBase >> 24) & 0xFF); saver++;
-
- *saver = (uint8_t)(PatternGeneratorBase & 0xFF); saver++; *saver = (uint8_t)((PatternGeneratorBase >> 8) & 0xFF); saver++;
- *saver = (uint8_t)((PatternGeneratorBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((PatternGeneratorBase >> 24) & 0xFF); saver++;
-
- *saver = (uint8_t)(SpritePatternGeneratorBase & 0xFF); saver++; *saver = (uint8_t)((SpritePatternGeneratorBase >> 8) & 0xFF); saver++;
- *saver = (uint8_t)((SpritePatternGeneratorBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((SpritePatternGeneratorBase >> 24) & 0xFF); saver++;
-
- *saver = (uint8_t)(TmsPatternNameTableBase & 0xFF); saver++; *saver = (uint8_t)((TmsPatternNameTableBase >> 8) & 0xFF); saver++;
- *saver = (uint8_t)((TmsPatternNameTableBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((TmsPatternNameTableBase >> 24) & 0xFF); saver++;
-
- *saver = (uint8_t)(TmsSpriteAttributeBase & 0xFF); saver++; *saver = (uint8_t)((TmsSpriteAttributeBase >> 8) & 0xFF); saver++;
- *saver = (uint8_t)((TmsSpriteAttributeBase >> 16) & 0xFF); saver++; *saver = (uint8_t)((TmsSpriteAttributeBase >> 24) & 0xFF); saver++;
-
- *saver = (uint8_t)(IPeriod & 0xFF); saver++; *saver = (uint8_t)((IPeriod >> 8) & 0xFF); saver++;
- *saver = (uint8_t)((IPeriod >> 16) & 0xFF); saver++; *saver = (uint8_t)((IPeriod >> 24) & 0xFF); saver++;
-
- *saver = (uint8_t)(FrameHeight & 0xFF); saver++; *saver = (uint8_t)((FrameHeight >> 8) & 0xFF); saver++;
- *saver = (uint8_t)((FrameHeight >> 16) & 0xFF); saver++; *saver = (uint8_t)((FrameHeight >> 24) & 0xFF); saver++;
-
- *saver = (uint8_t)(ScanLine & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 8) & 0xFF); saver++;
- *saver = (uint8_t)((ScanLine >> 16) & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 24) & 0xFF); saver++;
-
- return saver;
- }
-
- uint8_t* LoadState(uint8_t* loader)
- {
- VdpWaitingForLatchInt = *loader == 1; loader++;
- VIntPending = *loader == 1; loader++;
- HIntPending = *loader == 1; loader++;
-
- for (int i = 0; i < 0x4000; i++) { VRAM[i] = *loader; loader++; }
- for (int i = 0; i < 64; i++) { CRAM[i] = *loader; loader++; }
- for (int i = 0; i < 16; i++) { Registers[i] = *loader; loader++; }
-
- StatusInt = *loader; loader++;
- VdpLatch = *loader; loader++;
- VdpBuffer = *loader; loader++;
- VdpCommand = *loader; loader++;
- HCounter = *loader; loader++;
- TmsMode = *loader; loader++;
- lineIntLinesRemaining = *loader; loader++;
- mode_sys = *loader; loader++;
- DisplayType = *loader; loader++;
-
- VdpAddress = *loader; loader++; VdpAddress |= (*loader << 8); loader++;
-
- NameTableBase = *loader; loader++; NameTableBase |= (*loader << 8); loader++;
- NameTableBase |= (*loader << 16); loader++; NameTableBase |= (*loader << 24); loader++;
-
- ColorTableBase = *loader; loader++; ColorTableBase |= (*loader << 8); loader++;
- ColorTableBase |= (*loader << 16); loader++; ColorTableBase |= (*loader << 24); loader++;
-
- PatternGeneratorBase = *loader; loader++; PatternGeneratorBase |= (*loader << 8); loader++;
- PatternGeneratorBase |= (*loader << 16); loader++; PatternGeneratorBase |= (*loader << 24); loader++;
-
- SpritePatternGeneratorBase = *loader; loader++; SpritePatternGeneratorBase |= (*loader << 8); loader++;
- SpritePatternGeneratorBase |= (*loader << 16); loader++; SpritePatternGeneratorBase |= (*loader << 24); loader++;
-
- TmsPatternNameTableBase = *loader; loader++; TmsPatternNameTableBase |= (*loader << 8); loader++;
- TmsPatternNameTableBase |= (*loader << 16); loader++; TmsPatternNameTableBase |= (*loader << 24); loader++;
-
- TmsSpriteAttributeBase = *loader; loader++; TmsSpriteAttributeBase |= (*loader << 8); loader++;
- TmsSpriteAttributeBase |= (*loader << 16); loader++; TmsSpriteAttributeBase |= (*loader << 24); loader++;
-
- IPeriod = *loader; loader++; IPeriod |= (*loader << 8); loader++;
- IPeriod |= (*loader << 16); loader++; IPeriod |= (*loader << 24); loader++;
-
- FrameHeight = *loader; loader++; FrameHeight |= (*loader << 8); loader++;
- FrameHeight |= (*loader << 16); loader++; FrameHeight |= (*loader << 24); loader++;
-
- ScanLine = *loader; loader++; ScanLine |= (*loader << 8); loader++;
- ScanLine |= (*loader << 16); loader++; ScanLine |= (*loader << 24); loader++;
-
- for (uint32_t i = 0; i < 16; i++) { WriteRegister(i, Registers[i]); }
- for (uint16_t i = 0; i < 0x4000; i++) { UpdatePatternBuffer(i, VRAM[i]); }
- UpdatePrecomputedPalette();
-
- return loader;
- }
-
- #pragma endregion
- };
-}
diff --git a/libHawk/MSXHawk/MSXHawk/cpp.hint b/libHawk/MSXHawk/MSXHawk/cpp.hint
index a86b7f9896..5e14a8bb9b 100644
--- a/libHawk/MSXHawk/MSXHawk/cpp.hint
+++ b/libHawk/MSXHawk/MSXHawk/cpp.hint
@@ -1,2 +1,2 @@
-#define MSXHAWK_API __declspec(dllexport)
-#define MSXHAWK_API __declspec(dllimport)
+#define MSXHawk_API __declspec(dllexport)
+#define MSXHawk_API __declspec(dllimport)