commit f4984e3852c510e8d3705d8adfe8e686b674cd74
parent b0e4f19592eaefccc9f735982be5796f9b58570b
Author: Brian Swetland <swetland@frotz.net>
Date: Thu, 5 Apr 2012 18:42:47 -0700
emulator: fix incorrect handling of IFx instructions
- operand decoder is side-effecty, so skipped instructions
that modified SP still modified SP
- ditch the "skip" register and instead add a simplified
instruction decoder for skipping instructions
- tidy up some other details of the main emulation path
- grumble about non-uniformity of the instruction encoding
(a must be decoded before b, but they're different fields
in the two different instruction formats)
Diffstat:
M | emulator.c | | | 85 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
1 file changed, 42 insertions(+), 43 deletions(-)
diff --git a/emulator.c b/emulator.c
@@ -37,6 +37,7 @@
#include <string.h>
#include <ctype.h>
+typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
@@ -47,7 +48,7 @@ struct dcpu {
u16 pc;
u16 sp;
u16 ov;
- u16 skip;
+ u16 unused;
u16 m[65536];
};
@@ -90,28 +91,26 @@ u16 *dcpu_opr(struct dcpu *d, u16 code) {
}
}
+static u8 skiptable[32] = { /* operand forms that advance pc */
+ [0x10] = 1, [0x11] = 1, [0x12] = 1, [0x13] = 1,
+ [0x14] = 1, [0x15] = 1, [0x16] = 1, [0x17] = 1,
+ [0x1E] = 1, [0x1F] = 1,
+};
+
+void dcpu_skip(struct dcpu *d) {
+ u16 op = d->m[d->pc++];
+ d->pc += skiptable[op >> 10];
+ if ((op & 15) == 0)
+ d->pc += skiptable[(op >> 4) & 31];
+}
+
void dcpu_step(struct dcpu *d) {
u16 op = d->m[d->pc++];
u16 dst;
u32 res;
u16 a, b, *aa;
- if ((op & 0xF) == 0) {
- switch ((op >> 4) & 0x3F) {
- case 0x01:
- a = *dcpu_opr(d, op >> 10);
- if (d->skip) {
- d->skip = 0;
- } else {
- d->m[--(d->sp)] = d->pc;
- d->pc = a;
- }
- return;
- default:
- fprintf(stderr, "< ILLEGAL OPCODE >\n");
- exit(0);
- }
- }
+ if ((op & 0xF) == 0) goto extended;
aa = dcpu_opr(d, dst = (op >> 4) & 0x3F);
a = *aa;
@@ -119,50 +118,50 @@ void dcpu_step(struct dcpu *d) {
switch (op & 0xF) {
case 0x1: res = b; break;
- case 0x2: res = a + b; break;
- case 0x3: res = a - b; break;
- case 0x4: res = a * b; break;
- case 0x5: if (b) { res = a / b; } else { res = 0; } break;
+ case 0x2: res = a + b; d->ov = res >> 16; break;
+ case 0x3: res = a - b; d->ov = res >> 16; break;
+ case 0x4: res = a * b; d->ov = res >> 16; break;
+ case 0x5: if (b) { res = a / b; } else { res = 0; } d->ov = res >> 16; break;
case 0x6: if (b) { res = a % b; } else { res = 0; } break;
- case 0x7: res = a << b; break;
- case 0x8: res = a >> b; break;
+ case 0x7: res = a << b; d->ov = res >> 16; break;
+ case 0x8: res = a >> b; d->ov = res >> 16; break;
case 0x9: res = a & b; break;
case 0xA: res = a | b; break;
case 0xB: res = a ^ b; break;
- case 0xC: res = (a==b); break;
- case 0xD: res = (a!=b); break;
- case 0xE: res = (a>b); break;
- case 0xF: res = ((a&b)!=0); break;
+ case 0xC: if (a!=b) dcpu_skip(d); return;
+ case 0xD: if (a==b) dcpu_skip(d); return;
+ case 0xE: if (a<=b) dcpu_skip(d); return;
+ case 0xF: if ((a&b)==0) dcpu_skip(d); return;
}
- if (d->skip) {
- d->skip = 0;
- return;
- }
+ if (dst < 0x1f) *aa = res;
+ return;
- switch (op & 0xF) {
- case 0x2: case 0x3: case 0x4: case 0x5: case 0x7: case 0x8:
- d->ov = res >> 16;
- case 0x1: case 0x6: case 0x9: case 0xA: case 0xB:
- if (dst < 0x1f) *aa = res;
- break;
- case 0xC: case 0xD: case 0xE: case 0xF:
- d->skip = !res;
+extended:
+ a = *dcpu_opr(d, op >> 10);
+ switch ((op >> 4) & 0x3F) {
+ case 0x01:
+ d->m[--(d->sp)] = d->pc;
+ d->pc = a;
+ return;
+ default:
+ fprintf(stderr, "< ILLEGAL OPCODE >\n");
+ exit(0);
}
}
void dumpheader(void) {
fprintf(stderr,
- "PC SP OV SKIP A B C X Y Z I J Instruction\n"
- "---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -----------\n");
+ "PC SP OV A B C X Y Z I J Instruction\n"
+ "---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- -----------\n");
}
void dumpstate(struct dcpu *d) {
char out[128];
disassemble(d->m + d->pc, out);
fprintf(stderr,
- "%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %s\n",
- d->pc, d->sp, d->ov, d->skip,
+ "%04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %s\n",
+ d->pc, d->sp, d->ov,
d->r[0], d->r[1], d->r[2], d->r[3],
d->r[4], d->r[5], d->r[6], d->r[7],
out);