示例#1
0
void
sim_engine_run (SIM_DESC sd, int next_cpu_nr, int nr_cpus,
		int signal)
{
  micromips_m32_instruction_word instruction_0;
  sim_cpu *cpu = STATE_CPU (sd, next_cpu_nr);
  micromips32_instruction_address cia = CPU_PC_GET (cpu);
  sd->isa_mode = ISA_MODE_MIPS32;

  while (1)
    {
      micromips32_instruction_address nia;

      /* Allow us to switch back from MIPS32 to microMIPS
	 This covers two cases:
	 1. Setting the correct isa mode based on the start address
	 from the elf header.
	 2. Setting the correct isa mode after a MIPS32 jump or branch
	 instruction.  */
      if ((sd->isa_mode == ISA_MODE_MIPS32)
	  && ((cia & 0x1) == ISA_MODE_MICROMIPS))
	{
	  sd->isa_mode = ISA_MODE_MICROMIPS;
	  cia = cia & ~0x1;
	}

#if defined (ENGINE_ISSUE_PREFIX_HOOK)
      ENGINE_ISSUE_PREFIX_HOOK ();
#endif
      switch (sd->isa_mode)
	{
	case ISA_MODE_MICROMIPS:
	  nia =
	    micromips_instruction_decode (sd, cpu, cia,
					  MICROMIPS_DELAYSLOT_SIZE_ANY);
	  break;
	case ISA_MODE_MIPS32:
	  instruction_0 = IMEM32 (cia);
	  nia = micromips_m32_idecode_issue (sd, instruction_0, cia);
	  break;
	default:
	  nia = NULL_CIA;
	}

#if defined (ENGINE_ISSUE_POSTFIX_HOOK)
      ENGINE_ISSUE_POSTFIX_HOOK ();
#endif

      /* Update the instruction address */
      cia = nia;

      /* process any events */
      if (sim_events_tick (sd))
	{
	  CPU_PC_SET (cpu, cia);
	  sim_events_process (sd);
	  cia = CPU_PC_GET (cpu);
	}
    }
}
示例#2
0
/* Perform a software reset.  */
void
frv_software_reset (SIM_CPU *cpu)
{
  /* GR, FR and CPR registers are undefined at software reset.  */
  frv_reset_spr (cpu);
  /* Reset the RSTR register (in memory).  */
  if (frv_cache_enabled (CPU_DATA_CACHE (cpu)))
    frvbf_mem_set_SI (cpu, CPU_PC_GET (cpu), RSTR_ADDRESS, RSTR_SOFTWARE_RESET);
  else
    SETMEMSI (cpu, CPU_PC_GET (cpu), RSTR_ADDRESS, RSTR_SOFTWARE_RESET);
}
示例#3
0
/* Perform a power on reset.  */
void
frv_power_on_reset (SIM_CPU *cpu)
{
  /* GR, FR and CPR registers are undefined at initialization time.  */
  frv_initialize_spr (cpu);
  /* Initialize the RSTR register (in memory).  */
  if (frv_cache_enabled (CPU_DATA_CACHE (cpu)))
    frvbf_mem_set_SI (cpu, CPU_PC_GET (cpu), RSTR_ADDRESS, RSTR_INITIAL_VALUE);
  else
    SETMEMSI (cpu, CPU_PC_GET (cpu), RSTR_ADDRESS, RSTR_INITIAL_VALUE);
}
示例#4
0
/* Perform a hardware reset.  */
void
frv_hardware_reset (SIM_CPU *cpu)
{
  /* GR, FR and CPR registers are undefined at hardware reset.  */
  frv_initialize_spr (cpu);
  /* Reset the RSTR register (in memory).  */
  if (frv_cache_enabled (CPU_DATA_CACHE (cpu)))
    frvbf_mem_set_SI (cpu, CPU_PC_GET (cpu), RSTR_ADDRESS, RSTR_HARDWARE_RESET);
  else
    SETMEMSI (cpu, CPU_PC_GET (cpu), RSTR_ADDRESS, RSTR_HARDWARE_RESET);
  /* Reset the insn and data caches.  */
  frv_cache_invalidate_all (CPU_INSN_CACHE (cpu), 0/* no flush */);
  frv_cache_invalidate_all (CPU_DATA_CACHE (cpu), 0/* no flush */);
}
/* Process any pending interrupt(s) after a group of parallel insns.  */
void
frv_process_interrupts (SIM_CPU *current_cpu)
{
  SI NE_flags[2];
  /* Need to save the pc here because writeback may change it (due to a
     branch).  */
  IADDR pc = CPU_PC_GET (current_cpu);

  /* Check for a reset before anything else.  */
  if (check_reset (current_cpu, pc))
    return;

  /* First queue the writes for any accumulated NE flags.  */
  if (frv_interrupt_state.f_ne_flags[0] != 0
      || frv_interrupt_state.f_ne_flags[1] != 0)
    {
      GET_NE_FLAGS (NE_flags, H_SPR_FNER0);
      NE_flags[0] |= frv_interrupt_state.f_ne_flags[0];
      NE_flags[1] |= frv_interrupt_state.f_ne_flags[1];
      SET_NE_FLAGS (H_SPR_FNER0, NE_flags);
    }

  /* If there is no interrupt pending, then perform parallel writeback.  This
     may cause an interrupt.  */
  if (frv_interrupt_state.queue_index <= 0)
    frvbf_perform_writeback (current_cpu);

  /* If there is an interrupt pending, then process it.  */
  if (frv_interrupt_state.queue_index > 0)
    handle_interrupt (current_cpu, pc);
}
/* Determine the correct FQ register to use for the given exception.
   Return -1 if a register is not available.  */
static int
fq_for_exception (
  SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
)
{
  SI fq;
  struct frv_fp_exception_info *fp_info = & item->u.fp_info;

  /* For fp_exception overflow, underflow or inexact, use FQ0 or FQ1.  */
  if (fp_info->ftt == FTT_IEEE_754_EXCEPTION
      && (fp_info->fsr_mask & (FSR_OVERFLOW | FSR_UNDERFLOW | FSR_INEXACT)))
    {
      fq = GET_FQ (0);
      if (! GET_FQ_VALID (fq))
	return 0; /* FQ0 is available.  */
      fq = GET_FQ (1);
      if (! GET_FQ_VALID (fq))
	return 1; /* FQ1 is available.  */

      /* No FQ register is available */
      {
	SIM_DESC sd = CPU_STATE (current_cpu);
	IADDR pc = CPU_PC_GET (current_cpu);
	sim_engine_abort (sd, current_cpu, pc, "No FQ register available\n");
      }
      return -1;
    }
  /* For other exceptions, use FQ2 if the insn was in slot F0/I0 and FQ3
     otherwise.  */
  if (item->slot == UNIT_FM0 || item->slot == UNIT_I0)
    return 2;

  return 3;
}
示例#7
0
/* Write the given data out to memory.  */
static void
write_data_to_memory (FRV_CACHE *cache, SI address, char *data, int length)
{
  SIM_CPU *cpu = cache->cpu;
  IADDR pc = CPU_PC_GET (cpu);
  int write_index = 0;

  switch (length)
    {
    case 1:
    default:
      PROFILE_COUNT_WRITE (cpu, address, MODE_QI);
      break;
    case 2:
      PROFILE_COUNT_WRITE (cpu, address, MODE_HI);
      break;
    case 4:
      PROFILE_COUNT_WRITE (cpu, address, MODE_SI);
      break;
    case 8:
      PROFILE_COUNT_WRITE (cpu, address, MODE_DI);
      break;
    }

  for (write_index = 0; write_index < length; ++write_index)
    {
      /* TODO: Better way to copy memory than a byte at a time?  */
      sim_core_write_unaligned_1 (cpu, pc, write_map, address + write_index,
				  data[write_index]);
    }
}
示例#8
0
/* Fill the given cache line from memory.  */
static void
fill_line_from_memory (FRV_CACHE *cache, FRV_CACHE_TAG *tag, SI address)
{
  PCADDR pc;
  int line_alignment;
  SI read_address;
  SIM_CPU *current_cpu = cache->cpu;

  /* If this line is already valid and the cache is in copy-back mode, then
     write this line to memory before refilling it.
     Check the dirty bit first, since it is less likely to be set.  */
  if (tag->dirty && tag->valid)
    {
      int hsr0 = GET_HSR0 ();
      if (GET_HSR0_CBM (hsr0))
	write_line_to_memory (cache, tag);
    }
  else if (tag->line == NULL)
    {
      int line_index = tag - cache->tag_storage;
      tag->line = cache->data_storage + (line_index * cache->line_size);
    }

  pc = CPU_PC_GET (current_cpu);
  line_alignment = cache->line_size - 1;
  read_address = address & ~line_alignment;
  read_data_from_memory (current_cpu, read_address, tag->line,
			 cache->line_size);
  tag->tag = CACHE_ADDRESS_TAG (cache, address);
  tag->valid = 1;
}
示例#9
0
void sim_queue_pc_write (SIM_CPU *cpu, USI value)
{
  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (cpu);
  CGEN_WRITE_QUEUE_ELEMENT *element = CGEN_WRITE_QUEUE_NEXT (q);
  element->kind = CGEN_PC_WRITE;
  element->insn_address = CPU_PC_GET (cpu);
  element->kinds.pc_write.value = value;
}
示例#10
0
文件: m16run.c 项目: ChrisG0x20/gdb
void
sim_engine_run (SIM_DESC sd,
		int next_cpu_nr,
		int nr_cpus, /* ignore */
		int siggnal) /* ignore */
{
  sim_cpu *cpu = STATE_CPU (sd, next_cpu_nr);
  address_word cia = CPU_PC_GET (cpu);

  while (1)
    {
      address_word nia;

#if defined (ENGINE_ISSUE_PREFIX_HOOK)
      ENGINE_ISSUE_PREFIX_HOOK ();
#endif

      if ((cia & 1))
	{
	  m16_instruction_word instruction_0 = IMEM16 (cia);
	  nia = m16_idecode_issue (sd, instruction_0, cia);
	}
      else
	{
	  m32_instruction_word instruction_0 = IMEM32 (cia);
	  nia = m32_idecode_issue (sd, instruction_0, cia);
	}

#if defined (ENGINE_ISSUE_POSTFIX_HOOK)
      ENGINE_ISSUE_POSTFIX_HOOK ();
#endif

      /* Update the instruction address */
      cia = nia;

      /* process any events */
      if (sim_events_tick (sd))
        {
          CPU_PC_SET (CPU, cia);
          sim_events_process (sd);
	  cia = CPU_PC_GET (CPU);
        }

    }
}
示例#11
0
void sim_queue_sf_write (SIM_CPU *cpu, SI *target, SF value)
{
  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (cpu);
  CGEN_WRITE_QUEUE_ELEMENT *element = CGEN_WRITE_QUEUE_NEXT (q);
  element->kind = CGEN_SF_WRITE;
  element->insn_address = CPU_PC_GET (cpu);
  element->kinds.sf_write.target = target;
  element->kinds.sf_write.value  = value;
}
示例#12
0
void sim_queue_mem_df_write (SIM_CPU *cpu, SI address, DF value)
{
  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (cpu);
  CGEN_WRITE_QUEUE_ELEMENT *element = CGEN_WRITE_QUEUE_NEXT (q);
  element->kind = CGEN_MEM_DF_WRITE;
  element->insn_address = CPU_PC_GET (cpu);
  element->kinds.mem_df_write.address = address;
  element->kinds.mem_df_write.value   = value;
}
示例#13
0
void sim_queue_mem_xi_write (SIM_CPU *cpu, SI address, SI *value)
{
  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (cpu);
  CGEN_WRITE_QUEUE_ELEMENT *element = CGEN_WRITE_QUEUE_NEXT (q);
  element->kind = CGEN_MEM_XI_WRITE;
  element->insn_address = CPU_PC_GET (cpu);
  element->kinds.mem_xi_write.address = address;
  element->kinds.mem_xi_write.value[0] = value[0];
  element->kinds.mem_xi_write.value[1] = value[1];
  element->kinds.mem_xi_write.value[2] = value[2];
  element->kinds.mem_xi_write.value[3] = value[3];
}
示例#14
0
void sim_queue_fn_pc_write (
  SIM_CPU *cpu,
  void (*write_function)(SIM_CPU *cpu, USI),
  USI value
)
{
  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (cpu);
  CGEN_WRITE_QUEUE_ELEMENT *element = CGEN_WRITE_QUEUE_NEXT (q);
  element->kind = CGEN_FN_PC_WRITE;
  element->insn_address = CPU_PC_GET (cpu);
  element->kinds.fn_pc_write.function = write_function;
  element->kinds.fn_pc_write.value = value;
}
示例#15
0
static void
read_data_from_memory (SIM_CPU *current_cpu, SI address, char *buffer,
		       int length)
{
  PCADDR pc = CPU_PC_GET (current_cpu);
  int i;
  PROFILE_COUNT_READ (current_cpu, address, MODE_QI);
  for (i = 0; i < length; ++i)
    {
      /* TODO: Better way to copy memory than a byte at a time?  */
      buffer[i] = sim_core_read_unaligned_1 (current_cpu, pc, read_map,
					     address + i);
    }
}
示例#16
0
void sim_queue_fn_df_write (
  SIM_CPU *cpu,
  void (*write_function)(SIM_CPU *cpu, UINT, DF),
  UINT regno,
  DF value
)
{
  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (cpu);
  CGEN_WRITE_QUEUE_ELEMENT *element = CGEN_WRITE_QUEUE_NEXT (q);
  element->kind = CGEN_FN_DF_WRITE;
  element->insn_address = CPU_PC_GET (cpu);
  element->kinds.fn_df_write.function = write_function;
  element->kinds.fn_df_write.regno = regno;
  element->kinds.fn_df_write.value = value;
}
示例#17
0
void sim_queue_fn_mem_df_write (
  SIM_CPU *cpu,
  void (*write_function)(SIM_CPU *cpu, IADDR, SI, DF),
  SI address,
  DF value
)
{
  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (cpu);
  CGEN_WRITE_QUEUE_ELEMENT *element = CGEN_WRITE_QUEUE_NEXT (q);
  element->kind = CGEN_FN_MEM_DF_WRITE;
  element->insn_address = CPU_PC_GET (cpu);
  element->kinds.fn_mem_df_write.function = write_function;
  element->kinds.fn_mem_df_write.address = address;
  element->kinds.fn_mem_df_write.value   = value;
}
示例#18
0
void sim_queue_fn_xi_write (
  SIM_CPU *cpu,
  void (*write_function)(SIM_CPU *cpu, UINT, SI *),
  UINT regno,
  SI *value
)
{
  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (cpu);
  CGEN_WRITE_QUEUE_ELEMENT *element = CGEN_WRITE_QUEUE_NEXT (q);
  element->kind = CGEN_FN_XI_WRITE;
  element->insn_address = CPU_PC_GET (cpu);
  element->kinds.fn_xi_write.function = write_function;
  element->kinds.fn_xi_write.regno = regno;
  element->kinds.fn_xi_write.value[0] = value[0];
  element->kinds.fn_xi_write.value[1] = value[1];
  element->kinds.fn_xi_write.value[2] = value[2];
  element->kinds.fn_xi_write.value[3] = value[3];
}
示例#19
0
void sim_queue_fn_mem_xi_write (
  SIM_CPU *cpu,
  void (*write_function)(SIM_CPU *cpu, IADDR, SI, SI *),
  SI address,
  SI *value
)
{
  CGEN_WRITE_QUEUE *q = CPU_WRITE_QUEUE (cpu);
  CGEN_WRITE_QUEUE_ELEMENT *element = CGEN_WRITE_QUEUE_NEXT (q);
  element->kind = CGEN_FN_MEM_XI_WRITE;
  element->insn_address = CPU_PC_GET (cpu);
  element->kinds.fn_mem_xi_write.function = write_function;
  element->kinds.fn_mem_xi_write.address = address;
  element->kinds.fn_mem_xi_write.value[0] = value[0];
  element->kinds.fn_mem_xi_write.value[1] = value[1];
  element->kinds.fn_mem_xi_write.value[2] = value[2];
  element->kinds.fn_mem_xi_write.value[3] = value[3];
}
示例#20
0
文件: interp.c 项目: ChrisG0x20/gdb
void
program_interrupt (SIM_DESC sd,
		   sim_cpu *cpu,
		   sim_cia cia,
		   SIM_SIGNAL sig)
{
  int status;
  struct hw *device;
  static int in_interrupt = 0;

#ifdef SIM_CPU_EXCEPTION_TRIGGER
  SIM_CPU_EXCEPTION_TRIGGER(sd,cpu,cia);
#endif

  /* avoid infinite recursion */
  if (in_interrupt)
    {
      (*mn10300_callback->printf_filtered) (mn10300_callback, 
					    "ERROR: recursion in program_interrupt during software exception dispatch.");
    }
  else
    {
      in_interrupt = 1;
      /* copy NMI handler code from dv-mn103cpu.c */
      store_word (SP - 4, CPU_PC_GET (cpu));
      store_half (SP - 8, PSW);

      /* Set the SYSEF flag in NMICR by backdoor method.  See
	 dv-mn103int.c:write_icr().  This is necessary because
         software exceptions are not modelled by actually talking to
         the interrupt controller, so it cannot set its own SYSEF
         flag. */
     if ((NULL != board) && (strcmp(board, BOARD_AM32) == 0))
       store_byte (0x34000103, 0x04);
    }

  PSW &= ~PSW_IE;
  SP = SP - 8;
  CPU_PC_SET (cpu, 0x40000008);

  in_interrupt = 0;
  sim_engine_halt(sd, cpu, NULL, cia, sim_stopped, sig);
}
/* 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;
}
示例#22
0
文件: sim-run.c 项目: ChrisG0x20/gdb
void
sim_engine_run (SIM_DESC sd,
		int next_cpu_nr, /* ignore */
		int nr_cpus, /* ignore */
		int siggnal) /* ignore */
{
  sim_cia cia;
  sim_cpu *cpu;
  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
  cpu = STATE_CPU (sd, 0);
  cia = CPU_PC_GET (cpu);
  while (1)
    {
      instruction_word insn = IMEM32 (cia);
      cia = idecode_issue (sd, insn, cia);
      /* process any events */
      if (sim_events_tick (sd))
	{
	  CPU_PC_SET (cpu, cia);
	  sim_events_process (sd);
	}
    }
}
示例#23
0
static void
deliver_mn103cpu_interrupt (struct hw *me,
			    void *data)
{
  struct mn103cpu *controller = hw_data (me);
  SIM_DESC simulator = hw_system (me);
  sim_cpu *cpu = STATE_CPU (simulator, 0);

  if (controller->pending_reset)
    {
      controller->pending_reset = 0;
      /* need to clear all registers et.al! */
      HW_TRACE ((me, "Reset!"));
      hw_abort (me, "Reset!");
    }
  else if (controller->pending_nmi)
    {
      controller->pending_nmi = 0;
      store_word (SP - 4, CPU_PC_GET (cpu));
      store_half (SP - 8, PSW);
      PSW &= ~PSW_IE;
      SP = SP - 8;
      CPU_PC_SET (cpu, 0x40000008);
      HW_TRACE ((me, "nmi pc=0x%08lx psw=0x%04x sp=0x%08lx",
		 (long) CPU_PC_GET (cpu), (unsigned) PSW, (long) SP));
    }
  else if ((controller->pending_level < EXTRACT_PSW_LM)
	   && (PSW & PSW_IE))
    {
      /* Don't clear pending level.  Request continues to be pending
         until the interrupt controller clears/changes it */
      store_word (SP - 4, CPU_PC_GET (cpu));
      store_half (SP - 8, PSW);
      PSW &= ~PSW_IE;
      PSW &= ~PSW_LM;
      PSW |= INSERT_PSW_LM (controller->pending_level);
      SP = SP - 8;
      CPU_PC_SET (cpu, 0x40000000 + controller->interrupt_vector[controller->pending_level]);
      HW_TRACE ((me, "port-out ack %d", controller->pending_level));
      hw_port_event (me, ACK_PORT, controller->pending_level);
      HW_TRACE ((me, "int level=%d pc=0x%08lx psw=0x%04x sp=0x%08lx",
		 controller->pending_level,
		 (long) CPU_PC_GET (cpu), (unsigned) PSW, (long) SP));
    }

  if (controller->pending_level < 7) /* FIXME */
    {
      /* As long as there is the potential need to deliver an
	 interrupt we keep rescheduling this routine. */
      if (controller->pending_handler != NULL)
	controller->pending_handler =
	  hw_event_queue_schedule (me, 1, deliver_mn103cpu_interrupt, NULL);
    }
  else
    {
      /* Don't bother re-scheduling the interrupt handler as there is
         nothing to deliver */
      controller->pending_handler = NULL;
    }

}
/* Set ESFR0, EPCRx, ESRx, EARx and EDRx, according to the given program
   interrupt.  */
static void
set_exception_status_registers (
  SIM_CPU *current_cpu, struct frv_interrupt_queue_element *item
)
{
  struct frv_interrupt *interrupt = & frv_interrupt_table[item->kind];
  int slot = (item->vpc - previous_vliw_pc) / 4;
  int reg_index = -1;
  int set_ear = 0;
  int set_edr = 0;
  int set_daec = 0;
  int set_epcr = 0;
  SI esr = 0;
  SIM_DESC sd = CPU_STATE (current_cpu);

  /* If the interrupt is strict (precise) or the interrupt is on the insns
     in the I0 pipe, then set the 0 registers.  */
  if (interrupt->precise)
    {
      reg_index = 0;
      if (interrupt->kind == FRV_REGISTER_EXCEPTION)
	SET_ESR_REC (esr, item->u.rec);
      else if (interrupt->kind == FRV_INSTRUCTION_ACCESS_EXCEPTION)
	SET_ESR_IAEC (esr, item->u.iaec);
      /* For fr550, don't set epcr for precise interrupts.  */
      if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
	set_epcr = 1;
    }
  else
    {
      switch (interrupt->kind)
	{
	case FRV_DIVISION_EXCEPTION:
	  set_isr_exception_fields (current_cpu, item);
	  /* fall thru to set reg_index.  */
	case FRV_COMMIT_EXCEPTION:
	  /* For fr550, always use ESR0.  */
	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
	    reg_index = 0;
	  else if (item->slot == UNIT_I0)
	    reg_index = 0;
	  else if (item->slot == UNIT_I1)
	    reg_index = 1;
	  set_epcr = 1;
	  break;
	case FRV_DATA_STORE_ERROR:
	  reg_index = 14; /* Use ESR14.  */
	  break;
	case FRV_DATA_ACCESS_ERROR:
	  reg_index = 15; /* Use ESR15, EPCR15.  */
	  set_ear = 1;
	  break;
	case FRV_DATA_ACCESS_EXCEPTION:
	  set_daec = 1;
	  /* fall through */
	case FRV_DATA_ACCESS_MMU_MISS:
	case FRV_MEM_ADDRESS_NOT_ALIGNED:
	  /* Get the appropriate ESR, EPCR, EAR and EDR.
	     EAR will be set. EDR will not be set if this is a store insn.  */
	  set_ear = 1;
	  /* For fr550, never use EDRx.  */
	  if (STATE_ARCHITECTURE (sd)->mach != bfd_mach_fr550)
	    if (item->u.data_written.length != 0)
	      set_edr = 1;
	  reg_index = esr_for_data_access_exception (current_cpu, item);
	  set_epcr = 1;
	  break;
	case FRV_MP_EXCEPTION:
	  /* For fr550, use EPCR2 and ESR2.  */
	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
	    {
	      reg_index = 2;
	      set_epcr = 1;
	    }
	  break; /* MSR0-1, FQ0-9 are already set.  */
	case FRV_FP_EXCEPTION:
	  set_fp_exception_registers (current_cpu, item);
	  /* For fr550, use EPCR2 and ESR2.  */
	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr550)
	    {
	      reg_index = 2;
	      set_epcr = 1;
	    }
	  break;
	default:
	  {
	    SIM_DESC sd = CPU_STATE (current_cpu);
	    IADDR pc = CPU_PC_GET (current_cpu);
	    sim_engine_abort (sd, current_cpu, pc,
			      "invalid non-strict program interrupt kind: %d\n",
			      interrupt->kind);
	    break;
	  }
	}
    } /* non-strict (imprecise) interrupt */

  /* Now fill in the selected exception status registers.  */
  if (reg_index != -1)
    {
      /* Now set the exception status registers.  */
      SET_ESFR_FLAG (reg_index);
      SET_ESR_EC (esr, interrupt->ec);

      if (set_epcr)
	{
	  if (STATE_ARCHITECTURE (sd)->mach == bfd_mach_fr400)
	    SET_EPCR (reg_index, previous_vliw_pc);
	  else
	    SET_EPCR (reg_index, item->vpc);
	}

      if (set_ear)
	{
	  SET_EAR (reg_index, item->eaddress);
	  SET_ESR_EAV (esr);
	}
      else
	CLEAR_ESR_EAV (esr);

      if (set_edr)
	{
	  int edn = set_edr_register (current_cpu, item, 0/* EDR0-3 */);
	  SET_ESR_EDN (esr, edn);
	  SET_ESR_EDV (esr);
	}
      else
	CLEAR_ESR_EDV (esr);

      if (set_daec)
	SET_ESR_DAEC (esr, item->u.daec);

      SET_ESR_VALID (esr);
      SET_ESR (reg_index, esr);
    }
}
/* 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.  */
void
frv_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;
    }
}