diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index bc2ee55db0..0581efb55b 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -224,6 +224,7 @@ + diff --git a/BizHawk.Emulation/CPUs/MOS 6502/Execute.cs b/BizHawk.Emulation/CPUs/MOS 6502/Execute.cs index 9c95daa3ff..674bb028fc 100644 --- a/BizHawk.Emulation/CPUs/MOS 6502/Execute.cs +++ b/BizHawk.Emulation/CPUs/MOS 6502/Execute.cs @@ -17,16 +17,27 @@ namespace BizHawk.Emulation.CPUs.M6502 PendingCycles += cycles; while (PendingCycles > 0) { - if (NMI) - { - TriggerException(ExceptionType.NMI); - NMI = false; - } - if (IRQ && !FlagI) - { - TriggerException(ExceptionType.IRQ); - } - + if (NMI) + { + TriggerException(ExceptionType.NMI); + NMI = false; + } + if (IRQ && !FlagI) + { + if (SEI_Pending) + FlagI = true; + TriggerException(ExceptionType.IRQ); + } + if (CLI_Pending) + { + FlagI = false; + CLI_Pending = false; + } + if (SEI_Pending) + { + FlagI = true; + SEI_Pending = false; + } if(debug) Console.WriteLine(State()); ushort this_pc = PC; @@ -209,7 +220,15 @@ TriggerException(ExceptionType.BRK); PendingCycles -= 5; TotalExecutedCycles += 5; break; 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 PendingCycles -= 4; TotalExecutedCycles += 4; break; @@ -431,7 +450,8 @@ FlagT = true;// this seems wrong PendingCycles -= 6; TotalExecutedCycles += 6; break; case 0x58: // CLI - FlagI = false; + //FlagI = false; + CLI_Pending = true; PendingCycles -= 2; TotalExecutedCycles += 2; break; case 0x59: // EOR addr,Y @@ -594,7 +614,8 @@ FlagT = true;// this seems wrong PendingCycles -= 6; TotalExecutedCycles += 6; break; case 0x78: // SEI - FlagI = true; + //FlagI = true; + SEI_Pending = true; PendingCycles -= 2; TotalExecutedCycles += 2; break; case 0x79: // ADC addr,Y diff --git a/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs b/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs index 635209db00..2bd0e9a016 100644 --- a/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs +++ b/BizHawk.Emulation/CPUs/MOS 6502/MOS6502.cs @@ -103,6 +103,9 @@ namespace BizHawk.Emulation.CPUs.M6502 public bool IRQ; public bool NMI; + public bool CLI_Pending; + public bool SEI_Pending; + public bool EscapeRequest; public void SyncState(Serializer ser) { diff --git a/BizHawk.Emulation/Consoles/Nintendo/Docs/test_status.txt b/BizHawk.Emulation/Consoles/Nintendo/Docs/test_status.txt new file mode 100644 index 0000000000..e7651b4146 --- /dev/null +++ b/BizHawk.Emulation/Consoles/Nintendo/Docs/test_status.txt @@ -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 \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs index 22a47268ad..e8ed2a9fce 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs @@ -15,6 +15,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo bool Configure(NES.EDetectionOrigin origin); byte ReadPRG(int addr); byte ReadPPU(int addr); byte PeekPPU(int addr); + void AddressPPU(int addr); byte ReadWRAM(int addr); byte ReadEXP(int addr); 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 ReadPPU(int addr) diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/AxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/AxROM.cs index f98ce9efe3..12e2653c98 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/AxROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/AxROM.cs @@ -63,7 +63,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo public override void WritePRG(int addr, byte 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) SetMirrorType(NES.NESBoardBase.EMirrorType.OneScreenA); else diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3_family.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3_family.cs index 76aaaec427..dc1eedf90c 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3_family.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3_family.cs @@ -22,6 +22,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo { bank_regs[8] = (byte)(num_prg_banks - 1); 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() @@ -34,10 +41,28 @@ namespace BizHawk.Emulation.Consoles.Nintendo 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 + //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 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 }); + 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) { switch (addr & 0x6001) @@ -49,11 +74,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo break; case 0x0001: //$8001 bank_regs[reg_addr] = value; - //setup the 2K chr regs - 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); + sync_2k_chr(); break; } } @@ -114,37 +135,49 @@ namespace BizHawk.Emulation.Consoles.Nintendo case 0x2001: //$A001 //wram enable/protect break; - case 0x4000: //$C000 + case 0x4000: //$C000 - IRQ Reload value irq_reload = value; break; - case 0x4001: //$C001 + case 0x4001: //$C001 - IRQ Clear irq_counter = 0; break; - case 0x6000: //$E000 + case 0x6000: //$E000 - IRQ Acknowledge / Disable irq_enable = false; irq_pending = false; SyncIRQ(); break; - case 0x6001: //$E001 + case 0x6001: //$E001 - IRQ Enable irq_enable = true; SyncIRQ(); break; } } + void IRQ_EQ_Pass() + { + if (irq_enable) + irq_pending = true; + SyncIRQ(); + } + void ClockIRQ() { if (irq_counter == 0) + { 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 { irq_counter--; //Console.WriteLine(irq_counter); if (irq_counter == 0) { - if (irq_enable) - irq_pending = true; - SyncIRQ(); + IRQ_EQ_Pass(); } } } @@ -240,24 +273,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo //state protected MMC3 mmc3; + + public override void AddressPPU(int addr) + { + mmc3.Tick_PPU(addr); + } - public override byte ReadPPU(int 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() { wram_mask = (Cart.wram_size * 1024) - 1; diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/TxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/TxROM.cs index be3ada4fd6..cb907ade04 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/TxROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/TxROM.cs @@ -50,6 +50,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo //analyze board type switch (Cart.board_type) { + case "TXROM-HOMEBREW": + break; case "NES-TBROM": //tecmo world cup soccer (DE) [untested] AssertPrg(64); AssertChr(64); AssertVram(0); AssertWram(0); AssertBattery(false); diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Core.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Core.cs index 4e021461bb..5b2eb01a6f 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Core.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Core.cs @@ -96,13 +96,22 @@ namespace BizHawk.Emulation.Consoles.Nintendo else cycles <<= 4; + + //tricky logic to try to run one instruction at a time cpu_accumulate += cycles; - if (cpu_accumulate >= 48) + int cpu_cycles = cpu_accumulate / 48; + for (; ; ) { - int todo = cpu_accumulate / 48; - cpu_accumulate -= todo * 48; + if (cpu_cycles == 0) break; + 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); apu.Run(todo); + ppu.TickCpu(); } } diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs index cc6182466b..5b3dfb41fd 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs @@ -18,12 +18,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo //when the ppu issues a write it goes through here and into the game board public void ppubus_write(int addr, byte value) { + nes.board.AddressPPU(addr); nes.board.WritePPU(addr, value); } //when the ppu issues a read it goes through here and into the game board public byte ppubus_read(int addr) { + nes.board.AddressPPU(addr); //apply freeze if (ppubus_freeze[addr].IsFrozen) return ppubus_freeze[addr].value; @@ -89,17 +91,48 @@ namespace BizHawk.Emulation.Consoles.Nintendo nes.cpu.NMI = true; } + public void TickCpu() + { + if (NMI_PendingCycles > 0) + { + NMI_PendingCycles--; + if (NMI_PendingCycles == 0) + { + TriggerNMI(); + } + } + } + void runppu(int x) { //pputime+=x; //DON'T LIKE THIS.... 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; + + 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); - //pputime -= cputodo<<2; } //hack diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs index 9b7d6c5935..edf11799cd 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs @@ -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_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) + 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; public PPUREGS ppur; Reg_2000 reg_2000; @@ -324,11 +327,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo //PPU CONTROL (write) 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 - //FCEUX would use a "trigger NMI2" here in order to result in some delay effect - TriggerNMI(); + NMI_PendingCycles = 2; } 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); Reg2002_vblank_active = 0; + Reg2002_vblank_active_pending = false; return (byte)ret; } void clear_2002() { - Reg2002_vblank_active = Reg2002_objhit = Reg2002_objoverflow = 0; + Reg2002_objhit = Reg2002_objoverflow = 0; + Reg2002_vblank_clear_pending = true; } //OAM ADDRESS (write) @@ -378,7 +382,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo OAM[reg_2003] = value; 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) void write_2005(byte value) @@ -414,6 +420,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo ppur._vt |= (value >> 5); ppur._ht = value & 31; ppur.install_latches(); + + nes.board.AddressPPU(ppur.get_2007access()); } vtoggle ^= true; } @@ -443,6 +451,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo } ppur.increment2007(reg_2000.vram_incr32 != 0); + int newaddr = ppur.get_2007access() & 0x3FFF; + nes.board.AddressPPU(newaddr); } byte read_2007() { @@ -462,6 +472,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo } ppur.increment2007(reg_2000.vram_incr32 != 0); + + int newaddr = ppur.get_2007access() & 0x3FFF; + nes.board.AddressPPU(newaddr); return ret; } diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs index d362b5bab3..f11629dc7e 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs @@ -1,5 +1,7 @@ //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.Diagnostics; using System.Globalization; @@ -85,17 +87,19 @@ namespace BizHawk.Emulation.Consoles.Nintendo return; } - Reg2002_vblank_active = 1; + Reg2002_vblank_active_pending = true; ppuphase = PPUPHASE.VBL; - //Not sure if this is correct. According to Matt Conte and my own tests, it is. - //Timing is probably off, though. + //Not sure if this is correct. According to Matt Conte and my own tests, it is. Timing is probably off, though. //NOTE: Not having this here breaks a Super Donkey Kong game. 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); - if (reg_2000.vblank_nmi_gen) TriggerNMI(); + //fceu/fceux had 12 here, but 15 was required to pass blargg's 05-nmi_timing.nes + 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) runppu(70 * (kLineTime) - delay); else @@ -103,17 +107,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo //this seems to run just before the dummy scanline begins 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]; int* oamcounts = stackalloc int[2]; @@ -142,6 +135,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo //two of those tiles were read in the last scanline. for (int xt = 0; xt < 32; xt++) { + if (sl == 31 && xt == 31) + { + int zzz = 9; + } Read_bgdata(ref bgdata[xt + 2]); //ok, we're also going to draw here. @@ -205,11 +202,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo //transparent pixel bailout if (spixel == 0) continue; + //TODO - make sure we dont trigger spritehit if the edges are masked for either BG or OBJ //spritehit: //1. is it sprite#0? //2. is the bg pixel nonzero? //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; } @@ -397,20 +399,16 @@ namespace BizHawk.Emulation.Consoles.Nintendo 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. //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 //screen (or basically, the first nametable address that will be accessed when //the PPU is fetching background data on the next scanline). //(not implemented yet) - runppu(kFetchTime*2); + runppu(kFetchTime * 2); if (sl == 0) { - if (idleSynch && reg_2001.PPUON && !PAL) + if (idleSynch && reg_2001.show_bg && !PAL) ppur.status.end_cycle = 340; else ppur.status.end_cycle = 341; @@ -418,7 +416,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo } else 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 //equivelant of half a memory access cycle) before repeating the whole diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs index fd6c3e5b10..22852a6dea 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs @@ -55,12 +55,16 @@ static string ClassifyTable = @" 1 32 32 8 0 NES-SEROM; lolo 1 128 0 8 0 NES-SNROM; zelda 1 128 128 8 0 NES-SKROM; zelda 2 -1 128 0 8 8 NES-SNROM; some of blargg's tests (apu) -1 256 0 8 8 NES-SNROM; some of blargg's test (cpu tests) +1 32 0 8 8 NROM-HOMEBREW; instr_timing.nes +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 256 0 8 0 NES-UOROM; paperboy 2 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 32 8 8 0 TXROM-HOMEBREW; blargg's mmc3 tests 7 128 0 8 0 NES-ANROM; marble madness 7 256 0 8 8 NES-AOROM; battletoads 11 32 16 8 0 Discrete_74x377 diff --git a/CpuCoreGenerator/MOS 6502/CoreGenerator.cs b/CpuCoreGenerator/MOS 6502/CoreGenerator.cs index 10e8d73c6a..5363dca6bd 100644 --- a/CpuCoreGenerator/MOS 6502/CoreGenerator.cs +++ b/CpuCoreGenerator/MOS 6502/CoreGenerator.cs @@ -362,17 +362,27 @@ namespace M6502 w.WriteLine(" PendingCycles += cycles;"); w.WriteLine(" while (PendingCycles > 0)"); w.WriteLine(" {"); - - w.WriteLine(" if (NMI)"); - w.WriteLine(" {"); - w.WriteLine(" TriggerException(ExceptionType.NMI);"); - w.WriteLine(" NMI = false;"); - w.WriteLine(" }"); - w.WriteLine(" if (IRQ && !FlagI)"); - w.WriteLine(" {"); - w.WriteLine(" TriggerException(ExceptionType.IRQ);"); - w.WriteLine(" }"); - w.WriteLine(""); + w.WriteLine(" if (NMI)"); + w.WriteLine(" {"); + w.WriteLine(" TriggerException(ExceptionType.NMI);"); + w.WriteLine(" NMI = false;"); + w.WriteLine(" }"); + w.WriteLine(" if (IRQ && !FlagI)"); + w.WriteLine(" {"); + w.WriteLine(" if (SEI_Pending)"); + w.WriteLine(" FlagI = true;"); + w.WriteLine(" TriggerException(ExceptionType.IRQ);"); + 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(""); diff --git a/CpuCoreGenerator/MOS 6502/Instructions.cs b/CpuCoreGenerator/MOS 6502/Instructions.cs index 07394ae457..d9b9766bb6 100644 --- a/CpuCoreGenerator/MOS 6502/Instructions.cs +++ b/CpuCoreGenerator/MOS 6502/Instructions.cs @@ -82,7 +82,8 @@ namespace M6502 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); } @@ -244,7 +245,15 @@ namespace M6502 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(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) { - 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); }