+ ACCT_ILL(vm->reg[DCPU16_REG_PC] - pc_adjust);
+
+ dcpu16_cycle_inc(vm, 1);
+}
+
+OP_IMPL(nbi_int) {
+ OP_NBI(nbi_int);
+
+ 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");
+ return;
+ }
+
+ if (vm->interrupts_deferred_)
+ 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];
+ ACCT_REG_W(DCPU16_REG_PC);
+
+ vm->reg[DCPU16_REG_A] = *a;
+ ACCT_REG_W(DCPU16_REG_A);
+ }
+
+ 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(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);
+
+ 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;
+ }
+
+ dcpu16_cycle_inc(vm, 2);
+}
+
+OP_IMPL(nbi_hwn) {
+ OP_NBI(nbi_hwn);
+
+ *a = vm->hw_table_entries_;
+ ACCT_W(a);
+
+ dcpu16_cycle_inc(vm, 2);
+}
+
+OP_IMPL(nbi_hwq) {
+ OP_NBI(nbi_hwq);
+
+ ACCT_R(a);
+
+ if (*a >= vm->hw_table_entries_) {
+ WARN("hardware query for non-extant device 0x%04x", *a);
+ vm->reg[DCPU16_REG_A] = 0;
+ vm->reg[DCPU16_REG_B] = 0;
+ vm->reg[DCPU16_REG_C] = 0;
+ vm->reg[DCPU16_REG_X] = 0;
+ vm->reg[DCPU16_REG_Y] = 0;
+ } 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;
+ }
+
+ 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);
+}
+
+OP_IMPL(nbi_hwi) {
+ OP_NBI(nbi_hwi);
+
+ ACCT_R(a);
+
+ if (*a > vm->hw_table_entries_) {
+ WARN("interrupt for non-extant device 0x%04x", *a);
+ return;
+ }
+
+ 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(a);
+
+ vm->on_fire_ = 1;
+ WARN("system on fire");
+
+ dcpu16_cycle_inc(vm, 9);