Add addr_mode field, rely upon it vs. the opcode

This makes testing _slightly_ easier, because now the handlers require a
type of state in the cpu vs. a specific opcode state in the segment that
we execute from. (The latter being just more complex to work with and
require in testing.)
This commit is contained in:
Peter Evans 2018-04-15 00:56:34 -05:00
parent 56e9d97791
commit 8e810e724f
6 changed files with 38 additions and 51 deletions

View File

@ -104,6 +104,11 @@ typedef struct {
*/
vm_16bit eff_addr;
/*
* This is the address mode of the current execution.
*/
int addr_mode;
/*
* These are the last opcode and last effective address that was
* used in the instruction previous to the one currently being

View File

@ -154,19 +154,14 @@ DEFINE_INST(cpy)
*/
DEFINE_INST(dec)
{
vm_8bit opcode = mos6502_get(cpu, cpu->PC);
bool is_acc = mos6502_addr_mode(opcode) == ACC;
if (!is_acc) {
MOS_CHECK_NZ(oper - 1);
mos6502_set(cpu, cpu->eff_addr, oper - 1);
if (cpu->addr_mode == ACC) {
MOS_CHECK_NZ(cpu->A - 1);
cpu->A--;
return;
}
// If we get here, then this is ACC mode, and we should work off
// that.
MOS_CHECK_NZ(cpu->A - 1);
cpu->A--;
MOS_CHECK_NZ(oper - 1);
mos6502_set(cpu, cpu->eff_addr, oper - 1);
}
/*
@ -192,17 +187,14 @@ DEFINE_INST(dey)
*/
DEFINE_INST(inc)
{
vm_8bit opcode = mos6502_get(cpu, cpu->PC);
bool is_acc = mos6502_addr_mode(opcode) == ACC;
if (!is_acc) {
MOS_CHECK_NZ(oper + 1);
mos6502_set(cpu, cpu->eff_addr, oper + 1);
if (cpu->addr_mode == ACC) {
MOS_CHECK_NZ(cpu->A + 1);
cpu->A++;
return;
}
MOS_CHECK_NZ(cpu->A + 1);
cpu->A++;
MOS_CHECK_NZ(oper + 1);
mos6502_set(cpu, cpu->eff_addr, oper + 1);
}
/*

View File

@ -31,9 +31,6 @@ DEFINE_INST(and)
*/
DEFINE_INST(asl)
{
vm_8bit opcode = mos6502_get(cpu, cpu->PC);
bool is_acc = mos6502_addr_mode(opcode) == ACC;
vm_8bit result = oper << 1;
MOS_CHECK_NZ(result);
@ -42,10 +39,10 @@ DEFINE_INST(asl)
cpu->P |= MOS_CARRY;
}
if (!is_acc) {
mos6502_set(cpu, cpu->eff_addr, result);
} else {
if (cpu->addr_mode == ACC) {
cpu->A = result;
} else {
mos6502_set(cpu, cpu->eff_addr, result);
}
}
@ -114,9 +111,6 @@ DEFINE_INST(eor)
*/
DEFINE_INST(lsr)
{
vm_8bit opcode = mos6502_get(cpu, cpu->PC);
bool is_acc = mos6502_addr_mode(opcode) == ACC;
vm_8bit result = oper >> 1;
// The N flag is ALWAYS cleared in LSR, because a zero is always
@ -132,10 +126,10 @@ DEFINE_INST(lsr)
cpu->P |= MOS_CARRY;
}
if (!is_acc) {
mos6502_set(cpu, cpu->eff_addr, result);
} else {
if (cpu->addr_mode == ACC) {
cpu->A = result;
} else {
mos6502_set(cpu, cpu->eff_addr, result);
}
}
@ -156,9 +150,6 @@ DEFINE_INST(ora)
*/
DEFINE_INST(rol)
{
vm_8bit opcode = mos6502_get(cpu, cpu->PC);
bool is_acc = mos6502_addr_mode(opcode) == ACC;
vm_8bit result = oper << 1;
// Rotations are effectively _9-bit_. So we aren't rotating bit 7
@ -175,10 +166,10 @@ DEFINE_INST(rol)
MOS_CHECK_NZ(result);
if (!is_acc) {
mos6502_set(cpu, cpu->eff_addr, result);
} else {
if (cpu->addr_mode == ACC) {
cpu->A = result;
} else {
mos6502_set(cpu, cpu->eff_addr, result);
}
}
@ -188,9 +179,6 @@ DEFINE_INST(rol)
*/
DEFINE_INST(ror)
{
vm_8bit opcode = mos6502_get(cpu, cpu->PC);
bool is_acc = mos6502_addr_mode(opcode) == ACC;
vm_8bit result = oper >> 1;
// See the code for ROL for my note on 9-bit rotation (vs. 8-bit).
@ -205,10 +193,10 @@ DEFINE_INST(ror)
MOS_CHECK_NZ(result);
if (!is_acc) {
mos6502_set(cpu, cpu->eff_addr, result);
} else {
if (cpu->addr_mode == ACC) {
cpu->A = result;
} else {
mos6502_set(cpu, cpu->eff_addr, result);
}
}

View File

@ -170,6 +170,7 @@ mos6502_create(vm_segment *rmem, vm_segment *wmem)
mos6502_set_memory(cpu, rmem, wmem);
cpu->eff_addr = 0;
cpu->addr_mode = 0;
cpu->PC = 0;
cpu->A = 0;
cpu->X = 0;
@ -303,16 +304,17 @@ mos6502_execute(mos6502 *cpu)
mos6502_instruction_handler handler;
opcode = mos6502_get(cpu, cpu->PC);
cpu->addr_mode = mos6502_addr_mode(opcode);
// The disassembler knows how many bytes each operand requires
// (maybe this code doesn't belong in the disassembler); let's use
// that to figure out the total number of bytes to skip. We add 1
// because we need to account for the opcode as well.
bytes = 1 + mos6502_dis_expected_bytes(mos6502_addr_mode(opcode));
bytes = 1 + mos6502_dis_expected_bytes(cpu->addr_mode);
// First, we need to know how to resolve our effective address and
// how to execute anything.
resolver = mos6502_get_address_resolver(mos6502_addr_mode(opcode));
resolver = mos6502_get_address_resolver(cpu->addr_mode);
handler = mos6502_get_instruction_handler(opcode);
// The operand is the effective operand, the value that the

View File

@ -92,7 +92,7 @@ Test(mos6502_arith, cpy)
Test(mos6502_arith, dec)
{
cpu->A = 5;
mos6502_set(cpu, cpu->PC, 0x3A);
cpu->addr_mode = ACC;
mos6502_handle_dec(cpu, 0);
cr_assert_eq(cpu->A, 4);
@ -104,7 +104,7 @@ Test(mos6502_arith, dec)
cpu->eff_addr = 123;
mos6502_set(cpu, 123, 44);
mos6502_set(cpu, cpu->PC, 0x00);
cpu->addr_mode = 0;
mos6502_handle_dec(cpu, 44);
cr_assert_eq(mos6502_get(cpu, 123), 43);
}
@ -131,7 +131,7 @@ Test(mos6502_arith, inc)
cpu->A = 8;
cpu->eff_addr = 0;
mos6502_set(cpu, cpu->PC, 0x1A);
cpu->addr_mode = ACC;
mos6502_handle_inc(cpu, 0);
cr_assert_eq(cpu->A, 9);

View File

@ -23,7 +23,7 @@ Test(mos6502_bits, asl)
mos6502_handle_asl(cpu, 22);
cr_assert_eq(mos6502_get(cpu, 123), 44);
mos6502_set(cpu, cpu->PC, 0x0A);
cpu->addr_mode = ACC;
mos6502_handle_asl(cpu, 5);
cr_assert_eq(cpu->A, 10);
@ -98,7 +98,7 @@ Test(mos6502_bits, lsr)
cr_assert_eq(mos6502_get(cpu, 123), 5);
cr_assert_eq(cpu->P & MOS_CARRY, MOS_CARRY);
mos6502_set(cpu, cpu->PC, 0x4A);
cpu->addr_mode = ACC;
mos6502_handle_lsr(cpu, 5);
cr_assert_eq(cpu->A, 2);
cr_assert_eq(cpu->P & MOS_CARRY, MOS_CARRY);
@ -122,7 +122,7 @@ Test(mos6502_bits, rol)
mos6502_handle_rol(cpu, 128);
cr_assert_eq(mos6502_get(cpu, 234), 0);
mos6502_set(cpu, cpu->PC, 0x2A);
cpu->addr_mode = ACC;
cpu->P = 0;
cpu->A = 0xff;
mos6502_handle_rol(cpu, cpu->A);
@ -141,7 +141,7 @@ Test(mos6502_bits, ror)
mos6502_handle_ror(cpu, 0);
cr_assert_eq(mos6502_get(cpu, 123), 128);
mos6502_set(cpu, cpu->PC, 0x6A);
cpu->addr_mode = ACC;
cpu->P = 0;
cpu->A = 0xff;
mos6502_handle_ror(cpu, cpu->A);