/* value_decode_
* sets *v to be the destination of the value
- * workv is buffer to use to accumulate literal value before use
+ * workv is buffer to use to accumulate literal value before use, one exists for either potential instruction operand
* returns true if destination points to literal (id est *v should ignore writes)
*/
static
/* if we're skipping this instruction, just advance the pc if needed */
if (d->skip_) {
TRACE(">> SKIP decode");
- if (value == 0x1e || value == 0x1f)
+ if ((value >= 0x10 && value <= 0x17) || value == 0x1e || value == 0x1f)
d->pc++;
return retval;
}
ACCT_W(ev_a);
/* only set non-literal target */
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = *b;
}
ACCT_R(ev_b);
ACCT_R(ev_a);
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = acc;
}
d->o = (acc > 0xffff);
ACCT_R(ev_b);
ACCT_R(ev_a);
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = acc;
- d->o = (acc > 0xffff);
-
}
+ d->o = (acc > 0xffff);
d->cycle += 2;
ACCT_W(ev_a);
ACCT_R(ev_b);
ACCT_R(ev_a);
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = acc;
}
d->o = acc >> 16;
ACCT_R(ev_a);
if (*b == 0) {
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = 0;
}
d->o = 0;
} else {
unsigned int acc = *a / *b;
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = acc;
}
ACCT_R(ev_a);
if (*b == 0) {
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = 0;
}
} else {
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = *a % *b;
}
}
ACCT_R(ev_b);
ACCT_R(ev_a);
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = acc;
}
d->o = acc >> 16;
ACCT_R(ev_b);
ACCT_R(ev_a);
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = acc;
}
d->o = (*a << 16) >> *b;
ACCT_R(ev_b);
ACCT_R(ev_a);
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = *a & *b;
}
ACCT_R(ev_b);
ACCT_R(ev_a);
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = *a | *b;
}
ACCT_R(ev_b);
ACCT_R(ev_a);
- if (val_a < 0x1f) {
+ if (!lit_a) {
*a = *a ^ *b;
}
{0x0, "", NULL }
};
-void dump_value(WORD value, WORD nextword) {
- if (value < 0x07) {
+static inline
+void dump_operand_value_(WORD value, WORD nextword) {
+ if (value <= 0x07) {
printf(" %c", regnames_[value]);
- } else if (value < 0x0f) {
+ } else if (value <= 0x0f) {
printf(" [%c]", regnames_[value & 0x07]);
- } else if (value < 0x17) {
+ } else if (value <= 0x17) {
printf(" [0x%04x + %c]", nextword, regnames_[value & 0x07]);
} else switch (value) {
case 0x18: printf(" POP"); break;
}
}
-void dcpu16_disassemble_print(struct dcpu16 *d, WORD addr) {
+/* split a word into the parts of an instruction, and determine how many words it takes up in total */
+static inline
+void instruction_decode_(struct dcpu16 *d, WORD addr, WORD *opcode, WORD *a, WORD *b, unsigned int *instr_len) {
+ *opcode = d->ram[addr] & ((1 << OPCODE_BASIC_BITS) - 1);
+ *a = (d->ram[addr] >> OPCODE_BASIC_BITS) & ((1 << 6) - 1);
+ *b = (d->ram[addr] >> (OPCODE_BASIC_BITS + 6)) & ((1 << 6) - 1);
+ *instr_len = 1;
+ /* both basic and nbi opcodes use their b operand */
+ if ( (*b >= 0x10 && *b <= 0x17) || *b == 0x1e || *b == 0x1f )
+ *instr_len += 1;
+ /* but only basic uses a */
+ if (*opcode
+ && ((*a >= 0x10 && *a <= 0x17) || *a == 0x1e || *a == 0x1f) )
+ *instr_len += 1;
+}
+
+/* dcpu16_disassemble_print
+ print the words of the instruction at addr, followed by its assembly
+ 7c01 0030 ; SET A,
+ 7de1 1000 0020 ; SET [0x1000], 0x0020
+ 7803 1000 ; SUB A,
+ c00d ; IFN A,
+ */
+WORD dcpu16_disassemble_print(struct dcpu16 *d, WORD addr) {
WORD opcode, a, b;
- unsigned int instr_len = 1;
+ unsigned int instr_len, i;
const struct opcode_entry *e;
-
- opcode = (d->ram[addr] >> OPCODE_BASIC_SHIFT) & ((1 << OPCODE_BASIC_BITS) - 1);
- a = (d->ram[addr] >> (OPCODE_BASIC_SHIFT + OPCODE_BASIC_BITS)) & ((1 << 6) - 1);
- b = (d->ram[addr] >> (OPCODE_BASIC_SHIFT + OPCODE_BASIC_BITS + 6)) & ((1 << 6) - 1);
-
- assert(opcode <= 0x0f);
- assert(a <= 0x3f);
- assert(b <= 0x3f);
-
- printf("%04x", d->ram[addr]);
-
- if (opcode != 0)
- {
- if (a == 0x1e || a == 0x1f) {
- printf(" %04x", d->ram[addr + instr_len]);
- instr_len++;
+ unsigned int indent = 0;
+ unsigned int partial = 0;
+
+ /*
+ Check the previous instruction, to see if this one should be
+ indented. This check isn't foolproof, as preceeding addresses
+ could be data which happen to match instructions..
+ */
+ for (i = 3; i; i--) {
+ instruction_decode_(d, addr - i, &opcode, &a, &b, &instr_len);
+ if (instr_len > i)
+ partial++;
+ if (instr_len == i && opcode >= 0xc) {
+ indent++;
+ break;
}
}
- if (b == 0x1e || b == 0x1f) {
- printf(" %04x", d->ram[addr + instr_len]);
- instr_len++;
- }
+
+ /* now get what we're really interested in */
+ instruction_decode_(d, addr, &opcode, &a, &b, &instr_len);
if (opcode)
e = opcode_basic_entries + opcode;
else
e = opcode_nbi_entries + ( (a < OPCODE_NBI_MAX) ? a : (OPCODE_NBI_MAX - 1) );
- printf("%s%s ; %s",
+ /* show the raw words */
+ printf("%04x", d->ram[addr]);
+ for (i = 1; i < instr_len; i++) {
+ printf(" %04x", d->ram[addr + i]);
+ }
+
+ /* align things neatly, show the instruction */
+ printf("%s%s ;%s%s%s",
instr_len < 3 ? " " : "",
instr_len < 2 ? " " : "",
+ partial ? "*" : " ",
+ indent ? " " : "",
e->name);
- if (opcode != 0) {
- dump_value(a, d->ram[addr + 1]);
- if (a == 0x1e || a == 0x1f)
+
+ /* show the operands */
+ i = 0;
+ if (opcode) {
+ dump_operand_value_(a, d->ram[addr + 1]);
+ if ((a >= 0x10 && a <= 0x17) || a == 0x1e || a == 0x1f)
addr++;
printf(",");
}
- dump_value(b, d->ram[addr + 1]);
+ if (opcode || a)
+ dump_operand_value_(b, d->ram[addr + 1]);
+
+ return instr_len;
}
void dcpu16_step(struct dcpu16 *d) {