public void InterruptServiceRoutine() { byte bIF = Memory.DirectRead(IF); byte bIE = Memory.DirectRead(IE); int f = IRQLookup[bIF & bIE & 0x1F]; //-1 means no interrupt if (IME) { if (f != -1) { //2 Internal delays Board.AdvanceSystemTime(); //4 Board.AdvanceSystemTime(); //8 //PUSH PC Board.AdvanceSystemTime(); //12 Memory.Write((byte)(Registers.PC >> 8), --Registers.SP); Board.AdvanceSystemTime(); //16 Memory.Write((byte)Registers.PC, --Registers.SP); //SERVE bIF = ServeIRQ(f, bIF); Board.AdvanceSystemTime(); //20 Memory.DirectWrite(bIF, IF); if (GetCPU().Halt) { Board.AdvanceSystemTime(); //24 GetCPU().Halt = false; } SetIME(false); } } else { if (f != -1) { if (GetCPU().Halt) { Board.AdvanceSystemTime(); //4 GetCPU().Halt = false; GetCPU().DoubleInstructionExecutionBug = DoubleInstructionEnable; DoubleInstructionEnable = true; } } else { DoubleInstructionEnable = false; } } if (Schedule) { IME = true; Schedule = false; } }
public override void Update(int Clocks) { if (TransferSignal) { Clock -= Clocks; if (Clock <= 0) { SC &= 0x7F; SB = 0xFF; Memory.DirectWrite((byte)(Memory.DirectRead(0xFF0F) | 0x8), 0xFF0F); TransferSignal = false; Clock = 4096; } } }
/** * "It (DIV) works by using an internal system 16 bit counter. The counter increases each clock (4 clocks per * nop) and the value of DIV is the 8 upper bits of the counter: it increases every 256 oscillator clocks. * The value of DIV is the actual bits of the system internal counter, not a mirror, not a register that * increases with the system internal counter: The actual bits of the counter mapped to memory." * Source: AntonioND, The Cycle-Accurate Game Boy Docs * * "The signal used to increase the TIMA register is generated in a weird way. It selects the actual value * of one bit of the system internal counter, and performs an and operation with the enable bit in TAC. * This means that writing to the DIV register affects the timer too (writing to timer registers doesn't * affect the DIV register)." * Source: AntonioND, The Cycle-Accurate Game Boy Docs * * Tima is not blackbox so we can actually implement what Antonio mentions in his Docs about TIMA and indeed: * bool TIMASIGNAL = (((DIVREG & MASK) / MASK) & ((TACREG & 4) / 4)) != 0; * or to avoid the costly divisions: TIMASIGNAL = (DIV & MASK) == MASK && (TAC & 4) == 4; * TIMASIGNAL is true when the circuit is HI. TIMA increases if the FallingEdgeDetector * detects a 1 -> 0 transition of TIMASIGNAL. */ public override void Update(int clocks) { DIV = (ushort)(clocks + DIV); bool TIMASIGNAL = (DIV & MASK) == MASK && (TAC & 4) == 4; if (ReleaseOverflow) { //TIME: 8 Overflowing = false; ReleaseOverflow = false; } //After the brief period, TIMA will do its regular routine. if (Overflowing) { //TIME: 4 TIMA = TMA; Memory.DirectWrite((byte)(Memory.DirectRead(IF) | 0x4), IF); TIMACARRY = false; ReleaseOverflow = true; } if (FallingEdgeDetector.Check(TIMASIGNAL)) { TIMA++; //For a brief period (1 cycle or 4 clocks) TIMA has the value 0, and it's currently overflowing (AntonioND) if (TIMA == 0x0 && TIMACARRY) { //TIME: 0 Overflowing = true; } else if (TIMA == 0xFF) { //about to overflow TIMACARRY = true; } } }
private void IRQ(byte BIT) { Memory.DirectWrite((byte)(Memory.DirectRead(0xFF0F) | BIT), 0xFF0F); }