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