/* Queue a division exception. */ enum frv_dtt frvbf_division_exception (SIM_CPU *current_cpu, enum frv_dtt dtt, int target_index, int non_excepting) { /* If there was an overflow and it is masked, then record it in ISR.AEXC. */ USI isr = GET_ISR (); if ((dtt & FRV_DTT_OVERFLOW) && GET_ISR_EDE (isr)) { dtt &= ~FRV_DTT_OVERFLOW; SET_ISR_AEXC (isr); SET_ISR (isr); } if (dtt != FRV_DTT_NO_EXCEPTION) { if (non_excepting) { /* Non excepting instruction, simply set the NE flag for the target register. */ SI NE_flags[2]; GET_NE_FLAGS (NE_flags, H_SPR_GNER0); SET_NE_FLAG (NE_flags, target_index); SET_NE_FLAGS (H_SPR_GNER0, NE_flags); } else frv_queue_division_exception_interrupt (current_cpu, dtt); } return dtt; }
/* 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; }
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? */ }