expanded accounting-event coverage, rewrote cycle timing
authorJustin Wind <justin.wind@gmail.com>
Tue, 22 May 2012 20:26:05 +0000 (13:26 -0700)
committerJustin Wind <justin.wind@gmail.com>
Wed, 23 May 2012 20:09:20 +0000 (13:09 -0700)
Registering an accounting hook now requires a range of addresses of interest.
Accounting events now cover register accesses, indexed as address.

Cycle timing now uses all struct timespec.  This introduced another portability conditional between os x and posix.

Makefile
common.c
common.h
dcpu16.c
dcpu16.h
vm-dcpu16.c

index 4dcde613241b5595f8829ebf4fe6f0e34138e8c8..1ecac46d40f73f94e96b87c3c86e1bea893befdc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,8 @@ ifeq ($(UNAME),Linux)
 # linux needs _GNU_SOURCE for fopencookie
 # linux needs _XOPEN_SOURCE=600 (provided by _GNU_SOURCE) for getopt and strdup
 CPPFLAGS += -DHAVE_FOPENCOOKIE -D_GNU_SOURCE
+# linux needs librt for clock_gettime
+LDFLAGS += -lrt
 endif
 
 CPPFLAGS += -DHAVE_LIBVNCSERVER -DHAVE_LIBPNG
index 5887c224815c43c4daadaa1eae0ce2656bb2b88e..bf94ef7c98341ea198a0618d847c9f79fde0c172 100644 (file)
--- a/common.c
+++ b/common.c
@@ -7,6 +7,13 @@
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
+#include <time.h>
+#include <sys/time.h>
+
+#ifdef __MACH__
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif /* __MACH__ */
 
 #include "common.h"
 #include "dcpu16.h"
@@ -58,6 +65,17 @@ struct dynamic_array *dynarray_new(size_t entry_size, size_t grow_size) {
     return da;
 }
 
+void dynarray_empty(struct dynamic_array *da, void (*free_element)(void *)) {
+    while ( da->entries-- ) {
+        void *element = (void *)DYNARRAY_ITEM(*da, da->entries);
+
+        free_element(element);
+    }
+    free(da->a);
+    da->a = NULL;
+    da->allocated = 0;
+}
+
 /* copy item onto end of array */
 void *dynarray_add(struct dynamic_array *da, void *item) {
     void *dst;
@@ -205,6 +223,55 @@ char *strqtok_r(char *str, const char *sep, int esc, const char *quote, char **l
     return tok;
 }
 
+/* like gettimeofday, except with nanoseconds */
+inline
+int gettimespecofday(struct timespec *ts) {
+    int retval = 0;
+#ifdef __MACH__
+    clock_serv_t cclock;
+    mach_timespec_t mts;
+
+    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+    clock_get_time(cclock, &mts);
+    mach_port_deallocate(mach_task_self(), cclock);
+    ts->tv_sec = mts.tv_sec;
+    ts->tv_nsec = mts.tv_nsec;
+#else /* __MACH__ */
+    retval = clock_gettime(CLOCK_REALTIME, ts)
+#endif /* __MACH__ */
+
+    return retval;
+}
+
+inline
+int timespec_add(struct timespec *result, const struct timespec *x) {
+    result->tv_sec += x->tv_sec;
+    result->tv_nsec += x->tv_nsec;
+
+    result->tv_sec += result->tv_nsec / 1000000000;
+    result->tv_nsec %= 1000000000;
+
+    return 0;
+}
+
+inline
+int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y) {
+    if (x->tv_nsec < y->tv_nsec) {
+        int z = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
+        y->tv_nsec -= 1000000000 * z;
+        y->tv_sec += z;
+    }
+    if (x->tv_nsec - y->tv_nsec > 1000000000) {
+        int z = (x->tv_nsec - y->tv_nsec) / 1000000000;
+        y->tv_nsec += 1000000000 * z;
+        y->tv_sec -= z;
+    }
+    result->tv_sec = x->tv_sec - y->tv_sec;
+    result->tv_nsec = x->tv_nsec - y->tv_nsec;
+
+    return x->tv_sec < y->tv_sec;
+}
+
 int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) {
   /* Perform the carry for the later subtraction by updating y. */
   if (x->tv_usec < y->tv_usec) {
index 02db4d77fdc131f63166d63d9cdb5d0ecca7d73c..09e1509c96eec5eab8961163dd70cecf8596c039 100644 (file)
--- a/common.h
+++ b/common.h
@@ -2,6 +2,7 @@
 #define COMMON_H_QPRCB1BH
 
 #include <stdlib.h>
+#include <time.h>
 
 struct dynamic_array {
     size_t entry_size;
@@ -16,11 +17,14 @@ struct dynamic_array {
 int dynarray_init(struct dynamic_array *da, size_t entry_size, size_t grow_size);
 struct dynamic_array *dynarray_new(size_t entry_size, size_t grow_size);
 void *dynarray_add(struct dynamic_array *da, void *item);
+void dynarray_empty(struct dynamic_array *da, void (*free_element)(void *));
 
 int str_to_word(char *s);
 
 char *strqtok_r(char *str, const char *sep, int esc, const char *quote, char **lastq, char **lasts);
 
-int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y);
+int gettimespecofday(struct timespec *ts);
+int timespec_add(struct timespec *result, const struct timespec *x);
+int timespec_subtract(struct timespec *result, struct timespec *x, struct timespec *y);
 
 #endif /* COMMON_H_QPRCB1BH */
index 817cfb0da6c54d6490f4d32fda344526d152ed1f..e8e24d137c8f8a25b8bb62f810a6c9b9dd725ad1 100644 (file)
--- a/dcpu16.c
+++ b/dcpu16.c
@@ -120,7 +120,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);
     }
 }
 
@@ -192,15 +193,19 @@ void dcpu16_cycle_inc(struct dcpu16 *vm, unsigned int n) {
  * 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_SP] + *sp_adjust);
 
+    (void)pc;
     TRACE("%s>> is_a:%u pc:0x%04x sp:0x%04x value_data:0x%04x\n", 
           __func__,
           value_is_a,
@@ -209,7 +214,9 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
           value_data);
 
     if (value <= 0x07) { /* register */
-        *v = vm->reg + value;
+        *e_what = EWHAT_REG;
+        *e_reg = value & 0x07;
+        *v = vm->reg + *e_reg;
         TRACE("%s>>     %s (0x%04x)",
               __func__,
               dcpu16_reg_names[value],
@@ -218,8 +225,10 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
     }
 
     if (value <= 0x0f) { /* [register] */
-        *v = &(vm->ram[ vm->reg[value & 0x07] ]);
+        *e_what = EWHAT_RAM;
         *e_addr = vm->reg[value & 0x07];
+        *v = &(vm->ram[ *e_addr ]);
+        acct_event_(vm, DCPU16_ACCT_EV_REG_READ, value & 0x07);
         TRACE("%s>>     [%s] [0x%04x] (0x%04x)",
               __func__,
               dcpu16_reg_names[value & 0x07],
@@ -229,9 +238,12 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
     }
 
     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)",
               __func__,
@@ -244,6 +256,9 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
 
     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;
@@ -258,6 +273,8 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
         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)",
@@ -267,6 +284,8 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
         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;
@@ -279,6 +298,8 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
         break;
 
         case 0x1b: /* SP */
+        *e_reg = DCPU16_REG_SP;
+        *e_what = EWHAT_REG;
         *v = &(vm->reg[DCPU16_REG_SP]);
         TRACE("%s>>     %s (0x%04x)",
               __func__,
@@ -287,6 +308,8 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
         break;
 
         case 0x1c: /* PC */
+        *e_reg = DCPU16_REG_PC;
+        *e_what = EWHAT_REG;
         *v = &(vm->reg[DCPU16_REG_PC]);
         TRACE("%s>>     %s (0x%04x)",
               __func__,
@@ -295,6 +318,8 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
         break;
 
         case 0x1d: /* EX */
+        *e_reg = DCPU16_REG_EX;
+        *e_what = EWHAT_REG;
         *v = &(vm->reg[DCPU16_REG_EX]);
         TRACE("%s>>     %s (0x%04x)",
               __func__,
@@ -303,6 +328,8 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
         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;
@@ -314,6 +341,8 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
         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;
@@ -324,6 +353,7 @@ void value_decode_(struct dcpu16 *vm, DCPU16_WORD value, unsigned int value_is_a
         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)",
@@ -349,19 +379,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;\
         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_)
@@ -372,9 +404,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 */
 
@@ -391,23 +434,31 @@ 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);
 
     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);
 
-    dcpu16_cycle_inc(vm, 2);
 
-    ACCT_W(vm->reg[DCPU16_REG_SP] + 1);
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(nbi__reserved2_) {
@@ -417,13 +468,16 @@ OP_IMPL(nbi__reserved2_) {
     WARN("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");
@@ -434,10 +488,25 @@ 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);
     }
 
     dcpu16_cycle_inc(vm, 4);
@@ -446,30 +515,45 @@ OP_IMPL(nbi_int) {
 OP_IMPL(nbi_iag) {
     OP_NBI(nbi_iag);
 
+    ACCT_REG_R(DCPU16_REG_IA);
     *a = vm->reg[DCPU16_REG_IA];
 
-    dcpu16_cycle_inc(vm, 1);
+    ACCT_W(a);
 
-    ACCT_W(ev_a_addr);
+    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);
 
     dcpu16_cycle_inc(vm, 1);
-
-    ACCT_R(ev_a_addr);
 }
 
 /* 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);
 }
@@ -477,6 +561,8 @@ OP_IMPL(nbi_rfi) {
 OP_IMPL(nbi_iaq) {
     OP_NBI(nbi_iaq);
 
+    ACCT_R(a);
+
     if (*a) {
         vm->interrupts_deferred_ = 1;
     } else {
@@ -484,16 +570,13 @@ OP_IMPL(nbi_iaq) {
     }
 
     dcpu16_cycle_inc(vm, 2);
-
-    ACCT_R(ev_a_addr);
 }
 
 OP_IMPL(nbi_hwn) {
     OP_NBI(nbi_hwn);
 
-    ACCT_W(ev_a_addr);
-
     *a = vm->hw_table_entries_;
+    ACCT_W(a);
 
     dcpu16_cycle_inc(vm, 2);
 }
@@ -501,7 +584,7 @@ OP_IMPL(nbi_hwn) {
 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);
@@ -510,14 +593,19 @@ OP_IMPL(nbi_hwq) {
         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].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;
+    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);
 
     dcpu16_cycle_inc(vm, 4);
 }
@@ -525,24 +613,25 @@ OP_IMPL(nbi_hwq) {
 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);
         return;
     }
 
-    dcpu16_cycle_inc(vm, 4);
     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);
+
+    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");
@@ -604,7 +693,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,
@@ -612,9 +701,9 @@ OP_IMPL(set) {
      */
     *b = *a;
 
+    ACCT_W(b);
+    
     dcpu16_cycle_inc(vm, 1);
-
-    ACCT_W(ev_b_addr);
 }
 
 OP_IMPL(add) {
@@ -622,15 +711,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);
 
-    dcpu16_cycle_inc(vm, 2);
+    ACCT_REG_W(DCPU16_REG_EX);
 
-    ACCT_W(ev_b_addr);
+    ACCT_W(b);
+
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(sub) {
@@ -638,15 +729,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);
 
-    dcpu16_cycle_inc(vm, 2);
+    ACCT_REG_W(DCPU16_REG_EX);
 
-    ACCT_W(ev_b_addr);
+    ACCT_W(b);
+
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(mul) {
@@ -654,15 +747,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;
 
-    dcpu16_cycle_inc(vm, 2);
+    ACCT_REG_W(DCPU16_REG_EX);
+
+    ACCT_W(b);
 
-    ACCT_W(ev_b_addr);
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(mli) {
@@ -670,23 +765,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;
 
-    dcpu16_cycle_inc(vm, 2);
+    ACCT_REG_W(DCPU16_REG_EX);
 
-    ACCT_W(ev_b_addr);
+    ACCT_W(b);
+
+    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;
@@ -696,17 +793,19 @@ OP_IMPL(div) {
         vm->reg[DCPU16_REG_EX] = (*b << 16) / *a;
     }
 
-    dcpu16_cycle_inc(vm, 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;
@@ -716,17 +815,18 @@ OP_IMPL(dvi) {
         vm->reg[DCPU16_REG_EX] = (short)(*b << 16) / (short)*a;
     }
 
-    dcpu16_cycle_inc(vm, 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;
@@ -734,17 +834,17 @@ OP_IMPL(mod) {
         *b = *b % *a;
     }
 
-    dcpu16_cycle_inc(vm, 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;
@@ -752,51 +852,51 @@ OP_IMPL(mdi) {
         *b = (short)*b % (short)*a;
     }
 
-    dcpu16_cycle_inc(vm, 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;
 
-    dcpu16_cycle_inc(vm, 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;
 
-    dcpu16_cycle_inc(vm, 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;
 
     dcpu16_cycle_inc(vm, 1);
 
-    ACCT_W(ev_b_addr);
+    ACCT_W(b);
 }
 
 OP_IMPL(shr) {
@@ -804,17 +904,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;
 
-    dcpu16_cycle_inc(vm, 2);
-
     WARN("IMPLEMENT");
 
-    ACCT_W(ev_b_addr);
+    ACCT_REG_W(DCPU16_REG_EX);
+    ACCT_W(b);
+
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(asr) {
@@ -822,17 +923,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;
 
-    dcpu16_cycle_inc(vm, 2);
-
     WARN("IMPLEMENT");
 
-    ACCT_W(ev_b_addr);
+    ACCT_REG_W(DCPU16_REG_EX);
+    ACCT_W(b);
+
+    dcpu16_cycle_inc(vm, 2);
 }
 
 OP_IMPL(shl) {
@@ -840,24 +942,25 @@ OP_IMPL(shl) {
     /* sets b to b<<a, 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;
 
-    dcpu16_cycle_inc(vm, 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) {
         /* */
@@ -873,8 +976,8 @@ 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) {
         /* */
@@ -890,8 +993,8 @@ 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) {
         /* */
@@ -907,8 +1010,8 @@ 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) {
         /* */
@@ -924,8 +1027,8 @@ 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) {
         /* */
@@ -941,8 +1044,8 @@ 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) {
         /* */
@@ -958,8 +1061,8 @@ OP_IMPL(ifl) {
     OP_BASIC(ifl);
     /* 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) {
         /* */
@@ -975,8 +1078,8 @@ OP_IMPL(ifu) {
     OP_BASIC(ifu);
     /* 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) {
         /* */
@@ -993,8 +1096,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;
@@ -1003,9 +1108,10 @@ OP_IMPL(adx) {
     else
         vm->reg[DCPU16_REG_EX] = 0x0000;
 
-    dcpu16_cycle_inc(vm, 3);
+    ACCT_REG_W(DCPU16_REG_EX);
+    ACCT_W(b);
 
-    ACCT_W(ev_b_addr);
+    dcpu16_cycle_inc(vm, 3);
 }
 
 OP_IMPL(sbx) {
@@ -1013,8 +1119,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;
@@ -1023,41 +1131,49 @@ OP_IMPL(sbx) {
     else
         vm->reg[DCPU16_REG_EX] = 0;
 
-    dcpu16_cycle_inc(vm, 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;
 
-    dcpu16_cycle_inc(vm, 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(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;
 
-    dcpu16_cycle_inc(vm, 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(_reserved_) {
@@ -1413,13 +1529,21 @@ int dcpu16_hw_attach(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;
 
index d0b366ac6d1a7e223eb357d7da6acf4012e4ff83..94e70a3fc02cf901c064ab622ecb2a57a561553e 100644 (file)
--- a/dcpu16.h
+++ b/dcpu16.h
@@ -59,12 +59,16 @@ typedef void (dcpu16_ev_cb_t)(struct dcpu16 *, dcpu16_acct_event, DCPU16_WORD, v
 #define DCPU16_ACCT_EV_CYCLE    (1<<1)
 #define DCPU16_ACCT_EV_READ     (1<<2)
 #define DCPU16_ACCT_EV_WRITE    (1<<3)
-#define DCPU16_ACCT_EV_NOP      (1<<4)
-#define DCPU16_ACCT_EV_RESET    (1<<5)
+#define DCPU16_ACCT_EV_REG_READ (1<<4)
+#define DCPU16_ACCT_EV_REG_WRITE (1<<5)
+#define DCPU16_ACCT_EV_NOP      (1<<6)
+#define DCPU16_ACCT_EV_RESET    (1<<7)
 struct dcpu16_acct_cb {
-    dcpu16_ev_cb_t *fn;
-    void *data;
-    dcpu16_acct_event mask;
+    dcpu16_ev_cb_t *fn; /* call this */
+    void *data;         /* also mention this */
+    dcpu16_acct_event mask; /* when (mask & event) is true and */
+    DCPU16_WORD addr_l, /* addr is this or higher and */
+                addr_h; /* addr is this or lower */
 };
 
 typedef void (dcpu16_hw_signal_t)(struct dcpu16 *, struct dcpu16_hw *);
@@ -128,7 +132,7 @@ int dcpu16_hw_ctl(struct dcpu16_hw *, const char *, void *, void *);
 int dcpu16_hw_attach(struct dcpu16 *, struct dcpu16_hw *);
 
 /* register a callback for an accounting event */
-int dcpu16_acct_add(struct dcpu16 *, dcpu16_acct_event, dcpu16_ev_cb_t *, void *);
+int dcpu16_acct_add(struct dcpu16 *, dcpu16_acct_event, dcpu16_ev_cb_t *, DCPU16_WORD, DCPU16_WORD, void *);
 
 /* execute the next instruction */
 void dcpu16_step(struct dcpu16 *);
index b4798838328aeae8e7d9698c9af64c25b79014a3..f7f4c156f7e9d2b443c7c64ec507fbb85c9f0c70 100644 (file)
@@ -228,6 +228,9 @@ struct rfb_instance_ *rfbScreen_next_available_display_(struct dynamic_array *rf
         return NULL;
     }
 
+    new_instance.screen->port += rfbScreens->entries;
+    new_instance.screen->ipv6port += rfbScreens->entries;
+
     new_instance.attached_display = NULL;
     new_instance.attached_keyboard = NULL;
     s = dynarray_add(rfbScreens, &new_instance);
@@ -496,20 +499,21 @@ COMMAND_HELP(set) {
     fprintf(f, "Sets addr to value.");
 }
 
-#define MICROSECONDS_PER_CYCLE 10
+#define NANOSECONDS_PER_CYCLE 10000
+#define MIN_NANOSLEEP 31000
 COMMAND_IMPL(run) {
     struct sigaction act;
-    struct timeval run_start_tv, run_stop_tv;
-    long long run_cycle_start;
-    struct timeval start_tv, now_tv, diff_tv;
+    long long run_cycle_start, run_cycle_end;
     long long cycle_start, cycles_to_wait;
-    struct timespec sleep_time, rem_time;
-    long long run_usec;
+
+    struct timespec ts_run_start, ts_run_end, ts_run_diff;
+    struct timespec ts_cycle_start, ts_cycle_end_target, ts_cycle_end, ts_cycle_waste, ts_cycle_rem;
+    const struct timespec ts_cycle_time = { .tv_sec = 0, .tv_nsec = NANOSECONDS_PER_CYCLE };
 
     (void)arg_count, (void)arg_vector;
 
     running_ = 1;
-    gettimeofday(&run_start_tv, NULL);
+    gettimespecofday(&ts_run_start);
     run_cycle_start = vm->cycle_;
 
     memset(&act, 0, sizeof act);
@@ -522,7 +526,9 @@ COMMAND_IMPL(run) {
     }
 
     while (running_) {
-        gettimeofday(&start_tv, NULL);
+        gettimespecofday(&ts_cycle_start);
+        ts_cycle_end_target = ts_cycle_start;
+
         cycle_start = vm->cycle_;
 
         dcpu16_step(vm);
@@ -536,37 +542,44 @@ COMMAND_IMPL(run) {
         /* how many cycles did this instr use? */
         cycles_to_wait = vm->cycle_ - cycle_start;
 
-        if (cycles_to_wait == 0)
-            continue;
-
-        /* each cycle wants 10 microseconds */
+        /* each cycle wants to take 10 microseconds */
+        while (cycles_to_wait--)
+            timespec_add(&ts_cycle_end_target, &ts_cycle_time);
 
         /* how much of that did we spend already */
-        gettimeofday(&now_tv, NULL);
-        timeval_subtract(&diff_tv, &now_tv, &start_tv);
-        /* do we have time to kill? */
-        if (cycles_to_wait * MICROSECONDS_PER_CYCLE > diff_tv.tv_usec) {
-            sleep_time.tv_sec = diff_tv.tv_sec;
-            /* this is not accurate.. */
-            sleep_time.tv_nsec = 250 * ( (cycles_to_wait * MICROSECONDS_PER_CYCLE) - diff_tv.tv_usec);
+        gettimespecofday(&ts_cycle_end);
 
+        /* do we have time to kill? */
+        if (timespec_subtract(&ts_cycle_waste, &ts_cycle_end_target, &ts_cycle_end) == 0) {
             /* nanosleep doesn't interfere with libvncserver, unlike usleep */
-            while ( nanosleep(&sleep_time, &rem_time) ) {
-                sleep_time = rem_time;
-                fprintf(stderr, "rem:%ld %ld\n", rem_time.tv_sec, rem_time.tv_nsec);
-            }
+            if (ts_cycle_waste.tv_sec == 0 && ts_cycle_waste.tv_nsec >= MIN_NANOSLEEP)
+                while ( nanosleep(&ts_cycle_waste, &ts_cycle_rem) )
+                    ts_cycle_waste = ts_cycle_rem;
+        } else {
+            /* negative, we've already blown our time */
+#if 0
+            fprintf(stderr, "cycle time overrun %ld.%09lds\n", ts_cycle_waste.tv_sec, ts_cycle_waste.tv_nsec);
+#endif
         }
+
+#if 0
+        /* how did we do */
+        gettimespecofday(&ts_cycle_end);
+        timespec_subtract(&ts_cycle_rem, &ts_cycle_end_target, &ts_cycle_end);
+        fprintf(stderr, "projected end: %ld.%09ld  actual end: %ld.%09ld  diff: %ld.%09ld\n",
+                ts_cycle_end_target.tv_sec, ts_cycle_end_target.tv_nsec,
+                ts_cycle_end.tv_sec, ts_cycle_end.tv_nsec,
+                ts_cycle_rem.tv_sec, ts_cycle_rem.tv_nsec);
+#endif
+
     }
 
-    gettimeofday(&run_stop_tv, NULL);
-    timeval_subtract(&diff_tv, &run_stop_tv, &run_start_tv);
-    run_usec = diff_tv.tv_sec * 1000000;
-    run_usec += diff_tv.tv_usec;
-    fprintf(stderr, "ran %llu cycles in %lds %dus (%lldus)\n",
-            vm->cycle_ - run_cycle_start,
-            diff_tv.tv_sec,
-            diff_tv.tv_usec,
-            run_usec);
+    run_cycle_end = vm->cycle_;
+    gettimespecofday(&ts_run_end);
+    timespec_subtract(&ts_run_diff, &ts_run_end, &ts_run_start);
+    fprintf(stderr, "ran %lld cycles in %ld.%09lds\n",
+            run_cycle_end - run_cycle_start,
+            ts_run_diff.tv_sec, ts_run_diff.tv_nsec);
 
     printf("interrupted...\n");