summaryrefslogtreecommitdiff
path: root/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpu.c')
-rw-r--r--cpu.c89
1 files changed, 29 insertions, 60 deletions
diff --git a/cpu.c b/cpu.c
index 6e44c7f..df9c852 100644
--- a/cpu.c
+++ b/cpu.c
@@ -99,55 +99,6 @@ memwrite16(uint16_t addr, uint16_t word)
memory[addr + 1] = (word & 0xFF00) >> 8;
}
-static uint8_t
-opcode_arg(enum addressing_mode mode)
-{
- uint16_t arg, val;
-
- if (mode != AM_ABS && mode != AM_ABS_X && mode != AM_ABS_Y) {
- arg = peek(regs.pc++);
- } else {
- arg = peek16(regs.pc);
- regs.pc += 2;
- }
-
- switch (mode) {
- case AM_IMM:
- case AM_REL:
- val = arg;
- break;
- case AM_ZP:
- val = peek(arg % 256);
- break;
- case AM_ZP_X:
- val = peek((arg + regs.x) % 256);
- break;
- case AM_ZP_Y:
- val = peek((arg + regs.y) % 256);
- break;
- case AM_ABS:
- val = peek16(arg);
- break;
- case AM_ABS_X:
- val = peek16(arg + regs.x);
- break;
- case AM_ABS_Y:
- val = peek16(arg + regs.y);
- break;
- case AM_IND_X:
- val = peek(peek((arg + regs.x) % 256) + peek((arg + regs.x + 1) % 256) * 256);
- break;
- case AM_IND_Y:
- val = peek(peek(arg) + peek((arg + 1) % 256) * 256 + regs.y);
- break;
- default:
- fprintf(stderr, "INVALID ADDRESSING MODE %i\n", mode);
- abort();
- }
-
- return val;
-}
-
static uint16_t
opcode_mem(enum addressing_mode mode)
{
@@ -193,7 +144,7 @@ opcode_mem(enum addressing_mode mode)
val = peek(arg) + peek((arg + 1) % 256) * 256 + regs.y;
break;
default:
- fprintf(stderr, "opcode_mem INVALID ADDRESSING MODE %i\n", mode);
+ fprintf(stderr, "INVALID ADDRESSING MODE %i\n", mode);
abort();
}
@@ -271,7 +222,8 @@ BEQ(uint16_t arg)
void
BIT(uint16_t arg)
{
- uint8_t tmp = peek(arg);
+ uint8_t tmp = arg;
+
regs.status.zero = (regs.a & tmp) == 0;
regs.status.overflow = (tmp & (1 << 6)) != 0;
STATUS_UPDATE_NEGATIVE(tmp);
@@ -628,8 +580,18 @@ RTS(uint16_t arg)
void
SBC(uint16_t arg)
{
- /* SBC is described online as ADC with argument as two's complement */
- ADC(~(uint8_t)arg);
+ uint8_t tmp = arg & 0xFF;
+ uint16_t diff;
+
+ diff = regs.a - tmp - !regs.status.carry;
+
+ regs.status.carry = diff > 0xFF;
+ regs.status.carry = !regs.status.carry;
+ /* overflow flag formula: https://stackoverflow.com/a/29224684 */
+ regs.status.overflow = ((regs.a ^ arg) & (regs.a ^ diff) & 0x80) != 0;
+ regs.a = diff & 0xFF;
+
+ STATUS_UPDATE_NZ(regs.a);
}
void
@@ -759,10 +721,10 @@ interpret(void)
printf("$%04X", arg);
break;
case AM_ABS_X:
- printf("$%04X,X", arg);
+ printf("$%04X,X @ %04X", arg - regs.x, arg);
break;
case AM_ABS_Y:
- printf("$%04X,Y", arg);
+ printf("$%04X,Y @ %04X", arg - regs.y, arg);
break;
case AM_IND:
printf("($%04X) = %04X\t\t", arg, peek16(arg));
@@ -776,13 +738,20 @@ interpret(void)
break;
}
- if (opcodes[op].didmemory) printf(" = %02X", peek(arg));
- printf("\t\t\t");
+ if (opcodes[op].memread || opcodes[op].memwrite)
+ printf(" = %02X", peek(arg));
+
+ if (mode != AM_ABS_X && mode != AM_ABS_Y)
+ putchar('\t');
+ printf("\t\t");
- printf("A:%02X X:%02X Y:%02X P:%02X SP:%02X CYC:%d %08b\n",
- regs.a, regs.x, regs.y, STATUS_TO_INT(), regs.sp, cycles, STATUS_TO_INT());
+ printf("A:%02X X:%02X Y:%02X P:%02X SP:%02X CYC:%d\n",
+ regs.a, regs.x, regs.y, STATUS_TO_INT(), regs.sp, cycles);
- opcodes[op].instr(arg);
+ if (opcodes[op].memread)
+ opcodes[op].instr(peek(arg));
+ else
+ opcodes[op].instr(arg);
cycles += opcodes[op].cycles;
}
loop_exit: