/* WARNING: If this is called during a simulated instruction (ie. from a read/ * write mem callback), the interrupt will be delivered after the instruction * has finished executeing */ void report_interrupt (int line) { uint32_t lmask = 1 << line; /* Disable doze and sleep mode */ cpu_state.sprs[SPR_PMR] &= ~(SPR_PMR_DME | SPR_PMR_SME); /* If PIC is disabled, don't set any register, just raise EXCEPT_INT */ if (!config.pic.enabled) { if (cpu_state.sprs[SPR_SR] & SPR_SR_IEE) except_handle (EXCEPT_INT, cpu_state.sprs[SPR_EEAR_BASE]); return; } if (cpu_state.pic_lines & lmask) { /* No edge occured, warn about performance penalty and exit */ fprintf (stderr, "Warning: Int line %d did not change state\n", line); return; } cpu_state.pic_lines |= lmask; cpu_state.sprs[SPR_PICSR] |= lmask; if ((cpu_state.sprs[SPR_PICMR] & lmask) || line < 2) if (cpu_state.sprs[SPR_SR] & SPR_SR_IEE) SCHED_ADD (pic_rep_int, NULL, 0); }
/*! Restarts the tick timer */ static void tick_restart (void *dat) { cpu_state.sprs[SPR_TTCR] = 0; cycle_count_at_tick_start = runtime.sim.cycles; SCHED_ADD (tick_restart, NULL, cpu_state.sprs[SPR_TTMR] & SPR_TTMR_TP); }
/* Called whenever interrupts get enabled */ void pic_ints_en (void) { if ((cpu_state.sprs[SPR_PICMR] & cpu_state.sprs[SPR_PICSR])) SCHED_ADD (pic_rep_int, NULL, 0); }
/*! Schedules the timer jobs */ static void sched_timer_job (uorreg_t prev_ttmr) { uorreg_t ttmr = cpu_state.sprs[SPR_TTMR]; uint32_t match_ttmr = ttmr & SPR_TTMR_TP; /* TTCR register, only concerned with part of TTCR which will trigger int */ uint32_t match_ttcr = spr_read_ttcr () & SPR_TTMR_TP; uint32_t cycles_until_except; /* On clearing TTMR interrupt signal bit remove previous jobs if they exist */ if ((prev_ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP)) { SCHED_FIND_REMOVE (tick_raise_except, NULL); } switch (prev_ttmr & SPR_TTMR_M) { case SPR_TTMR_RT: SCHED_FIND_REMOVE (tick_restart, NULL); break; case SPR_TTMR_SR: SCHED_FIND_REMOVE (tick_one_shot, NULL); break; } /* Calculate cycles until next tick exception, based on current TTCR value */ if (match_ttmr >= match_ttcr) { cycles_until_except = match_ttmr - match_ttcr; } else { /* Cycles after "wrap" of section of TTCR which will cause a match and, potentially, an exception */ cycles_until_except = match_ttmr + (0x0fffffffu - match_ttcr) + 1; } switch (ttmr & SPR_TTMR_M) { case 0: /* Disabled timer */ if (!cycles_until_except && (ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP)) SCHED_ADD (tick_raise_except, NULL, 0); break; case SPR_TTMR_RT: /* Auto-restart timer */ SCHED_ADD (tick_restart, NULL, cycles_until_except); if ((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP)) SCHED_ADD (tick_raise_except, NULL, cycles_until_except); break; case SPR_TTMR_SR: /* One-shot timer */ if (tick_counting) { SCHED_ADD (tick_one_shot, NULL, cycles_until_except); if ((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP)) SCHED_ADD (tick_raise_except, NULL, cycles_until_except); } break; case SPR_TTMR_CR: /* Continuos timer */ if ((ttmr & SPR_TTMR_IE) && !(ttmr & SPR_TTMR_IP)) SCHED_ADD (tick_raise_except, NULL, cycles_until_except); } }