mirror of
https://github.com/bradgrantham/apple2e.git
synced 2024-06-27 08:29:29 +00:00
add initial support for recording softswitch history by byte clock
This commit is contained in:
parent
55bbd69e28
commit
48be02beb0
157
apple2e.cpp
157
apple2e.cpp
|
@ -38,6 +38,9 @@ volatile bool exit_on_memory_fallthrough = true;
|
||||||
volatile bool run_fast = false;
|
volatile bool run_fast = false;
|
||||||
volatile bool pause_cpu = false;
|
volatile bool pause_cpu = false;
|
||||||
|
|
||||||
|
// XXX - this should be handled through a function passed to MAINboard
|
||||||
|
APPLE2Einterface::ModeHistory mode_history;
|
||||||
|
|
||||||
const float paddle_max_pulse_seconds = .00282;
|
const float paddle_max_pulse_seconds = .00282;
|
||||||
|
|
||||||
typedef unsigned long long clk_t;
|
typedef unsigned long long clk_t;
|
||||||
|
@ -619,6 +622,7 @@ struct MAINboard : board_base
|
||||||
|
|
||||||
vector<SoftSwitch*> switches;
|
vector<SoftSwitch*> switches;
|
||||||
SoftSwitch* switches_by_address[256];
|
SoftSwitch* switches_by_address[256];
|
||||||
|
// SoftSwitch(const char* name_, int clear, int on, int read, bool read_changes, vector<SoftSwitch*>& s, bool implemented_ = false) :
|
||||||
SoftSwitch CXROM {"CXROM", 0xC006, 0xC007, 0xC015, false, switches, true};
|
SoftSwitch CXROM {"CXROM", 0xC006, 0xC007, 0xC015, false, switches, true};
|
||||||
SoftSwitch STORE80 {"STORE80", 0xC000, 0xC001, 0xC018, false, switches, true};
|
SoftSwitch STORE80 {"STORE80", 0xC000, 0xC001, 0xC018, false, switches, true};
|
||||||
SoftSwitch RAMRD {"RAMRD", 0xC002, 0xC003, 0xC013, false, switches, true};
|
SoftSwitch RAMRD {"RAMRD", 0xC002, 0xC003, 0xC013, false, switches, true};
|
||||||
|
@ -754,6 +758,29 @@ struct MAINboard : board_base
|
||||||
keyboard_buffer.push_back(k);
|
keyboard_buffer.push_back(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
APPLE2Einterface::ModeSettings convert_switches_to_mode_settings()
|
||||||
|
{
|
||||||
|
APPLE2Einterface::DisplayMode mode = TEXT ? APPLE2Einterface::TEXT : (HIRES ? APPLE2Einterface::HIRES : APPLE2Einterface::LORES);
|
||||||
|
int page = (PAGE2 && !STORE80) ? 1 : 0;
|
||||||
|
if(0)printf("mode %s, mixed %s, page %d, vid80 %s, altchar %s\n",
|
||||||
|
(mode == APPLE2Einterface::TEXT) ? "TEXT" : ((mode == APPLE2Einterface::LORES) ? "LORES" : "HIRES"),
|
||||||
|
MIXED ? "true" : "false",
|
||||||
|
page,
|
||||||
|
VID80 ? "true" : "false",
|
||||||
|
ALTCHAR ? "true" : "false");
|
||||||
|
return APPLE2Einterface::ModeSettings(mode, MIXED, page, VID80, ALTCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
APPLE2Einterface::ModeSettings old_mode_settings;
|
||||||
|
void post_soft_switch_mode_change()
|
||||||
|
{
|
||||||
|
APPLE2Einterface::ModeSettings settings = convert_switches_to_mode_settings();
|
||||||
|
if(settings != old_mode_settings) {
|
||||||
|
mode_history.push_back(make_tuple(clk.clock_cpu, settings));
|
||||||
|
old_mode_settings = settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
typedef std::function<bool (int addr, bool aux, unsigned char data)> display_write_func;
|
typedef std::function<bool (int addr, bool aux, unsigned char data)> display_write_func;
|
||||||
display_write_func display_write;
|
display_write_func display_write;
|
||||||
typedef std::function<void (char *audiobuffer, size_t dist)> audio_flush_func;
|
typedef std::function<void (char *audiobuffer, size_t dist)> audio_flush_func;
|
||||||
|
@ -790,7 +817,8 @@ struct MAINboard : board_base
|
||||||
switches_by_address[sw->set_address - 0xC000] = sw;
|
switches_by_address[sw->set_address - 0xC000] = sw;
|
||||||
switches_by_address[sw->read_address - 0xC000] = sw;
|
switches_by_address[sw->read_address - 0xC000] = sw;
|
||||||
}
|
}
|
||||||
TEXT.enabled = true;
|
// TEXT.enabled = true;
|
||||||
|
old_mode_settings = convert_switches_to_mode_settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~MAINboard()
|
virtual ~MAINboard()
|
||||||
|
@ -815,58 +843,6 @@ struct MAINboard : board_base
|
||||||
|
|
||||||
virtual bool read(int addr, unsigned char &data)
|
virtual bool read(int addr, unsigned char &data)
|
||||||
{
|
{
|
||||||
// Special case for floating bus for reading video scanout
|
|
||||||
// XXX doesn't handle 80-column nor AUX
|
|
||||||
if((addr == 0xC050) || (addr == 0xC051)) {
|
|
||||||
bool page1 = (PAGE2 && !STORE80) ? false : true;
|
|
||||||
|
|
||||||
// 65 bytes per line, 262 lines per frame (aka "field")
|
|
||||||
int byte_in_frame = clk.clock_cpu % 17030;
|
|
||||||
int line_in_frame = byte_in_frame / 65;
|
|
||||||
|
|
||||||
if(1)printf("TEXT %s, HIRES %s, MIXED %s, line_in_frame = %d\n",
|
|
||||||
TEXT ? "true" : "false",
|
|
||||||
HIRES ? "true" : "false",
|
|
||||||
MIXED ? "true" : "false",
|
|
||||||
line_in_frame);
|
|
||||||
|
|
||||||
bool mixed_text_scanout =
|
|
||||||
((line_in_frame >= 160) && (line_in_frame < 192)) ||
|
|
||||||
(line_in_frame >= 224);
|
|
||||||
if(TEXT || !HIRES || (MIXED && mixed_text_scanout)) {
|
|
||||||
// TEXT or GR mode; they read the same addresses.
|
|
||||||
int addr2 = get_text_scanout_address(byte_in_frame) + (page1 ? 0 : 0x0400);
|
|
||||||
printf("got text scanout address $%04X\n", addr2);
|
|
||||||
if(addr2 > 0xC00) {
|
|
||||||
printf("read 0C00 floating bus\n");
|
|
||||||
ram_0C00.read(addr2, data);
|
|
||||||
} else {
|
|
||||||
if(page1) {
|
|
||||||
printf("read text page1 floating bus\n");
|
|
||||||
text_page1.read(addr2, data);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
printf("read text page2 floating bus\n");
|
|
||||||
text_page2.read(addr2, data);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// HGR mode and not in text region if MIXED
|
|
||||||
int addr2 = get_hires_scanout_address(byte_in_frame) + (page1 ? 0 : 0x2000);
|
|
||||||
printf("got hires scanout address $%04X\n", addr2);
|
|
||||||
if(page1) {
|
|
||||||
printf("read hires page1 floating bus\n");
|
|
||||||
hires_page1.read(addr2, data);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
printf("read hires page2 floating bus\n");
|
|
||||||
hires_page2.read(addr2, data);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(debug & DEBUG_RW) printf("MAIN board read\n");
|
if(debug & DEBUG_RW) printf("MAIN board read\n");
|
||||||
for(auto b : boards) {
|
for(auto b : boards) {
|
||||||
if(b->read(addr, data)) {
|
if(b->read(addr, data)) {
|
||||||
|
@ -880,21 +856,74 @@ struct MAINboard : board_base
|
||||||
}
|
}
|
||||||
SoftSwitch* sw = switches_by_address[addr - 0xC000];
|
SoftSwitch* sw = switches_by_address[addr - 0xC000];
|
||||||
if(sw != NULL) {
|
if(sw != NULL) {
|
||||||
|
|
||||||
|
unsigned char result = 0xFF;
|
||||||
|
|
||||||
|
// Special case for floating bus for reading video scanout
|
||||||
|
// XXX doesn't handle 80-column nor AUX
|
||||||
|
if((addr == 0xC050) || (addr == 0xC051)) {
|
||||||
|
bool page1 = (PAGE2 && !STORE80) ? false : true;
|
||||||
|
|
||||||
|
// 65 bytes per line, 262 lines per frame (aka "field")
|
||||||
|
int byte_in_frame = clk.clock_cpu % 17030;
|
||||||
|
int line_in_frame = byte_in_frame / 65;
|
||||||
|
|
||||||
|
if(0)printf("TEXT %s, HIRES %s, MIXED %s, line_in_frame = %d\n",
|
||||||
|
TEXT ? "true" : "false",
|
||||||
|
HIRES ? "true" : "false",
|
||||||
|
MIXED ? "true" : "false",
|
||||||
|
line_in_frame);
|
||||||
|
|
||||||
|
bool mixed_text_scanout =
|
||||||
|
((line_in_frame >= 160) && (line_in_frame < 192)) ||
|
||||||
|
(line_in_frame >= 224);
|
||||||
|
if(TEXT || !HIRES || (MIXED && mixed_text_scanout)) {
|
||||||
|
// TEXT or GR mode; they read the same addresses.
|
||||||
|
int addr2 = get_text_scanout_address(byte_in_frame) + (page1 ? 0 : 0x0400);
|
||||||
|
printf("got text scanout address $%04X\n", addr2);
|
||||||
|
if(addr2 > 0xC00) {
|
||||||
|
printf("read 0C00 floating bus\n");
|
||||||
|
ram_0C00.read(addr2, result);
|
||||||
|
} else {
|
||||||
|
if(page1) {
|
||||||
|
printf("read text page1 floating bus\n");
|
||||||
|
text_page1.read(addr2, result);
|
||||||
|
} else {
|
||||||
|
printf("read text page2 floating bus\n");
|
||||||
|
text_page2.read(addr2, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// HGR mode and not in text region if MIXED
|
||||||
|
int addr2 = get_hires_scanout_address(byte_in_frame) + (page1 ? 0 : 0x2000);
|
||||||
|
printf("got hires scanout address $%04X\n", addr2);
|
||||||
|
if(page1) {
|
||||||
|
printf("read hires page1 floating bus\n");
|
||||||
|
hires_page1.read(addr2, result);
|
||||||
|
} else {
|
||||||
|
printf("read hires page2 floating bus\n");
|
||||||
|
hires_page2.read(addr2, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(addr == sw->read_address) {
|
if(addr == sw->read_address) {
|
||||||
data = sw->enabled ? 0x80 : 0x00;
|
data = sw->enabled ? 0x80 : 0x00;
|
||||||
if(debug & DEBUG_SWITCH) printf("Read status of %s = %02X\n", sw->name.c_str(), data);
|
if(debug & DEBUG_SWITCH) printf("Read status of %s = %02X\n", sw->name.c_str(), data);
|
||||||
return true;
|
return true;
|
||||||
} else if(sw->read_also_changes && addr == sw->set_address) {
|
} else if(sw->read_also_changes && addr == sw->set_address) {
|
||||||
if(!sw->implemented) { printf("%s ; set is unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
if(!sw->implemented) { printf("%s ; set is unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
||||||
data = 0xff;
|
data = result;
|
||||||
sw->enabled = true;
|
sw->enabled = true;
|
||||||
if(debug & DEBUG_SWITCH) printf("Set %s\n", sw->name.c_str());
|
if(debug & DEBUG_SWITCH) printf("Set %s\n", sw->name.c_str());
|
||||||
|
post_soft_switch_mode_change();
|
||||||
return true;
|
return true;
|
||||||
} else if(sw->read_also_changes && addr == sw->clear_address) {
|
} else if(sw->read_also_changes && addr == sw->clear_address) {
|
||||||
if(!sw->implemented) { printf("%s ; unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
if(!sw->implemented) { printf("%s ; unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
||||||
data = 0xff;
|
data = result;
|
||||||
sw->enabled = false;
|
sw->enabled = false;
|
||||||
if(debug & DEBUG_SWITCH) printf("Clear %s\n", sw->name.c_str());
|
if(debug & DEBUG_SWITCH) printf("Clear %s\n", sw->name.c_str());
|
||||||
|
post_soft_switch_mode_change();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1035,12 +1064,14 @@ struct MAINboard : board_base
|
||||||
data = 0xff;
|
data = 0xff;
|
||||||
sw->enabled = true;
|
sw->enabled = true;
|
||||||
if(debug & DEBUG_SWITCH) printf("Set %s\n", sw->name.c_str());
|
if(debug & DEBUG_SWITCH) printf("Set %s\n", sw->name.c_str());
|
||||||
|
post_soft_switch_mode_change();
|
||||||
return true;
|
return true;
|
||||||
} else if(addr == sw->clear_address) {
|
} else if(addr == sw->clear_address) {
|
||||||
// if(!sw->implemented) { printf("%s ; unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
// if(!sw->implemented) { printf("%s ; unimplemented\n", sw->name.c_str()); fflush(stdout); exit(0); }
|
||||||
data = 0xff;
|
data = 0xff;
|
||||||
sw->enabled = false;
|
sw->enabled = false;
|
||||||
if(debug & DEBUG_SWITCH) printf("Clear %s\n", sw->name.c_str());
|
if(debug & DEBUG_SWITCH) printf("Clear %s\n", sw->name.c_str());
|
||||||
|
post_soft_switch_mode_change();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3007,12 +3038,8 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
mainboard->sync();
|
mainboard->sync();
|
||||||
|
|
||||||
APPLE2Einterface::DisplayMode mode = mainboard->TEXT ? APPLE2Einterface::TEXT : (mainboard->HIRES ? APPLE2Einterface::HIRES : APPLE2Einterface::LORES);
|
APPLE2Einterface::iterate(mode_history);
|
||||||
int page = (mainboard->PAGE2 && !mainboard->STORE80) ? 1 : 0;
|
mode_history.clear();
|
||||||
APPLE2Einterface::ModeSettings settings(mode, mainboard->MIXED, page, mainboard->VID80, mainboard->ALTCHAR);
|
|
||||||
APPLE2Einterface::ModeHistory history;
|
|
||||||
history.push_back(make_tuple(0, settings));
|
|
||||||
APPLE2Einterface::iterate(history);
|
|
||||||
|
|
||||||
chrono::time_point<chrono::system_clock> now = std::chrono::system_clock::now();
|
chrono::time_point<chrono::system_clock> now = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
@ -3075,12 +3102,8 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
mainboard->sync();
|
mainboard->sync();
|
||||||
|
|
||||||
APPLE2Einterface::DisplayMode mode = mainboard->TEXT ? APPLE2Einterface::TEXT : (mainboard->HIRES ? APPLE2Einterface::HIRES : APPLE2Einterface::LORES);
|
APPLE2Einterface::iterate(mode_history);
|
||||||
int page = (mainboard->PAGE2 && !mainboard->STORE80) ? 1 : 0;
|
mode_history.clear();
|
||||||
APPLE2Einterface::ModeSettings settings(mode, mainboard->MIXED, page, mainboard->VID80, mainboard->ALTCHAR);
|
|
||||||
APPLE2Einterface::ModeHistory history;
|
|
||||||
history.push_back(make_tuple(0, settings));
|
|
||||||
APPLE2Einterface::iterate(history);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1939,8 +1939,9 @@ void iterate(const ModeHistory& history)
|
||||||
for(auto& h: history) {
|
for(auto& h: history) {
|
||||||
unsigned int byte_in_frame = get<0>(h);
|
unsigned int byte_in_frame = get<0>(h);
|
||||||
const ModeSettings& settings = get<1>(h);
|
const ModeSettings& settings = get<1>(h);
|
||||||
int line_in_frame = byte_in_frame / 65;
|
int line_in_frame = (byte_in_frame % 17030) / 65;
|
||||||
if(0)printf("%u, TEXT %s, HIRES %s, MIXED %s, line_in_frame = %d\n",
|
|
||||||
|
if(1)printf("%u, TEXT %s, HIRES %s, MIXED %s, line_in_frame = %d\n",
|
||||||
byte_in_frame,
|
byte_in_frame,
|
||||||
(settings.mode == TEXT) ? "true" : "false",
|
(settings.mode == TEXT) ? "true" : "false",
|
||||||
(settings.mode == HIRES) ? "true" : "false",
|
(settings.mode == HIRES) ? "true" : "false",
|
||||||
|
|
16
interface.h
16
interface.h
|
@ -52,6 +52,13 @@ struct ModeSettings
|
||||||
int page;
|
int page;
|
||||||
bool vid80;
|
bool vid80;
|
||||||
bool altchar;
|
bool altchar;
|
||||||
|
ModeSettings() :
|
||||||
|
mode(TEXT),
|
||||||
|
mixed(false),
|
||||||
|
page(0),
|
||||||
|
vid80(false),
|
||||||
|
altchar(false)
|
||||||
|
{}
|
||||||
ModeSettings(DisplayMode mode_, bool mixed_, int page_, bool vid80_, bool altchar_) :
|
ModeSettings(DisplayMode mode_, bool mixed_, int page_, bool vid80_, bool altchar_) :
|
||||||
mode(mode_),
|
mode(mode_),
|
||||||
mixed(mixed_),
|
mixed(mixed_),
|
||||||
|
@ -59,6 +66,15 @@ struct ModeSettings
|
||||||
vid80(vid80_),
|
vid80(vid80_),
|
||||||
altchar(altchar_)
|
altchar(altchar_)
|
||||||
{}
|
{}
|
||||||
|
bool operator !=(const ModeSettings& ms)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(ms.mode != mode) ||
|
||||||
|
(ms.mixed != mixed) ||
|
||||||
|
(ms.page != page) ||
|
||||||
|
(ms.vid80 != vid80) ||
|
||||||
|
(ms.altchar != altchar);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<std::tuple<unsigned int, ModeSettings> > ModeHistory;
|
typedef std::vector<std::tuple<unsigned int, ModeSettings> > ModeHistory;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user