mos656x.h
/*
* This file is part of libsidplayfp, a SID player engine.
*
* Copyright 2011-2014 Leandro Nini <drfiemost@users.sourceforge.net>
* Copyright 2009-2014 VICE Project
* Copyright 2007-2010 Antti Lankila
* Copyright 2001 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 MOS656X_H
#define MOS656X_H
#include <stdint.h>
#include "lightpen.h"
#include "sprites.h"
#include "sidplayfp/event.h"
#include "c64/component.h"
#include "EventScheduler.h"
class MOS656X: public component, private Event
{
public:
typedef enum
{
MOS6567R56A = 0
,MOS6567R8
,MOS6569
,MOS6572
} model_t;
private:
typedef event_clock_t (MOS656X::*ClockFunc)();
typedef struct
{
unsigned int rasterLines;
unsigned int cyclesPerLine;
ClockFunc clock;
} model_data_t;
private:
static const char *credit;
static const model_data_t modelData[];
static const int IRQ_RASTER = 1 << 0;
static const int IRQ_LIGHTPEN = 1 << 3;
static const unsigned int FIRST_DMA_LINE = 0x30;
static const unsigned int LAST_DMA_LINE = 0xf7;
private:
ClockFunc clock;
event_clock_t rasterClk;
EventContext &event_context;
unsigned int cyclesPerLine;
unsigned int maxRasters;
unsigned int lineCycle;
unsigned int rasterY;
unsigned int yscroll;
bool areBadLinesEnabled;
bool isBadLine;
bool rasterYIRQCondition;
bool vblanking;
bool lpAsserted;
uint8_t irqFlags;
uint8_t irqMask;
Lightpen lp;
Sprites sprites;
uint8_t regs[0x40];
private:
event_clock_t clockPAL();
event_clock_t clockNTSC();
event_clock_t clockOldNTSC();
void handleIrqState();
EventCallback<MOS656X> badLineStateChangeEvent;
void badLineStateChange() { setBA(!isBadLine); }
EventCallback<MOS656X> rasterYIRQEdgeDetectorEvent;
void rasterYIRQEdgeDetector()
{
const bool oldRasterYIRQCondition = rasterYIRQCondition;
rasterYIRQCondition = rasterY == readRasterLineIRQ();
if (!oldRasterYIRQCondition && rasterYIRQCondition)
activateIRQFlag(IRQ_RASTER);
}
void activateIRQFlag(int flag)
{
irqFlags |= flag;
handleIrqState();
}
unsigned int readRasterLineIRQ() const
{
return (regs[0x12] & 0xff) + ((regs[0x11] & 0x80) << 1);
}
bool readDEN() const { return (regs[0x11] & 0x10) != 0; }
bool evaluateIsBadLine() const
{
return areBadLinesEnabled
&& rasterY >= FIRST_DMA_LINE
&& rasterY <= LAST_DMA_LINE
&& (rasterY & 7) == yscroll;
}
inline unsigned int oldRasterY() const
{
return rasterY > 0 ? rasterY - 1 : maxRasters - 1;
}
inline void sync()
{
event_context.cancel(*this);
event();
}
inline void checkVblank()
{
// IRQ occurred (xraster != 0)
if (rasterY == (maxRasters - 1))
{
vblanking = true;
}
// Check DEN bit on first cycle of the line following the first DMA line
if (rasterY == FIRST_DMA_LINE
&& !areBadLinesEnabled
&& readDEN())
{
areBadLinesEnabled = true;
}
// Disallow bad lines after the last possible one has passed
if (rasterY == LAST_DMA_LINE)
{
areBadLinesEnabled = false;
}
isBadLine = false;
if (!vblanking)
{
rasterY++;
rasterYIRQEdgeDetector();
}
if (evaluateIsBadLine())
isBadLine = true;
}
inline void vblank()
{
// Vertical blank (line 0)
if (vblanking)
{
vblanking = false;
rasterY = 0;
rasterYIRQEdgeDetector();
lp.untrigger();
if (lpAsserted && lp.retrigger(lineCycle, rasterY))
{
activateIRQFlag(IRQ_LIGHTPEN);
}
}
}
template<int n>
inline void startDma()
{
if (sprites.isDma(0x01 << n))
setBA(false);
}
template<int n>
inline void endDma()
{
if (!sprites.isDma(0x06 << n))
setBA(true);
}
inline void startBadline()
{
if (isBadLine)
setBA(false);
}
protected:
MOS656X(EventContext *context);
~MOS656X() {}
// Environment Interface
virtual void interrupt (bool state) = 0;
virtual void setBA (bool state) = 0;
uint8_t read(uint_least8_t addr);
void write(uint_least8_t addr, uint8_t data);
public:
void event();
void chip(model_t model);
void triggerLightpen();
void clearLightpen();
// Component Standard Calls
void reset();
static const char *credits() { return credit; }
};
// Template specializations
template<>
inline void MOS656X::startDma<0>()
{
setBA(!sprites.isDma(0x01));
}
template<>
inline void MOS656X::endDma<7>()
{
setBA(true);
}
#endif // MOS656X_H
Lightpen::untrigger
void untrigger()
Definition: lightpen.h:133
Sprites::isDma
bool isDma(unsigned int val) const
Definition: sprites.h:159
MOS656X
Definition: mos656x.h:36
Sprites
Definition: sprites.h:33
MOS656X::model_t
model_t
Definition: mos656x.h:39
MOS656X::event
void event()
Definition: mos656x.cpp:245
EventContext
Definition: event.h:107
MOS656X::MOS6572
PAL-N.
Definition: mos656x.h:44
EventCallback< MOS656X >
component
Definition: component.h:28
Lightpen
Definition: lightpen.h:30
MOS656X::read
uint8_t read(uint_least8_t addr)
Definition: mos656x.cpp:104
MOS656X::clearLightpen
void clearLightpen()
Definition: mos656x.cpp:675
MOS656X::write
void write(uint_least8_t addr, uint8_t data)
Definition: mos656x.cpp:140
Lightpen::retrigger
bool retrigger(unsigned int lineCycle, unsigned int rasterY)
Definition: lightpen.h:88
Event
Definition: event.h:50
EventContext::cancel
virtual void cancel(Event &event)=0
MOS656X::MOS6567R56A
OLD NTSC CHIP.
Definition: mos656x.h:41
MOS656X::MOS6567R8
NTSC-M.
Definition: mos656x.h:42
MOS656X::triggerLightpen
void triggerLightpen()
Definition: mos656x.cpp:662
MOS656X::MOS6569
PAL-B.
Definition: mos656x.h:43