X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=dcpu16.c;h=e8e24d137c8f8a25b8bb62f810a6c9b9dd725ad1;hb=49be905f037fbd22b6ae0275efbab2ed95d4d9b7;hp=ea0ee261d7c02398e8d4c26caf9a2fd5720545d1;hpb=0a6b0889c67675bd71681ec41774d2ea57ce5335;p=dcpu16 diff --git a/dcpu16.c b/dcpu16.c index ea0ee26..e8e24d1 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 @@ -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); } } @@ -157,6 +158,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; + TRACE("%s>> starting cycle %llu", 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++) { + TRACE("%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,15 +193,19 @@ 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); + (void)pc; TRACE("%s>> is_a:%u pc:0x%04x sp:0x%04x value_data:0x%04x\n", __func__, value_is_a, @@ -188,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], @@ -197,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], @@ -208,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__, @@ -223,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; @@ -237,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)", @@ -246,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; @@ -258,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__, @@ -266,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__, @@ -274,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__, @@ -282,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; @@ -293,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; @@ -303,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)", @@ -328,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;\ - vm->cycle += 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_) @@ -351,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 */ @@ -370,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); - vm->cycle += 2; - ACCT_W(vm->reg[DCPU16_REG_SP] + 1); + dcpu16_cycle_inc(vm, 2); } OP_IMPL(nbi__reserved2_) { @@ -396,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"); @@ -413,66 +488,103 @@ 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); @@ -481,44 +593,50 @@ 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].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); 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); + + 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"); - vm->cycle += 9; + dcpu16_cycle_inc(vm, 9); } static const struct opcode_entry opcode_nbi_entries[] = { @@ -575,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, @@ -583,9 +701,9 @@ OP_IMPL(set) { */ *b = *a; - vm->cycle += 1; - - ACCT_W(ev_b_addr); + ACCT_W(b); + + dcpu16_cycle_inc(vm, 1); } OP_IMPL(add) { @@ -593,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); - 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) { @@ -609,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); - vm->cycle += 2; + ACCT_REG_W(DCPU16_REG_EX); - ACCT_W(ev_b_addr); + ACCT_W(b); + + dcpu16_cycle_inc(vm, 2); } OP_IMPL(mul) { @@ -625,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; - vm->cycle += 2; + ACCT_REG_W(DCPU16_REG_EX); + + ACCT_W(b); - ACCT_W(ev_b_addr); + dcpu16_cycle_inc(vm, 2); } OP_IMPL(mli) { @@ -641,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; - vm->cycle += 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; @@ -667,17 +793,19 @@ OP_IMPL(div) { vm->reg[DCPU16_REG_EX] = (*b << 16) / *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(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; @@ -687,17 +815,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; @@ -705,17 +834,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; @@ -723,51 +852,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) { @@ -775,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; - vm->cycle += 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) { @@ -793,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; - vm->cycle += 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) { @@ -811,152 +942,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) { @@ -964,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; @@ -974,9 +1108,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) { @@ -984,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; @@ -994,41 +1131,49 @@ 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_) { @@ -1229,24 +1374,11 @@ int dcpu16_interrupt(struct dcpu16 *vm, DCPU16_WORD 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); - } - } - instruction_decode_(vm->ram, vm->reg[DCPU16_REG_PC], &opcode, &b, &b_data, &a, &a_data, &instr_len); /* consume what we decoded */ @@ -1269,7 +1401,7 @@ void dcpu16_step(struct dcpu16 *vm) { TRACE("++ SKIPPED %x words", 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; } @@ -1282,78 +1414,92 @@ void dcpu16_step(struct dcpu16 *vm) { DCPU16_WORD message; message = interrupt_dequeue_(vm); + TRACE("%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("%s>> servicing interrupt IA:0x%04x message:0x%04x \n", __func__, 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("%s>> ignoring interrupt IA:0", __func__); } } } } -/* - 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"); + hw = malloc(sizeof *hw); + if (hw == NULL) { + vm->warn_cb_("%s():%s", "malloc", strerror(errno)); + return NULL; + } + hw->vm = vm; + hw->mod = mod; + + if (mod->data_init) { + if (mod->data_init(hw, data)) { + vm->warn_cb_("failed to init hw module data"); + free(hw); + return NULL; + } + } else { + hw->data = NULL; + } - 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"); + return hw; +} - dcpu16_disassemble_print(vm, vm->reg[DCPU16_REG_PC]); - printf("\n"); +/* destroy a 'hardware' device */ +void dcpu16_hw_del(struct dcpu16_hw **hw) { + if (hw) { + if (*hw) { + if ((*hw)->mod->data_free) { + (*hw)->mod->data_free(*hw); + } + free(*hw); + *hw = NULL; + } + } } -/* dcpu16_dump_ram - * print raw ram contents from start to stop +/* dcpu16_hw_ctl + * invokes per-module controls for hw device */ -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 */ - - if (!vm) return; - - 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" : ""); +int dcpu16_hw_ctl(struct dcpu16_hw *hw, const char *cmd, void *data_in, void *data_out) { + if (hw) { + 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; TRACE("%s>> name:%s ID:0x%04x%04x MFG:0x%04x%04x VER:0x%04x", __func__, - hw->name_, - hw->id_h, hw->id_l, - hw->mfg_l, hw->mfg_h, - hw->ver); + 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"); @@ -1383,13 +1529,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; @@ -1432,13 +1586,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); }