예제 #1
0
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
}
예제 #2
0
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);
}