/* 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]); }