From 8dd98852be48929d4cc02257ca1403a54802d360 Mon Sep 17 00:00:00 2001 From: alyosha-tas Date: Tue, 28 Dec 2021 21:09:13 -0500 Subject: [PATCH] NESHawk: Fix interaction between RDY and Branch_delay_irq bug. Fix regression in APU timing. --- .../CPUs/MOS 6502X/Execute.cs | 67 ++++++++++++------- .../Consoles/Nintendo/NES/APU.cs | 6 +- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/Execute.cs b/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/Execute.cs index 95f4aa9dc8..54cb4a4b8f 100644 --- a/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/Execute.cs +++ b/src/BizHawk.Emulation.Cores/CPUs/MOS 6502X/Execute.cs @@ -306,9 +306,9 @@ namespace BizHawk.Emulation.Cores.Components.M6502 /*ISC* addr,X [absolute indexed RMW X] [unofficial]*/ new Uop[] { Uop.Fetch2, Uop.AbsIdx_Stage3_X, Uop.AbsIdx_Stage4, Uop.AbsIdx_RMW_Stage5, Uop.AbsIdx_RMW_Stage6_ISC, Uop.AbsIdx_RMW_Stage7, Uop.End }, //0x100 /*VOP_Fetch1*/ new Uop[] { Uop.Fetch1 }, - /*VOP_RelativeStuff*/ new Uop[] { Uop.RelBranch_Stage3, Uop.End_BranchSpecial }, + /*VOP_RelativeStuff*/ new Uop[] { Uop.RelBranch_Stage3 }, /*VOP_RelativeStuff2*/ new Uop[] { Uop.RelBranch_Stage4, Uop.End }, - /*VOP_RelativeStuff2*/ new Uop[] { Uop.End_SuppressInterrupt }, + /*VOP_RelativeStuff3*/ new Uop[] { Uop.End_SuppressInterrupt }, //i assume these are dummy fetches.... maybe theyre just nops? supposedly these take 7 cycles so that's the only way i can make sense of it //one of them might be the next instruction's fetch, and whatever fetch follows it. //the interrupt would then take place if necessary, using a cached PC. but im not so sure about that. @@ -316,6 +316,8 @@ namespace BizHawk.Emulation.Cores.Components.M6502 /*VOP_IRQ*/ new Uop[] { Uop.FetchDummy, Uop.FetchDummy, Uop.PushPCH, Uop.PushPCL, Uop.PushP_IRQ, Uop.FetchPCLVector, Uop.FetchPCHVector, Uop.End_SuppressInterrupt }, /*VOP_RESET*/ new Uop[] { Uop.FetchDummy, /*Uop.FetchDummy,*/ Uop.FetchDummy, Uop.PushDummy, Uop.PushDummy, Uop.PushP_Reset, Uop.FetchPCLVector, Uop.FetchPCHVector, Uop.End_SuppressInterrupt }, /*VOP_Fetch1_NoInterrupt*/ new Uop[] { Uop.Fetch1_Real }, + /*VOP_Relative_Aux1*/ new Uop[] { Uop.RelBranch_Aux1 }, + /*VOP_Relative_Aux2*/ new Uop[] { Uop.FetchDummy, Uop.End } }; /* @@ -465,10 +467,11 @@ namespace BizHawk.Emulation.Cores.Components.M6502 End, End_ISpecial, //same as end, but preserves the iflag set by the instruction - End_BranchSpecial, End_SuppressInterrupt, Jam, + + RelBranch_Aux1, RelBranch_Aux2 } private void InitOpcodeHandlers() @@ -496,7 +499,7 @@ namespace BizHawk.Emulation.Cores.Components.M6502 // AbsInd_JMP_Stage4, AbsInd_JMP_Stage5,IndIdx_Stage3, IndIdx_Stage4, IndIdx_READ_Stage5, IndIdx_WRITE_Stage5, // IndIdx_WRITE_Stage6_STA, IndIdx_WRITE_Stage6_SHA,IndIdx_READ_Stage6_LDA, IndIdx_READ_Stage6_CMP, IndIdx_READ_Stage6_ORA, IndIdx_READ_Stage6_SBC, IndIdx_READ_Stage6_ADC, IndIdx_READ_Stage6_AND, IndIdx_READ_Stage6_EOR, // IndIdx_READ_Stage6_LAX,IndIdx_RMW_Stage5,IndIdx_RMW_Stage6, IndIdx_RMW_Stage7_SLO, IndIdx_RMW_Stage7_RLA, IndIdx_RMW_Stage7_SRE, IndIdx_RMW_Stage7_RRA, IndIdx_RMW_Stage7_ISC, IndIdx_RMW_Stage7_DCP,IndIdx_RMW_Stage8, - // End,End_ISpecial,End_BranchSpecial,End_SuppressInterrupt, + // End,End_ISpecial,End_SuppressInterrupt, //}; } @@ -508,7 +511,9 @@ namespace BizHawk.Emulation.Cores.Components.M6502 private const int VOP_IRQ = 261; private const int VOP_RESET = 262; private const int VOP_Fetch1_NoInterrupt = 263; - private const int VOP_NUM = 264; + private const int VOP_Relative_Aux1 = 264; + private const int VOP_Relative_Aux2 = 265; + private const int VOP_NUM = 266; //opcode bytes.. theoretically redundant with the temp variables? who knows. public int opcode; @@ -524,7 +529,7 @@ namespace BizHawk.Emulation.Cores.Components.M6502 private bool interrupt_pending; private bool branch_irq_hack; //see Uop.RelBranch_Stage3 for more details - private bool Interrupted => RDY && (NMI || (IRQ && !FlagI)); + private bool Interrupted => NMI || (IRQ && !FlagI); private void FetchDummy() { @@ -1205,27 +1210,43 @@ namespace BizHawk.Emulation.Cores.Components.M6502 } private void RelBranch_Stage3() + { + alu_temp = (byte)PC + (int)(sbyte)opcode2; + PC &= 0xFF00; + PC |= (ushort)((alu_temp & 0xFF)); + + if (alu_temp.Bit(8)) + { + opcode = VOP_Relative_Aux1; + mi = 0; + + RelBranch_Aux1(); + } + else + { + //to pass cpu_interrupts_v2/5-branch_delays_irq we need to handle a quirk here + //if we decide to interrupt in the next cycle, this condition will cause it to get deferred by one instruction + if (!interrupt_pending) + branch_irq_hack = true; + + opcode = VOP_Relative_Aux2; + mi = 0; + + FetchDummy(); + + //if (!RDY) { Console.WriteLine("not rdy " + TotalExecutedCycles);} + } + } + + private void RelBranch_Aux1() { rdy_freeze = !RDY; if (RDY) { _link.DummyReadMemory(PC); - alu_temp = (byte)PC + (int)(sbyte)opcode2; - PC &= 0xFF00; - PC |= (ushort)((alu_temp & 0xFF)); - if (alu_temp.Bit(8)) - { - //we need to carry the add, and then we'll be ready to fetch the next instruction - opcode = VOP_RelativeStuff2; - mi = -1; - } - else - { - //to pass cpu_interrupts_v2/5-branch_delays_irq we need to handle a quirk here - //if we decide to interrupt in the next cycle, this condition will cause it to get deferred by one instruction - if (!interrupt_pending) - branch_irq_hack = true; - } + + opcode = VOP_RelativeStuff2; + mi = -1; } } @@ -3121,8 +3142,8 @@ namespace BizHawk.Emulation.Cores.Components.M6502 case Uop.End_ISpecial: End_ISpecial(); break; case Uop.End_SuppressInterrupt: End_SuppressInterrupt(); break; case Uop.End: End(); break; - case Uop.End_BranchSpecial: End_BranchSpecial(); break; case Uop.Jam: Jam(); break; + case Uop.RelBranch_Aux1: RelBranch_Aux1(); break; } } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs index 746266aa57..3f719d7284 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs @@ -1195,8 +1195,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public void NESHardReset() { // "at power on it is as if $00 was written to $4017 9-12 cycles before the reset vector" - // that translates to a starting value for the counter of -3 - sequencer_counter = -1; + // DMC seems to run for a couple cycles after reset, so aim for the upper end of that range (12) + sequencer_counter = 2; sequencer_check_1 = (sequencer_lut[0][1] - 1); @@ -1339,7 +1339,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES // the current code simply matches known behaviour if (pending_reg != -1) { - if ( pending_reg == 0x4003 || pending_reg == 0x4007 || pending_reg == 0x4015 || pending_reg == 0x4017) + if ( pending_reg == 0x4003 || pending_reg == 0x4007 || pending_reg == 0x4010 || pending_reg == 0x4015 || pending_reg == 0x4017) { _WriteReg(pending_reg, pending_val); pending_reg = -1;