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:
parent
7d6886a3a8
commit
f69454c965
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user