diff --git a/include/apple2.dbuf.h b/include/apple2.dbuf.h index 61d6ce2..bc52268 100644 --- a/include/apple2.dbuf.h +++ b/include/apple2.dbuf.h @@ -7,5 +7,7 @@ extern SEGMENT_READER(apple2_dbuf_read); extern SEGMENT_WRITER(apple2_dbuf_write); extern void apple2_dbuf_map(vm_segment *); +extern SEGMENT_READER(apple2_dbuf_switch_read); +extern SEGMENT_WRITER(apple2_dbuf_switch_write); #endif diff --git a/src/apple2.dbuf.c b/src/apple2.dbuf.c index 9457cb7..dc47126 100644 --- a/src/apple2.dbuf.c +++ b/src/apple2.dbuf.c @@ -4,6 +4,33 @@ #include "apple2.dbuf.h" +static size_t switch_reads[] = { + 0xC01A, + 0xC01B, + 0xC01E, + 0xC01F, + 0xC07E, + 0xC07F, +}; + +static size_t switch_writes[] = { + 0xC00C, + 0xC00D, + 0xC00E, + 0xC00F, + 0xC050, + 0xC051, + 0xC052, + 0xC053, + 0xC056, + 0xC057, + 0xC059, + 0xC05E, + 0xC05F, + 0xC07E, + 0xC07F, +}; + /* * Handle reads from text page 1 and hires graphics page 1 (the display * buffers). @@ -71,6 +98,7 @@ void apple2_dbuf_map(vm_segment *segment) { size_t addr; + int i, rlen, wlen; for (addr = 0x400; addr < 0x800; addr++) { vm_segment_read_map(segment, addr, apple2_dbuf_read); @@ -81,13 +109,140 @@ apple2_dbuf_map(vm_segment *segment) vm_segment_read_map(segment, addr, apple2_dbuf_read); vm_segment_write_map(segment, addr, apple2_dbuf_write); } + + rlen = sizeof(switch_reads) / sizeof(size_t); + wlen = sizeof(switch_writes) / sizeof(size_t); + + for (i = 0; i < rlen; i++) { + vm_segment_read_map(segment, switch_reads[i], apple2_dbuf_switch_read); + } + + for (i = 0; i < wlen; i++) { + vm_segment_write_map(segment, switch_writes[i], apple2_dbuf_switch_write); + } } /* * Handle all read switches for display buffer code. Some switches * respond to either reads _or_ writes, so you may see some cases * duplicated in the write map. + * + * Additionally, a number of the display modes also count as memory + * modes, and are handled in apple2.mem.c. Notably, some are HIRES, + * PAGE2, and 80STORE. */ SEGMENT_READER(apple2_dbuf_switch_read) { + apple2 *mach = (apple2 *)_mach; + + switch (addr) { + case 0xC01E: + return mach->display_mode & DISPLAY_ALTCHAR + ? 0x80 + : 0x00; + + case 0xC01F: + return mach->display_mode & DISPLAY_80COL + ? 0x80 + : 0x00; + + case 0xC01A: + return mach->display_mode & DISPLAY_TEXT + ? 0x80 + : 0x00; + + case 0xC01B: + return mach->display_mode & DISPLAY_MIXED + ? 0x80 + : 0x00; + + // NOTE: IOUDIS is the only bit that seems to share a write + // address with a read address. We can certainly handle that, + // since we support separate read and write tables! But it's + // interesting that they chose to do that, where they mostly + // stick with separate addresses for separate functions. + case 0xC07E: + return mach->display_mode & DISPLAY_IOUDIS + ? 0x80 + : 0x00; + + case 0xC07F: + return mach->display_mode & DISPLAY_DHIRES + ? 0x80 + : 0x00; + } + + // ??? + return 0; +} + +/* + * Here we update the statuses of the various display soft switches, + * and--there's a bunch of them! + */ +SEGMENT_WRITER(apple2_dbuf_switch_write) +{ + apple2 *mach = (apple2 *)_mach; + + switch (addr) { + case 0xC00E: + apple2_set_display(mach, + mach->display_mode | DISPLAY_ALTCHAR); + break; + + case 0xC00F: + apple2_set_display(mach, + mach->display_mode & ~DISPLAY_ALTCHAR); + break; + + case 0xC00C: + apple2_set_display(mach, + mach->display_mode | DISPLAY_80COL); + break; + + case 0xC00D: + apple2_set_display(mach, + mach->display_mode & ~DISPLAY_80COL); + break; + + case 0xC050: + apple2_set_display(mach, + mach->display_mode | DISPLAY_TEXT); + break; + + case 0xC051: + apple2_set_display(mach, + mach->display_mode & ~DISPLAY_TEXT); + break; + + case 0xC052: + apple2_set_display(mach, + mach->display_mode | DISPLAY_MIXED); + break; + + case 0xC053: + apple2_set_display(mach, + mach->display_mode & ~DISPLAY_MIXED); + break; + + case 0xC07E: + apple2_set_display(mach, + mach->display_mode | DISPLAY_IOUDIS); + break; + + case 0xC07F: + apple2_set_display(mach, + mach->display_mode & ~DISPLAY_IOUDIS); + break; + + case 0xC05E: + apple2_set_display(mach, + mach->display_mode | DISPLAY_DHIRES); + break; + + case 0xC05F: + apple2_set_display(mach, + mach->display_mode & ~DISPLAY_DHIRES); + break; + } }