From 3738d70a43299e8f039f1d15cef67ec696fe87fe Mon Sep 17 00:00:00 2001 From: Peter Evans Date: Fri, 12 Jan 2018 22:06:49 -0600 Subject: [PATCH] Switch bank code into its own file --- include/apple2.bank.h | 13 +++ include/apple2.mem.h | 5 - sources.cmake | 1 + src/apple2.bank.c | 253 ++++++++++++++++++++++++++++++++++++++++++ src/apple2.mem.c | 30 +---- tests/apple2.bank.c | 193 ++++++++++++++++++++++++++++++++ tests/apple2.mem.c | 173 +---------------------------- 7 files changed, 463 insertions(+), 205 deletions(-) create mode 100644 include/apple2.bank.h create mode 100644 src/apple2.bank.c create mode 100644 tests/apple2.bank.c diff --git a/include/apple2.bank.h b/include/apple2.bank.h new file mode 100644 index 0000000..eb820c5 --- /dev/null +++ b/include/apple2.bank.h @@ -0,0 +1,13 @@ +#ifndef _APPLE2_BANK_H_ +#define _APPLE2_BANK_H_ + +#include "apple2.mem.h" +#include "vm_segment.h" + +extern SEGMENT_READER(apple2_bank_read); +extern SEGMENT_READER(apple2_bank_switch_read); +extern SEGMENT_WRITER(apple2_bank_switch_write); +extern SEGMENT_WRITER(apple2_bank_write); +extern void apple2_bank_map(vm_segment *); + +#endif diff --git a/include/apple2.mem.h b/include/apple2.mem.h index 7a80015..b36f902 100644 --- a/include/apple2.mem.h +++ b/include/apple2.mem.h @@ -56,13 +56,8 @@ */ #define APPLE2_BANK_OFFSET 0xD000 -extern SEGMENT_READER(apple2_mem_read_bank); -extern SEGMENT_WRITER(apple2_mem_write_bank); extern int apple2_mem_init_peripheral_rom(apple2 *); extern int apple2_mem_init_sys_rom(apple2 *); extern void apple2_mem_map(apple2 *, vm_segment *); -extern void apple2_mem_map_bank_switch(vm_segment *); -extern SEGMENT_READER(apple2_mem_read_bank_switch); -extern SEGMENT_WRITER(apple2_mem_write_bank_switch); #endif diff --git a/sources.cmake b/sources.cmake index 647c42b..e0139c3 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,6 @@ set(erc_sources apple2.c + apple2.bank.c apple2.dd.c apple2.draw.c apple2.mem.c diff --git a/src/apple2.bank.c b/src/apple2.bank.c new file mode 100644 index 0000000..f85fbfb --- /dev/null +++ b/src/apple2.bank.c @@ -0,0 +1,253 @@ +/* + * apple2.mem.c + */ + +#include "apple2.h" +#include "apple2.bank.h" +#include "apple2.mem.h" +#include "objstore.h" + +/* + * These are the addresses that need to be mapped to the + * bank_switch_read function. + */ +static size_t switch_reads[] = { + 0xC080, + 0xC081, + 0xC082, + 0xC083, + 0xC088, + 0xC089, + 0xC08A, + 0xC08B, + 0xC011, + 0xC012, + 0xC016, +}; + +/* + * These will be mapped to the bank_switch_write function. + */ +static size_t switch_writes[] = { + 0xC008, + 0xC009, +}; + +/* + * Return a byte of memory from a bank-switchable address. This may be + * from ROM, from main memory, or from the "extra" 4k bank of RAM. + */ +SEGMENT_READER(apple2_bank_read) +{ + apple2 *mach; + + mach = (apple2 *)_mach; + + // In the case of bank-switchable memory, BANK_ALTZP is the ultimate + // arbitrator; if it's on, we have to use aux, and if not, we have + // to use main. Whatever the segment was that was passed in will + // turn out to be immaterial. + segment = (mach->bank_switch & BANK_ALTZP) ? mach->aux : mach->main; + + if (~mach->bank_switch & BANK_RAM) { + // We need to account for the difference in address location + // before we can successfully get any data from ROM. + return vm_segment_get(mach->rom, addr - APPLE2_BANK_OFFSET); + } + + // Each memory bank (main or auxiliary) have an additional 4k of RAM + // that you can access through bank-switching in the $D000 - $DFFF + // range, which is actually held at the _end_ of memory beyond the + // 64k mark. + if (addr < 0xE000 && mach->bank_switch & BANK_RAM2) { + // The same caution holds for getting data from the + // second RAM bank. + return segment->memory[addr + 0x3000]; + } + + // Otherwise, the byte is returned from bank 1 RAM, which is the + // literal memory available in the segment. + return segment->memory[addr]; +} + +/* + * Write a byte into bank-switchable memory. Many of the same cautions, + * notes, etc. written for the read function apply here as well. + */ +SEGMENT_WRITER(apple2_bank_write) +{ + apple2 *mach; + + mach = (apple2 *)_mach; + + // No writes are allowed... sorry! + if (~mach->bank_switch & BANK_WRITE) { + return; + } + + // See my spiel in the read bank mapper; the same applies here. + segment = (mach->bank_switch & BANK_ALTZP) ? mach->aux : mach->main; + + // You will note, if we've gotten here, that it's possible to write + // to the bank-switch addresses even if the ROM flag is 1. It's + // true! Except that writes never go to ROM. That is to say, it's + // possible to read from ROM and write to RAM at the same + // time--well, nearly the same time, considering the 6502 does not + // allow parallel actions! + + // In this case, we need to assign the value at the 64-68k range at + // the end of memory; this is just a simple offset from the given + // address. + if (addr < 0xE000 && mach->bank_switch & BANK_RAM2) { + segment->memory[addr + 0x3000] = value; + return; + } + + // But if bank 2 RAM is not turned on, or the address is between + // $E000 - $FFFF, then writes go to bank 1 RAM, which is our main + // memory. + segment->memory[addr] = value; +} + +/* + * This function will establish all of the mapper functions to handle + * the soft switches for memory bank-switching. + */ +void +apple2_bank_map(vm_segment *segment) +{ + size_t addr; + int i, rlen, wlen; + + for (addr = APPLE2_BANK_OFFSET; addr < MOS6502_MEMSIZE; addr++) { + vm_segment_read_map(segment, addr, apple2_bank_read); + vm_segment_write_map(segment, addr, apple2_bank_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_bank_switch_read); + } + + for (i = 0; i < wlen; i++) { + vm_segment_write_map(segment, switch_writes[i], + apple2_bank_switch_write); + } +} + +/* + * Handle reads to the soft switches that handle bank-switching. Note + * that some of these "reads" actually modify how banks are switched + * between ROM, RAM, or bank 2 RAM. Sorry about that -- it's just the + * way it worked on the Apple II. + */ +SEGMENT_READER(apple2_bank_switch_read) +{ + apple2 *mach; + vm_16bit last_addr; + + mach = (apple2 *)_mach; + + // We need to know the last opcode and address, because some of our + // soft switches require two consecutive reads + mos6502_last_executed(mach->cpu, NULL, NULL, &last_addr); + + switch (addr) { + // The $C080 - $C083 range all control memory access while using + // bank 2 RAM for the $Dnnn range. Note that here and in the + // $C088 range, the returns are zero; I'm not exactly sure + // that's what they should be, but the purpose of reading from + // these soft switches is not actually to read anything useful, + // but simply to change the bank switch mode. + case 0xC080: + apple2_set_bank_switch(mach, BANK_RAM | BANK_RAM2); + return 0; + + case 0xC081: + if (last_addr == addr) { + apple2_set_bank_switch(mach, BANK_WRITE | BANK_RAM2); + } + return 0; + case 0xC082: + apple2_set_bank_switch(mach, BANK_RAM2); + return 0; + + case 0xC083: + if (last_addr == addr) { + apple2_set_bank_switch(mach, BANK_RAM | BANK_WRITE | BANK_RAM2); + } + return 0; + + // Conversely, the $C088 - $C08B range control memory access + // while using bank 1 RAM. + case 0xC088: + apple2_set_bank_switch(mach, BANK_RAM); + return 0; + + case 0xC089: + if (last_addr == addr) { + apple2_set_bank_switch(mach, BANK_WRITE); + } + return 0; + + case 0xC08A: + apple2_set_bank_switch(mach, BANK_DEFAULT); + return 0; + + case 0xC08B: + if (last_addr == addr) { + apple2_set_bank_switch(mach, BANK_RAM | BANK_WRITE); + } + return 0; + + // Return high on the 7th bit if we're using bank 2 memory + case 0xC011: + return mach->bank_switch & BANK_RAM2 + ? 0x80 + : 0x00; + + // Return high on 7th bit if we're reading RAM + case 0xC012: + return mach->bank_switch & BANK_RAM + ? 0x80 + : 0x00; + + // Return high on the 7th bit if we are using the zero page and + // stack from aux memory. + case 0xC016: + return mach->bank_switch & BANK_ALTZP + ? 0x80 + : 0x00; + } + + log_critical("Bank switch read mapper called with an unexpected address: %x", addr); + return 0; +} + +/* + * Handle writes to the soft switches that modify bank-switching + * behavior. + */ +SEGMENT_WRITER(apple2_bank_switch_write) +{ + apple2 *mach = (apple2 *)_mach; + + switch (addr) { + // Turn on auxiliary memory for zero page + stack + case 0xC008: + apple2_set_bank_switch(mach, + mach->bank_switch | BANK_ALTZP); + return; + + // Disable auxiliary memory for zero page + stack + case 0xC009: + apple2_set_bank_switch(mach, + mach->bank_switch & ~BANK_ALTZP); + return; + } + + log_critical("Bank switch write mapper called with an unexpected address: %x", addr); +} diff --git a/src/apple2.mem.c b/src/apple2.mem.c index 92a0716..a4421de 100644 --- a/src/apple2.mem.c +++ b/src/apple2.mem.c @@ -4,6 +4,7 @@ #include "apple2.h" #include "apple2.mem.h" +#include "apple2.bank.h" #include "objstore.h" /* @@ -92,34 +93,7 @@ apple2_mem_map(apple2 *mach, vm_segment *segment) vm_segment_set_map_machine(mach); - for (addr = APPLE2_BANK_OFFSET; addr < MOS6502_MEMSIZE; addr++) { - vm_segment_read_map(segment, addr, apple2_mem_read_bank); - vm_segment_write_map(segment, addr, apple2_mem_write_bank); - } - - apple2_mem_map_bank_switch(segment); -} - -/* - * This function will establish all of the mapper functions to handle - * the soft switches for memory bank-switching. - */ -void -apple2_mem_map_bank_switch(vm_segment *segment) -{ - vm_segment_read_map(segment, 0xC080, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC081, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC082, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC083, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC088, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC089, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC08A, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC08B, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC011, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC012, apple2_mem_read_bank_switch); - vm_segment_read_map(segment, 0xC016, apple2_mem_read_bank_switch); - vm_segment_write_map(segment, 0xC008, apple2_mem_write_bank_switch); - vm_segment_write_map(segment, 0xC009, apple2_mem_write_bank_switch); + apple2_bank_map(segment); } /* diff --git a/tests/apple2.bank.c b/tests/apple2.bank.c new file mode 100644 index 0000000..d76ae16 --- /dev/null +++ b/tests/apple2.bank.c @@ -0,0 +1,193 @@ +#include + +#include "apple2.h" +#include "apple2.bank.h" +#include "vm_segment.h" + +static apple2 *mach = NULL; + +static void +setup() +{ + mach = apple2_create(100, 100); + vm_segment_set_map_machine(mach); +} + +static void +teardown() +{ + apple2_free(mach); + vm_segment_set_map_machine(NULL); +} + +TestSuite(apple2_bank, .init = setup, .fini = teardown); + +Test(apple2_bank, map) +{ + // mach already had the mem_map function run, so we just need to + // test the results. + size_t addr; + int i; + + vm_segment *segments[2]; + + segments[0] = mach->main; + segments[1] = mach->aux; + + for (i = 0; i < 2; i++) { + for (addr = APPLE2_BANK_OFFSET; addr < MOS6502_MEMSIZE; addr++) { + cr_assert_eq(segments[i]->read_table[addr], apple2_bank_read); + cr_assert_eq(segments[i]->write_table[addr], apple2_bank_write); + } + + cr_assert_eq(segments[i]->read_table[0xC080], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC081], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC082], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC083], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC088], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC089], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC08A], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC08B], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC088], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC011], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC012], apple2_bank_switch_read); + cr_assert_eq(segments[i]->read_table[0xC016], apple2_bank_switch_read); + cr_assert_eq(segments[i]->write_table[0xC008], apple2_bank_switch_write); + cr_assert_eq(segments[i]->write_table[0xC009], apple2_bank_switch_write); + } +} + +Test(apple2_bank, read) +{ + vm_8bit val; + + // Test that setting a value in the rom segment is returned to us + // when addressing from main memory + apple2_set_bank_switch(mach, BANK_WRITE); + val = 123; + vm_segment_set(mach->rom, 0x77, val); + val = vm_segment_get(mach->rom, 0x77); + cr_assert_eq(vm_segment_get(mach->main, 0xD077), val); + + // In RAM1 bank mode, setting a value in memory should return thaty + // value in memory... but, as a twist, also check that the value is + // not set in ROM nor in RAM2. + val = 222; + apple2_set_bank_switch(mach, BANK_RAM | BANK_WRITE); + vm_segment_set(mach->main, 0xD077, val); + cr_assert_eq(vm_segment_get(mach->main, 0xD077), val); + cr_assert_neq(vm_segment_get(mach->rom, 0x77), val); + cr_assert_neq(vm_segment_get(mach->main, 0x10077), val); + + // Finally, in RAM2 bank mode, we test similarly to ROM mode. Set + // the value directly in ram2 (which is at $10000 - $1FFFF) and see + // if it's there when addressing from main memory in the $Dnnn + // range. + val = 111; + apple2_set_bank_switch(mach, mach->bank_switch | BANK_RAM2); + vm_segment_set(mach->main, 0x10077, val); + cr_assert_eq(vm_segment_get(mach->main, 0xD077), val); +} + +/* + * The write_bank test will look a bit similar to the read_bank one, + * except in logic it should be written somewhat as an inverse. That is, + * we want our writes to all go to memory, and double-check that the + * right location is being updated (or not being updated). + */ +Test(apple2_bank, write) +{ + vm_8bit right, wrong; + + // In BANK_DEFAULT mode, we expect that updates to ROM will never be + // successful (after all, it wouldn't be read-only memory if they + // were). + right = 123; + wrong = 222; + vm_segment_set(mach->rom, 0x77, right); + vm_segment_set(mach->main, 0xD077, wrong); + cr_assert_eq(vm_segment_get(mach->rom, 0x77), right); + cr_assert_eq(vm_segment_get(mach->main, 0xD077), right); + + // RAM1 is the main bank; it's all 64k RAM in one chunk. + right = 111; + wrong = 232; + apple2_set_bank_switch(mach, BANK_RAM | BANK_WRITE); + vm_segment_set(mach->main, 0xD078, right); + vm_segment_set(mach->main, 0x10078, wrong); + cr_assert_eq(vm_segment_get(mach->main, 0xD078), right); + cr_assert_eq(vm_segment_get(mach->main, 0x10078), wrong); + + // RAM2 is most of the 64k, except the first 4k of the last 12 + // ($D000..$DFFF) is in ram2. + right = 210; + wrong = 132; + apple2_set_bank_switch(mach, mach->bank_switch | BANK_RAM2); + vm_segment_set(mach->main, 0x10073, wrong); + vm_segment_set(mach->main, 0xD073, right); + cr_assert_eq(vm_segment_get(mach->main, 0x10073), right); +} + +Test(apple2_bank, switch_read) +{ + vm_segment_get(mach->main, 0xC080); + cr_assert_eq(mach->bank_switch, BANK_RAM | BANK_RAM2); + + // This (and a few others) are trickier to test, as they require + // consecutive reads to trigger. + vm_segment_get(mach->main, 0xC081); + cr_assert_neq(mach->bank_switch, BANK_WRITE | BANK_RAM2); + mach->cpu->last_addr = 0xC081; + vm_segment_get(mach->main, 0xC081); + cr_assert_eq(mach->bank_switch, BANK_WRITE | BANK_RAM2); + + vm_segment_get(mach->main, 0xC082); + cr_assert_eq(mach->bank_switch, BANK_RAM2); + + // Another that needs consecutives + vm_segment_get(mach->main, 0xC083); + cr_assert_neq(mach->bank_switch, BANK_RAM | BANK_WRITE | BANK_RAM2); + mach->cpu->last_addr = 0xC083; + vm_segment_get(mach->main, 0xC083); + cr_assert_eq(mach->bank_switch, BANK_RAM | BANK_WRITE | BANK_RAM2); + + vm_segment_get(mach->main, 0xC088); + cr_assert_eq(mach->bank_switch, BANK_RAM); + + // You get the idea + vm_segment_get(mach->main, 0xC089); + cr_assert_neq(mach->bank_switch, BANK_WRITE); + mach->cpu->last_addr = 0xC089; + vm_segment_get(mach->main, 0xC089); + cr_assert_eq(mach->bank_switch, BANK_WRITE); + + vm_segment_get(mach->main, 0xC08A); + cr_assert_eq(mach->bank_switch, BANK_DEFAULT); + + vm_segment_get(mach->main, 0xC08B); + cr_assert_neq(mach->bank_switch, BANK_RAM | BANK_WRITE); + mach->cpu->last_addr = 0xC08B; + vm_segment_get(mach->main, 0xC08B); + cr_assert_eq(mach->bank_switch, BANK_RAM | BANK_WRITE); + + mach->bank_switch = BANK_RAM | BANK_RAM2; + cr_assert_eq(vm_segment_get(mach->main, 0xC011), 0x80); + mach->bank_switch = BANK_DEFAULT; + cr_assert_eq(vm_segment_get(mach->main, 0xC011), 0x00); + mach->bank_switch = BANK_RAM; + cr_assert_eq(vm_segment_get(mach->main, 0xC012), 0x80); + mach->bank_switch = BANK_DEFAULT; + cr_assert_eq(vm_segment_get(mach->main, 0xC012), 0x00); + mach->bank_switch = BANK_ALTZP; + cr_assert_eq(vm_segment_get(mach->main, 0xC016), 0x80); + mach->bank_switch = BANK_DEFAULT; + cr_assert_eq(vm_segment_get(mach->main, 0xC016), 0x00); +} + +Test(apple2_bank, switch_write) +{ + vm_segment_set(mach->main, 0xC008, 1); + cr_assert_eq(mach->bank_switch & BANK_ALTZP, BANK_ALTZP); + vm_segment_set(mach->main, 0xC009, 1); + cr_assert_eq(mach->bank_switch & BANK_ALTZP, 0); +} diff --git a/tests/apple2.mem.c b/tests/apple2.mem.c index 2682348..4a4113b 100644 --- a/tests/apple2.mem.c +++ b/tests/apple2.mem.c @@ -2,6 +2,7 @@ #include "apple2.h" #include "apple2.mem.h" +#include "apple2.bank.h" static apple2 *mach = NULL; @@ -21,178 +22,6 @@ teardown() TestSuite(apple2_mem, .init = setup, .fini = teardown); -Test(apple2_mem, map) -{ - // mach already had the mem_map function run, so we just need to - // test the results. - size_t addr; - - for (addr = APPLE2_BANK_OFFSET; addr < MOS6502_MEMSIZE; addr++) { - cr_assert_eq(mach->main->read_table[addr], apple2_mem_read_bank); - cr_assert_eq(mach->main->write_table[addr], apple2_mem_write_bank); - } -} - -Test(apple2_mem, map_bank_switch) -{ - vm_segment *segments[2]; - - segments[0] = mach->main; - segments[1] = mach->aux; - - for (int i = 0; i < 2; i++) { - cr_assert_eq(segments[i]->read_table[0xC080], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC081], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC082], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC083], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC088], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC089], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC08A], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC08B], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC088], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC011], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC012], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->read_table[0xC016], apple2_mem_read_bank_switch); - cr_assert_eq(segments[i]->write_table[0xC008], apple2_mem_write_bank_switch); - cr_assert_eq(segments[i]->write_table[0xC009], apple2_mem_write_bank_switch); - } -} - -Test(apple2_mem, read_bank) -{ - vm_8bit val; - - // Test that setting a value in the rom segment is returned to us - // when addressing from main memory - apple2_set_bank_switch(mach, BANK_WRITE); - val = 123; - vm_segment_set(mach->rom, 0x77, val); - val = vm_segment_get(mach->rom, 0x77); - cr_assert_eq(vm_segment_get(mach->main, 0xD077), val); - - // In RAM1 bank mode, setting a value in memory should return thaty - // value in memory... but, as a twist, also check that the value is - // not set in ROM nor in RAM2. - val = 222; - apple2_set_bank_switch(mach, BANK_RAM | BANK_WRITE); - vm_segment_set(mach->main, 0xD077, val); - cr_assert_eq(vm_segment_get(mach->main, 0xD077), val); - cr_assert_neq(vm_segment_get(mach->rom, 0x77), val); - cr_assert_neq(vm_segment_get(mach->main, 0x10077), val); - - // Finally, in RAM2 bank mode, we test similarly to ROM mode. Set - // the value directly in ram2 (which is at $10000 - $1FFFF) and see - // if it's there when addressing from main memory in the $Dnnn - // range. - val = 111; - apple2_set_bank_switch(mach, mach->bank_switch | BANK_RAM2); - vm_segment_set(mach->main, 0x10077, val); - cr_assert_eq(vm_segment_get(mach->main, 0xD077), val); -} - -/* - * The write_bank test will look a bit similar to the read_bank one, - * except in logic it should be written somewhat as an inverse. That is, - * we want our writes to all go to memory, and double-check that the - * right location is being updated (or not being updated). - */ -Test(apple2_mem, write_bank) -{ - vm_8bit right, wrong; - - // In BANK_DEFAULT mode, we expect that updates to ROM will never be - // successful (after all, it wouldn't be read-only memory if they - // were). - right = 123; - wrong = 222; - vm_segment_set(mach->rom, 0x77, right); - vm_segment_set(mach->main, 0xD077, wrong); - cr_assert_eq(vm_segment_get(mach->rom, 0x77), right); - cr_assert_eq(vm_segment_get(mach->main, 0xD077), right); - - // RAM1 is the main bank; it's all 64k RAM in one chunk. - right = 111; - wrong = 232; - apple2_set_bank_switch(mach, BANK_RAM | BANK_WRITE); - vm_segment_set(mach->main, 0xD078, right); - vm_segment_set(mach->main, 0x10078, wrong); - cr_assert_eq(vm_segment_get(mach->main, 0xD078), right); - cr_assert_eq(vm_segment_get(mach->main, 0x10078), wrong); - - // RAM2 is most of the 64k, except the first 4k of the last 12 - // ($D000..$DFFF) is in ram2. - right = 210; - wrong = 132; - apple2_set_bank_switch(mach, mach->bank_switch | BANK_RAM2); - vm_segment_set(mach->main, 0x10073, wrong); - vm_segment_set(mach->main, 0xD073, right); - cr_assert_eq(vm_segment_get(mach->main, 0x10073), right); -} - -Test(apple2_mem, read_bank_switch) -{ - vm_segment_get(mach->main, 0xC080); - cr_assert_eq(mach->bank_switch, BANK_RAM | BANK_RAM2); - - // This (and a few others) are trickier to test, as they require - // consecutive reads to trigger. - vm_segment_get(mach->main, 0xC081); - cr_assert_neq(mach->bank_switch, BANK_WRITE | BANK_RAM2); - mach->cpu->last_addr = 0xC081; - vm_segment_get(mach->main, 0xC081); - cr_assert_eq(mach->bank_switch, BANK_WRITE | BANK_RAM2); - - vm_segment_get(mach->main, 0xC082); - cr_assert_eq(mach->bank_switch, BANK_RAM2); - - // Another that needs consecutives - vm_segment_get(mach->main, 0xC083); - cr_assert_neq(mach->bank_switch, BANK_RAM | BANK_WRITE | BANK_RAM2); - mach->cpu->last_addr = 0xC083; - vm_segment_get(mach->main, 0xC083); - cr_assert_eq(mach->bank_switch, BANK_RAM | BANK_WRITE | BANK_RAM2); - - vm_segment_get(mach->main, 0xC088); - cr_assert_eq(mach->bank_switch, BANK_RAM); - - // You get the idea - vm_segment_get(mach->main, 0xC089); - cr_assert_neq(mach->bank_switch, BANK_WRITE); - mach->cpu->last_addr = 0xC089; - vm_segment_get(mach->main, 0xC089); - cr_assert_eq(mach->bank_switch, BANK_WRITE); - - vm_segment_get(mach->main, 0xC08A); - cr_assert_eq(mach->bank_switch, BANK_DEFAULT); - - vm_segment_get(mach->main, 0xC08B); - cr_assert_neq(mach->bank_switch, BANK_RAM | BANK_WRITE); - mach->cpu->last_addr = 0xC08B; - vm_segment_get(mach->main, 0xC08B); - cr_assert_eq(mach->bank_switch, BANK_RAM | BANK_WRITE); - - mach->bank_switch = BANK_RAM | BANK_RAM2; - cr_assert_eq(vm_segment_get(mach->main, 0xC011), 0x80); - mach->bank_switch = BANK_DEFAULT; - cr_assert_eq(vm_segment_get(mach->main, 0xC011), 0x00); - mach->bank_switch = BANK_RAM; - cr_assert_eq(vm_segment_get(mach->main, 0xC012), 0x80); - mach->bank_switch = BANK_DEFAULT; - cr_assert_eq(vm_segment_get(mach->main, 0xC012), 0x00); - mach->bank_switch = BANK_ALTZP; - cr_assert_eq(vm_segment_get(mach->main, 0xC016), 0x80); - mach->bank_switch = BANK_DEFAULT; - cr_assert_eq(vm_segment_get(mach->main, 0xC016), 0x00); -} - -Test(apple2_mem, write_bank_switch) -{ - vm_segment_set(mach->main, 0xC008, 1); - cr_assert_eq(mach->bank_switch & BANK_ALTZP, BANK_ALTZP); - vm_segment_set(mach->main, 0xC009, 1); - cr_assert_eq(mach->bank_switch & BANK_ALTZP, 0); -} - Test(apple2_mem, init_peripheral_rom) { // FIXME: this isn't working, _and_ it's pretty tightly coupled into