X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=dcpu16.c;h=0b1d391e58261f46332fa914aeda4673abe889df;hb=ff3d78d4e1781afbac5d2e9e0fe8361f850bbccb;hp=d7b3d4822eb25cf61edf0cd2c4b9fd1f5f6dbd48;hpb=0a1b4588f79e3719af9431a98da44350030df754;p=dcpu16
diff --git a/dcpu16.c b/dcpu16.c
index d7b3d48..0b1d391 100644
--- a/dcpu16.c
+++ b/dcpu16.c
@@ -11,6 +11,7 @@
/*
* emulates the DCPU16 system from http://0x10c.com/doc/dcpu-16.txt
+ * currently emulates '1.7' spec from http://pastebin.com/Q4JvQvnM
*
* I couldn't remember ever implementing an emulator before, so this
* happened. As such, consider this a toy in progress.
@@ -26,7 +27,6 @@
* !! v1.7 hardware interface needs to be finished
* !! v1.7 interrupts need to be finished
* change api to print into buffers rather than stdio
- * refactor opcode functiontables into switch statements
* let callbacks determine whether to override events, or just observe
* sort init callbacks by base addr, to call in-order
* make all callbacks register addr range of interest
@@ -54,61 +54,62 @@ const char * const dcpu16_reg_names[] = {
NULL
};
-static void printf_null_(char *fmt, ...) { (void)fmt; }
+#define MSG_(__level__, __vm__, ...) do { ((__vm__) ? ((struct dcpu16 *)(__vm__))->msg_cb_ : dcpu16_msg_)((__level__), __VA_ARGS__); } while (0)
+#define MSG_INFO(__vm__,...) MSG_(DCPU16_MSG_INFO, __vm__, __VA_ARGS__)
+#define MSG_ERROR(__vm__,...) MSG_(DCPU16_MSG_ERROR, __vm__, __VA_ARGS__)
+#ifdef DEBUG
+#define MSG_DEBUG(__vm__,...) MSG_(DCPU16_MSG_DEBUG, __vm__, __VA_ARGS__)
+#else /* DEBUG */
+#define MSG_DEBUG(__vm__,...) do {} while (0)
+#endif /* DEBUG */
+#ifdef DEBUG_DECODE
+#define MSG_DEBUG_DECODE (DCPU16_MSG_DEBUG + 2)
+#endif /* DEBUG_DECODE
-/* some default warning and debug reporting functions, which can be overridden by clients */
-#define WARN(...) do { if (warn_cb_) warn_cb_(__VA_ARGS__); } while (0)
-static inline void warn_(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+/* messages could be sent nowhere */
+static void msg_null_(unsigned int l, char *fmt, ...) { (void)l, (void)fmt; }
+
+/* messages default to standard streams */
+static void msg_default_(unsigned int, char *, ...) __attribute__((format(printf, 2, 3)));
static inline
-void warn_(char *fmt, ...) {
+void msg_default_(unsigned int l, char *fmt, ...) {
+ static const char * const msg_tag_[] = { "info", "error", "debug" };
+ FILE *f = (l <= DCPU16_MSG_INFO) ? stderr : stdout;
va_list ap;
- fprintf(stderr, "[warning] ");
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- fprintf(stderr, "\n");
- fflush(stderr);
-}
-static void (*warn_cb_)(char *fmt, ...) = warn_;
-void dcpu16_warn_cb_set(void (*fn)(char *fmt, ...)) {
- if (fn)
- warn_cb_ = fn;
+ if (l < sizeof msg_tag_ / sizeof *msg_tag_)
+ fprintf(f, "[%s] ", msg_tag_[l]);
else
- warn_cb_ = printf_null_;
-}
-
-#ifdef DEBUG
-#define TRACE(...) do { if (trace_cb_) trace_cb_(__VA_ARGS__); } while (0)
-static inline void trace_(char *fmt, ...) __attribute__((format(printf, 1, 2)));
-static inline
-void trace_(char *fmt, ...) {
- va_list ap;
+ fprintf(f, "[%u] ", l);
- fprintf(stdout, "[debug] ");
va_start(ap, fmt);
- vfprintf(stdout, fmt, ap);
+ vfprintf(f, fmt, ap);
va_end(ap);
- fprintf(stdout, "\n");
- fflush(stdout);
-}
-#else /* DEBUG */
-#define TRACE(...) do {} while(0)
-#endif /* DEBUG */
-static void (*trace_cb_)(char *fmt, ...) =
-#ifdef DEBUG
- trace_
-#else /* DEBUG */
- NULL
-#endif
- ;
-void dcpu16_trace_cb_set(void (*fn)(char *fmt, ...)) {
- if (fn)
- trace_cb_ = fn;
- else
- trace_cb_ = printf_null_;
+
+ fprintf(f, "\n");
+
+ fflush(f);
}
+/* dcpu16 message callback
+ * This function pointer is copied into newly instantiated dcpu16 structures,
+ * and is invoked directly for messages independant of a dcpu16 context.
+ */
+dcpu16_msg_cb_t *dcpu16_msg_ = msg_default_;
+
+/* set a new default message callback */
+/* returns the previous setting */
+dcpu16_msg_cb_t *dcpu16_msg_set_default(dcpu16_msg_cb_t *msg_cb) {
+ dcpu16_msg_cb_t *r = dcpu16_msg_;
+ dcpu16_msg_ = msg_cb ? msg_cb : msg_null_;
+ return r;
+}
+/* set a new callback */
+dcpu16_msg_cb_t *dcpu16_msg_set(struct dcpu16 *vm, dcpu16_msg_cb_t *msg_cb) {
+ dcpu16_msg_cb_t *r = vm->msg_cb_;
+ vm->msg_cb_ = msg_cb ? msg_cb : msg_null_;
+ return r;
+}
/* acct_event_
* invokes callbacks for specified event
@@ -120,7 +121,8 @@ void acct_event_(struct dcpu16 *vm, dcpu16_acct_event ev, DCPU16_WORD addr) {
for (i = 0; i < vm->cb_table_entries_; i++) {
if ( (cb[i].mask & ev) )
- cb[i].fn(vm, ev, addr, cb[i].data);
+ if (addr >= cb[i].addr_l && addr <= cb[i].addr_h)
+ cb[i].fn(vm, ev, addr, cb[i].data);
}
}
@@ -134,7 +136,7 @@ int interrupt_enqueue_(struct dcpu16 *vm, DCPU16_WORD message) {
if (vm->interrupts_tail_ == vm->interrupts_head_) {
vm->on_fire_ = 1;
- WARN("interrupt queue overflow (system is now on fire)");
+ MSG_INFO(vm, "interrupt queue overflow (system is now on fire)");
return -1;
}
@@ -146,7 +148,7 @@ DCPU16_WORD interrupt_dequeue_(struct dcpu16 *vm) {
DCPU16_WORD message;
if (vm->interrupts_tail_ == vm->interrupts_head_) {
- WARN("interrupt underflow");
+ MSG_INFO(vm, "interrupt underflow");
return 0;
}
@@ -157,6 +159,27 @@ DCPU16_WORD interrupt_dequeue_(struct dcpu16 *vm) {
return message;
}
+inline
+void dcpu16_cycle_inc(struct dcpu16 *vm, unsigned int n) {
+ size_t i;
+
+ while (n--) {
+ /* new cycle */
+ vm->cycle_ += 1;
+ MSG_DEBUG(vm, "%s>> starting cycle %llu", __func__, vm->cycle_);
+
+ /* signal interested cycle hooks */
+ acct_event_(vm, DCPU16_ACCT_EV_CYCLE, vm->reg[DCPU16_REG_PC]);
+
+ /* signal attached hardware */
+ for (i = 0; i < vm->hw_table_entries_; i++) {
+ MSG_DEBUG(vm, "%s>> notifying %s", __func__, vm->hw_table_[i].mod->name_);
+ if (vm->hw_table_[i].mod->cycle)
+ vm->hw_table_[i].mod->cycle(vm, &vm->hw_table_[i]);
+ }
+ }
+}
+
/* value_decode_
* sets *v to be the address of the represented value
* value_is_a is 0 for b, 1 for a, alters behavior of some operands
@@ -171,142 +194,219 @@ DCPU16_WORD interrupt_dequeue_(struct dcpu16 *vm) {
* decoding next operand..
*
*/
+#define EWHAT_NONE (0)
+#define EWHAT_REG (1<<1)
+#define EWHAT_RAM (1<<2)
static inline
void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a, DCPU16_WORD value_data,
- DCPU16_WORD *work_v, DCPU16_WORD **v, DCPU16_WORD *e_addr,
+ DCPU16_WORD *work_v, DCPU16_WORD **v, DCPU16_WORD *e_addr, enum dcpu16_register_indexes *e_reg, unsigned int *e_what,
short *pc_adjust, short *sp_adjust, unsigned int *cycle_adjust) {
assert(value <= 0x3f);
DCPU16_WORD pc = (DCPU16_WORD)(vm->reg[DCPU16_REG_PC] + *pc_adjust),
- sp = (DCPU16_WORD)(vm->reg[DCPU16_REG_PC] + *sp_adjust);
+ sp = (DCPU16_WORD)(vm->reg[DCPU16_REG_SP] + *sp_adjust);
- TRACE("%s: pc:0x%04x sp:0x%04x value_data:0x%04x\n",
- __func__,
- pc,
- sp,
- value_data);
+ (void)pc;
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm ,"%s>> is_a:%u pc:0x%04x sp:0x%04x value_data:0x%04x\n",
+ __func__,
+ value_is_a,
+ pc,
+ sp,
+ value_data);
+#endif /* DEBUG_DECODE */
if (value <= 0x07) { /* register */
- *v = vm->reg + value;
- TRACE("%s>> %s (0x%04x)",
+ *e_what = EWHAT_REG;
+ *e_reg = value & 0x07;
+ *v = vm->reg + *e_reg;
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> %s (0x%04x)",
__func__,
dcpu16_reg_names[value],
**v);
+#endif /* DEBUG_DECODE */
+
return;
}
if (value <= 0x0f) { /* [register] */
- *v = &(vm->ram[ vm->reg[value & 0x07] ]);
+ *e_what = EWHAT_RAM;
*e_addr = vm->reg[value & 0x07];
- TRACE("%s>> [%s] [0x%04x] (0x%04x)",
+ *v = &(vm->ram[ *e_addr ]);
+ acct_event_(vm, DCPU16_ACCT_EV_REG_READ, value & 0x07);
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> [%s] [0x%04x] (0x%04x)",
__func__,
dcpu16_reg_names[value & 0x07],
vm->reg[value & 0x07],
**v);
+#endif /* DEBUG_DECODE */
+
return;
}
if (value <= 0x17) { /* [next word + register] */
+ acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, DCPU16_REG_PC);
*pc_adjust += 1; /* consume next word */
*cycle_adjust += 1;
+ *e_what = EWHAT_RAM;
*e_addr = value_data + vm->reg[value & 0x07];
+ acct_event_(vm, DCPU16_ACCT_EV_REG_READ, value & 0x07);
*v = vm->ram + *e_addr;
- TRACE("%s>> [nextword + %s] [0x%04x + 0x%04x] (0x%04x)",
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> [nextword + %s] [0x%04x + 0x%04x] (0x%04x)",
__func__,
dcpu16_reg_names[value & 0x07],
value_data,
vm->reg[value & 0x07],
**v);
+#endif /* DEBUG_DECODE */
+
return;
}
switch (value) {
case 0x18: /* PUSH/[--SP] or POP/[SP++] */
+ *e_what = EWHAT_RAM;
+ acct_event_(vm, DCPU16_ACCT_EV_REG_READ, DCPU16_REG_SP);
+ acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, DCPU16_REG_SP);
if (value_is_a == 0) { /* b */
*v = &(vm->ram[sp - 1]);
*sp_adjust -= 1;
*e_addr = sp - 1;
- TRACE("%s>> PUSH [0x%04x] (0x%04x)", __func__, sp - 1, **v);
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> PUSH [0x%04x] (0x%04x)", __func__, sp - 1, **v);
+#endif /* DEBUG_DECODE */
+
} else { /* a */
*v = &(vm->ram[sp]);
*sp_adjust += 1;
*e_addr = sp;
- TRACE("%s>> POP [0x%04x] (0x%04x)", __func__, sp, **v);
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> POP [0x%04x] (0x%04x)", __func__, sp, **v);
+#endif /* DEBUG_DECODE */
+
}
break;
case 0x19: /* PEEK/[SP] */
+ acct_event_(vm, DCPU16_ACCT_EV_REG_READ, DCPU16_REG_SP);
+ *e_what = EWHAT_RAM;
*v = &(vm->ram[sp]);
*e_addr = sp;
- TRACE("%s>> PEEK [0x%04x] (0x%04x)",
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> PEEK [0x%04x] (0x%04x)",
__func__,
sp,
**v);
+#endif /* DEBUG_DECODE */
break;
case 0x1a: /* PICK n */
+ acct_event_(vm, DCPU16_ACCT_EV_REG_READ, DCPU16_REG_SP);
+ *e_what = EWHAT_RAM;
*pc_adjust += 1;
*cycle_adjust += 1;
*e_addr = sp + value_data;
*v = vm->ram + *e_addr;
- TRACE("%s>> PICK 0x%04x [0x%04x] (0x%04x)",
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> PICK 0x%04x [0x%04x] (0x%04x)",
__func__,
value_data,
sp + value_data,
**v);
+#endif /* DEBUG_DECODE */
break;
case 0x1b: /* SP */
+ *e_reg = DCPU16_REG_SP;
+ *e_what = EWHAT_REG;
*v = &(vm->reg[DCPU16_REG_SP]);
- TRACE("%s>> %s (0x%04x)",
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> %s (0x%04x)",
__func__,
dcpu16_reg_names[DCPU16_REG_SP],
**v);
+#endif /* DEBUG_DECODE */
break;
case 0x1c: /* PC */
+ *e_reg = DCPU16_REG_PC;
+ *e_what = EWHAT_REG;
*v = &(vm->reg[DCPU16_REG_PC]);
- TRACE("%s>> %s (0x%04x)",
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> %s (0x%04x)",
__func__,
dcpu16_reg_names[DCPU16_REG_PC],
**v);
+#endif /* DEBUG_DECODE */
break;
case 0x1d: /* EX */
+ *e_reg = DCPU16_REG_EX;
+ *e_what = EWHAT_REG;
*v = &(vm->reg[DCPU16_REG_EX]);
- TRACE("%s>> %s (0x%04x)",
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> %s (0x%04x)",
__func__,
dcpu16_reg_names[DCPU16_REG_EX],
**v);
+#endif /* DEBUG_DECODE */
break;
case 0x1e: /* [next word] / [[pc++]] */
+ *e_what = EWHAT_RAM;
+ acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, DCPU16_REG_PC);
*pc_adjust += 1;
*cycle_adjust += 1;
*e_addr = value_data;
*v = vm->ram + *e_addr;
- TRACE("%s>> [nextword] [0x%04x] (0x%04x)",
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> [nextword] [0x%04x] (0x%04x)",
__func__,
value_data,
**v);
+#endif /* DEBUG_DECODE */
break;
case 0x1f: /* next word (literal) / [pc++] */
+ *e_what = EWHAT_NONE;
+ acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, DCPU16_REG_PC);
*pc_adjust += 1;
*cycle_adjust += 1;
*work_v = value_data;
*v = work_v;
- TRACE("%s>> nextword (0x%04x)",
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> nextword (0x%04x)",
__func__,
**v);
+#endif /* DEBUG_DECODE */
break;
default: /* 0x20-0x3f: literal values 0xffff-0x1e */
+ *e_what = EWHAT_NONE;
*work_v = (value & 0x1f) - 1;
*v = work_v;
- TRACE("%s>> literal (0x%04x)",
+
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, vm, "%s>> literal (0x%04x)",
__func__,
**v);
+#endif /* DEBUG_DECODE */
}
}
@@ -327,19 +427,21 @@ struct opcode_entry {
#define OP_TYPE(op_type) DCPU16_WORD *a, *b;\
DCPU16_WORD ev_a_addr = 0, ev_b_addr = 0;\
+ enum dcpu16_register_indexes ev_a_reg = DCPU16_REG__NUM, ev_b_reg = DCPU16_REG__NUM;\
+ unsigned int ev_a_what = 0, ev_b_what = 0;\
short pc_adjust = 0, sp_adjust = 0;\
unsigned int cycle_adjust = 0;\
do {\
op_type;\
value_decode_(vm, val_a, 1, val_a_data,\
- &vm->reg_work_[1], &a, &ev_a_addr,\
+ &vm->reg_work_[1], &a, &ev_a_addr, &ev_a_reg, &ev_a_what,\
&pc_adjust, &sp_adjust, &cycle_adjust);\
vm->reg[DCPU16_REG_SP] += sp_adjust;\
- vm->cycle += cycle_adjust;\
+ if (cycle_adjust) dcpu16_cycle_inc(vm, cycle_adjust);\
} while (0)
-#define OP_NBI_ (void)val_b, (void)b, (void)ev_b_addr, (void)val_b_data
+#define OP_NBI_ (void)val_b, (void)b, (void)ev_b_addr, (void)val_b_data, (void)ev_b_reg, (void)ev_b_what
#define OP_BASIC_ value_decode_(vm, val_b, 0, val_b_data,\
- &vm->reg_work_[0], &b, &ev_b_addr,\
+ &vm->reg_work_[0], &b, &ev_b_addr, &ev_b_reg, &ev_b_what,\
&pc_adjust, &sp_adjust, &cycle_adjust)
#define OP_BASIC(x) OP_TYPE(OP_BASIC_)
#define OP_NBI(x) OP_TYPE(OP_NBI_)
@@ -350,9 +452,20 @@ struct opcode_entry {
accounting helpers, these fire off the related callbacks for memory reads,
memory writes, and execution of reserved instructions
*/
-#define ACCT_R(addr) do { acct_event_(vm, DCPU16_ACCT_EV_READ, addr); } while (0)
-#define ACCT_W(addr) do { acct_event_(vm, DCPU16_ACCT_EV_WRITE, addr); } while (0)
#define ACCT_ILL(addr) do { acct_event_(vm, DCPU16_ACCT_EV_NOP, addr); } while (0)
+#define ACCT_RAM_R(addr) do { acct_event_(vm, DCPU16_ACCT_EV_READ, addr); } while (0)
+#define ACCT_RAM_W(addr) do { acct_event_(vm, DCPU16_ACCT_EV_WRITE, addr); } while (0)
+#define ACCT_REG_R(reg) do { acct_event_(vm, DCPU16_ACCT_EV_REG_READ, reg); } while (0)
+#define ACCT_REG_W(reg) do { acct_event_(vm, DCPU16_ACCT_EV_REG_WRITE, reg); } while (0)
+
+#define ACCT_R(__x__) do {\
+ if (ev_##__x__##_what & EWHAT_REG) ACCT_REG_R(ev_##__x__##_reg);\
+ if (ev_##__x__##_what & EWHAT_RAM) ACCT_RAM_R(ev_##__x__##_addr);\
+} while (0)
+#define ACCT_W(__x__) do {\
+ if (ev_##__x__##_what & EWHAT_REG) ACCT_REG_W(ev_##__x__##_reg);\
+ if (ev_##__x__##_what & EWHAT_RAM) ACCT_RAM_W(ev_##__x__##_addr);\
+} while (0)
/* extended opcodes */
@@ -369,42 +482,53 @@ OP_IMPL(nbi__reserved_) {
/* fire an illegal instruction event for current instruction */
DCPU16_WORD future_opcode = (vm->ram[vm->reg[DCPU16_REG_PC] - pc_adjust] >> (OPCODE_BASIC_BITS + OPCODE_OPERAND_B_BITS));
- WARN("reserved future opcode 0x%04x invoked", future_opcode);
+
+ MSG_INFO(vm, "reserved future opcode 0x%04x invoked", future_opcode);
ACCT_ILL(vm->reg[DCPU16_REG_PC] - pc_adjust);
+
+ dcpu16_cycle_inc(vm, 1);
}
OP_IMPL(nbi_jsr) {
OP_NBI(nbi_jsr);
/* pushes the address of the next instruction to the stack, then sets PC to a */
- ACCT_R(ev_a_addr);
+ ACCT_R(a);
+ ACCT_REG_R(DCPU16_REG_PC);
+ ACCT_REG_R(DCPU16_REG_SP);
vm->ram[ --vm->reg[DCPU16_REG_SP] ] = vm->reg[DCPU16_REG_PC];
+ ACCT_REG_W(DCPU16_REG_SP);
+ ACCT_RAM_W(vm->reg[DCPU16_REG_SP] + 1);
+
vm->reg[DCPU16_REG_PC] = *a;
+ ACCT_REG_W(DCPU16_REG_PC);
- vm->cycle += 2;
- ACCT_W(vm->reg[DCPU16_REG_SP] + 1);
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(nbi__reserved2_) {
OP_NBI(nbi__reserved2_);
/* reserved */
- WARN("reserved nbi opcode invoked");
+ MSG_INFO(vm, "reserved nbi opcode invoked");
ACCT_ILL(vm->reg[DCPU16_REG_PC] - pc_adjust);
+
+ dcpu16_cycle_inc(vm, 1);
}
OP_IMPL(nbi_int) {
OP_NBI(nbi_int);
- ACCT_R(ev_a_addr);
+ ACCT_R(a);
+ ACCT_REG_R(DCPU16_REG_IA);
if (vm->reg[DCPU16_REG_IA]) {
if ( interrupt_enqueue_(vm, *a) ) {
- WARN("failed to queue interrupt");
+ MSG_INFO(vm, "failed to queue interrupt");
return;
}
@@ -412,112 +536,155 @@ OP_IMPL(nbi_int) {
return;
vm->interrupts_deferred_ = 1;
+
+ ACCT_REG_R(DCPU16_REG_PC);
+ ACCT_REG_R(DCPU16_REG_SP);
vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_PC];
+ ACCT_RAM_W(vm->reg[DCPU16_REG_SP] + 1);
+ ACCT_REG_W(DCPU16_REG_SP);
+
+ ACCT_REG_R(DCPU16_REG_A);
+ ACCT_REG_R(DCPU16_REG_SP);
vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_A];
+ ACCT_RAM_W(vm->reg[DCPU16_REG_SP] + 1);
+ ACCT_REG_W(DCPU16_REG_SP);
+
+ ACCT_REG_R(DCPU16_REG_IA);
vm->reg[DCPU16_REG_PC] = vm->reg[DCPU16_REG_IA];
- vm->reg[0] = *a;
+ ACCT_REG_W(DCPU16_REG_PC);
+
+ vm->reg[DCPU16_REG_A] = *a;
+ ACCT_REG_W(DCPU16_REG_A);
}
- vm->cycle += 4;
+ dcpu16_cycle_inc(vm, 4);
}
OP_IMPL(nbi_iag) {
OP_NBI(nbi_iag);
+ ACCT_REG_R(DCPU16_REG_IA);
*a = vm->reg[DCPU16_REG_IA];
- ACCT_W(ev_a_addr);
+ ACCT_W(a);
+
+ dcpu16_cycle_inc(vm, 1);
}
OP_IMPL(nbi_ias) {
OP_NBI(nbi_ias);
+ ACCT_R(a);
+
vm->reg[DCPU16_REG_IA] = *a;
+ ACCT_REG_W(DCPU16_REG_IA);
- ACCT_R(ev_a_addr);
+ dcpu16_cycle_inc(vm, 1);
}
/* does this just ignore its operand? */
OP_IMPL(nbi_rfi) {
OP_NBI(nbi_rfi);
+ /* well, it consumes the argument, currently, so I guess pretend like we care */
+ ACCT_R(a);
+
vm->interrupts_deferred_ = 0;
+
+ ACCT_REG_R(DCPU16_REG_SP);
+ ACCT_RAM_R(vm->reg[DCPU16_REG_SP]);
vm->reg[DCPU16_REG_A] = vm->ram[vm->reg[DCPU16_REG_SP]++];
+ ACCT_REG_W(DCPU16_REG_A);
+ ACCT_REG_W(DCPU16_REG_SP);
+
+ ACCT_REG_R(DCPU16_REG_SP);
+ ACCT_RAM_R(vm->reg[DCPU16_REG_SP]);
vm->reg[DCPU16_REG_PC] = vm->ram[vm->reg[DCPU16_REG_SP]++];
+ ACCT_REG_W(DCPU16_REG_PC);
+ ACCT_REG_W(DCPU16_REG_SP);
+
+ dcpu16_cycle_inc(vm, 3);
}
OP_IMPL(nbi_iaq) {
OP_NBI(nbi_iaq);
+ ACCT_R(a);
+
if (*a) {
vm->interrupts_deferred_ = 1;
} else {
vm->interrupts_deferred_ = 0;
}
- ACCT_R(ev_a_addr);
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(nbi_hwn) {
OP_NBI(nbi_hwn);
- ACCT_W(ev_a_addr);
-
*a = vm->hw_table_entries_;
+ ACCT_W(a);
- vm->cycle += 2;
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(nbi_hwq) {
OP_NBI(nbi_hwq);
- ACCT_R(ev_a_addr);
+ ACCT_R(a);
if (*a >= vm->hw_table_entries_) {
- WARN("hardware query for non-extant device 0x%04x", *a);
+ MSG_INFO(vm, "hardware query for non-extant device 0x%04x", *a);
vm->reg[DCPU16_REG_A] = 0;
vm->reg[DCPU16_REG_B] = 0;
vm->reg[DCPU16_REG_C] = 0;
vm->reg[DCPU16_REG_X] = 0;
vm->reg[DCPU16_REG_Y] = 0;
- return;
+ } else {
+ vm->reg[DCPU16_REG_A] = vm->hw_table_[*a].mod->id_l;
+ vm->reg[DCPU16_REG_B] = vm->hw_table_[*a].mod->id_h;
+ vm->reg[DCPU16_REG_C] = vm->hw_table_[*a].mod->ver;
+ vm->reg[DCPU16_REG_X] = vm->hw_table_[*a].mod->mfg_l;
+ vm->reg[DCPU16_REG_Y] = vm->hw_table_[*a].mod->mfg_h;
}
- vm->reg[DCPU16_REG_A] = vm->hw_table_[*a].id_l;
- vm->reg[DCPU16_REG_B] = vm->hw_table_[*a].id_h;
- vm->reg[DCPU16_REG_C] = vm->hw_table_[*a].ver;
- vm->reg[DCPU16_REG_X] = vm->hw_table_[*a].mfg_l;
- vm->reg[DCPU16_REG_Y] = vm->hw_table_[*a].mfg_h;
+ ACCT_REG_W(DCPU16_REG_A);
+ ACCT_REG_W(DCPU16_REG_B);
+ ACCT_REG_W(DCPU16_REG_C);
+ ACCT_REG_W(DCPU16_REG_X);
+ ACCT_REG_W(DCPU16_REG_Y);
- vm->cycle += 4;
+ dcpu16_cycle_inc(vm, 4);
}
OP_IMPL(nbi_hwi) {
OP_NBI(nbi_hwi);
- ACCT_R(ev_a_addr);
+ ACCT_R(a);
if (*a > vm->hw_table_entries_) {
- WARN("interrupt for non-extant device 0x%04x", *a);
+ MSG_INFO(vm, "interrupt for non-extant device 0x%04x", *a);
return;
}
- vm->cycle += 4;
- if (vm->hw_table_[*a].hwi)
- vm->hw_table_[*a].hwi(vm, vm->hw_table_[*a].data);
+ if (vm->hw_table_[*a].mod->hwi)
+ vm->hw_table_[*a].mod->hwi(vm, &vm->hw_table_[*a]);
else
- WARN("hardware 0x%04x has no interrupt handler", *a);
+ MSG_INFO(vm, "hardware 0x%04x has no interrupt handler", *a);
+
+ dcpu16_cycle_inc(vm, 4);
}
OP_IMPL(nbi_hcf) {
OP_NBI(nbi_hcf);
- ACCT_R(ev_a_addr);
+ ACCT_R(a);
vm->on_fire_ = 1;
- WARN("system on fire");
+ MSG_INFO(vm, "system on fire");
- vm->cycle += 9;
+ dcpu16_cycle_inc(vm, 9);
}
static const struct opcode_entry opcode_nbi_entries[] = {
@@ -566,7 +733,7 @@ OP_IMPL(_nbi_) {
assert(e->impl != NULL);
- TRACE(">> %s 0x%04x", e->name, val_b);
+ MSG_DEBUG(vm, "%s>> %s 0x%04x", __func__, e->name, val_b);
e->impl(vm, 0, 0, val_a, val_a_data);
}
@@ -574,7 +741,7 @@ OP_IMPL(set) {
OP_BASIC(set);
/* sets b to a */
- ACCT_R(ev_a_addr);
+ ACCT_R(a);
/*
if b is a literal, it's aimed at a scratch register,
@@ -582,9 +749,9 @@ OP_IMPL(set) {
*/
*b = *a;
- vm->cycle += 1;
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 1);
}
OP_IMPL(add) {
@@ -592,15 +759,17 @@ OP_IMPL(add) {
/* sets b to b+a, sets EX to 0x0001 if there's an overflow, 0x0 otherwise */
unsigned int acc = *b + *a;
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = acc;
vm->reg[DCPU16_REG_EX] = (acc > 0xffff);
- vm->cycle += 2;
+ ACCT_REG_W(DCPU16_REG_EX);
+
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(sub) {
@@ -608,15 +777,17 @@ OP_IMPL(sub) {
/* sets b to b-a, sets EX to 0xffff if there's an underflow, 0x0 otherwise */
unsigned int acc = *b - *a;
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = acc;
vm->reg[DCPU16_REG_EX] = (acc > 0xffff);
- vm->cycle += 2;
+ ACCT_REG_W(DCPU16_REG_EX);
+
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(mul) {
@@ -624,15 +795,17 @@ OP_IMPL(mul) {
/* sets b to b*a, unsigned, sets EX to ((b*a)>>16)&0xffff */
unsigned int acc = *b * *a;
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = acc;
vm->reg[DCPU16_REG_EX] = acc >> 16;
- vm->cycle += 2;
+ ACCT_REG_W(DCPU16_REG_EX);
- ACCT_W(ev_b_addr);
+ ACCT_W(b);
+
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(mli) {
@@ -640,23 +813,25 @@ OP_IMPL(mli) {
/* sets b to b*a, signed */
int acc = (short)*b * (short)*a;
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = acc;
vm->reg[DCPU16_REG_EX] = acc >> 16;
- vm->cycle += 2;
+ ACCT_REG_W(DCPU16_REG_EX);
+
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(div) {
OP_BASIC(div);
/* sets b to b/a, sets EX to ((b<<16)/a)&0xffff. if a==0, sets a and EX to 0 instead. */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if (*a == 0) {
*b = 0;
@@ -666,17 +841,19 @@ OP_IMPL(div) {
vm->reg[DCPU16_REG_EX] = (*b << 16) / *a;
}
- vm->cycle += 3;
+ ACCT_REG_W(DCPU16_REG_EX);
- ACCT_W(ev_b_addr);
+ ACCT_W(b);
+
+ dcpu16_cycle_inc(vm, 3);
}
OP_IMPL(dvi) {
OP_BASIC(dvi);
/* sets b to b/a, signed, round towards 0 */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if (*a == 0) {
*b = 0;
@@ -686,17 +863,18 @@ OP_IMPL(dvi) {
vm->reg[DCPU16_REG_EX] = (short)(*b << 16) / (short)*a;
}
- vm->cycle += 3;
+ ACCT_REG_W(DCPU16_REG_EX);
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 3);
}
OP_IMPL(mod) {
OP_BASIC(mod);
/* sets b to b%a. if a==0, sets b to 0 instead. */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if (*a == 0) {
*b = 0;
@@ -704,17 +882,17 @@ OP_IMPL(mod) {
*b = *b % *a;
}
- vm->cycle += 3;
+ ACCT_W(a);
- ACCT_W(ev_a_addr);
+ dcpu16_cycle_inc(vm, 3);
}
OP_IMPL(mdi) {
OP_BASIC(mdi);
/* sets b to b%a, signed */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if (*a == 0) {
*b = 0;
@@ -722,51 +900,51 @@ OP_IMPL(mdi) {
*b = (short)*b % (short)*a;
}
- vm->cycle += 3;
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 3);
}
OP_IMPL(and) {
OP_BASIC(and);
/* sets b to b&a */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = *b & *a;
- vm->cycle += 1;
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 1);
}
OP_IMPL(bor) {
OP_BASIC(bor);
/* sets b to b|a */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = *b | *a;
- vm->cycle += 1;
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 1);
}
OP_IMPL(xor) {
OP_BASIC(xor);
/* sets b to b^a */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = *b ^ *a;
- vm->cycle += 1;
+ dcpu16_cycle_inc(vm, 1);
- ACCT_W(ev_b_addr);
+ ACCT_W(b);
}
OP_IMPL(shr) {
@@ -774,17 +952,18 @@ OP_IMPL(shr) {
/* sets b to b>>>a, sets EX to ((b<<16)>>a)&0xffff */
unsigned int acc = *b >> *a;
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = acc & 0xffff;
vm->reg[DCPU16_REG_EX] = (*b << 16) >> *a;
- vm->cycle += 2;
+ MSG_ERROR(vm, "IMPLEMENT");
- WARN("IMPLEMENT");
+ ACCT_REG_W(DCPU16_REG_EX);
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(asr) {
@@ -792,17 +971,18 @@ OP_IMPL(asr) {
/* sets b to b>>a, sets EX to ((b<<16)>>>a)&0xffff (arithmetic shift) (treats b as signed) */
unsigned int acc = *b << *a;
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = acc & 0xffff;
vm->reg[DCPU16_REG_EX] = (*b << 16) >> *a;
- vm->cycle += 2;
+ MSG_ERROR(vm, "IMPLEMENT");
- WARN("IMPLEMENT");
+ ACCT_REG_W(DCPU16_REG_EX);
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(shl) {
@@ -810,152 +990,153 @@ OP_IMPL(shl) {
/* sets b to b<>16)&0xffff */
unsigned int acc = *b << *a;
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = acc;
vm->reg[DCPU16_REG_EX] = acc >> 16;
- vm->cycle += 2;
+ ACCT_REG_W(DCPU16_REG_EX);
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(ifb) {
OP_BASIC(ifb);
/* performs next instruction only if (b&a)!=0 */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if ((*b & *a) != 0) {
/* */
} else {
vm->skip_ = 1;
- vm->cycle += 1;
+ dcpu16_cycle_inc(vm, 1);
}
- vm->cycle += 2;
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(ifc) {
OP_BASIC(ifc);
/* performs next instruction only if (b&a)==0 */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if ((*b & *a) == 0) {
/* */
} else {
vm->skip_ = 1;
- vm->cycle += 1;
+ dcpu16_cycle_inc(vm, 1);
}
- vm->cycle += 2;
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(ife) {
OP_BASIC(ife);
/* performs next instruction only if b==a */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if (*b == *a) {
/* */
} else {
vm->skip_ = 1;
- vm->cycle += 1;
+ dcpu16_cycle_inc(vm, 1);
}
- vm->cycle += 2;
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(ifn) {
OP_BASIC(ifn);
/* performs next instruction only if b!=a */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if (*b != *a) {
/* */
} else {
vm->skip_ = 1;
- vm->cycle++;
+ dcpu16_cycle_inc(vm, 1);
}
- vm->cycle += 2;
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(ifg) {
OP_BASIC(ifg);
/* performs next instruction only if b>a */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if (*b > *a) {
/* */
} else {
vm->skip_ = 1;
- vm->cycle++;
+ dcpu16_cycle_inc(vm, 1);
}
- vm->cycle += 2;
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(ifa) {
OP_BASIC(ifa);
/* performs next instruction only if b>a (signed) */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
if (*b > *a) {
/* */
} else {
vm->skip_ = 1;
- vm->cycle += 1;
+ dcpu16_cycle_inc(vm, 1);
}
- vm->cycle += 2;
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(ifl) {
OP_BASIC(ifl);
/* performs next instruction only if bskip_ = 1;
- vm->cycle++;
+ dcpu16_cycle_inc(vm, 1);
}
- vm->cycle += 2;
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(ifu) {
OP_BASIC(ifu);
/* performs next instruction only if bskip_ = 1;
- vm->cycle += 1;
+ dcpu16_cycle_inc(vm, 1);
}
- vm->cycle += 2;
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(adx) {
@@ -963,8 +1144,10 @@ OP_IMPL(adx) {
/* sets b to b+a+EX, sets EX to 0x0001 if overflow, 0x0 otherwise */
unsigned int acc;
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
+
+ ACCT_REG_R(DCPU16_REG_EX);
acc = *b + *a + vm->reg[DCPU16_REG_EX];
*b = acc & 0xffff;
@@ -973,9 +1156,10 @@ OP_IMPL(adx) {
else
vm->reg[DCPU16_REG_EX] = 0x0000;
- vm->cycle += 3;
+ ACCT_REG_W(DCPU16_REG_EX);
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 3);
}
OP_IMPL(sbx) {
@@ -983,8 +1167,10 @@ OP_IMPL(sbx) {
/* sets b to b-a+EX, sets EX to 0xffff if underflow, 0x0 otherwise */
unsigned int acc;
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
+
+ ACCT_REG_R(DCPU16_REG_EX);
acc = *b - *a + vm->reg[DCPU16_REG_EX];
*b = acc & 0xffff;
@@ -993,47 +1179,55 @@ OP_IMPL(sbx) {
else
vm->reg[DCPU16_REG_EX] = 0;
- vm->cycle += 3;
+ ACCT_REG_W(DCPU16_REG_EX);
+
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 3);
}
OP_IMPL(sti) {
OP_BASIC(sti);
/* sets b to a, then increases I and J by 1 */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = *a;
vm->reg[DCPU16_REG_I] += 1;
vm->reg[DCPU16_REG_J] += 1;
- vm->cycle += 2;
+ ACCT_REG_W(DCPU16_REG_I);
+ ACCT_REG_W(DCPU16_REG_J);
- ACCT_W(ev_b_addr);
+ ACCT_W(b);
+
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(std) {
OP_BASIC(std);
/* sets b to a, then decreases I and J by 1 */
- ACCT_R(ev_b_addr);
- ACCT_R(ev_a_addr);
+ ACCT_R(b);
+ ACCT_R(a);
*b = *a;
vm->reg[DCPU16_REG_I] -= 1;
vm->reg[DCPU16_REG_J] -= 1;
- vm->cycle += 2;
+ ACCT_REG_W(DCPU16_REG_I);
+ ACCT_REG_W(DCPU16_REG_J);
+
+ ACCT_W(b);
- ACCT_W(ev_b_addr);
+ dcpu16_cycle_inc(vm, 2);
}
OP_IMPL(_reserved_) {
OP_BASIC(_reserved_);
- WARN("reserved opcode invoked");
+ MSG_INFO(vm, "reserved opcode invoked");
ACCT_ILL(vm->reg[DCPU16_REG_PC] - pc_adjust);
}
@@ -1073,34 +1267,76 @@ static const struct opcode_entry opcode_basic_entries[] = {
{0x1f, "STD", op_std },
{0x00, "", NULL }
};
+#define OPCODE_BASIC_MAX (((sizeof(opcode_basic_entries)) / (sizeof(struct opcode_entry))) - 1)
static inline
void dump_operand_value_(DCPU16_WORD value, DCPU16_WORD nextword, unsigned int value_position) {
+ printf(" ");
if (value <= 0x07) {
- printf(" %s", dcpu16_reg_names[value]);
+ printf("%s", dcpu16_reg_names[value]);
} else if (value <= 0x0f) {
- printf(" [%s]", dcpu16_reg_names[value & 0x07]);
+ printf("[%s]", dcpu16_reg_names[value & 0x07]);
} else if (value <= 0x17) {
- printf(" [0x%04x + %s]", nextword, dcpu16_reg_names[value & 0x07]);
+ printf("[0x%04x + %s]", nextword, dcpu16_reg_names[value & 0x07]);
} else switch (value) {
case 0x18:
if (value_position == 0) { /* b */
- printf(" PUSH");
+ printf("PUSH");
} else {
- printf(" POP");
+ printf("POP");
}
break;
- case 0x19: printf(" PEEK"); break;
- case 0x1a: printf(" PICK 0x%04x", nextword); break;
- case 0x1b: printf(" SP"); break;
- case 0x1c: printf(" PC"); break;
- case 0x1d: printf(" EX"); break;
- case 0x1e: printf(" [0x%04x]", nextword); break;
- case 0x1f: printf(" 0x%04x", nextword); break;
- default: printf(" 0x%02x", value - 0x21);
+ case 0x19: printf("PEEK"); break;
+ case 0x1a: printf("PICK 0x%04x", nextword); break;
+ case 0x1b: printf("SP"); break;
+ case 0x1c: printf("PC"); break;
+ case 0x1d: printf("EX"); break;
+ case 0x1e: printf("[0x%04x]", nextword); break;
+ case 0x1f: printf("0x%04x", nextword); break;
+ default: printf("0x%02x", value - 0x21);
}
}
+static inline
+int operand_snprint_(char *buf, size_t buf_sz, DCPU16_WORD value, DCPU16_WORD nextword, unsigned int operand_is_a) {
+ int len;
+
+ len = snprintf(buf, buf_sz, " ");
+ if ((size_t)len >= buf_sz)
+ return -1;
+
+ buf += len, buf_sz -= len;
+
+ if (value <= 0x07) {
+ len = snprintf(buf, buf_sz, "%s", dcpu16_reg_names[value]);
+ } else if (value <= 0x0f) {
+ len = snprintf(buf, buf_sz, "[%s]", dcpu16_reg_names[value & 0x07]);
+ } else if (value <= 0x17) {
+ len = snprintf(buf, buf_sz, "[0x%04x + %s]", nextword, dcpu16_reg_names[value & 0x07]);
+ } else switch (value) {
+ case 0x18:
+ if (operand_is_a == 0) { /* b */
+ len = snprintf(buf, buf_sz, "PUSH");
+ } else {
+ len = snprintf(buf, buf_sz, "POP");
+ }
+ break;
+ case 0x19: len = snprintf(buf, buf_sz, "PEEK"); break;
+ case 0x1a: len = snprintf(buf, buf_sz, "PICK 0x%04x", nextword); break;
+ case 0x1b: len = snprintf(buf, buf_sz, "SP"); break;
+ case 0x1c: len = snprintf(buf, buf_sz, "PC"); break;
+ case 0x1d: len = snprintf(buf, buf_sz, "EX"); break;
+ case 0x1e: len = snprintf(buf, buf_sz, "[0x%04x]", nextword); break;
+ case 0x1f: len = snprintf(buf, buf_sz, "0x%04x", nextword); break;
+ default: len = snprintf(buf, buf_sz, "0x%02x", (short)(value - 0x21));
+ }
+
+ if ((size_t)len >= buf_sz)
+ return -1;
+
+ return len;
+}
+
/* split a sequence of (one to three) words into the components of an instruction */
static inline
@@ -1113,9 +1349,9 @@ void instruction_decode_(DCPU16_WORD *mem, DCPU16_WORD addr,
*a = (mem[addr] >> (OPCODE_BASIC_BITS + OPCODE_OPERAND_B_BITS)) & ((1 << OPCODE_OPERAND_A_BITS) - 1);
*instr_len = 1;
- if ( (*b >= 0x10 && *b <= 0x17) || *b == 0x1e || *b == 0x1f ) {
+ if ((*opcode != 0x0000) &&
+ ( (*b >= 0x10 && *b <= 0x17) || *b == 0x1e || *b == 0x1f ) ) {
*b_data = mem + (DCPU16_WORD)(addr + *instr_len);
- TRACE("**b_data:%hu", **b_data);
*instr_len += 1;
} else {
*b_data = NULL;
@@ -1124,14 +1360,13 @@ void instruction_decode_(DCPU16_WORD *mem, DCPU16_WORD addr,
if ( (*opcode != 0x0000 || (*opcode == 0 && *b != 0x0000) )
&& ( (*a >= 0x10 && *a <= 0x17) || *a == 0x1e || *a == 0x1f) ) {
*a_data = mem + (DCPU16_WORD)(addr + *instr_len);
- TRACE("**a_data:%hu", **a_data);
*instr_len += 1;
} else {
*a_data = NULL;
}
-#if 0
- TRACE("\n%s: [0x%04x]:0x%04x op:0x%02x b:0x%02x (b_data:0x%04x) a:0x%02x (a_data:0x%04x) len:0x%02x\n",
+#ifdef DEBUG_DECODE
+ MSG_(MSG_DEBUG_DECODE, NULL, "\n%s: [0x%04x]:0x%04x op:0x%02x b:0x%02x (b_data:0x%04x) a:0x%02x (a_data:0x%04x) len:0x%02x\n",
__func__,
addr,
mem[addr],
@@ -1141,7 +1376,7 @@ void instruction_decode_(DCPU16_WORD *mem, DCPU16_WORD addr,
*a,
*a_data ? **a_data : 0,
*instr_len);
-#endif
+#endif /* DEBUG_DECODE */
}
/* dcpu16_mnemonify_buf
@@ -1150,6 +1385,7 @@ void instruction_decode_(DCPU16_WORD *mem, DCPU16_WORD addr,
DCPU16_WORD dcpu16_mnemonify_buf(DCPU16_WORD *buf) {
DCPU16_WORD opcode, b, a, instr_len, *b_data, *a_data;
const struct opcode_entry *e;
+ char operand[16];
instruction_decode_(buf, 0, &opcode, &b, &b_data, &a, &a_data, &instr_len);
@@ -1161,12 +1397,13 @@ DCPU16_WORD dcpu16_mnemonify_buf(DCPU16_WORD *buf) {
printf("%s", e->name);
if (opcode) {
- dump_operand_value_(b, b_data ? *b_data : 0, 0);
- printf(",");
+ operand_snprint_(operand, sizeof operand, b, b_data ? *b_data : 0, 0);
+ printf("%s,", operand);
}
if (opcode || b) {
- dump_operand_value_(a, a_data ? *a_data : 0, 1);
+ operand_snprint_(operand, sizeof operand, a, a_data ? *a_data : 0, 1);
+ printf("%s", operand);
}
return instr_len;
@@ -1224,29 +1461,17 @@ DCPU16_WORD dcpu16_disassemble_print(struct dcpu16 *vm, DCPU16_WORD addr) {
}
int dcpu16_interrupt(struct dcpu16 *vm, DCPU16_WORD message) {
- TRACE("%s>> message:0x%04x", __func__, message);
+ MSG_DEBUG(vm, "%s>> message:0x%04x", __func__, message);
return interrupt_enqueue_(vm, message);
}
/* execute the next instruction */
void dcpu16_step(struct dcpu16 *vm) {
DCPU16_WORD opcode, b, a, instr_len, *b_data, *a_data;
- size_t i;
const struct opcode_entry *e;
- if (!vm) return;
-
- /* signal interested parties that a new cycle has ticked */
- TRACE("%s: sending global cycle event", __func__);
- acct_event_(vm, DCPU16_ACCT_EV_CYCLE, vm->reg[DCPU16_REG_PC]);
-
- /* signal attached hardware */
- for (i = 0; i < vm->hw_table_entries_; i++) {
- if (vm->hw_table_[i].cycle) {
- TRACE("%s: sending cycle to %s", __func__, vm->hw_table_[i].name_);
- vm->hw_table_[i].cycle(vm, vm->hw_table_[i].data);
- }
- }
+ if (!vm)
+ return;
instruction_decode_(vm->ram, vm->reg[DCPU16_REG_PC], &opcode, &b, &b_data, &a, &a_data, &instr_len);
@@ -1255,22 +1480,19 @@ void dcpu16_step(struct dcpu16 *vm) {
vm->reg[DCPU16_REG_PC] += instr_len;
/* run the operation */
- for (e = opcode_basic_entries; e->impl; e++) {
- if (e->value == opcode) {
- TRACE("%s>> %s 0x%04x, 0x%04x", __func__, e->name, b, a);
- e->impl(vm, b, b_data ? *b_data : 0, a, a_data ? *a_data : 0);
- break;
- }
- }
+ e = opcode_basic_entries + opcode;
+ MSG_DEBUG(vm, "%s", e->name ? e->name : "???");
+ e->impl(vm, b, b_data ? *b_data : 0, a, a_data ? *a_data : 0);
+
/* and jump over next instr(s) if needed */
while (vm->skip_) {
instruction_decode_(vm->ram, vm->reg[DCPU16_REG_PC], &opcode, &b, &b_data, &a, &a_data, &instr_len);
vm->reg[DCPU16_REG_PC] += instr_len;
- TRACE("++ SKIPPED %x words", instr_len);
+ MSG_DEBUG(vm, "%s>> ++ SKIPPED %x words", __func__, instr_len);
if (opcode >= 0x10 && opcode <= 0x17) {
/* skipping a branch instruction? skip branch's skippable instruction as well */
- vm->cycle += 1;
+ dcpu16_cycle_inc(vm, 1);
} else {
vm->skip_ = 0;
}
@@ -1283,74 +1505,111 @@ void dcpu16_step(struct dcpu16 *vm) {
DCPU16_WORD message;
message = interrupt_dequeue_(vm);
+ MSG_DEBUG(vm, "%s>> %s interrupt IA:0x%04x message:0x%04x",
+ __func__,
+ vm->reg[DCPU16_REG_IA] ? "servicing" : "ignoring",
+ vm->reg[DCPU16_REG_IA],
+ message);
+
if (vm->reg[DCPU16_REG_IA]) {
- TRACE("servicing interrupt IA:0x%04x message:0x%04x \n", vm->reg[DCPU16_REG_IA], message);
/* then service the next interrupt */
vm->interrupts_deferred_ = 1;
vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_PC];
vm->ram[--vm->reg[DCPU16_REG_SP]] = vm->reg[DCPU16_REG_A];
vm->reg[DCPU16_REG_PC] = vm->reg[DCPU16_REG_IA];
vm->reg[DCPU16_REG_A] = message;
- } else {
- TRACE("ignoring interrupt IA:0");
}
}
}
}
-/*
- print the current state of the machine
- shows current cycle count, registers, and next instruction
-*/
-void dcpu16_state_print(struct dcpu16 *vm) {
- unsigned int i;
- if (!vm) return;
+/* instantiate a new 'hardware' device */
+struct dcpu16_hw *dcpu16_hw_new(struct dcpu16 *vm, struct dcpu16_hw_module *mod, void *data) {
+ struct dcpu16_hw *hw;
- printf(" ");
- for (i = 0; i < 8; i++)
- printf(" %s:0x%04x", dcpu16_reg_names[i], vm->reg[i]);
- printf("\n");
+ MSG_DEBUG(vm, "%s>> mod:%p data:%p", __func__, mod, data);
- printf("(0x%08llx) %2s:0x%04x %2s:0x%04x %2s:0x%04x %2s:0x%04x [%2s]:",
- vm->cycle,
- dcpu16_reg_names[DCPU16_REG_EX], vm->reg[DCPU16_REG_EX],
- dcpu16_reg_names[DCPU16_REG_SP], vm->reg[DCPU16_REG_SP],
- dcpu16_reg_names[DCPU16_REG_PC], vm->reg[DCPU16_REG_PC],
- dcpu16_reg_names[DCPU16_REG_IA], vm->reg[DCPU16_REG_IA],
- "PC");
+ hw = malloc(sizeof *hw);
+ if (hw == NULL) {
+ MSG_ERROR(vm, "%s():%s", "malloc", strerror(errno));
+ return NULL;
+ }
+ hw->vm = vm;
+ hw->mod = mod;
+
+ if (mod->data_init) {
+ if (mod->data_init(hw, data)) {
+ MSG_ERROR(vm, "failed to init hw module data");
+ free(hw);
+ return NULL;
+ }
+ } else {
+ hw->data = NULL;
+ }
- dcpu16_disassemble_print(vm, vm->reg[DCPU16_REG_PC]);
- printf("\n");
+ return hw;
}
-/* dcpu16_dump_ram
- * print raw ram contents from start to stop
- */
-void dcpu16_dump_ram(struct dcpu16 *vm, DCPU16_WORD start, DCPU16_WORD end) {
- unsigned int i, j;
- const unsigned int n = 8; /* words per line */
+/* destroy a 'hardware' device */
+void dcpu16_hw_del(struct dcpu16_hw **hw) {
+ if (hw) {
+ if (*hw) {
+ MSG_DEBUG((*hw)->vm, "%s>> hw:%p",
+ __func__,
+ *hw);
- if (!vm) return;
+ if ((*hw)->mod->data_free) {
+ (*hw)->mod->data_free(*hw);
+ }
+ free(*hw);
+ *hw = NULL;
+ }
+ }
+}
- for (i = start, j = 0; i <= end; i++, j++) {
- if (j % n == 0)
- printf("0x%04x:\t", i);
- printf(" %04x%s", vm->ram[i], (j % n) == (n - 1) ? "\n" : "");
+/* dcpu16_hw_ctl
+ * invokes per-module controls for hw device
+ */
+int dcpu16_hw_ctl(struct dcpu16_hw *hw, const char *cmd, void *data_in, void *data_out) {
+ if (!hw)
+ return -1;
+
+ MSG_DEBUG(hw->vm, "%s>> name:%s cmd:%s in:%p out:%p",
+ __func__,
+ hw->mod->name_,
+ cmd,
+ data_in,
+ data_out);
+
+ if (hw->mod) {
+ if (hw->mod->ctl) {
+ if (cmd) {
+ return hw->mod->ctl(hw, cmd, data_in, data_out);
+ }
+ }
}
- if ((j % n) != (n - 1))
- printf("\n");
+
+ return 0;
}
-/* dcpu16_hw_add
+
+/* dcpu16_hw_attach
* registers new 'hardware' device with system
*/
-int dcpu16_hw_add(struct dcpu16 *vm, struct dcpu16_hw *hw) {
+int dcpu16_hw_attach(struct dcpu16 *vm, struct dcpu16_hw *hw) {
if (!vm || !hw)
return -1;
+ MSG_DEBUG(vm, "%s>> name:%s ID:0x%04x%04x MFG:0x%04x%04x VER:0x%04x",
+ __func__,
+ hw->mod->name_,
+ hw->mod->id_h, hw->mod->id_l,
+ hw->mod->mfg_l, hw->mod->mfg_h,
+ hw->mod->ver);
+
if (vm->hw_table_entries_ == 0xffff) {
- WARN("maximum hardware entries reached");
+ MSG_ERROR(vm, "maximum hardware entries reached");
return -1;
}
@@ -1358,7 +1617,7 @@ int dcpu16_hw_add(struct dcpu16 *vm, struct dcpu16_hw *hw) {
size_t new_entries = vm->hw_table_allocated_ + 32;
void *tmp_ptr = realloc(vm->hw_table_, new_entries * sizeof * (vm->hw_table_));
if (tmp_ptr == NULL) {
- fprintf(stderr, "%s():%s", "realloc", strerror(errno));
+ MSG_ERROR(vm, "%s():%s", "realloc", strerror(errno));
return -1;
}
vm->hw_table_ = tmp_ptr;
@@ -1368,6 +1627,8 @@ int dcpu16_hw_add(struct dcpu16 *vm, struct dcpu16_hw *hw) {
memcpy(vm->hw_table_ + vm->hw_table_entries_, hw, sizeof *hw);
vm->hw_table_entries_++;
+ MSG_DEBUG(vm, "%s>> added hw entry %zu", __func__, vm->hw_table_entries_);
+
return 0;
}
@@ -1375,13 +1636,21 @@ int dcpu16_hw_add(struct dcpu16 *vm, struct dcpu16_hw *hw) {
* Register callback fn to be triggered whenever event matching any events
* in bitwise mask occur.
*/
-int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event mask, dcpu16_ev_cb_t *fn, void *data) {
- struct dcpu16_acct_cb cb;
+int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event mask, dcpu16_ev_cb_t *fn, DCPU16_WORD addr_l, DCPU16_WORD addr_h, void *data) {
+ struct dcpu16_acct_cb cb = {
+ .mask = mask,
+ .addr_l = addr_l,
+ .addr_h = addr_h,
+ .fn = fn,
+ .data = data,
+ };
if (!vm)
return -1;
cb.mask = mask;
+ cb.addr_l = addr_l;
+ cb.addr_h = addr_h;
cb.fn = fn;
cb.data = data;
@@ -1389,7 +1658,7 @@ int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event mask, dcpu16_ev_cb_t *f
size_t new_entries = vm->cb_table_allocated_ + 32;
void *tmp_ptr = realloc(vm->cb_table_, new_entries * sizeof *(vm->cb_table_));
if (tmp_ptr == NULL) {
- fprintf(stderr, "%s():%s", "realloc", strerror(errno));
+ MSG_ERROR(vm, "%s():%s", "realloc", strerror(errno));
return -1;
}
vm->cb_table_ = tmp_ptr;
@@ -1399,6 +1668,8 @@ int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event mask, dcpu16_ev_cb_t *f
memcpy(vm->cb_table_ + vm->cb_table_entries_, &cb, sizeof cb);
vm->cb_table_entries_++;
+ MSG_DEBUG(vm, "%s>> attached event callback %zu", __func__, vm->cb_table_entries_);
+
return 0;
}
@@ -1411,6 +1682,8 @@ void dcpu16_reset(struct dcpu16 *vm) {
if (!vm)
return;
+ MSG_DEBUG(vm, "%s>> reset", __func__);
+
vm->skip_ = 0;
vm->interrupts_deferred_ = 0;
vm->on_fire_ = 0;
@@ -1420,13 +1693,13 @@ void dcpu16_reset(struct dcpu16 *vm) {
/* signal attached hardware */
for (i = 0; i < vm->hw_table_entries_; i++) {
- if (vm->hw_table_[i].reset)
- vm->hw_table_[i].reset(vm, vm->hw_table_[i].data);
+ if (vm->hw_table_[i].mod->reset)
+ vm->hw_table_[i].mod->reset(vm, &vm->hw_table_[i]);
}
memset(vm->reg, 0, sizeof vm->reg);
memset(vm->ram, 0, sizeof vm->ram);
- vm->cycle = 0;
+ vm->cycle_ = 0;
acct_event_(vm, DCPU16_ACCT_EV_RESET, 0);
}
@@ -1439,10 +1712,9 @@ struct dcpu16 *dcpu16_new(void) {
vm = calloc(1, sizeof *vm);
if (vm == NULL)
- WARN("%s: %s(%zu): %s", __func__, "calloc", strerror(errno));
+ MSG_ERROR(NULL, "%s: %s(%zu): %s", __func__, "calloc", strerror(errno));
- vm->warn_cb_ = warn_cb_;
- vm->trace_cb_ = trace_cb_;
+ vm->msg_cb_ = dcpu16_msg_;
return vm;
}