Merge pull request #27 from rdanbrook/master

Update core to 1.51.0
This commit is contained in:
Autechre 2021-03-20 19:38:24 +01:00 committed by GitHub
commit aac15a622f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 1236 additions and 463 deletions

View File

@ -26916,4 +26916,99 @@
</board>
</cartridge>
</game>
<game>
<cartridge system="NES-NTSC" dump="ok" crc="FDC7C50B" sha1="5E8F67BEFB2B1BCBD0384E3144ACB2766FC3E443">
<board type="NES-ETROM" mapper="5">
<prg size="128k" />
<chr size="128k" />
<wram size="8k" />
<wram size="8k" battery="1" />
</board>
</cartridge>
</game>
<game>
<cartridge system="Famicom" dump="unknown" crc="084F61CD" sha1="44BC6C4E8B3F6C635281B4C05382E8F316D8269E">
<board type="NAMCOT-3301" mapper="0">
<prg size="8k" />
<chr size="8k" />
<pad h="0" v="1" />
</board>
</cartridge>
</game>
<game>
<cartridge system="Famicom" dump="unknown" crc="76A6A813" sha1="0FE9120FD5ADC2790B0B9E8FADD136F9C66A709F">
<board type="NAMCOT-3301" mapper="0">
<prg size="8k" />
<chr size="8k" />
<pad h="0" v="1" />
</board>
</cartridge>
</game>
<game>
<peripherals>
<device type="fourplayer" />
</peripherals>
<cartridge system="NES-NTSC" dump="ok" crc="1394DED0" sha1="B1C6A700A9F3B73666018E46515D376F06B8E9C2">
<board type="NES-UNROM" mapper="2">
<prg size="64k" />
</board>
</cartridge>
</game>
<game>
<peripherals>
<device type="fourplayer" />
</peripherals>
<cartridge system="NES-NTSC" dump="ok" crc="90D2E9F0" sha1="2801AADD9D0308CF2C9069A2BB76242ECA5B1501">
<board type="NES-NROM-256" mapper="0">
<prg size="32k" />
<chr size="8k" />
</board>
</cartridge>
</game>
<game>
<peripherals>
<device type="fourplayer" />
</peripherals>
<cartridge system="NES-NTSC" dump="ok" crc="2DA5ECE0" sha1="F3554E45D3261157653643C23A378C0295A5F893">
<board type="NES-NROM-256" mapper="0">
<prg size="32k" />
<chr size="8k" />
</board>
</cartridge>
</game>
<game>
<peripherals>
<device type="fourplayer" />
</peripherals>
<cartridge system="Famicom" dump="unknown" crc="69977C9E" sha1="C43D5F049F4F7862E6DECCA7500C0C23E349AF9F">
<board mapper="0">
<prg size="32k" />
<chr size="8k" />
<pad h="0" v="1" />
</board>
</cartridge>
</game>
<game>
<peripherals>
<device type="fourplayer" />
</peripherals>
<cartridge system="Famicom" dump="ok" crc="4FF17864" sha1="5119F1D6B67C5E44D63BA1E7080A6FE17623415C">
<board type="NES-SLROM" mapper="1">
<prg size="128k" />
<chr size="128k" />
<chip type="MMC1B2" />
</board>
</cartridge>
</game>
<!--game>
<peripherals>
<device type="zapper" />
</peripherals>
<cartridge system="Famicom" dump="ok" crc="A0FBF02E" sha1="38236FBD5B70F651674D52EE519AB4DBB11F7955">
<board type="UNL-TF1201" mapper="298">
<prg size="128k" />
<chr size="128k" />
</board>
</cartridge>
</game>-->
</database>

View File

@ -204,6 +204,7 @@ SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardMmc5.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardMmc6.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNamcot163.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNamcot175.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNamcot340.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNamcot34xx.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNanjing.cpp
SOURCES_CXX += $(CORE_DIR)/source/core/board/NstBoardNihon.cpp

View File

@ -22,7 +22,7 @@
#include "nstdatabase.hpp"
#define NST_VERSION "1.50-WIP"
#define NST_VERSION "1.51.0"
#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))

View File

@ -361,6 +361,11 @@ namespace Nes
return 0;
}
uint Apu::GetCtrl()
{
return ctrl;
}
Result Apu::SetSpeed(const uint speed)
{
if (settings.speed == speed)
@ -1670,7 +1675,7 @@ namespace Nes
step = 0x7;
status = STATUS_COUNTING;
waveLength = 0;
linearCtrl = 0;
//linearCtrl = 0;
linearCounter = 0;
lengthCounter.Reset();
@ -1870,7 +1875,6 @@ namespace Nes
amp = (sum * outputVolume + rate/2) / rate * 3;
}
}
// Disabling these blocks fixes scratchy audio in many games
/*else if (amp < Channel::OUTPUT_DECAY)
{
return 0;

View File

@ -50,7 +50,6 @@ namespace Nes
public:
explicit Apu(Cpu&);
void Reset(bool);
void PowerOff();
void ClearBuffers();
@ -65,6 +64,7 @@ namespace Nes
Result SetSpeed(uint);
Result SetVolume(uint,uint);
uint GetVolume(uint) const;
uint GetCtrl();
void Mute(bool);
void SetAutoTranspose(bool);
void SetGenie(bool);
@ -461,7 +461,7 @@ namespace Nes
enum
{
MIN_FRQ = 2 + 1,
STEP_CHECK = 0x00, // >= 0x1F is technically correct but will produce clicks/pops
STEP_CHECK = 0x1F,
REG0_LINEAR_COUNTER_LOAD = 0x7F,
REG0_LINEAR_COUNTER_START = 0x80,
REG2_WAVE_LENGTH_LOW = 0x00FF,

View File

@ -674,7 +674,7 @@ namespace Nes
if (setup.version)
{
setup.mapper |= uint(header[8]) << 8 & 0x100;
setup.mapper |= uint(header[8]) << 8 & 0x300;
setup.subMapper = header[8] >> 4;
}

View File

@ -247,7 +247,12 @@ namespace Nes
if (hard)
{
Poke(0x4017, 0x00);
cycles.count = cycles.clock[RESET_CYCLES-1];
cycles.count = cycles.clock[RESET_CYCLES] + cycles.clock[0];
}
else
{
Poke(0x4017, apu.GetCtrl());
cycles.count = cycles.clock[RESET_CYCLES] + cycles.clock[0];
}
}
@ -1723,18 +1728,42 @@ namespace Nes
return address;
}
NST_SINGLE_CALL uint Cpu::Shx(uint address)
NST_SINGLE_CALL void Cpu::Shx(uint address)
{
address = x & ((address >> 8) + 1);
uint newaddress = (address + y);
uint data = x & ((address >> 8) + 1);
Peek((address & 0xFF00) | (newaddress & 0x00FF)); // Dummy read
if ((address ^ newaddress) & 0x100)
{
address = (newaddress & (x << 8)) | (newaddress & 0x00FF);
}
else
{
address = newaddress;
}
NotifyOp("SHX",1UL << 15);
return address;
StoreMem(address, data);
}
NST_SINGLE_CALL uint Cpu::Shy(uint address)
NST_SINGLE_CALL void Cpu::Shy(uint address)
{
address = y & ((address >> 8) + 1);
uint newaddress = (address + x);
uint data = y & ((address >> 8) + 1);
Peek((address & 0xFF00) | (newaddress & 0x00FF)); // Dummy read
if ((address ^ newaddress) & 0x100)
{
address = (newaddress & (y << 8)) | (newaddress & 0x00FF);
}
else
{
address = newaddress;
}
NotifyOp("SHY",1UL << 16);
return address;
StoreMem(address, data);
}
NST_NO_INLINE uint Cpu::Slo(uint data)
@ -2095,6 +2124,15 @@ namespace Nes
Store##addr_( dst, instr_(dst) ); \
}
// Unofficial Opcodes SHX/SHY are edge cases
#define NES_I_W_U(instr_,addr_,hex_) \
\
void Cpu::op##hex_() \
{ \
const uint dst = addr_##_W(); \
instr_(dst); \
}
#define NES_IP_C_(instr_,ops_,ticks_,hex_) \
\
void Cpu::op##hex_() \
@ -2352,8 +2390,8 @@ namespace Nes
NES_I_W_A( Sha, AbsY, 0x9F )
NES_I_W_A( Sha, IndY, 0x93 )
NES_I_W_A( Shs, AbsY, 0x9B )
NES_I_W_A( Shx, AbsY, 0x9E )
NES_I_W_A( Shy, AbsX, 0x9C )
NES_I_W_U( Shx, Abs, 0x9E ) // Edge case: AbsY done internally
NES_I_W_U( Shy, Abs, 0x9C ) // Edge case: AbsX done internally
NES_IRW__( Slo, Zpg, 0x07 )
NES_IRW__( Slo, ZpgX, 0x17 )
NES_IRW__( Slo, Abs, 0x0F )

View File

@ -260,8 +260,8 @@ namespace Nes
NST_SINGLE_CALL void Lxa (uint);
NST_SINGLE_CALL void Sbx (uint);
NST_SINGLE_CALL uint Shs (uint);
NST_SINGLE_CALL uint Shx (uint);
NST_SINGLE_CALL uint Shy (uint);
NST_SINGLE_CALL void Shx (uint);
NST_SINGLE_CALL void Shy (uint);
NST_NO_INLINE void Anc (uint);
NST_NO_INLINE uint Dcp (uint);

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

@ -169,7 +169,7 @@ namespace Nes
{
static const byte powerUpPalette[] =
{
0x3F,0x01,0x00,0x01,0x00,0x02,0x02,0x0D,
0x09,0x01,0x00,0x01,0x00,0x02,0x02,0x0D,
0x08,0x10,0x08,0x24,0x00,0x00,0x04,0x2C,
0x09,0x01,0x34,0x03,0x00,0x04,0x00,0x14,
0x08,0x3A,0x00,0x02,0x00,0x20,0x2C,0x08
@ -240,8 +240,7 @@ namespace Nes
cycles.count = Cpu::CYCLE_MAX;
scanline = SCANLINE_VBLANK;
scanline_sleep = -1;
ssleep = -1;
scanline_sleep = 0;
io.address = 0;
io.pattern = 0;
@ -493,8 +492,6 @@ namespace Nes
Cycle frame;
scanline_sleep = -1;
switch (model)
{
case PPU_RP2C02:
@ -503,8 +500,6 @@ namespace Nes
default:
ssleep = PPU_RP2C02_VSLEEP - 2;
if (cycles.hClock == HCLOCK_DUMMY)
{
cycles.vClock = PPU_RP2C02_HVINT / PPU_RP2C02_CC - HCLOCK_DUMMY;
@ -521,8 +516,6 @@ namespace Nes
case PPU_RP2C07:
ssleep = PPU_RP2C07_VSLEEP - 2;
if (cycles.hClock == HCLOCK_DUMMY)
{
cycles.vClock = PPU_RP2C07_HVINT / PPU_RP2C07_CC - HCLOCK_DUMMY;
@ -539,8 +532,6 @@ namespace Nes
case PPU_DENDY:
ssleep = PPU_DENDY_VSLEEP - 2;
if (cycles.hClock == HCLOCK_DUMMY)
{
cycles.vClock = PPU_DENDY_HVINT / PPU_DENDY_CC - HCLOCK_DUMMY;
@ -698,6 +689,12 @@ namespace Nes
io.line.Toggle( io.address, GetCycles() );
}
NST_FORCE_INLINE void Ppu::UpdateScrollAddressLine()
{
if (io.line)
io.line.Toggle( scroll.address & 0x3FFF, cpu.GetCycles() );
}
NST_FORCE_INLINE void Ppu::UpdateVramAddress()
{
if ((scanline != SCANLINE_VBLANK ) && (regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED))
@ -824,7 +821,7 @@ namespace Nes
oam.mask = oam.show[pos];
if ((regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) && !(data & Regs::CTRL1_BG_SP_ENABLED))
UpdateAddressLine(scroll.address & 0x3fff);
UpdateScrollAddressLine();
}
io.latch = data;
@ -968,10 +965,7 @@ namespace Nes
{
scroll.latch = (scroll.latch & 0x7F00) | data;
scroll.address = scroll.latch;
if (!(regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED) ||
(scanline == SCANLINE_VBLANK)) {
UpdateAddressLine(scroll.address & 0x3fff);
}
UpdateScrollAddressLine();
}
}
}
@ -983,13 +977,11 @@ namespace Nes
uint address = scroll.address;
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);
}
else {
else
return;
}
io.latch = data;
@ -1027,10 +1019,9 @@ namespace Nes
address = scroll.address & 0x3FFF;
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);
}
io.latch = (address & 0x3F00) != 0x3F00 ? io.buffer : palette.ram[address & 0x1F] & Coloring();
io.buffer = (address >= 0x2000 ? nmt.FetchName( address ) : chr.FetchPattern( address ));
@ -1458,7 +1449,7 @@ namespace Nes
{
NST_VERIFY( cycles.count != cycles.hClock );
if (scanline_sleep >= 0)
if (scanline_sleep) // Extra lines between VBLANK and NMI in Dendy mode
{
switch (cycles.hClock)
{
@ -1807,15 +1798,15 @@ namespace Nes
case 338:
if (scanline_sleep++ != ssleep)
if (++scanline_sleep < PPU_DENDY_VSLEEP)
{
cycles.hClock = 0;
cycles.vClock += 341;
cycles.vClock += HCLOCK_DUMMY;
if (cycles.count <= 341)
if (cycles.count <= HCLOCK_DUMMY)
break;
cycles.count -= 341;
cycles.count -= HCLOCK_DUMMY;
goto HActiveSleep;
}
@ -1828,37 +1819,13 @@ namespace Nes
}
case HCLOCK_VBLANK_0:
VBlank0:
regs.status |= Regs::STATUS_VBLANKING;
cycles.hClock = HCLOCK_VBLANK_1;
if (cycles.count <= HCLOCK_VBLANK_1)
break;
goto VBlank0;
case HCLOCK_VBLANK_1:
VBlank1:
regs.status = (regs.status & 0xFF) | (regs.status >> 1 & Regs::STATUS_VBLANK);
oam.visible = oam.output;
cycles.hClock = HCLOCK_VBLANK_2;
if (cycles.count <= HCLOCK_VBLANK_2)
break;
goto VBlank1;
case HCLOCK_VBLANK_2:
VBlank2:
scanline_sleep = -1;
cycles.hClock = HCLOCK_DUMMY;
cycles.count = Cpu::CYCLE_MAX;
cycles.reset = 0;
if (regs.ctrl[0] & regs.status & Regs::CTRL0_NMI)
cpu.DoNMI( cpu.GetFrameCycles() );
return;
goto VBlank2;
}
}
else if (regs.ctrl[1] & Regs::CTRL1_BG_SP_ENABLED)
@ -2519,7 +2486,7 @@ namespace Nes
if (scanline++ != 239)
{
const uint line = (scanline != 0 || model != PPU_RP2C02 || !regs.frame ? 341 : 340);
const uint line = (scanline != 0 || model != PPU_RP2C02 || !regs.frame ? HCLOCK_DUMMY : (HCLOCK_DUMMY - 1));
cycles.hClock = 0;
cycles.vClock += line;
@ -2533,16 +2500,17 @@ namespace Nes
}
else
{
if (ssleep >= 0)
if (model == PPU_DENDY)
{
scanline_sleep = 0;
cycles.hClock = 0;
cycles.vClock += 341;
scanline_sleep = 1;
if (cycles.count <= 341)
cycles.hClock = 0;
cycles.vClock += HCLOCK_DUMMY;
if (cycles.count <= HCLOCK_DUMMY)
break;
cycles.count -= 341;
cycles.count -= HCLOCK_DUMMY;
goto HActiveSleep;
}
@ -2556,13 +2524,37 @@ namespace Nes
}
case HCLOCK_VBLANK_0:
goto VBlank0;
VBlank0:
regs.status |= Regs::STATUS_VBLANKING;
cycles.hClock = HCLOCK_VBLANK_1;
if (cycles.count <= HCLOCK_VBLANK_1)
break;
case HCLOCK_VBLANK_1:
goto VBlank1;
VBlank1:
regs.status = (regs.status & 0xFF) | (regs.status >> 1 & Regs::STATUS_VBLANK);
oam.visible = oam.output;
cycles.hClock = HCLOCK_VBLANK_2;
if (cycles.count <= HCLOCK_VBLANK_2)
break;
case HCLOCK_VBLANK_2:
goto VBlank2;
VBlank2:
scanline_sleep = 0;
cycles.hClock = HCLOCK_DUMMY;
cycles.count = Cpu::CYCLE_MAX;
cycles.reset = 0;
if (regs.ctrl[0] & regs.status & Regs::CTRL0_NMI)
cpu.DoNMI( cpu.GetFrameCycles() );
return;
case HCLOCK_BOOT:
goto Boot;
@ -3227,29 +3219,29 @@ namespace Nes
if (scanline == 0 && model == PPU_RP2C02)
output.burstPhase = (output.burstPhase + 1) % 3;
cycles.vClock += 341;
cycles.vClock += HCLOCK_DUMMY;
cycles.hClock = 0;
if (cycles.count <= 341)
if (cycles.count <= HCLOCK_DUMMY)
break;
cycles.count -= 341;
cycles.count -= HCLOCK_DUMMY;
goto HActiveOff;
}
else
{
if (ssleep >= 0)
else
{
if (model == PPU_DENDY)
{
scanline_sleep = 0;
scanline_sleep = 1;
cycles.vClock += 341;
cycles.vClock += HCLOCK_DUMMY;
cycles.hClock = 0;
if (cycles.count <= 341)
if (cycles.count <= HCLOCK_DUMMY)
break;
cycles.count -= 341;
cycles.count -= HCLOCK_DUMMY;
goto HActiveSleep;
}

View File

@ -139,7 +139,6 @@ namespace Nes
enum
{
HCLOCK_POSTRENDER = 340,
HCLOCK_DUMMY = 341,
HCLOCK_VBLANK_0 = 681,
HCLOCK_VBLANK_1 = 682,
@ -176,6 +175,7 @@ namespace Nes
NST_FORCE_INLINE uint Emphasis() const;
NST_FORCE_INLINE void UpdateAddressLine(uint);
NST_FORCE_INLINE void UpdateScrollAddressLine();
NST_FORCE_INLINE void UpdateVramAddress();
NST_FORCE_INLINE void OpenName();
@ -345,9 +345,6 @@ namespace Nes
typedef void (Ppu::*Phase)();
byte ram[0x100];
byte buffer[MAX_LINE_SPRITES * 4];
const byte* limit;
Output* visible;
Phase phase;
@ -361,6 +358,9 @@ namespace Nes
bool spriteZeroInLine;
bool spriteLimit;
byte ram[0x100];
byte buffer[MAX_LINE_SPRITES*4];
Output output[MAX_LINE_SPRITES];
};
@ -415,9 +415,12 @@ namespace Nes
Nmt nmt;
int scanline;
int scanline_sleep;
int ssleep;
bool overclocked;
public:
Output output;
private:
PpuModel model;
Hook hActiveHook;
Hook hBlankHook;
@ -432,7 +435,6 @@ namespace Nes
static const byte yuvMaps[4][0x40];
public:
Output output;
void Update()
{
@ -553,6 +555,7 @@ namespace Nes
{
overclocked = overclock2x;
}
};
}
}

View File

@ -22,12 +22,10 @@
//
////////////////////////////////////////////////////////////////////////////////////////
#ifdef __LIBRETRO__
#define NST_NO_SCALEX 1
#define NST_NO_HQ2X 1
#define NST_NO_2XSAI 1
#define NST_NO_XBR 1
#endif
#include <cstring>
#include <cmath>

View File

@ -216,6 +216,11 @@ namespace Nes
MAX_HUE = +45
};
/**
* Adds extra scanlines to fix lag
*/
Result EnableOverclocking(bool state) throw();
/**
* Allows the PPU to render more than eight sprites per line.
*
@ -223,11 +228,6 @@ namespace Nes
* @return result code
*/
Result EnableUnlimSprites(bool state) throw();
/**
* Adds extra scanlines to fix lag
*/
Result EnableOverclocking(bool state) throw();
/**
* Checks if the PPU sprite software extension is enabled.

View File

@ -97,13 +97,13 @@
#include "NstBoardWaixing.hpp"
#include "NstBoardWhirlwind.hpp"
#include "NstBoardBenshengBs5.hpp"
#include "NstBoardUnlN625092.hpp"
#include "NstBoardUnlA9746.hpp"
#include "NstBoardUnlCc21.hpp"
#include "NstBoardUnlEdu2000.hpp"
#include "NstBoardUnlKingOfFighters96.hpp"
#include "NstBoardUnlKingOfFighters97.hpp"
#include "NstBoardUnlMortalKombat2.hpp"
#include "NstBoardUnlN625092.hpp"
#include "NstBoardUnlSuperFighter3.hpp"
#include "NstBoardUnlTf1201.hpp"
#include "NstBoardUnlWorldHero.hpp"
@ -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 );
@ -815,7 +824,7 @@ namespace Nes
{ "CAMERICA-BF9097", Type::CAMERICA_BF9097 },
{ "CAMERICA-GAMEGENIE", Type::STD_NROM },
{ "COLORDREAMS-74*377", Type::DISCRETE_74_377 },
{ "DREAMTECH01", Type::DREAMTECH_01 },
{ "DREAMTECH01", Type::DREAMTECH01 },
{ "HVC-AMROM", Type::STD_AMROM },
{ "HVC-AN1ROM", Type::STD_AN1ROM },
{ "HVC-ANROM", Type::STD_ANROM },
@ -1096,8 +1105,11 @@ namespace Nes
{ "UNL-EDU2000", Type::UNL_EDU2000 },
{ "UNL-H2288", Type::KAY_H2288 },
{ "UNL-KOF97", Type::UNL_KINGOFFIGHTERS97 },
{ "UNL-KS7013B", Type::KAISER_KS7013B },
{ "UNL-KS7016", Type::KAISER_KS7016 },
{ "UNL-KS7031", Type::KAISER_KS7031 },
{ "UNL-KS7032", Type::KAISER_KS7032 },
{ "UNL-KS7037", Type::KAISER_KS7037 },
{ "UNL-N625092", Type::UNL_N625092 },
{ "UNL-SA-0036", Type::SACHEN_SA0036 },
{ "UNL-SA-0037", Type::SACHEN_SA0037 },
@ -1110,7 +1122,7 @@ namespace Nes
{ "UNL-SACHEN-8259B", Type::SACHEN_8259B },
{ "UNL-SACHEN-8259C", Type::SACHEN_8259C },
{ "UNL-SACHEN-8259D", Type::SACHEN_8259D },
{ "UNL-SHERO", Type::SACHEN_STREETHEROES },
{ "UNL-SHERO", Type::UNL_SHERO },
{ "UNL-SL1632", Type::REXSOFT_SL1632 },
{ "UNL-SMB2J", Type::BTL_SMB2_C },
{ "UNL-T-230", Type::BTL_T230 },
@ -1218,7 +1230,7 @@ namespace Nes
return true;
}
bool Board::Context::DetectBoard(const byte mapper,const byte submapper,const dword chrRam,const dword wram,bool wramAuto)
bool Board::Context::DetectBoard(const word mapper,const byte submapper,const dword chrRam,const dword wram,bool wramAuto)
{
Type::Id id;
@ -1241,7 +1253,12 @@ namespace Nes
{
case 0:
if ((prg < SIZE_32K && prg != SIZE_16K) || !chr || wram >= SIZE_8K || (nmt != Type::NMT_HORIZONTAL && nmt != Type::NMT_VERTICAL))
if (prg == SIZE_8K && chr == SIZE_8K)
{
name = "NAMCOT-3301";
id = Type::STD_NROM;
}
else if ((prg < SIZE_32K && prg != SIZE_16K) || !chr || wram >= SIZE_8K || (nmt != Type::NMT_HORIZONTAL && nmt != Type::NMT_VERTICAL))
{
name = "NROM (non-standard)";
id = Type::UNL_NROM;
@ -1921,8 +1938,16 @@ namespace Nes
case 27:
name = "UNL WORLDHERO";
id = Type::UNL_WORLDHERO;
if (prg >= SIZE_128K)
{
name = "UNL WORLDHERO";
id = Type::UNL_WORLDHERO;
}
else
{
name = "UNL-CC-21";
id = Type::UNL_CC21;
}
break;
case 28:
@ -2833,8 +2858,21 @@ namespace Nes
case 176:
name = "XIAO ZHUAN YUAN";
id = Type::UNL_XZY;
if (prg >= SIZE_2048K)
{
name = "BMC-SUPER24IN1SC03";
id = Type::BMC_SUPER_24IN1;
}
else if (prg > SIZE_128K)
{
name = "BMC-FK23C";
id = Type::BMC_FKC23C;
}
else
{
name = "XIAO ZHUAN YUAN";
id = Type::UNL_XZY;
}
break;
case 177:
@ -3170,11 +3208,16 @@ namespace Nes
name = "BMC SUPER 42-IN-1";
id = Type::BMC_SUPER_42IN1;
}
else
else if (prg == SIZE_2048K)
{
name = "BMC 76-IN-1";
id = Type::BMC_76IN1;
}
else
{
name = "BMC-GHOSTBUSTERS63IN1";
id = Type::BMC_CTC65;
}
break;
case 227:
@ -3334,6 +3377,127 @@ namespace Nes
id = Type::BMC_110IN1;
break;
case 262:
name = "UNL-SHERO";
id = Type::UNL_SHERO;
break;
case 263:
name = "UNL-KOF97";
id = Type::UNL_KINGOFFIGHTERS97;
break;
case 265:
name = "BMC-T-262";
id = Type::BMC_T262;
break;
case 283:
if (prg > SIZE_256K)
{
name = "BMC-GS-2013";
id = Type::RCM_GS2013;
}
else
{
name = "BMC-GS-2004";
id = Type::RCM_GS2004;
}
break;
case 285:
name = "BMC-A65AS";
id = Type::BMC_A65AS;
break;
case 286:
name = "BMC-BS-5";
id = Type::BENSHENG_BS5;
break;
case 298:
name = "UNL-TF1201";
id = Type::UNL_TF1201;
break;
case 300:
name = "BMC-190IN1";
id = Type::BMC_GOLDEN_190IN1;
break;
case 301:
name = "BMC-8157";
id = Type::BMC_8157;
break;
case 305:
name = "UNL-KS7031";
id = Type::KAISER_KS7031;
break;
case 306:
name = "UNL-KS7016";
id = Type::KAISER_KS7016;
break;
case 307:
name = "UNL-KS7037";
id = Type::KAISER_KS7037;
break;
case 312:
name = "UNL-KS7013B";
id = Type::KAISER_KS7013B;
break;
case 314:
name = "BMC-64IN1NOREPEAT";
id = Type::BMC_Y2K_64IN1;
break;
case 329:
name = "UNL-EDU2000";
id = Type::UNL_EDU2000;
break;
case 332:
name = "BMC-WS";
id = Type::BMC_SUPER_40IN1;
break;
case 521:
name = "DREAMTECH01";
id = Type::DREAMTECH01;
break;
case 529:
name = "UNL-T-230";
id = Type::BTL_T230;
break;
case 530:
name = "UNL-AX5705";
id = Type::BTL_AX5705;
break;
default:
return false;
@ -3537,7 +3701,7 @@ namespace Nes
case Type::CNE_DECATHLON : return new Cne::Decathlon(c);
case Type::CNE_PSB : return new Cne::Psb(c);
case Type::CONY_STD : return new Cony::Standard(c);
case Type::DREAMTECH_01 : return new DreamTech::D01(c);
case Type::DREAMTECH01 : return new DreamTech::D01(c);
case Type::FUTUREMEDIA_STD : return new FutureMedia::Standard(c);
case Type::FUJIYA_STD : return new Fujiya::Standard(c);
case Type::FUKUTAKE_SBX : return new Fukutake::Sbx(c);
@ -3602,9 +3766,12 @@ 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_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_KS7058 : return new Kaiser::Ks7058(c);
case Type::KASING_STD : return new Kasing::Standard(c);
case Type::KAY_H2288 : return new Kay::H2288(c);
@ -3631,8 +3798,8 @@ namespace Nes
case Type::NAMCOT_163_1 :
case Type::NAMCOT_163_S_0 :
case Type::NAMCOT_163_S_1 : return new Namcot::N163(c);
case Type::NAMCOT_340 :
case Type::NAMCOT_175 : return new Namcot::N175(c);
case Type::NAMCOT_340 : return new Namcot::N340(c);
case Type::NANJING_STD : return new Nanjing::Standard(c);
case Type::UNL_UXROM_M5 :
case Type::NIHON_UNROM_M5 : return new Nihon::UnRomM5(c);
@ -3662,7 +3829,6 @@ namespace Nes
case Type::SACHEN_SA72008 : return new Sachen::Sa72008(c);
case Type::SACHEN_74_374A : return new Sachen::S74x374a(c);
case Type::SACHEN_74_374B : return new Sachen::S74x374b(c);
case Type::SACHEN_STREETHEROES : return new Sachen::StreetHeroes(c);
case Type::SOMERITEAM_SL12 : return new SomeriTeam::Sl12(c);
case Type::SUBOR_TYPE0 : return new Subor::Type0(c);
case Type::SUBOR_TYPE1 : return new Subor::Type1(c);
@ -3707,6 +3873,7 @@ namespace Nes
case Type::UNL_MORTALKOMBAT2 : return new Unlicensed::MortalKombat2(c);
case Type::UNL_N625092 : return new Unlicensed::N625092(c);
case Type::UNL_SUPERFIGHTER3 : return new Unlicensed::SuperFighter3(c);
case Type::UNL_SHERO : return new Sachen::StreetHeroes(c);
case Type::UNL_TF1201 : return new Unlicensed::Tf1201(c);
case Type::UNL_WORLDHERO : return new Unlicensed::WorldHero(c);
case Type::UNL_XZY : return new Unlicensed::Xzy(c);

View File

@ -94,7 +94,7 @@ namespace Nes
CRM_32
};
template<byte MPR,word PROM,word CROM,byte NVWRAM,byte WRAM,Cram CRAM,NmtInit NMT,byte UNIQUE>
template<word MPR,word PROM,word CROM,byte NVWRAM,byte WRAM,Cram CRAM,NmtInit NMT,byte UNIQUE>
struct MakeId
{
NST_COMPILE_ASSERT
@ -258,7 +258,7 @@ namespace Nes
BANDAI_AEROBICSSTUDIO = MakeId< 3, 32, 32, 0, 0, CRM_0, NMT_X, 2 >::ID,
BANDAI_OEKAKIDS = MakeId< 96, 128, 0, 0, 0, CRM_32, NMT_1, 0 >::ID,
// Bensheng
BENSHENG_BS5 = MakeId< NMPR, 128, 64, 0, 0, CRM_0, NMT_V, 2 >::ID,
BENSHENG_BS5 = MakeId< 286, 128, 64, 0, 0, CRM_0, NMT_V, 2 >::ID,
// Bootleg multicarts
BMC_110IN1 = MakeId< 255, 2048, 1024, 0, 0, CRM_0, NMT_V, 0 >::ID,
BMC_150IN1 = MakeId< 202, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID,
@ -273,16 +273,16 @@ namespace Nes
BMC_64IN1 = MakeId< 204, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID,
BMC_72IN1 = MakeId< 225, 1024, 512, 0, 0, CRM_0, NMT_V, 0 >::ID,
BMC_76IN1 = MakeId< 226, 2048, 0, 0, 0, CRM_8, NMT_H, 0 >::ID,
BMC_8157 = MakeId< NMPR, 512, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_8157 = MakeId< 301, 512, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_9999999IN1 = MakeId< 213, 128, 64, 0, 0, CRM_0, NMT_X, 0 >::ID,
BMC_A65AS = MakeId< NMPR, 512, 0, 0, 0, CRM_8, NMT_V, 1 >::ID,
BMC_A65AS = MakeId< 285, 512, 0, 0, 0, CRM_8, NMT_V, 1 >::ID,
BMC_BALLGAMES_11IN1 = MakeId< 51, 512, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_CTC65 = MakeId< NMPR, 2048, 0, 0, 0, CRM_8, NMT_H, 0 >::ID,
BMC_CTC65 = MakeId< 226, 2048, 0, 0, 0, CRM_8, NMT_H, 1 >::ID,
BMC_DRAGONBOLLPARTY = MakeId< 83, 1024, 1024, 8, 0, CRM_0, NMT_V, 0 >::ID,
BMC_FAMILY_4646B = MakeId< 134, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID,
BMC_FKC23C = MakeId< NMPR, 1024, 1024, 0, 0, CRM_0, NMT_X, 0 >::ID,
BMC_FKC23C = MakeId< 176, 1024, 1024, 0, 0, CRM_0, NMT_X, 0 >::ID,
BMC_GAME_800IN1 = MakeId< 236, 512, 64, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_GOLDEN_190IN1 = MakeId< NMPR, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID,
BMC_GOLDEN_190IN1 = MakeId< 300, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID,
BMC_GOLDENGAME_150IN1 = MakeId< 235, 2048, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_GOLDENGAME_260IN1 = MakeId< 235, 4096, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_GKA = MakeId< 57, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID,
@ -294,9 +294,9 @@ namespace Nes
BMC_CH001 = MakeId< 63, 4096, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_POWERJOY_84IN1 = MakeId< 126, 2048, 1024, 0, 0, CRM_0, NMT_X, 0 >::ID,
BMC_RESETBASED_4IN1 = MakeId< 60, 64, 32, 0, 0, CRM_0, NMT_X, 0 >::ID,
BMC_SUPER_24IN1 = MakeId< NMPR, 4096, 2048, 8, 0, CRM_8, NMT_X, 0 >::ID,
BMC_SUPER_24IN1 = MakeId< 176, 4096, 2048, 0, 0, CRM_8, NMT_X, 0 >::ID,
BMC_SUPER_22GAMES = MakeId< 233, 1024, 0, 0, 0, CRM_8, NMT_Z, 0 >::ID,
BMC_SUPER_40IN1 = MakeId< NMPR, 128, 64, 0, 0, CRM_0, NMT_V, 1 >::ID,
BMC_SUPER_40IN1 = MakeId< 332, 128, 64, 0, 0, CRM_0, NMT_V, 1 >::ID,
BMC_SUPER_42IN1 = MakeId< 226, 1024, 0, 0, 0, CRM_8, NMT_H, 0 >::ID,
BMC_SUPER_700IN1 = MakeId< 62, 2048, 1024, 0, 0, CRM_0, NMT_V, 0 >::ID,
BMC_SUPERBIG_7IN1 = MakeId< 44, 1024, 1024, 0, 0, CRM_0, NMT_X, 0 >::ID,
@ -304,15 +304,15 @@ namespace Nes
BMC_SUPERHIK_4IN1 = MakeId< 49, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID,
BMC_SUPERHIK_300IN1 = MakeId< 212, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID,
BMC_SUPERVISION_16IN1 = MakeId< 53, 4096, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_T262 = MakeId< NMPR, 1024, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_T262 = MakeId< 265, 1024, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BMC_VRC4 = MakeId< 23, 512, 0, 8, 0, CRM_8, NMT_V, 0 >::ID,
BMC_VT5201 = MakeId< 60, 128, 64, 0, 0, CRM_0, NMT_V, 0 >::ID,
BMC_Y2K_64IN1 = MakeId< NMPR, 1024, 512, 0, 0, CRM_0, NMT_V, 0 >::ID,
BMC_Y2K_64IN1 = MakeId< 314, 1024, 512, 0, 0, CRM_0, NMT_V, 0 >::ID,
// Bootlegs
BTL_2708 = MakeId< 103, 128, 0, 0, 16, CRM_8, NMT_V, 0 >::ID,
BTL_6035052 = MakeId< 238, 512, 256, 0, 0, CRM_0, NMT_X, 0 >::ID,
BTL_AISENSHINICOL = MakeId< 42, 128, 0, 0, 0, CRM_8, NMT_X, 0 >::ID,
BTL_AX5705 = MakeId< NMPR, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID,
BTL_AX5705 = MakeId< 530, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID,
BTL_DRAGONNINJA = MakeId< 222, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID,
BTL_GENIUSMERIOBROS = MakeId< 55, 64, 8, 2, 0, CRM_0, NMT_X, 0 >::ID,
BTL_MARIOBABY = MakeId< 42, 128, 128, 0, 0, CRM_0, NMT_X, 0 >::ID,
@ -323,7 +323,7 @@ namespace Nes
BTL_SMB2_C = MakeId< 43, 128, 8, 0, 0, CRM_0, NMT_X, 0 >::ID,
BTL_SMB3 = MakeId< 106, 256, 128, 8, 0, CRM_0, NMT_H, 0 >::ID,
BTL_SUPERBROS11 = MakeId< 196, 512, 128, 0, 0, CRM_0, NMT_V, 0 >::ID,
BTL_T230 = MakeId< NMPR, 256, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BTL_T230 = MakeId< 529, 256, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
BTL_TOBIDASEDAISAKUSEN = MakeId< 120, 128, 8, 0, 0, CRM_0, NMT_X, 0 >::ID,
// Camerica
CAMERICA_BF9093 = MakeId< 71, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID,
@ -342,7 +342,7 @@ namespace Nes
// Cony
CONY_STD = MakeId< 83, 256, 512, 0, 0, CRM_0, NMT_V, 0 >::ID,
// Dreamtech
DREAMTECH_01 = MakeId< NMPR, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID,
DREAMTECH01 = MakeId< 521, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID,
// Fujiya
FUJIYA_STD = MakeId< 170, 32, 8, 0, 0, CRM_0, NMT_X, 0 >::ID,
// Fukutake
@ -418,9 +418,12 @@ 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_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< NMPR, 128, 0, 0, 16, CRM_8, 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_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,
@ -454,8 +457,7 @@ namespace Nes
NAMCOT_163_S_0 = MakeId< 19, 512, 256, 0, 0, CRM_0, NMT_X, 1 >::ID,
NAMCOT_163_S_1 = MakeId< 19, 512, 256, 8, 0, CRM_0, NMT_X, 1 >::ID,
NAMCOT_175 = MakeId< 210, 512, 128, 8, 0, CRM_0, NMT_V, 0 >::ID,
// FIXME: Setting NMT_4 is incorrect but makes things work
NAMCOT_340 = MakeId< 210, 256, 256, 0, 0, CRM_0, NMT_4, 0 >::ID,
NAMCOT_340 = MakeId< 210, 256, 256, 0, 0, CRM_0, NMT_X, 0 >::ID,
// Nitra
NITRA_TDA = MakeId< 250, 512, 256, 0, 0, CRM_0, NMT_V, 0 >::ID,
// NTDEC
@ -468,10 +470,10 @@ 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,
RCM_GS2004 = MakeId< 283, 256, 0, 0, 0, CRM_8, NMT_X, 0 >::ID,
RCM_GS2013 = MakeId< 283, 512, 0, 0, 0, CRM_8, NMT_X, 1 >::ID,
RCM_GS2015 = MakeId< 216, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID,
RCM_TETRISFAMILY = MakeId< 61, 512, 0, 0, 0, CRM_8, NMT_V, 0 >::ID,
// Rex Soft
@ -492,7 +494,6 @@ namespace Nes
SACHEN_SA72008 = MakeId< 133, 64, 32, 0, 0, CRM_0, NMT_X, 0 >::ID,
SACHEN_74_374A = MakeId< 243, 64, 128, 0, 0, CRM_0, NMT_V, 0 >::ID,
SACHEN_74_374B = MakeId< 150, 64, 128, 0, 0, CRM_0, NMT_X, 0 >::ID,
SACHEN_STREETHEROES = MakeId< NMPR, 512, 512, 0, 0, CRM_8, NMT_2, 0 >::ID,
// Someri Team
SOMERITEAM_SL12 = MakeId< 116, 256, 512, 0, 0, CRM_0, NMT_X, 0 >::ID,
// Subor
@ -526,7 +527,6 @@ namespace Nes
TENGEN_800004 = MakeId< 206, 128, 64, 0, 0, CRM_0, NMT_2, 1 >::ID,
TENGEN_800008 = MakeId< 3, 64, 64, 0, 0, CRM_0, NMT_X, 0 >::ID,
TENGEN_800030 = MakeId< 206, 128, 64, 0, 0, CRM_0, NMT_X, 1 >::ID,
//TENGEN_800032 = MakeId< 64, 128, 128, 0, 0, CRM_0, NMT_V, 0 >::ID,
TENGEN_800032 = MakeId< 64, 128, 256, 0, 0, CRM_0, NMT_V, 0 >::ID,
TENGEN_800037 = MakeId< 158, 128, 128, 0, 0, CRM_0, NMT_Z, 0 >::ID,
TENGEN_800042 = MakeId< 68, 128, 256, 0, 0, CRM_0, NMT_V, 1 >::ID,
@ -539,14 +539,15 @@ namespace Nes
TXC_TW = MakeId< 189, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID,
// Unlicensed
UNL_A9746 = MakeId< 219, 128, 256, 0, 0, CRM_0, NMT_X, 0 >::ID,
UNL_CC21 = MakeId< NMPR, 32, 16, 0, 0, CRM_0, NMT_Z, 0 >::ID,
UNL_EDU2000 = MakeId< NMPR, 1024, 0, 32, 0, CRM_8, 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_KINGOFFIGHTERS96 = MakeId< 187, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID,
UNL_KINGOFFIGHTERS97 = MakeId< NMPR, 512, 256, 0, 0, CRM_0, NMT_X, 1 >::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_N625092 = MakeId< 221, 1024, 8, 0, 0, CRM_0, NMT_V, 0 >::ID,
UNL_SUPERFIGHTER3 = MakeId< 197, 512, 512, 0, 0, CRM_0, NMT_X, 0 >::ID,
UNL_TF1201 = MakeId< NMPR, 256, 256, 0, 0, CRM_0, NMT_V, 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_WORLDHERO = MakeId< 27, 128, 512, 0, 0, CRM_0, NMT_X, 0 >::ID,
UNL_AXROM = MakeId< 7, 512, 8, 8, 0, CRM_0, NMT_Z, 0 >::ID,
UNL_BXROM = MakeId< 34, 4096, 8, 8, 0, CRM_8, NMT_X, 0 >::ID,
@ -653,7 +654,7 @@ namespace Nes
Context(Cpu*,Apu*,Ppu*,Ram&,Ram&,const Ram&,Type::Nmt,bool,bool,Chips&);
bool DetectBoard(wcstring,dword);
bool DetectBoard(byte,byte,dword,dword,bool);
bool DetectBoard(word,byte,dword,dword,bool);
cstring name;
Type type;

View File

@ -40,6 +40,7 @@ namespace Nes
void Bf9093::SubReset(bool)
{
Map( 0xC000U, 0xFFFFU, PRG_SWAP_16K_0 );
Map( 0x8000U, 0xBFFFU, &Bf9093::Poke_C000 );
}
void Bf9096::SubReset(bool)
@ -68,6 +69,11 @@ namespace Nes
#pragma optimize("", on)
#endif
NES_POKE_D(Bf9093,C000)
{
prg.SwapBank<SIZE_16K,0x0000>( data );
}
void Bf9096::SwapBasePrg(uint base)
{
prg.SwapBanks<SIZE_16K,0x0000>( base | (prg.GetBank<SIZE_16K,0x0000>() & 0x3), base | 0x3 );

View File

@ -47,6 +47,10 @@ namespace Nes
protected:
void SubReset(bool);
private:
NES_DECL_POKE( C000 );
};
class Bf9096 : public Board

View File

@ -3,6 +3,7 @@
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
// Copyright (C) 2021 Rupert Carmichael
//
// This file is part of Nestopia.
//
@ -38,27 +39,6 @@ namespace Nes
#pragma optimize("s", on)
#endif
void Ks7058::SubReset(bool)
{
for (uint i=0x000; i < 0x1000; i += 0x100)
{
Map( 0xF000+i, 0xF07F+i, CHR_SWAP_4K_0 );
Map( 0xF080+i, 0xF0FF+i, CHR_SWAP_4K_1 );
}
}
void Ks7022::SubReset(const bool hard)
{
reg = 0;
if (hard)
prg.SwapBanks<SIZE_16K,0x0000>( 0, 0 );
Map( 0x8000, &Ks7022::Poke_8000 );
Map( 0xA000, &Ks7022::Poke_A000 );
Map( 0xFFFC, &Ks7022::Peek_FFFC );
}
Ks202::Ks202(const Context& c)
: Board(c), irq(*c.cpu) {}
@ -89,6 +69,36 @@ namespace Nes
irq.Reset( hard, hard ? false : irq.Connected() );
}
void Ks7013b::SubReset(const bool hard)
{
prg.SwapBank<SIZE_16K>( 0x4000, 0x7 );
Map( 0x6000U, 0x7FFFU, &Ks7013b::Poke_6000 );
Map( 0x8000U, 0xFFFFU, &Ks7013b::Poke_8000 );
}
void Ks7016::SubReset(const bool hard)
{
reg = 8;
prg.SwapBank<SIZE_32K>( 0x0000, 0x3 );
Map( 0x6000U, 0x7FFFU, &Ks7016::Peek_6000 );
Map( 0x8000U, 0xFFFFU, &Ks7016::Poke_8000 );
}
void Ks7022::SubReset(const bool hard)
{
reg = 0;
if (hard)
prg.SwapBanks<SIZE_16K,0x0000>( 0, 0 );
Map( 0x8000, &Ks7022::Poke_8000 );
Map( 0xA000, &Ks7022::Poke_A000 );
Map( 0xFFFC, &Ks7022::Peek_FFFC );
}
void Ks7031::SubReset(const bool hard)
{
Map( 0x6000U, 0xFFFEU, &Ks7031::Peek_6000 );
@ -106,6 +116,62 @@ namespace Nes
Map( 0x6000U, 0x7FFFU, &Ks7032::Peek_6000 );
}
void Ks7037::SubReset(const bool hard)
{
if (hard)
{
regNum = 0;
for (uint i = 0; i < 8; ++i)
regs[i] = 0;
}
Map( 0x6000U, 0x6FFFU, &Ks7037::Peek_6000 );
Map( 0x6000U, 0x6FFFU, &Ks7037::Poke_6000 );
Map( 0x7000U, 0x7FFFU, &Ks7037::Peek_7000 );
Map( 0x8000U, 0x9FFFU, &Ks7037::Peek_8000 );
for (uint i = 0x0000; i < 0x2000; i += 0x2)
{
Map( 0x8000 + i, &Ks7037::Poke_8000 );
Map( 0x8001 + i, &Ks7037::Poke_8001 );
}
Map( 0xA000U, 0xAFFFU, &Ks7037::Peek_A000 );
Map( 0xB000U, 0xBFFFU, &Ks7037::Peek_B000 );
Map( 0xB000U, 0xBFFFU, &Ks7037::Poke_B000 );
Map( 0xC000U, 0xDFFFU, &Ks7037::Peek_C000 );
Map( 0xE000U, 0xEFFFU, &Ks7037::Peek_E000 );
}
void Ks7058::SubReset(bool)
{
for (uint i=0x000; i < 0x1000; i += 0x100)
{
Map( 0xF000+i, 0xF07F+i, CHR_SWAP_4K_0 );
Map( 0xF080+i, 0xF0FF+i, CHR_SWAP_4K_1 );
}
}
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) );
@ -178,9 +244,32 @@ namespace Nes
}
}
void Ks7022::SubSave(State::Saver& state) const
void Ks7037::SubLoad(State::Loader& state,const dword baseChunk)
{
state.Begin( AsciiId<'K','7','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End();
NST_VERIFY( (baseChunk == AsciiId<'K','7','7'>::V) );
if (baseChunk == AsciiId<'K','7','7'>::V)
{
while (const dword chunk = state.Begin())
{
if (chunk == AsciiId<'R','E','G'>::V)
{
State::Loader::Data<9> 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];
regNum = data[8];
}
state.End();
}
}
}
void Ks202::SubSave(State::Saver& state) const
@ -201,6 +290,16 @@ namespace Nes
state.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();
}
void Ks7022::SubSave(State::Saver& state) const
{
state.Begin( AsciiId<'K','7','2'>::V ).Begin( AsciiId<'R','E','G'>::V ).Write8( reg ).End().End();
}
void Ks7031::SubSave(State::Saver& state) const
{
state.Begin( AsciiId<'K','7','1'>::V );
@ -209,34 +308,25 @@ namespace Nes
state.End();
}
void Ks7037::SubSave(State::Saver& state) const
{
state.Begin( AsciiId<'K','7','7'>::V );
const byte data[9] =
{
regs[0], regs[1], regs[2], regs[3],
regs[4], regs[5], regs[6], regs[7],
regNum
};
state.Begin( AsciiId<'R','E','G'>::V ).Write( data ).End();
state.End();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
NES_PEEK_A(Ks7032,6000)
{
return wrk[0][address - 0x6000];
}
NES_POKE_D(Ks7022,8000)
{
ppu.SetMirroring( (data & 0x4) ? Ppu::NMT_H : Ppu::NMT_V );
}
NES_POKE_D(Ks7022,A000)
{
reg = data & 0xF;
}
NES_PEEK(Ks7022,FFFC)
{
ppu.Update();
chr.SwapBank<SIZE_8K,0x0000>( reg );
prg.SwapBanks<SIZE_16K,0x0000>( reg, reg );
return prg.Peek(0x7FFC);
}
NES_POKE_D(Ks202,8000)
{
irq.Update();
@ -326,6 +416,68 @@ namespace Nes
}
}
bool Ks202::Irq::Clock()
{
return (count++ == 0xFFFF) ? (count=latch, true) : false;
}
void Ks202::Sync(Event event,Input::Controllers* controllers)
{
if (event == EVENT_END_FRAME)
irq.VSync();
Board::Sync( event, controllers );
}
NES_POKE_D(Ks7013b,6000)
{
prg.SwapBank<SIZE_16K>( 0x0000, data & 0x7 );
}
NES_POKE_D(Ks7013b,8000)
{
ppu.SetMirroring( (data & 0x1) ? Ppu::NMT_H : Ppu::NMT_V );
}
NES_PEEK_A(Ks7016,6000)
{
return *(prg.Source().Mem(reg * SIZE_8K) + (address & 0x1FFF));
}
NES_POKE_A(Ks7016,8000)
{
bool mode = (address & 0x30) == 0x30;
switch(address & 0xD943) {
case 0xD943:
reg = mode ? 0xB : (address >> 2) & 0xF;
break;
case 0xD903:
reg = mode ? 0x8 | ((address >> 2) & 0x3) : reg = 0xB;
break;
}
}
NES_POKE_D(Ks7022,8000)
{
ppu.SetMirroring( (data & 0x4) ? Ppu::NMT_H : Ppu::NMT_V );
}
NES_POKE_D(Ks7022,A000)
{
reg = data & 0xF;
}
NES_PEEK(Ks7022,FFFC)
{
ppu.Update();
chr.SwapBank<SIZE_8K,0x0000>( reg );
prg.SwapBanks<SIZE_16K,0x0000>( reg, reg );
return prg.Peek(0x7FFC);
}
NES_POKE_AD(Ks7031,8000)
{
regs[(address >> 11) & 0x03] = data;
@ -345,17 +497,74 @@ namespace Nes
return prg[0][new_addr];
}
bool Ks202::Irq::Clock()
NES_PEEK_A(Ks7032,6000)
{
return (count++ == 0xFFFF) ? (count=latch, true) : false;
return wrk[0][address - 0x6000];
}
void Ks202::Sync(Event event,Input::Controllers* controllers)
NES_PEEK_A(Ks7037,6000)
{
if (event == EVENT_END_FRAME)
irq.VSync();
NST_VERIFY( wrk.Readable(0) );
return wrk.Readable(0) ? wrk[0][address - 0x6000] : (address >> 8);
}
Board::Sync( event, controllers );
NES_POKE_AD(Ks7037,6000)
{
NST_VERIFY( wrk.Writable(0) );
if (wrk.Writable(0))
wrk[0][address- 0x6000] = data;
}
NES_PEEK_A(Ks7037,7000)
{
return *(prg.Source().Mem(SIZE_4K * 15) + (address & 0xFFF));
}
NES_PEEK_A(Ks7037,8000)
{
return *(prg.Source().Mem(regs[6] * SIZE_8K) + (address & 0x1FFF));
}
NES_POKE_D(Ks7037,8000)
{
regNum = data & 0x7U;
byte mirror[4] = { regs[2], regs[4], regs[3], regs[5] };
ppu.SetMirroring(mirror);
}
NES_POKE_D(Ks7037,8001)
{
regs[regNum] = data;
}
NES_PEEK_A(Ks7037,A000)
{
return *(prg.Source().Mem(SIZE_4K * 28) + (address & 0xFFF));
}
NES_PEEK_A(Ks7037,B000)
{
NST_VERIFY( wrk.Readable(0) );
return wrk.Readable(0) ? wrk[0][address - 0xA000] : (address >> 8);
}
NES_POKE_AD(Ks7037,B000)
{
NST_VERIFY( wrk.Writable(0) );
if (wrk.Writable(0))
wrk[0][address- 0xA000] = data;
}
NES_PEEK_A(Ks7037,C000)
{
return *(prg.Source().Mem(regs[7] * SIZE_8K) + (address & 0x1FFF));
}
NES_PEEK_A(Ks7037,E000)
{
return *(prg.Source().Mem(SIZE_8K * 15) + (address & 0x1FFF));
}
}
}

View File

@ -3,6 +3,7 @@
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
// Copyright (C) 2021 Rupert Carmichael
//
// This file is part of Nestopia.
//
@ -37,18 +38,6 @@ namespace Nes
{
namespace Kaiser
{
class Ks7058 : public Board
{
public:
explicit Ks7058(const Context& c)
: Board(c) {}
private:
void SubReset(bool);
};
class Ks202 : public Board
{
public:
@ -88,6 +77,59 @@ namespace Nes
Timer::M2<Irq> irq;
};
class Ks7013b : public Board
{
public:
explicit Ks7013b(const Context& c)
: Board(c) {}
private:
void SubReset(bool);
NES_DECL_POKE( 6000 );
NES_DECL_POKE( 8000 );
};
class Ks7016 : public Board
{
public:
explicit Ks7016(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_POKE( 8000 );
uint reg;
};
class Ks7022 : public Board
{
public:
explicit Ks7022(const Context& c)
: Board(c) {}
private:
void SubReset(bool);
void SubLoad(State::Loader&,dword);
void SubSave(State::Saver&) const;
NES_DECL_POKE( 8000 );
NES_DECL_POKE( A000 );
NES_DECL_PEEK( FFFC );
uint reg;
};
class Ks7031 : public Board
{
@ -121,11 +163,10 @@ namespace Nes
NES_DECL_PEEK( 6000 );
};
class Ks7022 : public Board
class Ks7037 : public Board
{
public:
explicit Ks7022(const Context& c)
explicit Ks7037(const Context& c)
: Board(c) {}
private:
@ -134,11 +175,32 @@ namespace Nes
void SubLoad(State::Loader&,dword);
void SubSave(State::Saver&) const;
NES_DECL_POKE( 8000 );
NES_DECL_POKE( A000 );
NES_DECL_PEEK( FFFC );
byte regNum;
byte regs[8];
uint reg;
NES_DECL_PEEK( 6000 );
NES_DECL_POKE( 6000 );
NES_DECL_PEEK( 7000 );
NES_DECL_PEEK( 8000 );
NES_DECL_POKE( 8000 );
NES_DECL_POKE( 8001 );
NES_DECL_PEEK( A000 );
NES_DECL_PEEK( B000 );
NES_DECL_POKE( B000 );
NES_DECL_PEEK( C000 );
NES_DECL_PEEK( E000 );
};
class Ks7058 : public Board
{
public:
explicit Ks7058(const Context& c)
: Board(c) {}
private:
void SubReset(bool);
};
}
}

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

@ -655,10 +655,9 @@ namespace Nes
NES_HOOK(Mmc5,HActive)
{
banks.fetchMode = Banks::FETCH_MODE_BG;
if (ppu.IsEnabled())
{
banks.fetchMode = Banks::FETCH_MODE_BG;
spliter.x = 0x1F;
if (ppu.GetPixelCycles() != ~0U)

View File

@ -31,6 +31,7 @@
#include "NstBoardNamcot163.hpp"
#include "NstBoardNamcot175.hpp"
#include "NstBoardNamcot340.hpp"
#include "NstBoardNamcot34xx.hpp"
namespace Nes

View File

@ -3,7 +3,7 @@
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
// Copyright (C) 2014 R. Danbrook
// Copyright (C) 2021 Rupert Carmichael
//
// This file is part of Nestopia.
//
@ -23,10 +23,7 @@
//
////////////////////////////////////////////////////////////////////////////////////////
#include <cstring>
#include "NstBoard.hpp"
#include "../NstTimer.hpp"
#include "../NstFile.hpp"
#include "NstBoardNamcot175.hpp"
namespace Nes
@ -43,16 +40,14 @@ namespace Nes
N175::N175(const Context& c)
:
Board (c),
irq (*c.cpu)
Board (c)
{
}
void N175::SubReset(const bool hard)
{
irq.Reset( hard, hard || irq.Connected() );
Map( 0x6000U, 0x7FFFU, &N175::Peek_6000 );
Map( 0x6000U, 0x7FFFU, &N175::Poke_6000 );
Map( 0x8000U, 0x87FFU, CHR_SWAP_1K_0 );
Map( 0x8800U, 0x8FFFU, CHR_SWAP_1K_1 );
Map( 0x9000U, 0x97FFU, CHR_SWAP_1K_2 );
@ -61,157 +56,35 @@ namespace Nes
Map( 0xA800U, 0xAFFFU, CHR_SWAP_1K_5 );
Map( 0xB000U, 0xB7FFU, CHR_SWAP_1K_6 );
Map( 0xB800U, 0xBFFFU, CHR_SWAP_1K_7 );
Map( 0xC000U, 0xC7FFU, &N175::Poke_C000 );
Map( 0xE000U, 0xE7FFU, PRG_SWAP_8K_0 );
Map( 0xE800U, 0xEFFFU, PRG_SWAP_8K_1 );
Map( 0xF000U, 0xF7FFU, PRG_SWAP_8K_2 );
}
void N175::Irq::Reset(const bool hard)
{
if (hard)
count = 0;
}
void N175::Load(File& file)
{
if (board.HasBattery())
{
const File::LoadBlock block[] =
{
{ wrk.Source().Mem(), board.GetWram() }
};
file.Load( File::BATTERY, block );
}
else
{
Board::Load( file );
}
}
void N175::Save(File& file) const
{
if (board.HasBattery())
{
const File::SaveBlock block[] =
{
{ wrk.Source().Mem(), board.GetWram() }
};
file.Save( File::BATTERY, block );
}
else
{
Board::Save( file );
}
}
void N175::SubLoad(State::Loader& state,const dword baseChunk)
{
NST_VERIFY( baseChunk == (AsciiId<'N','6','3'>::V) );
if (baseChunk == AsciiId<'N','6','3'>::V)
{
while (const dword chunk = state.Begin())
{
switch (chunk)
{
case AsciiId<'I','R','Q'>::V:
{
State::Loader::Data<3> data( state );
irq.unit.count = data[1] | (data[2] << 8 & 0x7F00) | (data[0] << 15 & 0x8000);
break;
}
}
state.End();
}
}
}
void N175::SubSave(State::Saver& state) const
{
state.Begin( AsciiId<'N','6','3'>::V );
const byte data[3] =
{
irq.unit.count >> 15,
irq.unit.count >> 0 & 0xFF,
irq.unit.count >> 8 & 0x7F
};
state.Begin( AsciiId<'I','R','Q'>::V ).Write( data ).End();
state.End();
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
bool N175::Irq::Clock()
NES_PEEK_A(N175,6000)
{
return (count - 0x8000 < 0x7FFF) && (++count == 0xFFFF);
NST_VERIFY( wrk.Readable(0) );
return wrk.Readable(0) ? wrk[0][address & 0x7FFU] : (address >> 8);
}
NES_PEEK(N175,5000)
NES_POKE_AD(N175,6000)
{
irq.Update();
return irq.unit.count & 0xFF;
}
NST_VERIFY( wrk.Writable(0) );
NES_POKE_D(N175,5000)
{
irq.Update();
irq.unit.count = (irq.unit.count & 0xFF00) | data;
irq.ClearIRQ();
}
NES_PEEK(N175,5800)
{
irq.Update();
return irq.unit.count >> 8;
}
NES_POKE_D(N175,5800)
{
irq.Update();
irq.unit.count = (irq.unit.count & 0x00FF) | (data << 8);
irq.ClearIRQ();
}
void N175::SwapNmt(const uint address,const uint data) const
{
ppu.Update();
nmt.Source( data < 0xE0 ).SwapBank<SIZE_1K>( address, data );
if (wrk.Writable(0))
wrk[0][address & 0x7FFU] = data;
}
NES_POKE_D(N175,C000)
{
SwapNmt( 0x0000, data );
}
NES_POKE_D(N175,C800)
{
SwapNmt( 0x0400, data );
}
NES_POKE_D(N175,D000)
{
SwapNmt( 0x0800, data );
}
NES_POKE_D(N175,D800)
{
SwapNmt( 0x0C00, data );
}
void N175::Sync(Event event,Input::Controllers* controllers)
{
if (event == EVENT_END_FRAME)
irq.VSync();
Board::Sync( event, controllers );
bool enable = data & 0x1;
wrk.Source().SetSecurity(enable, enable);
}
}
}

View File

@ -3,7 +3,7 @@
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
// Copyright (C) 2014 R. Danbrook
// Copyright (C) 2021 Rupert Carmichael
//
// This file is part of Nestopia.
//
@ -47,35 +47,10 @@ namespace Nes
private:
void SubReset(bool);
void SubSave(State::Saver&) const;
void SubLoad(State::Loader&,dword);
void Load(File&);
void Save(File&) const;
void Sync(Event,Input::Controllers*);
void SwapChr(uint,uint,uint) const;
void SwapNmt(uint,uint) const;
struct Irq
{
void Reset(bool);
bool Clock();
uint count;
};
NES_DECL_PEEK( 4800 );
NES_DECL_POKE( 4800 );
NES_DECL_PEEK( 5000 );
NES_DECL_POKE( 5000 );
NES_DECL_PEEK( 5800 );
NES_DECL_POKE( 5800 );
NES_DECL_PEEK( 6000 );
NES_DECL_POKE( 6000 );
NES_DECL_POKE( C000 );
NES_DECL_POKE( C800 );
NES_DECL_POKE( D000 );
NES_DECL_POKE( D800 );
NES_DECL_POKE( F800 );
Timer::M2<Irq> irq;
};
}
}

View File

@ -0,0 +1,89 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
// 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 "NstBoardNamcot340.hpp"
namespace Nes
{
namespace Core
{
namespace Boards
{
namespace Namcot
{
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("s", on)
#endif
N340::N340(const Context& c)
:
Board (c)
{
}
void N340::SubReset(const bool hard)
{
Map( 0x8000U, 0x87FFU, CHR_SWAP_1K_0 );
Map( 0x8800U, 0x8FFFU, CHR_SWAP_1K_1 );
Map( 0x9000U, 0x97FFU, CHR_SWAP_1K_2 );
Map( 0x9800U, 0x9FFFU, CHR_SWAP_1K_3 );
Map( 0xA000U, 0xA7FFU, CHR_SWAP_1K_4 );
Map( 0xA800U, 0xAFFFU, CHR_SWAP_1K_5 );
Map( 0xB000U, 0xB7FFU, CHR_SWAP_1K_6 );
Map( 0xB800U, 0xBFFFU, CHR_SWAP_1K_7 );
Map( 0xE000U, 0xE7FFU, &N340::Poke_E000 );
Map( 0xE800U, 0xEFFFU, PRG_SWAP_8K_1 );
Map( 0xF000U, 0xF7FFU, PRG_SWAP_8K_2 );
}
#ifdef NST_MSVC_OPTIMIZE
#pragma optimize("", on)
#endif
NES_POKE_D(N340,E000)
{
prg.SwapBank<SIZE_8K>( 0, data & 0x3FU );
switch ((data >> 6) & 0x3U)
{
case 0x0U: // One-screen A
ppu.SetMirroring( Ppu::NMT_0 );
break;
case 0x1U: // Vertical
ppu.SetMirroring( Ppu::NMT_V );
break;
case 0x2U: // One-screen B
ppu.SetMirroring( Ppu::NMT_1 );
break;
case 0x3U: // Horizontal
ppu.SetMirroring( Ppu::NMT_H );
break;
}
}
}
}
}
}

View File

@ -0,0 +1,58 @@
////////////////////////////////////////////////////////////////////////////////////////
//
// Nestopia - NES/Famicom emulator written in C++
//
// Copyright (C) 2003-2008 Martin Freij
// 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_NAMCOT_340_H
#define NST_BOARD_NAMCOT_340_H
#ifdef NST_PRAGMA_ONCE
#pragma once
#endif
namespace Nes
{
namespace Core
{
namespace Boards
{
namespace Namcot
{
class N340 : public Board
{
public:
explicit N340(const Context&);
private:
void SubReset(bool);
NES_DECL_POKE( E000 );
};
}
}
}
}
#endif

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,39 @@ namespace Nes
bool Rambo1::Irq::Unit::Clock()
{
/*if (!reload)
cycles++;
if (latch == 1)
{
if (count)
{
return !--count && enabled;
}
else
{
count = latch;
return false;
}
count = 0;
}
else if (reload)
{
reload = false;
count = latch | (latch ? 1 : 0);
if (mode)
count |= 2;
if (!latch && cycles > A12_FILTER)
count = 1;
else if (latch && (cycles > (A12_FILTER * 3)))
count++;
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 +316,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;

View File

@ -49,7 +49,8 @@ namespace Nes
NES_POKE_A(Cc21,8000)
{
ppu.SetMirroring( (address & 0x2) ? Ppu::NMT_1 : Ppu::NMT_0 );
chr.SwapBank<SIZE_8K,0x0000>( address );
chr.SwapBank<SIZE_4K,0x0000>( address );
chr.SwapBank<SIZE_4K,0x1000>( address );
}
}
}

View File

@ -51,7 +51,8 @@ namespace Nes
}
Map( 0x9000U, &KingOfFighters97::Poke_8001 );
Map( 0xA000U, &KingOfFighters97::Poke_8000 );
Map( 0xA000U, &KingOfFighters97::Poke_A000 );
Map( 0xB000U, &KingOfFighters97::Poke_A001 );
Map( 0xD000U, &KingOfFighters97::Poke_C001 );
for (uint i=0x0000; i < 0x1000; i += 0x2)
@ -89,6 +90,16 @@ namespace Nes
Mmc3::NES_DO_POKE(8001,0x8001,Unscramble(data));
}
NES_POKE_D(KingOfFighters97,A000)
{
ppu.SetMirroring( (data & 0x02) ? Ppu::NMT_H : Ppu::NMT_V );
}
NES_POKE_D(KingOfFighters97,A001)
{
Mmc3::NES_DO_POKE(A001,0xA001,Unscramble(data));
}
NES_POKE_D(KingOfFighters97,C000)
{
Mmc3::NES_DO_POKE(C000,0xC000,Unscramble(data));

View File

@ -52,6 +52,8 @@ namespace Nes
NES_DECL_POKE( 8000 );
NES_DECL_POKE( 8001 );
NES_DECL_POKE( A000 );
NES_DECL_POKE( A001 );
NES_DECL_POKE( C000 );
NES_DECL_POKE( C001 );
NES_DECL_POKE( E000 );