Update core to 1.52.0

This commit is contained in:
rdanbrook 2022-12-29 09:30:40 -06:00
parent 170b3bebbe
commit 63a4a991d3
29 changed files with 834 additions and 170 deletions

View File

@ -248,13 +248,16 @@ SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxcMxmdhtwo.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxcPoliceman.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxcPoliceman.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxcTw.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxcTw.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxRom.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardTxRom.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnl158b.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlA9746.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlA9746.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlCc21.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlCc21.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlEdu2000.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlEdu2000.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlKingOfFighters96.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlKingOfFighters96.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlKingOfFighters97.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlKingOfFighters97.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlMortalKombat2.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlMortalKombat2.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlMmc3BigPrgRom.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlN625092.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlN625092.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlRetX7Gbl.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlSuperFighter3.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlSuperFighter3.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlTf1201.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlTf1201.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlWorldHero.cpp SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardUnlWorldHero.cpp

View File

@ -22,7 +22,7 @@
#include "nstdatabase.hpp" #include "nstdatabase.hpp"
#define NST_VERSION "1.51.1" #define NST_VERSION "1.52.0"
#define MIN(a,b) ((a)<(b)?(a):(b)) #define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b)) #define MAX(a,b) ((a)>(b)?(a):(b))
@ -1557,7 +1557,6 @@ bool retro_load_game(const struct retro_game_info *info)
ivideo.SetRenderState(state); ivideo.SetRenderState(state);
Api::Sound isound(emulator); Api::Sound isound(emulator);
isound.SetSampleBits(16);
isound.SetSampleRate(SAMPLERATE); isound.SetSampleRate(SAMPLERATE);
isound.SetSpeaker(Api::Sound::SPEAKER_MONO); isound.SetSpeaker(Api::Sound::SPEAKER_MONO);

View File

@ -238,7 +238,7 @@ namespace Nes
stream = NULL; stream = NULL;
buffer.Reset( settings.bits ); buffer.Reset();
if (on) if (on)
{ {
@ -297,7 +297,7 @@ namespace Nes
if (!rate) if (!rate)
return RESULT_ERR_INVALID_PARAM; return RESULT_ERR_INVALID_PARAM;
if (rate < 11025 || rate > 96000) if (rate < 44100 || rate > 96000)
return RESULT_ERR_UNSUPPORTED; return RESULT_ERR_UNSUPPORTED;
settings.rate = rate; settings.rate = rate;
@ -306,23 +306,6 @@ namespace Nes
return RESULT_OK; return RESULT_OK;
} }
Result Apu::SetSampleBits(const uint bits)
{
if (settings.bits == bits)
return RESULT_NOP;
if (!bits)
return RESULT_ERR_INVALID_PARAM;
if (bits != 8 && bits != 16)
return RESULT_ERR_UNSUPPORTED;
settings.bits = bits;
UpdateSettings();
return RESULT_OK;
}
Result Apu::SetVolume(const uint channels,const uint volume) Result Apu::SetVolume(const uint channels,const uint volume)
{ {
if (volume > 100) if (volume > 100)
@ -421,7 +404,7 @@ namespace Nes
cycles.Update( settings.rate, settings.speed, cpu ); cycles.Update( settings.rate, settings.speed, cpu );
synchronizer.Reset( settings.speed, settings.rate, cpu ); synchronizer.Reset( settings.speed, settings.rate, cpu );
dcBlocker.Reset(); dcBlocker.Reset();
buffer.Reset( settings.bits ); buffer.Reset();
Cycle rate; uint fixed; Cycle rate; uint fixed;
CalculateOscillatorClock( rate, fixed ); CalculateOscillatorClock( rate, fixed );
@ -863,20 +846,10 @@ namespace Nes
{ {
streamed = stream->length[0] + stream->length[1]; streamed = stream->length[0] + stream->length[1];
if (settings.bits == 16)
{
if (!settings.stereo) if (!settings.stereo)
FlushSound<iword,false>(); FlushSound<iword,false>();
else else
FlushSound<iword,true>(); FlushSound<iword,true>();
}
else
{
if (!settings.stereo)
FlushSound<byte,false>();
else
FlushSound<byte,true>();
}
Sound::Output::unlockCallback( *stream ); Sound::Output::unlockCallback( *stream );
} }
@ -921,7 +894,7 @@ namespace Nes
#endif #endif
Apu::Settings::Settings() Apu::Settings::Settings()
: rate(44100), bits(16), speed(0), muted(false), transpose(false), stereo(false), audible(true) : rate(44100), speed(0), muted(false), transpose(false), stereo(false), audible(true)
{ {
for (uint i=0; i < MAX_CHANNELS; ++i) for (uint i=0; i < MAX_CHANNELS; ++i)
volumes[i] = Channel::DEFAULT_VOLUME; volumes[i] = Channel::DEFAULT_VOLUME;
@ -2474,7 +2447,7 @@ namespace Nes
dcBlocker.Reset(); dcBlocker.Reset();
buffer.Reset( settings.bits, false ); buffer.Reset( false );
} }
#ifdef NST_MSVC_OPTIMIZE #ifdef NST_MSVC_OPTIMIZE

View File

@ -60,7 +60,6 @@ namespace Nes
void ClockDMA(uint=0); void ClockDMA(uint=0);
Result SetSampleRate(dword); Result SetSampleRate(dword);
Result SetSampleBits(uint);
Result SetSpeed(uint); Result SetSpeed(uint);
Result SetVolume(uint,uint); Result SetVolume(uint,uint);
uint GetVolume(uint) const; uint GetVolume(uint) const;
@ -601,7 +600,6 @@ namespace Nes
Settings(); Settings();
dword rate; dword rate;
uint bits;
byte speed; byte speed;
bool muted; bool muted;
bool transpose; bool transpose;
@ -643,11 +641,6 @@ namespace Nes
return settings.rate; return settings.rate;
} }
uint GetSampleBits() const
{
return settings.bits;
}
uint GetSpeed() const uint GetSpeed() const
{ {
return settings.speed; return settings.speed;

View File

@ -147,7 +147,7 @@ namespace Nes
Log::Flush( "Ines: PRG-ROM was patched" NST_LINEBREAK ); Log::Flush( "Ines: PRG-ROM was patched" NST_LINEBREAK );
if (Load( chr, 16 + prg.Size() )) if (Load( chr, 16 + prg.Size() ))
Log::Flush( "Ines: PRG-ROM was patched" NST_LINEBREAK ); Log::Flush( "Ines: CHR-ROM was patched" NST_LINEBREAK );
} }
private: private:

View File

@ -124,7 +124,7 @@ namespace Nes
0x00, 0x20, 0x00, 0x20, 0x04, 0x04, 0x04, 0x04, 0x00, 0x20, 0x00, 0x20, 0x04, 0x04, 0x04, 0x04,
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
0x00, 0x20, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x20, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x10, 0x10, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -2128,11 +2128,12 @@ namespace Nes
} }
// Unofficial Opcodes SHX/SHY are edge cases // Unofficial Opcodes SHX/SHY are edge cases
#define NES_I_W_U(instr_,addr_,hex_) \ #define NES_I_W_U(instr_,hex_) \
\ \
void Cpu::op##hex_() \ void Cpu::op##hex_() \
{ \ { \
const uint dst = addr_##_W(); \ const uint dst = FetchPc16(); \
cycles.count += cycles.clock[3]; \
instr_(dst); \ instr_(dst); \
} }
@ -2393,8 +2394,8 @@ namespace Nes
NES_I_W_A( Sha, AbsY, 0x9F ) NES_I_W_A( Sha, AbsY, 0x9F )
NES_I_W_A( Sha, IndY, 0x93 ) NES_I_W_A( Sha, IndY, 0x93 )
NES_I_W_A( Shs, AbsY, 0x9B ) NES_I_W_A( Shs, AbsY, 0x9B )
NES_I_W_U( Shx, Abs, 0x9E ) // Edge case: AbsY done internally NES_I_W_U( Shx, 0x9E ) // Edge case: AbsY done internally
NES_I_W_U( Shy, Abs, 0x9C ) // Edge case: AbsX done internally NES_I_W_U( Shy, 0x9C ) // Edge case: AbsX done internally
NES_IRW__( Slo, Zpg, 0x07 ) NES_IRW__( Slo, Zpg, 0x07 )
NES_IRW__( Slo, ZpgX, 0x17 ) NES_IRW__( Slo, ZpgX, 0x17 )
NES_IRW__( Slo, Abs, 0x0F ) NES_IRW__( Slo, Abs, 0x0F )

View File

@ -221,17 +221,36 @@ namespace Nes
{ {
NST_ASSERT( it->length ); NST_ASSERT( it->length );
bool underflow = false;
dword uflow_length = 0;
if (it->offset < offset) if (it->offset < offset)
{
if (it->offset + it->length > offset)
{
underflow = true;
uflow_length = offset - it->offset;
}
else
{
continue; continue;
}
}
if (it->offset >= offset + length) if (it->offset >= offset + length)
break; break;
const dword pos = it->offset - offset; dword pos = it->offset - offset;
const dword part = NST_MIN(it->length,length-pos); dword part = NST_MIN(it->length,length-pos);
if (underflow)
{
part -= uflow_length;
pos += uflow_length;
}
if (it->fill == NO_FILL) if (it->fill == NO_FILL)
std::memcpy( dst + pos, it->data, part ); std::memcpy( dst + pos, it->data + uflow_length, part );
else else
std::memset( dst + pos, it->fill, part ); std::memset( dst + pos, it->fill, part );

View File

@ -401,6 +401,8 @@ namespace Nes
state.End(); state.End();
} }
output.bgColor = palette.ram[0] & uint(Palette::COLOR);
UpdateStates(); UpdateStates();
} }
@ -774,6 +776,17 @@ namespace Nes
return (regs.ctrl[1] & Regs::CTRL1_EMPHASIS) << 1; return (regs.ctrl[1] & Regs::CTRL1_EMPHASIS) << 1;
} }
NST_FORCE_INLINE void Ppu::UpdateDecay(byte mask)
{
Cycle curCyc = cpu.GetCycles();
for (uint i = 0; i < 8; ++i)
{
if (mask & (1 << i))
decay.timestamp[i] = curCyc;
}
}
NES_POKE_D(Ppu,2000) NES_POKE_D(Ppu,2000)
{ {
Update( cycles.one ); Update( cycles.one );
@ -786,6 +799,8 @@ namespace Nes
oam.height = (data >> 2 & 8) + 8; oam.height = (data >> 2 & 8) + 8;
io.latch = data; io.latch = data;
UpdateDecay(0xFF);
data = regs.ctrl[0] ; data = regs.ctrl[0] ;
regs.ctrl[0] = io.latch; regs.ctrl[0] = io.latch;
@ -825,6 +840,8 @@ namespace Nes
} }
io.latch = data; io.latch = data;
UpdateDecay(0xFF);
data = (regs.ctrl[1] ^ data) & (Regs::CTRL1_EMPHASIS|Regs::CTRL1_MONOCHROME); data = (regs.ctrl[1] ^ data) & (Regs::CTRL1_EMPHASIS|Regs::CTRL1_MONOCHROME);
regs.ctrl[1] = io.latch; regs.ctrl[1] = io.latch;
@ -852,13 +869,22 @@ namespace Nes
{ {
Update( cycles.one, address ); Update( cycles.one, address );
byte mask = 0xE0;
uint status = regs.status & 0xFF; uint status = regs.status & 0xFF;
regs.status &= (Regs::STATUS_VBLANK^0xFFU); regs.status &= (Regs::STATUS_VBLANK^0xFFU);
scroll.toggle = 0; scroll.toggle = 0;
io.latch = (io.latch & Regs::STATUS_LATCH) | status; io.latch = (io.latch & Regs::STATUS_LATCH) | status;
UpdateDecay(mask);
return io.latch; Cycle curCyc = cpu.GetCycles();
for (uint i = 0; i < 5; ++i)
{
if ((curCyc - decay.timestamp[i]) < 24576)
mask |= (1 << i);
}
return io.latch & mask;
} }
NES_PEEK_A(Ppu,2002_RC2C05_01_04) NES_PEEK_A(Ppu,2002_RC2C05_01_04)
@ -882,6 +908,7 @@ namespace Nes
regs.oam = data; regs.oam = data;
io.latch = data; io.latch = data;
UpdateDecay(0xFF);
} }
NES_POKE_D(Ppu,2004) NES_POKE_D(Ppu,2004)
@ -891,6 +918,9 @@ namespace Nes
NST_ASSERT( regs.oam < Oam::SIZE ); NST_ASSERT( regs.oam < Oam::SIZE );
NST_VERIFY( IsDead() ); NST_VERIFY( IsDead() );
io.latch = data;
UpdateDecay(0xFF);
if (IsDead()) if (IsDead())
{ {
if ((regs.oam & 0x03) == 0x02) if ((regs.oam & 0x03) == 0x02)
@ -903,7 +933,6 @@ namespace Nes
byte* const NST_RESTRICT value = oam.ram + regs.oam; byte* const NST_RESTRICT value = oam.ram + regs.oam;
regs.oam = (regs.oam + 1) & 0xFF; regs.oam = (regs.oam + 1) & 0xFF;
io.latch = data;
*value = data; *value = data;
} }
@ -914,12 +943,14 @@ namespace Nes
if (!(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) || cpu.GetCycles() - (cpu.GetFrameCycles() - (341 * 241) * cycles.one) >= (341 * 240) * cycles.one) if (!(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) || cpu.GetCycles() - (cpu.GetFrameCycles() - (341 * 241) * cycles.one) >= (341 * 240) * cycles.one)
{ {
io.latch = oam.ram[regs.oam]; io.latch = oam.ram[regs.oam];
UpdateDecay(0xFF);
} }
else else
{ {
Update( cycles.one ); Update( cycles.one );
io.latch = oam.latch; io.latch = oam.latch;
UpdateDecay(0xFF);
} }
return io.latch; return io.latch;
@ -934,6 +965,7 @@ namespace Nes
if (cpu.GetCycles() >= cycles.reset) if (cpu.GetCycles() >= cycles.reset)
{ {
io.latch = data; io.latch = data;
UpdateDecay(0xFF);
if (scroll.toggle ^= 1) if (scroll.toggle ^= 1)
{ {
@ -956,6 +988,7 @@ namespace Nes
if (cpu.GetCycles() >= cycles.reset) if (cpu.GetCycles() >= cycles.reset)
{ {
io.latch = data; io.latch = data;
UpdateDecay(0xFF);
if (scroll.toggle ^= 1) if (scroll.toggle ^= 1)
{ {
@ -984,6 +1017,7 @@ namespace Nes
return; return;
io.latch = data; io.latch = data;
UpdateDecay(0xFF);
if ((address & 0x3F00) == 0x3F00) if ((address & 0x3F00) == 0x3F00)
{ {
@ -1015,27 +1049,54 @@ namespace Nes
NES_PEEK_A(Ppu,2007) NES_PEEK_A(Ppu,2007)
{ {
byte mask = 0xFF;
byte cache = io.latch;
Update( cycles.one, address ); Update( cycles.one, address );
Cycle curCyc = cpu.GetCycles();
Cycle delta = curCyc - decay.rd2007;
decay.rd2007 = curCyc;
bool fastread = (delta <= 12);
address = scroll.address & 0x3FFF; address = scroll.address & 0x3FFF;
UpdateVramAddress(); UpdateVramAddress();
if (!(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) || (scanline == SCANLINE_VBLANK)) if (!(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) || (scanline == SCANLINE_VBLANK))
UpdateAddressLine(scroll.address & 0x3fff); UpdateAddressLine(scroll.address & 0x3fff);
io.latch = (address & 0x3F00) != 0x3F00 ? io.buffer : palette.ram[address & 0x1F] & Coloring(); if ((address & 0x3F00) == 0x3F00) // Palette
{
io.latch = (io.latch & 0xC0) | palette.ram[address & 0x1F] & Coloring();
mask = 0x3F;
}
else // Non-Palette
{
io.latch = io.buffer;
}
UpdateDecay(mask);
io.buffer = (address >= 0x2000 ? nmt.FetchName( address ) : chr.FetchPattern( address )); io.buffer = (address >= 0x2000 ? nmt.FetchName( address ) : chr.FetchPattern( address ));
if (fastread)
io.latch = cache;
return io.latch; return io.latch;
} }
NES_POKE_D(Ppu,2xxx) NES_POKE_D(Ppu,2xxx)
{ {
io.latch = data; io.latch = data;
UpdateDecay(0xFF);
} }
NES_PEEK(Ppu,2xxx) NES_PEEK(Ppu,2xxx)
{ {
if ((cpu.GetCycles() - decay.timestamp[0]) > 24576)
return 0;
return io.latch; return io.latch;
} }
@ -1074,10 +1135,13 @@ namespace Nes
} }
io.latch = oamRam[0xFF]; io.latch = oamRam[0xFF];
UpdateDecay(0xFF);
} }
else do else do
{ {
io.latch = cpu.Peek( data++ ); io.latch = cpu.Peek( data++ );
UpdateDecay(0xFF);
cpu.StealCycles( cpu.GetClock() ); cpu.StealCycles( cpu.GetClock() );
Update( cycles.one ); Update( cycles.one );

View File

@ -186,6 +186,7 @@ namespace Nes
NST_FORCE_INLINE uint FetchSpPattern() const; NST_FORCE_INLINE uint FetchSpPattern() const;
NST_FORCE_INLINE void FetchBgPattern0(); NST_FORCE_INLINE void FetchBgPattern0();
NST_FORCE_INLINE void FetchBgPattern1(); NST_FORCE_INLINE void FetchBgPattern1();
NST_FORCE_INLINE void UpdateDecay(byte);
NST_FORCE_INLINE void EvaluateSpritesEven(); NST_FORCE_INLINE void EvaluateSpritesEven();
NST_FORCE_INLINE void EvaluateSpritesOdd(); NST_FORCE_INLINE void EvaluateSpritesOdd();
@ -407,6 +408,12 @@ namespace Nes
Cycle reset; Cycle reset;
} cycles; } cycles;
struct
{
Cycle timestamp[8];
Cycle rd2007;
} decay;
Io io; Io io;
Regs regs; Regs regs;
Scroll scroll; Scroll scroll;
@ -419,7 +426,6 @@ namespace Nes
public: public:
Output output; Output output;
private: private:
PpuModel model; PpuModel model;
Hook hActiveHook; Hook hActiveHook;

View File

@ -39,7 +39,7 @@ namespace Nes
Buffer::Buffer(uint bits) Buffer::Buffer(uint bits)
: output(new iword [SIZE]) : output(new iword [SIZE])
{ {
Reset( bits, true ); Reset( true );
} }
Buffer::~Buffer() Buffer::~Buffer()
@ -47,12 +47,12 @@ namespace Nes
delete [] output; delete [] output;
} }
void Buffer::Reset(uint bits,bool clear) void Buffer::Reset(bool clear)
{ {
pos = start = 0; pos = start = 0;
history.pos = 0; history.pos = 0;
std::fill( history.buffer, history.buffer+History::SIZE, iword(bits == 16 ? 0 : 0x80) ); std::fill( history.buffer, history.buffer+History::SIZE, iword(0) );
if (clear) if (clear)
std::fill( output, output+SIZE, iword(0) ); std::fill( output, output+SIZE, iword(0) );

View File

@ -59,7 +59,7 @@ namespace Nes
uint length; uint length;
}; };
void Reset(uint,bool=true); void Reset(bool=true);
void operator >> (Block&); void operator >> (Block&);
template<typename,uint> template<typename,uint>

View File

@ -136,7 +136,6 @@ namespace Nes
enabled (e), enabled (e),
good (false), good (false),
stereo (false), stereo (false),
bits (0),
rate (0), rate (0),
index (0), index (0),
buffer (NULL), buffer (NULL),
@ -268,14 +267,13 @@ namespace Nes
bool Tracker::Rewinder::ReverseSound::Update() bool Tracker::Rewinder::ReverseSound::Update()
{ {
const dword old = (bits == 16 ? size * sizeof(iword) : size * sizeof(byte)); const dword old = size * sizeof(iword);
bits = apu.GetSampleBits();
rate = apu.GetSampleRate(); rate = apu.GetSampleRate();
stereo = apu.InStereo(); stereo = apu.InStereo();
size = rate << (stereo+1); size = rate << (stereo+1);
const dword total = (bits == 16 ? size * sizeof(iword) : size * sizeof(byte)); const dword total = size * sizeof(iword);
NST_ASSERT( total ); NST_ASSERT( total );
if (!buffer || total != old) if (!buffer || total != old)
@ -296,10 +294,7 @@ namespace Nes
good = true; good = true;
index = 0; index = 0;
if (bits == 16)
std::fill( static_cast<iword*>(buffer), static_cast<iword*>(buffer) + size, iword(0) ); std::fill( static_cast<iword*>(buffer), static_cast<iword*>(buffer) + size, iword(0) );
else
std::memset( buffer, 0x80, size );
return true; return true;
} }
@ -587,13 +582,13 @@ namespace Nes
{ {
NST_COMPILE_ASSERT( NUM_FRAMES % 2 == 0 ); NST_COMPILE_ASSERT( NUM_FRAMES % 2 == 0 );
if (!buffer || (bits ^ apu.GetSampleBits()) | (rate ^ apu.GetSampleRate()) | (stereo ^ uint(bool(apu.InStereo())))) if (!buffer || (rate ^ apu.GetSampleRate()) | (stereo ^ uint(bool(apu.InStereo()))))
{ {
if (!good || !Update() || !enabled) if (!good || !Update() || !enabled)
return NULL; return NULL;
} }
return bits == 16 ? StoreType<iword>() : StoreType<byte>(); return StoreType<iword>();
} }
template<typename T,int SILENCE> template<typename T,int SILENCE>
@ -632,14 +627,11 @@ namespace Nes
{ {
if (enabled & good) if (enabled & good)
{ {
input = (bits == 16) ? ReverseCopy<iword>( *target ) : ReverseCopy<byte>( *target ); input = ReverseCopy<iword>( *target );
} }
else else
{ {
if (bits == 16)
ReverseSilence<iword,0>( *target ); ReverseSilence<iword,0>( *target );
else
ReverseSilence<byte,0x80>( *target );
} }
mutex.Unlock( *target ); mutex.Unlock( *target );

View File

@ -181,7 +181,6 @@ namespace Nes
bool enabled; bool enabled;
bool good; bool good;
byte stereo; byte stereo;
byte bits;
dword rate; dword rate;
uint index; uint index;
void* buffer; void* buffer;

View File

@ -67,7 +67,7 @@ namespace Nes
HEIGHT = Input::HEIGHT, HEIGHT = Input::HEIGHT,
PIXELS = Input::PIXELS, PIXELS = Input::PIXELS,
PALETTE = Input::PALETTE, PALETTE = Input::PALETTE,
DEFAULT_PALETTE = PALETTE_YUV NST_DEFAULT_PALETTE = PALETTE_YUV
}; };
Result SetState(const RenderState&); Result SetState(const RenderState&);

View File

@ -62,11 +62,6 @@ namespace Nes
return emulator.cpu.GetApu().SetSampleRate( rate ); return emulator.cpu.GetApu().SetSampleRate( rate );
} }
Result Sound::SetSampleBits(uint bits) throw()
{
return emulator.cpu.GetApu().SetSampleBits( bits );
}
Result Sound::SetVolume(uint channels,uint volume) throw() Result Sound::SetVolume(uint channels,uint volume) throw()
{ {
return emulator.cpu.GetApu().SetVolume( channels, volume ); return emulator.cpu.GetApu().SetVolume( channels, volume );
@ -97,11 +92,6 @@ namespace Nes
return emulator.cpu.GetApu().GetSampleRate(); return emulator.cpu.GetApu().GetSampleRate();
} }
uint Sound::GetSampleBits() const throw()
{
return emulator.cpu.GetApu().GetSampleBits();
}
uint Sound::GetVolume(uint channel) const throw() uint Sound::GetVolume(uint channel) const throw()
{ {
return emulator.cpu.GetApu().GetVolume( channel ); return emulator.cpu.GetApu().GetVolume( channel );

View File

@ -262,7 +262,7 @@ namespace Nes
/** /**
* Sets the sample rate. * Sets the sample rate.
* *
* @param rate value in the range 11025 to 96000, default is 44100 * @param rate value in the range 44100 to 96000, default is 44100
* @return result code * @return result code
*/ */
Result SetSampleRate(ulong rate) throw(); Result SetSampleRate(ulong rate) throw();
@ -274,21 +274,6 @@ namespace Nes
*/ */
ulong GetSampleRate() const throw(); ulong GetSampleRate() const throw();
/**
* Sets the sample bits.
*
* @param bits value of 8 or 16, default is 16
* @return result code
*/
Result SetSampleBits(uint bits) throw();
/**
* Returns the sample bits.
*
* @return number
*/
uint GetSampleBits() const throw();
/** /**
* Sets the speaker type. * Sets the speaker type.
* *

View File

@ -334,7 +334,7 @@ namespace Nes
Video::Palette::Mode Video::Palette::GetDefaultMode() const throw() Video::Palette::Mode Video::Palette::GetDefaultMode() const throw()
{ {
NST_COMPILE_ASSERT( Core::Video::Renderer::DEFAULT_PALETTE - Core::Video::Renderer::PALETTE_YUV == 0 ); NST_COMPILE_ASSERT( Core::Video::Renderer::NST_DEFAULT_PALETTE - Core::Video::Renderer::PALETTE_YUV == 0 );
return MODE_YUV; return MODE_YUV;
} }

View File

@ -97,13 +97,16 @@
#include "NstBoardWaixing.hpp" #include "NstBoardWaixing.hpp"
#include "NstBoardWhirlwind.hpp" #include "NstBoardWhirlwind.hpp"
#include "NstBoardBenshengBs5.hpp" #include "NstBoardBenshengBs5.hpp"
#include "NstBoardUnl158b.hpp"
#include "NstBoardUnlA9746.hpp" #include "NstBoardUnlA9746.hpp"
#include "NstBoardUnlCc21.hpp" #include "NstBoardUnlCc21.hpp"
#include "NstBoardUnlEdu2000.hpp" #include "NstBoardUnlEdu2000.hpp"
#include "NstBoardUnlKingOfFighters96.hpp" #include "NstBoardUnlKingOfFighters96.hpp"
#include "NstBoardUnlKingOfFighters97.hpp" #include "NstBoardUnlKingOfFighters97.hpp"
#include "NstBoardUnlMmc3BigPrgRom.hpp"
#include "NstBoardUnlMortalKombat2.hpp" #include "NstBoardUnlMortalKombat2.hpp"
#include "NstBoardUnlN625092.hpp" #include "NstBoardUnlN625092.hpp"
#include "NstBoardUnlRetX7Gbl.hpp"
#include "NstBoardUnlSuperFighter3.hpp" #include "NstBoardUnlSuperFighter3.hpp"
#include "NstBoardUnlTf1201.hpp" #include "NstBoardUnlTf1201.hpp"
#include "NstBoardUnlWorldHero.hpp" #include "NstBoardUnlWorldHero.hpp"
@ -1096,6 +1099,7 @@ namespace Nes
{ "TENGEN-800032", Type::TENGEN_800032 }, { "TENGEN-800032", Type::TENGEN_800032 },
{ "TENGEN-800037", Type::TENGEN_800037 }, { "TENGEN-800037", Type::TENGEN_800037 },
{ "TENGEN-800042", Type::TENGEN_800042 }, { "TENGEN-800042", Type::TENGEN_800042 },
{ "UNL-158B", Type::UNL_158B },
{ "UNL-22211", Type::TXC_22211A }, { "UNL-22211", Type::TXC_22211A },
{ "UNL-603-5052", Type::BTL_6035052 }, { "UNL-603-5052", Type::BTL_6035052 },
{ "UNL-8237", Type::SUPERGAME_POCAHONTAS2 }, { "UNL-8237", Type::SUPERGAME_POCAHONTAS2 },
@ -1472,6 +1476,13 @@ namespace Nes
break; break;
} }
if (prg > SIZE_512K)
{
name = "UNL-MMC3BIGPRGROM";
id = Type::UNL_MMC3BIGPRGROM;
break;
}
if (nmt == Type::NMT_FOURSCREEN) if (nmt == Type::NMT_FOURSCREEN)
{ {
if (prg == SIZE_64K && (chr == SIZE_32K || chr == SIZE_64K) && !wram && !useWramAuto) if (prg == SIZE_64K && (chr == SIZE_32K || chr == SIZE_64K) && !wram && !useWramAuto)
@ -1804,34 +1815,53 @@ namespace Nes
case 21: case 21:
if (submapper == 1) if (submapper == 2 || wram >= SIZE_8K) // VRC4c
{
Chips::Type& chip = chips.Add(L"Konami VRC IV");
chip.Pin(3) = L"PRG A7";
chip.Pin(4) = L"PRG A6";
name = "KONAMI VRC4";
id = Type::KONAMI_VRC4_2;
}
else // VRC4a - submapper 1
{ {
Chips::Type& chip = chips.Add(L"Konami VRC IV"); Chips::Type& chip = chips.Add(L"Konami VRC IV");
chip.Pin(3) = L"PRG A2"; chip.Pin(3) = L"PRG A2";
chip.Pin(4) = L"PRG A1"; chip.Pin(4) = L"PRG A1";
name = "KONAMI VRC4";
id = Type::KONAMI_VRC4_0; id = Type::KONAMI_VRC4_0;
} }
name = "KONAMI VRC4";
break;
case 25: case 25:
if (submapper == 2) if (submapper == 3 || wram >= SIZE_8K) // VRC2c, but emulated as VRC4
{ // The correct board is VRC2 but the functionality is implemented in the VRC4 code currently {
Chips::Type& chip = chips.Add(L"Konami VRC IV"); Chips::Type& chip = chips.Add(L"Konami VRC IV");
chip.Pin(3) = L"PRG A0"; chip.Pin(3) = L"PRG A0";
chip.Pin(4) = L"PRG A1"; chip.Pin(4) = L"PRG A1";
name = "KONAMI VRC2";
id = Type::KONAMI_VRC4_2; id = Type::KONAMI_VRC4_2;
name = "KONAMI VRC2";
break; break;
} }
else if (submapper == 2 || prg >= SIZE_256K) // VRC4d
if (!this->chips.Has(L"Konami VRC IV")) {
return false; Chips::Type& chip = chips.Add(L"Konami VRC IV");
chip.Pin(3) = L"PRG A2";
chip.Pin(4) = L"PRG A3";
id = Type::KONAMI_VRC4_0;
}
else // VRC4b - submapper 1
{
Chips::Type& chip = chips.Add(L"Konami VRC IV");
chip.Pin(3) = L"PRG A0";
chip.Pin(4) = L"PRG A1";
id = Type::KONAMI_VRC4_1;
}
name = "KONAMI VRC4"; name = "KONAMI VRC4";
id = Type::KONAMI_VRC4_2;
break; break;
case 22: case 22:
@ -1858,50 +1888,49 @@ namespace Nes
case 23: case 23:
if (submapper == 2) if (submapper == 1) // VRC4f - Unknown, but plausibly World Hero?
{ {
Chips::Type& chip = chips.Add(L"Konami VRC IV"); Chips::Type& chip = chips.Add(L"Konami VRC IV");
chip.Pin(3) = L"PRG A1";
chip.Pin(3) = L"PRG A3"; chip.Pin(4) = L"PRG A0";
chip.Pin(4) = L"PRG A2";
name = "KONAMI VRC4"; name = "KONAMI VRC4";
id = Type::KONAMI_VRC4_0; id = Type::KONAMI_VRC4_0;
} }
else if (submapper == 3) else if (submapper == 2) // VRC4e
{
name = "KONAMI VRC2";
id = Type::KONAMI_VRC2;
break;
}
if (prg >= SIZE_512K)
{
if (!this->chips.Has(L"Konami VRC IV"))
{ {
Chips::Type& chip = chips.Add(L"Konami VRC IV"); Chips::Type& chip = chips.Add(L"Konami VRC IV");
chip.Pin(3) = L"PRG A3"; chip.Pin(3) = L"PRG A3";
chip.Pin(4) = L"PRG A2"; chip.Pin(4) = L"PRG A2";
name = "KONAMI VRC4";
id = Type::KONAMI_VRC4_1;
} }
else if (prg >= SIZE_512K)
{
Chips::Type& chip = chips.Add(L"Konami VRC IV");
chip.Pin(3) = L"PRG A3";
chip.Pin(4) = L"PRG A2";
name = "BMC VRC4"; name = "BMC VRC4";
id = Type::BMC_VRC4; id = Type::BMC_VRC4;
} }
else if (this->chips.Has(L"Konami VRC II")) else // VRC2b - submapper 3
{ {
Chips::Type& chip = chips.Add(L"Konami VRC II");
chip.Pin(3) = L"PRG A1";
chip.Pin(4) = L"PRG A0";
chip.Pin(21) = L"CHR A10";
chip.Pin(22) = L"CHR A16";
chip.Pin(23) = L"CHR A11";
chip.Pin(24) = L"CHR A13";
chip.Pin(25) = L"CHR A14";
chip.Pin(26) = L"CHR A12";
chip.Pin(27) = L"CHR A15";
chip.Pin(28) = (chr >= SIZE_256K ? L"CHR A17" : L"NC");
name = "KONAMI VRC2"; name = "KONAMI VRC2";
id = Type::KONAMI_VRC2; id = Type::KONAMI_VRC2;
} }
else if (this->chips.Has(L"Konami VRC IV"))
{
name = "KONAMI VRC4";
id = Type::KONAMI_VRC4_2;
}
else
{
return false;
}
break; break;
case 24: case 24:
@ -2344,13 +2373,6 @@ namespace Nes
case 78: case 78:
if (submapper == 1)
{
name = "JALECO JF-16";
id = Type::JALECO_JF16;
break;
}
if (submapper == 3) if (submapper == 3)
{ {
name = "IREM-HOLYDIVER"; name = "IREM-HOLYDIVER";
@ -2358,6 +2380,7 @@ namespace Nes
break; break;
} }
// Default to submapper 1
name = "JALECO JF-16"; name = "JALECO JF-16";
id = Type::JALECO_JF16; id = Type::JALECO_JF16;
break; break;
@ -3385,6 +3408,12 @@ namespace Nes
id = Type::BMC_110IN1; id = Type::BMC_110IN1;
break; break;
case 258:
name = "UNL-158B";
id = Type::UNL_158B;
break;
case 262: case 262:
name = "UNL-SHERO"; name = "UNL-SHERO";
@ -3494,6 +3523,12 @@ namespace Nes
id = Type::BMC_SUPER_40IN1; id = Type::BMC_SUPER_40IN1;
break; break;
case 400:
name = "UNL-RET-X7-GBL";
id = Type::UNL_RETX7GBL;
break;
case 521: case 521:
name = "DREAMTECH01"; name = "DREAMTECH01";
@ -3887,14 +3922,17 @@ namespace Nes
case Type::TXC_MXMDHTWO : return new Txc::Mxmdhtwo(c); case Type::TXC_MXMDHTWO : return new Txc::Mxmdhtwo(c);
case Type::TXC_POLICEMAN : return new Txc::Policeman(c); case Type::TXC_POLICEMAN : return new Txc::Policeman(c);
case Type::TXC_TW : return new Txc::Tw(c); case Type::TXC_TW : return new Txc::Tw(c);
case Type::UNL_158B : return new Unlicensed::Gd98158b(c);
case Type::UNL_A9746 : return new Unlicensed::A9746(c); case Type::UNL_A9746 : return new Unlicensed::A9746(c);
case Type::UNL_CC21 : return new Unlicensed::Cc21(c); case Type::UNL_CC21 : return new Unlicensed::Cc21(c);
case Type::UNL_EDU2000 : return new Unlicensed::Edu2000(c); case Type::UNL_EDU2000 : return new Unlicensed::Edu2000(c);
case Type::UNL_FS304 : return new Waixing::Fs304(c); case Type::UNL_FS304 : return new Waixing::Fs304(c);
case Type::UNL_KINGOFFIGHTERS96 : return new Unlicensed::KingOfFighters96(c); case Type::UNL_KINGOFFIGHTERS96 : return new Unlicensed::KingOfFighters96(c);
case Type::UNL_KINGOFFIGHTERS97 : return new Unlicensed::KingOfFighters97(c); case Type::UNL_KINGOFFIGHTERS97 : return new Unlicensed::KingOfFighters97(c);
case Type::UNL_MMC3BIGPRGROM : return new Unlicensed::Mmc3BigPrgRom(c);
case Type::UNL_MORTALKOMBAT2 : return new Unlicensed::MortalKombat2(c); case Type::UNL_MORTALKOMBAT2 : return new Unlicensed::MortalKombat2(c);
case Type::UNL_N625092 : return new Unlicensed::N625092(c); case Type::UNL_N625092 : return new Unlicensed::N625092(c);
case Type::UNL_RETX7GBL : return new Unlicensed::RetX7Gbl(c);
case Type::UNL_SUPERFIGHTER3 : return new Unlicensed::SuperFighter3(c); case Type::UNL_SUPERFIGHTER3 : return new Unlicensed::SuperFighter3(c);
case Type::UNL_SHERO : return new Sachen::StreetHeroes(c); case Type::UNL_SHERO : return new Sachen::StreetHeroes(c);
case Type::UNL_TF1201 : return new Unlicensed::Tf1201(c); case Type::UNL_TF1201 : return new Unlicensed::Tf1201(c);

View File

@ -540,6 +540,7 @@ namespace Nes
TXC_POLICEMAN = MakeId< 36, 512, 128, 0, 0, CRM_0, NMT_X, 0 >::ID, TXC_POLICEMAN = MakeId< 36, 512, 128, 0, 0, CRM_0, NMT_X, 0 >::ID,
TXC_TW = MakeId< 189, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, TXC_TW = MakeId< 189, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID,
// Unlicensed // Unlicensed
UNL_158B = MakeId< 258, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID,
UNL_A9746 = MakeId< 219, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID, 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_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_EDU2000 = MakeId< 329, 1024, 0, 0, 32, CRM_8, NMT_Z, 0 >::ID,
@ -548,6 +549,7 @@ namespace Nes
UNL_KINGOFFIGHTERS97 = MakeId< 263, 256, 256, 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, UNL_MORTALKOMBAT2 = MakeId< 91, 256, 512, 0, 0, CRM_0, NMT_X, 0 >::ID,
UNL_N625092 = MakeId< 221, 1024, 8, 0, 0, CRM_0, NMT_V, 0 >::ID, UNL_N625092 = MakeId< 221, 1024, 8, 0, 0, CRM_0, NMT_V, 0 >::ID,
UNL_RETX7GBL = MakeId< 400, 2048, 0, 0, 0, CRM_32, NMT_X, 0 >::ID,
UNL_SUPERFIGHTER3 = MakeId< 197, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID, UNL_SUPERFIGHTER3 = MakeId< 197, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID,
UNL_SHERO = MakeId< 262, 512, 512, 0, 0, CRM_8, NMT_4, 0 >::ID, UNL_SHERO = MakeId< 262, 512, 512, 0, 0, CRM_8, NMT_4, 0 >::ID,
UNL_TF1201 = MakeId< 298, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID, UNL_TF1201 = MakeId< 298, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID,
@ -562,6 +564,7 @@ namespace Nes
UNL_TRXROM = MakeId< 4, 512, 256, 8, 0, CRM_0, NMT_4, 0 >::ID, UNL_TRXROM = MakeId< 4, 512, 256, 8, 0, CRM_0, NMT_4, 0 >::ID,
UNL_XZY = MakeId< 176, 1024, 256, 8, 0, CRM_0, NMT_X, 0 >::ID, UNL_XZY = MakeId< 176, 1024, 256, 8, 0, CRM_0, NMT_X, 0 >::ID,
UNL_MMC3BIGCHRRAM = MakeId< 4, 512, 0, 0, 0, CRM_32, NMT_X, 0 >::ID, UNL_MMC3BIGCHRRAM = MakeId< 4, 512, 0, 0, 0, CRM_32, NMT_X, 0 >::ID,
UNL_MMC3BIGPRGROM = MakeId< 4, 1024, 0, 8, 0, CRM_8, NMT_X, 0 >::ID,
// Waixing // Waixing
WAIXING_PS2_0 = MakeId< 15, 1024, 0, 0, 0, CRM_8, NMT_V, 0 >::ID, WAIXING_PS2_0 = MakeId< 15, 1024, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
WAIXING_PS2_1 = MakeId< 15, 1024, 0, 8, 0, CRM_8, NMT_V, 0 >::ID, WAIXING_PS2_1 = MakeId< 15, 1024, 0, 8, 0, CRM_8, NMT_V, 0 >::ID,

View File

@ -162,8 +162,6 @@ namespace Nes
byte chr[8]; byte chr[8];
} banks; } banks;
private:
Irq<> irq; Irq<> irq;
}; };
} }

View File

@ -0,0 +1,129 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2022 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 "NstBoardUnl158b.hpp"
/* References:
https://github.com/SourMesen/Mesen/blob/master/Core/Unl158B.h
https://github.com/TASVideos/fceux/blob/master/src/boards/158B.cpp
*/
namespace Nes
{
namespace Core
{
namespace Boards
{
namespace Unlicensed
{
Gd98158b::Gd98158b(const Context& c)
: Mmc3(c) {}
void Gd98158b::SubReset(const bool hard)
{
lut[0] = lut[1] = lut[2] = lut[7] = 0x00;
lut[3] = 0x01;
lut[4] = 0x02;
lut[5] = 0x04;
lut[6] = 0x0F;
if (hard)
reg = 0;
banks.prg[0] = 0x00;
banks.prg[1] = 0x01;
banks.prg[2] = 0x3E;
banks.prg[3] = 0x3F;
Mmc3::SubReset( hard );
Map( 0x5000U, 0x5FFFU, &Gd98158b::Peek_5000 );
Map( 0x5000U, 0x5FFFU, &Gd98158b::Poke_5000 );
}
void Gd98158b::SubLoad(State::Loader& state,const dword baseChunk)
{
if (baseChunk == AsciiId<'1','5','8'>::V)
{
while (const dword chunk = state.Begin())
{
if (chunk == AsciiId<'R','E','G'>::V)
reg = state.Read8();
state.End();
}
}
else
{
Mmc3::SubLoad( state, baseChunk );
}
}
void Gd98158b::SubSave(State::Saver& state) const
{
Mmc3::SubSave( state );
state.Begin( AsciiId<'1','5','8'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End();
}
void NST_FASTCALL Gd98158b::UpdatePrg(uint address, uint data)
{
if (reg & 0x80)
{
const uint bank = reg & 0x7;
if (reg & 0x20)
{
prg.SwapBank<SIZE_32K>( 0x0000, bank >> 1 );
}
else
{
prg.SwapBank<SIZE_16K>( 0x0000, bank );
prg.SwapBank<SIZE_16K>( 0x4000, bank );
}
}
else
{
prg.SwapBank<SIZE_8K>( (address & 0x6000), data & 0xF );
}
}
NES_PEEK_A(Gd98158b,5000)
{
// Fake Open Bus read by always using 0x50
return 0x50 | lut[address & 0x7];
}
NES_POKE_AD(Gd98158b,5000)
{
if ((address & 0x7) == 0)
{
reg = data;
Mmc3::UpdatePrg();
}
}
}
}
}
}

View File

@ -0,0 +1,67 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2022 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_UNL_158B_H
#define NST_BOARD_UNL_158B_H
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
#include "NstBoardMmc3.hpp"
namespace Nes
{
namespace Core
{
namespace Boards
{
namespace Unlicensed
{
class Gd98158b : public Mmc3
{
public:
explicit Gd98158b(const Context&);
private:
void SubReset(bool);
void SubLoad(State::Loader&,dword);
void SubSave(State::Saver&) const;
void NST_FASTCALL UpdatePrg(uint, uint);
NES_DECL_PEEK( 5000 );
NES_DECL_POKE( 5000 );
byte lut[8];
uint reg;
};
}
}
}
}
#endif

View File

@ -0,0 +1,159 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
// Copyright (C) 2020-2022 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
//
////////////////////////////////////////////////////////////////////////////////////////
/* Note: At the time this was written, MMC3 boards with larger than 512K PRG
are fantasy hardware. This may change in the future if it is implemented in
a product along the lines of the PowerPak or Everdrive.
*/
#include "NstBoard.hpp"
#include "NstBoardMmc3.hpp"
#include "NstBoardUnlMmc3BigPrgRom.hpp"
#include "../NstFile.hpp"
namespace Nes
{
namespace Core
{
namespace Boards
{
namespace Unlicensed
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
void Mmc3BigPrgRom::SubReset(const bool hard)
{
Mmc3::SubReset( hard );
for (uint i=0x0000; i < 0x2000; i += 0x2)
{
Map( 0x8001 + i, &Mmc3BigPrgRom::Poke_8001 );
}
}
void Mmc3BigPrgRom::SubLoad(State::Loader& state,const dword baseChunk)
{
NST_VERIFY( baseChunk == (AsciiId<'M','M','3'>::V) );
if (baseChunk == AsciiId<'M','M','3'>::V)
{
while (const dword chunk = state.Begin())
{
switch (chunk)
{
case AsciiId<'R','E','G'>::V:
{
State::Loader::Data<12> data( state );
regs.ctrl0 = data[0];
regs.ctrl1 = data[1];
banks.prg[0] = data[2] & 0x7FU;
banks.prg[1] = data[3] & 0x7FU;
banks.chr[0] = (data[6] & 0x7FU) << 1;
banks.chr[1] = banks.chr[0] | 0x01U;
banks.chr[2] = (data[7] & 0x7FU) << 1;
banks.chr[3] = banks.chr[2] | 0x01U;
banks.chr[4] = data[8];
banks.chr[5] = data[9];
banks.chr[6] = data[10];
banks.chr[7] = data[11];
break;
}
case AsciiId<'I','R','Q'>::V:
irq.unit.LoadState( state );
break;
}
state.End();
}
}
}
void Mmc3BigPrgRom::SubSave(State::Saver& state) const
{
state.Begin( AsciiId<'M','M','3'>::V );
const byte data[12] =
{
regs.ctrl0,
regs.ctrl1,
banks.prg[0],
banks.prg[1],
0x7E,
0x7F,
banks.chr[0] >> 1,
banks.chr[2] >> 1,
banks.chr[4],
banks.chr[5],
banks.chr[6],
banks.chr[7]
};
state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End();
irq.unit.SaveState( state, AsciiId<'I','R','Q'>::V );
state.End();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
NES_POKE_D(Mmc3BigPrgRom,8001)
{
uint address = regs.ctrl0 & 0x7;
if (address < 6)
{
ppu.Update();
uint base = regs.ctrl0 << 5 & 0x1000;
if (address < 2)
{
address <<= 1;
base |= address << 10;
UpdateChr( base | 0x0000, (banks.chr[address+0] = data & 0xFE) );
UpdateChr( base | 0x0400, (banks.chr[address+1] = data | 0x01) );
}
else
{
UpdateChr( (base ^ 0x1000) | (address-2) << 10, (banks.chr[address+2] = data) );
}
}
else
{
UpdatePrg( (address == 6) ? (regs.ctrl0 << 8 & 0x4000) : 0x2000, (banks.prg[address-6] = data & 0x7F) );
}
}
}
}
}
}

View File

@ -0,0 +1,60 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
// Copyright (C) 2020-2022 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_UNL_MMC3BIGPRGROM_H
#define NST_BOARD_UNL_MMC3BIGPRGROM_H
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
namespace Nes
{
namespace Core
{
namespace Boards
{
namespace Unlicensed
{
class NST_NO_VTABLE Mmc3BigPrgRom : public Mmc3
{
public:
explicit Mmc3BigPrgRom(const Context& c)
: Mmc3(c) {}
private:
void SubReset(bool);
void SubSave(State::Saver&) const;
void SubLoad(State::Loader&,dword);
NES_DECL_POKE( 8001 );
};
}
}
}
}
#endif

View File

@ -0,0 +1,119 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2022 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
//
////////////////////////////////////////////////////////////////////////////////////////
/* References:
https://github.com/NovaSquirrel/Mesen-X/blob/master/Core/Mapper400.h
*/
#include "NstBoard.hpp"
#include "NstBoardUnlRetX7Gbl.hpp"
namespace Nes
{
namespace Core
{
namespace Boards
{
namespace Unlicensed
{
void RetX7Gbl::SubReset(bool)
{
Map( 0x7800U, 0x7FFFU, &RetX7Gbl::Poke_7800 );
Map( 0x8000U, 0xBFFFU, &RetX7Gbl::Poke_8000 );
Map( 0xC000U, 0xFFFFU, &RetX7Gbl::Poke_C000 );
regs[0] = 0x80;
regs[1] = 0x00;
UpdatePrg();
}
void RetX7Gbl::SubLoad(State::Loader& state,const dword baseChunk)
{
if (baseChunk == AsciiId<'R','X','G'>::V)
{
while (const dword chunk = state.Begin())
{
if (chunk == AsciiId<'R','E','G'>::V)
{
State::Loader::Data<3> data( state );
regs[0] = data[0];
regs[1] = data[1];
led = data[2];
}
state.End();
}
}
UpdatePrg();
}
void RetX7Gbl::SubSave(State::Saver& state) const
{
state.Begin( AsciiId<'R','X','G'>::V );
const byte data[3] =
{
regs[0], regs[1], led
};
state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End();
state.End();
}
void RetX7Gbl::UpdatePrg()
{
prg.SwapBank<SIZE_16K,0x0000>( (regs[0] & 0x78) | (regs[1] & 0x7) );
prg.SwapBank<SIZE_16K,0x4000>( (regs[0] & 0x78) | 0x7 );
if (regs[0] != 0x80)
{
ppu.SetMirroring( regs[0] & 0x20 ? Ppu::NMT_H : Ppu::NMT_V );
}
}
NES_POKE_D(RetX7Gbl,7800)
{
regs[0] = data;
UpdatePrg();
}
NES_POKE_D(RetX7Gbl,8000)
{
led = data;
}
NES_POKE_D(RetX7Gbl,C000)
{
regs[1] = data;
UpdatePrg();
chr.SwapBank<SIZE_8K,0x0000>( (data >> 5) & 0x3 );
}
}
}
}
}

View File

@ -0,0 +1,67 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2022 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_UNL_RETX7GBL_H
#define NST_BOARD_UNL_RETX7GBL_H
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
namespace Nes
{
namespace Core
{
namespace Boards
{
namespace Unlicensed
{
class RetX7Gbl : public Board
{
public:
explicit RetX7Gbl(const Context& c)
: Board(c) {}
private:
void SubReset(bool);
void SubLoad(State::Loader&,dword);
void SubSave(State::Saver&) const;
void UpdatePrg();
NES_DECL_POKE( 7800 );
NES_DECL_POKE( 8000 );
NES_DECL_POKE( C000 );
uint regs[2];
uint led;
};
}
}
}
}
#endif