1
0
mirror of https://github.com/pevans/erc-c.git synced 2024-08-20 09:29:01 +00:00

Some soft switches now require consecutive reads

To allow this to work, we had to allow the CPU struct to record what the
last opcode/operand/address were, although in truth we only needed the
last address.
This commit is contained in:
Peter Evans 2018-01-12 14:49:27 -06:00
parent 7d6886a3a8
commit f69454c965
4 changed files with 79 additions and 6 deletions

View File

@ -61,7 +61,7 @@ typedef struct {
vm_segment *wmem;
/*
* This contains the last _effective_ address we've resolved in one
* This contains the _effective_ address we've resolved in one
* of our address modes. In absolute mode, this would be the literal
* operand we read from memory; in indirect mode, this will be the
* address we _find_ after dereferencing the operand we read from
@ -70,6 +70,16 @@ typedef struct {
*/
vm_16bit eff_addr;
/*
* These are the last opcode and last effective address that was
* used in the instruction previous to the one currently being
* executed. Some things (notably soft switches) may need to
* the last opcode.
*/
vm_8bit last_opcode;
vm_8bit last_operand;
vm_16bit last_addr;
/*
* Our program counter register; this is what we'll use to determine
* where we're "at" in memory while executing opcodes. We use a
@ -127,6 +137,7 @@ extern vm_16bit mos6502_pop_stack(mos6502 *);
extern vm_8bit mos6502_get(mos6502 *, size_t);
extern void mos6502_execute(mos6502 *);
extern void mos6502_free(mos6502 *);
extern void mos6502_last_executed(mos6502 *, vm_8bit *, vm_8bit *, vm_16bit *);
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);

View File

@ -179,9 +179,14 @@ apple2_mem_init_sys_rom(apple2 *mach)
SEGMENT_READER(apple2_mem_read_bank_switch)
{
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
@ -194,15 +199,19 @@ SEGMENT_READER(apple2_mem_read_bank_switch)
return 0;
case 0xC081:
apple2_set_bank_switch(mach,
MEMORY_ROM | MEMORY_WRITE | MEMORY_RAM2);
if (last_addr == addr) {
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);
if (last_addr == addr) {
apple2_set_bank_switch(mach, MEMORY_WRITE | MEMORY_RAM2);
}
return 0;
// Conversely, the $C088 - $C08B range control memory access
@ -214,7 +223,9 @@ SEGMENT_READER(apple2_mem_read_bank_switch)
return 0;
case 0xC089:
apple2_set_bank_switch(mach, MEMORY_ROM | MEMORY_WRITE);
if (last_addr == addr) {
apple2_set_bank_switch(mach, MEMORY_ROM | MEMORY_WRITE);
}
return 0;
case 0xC08A:
@ -222,7 +233,9 @@ SEGMENT_READER(apple2_mem_read_bank_switch)
return 0;
case 0xC08B:
apple2_set_bank_switch(mach, MEMORY_WRITE);
if (last_addr == addr) {
apple2_set_bank_switch(mach, MEMORY_WRITE);
}
return 0;
// Return high on the 7th bit if we're using bank 2 memory

View File

@ -392,10 +392,38 @@ mos6502_execute(mos6502 *cpu)
// something.
usleep(cycles * 10000);
// We need to record the opcode and the effective address for
// anything which might need to reference it.
cpu->last_opcode = opcode;
cpu->last_addr = cpu->eff_addr;
cpu->last_operand = operand;
// Ok -- we're done! This wasn't so hard, was it?
return;
}
/*
* Given pointers for an opcode, operand, and effective address, set the
* dereferenced values of those pointers to what the CPU knows to have
* been the last of each.
*/
void
mos6502_last_executed(mos6502 *cpu, vm_8bit *opcode,
vm_8bit *operand, vm_16bit *addr)
{
if (opcode) {
*opcode = cpu->last_opcode;
}
if (operand) {
*operand = cpu->last_operand;
}
if (addr) {
*addr = cpu->last_addr;
}
}
/*
* Return true if the given instruction would require that we jump
* to somewhere else in the program.

View File

@ -134,19 +134,40 @@ Test(apple2_mem, read_bank_switch)
{
vm_segment_get(mach->main, 0xC080);
cr_assert_eq(mach->bank_switch, MEMORY_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, MEMORY_ROM | MEMORY_WRITE | MEMORY_RAM2);
mach->cpu->last_addr = 0xC081;
vm_segment_get(mach->main, 0xC081);
cr_assert_eq(mach->bank_switch, MEMORY_ROM | MEMORY_WRITE | MEMORY_RAM2);
vm_segment_get(mach->main, 0xC082);
cr_assert_eq(mach->bank_switch, MEMORY_ROM | MEMORY_RAM2);
// Another that needs consecutives
vm_segment_get(mach->main, 0xC083);
cr_assert_neq(mach->bank_switch, MEMORY_WRITE | MEMORY_RAM2);
mach->cpu->last_addr = 0xC083;
vm_segment_get(mach->main, 0xC083);
cr_assert_eq(mach->bank_switch, MEMORY_WRITE | MEMORY_RAM2);
vm_segment_get(mach->main, 0xC088);
cr_assert_eq(mach->bank_switch, 0);
vm_segment_get(mach->main, 0xC089);
cr_assert_neq(mach->bank_switch, MEMORY_ROM | MEMORY_WRITE);
mach->cpu->last_addr = 0xC089;
vm_segment_get(mach->main, 0xC089);
cr_assert_eq(mach->bank_switch, MEMORY_ROM | MEMORY_WRITE);
vm_segment_get(mach->main, 0xC08A);
cr_assert_eq(mach->bank_switch, MEMORY_ROM);
vm_segment_get(mach->main, 0xC08B);
cr_assert_neq(mach->bank_switch, MEMORY_WRITE);
mach->cpu->last_addr = 0xC08B;
vm_segment_get(mach->main, 0xC08B);
cr_assert_eq(mach->bank_switch, MEMORY_WRITE);