⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 interrupts.c

📁 这个是LINUX下的GDB调度工具的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* frv exception and interrupt support   Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.   Contributed by Red Hat.This file is part of the GNU simulators.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public License alongwith this program; if not, write to the Free Software Foundation, Inc.,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */#define WANT_CPU frvbf#define WANT_CPU_FRVBF#include "sim-main.h"#include "bfd.h"/* FR-V Interrupt table.   Describes the interrupts supported by the FR-V.   This table *must* be maintained in order of interrupt priority as defined by   frv_interrupt_kind.  */#define DEFERRED 1#define PRECISE  1#define ITABLE_ENTRY(name, class, deferral, precision, offset) \  {FRV_##name, FRV_EC_##name, class, deferral, precision, offset}struct frv_interrupt frv_interrupt_table[NUM_FRV_INTERRUPT_KINDS] ={  /* External interrupts */  ITABLE_ENTRY(INTERRUPT_LEVEL_1,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x21),  ITABLE_ENTRY(INTERRUPT_LEVEL_2,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x22),  ITABLE_ENTRY(INTERRUPT_LEVEL_3,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x23),  ITABLE_ENTRY(INTERRUPT_LEVEL_4,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x24),  ITABLE_ENTRY(INTERRUPT_LEVEL_5,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x25),  ITABLE_ENTRY(INTERRUPT_LEVEL_6,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x26),  ITABLE_ENTRY(INTERRUPT_LEVEL_7,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x27),  ITABLE_ENTRY(INTERRUPT_LEVEL_8,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x28),  ITABLE_ENTRY(INTERRUPT_LEVEL_9,            FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x29),  ITABLE_ENTRY(INTERRUPT_LEVEL_10,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2a),  ITABLE_ENTRY(INTERRUPT_LEVEL_11,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2b),  ITABLE_ENTRY(INTERRUPT_LEVEL_12,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2c),  ITABLE_ENTRY(INTERRUPT_LEVEL_13,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2d),  ITABLE_ENTRY(INTERRUPT_LEVEL_14,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2e),  ITABLE_ENTRY(INTERRUPT_LEVEL_15,           FRV_EXTERNAL_INTERRUPT, !DEFERRED, !PRECISE, 0x2f),  /* Software interrupt */  ITABLE_ENTRY(TRAP_INSTRUCTION,             FRV_SOFTWARE_INTERRUPT, !DEFERRED, !PRECISE, 0x80),  /* Program interrupts */  ITABLE_ENTRY(COMMIT_EXCEPTION,             FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x19),  ITABLE_ENTRY(DIVISION_EXCEPTION,           FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x17),  ITABLE_ENTRY(DATA_STORE_ERROR,             FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x14),  ITABLE_ENTRY(DATA_ACCESS_EXCEPTION,        FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x13),  ITABLE_ENTRY(DATA_ACCESS_MMU_MISS,         FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x12),  ITABLE_ENTRY(DATA_ACCESS_ERROR,            FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x11),  ITABLE_ENTRY(MP_EXCEPTION,                 FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x0e),  ITABLE_ENTRY(FP_EXCEPTION,                 FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x0d),  ITABLE_ENTRY(MEM_ADDRESS_NOT_ALIGNED,      FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x10),  ITABLE_ENTRY(REGISTER_EXCEPTION,           FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x08),  ITABLE_ENTRY(MP_DISABLED,                  FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x0b),  ITABLE_ENTRY(FP_DISABLED,                  FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x0a),  ITABLE_ENTRY(PRIVILEGED_INSTRUCTION,       FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x06),  ITABLE_ENTRY(ILLEGAL_INSTRUCTION,          FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x07),  ITABLE_ENTRY(INSTRUCTION_ACCESS_EXCEPTION, FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x03),  ITABLE_ENTRY(INSTRUCTION_ACCESS_ERROR,     FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x02),  ITABLE_ENTRY(INSTRUCTION_ACCESS_MMU_MISS,  FRV_PROGRAM_INTERRUPT,  !DEFERRED,  PRECISE, 0x01),  ITABLE_ENTRY(COMPOUND_EXCEPTION,           FRV_PROGRAM_INTERRUPT,  !DEFERRED, !PRECISE, 0x20),  /* Break interrupt */  ITABLE_ENTRY(BREAK_EXCEPTION,              FRV_BREAK_INTERRUPT,    !DEFERRED, !PRECISE, 0xff),  /* Reset interrupt */  ITABLE_ENTRY(RESET,                        FRV_RESET_INTERRUPT,    !DEFERRED, !PRECISE, 0x00)};/* The current interrupt state.  */struct frv_interrupt_state frv_interrupt_state;/* maintain the address of the start of the previous VLIW insn sequence.  */IADDR previous_vliw_pc;/* Add a break interrupt to the interrupt queue.  */struct frv_interrupt_queue_element *frv_queue_break_interrupt (SIM_CPU *current_cpu){  return frv_queue_interrupt (current_cpu, FRV_BREAK_EXCEPTION);}/* Add a software interrupt to the interrupt queue.  */struct frv_interrupt_queue_element *frv_queue_software_interrupt (SIM_CPU *current_cpu, SI offset){  struct frv_interrupt_queue_element *new_element    = frv_queue_interrupt (current_cpu, FRV_TRAP_INSTRUCTION);  struct frv_interrupt *interrupt = & frv_interrupt_table[new_element->kind];  interrupt->handler_offset = offset;  return new_element;}/* Add a program interrupt to the interrupt queue.  */struct frv_interrupt_queue_element *frv_queue_program_interrupt (  SIM_CPU *current_cpu, enum frv_interrupt_kind kind){  return frv_queue_interrupt (current_cpu, kind);}/* Add an external interrupt to the interrupt queue.  */struct frv_interrupt_queue_element *frv_queue_external_interrupt (  SIM_CPU *current_cpu, enum frv_interrupt_kind kind){  if (! GET_H_PSR_ET ()      || (kind != FRV_INTERRUPT_LEVEL_15 && kind < GET_H_PSR_PIL ()))    return NULL; /* Leave it for later.  */  return frv_queue_interrupt (current_cpu, kind);}/* Add any interrupt to the interrupt queue. It will be added in reverse   priority order.  This makes it easy to find the highest priority interrupt   at the end of the queue and to remove it after processing.  */struct frv_interrupt_queue_element *frv_queue_interrupt (SIM_CPU *current_cpu, enum frv_interrupt_kind kind){  int i;  int j;  int limit = frv_interrupt_state.queue_index;  struct frv_interrupt_queue_element *new_element;  enum frv_interrupt_class iclass;  if (limit >= FRV_INTERRUPT_QUEUE_SIZE)    abort (); /* TODO: Make the queue dynamic */  /* Find the right place in the queue.  */  for (i = 0; i < limit; ++i)    {      if (frv_interrupt_state.queue[i].kind >= kind)	break;    }  /* Don't queue two external interrupts of the same priority.  */  iclass = frv_interrupt_table[kind].iclass;  if (i < limit && iclass == FRV_EXTERNAL_INTERRUPT)    {      if (frv_interrupt_state.queue[i].kind == kind)	return & frv_interrupt_state.queue[i];    }  /* Make room for the new interrupt in this spot.  */  for (j = limit - 1; j >= i; --j)    frv_interrupt_state.queue[j + 1] = frv_interrupt_state.queue[j];  /* Add the new interrupt.  */  frv_interrupt_state.queue_index++;  new_element = & frv_interrupt_state.queue[i];  new_element->kind = kind;  new_element->vpc = CPU_PC_GET (current_cpu);  new_element->u.data_written.length = 0;  frv_set_interrupt_queue_slot (current_cpu, new_element);  return new_element;}struct frv_interrupt_queue_element *frv_queue_register_exception_interrupt (SIM_CPU *current_cpu, enum frv_rec rec){  struct frv_interrupt_queue_element *new_element =    frv_queue_program_interrupt (current_cpu, FRV_REGISTER_EXCEPTION);  new_element->u.rec = rec;  return new_element;}struct frv_interrupt_queue_element *frv_queue_mem_address_not_aligned_interrupt (SIM_CPU *current_cpu, USI addr){  struct frv_interrupt_queue_element *new_element;  USI isr = GET_ISR ();  /* Make sure that this exception is not masked.  */  if (GET_ISR_EMAM (isr))    return NULL;  /* Queue the interrupt.  */  new_element = frv_queue_program_interrupt (current_cpu,					     FRV_MEM_ADDRESS_NOT_ALIGNED);  new_element->eaddress = addr;  new_element->u.data_written = frv_interrupt_state.data_written;  frv_interrupt_state.data_written.length = 0;  return new_element;}struct frv_interrupt_queue_element *frv_queue_data_access_error_interrupt (SIM_CPU *current_cpu, USI addr){  struct frv_interrupt_queue_element *new_element;  new_element = frv_queue_program_interrupt (current_cpu,					     FRV_DATA_ACCESS_ERROR);  new_element->eaddress = addr;  return new_element;}struct frv_interrupt_queue_element *frv_queue_data_access_exception_interrupt (SIM_CPU *current_cpu){  return frv_queue_program_interrupt (current_cpu, FRV_DATA_ACCESS_EXCEPTION);}struct frv_interrupt_queue_element *frv_queue_instruction_access_error_interrupt (SIM_CPU *current_cpu){  return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_ERROR);}struct frv_interrupt_queue_element *frv_queue_instruction_access_exception_interrupt (SIM_CPU *current_cpu){  return frv_queue_program_interrupt (current_cpu, FRV_INSTRUCTION_ACCESS_EXCEPTION);}struct frv_interrupt_queue_element *frv_queue_illegal_instruction_interrupt (  SIM_CPU *current_cpu, const CGEN_INSN *insn){  SIM_DESC sd = CPU_STATE (current_cpu);  switch (STATE_ARCHITECTURE (sd)->mach)    {    case bfd_mach_fr400:    case bfd_mach_fr450:    case bfd_mach_fr550:      break;    default:      /* Some machines generate fp_exception for this case.  */      if (frv_is_float_insn (insn) || frv_is_media_insn (insn))	{	  struct frv_fp_exception_info fp_info = {	    FSR_NO_EXCEPTION, FTT_SEQUENCE_ERROR	  };	  return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);	}      break;    }  return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);}struct frv_interrupt_queue_element *frv_queue_privileged_instruction_interrupt (SIM_CPU *current_cpu, const CGEN_INSN *insn){  /* The fr550 has no privileged instruction interrupt. It uses     illegal_instruction.  */  SIM_DESC sd = CPU_STATE (current_cpu);  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)    return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);  return frv_queue_program_interrupt (current_cpu, FRV_PRIVILEGED_INSTRUCTION);}struct frv_interrupt_queue_element *frv_queue_float_disabled_interrupt (SIM_CPU *current_cpu){  /* The fr550 has no fp_disabled interrupt. It uses illegal_instruction.  */  SIM_DESC sd = CPU_STATE (current_cpu);  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)    return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);    return frv_queue_program_interrupt (current_cpu, FRV_FP_DISABLED);}struct frv_interrupt_queue_element *frv_queue_media_disabled_interrupt (SIM_CPU *current_cpu){  /* The fr550 has no mp_disabled interrupt. It uses illegal_instruction.  */  SIM_DESC sd = CPU_STATE (current_cpu);  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)    return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);    return frv_queue_program_interrupt (current_cpu, FRV_MP_DISABLED);}struct frv_interrupt_queue_element *frv_queue_non_implemented_instruction_interrupt (  SIM_CPU *current_cpu, const CGEN_INSN *insn){  SIM_DESC sd = CPU_STATE (current_cpu);  switch (STATE_ARCHITECTURE (sd)->mach)    {    case bfd_mach_fr400:    case bfd_mach_fr450:    case bfd_mach_fr550:      break;    default:      /* Some machines generate fp_exception or mp_exception for this case.  */      if (frv_is_float_insn (insn))	{	  struct frv_fp_exception_info fp_info = {	    FSR_NO_EXCEPTION, FTT_UNIMPLEMENTED_FPOP	  };	  return frv_queue_fp_exception_interrupt (current_cpu, & fp_info);	}      if (frv_is_media_insn (insn))	{	  frv_set_mp_exception_registers (current_cpu, MTT_UNIMPLEMENTED_MPOP,					  0);	  return NULL; /* no interrupt queued at this time.  */	}      break;    }  return frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);}/* 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;}struct frv_interrupt_queue_element *frv_queue_division_exception_interrupt (SIM_CPU *current_cpu, enum frv_dtt dtt){  struct frv_interrupt_queue_element *new_element =    frv_queue_program_interrupt (current_cpu, FRV_DIVISION_EXCEPTION);  new_element->u.dtt = dtt;  return new_element;}/* Check for interrupts caused by illegal insn access.  These conditions are   checked in the order specified by the fr400 and fr500 LSI specs.  */voidfrv_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}/* Record the current VLIW slot in the given interrupt queue element.  */voidfrv_set_interrupt_queue_slot (  SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item){  FRV_VLIW *vliw = CPU_VLIW (current_cpu);  int slot = vliw->next_slot - 1;  item->slot = (*vliw->current_vliw)[slot];}/* Handle an individual interrupt.  */static voidhandle_interrupt (SIM_CPU *current_cpu, IADDR pc){  struct frv_interrupt *interrupt;  int writeback_done = 0;  while (1)    {      /* Interrupts are queued in priority order with the highest priority	 last.  */      int index = frv_interrupt_state.queue_index - 1;      struct frv_interrupt_queue_element *item	= & frv_interrupt_state.queue[index];      interrupt = & frv_interrupt_table[item->kind];      switch (interrupt->iclass)	{	case FRV_EXTERNAL_INTERRUPT:	  /* Perform writeback first. This may cause a higher priority	     interrupt.  */	  if (! writeback_done)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -