convert leading tabs to spaces in all file (they were a random mixture of tabs and spaces before).
This commit is contained in:
parent
db7b722eea
commit
7059628f52
|
@ -19,74 +19,74 @@
|
||||||
|
|
||||||
static unsigned char tobyt(float x)
|
static unsigned char tobyt(float x)
|
||||||
{
|
{
|
||||||
x *= 256.0f;
|
x *= 256.0f;
|
||||||
x += 0.0001f;
|
x += 0.0001f;
|
||||||
int xi = (int)x;
|
int xi = (int)x;
|
||||||
|
|
||||||
if (xi > 255)
|
if (xi > 255)
|
||||||
xi = 255;
|
xi = 255;
|
||||||
|
|
||||||
return (unsigned char)xi;
|
return (unsigned char)xi;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0 <= h < 360 degrees; 0 <= s,v <= 1
|
// 0 <= h < 360 degrees; 0 <= s,v <= 1
|
||||||
static int HSVtoRGB(const int h, const float s, const float v)
|
static int HSVtoRGB(const int h, const float s, const float v)
|
||||||
{
|
{
|
||||||
const float f = (h % 60) / 60.0;
|
const float f = (h % 60) / 60.0;
|
||||||
|
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
switch (h / 60)
|
switch (h / 60)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
r = v;
|
r = v;
|
||||||
g = v * (1 - s * (1 - f));
|
g = v * (1 - s * (1 - f));
|
||||||
b = v * (1 - s);
|
b = v * (1 - s);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
r = v * (1 - s * f);
|
r = v * (1 - s * f);
|
||||||
g = v;
|
g = v;
|
||||||
b = v * (1 - s);
|
b = v * (1 - s);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
r = v * (1 - s);
|
r = v * (1 - s);
|
||||||
g = v;
|
g = v;
|
||||||
b = v * (1 - s * (1 - f));
|
b = v * (1 - s * (1 - f));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
r = v * (1 - s);
|
r = v * (1 - s);
|
||||||
g = v * (1 - s * f);
|
g = v * (1 - s * f);
|
||||||
b = v;
|
b = v;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
r = v * (1 - s * (1 - f));
|
r = v * (1 - s * (1 - f));
|
||||||
g = v * (1 - s);
|
g = v * (1 - s);
|
||||||
b = v;
|
b = v;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
r = v;
|
r = v;
|
||||||
g = v * (1 - s);
|
g = v * (1 - s);
|
||||||
b = v * (1 - s * f);
|
b = v * (1 - s * f);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
r = g = b = 0;
|
r = g = b = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (tobyt(r) << 16) | (tobyt(g) << 8) | (tobyt(b));
|
return (tobyt(r) << 16) | (tobyt(g) << 8) | (tobyt(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
A2ColorsObserved::A2ColorsObserved():
|
A2ColorsObserved::A2ColorsObserved():
|
||||||
COLOR(0x10)
|
COLOR(0x10)
|
||||||
{
|
{
|
||||||
// const unsigned int clr[] = { 0x1, 0xB, 0x3, 0x2, 0x7, 0x6, 0x4, 0xE, 0xC, 0x8, 0xD, 0x9, 0x5, 0xA, 0xF, 0x0 };
|
// const unsigned int clr[] = { 0x1, 0xB, 0x3, 0x2, 0x7, 0x6, 0x4, 0xE, 0xC, 0x8, 0xD, 0x9, 0x5, 0xA, 0xF, 0x0 };
|
||||||
const unsigned int map[] = { 0xF, 0x0, 0x3, 0x2, 0x6, 0xC, 0x5, 0x4, 0x9, 0xB, 0xD, 0x1, 0x8, 0xA, 0x7, 0xE };
|
const unsigned int map[] = { 0xF, 0x0, 0x3, 0x2, 0x6, 0xC, 0x5, 0x4, 0x9, 0xB, 0xD, 0x1, 0x8, 0xA, 0x7, 0xE };
|
||||||
const unsigned int hue[] = { 342, 342, 277, 233, 233, 213, 160, 160, 75, 33, 52, 24, 0, 0, 0, 0 };
|
const unsigned int hue[] = { 342, 342, 277, 233, 233, 213, 160, 160, 75, 33, 52, 24, 0, 0, 0, 0 };
|
||||||
const unsigned int sat[] = { 100, 50, 75, 100, 50, 100, 100, 100, 100, 100, 100, 100, 0, 0, 0, 0 };
|
const unsigned int sat[] = { 100, 50, 75, 100, 50, 100, 100, 100, 100, 100, 100, 100, 0, 0, 0, 0 };
|
||||||
const unsigned int val[] = { 67, 100, 100, 75, 100, 100, 33, 100, 75, 50, 100, 100, 50, 50, 100, 0 };
|
const unsigned int val[] = { 67, 100, 100, 75, 100, 100, 33, 100, 75, 50, 100, 100, 50, 50, 100, 0 };
|
||||||
|
|
||||||
for (unsigned int i(0); i < COLOR.size(); ++i)
|
for (unsigned int i(0); i < COLOR.size(); ++i)
|
||||||
{
|
{
|
||||||
COLOR[i] = HSVtoRGB(hue[map[i]],sat[map[i]]/100.0f,val[map[i]]/100.0f);
|
COLOR[i] = HSVtoRGB(hue[map[i]],sat[map[i]]/100.0f,val[map[i]]/100.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,33 +23,33 @@
|
||||||
class A2ColorsObserved
|
class A2ColorsObserved
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::vector<unsigned int> COLOR;
|
std::vector<unsigned int> COLOR;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
A2ColorsObserved();
|
A2ColorsObserved();
|
||||||
~A2ColorsObserved();
|
~A2ColorsObserved();
|
||||||
|
|
||||||
const std::vector<unsigned int>& c() { return this->COLOR; }
|
const std::vector<unsigned int>& c() { return this->COLOR; }
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
BLACK,
|
BLACK,
|
||||||
DARK_MAGENTA,
|
DARK_MAGENTA,
|
||||||
DARK_BLUE,
|
DARK_BLUE,
|
||||||
HIRES_VIOLET,
|
HIRES_VIOLET,
|
||||||
DARK_BLUE_GREEN,
|
DARK_BLUE_GREEN,
|
||||||
GREY,
|
GREY,
|
||||||
HIRES_BLUE,
|
HIRES_BLUE,
|
||||||
LIGHT_BLUE,
|
LIGHT_BLUE,
|
||||||
DARK_BROWN,
|
DARK_BROWN,
|
||||||
HIRES_ORANGE,
|
HIRES_ORANGE,
|
||||||
GREY_ALTERNATE,
|
GREY_ALTERNATE,
|
||||||
LIGHT_MAGENTA,
|
LIGHT_MAGENTA,
|
||||||
HIRES_GREEN,
|
HIRES_GREEN,
|
||||||
LIGHT_BROWN,
|
LIGHT_BROWN,
|
||||||
LIGHT_BLUE_GREEN,
|
LIGHT_BLUE_GREEN,
|
||||||
WHITE,
|
WHITE,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
504
src/analogtv.cpp
504
src/analogtv.cpp
|
@ -41,25 +41,25 @@
|
||||||
|
|
||||||
|
|
||||||
AnalogTV::AnalogTV(ScreenImage& image):
|
AnalogTV::AnalogTV(ScreenImage& image):
|
||||||
image(image),
|
image(image),
|
||||||
on(false),
|
on(false),
|
||||||
noise(false),
|
noise(false),
|
||||||
bleed_down(true)
|
bleed_down(true)
|
||||||
{
|
{
|
||||||
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_GREEN]);
|
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_GREEN]);
|
||||||
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_ORANGE]);
|
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_ORANGE]);
|
||||||
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_VIOLET]);
|
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_VIOLET]);
|
||||||
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_BLUE]);
|
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_BLUE]);
|
||||||
|
|
||||||
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BROWN]);
|
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BROWN]);
|
||||||
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_MAGENTA]);
|
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_MAGENTA]);
|
||||||
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE]);
|
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE]);
|
||||||
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE_GREEN]);
|
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE_GREEN]);
|
||||||
|
|
||||||
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE_GREEN]);
|
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE_GREEN]);
|
||||||
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BROWN]);
|
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BROWN]);
|
||||||
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_MAGENTA]);
|
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_MAGENTA]);
|
||||||
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE]);
|
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,25 +69,25 @@ AnalogTV::~AnalogTV()
|
||||||
|
|
||||||
void AnalogTV::powerOn(bool b)
|
void AnalogTV::powerOn(bool b)
|
||||||
{
|
{
|
||||||
this->on = b;
|
this->on = b;
|
||||||
this->image.notifyObservers();
|
this->image.notifyObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalogTV::setType(DisplayType type)
|
void AnalogTV::setType(DisplayType type)
|
||||||
{
|
{
|
||||||
this->type = type;
|
this->type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalogTV::cycleType()
|
void AnalogTV::cycleType()
|
||||||
{
|
{
|
||||||
this->type = (DisplayType)((((int)this->type)+1)%NUM_DISPLAY_TYPES);
|
this->type = (DisplayType)((((int)this->type)+1)%NUM_DISPLAY_TYPES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalogTV::toggleBleedDown()
|
void AnalogTV::toggleBleedDown()
|
||||||
{
|
{
|
||||||
this->bleed_down = !this->bleed_down;
|
this->bleed_down = !this->bleed_down;
|
||||||
this->image.blank();
|
this->image.blank();
|
||||||
this->image.notifyObservers();
|
this->image.notifyObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -137,18 +137,18 @@ void AnalogTV::toggleBleedDown()
|
||||||
class IQ
|
class IQ
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
double iq[4];
|
double iq[4];
|
||||||
IQ()
|
IQ()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
iq[i] = 0;
|
iq[i] = 0;
|
||||||
}
|
}
|
||||||
IQ(double aiq[])
|
IQ(double aiq[])
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
iq[i] = aiq[i];
|
iq[i] = aiq[i];
|
||||||
}
|
}
|
||||||
double get(int i) const { return this->iq[i]; }
|
double get(int i) const { return this->iq[i]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
const IQ& AnalogTV::BLACK_AND_WHITE = IQ();
|
const IQ& AnalogTV::BLACK_AND_WHITE = IQ();
|
||||||
|
@ -158,67 +158,67 @@ static const int CB_EXTRA(32);
|
||||||
class CB
|
class CB
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
std::vector<int> cb;
|
std::vector<int> cb;
|
||||||
|
|
||||||
CB(const int acb[]):
|
CB(const int acb[]):
|
||||||
cb(AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA)
|
cb(AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA)
|
||||||
{
|
{
|
||||||
for (std::vector<int>::size_type i(0); i < this->cb.size(); ++i)
|
for (std::vector<int>::size_type i(0); i < this->cb.size(); ++i)
|
||||||
{
|
{
|
||||||
this->cb[i] = acb[i];
|
this->cb[i] = acb[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int get(const int i) const { return this->cb[i]; }
|
int get(const int i) const { return this->cb[i]; }
|
||||||
int length() const { return this->cb.size(); }
|
int length() const { return this->cb.size(); }
|
||||||
void getPhase(double phase[]) const
|
void getPhase(double phase[]) const
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
phase[i & 3] = 0;
|
phase[i & 3] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
for (int i = 0; i < length(); ++i)
|
for (int i = 0; i < length(); ++i)
|
||||||
{
|
{
|
||||||
phase[i & 3] += this->cb[i];
|
phase[i & 3] += this->cb[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
double tot = 0;
|
double tot = 0;
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
{
|
{
|
||||||
tot += phase[i] * phase[i];
|
tot += phase[i] * phase[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const double tsrt = sqrt(tot);
|
const double tsrt = sqrt(tot);
|
||||||
if (tsrt < .0001)
|
if (tsrt < .0001)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
phase[i] /= tsrt;
|
phase[i] /= tsrt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool isColor() const
|
bool isColor() const
|
||||||
{
|
{
|
||||||
int tot = 0;
|
int tot = 0;
|
||||||
for (int i = 0; i < length(); ++i)
|
for (int i = 0; i < length(); ++i)
|
||||||
{
|
{
|
||||||
const int icb = this->cb[i];
|
const int icb = this->cb[i];
|
||||||
if (icb < 0)
|
if (icb < 0)
|
||||||
tot += -icb;
|
tot += -icb;
|
||||||
else
|
else
|
||||||
tot += icb;
|
tot += icb;
|
||||||
}
|
}
|
||||||
return 220 < tot && tot < 260;
|
return 220 < tot && tot < 260;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const CB& that) const
|
bool operator<(const CB& that) const
|
||||||
{
|
{
|
||||||
return this->cb < that.cb;
|
return this->cb < that.cb;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -229,21 +229,21 @@ public:
|
||||||
|
|
||||||
void AnalogTV::drawCurrent()
|
void AnalogTV::drawCurrent()
|
||||||
{
|
{
|
||||||
if (this->on)
|
if (this->on)
|
||||||
{
|
{
|
||||||
switch (this->type)
|
switch (this->type)
|
||||||
{
|
{
|
||||||
case MONITOR_COLOR: drawMonitorColor(); break;
|
case MONITOR_COLOR: drawMonitorColor(); break;
|
||||||
case MONITOR_GREEN: drawMonitorGreen(); break;
|
case MONITOR_GREEN: drawMonitorGreen(); break;
|
||||||
case TV_OLD_COLOR: drawTVOld(); break;
|
case TV_OLD_COLOR: drawTVOld(); break;
|
||||||
case NUM_DISPLAY_TYPES: break;
|
case NUM_DISPLAY_TYPES: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
drawBlank();
|
drawBlank();
|
||||||
}
|
}
|
||||||
this->image.notifyObservers();
|
this->image.notifyObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -252,80 +252,80 @@ static const int D_IP(AppleNTSC::H-2-350);
|
||||||
|
|
||||||
void AnalogTV::drawMonitorColor()
|
void AnalogTV::drawMonitorColor()
|
||||||
{
|
{
|
||||||
unsigned int *rgb = new unsigned int[AppleNTSC::H];
|
unsigned int *rgb = new unsigned int[AppleNTSC::H];
|
||||||
int ip = 0;
|
int ip = 0;
|
||||||
for (int row = 0; row < 192; ++row)
|
for (int row = 0; row < 192; ++row)
|
||||||
{
|
{
|
||||||
const CB cb = get_cb(row);
|
const CB cb = get_cb(row);
|
||||||
const bool removeColor = !cb.isColor();
|
const bool removeColor = !cb.isColor();
|
||||||
ntsc_to_rgb_monitor(row*AppleNTSC::H+350,AppleNTSC::H-350,rgb);
|
ntsc_to_rgb_monitor(row*AppleNTSC::H+350,AppleNTSC::H-350,rgb);
|
||||||
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
||||||
{
|
{
|
||||||
int rgbv = rgb[col-350];
|
int rgbv = rgb[col-350];
|
||||||
if (removeColor && rgbv != 0)
|
if (removeColor && rgbv != 0)
|
||||||
{
|
{
|
||||||
rgbv = 0xFFFFFF;
|
rgbv = 0xFFFFFF;
|
||||||
}
|
}
|
||||||
this->image.setElem(ip,rgbv);
|
this->image.setElem(ip,rgbv);
|
||||||
if (bleed_down)
|
if (bleed_down)
|
||||||
this->image.setElem(ip+D_IP,rgbv); // display same pixel on next row
|
this->image.setElem(ip+D_IP,rgbv); // display same pixel on next row
|
||||||
++ip;
|
++ip;
|
||||||
}
|
}
|
||||||
ip += D_IP;
|
ip += D_IP;
|
||||||
}
|
}
|
||||||
delete [] rgb;
|
delete [] rgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalogTV::drawMonitorGreen()
|
void AnalogTV::drawMonitorGreen()
|
||||||
{
|
{
|
||||||
drawMonitorMonochrome(colors.c()[A2ColorsObserved::HIRES_GREEN]);
|
drawMonitorMonochrome(colors.c()[A2ColorsObserved::HIRES_GREEN]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalogTV::drawMonitorMonochrome(const unsigned int color)
|
void AnalogTV::drawMonitorMonochrome(const unsigned int color)
|
||||||
{
|
{
|
||||||
int ip = 0;
|
int ip = 0;
|
||||||
for (int row = 0; row < 192; ++row)
|
for (int row = 0; row < 192; ++row)
|
||||||
{
|
{
|
||||||
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
||||||
{
|
{
|
||||||
const int is = row*AppleNTSC::H+col;
|
const int is = row*AppleNTSC::H+col;
|
||||||
const unsigned int rgb = this->signal[is] > 50 ? color : 0;
|
const unsigned int rgb = this->signal[is] > 50 ? color : 0;
|
||||||
this->image.setElem(ip,rgb);
|
this->image.setElem(ip,rgb);
|
||||||
if (bleed_down)
|
if (bleed_down)
|
||||||
this->image.setElem(ip+D_IP,rgb);
|
this->image.setElem(ip+D_IP,rgb);
|
||||||
++ip;
|
++ip;
|
||||||
}
|
}
|
||||||
ip += D_IP;
|
ip += D_IP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalogTV::drawTVOld()
|
void AnalogTV::drawTVOld()
|
||||||
{
|
{
|
||||||
int *yiq = new int[AppleNTSC::H];
|
int *yiq = new int[AppleNTSC::H];
|
||||||
int ip = 0;
|
int ip = 0;
|
||||||
for (int row = 0; row < 192; ++row)
|
for (int row = 0; row < 192; ++row)
|
||||||
{
|
{
|
||||||
IQ iq_factor;
|
IQ iq_factor;
|
||||||
const CB cb = get_cb(row);
|
const CB cb = get_cb(row);
|
||||||
iq_factor = get_iq_factor(cb);
|
iq_factor = get_iq_factor(cb);
|
||||||
ntsc_to_yiq(row*AppleNTSC::H+350,AppleNTSC::H-350,iq_factor,yiq);
|
ntsc_to_yiq(row*AppleNTSC::H+350,AppleNTSC::H-350,iq_factor,yiq);
|
||||||
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
for (int col = 350; col < AppleNTSC::H-2; ++col)
|
||||||
{
|
{
|
||||||
const int rgb = yiq2rgb(yiq[col-348]); // shift display left 1 pixel
|
const int rgb = yiq2rgb(yiq[col-348]); // shift display left 1 pixel
|
||||||
this->image.setElem(ip,rgb);
|
this->image.setElem(ip,rgb);
|
||||||
if (bleed_down)
|
if (bleed_down)
|
||||||
this->image.setElem(ip+D_IP,rgb);
|
this->image.setElem(ip+D_IP,rgb);
|
||||||
++ip;
|
++ip;
|
||||||
}
|
}
|
||||||
ip += D_IP;
|
ip += D_IP;
|
||||||
}
|
}
|
||||||
delete [] yiq;
|
delete [] yiq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AnalogTV::drawBlank()
|
void AnalogTV::drawBlank()
|
||||||
{
|
{
|
||||||
this->image.blank();
|
this->image.blank();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -334,47 +334,47 @@ void AnalogTV::drawBlank()
|
||||||
|
|
||||||
void AnalogTV::ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[])
|
void AnalogTV::ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[])
|
||||||
{
|
{
|
||||||
int s0, s1, se;
|
int s0, s1, se;
|
||||||
s0 = s1 = isignal;
|
s0 = s1 = isignal;
|
||||||
se = isignal+siglen;
|
se = isignal+siglen;
|
||||||
while (s1 < se)
|
while (s1 < se)
|
||||||
{
|
{
|
||||||
// no signal (black)
|
// no signal (black)
|
||||||
while (this->signal[s0] < 50 && s0<se) { rgb[s0-isignal] = 0; ++s0; }
|
while (this->signal[s0] < 50 && s0<se) { rgb[s0-isignal] = 0; ++s0; }
|
||||||
|
|
||||||
// signal (white, grey, or color)
|
// signal (white, grey, or color)
|
||||||
s1 = s0;
|
s1 = s0;
|
||||||
while (this->signal[s1] > 50 && s1<se) { ++s1; }
|
while (this->signal[s1] > 50 && s1<se) { ++s1; }
|
||||||
const int slen = s1-s0;
|
const int slen = s1-s0;
|
||||||
unsigned int c = 0;
|
unsigned int c = 0;
|
||||||
if (slen >= 4)
|
if (slen >= 4)
|
||||||
{
|
{
|
||||||
c = 0xFFFFFF;
|
c = 0xFFFFFF;
|
||||||
}
|
}
|
||||||
else if (slen == 1)
|
else if (slen == 1)
|
||||||
{
|
{
|
||||||
if (this->signal[s0-2] > 50 && this->signal[s0+2] > 50)
|
if (this->signal[s0-2] > 50 && this->signal[s0+2] > 50)
|
||||||
c = 0xFFFFFF;
|
c = 0xFFFFFF;
|
||||||
else
|
else
|
||||||
c = loresdarkcolor[s0 % 4];
|
c = loresdarkcolor[s0 % 4];
|
||||||
}
|
}
|
||||||
else if (slen == 2)
|
else if (slen == 2)
|
||||||
{
|
{
|
||||||
c = hirescolor[s0 % 4];
|
c = hirescolor[s0 % 4];
|
||||||
}
|
}
|
||||||
else if (slen == 3)
|
else if (slen == 3)
|
||||||
{
|
{
|
||||||
c = loreslightcolor[s0 % 4];
|
c = loreslightcolor[s0 % 4];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++s1;
|
++s1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = s0; i < s1; ++i)
|
for (int i = s0; i < s1; ++i)
|
||||||
rgb[i-isignal] = c;
|
rgb[i-isignal] = c;
|
||||||
s0 = s1;
|
s0 = s1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -386,12 +386,12 @@ void AnalogTV::ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned
|
||||||
int *AnalogTV::rcb = new int[AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA];
|
int *AnalogTV::rcb = new int[AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA];
|
||||||
CB AnalogTV::get_cb(int lineno)
|
CB AnalogTV::get_cb(int lineno)
|
||||||
{
|
{
|
||||||
const int isp = lineno * AppleNTSC::H;
|
const int isp = lineno * AppleNTSC::H;
|
||||||
for (int i = AppleNTSC::CB_START + CB_EXTRA/2; i < AppleNTSC::CB_END - CB_EXTRA/2; ++i)
|
for (int i = AppleNTSC::CB_START + CB_EXTRA/2; i < AppleNTSC::CB_END - CB_EXTRA/2; ++i)
|
||||||
{
|
{
|
||||||
this->rcb[i-(AppleNTSC::CB_START + CB_EXTRA/2)] = this->signal[isp + i];
|
this->rcb[i-(AppleNTSC::CB_START + CB_EXTRA/2)] = this->signal[isp + i];
|
||||||
}
|
}
|
||||||
return CB(this->rcb);
|
return CB(this->rcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -406,35 +406,35 @@ const double AnalogTV::COLOR_THRESH(sqrt(2));
|
||||||
|
|
||||||
IQ AnalogTV::get_iq_factor(const CB& cb)
|
IQ AnalogTV::get_iq_factor(const CB& cb)
|
||||||
{
|
{
|
||||||
std::map<CB,IQ>::iterator hit = cacheCB.find(cb);
|
std::map<CB,IQ>::iterator hit = cacheCB.find(cb);
|
||||||
if (hit != cacheCB.end())
|
if (hit != cacheCB.end())
|
||||||
{
|
{
|
||||||
return hit->second;
|
return hit->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
double cb_phase[4];
|
double cb_phase[4];
|
||||||
cb.getPhase(cb_phase);
|
cb.getPhase(cb_phase);
|
||||||
const double cb_i = cb_phase[2]-cb_phase[0];
|
const double cb_i = cb_phase[2]-cb_phase[0];
|
||||||
const double cb_q = cb_phase[3]-cb_phase[1];
|
const double cb_q = cb_phase[3]-cb_phase[1];
|
||||||
|
|
||||||
if ((cb_i*cb_i) + (cb_q*cb_q) < COLOR_THRESH)
|
if ((cb_i*cb_i) + (cb_q*cb_q) < COLOR_THRESH)
|
||||||
{
|
{
|
||||||
return BLACK_AND_WHITE;
|
return BLACK_AND_WHITE;
|
||||||
}
|
}
|
||||||
|
|
||||||
double iq_factor[4];
|
double iq_factor[4];
|
||||||
|
|
||||||
iq_factor[0] = cb_i * TINT_I + cb_q * TINT_Q;
|
iq_factor[0] = cb_i * TINT_I + cb_q * TINT_Q;
|
||||||
iq_factor[2] = -iq_factor[0];
|
iq_factor[2] = -iq_factor[0];
|
||||||
iq_factor[1] = cb_q * TINT_I - cb_i * TINT_Q;
|
iq_factor[1] = cb_q * TINT_I - cb_i * TINT_Q;
|
||||||
iq_factor[3] = -iq_factor[1];
|
iq_factor[3] = -iq_factor[1];
|
||||||
|
|
||||||
const IQ iq(iq_factor);
|
const IQ iq(iq_factor);
|
||||||
if (!this->noise)
|
if (!this->noise)
|
||||||
{
|
{
|
||||||
cacheCB[cb] = iq;
|
cacheCB[cb] = iq;
|
||||||
}
|
}
|
||||||
return iq;
|
return iq;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int AnalogTV::IQINTOFF(130);
|
const int AnalogTV::IQINTOFF(130);
|
||||||
|
@ -456,41 +456,41 @@ void AnalogTV::ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_fac
|
||||||
|
|
||||||
int inline AnalogTV::yiq2rgb(const int yiq)
|
int inline AnalogTV::yiq2rgb(const int yiq)
|
||||||
{
|
{
|
||||||
double r = (((yiq)&0xFF)-IQINTOFF) + 0.956 * (((yiq>>8)&0xFF)-IQINTOFF) + 0.621 * (((yiq>>16)&0xFF)-IQINTOFF);
|
double r = (((yiq)&0xFF)-IQINTOFF) + 0.956 * (((yiq>>8)&0xFF)-IQINTOFF) + 0.621 * (((yiq>>16)&0xFF)-IQINTOFF);
|
||||||
double g = (((yiq)&0xFF)-IQINTOFF) - 0.272 * (((yiq>>8)&0xFF)-IQINTOFF) - 0.647 * (((yiq>>16)&0xFF)-IQINTOFF);
|
double g = (((yiq)&0xFF)-IQINTOFF) - 0.272 * (((yiq>>8)&0xFF)-IQINTOFF) - 0.647 * (((yiq>>16)&0xFF)-IQINTOFF);
|
||||||
double b = (((yiq)&0xFF)-IQINTOFF) - 1.105 * (((yiq>>8)&0xFF)-IQINTOFF) + 1.702 * (((yiq>>16)&0xFF)-IQINTOFF);
|
double b = (((yiq)&0xFF)-IQINTOFF) - 1.105 * (((yiq>>8)&0xFF)-IQINTOFF) + 1.702 * (((yiq>>16)&0xFF)-IQINTOFF);
|
||||||
|
|
||||||
const int rgb =
|
const int rgb =
|
||||||
(calc_color(r) << 16)|
|
(calc_color(r) << 16)|
|
||||||
(calc_color(g) << 8)|
|
(calc_color(g) << 8)|
|
||||||
(calc_color(b) << 0);
|
(calc_color(b) << 0);
|
||||||
|
|
||||||
return rgb;
|
return rgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inline AnalogTV::color2bw(const int rgb)
|
int inline AnalogTV::color2bw(const int rgb)
|
||||||
{
|
{
|
||||||
const int y = rgb2y(rgb);
|
const int y = rgb2y(rgb);
|
||||||
return y<<16 | y<<8 | y;
|
return y<<16 | y<<8 | y;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inline AnalogTV::rgb2y(const int rgb) // y in range 0-255
|
int inline AnalogTV::rgb2y(const int rgb) // y in range 0-255
|
||||||
{
|
{
|
||||||
return (int)((0.299*((rgb>>16)&0xFF) + 0.587*((rgb>>8)&0xFF) + 0.114*((rgb)&0xFF))/1.04);
|
return (int)((0.299*((rgb>>16)&0xFF) + 0.587*((rgb>>8)&0xFF) + 0.114*((rgb)&0xFF))/1.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
int inline AnalogTV::calc_color(const double color)
|
int inline AnalogTV::calc_color(const double color)
|
||||||
{
|
{
|
||||||
int x = (int)(color * 0x100 / AppleNTSC::LEVEL_RANGE + .5);
|
int x = (int)(color * 0x100 / AppleNTSC::LEVEL_RANGE + .5);
|
||||||
x = clamp(0,x,0x100);
|
x = clamp(0,x,0x100);
|
||||||
return x & 0xFF;
|
return x & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inline AnalogTV::clamp(int min, int x, int lim)
|
int inline AnalogTV::clamp(int min, int x, int lim)
|
||||||
{
|
{
|
||||||
if (x < min)
|
if (x < min)
|
||||||
return min;
|
return min;
|
||||||
if (lim <= x)
|
if (lim <= x)
|
||||||
return lim-1;
|
return lim-1;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
112
src/analogtv.h
112
src/analogtv.h
|
@ -32,75 +32,75 @@ class CB;
|
||||||
class AnalogTV
|
class AnalogTV
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum DisplayType
|
enum DisplayType
|
||||||
{
|
{
|
||||||
TV_OLD_COLOR,
|
TV_OLD_COLOR,
|
||||||
MONITOR_COLOR,
|
MONITOR_COLOR,
|
||||||
MONITOR_GREEN,
|
MONITOR_GREEN,
|
||||||
|
|
||||||
NUM_DISPLAY_TYPES
|
NUM_DISPLAY_TYPES
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ScreenImage& image;
|
ScreenImage& image;
|
||||||
|
|
||||||
bool on;
|
bool on;
|
||||||
bool noise;
|
bool noise;
|
||||||
DisplayType type;
|
DisplayType type;
|
||||||
bool bleed_down;
|
bool bleed_down;
|
||||||
|
|
||||||
static int* rcb;
|
static int* rcb;
|
||||||
|
|
||||||
A2ColorsObserved colors;
|
A2ColorsObserved colors;
|
||||||
std::vector<unsigned int> hirescolor;
|
std::vector<unsigned int> hirescolor;
|
||||||
std::vector<unsigned int> loreslightcolor;
|
std::vector<unsigned int> loreslightcolor;
|
||||||
std::vector<unsigned int> loresdarkcolor;
|
std::vector<unsigned int> loresdarkcolor;
|
||||||
|
|
||||||
static const int IQINTOFF;
|
static const int IQINTOFF;
|
||||||
static const double IQ_OFFSET_DEGREES;
|
static const double IQ_OFFSET_DEGREES;
|
||||||
static const double IQ_OFFSET_RADIANS;
|
static const double IQ_OFFSET_RADIANS;
|
||||||
static const double TINT_I;
|
static const double TINT_I;
|
||||||
static const double TINT_Q;
|
static const double TINT_Q;
|
||||||
static const double COLOR_THRESH;
|
static const double COLOR_THRESH;
|
||||||
static const IQ& BLACK_AND_WHITE;
|
static const IQ& BLACK_AND_WHITE;
|
||||||
|
|
||||||
void drawMonitorColor();
|
void drawMonitorColor();
|
||||||
void drawMonitorWhite();
|
void drawMonitorWhite();
|
||||||
void drawMonitorGreen();
|
void drawMonitorGreen();
|
||||||
void drawMonitorOrange();
|
void drawMonitorOrange();
|
||||||
void drawMonitorMonochrome(const unsigned int color);
|
void drawMonitorMonochrome(const unsigned int color);
|
||||||
void drawTVOld();
|
void drawTVOld();
|
||||||
void drawTVNew();
|
void drawTVNew();
|
||||||
void drawBlank();
|
void drawBlank();
|
||||||
void ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[]);
|
void ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[]);
|
||||||
void ntsc_to_rgb_newtv(const int isignal, const int siglen, unsigned int rgb[]);
|
void ntsc_to_rgb_newtv(const int isignal, const int siglen, unsigned int rgb[]);
|
||||||
CB get_cb(int lineno);
|
CB get_cb(int lineno);
|
||||||
IQ get_iq_factor(const CB& cb);
|
IQ get_iq_factor(const CB& cb);
|
||||||
void ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_factor, int yiq[]);
|
void ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_factor, int yiq[]);
|
||||||
static int yiq2rgb(const int yiq);
|
static int yiq2rgb(const int yiq);
|
||||||
static int color2bw(const int rgb);
|
static int color2bw(const int rgb);
|
||||||
static int rgb2y(const int rgb); // ;y in range 0-255
|
static int rgb2y(const int rgb); // ;y in range 0-255
|
||||||
static int calc_color(const double color);
|
static int calc_color(const double color);
|
||||||
static int clamp(int min, int x, int lim);
|
static int clamp(int min, int x, int lim);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void drawCurrent();
|
void drawCurrent();
|
||||||
signed char* signal;
|
signed char* signal;
|
||||||
|
|
||||||
AnalogTV(ScreenImage& image);
|
AnalogTV(ScreenImage& image);
|
||||||
~AnalogTV();
|
~AnalogTV();
|
||||||
|
|
||||||
bool isOn() const
|
bool isOn() const
|
||||||
{
|
{
|
||||||
return this->on;
|
return this->on;
|
||||||
}
|
}
|
||||||
|
|
||||||
void powerOn(bool b);
|
void powerOn(bool b);
|
||||||
void toggleBleedDown();
|
void toggleBleedDown();
|
||||||
void restartSignal();
|
void restartSignal();
|
||||||
void setType(DisplayType type);
|
void setType(DisplayType type);
|
||||||
void cycleType();
|
void cycleType();
|
||||||
void setNoise(bool noise) { this->noise = noise; }
|
void setNoise(bool noise) { this->noise = noise; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -39,23 +39,23 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui):
|
Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui):
|
||||||
slts(gui),
|
slts(gui),
|
||||||
kbd(keypresses,fhyper,buffered),
|
kbd(keypresses,fhyper,buffered),
|
||||||
rom(AddressBus::MOTHERBOARD_ROM_SIZ),
|
rom(AddressBus::MOTHERBOARD_ROM_SIZ),
|
||||||
ram(revision),
|
ram(revision),
|
||||||
cassetteIn(gui),
|
cassetteIn(gui),
|
||||||
cassetteOut(gui),
|
cassetteOut(gui),
|
||||||
addressBus(gui,revision,ram,rom,kbd,videoMode,paddles,paddleButtonStates,speaker,cassetteIn,cassetteOut,slts),
|
addressBus(gui,revision,ram,rom,kbd,videoMode,paddles,paddleButtonStates,speaker,cassetteIn,cassetteOut,slts),
|
||||||
picgen(tv,videoMode,revision),
|
picgen(tv,videoMode,revision),
|
||||||
video(videoMode,addressBus,picgen,textRows),
|
video(videoMode,addressBus,picgen,textRows),
|
||||||
#ifdef USE_EMU
|
#ifdef USE_EMU
|
||||||
transistors("transistors"),
|
transistors("transistors"),
|
||||||
cpu(transistors,addressBus),
|
cpu(transistors,addressBus),
|
||||||
#else
|
#else
|
||||||
cpu(addressBus),
|
cpu(addressBus),
|
||||||
#endif
|
#endif
|
||||||
powerUpReset(*this),
|
powerUpReset(*this),
|
||||||
revision(1)
|
revision(1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,21 +80,21 @@ void Apple2::tick() {
|
||||||
|
|
||||||
void Apple2::powerOn()
|
void Apple2::powerOn()
|
||||||
{
|
{
|
||||||
this->ram.powerOn();
|
this->ram.powerOn();
|
||||||
this->cpu.powerOn();
|
this->cpu.powerOn();
|
||||||
this->videoMode.powerOn();
|
this->videoMode.powerOn();
|
||||||
this->video.powerOn();
|
this->video.powerOn();
|
||||||
this->picgen.powerOn();
|
this->picgen.powerOn();
|
||||||
this->powerUpReset.powerOn();
|
this->powerUpReset.powerOn();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Apple2::powerOff()
|
void Apple2::powerOff()
|
||||||
{
|
{
|
||||||
this->ram.powerOff();
|
this->ram.powerOff();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Apple2::reset()
|
void Apple2::reset()
|
||||||
{
|
{
|
||||||
this->cpu.reset();
|
this->cpu.reset();
|
||||||
this->slts.reset();
|
this->slts.reset();
|
||||||
}
|
}
|
||||||
|
|
38
src/apple2.h
38
src/apple2.h
|
@ -46,39 +46,39 @@ class ScreenImage;
|
||||||
|
|
||||||
class Apple2 : public Timable
|
class Apple2 : public Timable
|
||||||
{
|
{
|
||||||
Slots slts;
|
Slots slts;
|
||||||
VideoMode videoMode;
|
VideoMode videoMode;
|
||||||
Keyboard kbd;
|
Keyboard kbd;
|
||||||
Paddles paddles;
|
Paddles paddles;
|
||||||
SpeakerClicker speaker;
|
SpeakerClicker speaker;
|
||||||
Memory rom;
|
Memory rom;
|
||||||
MemoryRandomAccess ram;
|
MemoryRandomAccess ram;
|
||||||
CassetteIn cassetteIn;
|
CassetteIn cassetteIn;
|
||||||
CassetteOut cassetteOut;
|
CassetteOut cassetteOut;
|
||||||
AddressBus addressBus;
|
AddressBus addressBus;
|
||||||
PictureGenerator picgen;
|
PictureGenerator picgen;
|
||||||
TextCharacters textRows;
|
TextCharacters textRows;
|
||||||
Video video;
|
Video video;
|
||||||
#ifdef USE_EMU
|
#ifdef USE_EMU
|
||||||
std::ifstream transistors;
|
std::ifstream transistors;
|
||||||
Emu6502 cpu;
|
Emu6502 cpu;
|
||||||
#else
|
#else
|
||||||
CPU cpu;
|
CPU cpu;
|
||||||
#endif
|
#endif
|
||||||
PowerUpReset powerUpReset;
|
PowerUpReset powerUpReset;
|
||||||
int revision;
|
int revision;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui);
|
Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui);
|
||||||
~Apple2();
|
~Apple2();
|
||||||
|
|
||||||
void powerOn();
|
void powerOn();
|
||||||
void powerOff();
|
void powerOff();
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
virtual void tick();
|
virtual void tick();
|
||||||
|
|
||||||
friend class Emulator;
|
friend class Emulator;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,31 +21,31 @@
|
||||||
class AppleNTSC
|
class AppleNTSC
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
AppleNTSC() {}
|
AppleNTSC() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum { V = 262, H = (25+40)*14+2 };
|
enum { V = 262, H = (25+40)*14+2 };
|
||||||
enum { SIGNAL_LEN = V*H };
|
enum { SIGNAL_LEN = V*H };
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
FP_START = 0,
|
FP_START = 0,
|
||||||
SYNC_START = FP_START+126,
|
SYNC_START = FP_START+126,
|
||||||
BP_START = SYNC_START+112,
|
BP_START = SYNC_START+112,
|
||||||
CB_START = BP_START+0,
|
CB_START = BP_START+0,
|
||||||
CB_END = CB_START+56,
|
CB_END = CB_START+56,
|
||||||
SPIKE = CB_END+34,
|
SPIKE = CB_END+34,
|
||||||
PIC_START = CB_END+56
|
PIC_START = CB_END+56
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
WHITE_LEVEL = 100,
|
WHITE_LEVEL = 100,
|
||||||
BLANK_LEVEL = 0,
|
BLANK_LEVEL = 0,
|
||||||
SYNC_LEVEL = -40,
|
SYNC_LEVEL = -40,
|
||||||
CB_LEVEL = 20,
|
CB_LEVEL = 20,
|
||||||
LEVEL_RANGE = WHITE_LEVEL-SYNC_LEVEL
|
LEVEL_RANGE = WHITE_LEVEL-SYNC_LEVEL
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
34
src/card.cpp
34
src/card.cpp
|
@ -19,8 +19,8 @@
|
||||||
#include "configep2.h"
|
#include "configep2.h"
|
||||||
|
|
||||||
Card::Card():
|
Card::Card():
|
||||||
rom(0x0100),
|
rom(0x0100),
|
||||||
seventhRom(0x0800)
|
seventhRom(0x0800)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,44 +41,44 @@ void Card::tick()
|
||||||
|
|
||||||
unsigned char Card::io(const unsigned short /*address*/, const unsigned char data, const bool /*writing*/)
|
unsigned char Card::io(const unsigned short /*address*/, const unsigned char data, const bool /*writing*/)
|
||||||
{
|
{
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned char Card::readRom(const unsigned short address, const unsigned char data)
|
unsigned char Card::readRom(const unsigned short address, const unsigned char data)
|
||||||
{
|
{
|
||||||
this->activeSeventhRom = true;
|
this->activeSeventhRom = true;
|
||||||
return this->rom.read(address, data);
|
return this->rom.read(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::readSeventhRom(const unsigned short address, unsigned char* const pb)
|
void Card::readSeventhRom(const unsigned short address, unsigned char* const pb)
|
||||||
{
|
{
|
||||||
if (address == 0x7FF)
|
if (address == 0x7FF)
|
||||||
{
|
{
|
||||||
this->activeSeventhRom = false;
|
this->activeSeventhRom = false;
|
||||||
}
|
}
|
||||||
else if (this->activeSeventhRom && hasSeventhRom())
|
else if (this->activeSeventhRom && hasSeventhRom())
|
||||||
{
|
{
|
||||||
*pb = this->seventhRom.read(address, *pb);
|
*pb = this->seventhRom.read(address, *pb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::loadRom(const unsigned short base, std::istream& in)
|
void Card::loadRom(const unsigned short base, std::istream& in)
|
||||||
{
|
{
|
||||||
this->rom.load(base,in);
|
this->rom.load(base,in);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::loadSeventhRom(const unsigned short base, std::istream& in)
|
void Card::loadSeventhRom(const unsigned short base, std::istream& in)
|
||||||
{
|
{
|
||||||
this->seventhRom.load(base,in);
|
this->seventhRom.load(base,in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Card::inhibitMotherboardRom()
|
bool Card::inhibitMotherboardRom()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,17 +91,17 @@ void Card::ioBankRom(const unsigned short /*addr*/, unsigned char* const /*pb*/,
|
||||||
|
|
||||||
void Card::loadBankRom(const unsigned short /*base*/, std::istream& /*in*/)
|
void Card::loadBankRom(const unsigned short /*base*/, std::istream& /*in*/)
|
||||||
{
|
{
|
||||||
throw ConfigException("This card has no $D000 ROM");
|
throw ConfigException("This card has no $D000 ROM");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Card::getName()
|
std::string Card::getName()
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Card::isDirty()
|
bool Card::isDirty()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Card::save(int unit)
|
void Card::save(int unit)
|
||||||
|
|
32
src/card.h
32
src/card.h
|
@ -26,28 +26,28 @@
|
||||||
class Card
|
class Card
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool activeSeventhRom;
|
bool activeSeventhRom;
|
||||||
protected:
|
protected:
|
||||||
Memory rom;
|
Memory rom;
|
||||||
Memory seventhRom;
|
Memory seventhRom;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Card();
|
Card();
|
||||||
virtual ~Card();
|
virtual ~Card();
|
||||||
virtual void tick();
|
virtual void tick();
|
||||||
virtual void reset();
|
virtual void reset();
|
||||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||||
virtual unsigned char readRom(const unsigned short address, const unsigned char data);
|
virtual unsigned char readRom(const unsigned short address, const unsigned char data);
|
||||||
virtual bool hasSeventhRom() { return false; }
|
virtual bool hasSeventhRom() { return false; }
|
||||||
virtual void readSeventhRom(const unsigned short address, unsigned char* const pb);
|
virtual void readSeventhRom(const unsigned short address, unsigned char* const pb);
|
||||||
virtual void loadRom(const unsigned short base, std::istream& in);
|
virtual void loadRom(const unsigned short base, std::istream& in);
|
||||||
virtual void loadSeventhRom(const unsigned short base, std::istream& in);
|
virtual void loadSeventhRom(const unsigned short base, std::istream& in);
|
||||||
virtual bool inhibitMotherboardRom();
|
virtual bool inhibitMotherboardRom();
|
||||||
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
||||||
virtual void loadBankRom(const unsigned short base, std::istream& in);
|
virtual void loadBankRom(const unsigned short base, std::istream& in);
|
||||||
virtual bool isDirty();
|
virtual bool isDirty();
|
||||||
virtual void save(int unit);
|
virtual void save(int unit);
|
||||||
virtual std::string getName();
|
virtual std::string getName();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -233,7 +233,7 @@ bool CassetteIn::load(const std::string& filePath) {
|
||||||
if (!eject()) {
|
if (!eject()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* convert input sample to floating-point, at rate of 10 CPU cycles per sample, for easy calculation */
|
/* convert input sample to floating-point, at rate of 10 CPU cycles per sample, for easy calculation */
|
||||||
SDL_AudioCVT cvt;
|
SDL_AudioCVT cvt;
|
||||||
|
@ -256,7 +256,7 @@ bool CassetteIn::load(const std::string& filePath) {
|
||||||
rewind();
|
rewind();
|
||||||
tone();
|
tone();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CassetteIn::eject() {
|
bool CassetteIn::eject() {
|
||||||
|
|
|
@ -30,9 +30,9 @@ ClipboardHandler::~ClipboardHandler()
|
||||||
|
|
||||||
std::string ClipboardHandler::getText()
|
std::string ClipboardHandler::getText()
|
||||||
{
|
{
|
||||||
std::string ret;
|
std::string ret;
|
||||||
char* sdlAllocatedText = SDL_GetClipboardText();
|
char* sdlAllocatedText = SDL_GetClipboardText();
|
||||||
ret.assign(sdlAllocatedText);
|
ret.assign(sdlAllocatedText);
|
||||||
SDL_free(sdlAllocatedText);
|
SDL_free(sdlAllocatedText);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,10 @@
|
||||||
class ClipboardHandler
|
class ClipboardHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClipboardHandler();
|
ClipboardHandler();
|
||||||
~ClipboardHandler();
|
~ClipboardHandler();
|
||||||
|
|
||||||
std::string getText();
|
std::string getText();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
ClockCard::ClockCard():
|
ClockCard::ClockCard():
|
||||||
latch(0),
|
latch(0),
|
||||||
pos(0)
|
pos(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,38 +33,38 @@ ClockCard::~ClockCard()
|
||||||
|
|
||||||
unsigned char ClockCard::io(const unsigned short address, const unsigned char data, const bool writing)
|
unsigned char ClockCard::io(const unsigned short address, const unsigned char data, const bool writing)
|
||||||
{
|
{
|
||||||
const int sw = address & 0x0F;
|
const int sw = address & 0x0F;
|
||||||
if (sw == 0)
|
if (sw == 0)
|
||||||
{
|
{
|
||||||
if (!(this->latch & 0x80))
|
if (!(this->latch & 0x80))
|
||||||
{
|
{
|
||||||
if (this->pos == 0)
|
if (this->pos == 0)
|
||||||
{
|
{
|
||||||
getTime();
|
getTime();
|
||||||
}
|
}
|
||||||
char c = this->time[this->pos];
|
char c = this->time[this->pos];
|
||||||
this->latch = (unsigned char)(c | 0x80);
|
this->latch = (unsigned char)(c | 0x80);
|
||||||
++this->pos;
|
++this->pos;
|
||||||
if (this->pos >= this->timelen)
|
if (this->pos >= this->timelen)
|
||||||
{
|
{
|
||||||
this->pos = 0;
|
this->pos = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sw == 1)
|
else if (sw == 1)
|
||||||
{
|
{
|
||||||
this->latch &= 0x7F;
|
this->latch &= 0x7F;
|
||||||
}
|
}
|
||||||
return this->latch;
|
return this->latch;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TIMEFORMAT "%m,0%w,%d,%H,%M,%S,000,%Y,%Z,D\r"
|
#define TIMEFORMAT "%m,0%w,%d,%H,%M,%S,000,%Y,%Z,D\r"
|
||||||
|
|
||||||
void ClockCard::getTime()
|
void ClockCard::getTime()
|
||||||
{
|
{
|
||||||
time_t now;
|
time_t now;
|
||||||
::time(&now);
|
::time(&now);
|
||||||
struct tm* nowtm = ::localtime(&now);
|
struct tm* nowtm = ::localtime(&now);
|
||||||
this->timelen = ::strftime(this->time,sizeof(this->time),TIMEFORMAT,nowtm);
|
this->timelen = ::strftime(this->time,sizeof(this->time),TIMEFORMAT,nowtm);
|
||||||
this->time[this->timelen-2] = nowtm->tm_isdst>0 ? '1' : '0';
|
this->time[this->timelen-2] = nowtm->tm_isdst>0 ? '1' : '0';
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,19 +24,19 @@
|
||||||
class ClockCard : public Card
|
class ClockCard : public Card
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
unsigned char latch;
|
unsigned char latch;
|
||||||
unsigned int pos;
|
unsigned int pos;
|
||||||
char time[64];
|
char time[64];
|
||||||
size_t timelen;
|
size_t timelen;
|
||||||
|
|
||||||
void getTime();
|
void getTime();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ClockCard();
|
ClockCard();
|
||||||
~ClockCard();
|
~ClockCard();
|
||||||
|
|
||||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||||
virtual std::string getName() { return "clock"; }
|
virtual std::string getName() { return "clock"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
2058
src/cpu.cpp
2058
src/cpu.cpp
File diff suppressed because it is too large
Load Diff
338
src/cpu.h
338
src/cpu.h
|
@ -23,195 +23,195 @@ class AddressBus;
|
||||||
class CPU
|
class CPU
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
enum { MEMORY_LIM = 1 << 0x10 };
|
enum { MEMORY_LIM = 1 << 0x10 };
|
||||||
enum { IRQ_VECTOR = MEMORY_LIM-2 }; // or BRK
|
enum { IRQ_VECTOR = MEMORY_LIM-2 }; // or BRK
|
||||||
enum { RESET_VECTOR = IRQ_VECTOR-2 }; // or power-on
|
enum { RESET_VECTOR = IRQ_VECTOR-2 }; // or power-on
|
||||||
enum { NMI_VECTOR = RESET_VECTOR-2 };
|
enum { NMI_VECTOR = RESET_VECTOR-2 };
|
||||||
|
|
||||||
unsigned char adl;
|
unsigned char adl;
|
||||||
unsigned char adh;
|
unsigned char adh;
|
||||||
unsigned char bal;
|
unsigned char bal;
|
||||||
unsigned char bah;
|
unsigned char bah;
|
||||||
unsigned char ial;
|
unsigned char ial;
|
||||||
unsigned char iah;
|
unsigned char iah;
|
||||||
unsigned char idx;
|
unsigned char idx;
|
||||||
signed char offset;
|
signed char offset;
|
||||||
bool branch;
|
bool branch;
|
||||||
signed char sc;
|
signed char sc;
|
||||||
bool wc;
|
bool wc;
|
||||||
|
|
||||||
bool pendingIRQ;
|
bool pendingIRQ;
|
||||||
bool pendingNMI;
|
bool pendingNMI;
|
||||||
bool pendingReset;
|
bool pendingReset;
|
||||||
|
|
||||||
bool started;
|
bool started;
|
||||||
|
|
||||||
unsigned char a;
|
unsigned char a;
|
||||||
unsigned char x;
|
unsigned char x;
|
||||||
unsigned char y;
|
unsigned char y;
|
||||||
|
|
||||||
unsigned char s;
|
unsigned char s;
|
||||||
|
|
||||||
//p = NVMBDIZC
|
//p = NVMBDIZC
|
||||||
enum { PMASK_C = 1<<0 };
|
enum { PMASK_C = 1<<0 };
|
||||||
enum { PMASK_Z = 1<<1 };
|
enum { PMASK_Z = 1<<1 };
|
||||||
enum { PMASK_I = 1<<2 };
|
enum { PMASK_I = 1<<2 };
|
||||||
enum { PMASK_D = 1<<3 };
|
enum { PMASK_D = 1<<3 };
|
||||||
enum { PMASK_B = 1<<4 };
|
enum { PMASK_B = 1<<4 };
|
||||||
enum { PMASK_M = 1<<5 };
|
enum { PMASK_M = 1<<5 };
|
||||||
enum { PMASK_V = 1<<6 };
|
enum { PMASK_V = 1<<6 };
|
||||||
enum { PMASK_N = 1<<7 };
|
enum { PMASK_N = 1<<7 };
|
||||||
unsigned char p;
|
unsigned char p;
|
||||||
|
|
||||||
unsigned short pc;
|
unsigned short pc;
|
||||||
|
|
||||||
AddressBus& addressBus;
|
AddressBus& addressBus;
|
||||||
|
|
||||||
unsigned short address;
|
unsigned short address;
|
||||||
unsigned char data;
|
unsigned char data;
|
||||||
|
|
||||||
unsigned short opcode;
|
unsigned short opcode;
|
||||||
|
|
||||||
signed char t;
|
signed char t;
|
||||||
|
|
||||||
|
|
||||||
static void (CPU::*addr[])();
|
static void (CPU::*addr[])();
|
||||||
static void (CPU::*exec[])();
|
static void (CPU::*exec[])();
|
||||||
|
|
||||||
void firstCycle();
|
void firstCycle();
|
||||||
int getInterruptAddress();
|
int getInterruptAddress();
|
||||||
int getInterruptPseudoOpCode();
|
int getInterruptPseudoOpCode();
|
||||||
void subsequentCycle();
|
void subsequentCycle();
|
||||||
|
|
||||||
void read();
|
void read();
|
||||||
void write();
|
void write();
|
||||||
void execute();
|
void execute();
|
||||||
void done();
|
void done();
|
||||||
|
|
||||||
unsigned char pch();
|
unsigned char pch();
|
||||||
unsigned char pcl();
|
unsigned char pcl();
|
||||||
unsigned short sp();
|
unsigned short sp();
|
||||||
unsigned short push();
|
unsigned short push();
|
||||||
unsigned short pull();
|
unsigned short pull();
|
||||||
unsigned char getIndex();
|
unsigned char getIndex();
|
||||||
unsigned short ad();
|
unsigned short ad();
|
||||||
unsigned short ia();
|
unsigned short ia();
|
||||||
unsigned short ba();
|
unsigned short ba();
|
||||||
unsigned short combine(const unsigned char lo, const unsigned char hi);
|
unsigned short combine(const unsigned char lo, const unsigned char hi);
|
||||||
void setP(const unsigned char mask, const unsigned char val);
|
void setP(const unsigned char mask, const unsigned char val);
|
||||||
void setStatusRegisterNZ(const unsigned char val);
|
void setStatusRegisterNZ(const unsigned char val);
|
||||||
unsigned char shiftLeft(unsigned char byt);
|
unsigned char shiftLeft(unsigned char byt);
|
||||||
unsigned char shiftRight(unsigned char byt);
|
unsigned char shiftRight(unsigned char byt);
|
||||||
unsigned char rotateLeft(unsigned char byt);
|
unsigned char rotateLeft(unsigned char byt);
|
||||||
unsigned char rotateRight(unsigned char byt);
|
unsigned char rotateRight(unsigned char byt);
|
||||||
void compare(const unsigned char r);
|
void compare(const unsigned char r);
|
||||||
|
|
||||||
void addr_SINGLE();
|
void addr_SINGLE();
|
||||||
void addr_INTERNAL_IMMEDIATE();
|
void addr_INTERNAL_IMMEDIATE();
|
||||||
void addr_INTERNAL_ZERO_PAGE();
|
void addr_INTERNAL_ZERO_PAGE();
|
||||||
void addr_INTERNAL_ABSOLUTE();
|
void addr_INTERNAL_ABSOLUTE();
|
||||||
void addr_INTERNAL_INDIRECT_X();
|
void addr_INTERNAL_INDIRECT_X();
|
||||||
void addr_INTERNAL_ABSOLUTE_XY();
|
void addr_INTERNAL_ABSOLUTE_XY();
|
||||||
void addr_INTERNAL_ZERO_PAGE_XY();
|
void addr_INTERNAL_ZERO_PAGE_XY();
|
||||||
void addr_INTERNAL_INDIRECT_Y();
|
void addr_INTERNAL_INDIRECT_Y();
|
||||||
void addr_STORE_ZERO_PAGE();
|
void addr_STORE_ZERO_PAGE();
|
||||||
void addr_STORE_ABSOLUTE();
|
void addr_STORE_ABSOLUTE();
|
||||||
void addr_STORE_INDIRECT_X();
|
void addr_STORE_INDIRECT_X();
|
||||||
void addr_STORE_ABSOLUTE_XY();
|
void addr_STORE_ABSOLUTE_XY();
|
||||||
void addr_STORE_ZERO_PAGE_XY();
|
void addr_STORE_ZERO_PAGE_XY();
|
||||||
void addr_STORE_INDIRECT_Y();
|
void addr_STORE_INDIRECT_Y();
|
||||||
void addr_RMW_ZERO_PAGE();
|
void addr_RMW_ZERO_PAGE();
|
||||||
void addr_RMW_ABSOLUTE();
|
void addr_RMW_ABSOLUTE();
|
||||||
void addr_RMW_ZERO_PAGE_X();
|
void addr_RMW_ZERO_PAGE_X();
|
||||||
void addr_RMW_ABSOLUTE_X();
|
void addr_RMW_ABSOLUTE_X();
|
||||||
void addr_MISC_PUSH();
|
void addr_MISC_PUSH();
|
||||||
void addr_MISC_PULL();
|
void addr_MISC_PULL();
|
||||||
void addr_MISC_JSR();
|
void addr_MISC_JSR();
|
||||||
void addr_MISC_BREAK();
|
void addr_MISC_BREAK();
|
||||||
void addr_MISC_RTI();
|
void addr_MISC_RTI();
|
||||||
void addr_JMP_ABSOLUTE();
|
void addr_JMP_ABSOLUTE();
|
||||||
void addr_JMP_INDIRECT();
|
void addr_JMP_INDIRECT();
|
||||||
void addr_RTS();
|
void addr_RTS();
|
||||||
void addr_BRANCH();
|
void addr_BRANCH();
|
||||||
void addr_NMI();
|
void addr_NMI();
|
||||||
void addr_RESET();
|
void addr_RESET();
|
||||||
void addr_IRQ();
|
void addr_IRQ();
|
||||||
|
|
||||||
void LDA();
|
void LDA();
|
||||||
void LDX();
|
void LDX();
|
||||||
void LDY();
|
void LDY();
|
||||||
void STA();
|
void STA();
|
||||||
void STX();
|
void STX();
|
||||||
void STY();
|
void STY();
|
||||||
void CMP();
|
void CMP();
|
||||||
void CPX();
|
void CPX();
|
||||||
void CPY();
|
void CPY();
|
||||||
void AND();
|
void AND();
|
||||||
void ORA();
|
void ORA();
|
||||||
void EOR();
|
void EOR();
|
||||||
void ASL();
|
void ASL();
|
||||||
void ASL_A();
|
void ASL_A();
|
||||||
void LSR();
|
void LSR();
|
||||||
void LSR_A();
|
void LSR_A();
|
||||||
void ROL();
|
void ROL();
|
||||||
void ROL_A();
|
void ROL_A();
|
||||||
void ROR();
|
void ROR();
|
||||||
void ROR_A();
|
void ROR_A();
|
||||||
void ADC();
|
void ADC();
|
||||||
void SBC();
|
void SBC();
|
||||||
void INC();
|
void INC();
|
||||||
void DEC();
|
void DEC();
|
||||||
void INX();
|
void INX();
|
||||||
void INY();
|
void INY();
|
||||||
void DEX();
|
void DEX();
|
||||||
void DEY();
|
void DEY();
|
||||||
void BIT();
|
void BIT();
|
||||||
void PHA();
|
void PHA();
|
||||||
void PHP();
|
void PHP();
|
||||||
void PLA();
|
void PLA();
|
||||||
void PLP();
|
void PLP();
|
||||||
void BRK();
|
void BRK();
|
||||||
void RTI();
|
void RTI();
|
||||||
void JMP();
|
void JMP();
|
||||||
void RTS();
|
void RTS();
|
||||||
void JSR();
|
void JSR();
|
||||||
void BNE();
|
void BNE();
|
||||||
void BEQ();
|
void BEQ();
|
||||||
void BVC();
|
void BVC();
|
||||||
void BVS();
|
void BVS();
|
||||||
void BCC();
|
void BCC();
|
||||||
void BCS();
|
void BCS();
|
||||||
void BPL();
|
void BPL();
|
||||||
void BMI();
|
void BMI();
|
||||||
void TAX();
|
void TAX();
|
||||||
void TXA();
|
void TXA();
|
||||||
void TAY();
|
void TAY();
|
||||||
void TYA();
|
void TYA();
|
||||||
void TXS();
|
void TXS();
|
||||||
void TSX();
|
void TSX();
|
||||||
void CLC();
|
void CLC();
|
||||||
void SEC();
|
void SEC();
|
||||||
void CLI();
|
void CLI();
|
||||||
void SEI();
|
void SEI();
|
||||||
void CLV();
|
void CLV();
|
||||||
void CLD();
|
void CLD();
|
||||||
void SED();
|
void SED();
|
||||||
void NOP();
|
void NOP();
|
||||||
void Unoff();
|
void Unoff();
|
||||||
void Unoff1();
|
void Unoff1();
|
||||||
void Unoff2();
|
void Unoff2();
|
||||||
void Unoff3();
|
void Unoff3();
|
||||||
void Hang();
|
void Hang();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CPU(AddressBus& addressBus);
|
CPU(AddressBus& addressBus);
|
||||||
~CPU();
|
~CPU();
|
||||||
|
|
||||||
void powerOn();
|
void powerOn();
|
||||||
void reset();
|
void reset();
|
||||||
void IRQ();
|
void IRQ();
|
||||||
void NMI();
|
void NMI();
|
||||||
void tick();
|
void tick();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
236
src/e2const.h
236
src/e2const.h
|
@ -21,148 +21,148 @@
|
||||||
class E2Const
|
class E2Const
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
The NTSC standard defines the field rate as 60 fields per second. The number 60
|
The NTSC standard defines the field rate as 60 fields per second. The number 60
|
||||||
is based on the USA AC current frequency of 60 Hz. This, in turn, was based on the
|
is based on the USA AC current frequency of 60 Hz. This, in turn, was based on the
|
||||||
clock standard (60 seconds per minute and 60 minutes per hour).
|
clock standard (60 seconds per minute and 60 minutes per hour).
|
||||||
*/
|
*/
|
||||||
static const int NTSC_FIELD_HZ = 60;
|
static const int NTSC_FIELD_HZ = 60;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The NTSC standard defines 525 lines per frame, which was chosen to be a multiple
|
The NTSC standard defines 525 lines per frame, which was chosen to be a multiple
|
||||||
of a small number of standard tubes at the time, to produce a rate between RCA's
|
of a small number of standard tubes at the time, to produce a rate between RCA's
|
||||||
recommended 441 (used by NBC) and Philco's suggested 600-800 lines.
|
recommended 441 (used by NBC) and Philco's suggested 600-800 lines.
|
||||||
*/
|
*/
|
||||||
static const int NTSC_LINES_PER_FRAME = 3*5*5*7;
|
static const int NTSC_LINES_PER_FRAME = 3*5*5*7;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
When color was added to the NTSC signal, studies by General Electric showed that
|
When color was added to the NTSC signal, studies by General Electric showed that
|
||||||
minimum interference was achieved using a subcarrier frequency 455 times the field
|
minimum interference was achieved using a subcarrier frequency 455 times the field
|
||||||
rate, which can also be obtained using standard tubes.
|
rate, which can also be obtained using standard tubes.
|
||||||
*/
|
*/
|
||||||
static const int NTSC_COLOR_MULTIPLE = 5*7*13;
|
static const int NTSC_COLOR_MULTIPLE = 5*7*13;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Adding color to NTSC also required slowing down the frame rate, by dropping one
|
Adding color to NTSC also required slowing down the frame rate, by dropping one
|
||||||
field after every 1000.
|
field after every 1000.
|
||||||
*/
|
*/
|
||||||
static const int NTSC_COLOR_DROP_FIELD = 1000;
|
static const int NTSC_COLOR_DROP_FIELD = 1000;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculate the color sub-channel rate, times 4.
|
Calculate the color sub-channel rate, times 4.
|
||||||
This will be the (approximate) Hz of the "14M"
|
This will be the (approximate) Hz of the "14M"
|
||||||
crystal oscillator in the Apple ][.
|
crystal oscillator in the Apple ][.
|
||||||
14318181.818181818... Hz rounds to 14318182 Hz
|
14318181.818181818... Hz rounds to 14318182 Hz
|
||||||
U.A.II, p.3-2
|
U.A.II, p.3-2
|
||||||
*/
|
*/
|
||||||
static const int CRYSTAL_HZ = (int)(1.0F*NTSC_FIELD_HZ * NTSC_LINES_PER_FRAME * NTSC_COLOR_MULTIPLE * NTSC_COLOR_DROP_FIELD / (NTSC_COLOR_DROP_FIELD+1));
|
static const int CRYSTAL_HZ = (int)(1.0F*NTSC_FIELD_HZ * NTSC_LINES_PER_FRAME * NTSC_COLOR_MULTIPLE * NTSC_COLOR_DROP_FIELD / (NTSC_COLOR_DROP_FIELD+1));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
U.A.II, p. 3-3
|
U.A.II, p. 3-3
|
||||||
Normal 6502 cycle == 14 crystal periods
|
Normal 6502 cycle == 14 crystal periods
|
||||||
Long 6502 cycle == 16 crystal periods
|
Long 6502 cycle == 16 crystal periods
|
||||||
*/
|
*/
|
||||||
static const int CRYSTAL_CYCLES_PER_CPU_CYCLE = 14;
|
static const int CRYSTAL_CYCLES_PER_CPU_CYCLE = 14;
|
||||||
static const int EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE = 2;
|
static const int EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE = 2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
65 bytes per row (64 normal CPU cycles plus one long CPU cycle)
|
65 bytes per row (64 normal CPU cycles plus one long CPU cycle)
|
||||||
*/
|
*/
|
||||||
static const int BYTES_PER_ROW = (int)((NTSC_COLOR_DROP_FIELD+1)*1.0F*CRYSTAL_HZ/(NTSC_FIELD_HZ/2*NTSC_COLOR_DROP_FIELD*NTSC_LINES_PER_FRAME*CRYSTAL_CYCLES_PER_CPU_CYCLE));
|
static const int BYTES_PER_ROW = (int)((NTSC_COLOR_DROP_FIELD+1)*1.0F*CRYSTAL_HZ/(NTSC_FIELD_HZ/2*NTSC_COLOR_DROP_FIELD*NTSC_LINES_PER_FRAME*CRYSTAL_CYCLES_PER_CPU_CYCLE));
|
||||||
static const int HORIZ_CYCLES = BYTES_PER_ROW;
|
static const int HORIZ_CYCLES = BYTES_PER_ROW;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
U.A.II, p. 3-2, "composite frequency... 1.0205 MHz"
|
U.A.II, p. 3-2, "composite frequency... 1.0205 MHz"
|
||||||
Actually 1020484 Hz.
|
Actually 1020484 Hz.
|
||||||
*/
|
*/
|
||||||
static const int AVG_CPU_HZ = (int)((1.0F*CRYSTAL_HZ*HORIZ_CYCLES)/(CRYSTAL_CYCLES_PER_CPU_CYCLE*HORIZ_CYCLES+EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE));
|
static const int AVG_CPU_HZ = (int)((1.0F*CRYSTAL_HZ*HORIZ_CYCLES)/(CRYSTAL_CYCLES_PER_CPU_CYCLE*HORIZ_CYCLES+EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A normal NTSC field is 262.5 lines (half of a full frame's 525 lines).
|
A normal NTSC field is 262.5 lines (half of a full frame's 525 lines).
|
||||||
The Apple rounds this down to 262 lines.
|
The Apple rounds this down to 262 lines.
|
||||||
*/
|
*/
|
||||||
static const int NTSC_WHOLE_LINES_PER_FIELD = NTSC_LINES_PER_FRAME/2;
|
static const int NTSC_WHOLE_LINES_PER_FIELD = NTSC_LINES_PER_FRAME/2;
|
||||||
|
|
||||||
static const int BYTES_PER_FIELD = BYTES_PER_ROW*NTSC_WHOLE_LINES_PER_FIELD;
|
static const int BYTES_PER_FIELD = BYTES_PER_ROW*NTSC_WHOLE_LINES_PER_FIELD;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// exactly 1 million
|
// exactly 1 million
|
||||||
static const int MEGA = 1000000;
|
static const int MEGA = 1000000;
|
||||||
|
|
||||||
static const int VISIBLE_BITS_PER_BYTE = 7;
|
static const int VISIBLE_BITS_PER_BYTE = 7;
|
||||||
static const int VISIBLE_LINES_PER_CHARACTER = 8;
|
static const int VISIBLE_LINES_PER_CHARACTER = 8;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 1000+1 seconds 2 fields 1 frame 1000000 microseconds 63 50
|
* 1000+1 seconds 2 fields 1 frame 1000000 microseconds 63 50
|
||||||
* total horizontal line period = -------------- * -------- * ------------- * -------------------- = ( -- + -- ) microseconds per line
|
* total horizontal line period = -------------- * -------- * ------------- * -------------------- = ( -- + -- ) microseconds per line
|
||||||
* 60*1000 fields 1 frame 3*5*5*7 lines 1 second 90
|
* 60*1000 fields 1 frame 3*5*5*7 lines 1 second 90
|
||||||
*
|
*
|
||||||
* 10 81
|
* 10 81
|
||||||
* horizontal blanking period = (1.5+4.7+.6+2.5+1.6) = 10.9 microseconds per line = ( -- + -- ) microseconds per line
|
* horizontal blanking period = (1.5+4.7+.6+2.5+1.6) = 10.9 microseconds per line = ( -- + -- ) microseconds per line
|
||||||
* 90
|
* 90
|
||||||
*
|
*
|
||||||
* visible line period = total horizontal line period minus horizontal blanking period =
|
* visible line period = total horizontal line period minus horizontal blanking period =
|
||||||
*
|
*
|
||||||
* 52 59
|
* 52 59
|
||||||
* -- + -- microseconds per line
|
* -- + -- microseconds per line
|
||||||
* 90
|
* 90
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* To avoid the over-scan area, the Apple ][ uses only the middle 75% of the visible line, or 4739/120 microseconds
|
* To avoid the over-scan area, the Apple ][ uses only the middle 75% of the visible line, or 4739/120 microseconds
|
||||||
*
|
*
|
||||||
* Apple ][ uses half the clock rate, or 315/44 MHz, to oscillate the video signal.
|
* Apple ][ uses half the clock rate, or 315/44 MHz, to oscillate the video signal.
|
||||||
*
|
*
|
||||||
* The result is 315/44 MHz * 4739/120 microseconds/line, rounded down, = 282 full pixel spots across the screen.
|
* The result is 315/44 MHz * 4739/120 microseconds/line, rounded down, = 282 full pixel spots across the screen.
|
||||||
* The Apple ][ displays 7 bits per byte hi-res or lo-res, (or 7 pixel-wide characters for text mode), so that
|
* The Apple ][ displays 7 bits per byte hi-res or lo-res, (or 7 pixel-wide characters for text mode), so that
|
||||||
* gives 282/7, which rounds down to 40 bytes per line.
|
* gives 282/7, which rounds down to 40 bytes per line.
|
||||||
*/
|
*/
|
||||||
static const int VISIBLE_BYTES_PER_ROW = (int)((((1.0F*(NTSC_COLOR_DROP_FIELD+1)/(NTSC_FIELD_HZ*NTSC_COLOR_DROP_FIELD)*2/NTSC_LINES_PER_FRAME*MEGA)-(1.5+4.7+.6+2.5+1.6)) * 3/4) * (CRYSTAL_HZ/2)) / MEGA / VISIBLE_BITS_PER_BYTE;
|
static const int VISIBLE_BYTES_PER_ROW = (int)((((1.0F*(NTSC_COLOR_DROP_FIELD+1)/(NTSC_FIELD_HZ*NTSC_COLOR_DROP_FIELD)*2/NTSC_LINES_PER_FRAME*MEGA)-(1.5+4.7+.6+2.5+1.6)) * 3/4) * (CRYSTAL_HZ/2)) / MEGA / VISIBLE_BITS_PER_BYTE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NTSC total lines per frame (525) minus unusable lines (19 plus 20) = 486 usable lines
|
* NTSC total lines per frame (525) minus unusable lines (19 plus 20) = 486 usable lines
|
||||||
* To avoid the over-scan area, use the middle 80% of the vertical lines, giving 388 (rounded down) clearly visible lines
|
* To avoid the over-scan area, use the middle 80% of the vertical lines, giving 388 (rounded down) clearly visible lines
|
||||||
* Apple ][ uses only half the vertical resolution because it doesn't interlace, giving 194.
|
* Apple ][ uses only half the vertical resolution because it doesn't interlace, giving 194.
|
||||||
* Text characters are 8 pixels tall, so 194/8 rounded down gives 24 text lines.
|
* Text characters are 8 pixels tall, so 194/8 rounded down gives 24 text lines.
|
||||||
* Multiply by 8 to give 192 lines total.
|
* Multiply by 8 to give 192 lines total.
|
||||||
*/
|
*/
|
||||||
static const int VISIBLE_ROWS_PER_FIELD = (NTSC_LINES_PER_FRAME-(20+19)) * 8/10 / 2 /VISIBLE_LINES_PER_CHARACTER*VISIBLE_LINES_PER_CHARACTER;
|
static const int VISIBLE_ROWS_PER_FIELD = (NTSC_LINES_PER_FRAME-(20+19)) * 8/10 / 2 /VISIBLE_LINES_PER_CHARACTER*VISIBLE_LINES_PER_CHARACTER;
|
||||||
|
|
||||||
static const int BLANKED_BYTES_PER_ROW = BYTES_PER_ROW-VISIBLE_BYTES_PER_ROW;
|
static const int BLANKED_BYTES_PER_ROW = BYTES_PER_ROW-VISIBLE_BYTES_PER_ROW;
|
||||||
static const int VISIBLE_BYTES_PER_FIELD = BYTES_PER_ROW*VISIBLE_ROWS_PER_FIELD;
|
static const int VISIBLE_BYTES_PER_FIELD = BYTES_PER_ROW*VISIBLE_ROWS_PER_FIELD;
|
||||||
static const int SCANNABLE_ROWS = 0x100;
|
static const int SCANNABLE_ROWS = 0x100;
|
||||||
static const int SCANNABLE_BYTES = SCANNABLE_ROWS*BYTES_PER_ROW;
|
static const int SCANNABLE_BYTES = SCANNABLE_ROWS*BYTES_PER_ROW;
|
||||||
static const int RESET_ROWS = NTSC_WHOLE_LINES_PER_FIELD-SCANNABLE_ROWS;
|
static const int RESET_ROWS = NTSC_WHOLE_LINES_PER_FIELD-SCANNABLE_ROWS;
|
||||||
static const int RESET_BYTES = RESET_ROWS*BYTES_PER_ROW;
|
static const int RESET_BYTES = RESET_ROWS*BYTES_PER_ROW;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const int MIXED_TEXT_LINES = 4;
|
static const int MIXED_TEXT_LINES = 4;
|
||||||
static const int ROWS_PER_TEXT_LINE = 8;
|
static const int ROWS_PER_TEXT_LINE = 8;
|
||||||
static const int MIXED_TEXT_CYCLE = (VISIBLE_ROWS_PER_FIELD-MIXED_TEXT_LINES*ROWS_PER_TEXT_LINE)*BYTES_PER_ROW;
|
static const int MIXED_TEXT_CYCLE = (VISIBLE_ROWS_PER_FIELD-MIXED_TEXT_LINES*ROWS_PER_TEXT_LINE)*BYTES_PER_ROW;
|
||||||
|
|
||||||
|
|
||||||
static int test()
|
static int test()
|
||||||
{
|
{
|
||||||
if (NTSC_FIELD_HZ!=60) return NTSC_FIELD_HZ;
|
if (NTSC_FIELD_HZ!=60) return NTSC_FIELD_HZ;
|
||||||
if (NTSC_LINES_PER_FRAME!=525) return NTSC_LINES_PER_FRAME;
|
if (NTSC_LINES_PER_FRAME!=525) return NTSC_LINES_PER_FRAME;
|
||||||
if (NTSC_COLOR_MULTIPLE!=455) return NTSC_COLOR_MULTIPLE;
|
if (NTSC_COLOR_MULTIPLE!=455) return NTSC_COLOR_MULTIPLE;
|
||||||
if (NTSC_COLOR_DROP_FIELD!=1000) return NTSC_COLOR_DROP_FIELD;
|
if (NTSC_COLOR_DROP_FIELD!=1000) return NTSC_COLOR_DROP_FIELD;
|
||||||
if (CRYSTAL_HZ!=14318182) return CRYSTAL_HZ;
|
if (CRYSTAL_HZ!=14318182) return CRYSTAL_HZ;
|
||||||
if (BYTES_PER_ROW!=65) return BYTES_PER_ROW;
|
if (BYTES_PER_ROW!=65) return BYTES_PER_ROW;
|
||||||
if (AVG_CPU_HZ!=1020484) return AVG_CPU_HZ;
|
if (AVG_CPU_HZ!=1020484) return AVG_CPU_HZ;
|
||||||
if (BYTES_PER_FIELD!=17030) return BYTES_PER_FIELD;
|
if (BYTES_PER_FIELD!=17030) return BYTES_PER_FIELD;
|
||||||
if (VISIBLE_BYTES_PER_ROW!=40) return VISIBLE_BYTES_PER_ROW;
|
if (VISIBLE_BYTES_PER_ROW!=40) return VISIBLE_BYTES_PER_ROW;
|
||||||
if (VISIBLE_ROWS_PER_FIELD!=192) return VISIBLE_ROWS_PER_FIELD;
|
if (VISIBLE_ROWS_PER_FIELD!=192) return VISIBLE_ROWS_PER_FIELD;
|
||||||
if (RESET_BYTES!=390) return RESET_BYTES;
|
if (RESET_BYTES!=390) return RESET_BYTES;
|
||||||
if (BLANKED_BYTES_PER_ROW!=25) return BLANKED_BYTES_PER_ROW;
|
if (BLANKED_BYTES_PER_ROW!=25) return BLANKED_BYTES_PER_ROW;
|
||||||
if (VISIBLE_BYTES_PER_FIELD!=12480) return VISIBLE_BYTES_PER_FIELD;
|
if (VISIBLE_BYTES_PER_FIELD!=12480) return VISIBLE_BYTES_PER_FIELD;
|
||||||
if (SCANNABLE_BYTES!=16640) return SCANNABLE_BYTES;
|
if (SCANNABLE_BYTES!=16640) return SCANNABLE_BYTES;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,14 +23,14 @@
|
||||||
class EmptySlot : public Card
|
class EmptySlot : public Card
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
EmptySlot() {}
|
EmptySlot() {}
|
||||||
virtual ~EmptySlot() {}
|
virtual ~EmptySlot() {}
|
||||||
|
|
||||||
virtual std::string getName() { return "[empty]"; }
|
virtual std::string getName() { return "[empty]"; }
|
||||||
|
|
||||||
// empty slots have no ROMs, so just return data (for floating bus emulation)
|
// empty slots have no ROMs, so just return data (for floating bus emulation)
|
||||||
virtual unsigned char readRom(const unsigned short address, const unsigned char data) { return data; }
|
virtual unsigned char readRom(const unsigned short address, const unsigned char data) { return data; }
|
||||||
virtual void readSeventhRom(const unsigned short address, unsigned char* const pb) { }
|
virtual void readSeventhRom(const unsigned short address, unsigned char* const pb) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -34,48 +34,48 @@ class Config;
|
||||||
|
|
||||||
class Emulator
|
class Emulator
|
||||||
{
|
{
|
||||||
PaddleButtonStates paddleButtonStates;
|
PaddleButtonStates paddleButtonStates;
|
||||||
KeypressQueue keypresses;
|
KeypressQueue keypresses;
|
||||||
|
|
||||||
HyperMode fhyper;
|
HyperMode fhyper;
|
||||||
KeyboardBufferMode buffered;
|
KeyboardBufferMode buffered;
|
||||||
ScreenImage screenImage;
|
ScreenImage screenImage;
|
||||||
AnalogTV display;
|
AnalogTV display;
|
||||||
VideoStaticGenerator videoStatic;
|
VideoStaticGenerator videoStatic;
|
||||||
Apple2 apple2;
|
Apple2 apple2;
|
||||||
ClipboardHandler clip;
|
ClipboardHandler clip;
|
||||||
|
|
||||||
Timable* timable;
|
Timable* timable;
|
||||||
|
|
||||||
bool quit;
|
bool quit;
|
||||||
bool repeat;
|
bool repeat;
|
||||||
int keysDown;
|
int keysDown;
|
||||||
int rept;
|
int rept;
|
||||||
unsigned char lastKeyDown;
|
unsigned char lastKeyDown;
|
||||||
bool command;
|
bool command;
|
||||||
bool pendingCommandExit;
|
bool pendingCommandExit;
|
||||||
std::string cmdline;
|
std::string cmdline;
|
||||||
|
|
||||||
void dispatchKeypress(const SDL_KeyboardEvent& keyEvent);
|
void dispatchKeypress(const SDL_KeyboardEvent& keyEvent);
|
||||||
void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent);
|
void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent);
|
||||||
void cmdKey(const SDL_KeyboardEvent& keyEvent);
|
void cmdKey(const SDL_KeyboardEvent& keyEvent);
|
||||||
void processCommand();
|
void processCommand();
|
||||||
bool isSafeToQuit();
|
bool isSafeToQuit();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Emulator();
|
Emulator();
|
||||||
virtual ~Emulator();
|
virtual ~Emulator();
|
||||||
|
|
||||||
void config(Config& cfg);
|
void config(Config& cfg);
|
||||||
|
|
||||||
virtual void init();
|
virtual void init();
|
||||||
|
|
||||||
void powerOnComputer();
|
void powerOnComputer();
|
||||||
void powerOffComputer();
|
void powerOffComputer();
|
||||||
void toggleComputerPower();
|
void toggleComputerPower();
|
||||||
void cycleDisplayType();
|
void cycleDisplayType();
|
||||||
|
|
||||||
virtual int run();
|
virtual int run();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,12 +19,12 @@
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
|
|
||||||
FirmwareCard::FirmwareCard(ScreenImage& gui, int slot):
|
FirmwareCard::FirmwareCard(ScreenImage& gui, int slot):
|
||||||
gui(gui),
|
gui(gui),
|
||||||
slot(slot),
|
slot(slot),
|
||||||
inhibitBankRom(false),
|
inhibitBankRom(false),
|
||||||
inhibitF8Rom(false),
|
inhibitF8Rom(false),
|
||||||
inhibit(false),
|
inhibit(false),
|
||||||
bankRom(0x10000-0xD000)
|
bankRom(0x10000-0xD000)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,21 +40,21 @@ FirmwareCard::~FirmwareCard()
|
||||||
|
|
||||||
void FirmwareCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool)
|
void FirmwareCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool)
|
||||||
{
|
{
|
||||||
this->inhibit = false;
|
this->inhibit = false;
|
||||||
if (addr < 0x2800)
|
if (addr < 0x2800)
|
||||||
{
|
{
|
||||||
if (this->inhibitBankRom)
|
if (this->inhibitBankRom)
|
||||||
{
|
{
|
||||||
*pb = this->bankRom.read(addr, *pb);
|
*pb = this->bankRom.read(addr, *pb);
|
||||||
this->inhibit = true;
|
this->inhibit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (0x2800 <= addr && addr < 0x3000)
|
else if (0x2800 <= addr && addr < 0x3000)
|
||||||
{
|
{
|
||||||
if (this->inhibitF8Rom)
|
if (this->inhibitF8Rom)
|
||||||
{
|
{
|
||||||
*pb = this->bankRom.read(addr, *pb);
|
*pb = this->bankRom.read(addr, *pb);
|
||||||
this->inhibit = true;
|
this->inhibit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,49 +25,49 @@
|
||||||
class FirmwareCard : public Card
|
class FirmwareCard : public Card
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ScreenImage& gui;
|
ScreenImage& gui;
|
||||||
int slot;
|
int slot;
|
||||||
bool inhibitBankRom;
|
bool inhibitBankRom;
|
||||||
bool inhibitF8Rom;
|
bool inhibitF8Rom;
|
||||||
bool inhibit;
|
bool inhibit;
|
||||||
Memory bankRom;
|
Memory bankRom;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FirmwareCard(ScreenImage& gui, int slot);
|
FirmwareCard(ScreenImage& gui, int slot);
|
||||||
~FirmwareCard();
|
~FirmwareCard();
|
||||||
|
|
||||||
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
||||||
|
|
||||||
virtual void reset()
|
virtual void reset()
|
||||||
{
|
{
|
||||||
this->inhibitBankRom = false;
|
this->inhibitBankRom = false;
|
||||||
this->inhibitF8Rom = false;
|
this->inhibitF8Rom = false;
|
||||||
this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom);
|
this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing)
|
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing)
|
||||||
{
|
{
|
||||||
this->inhibitBankRom = !(address & 1);
|
this->inhibitBankRom = !(address & 1);
|
||||||
this->inhibitF8Rom = (address & 2);
|
this->inhibitF8Rom = (address & 2);
|
||||||
this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom);
|
this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void loadBankRom(const unsigned short base, std::istream& in)
|
virtual void loadBankRom(const unsigned short base, std::istream& in)
|
||||||
{
|
{
|
||||||
this->bankRom.load(base,in);
|
this->bankRom.load(base,in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual bool inhibitMotherboardRom()
|
virtual bool inhibitMotherboardRom()
|
||||||
{
|
{
|
||||||
return this->inhibit;
|
return this->inhibit;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::string getName() { return "firmware "; }
|
virtual std::string getName() { return "firmware "; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
16
src/gui.h
16
src/gui.h
|
@ -23,15 +23,15 @@
|
||||||
class GUI
|
class GUI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GUI();
|
GUI();
|
||||||
~GUI();
|
~GUI();
|
||||||
|
|
||||||
class NotInitException : public std::runtime_error
|
class NotInitException : public std::runtime_error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NotInitException();
|
NotInitException();
|
||||||
virtual ~NotInitException() throw () {}
|
virtual ~NotInitException() throw () {}
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -21,25 +21,25 @@
|
||||||
class HyperMode
|
class HyperMode
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool fhyper;
|
bool fhyper;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HyperMode(): fhyper(false) { }
|
HyperMode(): fhyper(false) { }
|
||||||
~HyperMode() { }
|
~HyperMode() { }
|
||||||
bool isHyper()
|
bool isHyper()
|
||||||
{
|
{
|
||||||
return this->fhyper;
|
return this->fhyper;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHyper(bool isHyper)
|
void setHyper(bool isHyper)
|
||||||
{
|
{
|
||||||
this->fhyper = isHyper;
|
this->fhyper = isHyper;
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggleHyper()
|
void toggleHyper()
|
||||||
{
|
{
|
||||||
this->fhyper = !this->fhyper;
|
this->fhyper = !this->fhyper;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,54 +20,54 @@
|
||||||
#include "keyboardbuffermode.h"
|
#include "keyboardbuffermode.h"
|
||||||
|
|
||||||
Keyboard::Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered):
|
Keyboard::Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered):
|
||||||
keys(q),
|
keys(q),
|
||||||
fhyper(fhyper),
|
fhyper(fhyper),
|
||||||
buffered(buffered),
|
buffered(buffered),
|
||||||
cGet(0)
|
cGet(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Keyboard::clear()
|
void Keyboard::clear()
|
||||||
{
|
{
|
||||||
this->latch &= 0x7F;
|
this->latch &= 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char Keyboard::get()
|
unsigned char Keyboard::get()
|
||||||
{
|
{
|
||||||
waitIfTooFast();
|
waitIfTooFast();
|
||||||
if (!this->buffered.isBuffered() || !(this->latch & 0x80))
|
if (!this->buffered.isBuffered() || !(this->latch & 0x80))
|
||||||
{
|
{
|
||||||
if (!this->keys.empty())
|
if (!this->keys.empty())
|
||||||
{
|
{
|
||||||
this->latch = this->keys.front() | 0x80;
|
this->latch = this->keys.front() | 0x80;
|
||||||
this->keys.pop();
|
this->keys.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this->latch;
|
return this->latch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Keyboard::waitIfTooFast()
|
void Keyboard::waitIfTooFast()
|
||||||
{
|
{
|
||||||
if (this->fhyper.isHyper())
|
if (this->fhyper.isHyper())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
++this->cGet;
|
++this->cGet;
|
||||||
if (!this->cGet)
|
if (!this->cGet)
|
||||||
{
|
{
|
||||||
if (SDL_GetTicks() - this->lastGet <= 1000)
|
if (SDL_GetTicks() - this->lastGet <= 1000)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Check every 256 gets to see if they are
|
* Check every 256 gets to see if they are
|
||||||
* happening too fast (within one second).
|
* happening too fast (within one second).
|
||||||
* If so, it means we are probably just
|
* If so, it means we are probably just
|
||||||
* looping waiting for a keypress, so
|
* looping waiting for a keypress, so
|
||||||
* wait a millisecond (or so) just to
|
* wait a millisecond (or so) just to
|
||||||
* prevent us from using 100% of CPU time.
|
* prevent us from using 100% of CPU time.
|
||||||
*/
|
*/
|
||||||
SDL_Delay(1);
|
SDL_Delay(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->lastGet = SDL_GetTicks();
|
this->lastGet = SDL_GetTicks();
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,20 +29,20 @@ class KeyboardBufferMode;
|
||||||
class Keyboard
|
class Keyboard
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
KeypressQueue& keys;
|
KeypressQueue& keys;
|
||||||
HyperMode& fhyper;
|
HyperMode& fhyper;
|
||||||
KeyboardBufferMode& buffered;
|
KeyboardBufferMode& buffered;
|
||||||
|
|
||||||
unsigned char latch;
|
unsigned char latch;
|
||||||
unsigned char cGet;
|
unsigned char cGet;
|
||||||
Uint32 lastGet;
|
Uint32 lastGet;
|
||||||
|
|
||||||
void waitIfTooFast();
|
void waitIfTooFast();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered);
|
Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered);
|
||||||
void clear();
|
void clear();
|
||||||
unsigned char get();
|
unsigned char get();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,26 +21,26 @@
|
||||||
class KeyboardBufferMode
|
class KeyboardBufferMode
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool buffered;
|
bool buffered;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KeyboardBufferMode(): buffered(true) { }
|
KeyboardBufferMode(): buffered(true) { }
|
||||||
~KeyboardBufferMode() { }
|
~KeyboardBufferMode() { }
|
||||||
|
|
||||||
bool isBuffered()
|
bool isBuffered()
|
||||||
{
|
{
|
||||||
return this->buffered;
|
return this->buffered;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBuffered(bool buffered)
|
void setBuffered(bool buffered)
|
||||||
{
|
{
|
||||||
this->buffered = buffered;
|
this->buffered = buffered;
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggleBuffered()
|
void toggleBuffered()
|
||||||
{
|
{
|
||||||
this->buffered = !this->buffered;
|
this->buffered = !this->buffered;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,17 +19,17 @@
|
||||||
#include "screenimage.h"
|
#include "screenimage.h"
|
||||||
|
|
||||||
LanguageCard::LanguageCard(ScreenImage& gui, int slot):
|
LanguageCard::LanguageCard(ScreenImage& gui, int slot):
|
||||||
gui(gui),
|
gui(gui),
|
||||||
slot(slot),
|
slot(slot),
|
||||||
inhibit(false),
|
inhibit(false),
|
||||||
ramTop(0x10000-0xE000),
|
ramTop(0x10000-0xE000),
|
||||||
bank(1),
|
bank(1),
|
||||||
readEnable(false),
|
readEnable(false),
|
||||||
writeEnable(true),
|
writeEnable(true),
|
||||||
writeCount(0)
|
writeCount(0)
|
||||||
{
|
{
|
||||||
this->ramBank.push_back(new Memory(0xE000-0xD000));
|
this->ramBank.push_back(new Memory(0xE000-0xD000));
|
||||||
this->ramBank.push_back(new Memory(0xE000-0xD000));
|
this->ramBank.push_back(new Memory(0xE000-0xD000));
|
||||||
}
|
}
|
||||||
|
|
||||||
LanguageCard::~LanguageCard()
|
LanguageCard::~LanguageCard()
|
||||||
|
@ -39,57 +39,57 @@ LanguageCard::~LanguageCard()
|
||||||
|
|
||||||
unsigned char LanguageCard::io(const unsigned short address, const unsigned char data, const bool writing)
|
unsigned char LanguageCard::io(const unsigned short address, const unsigned char data, const bool writing)
|
||||||
{
|
{
|
||||||
if ((address & 1) && !writing)
|
if ((address & 1) && !writing)
|
||||||
{
|
{
|
||||||
++this->writeCount;
|
++this->writeCount;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->writeCount = 0;
|
this->writeCount = 0;
|
||||||
}
|
}
|
||||||
if (this->writeCount > 1)
|
if (this->writeCount > 1)
|
||||||
{
|
{
|
||||||
this->writeEnable = true;
|
this->writeEnable = true;
|
||||||
}
|
}
|
||||||
if (!(address & 1))
|
if (!(address & 1))
|
||||||
{
|
{
|
||||||
this->writeEnable = false;
|
this->writeEnable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int r = address & 3;
|
const int r = address & 3;
|
||||||
this->readEnable = (r==0 || r==3);
|
this->readEnable = (r==0 || r==3);
|
||||||
|
|
||||||
this->bank = !(address & 8);
|
this->bank = !(address & 8);
|
||||||
|
|
||||||
this->gui.setLangCard(this->slot,this->readEnable,this->writeEnable,this->bank);
|
this->gui.setLangCard(this->slot,this->readEnable,this->writeEnable,this->bank);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LanguageCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write)
|
void LanguageCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write)
|
||||||
{
|
{
|
||||||
this->inhibit = false;
|
this->inhibit = false;
|
||||||
if (this->readEnable && !write)
|
if (this->readEnable && !write)
|
||||||
{
|
{
|
||||||
if (addr < 0x1000)
|
if (addr < 0x1000)
|
||||||
{
|
{
|
||||||
*pb = this->ramBank[this->bank]->read(addr, *pb);
|
*pb = this->ramBank[this->bank]->read(addr, *pb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*pb = this->ramTop.read(addr-0x1000, *pb);
|
*pb = this->ramTop.read(addr-0x1000, *pb);
|
||||||
}
|
}
|
||||||
this->inhibit = true;
|
this->inhibit = true;
|
||||||
}
|
}
|
||||||
else if (this->writeEnable && write)
|
else if (this->writeEnable && write)
|
||||||
{
|
{
|
||||||
if (addr < 0x1000)
|
if (addr < 0x1000)
|
||||||
{
|
{
|
||||||
this->ramBank[this->bank]->write(addr,*pb);
|
this->ramBank[this->bank]->write(addr,*pb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->ramTop.write(addr-0x1000,*pb);
|
this->ramTop.write(addr-0x1000,*pb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,25 +27,25 @@ class ScreenImage;
|
||||||
class LanguageCard : public Card
|
class LanguageCard : public Card
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ScreenImage& gui;
|
ScreenImage& gui;
|
||||||
int slot;
|
int slot;
|
||||||
bool inhibit;
|
bool inhibit;
|
||||||
std::vector<Memory*> ramBank;
|
std::vector<Memory*> ramBank;
|
||||||
Memory ramTop;
|
Memory ramTop;
|
||||||
unsigned char bank;
|
unsigned char bank;
|
||||||
bool readEnable;
|
bool readEnable;
|
||||||
bool writeEnable;
|
bool writeEnable;
|
||||||
unsigned char writeCount;
|
unsigned char writeCount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LanguageCard(ScreenImage& gui, int slot);
|
LanguageCard(ScreenImage& gui, int slot);
|
||||||
~LanguageCard();
|
~LanguageCard();
|
||||||
|
|
||||||
virtual void reset() { /* does nothing */ }
|
virtual void reset() { /* does nothing */ }
|
||||||
virtual bool inhibitMotherboardRom() { return this->inhibit; }
|
virtual bool inhibitMotherboardRom() { return this->inhibit; }
|
||||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||||
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
|
||||||
virtual std::string getName() { return "language W B2"; }
|
virtual std::string getName() { return "language W B2"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,14 +31,14 @@ PaddleButtonStates::~PaddleButtonStates()
|
||||||
|
|
||||||
bool PaddleButtonStates::isDown(const int paddle)
|
bool PaddleButtonStates::isDown(const int paddle)
|
||||||
{
|
{
|
||||||
if (paddle < 0 || PADDLE_COUNT <= paddle)
|
if (paddle < 0 || PADDLE_COUNT <= paddle)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
unsigned char btn = SDL_GetMouseState(0,0);
|
unsigned char btn = SDL_GetMouseState(0,0);
|
||||||
if (paddle==0)
|
if (paddle==0)
|
||||||
return btn&SDL_BUTTON_LMASK;
|
return btn&SDL_BUTTON_LMASK;
|
||||||
if (paddle==1)
|
if (paddle==1)
|
||||||
return btn&SDL_BUTTON_RMASK;
|
return btn&SDL_BUTTON_RMASK;
|
||||||
return btn&SDL_BUTTON_MMASK;
|
return btn&SDL_BUTTON_MMASK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,12 @@
|
||||||
|
|
||||||
class PaddleButtonStates
|
class PaddleButtonStates
|
||||||
{
|
{
|
||||||
static const int PADDLE_COUNT;
|
static const int PADDLE_COUNT;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PaddleButtonStates();
|
PaddleButtonStates();
|
||||||
~PaddleButtonStates();
|
~PaddleButtonStates();
|
||||||
bool isDown(const int paddle);
|
bool isDown(const int paddle);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
|
|
||||||
Paddles::Paddles():
|
Paddles::Paddles():
|
||||||
rTick(PADDLE_COUNT)
|
rTick(PADDLE_COUNT)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,59 +35,59 @@ Paddles::~Paddles()
|
||||||
|
|
||||||
void Paddles::tick()
|
void Paddles::tick()
|
||||||
{
|
{
|
||||||
for (int paddle = 0; paddle < PADDLE_COUNT; ++paddle)
|
for (int paddle = 0; paddle < PADDLE_COUNT; ++paddle)
|
||||||
{
|
{
|
||||||
if (this->rTick[paddle] > 0)
|
if (this->rTick[paddle] > 0)
|
||||||
--this->rTick[paddle];
|
--this->rTick[paddle];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Paddles::startTimers()
|
void Paddles::startTimers()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
tryStartPaddleTimers();
|
tryStartPaddleTimers();
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
std::cerr << "Warning: cannot start paddle timers; mouse will not function as paddles." << std::endl;
|
std::cerr << "Warning: cannot start paddle timers; mouse will not function as paddles." << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Paddles::tryStartPaddleTimers()
|
void Paddles::tryStartPaddleTimers()
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
SDL_GetMouseState(&x,&y);
|
SDL_GetMouseState(&x,&y);
|
||||||
|
|
||||||
double pMin = 0;
|
double pMin = 0;
|
||||||
double pMax = 500;
|
double pMax = 500;
|
||||||
x = (int)((x-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
|
x = (int)((x-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
|
||||||
y = (int)((y-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
|
y = (int)((y-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
|
||||||
|
|
||||||
if (isTimedOut(0))
|
if (isTimedOut(0))
|
||||||
this->rTick[0] = x;
|
this->rTick[0] = x;
|
||||||
if (isTimedOut(1))
|
if (isTimedOut(1))
|
||||||
this->rTick[1] = y;
|
this->rTick[1] = y;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Here we emulate having 4700 ohm across pins 7 and 1
|
Here we emulate having 4700 ohm across pins 7 and 1
|
||||||
of the game controller, and a 47Kohm resistor acros
|
of the game controller, and a 47Kohm resistor acros
|
||||||
pins 11 and 1, to give cheap real-time clocks at
|
pins 11 and 1, to give cheap real-time clocks at
|
||||||
paddles 2 and 3. Paddle 2 is the 100 microsecond reference,
|
paddles 2 and 3. Paddle 2 is the 100 microsecond reference,
|
||||||
and paddle 3 is the 1 millisecond reference. This is
|
and paddle 3 is the 1 millisecond reference. This is
|
||||||
described in U.A.2, p. 7-33.
|
described in U.A.2, p. 7-33.
|
||||||
*/
|
*/
|
||||||
if (isTimedOut(2))
|
if (isTimedOut(2))
|
||||||
this->rTick[2] = E2Const::AVG_CPU_HZ/10000; // was 90, but why?
|
this->rTick[2] = E2Const::AVG_CPU_HZ/10000; // was 90, but why?
|
||||||
if (isTimedOut(3))
|
if (isTimedOut(3))
|
||||||
this->rTick[3] = E2Const::AVG_CPU_HZ/1000;
|
this->rTick[3] = E2Const::AVG_CPU_HZ/1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Paddles::isTimedOut(const int paddle)
|
bool Paddles::isTimedOut(const int paddle)
|
||||||
{
|
{
|
||||||
if (paddle < 0 || PADDLE_COUNT <= paddle)
|
if (paddle < 0 || PADDLE_COUNT <= paddle)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this->rTick[paddle] <= 0;
|
return this->rTick[paddle] <= 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,19 +23,19 @@
|
||||||
class Paddles
|
class Paddles
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::vector<int> rTick;
|
std::vector<int> rTick;
|
||||||
|
|
||||||
enum { PADDLE_COUNT = 4 };
|
enum { PADDLE_COUNT = 4 };
|
||||||
enum { PADDLE_CYCLES = 2805 }; // TODO: document where PADDLE_CYCLES==2805 came from
|
enum { PADDLE_CYCLES = 2805 }; // TODO: document where PADDLE_CYCLES==2805 came from
|
||||||
|
|
||||||
void tryStartPaddleTimers();
|
void tryStartPaddleTimers();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Paddles();
|
Paddles();
|
||||||
~Paddles();
|
~Paddles();
|
||||||
void tick();
|
void tick();
|
||||||
void startTimers();
|
void startTimers();
|
||||||
bool isTimedOut(const int paddle);
|
bool isTimedOut(const int paddle);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,9 +22,9 @@
|
||||||
#include "e2const.h"
|
#include "e2const.h"
|
||||||
|
|
||||||
PictureGenerator::PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision):
|
PictureGenerator::PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision):
|
||||||
display(display), mode(mode), itestsig(testsig), itestsiglim(testsig+AppleNTSC::SIGNAL_LEN),
|
display(display), mode(mode), itestsig(testsig), itestsiglim(testsig+AppleNTSC::SIGNAL_LEN),
|
||||||
VISIBLE_X_OFFSET(E2Const::BYTES_PER_ROW-E2Const::VISIBLE_BYTES_PER_ROW),
|
VISIBLE_X_OFFSET(E2Const::BYTES_PER_ROW-E2Const::VISIBLE_BYTES_PER_ROW),
|
||||||
revision(revision)
|
revision(revision)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,96 +36,96 @@ PictureGenerator::~PictureGenerator()
|
||||||
|
|
||||||
void PictureGenerator::powerOn()
|
void PictureGenerator::powerOn()
|
||||||
{
|
{
|
||||||
this->hpos = 0;
|
this->hpos = 0;
|
||||||
this->line = 0;
|
this->line = 0;
|
||||||
this->display.signal = this->testsig;
|
this->display.signal = this->testsig;
|
||||||
this->itestsig = this->testsig;
|
this->itestsig = this->testsig;
|
||||||
}
|
}
|
||||||
|
|
||||||
void inline PictureGenerator::shiftLoRes()
|
void inline PictureGenerator::shiftLoRes()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* For byte ABCDEFGH in register, perform
|
* For byte ABCDEFGH in register, perform
|
||||||
* the following 4-bit end-around shifts:
|
* the following 4-bit end-around shifts:
|
||||||
*
|
*
|
||||||
* +---<----+ +---<----+
|
* +---<----+ +---<----+
|
||||||
* | | | |
|
* | | | |
|
||||||
* +->ABCD->+ +->EFGH->+
|
* +->ABCD->+ +->EFGH->+
|
||||||
*
|
*
|
||||||
* Therefore:
|
* Therefore:
|
||||||
*
|
*
|
||||||
* ABCDEFGH --> DABCHEFG
|
* ABCDEFGH --> DABCHEFG
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned char rot_bits = this->latchGraphics & 0x11;
|
unsigned char rot_bits = this->latchGraphics & 0x11;
|
||||||
// 000D000H
|
// 000D000H
|
||||||
rot_bits <<= 3;
|
rot_bits <<= 3;
|
||||||
// D000H000
|
// D000H000
|
||||||
|
|
||||||
this->latchGraphics &= 0xEE;
|
this->latchGraphics &= 0xEE;
|
||||||
// ABC0EFG0
|
// ABC0EFG0
|
||||||
this->latchGraphics >>= 1;
|
this->latchGraphics >>= 1;
|
||||||
// 0ABC0EFG
|
// 0ABC0EFG
|
||||||
this->latchGraphics |= rot_bits;
|
this->latchGraphics |= rot_bits;
|
||||||
// DABCHEFG
|
// DABCHEFG
|
||||||
}
|
}
|
||||||
|
|
||||||
void inline PictureGenerator::shiftHiRes()
|
void inline PictureGenerator::shiftHiRes()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* For byte ABCDEFGH in register, perform
|
* For byte ABCDEFGH in register, perform
|
||||||
* the following shift:
|
* the following shift:
|
||||||
*
|
*
|
||||||
* +---<----+
|
* +---<----+
|
||||||
* | |
|
* | |
|
||||||
* +->ABCD->+--->EFGH->
|
* +->ABCD->+--->EFGH->
|
||||||
*
|
*
|
||||||
* Therefore:
|
* Therefore:
|
||||||
*
|
*
|
||||||
* ABCDEFGH --> DABCDEFG
|
* ABCDEFGH --> DABCDEFG
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned char rot_bits = this->latchGraphics & 0x10;
|
unsigned char rot_bits = this->latchGraphics & 0x10;
|
||||||
// 000D0000
|
// 000D0000
|
||||||
rot_bits <<= 3;
|
rot_bits <<= 3;
|
||||||
// D0000000
|
// D0000000
|
||||||
|
|
||||||
this->latchGraphics >>= 1;
|
this->latchGraphics >>= 1;
|
||||||
// 0ABCDEFG
|
// 0ABCDEFG
|
||||||
this->latchGraphics |= rot_bits;
|
this->latchGraphics |= rot_bits;
|
||||||
// DABCDEFG
|
// DABCDEFG
|
||||||
}
|
}
|
||||||
|
|
||||||
void inline PictureGenerator::shiftText()
|
void inline PictureGenerator::shiftText()
|
||||||
{
|
{
|
||||||
this->latchText >>= 1;
|
this->latchText >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inline PictureGenerator::getTextBit()
|
bool inline PictureGenerator::getTextBit()
|
||||||
{
|
{
|
||||||
return this->latchText & 1;
|
return this->latchText & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inline PictureGenerator::getHiResBit()
|
bool inline PictureGenerator::getHiResBit()
|
||||||
{
|
{
|
||||||
return this->latchGraphics & 1;
|
return this->latchGraphics & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inline PictureGenerator::getLoResBit(const bool odd, const bool vc)
|
bool inline PictureGenerator::getLoResBit(const bool odd, const bool vc)
|
||||||
{
|
{
|
||||||
const int nibble = (this->latchGraphics >> (vc ? 4 : 0)) & 0x0F;
|
const int nibble = (this->latchGraphics >> (vc ? 4 : 0)) & 0x0F;
|
||||||
return (nibble >> (odd ? 2 : 0)) & 1;
|
return (nibble >> (odd ? 2 : 0)) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void inline PictureGenerator::loadGraphics(const unsigned char value)
|
void inline PictureGenerator::loadGraphics(const unsigned char value)
|
||||||
{
|
{
|
||||||
this->latchGraphics = value;
|
this->latchGraphics = value;
|
||||||
this->d7 = this->latchGraphics & 0x80;
|
this->d7 = this->latchGraphics & 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
void inline PictureGenerator::loadText(const int value)
|
void inline PictureGenerator::loadText(const int value)
|
||||||
{
|
{
|
||||||
this->latchText = value;
|
this->latchText = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO can we hand-optimize the main picture generator algorithm any more?
|
// TODO can we hand-optimize the main picture generator algorithm any more?
|
||||||
|
@ -133,154 +133,154 @@ void inline PictureGenerator::loadText(const int value)
|
||||||
// at 14MHz, in order to maintain authentic Apple ][ speed.
|
// at 14MHz, in order to maintain authentic Apple ][ speed.
|
||||||
void PictureGenerator::tick(const int t, const unsigned char rowToPlot)
|
void PictureGenerator::tick(const int t, const unsigned char rowToPlot)
|
||||||
{
|
{
|
||||||
const bool isText(this->mode.isDisplayingText(t));
|
const bool isText(this->mode.isDisplayingText(t));
|
||||||
const bool isHiRes(this->mode.isHiRes());
|
const bool isHiRes(this->mode.isHiRes());
|
||||||
|
|
||||||
signed char* is = this->itestsig;
|
signed char* is = this->itestsig;
|
||||||
|
|
||||||
if (isText)
|
if (isText)
|
||||||
loadText(rowToPlot);
|
loadText(rowToPlot);
|
||||||
else
|
else
|
||||||
loadGraphics(rowToPlot);
|
loadGraphics(rowToPlot);
|
||||||
|
|
||||||
if (t==0)
|
if (t==0)
|
||||||
{
|
{
|
||||||
this->line = 0;
|
this->line = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cycles = E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE;
|
int cycles = E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE;
|
||||||
if (this->hpos == E2Const::HORIZ_CYCLES-1)
|
if (this->hpos == E2Const::HORIZ_CYCLES-1)
|
||||||
{
|
{
|
||||||
cycles += E2Const::EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE;
|
cycles += E2Const::EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// hi-res half-pixel shift:
|
// hi-res half-pixel shift:
|
||||||
const bool shift = !isText && isHiRes && this->d7 && this->line < E2Const::VISIBLE_ROWS_PER_FIELD && !(this->hpos < VISIBLE_X_OFFSET) && this->revision > 0;
|
const bool shift = !isText && isHiRes && this->d7 && this->line < E2Const::VISIBLE_ROWS_PER_FIELD && !(this->hpos < VISIBLE_X_OFFSET) && this->revision > 0;
|
||||||
const bool showLastHiRes = shift && this->lasthires;
|
const bool showLastHiRes = shift && this->lasthires;
|
||||||
|
|
||||||
int xtra(0);
|
int xtra(0);
|
||||||
if (shift)
|
if (shift)
|
||||||
{
|
{
|
||||||
--cycles;
|
--cycles;
|
||||||
++xtra;
|
++xtra;
|
||||||
}
|
}
|
||||||
const int firstBlankedCycle(E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE-xtra);
|
const int firstBlankedCycle(E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE-xtra);
|
||||||
|
|
||||||
int hcycle(this->hpos*E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE);
|
int hcycle(this->hpos*E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE);
|
||||||
const bool lineVis(this->line < E2Const::VISIBLE_ROWS_PER_FIELD);
|
const bool lineVis(this->line < E2Const::VISIBLE_ROWS_PER_FIELD);
|
||||||
const bool hVis(this->hpos >= VISIBLE_X_OFFSET);
|
const bool hVis(this->hpos >= VISIBLE_X_OFFSET);
|
||||||
for (int cycle(0); cycle < cycles-1; ++cycle)
|
for (int cycle(0); cycle < cycles-1; ++cycle)
|
||||||
{
|
{
|
||||||
const bool bit = shiftLatch(t,cycle,isText,isHiRes);
|
const bool bit = shiftLatch(t,cycle,isText,isHiRes);
|
||||||
is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is);
|
is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is);
|
||||||
++hcycle;
|
++hcycle;
|
||||||
}
|
}
|
||||||
// optimization: pull the last iteration of the loop out, so we don't getHiResBit every time
|
// optimization: pull the last iteration of the loop out, so we don't getHiResBit every time
|
||||||
{
|
{
|
||||||
this->lasthires = getHiResBit(); // save it for the next plotted byte, just in case we need it
|
this->lasthires = getHiResBit(); // save it for the next plotted byte, just in case we need it
|
||||||
const int cycle = cycles-1;
|
const int cycle = cycles-1;
|
||||||
const bool bit = shiftLatch(t,cycle,isText,isHiRes);
|
const bool bit = shiftLatch(t,cycle,isText,isHiRes);
|
||||||
is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is);
|
is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->itestsig = is;
|
this->itestsig = is;
|
||||||
|
|
||||||
++this->hpos;
|
++this->hpos;
|
||||||
if (this->hpos >= E2Const::HORIZ_CYCLES)
|
if (this->hpos >= E2Const::HORIZ_CYCLES)
|
||||||
{
|
{
|
||||||
this->hpos = 0;
|
this->hpos = 0;
|
||||||
++this->line;
|
++this->line;
|
||||||
if (this->itestsig >= this->itestsiglim)
|
if (this->itestsig >= this->itestsiglim)
|
||||||
{
|
{
|
||||||
this->itestsig = this->testsig;
|
this->itestsig = this->testsig;
|
||||||
this->display.drawCurrent();
|
this->display.drawCurrent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool inline PictureGenerator::shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes)
|
bool inline PictureGenerator::shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes)
|
||||||
{
|
{
|
||||||
bool bit;
|
bool bit;
|
||||||
if (isText)
|
if (isText)
|
||||||
{
|
{
|
||||||
bit = getTextBit();
|
bit = getTextBit();
|
||||||
if (cycle & 1) // @ 7MHz
|
if (cycle & 1) // @ 7MHz
|
||||||
{
|
{
|
||||||
shiftText();
|
shiftText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isHiRes)
|
else if (isHiRes)
|
||||||
{
|
{
|
||||||
bit = getHiResBit();
|
bit = getHiResBit();
|
||||||
if (cycle & 1) // @ 7MHz
|
if (cycle & 1) // @ 7MHz
|
||||||
{
|
{
|
||||||
shiftHiRes();
|
shiftHiRes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // LO-RES
|
else // LO-RES
|
||||||
{
|
{
|
||||||
const int y = t / E2Const::BYTES_PER_ROW;
|
const int y = t / E2Const::BYTES_PER_ROW;
|
||||||
bit = getLoResBit((t & 1) == (this->line & 1), y & 4);
|
bit = getLoResBit((t & 1) == (this->line & 1), y & 4);
|
||||||
shiftLoRes();
|
shiftLoRes();
|
||||||
}
|
}
|
||||||
return bit;
|
return bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline signed char* PictureGenerator::writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is)
|
inline signed char* PictureGenerator::writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is)
|
||||||
{
|
{
|
||||||
if (shift && !cycle)
|
if (shift && !cycle)
|
||||||
{
|
{
|
||||||
*is++ = showLastHiRes ? AppleNTSC::WHITE_LEVEL : AppleNTSC::BLANK_LEVEL;
|
*is++ = showLastHiRes ? AppleNTSC::WHITE_LEVEL : AppleNTSC::BLANK_LEVEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
signed char sig;
|
signed char sig;
|
||||||
if (lineVis)
|
if (lineVis)
|
||||||
{
|
{
|
||||||
if (hVis)
|
if (hVis)
|
||||||
{
|
{
|
||||||
if (bit && cycle < firstBlankedCycle)
|
if (bit && cycle < firstBlankedCycle)
|
||||||
{
|
{
|
||||||
sig = AppleNTSC::WHITE_LEVEL;
|
sig = AppleNTSC::WHITE_LEVEL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sig = AppleNTSC::BLANK_LEVEL;
|
sig = AppleNTSC::BLANK_LEVEL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sig = hbl(hcycle);
|
sig = hbl(hcycle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sig = vbl(hcycle);
|
sig = vbl(hcycle);
|
||||||
}
|
}
|
||||||
*is++ = sig;
|
*is++ = sig;
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Just to be extremely accurate, fix picture signal values during HBL and VBL
|
// TODO Just to be extremely accurate, fix picture signal values during HBL and VBL
|
||||||
// (note that they vary by motherboard revision... there is a whole section in U.A.2)
|
// (note that they vary by motherboard revision... there is a whole section in U.A.2)
|
||||||
signed char inline PictureGenerator::vbl(const int hcycle)
|
signed char inline PictureGenerator::vbl(const int hcycle)
|
||||||
{
|
{
|
||||||
signed char sig;
|
signed char sig;
|
||||||
if (224 <= this->line && this->line < 240) // VSYNC // TODO symbolize constants
|
if (224 <= this->line && this->line < 240) // VSYNC // TODO symbolize constants
|
||||||
{
|
{
|
||||||
sig = AppleNTSC::SYNC_LEVEL;
|
sig = AppleNTSC::SYNC_LEVEL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START)
|
if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START)
|
||||||
{
|
{
|
||||||
sig = AppleNTSC::SYNC_LEVEL;
|
sig = AppleNTSC::SYNC_LEVEL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sig = AppleNTSC::BLANK_LEVEL;
|
sig = AppleNTSC::BLANK_LEVEL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -299,25 +299,25 @@ const signed char PictureGenerator::lutCB[] =
|
||||||
|
|
||||||
signed char inline PictureGenerator::hbl(const int hcycle)
|
signed char inline PictureGenerator::hbl(const int hcycle)
|
||||||
{
|
{
|
||||||
signed char cb;
|
signed char cb;
|
||||||
if (AppleNTSC::CB_START <= hcycle && hcycle < AppleNTSC::CB_END)
|
if (AppleNTSC::CB_START <= hcycle && hcycle < AppleNTSC::CB_END)
|
||||||
{
|
{
|
||||||
if (this->mode.isText() && this->revision > 0)
|
if (this->mode.isText() && this->revision > 0)
|
||||||
{
|
{
|
||||||
cb = AppleNTSC::BLANK_LEVEL;
|
cb = AppleNTSC::BLANK_LEVEL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cb = lutCB[(hcycle-AppleNTSC::CB_START)%4];
|
cb = lutCB[(hcycle-AppleNTSC::CB_START)%4];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START)
|
else if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START)
|
||||||
{
|
{
|
||||||
cb = AppleNTSC::SYNC_LEVEL;
|
cb = AppleNTSC::SYNC_LEVEL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cb = AppleNTSC::BLANK_LEVEL;
|
cb = AppleNTSC::BLANK_LEVEL;
|
||||||
}
|
}
|
||||||
return cb;
|
return cb;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,45 +24,45 @@ class VideoMode;
|
||||||
class PictureGenerator
|
class PictureGenerator
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
AnalogTV& display;
|
AnalogTV& display;
|
||||||
VideoMode& mode;
|
VideoMode& mode;
|
||||||
|
|
||||||
unsigned char latchGraphics;
|
unsigned char latchGraphics;
|
||||||
bool d7;
|
bool d7;
|
||||||
unsigned char latchText;
|
unsigned char latchText;
|
||||||
unsigned int hpos;
|
unsigned int hpos;
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
bool lasthires;
|
bool lasthires;
|
||||||
static const signed char lutCB[];
|
static const signed char lutCB[];
|
||||||
|
|
||||||
signed char testsig[AppleNTSC::SIGNAL_LEN];
|
signed char testsig[AppleNTSC::SIGNAL_LEN];
|
||||||
signed char* itestsig;
|
signed char* itestsig;
|
||||||
signed char* itestsiglim;
|
signed char* itestsiglim;
|
||||||
|
|
||||||
void shiftLoRes();
|
void shiftLoRes();
|
||||||
void shiftHiRes();
|
void shiftHiRes();
|
||||||
void shiftText();
|
void shiftText();
|
||||||
bool getTextBit();
|
bool getTextBit();
|
||||||
bool getHiResBit();
|
bool getHiResBit();
|
||||||
bool getLoResBit(const bool odd, const bool vc);
|
bool getLoResBit(const bool odd, const bool vc);
|
||||||
void loadGraphics(const unsigned char value);
|
void loadGraphics(const unsigned char value);
|
||||||
void loadText(const int value);
|
void loadText(const int value);
|
||||||
bool shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes);
|
bool shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes);
|
||||||
signed char* writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is);
|
signed char* writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is);
|
||||||
signed char vbl(const int hcycle);
|
signed char vbl(const int hcycle);
|
||||||
signed char hbl(const int hcycle);
|
signed char hbl(const int hcycle);
|
||||||
|
|
||||||
const unsigned int VISIBLE_X_OFFSET;
|
const unsigned int VISIBLE_X_OFFSET;
|
||||||
|
|
||||||
const int& revision;
|
const int& revision;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision);
|
PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision);
|
||||||
~PictureGenerator();
|
~PictureGenerator();
|
||||||
|
|
||||||
void powerOn();
|
void powerOn();
|
||||||
void tick(const int t, const unsigned char c);
|
void tick(const int t, const unsigned char c);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "e2const.h"
|
#include "e2const.h"
|
||||||
|
|
||||||
PowerUpReset::PowerUpReset(Apple2& apple):
|
PowerUpReset::PowerUpReset(Apple2& apple):
|
||||||
apple(apple)
|
apple(apple)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,21 +32,21 @@ PowerUpReset::~PowerUpReset()
|
||||||
|
|
||||||
void PowerUpReset::tick()
|
void PowerUpReset::tick()
|
||||||
{
|
{
|
||||||
if (this->pendingTicks > 0)
|
if (this->pendingTicks > 0)
|
||||||
{
|
{
|
||||||
--this->pendingTicks;
|
--this->pendingTicks;
|
||||||
if (this->pendingTicks == 0)
|
if (this->pendingTicks == 0)
|
||||||
{
|
{
|
||||||
this->apple.reset();
|
this->apple.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PowerUpReset::powerOn()
|
void PowerUpReset::powerOn()
|
||||||
{
|
{
|
||||||
#ifdef USE_EMU
|
#ifdef USE_EMU
|
||||||
this->pendingTicks = 99; // TODO REMOVE THIS
|
this->pendingTicks = 99; // TODO REMOVE THIS
|
||||||
#else
|
#else
|
||||||
this->pendingTicks = (int)(E2Const::AVG_CPU_HZ*.3); // U.A.II, p. 7-15
|
this->pendingTicks = (int)(E2Const::AVG_CPU_HZ*.3); // U.A.II, p. 7-15
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,14 @@ class Apple2;
|
||||||
class PowerUpReset
|
class PowerUpReset
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Apple2& apple;
|
Apple2& apple;
|
||||||
int pendingTicks;
|
int pendingTicks;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PowerUpReset(Apple2& apple);
|
PowerUpReset(Apple2& apple);
|
||||||
~PowerUpReset();
|
~PowerUpReset();
|
||||||
void powerOn();
|
void powerOn();
|
||||||
void tick();
|
void tick();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -20,11 +20,11 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
Slots::Slots(ScreenImage& gui):
|
Slots::Slots(ScreenImage& gui):
|
||||||
gui(gui),
|
gui(gui),
|
||||||
empty(),
|
empty(),
|
||||||
cards(8,&this->empty)
|
cards(8,&this->empty)
|
||||||
{
|
{
|
||||||
forceGuiUpdate();
|
forceGuiUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
Slots::~Slots()
|
Slots::~Slots()
|
||||||
|
@ -33,17 +33,17 @@ Slots::~Slots()
|
||||||
|
|
||||||
unsigned char Slots::io(const int islot, const int iswch, const unsigned char b, const bool writing)
|
unsigned char Slots::io(const int islot, const int iswch, const unsigned char b, const bool writing)
|
||||||
{
|
{
|
||||||
return this->cards[islot]->io(iswch,b,writing);
|
return this->cards[islot]->io(iswch,b,writing);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Slots_Card_reset
|
struct Slots_Card_reset
|
||||||
{
|
{
|
||||||
void operator() (Card* p) { p->reset(); }
|
void operator() (Card* p) { p->reset(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void Slots::reset()
|
void Slots::reset()
|
||||||
{
|
{
|
||||||
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_reset());
|
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_reset());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Slots_Card_tick
|
struct Slots_Card_tick
|
||||||
|
@ -58,79 +58,79 @@ void Slots::tick()
|
||||||
|
|
||||||
unsigned char Slots::readRom(const int islot, const unsigned short addr, const unsigned char data)
|
unsigned char Slots::readRom(const int islot, const unsigned short addr, const unsigned char data)
|
||||||
{
|
{
|
||||||
return this->cards[islot]->readRom(addr,data);
|
return this->cards[islot]->readRom(addr,data);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Slots_Card_readSeventhRom
|
struct Slots_Card_readSeventhRom
|
||||||
{
|
{
|
||||||
const unsigned short addr;
|
const unsigned short addr;
|
||||||
unsigned char* b;
|
unsigned char* b;
|
||||||
Slots_Card_readSeventhRom(const unsigned short addr, unsigned char* b):addr(addr),b(b){}
|
Slots_Card_readSeventhRom(const unsigned short addr, unsigned char* b):addr(addr),b(b){}
|
||||||
void operator() (Card* p) { p->readSeventhRom(this->addr,this->b); }
|
void operator() (Card* p) { p->readSeventhRom(this->addr,this->b); }
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char Slots::readSeventhRom(const unsigned short addr, const unsigned char data)
|
unsigned char Slots::readSeventhRom(const unsigned short addr, const unsigned char data)
|
||||||
{
|
{
|
||||||
unsigned char b(data);
|
unsigned char b(data);
|
||||||
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_readSeventhRom(addr,&b));
|
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_readSeventhRom(addr,&b));
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Slots_Card_ioBankRom
|
struct Slots_Card_ioBankRom
|
||||||
{
|
{
|
||||||
const unsigned short addr;
|
const unsigned short addr;
|
||||||
unsigned char* b;
|
unsigned char* b;
|
||||||
const bool write;
|
const bool write;
|
||||||
Slots_Card_ioBankRom(const unsigned short addr, unsigned char* b, const bool write):addr(addr),b(b),write(write){}
|
Slots_Card_ioBankRom(const unsigned short addr, unsigned char* b, const bool write):addr(addr),b(b),write(write){}
|
||||||
void operator() (Card* p) { p->ioBankRom(this->addr,this->b,this->write); }
|
void operator() (Card* p) { p->ioBankRom(this->addr,this->b,this->write); }
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned char Slots::ioBankRom(const unsigned short addr, const unsigned char data, const bool write)
|
unsigned char Slots::ioBankRom(const unsigned short addr, const unsigned char data, const bool write)
|
||||||
{
|
{
|
||||||
unsigned char b(data);
|
unsigned char b(data);
|
||||||
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_ioBankRom(addr,&b,write));
|
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_ioBankRom(addr,&b,write));
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Slots_Card_inhibitMotherboardRom
|
struct Slots_Card_inhibitMotherboardRom
|
||||||
{
|
{
|
||||||
bool inhibit;
|
bool inhibit;
|
||||||
Slots_Card_inhibitMotherboardRom():inhibit(false) { }
|
Slots_Card_inhibitMotherboardRom():inhibit(false) { }
|
||||||
void operator() (Card* p) { if (p->inhibitMotherboardRom()) { inhibit = true; }}
|
void operator() (Card* p) { if (p->inhibitMotherboardRom()) { inhibit = true; }}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Slots::inhibitMotherboardRom()
|
bool Slots::inhibitMotherboardRom()
|
||||||
{
|
{
|
||||||
return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_inhibitMotherboardRom()).inhibit;
|
return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_inhibitMotherboardRom()).inhibit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Slots::set(const int slot, Card* card)
|
void Slots::set(const int slot, Card* card)
|
||||||
{
|
{
|
||||||
remove(slot);
|
remove(slot);
|
||||||
this->cards[slot] = card;
|
this->cards[slot] = card;
|
||||||
this->gui.updateSlotName(slot,this->cards[slot]);
|
this->gui.updateSlotName(slot,this->cards[slot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Slots::remove(const int slot)
|
void Slots::remove(const int slot)
|
||||||
{
|
{
|
||||||
if (this->cards[slot] != &this->empty)
|
if (this->cards[slot] != &this->empty)
|
||||||
{
|
{
|
||||||
delete this->cards[slot];
|
delete this->cards[slot];
|
||||||
this->cards[slot] = &this->empty;
|
this->cards[slot] = &this->empty;
|
||||||
this->gui.removeCard(slot,this->cards[slot]);
|
this->gui.removeCard(slot,this->cards[slot]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Card* Slots::get(const int slot)
|
Card* Slots::get(const int slot)
|
||||||
{
|
{
|
||||||
return this->cards[slot];
|
return this->cards[slot];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Slots::forceGuiUpdate()
|
void Slots::forceGuiUpdate()
|
||||||
{
|
{
|
||||||
for (int slot(0); slot < 8; ++slot)
|
for (int slot(0); slot < 8; ++slot)
|
||||||
this->gui.updateSlotName(slot,this->cards[slot]);
|
this->gui.updateSlotName(slot,this->cards[slot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Slots::save(int unit) {
|
void Slots::save(int unit) {
|
||||||
|
@ -142,26 +142,26 @@ void Slots::save(int unit) {
|
||||||
/*
|
/*
|
||||||
struct isAnyDiskDriveMotorOnCard
|
struct isAnyDiskDriveMotorOnCard
|
||||||
{
|
{
|
||||||
bool on;
|
bool on;
|
||||||
isAnyDiskDriveMotorOnCard():on(false) {}
|
isAnyDiskDriveMotorOnCard():on(false) {}
|
||||||
void operator() (Card* p) { if (p->isMotorOn()) on = true; }
|
void operator() (Card* p) { if (p->isMotorOn()) on = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isAnyDiskDriveMotorOn()
|
bool isAnyDiskDriveMotorOn()
|
||||||
{
|
{
|
||||||
isAnyDiskDriveMotorOnCard on = isAnyDiskDriveMotorOnCard();
|
isAnyDiskDriveMotorOnCard on = isAnyDiskDriveMotorOnCard();
|
||||||
std::for_each(this->cards.begin(),this->cards.end(),inh);
|
std::for_each(this->cards.begin(),this->cards.end(),inh);
|
||||||
return on.inhibit;
|
return on.inhibit;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
struct Slots_Card_isDirty
|
struct Slots_Card_isDirty
|
||||||
{
|
{
|
||||||
bool dirty;
|
bool dirty;
|
||||||
Slots_Card_isDirty():dirty(false) {}
|
Slots_Card_isDirty():dirty(false) {}
|
||||||
void operator() (Card* p) { if (p->isDirty()) dirty = true; }
|
void operator() (Card* p) { if (p->isDirty()) dirty = true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Slots::isDirty()
|
bool Slots::isDirty()
|
||||||
{
|
{
|
||||||
return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_isDirty()).dirty;
|
return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_isDirty()).dirty;
|
||||||
}
|
}
|
||||||
|
|
30
src/slots.h
30
src/slots.h
|
@ -27,25 +27,25 @@ class ScreenImage;
|
||||||
class Slots
|
class Slots
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ScreenImage& gui;
|
ScreenImage& gui;
|
||||||
EmptySlot empty;
|
EmptySlot empty;
|
||||||
std::vector<Card*> cards;
|
std::vector<Card*> cards;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Slots(ScreenImage& gui);
|
Slots(ScreenImage& gui);
|
||||||
~Slots();
|
~Slots();
|
||||||
|
|
||||||
void tick();
|
void tick();
|
||||||
unsigned char io(const int islot, const int iswch, const unsigned char b, const bool writing);
|
unsigned char io(const int islot, const int iswch, const unsigned char b, const bool writing);
|
||||||
void reset();
|
void reset();
|
||||||
unsigned char readRom(const int islot, const unsigned short addr, const unsigned char data);
|
unsigned char readRom(const int islot, const unsigned short addr, const unsigned char data);
|
||||||
unsigned char readSeventhRom(const unsigned short addr, const unsigned char data);
|
unsigned char readSeventhRom(const unsigned short addr, const unsigned char data);
|
||||||
unsigned char ioBankRom(const unsigned short addr, const unsigned char data, const bool write);
|
unsigned char ioBankRom(const unsigned short addr, const unsigned char data, const bool write);
|
||||||
bool inhibitMotherboardRom();
|
bool inhibitMotherboardRom();
|
||||||
void set(const int slot, Card* card);
|
void set(const int slot, Card* card);
|
||||||
Card* get(const int slot);
|
Card* get(const int slot);
|
||||||
void remove(const int slot);
|
void remove(const int slot);
|
||||||
bool isDirty();
|
bool isDirty();
|
||||||
void save(int unit);
|
void save(int unit);
|
||||||
void forceGuiUpdate();
|
void forceGuiUpdate();
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,22 +29,22 @@ SpeakerClicker::SpeakerClicker():
|
||||||
clicked(false),
|
clicked(false),
|
||||||
t(TICKS_PER_SAMPLE),
|
t(TICKS_PER_SAMPLE),
|
||||||
positive(false) {
|
positive(false) {
|
||||||
SDL_AudioSpec audio;
|
SDL_AudioSpec audio;
|
||||||
audio.freq = E2Const::AVG_CPU_HZ/TICKS_PER_SAMPLE; // samples per second
|
audio.freq = E2Const::AVG_CPU_HZ/TICKS_PER_SAMPLE; // samples per second
|
||||||
audio.format = AUDIO_U8; // 8 bits (1 byte) per sample
|
audio.format = AUDIO_U8; // 8 bits (1 byte) per sample
|
||||||
audio.channels = 1; // mono
|
audio.channels = 1; // mono
|
||||||
audio.silence = 128;
|
audio.silence = 128;
|
||||||
audio.samples = 512;
|
audio.samples = 512;
|
||||||
audio.callback = 0;
|
audio.callback = 0;
|
||||||
audio.userdata = 0;
|
audio.userdata = 0;
|
||||||
|
|
||||||
SDL_AudioSpec obtained;
|
SDL_AudioSpec obtained;
|
||||||
obtained.callback = 0;
|
obtained.callback = 0;
|
||||||
obtained.userdata = 0;
|
obtained.userdata = 0;
|
||||||
|
|
||||||
this->devid = SDL_OpenAudioDevice(0,0,&audio,&obtained,0);
|
this->devid = SDL_OpenAudioDevice(0,0,&audio,&obtained,0);
|
||||||
if (!this->devid) {
|
if (!this->devid) {
|
||||||
std::cerr << "Unable to initialize audio: " << SDL_GetError() << std::endl;
|
std::cerr << "Unable to initialize audio: " << SDL_GetError() << std::endl;
|
||||||
} else {
|
} else {
|
||||||
this->silence = obtained.silence;
|
this->silence = obtained.silence;
|
||||||
|
|
||||||
|
@ -57,27 +57,27 @@ SpeakerClicker::SpeakerClicker():
|
||||||
std::cout << " samples: " << obtained.samples << std::endl;
|
std::cout << " samples: " << obtained.samples << std::endl;
|
||||||
std::cout << " size: " << obtained.size << std::endl;
|
std::cout << " size: " << obtained.size << std::endl;
|
||||||
SDL_PauseAudioDevice(this->devid, 0);
|
SDL_PauseAudioDevice(this->devid, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SpeakerClicker::~SpeakerClicker() {
|
SpeakerClicker::~SpeakerClicker() {
|
||||||
if (!this->devid) {
|
if (!this->devid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SDL_CloseAudioDevice(this->devid);
|
SDL_CloseAudioDevice(this->devid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpeakerClicker::tick() {
|
void SpeakerClicker::tick() {
|
||||||
if (!this->devid) {
|
if (!this->devid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!--this->t) {
|
if (!--this->t) {
|
||||||
std::uint8_t amp;
|
std::uint8_t amp;
|
||||||
if (this->clicked) {
|
if (this->clicked) {
|
||||||
amp = this->positive ? this->silence+100u : this->silence-100u;
|
amp = this->positive ? this->silence+100u : this->silence-100u;
|
||||||
this->positive = !this->positive;
|
this->positive = !this->positive;
|
||||||
this->clicked = false;
|
this->clicked = false;
|
||||||
} else {
|
} else {
|
||||||
amp = silence;
|
amp = silence;
|
||||||
|
@ -91,5 +91,5 @@ void SpeakerClicker::tick() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpeakerClicker::click() {
|
void SpeakerClicker::click() {
|
||||||
this->clicked = true;
|
this->clicked = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,12 +28,12 @@ class SpeakerClicker {
|
||||||
std::uint8_t silence;
|
std::uint8_t silence;
|
||||||
bool clicked;
|
bool clicked;
|
||||||
std::uint8_t t;
|
std::uint8_t t;
|
||||||
bool positive;
|
bool positive;
|
||||||
public:
|
public:
|
||||||
SpeakerClicker();
|
SpeakerClicker();
|
||||||
~SpeakerClicker();
|
~SpeakerClicker();
|
||||||
void tick();
|
void tick();
|
||||||
void click();
|
void click();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
#include "standardin.h"
|
#include "standardin.h"
|
||||||
|
|
||||||
StandardIn::StandardIn():
|
StandardIn::StandardIn():
|
||||||
latch(0),
|
latch(0),
|
||||||
gotEOF(false)
|
gotEOF(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,33 +33,33 @@ StandardIn::~StandardIn()
|
||||||
|
|
||||||
unsigned char StandardIn::io(const unsigned short address, const unsigned char data, const bool writing)
|
unsigned char StandardIn::io(const unsigned short address, const unsigned char data, const bool writing)
|
||||||
{
|
{
|
||||||
int sw = address & 0x0F;
|
int sw = address & 0x0F;
|
||||||
if (sw == 0)
|
if (sw == 0)
|
||||||
{
|
{
|
||||||
if (!(this->latch & 0x80))
|
if (!(this->latch & 0x80))
|
||||||
{
|
{
|
||||||
if (this->gotEOF)
|
if (this->gotEOF)
|
||||||
{
|
{
|
||||||
this->latch = 0xFF;
|
this->latch = 0xFF;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!this->producer.getKeys().empty())
|
if (!this->producer.getKeys().empty())
|
||||||
{
|
{
|
||||||
this->latch = this->producer.getKeys().front();
|
this->latch = this->producer.getKeys().front();
|
||||||
this->producer.getKeys().pop();
|
this->producer.getKeys().pop();
|
||||||
if (this->latch == 0xFF)
|
if (this->latch == 0xFF)
|
||||||
{
|
{
|
||||||
this->gotEOF = true;
|
this->gotEOF = true;
|
||||||
}
|
}
|
||||||
this->latch |= 0x80;
|
this->latch |= 0x80;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sw == 1)
|
else if (sw == 1)
|
||||||
{
|
{
|
||||||
this->latch &= 0x7F;
|
this->latch &= 0x7F;
|
||||||
}
|
}
|
||||||
return this->latch;
|
return this->latch;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,16 +24,16 @@
|
||||||
class StandardIn : public Card
|
class StandardIn : public Card
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
StandardInProducer producer;
|
StandardInProducer producer;
|
||||||
unsigned char latch;
|
unsigned char latch;
|
||||||
bool gotEOF;
|
bool gotEOF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StandardIn();
|
StandardIn();
|
||||||
~StandardIn();
|
~StandardIn();
|
||||||
|
|
||||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||||
virtual std::string getName() { return "standard input"; }
|
virtual std::string getName() { return "standard input"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,71 +28,71 @@ enum state_t { START, GOT_CR, GOT_LF, GOT_EOF };
|
||||||
|
|
||||||
static int readInput(void *voidkeys)
|
static int readInput(void *voidkeys)
|
||||||
{
|
{
|
||||||
KeypressQueue* keys = (KeypressQueue*)voidkeys;
|
KeypressQueue* keys = (KeypressQueue*)voidkeys;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Continuously read characters from standard in
|
* Continuously read characters from standard in
|
||||||
* and put them onto the queue.
|
* and put them onto the queue.
|
||||||
* Stop when we hit EOF (placing EOF onto the queue).
|
* Stop when we hit EOF (placing EOF onto the queue).
|
||||||
* Translate LF to CR.
|
* Translate LF to CR.
|
||||||
* If we hit a CR immediately after a LF, drop it.
|
* If we hit a CR immediately after a LF, drop it.
|
||||||
* If we hit a LF immediately after a CR, drop it.
|
* If we hit a LF immediately after a CR, drop it.
|
||||||
*/
|
*/
|
||||||
enum state_t state = START;
|
enum state_t state = START;
|
||||||
|
|
||||||
while (state != GOT_EOF)
|
while (state != GOT_EOF)
|
||||||
{
|
{
|
||||||
char c = std::cin.get();
|
char c = std::cin.get();
|
||||||
c &= 0x7F;
|
c &= 0x7F;
|
||||||
if (!std::cin.good())
|
if (!std::cin.good())
|
||||||
{
|
{
|
||||||
state = GOT_EOF;
|
state = GOT_EOF;
|
||||||
keys->push(0xFF);
|
keys->push(0xFF);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (state == START)
|
if (state == START)
|
||||||
{
|
{
|
||||||
if (c == CR)
|
if (c == CR)
|
||||||
{
|
{
|
||||||
state = GOT_CR;
|
state = GOT_CR;
|
||||||
}
|
}
|
||||||
else if (c == LF)
|
else if (c == LF)
|
||||||
{
|
{
|
||||||
state = GOT_LF;
|
state = GOT_LF;
|
||||||
c = CR;
|
c = CR;
|
||||||
}
|
}
|
||||||
keys->push(c);
|
keys->push(c);
|
||||||
}
|
}
|
||||||
else if (state == GOT_CR)
|
else if (state == GOT_CR)
|
||||||
{
|
{
|
||||||
if (c != LF)
|
if (c != LF)
|
||||||
{
|
{
|
||||||
keys->push(c);
|
keys->push(c);
|
||||||
}
|
}
|
||||||
state = START;
|
state = START;
|
||||||
}
|
}
|
||||||
else if (state == GOT_LF)
|
else if (state == GOT_LF)
|
||||||
{
|
{
|
||||||
if (c != CR)
|
if (c != CR)
|
||||||
{
|
{
|
||||||
if (c == LF)
|
if (c == LF)
|
||||||
{
|
{
|
||||||
c = CR;
|
c = CR;
|
||||||
}
|
}
|
||||||
keys->push(c);
|
keys->push(c);
|
||||||
}
|
}
|
||||||
state = START;
|
state = START;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
StandardInProducer::StandardInProducer()
|
StandardInProducer::StandardInProducer()
|
||||||
{
|
{
|
||||||
SDL_CreateThread(readInput,"stdin",&this->keys);
|
SDL_CreateThread(readInput,"stdin",&this->keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
StandardInProducer::~StandardInProducer()
|
StandardInProducer::~StandardInProducer()
|
||||||
|
|
|
@ -23,13 +23,13 @@
|
||||||
class StandardInProducer
|
class StandardInProducer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
KeypressQueue keys;
|
KeypressQueue keys;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StandardInProducer();
|
StandardInProducer();
|
||||||
~StandardInProducer();
|
~StandardInProducer();
|
||||||
|
|
||||||
KeypressQueue& getKeys() { return this->keys; }
|
KeypressQueue& getKeys() { return this->keys; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,21 +30,21 @@ StandardOut::~StandardOut()
|
||||||
|
|
||||||
unsigned char StandardOut::io(const unsigned short address, const unsigned char data, const bool writing)
|
unsigned char StandardOut::io(const unsigned short address, const unsigned char data, const bool writing)
|
||||||
{
|
{
|
||||||
if (!writing)
|
if (!writing)
|
||||||
{
|
{
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char c = (char)(data&0x7F);
|
const char c = (char)(data&0x7F);
|
||||||
if (c == '\r')
|
if (c == '\r')
|
||||||
{
|
{
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::cout << c;
|
std::cout << c;
|
||||||
}
|
}
|
||||||
std::cout << std::flush;
|
std::cout << std::flush;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,11 @@ class StandardOut : public Card
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StandardOut();
|
StandardOut();
|
||||||
~StandardOut();
|
~StandardOut();
|
||||||
|
|
||||||
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
|
||||||
virtual std::string getName() { return "standard output"; }
|
virtual std::string getName() { return "standard output"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,28 +18,28 @@
|
||||||
#include "textcharacters.h"
|
#include "textcharacters.h"
|
||||||
|
|
||||||
TextCharacters::TextCharacters():
|
TextCharacters::TextCharacters():
|
||||||
rows(0x40*8)
|
rows(0x40*8)
|
||||||
{
|
{
|
||||||
int r(0);
|
int r(0);
|
||||||
|
|
||||||
const char *pi =
|
const char *pi =
|
||||||
#include "textcharacterimages.h"
|
#include "textcharacterimages.h"
|
||||||
;
|
;
|
||||||
|
|
||||||
for (int ch(0); ch < 0x40; ++ch)
|
for (int ch(0); ch < 0x40; ++ch)
|
||||||
{
|
{
|
||||||
|
|
||||||
rows[r] = 0;
|
rows[r] = 0;
|
||||||
++r;
|
++r;
|
||||||
for (int ln(1); ln < 8; ++ln)
|
for (int ln(1); ln < 8; ++ln)
|
||||||
{
|
{
|
||||||
for (int bt(0); bt < 5; ++bt)
|
for (int bt(0); bt < 5; ++bt)
|
||||||
{
|
{
|
||||||
rows[r] >>= 1;
|
rows[r] >>= 1;
|
||||||
if (*pi++=='@')
|
if (*pi++=='@')
|
||||||
rows[r] |= 0x20;
|
rows[r] |= 0x20;
|
||||||
}
|
}
|
||||||
++r;
|
++r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,15 +23,15 @@
|
||||||
class TextCharacters
|
class TextCharacters
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::vector<unsigned char> rows;
|
std::vector<unsigned char> rows;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TextCharacters();
|
TextCharacters();
|
||||||
~TextCharacters() {}
|
~TextCharacters() {}
|
||||||
unsigned char get(unsigned int iRow)
|
unsigned char get(unsigned int iRow)
|
||||||
{
|
{
|
||||||
return this->rows[iRow];
|
return this->rows[iRow];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
class Timable
|
class Timable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Timable() {}
|
Timable() {}
|
||||||
virtual ~Timable() {}
|
virtual ~Timable() {}
|
||||||
|
|
||||||
virtual void tick() = 0;
|
virtual void tick() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -51,7 +51,7 @@ misrepresented as being the original software.
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
/* if tinydialogs.c is compiled as C++ code rather than C code, you may need to comment this out
|
/* if tinydialogs.c is compiled as C++ code rather than C code, you may need to comment this out
|
||||||
and the corresponding closing bracket near the end of this file. */
|
and the corresponding closing bracket near the end of this file. */
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ int tinyfd_getGlobalInt(char const * aIntVariableName); /* returns -1 on error *
|
||||||
int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue); /* returns -1 on error */
|
int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue); /* returns -1 on error */
|
||||||
/* aCharVariableName: "tinyfd_version" "tinyfd_needs" "tinyfd_response"
|
/* aCharVariableName: "tinyfd_version" "tinyfd_needs" "tinyfd_response"
|
||||||
aIntVariableName : "tinyfd_verbose" "tinyfd_silent" "tinyfd_allowCursesDialogs"
|
aIntVariableName : "tinyfd_verbose" "tinyfd_silent" "tinyfd_allowCursesDialogs"
|
||||||
"tinyfd_forceConsole" "tinyfd_assumeGraphicDisplay" "tinyfd_winUtf8"
|
"tinyfd_forceConsole" "tinyfd_assumeGraphicDisplay" "tinyfd_winUtf8"
|
||||||
**************/
|
**************/
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,58 +121,58 @@ for console mode:
|
||||||
void tinyfd_beep(void);
|
void tinyfd_beep(void);
|
||||||
|
|
||||||
int tinyfd_notifyPopup(
|
int tinyfd_notifyPopup(
|
||||||
char const * aTitle, /* NULL or "" */
|
char const * aTitle, /* NULL or "" */
|
||||||
char const * aMessage, /* NULL or "" may contain \n \t */
|
char const * aMessage, /* NULL or "" may contain \n \t */
|
||||||
char const * aIconType); /* "info" "warning" "error" */
|
char const * aIconType); /* "info" "warning" "error" */
|
||||||
/* return has only meaning for tinyfd_query */
|
/* return has only meaning for tinyfd_query */
|
||||||
|
|
||||||
int tinyfd_messageBox(
|
int tinyfd_messageBox(
|
||||||
char const * aTitle , /* NULL or "" */
|
char const * aTitle , /* NULL or "" */
|
||||||
char const * aMessage , /* NULL or "" may contain \n \t */
|
char const * aMessage , /* NULL or "" may contain \n \t */
|
||||||
char const * aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */
|
char const * aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */
|
||||||
char const * aIconType , /* "info" "warning" "error" "question" */
|
char const * aIconType , /* "info" "warning" "error" "question" */
|
||||||
int aDefaultButton ) ;
|
int aDefaultButton ) ;
|
||||||
/* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */
|
/* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */
|
||||||
|
|
||||||
char * tinyfd_inputBox(
|
char * tinyfd_inputBox(
|
||||||
char const * aTitle , /* NULL or "" */
|
char const * aTitle , /* NULL or "" */
|
||||||
char const * aMessage , /* NULL or "" (\n and \t have no effect) */
|
char const * aMessage , /* NULL or "" (\n and \t have no effect) */
|
||||||
char const * aDefaultInput ) ; /* NULL passwordBox, "" inputbox */
|
char const * aDefaultInput ) ; /* NULL passwordBox, "" inputbox */
|
||||||
/* returns NULL on cancel */
|
/* returns NULL on cancel */
|
||||||
|
|
||||||
char * tinyfd_saveFileDialog(
|
char * tinyfd_saveFileDialog(
|
||||||
char const * aTitle , /* NULL or "" */
|
char const * aTitle , /* NULL or "" */
|
||||||
char const * aDefaultPathAndFile , /* NULL or "" */
|
char const * aDefaultPathAndFile , /* NULL or "" */
|
||||||
int aNumOfFilterPatterns , /* 0 (1 in the following example) */
|
int aNumOfFilterPatterns , /* 0 (1 in the following example) */
|
||||||
char const * const * aFilterPatterns , /* NULL or char const * lFilterPatterns[1]={"*.txt"} */
|
char const * const * aFilterPatterns , /* NULL or char const * lFilterPatterns[1]={"*.txt"} */
|
||||||
char const * aSingleFilterDescription ) ; /* NULL or "text files" */
|
char const * aSingleFilterDescription ) ; /* NULL or "text files" */
|
||||||
/* returns NULL on cancel */
|
/* returns NULL on cancel */
|
||||||
|
|
||||||
char * tinyfd_openFileDialog(
|
char * tinyfd_openFileDialog(
|
||||||
char const * aTitle, /* NULL or "" */
|
char const * aTitle, /* NULL or "" */
|
||||||
char const * aDefaultPathAndFile, /* NULL or "" */
|
char const * aDefaultPathAndFile, /* NULL or "" */
|
||||||
int aNumOfFilterPatterns , /* 0 (2 in the following example) */
|
int aNumOfFilterPatterns , /* 0 (2 in the following example) */
|
||||||
char const * const * aFilterPatterns, /* NULL or char const * lFilterPatterns[2]={"*.png","*.jpg"}; */
|
char const * const * aFilterPatterns, /* NULL or char const * lFilterPatterns[2]={"*.png","*.jpg"}; */
|
||||||
char const * aSingleFilterDescription, /* NULL or "image files" */
|
char const * aSingleFilterDescription, /* NULL or "image files" */
|
||||||
int aAllowMultipleSelects ) ; /* 0 or 1 */
|
int aAllowMultipleSelects ) ; /* 0 or 1 */
|
||||||
/* in case of multiple files, the separator is | */
|
/* in case of multiple files, the separator is | */
|
||||||
/* returns NULL on cancel */
|
/* returns NULL on cancel */
|
||||||
|
|
||||||
char * tinyfd_selectFolderDialog(
|
char * tinyfd_selectFolderDialog(
|
||||||
char const * aTitle, /* NULL or "" */
|
char const * aTitle, /* NULL or "" */
|
||||||
char const * aDefaultPath); /* NULL or "" */
|
char const * aDefaultPath); /* NULL or "" */
|
||||||
/* returns NULL on cancel */
|
/* returns NULL on cancel */
|
||||||
|
|
||||||
char * tinyfd_colorChooser(
|
char * tinyfd_colorChooser(
|
||||||
char const * aTitle, /* NULL or "" */
|
char const * aTitle, /* NULL or "" */
|
||||||
char const * aDefaultHexRGB, /* NULL or "#FF0000" */
|
char const * aDefaultHexRGB, /* NULL or "#FF0000" */
|
||||||
unsigned char const aDefaultRGB[3] , /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
|
unsigned char const aDefaultRGB[3] , /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
|
||||||
unsigned char aoResultRGB[3] ) ; /* unsigned char lResultRGB[3]; */
|
unsigned char aoResultRGB[3] ) ; /* unsigned char lResultRGB[3]; */
|
||||||
/* returns the hexcolor as a string "#FF0000" */
|
/* returns the hexcolor as a string "#FF0000" */
|
||||||
/* aoResultRGB also contains the result */
|
/* aoResultRGB also contains the result */
|
||||||
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */
|
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */
|
||||||
/* aDefaultRGB and aoResultRGB can be the same array */
|
/* aDefaultRGB and aoResultRGB can be the same array */
|
||||||
/* returns NULL on cancel */
|
/* returns NULL on cancel */
|
||||||
|
|
||||||
|
|
||||||
/************ WINDOWS ONLY SECTION ************************/
|
/************ WINDOWS ONLY SECTION ************************/
|
||||||
|
@ -180,62 +180,62 @@ char * tinyfd_colorChooser(
|
||||||
|
|
||||||
/* windows only - utf-16 version */
|
/* windows only - utf-16 version */
|
||||||
int tinyfd_notifyPopupW(
|
int tinyfd_notifyPopupW(
|
||||||
wchar_t const * aTitle, /* NULL or L"" */
|
wchar_t const * aTitle, /* NULL or L"" */
|
||||||
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
|
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
|
||||||
wchar_t const * aIconType); /* L"info" L"warning" L"error" */
|
wchar_t const * aIconType); /* L"info" L"warning" L"error" */
|
||||||
|
|
||||||
/* windows only - utf-16 version */
|
/* windows only - utf-16 version */
|
||||||
int tinyfd_messageBoxW(
|
int tinyfd_messageBoxW(
|
||||||
wchar_t const * aTitle, /* NULL or L"" */
|
wchar_t const * aTitle, /* NULL or L"" */
|
||||||
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
|
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
|
||||||
wchar_t const * aDialogType, /* L"ok" L"okcancel" L"yesno" */
|
wchar_t const * aDialogType, /* L"ok" L"okcancel" L"yesno" */
|
||||||
wchar_t const * aIconType, /* L"info" L"warning" L"error" L"question" */
|
wchar_t const * aIconType, /* L"info" L"warning" L"error" L"question" */
|
||||||
int aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */
|
int aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */
|
||||||
/* returns 0 for cancel/no , 1 for ok/yes */
|
/* returns 0 for cancel/no , 1 for ok/yes */
|
||||||
|
|
||||||
/* windows only - utf-16 version */
|
/* windows only - utf-16 version */
|
||||||
wchar_t * tinyfd_inputBoxW(
|
wchar_t * tinyfd_inputBoxW(
|
||||||
wchar_t const * aTitle, /* NULL or L"" */
|
wchar_t const * aTitle, /* NULL or L"" */
|
||||||
wchar_t const * aMessage, /* NULL or L"" (\n nor \t not respected) */
|
wchar_t const * aMessage, /* NULL or L"" (\n nor \t not respected) */
|
||||||
wchar_t const * aDefaultInput); /* NULL passwordBox, L"" inputbox */
|
wchar_t const * aDefaultInput); /* NULL passwordBox, L"" inputbox */
|
||||||
|
|
||||||
/* windows only - utf-16 version */
|
/* windows only - utf-16 version */
|
||||||
wchar_t * tinyfd_saveFileDialogW(
|
wchar_t * tinyfd_saveFileDialogW(
|
||||||
wchar_t const * aTitle, /* NULL or L"" */
|
wchar_t const * aTitle, /* NULL or L"" */
|
||||||
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
|
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
|
||||||
int aNumOfFilterPatterns, /* 0 (1 in the following example) */
|
int aNumOfFilterPatterns, /* 0 (1 in the following example) */
|
||||||
wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[1]={L"*.txt"} */
|
wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[1]={L"*.txt"} */
|
||||||
wchar_t const * aSingleFilterDescription); /* NULL or L"text files" */
|
wchar_t const * aSingleFilterDescription); /* NULL or L"text files" */
|
||||||
/* returns NULL on cancel */
|
/* returns NULL on cancel */
|
||||||
|
|
||||||
/* windows only - utf-16 version */
|
/* windows only - utf-16 version */
|
||||||
wchar_t * tinyfd_openFileDialogW(
|
wchar_t * tinyfd_openFileDialogW(
|
||||||
wchar_t const * aTitle, /* NULL or L"" */
|
wchar_t const * aTitle, /* NULL or L"" */
|
||||||
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
|
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
|
||||||
int aNumOfFilterPatterns , /* 0 (2 in the following example) */
|
int aNumOfFilterPatterns , /* 0 (2 in the following example) */
|
||||||
wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[2]={L"*.png","*.jpg"} */
|
wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[2]={L"*.png","*.jpg"} */
|
||||||
wchar_t const * aSingleFilterDescription, /* NULL or L"image files" */
|
wchar_t const * aSingleFilterDescription, /* NULL or L"image files" */
|
||||||
int aAllowMultipleSelects ) ; /* 0 or 1 */
|
int aAllowMultipleSelects ) ; /* 0 or 1 */
|
||||||
/* in case of multiple files, the separator is | */
|
/* in case of multiple files, the separator is | */
|
||||||
/* returns NULL on cancel */
|
/* returns NULL on cancel */
|
||||||
|
|
||||||
/* windows only - utf-16 version */
|
/* windows only - utf-16 version */
|
||||||
wchar_t * tinyfd_selectFolderDialogW(
|
wchar_t * tinyfd_selectFolderDialogW(
|
||||||
wchar_t const * aTitle, /* NULL or L"" */
|
wchar_t const * aTitle, /* NULL or L"" */
|
||||||
wchar_t const * aDefaultPath); /* NULL or L"" */
|
wchar_t const * aDefaultPath); /* NULL or L"" */
|
||||||
/* returns NULL on cancel */
|
/* returns NULL on cancel */
|
||||||
|
|
||||||
/* windows only - utf-16 version */
|
/* windows only - utf-16 version */
|
||||||
wchar_t * tinyfd_colorChooserW(
|
wchar_t * tinyfd_colorChooserW(
|
||||||
wchar_t const * aTitle, /* NULL or L"" */
|
wchar_t const * aTitle, /* NULL or L"" */
|
||||||
wchar_t const * aDefaultHexRGB, /* NULL or L"#FF0000" */
|
wchar_t const * aDefaultHexRGB, /* NULL or L"#FF0000" */
|
||||||
unsigned char const aDefaultRGB[3], /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
|
unsigned char const aDefaultRGB[3], /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
|
||||||
unsigned char aoResultRGB[3]); /* unsigned char lResultRGB[3]; */
|
unsigned char aoResultRGB[3]); /* unsigned char lResultRGB[3]; */
|
||||||
/* returns the hexcolor as a string L"#FF0000" */
|
/* returns the hexcolor as a string L"#FF0000" */
|
||||||
/* aoResultRGB also contains the result */
|
/* aoResultRGB also contains the result */
|
||||||
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */
|
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */
|
||||||
/* aDefaultRGB and aoResultRGB can be the same array */
|
/* aDefaultRGB and aoResultRGB can be the same array */
|
||||||
/* returns NULL on cancel */
|
/* returns NULL on cancel */
|
||||||
|
|
||||||
#endif /*_WIN32 */
|
#endif /*_WIN32 */
|
||||||
|
|
||||||
|
|
68
src/util.h
68
src/util.h
|
@ -21,44 +21,44 @@
|
||||||
class Util
|
class Util
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static int divideRoundUp(const int num, const int denom)
|
static int divideRoundUp(const int num, const int denom)
|
||||||
{
|
{
|
||||||
return (num+denom-1)/denom;
|
return (num+denom-1)/denom;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int divideRound(const int dividend, const int divisor)
|
static int divideRound(const int dividend, const int divisor)
|
||||||
{
|
{
|
||||||
return (dividend+divisor/2)/divisor;
|
return (dividend+divisor/2)/divisor;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> static T mod(T x, const T m)
|
template<typename T> static T mod(T x, const T m)
|
||||||
{
|
{
|
||||||
x %= m;
|
x %= m;
|
||||||
if (x < 0)
|
if (x < 0)
|
||||||
{
|
{
|
||||||
x += m;
|
x += m;
|
||||||
}
|
}
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> static void constrain(const T& min, T& x, const T& lim)
|
template<typename T> static void constrain(const T& min, T& x, const T& lim)
|
||||||
{
|
{
|
||||||
if (x < min)
|
if (x < min)
|
||||||
{
|
{
|
||||||
x = min;
|
x = min;
|
||||||
}
|
}
|
||||||
else if (lim <= x)
|
else if (lim <= x)
|
||||||
{
|
{
|
||||||
x = lim-1;
|
x = lim-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0x0 <= nib <= 0xF
|
// 0x0 <= nib <= 0xF
|
||||||
// '0' <= ret <= 'F'
|
// '0' <= ret <= 'F'
|
||||||
static char hexDigit(unsigned char nib)
|
static char hexDigit(unsigned char nib)
|
||||||
{
|
{
|
||||||
return nib < 10 ? '0'+nib : 'A'+nib-10;
|
return nib < 10 ? '0'+nib : 'A'+nib-10;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
114
src/video.cpp
114
src/video.cpp
|
@ -28,12 +28,12 @@ static const int FLASH_HALF_PERIOD = E2Const::AVG_CPU_HZ/4; // 2 Hz period = 4 H
|
||||||
|
|
||||||
|
|
||||||
Video::Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows):
|
Video::Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows):
|
||||||
mode(mode), addressBus(addressBus), picgen(picgen), textRows(textRows)
|
mode(mode), addressBus(addressBus), picgen(picgen), textRows(textRows)
|
||||||
{
|
{
|
||||||
VideoAddressing::buildLUT(TEXT_BASE_1,TEXT_LEN,lutTEXT[0]);
|
VideoAddressing::buildLUT(TEXT_BASE_1,TEXT_LEN,lutTEXT[0]);
|
||||||
VideoAddressing::buildLUT(TEXT_BASE_2,TEXT_LEN,lutTEXT[1]);
|
VideoAddressing::buildLUT(TEXT_BASE_2,TEXT_LEN,lutTEXT[1]);
|
||||||
VideoAddressing::buildLUT(HRES_BASE_1,HRES_LEN,lutHRES[0]);
|
VideoAddressing::buildLUT(HRES_BASE_1,HRES_LEN,lutHRES[0]);
|
||||||
VideoAddressing::buildLUT(HRES_BASE_2,HRES_LEN,lutHRES[1]);
|
VideoAddressing::buildLUT(HRES_BASE_2,HRES_LEN,lutHRES[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Video::~Video()
|
Video::~Video()
|
||||||
|
@ -42,84 +42,84 @@ Video::~Video()
|
||||||
|
|
||||||
void Video::powerOn()
|
void Video::powerOn()
|
||||||
{
|
{
|
||||||
this->t = 0;
|
this->t = 0;
|
||||||
this->flash = false;
|
this->flash = false;
|
||||||
this->cflash = 0;
|
this->cflash = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video::tick()
|
void Video::tick()
|
||||||
{
|
{
|
||||||
const unsigned char data = getDataByte();
|
const unsigned char data = getDataByte();
|
||||||
const unsigned char rowToPlot = getRowToPlot(data);
|
const unsigned char rowToPlot = getRowToPlot(data);
|
||||||
|
|
||||||
this->picgen.tick(this->t,rowToPlot);
|
this->picgen.tick(this->t,rowToPlot);
|
||||||
|
|
||||||
updateFlash();
|
updateFlash();
|
||||||
|
|
||||||
++this->t;
|
++this->t;
|
||||||
|
|
||||||
if (this->t >= E2Const::BYTES_PER_FIELD)
|
if (this->t >= E2Const::BYTES_PER_FIELD)
|
||||||
{
|
{
|
||||||
this->t = 0;
|
this->t = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Video::updateFlash()
|
void Video::updateFlash()
|
||||||
{
|
{
|
||||||
++this->cflash;
|
++this->cflash;
|
||||||
if (this->cflash >= FLASH_HALF_PERIOD)
|
if (this->cflash >= FLASH_HALF_PERIOD)
|
||||||
{
|
{
|
||||||
this->flash = !this->flash;
|
this->flash = !this->flash;
|
||||||
this->cflash = 0;
|
this->cflash = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char Video::getDataByte()
|
unsigned char Video::getDataByte()
|
||||||
{
|
{
|
||||||
// TODO should fix the mixed-mode scanning during VBL (see U.A.][, p. 5-13)
|
// TODO should fix the mixed-mode scanning during VBL (see U.A.][, p. 5-13)
|
||||||
|
|
||||||
std::vector<unsigned short>& lut =
|
std::vector<unsigned short>& lut =
|
||||||
(this->mode.isDisplayingText(this->t) || !this->mode.isHiRes())
|
(this->mode.isDisplayingText(this->t) || !this->mode.isHiRes())
|
||||||
?
|
?
|
||||||
this->lutTEXT[this->mode.getPage()]
|
this->lutTEXT[this->mode.getPage()]
|
||||||
:
|
:
|
||||||
this->lutHRES[this->mode.getPage()];
|
this->lutHRES[this->mode.getPage()];
|
||||||
|
|
||||||
return this->addressBus.read(lut[this->t]);
|
return this->addressBus.read(lut[this->t]);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char Video::getRowToPlot(unsigned char d)
|
unsigned char Video::getRowToPlot(unsigned char d)
|
||||||
{
|
{
|
||||||
if (this->mode.isDisplayingText(this->t))
|
if (this->mode.isDisplayingText(this->t))
|
||||||
{
|
{
|
||||||
const bool inverse = inverseChar(d);
|
const bool inverse = inverseChar(d);
|
||||||
const int y = this->t / E2Const::BYTES_PER_ROW;
|
const int y = this->t / E2Const::BYTES_PER_ROW;
|
||||||
d = this->textRows.get(((d & 0x3F) << 3) | (y & 0x07));
|
d = this->textRows.get(((d & 0x3F) << 3) | (y & 0x07));
|
||||||
if (inverse)
|
if (inverse)
|
||||||
{
|
{
|
||||||
d = ~d & 0x7F;
|
d = ~d & 0x7F;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Video::inverseChar(const unsigned char d)
|
bool Video::inverseChar(const unsigned char d)
|
||||||
{
|
{
|
||||||
bool inverse;
|
bool inverse;
|
||||||
|
|
||||||
const int cs = (d >> 6) & 3;
|
const int cs = (d >> 6) & 3;
|
||||||
if (cs == 0)
|
if (cs == 0)
|
||||||
{
|
{
|
||||||
inverse = true;
|
inverse = true;
|
||||||
}
|
}
|
||||||
else if (cs == 1)
|
else if (cs == 1)
|
||||||
{
|
{
|
||||||
inverse = this->flash;
|
inverse = this->flash;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
inverse = false;
|
inverse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return inverse;
|
return inverse;
|
||||||
}
|
}
|
||||||
|
|
50
src/video.h
50
src/video.h
|
@ -28,38 +28,38 @@ class TextCharacters;
|
||||||
class Video
|
class Video
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
enum { TEXT_BASE_1 = 0x0400 };
|
enum { TEXT_BASE_1 = 0x0400 };
|
||||||
enum { TEXT_BASE_2 = 0x0800 };
|
enum { TEXT_BASE_2 = 0x0800 };
|
||||||
enum { TEXT_LEN = 0x0400 };
|
enum { TEXT_LEN = 0x0400 };
|
||||||
|
|
||||||
enum { HRES_BASE_1 = 0x2000 };
|
enum { HRES_BASE_1 = 0x2000 };
|
||||||
enum { HRES_BASE_2 = 0x4000 };
|
enum { HRES_BASE_2 = 0x4000 };
|
||||||
enum { HRES_LEN = 0x2000 };
|
enum { HRES_LEN = 0x2000 };
|
||||||
|
|
||||||
std::vector<unsigned short> lutTEXT[2]; // [0] is page 1, [1] is page 2
|
std::vector<unsigned short> lutTEXT[2]; // [0] is page 1, [1] is page 2
|
||||||
std::vector<unsigned short> lutHRES[2]; // [0] is page 1, [1] is page 2
|
std::vector<unsigned short> lutHRES[2]; // [0] is page 1, [1] is page 2
|
||||||
|
|
||||||
VideoMode& mode;
|
VideoMode& mode;
|
||||||
AddressBus& addressBus;
|
AddressBus& addressBus;
|
||||||
PictureGenerator& picgen;
|
PictureGenerator& picgen;
|
||||||
|
|
||||||
TextCharacters& textRows;
|
TextCharacters& textRows;
|
||||||
|
|
||||||
unsigned int t;
|
unsigned int t;
|
||||||
|
|
||||||
bool flash;
|
bool flash;
|
||||||
int cflash;
|
int cflash;
|
||||||
|
|
||||||
void updateFlash();
|
void updateFlash();
|
||||||
unsigned char getDataByte();
|
unsigned char getDataByte();
|
||||||
unsigned char getRowToPlot(unsigned char d);
|
unsigned char getRowToPlot(unsigned char d);
|
||||||
bool inverseChar(const unsigned char d);
|
bool inverseChar(const unsigned char d);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows);
|
Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows);
|
||||||
~Video();
|
~Video();
|
||||||
void powerOn();
|
void powerOn();
|
||||||
void tick();
|
void tick();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*VIDEO_H_*/
|
#endif /*VIDEO_H_*/
|
||||||
|
|
|
@ -24,62 +24,62 @@ VideoAddressing::VideoAddressing()
|
||||||
|
|
||||||
static int calc(const unsigned int t)
|
static int calc(const unsigned int t)
|
||||||
{
|
{
|
||||||
int c = t % E2Const::VISIBLE_BYTES_PER_FIELD;
|
int c = t % E2Const::VISIBLE_BYTES_PER_FIELD;
|
||||||
if (t >= E2Const::SCANNABLE_BYTES)
|
if (t >= E2Const::SCANNABLE_BYTES)
|
||||||
{
|
{
|
||||||
c -= E2Const::RESET_BYTES;
|
c -= E2Const::RESET_BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = c / E2Const::BYTES_PER_ROW;
|
int n = c / E2Const::BYTES_PER_ROW;
|
||||||
const int s = (n >> 6);
|
const int s = (n >> 6);
|
||||||
n -= s << 6;
|
n -= s << 6;
|
||||||
const int q = (n >> 3);
|
const int q = (n >> 3);
|
||||||
n -= q << 3;
|
n -= q << 3;
|
||||||
const int base = (n<<10) + (q<<7) + E2Const::VISIBLE_BYTES_PER_ROW*s;
|
const int base = (n<<10) + (q<<7) + E2Const::VISIBLE_BYTES_PER_ROW*s;
|
||||||
|
|
||||||
const int half_page = base & 0xFF80;
|
const int half_page = base & 0xFF80;
|
||||||
|
|
||||||
int a = base+(c%E2Const::BYTES_PER_ROW)-E2Const::BLANKED_BYTES_PER_ROW;
|
int a = base+(c%E2Const::BYTES_PER_ROW)-E2Const::BLANKED_BYTES_PER_ROW;
|
||||||
if (a < half_page)
|
if (a < half_page)
|
||||||
{
|
{
|
||||||
a += 0x80;
|
a += 0x80;
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoAddressing::buildLUT(const unsigned short base, const unsigned short len, std::vector<unsigned short>& lut)
|
void VideoAddressing::buildLUT(const unsigned short base, const unsigned short len, std::vector<unsigned short>& lut)
|
||||||
{
|
{
|
||||||
lut.resize(E2Const::BYTES_PER_FIELD);
|
lut.resize(E2Const::BYTES_PER_FIELD);
|
||||||
for (unsigned int t = 0; t < E2Const::BYTES_PER_FIELD; ++t)
|
for (unsigned int t = 0; t < E2Const::BYTES_PER_FIELD; ++t)
|
||||||
{
|
{
|
||||||
unsigned int off = (calc(t) % len);
|
unsigned int off = (calc(t) % len);
|
||||||
|
|
||||||
const unsigned int col = t % E2Const::BYTES_PER_ROW;
|
const unsigned int col = t % E2Const::BYTES_PER_ROW;
|
||||||
const unsigned int row = t / E2Const::BYTES_PER_ROW;
|
const unsigned int row = t / E2Const::BYTES_PER_ROW;
|
||||||
|
|
||||||
if (col < E2Const::BLANKED_BYTES_PER_ROW)
|
if (col < E2Const::BLANKED_BYTES_PER_ROW)
|
||||||
{
|
{
|
||||||
// HBL
|
// HBL
|
||||||
if (base < 0x1000)
|
if (base < 0x1000)
|
||||||
{
|
{
|
||||||
off += 0x1000;
|
off += 0x1000;
|
||||||
}
|
}
|
||||||
if (col == 0)
|
if (col == 0)
|
||||||
{
|
{
|
||||||
++off;
|
++off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row >= E2Const::VISIBLE_ROWS_PER_FIELD)
|
if (row >= E2Const::VISIBLE_ROWS_PER_FIELD)
|
||||||
{
|
{
|
||||||
// VBL
|
// VBL
|
||||||
const int base2 = off & 0xFF80;
|
const int base2 = off & 0xFF80;
|
||||||
off &= 0x7F;
|
off &= 0x7F;
|
||||||
off -= 8;
|
off -= 8;
|
||||||
off &= 0x7F;
|
off &= 0x7F;
|
||||||
off += base2;
|
off += base2;
|
||||||
}
|
}
|
||||||
|
|
||||||
lut[t] = base + off;
|
lut[t] = base + off;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
class VideoAddressing
|
class VideoAddressing
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
VideoAddressing();
|
VideoAddressing();
|
||||||
static void buildLUT(const unsigned short base, const unsigned short len, std::vector<unsigned short>& lut);
|
static void buildLUT(const unsigned short base, const unsigned short len, std::vector<unsigned short>& lut);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,26 +23,26 @@ VideoMode::VideoMode()
|
||||||
|
|
||||||
unsigned char VideoMode::io(const unsigned short addr, const unsigned char b)
|
unsigned char VideoMode::io(const unsigned short addr, const unsigned char b)
|
||||||
{
|
{
|
||||||
const int sw = (addr & 0xE) >> 1;
|
const int sw = (addr & 0xE) >> 1;
|
||||||
const bool on = addr & 0x1;
|
const bool on = addr & 0x1;
|
||||||
switch (sw)
|
switch (sw)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
this->swText = on; break;
|
this->swText = on; break;
|
||||||
case 1:
|
case 1:
|
||||||
this->swMixed = on; break;
|
this->swMixed = on; break;
|
||||||
case 2:
|
case 2:
|
||||||
this->swPage2 = on ? 1 : 0; break;
|
this->swPage2 = on ? 1 : 0; break;
|
||||||
case 3:
|
case 3:
|
||||||
this->swHiRes = on; break;
|
this->swHiRes = on; break;
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoMode::powerOn()
|
void VideoMode::powerOn()
|
||||||
{
|
{
|
||||||
this->swText = false;
|
this->swText = false;
|
||||||
this->swMixed = false;
|
this->swMixed = false;
|
||||||
this->swPage2 = 0;
|
this->swPage2 = 0;
|
||||||
this->swHiRes = false;
|
this->swHiRes = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,21 +24,21 @@
|
||||||
class VideoMode
|
class VideoMode
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool swText;
|
bool swText;
|
||||||
bool swMixed;
|
bool swMixed;
|
||||||
int swPage2;
|
int swPage2;
|
||||||
bool swHiRes;
|
bool swHiRes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VideoMode();
|
VideoMode();
|
||||||
unsigned char io(const unsigned short addr, const unsigned char b);
|
unsigned char io(const unsigned short addr, const unsigned char b);
|
||||||
void powerOn();
|
void powerOn();
|
||||||
|
|
||||||
bool isText() const { return this->swText; }
|
bool isText() const { return this->swText; }
|
||||||
bool isHiRes() const { return this->swHiRes; }
|
bool isHiRes() const { return this->swHiRes; }
|
||||||
bool isMixed() const { return this->swMixed; }
|
bool isMixed() const { return this->swMixed; }
|
||||||
int getPage() const { return this->swPage2; }
|
int getPage() const { return this->swPage2; }
|
||||||
bool isDisplayingText(const int atTickInField) const { return this->swText || (this->swMixed && atTickInField >= E2Const::MIXED_TEXT_CYCLE); }
|
bool isDisplayingText(const int atTickInField) const { return this->swText || (this->swMixed && atTickInField >= E2Const::MIXED_TEXT_CYCLE); }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,13 +22,13 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
VideoStaticGenerator::VideoStaticGenerator(AnalogTV& display):
|
VideoStaticGenerator::VideoStaticGenerator(AnalogTV& display):
|
||||||
display(display),
|
display(display),
|
||||||
isig(sig),
|
isig(sig),
|
||||||
isiglim(sig+AppleNTSC::SIGNAL_LEN),
|
isiglim(sig+AppleNTSC::SIGNAL_LEN),
|
||||||
hpos(0)
|
hpos(0)
|
||||||
{
|
{
|
||||||
this->display.signal = sig;
|
this->display.signal = sig;
|
||||||
srand(time(0));
|
srand(time(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,32 +39,32 @@ VideoStaticGenerator::~VideoStaticGenerator()
|
||||||
|
|
||||||
void VideoStaticGenerator::tick()
|
void VideoStaticGenerator::tick()
|
||||||
{
|
{
|
||||||
signed char* is = this->isig;
|
signed char* is = this->isig;
|
||||||
unsigned int cycles = E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE;
|
unsigned int cycles = E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE;
|
||||||
if (this->hpos == E2Const::HORIZ_CYCLES-1)
|
if (this->hpos == E2Const::HORIZ_CYCLES-1)
|
||||||
{
|
{
|
||||||
cycles += E2Const::EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE;
|
cycles += E2Const::EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE;
|
||||||
}
|
}
|
||||||
for (unsigned int i = 0; i < cycles; ++i)
|
for (unsigned int i = 0; i < cycles; ++i)
|
||||||
{
|
{
|
||||||
*is++ = (rand()>>7&0x7F)-27;
|
*is++ = (rand()>>7&0x7F)-27;
|
||||||
}
|
}
|
||||||
this->isig = is;
|
this->isig = is;
|
||||||
++this->hpos;
|
++this->hpos;
|
||||||
if (this->hpos >= E2Const::HORIZ_CYCLES)
|
if (this->hpos >= E2Const::HORIZ_CYCLES)
|
||||||
{
|
{
|
||||||
this->hpos = 0;
|
this->hpos = 0;
|
||||||
if (isig >= isiglim)
|
if (isig >= isiglim)
|
||||||
{
|
{
|
||||||
isig = sig;
|
isig = sig;
|
||||||
this->display.drawCurrent();
|
this->display.drawCurrent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoStaticGenerator::powerOn()
|
void VideoStaticGenerator::powerOn()
|
||||||
{
|
{
|
||||||
this->hpos = 0;
|
this->hpos = 0;
|
||||||
this->display.signal = sig;
|
this->display.signal = sig;
|
||||||
isig = sig;
|
isig = sig;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,18 +25,18 @@ class AnalogTV;
|
||||||
class VideoStaticGenerator : public Timable
|
class VideoStaticGenerator : public Timable
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
AnalogTV& display;
|
AnalogTV& display;
|
||||||
signed char sig[AppleNTSC::SIGNAL_LEN];
|
signed char sig[AppleNTSC::SIGNAL_LEN];
|
||||||
signed char* isig;
|
signed char* isig;
|
||||||
signed char* isiglim;
|
signed char* isiglim;
|
||||||
unsigned int hpos;
|
unsigned int hpos;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VideoStaticGenerator(AnalogTV& display);
|
VideoStaticGenerator(AnalogTV& display);
|
||||||
~VideoStaticGenerator();
|
~VideoStaticGenerator();
|
||||||
|
|
||||||
virtual void tick();
|
virtual void tick();
|
||||||
void powerOn();
|
void powerOn();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue