/* Handle a break interrupt.  */
void
frv_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.  */
void
frv_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.  */
void
frv_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);
}
Пример #4
0
void
frvbf_check_recovering_store (
  SIM_CPU *current_cpu, PCADDR address, SI regno, int size, int is_float
)
{
  FRV_CACHE *cache = CPU_DATA_CACHE (current_cpu);
  int reg_ix;

  CPU_RSTR_INVALIDATE(current_cpu) = 0;

  for (reg_ix = next_valid_nesr (current_cpu, NO_NESR);
       reg_ix != NO_NESR;
       reg_ix = next_valid_nesr (current_cpu, reg_ix))
    {
      if (address == GET_H_SPR (H_SPR_NEEAR0 + reg_ix))
	{
	  SI nesr = GET_NESR (reg_ix);
	  int nesr_drn = GET_NESR_DRN (nesr);
	  BI nesr_fr = GET_NESR_FR (nesr);
	  SI remain;

	  /* Invalidate cache block containing this address.
	     If we need to count cycles, then the cache operation will be
	     initiated from the model profiling functions.
	     See frvbf_model_....  */
	  if (model_insn)
	    {
	      CPU_RSTR_INVALIDATE(current_cpu) = 1;
	      CPU_LOAD_ADDRESS (current_cpu) = address;
	    }
	  else
	    frv_cache_invalidate (cache, address, 1/* flush */);

	  /* Copy the stored value to the register indicated by NESR.DRN.  */
	  for (remain = size; remain > 0; remain -= 4)
	    {
	      SI value;

	      if (is_float)
		value = GET_H_FR (regno);
	      else
		value = GET_H_GR (regno);

	      switch (size)
		{
		case 1:
		  value &= 0xff;
		  break;
		case 2:
		  value &= 0xffff;
		  break;
		default:
		  break;
		}

	      if (nesr_fr)
		sim_queue_fn_sf_write (current_cpu, frvbf_h_fr_set, nesr_drn,
				       value);
	      else
		sim_queue_fn_si_write (current_cpu, frvbf_h_gr_set, nesr_drn,
				       value);

	      nesr_drn++;
	      regno++;
	    }
	  break; /* Only consider the first matching register.  */
	}
    } /* loop over active neear registers.  */
}
Пример #5
0
/* Return from trap.  */
USI
frv_rett (SIM_CPU *current_cpu, PCADDR pc, BI debug_field)
{
  USI new_pc;
  /* if (normal running mode and debug_field==0
       PC=PCSR
       PSR.ET=1
       PSR.S=PSR.PS
     else if (debug running mode and debug_field==1)
       PC=(BPCSR)
       PSR.ET=BPSR.BET
       PSR.S=BPSR.BS
       change to normal running mode
  */
  int psr_s = GET_H_PSR_S ();
  int psr_et = GET_H_PSR_ET ();

  /* Check for exceptions in the priority order listed in the FRV Architecture
     Volume 2.  */
  if (! psr_s)
    {
      /* Halt if PSR.ET is not set.  See chapter 6 of the LSI.  */
      if (! psr_et)
	{
	  SIM_DESC sd = CPU_STATE (current_cpu);
	  sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
	}

      /* privileged_instruction interrupt will have already been queued by
	 frv_detect_insn_access_interrupts.  */
      new_pc = pc + 4;
    }
  else if (psr_et)
    {
      /* Halt if PSR.S is set.  See chapter 6 of the LSI.  */
      if (psr_s)
	{
	  SIM_DESC sd = CPU_STATE (current_cpu);
	  sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
	}

      frv_queue_program_interrupt (current_cpu, FRV_ILLEGAL_INSTRUCTION);
      new_pc = pc + 4;
    }
  else if (! CPU_DEBUG_STATE (current_cpu) && debug_field == 0)
    {
      USI psr = GET_PSR ();
      /* Return from normal running state.  */
      new_pc = GET_H_SPR (H_SPR_PCSR);
      SET_PSR_ET (psr, 1);
      SET_PSR_S (psr, GET_PSR_PS (psr));
      sim_queue_fn_si_write (current_cpu, frvbf_h_spr_set, H_SPR_PSR, psr);
    }
  else if (CPU_DEBUG_STATE (current_cpu) && debug_field == 1)
    {
      USI psr = GET_PSR ();
      /* Return from debug state.  */
      new_pc = GET_H_SPR (H_SPR_BPCSR);
      SET_PSR_ET (psr, GET_H_BPSR_BET ());
      SET_PSR_S (psr, GET_H_BPSR_BS ());
      sim_queue_fn_si_write (current_cpu, frvbf_h_spr_set, H_SPR_PSR, psr);
      CPU_DEBUG_STATE (current_cpu) = 0;
    }
  else
    new_pc = pc + 4;

  return new_pc;
}
Пример #6
0
/* Handle TRA and TIRA insns.  */
void
frv_itrap (SIM_CPU *current_cpu, PCADDR pc, USI base, SI offset)
{
  SIM_DESC sd = CPU_STATE (current_cpu);
  host_callback *cb = STATE_CALLBACK (sd);
  USI num = ((base + offset) & 0x7f) + 0x80;

#ifdef SIM_HAVE_BREAKPOINTS
  /* Check for breakpoints "owned" by the simulator first, regardless
     of --environment.  */
  if (num == TRAP_BREAKPOINT)
    {
      /* First try sim-break.c.  If it's a breakpoint the simulator "owns"
	 it doesn't return.  Otherwise it returns and let's us try.  */
      sim_handle_breakpoint (sd, current_cpu, pc);
      /* Fall through.  */
    }
#endif

  if (STATE_ENVIRONMENT (sd) == OPERATING_ENVIRONMENT)
    {
      frv_queue_software_interrupt (current_cpu, num);
      return;
    }

  switch (num)
    {
    case TRAP_SYSCALL :
      {
	CB_SYSCALL s;
	CB_SYSCALL_INIT (&s);
	s.func = GET_H_GR (7);
	s.arg1 = GET_H_GR (8);
	s.arg2 = GET_H_GR (9);
	s.arg3 = GET_H_GR (10);

	if (s.func == TARGET_SYS_exit)
	  {
	    sim_engine_halt (sd, current_cpu, NULL, pc, sim_exited, s.arg1);
	  }

	s.p1 = (PTR) sd;
	s.p2 = (PTR) current_cpu;
	s.read_mem = syscall_read_mem;
	s.write_mem = syscall_write_mem;
	cb_syscall (cb, &s);
	SET_H_GR (8, s.result);
	SET_H_GR (9, s.result2);
	SET_H_GR (10, s.errcode);
	break;
      }

    case TRAP_BREAKPOINT:
      sim_engine_halt (sd, current_cpu, NULL, pc, sim_stopped, SIM_SIGTRAP);
      break;

      /* Add support for dumping registers, either at fixed traps, or all
	 unknown traps if configured with --enable-sim-trapdump.  */
    default:
#if !TRAPDUMP
      frv_queue_software_interrupt (current_cpu, num);
      return;
#endif

#ifdef TRAP_REGDUMP1
    case TRAP_REGDUMP1:
#endif

#ifdef TRAP_REGDUMP2
    case TRAP_REGDUMP2:
#endif

#if TRAPDUMP || (defined (TRAP_REGDUMP1)) || (defined (TRAP_REGDUMP2))
      {
	char buf[256];
	int i, j;

	buf[0] = 0;
	if (STATE_TEXT_SECTION (sd)
	    && pc >= STATE_TEXT_START (sd)
	    && pc < STATE_TEXT_END (sd))
	  {
	    const char *pc_filename = (const char *)0;
	    const char *pc_function = (const char *)0;
	    unsigned int pc_linenum = 0;

	    if (bfd_find_nearest_line (STATE_PROG_BFD (sd),
				       STATE_TEXT_SECTION (sd),
				       (struct bfd_symbol **) 0,
				       pc - STATE_TEXT_START (sd),
				       &pc_filename, &pc_function, &pc_linenum)
		&& (pc_function || pc_filename))
	      {
		char *p = buf+2;
		buf[0] = ' ';
		buf[1] = '(';
		if (pc_function)
		  {
		    strcpy (p, pc_function);
		    p += strlen (p);
		  }
		else
		  {
		    char *q = (char *) strrchr (pc_filename, '/');
		    strcpy (p, (q) ? q+1 : pc_filename);
		    p += strlen (p);
		  }

		if (pc_linenum)
		  {
		    sprintf (p, " line %d", pc_linenum);
		    p += strlen (p);
		  }

		p[0] = ')';
		p[1] = '\0';
		if ((p+1) - buf > sizeof (buf))
		  abort ();
	      }
	  }

	sim_io_printf (sd,
		       "\nRegister dump,    pc = 0x%.8x%s, base = %u, offset = %d\n",
		       (unsigned)pc, buf, (unsigned)base, (int)offset);

	for (i = 0; i < 64; i += 8)
	  {
	    long g0 = (long)GET_H_GR (i);
	    long g1 = (long)GET_H_GR (i+1);
	    long g2 = (long)GET_H_GR (i+2);
	    long g3 = (long)GET_H_GR (i+3);
	    long g4 = (long)GET_H_GR (i+4);
	    long g5 = (long)GET_H_GR (i+5);
	    long g6 = (long)GET_H_GR (i+6);
	    long g7 = (long)GET_H_GR (i+7);

	    if ((g0 | g1 | g2 | g3 | g4 | g5 | g6 | g7) != 0)
	      sim_io_printf (sd,
			     "\tgr%02d - gr%02d:   0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx\n",
			     i, i+7, g0, g1, g2, g3, g4, g5, g6, g7);
	  }

	for (i = 0; i < 64; i += 8)
	  {
	    long f0 = (long)GET_H_FR (i);
	    long f1 = (long)GET_H_FR (i+1);
	    long f2 = (long)GET_H_FR (i+2);
	    long f3 = (long)GET_H_FR (i+3);
	    long f4 = (long)GET_H_FR (i+4);
	    long f5 = (long)GET_H_FR (i+5);
	    long f6 = (long)GET_H_FR (i+6);
	    long f7 = (long)GET_H_FR (i+7);

	    if ((f0 | f1 | f2 | f3 | f4 | f5 | f6 | f7) != 0)
	      sim_io_printf (sd,
			     "\tfr%02d - fr%02d:   0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx\n",
			     i, i+7, f0, f1, f2, f3, f4, f5, f6, f7);
	  }

	sim_io_printf (sd,
		       "\tlr/lcr/cc/ccc: 0x%.8lx 0x%.8lx 0x%.8lx 0x%.8lx\n",
		       (long)GET_H_SPR (272),
		       (long)GET_H_SPR (273),
		       (long)GET_H_SPR (256),
		       (long)GET_H_SPR (263));
      }
      break;
#endif
    }
}
Пример #7
0
USI
frvbf_h_spr_get (SIM_CPU *current_cpu, UINT regno)
{
  return GET_H_SPR (regno);
}