convert leading tabs to spaces in all file (they were a random mixture of tabs and spaces before).

This commit is contained in:
Christopher A. Mosher 2022-11-02 23:50:54 -04:00
parent db7b722eea
commit 7059628f52
60 changed files with 4421 additions and 4421 deletions

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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() {

View File

@ -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;
}

View File

@ -24,10 +24,10 @@
class ClipboardHandler
{
public:
ClipboardHandler();
~ClipboardHandler();
ClipboardHandler();
~ClipboardHandler();
std::string getText();
std::string getText();
};
#endif

View File

@ -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';
}

View File

@ -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

File diff suppressed because it is too large Load Diff

338
src/cpu.h
View File

@ -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

View File

@ -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;
}
};

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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 () {}
};
};

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

View File

@ -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_*/

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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