1 /* 2 * This file is part of libsidplayfp, a SID player engine. 3 * 4 * Copyright 2011-2020 Leandro Nini <drfiemost@users.sourceforge.net> 5 * Copyright 2007-2010 Antti Lankila 6 * Copyright 2000 Simon White 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 */ 22 23 #ifndef INTERRUPT_H 24 #define INTERRUPT_H 25 26 #include "Event.h" 27 #include "EventScheduler.h" 28 29 #include <stdint.h> 30 31 #include "sidcxx11.h" 32 33 namespace libsidplayfp 34 { 35 36 class MOS6526; 37 38 /** 39 * This is the base class for the MOS6526 interrupt sources. 40 */ 41 class InterruptSource : protected Event 42 { 43 public: 44 enum 45 { 46 INTERRUPT_NONE = 0, ///< no interrupt 47 INTERRUPT_UNDERFLOW_A = 1 << 0, ///< underflow Timer A 48 INTERRUPT_UNDERFLOW_B = 1 << 1, ///< underflow Timer B 49 INTERRUPT_ALARM = 1 << 2, ///< alarm clock 50 INTERRUPT_SP = 1 << 3, ///< serial port 51 INTERRUPT_FLAG = 1 << 4, ///< external flag 52 INTERRUPT_REQUEST = 1 << 7 ///< control bit 53 }; 54 55 private: 56 /// Pointer to the MOS6526 which this Interrupt belongs to. 57 MOS6526 &parent; 58 59 protected: 60 /// Event scheduler. 61 EventScheduler &eventScheduler; 62 63 /// Clock when clear was called last 64 event_clock_t last_clear; 65 66 /// Interrupt control register 67 uint8_t icr; 68 69 /// Interrupt data register 70 uint8_t idr; 71 72 private: 73 /// Have we already scheduled CIA->CPU interrupt transition? 74 bool scheduled; 75 76 protected: interruptMasked()77 bool interruptMasked() const { return icr & idr; } 78 interruptTriggered()79 bool interruptTriggered() const { return idr & INTERRUPT_REQUEST; } 80 triggerInterrupt()81 void triggerInterrupt() { idr |= INTERRUPT_REQUEST; } 82 83 protected: 84 /** 85 * Create a new InterruptSource. 86 * 87 * @param scheduler event scheduler 88 * @param parent the MOS6526 which this Interrupt belongs to 89 */ InterruptSource(EventScheduler & scheduler,MOS6526 & parent)90 InterruptSource(EventScheduler &scheduler, MOS6526 &parent) : 91 Event("CIA Interrupt"), 92 parent(parent), 93 eventScheduler(scheduler), 94 last_clear(0), 95 icr(0), 96 idr(0), 97 scheduled(false) 98 {} 99 100 /** 101 * Schedules an IRQ asserting state transition for next cycle. 102 */ schedule()103 void schedule() 104 { 105 if (!scheduled) 106 { 107 eventScheduler.schedule(*this, 1, EVENT_CLOCK_PHI1); 108 scheduled = true; 109 } 110 } 111 112 void interrupt(bool state); 113 114 public: ~InterruptSource()115 virtual ~InterruptSource() {} 116 117 /** 118 * Trigger an interrupt. 119 * 120 * @param interruptMask Interrupt flag number 121 */ trigger(uint8_t interruptMask)122 virtual void trigger(uint8_t interruptMask) { idr |= interruptMask; } 123 124 /** 125 * Clear interrupt state. 126 * 127 * @return old interrupt state 128 */ 129 virtual uint8_t clear(); 130 131 /** 132 * Clear pending interrupts, but do not signal to CPU we lost them. 133 * It is assumed that all components get reset() calls in synchronous manner. 134 */ reset()135 virtual void reset() 136 { 137 icr = 0; 138 idr = 0; 139 eventScheduler.cancel(*this); 140 scheduled = false; 141 } 142 143 /** 144 * Set interrupt control mask bits. 145 * 146 * @param interruptMask control mask bits 147 */ set(uint8_t interruptMask)148 void set(uint8_t interruptMask) 149 { 150 if (interruptMask & 0x80) 151 { 152 icr |= interruptMask & ~INTERRUPT_REQUEST; 153 trigger(INTERRUPT_NONE); 154 } 155 else 156 { 157 icr &= ~interruptMask; 158 } 159 } 160 161 /** 162 * Signal interrupt to CPU. 163 */ 164 void event() override; 165 }; 166 167 } 168 169 #endif // INTERRUPT_H 170