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)