void MY (f_model_insn_after) (SIM_CPU *current_cpu, int last_p ATTRIBUTE_UNUSED, int cycles) { PROFILE_DATA *p = CPU_PROFILE_DATA (current_cpu); PROFILE_MODEL_TOTAL_CYCLES (p) += cycles; CPU_CRIS_MISC_PROFILE (current_cpu)->basic_cycle_count += cycles; PROFILE_MODEL_CUR_INSN_CYCLES (p) = cycles; #if WITH_HW /* For some reason, we don't get to the sim_events_tick call in cgen-run.c:engine_run_1. Besides, more than one cycle has passed, so we want sim_events_tickn anyway. The "events we want to process" is usually to initiate an interrupt, but might also be other events. We can't do the former until the main loop is at point where it accepts changing the PC without internal inconsistency, so just set a flag and wait. */ if (sim_events_tickn (CPU_STATE (current_cpu), cycles)) STATE_EVENTS (CPU_STATE (current_cpu))->work_pending = 1; #endif }
static void m68hc11tim_timer_event (struct hw *me, void *data) { SIM_DESC sd; struct m68hc11tim *controller; sim_cpu *cpu; enum event_type type; unsigned long delay; struct hw_event **eventp; int check_interrupt = 0; unsigned mask; unsigned flags; unsigned long tcnt_internal; unsigned long tcnt, tcnt_prev; signed64 tcnt_insn_end; signed64 tcnt_insn_start; int i; sim_events *events; controller = hw_data (me); sd = hw_system (me); cpu = STATE_CPU (sd, 0); type = (enum event_type) ((long) data) & 0x0FF; events = STATE_EVENTS (sd); delay = 0; switch (type) { case COP_EVENT: eventp = &controller->cop_timer_event; delay = controller->cop_delay; delay = controller->cop_prev_interrupt + controller->cop_delay; controller->cop_prev_interrupt = delay; delay = delay - cpu->cpu_absolute_cycle; check_interrupt = 1; delay += events->nr_ticks_to_process; break; case RTI_EVENT: eventp = &controller->rti_timer_event; delay = controller->rti_prev_interrupt + controller->rti_delay; if (((long) (data) & 0x0100) == 0) { cpu->ios[M6811_TFLG2] |= M6811_RTIF; check_interrupt = 1; controller->rti_prev_interrupt = delay; delay += controller->rti_delay; } delay = delay - cpu->cpu_absolute_cycle; delay += events->nr_ticks_to_process; break; case OVERFLOW_EVENT: /* Compute the 68HC11 internal free running counter. */ tcnt_internal = (cpu->cpu_absolute_cycle - controller->tcnt_adjust); /* We must take into account the prescaler that comes before the counter (it's a power of 2). */ tcnt_internal &= 0x0ffff * controller->clock_prescaler; /* Compute the time when the overflow will occur. It occurs when the counter increments from 0x0ffff to 0x10000 (and thus resets). */ delay = (0x10000 * controller->clock_prescaler) - tcnt_internal; /* The 'nr_ticks_to_process' will be subtracted when the event is scheduled. */ delay += events->nr_ticks_to_process; eventp = &controller->tof_timer_event; if (((long) (data) & 0x100) == 0) { cpu->ios[M6811_TFLG2] |= M6811_TOF; check_interrupt = 1; } break; case COMPARE_EVENT: /* Compute value of TCNT register (64-bit precision) at beginning and end of instruction. */ tcnt_insn_end = (cpu->cpu_absolute_cycle - controller->tcnt_adjust); tcnt_insn_start = (tcnt_insn_end - cpu->cpu_current_cycle); /* TCNT value at beginning of current instruction. */ tcnt_prev = (tcnt_insn_start / controller->clock_prescaler) & 0x0ffff; /* TCNT value at end of current instruction. */ tcnt = (tcnt_insn_end / controller->clock_prescaler) & 0x0ffff; /* We must take into account the prescaler that comes before the counter (it's a power of 2). */ tcnt_internal = tcnt_insn_end; tcnt_internal &= 0x0ffff * controller->clock_prescaler; flags = cpu->ios[M6811_TMSK1]; mask = 0x80; delay = 65536 * controller->clock_prescaler; /* Scan each output compare register to see if one matches the free running counter. Set the corresponding OCi flag if the output compare is enabled. */ for (i = M6811_TOC1; i <= M6811_TOC5; i += 2, mask >>= 1) { unsigned long compare; compare = (cpu->ios[i] << 8) + cpu->ios[i + 1]; /* See if compare is reached; handle wrap arround. */ if ((compare >= tcnt_prev && compare <= tcnt && tcnt_prev < tcnt) || (compare >= tcnt_prev && tcnt_prev > tcnt) || (compare < tcnt && tcnt_prev > tcnt)) { unsigned dt; if (compare > tcnt) dt = 0x10000 - compare - tcnt; else dt = tcnt - compare; cpu->ios[M6811_TFLG1] |= mask; /* Raise interrupt now at the correct CPU cycle so that we can find the interrupt latency. */ cpu->cpu_absolute_cycle -= dt; interrupts_update_pending (&cpu->cpu_interrupts); cpu->cpu_absolute_cycle += dt; } /* Compute how many times for the next match. Use the internal counter value to take into account the prescaler accurately. */ compare = compare * controller->clock_prescaler; if (compare > tcnt_internal) compare = compare - tcnt_internal; else compare = compare - tcnt_internal + 65536 * controller->clock_prescaler; if (compare < delay) delay = compare; } /* Deactivate the compare timer if no output compare is enabled. */ if ((flags & 0xF8) == 0) delay = 0; else delay += events->nr_ticks_to_process; eventp = &controller->cmp_timer_event; break; default: eventp = 0; break; } if (*eventp) { hw_event_queue_deschedule (me, *eventp); *eventp = 0; } if (delay != 0) { *eventp = hw_event_queue_schedule (me, delay, m68hc11tim_timer_event, (void*) type); } if (check_interrupt) interrupts_update_pending (&cpu->cpu_interrupts); }