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 + -
显示快捷键?