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) static unsigned char tobyt(float x)
{ {
x *= 256.0f; x *= 256.0f;
x += 0.0001f; x += 0.0001f;
int xi = (int)x; int xi = (int)x;
if (xi > 255) if (xi > 255)
xi = 255; xi = 255;
return (unsigned char)xi; return (unsigned char)xi;
} }
// 0 <= h < 360 degrees; 0 <= s,v <= 1 // 0 <= h < 360 degrees; 0 <= s,v <= 1
static int HSVtoRGB(const int h, const float s, const float v) static int HSVtoRGB(const int h, const float s, const float v)
{ {
const float f = (h % 60) / 60.0; const float f = (h % 60) / 60.0;
float r, g, b; float r, g, b;
switch (h / 60) switch (h / 60)
{ {
case 0: case 0:
r = v; r = v;
g = v * (1 - s * (1 - f)); g = v * (1 - s * (1 - f));
b = v * (1 - s); b = v * (1 - s);
break; break;
case 1: case 1:
r = v * (1 - s * f); r = v * (1 - s * f);
g = v; g = v;
b = v * (1 - s); b = v * (1 - s);
break; break;
case 2: case 2:
r = v * (1 - s); r = v * (1 - s);
g = v; g = v;
b = v * (1 - s * (1 - f)); b = v * (1 - s * (1 - f));
break; break;
case 3: case 3:
r = v * (1 - s); r = v * (1 - s);
g = v * (1 - s * f); g = v * (1 - s * f);
b = v; b = v;
break; break;
case 4: case 4:
r = v * (1 - s * (1 - f)); r = v * (1 - s * (1 - f));
g = v * (1 - s); g = v * (1 - s);
b = v; b = v;
break; break;
case 5: case 5:
r = v; r = v;
g = v * (1 - s); g = v * (1 - s);
b = v * (1 - s * f); b = v * (1 - s * f);
break; break;
default: default:
r = g = b = 0; r = g = b = 0;
} }
return (tobyt(r) << 16) | (tobyt(g) << 8) | (tobyt(b)); return (tobyt(r) << 16) | (tobyt(g) << 8) | (tobyt(b));
} }
A2ColorsObserved::A2ColorsObserved(): A2ColorsObserved::A2ColorsObserved():
COLOR(0x10) COLOR(0x10)
{ {
// const unsigned int clr[] = { 0x1, 0xB, 0x3, 0x2, 0x7, 0x6, 0x4, 0xE, 0xC, 0x8, 0xD, 0x9, 0x5, 0xA, 0xF, 0x0 }; // const unsigned int clr[] = { 0x1, 0xB, 0x3, 0x2, 0x7, 0x6, 0x4, 0xE, 0xC, 0x8, 0xD, 0x9, 0x5, 0xA, 0xF, 0x0 };
const unsigned int map[] = { 0xF, 0x0, 0x3, 0x2, 0x6, 0xC, 0x5, 0x4, 0x9, 0xB, 0xD, 0x1, 0x8, 0xA, 0x7, 0xE }; const unsigned int map[] = { 0xF, 0x0, 0x3, 0x2, 0x6, 0xC, 0x5, 0x4, 0x9, 0xB, 0xD, 0x1, 0x8, 0xA, 0x7, 0xE };
const unsigned int hue[] = { 342, 342, 277, 233, 233, 213, 160, 160, 75, 33, 52, 24, 0, 0, 0, 0 }; const unsigned int hue[] = { 342, 342, 277, 233, 233, 213, 160, 160, 75, 33, 52, 24, 0, 0, 0, 0 };
const unsigned int sat[] = { 100, 50, 75, 100, 50, 100, 100, 100, 100, 100, 100, 100, 0, 0, 0, 0 }; const unsigned int sat[] = { 100, 50, 75, 100, 50, 100, 100, 100, 100, 100, 100, 100, 0, 0, 0, 0 };
const unsigned int val[] = { 67, 100, 100, 75, 100, 100, 33, 100, 75, 50, 100, 100, 50, 50, 100, 0 }; const unsigned int val[] = { 67, 100, 100, 75, 100, 100, 33, 100, 75, 50, 100, 100, 50, 50, 100, 0 };
for (unsigned int i(0); i < COLOR.size(); ++i) for (unsigned int i(0); i < COLOR.size(); ++i)
{ {
COLOR[i] = HSVtoRGB(hue[map[i]],sat[map[i]]/100.0f,val[map[i]]/100.0f); COLOR[i] = HSVtoRGB(hue[map[i]],sat[map[i]]/100.0f,val[map[i]]/100.0f);
} }
} }

View File

@ -23,33 +23,33 @@
class A2ColorsObserved class A2ColorsObserved
{ {
private: private:
std::vector<unsigned int> COLOR; std::vector<unsigned int> COLOR;
public: public:
A2ColorsObserved(); A2ColorsObserved();
~A2ColorsObserved(); ~A2ColorsObserved();
const std::vector<unsigned int>& c() { return this->COLOR; } const std::vector<unsigned int>& c() { return this->COLOR; }
enum enum
{ {
BLACK, BLACK,
DARK_MAGENTA, DARK_MAGENTA,
DARK_BLUE, DARK_BLUE,
HIRES_VIOLET, HIRES_VIOLET,
DARK_BLUE_GREEN, DARK_BLUE_GREEN,
GREY, GREY,
HIRES_BLUE, HIRES_BLUE,
LIGHT_BLUE, LIGHT_BLUE,
DARK_BROWN, DARK_BROWN,
HIRES_ORANGE, HIRES_ORANGE,
GREY_ALTERNATE, GREY_ALTERNATE,
LIGHT_MAGENTA, LIGHT_MAGENTA,
HIRES_GREEN, HIRES_GREEN,
LIGHT_BROWN, LIGHT_BROWN,
LIGHT_BLUE_GREEN, LIGHT_BLUE_GREEN,
WHITE, WHITE,
}; };
}; };
#endif #endif

View File

@ -41,25 +41,25 @@
AnalogTV::AnalogTV(ScreenImage& image): AnalogTV::AnalogTV(ScreenImage& image):
image(image), image(image),
on(false), on(false),
noise(false), noise(false),
bleed_down(true) bleed_down(true)
{ {
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_GREEN]); hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_GREEN]);
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_ORANGE]); hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_ORANGE]);
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_VIOLET]); hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_VIOLET]);
hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_BLUE]); hirescolor.push_back(colors.c()[A2ColorsObserved::HIRES_BLUE]);
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BROWN]); loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BROWN]);
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_MAGENTA]); loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_MAGENTA]);
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE]); loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE]);
loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE_GREEN]); loreslightcolor.push_back(colors.c()[A2ColorsObserved::LIGHT_BLUE_GREEN]);
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE_GREEN]); loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE_GREEN]);
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BROWN]); loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BROWN]);
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_MAGENTA]); loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_MAGENTA]);
loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE]); loresdarkcolor.push_back(colors.c()[A2ColorsObserved::DARK_BLUE]);
} }
@ -69,25 +69,25 @@ AnalogTV::~AnalogTV()
void AnalogTV::powerOn(bool b) void AnalogTV::powerOn(bool b)
{ {
this->on = b; this->on = b;
this->image.notifyObservers(); this->image.notifyObservers();
} }
void AnalogTV::setType(DisplayType type) void AnalogTV::setType(DisplayType type)
{ {
this->type = type; this->type = type;
} }
void AnalogTV::cycleType() void AnalogTV::cycleType()
{ {
this->type = (DisplayType)((((int)this->type)+1)%NUM_DISPLAY_TYPES); this->type = (DisplayType)((((int)this->type)+1)%NUM_DISPLAY_TYPES);
} }
void AnalogTV::toggleBleedDown() void AnalogTV::toggleBleedDown()
{ {
this->bleed_down = !this->bleed_down; this->bleed_down = !this->bleed_down;
this->image.blank(); this->image.blank();
this->image.notifyObservers(); this->image.notifyObservers();
} }
@ -137,18 +137,18 @@ void AnalogTV::toggleBleedDown()
class IQ class IQ
{ {
public: public:
double iq[4]; double iq[4];
IQ() IQ()
{ {
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
iq[i] = 0; iq[i] = 0;
} }
IQ(double aiq[]) IQ(double aiq[])
{ {
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
iq[i] = aiq[i]; iq[i] = aiq[i];
} }
double get(int i) const { return this->iq[i]; } double get(int i) const { return this->iq[i]; }
}; };
const IQ& AnalogTV::BLACK_AND_WHITE = IQ(); const IQ& AnalogTV::BLACK_AND_WHITE = IQ();
@ -158,67 +158,67 @@ static const int CB_EXTRA(32);
class CB class CB
{ {
public: public:
std::vector<int> cb; std::vector<int> cb;
CB(const int acb[]): CB(const int acb[]):
cb(AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA) cb(AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA)
{ {
for (std::vector<int>::size_type i(0); i < this->cb.size(); ++i) for (std::vector<int>::size_type i(0); i < this->cb.size(); ++i)
{ {
this->cb[i] = acb[i]; this->cb[i] = acb[i];
} }
} }
int get(const int i) const { return this->cb[i]; } int get(const int i) const { return this->cb[i]; }
int length() const { return this->cb.size(); } int length() const { return this->cb.size(); }
void getPhase(double phase[]) const void getPhase(double phase[]) const
{ {
{ {
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
phase[i & 3] = 0; phase[i & 3] = 0;
} }
} }
{ {
for (int i = 0; i < length(); ++i) for (int i = 0; i < length(); ++i)
{ {
phase[i & 3] += this->cb[i]; phase[i & 3] += this->cb[i];
} }
} }
double tot = 0; double tot = 0;
{ {
for (int i = 0; i < 4; ++i) for (int i = 0; i < 4; ++i)
{ {
tot += phase[i] * phase[i]; tot += phase[i] * phase[i];
} }
} }
const double tsrt = sqrt(tot); const double tsrt = sqrt(tot);
if (tsrt < .0001) if (tsrt < .0001)
{ {
return; return;
} }
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
phase[i] /= tsrt; phase[i] /= tsrt;
} }
} }
bool isColor() const bool isColor() const
{ {
int tot = 0; int tot = 0;
for (int i = 0; i < length(); ++i) for (int i = 0; i < length(); ++i)
{ {
const int icb = this->cb[i]; const int icb = this->cb[i];
if (icb < 0) if (icb < 0)
tot += -icb; tot += -icb;
else else
tot += icb; tot += icb;
} }
return 220 < tot && tot < 260; return 220 < tot && tot < 260;
} }
bool operator<(const CB& that) const bool operator<(const CB& that) const
{ {
return this->cb < that.cb; return this->cb < that.cb;
} }
}; };
@ -229,21 +229,21 @@ public:
void AnalogTV::drawCurrent() void AnalogTV::drawCurrent()
{ {
if (this->on) if (this->on)
{ {
switch (this->type) switch (this->type)
{ {
case MONITOR_COLOR: drawMonitorColor(); break; case MONITOR_COLOR: drawMonitorColor(); break;
case MONITOR_GREEN: drawMonitorGreen(); break; case MONITOR_GREEN: drawMonitorGreen(); break;
case TV_OLD_COLOR: drawTVOld(); break; case TV_OLD_COLOR: drawTVOld(); break;
case NUM_DISPLAY_TYPES: break; case NUM_DISPLAY_TYPES: break;
} }
} }
else else
{ {
drawBlank(); drawBlank();
} }
this->image.notifyObservers(); this->image.notifyObservers();
} }
@ -252,80 +252,80 @@ static const int D_IP(AppleNTSC::H-2-350);
void AnalogTV::drawMonitorColor() void AnalogTV::drawMonitorColor()
{ {
unsigned int *rgb = new unsigned int[AppleNTSC::H]; unsigned int *rgb = new unsigned int[AppleNTSC::H];
int ip = 0; int ip = 0;
for (int row = 0; row < 192; ++row) for (int row = 0; row < 192; ++row)
{ {
const CB cb = get_cb(row); const CB cb = get_cb(row);
const bool removeColor = !cb.isColor(); const bool removeColor = !cb.isColor();
ntsc_to_rgb_monitor(row*AppleNTSC::H+350,AppleNTSC::H-350,rgb); ntsc_to_rgb_monitor(row*AppleNTSC::H+350,AppleNTSC::H-350,rgb);
for (int col = 350; col < AppleNTSC::H-2; ++col) for (int col = 350; col < AppleNTSC::H-2; ++col)
{ {
int rgbv = rgb[col-350]; int rgbv = rgb[col-350];
if (removeColor && rgbv != 0) if (removeColor && rgbv != 0)
{ {
rgbv = 0xFFFFFF; rgbv = 0xFFFFFF;
} }
this->image.setElem(ip,rgbv); this->image.setElem(ip,rgbv);
if (bleed_down) if (bleed_down)
this->image.setElem(ip+D_IP,rgbv); // display same pixel on next row this->image.setElem(ip+D_IP,rgbv); // display same pixel on next row
++ip; ++ip;
} }
ip += D_IP; ip += D_IP;
} }
delete [] rgb; delete [] rgb;
} }
void AnalogTV::drawMonitorGreen() void AnalogTV::drawMonitorGreen()
{ {
drawMonitorMonochrome(colors.c()[A2ColorsObserved::HIRES_GREEN]); drawMonitorMonochrome(colors.c()[A2ColorsObserved::HIRES_GREEN]);
} }
void AnalogTV::drawMonitorMonochrome(const unsigned int color) void AnalogTV::drawMonitorMonochrome(const unsigned int color)
{ {
int ip = 0; int ip = 0;
for (int row = 0; row < 192; ++row) for (int row = 0; row < 192; ++row)
{ {
for (int col = 350; col < AppleNTSC::H-2; ++col) for (int col = 350; col < AppleNTSC::H-2; ++col)
{ {
const int is = row*AppleNTSC::H+col; const int is = row*AppleNTSC::H+col;
const unsigned int rgb = this->signal[is] > 50 ? color : 0; const unsigned int rgb = this->signal[is] > 50 ? color : 0;
this->image.setElem(ip,rgb); this->image.setElem(ip,rgb);
if (bleed_down) if (bleed_down)
this->image.setElem(ip+D_IP,rgb); this->image.setElem(ip+D_IP,rgb);
++ip; ++ip;
} }
ip += D_IP; ip += D_IP;
} }
} }
void AnalogTV::drawTVOld() void AnalogTV::drawTVOld()
{ {
int *yiq = new int[AppleNTSC::H]; int *yiq = new int[AppleNTSC::H];
int ip = 0; int ip = 0;
for (int row = 0; row < 192; ++row) for (int row = 0; row < 192; ++row)
{ {
IQ iq_factor; IQ iq_factor;
const CB cb = get_cb(row); const CB cb = get_cb(row);
iq_factor = get_iq_factor(cb); iq_factor = get_iq_factor(cb);
ntsc_to_yiq(row*AppleNTSC::H+350,AppleNTSC::H-350,iq_factor,yiq); ntsc_to_yiq(row*AppleNTSC::H+350,AppleNTSC::H-350,iq_factor,yiq);
for (int col = 350; col < AppleNTSC::H-2; ++col) for (int col = 350; col < AppleNTSC::H-2; ++col)
{ {
const int rgb = yiq2rgb(yiq[col-348]); // shift display left 1 pixel const int rgb = yiq2rgb(yiq[col-348]); // shift display left 1 pixel
this->image.setElem(ip,rgb); this->image.setElem(ip,rgb);
if (bleed_down) if (bleed_down)
this->image.setElem(ip+D_IP,rgb); this->image.setElem(ip+D_IP,rgb);
++ip; ++ip;
} }
ip += D_IP; ip += D_IP;
} }
delete [] yiq; delete [] yiq;
} }
void AnalogTV::drawBlank() void AnalogTV::drawBlank()
{ {
this->image.blank(); this->image.blank();
} }
@ -334,47 +334,47 @@ void AnalogTV::drawBlank()
void AnalogTV::ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[]) void AnalogTV::ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[])
{ {
int s0, s1, se; int s0, s1, se;
s0 = s1 = isignal; s0 = s1 = isignal;
se = isignal+siglen; se = isignal+siglen;
while (s1 < se) while (s1 < se)
{ {
// no signal (black) // no signal (black)
while (this->signal[s0] < 50 && s0<se) { rgb[s0-isignal] = 0; ++s0; } while (this->signal[s0] < 50 && s0<se) { rgb[s0-isignal] = 0; ++s0; }
// signal (white, grey, or color) // signal (white, grey, or color)
s1 = s0; s1 = s0;
while (this->signal[s1] > 50 && s1<se) { ++s1; } while (this->signal[s1] > 50 && s1<se) { ++s1; }
const int slen = s1-s0; const int slen = s1-s0;
unsigned int c = 0; unsigned int c = 0;
if (slen >= 4) if (slen >= 4)
{ {
c = 0xFFFFFF; c = 0xFFFFFF;
} }
else if (slen == 1) else if (slen == 1)
{ {
if (this->signal[s0-2] > 50 && this->signal[s0+2] > 50) if (this->signal[s0-2] > 50 && this->signal[s0+2] > 50)
c = 0xFFFFFF; c = 0xFFFFFF;
else else
c = loresdarkcolor[s0 % 4]; c = loresdarkcolor[s0 % 4];
} }
else if (slen == 2) else if (slen == 2)
{ {
c = hirescolor[s0 % 4]; c = hirescolor[s0 % 4];
} }
else if (slen == 3) else if (slen == 3)
{ {
c = loreslightcolor[s0 % 4]; c = loreslightcolor[s0 % 4];
} }
else else
{ {
++s1; ++s1;
} }
for (int i = s0; i < s1; ++i) for (int i = s0; i < s1; ++i)
rgb[i-isignal] = c; rgb[i-isignal] = c;
s0 = s1; s0 = s1;
} }
} }
@ -386,12 +386,12 @@ void AnalogTV::ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned
int *AnalogTV::rcb = new int[AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA]; int *AnalogTV::rcb = new int[AppleNTSC::CB_END-AppleNTSC::CB_START-CB_EXTRA];
CB AnalogTV::get_cb(int lineno) CB AnalogTV::get_cb(int lineno)
{ {
const int isp = lineno * AppleNTSC::H; const int isp = lineno * AppleNTSC::H;
for (int i = AppleNTSC::CB_START + CB_EXTRA/2; i < AppleNTSC::CB_END - CB_EXTRA/2; ++i) for (int i = AppleNTSC::CB_START + CB_EXTRA/2; i < AppleNTSC::CB_END - CB_EXTRA/2; ++i)
{ {
this->rcb[i-(AppleNTSC::CB_START + CB_EXTRA/2)] = this->signal[isp + i]; this->rcb[i-(AppleNTSC::CB_START + CB_EXTRA/2)] = this->signal[isp + i];
} }
return CB(this->rcb); return CB(this->rcb);
} }
@ -406,35 +406,35 @@ const double AnalogTV::COLOR_THRESH(sqrt(2));
IQ AnalogTV::get_iq_factor(const CB& cb) IQ AnalogTV::get_iq_factor(const CB& cb)
{ {
std::map<CB,IQ>::iterator hit = cacheCB.find(cb); std::map<CB,IQ>::iterator hit = cacheCB.find(cb);
if (hit != cacheCB.end()) if (hit != cacheCB.end())
{ {
return hit->second; return hit->second;
} }
double cb_phase[4]; double cb_phase[4];
cb.getPhase(cb_phase); cb.getPhase(cb_phase);
const double cb_i = cb_phase[2]-cb_phase[0]; const double cb_i = cb_phase[2]-cb_phase[0];
const double cb_q = cb_phase[3]-cb_phase[1]; const double cb_q = cb_phase[3]-cb_phase[1];
if ((cb_i*cb_i) + (cb_q*cb_q) < COLOR_THRESH) if ((cb_i*cb_i) + (cb_q*cb_q) < COLOR_THRESH)
{ {
return BLACK_AND_WHITE; return BLACK_AND_WHITE;
} }
double iq_factor[4]; double iq_factor[4];
iq_factor[0] = cb_i * TINT_I + cb_q * TINT_Q; iq_factor[0] = cb_i * TINT_I + cb_q * TINT_Q;
iq_factor[2] = -iq_factor[0]; iq_factor[2] = -iq_factor[0];
iq_factor[1] = cb_q * TINT_I - cb_i * TINT_Q; iq_factor[1] = cb_q * TINT_I - cb_i * TINT_Q;
iq_factor[3] = -iq_factor[1]; iq_factor[3] = -iq_factor[1];
const IQ iq(iq_factor); const IQ iq(iq_factor);
if (!this->noise) if (!this->noise)
{ {
cacheCB[cb] = iq; cacheCB[cb] = iq;
} }
return iq; return iq;
} }
const int AnalogTV::IQINTOFF(130); const int AnalogTV::IQINTOFF(130);
@ -456,41 +456,41 @@ void AnalogTV::ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_fac
int inline AnalogTV::yiq2rgb(const int yiq) int inline AnalogTV::yiq2rgb(const int yiq)
{ {
double r = (((yiq)&0xFF)-IQINTOFF) + 0.956 * (((yiq>>8)&0xFF)-IQINTOFF) + 0.621 * (((yiq>>16)&0xFF)-IQINTOFF); double r = (((yiq)&0xFF)-IQINTOFF) + 0.956 * (((yiq>>8)&0xFF)-IQINTOFF) + 0.621 * (((yiq>>16)&0xFF)-IQINTOFF);
double g = (((yiq)&0xFF)-IQINTOFF) - 0.272 * (((yiq>>8)&0xFF)-IQINTOFF) - 0.647 * (((yiq>>16)&0xFF)-IQINTOFF); double g = (((yiq)&0xFF)-IQINTOFF) - 0.272 * (((yiq>>8)&0xFF)-IQINTOFF) - 0.647 * (((yiq>>16)&0xFF)-IQINTOFF);
double b = (((yiq)&0xFF)-IQINTOFF) - 1.105 * (((yiq>>8)&0xFF)-IQINTOFF) + 1.702 * (((yiq>>16)&0xFF)-IQINTOFF); double b = (((yiq)&0xFF)-IQINTOFF) - 1.105 * (((yiq>>8)&0xFF)-IQINTOFF) + 1.702 * (((yiq>>16)&0xFF)-IQINTOFF);
const int rgb = const int rgb =
(calc_color(r) << 16)| (calc_color(r) << 16)|
(calc_color(g) << 8)| (calc_color(g) << 8)|
(calc_color(b) << 0); (calc_color(b) << 0);
return rgb; return rgb;
} }
int inline AnalogTV::color2bw(const int rgb) int inline AnalogTV::color2bw(const int rgb)
{ {
const int y = rgb2y(rgb); const int y = rgb2y(rgb);
return y<<16 | y<<8 | y; return y<<16 | y<<8 | y;
} }
int inline AnalogTV::rgb2y(const int rgb) // y in range 0-255 int inline AnalogTV::rgb2y(const int rgb) // y in range 0-255
{ {
return (int)((0.299*((rgb>>16)&0xFF) + 0.587*((rgb>>8)&0xFF) + 0.114*((rgb)&0xFF))/1.04); return (int)((0.299*((rgb>>16)&0xFF) + 0.587*((rgb>>8)&0xFF) + 0.114*((rgb)&0xFF))/1.04);
} }
int inline AnalogTV::calc_color(const double color) int inline AnalogTV::calc_color(const double color)
{ {
int x = (int)(color * 0x100 / AppleNTSC::LEVEL_RANGE + .5); int x = (int)(color * 0x100 / AppleNTSC::LEVEL_RANGE + .5);
x = clamp(0,x,0x100); x = clamp(0,x,0x100);
return x & 0xFF; return x & 0xFF;
} }
int inline AnalogTV::clamp(int min, int x, int lim) int inline AnalogTV::clamp(int min, int x, int lim)
{ {
if (x < min) if (x < min)
return min; return min;
if (lim <= x) if (lim <= x)
return lim-1; return lim-1;
return x; return x;
} }

View File

@ -32,75 +32,75 @@ class CB;
class AnalogTV class AnalogTV
{ {
public: public:
enum DisplayType enum DisplayType
{ {
TV_OLD_COLOR, TV_OLD_COLOR,
MONITOR_COLOR, MONITOR_COLOR,
MONITOR_GREEN, MONITOR_GREEN,
NUM_DISPLAY_TYPES NUM_DISPLAY_TYPES
}; };
private: private:
ScreenImage& image; ScreenImage& image;
bool on; bool on;
bool noise; bool noise;
DisplayType type; DisplayType type;
bool bleed_down; bool bleed_down;
static int* rcb; static int* rcb;
A2ColorsObserved colors; A2ColorsObserved colors;
std::vector<unsigned int> hirescolor; std::vector<unsigned int> hirescolor;
std::vector<unsigned int> loreslightcolor; std::vector<unsigned int> loreslightcolor;
std::vector<unsigned int> loresdarkcolor; std::vector<unsigned int> loresdarkcolor;
static const int IQINTOFF; static const int IQINTOFF;
static const double IQ_OFFSET_DEGREES; static const double IQ_OFFSET_DEGREES;
static const double IQ_OFFSET_RADIANS; static const double IQ_OFFSET_RADIANS;
static const double TINT_I; static const double TINT_I;
static const double TINT_Q; static const double TINT_Q;
static const double COLOR_THRESH; static const double COLOR_THRESH;
static const IQ& BLACK_AND_WHITE; static const IQ& BLACK_AND_WHITE;
void drawMonitorColor(); void drawMonitorColor();
void drawMonitorWhite(); void drawMonitorWhite();
void drawMonitorGreen(); void drawMonitorGreen();
void drawMonitorOrange(); void drawMonitorOrange();
void drawMonitorMonochrome(const unsigned int color); void drawMonitorMonochrome(const unsigned int color);
void drawTVOld(); void drawTVOld();
void drawTVNew(); void drawTVNew();
void drawBlank(); void drawBlank();
void ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[]); void ntsc_to_rgb_monitor(const int isignal, const int siglen, unsigned int rgb[]);
void ntsc_to_rgb_newtv(const int isignal, const int siglen, unsigned int rgb[]); void ntsc_to_rgb_newtv(const int isignal, const int siglen, unsigned int rgb[]);
CB get_cb(int lineno); CB get_cb(int lineno);
IQ get_iq_factor(const CB& cb); IQ get_iq_factor(const CB& cb);
void ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_factor, int yiq[]); void ntsc_to_yiq(const int isignal, const int siglen, const IQ& iq_factor, int yiq[]);
static int yiq2rgb(const int yiq); static int yiq2rgb(const int yiq);
static int color2bw(const int rgb); static int color2bw(const int rgb);
static int rgb2y(const int rgb); // ;y in range 0-255 static int rgb2y(const int rgb); // ;y in range 0-255
static int calc_color(const double color); static int calc_color(const double color);
static int clamp(int min, int x, int lim); static int clamp(int min, int x, int lim);
public: public:
void drawCurrent(); void drawCurrent();
signed char* signal; signed char* signal;
AnalogTV(ScreenImage& image); AnalogTV(ScreenImage& image);
~AnalogTV(); ~AnalogTV();
bool isOn() const bool isOn() const
{ {
return this->on; return this->on;
} }
void powerOn(bool b); void powerOn(bool b);
void toggleBleedDown(); void toggleBleedDown();
void restartSignal(); void restartSignal();
void setType(DisplayType type); void setType(DisplayType type);
void cycleType(); void cycleType();
void setNoise(bool noise) { this->noise = noise; } void setNoise(bool noise) { this->noise = noise; }
}; };
#endif #endif

View File

@ -39,23 +39,23 @@
#include <fstream> #include <fstream>
Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui): Apple2::Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui):
slts(gui), slts(gui),
kbd(keypresses,fhyper,buffered), kbd(keypresses,fhyper,buffered),
rom(AddressBus::MOTHERBOARD_ROM_SIZ), rom(AddressBus::MOTHERBOARD_ROM_SIZ),
ram(revision), ram(revision),
cassetteIn(gui), cassetteIn(gui),
cassetteOut(gui), cassetteOut(gui),
addressBus(gui,revision,ram,rom,kbd,videoMode,paddles,paddleButtonStates,speaker,cassetteIn,cassetteOut,slts), addressBus(gui,revision,ram,rom,kbd,videoMode,paddles,paddleButtonStates,speaker,cassetteIn,cassetteOut,slts),
picgen(tv,videoMode,revision), picgen(tv,videoMode,revision),
video(videoMode,addressBus,picgen,textRows), video(videoMode,addressBus,picgen,textRows),
#ifdef USE_EMU #ifdef USE_EMU
transistors("transistors"), transistors("transistors"),
cpu(transistors,addressBus), cpu(transistors,addressBus),
#else #else
cpu(addressBus), cpu(addressBus),
#endif #endif
powerUpReset(*this), powerUpReset(*this),
revision(1) revision(1)
{ {
} }
@ -80,21 +80,21 @@ void Apple2::tick() {
void Apple2::powerOn() void Apple2::powerOn()
{ {
this->ram.powerOn(); this->ram.powerOn();
this->cpu.powerOn(); this->cpu.powerOn();
this->videoMode.powerOn(); this->videoMode.powerOn();
this->video.powerOn(); this->video.powerOn();
this->picgen.powerOn(); this->picgen.powerOn();
this->powerUpReset.powerOn(); this->powerUpReset.powerOn();
} }
void Apple2::powerOff() void Apple2::powerOff()
{ {
this->ram.powerOff(); this->ram.powerOff();
} }
void Apple2::reset() void Apple2::reset()
{ {
this->cpu.reset(); this->cpu.reset();
this->slts.reset(); this->slts.reset();
} }

View File

@ -46,39 +46,39 @@ class ScreenImage;
class Apple2 : public Timable class Apple2 : public Timable
{ {
Slots slts; Slots slts;
VideoMode videoMode; VideoMode videoMode;
Keyboard kbd; Keyboard kbd;
Paddles paddles; Paddles paddles;
SpeakerClicker speaker; SpeakerClicker speaker;
Memory rom; Memory rom;
MemoryRandomAccess ram; MemoryRandomAccess ram;
CassetteIn cassetteIn; CassetteIn cassetteIn;
CassetteOut cassetteOut; CassetteOut cassetteOut;
AddressBus addressBus; AddressBus addressBus;
PictureGenerator picgen; PictureGenerator picgen;
TextCharacters textRows; TextCharacters textRows;
Video video; Video video;
#ifdef USE_EMU #ifdef USE_EMU
std::ifstream transistors; std::ifstream transistors;
Emu6502 cpu; Emu6502 cpu;
#else #else
CPU cpu; CPU cpu;
#endif #endif
PowerUpReset powerUpReset; PowerUpReset powerUpReset;
int revision; int revision;
public: public:
Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui); Apple2(KeypressQueue& keypresses, PaddleButtonStates& paddleButtonStates, AnalogTV& tv, HyperMode& fhyper, KeyboardBufferMode& buffered, ScreenImage& gui);
~Apple2(); ~Apple2();
void powerOn(); void powerOn();
void powerOff(); void powerOff();
void reset(); void reset();
virtual void tick(); virtual void tick();
friend class Emulator; friend class Emulator;
}; };
#endif #endif

View File

@ -21,31 +21,31 @@
class AppleNTSC class AppleNTSC
{ {
private: private:
AppleNTSC() {} AppleNTSC() {}
public: public:
enum { V = 262, H = (25+40)*14+2 }; enum { V = 262, H = (25+40)*14+2 };
enum { SIGNAL_LEN = V*H }; enum { SIGNAL_LEN = V*H };
enum enum
{ {
FP_START = 0, FP_START = 0,
SYNC_START = FP_START+126, SYNC_START = FP_START+126,
BP_START = SYNC_START+112, BP_START = SYNC_START+112,
CB_START = BP_START+0, CB_START = BP_START+0,
CB_END = CB_START+56, CB_END = CB_START+56,
SPIKE = CB_END+34, SPIKE = CB_END+34,
PIC_START = CB_END+56 PIC_START = CB_END+56
}; };
enum enum
{ {
WHITE_LEVEL = 100, WHITE_LEVEL = 100,
BLANK_LEVEL = 0, BLANK_LEVEL = 0,
SYNC_LEVEL = -40, SYNC_LEVEL = -40,
CB_LEVEL = 20, CB_LEVEL = 20,
LEVEL_RANGE = WHITE_LEVEL-SYNC_LEVEL LEVEL_RANGE = WHITE_LEVEL-SYNC_LEVEL
}; };
}; };
#endif #endif

View File

@ -19,8 +19,8 @@
#include "configep2.h" #include "configep2.h"
Card::Card(): Card::Card():
rom(0x0100), rom(0x0100),
seventhRom(0x0800) seventhRom(0x0800)
{ {
} }
@ -41,44 +41,44 @@ void Card::tick()
unsigned char Card::io(const unsigned short /*address*/, const unsigned char data, const bool /*writing*/) unsigned char Card::io(const unsigned short /*address*/, const unsigned char data, const bool /*writing*/)
{ {
return data; return data;
} }
unsigned char Card::readRom(const unsigned short address, const unsigned char data) unsigned char Card::readRom(const unsigned short address, const unsigned char data)
{ {
this->activeSeventhRom = true; this->activeSeventhRom = true;
return this->rom.read(address, data); return this->rom.read(address, data);
} }
void Card::readSeventhRom(const unsigned short address, unsigned char* const pb) void Card::readSeventhRom(const unsigned short address, unsigned char* const pb)
{ {
if (address == 0x7FF) if (address == 0x7FF)
{ {
this->activeSeventhRom = false; this->activeSeventhRom = false;
} }
else if (this->activeSeventhRom && hasSeventhRom()) else if (this->activeSeventhRom && hasSeventhRom())
{ {
*pb = this->seventhRom.read(address, *pb); *pb = this->seventhRom.read(address, *pb);
} }
} }
void Card::loadRom(const unsigned short base, std::istream& in) void Card::loadRom(const unsigned short base, std::istream& in)
{ {
this->rom.load(base,in); this->rom.load(base,in);
} }
void Card::loadSeventhRom(const unsigned short base, std::istream& in) void Card::loadSeventhRom(const unsigned short base, std::istream& in)
{ {
this->seventhRom.load(base,in); this->seventhRom.load(base,in);
} }
bool Card::inhibitMotherboardRom() bool Card::inhibitMotherboardRom()
{ {
return false; return false;
} }
@ -91,17 +91,17 @@ void Card::ioBankRom(const unsigned short /*addr*/, unsigned char* const /*pb*/,
void Card::loadBankRom(const unsigned short /*base*/, std::istream& /*in*/) void Card::loadBankRom(const unsigned short /*base*/, std::istream& /*in*/)
{ {
throw ConfigException("This card has no $D000 ROM"); throw ConfigException("This card has no $D000 ROM");
} }
std::string Card::getName() std::string Card::getName()
{ {
return ""; return "";
} }
bool Card::isDirty() bool Card::isDirty()
{ {
return false; return false;
} }
void Card::save(int unit) void Card::save(int unit)

View File

@ -26,28 +26,28 @@
class Card class Card
{ {
private: private:
bool activeSeventhRom; bool activeSeventhRom;
protected: protected:
Memory rom; Memory rom;
Memory seventhRom; Memory seventhRom;
public: public:
Card(); Card();
virtual ~Card(); virtual ~Card();
virtual void tick(); virtual void tick();
virtual void reset(); virtual void reset();
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing); virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
virtual unsigned char readRom(const unsigned short address, const unsigned char data); virtual unsigned char readRom(const unsigned short address, const unsigned char data);
virtual bool hasSeventhRom() { return false; } virtual bool hasSeventhRom() { return false; }
virtual void readSeventhRom(const unsigned short address, unsigned char* const pb); virtual void readSeventhRom(const unsigned short address, unsigned char* const pb);
virtual void loadRom(const unsigned short base, std::istream& in); virtual void loadRom(const unsigned short base, std::istream& in);
virtual void loadSeventhRom(const unsigned short base, std::istream& in); virtual void loadSeventhRom(const unsigned short base, std::istream& in);
virtual bool inhibitMotherboardRom(); virtual bool inhibitMotherboardRom();
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write); virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
virtual void loadBankRom(const unsigned short base, std::istream& in); virtual void loadBankRom(const unsigned short base, std::istream& in);
virtual bool isDirty(); virtual bool isDirty();
virtual void save(int unit); virtual void save(int unit);
virtual std::string getName(); virtual std::string getName();
}; };
#endif #endif

View File

@ -233,7 +233,7 @@ bool CassetteIn::load(const std::string& filePath) {
if (!eject()) { if (!eject()) {
return false; return false;
} }
} }
/* convert input sample to floating-point, at rate of 10 CPU cycles per sample, for easy calculation */ /* convert input sample to floating-point, at rate of 10 CPU cycles per sample, for easy calculation */
SDL_AudioCVT cvt; SDL_AudioCVT cvt;
@ -256,7 +256,7 @@ bool CassetteIn::load(const std::string& filePath) {
rewind(); rewind();
tone(); tone();
return true; return true;
} }
bool CassetteIn::eject() { bool CassetteIn::eject() {

View File

@ -30,9 +30,9 @@ ClipboardHandler::~ClipboardHandler()
std::string ClipboardHandler::getText() std::string ClipboardHandler::getText()
{ {
std::string ret; std::string ret;
char* sdlAllocatedText = SDL_GetClipboardText(); char* sdlAllocatedText = SDL_GetClipboardText();
ret.assign(sdlAllocatedText); ret.assign(sdlAllocatedText);
SDL_free(sdlAllocatedText); SDL_free(sdlAllocatedText);
return ret; return ret;
} }

View File

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

View File

@ -19,8 +19,8 @@
#include <ctime> #include <ctime>
ClockCard::ClockCard(): ClockCard::ClockCard():
latch(0), latch(0),
pos(0) pos(0)
{ {
} }
@ -33,38 +33,38 @@ ClockCard::~ClockCard()
unsigned char ClockCard::io(const unsigned short address, const unsigned char data, const bool writing) unsigned char ClockCard::io(const unsigned short address, const unsigned char data, const bool writing)
{ {
const int sw = address & 0x0F; const int sw = address & 0x0F;
if (sw == 0) if (sw == 0)
{ {
if (!(this->latch & 0x80)) if (!(this->latch & 0x80))
{ {
if (this->pos == 0) if (this->pos == 0)
{ {
getTime(); getTime();
} }
char c = this->time[this->pos]; char c = this->time[this->pos];
this->latch = (unsigned char)(c | 0x80); this->latch = (unsigned char)(c | 0x80);
++this->pos; ++this->pos;
if (this->pos >= this->timelen) if (this->pos >= this->timelen)
{ {
this->pos = 0; this->pos = 0;
} }
} }
} }
else if (sw == 1) else if (sw == 1)
{ {
this->latch &= 0x7F; this->latch &= 0x7F;
} }
return this->latch; return this->latch;
} }
#define TIMEFORMAT "%m,0%w,%d,%H,%M,%S,000,%Y,%Z,D\r" #define TIMEFORMAT "%m,0%w,%d,%H,%M,%S,000,%Y,%Z,D\r"
void ClockCard::getTime() void ClockCard::getTime()
{ {
time_t now; time_t now;
::time(&now); ::time(&now);
struct tm* nowtm = ::localtime(&now); struct tm* nowtm = ::localtime(&now);
this->timelen = ::strftime(this->time,sizeof(this->time),TIMEFORMAT,nowtm); this->timelen = ::strftime(this->time,sizeof(this->time),TIMEFORMAT,nowtm);
this->time[this->timelen-2] = nowtm->tm_isdst>0 ? '1' : '0'; this->time[this->timelen-2] = nowtm->tm_isdst>0 ? '1' : '0';
} }

View File

@ -24,19 +24,19 @@
class ClockCard : public Card class ClockCard : public Card
{ {
private: private:
unsigned char latch; unsigned char latch;
unsigned int pos; unsigned int pos;
char time[64]; char time[64];
size_t timelen; size_t timelen;
void getTime(); void getTime();
public: public:
ClockCard(); ClockCard();
~ClockCard(); ~ClockCard();
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing); virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
virtual std::string getName() { return "clock"; } virtual std::string getName() { return "clock"; }
}; };
#endif #endif

File diff suppressed because it is too large Load Diff

338
src/cpu.h
View File

@ -23,195 +23,195 @@ class AddressBus;
class CPU class CPU
{ {
private: private:
enum { MEMORY_LIM = 1 << 0x10 }; enum { MEMORY_LIM = 1 << 0x10 };
enum { IRQ_VECTOR = MEMORY_LIM-2 }; // or BRK enum { IRQ_VECTOR = MEMORY_LIM-2 }; // or BRK
enum { RESET_VECTOR = IRQ_VECTOR-2 }; // or power-on enum { RESET_VECTOR = IRQ_VECTOR-2 }; // or power-on
enum { NMI_VECTOR = RESET_VECTOR-2 }; enum { NMI_VECTOR = RESET_VECTOR-2 };
unsigned char adl; unsigned char adl;
unsigned char adh; unsigned char adh;
unsigned char bal; unsigned char bal;
unsigned char bah; unsigned char bah;
unsigned char ial; unsigned char ial;
unsigned char iah; unsigned char iah;
unsigned char idx; unsigned char idx;
signed char offset; signed char offset;
bool branch; bool branch;
signed char sc; signed char sc;
bool wc; bool wc;
bool pendingIRQ; bool pendingIRQ;
bool pendingNMI; bool pendingNMI;
bool pendingReset; bool pendingReset;
bool started; bool started;
unsigned char a; unsigned char a;
unsigned char x; unsigned char x;
unsigned char y; unsigned char y;
unsigned char s; unsigned char s;
//p = NVMBDIZC //p = NVMBDIZC
enum { PMASK_C = 1<<0 }; enum { PMASK_C = 1<<0 };
enum { PMASK_Z = 1<<1 }; enum { PMASK_Z = 1<<1 };
enum { PMASK_I = 1<<2 }; enum { PMASK_I = 1<<2 };
enum { PMASK_D = 1<<3 }; enum { PMASK_D = 1<<3 };
enum { PMASK_B = 1<<4 }; enum { PMASK_B = 1<<4 };
enum { PMASK_M = 1<<5 }; enum { PMASK_M = 1<<5 };
enum { PMASK_V = 1<<6 }; enum { PMASK_V = 1<<6 };
enum { PMASK_N = 1<<7 }; enum { PMASK_N = 1<<7 };
unsigned char p; unsigned char p;
unsigned short pc; unsigned short pc;
AddressBus& addressBus; AddressBus& addressBus;
unsigned short address; unsigned short address;
unsigned char data; unsigned char data;
unsigned short opcode; unsigned short opcode;
signed char t; signed char t;
static void (CPU::*addr[])(); static void (CPU::*addr[])();
static void (CPU::*exec[])(); static void (CPU::*exec[])();
void firstCycle(); void firstCycle();
int getInterruptAddress(); int getInterruptAddress();
int getInterruptPseudoOpCode(); int getInterruptPseudoOpCode();
void subsequentCycle(); void subsequentCycle();
void read(); void read();
void write(); void write();
void execute(); void execute();
void done(); void done();
unsigned char pch(); unsigned char pch();
unsigned char pcl(); unsigned char pcl();
unsigned short sp(); unsigned short sp();
unsigned short push(); unsigned short push();
unsigned short pull(); unsigned short pull();
unsigned char getIndex(); unsigned char getIndex();
unsigned short ad(); unsigned short ad();
unsigned short ia(); unsigned short ia();
unsigned short ba(); unsigned short ba();
unsigned short combine(const unsigned char lo, const unsigned char hi); unsigned short combine(const unsigned char lo, const unsigned char hi);
void setP(const unsigned char mask, const unsigned char val); void setP(const unsigned char mask, const unsigned char val);
void setStatusRegisterNZ(const unsigned char val); void setStatusRegisterNZ(const unsigned char val);
unsigned char shiftLeft(unsigned char byt); unsigned char shiftLeft(unsigned char byt);
unsigned char shiftRight(unsigned char byt); unsigned char shiftRight(unsigned char byt);
unsigned char rotateLeft(unsigned char byt); unsigned char rotateLeft(unsigned char byt);
unsigned char rotateRight(unsigned char byt); unsigned char rotateRight(unsigned char byt);
void compare(const unsigned char r); void compare(const unsigned char r);
void addr_SINGLE(); void addr_SINGLE();
void addr_INTERNAL_IMMEDIATE(); void addr_INTERNAL_IMMEDIATE();
void addr_INTERNAL_ZERO_PAGE(); void addr_INTERNAL_ZERO_PAGE();
void addr_INTERNAL_ABSOLUTE(); void addr_INTERNAL_ABSOLUTE();
void addr_INTERNAL_INDIRECT_X(); void addr_INTERNAL_INDIRECT_X();
void addr_INTERNAL_ABSOLUTE_XY(); void addr_INTERNAL_ABSOLUTE_XY();
void addr_INTERNAL_ZERO_PAGE_XY(); void addr_INTERNAL_ZERO_PAGE_XY();
void addr_INTERNAL_INDIRECT_Y(); void addr_INTERNAL_INDIRECT_Y();
void addr_STORE_ZERO_PAGE(); void addr_STORE_ZERO_PAGE();
void addr_STORE_ABSOLUTE(); void addr_STORE_ABSOLUTE();
void addr_STORE_INDIRECT_X(); void addr_STORE_INDIRECT_X();
void addr_STORE_ABSOLUTE_XY(); void addr_STORE_ABSOLUTE_XY();
void addr_STORE_ZERO_PAGE_XY(); void addr_STORE_ZERO_PAGE_XY();
void addr_STORE_INDIRECT_Y(); void addr_STORE_INDIRECT_Y();
void addr_RMW_ZERO_PAGE(); void addr_RMW_ZERO_PAGE();
void addr_RMW_ABSOLUTE(); void addr_RMW_ABSOLUTE();
void addr_RMW_ZERO_PAGE_X(); void addr_RMW_ZERO_PAGE_X();
void addr_RMW_ABSOLUTE_X(); void addr_RMW_ABSOLUTE_X();
void addr_MISC_PUSH(); void addr_MISC_PUSH();
void addr_MISC_PULL(); void addr_MISC_PULL();
void addr_MISC_JSR(); void addr_MISC_JSR();
void addr_MISC_BREAK(); void addr_MISC_BREAK();
void addr_MISC_RTI(); void addr_MISC_RTI();
void addr_JMP_ABSOLUTE(); void addr_JMP_ABSOLUTE();
void addr_JMP_INDIRECT(); void addr_JMP_INDIRECT();
void addr_RTS(); void addr_RTS();
void addr_BRANCH(); void addr_BRANCH();
void addr_NMI(); void addr_NMI();
void addr_RESET(); void addr_RESET();
void addr_IRQ(); void addr_IRQ();
void LDA(); void LDA();
void LDX(); void LDX();
void LDY(); void LDY();
void STA(); void STA();
void STX(); void STX();
void STY(); void STY();
void CMP(); void CMP();
void CPX(); void CPX();
void CPY(); void CPY();
void AND(); void AND();
void ORA(); void ORA();
void EOR(); void EOR();
void ASL(); void ASL();
void ASL_A(); void ASL_A();
void LSR(); void LSR();
void LSR_A(); void LSR_A();
void ROL(); void ROL();
void ROL_A(); void ROL_A();
void ROR(); void ROR();
void ROR_A(); void ROR_A();
void ADC(); void ADC();
void SBC(); void SBC();
void INC(); void INC();
void DEC(); void DEC();
void INX(); void INX();
void INY(); void INY();
void DEX(); void DEX();
void DEY(); void DEY();
void BIT(); void BIT();
void PHA(); void PHA();
void PHP(); void PHP();
void PLA(); void PLA();
void PLP(); void PLP();
void BRK(); void BRK();
void RTI(); void RTI();
void JMP(); void JMP();
void RTS(); void RTS();
void JSR(); void JSR();
void BNE(); void BNE();
void BEQ(); void BEQ();
void BVC(); void BVC();
void BVS(); void BVS();
void BCC(); void BCC();
void BCS(); void BCS();
void BPL(); void BPL();
void BMI(); void BMI();
void TAX(); void TAX();
void TXA(); void TXA();
void TAY(); void TAY();
void TYA(); void TYA();
void TXS(); void TXS();
void TSX(); void TSX();
void CLC(); void CLC();
void SEC(); void SEC();
void CLI(); void CLI();
void SEI(); void SEI();
void CLV(); void CLV();
void CLD(); void CLD();
void SED(); void SED();
void NOP(); void NOP();
void Unoff(); void Unoff();
void Unoff1(); void Unoff1();
void Unoff2(); void Unoff2();
void Unoff3(); void Unoff3();
void Hang(); void Hang();
public: public:
CPU(AddressBus& addressBus); CPU(AddressBus& addressBus);
~CPU(); ~CPU();
void powerOn(); void powerOn();
void reset(); void reset();
void IRQ(); void IRQ();
void NMI(); void NMI();
void tick(); void tick();
}; };
#endif #endif

View File

@ -21,148 +21,148 @@
class E2Const class E2Const
{ {
public: public:
/* /*
The NTSC standard defines the field rate as 60 fields per second. The number 60 The NTSC standard defines the field rate as 60 fields per second. The number 60
is based on the USA AC current frequency of 60 Hz. This, in turn, was based on the is based on the USA AC current frequency of 60 Hz. This, in turn, was based on the
clock standard (60 seconds per minute and 60 minutes per hour). clock standard (60 seconds per minute and 60 minutes per hour).
*/ */
static const int NTSC_FIELD_HZ = 60; static const int NTSC_FIELD_HZ = 60;
/* /*
The NTSC standard defines 525 lines per frame, which was chosen to be a multiple The NTSC standard defines 525 lines per frame, which was chosen to be a multiple
of a small number of standard tubes at the time, to produce a rate between RCA's of a small number of standard tubes at the time, to produce a rate between RCA's
recommended 441 (used by NBC) and Philco's suggested 600-800 lines. recommended 441 (used by NBC) and Philco's suggested 600-800 lines.
*/ */
static const int NTSC_LINES_PER_FRAME = 3*5*5*7; static const int NTSC_LINES_PER_FRAME = 3*5*5*7;
/* /*
When color was added to the NTSC signal, studies by General Electric showed that When color was added to the NTSC signal, studies by General Electric showed that
minimum interference was achieved using a subcarrier frequency 455 times the field minimum interference was achieved using a subcarrier frequency 455 times the field
rate, which can also be obtained using standard tubes. rate, which can also be obtained using standard tubes.
*/ */
static const int NTSC_COLOR_MULTIPLE = 5*7*13; static const int NTSC_COLOR_MULTIPLE = 5*7*13;
/* /*
Adding color to NTSC also required slowing down the frame rate, by dropping one Adding color to NTSC also required slowing down the frame rate, by dropping one
field after every 1000. field after every 1000.
*/ */
static const int NTSC_COLOR_DROP_FIELD = 1000; static const int NTSC_COLOR_DROP_FIELD = 1000;
/* /*
Calculate the color sub-channel rate, times 4. Calculate the color sub-channel rate, times 4.
This will be the (approximate) Hz of the "14M" This will be the (approximate) Hz of the "14M"
crystal oscillator in the Apple ][. crystal oscillator in the Apple ][.
14318181.818181818... Hz rounds to 14318182 Hz 14318181.818181818... Hz rounds to 14318182 Hz
U.A.II, p.3-2 U.A.II, p.3-2
*/ */
static const int CRYSTAL_HZ = (int)(1.0F*NTSC_FIELD_HZ * NTSC_LINES_PER_FRAME * NTSC_COLOR_MULTIPLE * NTSC_COLOR_DROP_FIELD / (NTSC_COLOR_DROP_FIELD+1)); static const int CRYSTAL_HZ = (int)(1.0F*NTSC_FIELD_HZ * NTSC_LINES_PER_FRAME * NTSC_COLOR_MULTIPLE * NTSC_COLOR_DROP_FIELD / (NTSC_COLOR_DROP_FIELD+1));
/* /*
U.A.II, p. 3-3 U.A.II, p. 3-3
Normal 6502 cycle == 14 crystal periods Normal 6502 cycle == 14 crystal periods
Long 6502 cycle == 16 crystal periods Long 6502 cycle == 16 crystal periods
*/ */
static const int CRYSTAL_CYCLES_PER_CPU_CYCLE = 14; static const int CRYSTAL_CYCLES_PER_CPU_CYCLE = 14;
static const int EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE = 2; static const int EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE = 2;
/* /*
65 bytes per row (64 normal CPU cycles plus one long CPU cycle) 65 bytes per row (64 normal CPU cycles plus one long CPU cycle)
*/ */
static const int BYTES_PER_ROW = (int)((NTSC_COLOR_DROP_FIELD+1)*1.0F*CRYSTAL_HZ/(NTSC_FIELD_HZ/2*NTSC_COLOR_DROP_FIELD*NTSC_LINES_PER_FRAME*CRYSTAL_CYCLES_PER_CPU_CYCLE)); static const int BYTES_PER_ROW = (int)((NTSC_COLOR_DROP_FIELD+1)*1.0F*CRYSTAL_HZ/(NTSC_FIELD_HZ/2*NTSC_COLOR_DROP_FIELD*NTSC_LINES_PER_FRAME*CRYSTAL_CYCLES_PER_CPU_CYCLE));
static const int HORIZ_CYCLES = BYTES_PER_ROW; static const int HORIZ_CYCLES = BYTES_PER_ROW;
/* /*
U.A.II, p. 3-2, "composite frequency... 1.0205 MHz" U.A.II, p. 3-2, "composite frequency... 1.0205 MHz"
Actually 1020484 Hz. Actually 1020484 Hz.
*/ */
static const int AVG_CPU_HZ = (int)((1.0F*CRYSTAL_HZ*HORIZ_CYCLES)/(CRYSTAL_CYCLES_PER_CPU_CYCLE*HORIZ_CYCLES+EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE)); static const int AVG_CPU_HZ = (int)((1.0F*CRYSTAL_HZ*HORIZ_CYCLES)/(CRYSTAL_CYCLES_PER_CPU_CYCLE*HORIZ_CYCLES+EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE));
/* /*
A normal NTSC field is 262.5 lines (half of a full frame's 525 lines). A normal NTSC field is 262.5 lines (half of a full frame's 525 lines).
The Apple rounds this down to 262 lines. The Apple rounds this down to 262 lines.
*/ */
static const int NTSC_WHOLE_LINES_PER_FIELD = NTSC_LINES_PER_FRAME/2; static const int NTSC_WHOLE_LINES_PER_FIELD = NTSC_LINES_PER_FRAME/2;
static const int BYTES_PER_FIELD = BYTES_PER_ROW*NTSC_WHOLE_LINES_PER_FIELD; static const int BYTES_PER_FIELD = BYTES_PER_ROW*NTSC_WHOLE_LINES_PER_FIELD;
// exactly 1 million // exactly 1 million
static const int MEGA = 1000000; static const int MEGA = 1000000;
static const int VISIBLE_BITS_PER_BYTE = 7; static const int VISIBLE_BITS_PER_BYTE = 7;
static const int VISIBLE_LINES_PER_CHARACTER = 8; static const int VISIBLE_LINES_PER_CHARACTER = 8;
/* /*
* 1000+1 seconds 2 fields 1 frame 1000000 microseconds 63 50 * 1000+1 seconds 2 fields 1 frame 1000000 microseconds 63 50
* total horizontal line period = -------------- * -------- * ------------- * -------------------- = ( -- + -- ) microseconds per line * total horizontal line period = -------------- * -------- * ------------- * -------------------- = ( -- + -- ) microseconds per line
* 60*1000 fields 1 frame 3*5*5*7 lines 1 second 90 * 60*1000 fields 1 frame 3*5*5*7 lines 1 second 90
* *
* 10 81 * 10 81
* horizontal blanking period = (1.5+4.7+.6+2.5+1.6) = 10.9 microseconds per line = ( -- + -- ) microseconds per line * horizontal blanking period = (1.5+4.7+.6+2.5+1.6) = 10.9 microseconds per line = ( -- + -- ) microseconds per line
* 90 * 90
* *
* visible line period = total horizontal line period minus horizontal blanking period = * visible line period = total horizontal line period minus horizontal blanking period =
* *
* 52 59 * 52 59
* -- + -- microseconds per line * -- + -- microseconds per line
* 90 * 90
* *
* *
* To avoid the over-scan area, the Apple ][ uses only the middle 75% of the visible line, or 4739/120 microseconds * To avoid the over-scan area, the Apple ][ uses only the middle 75% of the visible line, or 4739/120 microseconds
* *
* Apple ][ uses half the clock rate, or 315/44 MHz, to oscillate the video signal. * Apple ][ uses half the clock rate, or 315/44 MHz, to oscillate the video signal.
* *
* The result is 315/44 MHz * 4739/120 microseconds/line, rounded down, = 282 full pixel spots across the screen. * The result is 315/44 MHz * 4739/120 microseconds/line, rounded down, = 282 full pixel spots across the screen.
* The Apple ][ displays 7 bits per byte hi-res or lo-res, (or 7 pixel-wide characters for text mode), so that * The Apple ][ displays 7 bits per byte hi-res or lo-res, (or 7 pixel-wide characters for text mode), so that
* gives 282/7, which rounds down to 40 bytes per line. * gives 282/7, which rounds down to 40 bytes per line.
*/ */
static const int VISIBLE_BYTES_PER_ROW = (int)((((1.0F*(NTSC_COLOR_DROP_FIELD+1)/(NTSC_FIELD_HZ*NTSC_COLOR_DROP_FIELD)*2/NTSC_LINES_PER_FRAME*MEGA)-(1.5+4.7+.6+2.5+1.6)) * 3/4) * (CRYSTAL_HZ/2)) / MEGA / VISIBLE_BITS_PER_BYTE; static const int VISIBLE_BYTES_PER_ROW = (int)((((1.0F*(NTSC_COLOR_DROP_FIELD+1)/(NTSC_FIELD_HZ*NTSC_COLOR_DROP_FIELD)*2/NTSC_LINES_PER_FRAME*MEGA)-(1.5+4.7+.6+2.5+1.6)) * 3/4) * (CRYSTAL_HZ/2)) / MEGA / VISIBLE_BITS_PER_BYTE;
/* /*
* NTSC total lines per frame (525) minus unusable lines (19 plus 20) = 486 usable lines * NTSC total lines per frame (525) minus unusable lines (19 plus 20) = 486 usable lines
* To avoid the over-scan area, use the middle 80% of the vertical lines, giving 388 (rounded down) clearly visible lines * To avoid the over-scan area, use the middle 80% of the vertical lines, giving 388 (rounded down) clearly visible lines
* Apple ][ uses only half the vertical resolution because it doesn't interlace, giving 194. * Apple ][ uses only half the vertical resolution because it doesn't interlace, giving 194.
* Text characters are 8 pixels tall, so 194/8 rounded down gives 24 text lines. * Text characters are 8 pixels tall, so 194/8 rounded down gives 24 text lines.
* Multiply by 8 to give 192 lines total. * Multiply by 8 to give 192 lines total.
*/ */
static const int VISIBLE_ROWS_PER_FIELD = (NTSC_LINES_PER_FRAME-(20+19)) * 8/10 / 2 /VISIBLE_LINES_PER_CHARACTER*VISIBLE_LINES_PER_CHARACTER; static const int VISIBLE_ROWS_PER_FIELD = (NTSC_LINES_PER_FRAME-(20+19)) * 8/10 / 2 /VISIBLE_LINES_PER_CHARACTER*VISIBLE_LINES_PER_CHARACTER;
static const int BLANKED_BYTES_PER_ROW = BYTES_PER_ROW-VISIBLE_BYTES_PER_ROW; static const int BLANKED_BYTES_PER_ROW = BYTES_PER_ROW-VISIBLE_BYTES_PER_ROW;
static const int VISIBLE_BYTES_PER_FIELD = BYTES_PER_ROW*VISIBLE_ROWS_PER_FIELD; static const int VISIBLE_BYTES_PER_FIELD = BYTES_PER_ROW*VISIBLE_ROWS_PER_FIELD;
static const int SCANNABLE_ROWS = 0x100; static const int SCANNABLE_ROWS = 0x100;
static const int SCANNABLE_BYTES = SCANNABLE_ROWS*BYTES_PER_ROW; static const int SCANNABLE_BYTES = SCANNABLE_ROWS*BYTES_PER_ROW;
static const int RESET_ROWS = NTSC_WHOLE_LINES_PER_FIELD-SCANNABLE_ROWS; static const int RESET_ROWS = NTSC_WHOLE_LINES_PER_FIELD-SCANNABLE_ROWS;
static const int RESET_BYTES = RESET_ROWS*BYTES_PER_ROW; static const int RESET_BYTES = RESET_ROWS*BYTES_PER_ROW;
static const int MIXED_TEXT_LINES = 4; static const int MIXED_TEXT_LINES = 4;
static const int ROWS_PER_TEXT_LINE = 8; static const int ROWS_PER_TEXT_LINE = 8;
static const int MIXED_TEXT_CYCLE = (VISIBLE_ROWS_PER_FIELD-MIXED_TEXT_LINES*ROWS_PER_TEXT_LINE)*BYTES_PER_ROW; static const int MIXED_TEXT_CYCLE = (VISIBLE_ROWS_PER_FIELD-MIXED_TEXT_LINES*ROWS_PER_TEXT_LINE)*BYTES_PER_ROW;
static int test() static int test()
{ {
if (NTSC_FIELD_HZ!=60) return NTSC_FIELD_HZ; if (NTSC_FIELD_HZ!=60) return NTSC_FIELD_HZ;
if (NTSC_LINES_PER_FRAME!=525) return NTSC_LINES_PER_FRAME; if (NTSC_LINES_PER_FRAME!=525) return NTSC_LINES_PER_FRAME;
if (NTSC_COLOR_MULTIPLE!=455) return NTSC_COLOR_MULTIPLE; if (NTSC_COLOR_MULTIPLE!=455) return NTSC_COLOR_MULTIPLE;
if (NTSC_COLOR_DROP_FIELD!=1000) return NTSC_COLOR_DROP_FIELD; if (NTSC_COLOR_DROP_FIELD!=1000) return NTSC_COLOR_DROP_FIELD;
if (CRYSTAL_HZ!=14318182) return CRYSTAL_HZ; if (CRYSTAL_HZ!=14318182) return CRYSTAL_HZ;
if (BYTES_PER_ROW!=65) return BYTES_PER_ROW; if (BYTES_PER_ROW!=65) return BYTES_PER_ROW;
if (AVG_CPU_HZ!=1020484) return AVG_CPU_HZ; if (AVG_CPU_HZ!=1020484) return AVG_CPU_HZ;
if (BYTES_PER_FIELD!=17030) return BYTES_PER_FIELD; if (BYTES_PER_FIELD!=17030) return BYTES_PER_FIELD;
if (VISIBLE_BYTES_PER_ROW!=40) return VISIBLE_BYTES_PER_ROW; if (VISIBLE_BYTES_PER_ROW!=40) return VISIBLE_BYTES_PER_ROW;
if (VISIBLE_ROWS_PER_FIELD!=192) return VISIBLE_ROWS_PER_FIELD; if (VISIBLE_ROWS_PER_FIELD!=192) return VISIBLE_ROWS_PER_FIELD;
if (RESET_BYTES!=390) return RESET_BYTES; if (RESET_BYTES!=390) return RESET_BYTES;
if (BLANKED_BYTES_PER_ROW!=25) return BLANKED_BYTES_PER_ROW; if (BLANKED_BYTES_PER_ROW!=25) return BLANKED_BYTES_PER_ROW;
if (VISIBLE_BYTES_PER_FIELD!=12480) return VISIBLE_BYTES_PER_FIELD; if (VISIBLE_BYTES_PER_FIELD!=12480) return VISIBLE_BYTES_PER_FIELD;
if (SCANNABLE_BYTES!=16640) return SCANNABLE_BYTES; if (SCANNABLE_BYTES!=16640) return SCANNABLE_BYTES;
return -1; return -1;
} }
}; };

View File

@ -23,14 +23,14 @@
class EmptySlot : public Card class EmptySlot : public Card
{ {
public: public:
EmptySlot() {} EmptySlot() {}
virtual ~EmptySlot() {} virtual ~EmptySlot() {}
virtual std::string getName() { return "[empty]"; } virtual std::string getName() { return "[empty]"; }
// empty slots have no ROMs, so just return data (for floating bus emulation) // empty slots have no ROMs, so just return data (for floating bus emulation)
virtual unsigned char readRom(const unsigned short address, const unsigned char data) { return data; } virtual unsigned char readRom(const unsigned short address, const unsigned char data) { return data; }
virtual void readSeventhRom(const unsigned short address, unsigned char* const pb) { } virtual void readSeventhRom(const unsigned short address, unsigned char* const pb) { }
}; };
#endif #endif

View File

@ -34,48 +34,48 @@ class Config;
class Emulator class Emulator
{ {
PaddleButtonStates paddleButtonStates; PaddleButtonStates paddleButtonStates;
KeypressQueue keypresses; KeypressQueue keypresses;
HyperMode fhyper; HyperMode fhyper;
KeyboardBufferMode buffered; KeyboardBufferMode buffered;
ScreenImage screenImage; ScreenImage screenImage;
AnalogTV display; AnalogTV display;
VideoStaticGenerator videoStatic; VideoStaticGenerator videoStatic;
Apple2 apple2; Apple2 apple2;
ClipboardHandler clip; ClipboardHandler clip;
Timable* timable; Timable* timable;
bool quit; bool quit;
bool repeat; bool repeat;
int keysDown; int keysDown;
int rept; int rept;
unsigned char lastKeyDown; unsigned char lastKeyDown;
bool command; bool command;
bool pendingCommandExit; bool pendingCommandExit;
std::string cmdline; std::string cmdline;
void dispatchKeypress(const SDL_KeyboardEvent& keyEvent); void dispatchKeypress(const SDL_KeyboardEvent& keyEvent);
void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent); void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent);
void cmdKey(const SDL_KeyboardEvent& keyEvent); void cmdKey(const SDL_KeyboardEvent& keyEvent);
void processCommand(); void processCommand();
bool isSafeToQuit(); bool isSafeToQuit();
public: public:
Emulator(); Emulator();
virtual ~Emulator(); virtual ~Emulator();
void config(Config& cfg); void config(Config& cfg);
virtual void init(); virtual void init();
void powerOnComputer(); void powerOnComputer();
void powerOffComputer(); void powerOffComputer();
void toggleComputerPower(); void toggleComputerPower();
void cycleDisplayType(); void cycleDisplayType();
virtual int run(); virtual int run();
}; };
#endif #endif

View File

@ -19,12 +19,12 @@
#include "memory.h" #include "memory.h"
FirmwareCard::FirmwareCard(ScreenImage& gui, int slot): FirmwareCard::FirmwareCard(ScreenImage& gui, int slot):
gui(gui), gui(gui),
slot(slot), slot(slot),
inhibitBankRom(false), inhibitBankRom(false),
inhibitF8Rom(false), inhibitF8Rom(false),
inhibit(false), inhibit(false),
bankRom(0x10000-0xD000) bankRom(0x10000-0xD000)
{ {
} }
@ -40,21 +40,21 @@ FirmwareCard::~FirmwareCard()
void FirmwareCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool) void FirmwareCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool)
{ {
this->inhibit = false; this->inhibit = false;
if (addr < 0x2800) if (addr < 0x2800)
{ {
if (this->inhibitBankRom) if (this->inhibitBankRom)
{ {
*pb = this->bankRom.read(addr, *pb); *pb = this->bankRom.read(addr, *pb);
this->inhibit = true; this->inhibit = true;
} }
} }
else if (0x2800 <= addr && addr < 0x3000) else if (0x2800 <= addr && addr < 0x3000)
{ {
if (this->inhibitF8Rom) if (this->inhibitF8Rom)
{ {
*pb = this->bankRom.read(addr, *pb); *pb = this->bankRom.read(addr, *pb);
this->inhibit = true; this->inhibit = true;
} }
} }
} }

View File

@ -25,49 +25,49 @@
class FirmwareCard : public Card class FirmwareCard : public Card
{ {
private: private:
ScreenImage& gui; ScreenImage& gui;
int slot; int slot;
bool inhibitBankRom; bool inhibitBankRom;
bool inhibitF8Rom; bool inhibitF8Rom;
bool inhibit; bool inhibit;
Memory bankRom; Memory bankRom;
public: public:
FirmwareCard(ScreenImage& gui, int slot); FirmwareCard(ScreenImage& gui, int slot);
~FirmwareCard(); ~FirmwareCard();
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write); virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
virtual void reset() virtual void reset()
{ {
this->inhibitBankRom = false; this->inhibitBankRom = false;
this->inhibitF8Rom = false; this->inhibitF8Rom = false;
this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom); this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom);
} }
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing) virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing)
{ {
this->inhibitBankRom = !(address & 1); this->inhibitBankRom = !(address & 1);
this->inhibitF8Rom = (address & 2); this->inhibitF8Rom = (address & 2);
this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom); this->gui.setFirmCard(this->slot,this->inhibitBankRom,this->inhibitF8Rom);
return data; return data;
} }
virtual void loadBankRom(const unsigned short base, std::istream& in) virtual void loadBankRom(const unsigned short base, std::istream& in)
{ {
this->bankRom.load(base,in); this->bankRom.load(base,in);
} }
virtual bool inhibitMotherboardRom() virtual bool inhibitMotherboardRom()
{ {
return this->inhibit; return this->inhibit;
} }
virtual std::string getName() { return "firmware "; } virtual std::string getName() { return "firmware "; }
}; };
#endif #endif

View File

@ -23,15 +23,15 @@
class GUI class GUI
{ {
public: public:
GUI(); GUI();
~GUI(); ~GUI();
class NotInitException : public std::runtime_error class NotInitException : public std::runtime_error
{ {
public: public:
NotInitException(); NotInitException();
virtual ~NotInitException() throw () {} virtual ~NotInitException() throw () {}
}; };
}; };

View File

@ -21,25 +21,25 @@
class HyperMode class HyperMode
{ {
private: private:
bool fhyper; bool fhyper;
public: public:
HyperMode(): fhyper(false) { } HyperMode(): fhyper(false) { }
~HyperMode() { } ~HyperMode() { }
bool isHyper() bool isHyper()
{ {
return this->fhyper; return this->fhyper;
} }
void setHyper(bool isHyper) void setHyper(bool isHyper)
{ {
this->fhyper = isHyper; this->fhyper = isHyper;
} }
void toggleHyper() void toggleHyper()
{ {
this->fhyper = !this->fhyper; this->fhyper = !this->fhyper;
} }
}; };
#endif #endif

View File

@ -20,54 +20,54 @@
#include "keyboardbuffermode.h" #include "keyboardbuffermode.h"
Keyboard::Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered): Keyboard::Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered):
keys(q), keys(q),
fhyper(fhyper), fhyper(fhyper),
buffered(buffered), buffered(buffered),
cGet(0) cGet(0)
{ {
} }
void Keyboard::clear() void Keyboard::clear()
{ {
this->latch &= 0x7F; this->latch &= 0x7F;
} }
unsigned char Keyboard::get() unsigned char Keyboard::get()
{ {
waitIfTooFast(); waitIfTooFast();
if (!this->buffered.isBuffered() || !(this->latch & 0x80)) if (!this->buffered.isBuffered() || !(this->latch & 0x80))
{ {
if (!this->keys.empty()) if (!this->keys.empty())
{ {
this->latch = this->keys.front() | 0x80; this->latch = this->keys.front() | 0x80;
this->keys.pop(); this->keys.pop();
} }
} }
return this->latch; return this->latch;
} }
void Keyboard::waitIfTooFast() void Keyboard::waitIfTooFast()
{ {
if (this->fhyper.isHyper()) if (this->fhyper.isHyper())
{ {
return; return;
} }
++this->cGet; ++this->cGet;
if (!this->cGet) if (!this->cGet)
{ {
if (SDL_GetTicks() - this->lastGet <= 1000) if (SDL_GetTicks() - this->lastGet <= 1000)
{ {
/* /*
* Check every 256 gets to see if they are * Check every 256 gets to see if they are
* happening too fast (within one second). * happening too fast (within one second).
* If so, it means we are probably just * If so, it means we are probably just
* looping waiting for a keypress, so * looping waiting for a keypress, so
* wait a millisecond (or so) just to * wait a millisecond (or so) just to
* prevent us from using 100% of CPU time. * prevent us from using 100% of CPU time.
*/ */
SDL_Delay(1); SDL_Delay(1);
} }
} }
this->lastGet = SDL_GetTicks(); this->lastGet = SDL_GetTicks();
} }

View File

@ -29,20 +29,20 @@ class KeyboardBufferMode;
class Keyboard class Keyboard
{ {
private: private:
KeypressQueue& keys; KeypressQueue& keys;
HyperMode& fhyper; HyperMode& fhyper;
KeyboardBufferMode& buffered; KeyboardBufferMode& buffered;
unsigned char latch; unsigned char latch;
unsigned char cGet; unsigned char cGet;
Uint32 lastGet; Uint32 lastGet;
void waitIfTooFast(); void waitIfTooFast();
public: public:
Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered); Keyboard(KeypressQueue& q, HyperMode& fhyper, KeyboardBufferMode& buffered);
void clear(); void clear();
unsigned char get(); unsigned char get();
}; };
#endif #endif

View File

@ -21,26 +21,26 @@
class KeyboardBufferMode class KeyboardBufferMode
{ {
private: private:
bool buffered; bool buffered;
public: public:
KeyboardBufferMode(): buffered(true) { } KeyboardBufferMode(): buffered(true) { }
~KeyboardBufferMode() { } ~KeyboardBufferMode() { }
bool isBuffered() bool isBuffered()
{ {
return this->buffered; return this->buffered;
} }
void setBuffered(bool buffered) void setBuffered(bool buffered)
{ {
this->buffered = buffered; this->buffered = buffered;
} }
void toggleBuffered() void toggleBuffered()
{ {
this->buffered = !this->buffered; this->buffered = !this->buffered;
} }
}; };
#endif #endif

View File

@ -19,17 +19,17 @@
#include "screenimage.h" #include "screenimage.h"
LanguageCard::LanguageCard(ScreenImage& gui, int slot): LanguageCard::LanguageCard(ScreenImage& gui, int slot):
gui(gui), gui(gui),
slot(slot), slot(slot),
inhibit(false), inhibit(false),
ramTop(0x10000-0xE000), ramTop(0x10000-0xE000),
bank(1), bank(1),
readEnable(false), readEnable(false),
writeEnable(true), writeEnable(true),
writeCount(0) writeCount(0)
{ {
this->ramBank.push_back(new Memory(0xE000-0xD000)); this->ramBank.push_back(new Memory(0xE000-0xD000));
this->ramBank.push_back(new Memory(0xE000-0xD000)); this->ramBank.push_back(new Memory(0xE000-0xD000));
} }
LanguageCard::~LanguageCard() LanguageCard::~LanguageCard()
@ -39,57 +39,57 @@ LanguageCard::~LanguageCard()
unsigned char LanguageCard::io(const unsigned short address, const unsigned char data, const bool writing) unsigned char LanguageCard::io(const unsigned short address, const unsigned char data, const bool writing)
{ {
if ((address & 1) && !writing) if ((address & 1) && !writing)
{ {
++this->writeCount; ++this->writeCount;
} }
else else
{ {
this->writeCount = 0; this->writeCount = 0;
} }
if (this->writeCount > 1) if (this->writeCount > 1)
{ {
this->writeEnable = true; this->writeEnable = true;
} }
if (!(address & 1)) if (!(address & 1))
{ {
this->writeEnable = false; this->writeEnable = false;
} }
const int r = address & 3; const int r = address & 3;
this->readEnable = (r==0 || r==3); this->readEnable = (r==0 || r==3);
this->bank = !(address & 8); this->bank = !(address & 8);
this->gui.setLangCard(this->slot,this->readEnable,this->writeEnable,this->bank); this->gui.setLangCard(this->slot,this->readEnable,this->writeEnable,this->bank);
return data; return data;
} }
void LanguageCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write) void LanguageCard::ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write)
{ {
this->inhibit = false; this->inhibit = false;
if (this->readEnable && !write) if (this->readEnable && !write)
{ {
if (addr < 0x1000) if (addr < 0x1000)
{ {
*pb = this->ramBank[this->bank]->read(addr, *pb); *pb = this->ramBank[this->bank]->read(addr, *pb);
} }
else else
{ {
*pb = this->ramTop.read(addr-0x1000, *pb); *pb = this->ramTop.read(addr-0x1000, *pb);
} }
this->inhibit = true; this->inhibit = true;
} }
else if (this->writeEnable && write) else if (this->writeEnable && write)
{ {
if (addr < 0x1000) if (addr < 0x1000)
{ {
this->ramBank[this->bank]->write(addr,*pb); this->ramBank[this->bank]->write(addr,*pb);
} }
else else
{ {
this->ramTop.write(addr-0x1000,*pb); this->ramTop.write(addr-0x1000,*pb);
} }
} }
} }

View File

@ -27,25 +27,25 @@ class ScreenImage;
class LanguageCard : public Card class LanguageCard : public Card
{ {
private: private:
ScreenImage& gui; ScreenImage& gui;
int slot; int slot;
bool inhibit; bool inhibit;
std::vector<Memory*> ramBank; std::vector<Memory*> ramBank;
Memory ramTop; Memory ramTop;
unsigned char bank; unsigned char bank;
bool readEnable; bool readEnable;
bool writeEnable; bool writeEnable;
unsigned char writeCount; unsigned char writeCount;
public: public:
LanguageCard(ScreenImage& gui, int slot); LanguageCard(ScreenImage& gui, int slot);
~LanguageCard(); ~LanguageCard();
virtual void reset() { /* does nothing */ } virtual void reset() { /* does nothing */ }
virtual bool inhibitMotherboardRom() { return this->inhibit; } virtual bool inhibitMotherboardRom() { return this->inhibit; }
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing); virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write); virtual void ioBankRom(const unsigned short addr, unsigned char* const pb, const bool write);
virtual std::string getName() { return "language W B2"; } virtual std::string getName() { return "language W B2"; }
}; };
#endif #endif

View File

@ -31,14 +31,14 @@ PaddleButtonStates::~PaddleButtonStates()
bool PaddleButtonStates::isDown(const int paddle) bool PaddleButtonStates::isDown(const int paddle)
{ {
if (paddle < 0 || PADDLE_COUNT <= paddle) if (paddle < 0 || PADDLE_COUNT <= paddle)
{ {
return false; return false;
} }
unsigned char btn = SDL_GetMouseState(0,0); unsigned char btn = SDL_GetMouseState(0,0);
if (paddle==0) if (paddle==0)
return btn&SDL_BUTTON_LMASK; return btn&SDL_BUTTON_LMASK;
if (paddle==1) if (paddle==1)
return btn&SDL_BUTTON_RMASK; return btn&SDL_BUTTON_RMASK;
return btn&SDL_BUTTON_MMASK; return btn&SDL_BUTTON_MMASK;
} }

View File

@ -22,12 +22,12 @@
class PaddleButtonStates class PaddleButtonStates
{ {
static const int PADDLE_COUNT; static const int PADDLE_COUNT;
public: public:
PaddleButtonStates(); PaddleButtonStates();
~PaddleButtonStates(); ~PaddleButtonStates();
bool isDown(const int paddle); bool isDown(const int paddle);
}; };
#endif #endif

View File

@ -23,7 +23,7 @@
Paddles::Paddles(): Paddles::Paddles():
rTick(PADDLE_COUNT) rTick(PADDLE_COUNT)
{ {
} }
@ -35,59 +35,59 @@ Paddles::~Paddles()
void Paddles::tick() void Paddles::tick()
{ {
for (int paddle = 0; paddle < PADDLE_COUNT; ++paddle) for (int paddle = 0; paddle < PADDLE_COUNT; ++paddle)
{ {
if (this->rTick[paddle] > 0) if (this->rTick[paddle] > 0)
--this->rTick[paddle]; --this->rTick[paddle];
} }
} }
void Paddles::startTimers() void Paddles::startTimers()
{ {
try try
{ {
tryStartPaddleTimers(); tryStartPaddleTimers();
} }
catch (...) catch (...)
{ {
std::cerr << "Warning: cannot start paddle timers; mouse will not function as paddles." << std::endl; std::cerr << "Warning: cannot start paddle timers; mouse will not function as paddles." << std::endl;
} }
} }
void Paddles::tryStartPaddleTimers() void Paddles::tryStartPaddleTimers()
{ {
int x, y; int x, y;
SDL_GetMouseState(&x,&y); SDL_GetMouseState(&x,&y);
double pMin = 0; double pMin = 0;
double pMax = 500; double pMax = 500;
x = (int)((x-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5); x = (int)((x-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
y = (int)((y-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5); y = (int)((y-pMin)/(pMax-pMin)*PADDLE_CYCLES+.5);
if (isTimedOut(0)) if (isTimedOut(0))
this->rTick[0] = x; this->rTick[0] = x;
if (isTimedOut(1)) if (isTimedOut(1))
this->rTick[1] = y; this->rTick[1] = y;
/* /*
Here we emulate having 4700 ohm across pins 7 and 1 Here we emulate having 4700 ohm across pins 7 and 1
of the game controller, and a 47Kohm resistor acros of the game controller, and a 47Kohm resistor acros
pins 11 and 1, to give cheap real-time clocks at pins 11 and 1, to give cheap real-time clocks at
paddles 2 and 3. Paddle 2 is the 100 microsecond reference, paddles 2 and 3. Paddle 2 is the 100 microsecond reference,
and paddle 3 is the 1 millisecond reference. This is and paddle 3 is the 1 millisecond reference. This is
described in U.A.2, p. 7-33. described in U.A.2, p. 7-33.
*/ */
if (isTimedOut(2)) if (isTimedOut(2))
this->rTick[2] = E2Const::AVG_CPU_HZ/10000; // was 90, but why? this->rTick[2] = E2Const::AVG_CPU_HZ/10000; // was 90, but why?
if (isTimedOut(3)) if (isTimedOut(3))
this->rTick[3] = E2Const::AVG_CPU_HZ/1000; this->rTick[3] = E2Const::AVG_CPU_HZ/1000;
} }
bool Paddles::isTimedOut(const int paddle) bool Paddles::isTimedOut(const int paddle)
{ {
if (paddle < 0 || PADDLE_COUNT <= paddle) if (paddle < 0 || PADDLE_COUNT <= paddle)
{ {
return false; return false;
} }
return this->rTick[paddle] <= 0; return this->rTick[paddle] <= 0;
} }

View File

@ -23,19 +23,19 @@
class Paddles class Paddles
{ {
private: private:
std::vector<int> rTick; std::vector<int> rTick;
enum { PADDLE_COUNT = 4 }; enum { PADDLE_COUNT = 4 };
enum { PADDLE_CYCLES = 2805 }; // TODO: document where PADDLE_CYCLES==2805 came from enum { PADDLE_CYCLES = 2805 }; // TODO: document where PADDLE_CYCLES==2805 came from
void tryStartPaddleTimers(); void tryStartPaddleTimers();
public: public:
Paddles(); Paddles();
~Paddles(); ~Paddles();
void tick(); void tick();
void startTimers(); void startTimers();
bool isTimedOut(const int paddle); bool isTimedOut(const int paddle);
}; };
#endif #endif

View File

@ -22,9 +22,9 @@
#include "e2const.h" #include "e2const.h"
PictureGenerator::PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision): PictureGenerator::PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision):
display(display), mode(mode), itestsig(testsig), itestsiglim(testsig+AppleNTSC::SIGNAL_LEN), display(display), mode(mode), itestsig(testsig), itestsiglim(testsig+AppleNTSC::SIGNAL_LEN),
VISIBLE_X_OFFSET(E2Const::BYTES_PER_ROW-E2Const::VISIBLE_BYTES_PER_ROW), VISIBLE_X_OFFSET(E2Const::BYTES_PER_ROW-E2Const::VISIBLE_BYTES_PER_ROW),
revision(revision) revision(revision)
{ {
} }
@ -36,96 +36,96 @@ PictureGenerator::~PictureGenerator()
void PictureGenerator::powerOn() void PictureGenerator::powerOn()
{ {
this->hpos = 0; this->hpos = 0;
this->line = 0; this->line = 0;
this->display.signal = this->testsig; this->display.signal = this->testsig;
this->itestsig = this->testsig; this->itestsig = this->testsig;
} }
void inline PictureGenerator::shiftLoRes() void inline PictureGenerator::shiftLoRes()
{ {
/* /*
* For byte ABCDEFGH in register, perform * For byte ABCDEFGH in register, perform
* the following 4-bit end-around shifts: * the following 4-bit end-around shifts:
* *
* +---<----+ +---<----+ * +---<----+ +---<----+
* | | | | * | | | |
* +->ABCD->+ +->EFGH->+ * +->ABCD->+ +->EFGH->+
* *
* Therefore: * Therefore:
* *
* ABCDEFGH --> DABCHEFG * ABCDEFGH --> DABCHEFG
*/ */
unsigned char rot_bits = this->latchGraphics & 0x11; unsigned char rot_bits = this->latchGraphics & 0x11;
// 000D000H // 000D000H
rot_bits <<= 3; rot_bits <<= 3;
// D000H000 // D000H000
this->latchGraphics &= 0xEE; this->latchGraphics &= 0xEE;
// ABC0EFG0 // ABC0EFG0
this->latchGraphics >>= 1; this->latchGraphics >>= 1;
// 0ABC0EFG // 0ABC0EFG
this->latchGraphics |= rot_bits; this->latchGraphics |= rot_bits;
// DABCHEFG // DABCHEFG
} }
void inline PictureGenerator::shiftHiRes() void inline PictureGenerator::shiftHiRes()
{ {
/* /*
* For byte ABCDEFGH in register, perform * For byte ABCDEFGH in register, perform
* the following shift: * the following shift:
* *
* +---<----+ * +---<----+
* | | * | |
* +->ABCD->+--->EFGH-> * +->ABCD->+--->EFGH->
* *
* Therefore: * Therefore:
* *
* ABCDEFGH --> DABCDEFG * ABCDEFGH --> DABCDEFG
*/ */
unsigned char rot_bits = this->latchGraphics & 0x10; unsigned char rot_bits = this->latchGraphics & 0x10;
// 000D0000 // 000D0000
rot_bits <<= 3; rot_bits <<= 3;
// D0000000 // D0000000
this->latchGraphics >>= 1; this->latchGraphics >>= 1;
// 0ABCDEFG // 0ABCDEFG
this->latchGraphics |= rot_bits; this->latchGraphics |= rot_bits;
// DABCDEFG // DABCDEFG
} }
void inline PictureGenerator::shiftText() void inline PictureGenerator::shiftText()
{ {
this->latchText >>= 1; this->latchText >>= 1;
} }
bool inline PictureGenerator::getTextBit() bool inline PictureGenerator::getTextBit()
{ {
return this->latchText & 1; return this->latchText & 1;
} }
bool inline PictureGenerator::getHiResBit() bool inline PictureGenerator::getHiResBit()
{ {
return this->latchGraphics & 1; return this->latchGraphics & 1;
} }
bool inline PictureGenerator::getLoResBit(const bool odd, const bool vc) bool inline PictureGenerator::getLoResBit(const bool odd, const bool vc)
{ {
const int nibble = (this->latchGraphics >> (vc ? 4 : 0)) & 0x0F; const int nibble = (this->latchGraphics >> (vc ? 4 : 0)) & 0x0F;
return (nibble >> (odd ? 2 : 0)) & 1; return (nibble >> (odd ? 2 : 0)) & 1;
} }
void inline PictureGenerator::loadGraphics(const unsigned char value) void inline PictureGenerator::loadGraphics(const unsigned char value)
{ {
this->latchGraphics = value; this->latchGraphics = value;
this->d7 = this->latchGraphics & 0x80; this->d7 = this->latchGraphics & 0x80;
} }
void inline PictureGenerator::loadText(const int value) void inline PictureGenerator::loadText(const int value)
{ {
this->latchText = value; this->latchText = value;
} }
// TODO can we hand-optimize the main picture generator algorithm any more? // TODO can we hand-optimize the main picture generator algorithm any more?
@ -133,154 +133,154 @@ void inline PictureGenerator::loadText(const int value)
// at 14MHz, in order to maintain authentic Apple ][ speed. // at 14MHz, in order to maintain authentic Apple ][ speed.
void PictureGenerator::tick(const int t, const unsigned char rowToPlot) void PictureGenerator::tick(const int t, const unsigned char rowToPlot)
{ {
const bool isText(this->mode.isDisplayingText(t)); const bool isText(this->mode.isDisplayingText(t));
const bool isHiRes(this->mode.isHiRes()); const bool isHiRes(this->mode.isHiRes());
signed char* is = this->itestsig; signed char* is = this->itestsig;
if (isText) if (isText)
loadText(rowToPlot); loadText(rowToPlot);
else else
loadGraphics(rowToPlot); loadGraphics(rowToPlot);
if (t==0) if (t==0)
{ {
this->line = 0; this->line = 0;
} }
int cycles = E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE; int cycles = E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE;
if (this->hpos == E2Const::HORIZ_CYCLES-1) if (this->hpos == E2Const::HORIZ_CYCLES-1)
{ {
cycles += E2Const::EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE; cycles += E2Const::EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE;
} }
// hi-res half-pixel shift: // hi-res half-pixel shift:
const bool shift = !isText && isHiRes && this->d7 && this->line < E2Const::VISIBLE_ROWS_PER_FIELD && !(this->hpos < VISIBLE_X_OFFSET) && this->revision > 0; const bool shift = !isText && isHiRes && this->d7 && this->line < E2Const::VISIBLE_ROWS_PER_FIELD && !(this->hpos < VISIBLE_X_OFFSET) && this->revision > 0;
const bool showLastHiRes = shift && this->lasthires; const bool showLastHiRes = shift && this->lasthires;
int xtra(0); int xtra(0);
if (shift) if (shift)
{ {
--cycles; --cycles;
++xtra; ++xtra;
} }
const int firstBlankedCycle(E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE-xtra); const int firstBlankedCycle(E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE-xtra);
int hcycle(this->hpos*E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE); int hcycle(this->hpos*E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE);
const bool lineVis(this->line < E2Const::VISIBLE_ROWS_PER_FIELD); const bool lineVis(this->line < E2Const::VISIBLE_ROWS_PER_FIELD);
const bool hVis(this->hpos >= VISIBLE_X_OFFSET); const bool hVis(this->hpos >= VISIBLE_X_OFFSET);
for (int cycle(0); cycle < cycles-1; ++cycle) for (int cycle(0); cycle < cycles-1; ++cycle)
{ {
const bool bit = shiftLatch(t,cycle,isText,isHiRes); const bool bit = shiftLatch(t,cycle,isText,isHiRes);
is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is); is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is);
++hcycle; ++hcycle;
} }
// optimization: pull the last iteration of the loop out, so we don't getHiResBit every time // optimization: pull the last iteration of the loop out, so we don't getHiResBit every time
{ {
this->lasthires = getHiResBit(); // save it for the next plotted byte, just in case we need it this->lasthires = getHiResBit(); // save it for the next plotted byte, just in case we need it
const int cycle = cycles-1; const int cycle = cycles-1;
const bool bit = shiftLatch(t,cycle,isText,isHiRes); const bool bit = shiftLatch(t,cycle,isText,isHiRes);
is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is); is = writeVideoSignal(shift,showLastHiRes,firstBlankedCycle,cycle,hcycle,bit,lineVis,hVis,is);
} }
this->itestsig = is; this->itestsig = is;
++this->hpos; ++this->hpos;
if (this->hpos >= E2Const::HORIZ_CYCLES) if (this->hpos >= E2Const::HORIZ_CYCLES)
{ {
this->hpos = 0; this->hpos = 0;
++this->line; ++this->line;
if (this->itestsig >= this->itestsiglim) if (this->itestsig >= this->itestsiglim)
{ {
this->itestsig = this->testsig; this->itestsig = this->testsig;
this->display.drawCurrent(); this->display.drawCurrent();
} }
} }
} }
bool inline PictureGenerator::shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes) bool inline PictureGenerator::shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes)
{ {
bool bit; bool bit;
if (isText) if (isText)
{ {
bit = getTextBit(); bit = getTextBit();
if (cycle & 1) // @ 7MHz if (cycle & 1) // @ 7MHz
{ {
shiftText(); shiftText();
} }
} }
else if (isHiRes) else if (isHiRes)
{ {
bit = getHiResBit(); bit = getHiResBit();
if (cycle & 1) // @ 7MHz if (cycle & 1) // @ 7MHz
{ {
shiftHiRes(); shiftHiRes();
} }
} }
else // LO-RES else // LO-RES
{ {
const int y = t / E2Const::BYTES_PER_ROW; const int y = t / E2Const::BYTES_PER_ROW;
bit = getLoResBit((t & 1) == (this->line & 1), y & 4); bit = getLoResBit((t & 1) == (this->line & 1), y & 4);
shiftLoRes(); shiftLoRes();
} }
return bit; return bit;
} }
inline signed char* PictureGenerator::writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is) inline signed char* PictureGenerator::writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is)
{ {
if (shift && !cycle) if (shift && !cycle)
{ {
*is++ = showLastHiRes ? AppleNTSC::WHITE_LEVEL : AppleNTSC::BLANK_LEVEL; *is++ = showLastHiRes ? AppleNTSC::WHITE_LEVEL : AppleNTSC::BLANK_LEVEL;
} }
signed char sig; signed char sig;
if (lineVis) if (lineVis)
{ {
if (hVis) if (hVis)
{ {
if (bit && cycle < firstBlankedCycle) if (bit && cycle < firstBlankedCycle)
{ {
sig = AppleNTSC::WHITE_LEVEL; sig = AppleNTSC::WHITE_LEVEL;
} }
else else
{ {
sig = AppleNTSC::BLANK_LEVEL; sig = AppleNTSC::BLANK_LEVEL;
} }
} }
else else
{ {
sig = hbl(hcycle); sig = hbl(hcycle);
} }
} }
else else
{ {
sig = vbl(hcycle); sig = vbl(hcycle);
} }
*is++ = sig; *is++ = sig;
return is; return is;
} }
// TODO Just to be extremely accurate, fix picture signal values during HBL and VBL // TODO Just to be extremely accurate, fix picture signal values during HBL and VBL
// (note that they vary by motherboard revision... there is a whole section in U.A.2) // (note that they vary by motherboard revision... there is a whole section in U.A.2)
signed char inline PictureGenerator::vbl(const int hcycle) signed char inline PictureGenerator::vbl(const int hcycle)
{ {
signed char sig; signed char sig;
if (224 <= this->line && this->line < 240) // VSYNC // TODO symbolize constants if (224 <= this->line && this->line < 240) // VSYNC // TODO symbolize constants
{ {
sig = AppleNTSC::SYNC_LEVEL; sig = AppleNTSC::SYNC_LEVEL;
} }
else else
{ {
if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START) if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START)
{ {
sig = AppleNTSC::SYNC_LEVEL; sig = AppleNTSC::SYNC_LEVEL;
} }
else else
{ {
sig = AppleNTSC::BLANK_LEVEL; sig = AppleNTSC::BLANK_LEVEL;
} }
} }
return sig; return sig;
} }
@ -299,25 +299,25 @@ const signed char PictureGenerator::lutCB[] =
signed char inline PictureGenerator::hbl(const int hcycle) signed char inline PictureGenerator::hbl(const int hcycle)
{ {
signed char cb; signed char cb;
if (AppleNTSC::CB_START <= hcycle && hcycle < AppleNTSC::CB_END) if (AppleNTSC::CB_START <= hcycle && hcycle < AppleNTSC::CB_END)
{ {
if (this->mode.isText() && this->revision > 0) if (this->mode.isText() && this->revision > 0)
{ {
cb = AppleNTSC::BLANK_LEVEL; cb = AppleNTSC::BLANK_LEVEL;
} }
else else
{ {
cb = lutCB[(hcycle-AppleNTSC::CB_START)%4]; cb = lutCB[(hcycle-AppleNTSC::CB_START)%4];
} }
} }
else if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START) else if (AppleNTSC::SYNC_START <= hcycle && hcycle < AppleNTSC::BP_START)
{ {
cb = AppleNTSC::SYNC_LEVEL; cb = AppleNTSC::SYNC_LEVEL;
} }
else else
{ {
cb = AppleNTSC::BLANK_LEVEL; cb = AppleNTSC::BLANK_LEVEL;
} }
return cb; return cb;
} }

View File

@ -24,45 +24,45 @@ class VideoMode;
class PictureGenerator class PictureGenerator
{ {
private: private:
AnalogTV& display; AnalogTV& display;
VideoMode& mode; VideoMode& mode;
unsigned char latchGraphics; unsigned char latchGraphics;
bool d7; bool d7;
unsigned char latchText; unsigned char latchText;
unsigned int hpos; unsigned int hpos;
unsigned int line; unsigned int line;
bool lasthires; bool lasthires;
static const signed char lutCB[]; static const signed char lutCB[];
signed char testsig[AppleNTSC::SIGNAL_LEN]; signed char testsig[AppleNTSC::SIGNAL_LEN];
signed char* itestsig; signed char* itestsig;
signed char* itestsiglim; signed char* itestsiglim;
void shiftLoRes(); void shiftLoRes();
void shiftHiRes(); void shiftHiRes();
void shiftText(); void shiftText();
bool getTextBit(); bool getTextBit();
bool getHiResBit(); bool getHiResBit();
bool getLoResBit(const bool odd, const bool vc); bool getLoResBit(const bool odd, const bool vc);
void loadGraphics(const unsigned char value); void loadGraphics(const unsigned char value);
void loadText(const int value); void loadText(const int value);
bool shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes); bool shiftLatch(const int t, const int cycle, const bool isText, const bool isHiRes);
signed char* writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is); signed char* writeVideoSignal(const bool shift, const bool showLastHiRes, const int firstBlankedCycle, const int cycle, const int hcycle, const bool bit, const bool lineVis, const bool hVis, signed char* is);
signed char vbl(const int hcycle); signed char vbl(const int hcycle);
signed char hbl(const int hcycle); signed char hbl(const int hcycle);
const unsigned int VISIBLE_X_OFFSET; const unsigned int VISIBLE_X_OFFSET;
const int& revision; const int& revision;
public: public:
PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision); PictureGenerator(AnalogTV& display, VideoMode& mode, const int& revision);
~PictureGenerator(); ~PictureGenerator();
void powerOn(); void powerOn();
void tick(const int t, const unsigned char c); void tick(const int t, const unsigned char c);
}; };
#endif #endif

View File

@ -20,7 +20,7 @@
#include "e2const.h" #include "e2const.h"
PowerUpReset::PowerUpReset(Apple2& apple): PowerUpReset::PowerUpReset(Apple2& apple):
apple(apple) apple(apple)
{ {
} }
@ -32,21 +32,21 @@ PowerUpReset::~PowerUpReset()
void PowerUpReset::tick() void PowerUpReset::tick()
{ {
if (this->pendingTicks > 0) if (this->pendingTicks > 0)
{ {
--this->pendingTicks; --this->pendingTicks;
if (this->pendingTicks == 0) if (this->pendingTicks == 0)
{ {
this->apple.reset(); this->apple.reset();
} }
} }
} }
void PowerUpReset::powerOn() void PowerUpReset::powerOn()
{ {
#ifdef USE_EMU #ifdef USE_EMU
this->pendingTicks = 99; // TODO REMOVE THIS this->pendingTicks = 99; // TODO REMOVE THIS
#else #else
this->pendingTicks = (int)(E2Const::AVG_CPU_HZ*.3); // U.A.II, p. 7-15 this->pendingTicks = (int)(E2Const::AVG_CPU_HZ*.3); // U.A.II, p. 7-15
#endif #endif
} }

View File

@ -23,14 +23,14 @@ class Apple2;
class PowerUpReset class PowerUpReset
{ {
private: private:
Apple2& apple; Apple2& apple;
int pendingTicks; int pendingTicks;
public: public:
PowerUpReset(Apple2& apple); PowerUpReset(Apple2& apple);
~PowerUpReset(); ~PowerUpReset();
void powerOn(); void powerOn();
void tick(); void tick();
}; };
#endif #endif

View File

@ -20,11 +20,11 @@
#include <algorithm> #include <algorithm>
Slots::Slots(ScreenImage& gui): Slots::Slots(ScreenImage& gui):
gui(gui), gui(gui),
empty(), empty(),
cards(8,&this->empty) cards(8,&this->empty)
{ {
forceGuiUpdate(); forceGuiUpdate();
} }
Slots::~Slots() Slots::~Slots()
@ -33,17 +33,17 @@ Slots::~Slots()
unsigned char Slots::io(const int islot, const int iswch, const unsigned char b, const bool writing) unsigned char Slots::io(const int islot, const int iswch, const unsigned char b, const bool writing)
{ {
return this->cards[islot]->io(iswch,b,writing); return this->cards[islot]->io(iswch,b,writing);
} }
struct Slots_Card_reset struct Slots_Card_reset
{ {
void operator() (Card* p) { p->reset(); } void operator() (Card* p) { p->reset(); }
}; };
void Slots::reset() void Slots::reset()
{ {
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_reset()); std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_reset());
} }
struct Slots_Card_tick struct Slots_Card_tick
@ -58,79 +58,79 @@ void Slots::tick()
unsigned char Slots::readRom(const int islot, const unsigned short addr, const unsigned char data) unsigned char Slots::readRom(const int islot, const unsigned short addr, const unsigned char data)
{ {
return this->cards[islot]->readRom(addr,data); return this->cards[islot]->readRom(addr,data);
} }
struct Slots_Card_readSeventhRom struct Slots_Card_readSeventhRom
{ {
const unsigned short addr; const unsigned short addr;
unsigned char* b; unsigned char* b;
Slots_Card_readSeventhRom(const unsigned short addr, unsigned char* b):addr(addr),b(b){} Slots_Card_readSeventhRom(const unsigned short addr, unsigned char* b):addr(addr),b(b){}
void operator() (Card* p) { p->readSeventhRom(this->addr,this->b); } void operator() (Card* p) { p->readSeventhRom(this->addr,this->b); }
}; };
unsigned char Slots::readSeventhRom(const unsigned short addr, const unsigned char data) unsigned char Slots::readSeventhRom(const unsigned short addr, const unsigned char data)
{ {
unsigned char b(data); unsigned char b(data);
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_readSeventhRom(addr,&b)); std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_readSeventhRom(addr,&b));
return b; return b;
} }
struct Slots_Card_ioBankRom struct Slots_Card_ioBankRom
{ {
const unsigned short addr; const unsigned short addr;
unsigned char* b; unsigned char* b;
const bool write; const bool write;
Slots_Card_ioBankRom(const unsigned short addr, unsigned char* b, const bool write):addr(addr),b(b),write(write){} Slots_Card_ioBankRom(const unsigned short addr, unsigned char* b, const bool write):addr(addr),b(b),write(write){}
void operator() (Card* p) { p->ioBankRom(this->addr,this->b,this->write); } void operator() (Card* p) { p->ioBankRom(this->addr,this->b,this->write); }
}; };
unsigned char Slots::ioBankRom(const unsigned short addr, const unsigned char data, const bool write) unsigned char Slots::ioBankRom(const unsigned short addr, const unsigned char data, const bool write)
{ {
unsigned char b(data); unsigned char b(data);
std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_ioBankRom(addr,&b,write)); std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_ioBankRom(addr,&b,write));
return b; return b;
} }
struct Slots_Card_inhibitMotherboardRom struct Slots_Card_inhibitMotherboardRom
{ {
bool inhibit; bool inhibit;
Slots_Card_inhibitMotherboardRom():inhibit(false) { } Slots_Card_inhibitMotherboardRom():inhibit(false) { }
void operator() (Card* p) { if (p->inhibitMotherboardRom()) { inhibit = true; }} void operator() (Card* p) { if (p->inhibitMotherboardRom()) { inhibit = true; }}
}; };
bool Slots::inhibitMotherboardRom() bool Slots::inhibitMotherboardRom()
{ {
return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_inhibitMotherboardRom()).inhibit; return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_inhibitMotherboardRom()).inhibit;
} }
void Slots::set(const int slot, Card* card) void Slots::set(const int slot, Card* card)
{ {
remove(slot); remove(slot);
this->cards[slot] = card; this->cards[slot] = card;
this->gui.updateSlotName(slot,this->cards[slot]); this->gui.updateSlotName(slot,this->cards[slot]);
} }
void Slots::remove(const int slot) void Slots::remove(const int slot)
{ {
if (this->cards[slot] != &this->empty) if (this->cards[slot] != &this->empty)
{ {
delete this->cards[slot]; delete this->cards[slot];
this->cards[slot] = &this->empty; this->cards[slot] = &this->empty;
this->gui.removeCard(slot,this->cards[slot]); this->gui.removeCard(slot,this->cards[slot]);
} }
} }
Card* Slots::get(const int slot) Card* Slots::get(const int slot)
{ {
return this->cards[slot]; return this->cards[slot];
} }
void Slots::forceGuiUpdate() void Slots::forceGuiUpdate()
{ {
for (int slot(0); slot < 8; ++slot) for (int slot(0); slot < 8; ++slot)
this->gui.updateSlotName(slot,this->cards[slot]); this->gui.updateSlotName(slot,this->cards[slot]);
} }
void Slots::save(int unit) { void Slots::save(int unit) {
@ -142,26 +142,26 @@ void Slots::save(int unit) {
/* /*
struct isAnyDiskDriveMotorOnCard struct isAnyDiskDriveMotorOnCard
{ {
bool on; bool on;
isAnyDiskDriveMotorOnCard():on(false) {} isAnyDiskDriveMotorOnCard():on(false) {}
void operator() (Card* p) { if (p->isMotorOn()) on = true; } void operator() (Card* p) { if (p->isMotorOn()) on = true; }
}; };
bool isAnyDiskDriveMotorOn() bool isAnyDiskDriveMotorOn()
{ {
isAnyDiskDriveMotorOnCard on = isAnyDiskDriveMotorOnCard(); isAnyDiskDriveMotorOnCard on = isAnyDiskDriveMotorOnCard();
std::for_each(this->cards.begin(),this->cards.end(),inh); std::for_each(this->cards.begin(),this->cards.end(),inh);
return on.inhibit; return on.inhibit;
} }
*/ */
struct Slots_Card_isDirty struct Slots_Card_isDirty
{ {
bool dirty; bool dirty;
Slots_Card_isDirty():dirty(false) {} Slots_Card_isDirty():dirty(false) {}
void operator() (Card* p) { if (p->isDirty()) dirty = true; } void operator() (Card* p) { if (p->isDirty()) dirty = true; }
}; };
bool Slots::isDirty() bool Slots::isDirty()
{ {
return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_isDirty()).dirty; return std::for_each(this->cards.begin(),this->cards.end(),Slots_Card_isDirty()).dirty;
} }

View File

@ -27,25 +27,25 @@ class ScreenImage;
class Slots class Slots
{ {
private: private:
ScreenImage& gui; ScreenImage& gui;
EmptySlot empty; EmptySlot empty;
std::vector<Card*> cards; std::vector<Card*> cards;
public: public:
Slots(ScreenImage& gui); Slots(ScreenImage& gui);
~Slots(); ~Slots();
void tick(); void tick();
unsigned char io(const int islot, const int iswch, const unsigned char b, const bool writing); unsigned char io(const int islot, const int iswch, const unsigned char b, const bool writing);
void reset(); void reset();
unsigned char readRom(const int islot, const unsigned short addr, const unsigned char data); unsigned char readRom(const int islot, const unsigned short addr, const unsigned char data);
unsigned char readSeventhRom(const unsigned short addr, const unsigned char data); unsigned char readSeventhRom(const unsigned short addr, const unsigned char data);
unsigned char ioBankRom(const unsigned short addr, const unsigned char data, const bool write); unsigned char ioBankRom(const unsigned short addr, const unsigned char data, const bool write);
bool inhibitMotherboardRom(); bool inhibitMotherboardRom();
void set(const int slot, Card* card); void set(const int slot, Card* card);
Card* get(const int slot); Card* get(const int slot);
void remove(const int slot); void remove(const int slot);
bool isDirty(); bool isDirty();
void save(int unit); void save(int unit);
void forceGuiUpdate(); void forceGuiUpdate();
}; };

View File

@ -29,22 +29,22 @@ SpeakerClicker::SpeakerClicker():
clicked(false), clicked(false),
t(TICKS_PER_SAMPLE), t(TICKS_PER_SAMPLE),
positive(false) { positive(false) {
SDL_AudioSpec audio; SDL_AudioSpec audio;
audio.freq = E2Const::AVG_CPU_HZ/TICKS_PER_SAMPLE; // samples per second audio.freq = E2Const::AVG_CPU_HZ/TICKS_PER_SAMPLE; // samples per second
audio.format = AUDIO_U8; // 8 bits (1 byte) per sample audio.format = AUDIO_U8; // 8 bits (1 byte) per sample
audio.channels = 1; // mono audio.channels = 1; // mono
audio.silence = 128; audio.silence = 128;
audio.samples = 512; audio.samples = 512;
audio.callback = 0; audio.callback = 0;
audio.userdata = 0; audio.userdata = 0;
SDL_AudioSpec obtained; SDL_AudioSpec obtained;
obtained.callback = 0; obtained.callback = 0;
obtained.userdata = 0; obtained.userdata = 0;
this->devid = SDL_OpenAudioDevice(0,0,&audio,&obtained,0); this->devid = SDL_OpenAudioDevice(0,0,&audio,&obtained,0);
if (!this->devid) { if (!this->devid) {
std::cerr << "Unable to initialize audio: " << SDL_GetError() << std::endl; std::cerr << "Unable to initialize audio: " << SDL_GetError() << std::endl;
} else { } else {
this->silence = obtained.silence; this->silence = obtained.silence;
@ -57,27 +57,27 @@ SpeakerClicker::SpeakerClicker():
std::cout << " samples: " << obtained.samples << std::endl; std::cout << " samples: " << obtained.samples << std::endl;
std::cout << " size: " << obtained.size << std::endl; std::cout << " size: " << obtained.size << std::endl;
SDL_PauseAudioDevice(this->devid, 0); SDL_PauseAudioDevice(this->devid, 0);
} }
} }
SpeakerClicker::~SpeakerClicker() { SpeakerClicker::~SpeakerClicker() {
if (!this->devid) { if (!this->devid) {
return; return;
} }
SDL_CloseAudioDevice(this->devid); SDL_CloseAudioDevice(this->devid);
} }
void SpeakerClicker::tick() { void SpeakerClicker::tick() {
if (!this->devid) { if (!this->devid) {
return; return;
} }
if (!--this->t) { if (!--this->t) {
std::uint8_t amp; std::uint8_t amp;
if (this->clicked) { if (this->clicked) {
amp = this->positive ? this->silence+100u : this->silence-100u; amp = this->positive ? this->silence+100u : this->silence-100u;
this->positive = !this->positive; this->positive = !this->positive;
this->clicked = false; this->clicked = false;
} else { } else {
amp = silence; amp = silence;
@ -91,5 +91,5 @@ void SpeakerClicker::tick() {
} }
void SpeakerClicker::click() { void SpeakerClicker::click() {
this->clicked = true; this->clicked = true;
} }

View File

@ -28,12 +28,12 @@ class SpeakerClicker {
std::uint8_t silence; std::uint8_t silence;
bool clicked; bool clicked;
std::uint8_t t; std::uint8_t t;
bool positive; bool positive;
public: public:
SpeakerClicker(); SpeakerClicker();
~SpeakerClicker(); ~SpeakerClicker();
void tick(); void tick();
void click(); void click();
}; };
#endif #endif

View File

@ -18,8 +18,8 @@
#include "standardin.h" #include "standardin.h"
StandardIn::StandardIn(): StandardIn::StandardIn():
latch(0), latch(0),
gotEOF(false) gotEOF(false)
{ {
} }
@ -33,33 +33,33 @@ StandardIn::~StandardIn()
unsigned char StandardIn::io(const unsigned short address, const unsigned char data, const bool writing) unsigned char StandardIn::io(const unsigned short address, const unsigned char data, const bool writing)
{ {
int sw = address & 0x0F; int sw = address & 0x0F;
if (sw == 0) if (sw == 0)
{ {
if (!(this->latch & 0x80)) if (!(this->latch & 0x80))
{ {
if (this->gotEOF) if (this->gotEOF)
{ {
this->latch = 0xFF; this->latch = 0xFF;
} }
else else
{ {
if (!this->producer.getKeys().empty()) if (!this->producer.getKeys().empty())
{ {
this->latch = this->producer.getKeys().front(); this->latch = this->producer.getKeys().front();
this->producer.getKeys().pop(); this->producer.getKeys().pop();
if (this->latch == 0xFF) if (this->latch == 0xFF)
{ {
this->gotEOF = true; this->gotEOF = true;
} }
this->latch |= 0x80; this->latch |= 0x80;
} }
} }
} }
} }
else if (sw == 1) else if (sw == 1)
{ {
this->latch &= 0x7F; this->latch &= 0x7F;
} }
return this->latch; return this->latch;
} }

View File

@ -24,16 +24,16 @@
class StandardIn : public Card class StandardIn : public Card
{ {
private: private:
StandardInProducer producer; StandardInProducer producer;
unsigned char latch; unsigned char latch;
bool gotEOF; bool gotEOF;
public: public:
StandardIn(); StandardIn();
~StandardIn(); ~StandardIn();
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing); virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
virtual std::string getName() { return "standard input"; } virtual std::string getName() { return "standard input"; }
}; };
#endif #endif

View File

@ -28,71 +28,71 @@ enum state_t { START, GOT_CR, GOT_LF, GOT_EOF };
static int readInput(void *voidkeys) static int readInput(void *voidkeys)
{ {
KeypressQueue* keys = (KeypressQueue*)voidkeys; KeypressQueue* keys = (KeypressQueue*)voidkeys;
/* /*
* Continuously read characters from standard in * Continuously read characters from standard in
* and put them onto the queue. * and put them onto the queue.
* Stop when we hit EOF (placing EOF onto the queue). * Stop when we hit EOF (placing EOF onto the queue).
* Translate LF to CR. * Translate LF to CR.
* If we hit a CR immediately after a LF, drop it. * If we hit a CR immediately after a LF, drop it.
* If we hit a LF immediately after a CR, drop it. * If we hit a LF immediately after a CR, drop it.
*/ */
enum state_t state = START; enum state_t state = START;
while (state != GOT_EOF) while (state != GOT_EOF)
{ {
char c = std::cin.get(); char c = std::cin.get();
c &= 0x7F; c &= 0x7F;
if (!std::cin.good()) if (!std::cin.good())
{ {
state = GOT_EOF; state = GOT_EOF;
keys->push(0xFF); keys->push(0xFF);
} }
else else
{ {
if (state == START) if (state == START)
{ {
if (c == CR) if (c == CR)
{ {
state = GOT_CR; state = GOT_CR;
} }
else if (c == LF) else if (c == LF)
{ {
state = GOT_LF; state = GOT_LF;
c = CR; c = CR;
} }
keys->push(c); keys->push(c);
} }
else if (state == GOT_CR) else if (state == GOT_CR)
{ {
if (c != LF) if (c != LF)
{ {
keys->push(c); keys->push(c);
} }
state = START; state = START;
} }
else if (state == GOT_LF) else if (state == GOT_LF)
{ {
if (c != CR) if (c != CR)
{ {
if (c == LF) if (c == LF)
{ {
c = CR; c = CR;
} }
keys->push(c); keys->push(c);
} }
state = START; state = START;
} }
} }
} }
return 0; return 0;
} }
StandardInProducer::StandardInProducer() StandardInProducer::StandardInProducer()
{ {
SDL_CreateThread(readInput,"stdin",&this->keys); SDL_CreateThread(readInput,"stdin",&this->keys);
} }
StandardInProducer::~StandardInProducer() StandardInProducer::~StandardInProducer()

View File

@ -23,13 +23,13 @@
class StandardInProducer class StandardInProducer
{ {
private: private:
KeypressQueue keys; KeypressQueue keys;
public: public:
StandardInProducer(); StandardInProducer();
~StandardInProducer(); ~StandardInProducer();
KeypressQueue& getKeys() { return this->keys; } KeypressQueue& getKeys() { return this->keys; }
}; };
#endif #endif

View File

@ -30,21 +30,21 @@ StandardOut::~StandardOut()
unsigned char StandardOut::io(const unsigned short address, const unsigned char data, const bool writing) unsigned char StandardOut::io(const unsigned short address, const unsigned char data, const bool writing)
{ {
if (!writing) if (!writing)
{ {
return data; return data;
} }
const char c = (char)(data&0x7F); const char c = (char)(data&0x7F);
if (c == '\r') if (c == '\r')
{ {
std::cout << std::endl; std::cout << std::endl;
} }
else else
{ {
std::cout << c; std::cout << c;
} }
std::cout << std::flush; std::cout << std::flush;
return data; return data;
} }

View File

@ -24,11 +24,11 @@ class StandardOut : public Card
{ {
public: public:
StandardOut(); StandardOut();
~StandardOut(); ~StandardOut();
virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing); virtual unsigned char io(const unsigned short address, const unsigned char data, const bool writing);
virtual std::string getName() { return "standard output"; } virtual std::string getName() { return "standard output"; }
}; };
#endif #endif

View File

@ -18,28 +18,28 @@
#include "textcharacters.h" #include "textcharacters.h"
TextCharacters::TextCharacters(): TextCharacters::TextCharacters():
rows(0x40*8) rows(0x40*8)
{ {
int r(0); int r(0);
const char *pi = const char *pi =
#include "textcharacterimages.h" #include "textcharacterimages.h"
; ;
for (int ch(0); ch < 0x40; ++ch) for (int ch(0); ch < 0x40; ++ch)
{ {
rows[r] = 0; rows[r] = 0;
++r; ++r;
for (int ln(1); ln < 8; ++ln) for (int ln(1); ln < 8; ++ln)
{ {
for (int bt(0); bt < 5; ++bt) for (int bt(0); bt < 5; ++bt)
{ {
rows[r] >>= 1; rows[r] >>= 1;
if (*pi++=='@') if (*pi++=='@')
rows[r] |= 0x20; rows[r] |= 0x20;
} }
++r; ++r;
} }
} }
} }

View File

@ -23,15 +23,15 @@
class TextCharacters class TextCharacters
{ {
private: private:
std::vector<unsigned char> rows; std::vector<unsigned char> rows;
public: public:
TextCharacters(); TextCharacters();
~TextCharacters() {} ~TextCharacters() {}
unsigned char get(unsigned int iRow) unsigned char get(unsigned int iRow)
{ {
return this->rows[iRow]; return this->rows[iRow];
} }
}; };
#endif #endif

View File

@ -21,10 +21,10 @@
class Timable class Timable
{ {
public: public:
Timable() {} Timable() {}
virtual ~Timable() {} virtual ~Timable() {}
virtual void tick() = 0; virtual void tick() = 0;
}; };
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -51,7 +51,7 @@ misrepresented as being the original software.
#ifdef __cplusplus #ifdef __cplusplus
/* if tinydialogs.c is compiled as C++ code rather than C code, you may need to comment this out /* if tinydialogs.c is compiled as C++ code rather than C code, you may need to comment this out
and the corresponding closing bracket near the end of this file. */ and the corresponding closing bracket near the end of this file. */
extern "C" { extern "C" {
#endif #endif
@ -82,7 +82,7 @@ int tinyfd_getGlobalInt(char const * aIntVariableName); /* returns -1 on error *
int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue); /* returns -1 on error */ int tinyfd_setGlobalInt(char const * aIntVariableName, int aValue); /* returns -1 on error */
/* aCharVariableName: "tinyfd_version" "tinyfd_needs" "tinyfd_response" /* aCharVariableName: "tinyfd_version" "tinyfd_needs" "tinyfd_response"
aIntVariableName : "tinyfd_verbose" "tinyfd_silent" "tinyfd_allowCursesDialogs" aIntVariableName : "tinyfd_verbose" "tinyfd_silent" "tinyfd_allowCursesDialogs"
"tinyfd_forceConsole" "tinyfd_assumeGraphicDisplay" "tinyfd_winUtf8" "tinyfd_forceConsole" "tinyfd_assumeGraphicDisplay" "tinyfd_winUtf8"
**************/ **************/
@ -121,58 +121,58 @@ for console mode:
void tinyfd_beep(void); void tinyfd_beep(void);
int tinyfd_notifyPopup( int tinyfd_notifyPopup(
char const * aTitle, /* NULL or "" */ char const * aTitle, /* NULL or "" */
char const * aMessage, /* NULL or "" may contain \n \t */ char const * aMessage, /* NULL or "" may contain \n \t */
char const * aIconType); /* "info" "warning" "error" */ char const * aIconType); /* "info" "warning" "error" */
/* return has only meaning for tinyfd_query */ /* return has only meaning for tinyfd_query */
int tinyfd_messageBox( int tinyfd_messageBox(
char const * aTitle , /* NULL or "" */ char const * aTitle , /* NULL or "" */
char const * aMessage , /* NULL or "" may contain \n \t */ char const * aMessage , /* NULL or "" may contain \n \t */
char const * aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */ char const * aDialogType , /* "ok" "okcancel" "yesno" "yesnocancel" */
char const * aIconType , /* "info" "warning" "error" "question" */ char const * aIconType , /* "info" "warning" "error" "question" */
int aDefaultButton ) ; int aDefaultButton ) ;
/* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */ /* 0 for cancel/no , 1 for ok/yes , 2 for no in yesnocancel */
char * tinyfd_inputBox( char * tinyfd_inputBox(
char const * aTitle , /* NULL or "" */ char const * aTitle , /* NULL or "" */
char const * aMessage , /* NULL or "" (\n and \t have no effect) */ char const * aMessage , /* NULL or "" (\n and \t have no effect) */
char const * aDefaultInput ) ; /* NULL passwordBox, "" inputbox */ char const * aDefaultInput ) ; /* NULL passwordBox, "" inputbox */
/* returns NULL on cancel */ /* returns NULL on cancel */
char * tinyfd_saveFileDialog( char * tinyfd_saveFileDialog(
char const * aTitle , /* NULL or "" */ char const * aTitle , /* NULL or "" */
char const * aDefaultPathAndFile , /* NULL or "" */ char const * aDefaultPathAndFile , /* NULL or "" */
int aNumOfFilterPatterns , /* 0 (1 in the following example) */ int aNumOfFilterPatterns , /* 0 (1 in the following example) */
char const * const * aFilterPatterns , /* NULL or char const * lFilterPatterns[1]={"*.txt"} */ char const * const * aFilterPatterns , /* NULL or char const * lFilterPatterns[1]={"*.txt"} */
char const * aSingleFilterDescription ) ; /* NULL or "text files" */ char const * aSingleFilterDescription ) ; /* NULL or "text files" */
/* returns NULL on cancel */ /* returns NULL on cancel */
char * tinyfd_openFileDialog( char * tinyfd_openFileDialog(
char const * aTitle, /* NULL or "" */ char const * aTitle, /* NULL or "" */
char const * aDefaultPathAndFile, /* NULL or "" */ char const * aDefaultPathAndFile, /* NULL or "" */
int aNumOfFilterPatterns , /* 0 (2 in the following example) */ int aNumOfFilterPatterns , /* 0 (2 in the following example) */
char const * const * aFilterPatterns, /* NULL or char const * lFilterPatterns[2]={"*.png","*.jpg"}; */ char const * const * aFilterPatterns, /* NULL or char const * lFilterPatterns[2]={"*.png","*.jpg"}; */
char const * aSingleFilterDescription, /* NULL or "image files" */ char const * aSingleFilterDescription, /* NULL or "image files" */
int aAllowMultipleSelects ) ; /* 0 or 1 */ int aAllowMultipleSelects ) ; /* 0 or 1 */
/* in case of multiple files, the separator is | */ /* in case of multiple files, the separator is | */
/* returns NULL on cancel */ /* returns NULL on cancel */
char * tinyfd_selectFolderDialog( char * tinyfd_selectFolderDialog(
char const * aTitle, /* NULL or "" */ char const * aTitle, /* NULL or "" */
char const * aDefaultPath); /* NULL or "" */ char const * aDefaultPath); /* NULL or "" */
/* returns NULL on cancel */ /* returns NULL on cancel */
char * tinyfd_colorChooser( char * tinyfd_colorChooser(
char const * aTitle, /* NULL or "" */ char const * aTitle, /* NULL or "" */
char const * aDefaultHexRGB, /* NULL or "#FF0000" */ char const * aDefaultHexRGB, /* NULL or "#FF0000" */
unsigned char const aDefaultRGB[3] , /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */ unsigned char const aDefaultRGB[3] , /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
unsigned char aoResultRGB[3] ) ; /* unsigned char lResultRGB[3]; */ unsigned char aoResultRGB[3] ) ; /* unsigned char lResultRGB[3]; */
/* returns the hexcolor as a string "#FF0000" */ /* returns the hexcolor as a string "#FF0000" */
/* aoResultRGB also contains the result */ /* aoResultRGB also contains the result */
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */ /* aDefaultRGB is used only if aDefaultHexRGB is NULL */
/* aDefaultRGB and aoResultRGB can be the same array */ /* aDefaultRGB and aoResultRGB can be the same array */
/* returns NULL on cancel */ /* returns NULL on cancel */
/************ WINDOWS ONLY SECTION ************************/ /************ WINDOWS ONLY SECTION ************************/
@ -180,62 +180,62 @@ char * tinyfd_colorChooser(
/* windows only - utf-16 version */ /* windows only - utf-16 version */
int tinyfd_notifyPopupW( int tinyfd_notifyPopupW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */ wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
wchar_t const * aIconType); /* L"info" L"warning" L"error" */ wchar_t const * aIconType); /* L"info" L"warning" L"error" */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
int tinyfd_messageBoxW( int tinyfd_messageBoxW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" may contain \n \t */ wchar_t const * aMessage, /* NULL or L"" may contain \n \t */
wchar_t const * aDialogType, /* L"ok" L"okcancel" L"yesno" */ wchar_t const * aDialogType, /* L"ok" L"okcancel" L"yesno" */
wchar_t const * aIconType, /* L"info" L"warning" L"error" L"question" */ wchar_t const * aIconType, /* L"info" L"warning" L"error" L"question" */
int aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */ int aDefaultButton ); /* 0 for cancel/no , 1 for ok/yes */
/* returns 0 for cancel/no , 1 for ok/yes */ /* returns 0 for cancel/no , 1 for ok/yes */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_inputBoxW( wchar_t * tinyfd_inputBoxW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aMessage, /* NULL or L"" (\n nor \t not respected) */ wchar_t const * aMessage, /* NULL or L"" (\n nor \t not respected) */
wchar_t const * aDefaultInput); /* NULL passwordBox, L"" inputbox */ wchar_t const * aDefaultInput); /* NULL passwordBox, L"" inputbox */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_saveFileDialogW( wchar_t * tinyfd_saveFileDialogW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */ wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
int aNumOfFilterPatterns, /* 0 (1 in the following example) */ int aNumOfFilterPatterns, /* 0 (1 in the following example) */
wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[1]={L"*.txt"} */ wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[1]={L"*.txt"} */
wchar_t const * aSingleFilterDescription); /* NULL or L"text files" */ wchar_t const * aSingleFilterDescription); /* NULL or L"text files" */
/* returns NULL on cancel */ /* returns NULL on cancel */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_openFileDialogW( wchar_t * tinyfd_openFileDialogW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPathAndFile, /* NULL or L"" */ wchar_t const * aDefaultPathAndFile, /* NULL or L"" */
int aNumOfFilterPatterns , /* 0 (2 in the following example) */ int aNumOfFilterPatterns , /* 0 (2 in the following example) */
wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[2]={L"*.png","*.jpg"} */ wchar_t const * const * aFilterPatterns, /* NULL or wchar_t const * lFilterPatterns[2]={L"*.png","*.jpg"} */
wchar_t const * aSingleFilterDescription, /* NULL or L"image files" */ wchar_t const * aSingleFilterDescription, /* NULL or L"image files" */
int aAllowMultipleSelects ) ; /* 0 or 1 */ int aAllowMultipleSelects ) ; /* 0 or 1 */
/* in case of multiple files, the separator is | */ /* in case of multiple files, the separator is | */
/* returns NULL on cancel */ /* returns NULL on cancel */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_selectFolderDialogW( wchar_t * tinyfd_selectFolderDialogW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultPath); /* NULL or L"" */ wchar_t const * aDefaultPath); /* NULL or L"" */
/* returns NULL on cancel */ /* returns NULL on cancel */
/* windows only - utf-16 version */ /* windows only - utf-16 version */
wchar_t * tinyfd_colorChooserW( wchar_t * tinyfd_colorChooserW(
wchar_t const * aTitle, /* NULL or L"" */ wchar_t const * aTitle, /* NULL or L"" */
wchar_t const * aDefaultHexRGB, /* NULL or L"#FF0000" */ wchar_t const * aDefaultHexRGB, /* NULL or L"#FF0000" */
unsigned char const aDefaultRGB[3], /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */ unsigned char const aDefaultRGB[3], /* unsigned char lDefaultRGB[3] = { 0 , 128 , 255 }; */
unsigned char aoResultRGB[3]); /* unsigned char lResultRGB[3]; */ unsigned char aoResultRGB[3]); /* unsigned char lResultRGB[3]; */
/* returns the hexcolor as a string L"#FF0000" */ /* returns the hexcolor as a string L"#FF0000" */
/* aoResultRGB also contains the result */ /* aoResultRGB also contains the result */
/* aDefaultRGB is used only if aDefaultHexRGB is NULL */ /* aDefaultRGB is used only if aDefaultHexRGB is NULL */
/* aDefaultRGB and aoResultRGB can be the same array */ /* aDefaultRGB and aoResultRGB can be the same array */
/* returns NULL on cancel */ /* returns NULL on cancel */
#endif /*_WIN32 */ #endif /*_WIN32 */

View File

@ -21,44 +21,44 @@
class Util class Util
{ {
public: public:
static int divideRoundUp(const int num, const int denom) static int divideRoundUp(const int num, const int denom)
{ {
return (num+denom-1)/denom; return (num+denom-1)/denom;
} }
static int divideRound(const int dividend, const int divisor) static int divideRound(const int dividend, const int divisor)
{ {
return (dividend+divisor/2)/divisor; return (dividend+divisor/2)/divisor;
} }
template<typename T> static T mod(T x, const T m) template<typename T> static T mod(T x, const T m)
{ {
x %= m; x %= m;
if (x < 0) if (x < 0)
{ {
x += m; x += m;
} }
return x; return x;
} }
template<typename T> static void constrain(const T& min, T& x, const T& lim) template<typename T> static void constrain(const T& min, T& x, const T& lim)
{ {
if (x < min) if (x < min)
{ {
x = min; x = min;
} }
else if (lim <= x) else if (lim <= x)
{ {
x = lim-1; x = lim-1;
} }
} }
// 0x0 <= nib <= 0xF // 0x0 <= nib <= 0xF
// '0' <= ret <= 'F' // '0' <= ret <= 'F'
static char hexDigit(unsigned char nib) static char hexDigit(unsigned char nib)
{ {
return nib < 10 ? '0'+nib : 'A'+nib-10; return nib < 10 ? '0'+nib : 'A'+nib-10;
} }
}; };
#endif #endif

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): Video::Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows):
mode(mode), addressBus(addressBus), picgen(picgen), textRows(textRows) mode(mode), addressBus(addressBus), picgen(picgen), textRows(textRows)
{ {
VideoAddressing::buildLUT(TEXT_BASE_1,TEXT_LEN,lutTEXT[0]); VideoAddressing::buildLUT(TEXT_BASE_1,TEXT_LEN,lutTEXT[0]);
VideoAddressing::buildLUT(TEXT_BASE_2,TEXT_LEN,lutTEXT[1]); VideoAddressing::buildLUT(TEXT_BASE_2,TEXT_LEN,lutTEXT[1]);
VideoAddressing::buildLUT(HRES_BASE_1,HRES_LEN,lutHRES[0]); VideoAddressing::buildLUT(HRES_BASE_1,HRES_LEN,lutHRES[0]);
VideoAddressing::buildLUT(HRES_BASE_2,HRES_LEN,lutHRES[1]); VideoAddressing::buildLUT(HRES_BASE_2,HRES_LEN,lutHRES[1]);
} }
Video::~Video() Video::~Video()
@ -42,84 +42,84 @@ Video::~Video()
void Video::powerOn() void Video::powerOn()
{ {
this->t = 0; this->t = 0;
this->flash = false; this->flash = false;
this->cflash = 0; this->cflash = 0;
} }
void Video::tick() void Video::tick()
{ {
const unsigned char data = getDataByte(); const unsigned char data = getDataByte();
const unsigned char rowToPlot = getRowToPlot(data); const unsigned char rowToPlot = getRowToPlot(data);
this->picgen.tick(this->t,rowToPlot); this->picgen.tick(this->t,rowToPlot);
updateFlash(); updateFlash();
++this->t; ++this->t;
if (this->t >= E2Const::BYTES_PER_FIELD) if (this->t >= E2Const::BYTES_PER_FIELD)
{ {
this->t = 0; this->t = 0;
} }
} }
void Video::updateFlash() void Video::updateFlash()
{ {
++this->cflash; ++this->cflash;
if (this->cflash >= FLASH_HALF_PERIOD) if (this->cflash >= FLASH_HALF_PERIOD)
{ {
this->flash = !this->flash; this->flash = !this->flash;
this->cflash = 0; this->cflash = 0;
} }
} }
unsigned char Video::getDataByte() unsigned char Video::getDataByte()
{ {
// TODO should fix the mixed-mode scanning during VBL (see U.A.][, p. 5-13) // TODO should fix the mixed-mode scanning during VBL (see U.A.][, p. 5-13)
std::vector<unsigned short>& lut = std::vector<unsigned short>& lut =
(this->mode.isDisplayingText(this->t) || !this->mode.isHiRes()) (this->mode.isDisplayingText(this->t) || !this->mode.isHiRes())
? ?
this->lutTEXT[this->mode.getPage()] this->lutTEXT[this->mode.getPage()]
: :
this->lutHRES[this->mode.getPage()]; this->lutHRES[this->mode.getPage()];
return this->addressBus.read(lut[this->t]); return this->addressBus.read(lut[this->t]);
} }
unsigned char Video::getRowToPlot(unsigned char d) unsigned char Video::getRowToPlot(unsigned char d)
{ {
if (this->mode.isDisplayingText(this->t)) if (this->mode.isDisplayingText(this->t))
{ {
const bool inverse = inverseChar(d); const bool inverse = inverseChar(d);
const int y = this->t / E2Const::BYTES_PER_ROW; const int y = this->t / E2Const::BYTES_PER_ROW;
d = this->textRows.get(((d & 0x3F) << 3) | (y & 0x07)); d = this->textRows.get(((d & 0x3F) << 3) | (y & 0x07));
if (inverse) if (inverse)
{ {
d = ~d & 0x7F; d = ~d & 0x7F;
} }
} }
return d; return d;
} }
bool Video::inverseChar(const unsigned char d) bool Video::inverseChar(const unsigned char d)
{ {
bool inverse; bool inverse;
const int cs = (d >> 6) & 3; const int cs = (d >> 6) & 3;
if (cs == 0) if (cs == 0)
{ {
inverse = true; inverse = true;
} }
else if (cs == 1) else if (cs == 1)
{ {
inverse = this->flash; inverse = this->flash;
} }
else else
{ {
inverse = false; inverse = false;
} }
return inverse; return inverse;
} }

View File

@ -28,38 +28,38 @@ class TextCharacters;
class Video class Video
{ {
private: private:
enum { TEXT_BASE_1 = 0x0400 }; enum { TEXT_BASE_1 = 0x0400 };
enum { TEXT_BASE_2 = 0x0800 }; enum { TEXT_BASE_2 = 0x0800 };
enum { TEXT_LEN = 0x0400 }; enum { TEXT_LEN = 0x0400 };
enum { HRES_BASE_1 = 0x2000 }; enum { HRES_BASE_1 = 0x2000 };
enum { HRES_BASE_2 = 0x4000 }; enum { HRES_BASE_2 = 0x4000 };
enum { HRES_LEN = 0x2000 }; enum { HRES_LEN = 0x2000 };
std::vector<unsigned short> lutTEXT[2]; // [0] is page 1, [1] is page 2 std::vector<unsigned short> lutTEXT[2]; // [0] is page 1, [1] is page 2
std::vector<unsigned short> lutHRES[2]; // [0] is page 1, [1] is page 2 std::vector<unsigned short> lutHRES[2]; // [0] is page 1, [1] is page 2
VideoMode& mode; VideoMode& mode;
AddressBus& addressBus; AddressBus& addressBus;
PictureGenerator& picgen; PictureGenerator& picgen;
TextCharacters& textRows; TextCharacters& textRows;
unsigned int t; unsigned int t;
bool flash; bool flash;
int cflash; int cflash;
void updateFlash(); void updateFlash();
unsigned char getDataByte(); unsigned char getDataByte();
unsigned char getRowToPlot(unsigned char d); unsigned char getRowToPlot(unsigned char d);
bool inverseChar(const unsigned char d); bool inverseChar(const unsigned char d);
public: public:
Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows); Video(VideoMode& mode, AddressBus& addressBus, PictureGenerator& picgen, TextCharacters& textRows);
~Video(); ~Video();
void powerOn(); void powerOn();
void tick(); void tick();
}; };
#endif /*VIDEO_H_*/ #endif /*VIDEO_H_*/

View File

@ -24,62 +24,62 @@ VideoAddressing::VideoAddressing()
static int calc(const unsigned int t) static int calc(const unsigned int t)
{ {
int c = t % E2Const::VISIBLE_BYTES_PER_FIELD; int c = t % E2Const::VISIBLE_BYTES_PER_FIELD;
if (t >= E2Const::SCANNABLE_BYTES) if (t >= E2Const::SCANNABLE_BYTES)
{ {
c -= E2Const::RESET_BYTES; c -= E2Const::RESET_BYTES;
} }
int n = c / E2Const::BYTES_PER_ROW; int n = c / E2Const::BYTES_PER_ROW;
const int s = (n >> 6); const int s = (n >> 6);
n -= s << 6; n -= s << 6;
const int q = (n >> 3); const int q = (n >> 3);
n -= q << 3; n -= q << 3;
const int base = (n<<10) + (q<<7) + E2Const::VISIBLE_BYTES_PER_ROW*s; const int base = (n<<10) + (q<<7) + E2Const::VISIBLE_BYTES_PER_ROW*s;
const int half_page = base & 0xFF80; const int half_page = base & 0xFF80;
int a = base+(c%E2Const::BYTES_PER_ROW)-E2Const::BLANKED_BYTES_PER_ROW; int a = base+(c%E2Const::BYTES_PER_ROW)-E2Const::BLANKED_BYTES_PER_ROW;
if (a < half_page) if (a < half_page)
{ {
a += 0x80; a += 0x80;
} }
return a; return a;
} }
void VideoAddressing::buildLUT(const unsigned short base, const unsigned short len, std::vector<unsigned short>& lut) void VideoAddressing::buildLUT(const unsigned short base, const unsigned short len, std::vector<unsigned short>& lut)
{ {
lut.resize(E2Const::BYTES_PER_FIELD); lut.resize(E2Const::BYTES_PER_FIELD);
for (unsigned int t = 0; t < E2Const::BYTES_PER_FIELD; ++t) for (unsigned int t = 0; t < E2Const::BYTES_PER_FIELD; ++t)
{ {
unsigned int off = (calc(t) % len); unsigned int off = (calc(t) % len);
const unsigned int col = t % E2Const::BYTES_PER_ROW; const unsigned int col = t % E2Const::BYTES_PER_ROW;
const unsigned int row = t / E2Const::BYTES_PER_ROW; const unsigned int row = t / E2Const::BYTES_PER_ROW;
if (col < E2Const::BLANKED_BYTES_PER_ROW) if (col < E2Const::BLANKED_BYTES_PER_ROW)
{ {
// HBL // HBL
if (base < 0x1000) if (base < 0x1000)
{ {
off += 0x1000; off += 0x1000;
} }
if (col == 0) if (col == 0)
{ {
++off; ++off;
} }
} }
if (row >= E2Const::VISIBLE_ROWS_PER_FIELD) if (row >= E2Const::VISIBLE_ROWS_PER_FIELD)
{ {
// VBL // VBL
const int base2 = off & 0xFF80; const int base2 = off & 0xFF80;
off &= 0x7F; off &= 0x7F;
off -= 8; off -= 8;
off &= 0x7F; off &= 0x7F;
off += base2; off += base2;
} }
lut[t] = base + off; lut[t] = base + off;
} }
} }

View File

@ -23,8 +23,8 @@
class VideoAddressing class VideoAddressing
{ {
public: public:
VideoAddressing(); VideoAddressing();
static void buildLUT(const unsigned short base, const unsigned short len, std::vector<unsigned short>& lut); static void buildLUT(const unsigned short base, const unsigned short len, std::vector<unsigned short>& lut);
}; };
#endif #endif

View File

@ -23,26 +23,26 @@ VideoMode::VideoMode()
unsigned char VideoMode::io(const unsigned short addr, const unsigned char b) unsigned char VideoMode::io(const unsigned short addr, const unsigned char b)
{ {
const int sw = (addr & 0xE) >> 1; const int sw = (addr & 0xE) >> 1;
const bool on = addr & 0x1; const bool on = addr & 0x1;
switch (sw) switch (sw)
{ {
case 0: case 0:
this->swText = on; break; this->swText = on; break;
case 1: case 1:
this->swMixed = on; break; this->swMixed = on; break;
case 2: case 2:
this->swPage2 = on ? 1 : 0; break; this->swPage2 = on ? 1 : 0; break;
case 3: case 3:
this->swHiRes = on; break; this->swHiRes = on; break;
} }
return b; return b;
} }
void VideoMode::powerOn() void VideoMode::powerOn()
{ {
this->swText = false; this->swText = false;
this->swMixed = false; this->swMixed = false;
this->swPage2 = 0; this->swPage2 = 0;
this->swHiRes = false; this->swHiRes = false;
} }

View File

@ -24,21 +24,21 @@
class VideoMode class VideoMode
{ {
private: private:
bool swText; bool swText;
bool swMixed; bool swMixed;
int swPage2; int swPage2;
bool swHiRes; bool swHiRes;
public: public:
VideoMode(); VideoMode();
unsigned char io(const unsigned short addr, const unsigned char b); unsigned char io(const unsigned short addr, const unsigned char b);
void powerOn(); void powerOn();
bool isText() const { return this->swText; } bool isText() const { return this->swText; }
bool isHiRes() const { return this->swHiRes; } bool isHiRes() const { return this->swHiRes; }
bool isMixed() const { return this->swMixed; } bool isMixed() const { return this->swMixed; }
int getPage() const { return this->swPage2; } int getPage() const { return this->swPage2; }
bool isDisplayingText(const int atTickInField) const { return this->swText || (this->swMixed && atTickInField >= E2Const::MIXED_TEXT_CYCLE); } bool isDisplayingText(const int atTickInField) const { return this->swText || (this->swMixed && atTickInField >= E2Const::MIXED_TEXT_CYCLE); }
}; };
#endif #endif

View File

@ -22,13 +22,13 @@
#include <cstdlib> #include <cstdlib>
VideoStaticGenerator::VideoStaticGenerator(AnalogTV& display): VideoStaticGenerator::VideoStaticGenerator(AnalogTV& display):
display(display), display(display),
isig(sig), isig(sig),
isiglim(sig+AppleNTSC::SIGNAL_LEN), isiglim(sig+AppleNTSC::SIGNAL_LEN),
hpos(0) hpos(0)
{ {
this->display.signal = sig; this->display.signal = sig;
srand(time(0)); srand(time(0));
} }
@ -39,32 +39,32 @@ VideoStaticGenerator::~VideoStaticGenerator()
void VideoStaticGenerator::tick() void VideoStaticGenerator::tick()
{ {
signed char* is = this->isig; signed char* is = this->isig;
unsigned int cycles = E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE; unsigned int cycles = E2Const::CRYSTAL_CYCLES_PER_CPU_CYCLE;
if (this->hpos == E2Const::HORIZ_CYCLES-1) if (this->hpos == E2Const::HORIZ_CYCLES-1)
{ {
cycles += E2Const::EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE; cycles += E2Const::EXTRA_CRYSTAL_CYCLES_PER_CPU_LONG_CYCLE;
} }
for (unsigned int i = 0; i < cycles; ++i) for (unsigned int i = 0; i < cycles; ++i)
{ {
*is++ = (rand()>>7&0x7F)-27; *is++ = (rand()>>7&0x7F)-27;
} }
this->isig = is; this->isig = is;
++this->hpos; ++this->hpos;
if (this->hpos >= E2Const::HORIZ_CYCLES) if (this->hpos >= E2Const::HORIZ_CYCLES)
{ {
this->hpos = 0; this->hpos = 0;
if (isig >= isiglim) if (isig >= isiglim)
{ {
isig = sig; isig = sig;
this->display.drawCurrent(); this->display.drawCurrent();
} }
} }
} }
void VideoStaticGenerator::powerOn() void VideoStaticGenerator::powerOn()
{ {
this->hpos = 0; this->hpos = 0;
this->display.signal = sig; this->display.signal = sig;
isig = sig; isig = sig;
} }

View File

@ -25,18 +25,18 @@ class AnalogTV;
class VideoStaticGenerator : public Timable class VideoStaticGenerator : public Timable
{ {
private: private:
AnalogTV& display; AnalogTV& display;
signed char sig[AppleNTSC::SIGNAL_LEN]; signed char sig[AppleNTSC::SIGNAL_LEN];
signed char* isig; signed char* isig;
signed char* isiglim; signed char* isiglim;
unsigned int hpos; unsigned int hpos;
public: public:
VideoStaticGenerator(AnalogTV& display); VideoStaticGenerator(AnalogTV& display);
~VideoStaticGenerator(); ~VideoStaticGenerator();
virtual void tick(); virtual void tick();
void powerOn(); void powerOn();
}; };
#endif #endif