[nes] timing and accuracy work.

This commit is contained in:
zeromus 2011-06-06 10:27:42 +00:00
parent 89ff0c8927
commit e6afb2359b
15 changed files with 257 additions and 94 deletions

View File

@ -224,6 +224,7 @@
<Compile Include="Sound\Utilities\Waves.cs" /> <Compile Include="Sound\Utilities\Waves.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Consoles\Nintendo\Docs\test_status.txt" />
<Content Include="Consoles\PC Engine\Compat.txt" /> <Content Include="Consoles\PC Engine\Compat.txt" />
<Content Include="Consoles\Sega\SMS\Compat.txt" /> <Content Include="Consoles\Sega\SMS\Compat.txt" />
<Content Include="Notes.txt" /> <Content Include="Notes.txt" />

View File

@ -24,9 +24,20 @@ namespace BizHawk.Emulation.CPUs.M6502
} }
if (IRQ && !FlagI) if (IRQ && !FlagI)
{ {
if (SEI_Pending)
FlagI = true;
TriggerException(ExceptionType.IRQ); TriggerException(ExceptionType.IRQ);
} }
if (CLI_Pending)
{
FlagI = false;
CLI_Pending = false;
}
if (SEI_Pending)
{
FlagI = true;
SEI_Pending = false;
}
if(debug) Console.WriteLine(State()); if(debug) Console.WriteLine(State());
ushort this_pc = PC; ushort this_pc = PC;
@ -209,7 +220,15 @@ TriggerException(ExceptionType.BRK);
PendingCycles -= 5; TotalExecutedCycles += 5; PendingCycles -= 5; TotalExecutedCycles += 5;
break; break;
case 0x28: // PLP case 0x28: // PLP
P = ReadMemory((ushort)(++S + 0x100)); //handle I flag differently. sort of a sloppy way to do the job, but it does finish it off.
value8 = ReadMemory((ushort)(++S + 0x100));
if ((value8 & 0x04) != 0 && !FlagI)
SEI_Pending = true;
if ((value8 & 0x04) == 0 && FlagI)
CLI_Pending = true;
value8 &= unchecked((byte)~0x04);
P &= 0x04;
P |= value8;
FlagT = true;//this seems wrong FlagT = true;//this seems wrong
PendingCycles -= 4; TotalExecutedCycles += 4; PendingCycles -= 4; TotalExecutedCycles += 4;
break; break;
@ -431,7 +450,8 @@ FlagT = true;// this seems wrong
PendingCycles -= 6; TotalExecutedCycles += 6; PendingCycles -= 6; TotalExecutedCycles += 6;
break; break;
case 0x58: // CLI case 0x58: // CLI
FlagI = false; //FlagI = false;
CLI_Pending = true;
PendingCycles -= 2; TotalExecutedCycles += 2; PendingCycles -= 2; TotalExecutedCycles += 2;
break; break;
case 0x59: // EOR addr,Y case 0x59: // EOR addr,Y
@ -594,7 +614,8 @@ FlagT = true;// this seems wrong
PendingCycles -= 6; TotalExecutedCycles += 6; PendingCycles -= 6; TotalExecutedCycles += 6;
break; break;
case 0x78: // SEI case 0x78: // SEI
FlagI = true; //FlagI = true;
SEI_Pending = true;
PendingCycles -= 2; TotalExecutedCycles += 2; PendingCycles -= 2; TotalExecutedCycles += 2;
break; break;
case 0x79: // ADC addr,Y case 0x79: // ADC addr,Y

View File

@ -103,6 +103,9 @@ namespace BizHawk.Emulation.CPUs.M6502
public bool IRQ; public bool IRQ;
public bool NMI; public bool NMI;
public bool CLI_Pending;
public bool SEI_Pending;
public bool EscapeRequest;
public void SyncState(Serializer ser) public void SyncState(Serializer ser)
{ {

View File

@ -0,0 +1,32 @@
look for tests here: http://wiki.nesdev.com/w/index.php/Emulator_tests
blargg's MMC3:
FAIL for 4 and 6. i think 4 might not fail until some invisible PPU operations are correct. neither nintendulator or fceux pass these.
blargg's ppu tests:
PASS for all but power_up_palette.nes which is lame
blargg's ppu_vbl_nmi:
FAIL for 9. But hardly anyone passes this.....
blargg's sprite hit tests:
FAIL for 9 and 10. fceux passes 10 (oldppu) and nintendulator passes both.
boath are not going to work any time soon due to sprite pattern decoding being separate from BG pattern fetching instead of interleaved.
all_instrs.nes
FAIL (freezes emu??). I think this requires undocumented instructions.
cpu_interrupts.nes
PASS
instr_misc.nes
PASS
instr_timing.nes
PASS
nestest.nes
PASS
official_only.nes
PASS

View File

@ -15,6 +15,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
bool Configure(NES.EDetectionOrigin origin); bool Configure(NES.EDetectionOrigin origin);
byte ReadPRG(int addr); byte ReadPRG(int addr);
byte ReadPPU(int addr); byte PeekPPU(int addr); byte ReadPPU(int addr); byte PeekPPU(int addr);
void AddressPPU(int addr);
byte ReadWRAM(int addr); byte ReadWRAM(int addr);
byte ReadEXP(int addr); byte ReadEXP(int addr);
void WritePRG(int addr, byte value); void WritePRG(int addr, byte value);
@ -140,6 +141,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
} }
} }
public virtual void AddressPPU(int addr) { }
public virtual byte PeekPPU(int addr) { return ReadPPU(addr); } public virtual byte PeekPPU(int addr) { return ReadPPU(addr); }
public virtual byte ReadPPU(int addr) public virtual byte ReadPPU(int addr)

View File

@ -63,7 +63,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public override void WritePRG(int addr, byte value) public override void WritePRG(int addr, byte value)
{ {
if (ROM != null && bus_conflict) value = HandleNormalPRGConflict(addr,value); if (ROM != null && bus_conflict) value = HandleNormalPRGConflict(addr,value);
prg = (value*2) & prg_mask; int prg_bank = value & 7;
prg = (prg_bank * 2) & prg_mask;
if ((value & 0x10) == 0) if ((value & 0x10) == 0)
SetMirrorType(NES.NESBoardBase.EMirrorType.OneScreenA); SetMirrorType(NES.NESBoardBase.EMirrorType.OneScreenA);
else else

View File

@ -22,6 +22,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{ {
bank_regs[8] = (byte)(num_prg_banks - 1); bank_regs[8] = (byte)(num_prg_banks - 1);
bank_regs[9] = (byte)(num_prg_banks - 2); bank_regs[9] = (byte)(num_prg_banks - 2);
bank_regs[0] = 0;
bank_regs[1] = 1;
bank_regs[2] = 2;
bank_regs[3] = 3;
bank_regs[4] = 4;
bank_regs[5] = 5;
sync_2k_chr();
} }
public void Dispose() public void Dispose()
@ -34,10 +41,28 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public int chr_mode, prg_mode, reg_addr; public int chr_mode, prg_mode, reg_addr;
//this contains the 8 programmable regs and 2 more at the end to represent PRG banks -2 and -1; and 4 more at the end to break down chr regs 0 and 1 //this contains the 8 programmable regs and 2 more at the end to represent PRG banks -2 and -1; and 4 more at the end to break down chr regs 0 and 1
//in other words:
//0: chr reg 0 (not used directly)
//1: chr reg 1 (not used directly)
//2,3,4,5: chr reg 2,3,4,5
//6,7: prg reg 6,7
//8,9: prg reg -2,-1
//10: chr reg 0A
//11: chr reg 0B
//12: chr reg 1A
//13: chr reg 1B
ByteBuffer bank_regs = new ByteBuffer(14); ByteBuffer bank_regs = new ByteBuffer(14);
ByteBuffer prg_lookup = new ByteBuffer(new byte[] { 6, 7, 9, 8, 9, 7, 6, 8 }); ByteBuffer prg_lookup = new ByteBuffer(new byte[] { 6, 7, 9, 8, 9, 7, 6, 8 });
ByteBuffer chr_lookup = new ByteBuffer(new byte[] { 10, 11, 12, 13, 2, 3, 4, 5 }); ByteBuffer chr_lookup = new ByteBuffer(new byte[] { 10, 11, 12, 13, 2, 3, 4, 5 });
void sync_2k_chr()
{
bank_regs[10] = (byte)((bank_regs[0] & ~1) + 0);
bank_regs[11] = (byte)((bank_regs[0] & ~1) + 1);
bank_regs[12] = (byte)((bank_regs[1] & ~1) + 0);
bank_regs[13] = (byte)((bank_regs[1] & ~1) + 1);
}
public virtual void WritePRG(int addr, byte value) public virtual void WritePRG(int addr, byte value)
{ {
switch (addr & 0x6001) switch (addr & 0x6001)
@ -49,11 +74,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
break; break;
case 0x0001: //$8001 case 0x0001: //$8001
bank_regs[reg_addr] = value; bank_regs[reg_addr] = value;
//setup the 2K chr regs sync_2k_chr();
bank_regs[10] = (byte)((bank_regs[0] & ~1) + 0);
bank_regs[11] = (byte)((bank_regs[0] & ~1) + 1);
bank_regs[12] = (byte)((bank_regs[1] & ~1) + 0);
bank_regs[13] = (byte)((bank_regs[1] & ~1) + 1);
break; break;
} }
} }
@ -114,37 +135,49 @@ namespace BizHawk.Emulation.Consoles.Nintendo
case 0x2001: //$A001 case 0x2001: //$A001
//wram enable/protect //wram enable/protect
break; break;
case 0x4000: //$C000 case 0x4000: //$C000 - IRQ Reload value
irq_reload = value; irq_reload = value;
break; break;
case 0x4001: //$C001 case 0x4001: //$C001 - IRQ Clear
irq_counter = 0; irq_counter = 0;
break; break;
case 0x6000: //$E000 case 0x6000: //$E000 - IRQ Acknowledge / Disable
irq_enable = false; irq_enable = false;
irq_pending = false; irq_pending = false;
SyncIRQ(); SyncIRQ();
break; break;
case 0x6001: //$E001 case 0x6001: //$E001 - IRQ Enable
irq_enable = true; irq_enable = true;
SyncIRQ(); SyncIRQ();
break; break;
} }
} }
void IRQ_EQ_Pass()
{
if (irq_enable)
irq_pending = true;
SyncIRQ();
}
void ClockIRQ() void ClockIRQ()
{ {
if (irq_counter == 0) if (irq_counter == 0)
{
irq_counter = irq_reload; irq_counter = irq_reload;
//TODO - MMC3 variant behaviour??? not sure
//was needed to pass 2-details.nes
if (irq_counter == 0)
IRQ_EQ_Pass();
}
else else
{ {
irq_counter--; irq_counter--;
//Console.WriteLine(irq_counter); //Console.WriteLine(irq_counter);
if (irq_counter == 0) if (irq_counter == 0)
{ {
if (irq_enable) IRQ_EQ_Pass();
irq_pending = true;
SyncIRQ();
} }
} }
} }
@ -241,21 +274,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//state //state
protected MMC3 mmc3; protected MMC3 mmc3;
public override byte ReadPPU(int addr) public override void AddressPPU(int addr)
{ {
mmc3.Tick_PPU(addr); mmc3.Tick_PPU(addr);
return base.ReadPPU(addr);
}
public override void WritePPU(int addr, byte value)
{
mmc3.Tick_PPU(addr);
base.WritePPU(addr, value);
}
public override void WritePRG(int addr, byte value)
{
base.WritePRG(addr, value);
} }
protected override void BaseSetup() protected override void BaseSetup()

View File

@ -50,6 +50,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//analyze board type //analyze board type
switch (Cart.board_type) switch (Cart.board_type)
{ {
case "TXROM-HOMEBREW":
break;
case "NES-TBROM": //tecmo world cup soccer (DE) [untested] case "NES-TBROM": //tecmo world cup soccer (DE) [untested]
AssertPrg(64); AssertChr(64); AssertVram(0); AssertWram(0); AssertPrg(64); AssertChr(64); AssertVram(0); AssertWram(0);
AssertBattery(false); AssertBattery(false);

View File

@ -96,13 +96,22 @@ namespace BizHawk.Emulation.Consoles.Nintendo
else else
cycles <<= 4; cycles <<= 4;
//tricky logic to try to run one instruction at a time
cpu_accumulate += cycles; cpu_accumulate += cycles;
if (cpu_accumulate >= 48) int cpu_cycles = cpu_accumulate / 48;
for (; ; )
{ {
int todo = cpu_accumulate / 48; if (cpu_cycles == 0) break;
cpu_accumulate -= todo * 48; int need_cpu = -cpu.PendingCycles + 1;
if (cpu_cycles < need_cpu) break;
if (need_cpu == 0) need_cpu = 1;
int todo = need_cpu;
cpu_cycles -= todo;
cpu_accumulate -= 48*todo;
cpu.Execute(todo); cpu.Execute(todo);
apu.Run(todo); apu.Run(todo);
ppu.TickCpu();
} }
} }

View File

@ -18,12 +18,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//when the ppu issues a write it goes through here and into the game board //when the ppu issues a write it goes through here and into the game board
public void ppubus_write(int addr, byte value) public void ppubus_write(int addr, byte value)
{ {
nes.board.AddressPPU(addr);
nes.board.WritePPU(addr, value); nes.board.WritePPU(addr, value);
} }
//when the ppu issues a read it goes through here and into the game board //when the ppu issues a read it goes through here and into the game board
public byte ppubus_read(int addr) public byte ppubus_read(int addr)
{ {
nes.board.AddressPPU(addr);
//apply freeze //apply freeze
if (ppubus_freeze[addr].IsFrozen) if (ppubus_freeze[addr].IsFrozen)
return ppubus_freeze[addr].value; return ppubus_freeze[addr].value;
@ -89,17 +91,48 @@ namespace BizHawk.Emulation.Consoles.Nintendo
nes.cpu.NMI = true; nes.cpu.NMI = true;
} }
public void TickCpu()
{
if (NMI_PendingCycles > 0)
{
NMI_PendingCycles--;
if (NMI_PendingCycles == 0)
{
TriggerNMI();
}
}
}
void runppu(int x) void runppu(int x)
{ {
//pputime+=x; //pputime+=x;
//DON'T LIKE THIS.... //DON'T LIKE THIS....
ppur.status.cycle += x; ppur.status.cycle += x;
if (ppur.status.cycle > ppur.status.end_cycle) while(ppur.status.cycle >= ppur.status.end_cycle)
ppur.status.cycle -= ppur.status.end_cycle; ppur.status.cycle -= ppur.status.end_cycle;
if(x == 0) return;
nes.RunCpu(1);
x--;
if (Reg2002_vblank_active_pending)
{
if (Reg2002_vblank_active_pending)
Reg2002_vblank_active = 1;
Reg2002_vblank_active_pending = false;
}
if (Reg2002_vblank_clear_pending)
{
Reg2002_vblank_active = 0;
Reg2002_vblank_clear_pending = false;
}
if (x == 0) return;
nes.RunCpu(x); nes.RunCpu(x);
//pputime -= cputodo<<2;
} }
//hack //hack

View File

@ -294,6 +294,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
Bit Reg2002_objoverflow; //Sprite overflow. The PPU can handle only eight sprites on one scanline and sets this bit if it starts drawing sprites. Bit Reg2002_objoverflow; //Sprite overflow. The PPU can handle only eight sprites on one scanline and sets this bit if it starts drawing sprites.
Bit Reg2002_objhit; //Sprite 0 overlap. Set when a nonzero pixel of sprite 0 is drawn overlapping a nonzero background pixel. Used for raster timing. Bit Reg2002_objhit; //Sprite 0 overlap. Set when a nonzero pixel of sprite 0 is drawn overlapping a nonzero background pixel. Used for raster timing.
Bit Reg2002_vblank_active; //Vertical blank start (0: has not started; 1: has started) Bit Reg2002_vblank_active; //Vertical blank start (0: has not started; 1: has started)
bool Reg2002_vblank_active_pending; //set of Reg2002_vblank_active is pending
bool Reg2002_vblank_clear_pending; //ppu's clear of vblank flag is pending
int NMI_PendingCycles;
byte PPUGenLatch; byte PPUGenLatch;
public PPUREGS ppur; public PPUREGS ppur;
Reg_2000 reg_2000; Reg_2000 reg_2000;
@ -324,11 +327,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//PPU CONTROL (write) //PPU CONTROL (write)
void write_2000(byte value) void write_2000(byte value)
{ {
if (!reg_2000.vblank_nmi_gen & ((value & 0x80) != 0) && (Reg2002_vblank_active)) if (!reg_2000.vblank_nmi_gen & ((value & 0x80) != 0) && (Reg2002_vblank_active) && !Reg2002_vblank_clear_pending)
{ {
//if we just unleashed the vblank interrupt then activate it now //if we just unleashed the vblank interrupt then activate it now
//FCEUX would use a "trigger NMI2" here in order to result in some delay effect NMI_PendingCycles = 2;
TriggerNMI();
} }
reg_2000.Value = value; reg_2000.Value = value;
} }
@ -354,12 +356,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo
int ret = (Reg2002_vblank_active << 7) | (Reg2002_objhit << 6) | (Reg2002_objoverflow << 5) | (PPUGenLatch & 0x1F); int ret = (Reg2002_vblank_active << 7) | (Reg2002_objhit << 6) | (Reg2002_objoverflow << 5) | (PPUGenLatch & 0x1F);
Reg2002_vblank_active = 0; Reg2002_vblank_active = 0;
Reg2002_vblank_active_pending = false;
return (byte)ret; return (byte)ret;
} }
void clear_2002() void clear_2002()
{ {
Reg2002_vblank_active = Reg2002_objhit = Reg2002_objoverflow = 0; Reg2002_objhit = Reg2002_objoverflow = 0;
Reg2002_vblank_clear_pending = true;
} }
//OAM ADDRESS (write) //OAM ADDRESS (write)
@ -378,7 +382,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
OAM[reg_2003] = value; OAM[reg_2003] = value;
reg_2003++; reg_2003++;
} }
byte read_2004() { return 0xFF; /* TODO !!!!!! THIS IS UGLY. WE SHOULD PASTE IT IN OR REWRITE IT BUT WE NEED TO ASK QEED FOR TEST CASES*/ } byte read_2004() {
return OAM[reg_2003];
}
//SCROLL (write) //SCROLL (write)
void write_2005(byte value) void write_2005(byte value)
@ -414,6 +420,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ppur._vt |= (value >> 5); ppur._vt |= (value >> 5);
ppur._ht = value & 31; ppur._ht = value & 31;
ppur.install_latches(); ppur.install_latches();
nes.board.AddressPPU(ppur.get_2007access());
} }
vtoggle ^= true; vtoggle ^= true;
} }
@ -443,6 +451,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
} }
ppur.increment2007(reg_2000.vram_incr32 != 0); ppur.increment2007(reg_2000.vram_incr32 != 0);
int newaddr = ppur.get_2007access() & 0x3FFF;
nes.board.AddressPPU(newaddr);
} }
byte read_2007() byte read_2007()
{ {
@ -463,6 +473,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ppur.increment2007(reg_2000.vram_incr32 != 0); ppur.increment2007(reg_2000.vram_incr32 != 0);
int newaddr = ppur.get_2007access() & 0x3FFF;
nes.board.AddressPPU(newaddr);
return ret; return ret;
} }
//-------- //--------

View File

@ -1,5 +1,7 @@
//http://nesdev.parodius.com/bbs/viewtopic.php?p=4571&sid=db4c7e35316cc5d734606dd02f11dccb //http://nesdev.parodius.com/bbs/viewtopic.php?p=4571&sid=db4c7e35316cc5d734606dd02f11dccb
//todo - read http://wiki.nesdev.com/w/index.php/PPU_sprite_priority
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
@ -85,17 +87,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo
return; return;
} }
Reg2002_vblank_active = 1; Reg2002_vblank_active_pending = true;
ppuphase = PPUPHASE.VBL; ppuphase = PPUPHASE.VBL;
//Not sure if this is correct. According to Matt Conte and my own tests, it is. //Not sure if this is correct. According to Matt Conte and my own tests, it is. Timing is probably off, though.
//Timing is probably off, though.
//NOTE: Not having this here breaks a Super Donkey Kong game. //NOTE: Not having this here breaks a Super Donkey Kong game.
reg_2003 = 0; reg_2003 = 0;
const int delay = 20; //fceu used 12 here but I couldnt get it to work in marble madness and pirates.
runppu(delay); //X6502_Run(12); //fceu/fceux had 12 here, but 15 was required to pass blargg's 05-nmi_timing.nes
if (reg_2000.vblank_nmi_gen) TriggerNMI(); const int delay = 15;
runppu(3);
bool nmi_destiny = reg_2000.vblank_nmi_gen && Reg2002_vblank_active;
runppu(delay - 3);
if (nmi_destiny) TriggerNMI();
if (PAL) if (PAL)
runppu(70 * (kLineTime) - delay); runppu(70 * (kLineTime) - delay);
else else
@ -103,17 +107,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//this seems to run just before the dummy scanline begins //this seems to run just before the dummy scanline begins
clear_2002(); clear_2002();
//this early out caused metroid to fail to boot. I am leaving it here as a reminder of what not to do
//if(!PPUON) { runppu(kLineTime*242); goto finish; }
//There are 2 conditions that update all 5 PPU scroll counters with the
//contents of the latches adjacent to them. The first is after a write to
//2006/2. The second, is at the beginning of scanline 20, when the PPU starts
//rendering data for the first time in a frame (this update won't happen if
//all rendering is disabled via 2001.3 and 2001.4).
//if(PPUON)
// ppur.install_latches();
TempOAM* oams = stackalloc TempOAM[128]; TempOAM* oams = stackalloc TempOAM[128];
int* oamcounts = stackalloc int[2]; int* oamcounts = stackalloc int[2];
@ -142,6 +135,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//two of those tiles were read in the last scanline. //two of those tiles were read in the last scanline.
for (int xt = 0; xt < 32; xt++) for (int xt = 0; xt < 32; xt++)
{ {
if (sl == 31 && xt == 31)
{
int zzz = 9;
}
Read_bgdata(ref bgdata[xt + 2]); Read_bgdata(ref bgdata[xt + 2]);
//ok, we're also going to draw here. //ok, we're also going to draw here.
@ -205,11 +202,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//transparent pixel bailout //transparent pixel bailout
if (spixel == 0) continue; if (spixel == 0) continue;
//TODO - make sure we dont trigger spritehit if the edges are masked for either BG or OBJ
//spritehit: //spritehit:
//1. is it sprite#0? //1. is it sprite#0?
//2. is the bg pixel nonzero? //2. is the bg pixel nonzero?
//then, it is spritehit. //then, it is spritehit.
if (oam->index == 0 && (pixel & 3) != 0 && rasterpos < 255) if (oam->index == 0)
{
int zzz = 9;
}
if (oam->index == 0 && pixel != 0 && rasterpos < 255)
{ {
Reg2002_objhit = true; Reg2002_objhit = true;
} }
@ -397,20 +399,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ppuphase = PPUPHASE.BG; ppuphase = PPUPHASE.BG;
//fetch BG: two tiles for next line
for (int xt = 0; xt < 2; xt++)
Read_bgdata(ref bgdata[xt]);
//I'm unclear of the reason why this particular access to memory is made. //I'm unclear of the reason why this particular access to memory is made.
//The nametable address that is accessed 2 times in a row here, is also the //The nametable address that is accessed 2 times in a row here, is also the
//same nametable address that points to the 3rd tile to be rendered on the //same nametable address that points to the 3rd tile to be rendered on the
//screen (or basically, the first nametable address that will be accessed when //screen (or basically, the first nametable address that will be accessed when
//the PPU is fetching background data on the next scanline). //the PPU is fetching background data on the next scanline).
//(not implemented yet) //(not implemented yet)
runppu(kFetchTime*2); runppu(kFetchTime * 2);
if (sl == 0) if (sl == 0)
{ {
if (idleSynch && reg_2001.PPUON && !PAL) if (idleSynch && reg_2001.show_bg && !PAL)
ppur.status.end_cycle = 340; ppur.status.end_cycle = 340;
else else
ppur.status.end_cycle = 341; ppur.status.end_cycle = 341;
@ -418,7 +416,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
} }
else else
ppur.status.end_cycle = 341; ppur.status.end_cycle = 341;
//runppu(kFetchTime);
//fetch BG: two tiles for next line
for (int xt = 0; xt < 2; xt++)
Read_bgdata(ref bgdata[xt]);
//After memory access 170, the PPU simply rests for 4 cycles (or the //After memory access 170, the PPU simply rests for 4 cycles (or the
//equivelant of half a memory access cycle) before repeating the whole //equivelant of half a memory access cycle) before repeating the whole

View File

@ -55,12 +55,16 @@ static string ClassifyTable = @"
1 32 32 8 0 NES-SEROM; lolo 1 32 32 8 0 NES-SEROM; lolo
1 128 0 8 0 NES-SNROM; zelda 1 128 0 8 0 NES-SNROM; zelda
1 128 128 8 0 NES-SKROM; zelda 2 1 128 128 8 0 NES-SKROM; zelda 2
1 128 0 8 8 NES-SNROM; some of blargg's tests (apu) 1 32 0 8 8 NROM-HOMEBREW; instr_timing.nes
1 256 0 8 8 NES-SNROM; some of blargg's test (cpu tests) 1 64 0 8 8 NROM-HOMEBREW; instr_misc.nes
1 80 0 8 8 NROM-HOMEBREW; blargg's cpu_interrupts.nes
1 128 0 8 8 NES-SNROM; some of blargg's tests (apu) [TODO recheck as NROM-HOMEBREW]
1 256 0 8 8 NES-SNROM; some of blargg's test (cpu tests) [TODO recheck as NROM-HOMEBREW]
2 128 0 8 0 NES-UNROM; mega man 2 128 0 8 0 NES-UNROM; mega man
2 256 0 8 0 NES-UOROM; paperboy 2 2 256 0 8 0 NES-UOROM; paperboy 2
3 32 32 8 0 NES-CNROM; adventure island 3 32 32 8 0 NES-CNROM; adventure island
4 128 128 8 0 NES-TSROM; double dragon 2 (should be TL1ROM but maybe this will work) 4 128 128 8 0 NES-TSROM; double dragon 2 (should be TL1ROM but maybe this will work)
4 32 8 8 0 TXROM-HOMEBREW; blargg's mmc3 tests
7 128 0 8 0 NES-ANROM; marble madness 7 128 0 8 0 NES-ANROM; marble madness
7 256 0 8 8 NES-AOROM; battletoads 7 256 0 8 8 NES-AOROM; battletoads
11 32 16 8 0 Discrete_74x377 11 32 16 8 0 Discrete_74x377

View File

@ -362,7 +362,6 @@ namespace M6502
w.WriteLine(" PendingCycles += cycles;"); w.WriteLine(" PendingCycles += cycles;");
w.WriteLine(" while (PendingCycles > 0)"); w.WriteLine(" while (PendingCycles > 0)");
w.WriteLine(" {"); w.WriteLine(" {");
w.WriteLine(" if (NMI)"); w.WriteLine(" if (NMI)");
w.WriteLine(" {"); w.WriteLine(" {");
w.WriteLine(" TriggerException(ExceptionType.NMI);"); w.WriteLine(" TriggerException(ExceptionType.NMI);");
@ -370,9 +369,20 @@ namespace M6502
w.WriteLine(" }"); w.WriteLine(" }");
w.WriteLine(" if (IRQ && !FlagI)"); w.WriteLine(" if (IRQ && !FlagI)");
w.WriteLine(" {"); w.WriteLine(" {");
w.WriteLine(" if (SEI_Pending)");
w.WriteLine(" FlagI = true;");
w.WriteLine(" TriggerException(ExceptionType.IRQ);"); w.WriteLine(" TriggerException(ExceptionType.IRQ);");
w.WriteLine(" }"); w.WriteLine(" }");
w.WriteLine(""); w.WriteLine(" if (CLI_Pending)");
w.WriteLine(" {");
w.WriteLine(" FlagI = false;");
w.WriteLine(" CLI_Pending = false;");
w.WriteLine(" }");
w.WriteLine(" if (SEI_Pending)");
w.WriteLine(" {");
w.WriteLine(" FlagI = true;");
w.WriteLine(" SEI_Pending = false;");
w.WriteLine(" }");
w.WriteLine(" if(debug) Console.WriteLine(State());"); w.WriteLine(" if(debug) Console.WriteLine(State());");
w.WriteLine(""); w.WriteLine("");

View File

@ -82,7 +82,8 @@ namespace M6502
private void CLI(OpcodeInfo op, TextWriter w) private void CLI(OpcodeInfo op, TextWriter w)
{ {
w.WriteLine(Spaces + "FlagI = false;"); w.WriteLine(Spaces + "//FlagI = false;");
w.WriteLine(Spaces + "CLI_Pending = true;");
w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles);
} }
@ -244,7 +245,15 @@ namespace M6502
private void PLP(OpcodeInfo op, TextWriter w) private void PLP(OpcodeInfo op, TextWriter w)
{ {
w.WriteLine(Spaces + "P = ReadMemory((ushort)(++S + 0x100));"); w.WriteLine(Spaces + "//handle I flag differently. sort of a sloppy way to do the job, but it does finish it off.");
w.WriteLine(Spaces + "value8 = ReadMemory((ushort)(++S + 0x100));");
w.WriteLine(Spaces + "if ((value8 & 0x04) != 0 && !FlagI)");
w.WriteLine(Spaces + "\tSEI_Pending = true;");
w.WriteLine(Spaces + "if ((value8 & 0x04) == 0 && FlagI)");
w.WriteLine(Spaces + "\tCLI_Pending = true;");
w.WriteLine(Spaces + "value8 &= unchecked((byte)~0x04);");
w.WriteLine(Spaces + "P &= 0x04;");
w.WriteLine(Spaces + "P |= value8;");
w.WriteLine("FlagT = true;//this seems wrong");//this seems wrong w.WriteLine("FlagT = true;//this seems wrong");//this seems wrong
w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles);
} }
@ -333,7 +342,8 @@ w.WriteLine("FlagT = true;// this seems wrong");//this seems wrong
private void SEI(OpcodeInfo op, TextWriter w) private void SEI(OpcodeInfo op, TextWriter w)
{ {
w.WriteLine(Spaces + "FlagI = true;"); w.WriteLine(Spaces + "//FlagI = true;");
w.WriteLine(Spaces + "SEI_Pending = true;");
w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles); w.WriteLine(Spaces + "PendingCycles -= {0}; TotalExecutedCycles += {0};", op.Cycles);
} }