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;
    }

}
void
sim_board_reset (SIM_DESC sd)
{
  struct hw *hw_cpu;
  sim_cpu *cpu;
  const struct bfd_arch_info *arch;
  const char *cpu_type;

  cpu = STATE_CPU (sd, 0);
  arch = STATE_ARCHITECTURE (sd);

  /*  hw_cpu = sim_hw_parse (sd, "/"); */
  if (arch->arch == bfd_arch_m68hc11)
    {
      cpu->cpu_type = CPU_M6811;
      cpu_type = "/m68hc11";
    }
  else
    {
      cpu->cpu_type = CPU_M6812;
      cpu_type = "/m68hc12";
    }
  
  hw_cpu = sim_hw_parse (sd, cpu_type);
  if (hw_cpu == 0)
    {
      sim_io_eprintf (sd, "%s cpu not found in device tree.", cpu_type);
      return;
    }

  cpu_reset (cpu);
  hw_port_event (hw_cpu, 3, 0);
  cpu_restart (cpu);
}
Exemple #3
0
static void
write_txb (struct hw *me,
	   struct mn103ser *serial,
	   unsigned_word serial_reg,
	   const void *source,
	   unsigned  nr_bytes)
{
  if ( nr_bytes == 1 )
    {
      serial->device[serial_reg].txb = *(unsigned8 *)source;

      if(USE_SOCKSER_P)
	{
	  dv_sockser_write(hw_system (me), * (char*) source);
	}
      else
	{
	  sim_io_write_stdout(hw_system (me), (char *)source, 1);
	  sim_io_flush_stdout(hw_system (me));
	}

      hw_port_event (me, serial_reg+SERIAL0_SEND, 1);
    }
  else
    {
      hw_abort (me, "bad write size of %d bytes to SC%dTXB.", nr_bytes, 
		serial_reg);
    }
}
Exemple #4
0
static void
write_txb (struct hw *me,
	   struct mn103ser *serial,
	   unsigned_word serial_reg,
	   const void *source,
	   unsigned  nr_bytes)
{
  if ( nr_bytes == 1 )
    {
      SIM_DESC sd = hw_system (me);
      int status;

      serial->device[serial_reg].txb = *(unsigned8 *)source;

      status = dv_sockser_status (sd);
      if (!(status & DV_SOCKSER_DISCONNECTED))
	{
	  dv_sockser_write(sd, * (char*) source);
	}
      else
	{
	  sim_io_write_stdout(sd, (char *)source, 1);
	  sim_io_flush_stdout(sd);
	}

      hw_port_event (me, serial_reg+SERIAL0_SEND, 1);
    }
  else
    {
      hw_abort (me, "bad write size of %d bytes to SC%dTXB.", nr_bytes, 
		serial_reg);
    }
}
Exemple #5
0
static void
bfin_gpio_port_event (struct hw *me, int my_port, struct hw *source,
		      int source_port, int level)
{
  struct bfin_gpio *port = hw_data (me);
  bu32 bit = (1 << my_port);

  /* Normalize the level value.  A simulated device can send any value
     it likes to us, but in reality we only care about 0 and 1.  This
     lets us assume only those two values below.  */
  level = !!level;

  HW_TRACE ((me, "pin %i set to %i", my_port, level));

  /* Only screw with state if this pin is set as an input, and the
     input is actually enabled, and it isn't in peripheral mode.  */
  if ((port->dir & bit) || !(port->inen & bit) || !(port->fer & bit))
    {
      HW_TRACE ((me, "ignoring level due to DIR=%i INEN=%i FER=%i",
		 !!(port->dir & bit), !!(port->inen & bit),
		 !!(port->fer & bit)));
      return;
    }

  hw_port_event (me, my_port, level);
}
Exemple #6
0
static unsigned
bfin_uart_io_write_buffer (struct hw *me, const void *source,
			   int space, address_word addr, unsigned nr_bytes)
{
  struct bfin_uart *uart = hw_data (me);
  bu32 mmr_off;
  bu32 value;
  bu16 *valuep;

  /* Invalid access mode is higher priority than missing register.  */
  if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
    return 0;

  value = dv_load_2 (source);
  mmr_off = addr - uart->base;
  valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);

  HW_TRACE_WRITE ();

  /* XXX: All MMRs are "8bit" ... what happens to high 8bits ?  */

  switch (mmr_off)
    {
    case mmr_offset(thr):
      uart->thr = bfin_uart_write_byte (me, value, uart->mcr);
      if (uart->ier & ETBEI)
	hw_port_event (me, DV_PORT_TX, 1);
      break;
    case mmr_offset(ier_set):
      uart->ier |= value;
      break;
    case mmr_offset(ier_clear):
      dv_w1c_2 (&uart->ier, value, -1);
      break;
    case mmr_offset(lsr):
      dv_w1c_2 (valuep, value, TFI | BI | FE | PE | OE);
      break;
    case mmr_offset(rbr):
      /* XXX: Writes are ignored ?  */
      break;
    case mmr_offset(msr):
      dv_w1c_2 (valuep, value, SCTS);
      break;
    case mmr_offset(dll):
    case mmr_offset(dlh):
    case mmr_offset(gctl):
    case mmr_offset(lcr):
    case mmr_offset(mcr):
    case mmr_offset(scr):
      *valuep = value;
      break;
    default:
      dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
      return 0;
    }

  return nr_bytes;
}
Exemple #7
0
static unsigned
bfin_uart_io_write_buffer (struct hw *me, const void *source,
			   int space, address_word addr, unsigned nr_bytes)
{
  struct bfin_uart *uart = hw_data (me);
  bu32 mmr_off;
  bu32 value;
  bu16 *valuep;

  value = dv_load_2 (source);
  mmr_off = addr - uart->base;
  valuep = (void *)((unsigned long)uart + mmr_base() + mmr_off);

  HW_TRACE_WRITE ();

  dv_bfin_mmr_require_16 (me, addr, nr_bytes, true);

  /* XXX: All MMRs are "8bit" ... what happens to high 8bits ?  */
  switch (mmr_off)
    {
    case mmr_offset(dll):
      if (uart->lcr & DLAB)
	uart->dll = value;
      else
	{
	  uart->thr = bfin_uart_write_byte (me, value, uart->mcr);

	  if (uart->ier & ETBEI)
	    hw_port_event (me, DV_PORT_TX, 1);
	}
      break;
    case mmr_offset(dlh):
      if (uart->lcr & DLAB)
	uart->dlh = value;
      else
	{
	  uart->ier = value;
	  bfin_uart_reschedule (me);
	}
      break;
    case mmr_offset(iir):
    case mmr_offset(lsr):
      /* XXX: Writes are ignored ?  */
      break;
    case mmr_offset(lcr):
    case mmr_offset(mcr):
    case mmr_offset(scr):
    case mmr_offset(gctl):
      *valuep = value;
      break;
    default:
      dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
      break;
    }

  return nr_bytes;
}
static void
push_interrupt_level (struct hw *me,
		      struct mn103int *controller)
{
  int selected = find_highest_interrupt_group (me, controller);
  int level = controller->group[selected].level;
  HW_TRACE ((me, "port-out - selected=%d level=%d", selected, level));
  hw_port_event (me, LEVEL_PORT, level);
}
static unsigned
hw_pal_io_write_buffer (struct hw *me,
			const void *source,
			int space,
			unsigned_word addr,
			unsigned nr_bytes)
{
  hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me);
  unsigned_1 *byte = (unsigned_1 *) source;
  
  switch (addr & hw_pal_address_mask)
    {

    case hw_pal_reset_register:
      hw_halt (me, sim_exited, byte[0]);
      break;

    case hw_pal_int_register:
      hw_port_event (me,
		     INT_PORT + byte[0], /*port*/
		     (nr_bytes > 1 ? byte[1] : 0)); /* val */
      break;

    case hw_pal_read_fifo:
      hw_pal->input.buffer = byte[0];
      HW_TRACE ((me, "write - input-fifo %d\n", byte[0]));
      break;

    case hw_pal_read_status:
      hw_pal->input.status = byte[0];
      HW_TRACE ((me, "write - input-status %d\n", byte[0]));
      break;

    case hw_pal_write_fifo:
      write_hw_pal (me, byte[0]);
      HW_TRACE ((me, "write - output-fifo %d\n", byte[0]));
      break;

    case hw_pal_write_status:
      hw_pal->output.status = byte[0];
      HW_TRACE ((me, "write - output-status %d\n", byte[0]));
      break;

    case hw_pal_countdown:
      do_counter_write (me, hw_pal, "countdown",
			&hw_pal->countdown, source, nr_bytes);
      break;
      
    case hw_pal_timer:
      do_counter_write (me, hw_pal, "timer",
			&hw_pal->timer, source, nr_bytes);
      break;
      
    }
  return nr_bytes;
}
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
bfin_wdog_port_event (struct hw *me, int my_port, struct hw *source,
                      int source_port, int level)
{
    struct bfin_wdog *wdog = hw_data (me);
    bu16 wdev;

    wdog->ctl |= WDRO;
    wdev = (wdog->ctl & WDEV);
    if (wdev != WDEV_NONE)
        hw_port_event (me, wdev, 1);
}
Exemple #12
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);

}
Exemple #13
0
static void
bfin_uart_poll (struct hw *me, void *data)
{
  struct bfin_uart *uart = data;
  bu16 lsr;

  uart->handler = NULL;

  lsr = bfin_uart_get_status (me);
  if (lsr & DR)
    hw_port_event (me, DV_PORT_RX, 1);

  bfin_uart_reschedule (me);
}
Exemple #14
0
static unsigned
bfin_uart_dma_write_buffer (struct hw *me, const void *source,
			    int space, unsigned_word addr,
			    unsigned nr_bytes,
			    int violate_read_only_section)
{
  struct bfin_uart *uart = hw_data (me);
  unsigned ret;

  HW_TRACE_DMA_WRITE ();

  ret = bfin_uart_write_buffer (me, source, nr_bytes);

  if (ret == nr_bytes && (uart->ier & ETBEI))
    hw_port_event (me, DV_PORT_TX, 1);

  return ret;
}
Exemple #15
0
static void
bfin_ctimer_expire (struct hw *me, void *data)
{
  struct bfin_ctimer *ctimer = data;

  ctimer->tcntl |= TINT;
  if (ctimer->tcntl & TAUTORLD)
    {
      ctimer->tcount = ctimer->tperiod;
      bfin_ctimer_schedule (me, ctimer);
    }
  else
    {
      ctimer->tcount = 0;
      ctimer->handler = NULL;
    }

  hw_port_event (me, IVG_IVTMR, 1);
}
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;
    }

}
Exemple #17
0
static void
do_uart_tx_event (struct hw *me, void *data)
{
  struct lm32uart *uart = hw_data (me);
  char c;

  /* Generate interrupt when transmission is complete.  */
  if (uart->ier & LM32_UART_IER_TX_INT)
    {
      /* Generate interrupt */
      hw_port_event (me, INT_PORT, 1);
    }

  /* Indicate which interrupt has occured.  */
  uart->iir = MICOUART_IIR_TXRDY;

  /* Indicate THR is empty.  */
  uart->lsr |= LM32_UART_LSR_TX_RDY;

  /* Output the character in the THR.  */
  c = (char) uart->thr;

  /* WLS field in LCR register specifies the number of bits to output.  */
  switch (uart->lcr & LM32_UART_LCR_WLS_MASK)
    {
    case LM32_UART_LCR_WLS_5:
      c &= 0x1f;
      break;
    case LM32_UART_LCR_WLS_6:
      c &= 0x3f;
      break;
    case LM32_UART_LCR_WLS_7:
      c &= 0x7f;
      break;
    }
  printf ("%c", c);
}
Exemple #18
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;
    }

}
static void
mn103int_port_event (struct hw *me,
		     int my_port,
		     struct hw *source,
		     int source_port,
		     int level)
{
  struct mn103int *controller = hw_data (me);

  switch (my_port)
    {

    case ACK_PORT:
      {
	int selected = find_highest_interrupt_group (me, controller);
	if (controller->group[selected].level != level)
	  hw_abort (me, "botched level synchronisation");
	controller->interrupt_accepted_group = selected;	
	HW_TRACE ((me, "port-event port=ack level=%d - selected=%d",
		   level, selected));
	break;
      }

    default:
      {
	int gid;
	int iid;
	struct mn103int_group *group;
	unsigned interrupt;
	if (my_port > NR_G_PORTS)
	  hw_abort (me, "Event on unknown port %d", my_port);

	/* map the port onto an interrupt group */
	gid = (my_port % NR_G_PORTS) / 4;
	group = &controller->group[gid];
	iid = (my_port % 4);
	interrupt = 1 << iid;

	/* update our cached input */
	if (level)
	  group->input |= interrupt;
	else
	  group->input &= ~interrupt;

	/* update the request bits */
	switch (group->trigger)
	  {
	  case ACTIVE_LOW:
	  case ACTIVE_HIGH:
	    if (level)
	      group->request |= interrupt;
	    break;
	  case NEGATIVE_EDGE:
	  case POSITIVE_EDGE:
	    group->request |= interrupt;
	  }

	/* force a corresponding output */
	switch (group->type)
	  {

	  case NMI_GROUP:
	    {
	      /* for NMI's the event is the trigger */
	      HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - NMI",
			 my_port, gid, iid));
	      if ((group->request & group->enable) != 0)
		{
		  HW_TRACE ((me, "port-out NMI"));
		  hw_port_event (me, NMI_PORT, 1);
		}
	      break;
	    }
	      
	  case LEVEL_GROUP:
	    {
	      /* if an interrupt is now pending */
	      HW_TRACE ((me, "port-in port=%d group=%d interrupt=%d - INT",
			 my_port, gid, iid));
	      push_interrupt_level (me, controller);
	      break;
	    }
	  }
	break;
      }

    }
}
Exemple #20
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;
}     
Exemple #21
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);
}
/* 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);

    }
}
static unsigned
tx3904sio_io_write_buffer (struct hw *me,
			  const void *source,
			  int space,
			  unsigned_word base,
			  unsigned nr_bytes)
{
  struct tx3904sio *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 unsigned char*) source)[byte];
      int reg_number = (address - controller->base_address) / 4;
      int reg_offset = 3 - (address - controller->base_address) % 4;

      /* HW_TRACE ((me, "byte %d %02x", reg_offset, write_byte)); */

      /* fill in entire register_value word */
      switch (reg_number)
	{
	case SLCR_REG:
	  SLCR_SET_BYTE(controller, reg_offset, write_byte);
	  break;

	case SLSR_REG: /* unwriteable */ break;

	case SDICR_REG:
	  {
	    unsigned_4 last_int, next_int;
	    
	    /* deassert interrupt upon clear */
	    last_int = controller->sdisr & controller->sdicr;
	    /* HW_TRACE ((me, "sdicr - sdisr %08x sdicr %08x",
	       controller->sdisr, controller->sdicr)); */
	    SDICR_SET_BYTE(controller, reg_offset, write_byte);
	    /* HW_TRACE ((me, "sdicr + sdisr %08x sdicr %08x",
	       controller->sdisr, controller->sdicr)); */
	    next_int = controller->sdisr & controller->sdicr;
	    
	    if(SDICR_GET_SDMAE(controller))
	      hw_abort(me, "Cannot support DMA-driven sio.");

	    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);
	  }
	break;

	case SDISR_REG:
	  {
	    unsigned_4 last_int, next_int;

	    /* deassert interrupt upon clear */
	    last_int = controller->sdisr & controller->sdicr;
	    /* HW_TRACE ((me, "sdisr - sdisr %08x sdicr %08x", 
	       controller->sdisr, controller->sdicr)); */
	    SDISR_CLEAR_FLAG_BYTE(controller, reg_offset, write_byte);
	    /* HW_TRACE ((me, "sdisr + sdisr %08x sdicr %08x", 
	       controller->sdisr, controller->sdicr)); */
	    next_int = 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);
	  }
	break;
	
	case SFCR_REG:
	  SFCR_SET_BYTE(controller, reg_offset, write_byte);
	  if(SFCR_GET_FRSTE(controller))
	    {
	      if(SFCR_GET_TFRST(controller)) tx3904sio_fifo_reset(me, & controller->tx_fifo);
	      if(SFCR_GET_RFRST(controller)) tx3904sio_fifo_reset(me, & controller->rx_fifo);
	    }
	  break;
	  
	case SBGR_REG:
	  SBGR_SET_BYTE(controller, reg_offset, write_byte);
	  break;
	  
	case SFIFO_REG: /* unwriteable */ break;
	  
	case TFIFO_REG: 
	  if(reg_offset == 3) /* first byte */
	    tx3904sio_fifo_push(me, & controller->tx_fifo, write_byte);
	  break;

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

  /* tickle fifos */
  tx3904sio_tickle(me);

  return nr_bytes;
}     
Exemple #24
0
static unsigned
bfin_gpio_io_write_buffer (struct hw *me, const void *source, int space,
			   address_word addr, unsigned nr_bytes)
{
  struct bfin_gpio *port = hw_data (me);
  bu32 mmr_off;
  bu32 value;
  bu16 *value16p;
  bu32 *value32p;
  void *valuep;

  mmr_off = addr - port->base;

  /* Invalid access mode is higher priority than missing register.  */
  if (mmr_off == mmr_offset (mux))
    {
      if (!dv_bfin_mmr_require_32 (me, addr, nr_bytes, true))
	return 0;
    }
  else
    if (!dv_bfin_mmr_require_16 (me, addr, nr_bytes, true))
	return 0;

  if (nr_bytes == 4)
    value = dv_load_4 (source);
  else
    value = dv_load_2 (source);
  valuep = (void *)((unsigned long)port + mmr_base() + mmr_off);
  value16p = valuep;
  value32p = valuep;

  HW_TRACE_WRITE ();

  switch (mmr_off)
    {
    case mmr_offset(fer):
    case mmr_offset(data):
    case mmr_offset(inen):
      *value16p = value;
      break;
    case mmr_offset(clear):
      /* We want to clear the related data MMR.  */
      dv_w1c_2 (&port->data, value, -1);
      break;
    case mmr_offset(set):
      /* We want to set the related data MMR.  */
      port->data |= value;
      break;
    case mmr_offset(dir_clear):
      dv_w1c_2 (&port->dir, value, -1);
      break;
    case mmr_offset(dir_set):
      port->dir |= value;
      break;
    case mmr_offset(mux):
      *value32p = value;
      break;
    default:
      dv_bfin_mmr_invalid (me, addr, nr_bytes, true);
      return 0;
    }

  /* If tweaking output pins, make sure we send updated port info.  */
  switch (mmr_off)
    {
    case mmr_offset(data):
    case mmr_offset(set):
    case mmr_offset(clear):
    case mmr_offset(dir_set):
      {
	int i;
	bu32 bit;

	for (i = 0; i < 16; ++i)
	  {
	    bit = (1 << i);

	    if (!(port->inen & bit))
	      hw_port_event (me, i, !!(port->data & bit));
	  }

	break;
      }
    }

  return nr_bytes;
}
Exemple #25
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;
}
Exemple #26
0
static void
tx3904irc_port_event (struct hw *me,
		     int my_port,
		     struct hw *source_dev,
		     int source_port,
		     int level)
{
  struct tx3904irc *controller = hw_data (me);

  /* handle deactivated interrupt */
  if(level == 0)
    {
      HW_TRACE ((me, "interrupt cleared on port %d", my_port));
      hw_port_event(me, IP_PORT, 0);
      return;
    }

  switch (my_port)
    {
    case INT0_PORT: 
      {
	int ip_number = 32; /* compute IP[5:0] */
	HW_TRACE ((me, "port-event INT[0]"));
	hw_port_event(me, IP_PORT, ip_number);
	break;
      }

    case INT1_PORT: case INT2_PORT: case INT3_PORT: case INT4_PORT:
    case INT5_PORT: case INT6_PORT: case INT7_PORT: case DMAC3_PORT:
    case DMAC2_PORT: case DMAC1_PORT: case DMAC0_PORT: case SIO0_PORT:
    case SIO1_PORT: case TMR0_PORT: case TMR1_PORT: case TMR2_PORT:
      {
	int source = my_port - INT1_PORT;

	HW_TRACE ((me, "interrupt asserted on port %d", source));
	ISR_SET(controller, source);
	if(ILR_GET(controller, source) > IMR_GET(controller))
	  {
	    int ip_number = 16 + source; /* compute IP[4:0] */
	    HW_TRACE ((me, "interrupt level %d", ILR_GET(controller,source)));
	    hw_port_event(me, IP_PORT, ip_number);
	  }
	break;
      }

    case RESET_PORT:
      {
	HW_TRACE ((me, "reset"));
	controller->isr = 0x0000ffff;
	controller->imr = 0;
	controller->ilr[0] =
	  controller->ilr[1] =
	  controller->ilr[2] =
	  controller->ilr[3] = 0;
	break;
      }

    case IP_PORT:
      hw_abort (me, "Event on output port %d", my_port);
      break;

    default:
      hw_abort (me, "Event on unknown port %d", my_port);
      break;
    }
}
Exemple #27
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);
    }
}