Exemple #1
0
/* Queue a division exception.  */
enum frv_dtt
frvbf_division_exception (SIM_CPU *current_cpu, enum frv_dtt dtt,
			  int target_index, int non_excepting)
{
  /* If there was an overflow and it is masked, then record it in
     ISR.AEXC.  */
  USI isr = GET_ISR ();
  if ((dtt & FRV_DTT_OVERFLOW) && GET_ISR_EDE (isr))
    {
      dtt &= ~FRV_DTT_OVERFLOW;
      SET_ISR_AEXC (isr);
      SET_ISR (isr);
    }
  if (dtt != FRV_DTT_NO_EXCEPTION)
    {
      if (non_excepting)
	{
	  /* Non excepting instruction, simply set the NE flag for the target
	     register.  */
	  SI NE_flags[2];
	  GET_NE_FLAGS (NE_flags, H_SPR_GNER0);
	  SET_NE_FLAG (NE_flags, target_index);
	  SET_NE_FLAGS (H_SPR_GNER0, NE_flags);
	}
      else
	frv_queue_division_exception_interrupt (current_cpu, dtt);
    }
  return dtt;
}
/* Process any pending interrupt(s) after a group of parallel insns.  */
void
frv_process_interrupts (SIM_CPU *current_cpu)
{
  SI NE_flags[2];
  /* Need to save the pc here because writeback may change it (due to a
     branch).  */
  IADDR pc = CPU_PC_GET (current_cpu);

  /* Check for a reset before anything else.  */
  if (check_reset (current_cpu, pc))
    return;

  /* First queue the writes for any accumulated NE flags.  */
  if (frv_interrupt_state.f_ne_flags[0] != 0
      || frv_interrupt_state.f_ne_flags[1] != 0)
    {
      GET_NE_FLAGS (NE_flags, H_SPR_FNER0);
      NE_flags[0] |= frv_interrupt_state.f_ne_flags[0];
      NE_flags[1] |= frv_interrupt_state.f_ne_flags[1];
      SET_NE_FLAGS (H_SPR_FNER0, NE_flags);
    }

  /* If there is no interrupt pending, then perform parallel writeback.  This
     may cause an interrupt.  */
  if (frv_interrupt_state.queue_index <= 0)
    frvbf_perform_writeback (current_cpu);

  /* If there is an interrupt pending, then process it.  */
  if (frv_interrupt_state.queue_index > 0)
    handle_interrupt (current_cpu, pc);
}
Exemple #3
0
void
frvbf_commit (SIM_CPU *current_cpu, SI target_index, BI is_float)
{
  SI NE_base;
  SI NE_flags[2];
  BI NE_flag;
  int exception;
  int hi_available;
  int lo_available;
  USI necr;
  FRV_REGISTER_CONTROL *control;

  /* Check for availability of the target register(s).  */
  which_registers_available (current_cpu, & hi_available, & lo_available,
			     is_float);

  /* Check to make sure that the target register is available.  */
  if (! frv_check_register_access (current_cpu, target_index,
				   hi_available, lo_available))
    return;

  /* Determine whether we're working with GR or FR registers.  */
  if (is_float)
    NE_base = H_SPR_FNER0;
  else
    NE_base = H_SPR_GNER0;

  /* Determine whether a ne exception is pending.  */
  GET_NE_FLAGS (NE_flags, NE_base);
  if (target_index >= 0)
    NE_flag = GET_NE_FLAG (NE_flags, target_index);
  else
    {
      NE_flag =
	hi_available && NE_flags[0] != 0 || lo_available && NE_flags[1] != 0;
    }

  /* Always clear the appropriate NE flags.  */
  clear_ne_flags (current_cpu, target_index, hi_available, lo_available,
		  NE_base);

  control = CPU_REGISTER_CONTROL (current_cpu);
  if (control->spr[H_SPR_NECR].implemented)
    {
      necr = GET_NECR ();
      if (GET_NECR_VALID (necr) && GET_NECR_ELOS (necr) && NE_flag)
	{
	  /* Clear the appropriate NESR and NEEAR registers.  */
	  clear_nesr_neear (current_cpu, target_index, is_float);
	  frv_queue_program_interrupt (current_cpu, FRV_COMMIT_EXCEPTION);
	}
    }
}
Exemple #4
0
static void
clear_ne_flags (
  SIM_CPU *current_cpu,
  SI target_index,
  int hi_available,
  int lo_available,
  SI NE_base
)
{
  SI NE_flags[2];
  int exception;

  GET_NE_FLAGS (NE_flags, NE_base);
  if (target_index >= 0)
    CLEAR_NE_FLAG (NE_flags, target_index);
  else
    {
      if (lo_available)
	NE_flags[1] = 0;
      if (hi_available)
	NE_flags[0] = 0;
    }
  SET_NE_FLAGS (NE_base, NE_flags);
}
Exemple #5
0
BI
frvbf_check_non_excepting_load (
  SIM_CPU *current_cpu, SI base_index, SI disp_index, SI target_index,
  SI immediate_disp, QI data_size, BI is_float
)
{
  BI rc = 1; /* perform the load.  */
  SIM_DESC sd = CPU_STATE (current_cpu);
  int daec = 0;
  int rec  = 0;
  int ec   = 0;
  USI necr;
  int do_elos;
  SI NE_flags[2];
  SI NE_base;
  SI nesr;
  SI ne_index;
  FRV_REGISTER_CONTROL *control;

  SI address = GET_H_GR (base_index);
  if (disp_index >= 0)
    address += GET_H_GR (disp_index);
  else
    address += immediate_disp;

  /* Check for interrupt factors.  */
  switch (data_size)
    {
    case NESR_UQI_SIZE:
    case NESR_QI_SIZE:
      break;
    case NESR_UHI_SIZE:
    case NESR_HI_SIZE:
      if (address & 1)
	ec = 1;
      break;
    case NESR_SI_SIZE:
      if (address & 3)
	ec = 1;
      break;
    case NESR_DI_SIZE:
      if (address & 7)
	ec = 1;
      if (target_index & 1)
	rec = 1;
      break;
    case NESR_XI_SIZE:
      if (address & 0xf)
	ec = 1;
      if (target_index & 3)
	rec = 1;
      break;
    default:
      {
	IADDR pc = GET_H_PC ();
	sim_engine_abort (sd, current_cpu, pc, 
			  "check_non_excepting_load: Incorrect data_size\n");
	break;
      }
    }

  control = CPU_REGISTER_CONTROL (current_cpu);
  if (control->spr[H_SPR_NECR].implemented)
    {
      necr = GET_NECR ();
      do_elos = GET_NECR_VALID (necr) && GET_NECR_ELOS (necr);
    }
  else
    do_elos = 0;

  /* NECR, NESR, NEEAR are only implemented for the full frv machine.  */
  if (do_elos)
    {
      ne_index = next_available_nesr (current_cpu, NO_NESR);
      if (ne_index == NO_NESR)
	{
	  IADDR pc = GET_H_PC ();
	  sim_engine_abort (sd, current_cpu, pc, 
			    "No available NESR register\n");
	}

      /* Fill in the basic fields of the NESR.  */
      nesr = GET_NESR (ne_index);
      SET_NESR_VALID (nesr);
      SET_NESR_EAV (nesr);
      SET_NESR_DRN (nesr, target_index);
      SET_NESR_SIZE (nesr, data_size);
      SET_NESR_NEAN (nesr, ne_index);
      if (is_float)
	SET_NESR_FR (nesr);
      else
	CLEAR_NESR_FR (nesr);

      /* Set the corresponding NEEAR.  */
      SET_NEEAR (ne_index, address);
  
      SET_NESR_DAEC (nesr, 0);
      SET_NESR_REC (nesr, 0);
      SET_NESR_EC (nesr, 0);
    }

  /* Set the NE flag corresponding to the target register if an interrupt
     factor was detected. 
     daec is not checked here yet, but is declared for future reference.  */
  if (is_float)
    NE_base = H_SPR_FNER0;
  else
    NE_base = H_SPR_GNER0;

  GET_NE_FLAGS (NE_flags, NE_base);
  if (rec)
    {
      SET_NE_FLAG (NE_flags, target_index);
      if (do_elos)
	SET_NESR_REC (nesr, NESR_REGISTER_NOT_ALIGNED);
    }

  if (ec)
    {
      SET_NE_FLAG (NE_flags, target_index);
      if (do_elos)
	SET_NESR_EC (nesr, NESR_MEM_ADDRESS_NOT_ALIGNED);
    }

  if (do_elos)
    SET_NESR (ne_index, nesr);

  /* If no interrupt factor was detected then set the NE flag on the
     target register if the NE flag on one of the input registers
     is already set.  */
  if (! rec && ! ec && ! daec)
    {
      BI ne_flag = GET_NE_FLAG (NE_flags, base_index);
      if (disp_index >= 0)
	ne_flag |= GET_NE_FLAG (NE_flags, disp_index);
      if (ne_flag)
	{
	  SET_NE_FLAG (NE_flags, target_index);
	  rc = 0; /* Do not perform the load.  */
	}
      else
	CLEAR_NE_FLAG (NE_flags, target_index);
    }

  SET_NE_FLAGS (NE_base, NE_flags);

  return rc; /* perform the load?  */
}