/* Handle the BREAK insn. */ void frv_break (SIM_CPU *current_cpu) { IADDR pc; SIM_DESC sd = CPU_STATE (current_cpu); #ifdef SIM_HAVE_BREAKPOINTS /* First try sim-break.c. If it's a breakpoint the simulator "owns" it doesn't return. Otherwise it returns and let's us try. */ pc = GET_H_PC (); sim_handle_breakpoint (sd, current_cpu, pc); /* Fall through. */ #endif if (STATE_ENVIRONMENT (sd) != OPERATING_ENVIRONMENT) { /* Invalidate the insn cache because the debugger will presumably replace the breakpoint insn with the real one. */ #ifndef SIM_HAVE_BREAKPOINTS pc = GET_H_PC (); #endif sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP); } frv_queue_break_interrupt (current_cpu); }
/* 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 }
/* Handle a program interrupt or a software interrupt. */ void frv_external_interrupt ( SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc ) { USI new_pc; struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind]; /* Don't process the interrupt if PSR.ET is not set or if it is masked. Interrupt 15 is processed even if it appears to be masked. */ if (! GET_H_PSR_ET () || (interrupt->kind != FRV_INTERRUPT_LEVEL_15 && interrupt->kind < GET_H_PSR_PIL ())) return; /* Leave it for later. */ /* Remove the interrupt from the queue. */ --frv_interrupt_state.queue_index; /* PCSR=PC PSR.PS=PSR.S PSR.ET=0 PSR.S=1 if PSR.ESR==1 SR0 through SR3=GR4 through GR7 TBR.TT=interrupt handler offset PC=TBR */ SET_H_PSR_PS (GET_H_PSR_S ()); SET_H_PSR_ET (0); SET_H_PSR_S (1); /* Must set PSR.S first to allow access to supervisor-only spr registers. */ SET_H_SPR (H_SPR_PCSR, GET_H_PC ()); /* Set the new PC in the TBR. */ SET_H_TBR_TT (interrupt->handler_offset); new_pc = GET_H_SPR (H_SPR_TBR); SET_H_PC (new_pc); }
USI iq2000bf_h_pc_get (SIM_CPU *current_cpu) { return GET_H_PC (); }
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? */ }