cleanup, simplified event callbacks, step now consumes branch-skipped instructions
authorJustin Wind <justin.wind@gmail.com>
Fri, 13 Apr 2012 21:31:30 +0000 (14:31 -0700)
committerJustin Wind <justin.wind@gmail.com>
Fri, 13 Apr 2012 21:31:30 +0000 (14:31 -0700)
Makefile
dcpu16.c
dcpu16.h
vm-dcpu16.c

index 1a931a1c8f709724d37f398aabfaea17c30c6534..a0745cfe2302f7493cb70b7938375ad874d625dc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,23 +1,30 @@
 #!make
 #
 PROGRAMS = as-dcpu16 vm-dcpu16
+SOURCES = dcpu16.c as-dcpu16.c vm-dcpu16.c
 
 CFLAGS = -g -Wall -Wextra -pedantic -std=c99
 LDFLAGS = -lreadline
 
-HEADERS = dcpu16.h
 
 all:   $(PROGRAMS)
 
-%.o:   %.c $(HEADERS)
+depend:        .depend
 
-vm-dcpu16: vm-dcpu16.o dcpu16.o
+.depend:       $(SOURCES)
+       @rm -f ./.depend
+       $(CC) $(CFLAGS) -MM $^ >> ./.depend
 
-as-dcpu16: as-dcpu16.o
+include .depend
+
+
+vm-dcpu16:     vm-dcpu16.o dcpu16.o
+
+as-dcpu16:     as-dcpu16.o
 
 dcpu16:        dcpu16.o
 
 clean: 
-       @rm -rf $(PROGRAMS) *.o *.dSYM
+       @rm -rf $(PROGRAMS) *.o *.dSYM .depend
 
 check: $(PROGRAMS)
index b21f0f9cda33298895f365c982ad7b09c1125871..e231e5f1bca8282945db90c41d2ac2e704631fb7 100644 (file)
--- a/dcpu16.c
+++ b/dcpu16.c
  *    2012 04 12 - added basic callback support for address accesses
  *
  *  TODO
+ *    change api to print into buffers rather than stdio
  *    drop checks for assigning to literals -- it won't affect anything anyhow
- *    debug short literal decoding
+ *    refactor opcode functiontables into switch statements
  */
 
 static const char * const src_id_ = "$Id$";
 
-#define WORD DCPU16_WORD
+#define OPCODE_BASIC_BITS   4
+#define OPCODE_OPERAND_BITS 6
 
 static const char regnames_[] = "ABCXYZIJ";
 
@@ -82,35 +84,6 @@ void dcpu16_trace_cb_set(void (*fn)(char *fmt, ...)) {
 }
 
 
-/*  dcpu16_acct_add
- *  Register callback fn to be triggered whenever event matching exactly mask_ev
- *  and additionally matching any of mask events occur.
- */
-int dcpu16_acct_add(struct dcpu16 *vm, dcpu16_acct_event_ match_all, dcpu16_acct_event_ match_any, void (*fn)(dcpu16_acct_event_, DCPU16_WORD)) {
-    struct dcpu16_acct_cb cb;
-
-    cb.match_all = match_all;
-    cb.match_any = match_any;
-    cb.fn = fn;
-
-    /* add to vm->cb_table_, vm->cb_table_entries_, vm->cb_table_allocated_ */
-    if (vm->cb_table_entries_ == vm->cb_table_allocated_) {
-        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));
-            return -1;
-        }
-        vm->cb_table_ = tmp_ptr;
-        vm->cb_table_allocated_ += 32;
-    }
-
-    memcpy(vm->cb_table_ + vm->cb_table_entries_, &cb, sizeof cb);
-    vm->cb_table_entries_++;
-
-    return 0;
-}
-
 /*  acct_event_
  *  invokes callbacks for specified event
  */
@@ -120,27 +93,26 @@ void acct_event_(struct dcpu16 *vm, dcpu16_acct_event_ ev, DCPU16_WORD addr) {
     size_t i;
 
     for (i = 0; i < vm->cb_table_entries_; i++) {
-        if ( (cb[i].match_all & ev) == cb[i].match_all    /* exact match on event flags */
-        &&   (cb[i].match_any & ev) ) {                /* any match on rest */
+        if ( (cb[i].mask & ev) )
             cb[i].fn(ev, addr);
-        }
     }
 }
 
+
 /*  value_decode_
  * sets *v to be the destination of the value
+ * advances d->pc if necessary
  * workv is buffer to use to accumulate literal value before use, one exists for either potential instruction operand
+ * e_addr is for accounting callback
  * returns true if destination points to literal (id est *v should ignore writes)
  */
 static
-unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v, dcpu16_acct_event_ *e, WORD *e_addr) {
-    WORD nextword;
+unsigned int value_decode_(struct dcpu16 *d, DCPU16_WORD value, DCPU16_WORD *work_v, DCPU16_WORD **v, DCPU16_WORD *e_addr) {
+    DCPU16_WORD nextword;
     unsigned int retval = 0;
 
     assert(value <= 0x3f);
 
-    *e = 0;
-
     /* does this value indicate a literal */
     if (value >= 0x1f)
         retval = 1;
@@ -165,7 +137,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v,
               regnames_[value&0x07],
               d->reg[value&0x07],
               **v);
-        *e |= DCPU16_ACCT_RAM;
         *e_addr = d->reg[(value & 0x07)];
 
     } else if (value <= 0x17) { /* [next word + register] */
@@ -177,7 +148,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v,
               nextword,
               d->reg[(value & 0x07)],
               **v);
-        *e |= DCPU16_ACCT_RAM;
         *e_addr = nextword + d->reg[(value & 0x07)];
 
     } else switch (value) {
@@ -186,7 +156,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v,
         TRACE(">>     POP [0x%04x] (0x%04x)",
               d->sp - 1,
               **v);
-        *e |= DCPU16_ACCT_RAM;
         *e_addr = d->sp - 1;
         break;
 
@@ -195,7 +164,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v,
         TRACE(">>     PEEK [0x%04x] (0x%04x)",
               d->sp,
               **v);
-        *e |= DCPU16_ACCT_RAM;
         *e_addr = d->sp;
         break;
 
@@ -204,7 +172,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v,
         TRACE(">>     PUSH [0x%04x] (0x%04x)",
               d->sp + 1,
               **v);
-        *e |= DCPU16_ACCT_RAM;
         *e_addr = d->sp + 1;
         break;
 
@@ -231,7 +198,6 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v,
         TRACE(">>     [nextword] [0x%04x] (0x%04x)",
               nextword,
               **v);
-        *e |= DCPU16_ACCT_RAM;
         *e_addr = nextword;
         break;
 
@@ -252,47 +218,37 @@ unsigned int value_decode(struct dcpu16 *d, WORD value, WORD *work_v, WORD **v,
     return retval;
 }
 
-#define OPCODE_BASIC_BITS (4)
-#define OPCODE_BASIC_SHIFT (0)
-
-#define OPCODE_NBI_BITS (6)
-#define OPCODE_NBI_SHIFT (4)
-
-#define OPCODE_FUTURE_BITS (16)
-#define OPCODE_FUTURE_SHIFT (10)
 
 #define OPCODE_NAME_LEN 16
 struct opcode_entry {
     unsigned short value;
     char name[OPCODE_NAME_LEN];
-    void (*impl)(struct dcpu16 *, WORD, WORD);
+    void (*impl)(struct dcpu16 *, DCPU16_WORD, DCPU16_WORD);
 };
 
 /* messy boilerplate for opcode handlers */
 
-#define OP_IMPL(x) static void op_##x(struct dcpu16 *d, WORD val_a, WORD val_b)
+#define OP_IMPL(x) static void op_##x(struct dcpu16 *d, DCPU16_WORD val_a, DCPU16_WORD val_b)
 
-#define OP_NBI_ (void)val_b, (void)b, (void)ev_b, (void)ev_b_addr
-#define OP_BASIC_ (void)value_decode(d, val_b, &d->reg_work_[0], &b, &ev_b, &ev_b_addr)
-#define OP_TYPE(op_type) WORD *a, *b;\
+#define OP_TYPE(op_type) DCPU16_WORD *a, *b;\
     unsigned int lit_a;\
-    dcpu16_acct_event_ ev_a = 0, ev_b = 0;\
-    WORD ev_a_addr = 0, ev_b_addr = 0;\
+    DCPU16_WORD ev_a_addr = 0, ev_b_addr = 0;\
     do {\
-        lit_a = value_decode(d, val_a, &d->reg_work_[0], &a, &ev_a, &ev_a_addr);\
+        lit_a = value_decode_(d, val_a, &d->reg_work_[0], &a, &ev_a_addr);\
         op_type;\
-        if (d->skip_) {\
-            TRACE("++ SKIPPED");\
-            d->skip_ = 0;\
-            return;\
-        }\
     } while (0)
+#define OP_NBI_ (void)val_b, (void)b, (void)ev_b_addr
+#define OP_BASIC_ (void)value_decode_(d, val_b, &d->reg_work_[0], &b, &ev_b_addr)
 #define OP_BASIC(x) OP_TYPE(OP_BASIC_)
 #define OP_NBI(x) OP_TYPE(OP_NBI_)
 
-/* accounting helpers */
-#define ACCT_R(ev) do { if (ev) { acct_event_(d, ev | DCPU16_ACCT_EV_READ, ev##_addr); } } while (0)
-#define ACCT_W(ev) do { if (ev) { acct_event_(d, ev | DCPU16_ACCT_EV_WRITE, ev##_addr); } } while (0)
+/*
+    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_(d, DCPU16_ACCT_EV_READ, addr); } while (0)
+#define ACCT_W(addr) do { acct_event_(d, DCPU16_ACCT_EV_WRITE, addr); } while (0)
+#define ACCT_ILL(addr) do { acct_event_(d, DCPU16_ACCT_EV_NOP, addr); } while (0)
 
 /* extended opcodes */
 
@@ -307,20 +263,24 @@ OP_IMPL(nbi__reserved_) {
     OP_NBI(nbi__reserved_);
     /* reserved for future expansion */
 
-    WORD future_opcode = (d->ram[d->pc] >> OPCODE_FUTURE_SHIFT);
+    DCPU16_WORD future_opcode = (d->ram[d->pc] >> (OPCODE_BASIC_BITS + OPCODE_OPERAND_BITS));
     WARN("reserved future opcode 0x%04x invoked", future_opcode);
+
+    ACCT_ILL(d->pc);
 }
 
 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);
+    ACCT_R(ev_a_addr);
 
     d->ram[ --d->sp ] = d->pc;
     d->pc = *a;
 
     d->cycle += 2;
+
+    ACCT_W(d->sp + 1);
 }
 
 OP_IMPL(nbi__reserved2_) {
@@ -328,6 +288,8 @@ OP_IMPL(nbi__reserved2_) {
     /* reserved */
 
     WARN("reserved nbi opcode invoked");
+
+    ACCT_ILL(d->pc);
 }
 
 static const struct opcode_entry opcode_nbi_entries[] = {
@@ -350,7 +312,7 @@ OP_IMPL(_nbi_) {
 
     /* don't do normal value decoding here */
 
-    WORD nbi_opcode = val_a;
+    DCPU16_WORD nbi_opcode = val_a;
     const struct opcode_entry *e = opcode_nbi_entries;
 
     e = opcode_nbi_entries + ( (nbi_opcode < OPCODE_NBI_MAX) ? nbi_opcode : (OPCODE_NBI_MAX - 1) );
@@ -365,8 +327,8 @@ OP_IMPL(set) {
     OP_BASIC(set);
     /* sets a to b */
 
-    ACCT_R(ev_b);
-    ACCT_W(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_W(ev_a_addr);
 
     /* only set non-literal target */
     if (!lit_a) {
@@ -381,8 +343,8 @@ OP_IMPL(add) {
     /* sets a to a+b, sets O to 0x0001 if there's an overflow, 0x0 otherwise */
     unsigned int acc = *a + *b;
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (!lit_a) {
         *a = acc;
@@ -391,7 +353,7 @@ OP_IMPL(add) {
 
     d->cycle += 2;
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 }
 
 OP_IMPL(sub) {
@@ -399,8 +361,8 @@ OP_IMPL(sub) {
     /* sets a to a-b, sets O to 0xffff if there's an underflow, 0x0 otherwise */
     unsigned int acc = *a - *b;
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (!lit_a) {
         *a = acc;
@@ -408,7 +370,7 @@ OP_IMPL(sub) {
     d->o = (acc > 0xffff);
     d->cycle += 2;
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 }
 
 OP_IMPL(mul) {
@@ -416,8 +378,8 @@ OP_IMPL(mul) {
     /* sets a to a*b, sets O to ((a*b)>>16)&0xffff */
     unsigned int acc = *a * *b;
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (!lit_a) {
         *a = acc;
@@ -425,15 +387,15 @@ OP_IMPL(mul) {
     d->o = acc >> 16;
     d->cycle += 2;
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 }
 
 OP_IMPL(div) {
     OP_BASIC(div);
     /* sets a to a/b, sets O to ((a<<16)/b)&0xffff. if b==0, sets a and O to 0 instead. */
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (*b == 0) {
         if (!lit_a) {
@@ -453,15 +415,15 @@ OP_IMPL(div) {
 
     d->cycle += 3;
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 }
 
 OP_IMPL(mod) {
     OP_BASIC(mod);
     /* sets a to a%b. if b==0, sets a to 0 instead. */
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (*b == 0) {
         if (!lit_a) {
@@ -475,7 +437,7 @@ OP_IMPL(mod) {
 
     d->cycle += 3;
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 }
 
 OP_IMPL(shl) {
@@ -483,8 +445,8 @@ OP_IMPL(shl) {
     /* sets a to a<<b, sets O to ((a<<b)>>16)&0xffff */
     unsigned int acc = *a << *b;
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (!lit_a) {
         *a = acc;
@@ -493,7 +455,7 @@ OP_IMPL(shl) {
 
     d->cycle += 2;
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 }
 
 OP_IMPL(shr) {
@@ -501,8 +463,8 @@ OP_IMPL(shr) {
     /* sets a to a>>b, sets O to ((a<<16)>>b)&0xffff */
     unsigned int acc = *a >> *b;
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (!lit_a) {
         *a = acc;
@@ -511,15 +473,15 @@ OP_IMPL(shr) {
 
     d->cycle += 2;
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 }
 
 OP_IMPL(and) {
     OP_BASIC(and);
     /* sets a to a&b */
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (!lit_a) {
         *a = *a & *b;
@@ -527,15 +489,15 @@ OP_IMPL(and) {
 
     d->cycle += 1;
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 }
 
 OP_IMPL(bor) {
     OP_BASIC(bor);
     /* sets a to a|b */
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (!lit_a) {
         *a = *a | *b;
@@ -543,21 +505,21 @@ OP_IMPL(bor) {
 
     d->cycle += 1;
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 }
 
 OP_IMPL(xor) {
     OP_BASIC(xor);
     /* sets a to a^b */
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (!lit_a) {
         *a = *a ^ *b;
     }
 
-    ACCT_W(ev_a);
+    ACCT_W(ev_a_addr);
 
     d->cycle += 1;
 }
@@ -566,8 +528,8 @@ OP_IMPL(ife) {
     OP_BASIC(ife);
     /* performs next instruction only if a==b */
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (*a == *b) {
         /* */
@@ -583,8 +545,8 @@ OP_IMPL(ifn) {
     OP_BASIC(ifn);
     /* performs next instruction only if a!=b */
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (*a != *b) {
         /* */
@@ -600,8 +562,8 @@ OP_IMPL(ifg) {
     OP_BASIC(ifg);
     /* performs next instruction only if a>b */
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if (*a > *b) {
         /* */
@@ -617,8 +579,8 @@ OP_IMPL(ifb) {
     OP_BASIC(ifb);
     /* performs next instruction only if (a&b)!=0 */
 
-    ACCT_R(ev_b);
-    ACCT_R(ev_a);
+    ACCT_R(ev_b_addr);
+    ACCT_R(ev_a_addr);
 
     if ((*a & *b) != 0) {
         /* */
@@ -651,7 +613,7 @@ static const struct opcode_entry opcode_basic_entries[] = {
 };
 
 static inline
-void dump_operand_value_(WORD value, WORD nextword) {
+void dump_operand_value_(DCPU16_WORD value, DCPU16_WORD nextword) {
     if (value <= 0x07) {
         printf(" %c", regnames_[value]);
     } else if (value <= 0x0f) {
@@ -671,36 +633,37 @@ void dump_operand_value_(WORD value, WORD nextword) {
     }
 }
 
+
 /* 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) {
+void instruction_decode_(struct dcpu16 *d, DCPU16_WORD addr, DCPU16_WORD *opcode, DCPU16_WORD *a, DCPU16_WORD *b, DCPU16_WORD *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) )
+    *a = (d->ram[addr] >> OPCODE_BASIC_BITS) & ((1 << OPCODE_OPERAND_BITS) - 1);
+    *b = (d->ram[addr] >> (OPCODE_BASIC_BITS + OPCODE_OPERAND_BITS)) & ((1 << OPCODE_OPERAND_BITS) - 1);
+    if (instr_len) {
+        *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,
+    print the words of the instruction at addr, followed by its assembly representation
+    returns the length of the instruction in words
  */
-WORD dcpu16_disassemble_print(struct dcpu16 *d, WORD addr) {
-    WORD opcode, a, b;
-    unsigned int instr_len, i;
+DCPU16_WORD dcpu16_disassemble_print(struct dcpu16 *d, DCPU16_WORD addr) {
+    DCPU16_WORD opcode, a, b, instr_len, i;
     const struct opcode_entry *e;
     unsigned int indent = 0;
     unsigned int partial = 0;
 
+    if (!d) return 0;
+
     /*
         Check the previous instruction, to see if this one should be
         indented.  This check isn't foolproof, as preceeding addresses
@@ -753,31 +716,52 @@ WORD dcpu16_disassemble_print(struct dcpu16 *d, WORD addr) {
     return instr_len;
 }
 
+/* execute the next instruction */
 void dcpu16_step(struct dcpu16 *d) {
-    WORD opcode;
-    WORD val_a, val_b;
+    DCPU16_WORD opcode, a, b, instr_len;
     const struct opcode_entry *e;
 
-    /* decode opcode and invoke */
+    if (!d) return;
 
-    opcode = (d->ram[ d->pc ] >> OPCODE_BASIC_SHIFT) & ((1 << OPCODE_BASIC_BITS) - 1);
-    val_a = (d->ram[d->pc] >> (OPCODE_BASIC_SHIFT + OPCODE_BASIC_BITS)) & ((1 << 6) - 1);
-    val_b = (d->ram[d->pc] >> (OPCODE_BASIC_SHIFT + OPCODE_BASIC_BITS + 6)) & ((1 << 6) - 1);
+    /*
+        PC is advanced while decoding the operands by the opcode functions.
+        Things like this could be organized a little better..
+    */
+    instruction_decode_(d, d->pc, &opcode, &a, &b, NULL);
 
-    d->pc++;
+    d->pc++; /* all instructions take at least one word */
 
     for (e = opcode_basic_entries; e->impl; e++) {
         if (e->value == opcode) {
-            TRACE(">> %s 0x%04x, 0x%04x", e->name, val_a, val_b);
-            e->impl(d, val_a, val_b);
+            TRACE(">> %s 0x%04x, 0x%04x", e->name, a, b);
+            e->impl(d, a, b);
             break;
         }
     }
+
+    /* and jump over next instr if needed */
+    if (d->skip_) {
+        instruction_decode_(d, d->pc, &opcode, &a, &b, &instr_len);
+        d->pc += instr_len;
+        d->skip_ = 0;
+        TRACE("++ SKIPPED %x words", instr_len);
+    }
 }
 
+/*
+    print the current state of the machine
+    shows current cycle count, registers, and next instruction
+*/
 void dcpu16_state_print(struct dcpu16 *d) {
     unsigned int i;
 
+    if (!d) return;
+
+    printf("  ");
+    for (i = 0; i < 8; i++)
+        printf("  %c:0x%04x", regnames_[i], d->reg[i]);
+    printf("\n");
+
     printf("(0x%08llx) %2s:0x%04x %2s:0x%04x %2s:0x%04x [%2s]:",
            d->cycle,
            "O", d->o,
@@ -786,20 +770,18 @@ void dcpu16_state_print(struct dcpu16 *d) {
            "PC");
 
     dcpu16_disassemble_print(d, d->pc);
-    printf("\n  ");
-
-    for (i = 0; i < 8; i++)
-        printf("  %c:0x%04x", regnames_[i], d->reg[i]);
     printf("\n");
 }
 
 /*  dcpu16_dump_ram
  *  print raw ram contents from start to stop
  */
-void dcpu16_dump_ram(struct dcpu16 *d, WORD start, WORD end) {
+void dcpu16_dump_ram(struct dcpu16 *d, DCPU16_WORD start, DCPU16_WORD end) {
     unsigned int i, j;
     const unsigned int n = 8; /* words per line */
 
+    if (!d) return;
+
     for (i = start, j = 0; i <= end; i++, j++) {
         if (j % n == 0)
             printf("0x%04x:\t", i);
@@ -809,10 +791,39 @@ void dcpu16_dump_ram(struct dcpu16 *d, WORD start, WORD end) {
         printf("\n");
 }
 
+/*  dcpu16_acct_add
+ *  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, void (*fn)(dcpu16_acct_event_, DCPU16_WORD)) {
+    struct dcpu16_acct_cb cb;
+
+    cb.mask = mask;
+    cb.fn = fn;
+
+    if (vm->cb_table_entries_ == vm->cb_table_allocated_) {
+        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));
+            return -1;
+        }
+        vm->cb_table_ = tmp_ptr;
+        vm->cb_table_allocated_ += 32;
+    }
+
+    memcpy(vm->cb_table_ + vm->cb_table_entries_, &cb, sizeof cb);
+    vm->cb_table_entries_++;
+
+    return 0;
+}
+
 /*  dcpu16_reset
  *  resets a dcpu16 instance to initial state
  */
 void dcpu16_reset(struct dcpu16 *d) {
+    if (!d) return;
+
     memset(d, 0, sizeof *d);
 }
 
@@ -833,6 +844,8 @@ struct dcpu16 *dcpu16_new(void) {
  *  release a dcpu16 instance
  */
 void dcpu16_delete(struct dcpu16 **vm) {
+    if (!vm || !*vm) return;
+
     free(*vm);
     *vm = NULL;
 }
index a96bd417ba1d8760a64be1817770ec452b68ebaa..005aad3a858fbe656adfd8bc9df92841c7f26696 100644 (file)
--- a/dcpu16.h
+++ b/dcpu16.h
@@ -11,12 +11,11 @@ typedef unsigned short DCPU16_WORD;
 typedef unsigned int dcpu16_acct_event_;
 #define DCPU16_ACCT_EV_READ     (1<<1)
 #define DCPU16_ACCT_EV_WRITE    (1<<2)
-#define DCPU16_ACCT_RAM         (1<<3)
+#define DCPU16_ACCT_EV_NOP      (1<<3)
 
 struct dcpu16_acct_cb {
     void (*fn)(dcpu16_acct_event_ e, DCPU16_WORD addr);
-    dcpu16_acct_event_ match_all;
-    dcpu16_acct_event_ match_any;
+    dcpu16_acct_event_ mask;
 };
 
 /* a self-contained dcpu16 core */
@@ -50,7 +49,7 @@ void dcpu16_dump_ram(struct dcpu16 *, DCPU16_WORD, DCPU16_WORD);
 DCPU16_WORD dcpu16_disassemble_print(struct dcpu16 *, DCPU16_WORD);
 
 /* register a callback for an accounting event */
-int dcpu16_acct_add(struct dcpu16 *, dcpu16_acct_event_ match_all, dcpu16_acct_event_ match_any, void (*fn)(dcpu16_acct_event_, DCPU16_WORD));
+int dcpu16_acct_add(struct dcpu16 *, dcpu16_acct_event_ mask, void (*fn)(dcpu16_acct_event_, DCPU16_WORD));
 
 /* execute the next instruction */
 void dcpu16_step(struct dcpu16 *);
index 17effb6a558db14d11698cfceaf56d452c202252..df86455070e7c91b008456579eeb2360b0425959 100644 (file)
@@ -43,7 +43,8 @@ void sigint_handler_(int sig) {
 
 #define VERBOSE_PRINTF(...) do { if (opt_.verbose) printf(__VA_ARGS__); } while (0)
 
-static void usage_(char *prog, unsigned int full) {
+static
+void usage_(char *prog, unsigned int full) {
     FILE *f = full ? stdout : stderr;
     char *x = strrchr(prog, '/');
 
@@ -130,13 +131,17 @@ int buf_tok_vect_(char ***v, int *c, char *buf) {
     return 0;
 }
 
-/* resets the instance and loads an image into ram starting at addr */
+/*
+    resets the vm if addr is zero then
+    loads an image from filename into ram starting at addr
+*/
 static
 int file_load_(struct dcpu16 *vm, char *filename, DCPU16_WORD addr) {
     FILE *f;
     size_t r;
 
-    dcpu16_reset(vm);
+    if (!addr)
+        dcpu16_reset(vm);
 
     f = fopen(filename, "rb");
     if (f == NULL) {
@@ -196,6 +201,21 @@ COMMAND_HELP(quit) {
 }
 
 
+COMMAND_IMPL(reset) {
+    (void)arg_count, (void)arg_vector;
+
+    dcpu16_reset(vm);
+    printf("initialized\n");
+    return 0;
+}
+COMMAND_HELP(reset) {
+    fprintf(f, "\treset\n");
+    if (summary) return;
+
+    fprintf(f, "Clears and reinitializes emulator.\n");
+}
+
+
 COMMAND_IMPL(load) {
     int addr = 0;
 
@@ -379,6 +399,7 @@ static struct command_ command_table_[] = {
     COMMAND_ENTRY(disassemble, 0, 2),
     COMMAND_ENTRY(step, 0, 1),
     COMMAND_ENTRY(run, 0, 0),
+    COMMAND_ENTRY(reset, 0, 0),
     { NULL, 0, 0, NULL, NULL }
 };