static void
do_counter6_event (struct hw *me,
		  void *data)
{
  struct mn103tim *timers = hw_data(me);
  long timer_nr = (long) data;
  int next_timer;

  /* Check if counting is still enabled. */
  if ( (timers->reg[timer_nr].mode & count_mask) != 0 )
    {
      /* Generate an interrupt for the timer underflow (TIMERn_UFLOW). */
      hw_port_event (me, timer_nr, 1);

      /* Schedule next timeout.  */
      timers->timer[timer_nr].start = hw_event_queue_time(me);
      /* FIX: Check if div_ratio has changed and if it's now 0. */
      timers->timer[timer_nr].event
	= hw_event_queue_schedule (me, timers->timer[timer_nr].div_ratio,
				   do_counter6_event, (void *)timer_nr);
    }
  else
    {
      timers->timer[timer_nr].event = NULL;
    }

}
Beispiel #2
0
static void
bfin_cec_check_pending (struct hw *me, struct bfin_cec *cec)
{
  if (cec->pending)
    return;
  cec->pending = hw_event_queue_schedule (me, 0, bfin_cec_hw_event_callback, cec);
}
void
m68hc11sio_tx_poll (struct hw *me, void *data)
{
  SIM_DESC sd;
  struct m68hc11sio *controller;
  sim_cpu *cpu;
  
  controller = hw_data (me);
  sd         = hw_system (me);
  cpu        = STATE_CPU (sd, 0);

  cpu->ios[M6811_SCSR] |= M6811_TDRE;
  cpu->ios[M6811_SCSR] |= M6811_TC;
  
  /* Transmitter is enabled and we have something to send.  */
  if ((cpu->ios[M6811_SCCR2] & M6811_TE) && controller->tx_has_char)
    {
      cpu->ios[M6811_SCSR] &= ~M6811_TDRE;
      cpu->ios[M6811_SCSR] &= ~M6811_TC;
      controller->tx_has_char = 0;
      switch (controller->backend)
        {
        case sio_tcp:
          dv_sockser_write (sd, controller->tx_char);
          break;

        case sio_stdio:
          sim_io_write_stdout (sd, &controller->tx_char, 1);
          sim_io_flush_stdout (sd);
          break;

        default:
          break;
        }
    }

  if (controller->tx_poll_event)
    {
      hw_event_queue_deschedule (me, controller->tx_poll_event);
      controller->tx_poll_event = 0;
    }
  
  if ((cpu->ios[M6811_SCCR2] & M6811_TE)
      && ((cpu->ios[M6811_SCSR] & M6811_TC) == 0))
    {
      unsigned long clock_cycle;
      
      /* Compute CPU clock cycles to wait for the next character.  */
      clock_cycle = controller->data_length * controller->baud_cycle;

      controller->tx_poll_event = hw_event_queue_schedule (me, clock_cycle,
                                                           m68hc11sio_tx_poll,
                                                           NULL);
    }

  interrupts_update_pending (&cpu->cpu_interrupts);
}
Beispiel #4
0
static void
bfin_ctimer_schedule (struct hw *me, struct bfin_ctimer *ctimer)
{
  bu32 scale = bfin_ctimer_scale (ctimer);
  ctimer->timeout = (ctimer->tcount / scale) + !!(ctimer->tcount % scale);
  ctimer->handler = hw_event_queue_schedule (me, ctimer->timeout,
					     bfin_ctimer_expire,
					     ctimer);
}
void
tx3904sio_poll(struct hw* me, void* ignored)
{
  struct tx3904sio* controller = hw_data (me);
  tx3904sio_tickle (me);
  hw_event_queue_deschedule (me, controller->poll_event);
  controller->poll_event = hw_event_queue_schedule (me, 1000,
						    tx3904sio_poll, NULL);
}
Beispiel #6
0
static void
do_polling_event (struct hw *me,
		  void *data)
{
  SIM_DESC sd = hw_system (me);
  struct mn103ser *serial = hw_data(me);
  long serial_reg = (long) data;
  char c;
  int count, status;

  status = dv_sockser_status (sd);
  if (!(status & DV_SOCKSER_DISCONNECTED))
    {
      int rd;
      rd = dv_sockser_read (sd);
      if(rd != -1)
	{
	  c = (char) rd;
	  count = 1;
	}
      else
	{
	  count = HW_IO_NOT_READY;
	}
    }
  else
    {
      count = do_hw_poll_read (me, serial->reader,
			       0/*STDIN*/, &c, sizeof(c));
    }


  switch (count)
    {
    case HW_IO_NOT_READY:
    case HW_IO_EOF:
      serial->device[serial_reg].rxb = 0;
      serial->device[serial_reg].status &= ~SIO_STAT_RRDY;
      break;
    default:
      serial->device[serial_reg].rxb = c;
      serial->device[serial_reg].status |= SIO_STAT_RRDY;
      hw_port_event (me, serial_reg+SERIAL0_RECEIVE, 1);
    }

  /* Schedule next polling event */
  serial->device[serial_reg].event
    = hw_event_queue_schedule (me, 1000,
			       do_polling_event, (void *)serial_reg);

}
Beispiel #7
0
static void
do_counter_event (struct hw *me,
		  void *data)
{
  hw_pal_counter *counter = (hw_pal_counter *) data;
  if (counter->periodic_p)
    {
      HW_TRACE ((me, "timer expired"));
      counter->start = hw_event_queue_time (me);
      hw_port_event (me, TIMER_PORT, 1);
      hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
    }
  else
    {
      HW_TRACE ((me, "countdown expired"));
      counter->delta = 0;
      hw_port_event (me, COUNTDOWN_PORT, 1);
    }
}
static void
deliver_cris_interrupt (struct hw *me, void *data)
{
  struct cris_hw *crishw = hw_data (me);
  SIM_DESC simulator = hw_system (me);
  sim_cpu *cpu = STATE_CPU (simulator, 0);
  unsigned int intno = crishw->pending_vector;

 if (CPU_CRIS_DELIVER_INTERRUPT (cpu) (cpu, CRIS_INT_INT, intno))
    {
      crishw->pending_vector = 0;
      crishw->pending_handler = NULL;
      return;
    }

 {
   /* Bug workaround: at time T with a pending number of cycles N to
      process, if re-scheduling an event at time T+M, M < N,
      sim_events_process gets stuck at T (updating the "time" to
      before the event rather than after the event, or somesuch).

      Hacking this locally is thankfully easy: if we see the same
      simulation time, increase the number of cycles.  Do this every
      time we get here, until a new time is seen (supposedly unstuck
      re-delivery).  (Fixing in SIM/GDB source will hopefully then
      also be easier, having a tangible test-case.)  */
   static signed64 last_events_time = 0;
   static signed64 delta = 1;
   signed64 this_events_time = hw_event_queue_time (me);

   if (this_events_time == last_events_time)
     delta++;
   else
     {
       delta = 1;
       last_events_time = this_events_time;
     }

   crishw->pending_handler
     = hw_event_queue_schedule (me, delta, deliver_cris_interrupt, NULL);
 }
}
Beispiel #9
0
void
bfin_uart_reschedule (struct hw *me)
{
  struct bfin_uart *uart = hw_data (me);

  if (uart->ier & ERBFI)
    {
      if (!uart->handler)
	uart->handler = hw_event_queue_schedule (me, 10000,
						 bfin_uart_poll, uart);
    }
  else
    {
      if (uart->handler)
	{
	  hw_event_queue_deschedule (me, uart->handler);
	  uart->handler = NULL;
	}
    }
}
Beispiel #10
0
static void
do_counter_write (struct hw *me,
		  hw_pal_device *pal,
		  const char *reg,
		  hw_pal_counter *counter,
		  const unsigned32 *word,
		  unsigned nr_bytes)
{
  if (nr_bytes != 4)
    hw_abort (me, "%s - bad write size must be 4 bytes", reg);
  if (counter->handler != NULL)
    {
      hw_event_queue_deschedule (me, counter->handler);
      counter->handler = NULL;
    }
  counter->delta = BE2H_4 (*word);
  counter->start = hw_event_queue_time (me);
  HW_TRACE ((me, "write - %s %ld", reg, (long) counter->delta));
  if (counter->delta > 0)
    hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
}
static void
do_counter_event (struct hw *me,
		  void *data)
{
  struct mn103tim *timers = hw_data(me);
  long timer_nr = (long) data;
  int next_timer;

  /* Check if counting is still enabled. */
  if ( (timers->reg[timer_nr].mode & count_mask) != 0 )
    {
      /* Generate an interrupt for the timer underflow (TIMERn_UFLOW). */

      /* Port event occurs on port of last cascaded timer. */
      /* This works across timer range from 0 to NR_REG_TIMERS because */
      /* the first 16 bit timer (timer 4) is not allowed to be set as  */
      /* a cascading timer. */
      for ( next_timer = timer_nr+1; next_timer < NR_REG_TIMERS; ++next_timer )
	{
	  if ( (timers->reg[next_timer].mode & clock_mask) != clk_cascaded )
	    {
	      break;
	    }
	}
      hw_port_event (me, next_timer-1, 1);

      /* Schedule next timeout.  */
      timers->timer[timer_nr].start = hw_event_queue_time(me);
      /* FIX: Check if div_ratio has changed and if it's now 0. */
      timers->timer[timer_nr].event
	= hw_event_queue_schedule (me, timers->timer[timer_nr].div_ratio,
				   do_counter_event, (void *)timer_nr);
    }
  else
    {
      timers->timer[timer_nr].event = NULL;
    }

}
Beispiel #12
0
static void
mn103cpu_port_event (struct hw *me,
		     int my_port,
		     struct hw *source,
		     int source_port,
		     int level)
{
  struct mn103cpu *controller = hw_data (me);

  /* Schedule our event handler *now* */
  if (controller->pending_handler == NULL)
    controller->pending_handler =
      hw_event_queue_schedule (me, 0, deliver_mn103cpu_interrupt, NULL);

  switch (my_port)
    {
      
    case RESET_PORT:
      controller->pending_reset = 1;
      HW_TRACE ((me, "port-in reset"));
      break;
      
    case NMI_PORT:
      controller->pending_nmi = 1;
      HW_TRACE ((me, "port-in nmi"));
      break;
      
    case LEVEL_PORT:
      controller->pending_level = level;
      HW_TRACE ((me, "port-in level=%d", level));
      break;
      
    default:
      hw_abort (me, "bad switch");
      break;

    }
}
Beispiel #13
0
int
main (int argc,
      char **argv)
{
  host_callback *cb = ZALLOC (host_callback);
  struct sim_state *sd = sim_state_alloc (0, cb);
  struct hw *me = ZALLOC (struct hw);
  sim_pre_argv_init (sd, "test-hw-events");
  sim_post_argv_init (sd);
  me->system_of_hw = sd;

  printf ("Create hw-event-data\n");
  {
    create_hw_alloc_data (me);
    create_hw_event_data (me);
    delete_hw_event_data (me);
    delete_hw_alloc_data (me);
  }

  printf ("Create hw-events\n");
  {
    struct hw_event *a;
    struct hw_event *b;
    struct hw_event *c;
    struct hw_event *d;
    create_hw_alloc_data (me);
    create_hw_event_data (me);
    a = hw_event_queue_schedule (me, 0, NULL, NULL);
    b = hw_event_queue_schedule (me, 1, NULL, NULL);
    c = hw_event_queue_schedule (me, 2, NULL, NULL);
    d = hw_event_queue_schedule (me, 1, NULL, NULL);
    hw_event_queue_deschedule (me, c);
    hw_event_queue_deschedule (me, b);
    hw_event_queue_deschedule (me, a);
    hw_event_queue_deschedule (me, d);
    c = HW_ZALLOC (me, struct hw_event);
    hw_event_queue_deschedule (me, b); /* OOPS! */
    hw_free (me, c);
    delete_hw_event_data (me);
    delete_hw_alloc_data (me);
  }

  printf ("Schedule hw-events\n");
  {
    struct hw_event **e;
    int *n;
    int i;
    int nr = 4;
    e = HW_NZALLOC (me, struct hw_event *, nr);
    n = HW_NZALLOC (me, int, nr);
    create_hw_alloc_data (me);
    create_hw_event_data (me);
    for (i = 0; i < nr; i++)
      {
	n[i] = i;
	e[i] = hw_event_queue_schedule (me, i, test_handler, &n[i]);
      }
    sim_events_preprocess (sd, 1, 1);
    for (i = 0; i < nr; i++)
      {
	if (sim_events_tick (sd))
	  sim_events_process (sd);
      }
    for (i = 0; i < nr; i++)
      {
	if (n[i] != -i)
	  abort ();
	hw_event_queue_deschedule (me, e[i]);
      }
    hw_free (me, n);
    hw_free (me, e);
    delete_hw_event_data (me);
    delete_hw_alloc_data (me);
  }

  return 0;
}
Beispiel #14
0
static unsigned
lm32uart_io_write_buffer (struct hw *me,
			  const void *source,
			  int space, unsigned_word base, unsigned nr_bytes)
{
  struct lm32uart *uart = hw_data (me);
  int uart_reg;
  const unsigned char *source_bytes = source;
  int value = 0;

  HW_TRACE ((me, "write to 0x%08lx length %d with 0x%x", (long) base,
	     (int) nr_bytes, value));

  if (nr_bytes == 4)
    value = (source_bytes[0] << 24)
      | (source_bytes[1] << 16) | (source_bytes[2] << 8) | (source_bytes[3]);
  else
    hw_abort (me, "write of unsupported number of bytes: %d.", nr_bytes);

  uart_reg = base - uart->base;

  switch (uart_reg)
    {
    case LM32_UART_THR:
      /* Buffer the character to output.  */
      uart->thr = value;

      /* Indicate the THR is full.  */
      uart->lsr &= ~LM32_UART_LSR_TX_RDY;

      /* deassert interrupt when IER is loaded.  */
      uart->iir &= ~MICOUART_IIR_TXRDY;

      /* schedule an event to output the character.  */
      hw_event_queue_schedule (me, 1, do_uart_tx_event, 0);

      break;
    case LM32_UART_IER:
      uart->ier = value;
      if ((value & LM32_UART_IER_TX_INT)
	  && (uart->lsr & LM32_UART_LSR_TX_RDY))
	{
	  /* hw_event_queue_schedule (me, 1, do_uart_tx_event, 0); */
	  uart->lsr |= LM32_UART_LSR_TX_RDY;
	  uart->iir |= MICOUART_IIR_TXRDY;
	  hw_port_event (me, INT_PORT, 1);
	}
      else if ((value & LM32_UART_IER_TX_INT) == 0)
	{
	  hw_port_event (me, INT_PORT, 0);
	}
      break;
    case LM32_UART_IIR:
      uart->iir = value;
      break;
    case LM32_UART_LCR:
      uart->lcr = value;
      break;
    case LM32_UART_MCR:
      uart->mcr = value;
      break;
    case LM32_UART_LSR:
      uart->lsr = value;
      break;
    case LM32_UART_MSR:
      uart->msr = value;
      break;
    case LM32_UART_DIV:
      uart->div = value;
      break;
    default:
      hw_abort (me, "write to invalid register address: 0x%x.", uart_reg);
    }

  return nr_bytes;
}
Beispiel #15
0
static void
read_status_reg (struct hw *me,
		 struct mn103ser *serial,
		 unsigned_word serial_reg,
		 void *dest,
		 unsigned  nr_bytes)
{
  char c;
  int count;

  if ( (serial->device[serial_reg].status & SIO_STAT_RRDY) == 0 )
    {
      SIM_DESC sd = hw_system (me);
      int status;

      /* FIFO is empty */
      /* Kill current poll event */
      if ( NULL != serial->device[serial_reg].event )
	{
	  hw_event_queue_deschedule (me, serial->device[serial_reg].event);
	  serial->device[serial_reg].event = NULL;
	}

      status = dv_sockser_status (sd);
      if (!(status & DV_SOCKSER_DISCONNECTED))
	{
	  int rd;
	  rd = dv_sockser_read (sd);
	  if(rd != -1)
	    {
	      c = (char) rd;
	      count = 1;
	    }
	  else
	    {
	      count = HW_IO_NOT_READY;
	    }
	}
      else
	{
	  count = do_hw_poll_read (me, serial->reader,
				   0/*STDIN*/, &c, sizeof(c));
	}

      switch (count)
	{
	case HW_IO_NOT_READY:
	case HW_IO_EOF:
	  serial->device[serial_reg].rxb = 0;
	  serial->device[serial_reg].status &= ~SIO_STAT_RRDY;
	  break;
	default:
	  serial->device[serial_reg].rxb = c;
	  serial->device[serial_reg].status |= SIO_STAT_RRDY;
	  hw_port_event (me, serial_reg+SERIAL0_RECEIVE, 1);
	}

      /* schedule polling event */
      serial->device[serial_reg].event
	= hw_event_queue_schedule (me, 1000,
				   do_polling_event,
				   (void *) (long) serial_reg);
    }

  if ( nr_bytes == 1 )
    {
      *(unsigned8 *)dest = (unsigned8)serial->device[serial_reg].status;
    }
  else if ( nr_bytes == 2 && serial_reg != SC2STR )
    {
      *(unsigned16 *)dest = H2LE_2 (serial->device[serial_reg].status);
    }
  else
    {
      hw_abort (me, "bad read size of %d bytes from SC%dSTR.", nr_bytes, 
		serial_reg);
    }
}
static void
write_tm6md (struct hw *me,
	     struct mn103tim *timers,
	     unsigned_word address,
	     const void *source,
	     unsigned nr_bytes)
{
  unsigned8 mode_val0 = 0x00, mode_val1 = 0x00;
  unsigned32 div_ratio;
  long timer_nr = 6;

  unsigned_word offset = address - timers->block[0].base;
  
  if ((offset != 0x84 && nr_bytes > 1) || nr_bytes > 2 )
    {
      hw_abort (me, "Bad write size of %d bytes to TM6MD", nr_bytes);
    }

  if ( offset == 0x84 )  /* address of TM6MD */
    {
      /*  Fill in first byte of mode */
      mode_val0 = *(unsigned8 *)source;
      timers->tm6md0 = mode_val0;
    
      if ( ( mode_val0 & 0x26 ) != 0 )
	{
	  hw_abort(me, "Cannot write to bits 5, 3, and 2 of TM6MD");
	}
    }
  
  if ( offset == 0x85 || nr_bytes == 2 )
    {
      /*  Fill in second byte of mode */
      if ( nr_bytes == 2 )
	{
	  mode_val1 = *(unsigned8 *)source+1;
	}
      else
	{
	  mode_val1 = *(unsigned8 *)source;
	}

      timers->tm6md1 = mode_val1;

      if ( ( mode_val1 & count_and_load_mask ) == count_and_load_mask )
	{
	  hw_abort(me, "Cannot load base reg and start counting simultaneously.");
	}
      if ( ( mode_val1 & bits0to2_mask ) != 0 )
	{
	  hw_abort(me, "Cannot write to bits 8 to 10 of TM6MD");
	}
    }

  if ( mode_val1 & count_mask )
    {
      /* - de-schedule any previous event. */
      /* - add new event to queue to start counting. */
      /* - assert that counter == base reg? */

      div_ratio = timers->tm6ca;  /* binary counter for timer 6 */
      timers->timer[timer_nr].div_ratio = div_ratio;
      if ( NULL != timers->timer[timer_nr].event )
	{
	  hw_event_queue_deschedule (me, timers->timer[timer_nr].event);
	  timers->timer[timer_nr].event = NULL;
	}

      if ( div_ratio > 0 )
	{
	  /* Set start time. */
	  timers->timer[timer_nr].start = hw_event_queue_time(me);
	  timers->timer[timer_nr].event
	    = hw_event_queue_schedule(me, div_ratio,
				      do_counter6_event,
				      (void *)(timer_nr)); 
	}
    }
  else
    {
      /* Turn off counting */
      if ( NULL != timers->timer[timer_nr].event )
	{
	  hw_event_queue_deschedule (me, timers->timer[timer_nr].event);
	  timers->timer[timer_nr].event = NULL;
	}
    }
}
static void
write_mode_reg (struct hw *me,
		struct mn103tim *timers,
		long timer_nr,
		const void *source,
		unsigned nr_bytes)
     /* for timers 0 to 5 */
{
  unsigned i;
  unsigned8 mode_val, next_mode_val;
  unsigned32 div_ratio;

  if ( nr_bytes != 1 )
    {
      hw_abort (me, "bad write size of %d bytes to TM%ldMD.", nr_bytes,
		timer_nr);
    }

  mode_val = *(unsigned8 *)source;
  timers->reg[timer_nr].mode = mode_val;
      
  if ( ( mode_val & count_and_load_mask ) == count_and_load_mask )
    {
      hw_abort(me, "Cannot load base reg and start counting simultaneously.");
    }
  if ( ( mode_val & bits2to5_mask ) != 0 )
    {
      hw_abort(me, "Cannot write to bits 2 to 5 of mode register");
    }

  if ( mode_val & count_mask )
    {
      /* - de-schedule any previous event. */
      /* - add new event to queue to start counting. */
      /* - assert that counter == base reg? */

      /* For cascaded timers, */
      if ( (mode_val & clock_mask) == clk_cascaded )
	{
	  if ( timer_nr == 0 || timer_nr == 4 )
	    {
	      hw_abort(me, "Timer %ld cannot be cascaded.", timer_nr);
	    }
	}
      else
	{
	  div_ratio = timers->reg[timer_nr].base;

	  /* Check for cascading. */
	  if ( timer_nr < NR_8BIT_TIMERS )
	    {
	      for ( i = timer_nr + 1; i <= 3; ++i ) 
		{
		  next_mode_val = timers->reg[i].mode;
		  if ( ( next_mode_val & clock_mask ) == clk_cascaded )
		    {
		      /* Check that CNE is on. */
		      if ( ( next_mode_val & count_mask ) == 0 ) 
			{
			  hw_abort (me, "cascaded timer not ready for counting");
			}
		      ASSERT(timers->timer[i].event == NULL);
		      ASSERT(timers->timer[i].div_ratio == 0);
		      div_ratio = div_ratio
			| (timers->reg[i].base << (8*(i-timer_nr)));
		    }
		  else
		    {
		      break;
		    }
		}
	    }
	  else
	    {
	      /* Mode register for a 16 bit timer */
	      next_mode_val = timers->reg[timer_nr+1].mode;
	      if ( ( next_mode_val & clock_mask ) == clk_cascaded )
		{
		  /* Check that CNE is on. */
		  if ( ( next_mode_val & count_mask ) == 0 ) 
		    {
		      hw_abort (me, "cascaded timer not ready for counting");
		    }
		  ASSERT(timers->timer[timer_nr+1].event == NULL);
		  ASSERT(timers->timer[timer_nr+1].div_ratio == 0);
		  div_ratio = div_ratio | (timers->reg[timer_nr+1].base << 16);
		}
	    }

	  timers->timer[timer_nr].div_ratio = div_ratio;

	  if ( NULL != timers->timer[timer_nr].event )
	    {
	      hw_event_queue_deschedule (me, timers->timer[timer_nr].event);
	      timers->timer[timer_nr].event = NULL;
	    }

	  if ( div_ratio > 0 )
	    {
	      /* Set start time. */
	      timers->timer[timer_nr].start = hw_event_queue_time(me);
	      timers->timer[timer_nr].event
		= hw_event_queue_schedule(me, div_ratio,
					  do_counter_event,
					  (void *)(timer_nr)); 
	    }
	}
    }
  else
    {
      /* Turn off counting */
      if ( NULL != timers->timer[timer_nr].event )
	{
	  ASSERT((timers->reg[timer_nr].mode & clock_mask) != clk_cascaded);
	  hw_event_queue_deschedule (me, timers->timer[timer_nr].event);
	  timers->timer[timer_nr].event = NULL;
	}
      else
	{
	  if ( (timers->reg[timer_nr].mode & clock_mask) == clk_cascaded )
	    {
	      ASSERT(timers->timer[timer_nr].event == NULL);
	    }
	}
      
    }

}
static unsigned
m68hc11sio_io_write_buffer (struct hw *me,
                            const void *source,
                            int space,
                            unsigned_word base,
                            unsigned nr_bytes)
{
  SIM_DESC sd;
  struct m68hc11sio *controller;
  sim_cpu *cpu;
  unsigned8 val;

  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));

  sd  = hw_system (me);
  cpu = STATE_CPU (sd, 0);
  controller = hw_data (me);
  
  val = *((const unsigned8*) source);
  switch (base)
    {
    case M6811_BAUD:
      {
        long divisor;
        long baud;

        cpu->ios[M6811_BAUD] = val;        
        switch (val & (M6811_SCP1|M6811_SCP0))
          {
          case M6811_BAUD_DIV_1:
            divisor = 1 * 16;
            break;

          case M6811_BAUD_DIV_3:
            divisor = 3 * 16;
            break;

          case M6811_BAUD_DIV_4:
            divisor = 4 * 16;
            break;

          default:
          case M6811_BAUD_DIV_13:
            divisor = 13 * 16;
            break;
          }
        val &= (M6811_SCR2|M6811_SCR1|M6811_SCR0);
        divisor *= (1 << val);

        baud = (cpu->cpu_frequency / 4) / divisor;

        HW_TRACE ((me, "divide rate %ld, baud rate %ld",
                   divisor, baud));

        controller->baud_cycle = divisor;
      }
      break;
      
    case M6811_SCCR1:
      {
        if (val & M6811_M)
          controller->data_length = 11;
        else
          controller->data_length = 10;

        cpu->ios[M6811_SCCR1] = val;
      }
      break;
      
    case M6811_SCCR2:
      if ((val & M6811_RE) == 0)
        {
          val &= ~(M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF);
          val |= (cpu->ios[M6811_SCCR2]
                  & (M6811_RDRF|M6811_IDLE|M6811_OR|M6811_NF|M6811_NF));
          cpu->ios[M6811_SCCR2] = val;
          break;
        }

      /* Activate reception.  */
      if (controller->rx_poll_event == 0)
        {
          long clock_cycle;
          
          /* Compute CPU clock cycles to wait for the next character.  */
          clock_cycle = controller->data_length * controller->baud_cycle;

          controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
                                                               m68hc11sio_rx_poll,
                                                               NULL);
        }      
      cpu->ios[M6811_SCCR2] = val;
      interrupts_update_pending (&cpu->cpu_interrupts);
      break;

      /* No effect.  */
    case M6811_SCSR:
      return 1;
      
    case M6811_SCDR:
      if (!(cpu->ios[M6811_SCSR] & M6811_TDRE))
        {
          return 0;
        }

      controller->tx_char     = val;
      controller->tx_has_char = 1;
      if ((cpu->ios[M6811_SCCR2] & M6811_TE)
          && controller->tx_poll_event == 0)
        {
          m68hc11sio_tx_poll (me, NULL);
        }
      return 1;
      
    default:
      return 0;
    }
  return nr_bytes;
}     
Beispiel #19
0
static void
cris_port_event (struct hw *me,
		 int my_port,
		 struct hw *source,
		 int source_port,
		 int intparam)
{
  struct cris_hw *crishw = hw_data (me);
  unsigned32 vec;

  /* A few placeholders; only the INT port is implemented.  */
  switch (my_port)
    {
    case INT_PORT:
      HW_TRACE ((me, "INT value=0x%x", intparam));
      break;

    default:
      hw_abort (me, "bad switch");
      break;
    }

  if (intparam == 0)
    return;

  if (crishw->int_to_vec != NULL)
    {
      unsigned int i;
      for (i = 0; crishw->int_to_vec[i].portval != 0; i++)
	if (crishw->int_to_vec[i].portval == intparam)
	  break;

      if (crishw->int_to_vec[i].portval == 0)
	hw_abort (me, "unsupported value for int port: 0x%x", intparam);

      vec = crishw->int_to_vec[i].vec;
    }
  else
    vec = (unsigned32) intparam;

  if (crishw->pending_vector != 0)
    {
      if (vec == crishw->pending_vector)
	return;

      switch (crishw->multi_int_action)
	{
	case cris_multint_abort:
	  hw_abort (me, "int 0x%x (0x%x) while int 0x%x hasn't been delivered",
		    vec, intparam, crishw->pending_vector);
	  break;

	case cris_multint_ignore_previous:
	  break;

	case cris_multint_vector:
	  vec = crishw->multiple_int_vector;
	  break;

	default:
	  hw_abort (me, "bad switch");
	}
    }

  crishw->pending_vector = vec;

  /* Schedule our event handler *now*.  */
  if (crishw->pending_handler == NULL)
    crishw->pending_handler
      = hw_event_queue_schedule (me, 0, deliver_cris_interrupt, NULL);
}
void
m68hc11sio_rx_poll (struct hw *me, void *data)
{
  SIM_DESC sd;
  struct m68hc11sio *controller;
  sim_cpu *cpu;
  char cc;
  int cnt;
  int check_interrupt = 0;
  
  controller = hw_data (me);
  sd         = hw_system (me);
  cpu        = STATE_CPU (sd, 0);
  switch (controller->backend)
    {
    case sio_tcp:
      cnt = dv_sockser_read (sd);
      if (cnt != -1)
        {
          cc = (char) cnt;
          cnt = 1;
        }
      break;

    case sio_stdio:
      cnt = sim_io_poll_read (sd, 0 /* stdin */, &cc, 1);
      break;

    default:
      cnt = 0;
      break;
    }

  if (cnt == 1)
    {
      /* Raise the overrun flag if the previous character was not read.  */
      if (cpu->ios[M6811_SCSR] & M6811_RDRF)
        cpu->ios[M6811_SCSR] |= M6811_OR;

      cpu->ios[M6811_SCSR]     |= M6811_RDRF;
      controller->rx_char       = cc;
      controller->rx_clear_scsr = 0;
      check_interrupt = 1;
    }
  else
    {
      /* handle idle line detect here.  */
      ;
    }

  if (controller->rx_poll_event)
    {
      hw_event_queue_deschedule (me, controller->rx_poll_event);
      controller->rx_poll_event = 0;
    }

  if (cpu->ios[M6811_SCCR2] & M6811_RE)
    {
      unsigned long clock_cycle;

      /* Compute CPU clock cycles to wait for the next character.  */
      clock_cycle = controller->data_length * controller->baud_cycle;

      controller->rx_poll_event = hw_event_queue_schedule (me, clock_cycle,
                                                           m68hc11sio_rx_poll,
                                                           NULL);
    }

  if (check_interrupt)
      interrupts_update_pending (&cpu->cpu_interrupts);
}
/* Send enqueued characters from tx_fifo and trigger TX interrupt.
Receive characters into rx_fifo and trigger RX interrupt. */
void
tx3904sio_tickle(struct hw *me)
{
  struct tx3904sio* controller = hw_data(me);
  int c;
  char cc;
  unsigned_4 last_int, next_int;

  /* HW_TRACE ((me, "tickle backend: %02x", controller->backend)); */
  switch(controller->backend) 
    {
    case sio_tcp:

      while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
	{
	  cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
	  dv_sockser_write(hw_system(me), cc);
	  HW_TRACE ((me, "tcp output: %02x", cc));
	}

      c = dv_sockser_read(hw_system(me));
      while(c != -1)
	{
	  cc = (char) c;
	  HW_TRACE ((me, "tcp input: %02x", cc));
	  tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
	  c = dv_sockser_read(hw_system(me));
	}
      break;

    case sio_stdio:

      while(tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
	{
	  cc = tx3904sio_fifo_pop(me, & controller->tx_fifo);
	  sim_io_write_stdout(hw_system(me), & cc, 1);
	  sim_io_flush_stdout(hw_system(me));
	  HW_TRACE ((me, "stdio output: %02x", cc));
	}

      c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
      while(c == 1)
	{
	  HW_TRACE ((me, "stdio input: %02x", cc));
	  tx3904sio_fifo_push(me, & controller->rx_fifo, cc);
	  c = sim_io_poll_read(hw_system(me), 0 /* stdin */, & cc, 1);
	}

      break;

    default:
      hw_abort(me, "Illegal backend mode: %d", controller->backend);
    }

  /* Update RDIS / TDIS flags */
  last_int = controller->sdisr & controller->sdicr;
  /* HW_TRACE ((me, "tickle - sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */
  if(tx3904sio_fifo_nonempty(me, & controller->rx_fifo))
    SDISR_SET_RDIS(controller);
  if(! tx3904sio_fifo_nonempty(me, & controller->tx_fifo))
    SDISR_SET_TDIS(controller);
  next_int = controller->sdisr & controller->sdicr;
  /* HW_TRACE ((me, "tickle + sdisr %08x sdicr %08x", controller->sdisr, controller->sdicr)); */

  if(~last_int & next_int) /* any bits set? */
    hw_port_event(me, INT_PORT, 1);
  if(last_int & ~next_int) /* any bits cleared? */
    hw_port_event(me, INT_PORT, 0);

  /* Add periodic polling for this port, if it's not already going. */
  if(controller->poll_event == NULL)
    {
      controller->poll_event = hw_event_queue_schedule (me, 1000,
							tx3904sio_poll, NULL);

    }
}
void
m68hc11spi_clock (struct hw *me, void *data)
{
  SIM_DESC sd;
  struct m68hc11spi* controller;
  sim_cpu *cpu;
  int check_interrupt = 0;
  
  controller = hw_data (me);
  sd         = hw_system (me);
  cpu        = STATE_CPU (sd, 0);

  /* Cleanup current event.  */
  if (controller->spi_event)
    {
      hw_event_queue_deschedule (me, controller->spi_event);
      controller->spi_event = 0;
    }

  /* Change a bit of data at each two SPI event.  */
  if (controller->mode == SPI_START_BIT)
    {
      /* Reflect the bit value on bit 2 of port D.  */
      set_bit_port (me, cpu, M6811_PORTD, (1 << 2),
                    (controller->tx_char & (1 << controller->tx_bit)));
      controller->tx_bit--;
      controller->mode = SPI_MIDDLE_BIT;
    }
  else if (controller->mode == SPI_MIDDLE_BIT)
    {
      controller->mode = SPI_START_BIT;
    }

  if (controller->mode == SPI_START_BYTE)
    {
      /* Start a new SPI transfer.  */
      
      /* TBD: clear SS output.  */
      controller->mode = SPI_START_BIT;
      controller->tx_bit = 7;
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), ~controller->clk_pin);
    }
  else
    {
      /* Change the SPI clock at each event on bit 4 of port D.  */
      controller->clk_pin = ~controller->clk_pin;
      set_bit_port (me, cpu, M6811_PORTD, (1 << 4), controller->clk_pin);
    }
  
  /* Transmit is now complete for this byte.  */
  if (controller->mode == SPI_START_BIT && controller->tx_bit < 0)
    {
      controller->rx_clear_scsr = 0;
      cpu->ios[M6811_SPSR] |= M6811_SPIF;
      if (cpu->ios[M6811_SPCR] & M6811_SPIE)
        check_interrupt = 1;
    }
  else
    {
      controller->spi_event = hw_event_queue_schedule (me, controller->clock,
                                                       m68hc11spi_clock,
                                                       NULL);
    }

  if (check_interrupt)
    interrupts_update_pending (&cpu->cpu_interrupts);
}
Beispiel #23
0
static void
deliver_mn103cpu_interrupt (struct hw *me,
			    void *data)
{
  struct mn103cpu *controller = hw_data (me);
  SIM_DESC simulator = hw_system (me);
  sim_cpu *cpu = STATE_CPU (simulator, 0);

  if (controller->pending_reset)
    {
      controller->pending_reset = 0;
      /* need to clear all registers et.al! */
      HW_TRACE ((me, "Reset!"));
      hw_abort (me, "Reset!");
    }
  else if (controller->pending_nmi)
    {
      controller->pending_nmi = 0;
      store_word (SP - 4, CPU_PC_GET (cpu));
      store_half (SP - 8, PSW);
      PSW &= ~PSW_IE;
      SP = SP - 8;
      CPU_PC_SET (cpu, 0x40000008);
      HW_TRACE ((me, "nmi pc=0x%08lx psw=0x%04x sp=0x%08lx",
		 (long) CPU_PC_GET (cpu), (unsigned) PSW, (long) SP));
    }
  else if ((controller->pending_level < EXTRACT_PSW_LM)
	   && (PSW & PSW_IE))
    {
      /* Don't clear pending level.  Request continues to be pending
         until the interrupt controller clears/changes it */
      store_word (SP - 4, CPU_PC_GET (cpu));
      store_half (SP - 8, PSW);
      PSW &= ~PSW_IE;
      PSW &= ~PSW_LM;
      PSW |= INSERT_PSW_LM (controller->pending_level);
      SP = SP - 8;
      CPU_PC_SET (cpu, 0x40000000 + controller->interrupt_vector[controller->pending_level]);
      HW_TRACE ((me, "port-out ack %d", controller->pending_level));
      hw_port_event (me, ACK_PORT, controller->pending_level);
      HW_TRACE ((me, "int level=%d pc=0x%08lx psw=0x%04x sp=0x%08lx",
		 controller->pending_level,
		 (long) CPU_PC_GET (cpu), (unsigned) PSW, (long) SP));
    }

  if (controller->pending_level < 7) /* FIXME */
    {
      /* As long as there is the potential need to deliver an
	 interrupt we keep rescheduling this routine. */
      if (controller->pending_handler != NULL)
	controller->pending_handler =
	  hw_event_queue_schedule (me, 1, deliver_mn103cpu_interrupt, NULL);
    }
  else
    {
      /* Don't bother re-scheduling the interrupt handler as there is
         nothing to deliver */
      controller->pending_handler = NULL;
    }

}
Beispiel #24
0
static unsigned
tx3904tmr_io_write_buffer (struct hw *me,
			  const void *source,
			  int space,
			  unsigned_word base,
			  unsigned nr_bytes)
{
  struct tx3904tmr *controller = hw_data (me);
  unsigned byte;

  HW_TRACE ((me, "write 0x%08lx %d", (long) base, (int) nr_bytes));
  for (byte = 0; byte < nr_bytes; byte++)
    {
      address_word address = base + byte;
      unsigned_1 write_byte = ((const char*) source)[byte];
      int reg_number = (address - controller->base_address) / 4;
      int reg_offset = 3 - (address - controller->base_address) % 4;

      /* fill in entire register_value word */
      switch (reg_number)
	{
	case TCR_REG:
	  if(reg_offset == 0) /* first byte */
	    {
	      /* update register, but mask out NOP bits */
	      controller->tcr = (unsigned_4) (write_byte & 0xef);

	      /* Reset counter value if timer suspended and CRE is set. */
	      if(GET_TCR_TCE(controller) == 0 &&
		 GET_TCR_CRE(controller) == 1)
		controller->trr = 0;
	    }
	  /* HW_TRACE ((me, "tcr: %08lx", (long) controller->tcr)); */
	  break;

	case ITMR_REG:
	  if(reg_offset == 1) /* second byte */
	    {
	      SET_ITMR_TIIE(controller, write_byte & 0x80);
	    }
	  else if(reg_offset == 0) /* first byte */
	    {
	      SET_ITMR_TZCE(controller, write_byte & 0x01);
	    }
	  /* HW_TRACE ((me, "itmr: %08lx", (long) controller->itmr)); */
	  break;

	case CCDR_REG:
	  if(reg_offset == 0) /* first byte */
	    {
	      controller->ccdr = write_byte & 0x07;
	    }
	  /* HW_TRACE ((me, "ccdr: %08lx", (long) controller->ccdr)); */
	  break;

	case PMGR_REG:
	  if(reg_offset == 1) /* second byte */
	    {
	      SET_PMGR_TPIBE(controller, write_byte & 0x80);
	      SET_PMGR_TPIAE(controller, write_byte & 0x40);
	    }
	  else if(reg_offset == 0) /* first byte */
	    {
	      SET_PMGR_FFI(controller, write_byte & 0x01);
	    }
	  /* HW_TRACE ((me, "pmgr: %08lx", (long) controller->pmgr)); */
	  break;

	case WTMR_REG:
	  if(reg_offset == 1) /* second byte */
	    {
	      SET_WTMR_TWIE(controller, write_byte & 0x80);
	    }
	  else if(reg_offset == 0) /* first byte */
	    {
	      SET_WTMR_WDIS(controller, write_byte & 0x80);
	      SET_WTMR_TWC(controller, write_byte & 0x01);
	    }
	  /* HW_TRACE ((me, "wtmr: %08lx", (long) controller->wtmr)); */
	  break;

	case TISR_REG:
	  if(reg_offset == 0) /* first byte */
	    {
	      /* All bits must be zero in given byte, according to
                 spec. */

	      /* Send an "interrupt off" event on the interrupt port */
	      if(controller->tisr != 0) /* any interrupts active? */
		{
		  hw_port_event(me, INT_PORT, 0);		  
		}
	      
	      /* clear interrupt status register */
	      controller->tisr = 0;
	    }
	  /* HW_TRACE ((me, "tisr: %08lx", (long) controller->tisr)); */
	  break;

	case CPRA_REG:
	  if(reg_offset < 3) /* first, second, or third byte */
	    {
	      MBLIT32(controller->cpra, (reg_offset*8)+7, (reg_offset*8), write_byte);
	    }
	  /* HW_TRACE ((me, "cpra: %08lx", (long) controller->cpra)); */
	  break;

	case CPRB_REG:
	  if(reg_offset < 3) /* first, second, or third byte */
	    {
	      MBLIT32(controller->cprb, (reg_offset*8)+7, (reg_offset*8), write_byte);
	    }
	  /* HW_TRACE ((me, "cprb: %08lx", (long) controller->cprb)); */
	  break;

	default: 
	  HW_TRACE ((me, "write to illegal register %d", reg_number));
	}
    } /* loop over bytes */

  /* Schedule a timer event in near future, so we can increment or
     stop the counter, to respond to register updates. */
  hw_event_queue_schedule(me, 1, deliver_tx3904tmr_tick, NULL);

  return nr_bytes;
}     
Beispiel #25
0
/* Deliver a clock tick to the counter. */
static void
deliver_tx3904tmr_tick (struct hw *me,
			void *data)
{
  struct tx3904tmr *controller = hw_data (me);
  SIM_DESC sd = hw_system (me);
  signed_8 this_ticks = sim_events_time(sd);

  signed_8 warp;
  signed_8 divisor;
  signed_8 quotient, remainder;

  /* compute simulation ticks between last tick and this tick */
  if(controller->last_ticks != 0)
    warp = this_ticks - controller->last_ticks + controller->roundoff_ticks;
  else
    {
      controller->last_ticks = this_ticks; /* initialize */
      warp = controller->roundoff_ticks;
    }

  if(controller->event != NULL)
    hw_event_queue_deschedule(me, controller->event);
  controller->event = NULL;

  /* Check whether the timer ticking is enabled at this moment.  This
     largely a function of the TCE bit, but is also slightly
     mode-dependent. */
  switch((int) GET_TCR_TMODE(controller))
    {
    case 0: /* interval */
      /* do not advance counter if TCE = 0 or if holding at count = CPRA */
      if(GET_TCR_TCE(controller) == 0 ||
	 controller->trr == controller->cpra)
	return;
      break;

    case 1: /* pulse generator */
      /* do not advance counter if TCE = 0 */
      if(GET_TCR_TCE(controller) == 0)
	return;
      break;

    case 2: /* watchdog */
      /* do not advance counter if TCE = 0 and WDIS = 1 */
      if(GET_TCR_TCE(controller) == 0 &&
	 GET_WTMR_WDIS(controller) == 1)
	return;
      break;

    case 3: /* disabled */
      /* regardless of TCE, do not advance counter */
      return;
    }

  /* In any of the above cases that return, a subsequent register
     write will be needed to restart the timer.  A tick event is
     scheduled by any register write, so it is more efficient not to
     reschedule dummy events here. */


  /* find appropriate divisor etc. */ 
  if(GET_TCR_CCS(controller) == 0) /* internal system clock */
    {
      /* apply internal clock divider */
      if(GET_TCR_CCDE(controller)) /* divisor circuit enabled? */
	divisor = controller->clock_ticks * (1 << (1 + GET_CCDR_CDR(controller)));
      else
	divisor = controller->clock_ticks;
    }
  else
    {
      divisor = controller->ext_ticks;
    }

  /* how many times to increase counter? */
  quotient = warp / divisor;
  remainder = warp % divisor;

  /* NOTE: If the event rescheduling code works properly, the quotient
     should never be larger than 1.  That is, we should receive events
     here at least as frequently as the simulated counter is supposed
     to decrement.  So the remainder (-> roundoff_ticks) will slowly
     accumulate, with the quotient == 0.  Once in a while, quotient
     will equal 1. */

  controller->roundoff_ticks = remainder;
  controller->last_ticks = this_ticks;
  while(quotient > 0) /* Is it time to increment counter? */
    {
      /* next 24-bit counter value */
      unsigned_4 next_trr = (controller->trr + 1) % (1 << 24);
      quotient --;
      
      switch((int) GET_TCR_TMODE(controller))
	{
	case 0: /* interval timer mode */
	  {
	    /* Current or next counter value matches CPRA value?  The
	       first case covers counter holding at maximum before
	       reset.  The second case covers normal counting
	       behavior. */
	    if(controller->trr == controller->cpra ||
	       next_trr == controller->cpra)
	      {
		/* likely hold CPRA value */
		if(controller->trr == controller->cpra)
		  next_trr = controller->cpra;

		SET_TISR_TIIS(controller);

		/* Signal an interrupt if it is enabled with TIIE,
		   and if we just arrived at CPRA.  Don't repeatedly
		   interrupt if holding due to TZCE=0 */
		if(GET_ITMR_TIIE(controller) &&
		   next_trr != controller->trr)
		  {
		    hw_port_event(me, INT_PORT, 1);
		  }

		/* Reset counter? */
		if(GET_ITMR_TZCE(controller))
		  {
		    next_trr = 0;
		  }
	      }
	  }
	break;

	case 1: /* pulse generator mode */
	  {
	    /* first trip point */
	    if(next_trr == controller->cpra)
	      {
		/* flip flip-flop & report */
		controller->ff ^= 1;
		hw_port_event(me, FF_PORT, controller->ff);
		SET_TISR_TPIAS(controller);

		/* signal interrupt */
		if(GET_PMGR_TPIAE(controller))
		  {
		    hw_port_event(me, INT_PORT, 1);
		  }

	      }
	    /* second trip point */
	    else if(next_trr == controller->cprb)
	      {
		/* flip flip-flop & report */
		controller->ff ^= 1;
		hw_port_event(me, FF_PORT, controller->ff);
		SET_TISR_TPIBS(controller);

		/* signal interrupt */
		if(GET_PMGR_TPIBE(controller))
		  {
		    hw_port_event(me, INT_PORT, 1);
		  }

		/* clear counter */
		next_trr = 0;
	      }
	  }
	break;

	case 2: /* watchdog timer mode */
	  {
	    /* watchdog timer expiry */
	    if(next_trr == controller->cpra)
	      {
		SET_TISR_TWIS(controller);

		/* signal interrupt */
		if(GET_WTMR_TWIE(controller))
		  {
		    hw_port_event(me, INT_PORT, 1);
		  }

		/* clear counter */
		next_trr = 0;
	      }
	  }
	break;

	case 3: /* disabled */
	default:
	  break;
	}

      /* update counter and report */
      controller->trr = next_trr;
      /* HW_TRACE ((me, "counter trr %ld tisr %lx",
	 (long) controller->trr, (long) controller->tisr)); */
    } /* end quotient loop */

  /* Reschedule a timer event in near future, so we can increment the
     counter again.  Set the event about 75% of divisor time away, so
     we will experience roughly 1.3 events per counter increment. */
  controller->event = hw_event_queue_schedule(me, divisor*3/4, deliver_tx3904tmr_tick, NULL);
}
Beispiel #26
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);
}