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