/* Set FSR0, FQ0-FQ9, depending on the interrupt.  */
static void
set_fp_exception_registers (
  SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
)
{
  int fq_index;
  SI fq;
  SI insn;
  SI fsr0;
  IADDR pc;
  struct frv_fp_exception_info *fp_info;
  SIM_DESC sd = CPU_STATE (current_cpu);

  /* No FQ registers on fr550 */
  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
    {
      /* Update the fsr.  */
      fp_info = & item->u.fp_info;
      fsr0 = GET_FSR (0);
      SET_FSR_FTT (fsr0, fp_info->ftt);
      SET_FSR (0, fsr0);
      return;
    }

  /* Select an FQ and update it with the exception information.  */
  fq_index = fq_for_exception (current_cpu, item);
  if (fq_index == -1)
    return;

  fp_info = & item->u.fp_info;
  fq = GET_FQ (fq_index);
  SET_FQ_MIV (fq, MIV_FLOAT);
  SET_FQ_SIE (fq, SIE_NIL);
  SET_FQ_FTT (fq, fp_info->ftt);
  SET_FQ_CEXC (fq, fp_info->fsr_mask);
  SET_FQ_VALID (fq);
  SET_FQ (fq_index, fq);

  /* Write the failing insn into FQx.OPC.  */
  pc = item->vpc;
  insn = GETMEMSI (current_cpu, pc, pc);
  SET_FQ_OPC (fq_index, insn);

  /* Update the fsr.  */
  fsr0 = GET_FSR (0);
  SET_FSR_QNE (fsr0); /* FQ not empty */
  SET_FSR_FTT (fsr0, fp_info->ftt);
  SET_FSR (0, fsr0);
}
/* Queue the given fp_exception interrupt. Also update fp_info by removing
   masked interrupts and updating the 'slot' flield.  */
struct frv_interrupt_queue_element *
frv_queue_fp_exception_interrupt (
  SIM_CPU *current_cpu, struct frv_fp_exception_info *fp_info
)
{
  SI fsr0 = GET_FSR (0);
  int tem = GET_FSR_TEM (fsr0);
  int aexc = GET_FSR_AEXC (fsr0);
  struct frv_interrupt_queue_element *new_element = NULL;

  /* Update AEXC with the interrupts that are masked.  */
  aexc |= fp_info->fsr_mask & ~tem;
  SET_FSR_AEXC (fsr0, aexc);
  SET_FSR (0, fsr0);

  /* update fsr_mask with the exceptions that are enabled.  */
  fp_info->fsr_mask &= tem;

  /* If there is an unmasked interrupt then queue it, unless
     this was a non-excepting insn, in which case simply set the NE
     status registers.  */
  if (frv_interrupt_state.ne_index != NE_NOFLAG
      && fp_info->fsr_mask != FSR_NO_EXCEPTION)
    {
      SET_NE_FLAG (frv_interrupt_state.f_ne_flags, 
		   frv_interrupt_state.ne_index);
      /* TODO -- Set NESR for chips which support it.  */
      new_element = NULL;
    }
  else if (fp_info->fsr_mask != FSR_NO_EXCEPTION
	   || fp_info->ftt == FTT_UNIMPLEMENTED_FPOP
	   || fp_info->ftt == FTT_SEQUENCE_ERROR
	   || fp_info->ftt == FTT_INVALID_FR)
    {
      new_element = frv_queue_program_interrupt (current_cpu, FRV_FP_EXCEPTION);
      new_element->u.fp_info = *fp_info;
    }

  return new_element;
}
void
frv_vliw_setup_insn (SIM_CPU *current_cpu, const CGEN_INSN *insn)
{
  FRV_VLIW *vliw;
  int index;

  /* Always clear the NE index which indicates the target register
     of a non excepting insn. This will be reset by the insn if
     necessary.  */
  frv_interrupt_state.ne_index = NE_NOFLAG;

  vliw = CPU_VLIW (current_cpu);
  index = vliw->next_slot - 1;
  if (frv_is_float_insn (insn))
    {
      /* If the insn is to be added and is a floating point insn and
	 it is the first floating point insn in the vliw, then clear
	 FSR0.FTT.  */
      int i;
      for (i = 0; i < index; ++i)
	if (frv_is_float_major (vliw->major[i], vliw->mach))
	  break; /* found float insn.  */
      if (i >= index)
	{
	  SI fsr0 = GET_FSR (0);
	  SET_FSR_FTT (fsr0, FTT_NONE);
	  SET_FSR (0, fsr0);
	}
    }
  else if (frv_is_media_insn (insn))
    {
      /* Clear the appropriate MSR fields depending on which slot
	 this insn is in.  */
      CGEN_ATTR_VALUE_ENUM_TYPE preserve_ovf;
      SI msr0 = GET_MSR (0);

      preserve_ovf = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_PRESERVE_OVF);
      if ((*vliw->current_vliw)[index] == UNIT_FM0)
	{
	  if (! preserve_ovf)
	    {
	      /* Clear MSR0.OVF and MSR0.SIE.  */
	      CLEAR_MSR_SIE (msr0);
	      CLEAR_MSR_OVF (msr0);
	    }
	}
      else
	{
	  if (! preserve_ovf)
	    {
	      /* Clear MSR1.OVF and MSR1.SIE.  */
	      SI msr1 = GET_MSR (1);
	      CLEAR_MSR_SIE (msr1);
	      CLEAR_MSR_OVF (msr1);
	      SET_MSR (1, msr1);
	    }
	}
      SET_MSR (0, msr0);
    } /* Insn is a media insns.  */
  COUNT_INSNS_IN_SLOT ((*vliw->current_vliw)[index]);
}