// ----------------------------------------------------------------------- int cpu_ctx_switch(uint16_t arg, uint16_t ic, uint16_t sr_mask) { uint16_t sp; if (!mem_cpu_get(0, 97, &sp)) return 0; LOG(L_CPU, 3, "H/W stack push @ 0x%04x (IC = 0x%04x, R0 = 0x%04x, SR = 0x%04x, arg = 0x%04x), new IC = 0x%04x", sp, regs[R_IC], regs[0], regs[R_SR], arg, ic ); if (!mem_cpu_put(0, sp, regs[R_IC])) return 0; if (!mem_cpu_put(0, sp+1, regs[0])) return 0; if (!mem_cpu_put(0, sp+2, regs[R_SR])) return 0; if (!mem_cpu_put(0, sp+3, arg)) return 0; if (!mem_cpu_put(0, 97, sp+4)) return 0; regs[0] = 0; regs[R_IC] = ic; regs[R_SR] &= sr_mask; int_update_mask(regs[R_SR]); return 1; }
// ----------------------------------------------------------------------- int cpu_ctx_restore() { uint16_t data; uint16_t sp; if (!mem_cpu_get(0, 97, &sp)) return 0; if (!mem_cpu_get(0, sp-4, &data)) return 0; regs[R_IC] = data; if (!mem_cpu_get(0, sp-3, &data)) return 0; regs[0] = data; if (!mem_cpu_get(0, sp-2, &data)) return 0; regs[R_SR] = data; int_update_mask(regs[R_SR]); if (!mem_cpu_put(0, 97, sp-4)) return 0; LOG(L_CPU, 3, "H/W stack pop @ 0x%04x (IC = 0x%04x, R0 = 0x%04x, SR = 0x%04x)", sp-4, regs[R_IC], regs[0], regs[R_SR] ); return 1; }
// ----------------------------------------------------------------------- void int_serve() { int probe = 31; int interrupt; uint16_t int_vec; uint16_t int_spec = 0; uint16_t sr_mask; // find highest interrupt to serve uint32_t rp = atom_load(&RP); while ((probe > 0) && !(rp & (1 << probe))) { probe--; } interrupt = 31 - probe; // clear interrupt, we update rp together with mask upon ctx switch pthread_mutex_lock(&int_mutex); RZ &= ~INT_BIT(interrupt); pthread_mutex_unlock(&int_mutex); // get interrupt vector if (!mem_cpu_get(0, 64+interrupt, &int_vec)) return; LOG(L_INT, 1, "Serve interrupt: %d (%s) -> 0x%04x", interrupt, int_names[interrupt], int_vec); // get interrupt specification for channel interrupts if ((interrupt >= 12) && (interrupt <= 27)) { io_get_intspec(interrupt-12, &int_spec); } // put system status on stack sr_mask = int_int2mask[interrupt] & MASK_Q; // calculate mask and clear Q if (cpu_mod_active && (interrupt >= 12) && (interrupt <= 27)) sr_mask &= MASK_EX; // put extended mask if cpu_mod // switch context if (!cpu_ctx_switch(int_spec, int_vec, sr_mask)) return; if (LOG_ENABLED) { log_intlevel_inc(); } }
// ----------------------------------------------------------------------- void cpu_step() { struct em400_op *op; uint16_t data; if (LOG_ENABLED) { log_store_cycle_state(regs[R_SR], regs[R_IC]); } // fetch instruction if (!mem_cpu_get(QNB, regs[R_IC], regs+R_IR)) { regs[R_MODc] = regs[R_MOD] = 0; LOGCPU(L_CPU, 2, " (NO MEM: instruction fetch)"); return; } regs[R_IC]++; // find instruction (by design op is always set to something, // even for illegal instructions) op = em400_op_tab[regs[R_IR]]; // end cycle if P is set if (P) { LOGCPU(L_CPU, 2, " (skip)"); P = 0; // skip also M-arg if present if (op->norm_arg && !IR_C) regs[R_IC]++; return; } // process argument if (op->norm_arg) { if (IR_C) { N = regs[IR_C] + regs[R_MOD]; } else { if (!mem_cpu_get(QNB, regs[R_IC], &data)) { LOGCPU(L_CPU, 2, " (no mem: long arg fetch)"); goto finish; } else { N = data + regs[R_MOD]; regs[R_IC]++; } } if (IR_B) { N = (uint16_t) N + regs[IR_B]; } if (IR_D) { if (!mem_cpu_get(QNB, N, &data)) { LOGCPU(L_CPU, 2, " (no mem: indirect arg fetch)"); goto finish; } else { N = data; } } } else if (op->short_arg) { N = (uint16_t) IR_T + (uint16_t) regs[R_MOD]; } if (LOG_WANTS(L_CPU, 2)) { log_log_dasm(L_CPU, 2, regs[R_MOD], op->norm_arg, op->short_arg, N); } // execute instruction op->fun(); // clear mod if instruction wasn't md if (op->fun != op_77_md) { finish: regs[R_MODc] = 0; regs[R_MOD] = 0; } }