interrupts.c
来自「这个是LINUX下的GDB调度工具的源码」· C语言 代码 · 共 1,414 行 · 第 1/3 页
C
1,414 行
/* Set the exception status registers for the original interrupt. */ set_exception_status_registers (current_cpu, item); interrupt = & frv_interrupt_table[item->kind]; if (! interrupt->precise) { IADDR vpc = 0; int mask = 0; vpc = item->vpc; mask = (1 << item->kind); /* Look for more queued program interrupts which are non-deferred (pending inhibit), imprecise (non-strict) different than an interrupt already found and caused by a different insn. A bit mask is used to keep track of interrupts which have already been detected. */ while (item != frv_interrupt_state.queue) { enum frv_interrupt_kind kind; struct frv_interrupt *next_interrupt; --item; kind = item->kind; next_interrupt = & frv_interrupt_table[kind]; if (next_interrupt->iclass != FRV_PROGRAM_INTERRUPT) break; /* no program interrupts left. */ if (item->vpc == vpc) continue; /* caused by the same insn. */ vpc = item->vpc; if (! next_interrupt->precise && ! next_interrupt->deferred) { if (! (mask & (1 << kind))) { /* Set the exception status registers for the additional interrupt. */ set_exception_status_registers (current_cpu, item); mask |= (1 << kind); interrupt = & frv_interrupt_table[FRV_COMPOUND_EXCEPTION]; } } } } /* Return with either the original interrupt, a compound_exception, or no exception. */ return interrupt;}/* Handle a program interrupt. */voidfrv_program_interrupt ( SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc){ struct frv_interrupt *interrupt; clear_exception_status_registers (current_cpu); /* If two or more non-deferred imprecise (non-strict) interrupts occur on two or more insns, then generate a compound_exception. */ interrupt = check_for_compound_interrupt (current_cpu, item); if (interrupt != NULL) { frv_program_or_software_interrupt (current_cpu, interrupt, pc); frv_clear_interrupt_classes (FRV_SOFTWARE_INTERRUPT, FRV_PROGRAM_INTERRUPT); }}/* Handle a software interrupt. */voidfrv_software_interrupt ( SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item, IADDR pc){ struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind]; frv_program_or_software_interrupt (current_cpu, interrupt, pc);}/* Handle a program interrupt or a software interrupt in non-operating mode. */voidfrv_non_operating_interrupt ( SIM_CPU *current_cpu, enum frv_interrupt_kind kind, IADDR pc){ SIM_DESC sd = CPU_STATE (current_cpu); switch (kind) { case FRV_INTERRUPT_LEVEL_1: case FRV_INTERRUPT_LEVEL_2: case FRV_INTERRUPT_LEVEL_3: case FRV_INTERRUPT_LEVEL_4: case FRV_INTERRUPT_LEVEL_5: case FRV_INTERRUPT_LEVEL_6: case FRV_INTERRUPT_LEVEL_7: case FRV_INTERRUPT_LEVEL_8: case FRV_INTERRUPT_LEVEL_9: case FRV_INTERRUPT_LEVEL_10: case FRV_INTERRUPT_LEVEL_11: case FRV_INTERRUPT_LEVEL_12: case FRV_INTERRUPT_LEVEL_13: case FRV_INTERRUPT_LEVEL_14: case FRV_INTERRUPT_LEVEL_15: sim_engine_abort (sd, current_cpu, pc, "interrupt: external %d\n", kind + 1); break; case FRV_TRAP_INSTRUCTION: break; /* handle as in operating mode. */ case FRV_COMMIT_EXCEPTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: commit_exception\n"); break; case FRV_DIVISION_EXCEPTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: division_exception\n"); break; case FRV_DATA_STORE_ERROR: sim_engine_abort (sd, current_cpu, pc, "interrupt: data_store_error\n"); break; case FRV_DATA_ACCESS_EXCEPTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: data_access_exception\n"); break; case FRV_DATA_ACCESS_MMU_MISS: sim_engine_abort (sd, current_cpu, pc, "interrupt: data_access_mmu_miss\n"); break; case FRV_DATA_ACCESS_ERROR: sim_engine_abort (sd, current_cpu, pc, "interrupt: data_access_error\n"); break; case FRV_MP_EXCEPTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: mp_exception\n"); break; case FRV_FP_EXCEPTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: fp_exception\n"); break; case FRV_MEM_ADDRESS_NOT_ALIGNED: sim_engine_abort (sd, current_cpu, pc, "interrupt: mem_address_not_aligned\n"); break; case FRV_REGISTER_EXCEPTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: register_exception\n"); break; case FRV_MP_DISABLED: sim_engine_abort (sd, current_cpu, pc, "interrupt: mp_disabled\n"); break; case FRV_FP_DISABLED: sim_engine_abort (sd, current_cpu, pc, "interrupt: fp_disabled\n"); break; case FRV_PRIVILEGED_INSTRUCTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: privileged_instruction\n"); break; case FRV_ILLEGAL_INSTRUCTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: illegal_instruction\n"); break; case FRV_INSTRUCTION_ACCESS_EXCEPTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: instruction_access_exception\n"); break; case FRV_INSTRUCTION_ACCESS_MMU_MISS: sim_engine_abort (sd, current_cpu, pc, "interrupt: instruction_access_mmu_miss\n"); break; case FRV_INSTRUCTION_ACCESS_ERROR: sim_engine_abort (sd, current_cpu, pc, "interrupt: insn_access_error\n"); break; case FRV_COMPOUND_EXCEPTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: compound_exception\n"); break; case FRV_BREAK_EXCEPTION: sim_engine_abort (sd, current_cpu, pc, "interrupt: break_exception\n"); break; case FRV_RESET: sim_engine_abort (sd, current_cpu, pc, "interrupt: reset\n"); break; default: sim_engine_abort (sd, current_cpu, pc, "unhandled interrupt kind: %d\n", kind); break; }}/* Handle a break interrupt. */voidfrv_break_interrupt ( SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc){ IADDR new_pc; /* BPCSR=PC BPSR.BS=PSR.S BPSR.BET=PSR.ET PSR.S=1 PSR.ET=0 TBR.TT=0xff PC=TBR */ /* Must set PSR.S first to allow access to supervisor-only spr registers. */ SET_H_BPSR_BS (GET_H_PSR_S ()); SET_H_BPSR_BET (GET_H_PSR_ET ()); SET_H_PSR_S (1); SET_H_PSR_ET (0); /* Must set PSR.S first to allow access to supervisor-only spr registers. */ SET_H_SPR (H_SPR_BPCSR, current_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); CPU_DEBUG_STATE (current_cpu) = 1;}/* Handle a program interrupt or a software interrupt. */voidfrv_program_or_software_interrupt ( SIM_CPU *current_cpu, struct frv_interrupt *interrupt, IADDR current_pc){ USI new_pc; int original_psr_et; /* 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 */ original_psr_et = GET_H_PSR_ET (); 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. */ /* The PCSR depends on the precision of the interrupt. */ if (interrupt->precise) SET_H_SPR (H_SPR_PCSR, previous_vliw_pc); else SET_H_SPR (H_SPR_PCSR, current_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); /* If PSR.ET was not originally set, then enter the stopped state. */ if (! original_psr_et) { SIM_DESC sd = CPU_STATE (current_cpu); frv_non_operating_interrupt (current_cpu, interrupt->kind, current_pc); sim_engine_halt (sd, current_cpu, NULL, new_pc, sim_stopped, SIM_SIGINT); }}/* Handle a program interrupt or a software interrupt. */voidfrv_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);}/* Clear interrupts which fall within the range of classes given. */voidfrv_clear_interrupt_classes ( enum frv_interrupt_class low_class, enum frv_interrupt_class high_class){ int i; int j; int limit = frv_interrupt_state.queue_index; /* Find the lowest priority interrupt to be removed. */ for (i = 0; i < limit; ++i) { enum frv_interrupt_kind kind = frv_interrupt_state.queue[i].kind; struct frv_interrupt* interrupt = & frv_interrupt_table[kind]; if (interrupt->iclass >= low_class) break; } /* Find the highest priority interrupt to be removed. */ for (j = limit - 1; j >= i; --j) { enum frv_interrupt_kind kind = frv_interrupt_state.queue[j].kind; struct frv_interrupt* interrupt = & frv_interrupt_table[kind]; if (interrupt->iclass <= high_class) break; } /* Shuffle the remaining high priority interrupts down into the empty space left by the deleted interrupts. */ if (j >= i) { for (++j; j < limit; ++j) frv_interrupt_state.queue[i++] = frv_interrupt_state.queue[j]; frv_interrupt_state.queue_index -= (j - i); }}/* Save data written to memory into the interrupt state so that it can be copied to the appropriate EDR register, if necessary, in the event of an interrupt. */voidfrv_save_data_written_for_interrupts ( SIM_CPU *current_cpu, CGEN_WRITE_QUEUE_ELEMENT *item){ /* Record the slot containing the insn doing the write in the interrupt state. */ frv_interrupt_state.slot = CGEN_WRITE_QUEUE_ELEMENT_PIPE (item); /* Now record any data written to memory in the interrupt state. */ switch (CGEN_WRITE_QUEUE_ELEMENT_KIND (item)) { case CGEN_BI_WRITE: case CGEN_QI_WRITE: case CGEN_SI_WRITE: case CGEN_SF_WRITE: case CGEN_PC_WRITE: case CGEN_FN_HI_WRITE: case CGEN_FN_SI_WRITE: case CGEN_FN_SF_WRITE: case CGEN_FN_DI_WRITE: case CGEN_FN_DF_WRITE: case CGEN_FN_XI_WRITE: case CGEN_FN_PC_WRITE: break; /* Ignore writes to registers. */ case CGEN_MEM_QI_WRITE: frv_interrupt_state.data_written.length = 1; frv_interrupt_state.data_written.words[0] = item->kinds.mem_qi_write.value; break; case CGEN_MEM_HI_WRITE: frv_interrupt_state.data_written.length = 1; frv_interrupt_state.data_written.words[0] = item->kinds.mem_hi_write.value; break; case CGEN_MEM_SI_WRITE: frv_interrupt_state.data_written.length = 1; frv_interrupt_state.data_written.words[0] = item->kinds.mem_si_write.value; break; case CGEN_MEM_DI_WRITE: frv_interrupt_state.data_written.length = 2; frv_interrupt_state.data_written.words[0] = item->kinds.mem_di_write.value >> 32; frv_interrupt_state.data_written.words[1] = item->kinds.mem_di_write.value; break; case CGEN_MEM_DF_WRITE: frv_interrupt_state.data_written.length = 2; frv_interrupt_state.data_written.words[0] = item->kinds.mem_df_write.value >> 32; frv_interrupt_state.data_written.words[1] = item->kinds.mem_df_write.value; break; case CGEN_MEM_XI_WRITE: frv_interrupt_state.data_written.length = 4; frv_interrupt_state.data_written.words[0] = item->kinds.mem_xi_write.value[0]; frv_interrupt_state.data_written.words[1] = item->kinds.mem_xi_write.value[1]; frv_interrupt_state.data_written.words[2] = item->kinds.mem_xi_write.value[2]; frv_interrupt_state.data_written.words[3] = item->kinds.mem_xi_write.value[3]; break; case CGEN_FN_MEM_QI_WRITE: frv_interrupt_state.data_written.length = 1; frv_interrupt_state.data_written.words[0] = item->kinds.fn_mem_qi_write.value; break; case CGEN_FN_MEM_HI_WRITE: frv_interrupt_state.data_written.length = 1; frv_interrupt_state.data_written.words[0] = item->kinds.fn_mem_hi_write.value; break; case CGEN_FN_MEM_SI_WRITE: frv_interrupt_state.data_written.length = 1; frv_interrupt_state.data_written.words[0] = item->kinds.fn_mem_si_write.value; break; case CGEN_FN_MEM_DI_WRITE: frv_interrupt_state.data_written.length = 2; frv_interrupt_state.data_written.words[0] = item->kinds.fn_mem_di_write.value >> 32; frv_interrupt_state.data_written.words[1] = item->kinds.fn_mem_di_write.value; break; case CGEN_FN_MEM_DF_WRITE: frv_interrupt_state.data_written.length = 2; frv_interrupt_state.data_written.words[0] = item->kinds.fn_mem_df_write.value >> 32; frv_interrupt_state.data_written.words[1] = item->kinds.fn_mem_df_write.value; break; case CGEN_FN_MEM_XI_WRITE: frv_interrupt_state.data_written.length = 4; frv_interrupt_state.data_written.words[0] = item->kinds.fn_mem_xi_write.value[0]; frv_interrupt_state.data_written.words[1] = item->kinds.fn_mem_xi_write.value[1]; frv_interrupt_state.data_written.words[2] = item->kinds.fn_mem_xi_write.value[2]; frv_interrupt_state.data_written.words[3] = item->kinds.fn_mem_xi_write.value[3]; break; default: { SIM_DESC sd = CPU_STATE (current_cpu); IADDR pc = CPU_PC_GET (current_cpu); sim_engine_abort (sd, current_cpu, pc, "unknown write kind during save for interrupt\n"); } break; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?