X-Git-Url: http://git.squeep.com/?p=dcpu16;a=blobdiff_plain;f=dcpu16.c;h=ac052d59887a148f62f5195db9ac8c2c08557063;hp=616237de3d99d7bc2628cd405ea6f8ee65c2fad1;hb=ce296c260b229bb5c2e866db7842f3a46ea8c4b7;hpb=ca03eaaf8fc937a38221cb724857276ece6fd816 diff --git a/dcpu16.c b/dcpu16.c index 616237d..ac052d5 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 @@ -157,6 +157,26 @@ 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].name_); + vm->hw_table_[i].cycle(vm, vm->hw_table_[i].data); + } + } +} + /* 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 @@ -336,7 +356,7 @@ struct opcode_entry { &vm->reg_work_[1], &a, &ev_a_addr,\ &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_BASIC_ value_decode_(vm, val_b, 0, val_b_data,\ @@ -384,7 +404,7 @@ OP_IMPL(nbi_jsr) { vm->ram[ --vm->reg[DCPU16_REG_SP] ] = vm->reg[DCPU16_REG_PC]; vm->reg[DCPU16_REG_PC] = *a; - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); ACCT_W(vm->reg[DCPU16_REG_SP] + 1); } @@ -419,7 +439,7 @@ OP_IMPL(nbi_int) { vm->reg[0] = *a; } - vm->cycle += 4; + dcpu16_cycle_inc(vm, 4); } OP_IMPL(nbi_iag) { @@ -427,6 +447,8 @@ OP_IMPL(nbi_iag) { *a = vm->reg[DCPU16_REG_IA]; + dcpu16_cycle_inc(vm, 1); + ACCT_W(ev_a_addr); } @@ -435,6 +457,8 @@ OP_IMPL(nbi_ias) { vm->reg[DCPU16_REG_IA] = *a; + dcpu16_cycle_inc(vm, 1); + ACCT_R(ev_a_addr); } @@ -445,6 +469,8 @@ OP_IMPL(nbi_rfi) { vm->interrupts_deferred_ = 0; vm->reg[DCPU16_REG_A] = vm->ram[vm->reg[DCPU16_REG_SP]++]; vm->reg[DCPU16_REG_PC] = vm->ram[vm->reg[DCPU16_REG_SP]++]; + + dcpu16_cycle_inc(vm, 3); } OP_IMPL(nbi_iaq) { @@ -456,6 +482,8 @@ OP_IMPL(nbi_iaq) { vm->interrupts_deferred_ = 0; } + dcpu16_cycle_inc(vm, 2); + ACCT_R(ev_a_addr); } @@ -466,7 +494,7 @@ OP_IMPL(nbi_hwn) { *a = vm->hw_table_entries_; - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); } OP_IMPL(nbi_hwq) { @@ -490,7 +518,7 @@ OP_IMPL(nbi_hwq) { vm->reg[DCPU16_REG_X] = vm->hw_table_[*a].mfg_l; vm->reg[DCPU16_REG_Y] = vm->hw_table_[*a].mfg_h; - vm->cycle += 4; + dcpu16_cycle_inc(vm, 4); } OP_IMPL(nbi_hwi) { @@ -503,7 +531,7 @@ OP_IMPL(nbi_hwi) { return; } - vm->cycle += 4; + dcpu16_cycle_inc(vm, 4); if (vm->hw_table_[*a].hwi) vm->hw_table_[*a].hwi(vm, vm->hw_table_[*a].data); else @@ -518,7 +546,7 @@ OP_IMPL(nbi_hcf) { vm->on_fire_ = 1; WARN("system on fire"); - vm->cycle += 9; + dcpu16_cycle_inc(vm, 9); } static const struct opcode_entry opcode_nbi_entries[] = { @@ -583,7 +611,7 @@ OP_IMPL(set) { */ *b = *a; - vm->cycle += 1; + dcpu16_cycle_inc(vm, 1); ACCT_W(ev_b_addr); } @@ -599,7 +627,7 @@ OP_IMPL(add) { *b = acc; vm->reg[DCPU16_REG_EX] = (acc > 0xffff); - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); ACCT_W(ev_b_addr); } @@ -615,7 +643,7 @@ OP_IMPL(sub) { *b = acc; vm->reg[DCPU16_REG_EX] = (acc > 0xffff); - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); ACCT_W(ev_b_addr); } @@ -631,7 +659,7 @@ OP_IMPL(mul) { *b = acc; vm->reg[DCPU16_REG_EX] = acc >> 16; - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); ACCT_W(ev_b_addr); } @@ -647,7 +675,7 @@ OP_IMPL(mli) { *b = acc; vm->reg[DCPU16_REG_EX] = acc >> 16; - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); ACCT_W(ev_b_addr); } @@ -667,7 +695,7 @@ OP_IMPL(div) { vm->reg[DCPU16_REG_EX] = (*b << 16) / *a; } - vm->cycle += 3; + dcpu16_cycle_inc(vm, 3); ACCT_W(ev_b_addr); } @@ -687,7 +715,7 @@ OP_IMPL(dvi) { vm->reg[DCPU16_REG_EX] = (short)(*b << 16) / (short)*a; } - vm->cycle += 3; + dcpu16_cycle_inc(vm, 3); ACCT_W(ev_b_addr); } @@ -705,7 +733,7 @@ OP_IMPL(mod) { *b = *b % *a; } - vm->cycle += 3; + dcpu16_cycle_inc(vm, 3); ACCT_W(ev_a_addr); } @@ -723,7 +751,7 @@ OP_IMPL(mdi) { *b = (short)*b % (short)*a; } - vm->cycle += 3; + dcpu16_cycle_inc(vm, 3); ACCT_W(ev_b_addr); } @@ -737,7 +765,7 @@ OP_IMPL(and) { *b = *b & *a; - vm->cycle += 1; + dcpu16_cycle_inc(vm, 1); ACCT_W(ev_b_addr); } @@ -751,7 +779,7 @@ OP_IMPL(bor) { *b = *b | *a; - vm->cycle += 1; + dcpu16_cycle_inc(vm, 1); ACCT_W(ev_b_addr); } @@ -765,7 +793,7 @@ OP_IMPL(xor) { *b = *b ^ *a; - vm->cycle += 1; + dcpu16_cycle_inc(vm, 1); ACCT_W(ev_b_addr); } @@ -781,7 +809,7 @@ OP_IMPL(shr) { *b = acc & 0xffff; vm->reg[DCPU16_REG_EX] = (*b << 16) >> *a; - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); WARN("IMPLEMENT"); @@ -799,7 +827,7 @@ OP_IMPL(asr) { *b = acc & 0xffff; vm->reg[DCPU16_REG_EX] = (*b << 16) >> *a; - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); WARN("IMPLEMENT"); @@ -818,7 +846,7 @@ OP_IMPL(shl) { vm->reg[DCPU16_REG_EX] = acc >> 16; - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); ACCT_W(ev_b_addr); } @@ -834,10 +862,10 @@ OP_IMPL(ifb) { /* */ } else { vm->skip_ = 1; - vm->cycle += 1; + dcpu16_cycle_inc(vm, 1); } - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); } OP_IMPL(ifc) { @@ -851,10 +879,10 @@ OP_IMPL(ifc) { /* */ } else { vm->skip_ = 1; - vm->cycle += 1; + dcpu16_cycle_inc(vm, 1); } - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); } OP_IMPL(ife) { @@ -868,10 +896,10 @@ OP_IMPL(ife) { /* */ } else { vm->skip_ = 1; - vm->cycle += 1; + dcpu16_cycle_inc(vm, 1); } - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); } OP_IMPL(ifn) { @@ -885,10 +913,10 @@ OP_IMPL(ifn) { /* */ } else { vm->skip_ = 1; - vm->cycle++; + dcpu16_cycle_inc(vm, 1); } - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); } OP_IMPL(ifg) { @@ -902,10 +930,10 @@ OP_IMPL(ifg) { /* */ } else { vm->skip_ = 1; - vm->cycle++; + dcpu16_cycle_inc(vm, 1); } - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); } OP_IMPL(ifa) { @@ -919,10 +947,10 @@ OP_IMPL(ifa) { /* */ } else { vm->skip_ = 1; - vm->cycle += 1; + dcpu16_cycle_inc(vm, 1); } - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); } OP_IMPL(ifl) { @@ -936,10 +964,10 @@ OP_IMPL(ifl) { /* */ } else { vm->skip_ = 1; - vm->cycle++; + dcpu16_cycle_inc(vm, 1); } - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); } OP_IMPL(ifu) { @@ -953,10 +981,10 @@ OP_IMPL(ifu) { /* */ } else { vm->skip_ = 1; - vm->cycle += 1; + dcpu16_cycle_inc(vm, 1); } - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); } OP_IMPL(adx) { @@ -974,7 +1002,7 @@ OP_IMPL(adx) { else vm->reg[DCPU16_REG_EX] = 0x0000; - vm->cycle += 3; + dcpu16_cycle_inc(vm, 3); ACCT_W(ev_b_addr); } @@ -994,7 +1022,7 @@ OP_IMPL(sbx) { else vm->reg[DCPU16_REG_EX] = 0; - vm->cycle += 3; + dcpu16_cycle_inc(vm, 3); ACCT_W(ev_b_addr); } @@ -1010,7 +1038,7 @@ OP_IMPL(sti) { vm->reg[DCPU16_REG_I] += 1; vm->reg[DCPU16_REG_J] += 1; - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); ACCT_W(ev_b_addr); } @@ -1026,7 +1054,7 @@ OP_IMPL(std) { vm->reg[DCPU16_REG_I] -= 1; vm->reg[DCPU16_REG_J] -= 1; - vm->cycle += 2; + dcpu16_cycle_inc(vm, 2); ACCT_W(ev_b_addr); } @@ -1229,24 +1257,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 +1284,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,16 +1297,18 @@ 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__); } } } @@ -1312,7 +1329,7 @@ void dcpu16_state_print(struct dcpu16 *vm) { printf("\n"); printf("(0x%08llx) %2s:0x%04x %2s:0x%04x %2s:0x%04x %2s:0x%04x [%2s]:", - vm->cycle, + 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], @@ -1438,7 +1455,7 @@ void dcpu16_reset(struct dcpu16 *vm) { 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); }