mos656x.h
/*
* This file is part of libsidplayfp, a SID player engine.
*
* Copyright 2011-2013 Leandro Nini <drfiemost@users.sourceforge.net>
* 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 "sidplayfp/event.h"
#include "sidplayfp/component.h"
#include "sidplayfp/EventScheduler.h"
class MOS656X: public component, private Event
{
public:
typedef enum
{
MOS6567R56A = 0 /* OLD NTSC CHIP */
,MOS6567R8 /* NTSC-M */
,MOS6569 /* PAL-B */
,MOS6572 /* PAL-N */
} model_t;
private:
typedef struct
{
unsigned int rasterLines;
unsigned int cyclesPerLine;
event_clock_t (MOS656X::*clock)();
} model_data_t;
private:
static const char *credit;
static const model_data_t modelData[];
private:
static const int IRQ_RASTER = 1 << 0;
static const int IRQ_LIGHTPEN = 1 << 3;
protected:
static const unsigned int FIRST_DMA_LINE = 0x30;
static const unsigned int LAST_DMA_LINE = 0xf7;
protected:
event_clock_t (MOS656X::*clock)();
event_clock_t rasterClk;
EventContext &event_context;
unsigned int cyclesPerLine;
unsigned int maxRasters;
unsigned int lineCycle;
unsigned int rasterY;
unsigned int yscroll;
uint16_t raster_irq;
bool areBadLinesEnabled;
bool isBadLine;
bool vblanking;
bool lp_triggered;
uint8_t irqFlags;
uint8_t irqMask;
uint8_t lpx, lpy;
uint8_t &sprite_enable, &sprite_y_expansion;
uint8_t sprite_dma;
uint8_t sprite_mc_base[8];
uint8_t sprite_mc[8];
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); }
void activateIRQFlag(int flag)
{
irqFlags |= flag;
handleIrqState();
}
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 void sync()
{
event_context.cancel(*this);
event();
}
inline void checkVblank()
{
// IRQ occurred (xraster != 0)
if (rasterY == (maxRasters - 1))
vblanking = true;
else
{
rasterY++;
// Trigger raster IRQ if IRQ line reached
if (rasterY == raster_irq)
activateIRQFlag(IRQ_RASTER);
}
// In line $30, the DEN bit controls if Bad Lines can occur
if (rasterY == FIRST_DMA_LINE)
areBadLinesEnabled = readDEN();
// Test for bad line condition
isBadLine = evaluateIsBadLine();
}
inline void vblank()
{
// Vertical blank (line 0)
if (vblanking)
{
vblanking = lp_triggered = false;
rasterY = 0;
// Trigger raster IRQ if IRQ in line 0
if (raster_irq == 0)
activateIRQFlag(IRQ_RASTER);
}
}
inline void updateMc()
{
// Update mc values in one pass
// after the dma has been processed
uint8_t mask = 1;
for (unsigned int i=0; i<8; i++, mask<<=1)
{
if (sprite_enable & mask)
sprite_mc[i] = (sprite_mc[i] + 3) & 0x3f;
}
}
inline void updateMcBase()
{
uint8_t mask = 1;
for (unsigned int i=0; i<8; i++, mask<<=1)
{
if (sprite_y_expansion & mask)
sprite_mc_base[i] = sprite_mc[i];
if (sprite_mc_base[i] == 0x3f)
sprite_dma &= ~mask;
}
}
inline void checkSpriteDmaExp()
{
const uint8_t y = rasterY & 0xff;
uint8_t mask = 1;
for (unsigned int i=0; i<8; i++, mask<<=1)
{
if ((sprite_enable & mask) && (y == regs[i << 1]))
{
sprite_dma |= mask;
sprite_mc_base[i] = 0;
sprite_y_expansion |= mask;
}
}
}
inline void checkSpriteDma()
{
const uint8_t y = rasterY & 0xff;
uint8_t mask = 1;
for (unsigned int i=0; i<8; i++, mask<<=1)
{
if ((sprite_enable & mask) && (y == regs[i << 1]))
{
sprite_dma |= mask;
sprite_mc_base[i] = 0;
}
}
}
inline void checkSpriteDisplay()
{
for (unsigned int i=0; i<8; i++)
{
sprite_mc[i] = sprite_mc_base[i];
}
}
template<int n>
inline void startDma()
{
if (sprite_dma & (0x01 << n))
setBA(false);
}
template<int n>
inline void endDma()
{
if (!(sprite_dma & (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 lightpen();
// Component Standard Calls
void reset();
const char *credits() const { return credit; }
int getCyclesPerLine() const { return cyclesPerLine; }
int getRasterLines() const { return maxRasters; }
};
// Template specializations
template<>
inline void MOS656X::startDma<0>()
{
setBA(!(sprite_dma & 0x01));
}
template<>
inline void MOS656X::endDma<7>()
{
setBA(true);
}
#endif // MOS656X_H
MOS656X::sprite_mc
uint8_t sprite_mc[8]
Definition: mos656x.h:121
MOS656X::vblanking
bool vblanking
Definition: mos656x.h:102
MOS656X::areBadLinesEnabled
bool areBadLinesEnabled
Definition: mos656x.h:96
MOS656X
Definition: mos656x.h:33
MOS656X::isBadLine
bool isBadLine
Definition: mos656x.h:99
MOS656X::event
void event()
Definition: mos656x.cpp:214
MOS656X::yscroll
unsigned int yscroll
Definition: mos656x.h:91
EventContext
Definition: event.h:101
MOS656X::lineCycle
unsigned int lineCycle
Definition: mos656x.h:85
EventCallback< MOS656X >
MOS656X::cyclesPerLine
unsigned int cyclesPerLine
Definition: mos656x.h:80
component
Definition: component.h:28
MOS656X::sprite_y_expansion
uint8_t & sprite_y_expansion
Definition: mos656x.h:118
MOS656X::LAST_DMA_LINE
static const unsigned int LAST_DMA_LINE
Definition: mos656x.h:69
MOS656X::read
uint8_t read(uint_least8_t addr)
Definition: mos656x.cpp:91
MOS656X::sprite_mc_base
uint8_t sprite_mc_base[8]
Definition: mos656x.h:120
MOS656X::lpx
uint8_t lpx
Definition: mos656x.h:114
MOS656X::irqMask
uint8_t irqMask
Definition: mos656x.h:111
MOS656X::regs
uint8_t regs[0x40]
Definition: mos656x.h:125
MOS656X::write
void write(uint_least8_t addr, uint8_t data)
Definition: mos656x.cpp:127
MOS656X::FIRST_DMA_LINE
static const unsigned int FIRST_DMA_LINE
Definition: mos656x.h:66
MOS656X::irqFlags
uint8_t irqFlags
Definition: mos656x.h:108
Event
Definition: event.h:50
MOS656X::sprite_dma
uint8_t sprite_dma
Definition: mos656x.h:119
MOS656X::event_context
EventContext & event_context
Definition: mos656x.h:77
MOS656X::rasterY
unsigned int rasterY
Definition: mos656x.h:88
MOS656X::lp_triggered
bool lp_triggered
Definition: mos656x.h:105
EventContext::cancel
virtual void cancel(Event &event)=0
MOS656X::sprite_enable
uint8_t & sprite_enable
Definition: mos656x.h:118