dcpu16

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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:
Memulator.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);