📄 nes.cpp
字号:
void NES::EmulationCPU_BeforeNMI( INT cycles )
{
base_cycles += cycles;
emul_cycles += cpu->EXEC( cycles/12 );
}
/*
昤夋僔乕働儞僗
0 僟儈乕僗僉儍儞儔僀儞(昤夋偟側偄)
1 - 239 昤夋
240 僟儈乕僗僉儍儞儔僀儞,VBLANK僼儔僌ON
241 VINT婜娫,NMI敪惗
242-261 VINT婜娫
261 VINT婜娫,VBLANK僼儔僌OFF
*/
void NES::EmulateFrame( BOOL bDraw )
{
INT scanline = 0;
// NSF僾儗僀儎偺帪
if( rom->IsNSF() ) {
EmulateNSF();
return;
}
// Cheat
CheatCodeProcess();
//
NES_scanline = scanline;
if( RenderMethod != TILE_RENDER ) {
bZapper = FALSE;
while( TRUE ) {
ppu->SetRenderScanline( scanline );
if( scanline == 0 ) {
// 僟儈乕僗僉儍儞儔僀儞
if( RenderMethod < POST_RENDER ) {
EmulationCPU( nescfg->ScanlineCycles );
ppu->FrameStart();
ppu->ScanlineNext();
mapper->HSync( scanline );
ppu->ScanlineStart();
} else {
EmulationCPU( nescfg->HDrawCycles );
ppu->FrameStart();
ppu->ScanlineNext();
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*32 );
ppu->ScanlineStart();
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(); // 偙傟偺埵抲偱儔僗僞乕宯偼夋柺偑堘偆
if( RenderMethod == PRE_ALL_RENDER )
EmulationCPU( nescfg->ScanlineCycles );
// ppu->ScanlineNext(); // 偙傟偺埵抲偱儔僗僞乕宯偼夋柺偑堘偆
mapper->HSync( scanline );
ppu->ScanlineStart();
} 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 );
}
}
}
if( RenderMethod == PRE_RENDER )
EmulationCPU( nescfg->HDrawCycles );
ppu->ScanlineNext();
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*32 );
ppu->ScanlineStart();
EmulationCPU( FETCH_CYCLES*10+nescfg->ScanlineEndCycles );
}
} else if( scanline == 240 ) {
mapper->VSync();
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 ) {
// VBLANK婜娫
if( scanline == nescfg->TotalScanlines-1 ) {
ppu->VBlankEnd();
}
if( RenderMethod < POST_RENDER ) {
if( scanline == 241 ) {
ppu->VBlankStart();
if( PPUREG[0] & PPU_VBLANK_BIT ) {
cpu->NMI();
}
}
EmulationCPU( nescfg->ScanlineCycles );
mapper->HSync( scanline );
} else {
if( scanline == 241 ) {
ppu->VBlankStart();
if( PPUREG[0] & PPU_VBLANK_BIT ) {
cpu->NMI();
}
}
EmulationCPU( nescfg->HDrawCycles );
mapper->HSync( scanline );
EmulationCPU( nescfg->HBlankCycles );
}
if( scanline == nescfg->TotalScanlines-1 ) {
break;
}
}
if( pad->IsZapperMode() ) {
if( scanline == ZapperY )
bZapper = TRUE;
else
bZapper = FALSE;
}
scanline++;
NES_scanline = scanline;
}
} else {
bZapper = FALSE;
while( TRUE ) {
ppu->SetRenderScanline( scanline );
if( scanline == 0 ) {
// 僟儈乕僗僉儍儞儔僀儞
// H-Draw (4fetches*32)
EmulationCPU( FETCH_CYCLES*128 );
ppu->FrameStart();
ppu->ScanlineNext();
#if 0
EmulationCPU( FETCH_CYCLES*16 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*16 );
#else
EmulationCPU( FETCH_CYCLES*10 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*22 );
#endif
ppu->ScanlineStart();
EmulationCPU( FETCH_CYCLES*10+nescfg->ScanlineEndCycles );
} else if( scanline < 240 ) {
// 僗僋儕乕儞昤夋(Scanline 1乣239)
if( bDraw ) {
ppu->Scanline( scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip );
ppu->ScanlineNext();
#if 0
EmulationCPU( FETCH_CYCLES*16 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*16 );
#else
EmulationCPU( FETCH_CYCLES*10 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*22 );
#endif
ppu->ScanlineStart();
EmulationCPU( FETCH_CYCLES*10+nescfg->ScanlineEndCycles );
} else {
if( pad->IsZapperMode() && scanline == ZapperY ) {
ppu->Scanline( scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip );
ppu->ScanlineNext();
#if 0
EmulationCPU( FETCH_CYCLES*16 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*16 );
#else
EmulationCPU( FETCH_CYCLES*10 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*22 );
#endif
ppu->ScanlineStart();
EmulationCPU( FETCH_CYCLES*10+nescfg->ScanlineEndCycles );
} else {
if( !ppu->IsSprite0( scanline ) ) {
// H-Draw (4fetches*32)
EmulationCPU( FETCH_CYCLES*128 );
ppu->DummyScanline( scanline );
ppu->ScanlineNext();
#if 0
EmulationCPU( FETCH_CYCLES*16 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*16 );
#else
EmulationCPU( FETCH_CYCLES*10 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*22 );
#endif
ppu->ScanlineStart();
EmulationCPU( FETCH_CYCLES*10+nescfg->ScanlineEndCycles );
} else {
///////--- EmulationCPU( nescfg->HDrawCycles );
ppu->Scanline( scanline, Config.graphics.bAllSprite, Config.graphics.bLeftClip );
ppu->ScanlineNext();
#if 0
EmulationCPU( FETCH_CYCLES*16 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*16 );
#else
EmulationCPU( FETCH_CYCLES*10 );
mapper->HSync( scanline );
EmulationCPU( FETCH_CYCLES*22 );
#endif
ppu->ScanlineStart();
EmulationCPU( FETCH_CYCLES*10+nescfg->ScanlineEndCycles );
}
}
}
} else if( scanline == 240 ) {
// 僟儈乕僗僉儍儞儔僀儞 (Scanline 240)
mapper->VSync();
EmulationCPU( nescfg->HDrawCycles );
// H-Sync
mapper->HSync( scanline );
EmulationCPU( nescfg->HBlankCycles );
} else if( scanline <= nescfg->TotalScanlines-1 ) {
// VBLANK婜娫
if( scanline == nescfg->TotalScanlines-1 ) {
ppu->VBlankEnd();
}
if( scanline == 241 ) {
ppu->VBlankStart();
if( PPUREG[0]&PPU_VBLANK_BIT ) {
cpu->NMI();
}
}
EmulationCPU( nescfg->HDrawCycles );
// H-Sync
mapper->HSync( scanline );
EmulationCPU( nescfg->HBlankCycles );
if( scanline == nescfg->TotalScanlines-1 ) {
break;
}
}
if( pad->IsZapperMode() ) {
if( scanline == ZapperY )
bZapper = TRUE;
else
bZapper = FALSE;
}
scanline++;
NES_scanline = scanline;
}
}
// Movie pad
if( Config.movie.bPadDisplay && bDraw ) {
DrawPad();
}
}
void NES::EmulateNSF()
{
R6502 reg;
ppu->Reset();
mapper->VSync();
//DEBUGOUT( "Frame\n" );
if( m_bNsfPlaying ) {
if( m_bNsfInit ) {
ZEROMEMORY( RAM, sizeof(RAM) );
if( !(rom->GetNsfHeader()->ExtraChipSelect&0x04) ) {
ZEROMEMORY( WRAM, 0x2000 );
}
apu->Reset();
apu->Write( 0x4015, 0x1F );
apu->Write( 0x4017, 0xC0 );
apu->ExWrite( 0x4080, 0x80 ); // FDS Volume 0
apu->ExWrite( 0x408A, 0xE8 ); // FDS Envelope Speed
cpu->GetContext( reg );
reg.PC = 0x4710; // Init Address
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 );
// 埨慡懳嶔傪寭偹偰偁偊偰儖乕僾偵(1昩暘)
for( INT i = 0; i < nescfg->TotalScanlines*60; i++ ) {
EmulationCPU( nescfg->ScanlineCycles );
cpu->GetContext( reg );
// 柍尷儖乕僾偵擖偭偨偙偲傪妋擣偟偨傜敳偗傞
if( reg.PC == 0x4700 ) {
break;
}
}
m_bNsfInit = FALSE;
}
cpu->GetContext( reg );
// 柍尷儖乕僾偵擖偭偰偄偨傜嵞愝掕偡傞
if( reg.PC == 0x4700 ) {
reg.PC = 0x4720; // Play Address
reg.A = 0;
reg.S = 0xFF;
cpu->SetContext( reg );
}
for( INT i = 0; i < nescfg->TotalScanlines; i++ ) {
EmulationCPU( nescfg->ScanlineCycles );
}
} else {
cpu->GetContext( reg );
reg.PC = 0x4700; // 柍尷儖乕僾
reg.S = 0xFF;
cpu->SetContext( reg );
EmulationCPU( nescfg->ScanlineCycles*nescfg->TotalScanlines );
}
}
void NES::SetNsfPlay( INT songno, INT songmode )
{
m_bNsfPlaying = TRUE;
m_bNsfInit = TRUE;
m_nNsfSongNo = songno;
m_nNsfSongMode = songmode;
}
void NES::SetNsfStop()
{
m_bNsfPlaying = FALSE;
apu->Reset();
}
void NES::Clock( INT cycles )
{
Tape( cycles );
Barcode( cycles );
}
BYTE NES::Read( WORD addr )
{
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梊杊
}
void NES::Write( WORD addr, BYTE data )
{
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 );
GenieCodeProcess();
break;
}
}
BYTE NES::ReadReg( WORD addr )
{
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;
}
}
void NES::WriteReg( WORD addr, BYTE data )
{
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -