From fecad6d8a5691b517d58acd1d3b82afe59244660 Mon Sep 17 00:00:00 2001 From: rdanbrook <1869094+rdanbrook@users.noreply.github.com> Date: Wed, 25 Aug 2021 22:20:30 -0400 Subject: [PATCH] Merge upstream core at tag 1.51.1 --- Makefile.am | 2 + NstDatabase.xml | 37 ++++ projects/core.vcproj | 7 + projects/core.vcxproj | 2 + source/core/NstApu.cpp | 12 +- source/core/NstCpu.cpp | 3 + source/core/board/NstBoard.cpp | 25 ++- source/core/board/NstBoard.hpp | 3 + source/core/board/NstBoardKaiser.cpp | 204 +++++++++++++++++---- source/core/board/NstBoardKaiser.hpp | 38 ++++ source/core/board/NstBoardMmc3.hpp | 22 +-- source/core/board/NstBoardMmc6.cpp | 2 +- source/core/board/NstBoardWaixing.hpp | 1 + source/core/board/NstBoardWaixingFs304.cpp | 106 +++++++++++ source/core/board/NstBoardWaixingFs304.hpp | 63 +++++++ 15 files changed, 477 insertions(+), 50 deletions(-) create mode 100644 source/core/board/NstBoardWaixingFs304.cpp create mode 100644 source/core/board/NstBoardWaixingFs304.hpp diff --git a/Makefile.am b/Makefile.am index 0e04a83..ce54502 100644 --- a/Makefile.am +++ b/Makefile.am @@ -662,6 +662,8 @@ nestopia_SOURCES = \ source/core/board/NstBoardInlNsf.hpp \ source/core/board/NstBoardAction53.cpp \ source/core/board/NstBoardAction53.hpp \ + source/core/board/NstBoardWaixingFs304.cpp \ + source/core/board/NstBoardWaixingFs304.hpp \ source/core/NstPins.hpp \ source/core/NstNsf.hpp \ source/core/NstTrackerRewinder.hpp \ diff --git a/NstDatabase.xml b/NstDatabase.xml index d768c9c..980a996 100644 --- a/NstDatabase.xml +++ b/NstDatabase.xml @@ -27023,4 +27023,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/projects/core.vcproj b/projects/core.vcproj index 46d7fd0..c3fb13f 100644 --- a/projects/core.vcproj +++ b/projects/core.vcproj @@ -1667,6 +1667,13 @@ + + + + @@ -620,6 +621,7 @@ + diff --git a/source/core/NstApu.cpp b/source/core/NstApu.cpp index 746096d..03d7c9b 100644 --- a/source/core/NstApu.cpp +++ b/source/core/NstApu.cpp @@ -2324,9 +2324,15 @@ namespace Nes cpu.StealCycles( cpu.GetClock(1) ); - // This is disabled until a real solution is discovered - //if ((readAddress & 0xF000) != 0x4000) - // cpu.Peek( readAddress ); + /* According to dmc_dma_during_read4/dma_2007_read, DMC DMA during read causes + * 2-3 extra $2007 reads before the real read. The nesdev wiki states that this + * also happens when polling $2002 for vblank. + */ + if ((readAddress & 0xF000) != 0x4000) + { + cpu.Peek( readAddress ); + cpu.Peek( readAddress ); + } cpu.StealCycles( cpu.GetClock(1) ); cpu.Peek( readAddress ); diff --git a/source/core/NstCpu.cpp b/source/core/NstCpu.cpp index f02f53a..49e957d 100644 --- a/source/core/NstCpu.cpp +++ b/source/core/NstCpu.cpp @@ -1280,6 +1280,7 @@ namespace Nes NST_SINGLE_CALL void Cpu::Rts() { + opcode = map.Peek8( pc ); pc = Pull16() + 1; cycles.count += cycles.clock[RTS_CYCLES-1]; } @@ -1290,6 +1291,7 @@ namespace Nes { const uint packed = Pull8(); + opcode = map.Peek8( pc ); pc = Pull16(); flags.Unpack( packed ); } @@ -1802,6 +1804,7 @@ namespace Nes { NST_DEBUG_MSG("6502 BRK"); + opcode = map.Peek8( pc ); Push16( pc + 1 ); Push8( flags.Pack() | Flags::B ); flags.i = Flags::I; diff --git a/source/core/board/NstBoard.cpp b/source/core/board/NstBoard.cpp index 06f949f..570175e 100644 --- a/source/core/board/NstBoard.cpp +++ b/source/core/board/NstBoard.cpp @@ -1103,6 +1103,7 @@ namespace Nes { "UNL-AX5705", Type::BTL_AX5705 }, { "UNL-CC-21", Type::UNL_CC21 }, { "UNL-EDU2000", Type::UNL_EDU2000 }, + { "UNL-FS304", Type::UNL_FS304 }, { "UNL-H2288", Type::KAY_H2288 }, { "UNL-KOF97", Type::UNL_KINGOFFIGHTERS97 }, { "UNL-KS7013B", Type::KAISER_KS7013B }, @@ -1110,6 +1111,7 @@ namespace Nes { "UNL-KS7031", Type::KAISER_KS7031 }, { "UNL-KS7032", Type::KAISER_KS7032 }, { "UNL-KS7037", Type::KAISER_KS7037 }, + { "UNL-KS7057", Type::KAISER_KS7057 }, { "UNL-N625092", Type::UNL_N625092 }, { "UNL-SA-0036", Type::SACHEN_SA0036 }, { "UNL-SA-0037", Type::SACHEN_SA0037 }, @@ -1449,7 +1451,7 @@ namespace Nes case 4: if (submapper == 1) - { // StarTropics/Zoda's Revenge - might not be correct + { // StarTropics/Zoda's Revenge chips.Add(L"MMC6B"); name = "NES-HKROM"; id = Type::STD_HKROM; @@ -2778,6 +2780,12 @@ namespace Nes id = Type::BANDAI_LZ93D50_24C01; break; + case 162: + + name = "UNL-FS304"; + id = Type::UNL_FS304; + break; + case 163: name = "NANJING"; @@ -3438,6 +3446,12 @@ namespace Nes id = Type::BMC_8157; break; + case 302: + + name = "UNL-KS7057"; + id = Type::KAISER_KS7057; + break; + case 305: name = "UNL-KS7031"; @@ -3498,6 +3512,12 @@ namespace Nes id = Type::BTL_AX5705; break; + case 554: + + name = "UNL-KS7010"; + id = Type::KAISER_KS7010; + break; + default: return false; @@ -3766,12 +3786,14 @@ namespace Nes case Type::JYCOMPANY_TYPE_B : case Type::JYCOMPANY_TYPE_C : return new JyCompany::Standard(c); case Type::KAISER_KS202 : return new Kaiser::Ks202(c); + case Type::KAISER_KS7010 : return new Kaiser::Ks7010(c); case Type::KAISER_KS7013B : return new Kaiser::Ks7013b(c); case Type::KAISER_KS7016 : return new Kaiser::Ks7016(c); case Type::KAISER_KS7022 : return new Kaiser::Ks7022(c); case Type::KAISER_KS7031 : return new Kaiser::Ks7031(c); case Type::KAISER_KS7032 : return new Kaiser::Ks7032(c); case Type::KAISER_KS7037 : return new Kaiser::Ks7037(c); + case Type::KAISER_KS7057 : return new Kaiser::Ks7057(c); case Type::KAISER_KS7058 : return new Kaiser::Ks7058(c); case Type::KASING_STD : return new Kasing::Standard(c); case Type::KAY_H2288 : return new Kay::H2288(c); @@ -3868,6 +3890,7 @@ namespace Nes case Type::UNL_A9746 : return new Unlicensed::A9746(c); case Type::UNL_CC21 : return new Unlicensed::Cc21(c); case Type::UNL_EDU2000 : return new Unlicensed::Edu2000(c); + case Type::UNL_FS304 : return new Waixing::Fs304(c); case Type::UNL_KINGOFFIGHTERS96 : return new Unlicensed::KingOfFighters96(c); case Type::UNL_KINGOFFIGHTERS97 : return new Unlicensed::KingOfFighters97(c); case Type::UNL_MORTALKOMBAT2 : return new Unlicensed::MortalKombat2(c); diff --git a/source/core/board/NstBoard.hpp b/source/core/board/NstBoard.hpp index bc455ee..2cd142b 100644 --- a/source/core/board/NstBoard.hpp +++ b/source/core/board/NstBoard.hpp @@ -418,12 +418,14 @@ namespace Nes JYCOMPANY_TYPE_C = MakeId< 211, 2048, 2048, 0, 0, CRM_0, NMT_X, 0 >::ID, // Kaiser KAISER_KS202 = MakeId< 56, 256, 128, 8, 0, CRM_0, NMT_V, 0 >::ID, + KAISER_KS7010 = MakeId< 554, 128, 128, 0, 0, CRM_0, NMT_V, 1 >::ID, KAISER_KS7013B = MakeId< 312, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, KAISER_KS7016 = MakeId< 306, 128, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, KAISER_KS7022 = MakeId< 175, 256, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, KAISER_KS7031 = MakeId< 305, 128, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, KAISER_KS7032 = MakeId< 142, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, KAISER_KS7037 = MakeId< 307, 128, 0, 0, 8, CRM_8, NMT_X, 0 >::ID, + KAISER_KS7057 = MakeId< 302, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID, KAISER_KS7058 = MakeId< 171, 32, 32, 0, 0, CRM_0, NMT_X, 0 >::ID, // Kasing KASING_STD = MakeId< 115, 512, 512, 0, 0, CRM_0, NMT_V, 0 >::ID, @@ -541,6 +543,7 @@ namespace Nes UNL_A9746 = MakeId< 219, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_CC21 = MakeId< 27, 32, 8, 0, 0, CRM_0, NMT_Z, 0 >::ID, UNL_EDU2000 = MakeId< 329, 1024, 0, 0, 32, CRM_8, NMT_Z, 0 >::ID, + UNL_FS304 = MakeId< 162, 2048, 0, 8, 0, CRM_8, NMT_X, 0 >::ID, UNL_KINGOFFIGHTERS96 = MakeId< 187, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_KINGOFFIGHTERS97 = MakeId< 263, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_MORTALKOMBAT2 = MakeId< 91, 256, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, diff --git a/source/core/board/NstBoardKaiser.cpp b/source/core/board/NstBoardKaiser.cpp index 91e553f..e48ff17 100644 --- a/source/core/board/NstBoardKaiser.cpp +++ b/source/core/board/NstBoardKaiser.cpp @@ -69,6 +69,21 @@ namespace Nes irq.Reset( hard, hard ? false : irq.Connected() ); } + void Ks7010::SubReset(const bool hard) + { + prg.SwapBank( 0x0000, 0x5 ); + prg.SwapBank( 0x4000, 0x3 ); + + // At the time of writing, the true mask for bankswitching is unknown + Map( 0x6000U, 0x7FFFU, &Ks7010::Peek_6000 ); + Map( 0xCAB6U, 0xCAD6U, &Ks7010::Peek_FFFC ); + Map( 0xEBE2U, 0xEBE3U, &Ks7010::Peek_FFFC ); + Map( 0xEE32U, &Ks7010::Peek_FFFC ); + Map( 0xFFFCU, &Ks7010::Peek_FFFC ); + + reg = 0; + } + void Ks7013b::SubReset(const bool hard) { prg.SwapBank( 0x4000, 0x7 ); @@ -147,6 +162,22 @@ namespace Nes Map( 0xE000U, 0xEFFFU, &Ks7037::Peek_E000 ); } + void Ks7057::SubReset(const bool hard) + { + prg.SwapBank( 0x2000, 0xD ); + prg.SwapBank( 0x4000, 0x7 ); + + Map( 0x6000U, 0x9FFFU, &Ks7057::Peek_6000 ); + Map( 0x8000U, 0x9FFFU, &Ks7057::Poke_8000 ); + Map( 0xB000U, 0xE003U, &Ks7057::Poke_B000 ); + + if (hard) + { + for (uint i = 0; i < 8; ++i) + regs[i] = 0; + } + } + void Ks7058::SubReset(bool) { for (uint i=0x000; i < 0x1000; i += 0x100) @@ -156,38 +187,6 @@ namespace Nes } } - void Ks7016::SubLoad(State::Loader& state,const dword baseChunk) - { - NST_VERIFY( (baseChunk == AsciiId<'K','7','6'>::V) ); - - if (baseChunk == AsciiId<'K','7','6'>::V) - { - while (const dword chunk = state.Begin()) - { - if (chunk == AsciiId<'R','E','G'>::V) - reg = state.Read8(); - - state.End(); - } - } - } - - void Ks7022::SubLoad(State::Loader& state,const dword baseChunk) - { - NST_VERIFY( (baseChunk == AsciiId<'K','7','2'>::V) ); - - if (baseChunk == AsciiId<'K','7','2'>::V) - { - while (const dword chunk = state.Begin()) - { - if (chunk == AsciiId<'R','E','G'>::V) - reg = state.Read8(); - - state.End(); - } - } - } - void Ks202::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','0','2'>::V) ); @@ -221,6 +220,54 @@ namespace Nes } } + void Ks7010::SubLoad(State::Loader& state,const dword baseChunk) + { + NST_VERIFY( (baseChunk == AsciiId<'K','7','0'>::V) ); + + if (baseChunk == AsciiId<'K','7','0'>::V) + { + while (const dword chunk = state.Begin()) + { + if (chunk == AsciiId<'R','E','G'>::V) + reg = state.Read8(); + + state.End(); + } + } + } + + void Ks7016::SubLoad(State::Loader& state,const dword baseChunk) + { + NST_VERIFY( (baseChunk == AsciiId<'K','7','6'>::V) ); + + if (baseChunk == AsciiId<'K','7','6'>::V) + { + while (const dword chunk = state.Begin()) + { + if (chunk == AsciiId<'R','E','G'>::V) + reg = state.Read8(); + + state.End(); + } + } + } + + void Ks7022::SubLoad(State::Loader& state,const dword baseChunk) + { + NST_VERIFY( (baseChunk == AsciiId<'K','7','2'>::V) ); + + if (baseChunk == AsciiId<'K','7','2'>::V) + { + while (const dword chunk = state.Begin()) + { + if (chunk == AsciiId<'R','E','G'>::V) + reg = state.Read8(); + + state.End(); + } + } + } + void Ks7031::SubLoad(State::Loader& state,const dword baseChunk) { NST_VERIFY( (baseChunk == AsciiId<'K','7','1'>::V) ); @@ -272,6 +319,33 @@ namespace Nes } } + void Ks7057::SubLoad(State::Loader& state,const dword baseChunk) + { + NST_VERIFY( (baseChunk == AsciiId<'K','5','7'>::V) ); + + if (baseChunk == AsciiId<'K','5','7'>::V) + { + while (const dword chunk = state.Begin()) + { + if (chunk == AsciiId<'R','E','G'>::V) + { + State::Loader::Data<8> data( state ); + + regs[0] = data[0]; + regs[1] = data[1]; + regs[2] = data[2]; + regs[3] = data[3]; + regs[4] = data[4]; + regs[5] = data[5]; + regs[6] = data[6]; + regs[7] = data[7]; + } + + state.End(); + } + } + } + void Ks202::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','0','2'>::V ); @@ -290,6 +364,11 @@ namespace Nes state.End(); } + void Ks7010::SubSave(State::Saver& state) const + { + state.Begin( AsciiId<'K','7','0'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); + } + void Ks7016::SubSave(State::Saver& state) const { state.Begin( AsciiId<'K','7','6'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End(); @@ -323,6 +402,20 @@ namespace Nes state.End(); } + void Ks7057::SubSave(State::Saver& state) const + { + state.Begin( AsciiId<'K','5','7'>::V ); + + const byte data[8] = + { + regs[0], regs[1], regs[2], regs[3], + regs[4], regs[5], regs[6], regs[7] + }; + + state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End(); + state.End(); + } + #ifdef NST_MSVC_OPTIMIZE #pragma optimize("", on) #endif @@ -429,6 +522,20 @@ namespace Nes Board::Sync( event, controllers ); } + NES_PEEK_A(Ks7010,6000) + { + return *(prg.Source().Mem(reg * SIZE_8K) + (address & 0x1FFF)); + } + + NES_PEEK_A(Ks7010,FFFC) + { + reg = (address >> 2) & 0xF; + chr.SwapBank( reg ); + ppu.Update(); + + return prg.Peek(address & 0x7FFF); + } + NES_POKE_D(Ks7013b,6000) { prg.SwapBank( 0x0000, data & 0x7 ); @@ -566,6 +673,39 @@ namespace Nes { return *(prg.Source().Mem(SIZE_8K * 15) + (address & 0x1FFF)); } + + NES_PEEK_A(Ks7057,6000) + { + return *(prg.Source().Mem(regs[(address >> 11) - 0xC] * SIZE_2K) + (address & 0x7FF)); + } + + NES_POKE_D(Ks7057,8000) + { + ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_V : Ppu::NMT_H ); + } + + NES_POKE_AD(Ks7057,B000) + { + switch(address & 0xF003) + { + case 0xB000: regs[4] = (regs[4] & 0xF0) | (data & 0xF); break; + case 0xB001: regs[4] = (regs[4] & 0xF) | (data << 4); break; + case 0xB002: regs[5] = (regs[5] & 0xF0) | (data & 0xF); break; + case 0xB003: regs[5] = (regs[5] & 0xF) | (data << 4); break; + case 0xC000: regs[6] = (regs[6] & 0xF0) | (data & 0xF); break; + case 0xC001: regs[6] = (regs[6] & 0xF) | (data << 4); break; + case 0xC002: regs[7] = (regs[7] & 0xF0) | (data & 0xF); break; + case 0xC003: regs[7] = (regs[7] & 0xF) | (data << 4); break; + case 0xD000: regs[0] = (regs[0] & 0xF0) | (data & 0xF); break; + case 0xD001: regs[0] = (regs[0] & 0xF) | (data << 4); break; + case 0xD002: regs[1] = (regs[1] & 0xF0) | (data & 0xF); break; + case 0xD003: regs[1] = (regs[1] & 0xF) | (data << 4); break; + case 0xE000: regs[2] = (regs[2] & 0xF0) | (data & 0xF); break; + case 0xE001: regs[2] = (regs[2] & 0xF) | (data << 4); break; + case 0xE002: regs[3] = (regs[3] & 0xF0) | (data & 0xF); break; + case 0xE003: regs[3] = (regs[3] & 0xF) | (data << 4); break; + } + } } } } diff --git a/source/core/board/NstBoardKaiser.hpp b/source/core/board/NstBoardKaiser.hpp index bf6def2..9d19c43 100644 --- a/source/core/board/NstBoardKaiser.hpp +++ b/source/core/board/NstBoardKaiser.hpp @@ -77,6 +77,25 @@ namespace Nes Timer::M2 irq; }; + class Ks7010 : public Board + { + public: + + explicit Ks7010(const Context& c) + : Board(c) {} + + private: + + void SubReset(bool); + void SubLoad(State::Loader&,dword); + void SubSave(State::Saver&) const; + + NES_DECL_PEEK( 6000 ); + NES_DECL_PEEK( FFFC ); + + uint reg; + }; + class Ks7013b : public Board { public: @@ -191,6 +210,25 @@ namespace Nes NES_DECL_PEEK( E000 ); }; + class Ks7057 : public Board + { + public: + explicit Ks7057(const Context& c) + : Board(c) {} + + private: + + void SubReset(bool); + void SubLoad(State::Loader&,dword); + void SubSave(State::Saver&) const; + + byte regs[8]; + + NES_DECL_PEEK( 6000 ); + NES_DECL_POKE( 8000 ); + NES_DECL_POKE( B000 ); + }; + class Ks7058 : public Board { public: diff --git a/source/core/board/NstBoardMmc3.hpp b/source/core/board/NstBoardMmc3.hpp index eafd5d5..8694a5a 100644 --- a/source/core/board/NstBoardMmc3.hpp +++ b/source/core/board/NstBoardMmc3.hpp @@ -58,32 +58,28 @@ namespace Nes uint latch; ibool reload; ibool enabled; - const ibool persistant; + const ibool persistent; public: explicit BaseIrq(bool p) - : persistant(p) {} + : persistent(p) {} NST_FORCE_INLINE bool Clock() { - const uint tmp = count; + const bool tmp = count || reload; - if (reload) - { - reload = false; - count = latch; - } - else if (!count) + if (!count || reload) { count = latch; } else { - count--; + --count; } - return (tmp | persistant) && !count && enabled; + reload = false; + return (tmp | persistent) && !count && enabled; } void SetLatch(uint data) @@ -120,8 +116,8 @@ namespace Nes template struct Irq : Timer::A12 { - Irq(Cpu& c,Ppu& p,bool persistant) - : Timer::A12(c,p,persistant) {} + Irq(Cpu& c,Ppu& p,bool persistent) + : Timer::A12(c,p,persistent) {} }; protected: diff --git a/source/core/board/NstBoardMmc6.cpp b/source/core/board/NstBoardMmc6.cpp index f239b11..0898be2 100644 --- a/source/core/board/NstBoardMmc6.cpp +++ b/source/core/board/NstBoardMmc6.cpp @@ -37,7 +37,7 @@ namespace Nes #endif Mmc6::Mmc6(const Context& c) - : Mmc3(c,REV_B) {} + : Mmc3(c,REV_A) {} void Mmc6::SubReset(const bool hard) { diff --git a/source/core/board/NstBoardWaixing.hpp b/source/core/board/NstBoardWaixing.hpp index aa3f29c..1943632 100644 --- a/source/core/board/NstBoardWaixing.hpp +++ b/source/core/board/NstBoardWaixing.hpp @@ -32,6 +32,7 @@ #include "NstBoardMmc3.hpp" #include "NstBoardWaixingPs2.hpp" #include "NstBoardWaixingFfv.hpp" +#include "NstBoardWaixingFs304.hpp" #include "NstBoardWaixingSh2.hpp" #include "NstBoardWaixingZs.hpp" #include "NstBoardWaixingSecurity.hpp" diff --git a/source/core/board/NstBoardWaixingFs304.cpp b/source/core/board/NstBoardWaixingFs304.cpp new file mode 100644 index 0000000..837e748 --- /dev/null +++ b/source/core/board/NstBoardWaixingFs304.cpp @@ -0,0 +1,106 @@ +//////////////////////////////////////////////////////////////////////////////////////// +// +// Nestopia - NES/Famicom emulator written in C++ +// +// Copyright (C) 2021 Rupert Carmichael +// +// This file is part of Nestopia. +// +// Nestopia is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// Nestopia is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Nestopia; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////////////// + +#include "NstBoard.hpp" +#include "NstBoardWaixing.hpp" + +// Reference: https://github.com/TASVideos/fceux/blob/master/src/boards/164.cpp + +namespace Nes +{ + namespace Core + { + namespace Boards + { + namespace Waixing + { + + void Fs304::SubReset(bool) + { + Map( 0x5000U, 0x5FFFU, &Fs304::Poke_5000 ); + + regs[0] = 0x3; + regs[1] = 0x0; + regs[2] = 0x0; + regs[3] = 0x7; + + UpdatePrg(); + } + + void Fs304::SubSave(State::Saver& state) const + { + const byte data[4] = { regs[0], regs[1], regs[2], regs[3] }; + state.Begin( AsciiId<'3','0','4'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write( data ).End().End(); + } + + void Fs304::SubLoad(State::Loader& state,const dword baseChunk) + { + NST_VERIFY( baseChunk == (AsciiId<'3','0','4'>::V) ); + + if (baseChunk == AsciiId<'3','0','4'>::V) + { + while (const dword chunk = state.Begin()) + { + if (chunk == AsciiId<'R','E','G'>::V) + { + State::Loader::Data<4> data( state ); + + regs[0] = data[0]; + regs[1] = data[1]; + regs[2] = data[2]; + regs[3] = data[3]; + } + + state.End(); + } + } + } + + void Fs304::UpdatePrg() + { + switch (regs[3] & 0x5) { + case 0: + prg.SwapBank( 0x0000, ((regs[0] & 0xC) | (regs[1] & 0x2) | ((regs[2] & 0xF) << 4)) ); + break; + case 1: + prg.SwapBank( 0x0000, ((regs[0] & 0xC) | (regs[2] & 0xF) << 4) ); + break; + case 4: + prg.SwapBank( 0x0000, ((regs[0] & 0xE) | ((regs[1] >> 1) & 0x1) | ((regs[2] & 0xF) << 4)) ); + break; + case 5: + prg.SwapBank( 0x0000, ((regs[0] & 0xF) | ((regs[2] & 0xF) << 4)) ); + break; + } + } + + NES_POKE_AD(Fs304,5000) + { + regs[(address >> 8) & 0x3] = data; + UpdatePrg(); + } + } + } + } +} diff --git a/source/core/board/NstBoardWaixingFs304.hpp b/source/core/board/NstBoardWaixingFs304.hpp new file mode 100644 index 0000000..1e052cc --- /dev/null +++ b/source/core/board/NstBoardWaixingFs304.hpp @@ -0,0 +1,63 @@ +//////////////////////////////////////////////////////////////////////////////////////// +// +// Nestopia - NES/Famicom emulator written in C++ +// +// Copyright (C) 2021 Rupert Carmichael +// +// This file is part of Nestopia. +// +// Nestopia is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// Nestopia is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Nestopia; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//////////////////////////////////////////////////////////////////////////////////////// + +#ifndef NST_BOARD_WAIXING_FS304_H +#define NST_BOARD_WAIXING_FS304_H + +#ifdef NST_PRAGMA_ONCE +#pragma once +#endif + +namespace Nes +{ + namespace Core + { + namespace Boards + { + namespace Waixing + { + class Fs304 : public Board + { + public: + + explicit Fs304(const Context& c) + : Board(c) {} + + private: + + void SubReset(bool); + void SubSave(State::Saver&) const; + void SubLoad(State::Loader&,dword); + void UpdatePrg(); + + NES_DECL_POKE( 5000 ); + + uint regs[4]; + }; + } + } + } +} + +#endif