📄 nes.cpp
字号:
#ifndef _DEBUG
} catch(...) {
DEBUGOUT( "Writing TurboFile Error.\n" );
FCLOSE( fp );
// 晄柧側僄儔乕偑敪惗偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_UNKNOWN );
#endif
}
}
}
INT NES::IsStateFile( const char* fname, ROM* rom )
{
FILE* fp = NULL;
FILEHDR2 header;
if( !(fp = ::fopen( fname, "rb" )) )
return -1;
if( ::fread( &header, sizeof(header), 1, fp ) != 1 ) {
FCLOSE( fp );
return -1;
}
FCLOSE( fp );
if( ::memcmp( header.ID, "VirtuaNES ST", sizeof(header.ID) ) == 0 ) {
if( header.BlockVersion < 0x0100 )
return 0;
if( Config.emulator.bCrcCheck ) {
if( header.BlockVersion >= 0x200 ) {
if( rom->GetMapperNo() != 20 ) {
// FDS埲奜
if( header.Ext0 != rom->GetPROM_CRC() ) {
return IDS_ERROR_ILLEGALSTATECRC; // 堘偆偠傖傫
}
} else {
// FDS
if( header.Ext0 != rom->GetGameID() ||
header.Ext1 != (WORD)rom->GetMakerID() ||
header.Ext2 != (WORD)rom->GetDiskNo() )
return IDS_ERROR_ILLEGALSTATECRC; // 堘偆偠傖傫
}
}
}
return 0;
}
return -1;
}
BOOL NES::LoadState( const char* fname )
{
FILE* fp = NULL;
BOOL bRet = FALSE;
if( rom->IsNSF() )
return TRUE;
try {
if( !(fp = ::fopen( fname, "rb" )) ) {
// xxx 僼傽僀儖傪奐偗傑偣傫
LPCSTR szErrStr = CApp::GetErrorString( IDS_ERROR_OPEN );
sprintf( szErrorString, szErrStr, fname );
throw szErrorString;
}
bRet = ReadState( fp );
FCLOSE( fp );
} catch( CHAR* str ) {
DEBUGOUT( "State load error.\n" );
DEBUGOUT( "%s\n", str );
FCLOSE( fp );
return FALSE;
#ifndef _DEBUG
} catch(...) {
DEBUGOUT( "State load error.\n" );
FCLOSE( fp );
// 晄柧側僄儔乕偑敪惗偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_UNKNOWN );
#endif
}
return bRet;
}
BOOL NES::SaveState( const char* fname )
{
FILE* fp = NULL;
if( rom->IsNSF() )
return TRUE;
try {
if( !(fp = ::fopen( fname, "wb" )) ) {
// xxx 僼傽僀儖傪奐偗傑偣傫
LPCSTR szErrStr = CApp::GetErrorString( IDS_ERROR_OPEN );
sprintf( szErrorString, szErrStr, fname );
throw szErrorString;
}
WriteState( fp );
FCLOSE( fp );
} catch( CHAR* str ) {
DEBUGOUT( "State save error.\n" );
FCLOSE( fp );
throw str;
#ifndef _DEBUG
} catch(...) {
DEBUGOUT( "State save error.\n" );
FCLOSE( fp );
// 晄柧側僄儔乕偑敪惗偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_UNKNOWN );
#endif
}
return TRUE;
}
BOOL NES::ReadState( FILE* fp )
{
INT i;
BOOL bHeader = FALSE;
WORD Version = 0;
BLOCKHDR hdr;
INT type;
while( TRUE ) {
// Read File
if( ::fread( &hdr, sizeof(BLOCKHDR), 1, fp ) != 1 )
break;
// File Header check
if( !bHeader ) {
LPFILEHDR fh = (LPFILEHDR)&hdr;
if( ::memcmp( fh->ID, "VirtuaNES ST", sizeof(fh->ID) ) == 0 ) {
Version = fh->BlockVersion;
if( Version == 0x0100 ) {
// Ver0.24傑偱
bHeader = TRUE;
// 屆偄搝偼儉乕價乕拞偼儘乕僪弌棃傑偣傫
if( m_bMoviePlay ) {
return FALSE;
}
// 屆偄搝偺FDS偼儘乕僪弌棃傑偣傫
if( rom->GetMapperNo() == 20 ) {
// 枹懳墳宍幃偱偡
throw CApp::GetErrorString( IDS_ERROR_UNSUPPORTFORMAT );
}
} else
if( Version == 0x0200 || Version == 0x0210 ) {
// Ver0.30埲崀 Ver0.60埲崀
FILEHDR2 hdr2;
// 僿僢僟晹撉傒捈偟
if( ::fseek( fp, -sizeof(BLOCKHDR), SEEK_CUR ) ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
// Read File
if( ::fread( &hdr2, sizeof(FILEHDR2), 1, fp ) != 1 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
#if 0
if( Config.emulator.bCrcCheck ) {
// 尰嵼儘乕僪拞偺僞僀僩儖偲堘偆偐傪僠僃僢僋
if( rom->GetMapperNo() != 20 ) {
// FDS埲奜
if( hdr2.Ext0 != rom->GetPROM_CRC() ) {
return FALSE; // 堘偆偠傖傫
}
} else {
// FDS
if( hdr2.Ext0 != rom->GetGameID() ||
hdr2.Ext1 != (WORD)rom->GetMakerID() ||
hdr2.Ext2 != (WORD)rom->GetDiskNo() )
return FALSE; // 堘偆偠傖傫
}
}
#endif
// 儉乕價乕拞偼僼傽僀儖億僀儞僞偲僗僥僢僾悢傪
// 曄峏偟偰丆儉乕價乕傪婰榐儌乕僪偵曄峏
if( m_bMoviePlay || m_bMovieRec ) {
// 嶣傝捈偟壜擻丠
if( m_hedMovie.Control & 0x80 ) {
if( hdr2.MovieOffset && hdr2.MovieStep ) {
if( m_bMoviePlay ) {
// 嵞惗拞
// 僗僥乕僩偺僗僥僢僾悢偑婰榐傛傝恑傫偱偨傜僟儊
if( hdr2.MovieStep > m_hedMovie.MovieStep )
return FALSE;
} else {
// 婰榐拞
// 僗僥乕僩偺僗僥僢僾悢偑尰嵼傛傝恑傫偱偨傜僟儊
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++; // 嶣傝捈偟夞悢+1
if( ::fseek( m_fpMovie, hdr2.MovieOffset, SEEK_SET ) ) {
//DEBUGOUT( "MOVIE:STATE LOAD SEEK 幐攕\n" );
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
} else {
return FALSE;
}
} else {
return FALSE;
}
}
}
bHeader = TRUE;
continue;
}
}
if( !bHeader ) {
// 枹懳墳宍幃偱偡
throw CApp::GetErrorString( IDS_ERROR_UNSUPPORTFORMAT );
}
//DEBUGOUT( "HEADER ID=%8s\n", hdr.ID );
type = -1;
if( ::memcmp( hdr.ID, "REG DATA", sizeof(hdr.ID) ) == 0 )
type = 0;
if( ::memcmp( hdr.ID, "RAM DATA", sizeof(hdr.ID) ) == 0 )
type = 1;
if( ::memcmp( hdr.ID, "MMU DATA", sizeof(hdr.ID) ) == 0 )
type = 2;
if( ::memcmp( hdr.ID, "MMC DATA", sizeof(hdr.ID) ) == 0 )
type = 3;
if( ::memcmp( hdr.ID, "CTR DATA", sizeof(hdr.ID) ) == 0 )
type = 4;
if( ::memcmp( hdr.ID, "SND DATA", sizeof(hdr.ID) ) == 0 )
type = 5;
if( rom->GetMapperNo() == 20 ) {
if( ::memcmp( hdr.ID, "DISKDATA", sizeof(hdr.ID) ) == 0 )
type = 6;
}
if( type == -1 ) {
//DEBUGOUT( "UNKNOWN HEADER ID=%8s\n", hdr.ID );
break;
}
switch( type ) {
case 0:
// REGISTER STATE
{
if( hdr.BlockVersion < 0x0200 ) {
REGSTAT_O reg;
if( ::fread( ®, sizeof(REGSTAT_O), 1, fp ) != 1 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
// 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;
}
// 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( ®, sizeof(REGSTAT), 1, fp ) != 1 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
// 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;
} 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
// 僉儏乕傪徚偡
apu->QueueClear();
// APU僗僥乕僩傪曐懚偡傞傛偆偵偟偨偺偱儎儊
// // DMC偼巭傔側偄偲傑偢偄帠偑婲偙傞
// 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 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
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 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
}
}
break;
case 2:
// BANK STATE
{
MMUSTAT mmu;
if( ::fread( &mmu, sizeof(MMUSTAT), 1, fp ) != 1 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
if( hdr.BlockVersion == 0x100 ) {
// 偪傚偭偲慜偺僶乕僕儑儞
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 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
} else if( !rom->IsSAVERAM() ) {
SetPROM_8K_Bank( 3, mmu.CPU_MEM_PAGE[3] );
}
// 僶儞僋0乣3埲奜儘乕僪
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 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
}
}
} else if( hdr.BlockVersion == 0x200 ) {
// 嵟怴僶乕僕儑儞
// SRAM偑偁偭偰傕慡晹儘乕僪偟側偍偟
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] );
} else {
if( ::fread( CPU_MEM_BANK[i], 8*1024, 1, fp ) != 1 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
}
}
}
// VRAM
if( ::fread( VRAM, 4*1024, 1, fp ) != 1 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
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 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
}
}
// BANK
for( i = 0; i < 12; i++ ) {
if( mmu.PPU_MEM_TYPE[i] == BANKTYPE_VROM ) {
SetVROM_1K_Bank( i, mmu.PPU_MEM_PAGE[i] );
} else if( mmu.PPU_MEM_TYPE[i] == BANKTYPE_CRAM ) {
SetCRAM_1K_Bank( i, mmu.PPU_MEM_PAGE[i] );
} else if( mmu.PPU_MEM_TYPE[i] == BANKTYPE_VRAM ) {
SetVRAM_1K_Bank( i, mmu.PPU_MEM_PAGE[i] );
} else {
throw "Unknown bank types.";
}
}
}
break;
case 3:
// MMC STATE
{
MMCSTAT mmc;
if( ::fread( &mmc, sizeof(MMCSTAT), 1, fp ) != 1 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
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 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
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;
case 5:
// SND STATE
{
SNDSTAT snd;
if( ::fread( &snd, sizeof(SNDSTAT), 1, fp ) != 1 ) {
// 僼傽僀儖偺撉傒崬傒偵幐攕偟傑偟偨
throw CApp::GetErrorString( IDS_ERROR_READ );
}
apu->LoadState( snd.snddata );
}
break;
// Disk Images
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -