Add arg_t, more robust address mode parsing
diff --git a/.gitignore b/.gitignore
index b0d1121..798ef86 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,2 @@
-~*
+.~*
build
diff --git a/cpu.c b/cpu.c
index f0d7d68..af9ad27 100644
--- a/cpu.c
+++ b/cpu.c
@@ -32,9 +32,11 @@
free(cpu->mem);
}
-void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, uint16_t addr)
+void execute(cpu_t *cpu, const char *mnemonic, uint8_t op, arg_t addr)
{
-
+ switch (op) {
+
+ }
}
uint16_t le_to_native(uint8_t a, uint8_t b)
@@ -53,28 +55,46 @@
return le_to_native(a, b);
}
-uint16_t fetch_addr(cpu_t *cpu, uint8_t am)
+arg_t arg_imm(uint16_t a)
+{
+ return (arg_t){ a, a };
+}
+
+arg_t arg_ptr(cpu_t *c, uint flags, uint16_t p)
+{
+ if (flags & FETCH_NO_INDIRECTION)
+ return arg_imm(p);
+
+ return (arg_t){ c->mem[p], p };
+}
+
+arg_t arg(uint16_t v, uint16_t a)
+{
+ return (arg_t){ v, a };
+}
+
+arg_t fetch_addr(cpu_t *cpu, uint8_t am, uint f)
{
switch (am)
{
case AM_ACC:
case AM_IMP:
- return 0;
+ return arg_imm(0);
// In both cases return immediate 8 bit value
case AM_IMM:
case AM_ZP:
- return cpu->mem[cpu->pc++];
+ return arg_imm(cpu->mem[cpu->pc++]);
case AM_ABS:
- return fetch_le(cpu);
+ return arg_ptr(cpu, f, fetch_le(cpu));
case AM_REL:
{
// PC should point to the opcode
// braces needed to avoid c stupidity
uint16_t pc = cpu->pc - 1;
- return cpu->mem[cpu->pc++] + pc;
+ return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + pc);
}
case AM_IND:
@@ -83,37 +103,39 @@
uint8_t low = cpu->mem[addr],
high = cpu->mem[addr + 1];
- return le_to_native(low, high);
+ return arg_ptr(cpu, f, le_to_native(low, high));
}
case AM_AX:
- return fetch_le(cpu) + cpu->regs[X];
+ return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[X]);
case AM_AY:
- return fetch_le(cpu) + cpu->regs[Y];
+ return arg_ptr(cpu, f, fetch_le(cpu) + cpu->regs[Y]);
case AM_ZPX:
- return cpu->mem[cpu->pc++] + cpu->regs[X];
+ return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[X]);
case AM_ZPY:
- return cpu->mem[cpu->pc++] + cpu->regs[Y];
+ return arg_ptr(cpu, f, cpu->mem[cpu->pc++] + cpu->regs[Y]);
case AM_ZIX:
{
uint8_t zp = cpu->mem[cpu->pc++];
- return le_to_native(cpu->mem[zp + cpu->regs[X]], cpu->mem[zp + cpu->regs[X] + 1]);
+ uint16_t addr = zp + cpu->regs[X];
+ uint16_t indirect = le_to_native(cpu->mem[addr], cpu->mem[addr + 1]);
+ return arg_ptr(cpu, f, indirect);
}
case AM_ZIY:
{
uint8_t zp = cpu->mem[cpu->pc++];
uint16_t base = le_to_native(cpu->mem[zp], cpu->mem[zp + 1]);
- return base + cpu->regs[Y];
+ return arg_ptr(cpu, f, base + cpu->regs[Y]);
}
default:
die("Unknown address mode %x", am);
- return -1; // unreachable
+ __builtin_unreachable();
}
}
@@ -123,7 +145,7 @@
{
#define INST(mn, am, op) \
case op: \
- execute(cpu, #mn, mn, fetch_addr(cpu, am)); \
+ execute(cpu, #mn, mn, fetch_addr(cpu, am, 0)); \
break;
INSTRUCTIONS
@@ -183,7 +205,8 @@
{
#define INST(mn, am, op) \
case op: \
- dump_inst(cpu, #mn, fetch_addr(cpu, am), am); \
+ dump_inst(cpu, #mn, \
+ fetch_addr(cpu, am, FETCH_NO_INDIRECTION).ptr, am); \
break;
INSTRUCTIONS
diff --git a/cpu.h b/cpu.h
index bbe6c60..20551ec 100644
--- a/cpu.h
+++ b/cpu.h
@@ -96,6 +96,11 @@
NOP,
};
+enum // Fetch flags
+{
+ FETCH_NO_INDIRECTION = 1, // Do not follow indirection (used for disassembly)
+};
+
// Emulator instance, create with new_cpu()
typedef struct
{