interrupt.h
/*
* This file is part of libsidplayfp, a SID player engine.
*
* Copyright 2011-2020 Leandro Nini <drfiemost@users.sourceforge.net>
* Copyright 2007-2010 Antti Lankila
* Copyright 2000 Simon White
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef INTERRUPT_H
#define INTERRUPT_H
#include "Event.h"
#include "EventScheduler.h"
#include "EventCallback.h"
#include <stdint.h>
#include "sidcxx11.h"
namespace libsidplayfp
{
class MOS652X;
class InterruptSource
{
public:
enum
{
INTERRUPT_NONE = 0,
INTERRUPT_UNDERFLOW_A = 1 << 0,
INTERRUPT_UNDERFLOW_B = 1 << 1,
INTERRUPT_ALARM = 1 << 2,
INTERRUPT_SP = 1 << 3,
INTERRUPT_FLAG = 1 << 4,
INTERRUPT_REQUEST = 1 << 7
};
private:
MOS652X &parent;
protected:
EventScheduler &eventScheduler;
event_clock_t last_clear = 0;
event_clock_t last_set = 0;
uint8_t icr = 0;
uint8_t idr = 0;
uint8_t idrTemp = 0;
bool scheduled = false;
bool asserted = false;
private:
EventCallback<InterruptSource> interruptEvent;
EventCallback<InterruptSource> updateIdrEvent;
EventCallback<InterruptSource> setIrqEvent;
EventCallback<InterruptSource> clearIrqEvent;
protected:
inline bool interruptTriggered() const { return idr & INTERRUPT_REQUEST; }
inline bool interruptMasked(uint8_t interruptMask) const
{
return ((interruptMask != INTERRUPT_NONE) ? interruptMask : idr) & icr;
}
virtual void triggerInterrupt() =0;
inline bool ack0() const { return eventScheduler.getTime(EVENT_CLOCK_PHI2) == (last_clear+1); }
inline bool write0() const { return eventScheduler.getTime(EVENT_CLOCK_PHI2) == (last_set+1); }
void interrupt();
void updateIdr();
void setIrq();
void clearIrq();
protected:
InterruptSource(EventScheduler &scheduler, MOS652X &parent) :
parent(parent),
eventScheduler(scheduler),
interruptEvent("CIA Interrupt", *this, &InterruptSource::interrupt),
updateIdrEvent("CIA update ICR", *this, &InterruptSource::updateIdr),
setIrqEvent("CIA set IRQ", *this, &InterruptSource::setIrq),
clearIrqEvent("CIA clear IRQ", *this, &InterruptSource::clearIrq)
{}
void schedule(int delay)
{
if (!scheduled)
{
eventScheduler.schedule(interruptEvent, delay, EVENT_CLOCK_PHI1);
scheduled = true;
}
}
void scheduleIrq()
{
eventScheduler.schedule(setIrqEvent, 1, EVENT_CLOCK_PHI1);
}
bool isTriggered(uint8_t interruptMask);
public:
virtual ~InterruptSource() = default;
virtual void trigger(uint8_t interruptMask) =0;
virtual uint8_t clear();
virtual void reset()
{
last_clear = 0;
last_set = 0;
icr = 0;
idr = 0;
eventScheduler.cancel(updateIdrEvent);
eventScheduler.cancel(setIrqEvent);
eventScheduler.cancel(clearIrqEvent);
eventScheduler.cancel(interruptEvent);
scheduled = false;
asserted = false;
}
void set(uint8_t interruptMask);
};
}
#endif // INTERRUPT_H
libsidplayfp::EventCallback
Definition EventCallback.h:36
libsidplayfp::EventScheduler
Definition EventScheduler.h:62
libsidplayfp::EventScheduler::getTime
event_clock_t getTime(event_phase_t phase) const
Definition EventScheduler.h:158
libsidplayfp::InterruptSource::idr
uint8_t idr
Interrupt data register.
Definition interrupt.h:73
libsidplayfp::InterruptSource::eventScheduler
EventScheduler & eventScheduler
Event scheduler.
Definition interrupt.h:63
libsidplayfp::InterruptSource::last_clear
event_clock_t last_clear
Clock when clear was called last.
Definition interrupt.h:66
libsidplayfp::InterruptSource::InterruptSource
InterruptSource(EventScheduler &scheduler, MOS652X &parent)
Definition interrupt.h:126
libsidplayfp::InterruptSource::asserted
bool asserted
is the irq pin asserted?
Definition interrupt.h:81
libsidplayfp::InterruptSource::set
void set(uint8_t interruptMask)
Definition interrupt.cpp:93
libsidplayfp::InterruptSource::INTERRUPT_NONE
@ INTERRUPT_NONE
no interrupt
Definition interrupt.h:48
libsidplayfp::InterruptSource::INTERRUPT_REQUEST
@ INTERRUPT_REQUEST
control bit
Definition interrupt.h:54
libsidplayfp::InterruptSource::INTERRUPT_SP
@ INTERRUPT_SP
serial port
Definition interrupt.h:52
libsidplayfp::InterruptSource::INTERRUPT_UNDERFLOW_B
@ INTERRUPT_UNDERFLOW_B
underflow Timer B
Definition interrupt.h:50
libsidplayfp::InterruptSource::INTERRUPT_FLAG
@ INTERRUPT_FLAG
external flag
Definition interrupt.h:53
libsidplayfp::InterruptSource::INTERRUPT_ALARM
@ INTERRUPT_ALARM
alarm clock
Definition interrupt.h:51
libsidplayfp::InterruptSource::INTERRUPT_UNDERFLOW_A
@ INTERRUPT_UNDERFLOW_A
underflow Timer A
Definition interrupt.h:49
libsidplayfp::InterruptSource::ack0
bool ack0() const
Definition interrupt.h:105
libsidplayfp::InterruptSource::scheduled
bool scheduled
Have we already scheduled CIA->CPU interrupt transition?
Definition interrupt.h:78
libsidplayfp::InterruptSource::icr
uint8_t icr
Interrupt control register.
Definition interrupt.h:70
libsidplayfp::InterruptSource::reset
virtual void reset()
Definition interrupt.h:175
libsidplayfp::InterruptSource::schedule
void schedule(int delay)
Definition interrupt.h:138
libsidplayfp::InterruptSource::trigger
virtual void trigger(uint8_t interruptMask)=0
libsidplayfp::InterruptSource::clear
virtual uint8_t clear()
Definition interrupt.cpp:110
libsidplayfp::InterruptSource::interrupt
void interrupt()
Definition interrupt.cpp:30
libsidplayfp::MOS652X
Definition mos652x.h:154