protected void OnExpire(TimerExpirationEventArgs args) { if (Expired != null) { Expired(this, args); } }
private void DisplayEndOfFrame(object sender, TimerExpirationEventArgs e) { TimerExpired(sender, e); currentLcdDmaCounter = 0; currentLine = Timers[2].BackupValue; device.NewVideoFrameAvailable = true; }
private void TimerExpired(object sender, TimerExpirationEventArgs e) { Timer timer = (Timer)sender; // Only timers with enabled interrupt will trigger if (timer.StaticControlBits.EnableInterrupt) { // Update interrupt status timerInterruptStatusRegister |= e.InterruptMask; // Trigger a maskable interrupt device.Cpu.SignalInterrupt(InterruptType.Irq); } }
public void GenerateBaudRate(object sender, TimerExpirationEventArgs e) { Timer timer = (Timer)sender; // bool fireInterrupt = comLynx.GenerateBaudRate(); bool fireInterrupt = ComLynx.GenerateBaudPulse(); if (fireInterrupt) { // Update interrupt status timerInterruptStatusRegister |= e.InterruptMask; // Trigger a maskable interrupt device.Cpu.SignalInterrupt(InterruptType.Irq); } }
// "The interrupt signal comes from the timer when the timer value is zero // AND the timer is attempting to perform a 'borrow'." protected ulong Expire() { ulong cyclesInterrupt = 0; // "It is set on time out, reset with the reset timer done bit (xxx1, B6)" DynamicControlBits.TimerDone = true; // !StaticControlBits.ResetTimerDone; DynamicControlBits.BorrowOut = true; // "Timers can be set to stop when they reach a count of 0 or to reload from their backup register." // Reload if neccessary CurrentValue = StaticControlBits.EnableReload ? BackupValue : (byte)0; TimerExpirationEventArgs args = new TimerExpirationEventArgs(this.InterruptMask); OnExpire(args); cyclesInterrupt = args.CyclesInterrupt; return(cyclesInterrupt); }
private void RenderLine(object sender, TimerExpirationEventArgs e) { TimerExpired(sender, e); // TODO: Implementation of Keith does not always trigger IRQ when DMA is not enabled, // display bits (?) or display current have not been set if (!DISPCTL.EnableVideoDma) { return; } int backupValue = Timers[2].BackupValue; //currentLine = Timers[2].CurrentValue; // "The current method of driving the LCD requires 3 scan lines of vertical blank." // TODO: Determine if rest is between frames 104, 103 and 102 (for 60Hz) // Keith Wilkins has Rest period between 102, 101 and 100 bool rest = (currentLine >= (backupValue - 4) && currentLine <= (backupValue - 2)); RestActive = rest; //IODAT.Rest = rest; if (currentLine > (backupValue - 3)) { currentLine--; return; } if (currentLine == (backupValue - 3)) { // Pick up current video start address // "The hardware address in Mikey (DISPADDR) is the backup value for the actual address counter. // The backup value is transferred to the address counter at the very start of the third line of // vertical blanking." currentLynxDmaAddress = (ushort)(VideoDisplayStartAddress.Value & 0xFFFC); // "The value in the register is the start (upper left corner) of the display buffer in normal // mode and the end (lower right corner) of the display buffer in FLIP mode" if (DISPCTL.Flip) { currentLynxDmaAddress += 3; } } if (currentLine > 0) { currentLine--; } if (currentLcdDmaCounter < 0) { return; } // TODO: Define constant for DMA_READWRITE_CYCLE e.CyclesInterrupt = 80 * 4; // Every byte has two nibbles for two pixels for (int loop = 0; loop < Suzy.SCREEN_WIDTH / 2; loop++) { byte source = VideoMemoryDma[currentLynxDmaAddress]; if (DISPCTL.Flip) { currentLynxDmaAddress--; SetPixel((byte)(source & 0x0F)); SetPixel((byte)(source >> 4)); } else { currentLynxDmaAddress++; SetPixel((byte)(source >> 4)); SetPixel((byte)(source & 0x0F)); } } }