1
0
mirror of https://github.com/pevans/erc-c.git synced 2025-02-17 07:32:05 +00:00

Allow us to switch main/aux; write bank switch mappers

This commit is contained in:
Peter Evans 2018-01-11 19:52:13 -06:00
parent a17ad0596b
commit 578e0b291c
7 changed files with 155 additions and 13 deletions

View File

@ -94,6 +94,7 @@ enum memory_mode {
MEMORY_ROM = 1, // on = read ROM; off = read RAM
MEMORY_WRITE = 2, // on = allow writes to RAM; off = disallow writes
MEMORY_RAM2 = 4, // on = use bank 2 for $D000-$DFFF; off = use bank 1
MEMORY_AUX = 8, // on = use auxiliary memory; off = use main memory
};
typedef struct {

View File

@ -61,6 +61,9 @@ 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 *);
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

View File

@ -132,6 +132,7 @@ extern void mos6502_modify_status(mos6502 *, vm_8bit, vm_8bit);
extern void mos6502_push_stack(mos6502 *, vm_16bit);
extern void mos6502_set(mos6502 *, size_t, vm_8bit);
extern void mos6502_set16(mos6502 *, size_t, vm_16bit);
extern void mos6502_set_memory(mos6502 *, vm_segment *, vm_segment *);
extern void mos6502_set_status(mos6502 *, vm_8bit);
/*

View File

@ -53,6 +53,12 @@ apple2_create(int width, int height)
mach->drive1 = NULL;
mach->drive2 = NULL;
// This is more-or-less the same setup you do in apple2_reset(). We
// need to hard-set these values because apple2_set_bank_switch
// assumes that the bank_switch variable has been initialized
// before, which to this point, it hasn't!
mach->bank_switch = MEMORY_ROM | MEMORY_WRITE | MEMORY_RAM2;
mach->main = vm_segment_create(APPLE2_MEMORY_SIZE);
if (mach->main == NULL) {
log_critical("Could not initialize main RAM!");
@ -67,12 +73,6 @@ apple2_create(int width, int height)
return NULL;
}
// This is more-or-less the same setup you do in apple2_reset().
apple2_set_bank_switch(mach, MEMORY_ROM | MEMORY_WRITE | MEMORY_RAM2);
// Set the read/write mappers for everything
apple2_mem_map(mach);
// Initliaze our system ROM and separate bank-switched block of RAM
mach->rom = vm_segment_create(APPLE2_ROM_SIZE);
mach->aux = vm_segment_create(APPLE2_MEMORY_SIZE);
@ -82,6 +82,10 @@ apple2_create(int width, int height)
return NULL;
}
// Set the read/write mappers for everything
apple2_mem_map(mach, mach->main);
apple2_mem_map(mach, mach->aux);
if (apple2_mem_init_peripheral_rom(mach) != OK) {
log_critical("Could not initialize disk2 ROM");
apple2_free(mach);
@ -149,6 +153,24 @@ apple2_create(int width, int height)
void
apple2_set_bank_switch(apple2 *mach, vm_8bit flags)
{
int have_aux = mach->bank_switch & MEMORY_AUX;
int flags_aux = flags & MEMORY_AUX;
if (flags_aux && !have_aux) {
// Switch to auxiliary memory.
mos6502_set_memory(mach->cpu, mach->aux, mach->aux);
// We need to copy page 0 and 1 from main over to aux.
vm_segment_copy(mach->aux, mach->main, 0, 0, 0x200);
} else if (!flags_aux && have_aux) {
// Switching back to main memory
mos6502_set_memory(mach->cpu, mach->main, mach->main);
// And, like above, we need to copy page 0 and 1 from aux back
// to main.
vm_segment_copy(mach->main, mach->aux, 0, 0, 0x200);
}
mach->bank_switch = flags;
}

View File

@ -77,16 +77,36 @@ SEGMENT_WRITER(apple2_mem_write_bank)
* Set the memory map functions for main memory in an apple2 machine
*/
void
apple2_mem_map(apple2 *mach)
apple2_mem_map(apple2 *mach, vm_segment *segment)
{
size_t addr;
vm_segment_set_map_machine(mach);
for (addr = APPLE2_BANK_OFFSET; addr < MOS6502_MEMSIZE; addr++) {
vm_segment_read_map(mach->main, addr, apple2_mem_read_bank);
vm_segment_write_map(mach->main, addr, apple2_mem_write_bank);
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);
}
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);
}
int
@ -142,3 +162,93 @@ apple2_mem_init_sys_rom(apple2 *mach)
return OK;
}
SEGMENT_READER(apple2_mem_read_bank_switch)
{
apple2 *mach;
mach = (apple2 *)_mach;
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, MEMORY_RAM2);
return 0;
case 0xC081:
apple2_set_bank_switch(mach,
MEMORY_ROM | MEMORY_WRITE | MEMORY_RAM2);
return 0;
case 0xC082:
apple2_set_bank_switch(mach, MEMORY_ROM | MEMORY_RAM2);
return 0;
case 0xC083:
apple2_set_bank_switch(mach, MEMORY_WRITE | MEMORY_RAM2);
return 0;
// Conversely, the $C088 - $C08B range control memory access
// while using bank 1 RAM.
case 0xC088:
// The 0 means there are no special privileges; reads are to
// RAM, writes are disabled, and we are using bank 1 memory.
apple2_set_bank_switch(mach, 0);
return 0;
case 0xC089:
apple2_set_bank_switch(mach, MEMORY_ROM | MEMORY_WRITE);
return 0;
case 0xC08A:
apple2_set_bank_switch(mach, MEMORY_ROM);
return 0;
case 0xC08B:
apple2_set_bank_switch(mach, MEMORY_WRITE);
return 0;
// Return high on the 7th bit if we're using bank 2 memory
case 0xC011:
return mach->bank_switch & MEMORY_RAM2
? 0x80
: 0x00;
// Return high on 7th bit if we're reading RAM
case 0xC012:
return ~mach->bank_switch & MEMORY_ROM
? 0x80
: 0x00;
// Return high on the 7th bit if we're using aux memory
case 0xC016:
return mach->bank_switch & MEMORY_AUX
? 0x80
: 0x00;
}
log_critical("Bank switch mapper called with an unexpected address: %x", addr);
return 0;
}
SEGMENT_WRITER(apple2_mem_write_bank_switch)
{
apple2 *mach = (apple2 *)_mach;
switch (addr) {
// Turn on auxiliary memory
case 0xC008:
apple2_set_bank_switch(mach,
mach->bank_switch | MEMORY_AUX);
break;
// Disable auxiliary memory
case 0xC009:
apple2_set_bank_switch(mach,
mach->bank_switch & ~MEMORY_AUX);
}
}

View File

@ -155,8 +155,7 @@ mos6502_create(vm_segment *rmem, vm_segment *wmem)
exit(1);
}
cpu->rmem = rmem;
cpu->wmem = wmem;
mos6502_set_memory(cpu, rmem, wmem);
cpu->last_addr = 0;
cpu->PC = 0;
@ -482,3 +481,10 @@ mos6502_set16(mos6502 *cpu, size_t addr, vm_16bit value)
{
vm_segment_set16(cpu->wmem, addr, value);
}
void
mos6502_set_memory(mos6502 *cpu, vm_segment *rmem, vm_segment *wmem)
{
cpu->rmem = rmem;
cpu->wmem = wmem;
}

View File

@ -9,7 +9,6 @@ static void
setup()
{
mach = apple2_create(100, 100);
apple2_mem_map(mach);
vm_segment_set_map_machine(mach);
}