⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nes.cpp

📁 著名的任天堂FC游戏机模拟器VirtuaNes 085版的源码!
💻 CPP
📖 第 1 页 / 共 5 页
字号:
	#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( &reg, 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( &reg, 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 + -