AxibugEmuOnline/References/virtuanessrc097-master/NES/Nes.cpp

4142 lines
198 KiB
C++
Raw Normal View History

<EFBFBD><EFBFBD>//////////////////////////////////////////////////////////////////////////
// //
// NES Emulation core //
// Norix //
// written 2001/02/22 //
// last modify ----/--/-- //
//////////////////////////////////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "typedef.h"
#include "macro.h"
#include "VirtuaNESres.h"
#include "DebugOut.h"
#include "App.h"
#include "Pathlib.h"
#include "Config.h"
#include "Crclib.h"
#include "nes.h"
#include "mmu.h"
#include "cpu.h"
#include "ppu.h"
#include "apu.h"
#include "pad.h"
#include "rom.h"
#include "mapper.h"
#include "DirectDraw.h"
#include "DirectSound.h"
#include "DirectInput.h"
#include "pngwrite.h"
NESCONFIG NESCONFIG_NTSC = {
21477270.0f, // Base clock
1789772.5f, // Cpu clock
262, // Total scanlines
1364, // Scanline total cycles(15.75KHz)
1024, // H-Draw cycles
340, // H-Blank cycles
4, // End cycles
2024-07-31 17:40:32 +08:00
1364 * 262, // Frame cycles
29830, // FrameIRQ cycles
60, // Frame rate(Be originally 59.94Hz)
2024-07-31 17:40:32 +08:00
1000.0f / 60.0f // Frame period(ms)
};
NESCONFIG NESCONFIG_PAL = {
2024-07-31 17:40:32 +08:00
// 21281364.0f, // Base clock
26601714.0f, // Base clock
// 1773447.0f, // Cpu clock
1662607.125f, // Cpu clock
2024-07-31 17:40:32 +08:00
312, // Total scanlines
2024-07-31 17:40:32 +08:00
// 1362, // Scanline total cycles(15.625KHz)
1278, // Scanline total cycles(15.625KHz)
2024-07-31 17:40:32 +08:00
// 1024, // H-Draw cycles
960, // H-Draw cycles
// 338, // H-Blank cycles
318, // H-Blank cycles
2, // End cycles
2024-07-31 17:40:32 +08:00
// 1362*312, // Frame cycles
1278 * 312, // Frame cycles
// 35469, // FrameIRQ cycles
33252, // FrameIRQ cycles
2024-07-31 17:40:32 +08:00
50, // Frame rate(Hz)
1000.0f / 50.0f // Frame period(ms)
};
// Pad disp
2024-07-31 17:40:32 +08:00
BYTE NES::m_PadImg[] = {
28, 8,
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, 0x0F, 0x0F, 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, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00,
0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x0F,
0x0F, 0x0F, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x0F, 0x0F, 0x0F, 0x0F, 0x00,
0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x0F, 0x00, 0x0F,
0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 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,
};
BYTE NES::m_KeyImg0[] = {
2, 2,
0x2A, 0x2A,
0x2A, 0x2A,
};
BYTE NES::m_KeyImg1[] = {
3, 3,
0x2A, 0x2A, 0x2A,
0x2A, 0x2A, 0x2A,
};
BYTE NES::m_KeyImg2[] = {
4, 4,
0xFF, 0x2A, 0x2A, 0xFF,
0x2A, 0x2A, 0x2A, 0x2A,
0x2A, 0x2A, 0x2A, 0x2A,
0xFF, 0x2A, 0x2A, 0xFF,
};
//----------
#define ASMVER 0
#if ASMVER
static INT cache = 0;
static UINT cache_hiRem = 0;
#endif
//
//
//
2024-07-31 17:40:32 +08:00
NES::NES(const char* fname)
{
2024-07-31 17:40:32 +08:00
DEBUGOUT("VirtuaNES - NES Emulator for Win32 by Norix (C)2001\n");
m_bDiskThrottle = FALSE;
m_CommandRequest = 0;
m_nSnapNo = 0;
m_bNsfPlaying = FALSE;
m_bMoviePlay = m_bMovieRec = FALSE;
m_fpMovie = NULL;
m_bTapePlay = m_bTapeRec = FALSE;
m_fpTape = NULL;
m_TapeCycles = 0.0;
m_TapeIn = m_TapeOut = 0;
m_bBarcode = FALSE;
m_BarcodeOut = 0;
m_BarcodePtr = 0;
m_BarcodeCycles = 0;
m_bBarcode2 = FALSE;
m_TurboFileBank = 0;
cpu = NULL;
ppu = NULL;
apu = NULL;
rom = NULL;
pad = NULL;
mapper = NULL;
2024-07-31 17:40:32 +08:00
SAVERAM_SIZE = 8 * 1024; // 8K byte
// IRQ type
nIRQtype = 0;
// FrameIRQ mode
bFrameIRQ = TRUE;
// NTSC/PAL VideoMode
bVideoMode = FALSE;
// Default config
nescfg = &NESCONFIG_NTSC;
// Cheat
CheatInitial();
// TEST
#if NES_PROFILER
m_dwTotalCycle = 0;
m_dwTotalTempCycle = 0;
m_dwProfileTotalCycle = 0;
m_dwProfileTotalCount = 0;
m_dwProfileCycle = 0;
m_dwProfileTempCycle = 0;
m_dwProfileAveCycle = 0;
m_dwProfileMaxCycle = 0;
#endif
//-------
#if ASMVER
cache = 0;
cache_hiRem = 0;
#endif
try {
2024-07-31 17:40:32 +08:00
DEBUGOUT("Allocating CPU...");
if (!(cpu = new CPU(this)))
throw "Allocating CPU failed.";
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
2024-07-31 17:40:32 +08:00
DEBUGOUT("Allocating PPU...");
if (!(ppu = new PPU(this)))
throw "Allocating PPU failed.";
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
2024-07-31 17:40:32 +08:00
DEBUGOUT("Allocating APU...");
if (!(apu = new APU(this)))
throw "Allocating APU failed.";
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
2024-07-31 17:40:32 +08:00
DEBUGOUT("Allocating PAD...");
if (!(pad = new PAD(this)))
throw "Allocating PAD failed.";
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
2024-07-31 17:40:32 +08:00
DEBUGOUT("Loading ROM Image...\n");
2024-07-31 17:40:32 +08:00
if (!(rom = new ROM(fname)))
throw "Allocating ROM failed.";
2024-07-31 17:40:32 +08:00
if (!(mapper = CreateMapper(this, rom->GetMapperNo()))) {
// *g<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0g0Y0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_UNSUPPORTMAPPER);
sprintf(szErrorString, szErrStr, rom->GetMapperNo());
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
DEBUGOUT("ROM status\n");
DEBUGOUT(" %s\n", rom->GetRomName());
DEBUGOUT(" Mapper : %03d\n", rom->GetMapperNo());
DEBUGOUT(" PRG SIZE : %4dK\n", 16 * (INT)rom->GetPROM_SIZE());
DEBUGOUT(" CHR SIZE : %4dK\n", 8 * (INT)rom->GetVROM_SIZE());
DEBUGOUT(" V MIRROR : ");
if (rom->IsVMIRROR()) DEBUGOUT("Yes\n");
else DEBUGOUT("No\n");
DEBUGOUT(" 4 SCREEN : ");
if (rom->Is4SCREEN()) DEBUGOUT("Yes\n");
else DEBUGOUT("No\n");
DEBUGOUT(" SAVE RAM : ");
if (rom->IsSAVERAM()) DEBUGOUT("Yes\n");
else DEBUGOUT("No\n");
DEBUGOUT(" TRAINER : ");
if (rom->IsTRAINER()) DEBUGOUT("Yes\n");
else DEBUGOUT("No\n");
DEBUGOUT(" VS-Unisystem : ");
if (rom->IsVSUNISYSTEM()) DEBUGOUT("Yes\n");
else DEBUGOUT("No\n");
NesSub_MemoryInitial();
LoadSRAM();
LoadDISK();
{
2024-07-31 17:40:32 +08:00
// Pad<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>Q`0h0RgS<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0E<EFBFBD>D0n0g0S0S0g0
DWORD crc = rom->GetPROM_CRC();
if (crc == 0xe792de94 // Best Play - Pro Yakyuu (New) (J)
|| crc == 0xf79d684a // Best Play - Pro Yakyuu (Old) (J)
|| crc == 0xc2ef3422 // Best Play - Pro Yakyuu 2 (J)
|| crc == 0x974e8840 // Best Play - Pro Yakyuu '90 (J)
|| crc == 0xb8747abf // Best Play - Pro Yakyuu Special (J)
|| crc == 0x9fa1c11f // Castle Excellent (J)
|| crc == 0x0b0d4d1b // Derby Stallion - Zenkoku Ban (J)
|| crc == 0x728c3d98 // Downtown - Nekketsu Monogatari (J)
|| crc == 0xd68a6f33 // Dungeon Kid (J)
|| crc == 0x3a51eb04 // Fleet Commander (J)
|| crc == 0x7c46998b // Haja no Fuuin (J)
|| crc == 0x7e5d2f1a // Itadaki Street - Watashi no Mise ni Yottette (J)
|| crc == 0xcee5857b // Ninjara Hoi! (J)
|| crc == 0x50ec5e8b // Wizardry - Legacy of Llylgamyn (J)
|| crc == 0x343e9146 // Wizardry - Proving Grounds of the Mad Overlord (J)
|| crc == 0x33d07e45) { // Wizardry - The Knight of Diamonds (J)
pad->SetExController(PAD::EXCONTROLLER_TURBOFILE);
}
}
LoadTurboFile();
// VS-Unisystemn0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0-<EFBFBD><EFBFBD>[
2024-07-31 17:40:32 +08:00
if (rom->IsVSUNISYSTEM()) {
DWORD crc = rom->GetPROM_CRC();
2024-07-31 17:40:32 +08:00
m_VSDipValue = GetVSDefaultDipSwitchValue(crc);
m_VSDipTable = FindVSDipSwitchTable(crc);
2024-07-31 17:40:32 +08:00
#include "VS_Setting.h"
}
else {
m_VSDipValue = 0;
m_VSDipTable = vsdip_default;
}
Reset();
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>V gn0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0-<EFBFBD><EFBFBD>[(-<EFBFBD><EFBFBD>[;bY0Bfk0OF0<EFBFBD>p)
GameOption.defRenderMethod = (INT)GetRenderMethod();
2024-07-31 17:40:32 +08:00
GameOption.defIRQtype = (INT)GetIrqType();
GameOption.defFrameIRQ = GetFrameIRQmode();
GameOption.defVideoMode = GetVideoMode();
// -<EFBFBD><EFBFBD>[<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0W0f0-<EFBFBD><EFBFBD>[Y0<EFBFBD>0(<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0!qQ0<EFBFBD>0p0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0eQ<EFBFBD>0)
2024-07-31 17:40:32 +08:00
if (rom->GetMapperNo() != 20) {
GameOption.Load(rom->GetPROM_CRC());
}
else {
GameOption.Load(rom->GetGameID(), rom->GetMakerID());
}
SetRenderMethod((RENDERMETHOD)GameOption.nRenderMethod);
SetIrqType(GameOption.nIRQtype);
SetFrameIRQmode(GameOption.bFrameIRQ);
SetVideoMode(GameOption.bVideoMode);
}
catch (CHAR* str) {
DELETEPTR(cpu);
DELETEPTR(ppu);
DELETEPTR(apu);
DELETEPTR(pad);
DELETEPTR(rom);
DELETEPTR(mapper);
throw str;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
DELETEPTR(cpu);
DELETEPTR(ppu);
DELETEPTR(apu);
DELETEPTR(pad);
DELETEPTR(rom);
DELETEPTR(mapper);
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("Starting emulation!\n");
}
NES::~NES()
{
MovieStop();
SaveSRAM();
SaveDISK();
SaveTurboFile();
2024-07-31 17:40:32 +08:00
DEBUGOUT("Free NES...");
2024-07-31 17:40:32 +08:00
DELETEPTR(cpu);
DELETEPTR(ppu);
DELETEPTR(apu);
DELETEPTR(pad);
DELETEPTR(rom);
DELETEPTR(mapper);
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
}
2024-07-31 17:40:32 +08:00
void NES::SetVideoMode(BOOL bMode)
{
bVideoMode = bMode;
2024-07-31 17:40:32 +08:00
if (!bVideoMode) {
nescfg = &NESCONFIG_NTSC;
2024-07-31 17:40:32 +08:00
}
else {
nescfg = &NESCONFIG_PAL;
}
apu->SoundSetup();
}
void NES::Reset()
{
SaveSRAM();
SaveDISK();
SaveTurboFile();
// RAM Clear
2024-07-31 17:40:32 +08:00
ZEROMEMORY(RAM, sizeof(RAM));
if (rom->GetPROM_CRC() == 0x29401686) { // Minna no Taabou no Nakayoshi Dai Sakusen(J)
::memset(RAM, 0xFF, sizeof(RAM));
}
// RAM set
2024-07-31 17:40:32 +08:00
if (!rom->IsSAVERAM() && rom->GetMapperNo() != 20) {
::memset(WRAM, 0xFF, sizeof(WRAM));
}
2024-07-31 17:40:32 +08:00
ZEROMEMORY(CRAM, sizeof(CRAM));
ZEROMEMORY(VRAM, sizeof(VRAM));
2024-07-31 17:40:32 +08:00
ZEROMEMORY(SPRAM, sizeof(SPRAM));
ZEROMEMORY(BGPAL, sizeof(BGPAL));
ZEROMEMORY(SPPAL, sizeof(SPPAL));
2024-07-31 17:40:32 +08:00
ZEROMEMORY(CPUREG, sizeof(CPUREG));
ZEROMEMORY(PPUREG, sizeof(PPUREG));
m_bDiskThrottle = FALSE;
2024-07-31 17:40:32 +08:00
SetRenderMethod(PRE_RENDER);
2024-07-31 17:40:32 +08:00
if (rom->IsPAL()) {
SetVideoMode(TRUE);
}
PROM = rom->GetPROM();
VROM = rom->GetVROM();
2024-07-31 17:40:32 +08:00
PROM_8K_SIZE = rom->GetPROM_SIZE() * 2;
PROM_16K_SIZE = rom->GetPROM_SIZE();
2024-07-31 17:40:32 +08:00
PROM_32K_SIZE = rom->GetPROM_SIZE() / 2;
2024-07-31 17:40:32 +08:00
VROM_1K_SIZE = rom->GetVROM_SIZE() * 8;
VROM_2K_SIZE = rom->GetVROM_SIZE() * 4;
VROM_4K_SIZE = rom->GetVROM_SIZE() * 2;
VROM_8K_SIZE = rom->GetVROM_SIZE();
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
if (VROM_8K_SIZE) {
SetVROM_8K_Bank(0);
}
else {
SetCRAM_8K_Bank(0);
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
if (rom->Is4SCREEN()) {
SetVRAM_Mirror(VRAM_MIRROR4);
}
else if (rom->IsVMIRROR()) {
SetVRAM_Mirror(VRAM_VMIRROR);
}
else {
SetVRAM_Mirror(VRAM_HMIRROR);
}
2024-07-31 17:40:32 +08:00
apu->SelectExSound(0);
ppu->Reset();
mapper->Reset();
// Trainer
2024-07-31 17:40:32 +08:00
if (rom->IsTRAINER()) {
::memcpy(WRAM + 0x1000, rom->GetTRAINER(), 512);
}
pad->Reset();
cpu->Reset();
apu->Reset();
2024-07-31 17:40:32 +08:00
if (rom->IsNSF()) {
mapper->Reset();
}
base_cycles = emul_cycles = 0;
}
void NES::SoftReset()
{
pad->Reset();
cpu->Reset();
apu->Reset();
2024-07-31 17:40:32 +08:00
if (rom->IsNSF()) {
mapper->Reset();
}
m_bDiskThrottle = FALSE;
base_cycles = emul_cycles = 0;
}
2024-07-31 17:40:32 +08:00
INT CPU_CALL_COUNT = 0;
void NES::EmulationCPU(INT basecycles)
{
2024-07-31 17:40:32 +08:00
INT cycles;
base_cycles += basecycles;
#if !ASMVER
2024-07-31 17:40:32 +08:00
cycles = (INT)((base_cycles / 12) - emul_cycles);
#else
2024-07-31 17:40:32 +08:00
SQWORD& rBase = base_cycles;
SQWORD& rEmul = emul_cycles;
__asm {
// check if high DWORD changed
mov edi, 12
mov eax, cache
2024-07-31 17:40:32 +08:00
mov ebx, DWORD PTR[rBase]
mov ecx, DWORD PTR[rEmul]
cmp eax, [ebx + 4]
jz low_dword
2024-07-31 17:40:32 +08:00
// high_dword:
// temp = (base_cycles/12)
// Calculate upper DWORD and remainder
xor edx, edx
mov eax, [ebx + 4]
mov cache, eax
div edi
mov cache_hiRem, edx
2024-07-31 17:40:32 +08:00
low_dword :
// Calculate bottom DWORD with upper remainder
mov edx, cache_hiRem
2024-07-31 17:40:32 +08:00
mov eax, [ebx]
div edi
// diff:
// cycles = temp - emul_cycles
// eax carried from DIV above
xor edx, edx
sub edx, [ecx]
add eax, edx
mov cycles, eax
}
#endif
2024-07-31 17:40:32 +08:00
if (cycles > 0) {
INT cycleAdd = cpu->EXEC(cycles);
DEBUGOUT("[%d] add:[%d]\n",CPU_CALL_COUNT,cycleAdd);
emul_cycles += cycleAdd;
}
2024-07-31 17:40:32 +08:00
CPU_CALL_COUNT++;
}
2024-07-31 17:40:32 +08:00
void NES::EmulationCPU_BeforeNMI(INT cycles)
{
base_cycles += cycles;
2024-07-31 17:40:32 +08:00
emul_cycles += cpu->EXEC(cycles / 12);
}
/*
<EFBFBD>c;u<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
0 <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0(<EFBFBD>c;uW0j0D0)
1 - 239 <EFBFBD>c;u
240 <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0,VBLANK<EFBFBD>0<EFBFBD>0<EFBFBD>0ON
241 VINTg<EFBFBD><EFBFBD>,NMIzvu
242-261 VINTg<EFBFBD><EFBFBD>
261 VINTg<EFBFBD><EFBFBD>,VBLANK<EFBFBD>0<EFBFBD>0<EFBFBD>0OFF
*/
2024-07-31 17:40:32 +08:00
INT FrameCount = 0;
void NES::EmulateFrame(BOOL bDraw)
{
2024-07-31 17:40:32 +08:00
FrameCount++;
INT scanline = 0;
// NSF<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0Bf
2024-07-31 17:40:32 +08:00
if (rom->IsNSF()) {
EmulateNSF();
return;
}
// Cheat
CheatCodeProcess();
//
NES_scanline = scanline;
2024-07-31 17:40:32 +08:00
if (RenderMethod != TILE_RENDER) {
bZapper = FALSE;
2024-07-31 17:40:32 +08:00
while (TRUE) {
ppu->SetRenderScanline(scanline);
2024-07-31 17:40:32 +08:00
if (scanline == 0) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
if (RenderMethod < POST_RENDER) {
EmulationCPU(nescfg->ScanlineCycles);
ppu->FrameStart();
ppu->ScanlineNext();
2024-07-31 17:40:32 +08:00
mapper->HSync(scanline);
ppu->ScanlineStart();
2024-07-31 17:40:32 +08:00
}
else {
EmulationCPU(nescfg->HDrawCycles);
ppu->FrameStart();
ppu->ScanlineNext();
2024-07-31 17:40:32 +08:00
mapper->HSync(scanline);
EmulationCPU(FETCH_CYCLES * 32);
ppu->ScanlineStart();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10 + nescfg->ScanlineEndCycles);
}
}
else if (scanline < 240) {
if (RenderMethod < POST_RENDER) {
if (RenderMethod == POST_ALL_RENDER)
EmulationCPU(nescfg->ScanlineCycles);
if (bDraw) {
ppu->Scanline(scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip);
}
else {
if (pad->IsZapperMode() && scanline == ZapperY) {
ppu->Scanline(scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip);
}
else {
if (!ppu->IsSprite0(scanline)) {
ppu->DummyScanline(scanline);
}
else {
ppu->Scanline(scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip);
}
}
}
ppu->ScanlineNext(); // S0<EFBFBD>0n0MOng0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>|o0;ub<EFBFBD>L0U<EFBFBD>F0
2024-07-31 17:40:32 +08:00
if (RenderMethod == PRE_ALL_RENDER)
EmulationCPU(nescfg->ScanlineCycles);
// ppu->ScanlineNext(); // S0<EFBFBD>0n0MOng0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>|o0;ub<EFBFBD>L0U<EFBFBD>F0
mapper->HSync(scanline);
ppu->ScanlineStart();
2024-07-31 17:40:32 +08:00
}
else {
if (RenderMethod == POST_RENDER)
EmulationCPU(nescfg->HDrawCycles);
if (bDraw) {
ppu->Scanline(scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip);
}
else {
if (pad->IsZapperMode() && scanline == ZapperY) {
ppu->Scanline(scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip);
}
else {
if (!ppu->IsSprite0(scanline)) {
ppu->DummyScanline(scanline);
}
else {
ppu->Scanline(scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip);
}
}
}
2024-07-31 17:40:32 +08:00
if (RenderMethod == PRE_RENDER)
EmulationCPU(nescfg->HDrawCycles);
ppu->ScanlineNext();
2024-07-31 17:40:32 +08:00
mapper->HSync(scanline);
EmulationCPU(FETCH_CYCLES * 32);
ppu->ScanlineStart();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10 + nescfg->ScanlineEndCycles);
}
2024-07-31 17:40:32 +08:00
}
else if (scanline == 240) {
mapper->VSync();
2024-07-31 17:40:32 +08:00
if (RenderMethod < POST_RENDER) {
EmulationCPU(nescfg->ScanlineCycles);
mapper->HSync(scanline);
}
else {
EmulationCPU(nescfg->HDrawCycles);
mapper->HSync(scanline);
EmulationCPU(nescfg->HBlankCycles);
}
}
else if (scanline <= nescfg->TotalScanlines - 1) {
pad->VSync();
// VBLANKg<EFBFBD><EFBFBD>
2024-07-31 17:40:32 +08:00
if (scanline == nescfg->TotalScanlines - 1) {
ppu->VBlankEnd();
}
2024-07-31 17:40:32 +08:00
if (RenderMethod < POST_RENDER) {
if (scanline == 241) {
ppu->VBlankStart();
2024-07-31 17:40:32 +08:00
if (PPUREG[0] & PPU_VBLANK_BIT) {
cpu->NMI();
}
}
2024-07-31 17:40:32 +08:00
EmulationCPU(nescfg->ScanlineCycles);
mapper->HSync(scanline);
}
else {
if (scanline == 241) {
ppu->VBlankStart();
2024-07-31 17:40:32 +08:00
if (PPUREG[0] & PPU_VBLANK_BIT) {
cpu->NMI();
}
}
2024-07-31 17:40:32 +08:00
EmulationCPU(nescfg->HDrawCycles);
mapper->HSync(scanline);
EmulationCPU(nescfg->HBlankCycles);
}
2024-07-31 17:40:32 +08:00
if (scanline == nescfg->TotalScanlines - 1) {
break;
}
}
2024-07-31 17:40:32 +08:00
if (pad->IsZapperMode()) {
if (scanline == ZapperY)
bZapper = TRUE;
else
bZapper = FALSE;
}
scanline++;
NES_scanline = scanline;
}
2024-07-31 17:40:32 +08:00
}
else {
bZapper = FALSE;
2024-07-31 17:40:32 +08:00
while (TRUE) {
ppu->SetRenderScanline(scanline);
2024-07-31 17:40:32 +08:00
if (scanline == 0) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
// H-Draw (4fetches*32)
EmulationCPU(FETCH_CYCLES * 128);
ppu->FrameStart();
ppu->ScanlineNext();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10);
mapper->HSync(scanline);
EmulationCPU(FETCH_CYCLES * 22);
ppu->ScanlineStart();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10 + nescfg->ScanlineEndCycles);
}
else if (scanline < 240) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>c;u(Scanline 10239)
if (bDraw) {
ppu->Scanline(scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip);
ppu->ScanlineNext();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10);
mapper->HSync(scanline);
EmulationCPU(FETCH_CYCLES * 22);
ppu->ScanlineStart();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10 + nescfg->ScanlineEndCycles);
}
else {
if (pad->IsZapperMode() && scanline == ZapperY) {
ppu->Scanline(scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip);
ppu->ScanlineNext();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10);
mapper->HSync(scanline);
EmulationCPU(FETCH_CYCLES * 22);
ppu->ScanlineStart();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10 + nescfg->ScanlineEndCycles);
}
else {
if (!ppu->IsSprite0(scanline)) {
// H-Draw (4fetches*32)
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 128);
ppu->DummyScanline(scanline);
ppu->ScanlineNext();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10);
mapper->HSync(scanline);
EmulationCPU(FETCH_CYCLES * 22);
ppu->ScanlineStart();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10 + nescfg->ScanlineEndCycles);
}
else {
ppu->Scanline(scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip);
ppu->ScanlineNext();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10);
mapper->HSync(scanline);
EmulationCPU(FETCH_CYCLES * 22);
ppu->ScanlineStart();
2024-07-31 17:40:32 +08:00
EmulationCPU(FETCH_CYCLES * 10 + nescfg->ScanlineEndCycles);
}
}
}
2024-07-31 17:40:32 +08:00
}
else if (scanline == 240) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0 (Scanline 240)
mapper->VSync();
2024-07-31 17:40:32 +08:00
EmulationCPU(nescfg->HDrawCycles);
// H-Sync
2024-07-31 17:40:32 +08:00
mapper->HSync(scanline);
2024-07-31 17:40:32 +08:00
EmulationCPU(nescfg->HBlankCycles);
}
else if (scanline <= nescfg->TotalScanlines - 1) {
pad->VSync();
2024-07-31 17:40:32 +08:00
// VBLANKg<EFBFBD><EFBFBD>
if (scanline == nescfg->TotalScanlines - 1) {
ppu->VBlankEnd();
}
2024-07-31 17:40:32 +08:00
if (scanline == 241) {
ppu->VBlankStart();
2024-07-31 17:40:32 +08:00
if (PPUREG[0] & PPU_VBLANK_BIT) {
cpu->NMI();
}
}
2024-07-31 17:40:32 +08:00
EmulationCPU(nescfg->HDrawCycles);
// H-Sync
2024-07-31 17:40:32 +08:00
mapper->HSync(scanline);
2024-07-31 17:40:32 +08:00
EmulationCPU(nescfg->HBlankCycles);
2024-07-31 17:40:32 +08:00
if (scanline == nescfg->TotalScanlines - 1) {
break;
}
}
2024-07-31 17:40:32 +08:00
if (pad->IsZapperMode()) {
if (scanline == ZapperY)
bZapper = TRUE;
else
bZapper = FALSE;
}
scanline++;
NES_scanline = scanline;
}
}
// Movie pad
// if( Config.movie.bPadDisplay && bDraw ) {
// DrawPad();
// }
// Movie pad
2024-07-31 17:40:32 +08:00
if (bDraw) {
DrawPad();
}
#if NES_PROFILER
{
2024-07-31 17:40:32 +08:00
CHAR str[256];
::wsprintf(str, "Cyc:%10d", m_dwProfileCycle);
DrawString(9, 240 - 32, str, 0x1F);
DrawString(8, 240 - 33, str, 0x30);
::wsprintf(str, "Ave:%10d", m_dwProfileAveCycle);
DrawString(9, 240 - 23, str, 0x1F);
DrawString(8, 240 - 24, str, 0x30);
::wsprintf(str, "Max:%10d", m_dwProfileMaxCycle);
DrawString(9, 240 - 14, str, 0x1F);
DrawString(8, 240 - 15, str, 0x30);
}
#endif
}
void NES::EmulateNSF()
{
2024-07-31 17:40:32 +08:00
R6502 reg;
ppu->Reset();
mapper->VSync();
2024-07-31 17:40:32 +08:00
//DEBUGOUT( "Frame\n" );
2024-07-31 17:40:32 +08:00
if (m_bNsfPlaying) {
if (m_bNsfInit) {
ZEROMEMORY(RAM, sizeof(RAM));
if (!(rom->GetNsfHeader()->ExtraChipSelect & 0x04)) {
ZEROMEMORY(WRAM, 0x2000);
}
apu->Reset();
2024-07-31 17:40:32 +08:00
apu->Write(0x4015, 0x0F);
apu->Write(0x4017, 0xC0);
apu->ExWrite(0x4080, 0x80); // FDS Volume 0
apu->ExWrite(0x408A, 0xE8); // FDS Envelope Speed
2024-07-31 17:40:32 +08:00
cpu->GetContext(reg);
reg.PC = 0x4710; // Init Address
2024-07-31 17:40:32 +08:00
reg.A = (BYTE)m_nNsfSongNo;
reg.X = (BYTE)m_nNsfSongMode;
reg.Y = 0;
reg.S = 0xFF;
reg.P = Z_FLAG | R_FLAG | I_FLAG;
cpu->SetContext(reg);
// <EFBFBD>[hQ<EFBFBD>[V{<EFBFBD>0|Qm0f0B0H0f0<EFBFBD>0<EFBFBD>0<EFBFBD>0k0(1<EFBFBD>yR)
2024-07-31 17:40:32 +08:00
for (INT i = 0; i < nescfg->TotalScanlines * 60; i++) {
EmulationCPU(nescfg->ScanlineCycles);
cpu->GetContext(reg);
// !qP<EFBFBD><EFBFBD>0<EFBFBD>0<EFBFBD>0k0eQc0_0S0h0<EFBFBD>0<EFBFBD>x<EFBFBD><EFBFBD>W0_0<EFBFBD>0<EFBFBD>bQ0<EFBFBD>0
2024-07-31 17:40:32 +08:00
if (reg.PC == 0x4700) {
break;
}
}
m_bNsfInit = FALSE;
}
2024-07-31 17:40:32 +08:00
cpu->GetContext(reg);
// !qP<EFBFBD><EFBFBD>0<EFBFBD>0<EFBFBD>0k0eQc0f0D0_0<EFBFBD>0<EFBFBD>Q-<EFBFBD><EFBFBD>[Y0<EFBFBD>0
2024-07-31 17:40:32 +08:00
if (reg.PC == 0x4700) {
reg.PC = 0x4720; // Play Address
2024-07-31 17:40:32 +08:00
reg.A = 0;
reg.S = 0xFF;
cpu->SetContext(reg);
}
2024-07-31 17:40:32 +08:00
for (INT i = 0; i < nescfg->TotalScanlines; i++) {
EmulationCPU(nescfg->ScanlineCycles);
}
2024-07-31 17:40:32 +08:00
}
else {
cpu->GetContext(reg);
reg.PC = 0x4700; // !qP<EFBFBD><EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
reg.S = 0xFF;
cpu->SetContext(reg);
2024-07-31 17:40:32 +08:00
EmulationCPU(nescfg->ScanlineCycles * nescfg->TotalScanlines);
}
}
2024-07-31 17:40:32 +08:00
void NES::SetNsfPlay(INT songno, INT songmode)
{
2024-07-31 17:40:32 +08:00
m_bNsfPlaying = TRUE;
m_bNsfInit = TRUE;
m_nNsfSongNo = songno;
m_nNsfSongMode = songmode;
}
void NES::SetNsfStop()
{
m_bNsfPlaying = FALSE;
apu->Reset();
}
2024-07-31 17:40:32 +08:00
void NES::Clock(INT cycles)
{
2024-07-31 17:40:32 +08:00
Tape(cycles);
Barcode(cycles);
}
2024-07-31 17:40:32 +08:00
BYTE NES::Read(WORD addr)
{
2024-07-31 17:40:32 +08:00
switch (addr >> 13) {
case 0x00: // $0000-$1FFF
return RAM[addr & 0x07FF];
case 0x01: // $2000-$3FFF
return ppu->Read(addr & 0xE007);
case 0x02: // $4000-$5FFF
if (addr < 0x4100) {
return ReadReg(addr);
}
else {
return mapper->ReadLow(addr);
}
break;
case 0x03: // $6000-$7FFF
return mapper->ReadLow(addr);
case 0x04: // $8000-$9FFF
case 0x05: // $A000-$BFFF
case 0x06: // $C000-$DFFF
case 0x07: // $E000-$FFFF
return CPU_MEM_BANK[addr >> 13][addr & 0x1FFF];
}
return 0x00; // Warning<EFBFBD>N2<EFBFBD>
}
2024-07-31 17:40:32 +08:00
void NES::SetRenderMethod(RENDERMETHOD type) {
RenderMethod = type;
}
void NES::Write(WORD addr, BYTE data)
{
2024-07-31 17:40:32 +08:00
switch (addr >> 13) {
case 0x00: // $0000-$1FFF
RAM[addr & 0x07FF] = data;
break;
case 0x01: // $2000-$3FFF
if (!rom->IsNSF()) {
ppu->Write(addr & 0xE007, data);
}
break;
case 0x02: // $4000-$5FFF
if (addr < 0x4100) {
WriteReg(addr, data);
}
else {
mapper->WriteLow(addr, data);
}
break;
case 0x03: // $6000-$7FFF
mapper->WriteLow(addr, data);
break;
case 0x04: // $8000-$9FFF
case 0x05: // $A000-$BFFF
case 0x06: // $C000-$DFFF
case 0x07: // $E000-$FFFF
mapper->Write(addr, data);
2024-07-31 17:40:32 +08:00
GenieCodeProcess();
break;
}
}
2024-07-31 17:40:32 +08:00
BYTE NES::ReadReg(WORD addr)
{
2024-07-31 17:40:32 +08:00
switch (addr & 0xFF) {
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0A: case 0x0B:
case 0x0C: case 0x0D: case 0x0E: case 0x0F:
case 0x10: case 0x11: case 0x12: case 0x13:
return apu->Read(addr);
break;
case 0x15:
return apu->Read(addr);
break;
case 0x14:
return addr & 0xFF;
break;
case 0x16:
if (rom->IsVSUNISYSTEM()) {
return pad->Read(addr);
}
else {
return pad->Read(addr) | 0x40 | m_TapeOut;
}
break;
case 0x17:
if (rom->IsVSUNISYSTEM()) {
return pad->Read(addr);
}
else {
return pad->Read(addr) | apu->Read(addr);
}
break;
default:
return mapper->ExRead(addr);
break;
}
}
2024-07-31 17:40:32 +08:00
void NES::WriteReg(WORD addr, BYTE data)
{
2024-07-31 17:40:32 +08:00
switch (addr & 0xFF) {
case 0x00: case 0x01: case 0x02: case 0x03:
case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0A: case 0x0B:
case 0x0C: case 0x0D: case 0x0E: case 0x0F:
case 0x10: case 0x11: case 0x12: case 0x13:
case 0x15:
apu->Write(addr, data);
CPUREG[addr & 0xFF] = data;
break;
case 0x14:
ppu->DMA(data);
cpu->DMA(514); // DMA Pending cycle
CPUREG[addr & 0xFF] = data;
break;
case 0x16:
mapper->ExWrite(addr, data); // For VS-Unisystem
pad->Write(addr, data);
CPUREG[addr & 0xFF] = data;
m_TapeIn = data;
break;
case 0x17:
CPUREG[addr & 0xFF] = data;
pad->Write(addr, data);
apu->Write(addr, data);
break;
// VirtuaNES<EFBFBD>V g<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
case 0x18:
apu->Write(addr, data);
break;
#if NES_PROFILER
2024-07-31 17:40:32 +08:00
case 0x1D:
m_dwProfileAveCycle = 0;
m_dwProfileMaxCycle = 0;
break;
case 0x1E:
m_dwProfileTempCycle = cpu->GetTotalCycles();
break;
case 0x1F:
m_dwProfileCycle = cpu->GetTotalCycles() - m_dwProfileTempCycle - 4;
if (!m_dwProfileAveCycle) {
m_dwProfileAveCycle += m_dwProfileCycle;
}
else {
m_dwProfileAveCycle += m_dwProfileCycle;
m_dwProfileAveCycle /= 2;
}
if (m_dwProfileMaxCycle < m_dwProfileCycle) {
m_dwProfileMaxCycle = m_dwProfileCycle;
}
break;
#endif
#if 0
2024-07-31 17:40:32 +08:00
case 0x1C:
m_dwProfileTempCycle = cpu->GetTotalCycles();
break;
case 0x1D:
m_dwProfileCycle = cpu->GetTotalCycles() - m_dwProfileTempCycle - 4;
m_dwProfileTotalCycle += m_dwProfileCycle;
m_dwProfileTotalCount++;
break;
case 0x1E:
m_dwProfileTotalCount = 0;
m_dwProfileTotalCycle = 0;
m_dwTotalTempCycle = cpu->GetTotalCycles();
break;
case 0x1F:
m_dwTotalCycle = cpu->GetTotalCycles() - m_dwTotalTempCycle - 4;
break;
#endif
2024-07-31 17:40:32 +08:00
default:
mapper->ExWrite(addr, data);
break;
}
}
void NES::LoadSRAM()
{
2024-07-31 17:40:32 +08:00
if (rom->IsNSF())
return;
2024-07-31 17:40:32 +08:00
ZEROMEMORY(WRAM, sizeof(WRAM));
2024-07-31 17:40:32 +08:00
if (!rom->IsSAVERAM())
return;
string pathstr, tempstr;
2024-07-31 17:40:32 +08:00
if (Config.path.bSavePath) {
pathstr = CPathlib::CreatePath(CApp::GetModulePath(), Config.path.szSavePath);
}
else {
pathstr = rom->GetRomPath();
}
2024-07-31 17:40:32 +08:00
tempstr = CPathlib::MakePathExt(pathstr.c_str(), rom->GetRomName(), "sav");
DEBUGOUT("Path: %s\n", tempstr.c_str());
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
try
{
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(tempstr.c_str(), "rb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, tempstr.c_str());
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("Loading SAVERAM...");
LONG size;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>S<EFBFBD>_
2024-07-31 17:40:32 +08:00
::fseek(fp, 0, SEEK_END);
size = ftell(fp);
::fseek(fp, 0, SEEK_SET);
if (size <= 128 * 1024) {
if (::fread(WRAM, size, 1, fp) != 1)
throw "File Read error.";
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
FCLOSE(fp);
}
catch (CHAR* str) {
FCLOSE(fp);
DEBUGOUT("Loading SAVERAM Error.\n");
DEBUGOUT("%s\n", str);
// throw str;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
FCLOSE(fp);
DEBUGOUT("Loading SAVERAM Error.\n");
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
}
void NES::SaveSRAM()
{
2024-07-31 17:40:32 +08:00
INT i;
2024-07-31 17:40:32 +08:00
if (rom->IsNSF())
return;
2024-07-31 17:40:32 +08:00
if (!rom->IsSAVERAM())
return;
2024-07-31 17:40:32 +08:00
for (i = 0; i < SAVERAM_SIZE; i++) {
if (WRAM[i] != 0x00)
break;
}
2024-07-31 17:40:32 +08:00
if (i < SAVERAM_SIZE) {
DEBUGOUT("Saving SAVERAM...\n");
string pathstr, tempstr;
2024-07-31 17:40:32 +08:00
if (Config.path.bSavePath) {
pathstr = CPathlib::CreatePath(CApp::GetModulePath(), Config.path.szSavePath);
::CreateDirectory(pathstr.c_str(), NULL);
}
else {
pathstr = rom->GetRomPath();
}
2024-07-31 17:40:32 +08:00
tempstr = CPathlib::MakePathExt(pathstr.c_str(), rom->GetRomName(), "sav");
DEBUGOUT("Path: %s\n", tempstr.c_str());
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
try
{
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(tempstr.c_str(), "wb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, tempstr.c_str());
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
if (::fwrite(WRAM, SAVERAM_SIZE, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
FCLOSE(fp);
}
catch (CHAR* str) {
DEBUGOUT("Writing SAVERAM Error.\n");
FCLOSE(fp);
throw str;
2024-07-31 17:40:32 +08:00
#ifndef _DEBUG
}
catch (...) {
DEBUGOUT("Writing SAVERAM Error.\n");
FCLOSE(fp);
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
}
}
void NES::LoadDISK()
{
2024-07-31 17:40:32 +08:00
if (rom->GetMapperNo() != 20)
return;
BOOL bExit = FALSE;
INT i, j, diskno;
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
DISKIMGFILEHDR ifh;
DISKIMGHDR hdr;
LPBYTE disk;
WORD Version;
string pathstr, tempstr;
2024-07-31 17:40:32 +08:00
if (Config.path.bSavePath) {
pathstr = CPathlib::CreatePath(CApp::GetModulePath(), Config.path.szSavePath);
}
else {
pathstr = rom->GetRomPath();
}
2024-07-31 17:40:32 +08:00
tempstr = CPathlib::MakePathExt(pathstr.c_str(), rom->GetRomName(), "dsv");
DEBUGOUT("Path: %s\n", tempstr.c_str());
try
{
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(tempstr.c_str(), "rb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, tempstr.c_str());
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
if (::fread(&ifh, sizeof(DISKIMGFILEHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
if (::memcmp(ifh.ID, "VirtuaNES DI", sizeof(ifh.ID)) == 0) {
if (ifh.BlockVersion < 0x0100 && ifh.BlockVersion > 0x200) {
// *g<EFBFBD>[<EFBFBD>_b__g0Y0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNSUPPORTFORMAT);
}
Version = ifh.BlockVersion;
2024-07-31 17:40:32 +08:00
}
else {
// *g<EFBFBD>[<EFBFBD>_b__g0Y0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNSUPPORTFORMAT);
}
2024-07-31 17:40:32 +08:00
if (Version == 0x0100) {
// Ver0.24<EFBFBD>NMR
if (ifh.DiskNumber > 4) {
// *g<EFBFBD>[<EFBFBD>_b__g0Y0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNSUPPORTFORMAT);
}
2024-07-31 17:40:32 +08:00
for (i = 0; i < (INT)ifh.DiskNumber; i++) {
if (::fread(&hdr, sizeof(DISKIMGHDR), 1, fp) != 1) {
if (i == 0) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
else {
break;
}
}
2024-07-31 17:40:32 +08:00
if (::memcmp(hdr.ID, "SIDE0A", sizeof(hdr.ID)) == 0) {
diskno = 0;
2024-07-31 17:40:32 +08:00
}
else if (::memcmp(hdr.ID, "SIDE0B", sizeof(hdr.ID)) == 0) {
diskno = 1;
2024-07-31 17:40:32 +08:00
}
else if (::memcmp(hdr.ID, "SIDE1A", sizeof(hdr.ID)) == 0) {
diskno = 2;
2024-07-31 17:40:32 +08:00
}
else if (::memcmp(hdr.ID, "SIDE1B", sizeof(hdr.ID)) == 0) {
diskno = 3;
2024-07-31 17:40:32 +08:00
}
else {
// *g<EFBFBD>[<EFBFBD>_b__g0Y0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNSUPPORTFORMAT);
}
2024-07-31 17:40:32 +08:00
for (j = 0; j < 16; j++) {
if (hdr.DiskTouch[j]) {
disk = rom->GetPROM() + 16 + 65500 * diskno + (4 * 1024) * j;
if (j < 15) {
if (::fread(disk, 4 * 1024, 1, fp) != 1) {
bExit = TRUE;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
}
else {
if (::fread(disk, 4 * 1024 - 36, 1, fp) != 1) {
bExit = TRUE;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
}
}
}
}
2024-07-31 17:40:32 +08:00
}
else
if (Version == 0x0200 || Version == 0x0210) {
// Ver0.30<EFBFBD>NM<EFBFBD>
DISKFILEHDR dfh;
LPBYTE lpDisk = rom->GetPROM();
LPBYTE lpWrite = rom->GetDISK();
LONG DiskSize = 16 + 65500 * rom->GetDiskNo();
DWORD pos;
BYTE data;
2024-07-31 17:40:32 +08:00
// <EFBFBD>fM0<EFBFBD>cH0FLAG<EFBFBD>m<EFBFBD>S
::ZeroMemory(lpWrite, 16 + 65500 * rom->GetDiskNo());
2024-07-31 17:40:32 +08:00
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>0<EFBFBD>vW0
if (::fseek(fp, 0, SEEK_SET)) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
if (::fread(&dfh, sizeof(DISKFILEHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
if (Config.emulator.bCrcCheck) {
// <EFBFBD>s(W<EFBFBD>0<EFBFBD>0<EFBFBD>0-Nn0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0h0U<EFBFBD>F0K0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
if (dfh.ProgID != rom->GetGameID()
|| dfh.MakerID != (WORD)rom->GetMakerID()
|| dfh.DiskNo != (WORD)rom->GetDiskNo()) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
}
for (i = 0; i < dfh.DifferentSize; i++) {
if (::fread(&pos, sizeof(DWORD), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
bExit = TRUE;
throw CApp::GetErrorString(IDS_ERROR_READ);
}
data = (BYTE)(pos >> 24);
pos &= 0x00FFFFFF;
if (pos >= 16 && pos < DiskSize) {
lpDisk[pos] = data;
lpWrite[pos] = 0xFF;
}
}
}
2024-07-31 17:40:32 +08:00
FCLOSE(fp);
}
catch (CHAR* str) {
FCLOSE(fp);
DEBUGOUT("%s\n", str);
if (bExit)
throw str;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
FCLOSE(fp);
DEBUGOUT("Loading DISKIMAGE Error.\n");
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
}
void NES::SaveDISK()
{
2024-07-31 17:40:32 +08:00
if (rom->GetMapperNo() != 20)
return;
INT i;
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
DISKFILEHDR ifh;
2024-07-31 17:40:32 +08:00
LPBYTE lpDisk = rom->GetPROM();
LPBYTE lpWrite = rom->GetDISK();
2024-07-31 17:40:32 +08:00
LONG DiskSize = 16 + 65500 * rom->GetDiskNo();
DWORD data;
try
{
2024-07-31 17:40:32 +08:00
::ZeroMemory(&ifh, sizeof(ifh));
2024-07-31 17:40:32 +08:00
::memcpy(ifh.ID, "VirtuaNES DI", sizeof(ifh.ID));
ifh.BlockVersion = 0x0210;
2024-07-31 17:40:32 +08:00
ifh.ProgID = rom->GetGameID();
ifh.MakerID = (WORD)rom->GetMakerID();
2024-07-31 17:40:32 +08:00
ifh.DiskNo = (WORD)rom->GetDiskNo();
// <EFBFBD>vU<EFBFBD>pe<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
for (i = 16; i < DiskSize; i++) {
if (lpWrite[i])
ifh.DifferentSize++;
}
2024-07-31 17:40:32 +08:00
if (!ifh.DifferentSize)
return;
string pathstr, tempstr;
2024-07-31 17:40:32 +08:00
if (Config.path.bSavePath) {
pathstr = CPathlib::CreatePath(CApp::GetModulePath(), Config.path.szSavePath);
::CreateDirectory(pathstr.c_str(), NULL);
}
else {
pathstr = rom->GetRomPath();
}
2024-07-31 17:40:32 +08:00
tempstr = CPathlib::MakePathExt(pathstr.c_str(), rom->GetRomName(), "dsv");
DEBUGOUT("Path: %s\n", tempstr.c_str());
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(tempstr.c_str(), "wb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
::wsprintf(szErrorString, szErrStr, tempstr.c_str());
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
if (::fwrite(&ifh, sizeof(DISKFILEHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
for (i = 16; i < DiskSize; i++) {
if (lpWrite[i]) {
data = i & 0x00FFFFFF;
2024-07-31 17:40:32 +08:00
data |= ((DWORD)lpDisk[i] & 0xFF) << 24;
// Write File
2024-07-31 17:40:32 +08:00
if (::fwrite(&data, sizeof(DWORD), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
}
2024-07-31 17:40:32 +08:00
FCLOSE(fp);
}
catch (CHAR* str) {
FCLOSE(fp);
DEBUGOUT("%s\n", str);
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
FCLOSE(fp);
DEBUGOUT("Saving DISKIMAGE Error.\n");
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
}
void NES::LoadTurboFile()
{
2024-07-31 17:40:32 +08:00
ZEROMEMORY(ERAM, sizeof(ERAM));
2024-07-31 17:40:32 +08:00
if (pad->GetExController() != PAD::EXCONTROLLER_TURBOFILE)
return;
string pathstr, tempstr;
2024-07-31 17:40:32 +08:00
if (Config.path.bSavePath) {
pathstr = CPathlib::CreatePath(CApp::GetModulePath(), Config.path.szSavePath);
}
else {
pathstr = rom->GetRomPath();
}
2024-07-31 17:40:32 +08:00
tempstr = CPathlib::MakePathExt(pathstr.c_str(), "TurboFile", "vtf");
DEBUGOUT("Path: %s\n", tempstr.c_str());
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
try
{
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(tempstr.c_str(), "rb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, tempstr.c_str());
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("Loading TURBOFILE...");
LONG size;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>S<EFBFBD>_
2024-07-31 17:40:32 +08:00
::fseek(fp, 0, SEEK_END);
size = ftell(fp);
::fseek(fp, 0, SEEK_SET);
if (size > 32 * 1024) {
size = 32 * 1024;
}
2024-07-31 17:40:32 +08:00
if (::fread(ERAM, size, 1, fp) != 1)
throw "File Read error.";
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
FCLOSE(fp);
}
catch (CHAR* str) {
FCLOSE(fp);
DEBUGOUT("Loading TurboFile Error.\n");
DEBUGOUT("%s\n", str);
// throw str;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
FCLOSE(fp);
DEBUGOUT("Loading TurboFile Error.\n");
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
}
void NES::SaveTurboFile()
{
2024-07-31 17:40:32 +08:00
INT i;
2024-07-31 17:40:32 +08:00
if (pad->GetExController() != PAD::EXCONTROLLER_TURBOFILE)
return;
2024-07-31 17:40:32 +08:00
for (i = 0; i < sizeof(ERAM); i++) {
if (ERAM[i] != 0x00)
break;
}
2024-07-31 17:40:32 +08:00
if (i < sizeof(ERAM)) {
DEBUGOUT("Saving TURBOFILE...\n");
string pathstr, tempstr;
2024-07-31 17:40:32 +08:00
if (Config.path.bSavePath) {
pathstr = CPathlib::CreatePath(CApp::GetModulePath(), Config.path.szSavePath);
::CreateDirectory(pathstr.c_str(), NULL);
}
else {
pathstr = rom->GetRomPath();
}
2024-07-31 17:40:32 +08:00
tempstr = CPathlib::MakePathExt(pathstr.c_str(), "TurboFile", "vtf");
DEBUGOUT("Path: %s\n", tempstr.c_str());
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
try
{
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(tempstr.c_str(), "wb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, tempstr.c_str());
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
if (::fwrite(ERAM, sizeof(ERAM), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("Ok.\n");
FCLOSE(fp);
}
catch (CHAR* str) {
DEBUGOUT("Writing TurboFile Error.\n");
FCLOSE(fp);
throw str;
2024-07-31 17:40:32 +08:00
#ifndef _DEBUG
}
catch (...) {
DEBUGOUT("Writing TurboFile Error.\n");
FCLOSE(fp);
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
}
}
2024-07-31 17:40:32 +08:00
INT NES::IsStateFile(const char* fname, ROM* rom)
{
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
FILEHDR2 header;
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(fname, "rb")))
return -1;
2024-07-31 17:40:32 +08:00
if (::fread(&header, sizeof(header), 1, fp) != 1) {
FCLOSE(fp);
return -1;
}
2024-07-31 17:40:32 +08:00
FCLOSE(fp);
2024-07-31 17:40:32 +08:00
if (::memcmp(header.ID, "VirtuaNES ST", sizeof(header.ID)) == 0) {
if (header.BlockVersion < 0x0100)
return 0;
2024-07-31 17:40:32 +08:00
if (Config.emulator.bCrcCheck) {
if (header.BlockVersion >= 0x200) {
if (rom->GetMapperNo() != 20) {
// FDS<EFBFBD>NY
if (header.Ext0 != rom->GetPROM_CRC()) {
return IDS_ERROR_ILLEGALSTATECRC; // U<EFBFBD>F0X0<EFBFBD>0<EFBFBD>0
}
2024-07-31 17:40:32 +08:00
}
else {
// FDS
if (header.Ext0 != rom->GetGameID() ||
header.Ext1 != (WORD)rom->GetMakerID() ||
header.Ext2 != (WORD)rom->GetDiskNo())
return IDS_ERROR_ILLEGALSTATECRC; // U<EFBFBD>F0X0<EFBFBD>0<EFBFBD>0
}
}
}
return 0;
}
return -1;
}
2024-07-31 17:40:32 +08:00
BOOL NES::LoadState(const char* fname)
{
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
BOOL bRet = FALSE;
2024-07-31 17:40:32 +08:00
if (rom->IsNSF())
return TRUE;
try {
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(fname, "rb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, fname);
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
bRet = ReadState(fp);
2024-07-31 17:40:32 +08:00
FCLOSE(fp);
}
catch (CHAR* str) {
DEBUGOUT("State load error.\n");
DEBUGOUT("%s\n", str);
FCLOSE(fp);
return FALSE;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
DEBUGOUT("State load error.\n");
FCLOSE(fp);
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
return bRet;
}
2024-07-31 17:40:32 +08:00
BOOL NES::SaveState(const char* fname)
{
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
2024-07-31 17:40:32 +08:00
if (rom->IsNSF())
return TRUE;
try {
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(fname, "wb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, fname);
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
WriteState(fp);
2024-07-31 17:40:32 +08:00
FCLOSE(fp);
}
catch (CHAR* str) {
DEBUGOUT("State save error.\n");
FCLOSE(fp);
throw str;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
DEBUGOUT("State save error.\n");
FCLOSE(fp);
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
return TRUE;
}
2024-07-31 17:40:32 +08:00
BOOL NES::ReadState(FILE* fp)
{
INT i;
BOOL bHeader = FALSE;
WORD Version = 0;
BLOCKHDR hdr;
INT type;
2024-07-31 17:40:32 +08:00
while (TRUE) {
// Read File
2024-07-31 17:40:32 +08:00
if (::fread(&hdr, sizeof(BLOCKHDR), 1, fp) != 1)
break;
// File Header check
2024-07-31 17:40:32 +08:00
if (!bHeader) {
LPFILEHDR fh = (LPFILEHDR)&hdr;
2024-07-31 17:40:32 +08:00
if (::memcmp(fh->ID, "VirtuaNES ST", sizeof(fh->ID)) == 0) {
Version = fh->BlockVersion;
2024-07-31 17:40:32 +08:00
if (Version == 0x0100) {
// Ver0.24~0g0
bHeader = TRUE;
// <EFBFBD>SD0tYo0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0-No0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>Qeg~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
if (m_bMoviePlay) {
return FALSE;
}
// <EFBFBD>SD0tYn0FDSo0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>Qeg~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
if (rom->GetMapperNo() == 20) {
// *g<EFBFBD>[<EFBFBD>_b__g0Y0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNSUPPORTFORMAT);
}
2024-07-31 17:40:32 +08:00
}
else
if (Version == 0x0200 || Version == 0x0210) {
// Ver0.30<EFBFBD>NM<EFBFBD> Ver0.60<EFBFBD>NM<EFBFBD>
FILEHDR2 hdr2;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>vW0
if (::fseek(fp, -sizeof(BLOCKHDR), SEEK_CUR)) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
// Read File
if (::fread(&hdr2, sizeof(FILEHDR2), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
#if 0
2024-07-31 17:40:32 +08:00
if (Config.emulator.bCrcCheck) {
// <EFBFBD>s(W<EFBFBD>0<EFBFBD>0<EFBFBD>0-Nn0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0h0U<EFBFBD>F0K0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
if (rom->GetMapperNo() != 20) {
// FDS<EFBFBD>NY
if (hdr2.Ext0 != rom->GetPROM_CRC()) {
return FALSE; // U<EFBFBD>F0X0<EFBFBD>0<EFBFBD>0
}
}
2024-07-31 17:40:32 +08:00
else {
// FDS
if (hdr2.Ext0 != rom->GetGameID() ||
hdr2.Ext1 != (WORD)rom->GetMakerID() ||
hdr2.Ext2 != (WORD)rom->GetDiskNo())
return FALSE; // U<EFBFBD>F0X0<EFBFBD>0<EFBFBD>0
}
}
#endif
2024-07-31 17:40:32 +08:00
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0-No0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0h0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0pe<EFBFBD>0
// Y<EFBFBD>fW0f0 <EFBFBD><EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>2<EFBFBD><EFBFBD>0<EFBFBD>0<EFBFBD>0k0 Y<EFBFBD>f
if (m_bMoviePlay || m_bMovieRec) {
// <EFBFBD>d<EFBFBD>0<EFBFBD>vW0<EFBFBD>S<EFBFBD><EFBFBD><EFBFBD>
if (m_hedMovie.Control & 0x80) {
if (hdr2.MovieOffset && hdr2.MovieStep) {
if (m_bMoviePlay) {
// <EFBFBD>Qu-N
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0peL0<EFBFBD>2<EFBFBD><EFBFBD>0<EFBFBD>02<EFBFBD><EFBFBD>0g0_0<EFBFBD>0<EFBFBD>0<EFBFBD>0
if (hdr2.MovieStep > m_hedMovie.MovieStep)
return FALSE;
}
else {
// <EFBFBD>2<EFBFBD>-N
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0peL0<EFBFBD>s(W<EFBFBD>0<EFBFBD>02<EFBFBD><EFBFBD>0g0_0<EFBFBD>0<EFBFBD>0<EFBFBD>0
if (hdr2.MovieStep > m_MovieStep)
return FALSE;
}
//DEBUGOUT( "LD STEP=%d POS=%d\n", hdr2.MovieStep, hdr2.MovieOffset );
m_bMoviePlay = FALSE;
m_bMovieRec = TRUE;
m_MovieStep = hdr2.MovieStep;
m_hedMovie.RecordTimes++; // <EFBFBD>d<EFBFBD>0<EFBFBD>vW0<EFBFBD>Vpe+1
if (::fseek(m_fpMovie, hdr2.MovieOffset, SEEK_SET)) {
//DEBUGOUT( "MOVIE:STATE LOAD SEEK 1YWe\n" );
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
}
2024-07-31 17:40:32 +08:00
else {
return FALSE;
}
2024-07-31 17:40:32 +08:00
}
else {
return FALSE;
}
}
2024-07-31 17:40:32 +08:00
}
bHeader = TRUE;
continue;
}
2024-07-31 17:40:32 +08:00
}
2024-07-31 17:40:32 +08:00
if (!bHeader) {
// *g<EFBFBD>[<EFBFBD>_b__g0Y0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNSUPPORTFORMAT);
}
2024-07-31 17:40:32 +08:00
//DEBUGOUT( "HEADER ID=%8s\n", hdr.ID );
type = -1;
2024-07-31 17:40:32 +08:00
if (::memcmp(hdr.ID, "REG DATA", sizeof(hdr.ID)) == 0)
type = 0;
2024-07-31 17:40:32 +08:00
if (::memcmp(hdr.ID, "RAM DATA", sizeof(hdr.ID)) == 0)
type = 1;
2024-07-31 17:40:32 +08:00
if (::memcmp(hdr.ID, "MMU DATA", sizeof(hdr.ID)) == 0)
type = 2;
2024-07-31 17:40:32 +08:00
if (::memcmp(hdr.ID, "MMC DATA", sizeof(hdr.ID)) == 0)
type = 3;
2024-07-31 17:40:32 +08:00
if (::memcmp(hdr.ID, "CTR DATA", sizeof(hdr.ID)) == 0)
type = 4;
2024-07-31 17:40:32 +08:00
if (::memcmp(hdr.ID, "SND DATA", sizeof(hdr.ID)) == 0)
type = 5;
2024-07-31 17:40:32 +08:00
if (rom->GetMapperNo() == 20) {
if (::memcmp(hdr.ID, "DISKDATA", sizeof(hdr.ID)) == 0)
type = 6;
}
2024-07-31 17:40:32 +08:00
if (::memcmp(hdr.ID, "EXCTRDAT", sizeof(hdr.ID)) == 0)
type = 7;
2024-07-31 17:40:32 +08:00
if (type == -1) {
//DEBUGOUT( "UNKNOWN HEADER ID=%8s\n", hdr.ID );
break;
}
2024-07-31 17:40:32 +08:00
switch (type) {
case 0:
// REGISTER STATE
{
if (hdr.BlockVersion < 0x0200) {
REGSTAT_O reg;
if (::fread(&reg, sizeof(REGSTAT_O), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
// LOAD CPU STATE
R6502 R;
R.PC = reg.cpureg.cpu.PC;
R.A = reg.cpureg.cpu.A;
R.X = reg.cpureg.cpu.X;
R.Y = reg.cpureg.cpu.Y;
R.S = reg.cpureg.cpu.S;
R.P = reg.cpureg.cpu.P;
R.INT_pending = reg.cpureg.cpu.I;
cpu->SetContext(R);
// FrameIRQ = reg.cpureg.cpu.FrameIRQ;
if (hdr.BlockVersion < 0x0110) {
emul_cycles = 0;
base_cycles = reg.cpureg.cpu.mod_cycles;
}
else if (hdr.BlockVersion == 0x0110) {
// FrameIRQ_cycles = reg.cpureg.cpu.mod_cycles;
emul_cycles = reg.cpureg.cpu.emul_cycles;
base_cycles = reg.cpureg.cpu.base_cycles;
2024-07-31 17:40:32 +08:00
}
2024-07-31 17:40:32 +08:00
// LOAD PPU STATE
PPUREG[0] = reg.ppureg.ppu.reg0;
PPUREG[1] = reg.ppureg.ppu.reg1;
PPUREG[2] = reg.ppureg.ppu.reg2;
PPUREG[3] = reg.ppureg.ppu.reg3;
PPU7_Temp = reg.ppureg.ppu.reg7;
loopy_t = reg.ppureg.ppu.loopy_t;
loopy_v = reg.ppureg.ppu.loopy_v;
loopy_x = reg.ppureg.ppu.loopy_x;
PPU56Toggle = reg.ppureg.ppu.toggle56;
}
else {
REGSTAT reg;
if (::fread(&reg, sizeof(REGSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
// LOAD CPU STATE
R6502 R;
R.PC = reg.cpureg.cpu.PC;
R.A = reg.cpureg.cpu.A;
R.X = reg.cpureg.cpu.X;
R.Y = reg.cpureg.cpu.Y;
R.S = reg.cpureg.cpu.S;
R.P = reg.cpureg.cpu.P;
R.INT_pending = reg.cpureg.cpu.I;
cpu->SetContext(R);
if (hdr.BlockVersion == 0x0200) {
// FrameIRQ = reg.cpureg.cpu.FrameIRQ;
// bFrameIRQ_occur = (reg.cpureg.cpu.FrameIRQ_occur!=0)?TRUE:FALSE;
// FrameIRQ_cycles = reg.cpureg.cpu.FrameIRQ_cycles;
}
2024-07-31 17:40:32 +08:00
else {
apu->SetFrameIRQ(reg.cpureg.cpu.FrameIRQ_cycles,
reg.cpureg.cpu.FrameIRQ_count,
reg.cpureg.cpu.FrameIRQ_type,
reg.cpureg.cpu.FrameIRQ,
reg.cpureg.cpu.FrameIRQ_occur);
}
emul_cycles = reg.cpureg.cpu.emul_cycles;
base_cycles = reg.cpureg.cpu.base_cycles;
cpu->SetDmaCycles((INT)reg.cpureg.cpu.DMA_cycles);
// LOAD PPU STATE
PPUREG[0] = reg.ppureg.ppu.reg0;
PPUREG[1] = reg.ppureg.ppu.reg1;
PPUREG[2] = reg.ppureg.ppu.reg2;
PPUREG[3] = reg.ppureg.ppu.reg3;
PPU7_Temp = reg.ppureg.ppu.reg7;
loopy_t = reg.ppureg.ppu.loopy_t;
loopy_v = reg.ppureg.ppu.loopy_v;
loopy_x = reg.ppureg.ppu.loopy_x;
PPU56Toggle = reg.ppureg.ppu.toggle56;
}
// APU STATE
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>mY0
apu->QueueClear();
// APU<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>OX[Y0<EFBFBD>0<EFBFBD>0F0k0W0_0n0g0<EFBFBD>0<EFBFBD>0
// // DMCo0bk<EFBFBD>0j0D0h0~0Z0D0<EFBFBD>NL0w<EFBFBD>S0<EFBFBD>0
// for( i = 0x4010; i <= 0x4013; i++ ) {
// apu->Write( i, 0 );
// }
}
break;
case 1:
// RAM STATE
{
RAMSTAT ram;
if (::fread(&ram, sizeof(RAMSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
::memcpy(RAM, ram.RAM, sizeof(ram.RAM));
::memcpy(BGPAL, ram.BGPAL, sizeof(ram.BGPAL));
::memcpy(SPPAL, ram.SPPAL, sizeof(ram.SPPAL));
::memcpy(SPRAM, ram.SPRAM, sizeof(ram.SPRAM));
if (rom->IsSAVERAM()) {
if (::fread(WRAM, SAVERAM_SIZE, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
}
}
break;
case 2:
// BANK STATE
{
MMUSTAT mmu;
if (::fread(&mmu, sizeof(MMUSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
if (hdr.BlockVersion == 0x100) {
// a0<EFBFBD>0c0h0MRn0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
if (mmu.CPU_MEM_TYPE[3] == BANKTYPE_RAM
|| mmu.CPU_MEM_TYPE[3] == BANKTYPE_DRAM) {
if (::fread(CPU_MEM_BANK[3], 8 * 1024, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
}
else if (!rom->IsSAVERAM()) {
SetPROM_8K_Bank(3, mmu.CPU_MEM_PAGE[3]);
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0003<EFBFBD>NY<EFBFBD>0<EFBFBD>0<EFBFBD>0
for (i = 4; i < 8; i++) {
CPU_MEM_TYPE[i] = mmu.CPU_MEM_TYPE[i];
CPU_MEM_PAGE[i] = mmu.CPU_MEM_PAGE[i];
if (CPU_MEM_TYPE[i] == BANKTYPE_ROM) {
SetPROM_8K_Bank(i, CPU_MEM_PAGE[i]);
}
else {
if (::fread(CPU_MEM_BANK[i], 8 * 1024, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
}
2024-07-31 17:40:32 +08:00
}
}
else if (hdr.BlockVersion == 0x200) {
// g<EFBFBD>e<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
// SRAML0B0c0f0<EFBFBD>0hQ<EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>0<EFBFBD>0W0j0J0W0
2024-07-31 17:40:32 +08:00
for (i = 3; i < 8; i++) {
CPU_MEM_TYPE[i] = mmu.CPU_MEM_TYPE[i];
CPU_MEM_PAGE[i] = mmu.CPU_MEM_PAGE[i];
if (CPU_MEM_TYPE[i] == BANKTYPE_ROM) {
SetPROM_8K_Bank(i, CPU_MEM_PAGE[i]);
}
2024-07-31 17:40:32 +08:00
else {
if (::fread(CPU_MEM_BANK[i], 8 * 1024, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
}
}
2024-07-31 17:40:32 +08:00
}
// VRAM
if (::fread(VRAM, 4 * 1024, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
// CRAM
for (i = 0; i < 8; i++) {
if (mmu.CRAM_USED[i] != 0) {
if (::fread(&CRAM[0x1000 * i], 4 * 1024, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
}
2024-07-31 17:40:32 +08:00
}
// BANK
for (i = 0; i < 12; i++) {
if (mmu.PPU_MEM_TYPE[i] == BANKTYPE_VROM) {
SetVROM_1K_Bank(i, mmu.PPU_MEM_PAGE[i]);
}
2024-07-31 17:40:32 +08:00
else if (mmu.PPU_MEM_TYPE[i] == BANKTYPE_CRAM) {
SetCRAM_1K_Bank(i, mmu.PPU_MEM_PAGE[i]);
}
2024-07-31 17:40:32 +08:00
else if (mmu.PPU_MEM_TYPE[i] == BANKTYPE_VRAM) {
SetVRAM_1K_Bank(i, mmu.PPU_MEM_PAGE[i]);
}
2024-07-31 17:40:32 +08:00
else {
throw "Unknown bank types.";
}
2024-07-31 17:40:32 +08:00
}
}
break;
case 3:
// MMC STATE
{
MMCSTAT mmc;
if (::fread(&mmc, sizeof(MMCSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
mapper->LoadState(mmc.mmcdata);
}
break;
case 4:
// CTR STATE
{
CTRSTAT ctr;
if (::fread(&ctr, sizeof(CTRSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
pad->pad1bit = ctr.ctrreg.ctr.pad1bit;
pad->pad2bit = ctr.ctrreg.ctr.pad2bit;
pad->pad3bit = ctr.ctrreg.ctr.pad3bit;
pad->pad4bit = ctr.ctrreg.ctr.pad4bit;
pad->SetStrobe((ctr.ctrreg.ctr.strobe != 0) ? TRUE : FALSE);
}
break;
2024-07-31 17:40:32 +08:00
case 5:
// SND STATE
{
SNDSTAT snd;
if (::fread(&snd, sizeof(SNDSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
apu->LoadState(snd.snddata);
}
break;
2024-07-31 17:40:32 +08:00
// Disk Images
// Ver0.30<EFBFBD>NM<EFBFBD>
case 6:
{
DISKDATA ddata;
DWORD pos;
BYTE data;
LONG DiskSize = 16 + 65500 * rom->GetDiskNo();
LPBYTE lpDisk = rom->GetPROM();
LPBYTE lpWrite = rom->GetDISK();
2024-07-31 17:40:32 +08:00
// <EFBFBD>fM0<EFBFBD>cH0FLAG<EFBFBD>m<EFBFBD>S
::ZeroMemory(lpWrite, 16 + 65500 * rom->GetDiskNo());
2024-07-31 17:40:32 +08:00
if (::fread(&ddata, sizeof(DISKDATA), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
for (i = 0; i < ddata.DifferentSize; i++) {
if (::fread(&pos, sizeof(DWORD), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
data = (BYTE)(pos >> 24);
pos &= 0x00FFFFFF;
if (pos >= 16 && pos < DiskSize) {
lpDisk[pos] = data;
lpWrite[pos] = 0xFF;
}
2024-07-31 17:40:32 +08:00
}
2024-07-31 17:40:32 +08:00
}
break;
2024-07-31 17:40:32 +08:00
// EXCTR STATE
case 7:
{
EXCTRSTAT exctr;
if (::fread(&exctr, sizeof(EXCTRSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
pad->SetSyncExData(exctr.data);
}
2024-07-31 17:40:32 +08:00
break;
}
}
return TRUE;
}
2024-07-31 17:40:32 +08:00
void NES::WriteState(FILE* fp)
{
INT i;
// HEADER
{
2024-07-31 17:40:32 +08:00
FILEHDR2 hdr;
2024-07-31 17:40:32 +08:00
ZEROMEMORY(&hdr, sizeof(FILEHDR2));
::memcpy(hdr.ID, "VirtuaNES ST", sizeof(hdr.ID));
hdr.BlockVersion = 0x0200;
2024-07-31 17:40:32 +08:00
if (rom->GetMapperNo() != 20) {
hdr.Ext0 = rom->GetPROM_CRC();
}
else {
hdr.Ext0 = rom->GetGameID();
hdr.Ext1 = (WORD)rom->GetMakerID();
hdr.Ext2 = (WORD)rom->GetDiskNo();
}
2024-07-31 17:40:32 +08:00
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>Qu<EFBFBD>0<EFBFBD>2<EFBFBD>-Ng0B0<EFBFBD>0p0]0n0MOn<EFBFBD>0<EFBFBD>2<EFBFBD>Y0<EFBFBD>0
if (m_bMoviePlay || m_bMovieRec) {
hdr.MovieStep = m_MovieStep;
hdr.MovieOffset = ::ftell(m_fpMovie);
//DEBUGOUT( "\nSV STEP=%d POS=%d\n", m_MovieStep, hdr.MovieOffset );
}
2024-07-31 17:40:32 +08:00
// Write File
if (::fwrite(&hdr, sizeof(FILEHDR2), 1, fp) != 1)
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
BLOCKHDR hdr;
// REGISTER STATE
{
2024-07-31 17:40:32 +08:00
REGSTAT reg;
2024-07-31 17:40:32 +08:00
ZEROMEMORY(&hdr, sizeof(BLOCKHDR));
ZEROMEMORY(&reg, sizeof(REGSTAT));
2024-07-31 17:40:32 +08:00
// Create Header
::memcpy(hdr.ID, "REG DATA", sizeof(hdr.ID));
hdr.BlockVersion = 0x0210;
hdr.BlockSize = sizeof(REGSTAT);
// SAVE CPU STATE
R6502 R;
cpu->GetContext(R);
reg.cpureg.cpu.PC = R.PC;
reg.cpureg.cpu.A = R.A;
reg.cpureg.cpu.X = R.X;
reg.cpureg.cpu.Y = R.Y;
reg.cpureg.cpu.S = R.S;
reg.cpureg.cpu.P = R.P;
reg.cpureg.cpu.I = R.INT_pending;
INT cycles;
apu->GetFrameIRQ(cycles,
reg.cpureg.cpu.FrameIRQ_count,
reg.cpureg.cpu.FrameIRQ_type,
reg.cpureg.cpu.FrameIRQ,
reg.cpureg.cpu.FrameIRQ_occur);
reg.cpureg.cpu.FrameIRQ_cycles = (LONG)cycles; // <EFBFBD>SgqL0INTj0<EFBFBD>p<EFBFBD>I0
reg.cpureg.cpu.DMA_cycles = (LONG)cpu->GetDmaCycles();
reg.cpureg.cpu.emul_cycles = emul_cycles;
reg.cpureg.cpu.base_cycles = base_cycles;
// SAVE PPU STATE
reg.ppureg.ppu.reg0 = PPUREG[0];
reg.ppureg.ppu.reg1 = PPUREG[1];
reg.ppureg.ppu.reg2 = PPUREG[2];
reg.ppureg.ppu.reg3 = PPUREG[3];
reg.ppureg.ppu.reg7 = PPU7_Temp;
reg.ppureg.ppu.loopy_t = loopy_t;
reg.ppureg.ppu.loopy_v = loopy_v;
reg.ppureg.ppu.loopy_x = loopy_x;
reg.ppureg.ppu.toggle56 = PPU56Toggle;
2024-07-31 17:40:32 +08:00
// Write File
if (::fwrite(&hdr, sizeof(BLOCKHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
if (::fwrite(&reg, sizeof(REGSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
// RAM STATE
{
2024-07-31 17:40:32 +08:00
RAMSTAT ram;
DWORD size = 0;
2024-07-31 17:40:32 +08:00
::ZeroMemory(&hdr, sizeof(BLOCKHDR));
::ZeroMemory(&ram, sizeof(RAMSTAT));
2024-07-31 17:40:32 +08:00
// SAVE RAM STATE
::memcpy(ram.RAM, RAM, sizeof(ram.RAM));
::memcpy(ram.BGPAL, BGPAL, sizeof(ram.BGPAL));
::memcpy(ram.SPPAL, SPPAL, sizeof(ram.SPPAL));
::memcpy(ram.SPRAM, SPRAM, sizeof(ram.SPRAM));
2024-07-31 17:40:32 +08:00
// S-RAM STATE(O(u/*gO(uk0<EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>0Z0X[(WY0<EFBFBD>0p0<EFBFBD>0<EFBFBD>0<EFBFBD>0Y0<EFBFBD>0)
if (rom->IsSAVERAM()) {
size = SAVERAM_SIZE;
}
2024-07-31 17:40:32 +08:00
// Create Header
::memcpy(hdr.ID, "RAM DATA", sizeof(hdr.ID));
hdr.BlockVersion = 0x0100;
hdr.BlockSize = size + sizeof(RAMSTAT);
2024-07-31 17:40:32 +08:00
// Write File
if (::fwrite(&hdr, sizeof(BLOCKHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
if (::fwrite(&ram, sizeof(RAMSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
if (rom->IsSAVERAM()) {
if (::fwrite(WRAM, SAVERAM_SIZE, 1, fp) != 1)
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
// BANK STATE
{
2024-07-31 17:40:32 +08:00
MMUSTAT mmu;
DWORD size;
::ZeroMemory(&hdr, sizeof(BLOCKHDR));
::ZeroMemory(&mmu, sizeof(MMUSTAT));
size = 0;
// SAVE CPU MEMORY BANK DATA
// BANK0,1,2o0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0k0<EFBFBD><EFBFBD><EFBFBD>Oj0W0
// VirtuaNES0.30K0<EFBFBD>0
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>o0SRAMO(uk0<EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>0Z0<EFBFBD>0<EFBFBD>0<EFBFBD>0
for (i = 3; i < 8; i++) {
mmu.CPU_MEM_TYPE[i] = CPU_MEM_TYPE[i];
mmu.CPU_MEM_PAGE[i] = CPU_MEM_PAGE[i];
if (CPU_MEM_TYPE[i] == BANKTYPE_RAM
|| CPU_MEM_TYPE[i] == BANKTYPE_DRAM) {
size += 8 * 1024; // 8K BANK
}
}
2024-07-31 17:40:32 +08:00
// SAVE VRAM MEMORY DATA
for (i = 0; i < 12; i++) {
mmu.PPU_MEM_TYPE[i] = PPU_MEM_TYPE[i];
mmu.PPU_MEM_PAGE[i] = PPU_MEM_PAGE[i];
}
size += 4 * 1024; // 1K BANK x 4 (VRAM)
2024-07-31 17:40:32 +08:00
for (i = 0; i < 8; i++) {
mmu.CRAM_USED[i] = CRAM_USED[i];
if (CRAM_USED[i] != 0) {
size += 4 * 1024; // 4K BANK
}
}
2024-07-31 17:40:32 +08:00
// Create Header
::memcpy(hdr.ID, "MMU DATA", sizeof(hdr.ID));
hdr.BlockVersion = 0x0200;
hdr.BlockSize = size + sizeof(MMUSTAT);
2024-07-31 17:40:32 +08:00
// Write File
if (::fwrite(&hdr, sizeof(BLOCKHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
if (::fwrite(&mmu, sizeof(MMUSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
// WRITE CPU RAM MEMORY BANK
for (i = 3; i < 8; i++) {
if (mmu.CPU_MEM_TYPE[i] != BANKTYPE_ROM) {
if (::fwrite(CPU_MEM_BANK[i], 8 * 1024, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
}
2024-07-31 17:40:32 +08:00
// WRITE VRAM MEMORY(8^k04KRY0y0f0<EFBFBD>fM0<EFBFBD><EFBFBD><EFBFBD>0)
if (::fwrite(VRAM, 4 * 1024, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
// WRITE CRAM MEMORY
for (i = 0; i < 8; i++) {
if (CRAM_USED[i] != 0) {
if (::fwrite(&CRAM[0x1000 * i], 4 * 1024, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
}
}
// MMC STATE
{
2024-07-31 17:40:32 +08:00
MMCSTAT mmc;
2024-07-31 17:40:32 +08:00
::ZeroMemory(&hdr, sizeof(BLOCKHDR));
::ZeroMemory(&mmc, sizeof(MMCSTAT));
2024-07-31 17:40:32 +08:00
// Create Header
::memcpy(hdr.ID, "MMC DATA", sizeof(hdr.ID));
hdr.BlockVersion = 0x0100;
hdr.BlockSize = sizeof(MMCSTAT);
2024-07-31 17:40:32 +08:00
if (mapper->IsStateSave()) {
mapper->SaveState(mmc.mmcdata);
// Write File
if (::fwrite(&hdr, sizeof(BLOCKHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
if (::fwrite(&mmc, sizeof(MMCSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
}
// CONTROLLER STATE
{
2024-07-31 17:40:32 +08:00
CTRSTAT ctr;
2024-07-31 17:40:32 +08:00
::ZeroMemory(&hdr, sizeof(BLOCKHDR));
::ZeroMemory(&ctr, sizeof(CTRSTAT));
2024-07-31 17:40:32 +08:00
// Create Header
::memcpy(hdr.ID, "CTR DATA", sizeof(hdr.ID));
hdr.BlockVersion = 0x0100;
hdr.BlockSize = sizeof(CTRSTAT);
2024-07-31 17:40:32 +08:00
ctr.ctrreg.ctr.pad1bit = pad->pad1bit;
ctr.ctrreg.ctr.pad2bit = pad->pad2bit;
ctr.ctrreg.ctr.pad3bit = pad->pad3bit;
ctr.ctrreg.ctr.pad4bit = pad->pad4bit;
ctr.ctrreg.ctr.strobe = pad->GetStrobe() ? 0xFF : 0;
//DEBUGOUT( "SV pad1bit=%08X Strobe=%d\n", pad->pad1bit, pad->GetStrobe()?1:0 );
2024-07-31 17:40:32 +08:00
if (::fwrite(&hdr, sizeof(BLOCKHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
if (::fwrite(&ctr, sizeof(CTRSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
// SND STATE
{
2024-07-31 17:40:32 +08:00
SNDSTAT snd;
2024-07-31 17:40:32 +08:00
::ZeroMemory(&hdr, sizeof(BLOCKHDR));
::ZeroMemory(&snd, sizeof(SNDSTAT));
2024-07-31 17:40:32 +08:00
// Create Header
::memcpy(hdr.ID, "SND DATA", sizeof(hdr.ID));
hdr.BlockVersion = 0x0100;
hdr.BlockSize = sizeof(SNDSTAT);
2024-07-31 17:40:32 +08:00
apu->SaveState(snd.snddata);
2024-07-31 17:40:32 +08:00
if (::fwrite(&hdr, sizeof(BLOCKHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
if (::fwrite(&snd, sizeof(SNDSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
// DISKIMAGE STATE
2024-07-31 17:40:32 +08:00
if (rom->GetMapperNo() == 20)
{
2024-07-31 17:40:32 +08:00
DISKDATA dsk;
LPBYTE lpDisk = rom->GetPROM();
LPBYTE lpWrite = rom->GetDISK();
LONG DiskSize = 16 + 65500 * rom->GetDiskNo();
DWORD data;
2024-07-31 17:40:32 +08:00
::ZeroMemory(&hdr, sizeof(BLOCKHDR));
::ZeroMemory(&dsk, sizeof(DISKDATA));
2024-07-31 17:40:32 +08:00
// <EFBFBD>vU<EFBFBD>pe<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
for (i = 16; i < DiskSize; i++) {
if (lpWrite[i])
dsk.DifferentSize++;
}
2024-07-31 17:40:32 +08:00
::memcpy(hdr.ID, "DISKDATA", sizeof(hdr.ID));
hdr.BlockVersion = 0x0210;
hdr.BlockSize = 0;
2024-07-31 17:40:32 +08:00
// Write File
if (::fwrite(&hdr, sizeof(BLOCKHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
// Write File
if (::fwrite(&dsk, sizeof(DISKDATA), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
for (i = 16; i < DiskSize; i++) {
if (lpWrite[i]) {
data = i & 0x00FFFFFF;
data |= ((DWORD)lpDisk[i] & 0xFF) << 24;
2024-07-31 17:40:32 +08:00
// Write File
if (::fwrite(&data, sizeof(DWORD), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
}
}
// EXCTR STATE
2024-07-31 17:40:32 +08:00
if (pad->GetExController()) {
EXCTRSTAT exctr;
2024-07-31 17:40:32 +08:00
::ZeroMemory(&hdr, sizeof(BLOCKHDR));
::ZeroMemory(&exctr, sizeof(EXCTRSTAT));
// Create Header
2024-07-31 17:40:32 +08:00
::memcpy(hdr.ID, "EXCTRDAT", sizeof(hdr.ID));
hdr.BlockVersion = 0x0100;
2024-07-31 17:40:32 +08:00
hdr.BlockSize = sizeof(EXCTRSTAT);
// Some excontrollers will default 0
exctr.data = pad->GetSyncExData();
2024-07-31 17:40:32 +08:00
if (::fwrite(&hdr, sizeof(BLOCKHDR), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
if (::fwrite(&exctr, sizeof(EXCTRSTAT), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
}
INT NES::GetDiskNo()
{
return rom->GetDiskNo();
}
void NES::SoundSetup()
{
apu->SoundSetup();
}
2024-07-31 17:40:32 +08:00
void NES::Command(NESCOMMAND cmd)
{
2024-07-31 17:40:32 +08:00
CommandParam(cmd, 0);
}
2024-07-31 17:40:32 +08:00
BOOL NES::CommandParam(NESCOMMAND cmd, INT param)
{
2024-07-31 17:40:32 +08:00
switch (cmd) {
case NESCMD_NONE:
break;
case NESCMD_DISK_THROTTLE_ON:
if (Config.emulator.bDiskThrottle) {
m_bDiskThrottle = TRUE;
}
break;
case NESCMD_DISK_THROTTLE_OFF:
m_bDiskThrottle = FALSE;
break;
case NESCMD_DISK_EJECT:
mapper->ExCmdWrite(Mapper::EXCMDWR_DISKEJECT, 0);
m_CommandRequest = (INT)cmd;
break;
case NESCMD_DISK_0A:
if (rom->GetDiskNo() > 0) {
mapper->ExCmdWrite(Mapper::EXCMDWR_DISKINSERT, 0);
m_CommandRequest = (INT)cmd;
2024-07-31 17:40:32 +08:00
}
break;
case NESCMD_DISK_0B:
if (rom->GetDiskNo() > 1) {
mapper->ExCmdWrite(Mapper::EXCMDWR_DISKINSERT, 1);
m_CommandRequest = (INT)cmd;
2024-07-31 17:40:32 +08:00
}
break;
case NESCMD_DISK_1A:
if (rom->GetDiskNo() > 2) {
mapper->ExCmdWrite(Mapper::EXCMDWR_DISKINSERT, 2);
m_CommandRequest = (INT)cmd;
2024-07-31 17:40:32 +08:00
}
break;
case NESCMD_DISK_1B:
if (rom->GetDiskNo() > 3) {
mapper->ExCmdWrite(Mapper::EXCMDWR_DISKINSERT, 3);
m_CommandRequest = (INT)cmd;
}
break;
case NESCMD_DISK_2A:
if (rom->GetDiskNo() > 4) {
mapper->ExCmdWrite(Mapper::EXCMDWR_DISKINSERT, 4);
m_CommandRequest = (INT)cmd;
}
break;
case NESCMD_DISK_2B:
if (rom->GetDiskNo() > 5) {
mapper->ExCmdWrite(Mapper::EXCMDWR_DISKINSERT, 5);
m_CommandRequest = (INT)cmd;
}
break;
case NESCMD_DISK_3A:
if (rom->GetDiskNo() > 6) {
mapper->ExCmdWrite(Mapper::EXCMDWR_DISKINSERT, 6);
m_CommandRequest = (INT)cmd;
}
break;
case NESCMD_DISK_3B:
if (rom->GetDiskNo() > 7) {
mapper->ExCmdWrite(Mapper::EXCMDWR_DISKINSERT, 7);
m_CommandRequest = (INT)cmd;
}
break;
2024-07-31 17:40:32 +08:00
case NESCMD_HWRESET:
Reset();
m_CommandRequest = (INT)cmd;
break;
case NESCMD_SWRESET:
SoftReset();
m_CommandRequest = (INT)cmd;
break;
case NESCMD_EXCONTROLLER:
pad->SetExController(param & 0xFF);
m_CommandRequest = 0x0100 | (param & 0xFF);
break;
case NESCMD_SOUND_MUTE:
return apu->SetChannelMute((BOOL)param); // <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0$Po0 Y<EFBFBD>f<EFBFBD>_n0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>rKa
}
return TRUE;
}
BOOL NES::Snapshot()
{
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
try {
SYSTEMTIME now;
2024-07-31 17:40:32 +08:00
::GetLocalTime(&now);
CHAR name[_MAX_PATH];
2024-07-31 17:40:32 +08:00
if (!Config.emulator.bPNGsnapshot) {
sprintf(name, "%s %04d%02d%02d%02d%02d%02d%01d.bmp", rom->GetRomName(),
now.wYear, now.wMonth, now.wDay, now.wHour, now.wMinute, now.wSecond, now.wMilliseconds / 100);
}
else {
sprintf(name, "%s %04d%02d%02d%02d%02d%02d%01d.png", rom->GetRomName(),
now.wYear, now.wMonth, now.wDay, now.wHour, now.wMinute, now.wSecond, now.wMilliseconds / 100);
}
string pathstr, tempstr;
2024-07-31 17:40:32 +08:00
if (Config.path.bSnapshotPath) {
pathstr = CPathlib::CreatePath(CApp::GetModulePath(), Config.path.szSnapshotPath);
::CreateDirectory(pathstr.c_str(), NULL);
}
else {
pathstr = rom->GetRomPath();
}
2024-07-31 17:40:32 +08:00
tempstr = CPathlib::MakePath(pathstr.c_str(), name);
DEBUGOUT("Snapshot: %s\n", tempstr.c_str());
2024-07-31 17:40:32 +08:00
if (!Config.emulator.bPNGsnapshot) {
if (!(fp = ::fopen(tempstr.c_str(), "wb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, tempstr.c_str());
throw szErrorString;
}
LPBYTE lpScn = ppu->GetScreenPtr();
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;
RGBQUAD rgb[256];
2024-07-31 17:40:32 +08:00
ZEROMEMORY(&bfh, sizeof(bfh));
ZEROMEMORY(&bih, sizeof(bih));
ZEROMEMORY(rgb, sizeof(rgb));
bfh.bfType = 0x4D42; // 'BM'
2024-07-31 17:40:32 +08:00
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256;
bfh.bfSize = bfh.bfOffBits + 256 * 240;
bih.biSize = sizeof(bih);
bih.biWidth = 256;
bih.biHeight = 240;
bih.biPlanes = 1;
bih.biBitCount = 8;
bih.biCompression = BI_RGB;
bih.biSizeImage = 0;
bih.biXPelsPerMeter = 0;
bih.biYPelsPerMeter = 0;
2024-07-31 17:40:32 +08:00
bih.biClrUsed = 256;
bih.biClrImportant = 0;
2024-07-31 17:40:32 +08:00
DirectDraw.GetPaletteData(rgb);
2024-07-31 17:40:32 +08:00
if (::fwrite(&bfh, sizeof(bfh), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
if (::fwrite(&bih, sizeof(bih), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
if (::fwrite(&rgb, sizeof(rgb), 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
lpScn += 8;
2024-07-31 17:40:32 +08:00
for (INT i = 239; i >= 0; i--) {
if (::fwrite(&lpScn[(256 + 16) * i], 256, 1, fp) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
2024-07-31 17:40:32 +08:00
FCLOSE(fp);
}
else {
LPBYTE lpScn = ppu->GetScreenPtr();
RGBQUAD rgb[256];
2024-07-31 17:40:32 +08:00
ZEROMEMORY(rgb, sizeof(rgb));
DirectDraw.GetPaletteData(rgb);
PNGWRITE png;
2024-07-31 17:40:32 +08:00
png.Write(tempstr.c_str(), 256, 240, rgb, lpScn + 8, CDirectDraw::RENDER_WIDTH);
}
2024-07-31 17:40:32 +08:00
}
catch (CHAR* str) {
DEBUGOUT("Snapshot error.\n");
FCLOSE(fp);
throw str;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
DEBUGOUT("Snapshot error.\n");
FCLOSE(fp);
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
return TRUE;
}
2024-07-31 17:40:32 +08:00
INT NES::IsMovieFile(const char* fname, ROM* rom)
{
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
MOVIEFILEHDR header;
2024-07-31 17:40:32 +08:00
if (!(fp = ::fopen(fname, "rb")))
return -1;
2024-07-31 17:40:32 +08:00
if (::fread(&header, sizeof(header), 1, fp) != 1) {
FCLOSE(fp);
return -1;
}
2024-07-31 17:40:32 +08:00
FCLOSE(fp);
2024-07-31 17:40:32 +08:00
if (::memcmp(header.ID, "VirtuaNES MV", sizeof(header.ID)) == 0) {
if (header.BlockVersion < 0x0300) {
return IDS_ERROR_ILLEGALMOVIEOLD;
2024-07-31 17:40:32 +08:00
}
else
if (header.BlockVersion >= 0x0300) {
if (rom->GetMapperNo() != 20) {
// FDS<EFBFBD>NY
if (header.Ext0 != rom->GetPROM_CRC()) {
return IDS_ERROR_ILLEGALMOVIECRC; // U<EFBFBD>F0X0<EFBFBD>0<EFBFBD>0
}
}
else {
// FDS
if (header.Ext0 != rom->GetGameID() ||
header.Ext1 != (WORD)rom->GetMakerID() ||
header.Ext2 != (WORD)rom->GetDiskNo())
return IDS_ERROR_ILLEGALMOVIECRC; // U<EFBFBD>F0X0<EFBFBD>0<EFBFBD>0
}
2024-07-31 17:40:32 +08:00
if (header.RecordVersion != VIRTUANES_VERSION) {
return IDS_ERROR_ILLEGALMOVIEVER;
}
2024-07-31 17:40:32 +08:00
return 0;
}
}
return -1;
}
2024-07-31 17:40:32 +08:00
BOOL NES::MoviePlay(const char* fname)
{
2024-07-31 17:40:32 +08:00
if (rom->IsNSF())
return FALSE;
2024-07-31 17:40:32 +08:00
if (IsMoviePlay() || IsMovieRec()) {
MovieStop();
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("NES::MoviePlay\n");
try {
2024-07-31 17:40:32 +08:00
if (!(m_fpMovie = ::fopen(fname, "rb+"))) {
DEBUGOUT("Movie play error. File not found.\n");
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0!qD0g0Y0
return FALSE;
}
// <EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fread(&m_hedMovie, sizeof(m_hedMovie), 1, m_fpMovie) != 1) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
if (::memcmp(m_hedMovie.ID, "VirtuaNES MV", sizeof(m_hedMovie.ID)) == 0) {
m_MovieVersion = m_hedMovie.BlockVersion;
2024-07-31 17:40:32 +08:00
// if( m_hedMovie.BlockVersion == 0x0300 ) {
if (m_hedMovie.BlockVersion >= 0x0300) {
if (m_hedMovie.CRC != 0) {
if (CRC::Crc(sizeof(m_hedMovie) - sizeof(DWORD), (LPBYTE)&m_hedMovie) != m_hedMovie.CRC) {
FCLOSE(m_fpMovie);
return FALSE; // U<EFBFBD>F0X0<EFBFBD>0<EFBFBD>0
}
}
// J0c0Q00
2024-07-31 17:40:32 +08:00
}
else {
// HQu<EFBFBD><EFBFBD>SD0n0g0<EFBFBD>0<EFBFBD>0c0Y00
2024-07-31 17:40:32 +08:00
FCLOSE(m_fpMovie);
return FALSE;
}
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>V g<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
m_saveRenderMethod = (INT)GetRenderMethod();
2024-07-31 17:40:32 +08:00
m_saveIrqType = GetIrqType();
m_saveFrameIRQ = GetFrameIRQmode();
m_saveVideoMode = GetVideoMode();
SetRenderMethod((RENDERMETHOD)m_hedMovie.RenderMethod);
SetIrqType((INT)m_hedMovie.IRQtype);
SetFrameIRQmode((m_hedMovie.FrameIRQ != 0) ? TRUE : FALSE);
SetVideoMode((m_hedMovie.VideoMode != 0) ? TRUE : FALSE);
LONG MovieOffset;
2024-07-31 17:40:32 +08:00
m_MovieControl = m_hedMovie.Control;
m_MovieStepTotal = m_hedMovie.MovieStep;
2024-07-31 17:40:32 +08:00
MovieOffset = m_hedMovie.MovieOffset;
2024-07-31 17:40:32 +08:00
if (m_hedMovie.BlockVersion < 0x0400) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
ReadState(m_fpMovie);
}
else if (!(m_MovieControl & 0x40)) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
ReadState(m_fpMovie);
}
else {
Reset();
}
2024-07-31 17:40:32 +08:00
if (::fseek(m_fpMovie, MovieOffset, SEEK_SET)) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0<EFBFBD>2<EFBFBD>U0<EFBFBD>0f0D0j0D0<EFBFBD>
2024-07-31 17:40:32 +08:00
if (m_MovieStepTotal == 0) {
MovieStop();
return FALSE;
}
m_bMoviePlay = TRUE;
m_MovieStep = 0;
2024-07-31 17:40:32 +08:00
}
catch (CHAR* str) {
DEBUGOUT("Movie play error. %s\n", str);
FCLOSE(m_fpMovie);
throw str;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
DEBUGOUT("Movie play error.\n");
FCLOSE(m_fpMovie);
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
return TRUE;
}
2024-07-31 17:40:32 +08:00
BOOL NES::MovieRec(const char* fname)
{
2024-07-31 17:40:32 +08:00
if (rom->IsNSF())
return FALSE;
2024-07-31 17:40:32 +08:00
if (IsMoviePlay() || IsMovieRec()) {
MovieStop();
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("NES::MovieRec\n");
try {
2024-07-31 17:40:32 +08:00
if (!(m_fpMovie = ::fopen(fname, "wb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, fname);
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
::ZeroMemory(&m_hedMovie, sizeof(m_hedMovie));
::memcpy(m_hedMovie.ID, "VirtuaNES MV", sizeof(m_hedMovie.ID));
// m_hedMovie.BlockVersion = 0x0300;
m_hedMovie.BlockVersion = 0x0400;
m_hedMovie.RecordVersion = VIRTUANES_VERSION;
m_hedMovie.StateStOffset = sizeof(m_hedMovie);
2024-07-31 17:40:32 +08:00
m_hedMovie.Control |= Config.movie.bUsePlayer[0] ? 0x01 : 0x00;
m_hedMovie.Control |= Config.movie.bUsePlayer[1] ? 0x02 : 0x00;
m_hedMovie.Control |= Config.movie.bUsePlayer[2] ? 0x04 : 0x00;
m_hedMovie.Control |= Config.movie.bUsePlayer[3] ? 0x08 : 0x00;
m_hedMovie.Control |= Config.movie.bResetRec ? 0x40 : 0x00;
m_hedMovie.Control |= Config.movie.bRerecord ? 0x80 : 0x00;
m_MovieControl = m_hedMovie.Control;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>V g<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
m_hedMovie.RenderMethod = (BYTE)GetRenderMethod();
2024-07-31 17:40:32 +08:00
m_hedMovie.IRQtype = (BYTE)GetIrqType();
m_hedMovie.FrameIRQ = GetFrameIRQmode() ? 0xFF : 0;
m_hedMovie.VideoMode = GetVideoMode() ? 0xFF : 0;
// CRC,ID$P<EFBFBD>0<EFBFBD>fM0<EFBFBD><EFBFBD><EFBFBD>0(<EFBFBD><EFBFBD><EFBFBD>R\O2<EFBFBD>bk(u)
2024-07-31 17:40:32 +08:00
if (rom->GetMapperNo() != 20) {
// FDS<EFBFBD>NY
m_hedMovie.Ext0 = rom->GetPROM_CRC();
2024-07-31 17:40:32 +08:00
}
else {
// FDS
m_hedMovie.Ext0 = rom->GetGameID();
m_hedMovie.Ext1 = (WORD)rom->GetMakerID();
m_hedMovie.Ext2 = (WORD)rom->GetDiskNo();
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&m_hedMovie, sizeof(m_hedMovie), 1, m_fpMovie) != 1) {
FCLOSE(m_fpMovie);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
if (Config.movie.bResetRec) {
Reset(); // <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0K0<EFBFBD>0n0<EFBFBD>2<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Y
2024-07-31 17:40:32 +08:00
}
else {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
WriteState(m_fpMovie);
}
2024-07-31 17:40:32 +08:00
m_hedMovie.MovieOffset = ::ftell(m_fpMovie);
m_bMovieRec = TRUE;
m_MovieStep = m_MovieStepTotal = 0;
2024-07-31 17:40:32 +08:00
// m_MovieVersion = 0x0300;
m_MovieVersion = 0x0400;
2024-07-31 17:40:32 +08:00
}
catch (CHAR* str) {
DEBUGOUT("Movie record error. %s\n", str);
FCLOSE(m_fpMovie);
throw str;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
DEBUGOUT("Movie record error.\n");
FCLOSE(m_fpMovie);
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
return TRUE;
}
2024-07-31 17:40:32 +08:00
BOOL NES::MovieRecAppend(const char* fname)
{
2024-07-31 17:40:32 +08:00
if (rom->IsNSF())
return FALSE;
// <EFBFBD>2<EFBFBD>-No0asTL0!qD0^0
2024-07-31 17:40:32 +08:00
if (IsMovieRec())
return FALSE;
2024-07-31 17:40:32 +08:00
if (IsMoviePlay()) {
MovieStop();
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("NES::MovieAppendRec\n");
try {
2024-07-31 17:40:32 +08:00
if (!(m_fpMovie = ::fopen(fname, "rb"))) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0!qD0h0M0
2024-07-31 17:40:32 +08:00
if (!(m_fpMovie = ::fopen(fname, "wb"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, fname);
throw szErrorString;
}
2024-07-31 17:40:32 +08:00
::ZeroMemory(&m_hedMovie, sizeof(m_hedMovie));
::memcpy(m_hedMovie.ID, "VirtuaNES MV", sizeof(m_hedMovie.ID));
// m_hedMovie.BlockVersion = 0x0300;
m_hedMovie.BlockVersion = 0x0400;
m_hedMovie.RecordVersion = VIRTUANES_VERSION;
m_hedMovie.StateStOffset = sizeof(m_hedMovie);
2024-07-31 17:40:32 +08:00
m_hedMovie.Control |= Config.movie.bUsePlayer[0] ? 0x01 : 0x00;
m_hedMovie.Control |= Config.movie.bUsePlayer[1] ? 0x02 : 0x00;
m_hedMovie.Control |= Config.movie.bUsePlayer[2] ? 0x04 : 0x00;
m_hedMovie.Control |= Config.movie.bUsePlayer[3] ? 0x08 : 0x00;
m_hedMovie.Control |= Config.movie.bRerecord ? 0x80 : 0x00;
m_hedMovie.Control |= Config.movie.bResetRec ? 0x40 : 0x00;
m_MovieControl = m_hedMovie.Control;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>V g<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
m_hedMovie.RenderMethod = (BYTE)GetRenderMethod();
2024-07-31 17:40:32 +08:00
m_hedMovie.IRQtype = (BYTE)GetIrqType();
m_hedMovie.FrameIRQ = GetFrameIRQmode() ? 0xFF : 0;
m_hedMovie.VideoMode = GetVideoMode() ? 0xFF : 0;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&m_hedMovie, sizeof(m_hedMovie), 1, m_fpMovie) != 1) {
FCLOSE(m_fpMovie);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
if (Config.movie.bResetRec) {
Reset(); // <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0K0<EFBFBD>0n0<EFBFBD>2<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Y
2024-07-31 17:40:32 +08:00
}
else {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
WriteState(m_fpMovie);
}
2024-07-31 17:40:32 +08:00
m_hedMovie.MovieOffset = ::ftell(m_fpMovie);
m_MovieStep = m_MovieStepTotal = 0;
2024-07-31 17:40:32 +08:00
// m_MovieVersion = 0x0300;
m_MovieVersion = 0x0400;
2024-07-31 17:40:32 +08:00
}
else {
if (!(m_fpMovie = ::fopen(fname, "rb+"))) {
// xxx <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>Q0~0[0<EFBFBD>0
2024-07-31 17:40:32 +08:00
LPCSTR szErrStr = CApp::GetErrorString(IDS_ERROR_OPEN);
sprintf(szErrorString, szErrStr, fname);
throw szErrorString;
}
// <EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fseek(m_fpMovie, 0, SEEK_SET)) {
FCLOSE(m_fpMovie);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
if (::fread(&m_hedMovie, sizeof(m_hedMovie), 1, m_fpMovie) != 1) {
FCLOSE(m_fpMovie);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
if (::memcmp(m_hedMovie.ID, "VirtuaNES MV", sizeof(m_hedMovie.ID)) != 0) {
FCLOSE(m_fpMovie);
return FALSE;
}
// <EFBFBD>SD0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0o0hcf0
2024-07-31 17:40:32 +08:00
if (m_hedMovie.BlockVersion < 0x0300) {
FCLOSE(m_fpMovie);
return FALSE;
}
m_MovieControl = m_hedMovie.Control;
m_MovieStep = m_MovieStepTotal = m_hedMovie.MovieStep;
2024-07-31 17:40:32 +08:00
// m_MovieVersion = 0x0300;
m_MovieVersion = 0x0400;
2024-07-31 17:40:32 +08:00
if (::fseek(m_fpMovie, m_hedMovie.StateEdOffset, SEEK_SET)) {
FCLOSE(m_fpMovie);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
if (!ReadState(m_fpMovie)) {
FCLOSE(m_fpMovie);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
2024-07-31 17:40:32 +08:00
if (::fseek(m_fpMovie, m_hedMovie.StateEdOffset, SEEK_SET)) {
FCLOSE(m_fpMovie);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_READ);
}
}
m_bMovieRec = TRUE;
2024-07-31 17:40:32 +08:00
}
catch (CHAR* str) {
DEBUGOUT("Movie record error. %s\n", str);
FCLOSE(m_fpMovie);
throw str;
#ifndef _DEBUG
2024-07-31 17:40:32 +08:00
}
catch (...) {
DEBUGOUT("Movie record error.\n");
FCLOSE(m_fpMovie);
// Nfj0<EFBFBD>0<EFBFBD>0<EFBFBD>0L0zvuW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_UNKNOWN);
#endif
}
return TRUE;
}
BOOL NES::MovieStop()
{
2024-07-31 17:40:32 +08:00
if (!m_fpMovie && !(m_bMoviePlay || m_bMovieRec))
return FALSE;
2024-07-31 17:40:32 +08:00
DEBUGOUT("NES::MovieStop\n");
2024-07-31 17:40:32 +08:00
DirectDraw.SetMessageString("Movie stop.");
2024-07-31 17:40:32 +08:00
if (m_bMovieRec) {
m_hedMovie.MovieStep = m_MovieStep;
2024-07-31 17:40:32 +08:00
m_hedMovie.StateEdOffset = ::ftell(m_fpMovie);
WriteState(m_fpMovie);
// // <EFBFBD>d<EFBFBD>0<EFBFBD>vW0<EFBFBD>ybkn04XTo0<EFBFBD><EFBFBD><EFBFBD> N<EFBFBD>S<EFBFBD><EFBFBD>
// if( m_MovieControl & 0x80 ) {
// } else {
// m_hedMovie.StateEdOffset = 0;
// }
if (::fseek(m_fpMovie, 0, SEEK_SET)) {
FCLOSE(m_fpMovie);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
// CRC <EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
m_hedMovie.CRC = CRC::Crc(sizeof(m_hedMovie) - sizeof(DWORD), (LPBYTE)&m_hedMovie);
// gB}<EFBFBD>vj0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&m_hedMovie, sizeof(m_hedMovie), 1, m_fpMovie) != 1) {
FCLOSE(m_fpMovie);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
2024-07-31 17:40:32 +08:00
FCLOSE(m_fpMovie);
m_bMovieRec = FALSE;
}
2024-07-31 17:40:32 +08:00
if (m_bMoviePlay) {
FCLOSE(m_fpMovie);
m_bMoviePlay = FALSE;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>V g<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0CQk0;bY0
2024-07-31 17:40:32 +08:00
SetRenderMethod((RENDERMETHOD)m_saveRenderMethod);
SetIrqType(m_saveIrqType);
SetFrameIRQmode(m_saveFrameIRQ);
SetVideoMode(m_saveVideoMode);
}
return TRUE;
}
2024-07-31 17:40:32 +08:00
void NES::GetMovieInfo(WORD& wRecVersion, WORD& wVersion, DWORD& dwRecordFrames, DWORD& dwRecordTimes)
{
2024-07-31 17:40:32 +08:00
wRecVersion = m_hedMovie.RecordVersion;
wVersion = m_hedMovie.BlockVersion;
dwRecordFrames = m_hedMovie.MovieStep;
2024-07-31 17:40:32 +08:00
dwRecordTimes = m_hedMovie.RecordTimes;
}
// <EFBFBD>k<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0|Ts0<EFBFBD>QY0
void NES::Movie()
{
2024-07-31 17:40:32 +08:00
if (!m_fpMovie && !(m_bMoviePlay || m_bMovieRec)) {
m_CommandRequest = 0; // <EFBFBD>0<EFBFBD>0eQ<EFBFBD>0j0D0h0{kl0
return;
}
INT exctr = pad->GetExController();
BYTE Data;
WORD wData;
DWORD dwData;
2024-07-31 17:40:32 +08:00
if (m_bMovieRec) {
// gRK0<EFBFBD>0<EFBFBD>b5_z<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>p<EFBFBD><EFBFBD><EFBFBD>L0-<EFBFBD><EFBFBD>[U0<EFBFBD>0f0D0_04XT
2024-07-31 17:40:32 +08:00
if (m_MovieStep == 0) {
if (exctr == PAD::EXCONTROLLER_ZAPPER
|| exctr == PAD::EXCONTROLLER_PADDLE
|| exctr == PAD::EXCONTROLLER_CRAZYCLIMBER
|| exctr == PAD::EXCONTROLLER_TOPRIDER
|| exctr == PAD::EXCONTROLLER_SPACESHADOWGUN
|| exctr == PAD::EXCONTROLLER_FAMILYTRAINER_A
|| exctr == PAD::EXCONTROLLER_FAMILYTRAINER_B
|| exctr == PAD::EXCONTROLLER_MAHJANG
|| exctr == PAD::EXCONTROLLER_EXCITINGBOXING
|| exctr == PAD::EXCONTROLLER_OEKAKIDS_TABLET) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0ID
Data = 0xF0;
// <EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&Data, sizeof(Data), 1, m_fpMovie) != 1) {
MovieStop();
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
// .z^<EFBFBD>
2024-07-31 17:40:32 +08:00
wData = (WORD)(0x0100 | (pad->GetExController() & 0x0FF));
// <EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&wData, sizeof(wData), 1, m_fpMovie) != 1) {
MovieStop();
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
}
2024-07-31 17:40:32 +08:00
if (m_CommandRequest) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0ID
Data = 0xF0;
// <EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&Data, sizeof(Data), 1, m_fpMovie) != 1) {
MovieStop();
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
wData = (WORD)m_CommandRequest;
// <EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&wData, sizeof(wData), 1, m_fpMovie) != 1) {
MovieStop();
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
m_CommandRequest = 0;
// <EFBFBD>b5_z<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>p<EFBFBD><EFBFBD><EFBFBD>
2024-07-31 17:40:32 +08:00
if (exctr == PAD::EXCONTROLLER_ZAPPER
|| exctr == PAD::EXCONTROLLER_PADDLE
|| exctr == PAD::EXCONTROLLER_CRAZYCLIMBER
|| exctr == PAD::EXCONTROLLER_TOPRIDER
|| exctr == PAD::EXCONTROLLER_SPACESHADOWGUN
|| exctr == PAD::EXCONTROLLER_FAMILYTRAINER_A
|| exctr == PAD::EXCONTROLLER_FAMILYTRAINER_B
|| exctr == PAD::EXCONTROLLER_MAHJANG
|| exctr == PAD::EXCONTROLLER_EXCITINGBOXING
|| exctr == PAD::EXCONTROLLER_OEKAKIDS_TABLET) {
// <EFBFBD>b5_<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0ID
Data = 0xF3;
// <EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&Data, sizeof(Data), 1, m_fpMovie) != 1) {
MovieStop();
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0
dwData = pad->GetSyncExData();
// <EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&dwData, sizeof(dwData), 1, m_fpMovie) != 1) {
MovieStop();
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
dwData = pad->GetSyncData();
2024-07-31 17:40:32 +08:00
for (INT i = 0; i < 4; i++) {
Data = (BYTE)(dwData >> (i * 8));
if (m_MovieControl & (1 << i)) {
// <EFBFBD>fM0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fwrite(&Data, sizeof(Data), 1, m_fpMovie) != 1) {
MovieStop();
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>fM0<EFBFBD><EFBFBD>0k01YWeW0~0W0_0
2024-07-31 17:40:32 +08:00
throw CApp::GetErrorString(IDS_ERROR_WRITE);
}
}
}
m_MovieStep++;
}
2024-07-31 17:40:32 +08:00
if (m_bMoviePlay) {
DWORD dwPadData = 0;
INT num = 0;
BYTE PadBuf[4];
PadBuf[0] = PadBuf[1] = PadBuf[2] = PadBuf[3] = 0;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>QuB}<EFBFBD>N<EFBFBD>
2024-07-31 17:40:32 +08:00
if (m_MovieStep >= m_MovieStepTotal) {
if (!Config.movie.bLoopPlay) {
MovieStop();
return;
2024-07-31 17:40:32 +08:00
}
else {
// N<EFBFBD>e<EFBFBD>Qu-NX0<EFBFBD>0j0D0c0f0<EFBFBD>Nk0Y0<EFBFBD>0
m_bMoviePlay = FALSE;
m_MovieStep = 0;
2024-07-31 17:40:32 +08:00
::fseek(m_fpMovie, m_hedMovie.StateStOffset, SEEK_SET);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
ReadState(m_fpMovie);
::fseek(m_fpMovie, m_hedMovie.MovieOffset, SEEK_SET);
// <EFBFBD>Qu-Nc0f0<EFBFBD>Nk0Y0<EFBFBD>0
m_bMoviePlay = TRUE;
}
}
do {
// <EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fread(&Data, sizeof(Data), 1, m_fpMovie) != 1) {
// B}<EFBFBD>N<EFBFBD>
MovieStop();
return;
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>
2024-07-31 17:40:32 +08:00
if ((Data & 0xF0) == 0xF0) {
if (Data == 0xF0) {
// <EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0
2024-07-31 17:40:32 +08:00
if (::fread(&wData, sizeof(wData), 1, m_fpMovie) != 1) {
// B}<EFBFBD>N<EFBFBD>
MovieStop();
return;
}
2024-07-31 17:40:32 +08:00
if (wData < 0x0100) {
Command((NESCOMMAND)((INT)wData));
}
else {
// <EFBFBD>b5_z<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>p<EFBFBD><EFBFBD><EFBFBD>
2024-07-31 17:40:32 +08:00
CommandParam(NESCMD_EXCONTROLLER, ((INT)wData) & 0x00FF);
}
2024-07-31 17:40:32 +08:00
}
else
if (Data == 0xF3) {
// <EFBFBD><EFBFBD>0<EFBFBD><EFBFBD>0
if (::fread(&dwData, sizeof(dwData), 1, m_fpMovie) != 1) {
// B}<EFBFBD>N<EFBFBD>
MovieStop();
return;
}
pad->SetSyncExData(dwData);
}
else {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0v0c0<EFBFBD>X<EFBFBD>0f0<EFBFBD>0<EFBFBD>B}<EFBFBD>NX0<EFBFBD>0
MovieStop();
return;
}
2024-07-31 17:40:32 +08:00
}
else {
// *gO(u<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0RY0c0ۘp0W0
2024-07-31 17:40:32 +08:00
while (!(m_MovieControl & (1 << num)) && (num < 4)) {
PadBuf[num] = 0;
num++;
}
PadBuf[num] = Data;
num++;
// *gO(u<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0RY0c0ۘp0W0
2024-07-31 17:40:32 +08:00
while (!(m_MovieControl & (1 << num)) && (num < 4)) {
PadBuf[num] = 0;
num++;
}
}
2024-07-31 17:40:32 +08:00
} while (num < 4);
2024-07-31 17:40:32 +08:00
dwData = (((DWORD)PadBuf[3]) << 24) | (((DWORD)PadBuf[2]) << 16) | (((DWORD)PadBuf[1]) << 8) | ((DWORD)PadBuf[0]);
pad->SetSyncData(dwData);
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>X<EFBFBD>0Y0
m_MovieStep++;
}
m_CommandRequest = 0;
}
// For Cheat
void NES::CheatInitial()
{
m_CheatCode.clear();
}
BOOL NES::IsCheatCodeAdd()
{
BOOL bRet = m_bCheatCodeAdd;
m_bCheatCodeAdd = FALSE;
return bRet;
}
INT NES::GetCheatCodeNum()
{
return m_CheatCode.size();
}
2024-07-31 17:40:32 +08:00
BOOL NES::GetCheatCode(INT no, CHEATCODE& code)
{
2024-07-31 17:40:32 +08:00
if (m_CheatCode.size() - 1 < no)
return FALSE;
code = m_CheatCode[no];
return TRUE;
}
2024-07-31 17:40:32 +08:00
void NES::SetCheatCodeFlag(INT no, BOOL bEnable)
{
2024-07-31 17:40:32 +08:00
if (m_CheatCode.size() - 1 < no)
return;
2024-07-31 17:40:32 +08:00
if (bEnable) {
m_CheatCode[no].enable |= CHEAT_ENABLE;
2024-07-31 17:40:32 +08:00
}
else {
m_CheatCode[no].enable &= ~CHEAT_ENABLE;
}
}
2024-07-31 17:40:32 +08:00
void NES::SetCheatCodeAllFlag(BOOL bEnable, BOOL bKey)
{
2024-07-31 17:40:32 +08:00
for (INT i = 0; i < m_CheatCode.size(); i++) {
if (!bKey) {
if (bEnable) {
m_CheatCode[i].enable |= CHEAT_ENABLE;
2024-07-31 17:40:32 +08:00
}
else {
m_CheatCode[i].enable &= ~CHEAT_ENABLE;
}
2024-07-31 17:40:32 +08:00
}
else if (!(m_CheatCode[i].enable & CHEAT_KEYDISABLE)) {
if (bEnable) {
m_CheatCode[i].enable |= CHEAT_ENABLE;
2024-07-31 17:40:32 +08:00
}
else {
m_CheatCode[i].enable &= ~CHEAT_ENABLE;
}
}
}
}
2024-07-31 17:40:32 +08:00
void NES::ReplaceCheatCode(INT no, CHEATCODE code)
{
2024-07-31 17:40:32 +08:00
if (m_CheatCode.size() - 1 < no)
return;
m_CheatCode[no] = code;
}
2024-07-31 17:40:32 +08:00
void NES::AddCheatCode(CHEATCODE code)
{
2024-07-31 17:40:32 +08:00
m_CheatCode.push_back(code);
m_bCheatCodeAdd = TRUE;
}
2024-07-31 17:40:32 +08:00
void NES::DelCheatCode(INT no)
{
2024-07-31 17:40:32 +08:00
if (m_CheatCode.size() - 1 < no)
return;
2024-07-31 17:40:32 +08:00
m_CheatCode.erase(m_CheatCode.begin() + no);
}
2024-07-31 17:40:32 +08:00
DWORD NES::CheatRead(INT length, WORD addr)
{
DWORD data = 0;
2024-07-31 17:40:32 +08:00
for (INT i = 0; i <= length; i++) {
data |= (DWORD)Read(addr + i) * (1 << (i * 8));
}
return data;
}
2024-07-31 17:40:32 +08:00
void NES::CheatWrite(INT length, WORD addr, DWORD data)
{
2024-07-31 17:40:32 +08:00
for (INT i = 0; i <= length; i++) {
Write((WORD)(addr + i), data & 0xFF);
data >>= 8;
}
}
void NES::CheatCodeProcess()
{
2024-07-31 17:40:32 +08:00
for (vector<CHEATCODE>::iterator it = m_CheatCode.begin(); it != m_CheatCode.end(); it++) {
if (!(it->enable & CHEAT_ENABLE))
continue;
2024-07-31 17:40:32 +08:00
switch (it->type) {
case CHEAT_TYPE_ALWAYS:
CheatWrite(it->length, it->address, it->data);
break;
case CHEAT_TYPE_ONCE:
CheatWrite(it->length, it->address, it->data);
it->enable = 0;
break;
case CHEAT_TYPE_GREATER:
if (CheatRead(it->length, it->address) > it->data) {
CheatWrite(it->length, it->address, it->data);
}
break;
case CHEAT_TYPE_LESS:
if (CheatRead(it->length, it->address) < it->data) {
CheatWrite(it->length, it->address, it->data);
}
break;
}
}
}
void NES::GenieInitial()
{
m_bCheatCodeAdd = FALSE;
m_GenieCode.clear();
}
2024-07-31 17:40:32 +08:00
void NES::GenieLoad(char* fname)
{
2024-07-31 17:40:32 +08:00
FILE* fp = NULL;
CHAR buf[256];
GENIECODE code;
BYTE codetmp[9];
INT no;
2024-07-31 17:40:32 +08:00
if ((fp = ::fopen(fname, "r"))) {
m_GenieCode.clear();
2024-07-31 17:40:32 +08:00
while (::fgets(buf, sizeof(buf), fp)) {
if (buf[0] == ';')
continue;
2024-07-31 17:40:32 +08:00
if (buf[0] == 0x0D || buf[0] == 0x0A)
continue;
2024-07-31 17:40:32 +08:00
if (::strlen(buf) < 6)
continue;
code.address = 0;
code.data = 0;
code.cmp = 0;
2024-07-31 17:40:32 +08:00
for (no = 0; isalpha(buf[no]) && no < 8; no++) {
switch (buf[no]) {
case 'A': codetmp[no] = 0x00; break;
case 'P': codetmp[no] = 0x01; break;
case 'Z': codetmp[no] = 0x02; break;
case 'L': codetmp[no] = 0x03; break;
case 'G': codetmp[no] = 0x04; break;
case 'I': codetmp[no] = 0x05; break;
case 'T': codetmp[no] = 0x06; break;
case 'Y': codetmp[no] = 0x07; break;
case 'E': codetmp[no] = 0x08; break;
case 'O': codetmp[no] = 0x09; break;
case 'X': codetmp[no] = 0x0A; break;
case 'U': codetmp[no] = 0x0B; break;
case 'K': codetmp[no] = 0x0C; break;
case 'S': codetmp[no] = 0x0D; break;
case 'V': codetmp[no] = 0x0E; break;
case 'N': codetmp[no] = 0x0F; break;
}
}
2024-07-31 17:40:32 +08:00
if (no == 6) {
// Address
2024-07-31 17:40:32 +08:00
code.address |= (WORD)(codetmp[3] & 0x07) << 12;
code.address |= (WORD)(codetmp[4] & 0x08) << 8;
code.address |= (WORD)(codetmp[5] & 0x07) << 8;
code.address |= (WORD)(codetmp[1] & 0x08) << 4;
code.address |= (WORD)(codetmp[2] & 0x07) << 4;
code.address |= (WORD)(codetmp[3] & 0x08);
code.address |= (WORD)(codetmp[4] & 0x07);
// Data
2024-07-31 17:40:32 +08:00
code.data |= (codetmp[0] & 0x08) << 4;
code.data |= (codetmp[1] & 0x07) << 4;
code.data |= (codetmp[5] & 0x08);
code.data |= (codetmp[0] & 0x07);
2024-07-31 17:40:32 +08:00
m_GenieCode.push_back(code);
}
2024-07-31 17:40:32 +08:00
else
if (no == 8) {
// Address
code.address |= 0x8000;
code.address |= (WORD)(codetmp[3] & 0x07) << 12;
code.address |= (WORD)(codetmp[4] & 0x08) << 8;
code.address |= (WORD)(codetmp[5] & 0x07) << 8;
code.address |= (WORD)(codetmp[1] & 0x08) << 4;
code.address |= (WORD)(codetmp[2] & 0x07) << 4;
code.address |= (WORD)(codetmp[3] & 0x08);
code.address |= (WORD)(codetmp[4] & 0x07);
// Data
code.data |= (codetmp[0] & 0x08) << 4;
code.data |= (codetmp[1] & 0x07) << 4;
code.data |= (codetmp[7] & 0x08);
code.data |= (codetmp[0] & 0x07);
// Data
code.cmp |= (codetmp[6] & 0x08) << 4;
code.cmp |= (codetmp[7] & 0x07) << 4;
code.cmp |= (codetmp[5] & 0x08);
code.cmp |= (codetmp[6] & 0x07);
m_GenieCode.push_back(code);
}
}
GenieCodeProcess();
}
2024-07-31 17:40:32 +08:00
FCLOSE(fp);
}
void NES::GenieCodeProcess()
{
WORD addr;
2024-07-31 17:40:32 +08:00
for (INT i = 0; i < m_GenieCode.size(); i++) {
addr = m_GenieCode[i].address;
2024-07-31 17:40:32 +08:00
if (addr & 0x8000) {
// 8character codes
if (CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] == m_GenieCode[i].cmp) {
CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = m_GenieCode[i].data;
}
2024-07-31 17:40:32 +08:00
}
else {
// 6character codes
addr |= 0x8000;
2024-07-31 17:40:32 +08:00
CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = m_GenieCode[i].data;
}
}
}
void NES::DrawPad()
{
2024-07-31 17:40:32 +08:00
if (m_bMoviePlay) {
INT offset_h = 12;
2024-07-31 17:40:32 +08:00
INT offset_v = Config.graphics.bAllLine ? (240 - 18) : (240 - 22);
2024-07-31 17:40:32 +08:00
if (Config.movie.bPadDisplay) {
DWORD dwData = pad->GetSyncData();
2024-07-31 17:40:32 +08:00
for (INT i = 0; i < 4; i++) {
BYTE Data = (BYTE)(dwData >> (i * 8));
if (m_MovieControl & (1 << i)) {
DrawBitmap(offset_h, offset_v, m_PadImg);
// KEY
2024-07-31 17:40:32 +08:00
if (Data & (1 << 4)) DrawBitmap(offset_h + 3, offset_v + 1, m_KeyImg0); // U
if (Data & (1 << 5)) DrawBitmap(offset_h + 3, offset_v + 5, m_KeyImg0); // D
if (Data & (1 << 6)) DrawBitmap(offset_h + 1, offset_v + 3, m_KeyImg0); // L
if (Data & (1 << 7)) DrawBitmap(offset_h + 5, offset_v + 3, m_KeyImg0); // R
// START,SELECT
2024-07-31 17:40:32 +08:00
if (Data & (1 << 2)) DrawBitmap(offset_h + 9, offset_v + 5, m_KeyImg1); // SELECT
if (Data & (1 << 3)) DrawBitmap(offset_h + 13, offset_v + 5, m_KeyImg1); // START
// A,B
2024-07-31 17:40:32 +08:00
if (Data & (1 << 0)) DrawBitmap(offset_h + 23, offset_v + 3, m_KeyImg2); // A
if (Data & (1 << 1)) DrawBitmap(offset_h + 18, offset_v + 3, m_KeyImg2); // B
offset_h += 30;
}
}
}
2024-07-31 17:40:32 +08:00
if (Config.movie.bTimeDisplay) {
// Time display
INT t = m_MovieStep;
INT h = t / 216000;
t -= h * 216000;
INT m = t / 3600;
t -= m * 3600;
INT s = t / 60;
t -= s * 60;
CHAR szTemp[64];
2024-07-31 17:40:32 +08:00
sprintf(szTemp, "%02d:%02d:%02d.%02d", h, m, s, t * 100 / 60);
DrawString(256 - 80 + 0, offset_v - 1, szTemp, 0x1F);
DrawString(256 - 80 + 0, offset_v + 1, szTemp, 0x1F);
DrawString(256 - 80 - 1, offset_v + 0, szTemp, 0x1F);
DrawString(256 - 80 + 1, offset_v + 0, szTemp, 0x1F);
DrawString(256 - 80, offset_v, szTemp, 0x30);
}
}
}
2024-07-31 17:40:32 +08:00
void NES::DrawBitmap(INT x, INT y, LPBYTE lpBitmap)
{
2024-07-31 17:40:32 +08:00
INT i, j;
INT h, v;
LPBYTE pScn = ppu->GetScreenPtr() + 8 + (256 + 16) * y + x;
LPBYTE pPtr;
h = (INT)*lpBitmap++;
v = (INT)*lpBitmap++;
2024-07-31 17:40:32 +08:00
for (j = 0; j < v; j++) {
pPtr = pScn;
2024-07-31 17:40:32 +08:00
for (i = 0; i < h; i++) {
if (*lpBitmap != 0xFF) {
*pPtr = *lpBitmap;
}
lpBitmap++;
pPtr++;
}
2024-07-31 17:40:32 +08:00
pScn += 256 + 16;
}
}
// TapeDevice
2024-07-31 17:40:32 +08:00
BOOL NES::TapePlay(const char* fname)
{
2024-07-31 17:40:32 +08:00
if (rom->IsNSF())
return FALSE;
2024-07-31 17:40:32 +08:00
if (IsTapePlay() || IsTapeRec()) {
TapeStop();
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("NES::TapePlay\n");
2024-07-31 17:40:32 +08:00
if (!(m_fpTape = ::fopen(fname, "rb"))) {
DEBUGOUT("Tape play error. File not found.\n");
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0!qD0g0Y0
return FALSE;
}
2024-07-31 17:40:32 +08:00
m_bTapePlay = TRUE;
m_TapeCycles = 0;
2024-07-31 17:40:32 +08:00
m_TapeOut = 0;
2024-07-31 17:40:32 +08:00
cpu->SetClockProcess(TRUE);
return TRUE;
}
2024-07-31 17:40:32 +08:00
BOOL NES::TapeRec(const char* fname)
{
2024-07-31 17:40:32 +08:00
if (rom->IsNSF())
return FALSE;
2024-07-31 17:40:32 +08:00
if (IsTapePlay() || IsTapeRec()) {
TapeStop();
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("NES::TapeRec\n");
2024-07-31 17:40:32 +08:00
if (!(m_fpTape = ::fopen(fname, "wb"))) {
DEBUGOUT("Tape rec error. File not found.\n");
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0!qD0g0Y0
return FALSE;
}
2024-07-31 17:40:32 +08:00
m_bTapeRec = TRUE;
m_TapeCycles = 0;
2024-07-31 17:40:32 +08:00
m_TapeIn = 0;
2024-07-31 17:40:32 +08:00
cpu->SetClockProcess(TRUE);
return TRUE;
}
void NES::TapeStop()
{
2024-07-31 17:40:32 +08:00
DirectDraw.SetMessageString("Tape stop.");
2024-07-31 17:40:32 +08:00
if (!m_bBarcode) {
cpu->SetClockProcess(FALSE);
}
m_bTapePlay = m_bTapeRec = FALSE;
2024-07-31 17:40:32 +08:00
FCLOSE(m_fpTape);
}
2024-07-31 17:40:32 +08:00
void NES::Tape(INT cycles)
{
2024-07-31 17:40:32 +08:00
if (!(IsTapePlay() || IsTapeRec())) {
return;
}
2024-07-31 17:40:32 +08:00
if ((m_TapeCycles -= (double)cycles) > 0)
return;
m_TapeCycles += (nescfg->CpuClock / 32000.0);
2024-07-31 17:40:32 +08:00
// m_TapeCycles += (nescfg->CpuClock / 22050.0); // E<EFBFBD>Y0N0f0<EFBFBD>0<EFBFBD>0c0}0D0
2024-07-31 17:40:32 +08:00
if (m_bTapePlay) {
INT data = ::fgetc(m_fpTape);
if (data != EOF) {
if ((data & 0xFF) >= 0x8C) {
m_TapeOut = 0x02;
}
2024-07-31 17:40:32 +08:00
else
if ((data & 0xFF) <= 0x74) {
m_TapeOut = 0x00;
}
}
else {
TapeStop();
}
}
2024-07-31 17:40:32 +08:00
if (m_bTapeRec) {
::fputc((int)((m_TapeIn & 7) == 7) ? 0x90 : 0x70, m_fpTape);
}
}
2024-07-31 17:40:32 +08:00
void NES::Barcode(INT cycles)
{
2024-07-31 17:40:32 +08:00
if (m_bBarcode) {
if ((m_BarcodeCycles += cycles) > 1000) {
m_BarcodeCycles = 0;
// \Pbk<EFBFBD>
2024-07-31 17:40:32 +08:00
if (m_BarcodeData[m_BarcodePtr] != 0xFF) {
m_BarcodeOut = m_BarcodeData[m_BarcodePtr++];
2024-07-31 17:40:32 +08:00
}
else {
m_bBarcode = FALSE;
m_BarcodeOut = 0;
2024-07-31 17:40:32 +08:00
DEBUGOUT("Barcode data trasnfer complete!!\n");
2024-07-31 17:40:32 +08:00
if (!(IsTapePlay() || IsTapeRec())) {
cpu->SetClockProcess(FALSE);
}
}
}
}
}
2024-07-31 17:40:32 +08:00
void NES::SetBarcodeData(LPBYTE code, INT len)
{
2024-07-31 17:40:32 +08:00
if (rom->GetPROM_CRC() == 0x67898319) { // Barcode World (J)
SetBarcode2Data(code, len);
return;
}
2024-07-31 17:40:32 +08:00
DEBUGOUT("NES::SetBarcodeData code=%s len=%d\n", code, len);
bool prefix_parity_type[10][6] = {
{0,0,0,0,0,0}, {0,0,1,0,1,1}, {0,0,1,1,0,1}, {0,0,1,1,1,0},
{0,1,0,0,1,1}, {0,1,1,0,0,1}, {0,1,1,1,0,0}, {0,1,0,1,0,1},
{0,1,0,1,1,0}, {0,1,1,0,1,0}
};
bool data_left_odd[10][7] = {
{0,0,0,1,1,0,1}, {0,0,1,1,0,0,1}, {0,0,1,0,0,1,1}, {0,1,1,1,1,0,1},
{0,1,0,0,0,1,1}, {0,1,1,0,0,0,1}, {0,1,0,1,1,1,1}, {0,1,1,1,0,1,1},
{0,1,1,0,1,1,1}, {0,0,0,1,0,1,1}
};
bool data_left_even[10][7] = {
{0,1,0,0,1,1,1}, {0,1,1,0,0,1,1}, {0,0,1,1,0,1,1}, {0,1,0,0,0,0,1},
{0,0,1,1,1,0,1}, {0,1,1,1,0,0,1}, {0,0,0,0,1,0,1}, {0,0,1,0,0,0,1},
{0,0,0,1,0,0,1}, {0,0,1,0,1,1,1}
};
bool data_right[10][7] = {
{1,1,1,0,0,1,0}, {1,1,0,0,1,1,0}, {1,1,0,1,1,0,0}, {1,0,0,0,0,1,0},
{1,0,1,1,1,0,0}, {1,0,0,1,1,1,0}, {1,0,1,0,0,0,0}, {1,0,0,0,1,0,0},
{1,0,0,1,0,0,0}, {1,1,1,0,1,0,0}
};
INT i, j, count = 0;;
// pe$Pk0 Y<EFBFBD>c
2024-07-31 17:40:32 +08:00
for (i = 0; i < len; i++) {
code[i] = code[i] - '0';
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
for (i = 0; i < 32; i++) {
m_BarcodeData[count++] = 0x08;
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
m_BarcodeData[count++] = 0x00;
m_BarcodeData[count++] = 0x08;
m_BarcodeData[count++] = 0x00;
2024-07-31 17:40:32 +08:00
if (len == 13) {
#if 0
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>Q<EFBFBD><EFBFBD>{
INT sum = 0;
2024-07-31 17:40:32 +08:00
for (i = 0; i < 12; i++) {
sum += (i & 1) ? (code[i] * 3) : code[i];
}
code[12] = (10 - (sum % 10)) % 10;
// test start
// INT cs = (10-(sum%10))%10;
// if( cs == 0 ) {
// cs = 9;
// } else {
// cs--;
// }
// code[12] = cs;
// test end
#endif
// <EFBFBD>]tP6<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
for (i = 0; i < 6; i++) {
if (prefix_parity_type[code[0]][i]) {
// vPpe<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
for (j = 0; j < 7; j++) {
m_BarcodeData[count++] = data_left_even[code[i + 1]][j] ? 0x00 : 0x08;
}
2024-07-31 17:40:32 +08:00
}
else {
// GYpe<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
for (j = 0; j < 7; j++) {
m_BarcodeData[count++] = data_left_odd[code[i + 1]][j] ? 0x00 : 0x08;
}
}
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
m_BarcodeData[count++] = 0x08;
m_BarcodeData[count++] = 0x00;
m_BarcodeData[count++] = 0x08;
m_BarcodeData[count++] = 0x00;
m_BarcodeData[count++] = 0x08;
// <EFBFBD>StP5<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0h0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
for (i = 7; i < 13; i++) {
// vPpe<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
for (j = 0; j < 7; j++) {
m_BarcodeData[count++] = data_right[code[i]][j] ? 0x00 : 0x08;
}
}
2024-07-31 17:40:32 +08:00
}
else
if (len == 8) {
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>Q<EFBFBD><EFBFBD>{
INT sum = 0;
for (i = 0; i < 7; i++) {
sum += (i & 1) ? code[i] : (code[i] * 3);
}
code[7] = (10 - (sum % 10)) % 10;
2024-07-31 17:40:32 +08:00
// <EFBFBD>]tP4<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
for (i = 0; i < 4; i++) {
// GYpe<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
for (j = 0; j < 7; j++) {
m_BarcodeData[count++] = data_left_odd[code[i]][j] ? 0x00 : 0x08;
}
}
2024-07-31 17:40:32 +08:00
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
m_BarcodeData[count++] = 0x08;
m_BarcodeData[count++] = 0x00;
m_BarcodeData[count++] = 0x08;
m_BarcodeData[count++] = 0x00;
m_BarcodeData[count++] = 0x08;
2024-07-31 17:40:32 +08:00
// <EFBFBD>StP3<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0h0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
for (i = 4; i < 8; i++) {
// vPpe<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
for (j = 0; j < 7; j++) {
m_BarcodeData[count++] = data_right[code[i]][j] ? 0x00 : 0x08;
}
}
}
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
m_BarcodeData[count++] = 0x00;
m_BarcodeData[count++] = 0x08;
m_BarcodeData[count++] = 0x00;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
2024-07-31 17:40:32 +08:00
for (i = 0; i < 32; i++) {
m_BarcodeData[count++] = 0x08;
}
// B}<EFBFBD>N<EFBFBD>0<EFBFBD>0<EFBFBD>0
m_BarcodeData[count++] = 0xFF;
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Y
2024-07-31 17:40:32 +08:00
m_bBarcode = TRUE;
m_BarcodeCycles = 0;
2024-07-31 17:40:32 +08:00
m_BarcodePtr = 0;
m_BarcodeOut = 0x08;
2024-07-31 17:40:32 +08:00
cpu->SetClockProcess(TRUE);
2024-07-31 17:40:32 +08:00
DEBUGOUT("BARCODE DATA MAX:%d\n", count);
}
2024-07-31 17:40:32 +08:00
BYTE NES::Barcode2(void)
{
2024-07-31 17:40:32 +08:00
BYTE ret = 0x00;
2024-07-31 17:40:32 +08:00
if (!m_bBarcode2 || m_Barcode2seq < 0)
return ret;
2024-07-31 17:40:32 +08:00
switch (m_Barcode2seq) {
case 0:
m_Barcode2seq++;
m_Barcode2ptr = 0;
ret = 0x04; // d3
break;
case 1:
m_Barcode2seq++;
m_Barcode2bit = m_Barcode2data[m_Barcode2ptr];
m_Barcode2cnt = 0;
ret = 0x04; // d3
break;
case 2:
ret = (m_Barcode2bit & 0x01) ? 0x00 : 0x04; // Bit rev.
m_Barcode2bit >>= 1;
if (++m_Barcode2cnt > 7) {
m_Barcode2seq++;
2024-07-31 17:40:32 +08:00
}
break;
case 3:
if (++m_Barcode2ptr > 19) {
m_bBarcode2 = FALSE;
m_Barcode2seq = -1;
}
else {
m_Barcode2seq = 1;
}
break;
default:
break;
}
return ret;
}
2024-07-31 17:40:32 +08:00
void NES::SetBarcode2Data(LPBYTE code, INT len)
{
2024-07-31 17:40:32 +08:00
DEBUGOUT("NES::SetBarcodeData2 code=%s len=%d\n", code, len);
2024-07-31 17:40:32 +08:00
if (len < 13)
return;
2024-07-31 17:40:32 +08:00
m_bBarcode2 = TRUE;
m_Barcode2seq = 0;
m_Barcode2ptr = 0;
2024-07-31 17:40:32 +08:00
::strcpy((char*)m_Barcode2data, (char*)code);
m_Barcode2data[13] = 'S';
m_Barcode2data[14] = 'U';
m_Barcode2data[15] = 'N';
m_Barcode2data[16] = 'S';
m_Barcode2data[17] = 'O';
m_Barcode2data[18] = 'F';
m_Barcode2data[19] = 'T';
}
//#if NES_PROFILER
#if 1
BYTE NES::Font6x8[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,
0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x50,0xF8,0x50,0xF8,0x50,0x50,0x00,
0x20,0x78,0xA0,0x70,0x28,0xF0,0x20,0x00,0x48,0xB0,0x50,0x20,0x50,0x68,0x90,0x00,
0x40,0xA0,0xA8,0x68,0x90,0x90,0x68,0x00,0x30,0x20,0x00,0x00,0x00,0x00,0x00,0x00,
0x10,0x20,0x40,0x40,0x40,0x20,0x10,0x00,0x40,0x20,0x10,0x10,0x10,0x20,0x40,0x00,
0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00,0x00,0x20,0x20,0xF8,0x20,0x20,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x20,0x40,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x08,0x10,0x10,0x20,0x40,0x40,0x80,0x00,
0x70,0x88,0x98,0xA8,0xC8,0x88,0x70,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0xF8,0x00,
0x70,0x88,0x08,0x30,0x40,0x80,0xF8,0x00,0x70,0x88,0x08,0x30,0x08,0x88,0x70,0x00,
0x30,0x50,0x90,0x90,0xF8,0x10,0x10,0x00,0xF8,0x80,0x80,0xF0,0x08,0x08,0xF0,0x00,
0x70,0x88,0x80,0xF0,0x88,0x88,0x70,0x00,0xF8,0x08,0x10,0x10,0x20,0x20,0x20,0x00,
0x70,0x88,0x88,0x70,0x88,0x88,0x70,0x00,0x70,0x88,0x88,0x78,0x08,0x88,0x70,0x00,
0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x40,0x00,
0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x00,0x00,0x00,0xF8,0x00,0xF8,0x00,0x00,0x00,
0x40,0x20,0x10,0x08,0x10,0x20,0x40,0x00,0x70,0x88,0x08,0x10,0x20,0x00,0x20,0x00,
0x30,0x48,0x88,0x98,0xA8,0xA8,0x78,0x00,0x20,0x50,0x50,0x88,0xF8,0x88,0x88,0x00,
0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0,0x00,0x70,0x88,0x80,0x80,0x80,0x88,0x70,0x00,
0xF0,0x88,0x88,0x88,0x88,0x88,0xF0,0x00,0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8,0x00,
0xF8,0x80,0x80,0xF0,0x80,0x80,0x80,0x00,0x70,0x88,0x80,0xB8,0x88,0x88,0x70,0x00,
0x88,0x88,0x88,0xF8,0x88,0x88,0x88,0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,
0x38,0x08,0x08,0x08,0x08,0x88,0x70,0x00,0x88,0x88,0x90,0xE0,0x90,0x88,0x88,0x00,
0x80,0x80,0x80,0x80,0x80,0x80,0xF8,0x00,0x88,0xD8,0xA8,0xA8,0xA8,0xA8,0xA8,0x00,
0x88,0xC8,0xA8,0xA8,0xA8,0x98,0x88,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x70,0x00,
0xF0,0x88,0x88,0xF0,0x80,0x80,0x80,0x00,0x70,0x88,0x88,0x88,0xA8,0x90,0x68,0x00,
0xF0,0x88,0x88,0xF0,0x88,0x88,0x88,0x00,0x70,0x88,0x80,0x70,0x08,0x88,0x70,0x00,
0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,
0x88,0x88,0x88,0x50,0x50,0x50,0x20,0x00,0x88,0xA8,0xA8,0xA8,0xA8,0xD8,0x88,0x00,
0x88,0x88,0x50,0x20,0x50,0x88,0x88,0x00,0x88,0x88,0x88,0x70,0x20,0x20,0x20,0x00,
0xF8,0x08,0x10,0x20,0x40,0x80,0xF8,0x00,0x70,0x40,0x40,0x40,0x40,0x40,0x70,0x00,
0x88,0x50,0xF8,0x20,0xF8,0x20,0x20,0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x70,0x00,
0x20,0x50,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x00,
0x80,0xC0,0xE0,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x70,0x08,0x78,0x88,0xF8,0x00,
0x80,0x80,0x80,0xF0,0x88,0x88,0xF0,0x00,0x00,0x00,0x78,0x80,0x80,0x80,0x78,0x00,
0x08,0x08,0x08,0x78,0x88,0x88,0x78,0x00,0x00,0x00,0x70,0x88,0xF8,0x80,0x78,0x00,
0x18,0x20,0xF8,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x78,0x88,0x78,0x08,0xF0,0x00,
0x80,0x80,0x80,0xF0,0x88,0x88,0x88,0x00,0x20,0x00,0x20,0x20,0x20,0x20,0x20,0x00,
0x20,0x00,0x20,0x20,0x20,0x20,0xC0,0x00,0x80,0x80,0x88,0x90,0xE0,0x90,0x88,0x00,
0x20,0x20,0x20,0x20,0x20,0x20,0x30,0x00,0x00,0x00,0xF0,0xA8,0xA8,0xA8,0xA8,0x00,
0x00,0x00,0xF0,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x70,0x88,0x88,0x88,0x70,0x00,
0x00,0x00,0xF0,0x88,0xF0,0x80,0x80,0x00,0x00,0x00,0x78,0x88,0x78,0x08,0x08,0x00,
0x00,0x00,0xB8,0xC0,0x80,0x80,0x80,0x00,0x00,0x00,0x78,0x80,0x70,0x08,0xF0,0x00,
0x20,0x20,0xF8,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x70,0x00,
0x00,0x00,0x88,0x88,0x50,0x50,0x20,0x00,0x00,0x00,0x88,0xA8,0xA8,0xD8,0x88,0x00,
0x00,0x00,0x88,0x50,0x20,0x50,0x88,0x00,0x00,0x00,0x88,0x88,0x78,0x08,0xF0,0x00,
0x00,0x00,0xF8,0x08,0x70,0x80,0xF8,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,
};
2024-07-31 17:40:32 +08:00
void NES::DrawFont(INT x, INT y, BYTE chr, BYTE col)
{
2024-07-31 17:40:32 +08:00
INT i;
LPBYTE pFnt;
LPBYTE pPtr;
LPBYTE pScn = ppu->GetScreenPtr() + 8;
2024-07-31 17:40:32 +08:00
if (chr < 0x20 || chr > 0x7F)
return;
chr -= 0x20;
2024-07-31 17:40:32 +08:00
pFnt = &Font6x8[chr * 8];
pPtr = pScn + (256 + 16) * y + x;
for (i = 0; i < 8; i++) {
if (pFnt[i] & 0x80) pPtr[0] = col;
if (pFnt[i] & 0x40) pPtr[1] = col;
if (pFnt[i] & 0x20) pPtr[2] = col;
if (pFnt[i] & 0x10) pPtr[3] = col;
if (pFnt[i] & 0x08) pPtr[4] = col;
if (pFnt[i] & 0x04) pPtr[5] = col;
pPtr += (256 + 16);
}
}
2024-07-31 17:40:32 +08:00
void NES::DrawString(INT x, INT y, LPSTR str, BYTE col)
{
2024-07-31 17:40:32 +08:00
while (*str) {
DrawFont(x, y, *str, col);
str++;
x += 6;
}
}
#endif