/* Check for interrupts caused by illegal insn access. These conditions are checked in the order specified by the fr400 and fr500 LSI specs. */ void frv_detect_insn_access_interrupts (SIM_CPU *current_cpu, SCACHE *sc) { const CGEN_INSN *insn = sc->argbuf.idesc->idata; SIM_DESC sd = CPU_STATE (current_cpu); FRV_VLIW *vliw = CPU_VLIW (current_cpu); /* Check for vliw constraints. */ if (vliw->constraint_violation) frv_queue_illegal_instruction_interrupt (current_cpu, insn); /* Check for non-excepting insns. */ else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_NON_EXCEPTING) && ! GET_H_PSR_NEM ()) frv_queue_non_implemented_instruction_interrupt (current_cpu, insn); /* Check for conditional insns. */ else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_CONDITIONAL) && ! GET_H_PSR_CM ()) frv_queue_non_implemented_instruction_interrupt (current_cpu, insn); /* Make sure floating point support is enabled. */ else if (! GET_H_PSR_EF ()) { /* Generate fp_disabled if it is a floating point insn or if PSR.EM is off and the insns accesses a fp register. */ if (frv_is_float_insn (insn) || (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS) && ! GET_H_PSR_EM ())) frv_queue_float_disabled_interrupt (current_cpu); } /* Make sure media support is enabled. */ else if (! GET_H_PSR_EM ()) { /* Generate mp_disabled if it is a media insn. */ if (frv_is_media_insn (insn) || CGEN_INSN_NUM (insn) == FRV_INSN_MTRAP) frv_queue_media_disabled_interrupt (current_cpu); } /* Check for privileged insns. */ else if (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_PRIVILEGED) && ! GET_H_PSR_S ()) frv_queue_privileged_instruction_interrupt (current_cpu, insn); #if 0 /* disable for now until we find out how FSR0.QNE gets reset. */ else { /* Enter the halt state if FSR0.QNE is set and we are executing a floating point insn, a media insn or an insn which access a FR register. */ SI fsr0 = GET_FSR (0); if (GET_FSR_QNE (fsr0) && (frv_is_float_insn (insn) || frv_is_media_insn (insn) || CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_FR_ACCESS))) { sim_engine_halt (sd, current_cpu, NULL, GET_H_PC (), sim_stopped, SIM_SIGINT); } } #endif }
struct frv_interrupt_queue_element * frv_queue_non_implemented_instruction_interrupt ( SIM_CPU *current_cpu, const CGEN_INSN *insn ) { SIM_DESC sd = CPU_STATE (current_cpu); switch (STATE_ARCHITECTURE (sd)->mach) { case bfd_mach_fr400: case bfd_mach_fr450: case bfd_mach_fr550: break; default: /* Some machines generate fp_exception or mp_exception for this case. */ if (frv_is_float_insn (insn)) { struct frv_fp_exception_info fp_info = { FSR_NO_EXCEPTION, FTT_UNIMPLEMENTED_FPOP }; return frv_queue_fp_exception_interrupt (current_cpu, & fp_info); } if (frv_is_media_insn (insn)) { frv_set_mp_exception_registers (current_cpu, MTT_UNIMPLEMENTED_MPOP, 0); return NULL; /* no interrupt queued at this time. */ } break; } return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); }
struct frv_interrupt_queue_element * frv_queue_illegal_instruction_interrupt ( SIM_CPU *current_cpu, const CGEN_INSN *insn ) { SIM_DESC sd = CPU_STATE (current_cpu); switch (STATE_ARCHITECTURE (sd)->mach) { case bfd_mach_fr400: case bfd_mach_fr450: case bfd_mach_fr550: break; default: /* Some machines generate fp_exception for this case. */ if (frv_is_float_insn (insn) || frv_is_media_insn (insn)) { struct frv_fp_exception_info fp_info = { FSR_NO_EXCEPTION, FTT_SEQUENCE_ERROR }; return frv_queue_fp_exception_interrupt (current_cpu, & fp_info); } break; } return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION); }
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]); }