Merge improvements from upstream core

This commit is contained in:
rdanbrook 2021-02-15 08:01:46 -05:00
parent f631ba0d16
commit da5ac83f17
13 changed files with 265 additions and 74 deletions

View file

@ -13,11 +13,15 @@ Core:
- Use Nestopia core from jgemu
Fixes:
- Timing and other accuracy fixes
- Timing and other accuracy fixes for CPU/APU
- Revert changes that caused regressions
- Fix Camerica mapper for Dooly Bravo Land
- Improve MMC5 emulation for Sim City
- Fix 8K PRG NROM games such as Galaxian
- Full implementation of mapper 156
- Fix SOROM saving/loading
- Fix FDS IRQ behaviour
- Improve RAMBO-1 timing
----------------------------------------------------------------
1.50

View file

@ -373,7 +373,7 @@ namespace Nes
{
State::Loader::Data<4> data( state );
io.ctrl = data[0];
io.ctrl = adapter.ctrl = data[0];
io.port = data[1];
break;
}
@ -550,7 +550,13 @@ namespace Nes
NES_POKE_D(Fds,4023)
{
io.ctrl = data;
io.ctrl = adapter.ctrl = data;
if (!(io.ctrl & Io::CTRL0_DISK_ENABLED))
{
cpu.ClearIRQ();
adapter.DisableIRQ();
}
}
NES_POKE_D(Fds,4026)
@ -783,21 +789,25 @@ namespace Nes
#pragma optimize("", on)
#endif
void Fds::Unit::Timer::Advance(uint& timer)
bool Fds::Unit::Timer::Clock()
{
timer |= STATUS_PENDING_IRQ;
bool retval = false;
if (ctrl & CTRL_REPEAT)
count = latch;
else
ctrl &= ~uint(CTRL_ENABLED);
latch = 0; // Fixes Kaettekita Mario Bros - FHorse/dragon2snow
}
if (ctrl & CTRL_ENABLED)
{
if (count == 0)
{
retval = true;
count = latch;
NST_SINGLE_CALL bool Fds::Unit::Timer::Clock()
{
return !(ctrl & CTRL_ENABLED) || !count || --count;
if (!(ctrl & CTRL_REPEAT))
ctrl &= ~uint(CTRL_ENABLED);
}
else
count--;
}
return retval;
}
#ifdef NST_MSVC_OPTIMIZE
@ -1202,11 +1212,15 @@ namespace Nes
ibool Fds::Unit::Clock()
{
return
(
(timer.Clock() ? 0 : (timer.Advance(status), 1)) |
(drive.Clock() ? 0 : drive.Advance(status))
);
bool retval = false;
if (timer.Clock())
{
status |= STATUS_PENDING_IRQ;
retval = true;
}
return (retval | (drive.Clock() ? 0 : drive.Advance(status)));
}
#ifdef NST_MSVC_OPTIMIZE
@ -1216,6 +1230,12 @@ namespace Nes
Fds::Adapter::Adapter(Cpu& c,const Disks::Sides& s)
: Timer::M2<Unit>(c,s) {}
void Fds::Adapter::DisableIRQ()
{
unit.status &= ~uint(Unit::STATUS_PENDING_IRQ);
unit.timer.ctrl &= ~uint(Unit::Timer::CTRL_ENABLED);
}
void Fds::Adapter::Reset(Cpu& cpu,byte* const io,bool protect)
{
Timer::M2<Unit>::Reset( true, true );
@ -1379,12 +1399,17 @@ namespace Nes
{
Update();
if (!(ctrl & Io::CTRL0_DISK_ENABLED))
return;
unit.timer.ctrl = data;
unit.timer.count = unit.timer.latch;
unit.status &= Unit::STATUS_TRANSFERED;
if (!unit.status)
ClearIRQ();
if (data & Unit::Timer::CTRL_ENABLED)
return;
ClearIRQ();
}
NES_POKE_D(Fds::Adapter,4024)

View file

@ -340,7 +340,6 @@ namespace Nes
Timer();
void Reset();
void Advance(uint&);
NST_SINGLE_CALL bool Clock();
@ -435,6 +434,7 @@ namespace Nes
Adapter(Cpu&,const Disks::Sides&);
void DisableIRQ();
void Reset(Cpu&,byte*,bool=false);
void LoadState(State::Loader&,dword,Ppu&);
void SaveState(State::Saver&) const;
@ -447,6 +447,8 @@ namespace Nes
NST_SINGLE_CALL uint Activity() const;
using Timer::M2<Unit>::VSync;
byte ctrl;
};
struct Io

View file

@ -397,7 +397,16 @@ namespace Nes
{
wrk.Source().SetSecurity( true, board.GetWram() > 0 );
for (uint i=board.GetSavableWram(), n=board.GetWram(); i < n; ++i)
uint i = board.GetSavableWram();
uint n = board.GetWram();
if (board.GetMapper() == 1 && board.GetWram() == SIZE_16K)
{
i = 0;
n = SIZE_8K;
}
for (; i < n; ++i)
*wrk.Source().Mem(i) = (board.IsAutoWram() && i < SIZE_8K) ? (0x6000 + i) >> 8 : 0x00;
vram.Fill( 0x00 );

View file

@ -468,7 +468,7 @@ namespace Nes
// Nihon Bussan
NIHON_UNROM_M5 = MakeId< 180, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID,
// Open Corp
OPENCORP_DAOU306 = MakeId< 156, 256, 256, 8, 0, CRM_0, NMT_1, 0 >::ID,
OPENCORP_DAOU306 = MakeId< 156, 256, 512, 8, 0, CRM_0, NMT_1, 0 >::ID,
// RCM
RCM_GS2004 = MakeId< NMPR, 512, 0, 0, 0, CRM_8, NMT_X, 0 >::ID,
RCM_GS2013 = MakeId< NMPR, 512, 0, 0, 0, CRM_8, NMT_X, 1 >::ID,

View file

@ -153,7 +153,12 @@ namespace Nes
void Vrc2::SwapChr(uint address,uint subBank) const
{
ppu.Update();
chr.SwapBank<SIZE_1K>( address, (chr.GetBank<SIZE_1K>(address) & 0xF0U >> OFFSET) | ((subBank >> chrShift & 0xF) << OFFSET) );
chr.SwapBank<SIZE_1K>( address, chrShift ? OFFSET ?
(chr.GetBank<SIZE_1K>(address) & 0x07U) | ((subBank & 0xFU) << 3) :
(chr.GetBank<SIZE_1K>(address) & 0xF8U) | ((subBank >> 1) & 0x7U) :
(chr.GetBank<SIZE_1K>(address) & 0xF0U >> OFFSET) | ((subBank & 0xFU) << OFFSET)
);
}
NES_POKE_D(Vrc2,B000) { SwapChr<0>( 0x0000, data ); }

View file

@ -25,6 +25,7 @@
#include "../NstLog.hpp"
#include "NstBoard.hpp"
#include "NstBoardMmc1.hpp"
#include "../NstFile.hpp"
namespace Nes
{
@ -119,6 +120,20 @@ namespace Nes
#pragma optimize("", on)
#endif
void Mmc1::Save(File& file) const
{
uint offset = (board.GetWram() == SIZE_16K) ? SIZE_8K : 0; // SOROM
if (board.HasBattery() && board.GetSavableWram())
file.Save( File::BATTERY, wrk.Source().Mem(offset), board.GetSavableWram() );
}
void Mmc1::Load(File& file)
{
uint offset = (board.GetWram() == SIZE_16K) ? SIZE_8K : 0; // SOROM
if (board.HasBattery() && board.GetSavableWram())
file.Load( File::BATTERY, wrk.Source().Mem(offset), board.GetSavableWram() );
}
void Mmc1::UpdatePrg()
{
prg.SwapBanks<SIZE_16K,0x0000>

View file

@ -82,6 +82,9 @@ namespace Nes
private:
void Save(File&) const;
void Load(File&);
void ResetRegisters();
virtual void NST_FASTCALL UpdateRegisters(uint);

View file

@ -22,6 +22,8 @@
//
////////////////////////////////////////////////////////////////////////////////////////
// Reference: https://github.com/TASVideos/fceux/blob/master/src/boards/156.cpp
#include "NstBoard.hpp"
#include "NstBoardOpenCorp.hpp"
@ -37,17 +39,139 @@ namespace Nes
#pragma optimize("s", on)
#endif
void Daou306::RemapChr()
{
chr.SwapBank<SIZE_1K>( 0x0000, (chrHigh[0] << 8) | chrLow[0] );
chr.SwapBank<SIZE_1K>( 0x0400, (chrHigh[1] << 8) | chrLow[1] );
chr.SwapBank<SIZE_1K>( 0x0800, (chrHigh[2] << 8) | chrLow[2] );
chr.SwapBank<SIZE_1K>( 0x0C00, (chrHigh[3] << 8) | chrLow[3] );
chr.SwapBank<SIZE_1K>( 0x1000, (chrHigh[4] << 8) | chrLow[4] );
chr.SwapBank<SIZE_1K>( 0x1400, (chrHigh[5] << 8) | chrLow[5] );
chr.SwapBank<SIZE_1K>( 0x1800, (chrHigh[6] << 8) | chrLow[6] );
chr.SwapBank<SIZE_1K>( 0x1C00, (chrHigh[7] << 8) | chrLow[7] );
if (mirrorUsed) {
ppu.SetMirroring( mirror ^ 0x1 ? Ppu::NMT_V : Ppu::NMT_H );
}
else
{
ppu.SetMirroring( Ppu::NMT_0 );
}
}
void Daou306::SubReset(bool)
{
Map( 0xC000U, CHR_SWAP_1K_0 );
Map( 0xC001U, CHR_SWAP_1K_1 );
Map( 0xC002U, CHR_SWAP_1K_2 );
Map( 0xC003U, CHR_SWAP_1K_3 );
Map( 0xC008U, CHR_SWAP_1K_4 );
Map( 0xC009U, CHR_SWAP_1K_5 );
Map( 0xC00AU, CHR_SWAP_1K_6 );
Map( 0xC00BU, CHR_SWAP_1K_7 );
for (uint i = 0; i < 8; i++)
{
chrLow[i] = chrHigh[i] = 0;
}
Map( 0xC000U, 0xC00FU, &Daou306::Poke_C000 );
Map( 0xC010U, PRG_SWAP_16K_0 );
Map( 0xC014U, &Daou306::Poke_C014 );
}
NES_POKE_AD(Daou306,C000)
{
switch (address)
{
case 0xC000:
case 0xC001:
case 0xC002:
case 0xC003:
chrLow[address & 0x03] = data;
break;
case 0xC004:
case 0xC005:
case 0xC006:
case 0xC007:
chrHigh[address & 0x03] = data;
break;
case 0xC008:
case 0xC009:
case 0xC00A:
case 0xC00B:
chrLow[4 + (address & 0x03)] = data;
break;
case 0xC00C:
case 0xC00D:
case 0xC00E:
case 0xC00F:
chrHigh[4 + (address & 0x03)] = data;
break;
}
RemapChr();
}
NES_POKE_D(Daou306,C014)
{
mirror = data;
mirrorUsed = 1;
}
void Daou306::SubLoad(State::Loader& state,const dword baseChunk)
{
NST_VERIFY( baseChunk == (AsciiId<'O','P','C'>::V) );
if (baseChunk == AsciiId<'O','P','C'>::V)
{
state.Begin();
State::Loader::Data<18> data( state );
chrLow[0] = data[0];
chrLow[1] = data[1];
chrLow[2] = data[2];
chrLow[3] = data[3];
chrLow[4] = data[4];
chrLow[5] = data[5];
chrLow[6] = data[6];
chrLow[7] = data[7];
chrHigh[0] = data[8];
chrHigh[1] = data[9];
chrHigh[2] = data[10];
chrHigh[3] = data[11];
chrHigh[4] = data[12];
chrHigh[5] = data[13];
chrHigh[6] = data[14];
chrHigh[7] = data[15];
mirror = data[16];
mirrorUsed = data[17];
state.End();
RemapChr();
}
}
void Daou306::SubSave(State::Saver& state) const
{
state.Begin( AsciiId<'O','P','C'>::V );
const byte data[18] =
{
chrLow[0],
chrLow[1],
chrLow[2],
chrLow[3],
chrLow[4],
chrLow[5],
chrLow[6],
chrLow[7],
chrHigh[0],
chrHigh[1],
chrHigh[2],
chrHigh[3],
chrHigh[4],
chrHigh[5],
chrHigh[6],
chrHigh[7],
mirror,
mirrorUsed,
};
state.Begin( AsciiId<'C','H','R'>::V ).Write( data ).End();
state.End();
}
#ifdef NST_MSVC_OPTIMIZE

View file

@ -46,7 +46,18 @@ namespace Nes
private:
byte chrLow[8];
byte chrHigh[8];
byte mirror;
byte mirrorUsed;
void RemapChr();
void SubReset(bool);
void SubSave(State::Saver&) const;
void SubLoad(State::Loader&,dword);
NES_DECL_POKE( C000 );
NES_DECL_POKE( C014 );
};
}
}

View file

@ -322,7 +322,7 @@ namespace Nes
ctrl = data[0] >> 1 & 0x1F;
length = data[1] | (data[2] << 8 & 0xF00);
volume = levels[(ctrl & 0xF) ? (ctrl & 0xF) * 2 + 1 : 0];
dc = (status & 0x1) ? ~0UL : 0UL;
dc = (status & 0x1) ? ~dword(0) : dword(0);
UpdateSettings( fixed );
}

View file

@ -54,6 +54,7 @@ namespace Nes
if (hard)
{
count = 0;
cycles = 0;
reload = false;
latch = 0;
enabled = false;
@ -121,14 +122,16 @@ namespace Nes
case AsciiId<'I','R','Q'>::V:
{
State::Loader::Data<3> data( state );
State::Loader::Data<4> data( state );
irq.unit.enabled = data[0] & 0x1;
irq.unit.mode = data[0] & 0x2 ? 1 : 0;
irq.a12.Connect( data[0] & 0x2 );
irq.m2.Connect( data[0] & 0x2 );
irq.unit.reload = data[0] & 0x4;
irq.unit.latch = data[1];
irq.unit.count = data[2];
irq.unit.cycles = data[3];
break;
}
@ -164,13 +167,14 @@ namespace Nes
}
{
const byte data[3] =
const byte data[4] =
{
(irq.unit.enabled ? 0x1U : 0x0U) |
(irq.m2.Connected() ? 0x2U : 0x0U) |
(irq.unit.reload ? 0x4U : 0x0U),
irq.unit.latch,
irq.unit.count & 0xFF
irq.unit.count & 0xFF,
irq.unit.cycles,
};
state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End();
@ -185,47 +189,33 @@ namespace Nes
bool Rambo1::Irq::Unit::Clock()
{
/*if (!reload)
cycles++;
if (reload)
{
if (count)
{
return !--count && enabled;
}
else
{
count = latch;
return false;
}
reload = false;
count = latch | (latch ? 1 : 0);
if (mode)
count |= 2;
if (!latch && cycles > A12_FILTER)
count = 1;
cycles = 0;
}
else if (!count)
{
count = latch;
if (cycles > A12_FILTER)
cycles = 0;
}
else
{
reload = false;
count = latch + 1;
return false;
}*/
// From dragon2snow
if (reload) {
if (latch < 1) {
count = latch + 1;
}
else {
count = latch + 2;
}
reload = false;
count--;
}
else if (!count) {
count = latch + 1;
}
count--;
if (!count && enabled) {
/* wait one M2 cycle, then trigger IRQ */
return true;
}
return false;
return (!count && enabled);
}
void Rambo1::Irq::Update()
@ -320,6 +310,7 @@ namespace Nes
{
irq.Update();
irq.unit.latch = data;
irq.unit.mode = irq.m2.Connected();
}
NES_POKE_D(Rambo1,C001)

View file

@ -95,9 +95,11 @@ namespace Nes
bool Clock();
uint count;
uint cycles;
uint latch;
ibool reload;
ibool enabled;
ibool mode;
};
typedef Timer::A12<Unit&,A12_FILTER,IRQ_DELAY> A12;