From: Justin Wind Date: Tue, 22 May 2012 20:26:05 +0000 (-0700) Subject: expanded accounting-event coverage, rewrote cycle timing X-Git-Url: https://git.squeep.com/?a=commitdiff_plain;h=5ee7307cad8c222933e144787cb8b265646878df;p=dcpu16 expanded accounting-event coverage, rewrote cycle timing 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. --- diff --git a/Makefile b/Makefile index 4dcde61..1ecac46 100644 --- 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 diff --git a/common.c b/common.c index 5887c22..bf94ef7 100644 --- a/common.c +++ b/common.c @@ -7,6 +7,13 @@ #include #include #include +#include +#include + +#ifdef __MACH__ +#include +#include +#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) { diff --git a/common.h b/common.h index 02db4d7..09e1509 100644 --- a/common.h +++ b/common.h @@ -2,6 +2,7 @@ #define COMMON_H_QPRCB1BH #include +#include 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 */ diff --git a/dcpu16.c b/dcpu16.c index 817cfb0..e8e24d1 100644 --- 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<>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 breg[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; diff --git a/dcpu16.h b/dcpu16.h index d0b366a..94e70a3 100644 --- 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 *); diff --git a/vm-dcpu16.c b/vm-dcpu16.c index b479883..f7f4c15 100644 --- a/vm-dcpu16.c +++ b/vm-dcpu16.c @@ -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");