📄 interrupts.c
字号:
{ frvbf_perform_writeback (current_cpu); writeback_done = 1; continue; } frv_external_interrupt (current_cpu, item, pc); return; case FRV_SOFTWARE_INTERRUPT: frv_interrupt_state.queue_index = index; frv_software_interrupt (current_cpu, item, pc); return; case FRV_PROGRAM_INTERRUPT: /* If the program interrupt is not strict (imprecise), then perform writeback first. This may, in turn, cause a higher priority interrupt. */ if (! interrupt->precise && ! writeback_done) { frv_interrupt_state.imprecise_interrupt = item; frvbf_perform_writeback (current_cpu); writeback_done = 1; continue; } frv_interrupt_state.queue_index = index; frv_program_interrupt (current_cpu, item, pc); return; case FRV_BREAK_INTERRUPT: frv_interrupt_state.queue_index = index; frv_break_interrupt (current_cpu, interrupt, pc); return; case FRV_RESET_INTERRUPT: break; default: break; } frv_interrupt_state.queue_index = index; break; /* out of loop. */ } /* We should never get here. */ { SIM_DESC sd = CPU_STATE (current_cpu); sim_engine_abort (sd, current_cpu, pc, "interrupt class not supported %d\n", interrupt->iclass); }}/* Check to see the if the RSTR.HR or RSTR.SR bits have been set. If so, handle the appropriate reset interrupt. */static intcheck_reset (SIM_CPU *current_cpu, IADDR pc){ int hsr0; int hr; int sr; SI rstr; FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu); IADDR address = RSTR_ADDRESS; /* We don't want this to show up in the cache statistics, so read the cache passively. */ if (! frv_cache_read_passive_SI (cache, address, & rstr)) rstr = sim_core_read_unaligned_4 (current_cpu, pc, read_map, address); hr = GET_RSTR_HR (rstr); sr = GET_RSTR_SR (rstr); if (! hr && ! sr) return 0; /* no reset. */ /* Reinitialize the machine state. */ if (hr) frv_hardware_reset (current_cpu); else frv_software_reset (current_cpu); /* Branch to the reset address. */ hsr0 = GET_HSR0 (); if (GET_HSR0_SA (hsr0)) SET_H_PC (0xff000000); else SET_H_PC (0); return 1; /* reset */}/* Process any pending interrupt(s) after a group of parallel insns. */voidfrv_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);}/* Find the next available ESR and return its index */static intesr_for_data_access_exception ( SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item){ SIM_DESC sd = CPU_STATE (current_cpu); if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) return 8; /* Use ESR8, EPCR8. */ if (item->slot == UNIT_I0) return 8; /* Use ESR8, EPCR8, EAR8, EDR8. */ return 9; /* Use ESR9, EPCR9, EAR9. */}/* Set the next available EDR register with the data which was to be stored and return the index of the register. */static intset_edr_register ( SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, int edr_index){ /* EDR0, EDR4 and EDR8 are available as blocks of 4. SI data uses EDR3, EDR7 and EDR11 DI data uses EDR2, EDR6 and EDR10 XI data uses EDR0, EDR4 and EDR8. */ int i; edr_index += 4 - item->u.data_written.length; for (i = 0; i < item->u.data_written.length; ++i) SET_EDR (edr_index + i, item->u.data_written.words[i]); return edr_index;};/* Clear ESFR0, EPCRx, ESRx, EARx and EDRx. */static voidclear_exception_status_registers (SIM_CPU *current_cpu){ int i; /* It is only necessary to clear the flag bits indicating which registers are valid. */ SET_ESFR (0, 0); SET_ESFR (1, 0); for (i = 0; i <= 2; ++i) { SI esr = GET_ESR (i); CLEAR_ESR_VALID (esr); SET_ESR (i, esr); } for (i = 8; i <= 15; ++i) { SI esr = GET_ESR (i); CLEAR_ESR_VALID (esr); SET_ESR (i, esr); }}/* Record state for media exception. */voidfrv_set_mp_exception_registers ( SIM_CPU *current_cpu, enum frv_msr_mtt mtt, int sie){ /* Record the interrupt factor in MSR0. */ SI msr0 = GET_MSR (0); if (GET_MSR_MTT (msr0) == MTT_NONE) SET_MSR_MTT (msr0, mtt); /* Also set the OVF bit in the appropriate MSR as well as MSR0.AOVF. */ if (mtt == MTT_OVERFLOW) { FRV_VLIW *vliw = CPU_VLIW (current_cpu); int slot = vliw->next_slot - 1; SIM_DESC sd = CPU_STATE (current_cpu); /* If this insn is in the M2 slot, then set MSR1.OVF and MSR1.SIE, otherwise set MSR0.OVF and MSR0.SIE. */ if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550 && (*vliw->current_vliw)[slot] == UNIT_FM1) { SI msr = GET_MSR (1); OR_MSR_SIE (msr, sie); SET_MSR_OVF (msr); SET_MSR (1, msr); } else { OR_MSR_SIE (msr0, sie); SET_MSR_OVF (msr0); } /* Generate the interrupt now if MSR0.MPEM is set on fr550 */ if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550 && GET_MSR_MPEM (msr0)) frv_queue_program_interrupt (current_cpu, FRV_MP_EXCEPTION); else { /* Regardless of the slot, set MSR0.AOVF. */ SET_MSR_AOVF (msr0); } } SET_MSR (0, msr0);}/* Determine the correct FQ register to use for the given exception. Return -1 if a register is not available. */static intfq_for_exception ( SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item){ SI fq; struct frv_fp_exception_info *fp_info = & item->u.fp_info; /* For fp_exception overflow, underflow or inexact, use FQ0 or FQ1. */ if (fp_info->ftt == FTT_IEEE_754_EXCEPTION && (fp_info->fsr_mask & (FSR_OVERFLOW | FSR_UNDERFLOW | FSR_INEXACT))) { fq = GET_FQ (0); if (! GET_FQ_VALID (fq)) return 0; /* FQ0 is available. */ fq = GET_FQ (1); if (! GET_FQ_VALID (fq)) return 1; /* FQ1 is available. */ /* No FQ register is available */ { SIM_DESC sd = CPU_STATE (current_cpu); IADDR pc = CPU_PC_GET (current_cpu); sim_engine_abort (sd, current_cpu, pc, "No FQ register available\n"); } return -1; } /* For other exceptions, use FQ2 if the insn was in slot F0/I0 and FQ3 otherwise. */ if (item->slot == UNIT_FM0 || item->slot == UNIT_I0) return 2; return 3;}/* Set FSR0, FQ0-FQ9, depending on the interrupt. */static voidset_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);}/* Record the state of a division exception in the ISR. */static voidset_isr_exception_fields ( SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item){ USI isr = GET_ISR (); int dtt = GET_ISR_DTT (isr); dtt |= item->u.dtt; SET_ISR_DTT (isr, dtt); SET_ISR (isr);}/* Set ESFR0, EPCRx, ESRx, EARx and EDRx, according to the given program interrupt. */static voidset_exception_status_registers ( SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item){ struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind]; int slot = (item->vpc - previous_vliw_pc) / 4; int reg_index = -1; int set_ear = 0; int set_edr = 0; int set_daec = 0; int set_epcr = 0; SI esr = 0; SIM_DESC sd = CPU_STATE (current_cpu); /* If the interrupt is strict (precise) or the interrupt is on the insns in the I0 pipe, then set the 0 registers. */ if (interrupt->precise) { reg_index = 0; if (interrupt->kind == FRV_REGISTER_EXCEPTION) SET_ESR_REC (esr, item->u.rec); else if (interrupt->kind == FRV_INSTRUCTION_ACCESS_EXCEPTION) SET_ESR_IAEC (esr, item->u.iaec); /* For fr550, don't set epcr for precise interrupts. */ if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550) set_epcr = 1; } else { switch (interrupt->kind) { case FRV_DIVISION_EXCEPTION: set_isr_exception_fields (current_cpu, item); /* fall thru to set reg_index. */ case FRV_COMMIT_EXCEPTION: /* For fr550, always use ESR0. */ if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) reg_index = 0; else if (item->slot == UNIT_I0) reg_index = 0; else if (item->slot == UNIT_I1) reg_index = 1; set_epcr = 1; break; case FRV_DATA_STORE_ERROR: reg_index = 14; /* Use ESR14. */ break; case FRV_DATA_ACCESS_ERROR: reg_index = 15; /* Use ESR15, EPCR15. */ set_ear = 1; break; case FRV_DATA_ACCESS_EXCEPTION: set_daec = 1; /* fall through */ case FRV_DATA_ACCESS_MMU_MISS: case FRV_MEM_ADDRESS_NOT_ALIGNED: /* Get the appropriate ESR, EPCR, EAR and EDR. EAR will be set. EDR will not be set if this is a store insn. */ set_ear = 1; /* For fr550, never use EDRx. */ if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550) if (item->u.data_written.length != 0) set_edr = 1; reg_index = esr_for_data_access_exception (current_cpu, item); set_epcr = 1; break; case FRV_MP_EXCEPTION: /* For fr550, use EPCR2 and ESR2. */ if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) { reg_index = 2; set_epcr = 1; } break; /* MSR0-1, FQ0-9 are already set. */ case FRV_FP_EXCEPTION: set_fp_exception_registers (current_cpu, item); /* For fr550, use EPCR2 and ESR2. */ if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550) { reg_index = 2; set_epcr = 1; } break; default: { SIM_DESC sd = CPU_STATE (current_cpu); IADDR pc = CPU_PC_GET (current_cpu); sim_engine_abort (sd, current_cpu, pc, "invalid non-strict program interrupt kind: %d\n", interrupt->kind); break; } } } /* non-strict (imprecise) interrupt */ /* Now fill in the selected exception status registers. */ if (reg_index != -1) { /* Now set the exception status registers. */ SET_ESFR_FLAG (reg_index); SET_ESR_EC (esr, interrupt->ec); if (set_epcr) { if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400) SET_EPCR (reg_index, previous_vliw_pc); else SET_EPCR (reg_index, item->vpc); } if (set_ear) { SET_EAR (reg_index, item->eaddress); SET_ESR_EAV (esr); } else CLEAR_ESR_EAV (esr); if (set_edr) { int edn = set_edr_register (current_cpu, item, 0/* EDR0-3 */); SET_ESR_EDN (esr, edn); SET_ESR_EDV (esr); } else CLEAR_ESR_EDV (esr); if (set_daec) SET_ESR_DAEC (esr, item->u.daec); SET_ESR_VALID (esr); SET_ESR (reg_index, esr); }}/* Check for compound interrupts. Returns NULL if no interrupt is to be processed. */static struct frv_interrupt *check_for_compound_interrupt ( SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item){ struct frv_interrupt *interrupt;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -