OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [final_interface/] [gdb-5.0/] [gdb/] [or1k-tdep.c] - Rev 1765

Compare with Previous | Blame | View Log

/* Target-dependent code for the or1k architecture, for GDB, the GNU Debugger.
   Copyright 1988-1999, Free Software Foundation, Inc.
   Contributed by Alessandro Forin(af@cs.cmu.edu at CMU
   and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
 
   This file is part of GDB.
 
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, 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 of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
 
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */
 
#include "defs.h"
#include "gdb_string.h"
#include "frame.h"
#include "inferior.h"
#include "symtab.h"
#include "value.h"
#include "gdbcmd.h"
#include "language.h"
#include "gdbcore.h"
#include "symfile.h"
#include "objfiles.h"
#include "gdbtypes.h"
#include "target.h"
 
#include "opcode/or32.h"
 
/* *INDENT-OFF* */
 
/* Group reg name size.  See or1k_reg_names.  */
int or1k_group_name_sizes[OR1K_NUM_SPR_GROUPS] = {
  64,   0,   0, 6, 6, 2, (24+32+32), 16, 1, 3, 2};
 
/* Generated reg names.  See or1k_spr_reg_name.  */
int or1k_spr_valid_aliases[OR1K_NUM_SPR_GROUPS] = {
  64, 515, 515, 6, 6, 2, (24+32+32), 16, 1, 3, 2};
 
/* Register names.  */
char *or1k_reg_names[] = {
  /* group 0 - general*/  
  "UPR",    "VR", "PC", "SR", "EPCR0", "SPR0_5", "SPR0_6", "SPR0_7", 
  "SPR0_8", "SPR0_9", "SPR0_10", "SPR0_11", "SPR0_12", "SPR0_13", "SPR0_14", "SPR0_15",
  "EPCR0", "EPCR1", "EPCR2", "EPCR3", "EPCR4", "EPCR5", "EPCR6", "EPCR7",
  "EPCR8", "EPCR9", "EPCR10", "EPCR11", "EPCR12", "EPCR13", "EPCR14", "EPCR15",
  "EEAR0","EEAR1", "EEAR2", "EEAR3", "EEAR4", "EEAR5", "EEAR6", "EEAR7",
  "EEAR8", "EEAR9", "EEAR10", "EEAR11", "EEAR12", "EEAR13", "EEAR14", "EEAR15",
  "ESR0", "ESR1", "ESR2", "ESR3", "ESR4", "ESR5", "ESR6", "ESR7",
  "ESR8", "ESR9", "ESR10", "ESR11", "ESR12", "ESR13", "ESR14", "ESR15",
  /* gpr+vf registers generated */ 
  /* group 1 - Data MMU - not listed, generated */
  /* group 2 - Instruction MMU - not listed, generated */
  /* group 3 - Data cache */
  "DCCR", "DCBPR", "DCBFR", "DCBIR", "DCBWR", "DCBLR",
  /* group 4 - Instruction cache */
  "ICCR", "ICBPR", "ICBFR", "ICBIR", "ICBWR", "ICBLR",
  /* group 5 - MAC */
  "MACLO", "MACHI",
  /* group 6 - debug */
  "DVR0", "DVR1", "DVR2", "DVR3", "DVR4", "DVR5", "DVR6", "DVR7",
  "DCR0", "DCR1", "DCR2", "DCR3", "DCR4", "DCR5", "DCR6", "DCR7",
  "DMR1", "DMR2", "DCWR0","DCWR1", "DSR", "DRR",  "PC",   "SPR6_23",
 
  /* group 7 - performance counters unit */
  "PCCR0", "PCCR1", "PCCR2", "PCCR3", "PCCR4", "PCCR5", "PCCR6", "PCCR7",
  "PCCM0", "PCMR1", "PCMR2", "PCMR3", "PCMR4", "PCMR5", "PCMR6", "PCMR7",
 
  /* group 8 - power management */
  "PMR",
 
  /* group 9 - PIC */
  "PICMR", "PICPR",
 
  /* group 10 - tick timer */
  "TTCR", "TTIR"
};
 
static char *or1k_gdb_reg_names[] = {
  /* general purpose registers */
  "ZERO", "SP", "FP", "A0", "A1", "A2", "A3", "A4",
  "A5", "LR", "R10", "RV", "R12", "R13", "R14", "R15",
  "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
  "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31",
  /* vector/floating point registers */
  "VFA0",  "VFA1",  "VFA2",  "VFA3",  "VFA4",  "VFA5",  "VFRV ", "VFR7", 
  "VFR8",  "VFR9",  "VFR10", "VFR11", "VFR12", "VFR13", "VFR14", "VFR15",
  "VFR16", "VFR17", "VFR18", "VFR19", "VFR20", "VFR21", "VFR22", "VFR23",
  "VFR24", "VFR25", "VFR26", "VFR27", "VFR28", "VFR29", "VFR30", "VFR31",
  "PC",    "SR",    "EPCR"
};
 
static char *or1k_group_names[] = {
  "SYS", "DMMU", "IMMU", "DCACHE", "ICACHE", "MAC", "DEBUG", "PERF", "POWER",
  "PIC", "TIMER"
};
/* Table of or1k signals.  */
static struct {
  char *name;
  char *string;
  } or1k_signals [NUM_OR1K_SIGNALS + 1] =
{
  {"RSTE", "Reset Exception"},
  {"DFPE", "Data Page Fault Exception"},
  {"IFPE", "Instruction Page Fault Exception"},
  {"LPINTE", "Low Priority Interrupt Exception"},
  {"AE", "Alignment Exception"},
  {"HPINTE", "High Priority Interrupt Exception"},
  {"DME", "DTLB Miss Exception"},
  {"IME", "ITLB Miss Exception"},
  {"RE", "Range Exception"},
  {"SCE", "SCE Exception"}, //!!!
  {NULL, NULL}
};
 
/* *INDENT-ON* */
 
/* The list of available "set or1k " and "show or1k " commands */
static struct cmd_list_element *setor1kcmdlist = NULL;
static struct cmd_list_element *showor1kcmdlist = NULL;
 
/* List of all saved register addresses, produced by skip_prologue.  
   Relative address to sp, not used if 0.  */
static int or1k_saved_reg_addr[NUM_REGS];
 
 
/* Converts regno to sprno.  or1k debug unit has GPRs mapped to SPRs,
   which are not compact, so we are mapping them for GDB.  */
int
or1k_regnum_to_sprnum (int regno)
{
  if (regno < MAX_GPR_REGS)
    return SPR_REG(SPR_SYSTEM_GROUP, regno + CURRENT_CID * MAX_GPR_REGS + SPR_GPR);
  if (regno < MAX_GPR_REGS + MAX_VF_REGS)
    return SPR_REG(SPR_SYSTEM_GROUP, regno - MAX_GPR_REGS
		   + CURRENT_CID * MAX_GPR_REGS + SPR_VFPR);
  if (regno == PS_REGNUM)
    return SR_SPRNUM; 
  if (regno == PC_REGNUM)
    return PC_SPRNUM;
  if (regno == CCR_REGNUM)
    return CCR_SPRNUM(CURRENT_CID);
  error ("Invalid register number!");
}
 
/* Builds and returns register name.  */
 
static char tmp_name[16];
static char *
or1k_spr_register_name (i)
     int i;
{
  int group = i >> SPR_GROUP_SIZE_BITS;
  int index = i & (SPR_GROUP_SIZE - 1);
  switch (group)
    {
      /* Names covered in or1k_reg_names.  */
    case 0:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
    case 10:
      {
	int group_start = 0;
	for (i = 0; i < group; i++) 
	  group_start += or1k_group_name_sizes[i];
 
	if (index >= or1k_group_name_sizes[group])
	  {
	    sprintf (tmp_name, "SPR%i_%i", group, index);
	    return (char *)&tmp_name;
	  }
	else
	  return or1k_reg_names[group_start + index];
      }	  
      /* Build names for DMMU group.  */
    case 1:
      if (index < 256) {
	sprintf (tmp_name, "DTLBMR%i", index);
	return (char *)&tmp_name;
      }
      index -= 256;
      if (index < 256) {
	sprintf (tmp_name, "DTLBTR%i", index);
	return (char *)&tmp_name;
      }
      index -= 256;
      switch (index)
	{
	case 0:
	  return "DMMUCR";
	case 1:
	  return "DMMUPR";
	case 2:
	  return "DTLBEIR";
	default:
	  sprintf (tmp_name, "SPR1_%i", index+512);
	  return (char *)&tmp_name;
      }
      /* Build names for IMMU group.  */
    case 2:
      if (index < 256) {
	sprintf (tmp_name, "ITLBMR%i", index);
	return (char *)&tmp_name;
      }
      index -= 256;
      if (index < 256) {
	sprintf (tmp_name, "ITLBTR%i", index);
	return (char *)&tmp_name;
      }
      index -= 256;
      switch (index)
	{
	case 0:
	  return "IMMUCR";
	case 1:
	  return "IMMUPR";
	case 2:
	  return "ITLBEIR";
	default:
	  sprintf (tmp_name, "SPR1_%i", index+512);
	  return (char *)&tmp_name;
      }      
    default:
      sprintf (tmp_name, "SPR%i_%i", group, index);
      return (char *)&tmp_name;
    }
}
 
/* Get register index in group from name.  Negative if no match.  */
 
static int
or1k_regno_from_name (group, name)
     int group;
     char *name;
{
  int i;
  if (toupper(name[0]) == 'S' && toupper(name[1]) == 'P' && toupper(name[2]) == 'R')
    {
      char *ptr_c;      
      name += 3;
      i = (int) strtoul (name, &ptr_c, 10);
      if (*ptr_c != '_' || i != group)
	return -1;
      ptr_c++;
      i = (int) strtoul (name, &ptr_c, 10);
      if (*ptr_c)
	return -1;
      else return i;
    }
  for (i = 0; i < or1k_spr_valid_aliases[group]; i++)
    {
      char *s;
      s = or1k_spr_register_name (SPR_REG(group, i));
      if (strcasecmp (name, s) == 0)
	return i;
    }
  return -1;
}
 
/* Resturs gdb register name.  */
char *
or1k_register_name (regno)
     int regno;
{
  return or1k_gdb_reg_names[regno];
}
 
static int
do_vf_register (regnum)
     int regnum;
{				/* do values for FP (float) regs */
  char *raw_buffer;
  double doub, flt;	        /* doubles extracted from raw hex data */
  int inv1, inv3, byte;
 
  raw_buffer = (char *) alloca (OR1K_VF_REGSIZE);
 
  /* Get the data in raw format.  */
  if (read_relative_register_raw_bytes (regnum, raw_buffer))
    error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
 
  flt = unpack_double (builtin_type_float, raw_buffer, &inv1);
  doub = unpack_double (builtin_type_double, raw_buffer, &inv3);
 
  printf_filtered (inv1 ? " %-5s flt: <invalid float>" :
		       " %-5s flt:%-17.9g", REGISTER_NAME (regnum), flt);
  printf_filtered (inv3 ? " dbl: <invalid double> " :
		   " dbl: %-24.17g ", doub);
 
  /* pad small registers */
  for (byte = 0; byte < (OR1K_GPR_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++)
    printf_filtered ("  ");
  /* Now print the register value in hex, endian order. */
  if (TARGET_BYTE_ORDER == BIG_ENDIAN)
    for (byte = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum);
	 byte < REGISTER_RAW_SIZE (regnum);
	 byte++)
      printf_filtered ("%02x", (unsigned char) raw_buffer[byte]);
  else
    for (byte = REGISTER_VIRTUAL_SIZE (regnum) - 1;
	 byte >= 0;
	 byte--)
      printf_filtered ("%02x", (unsigned char) raw_buffer[byte]);
  printf_filtered ("\n");
 
  regnum++;
  return regnum;
}
 
/* Print a row's worth of GP (int) registers, with name labels above */
 
static int
do_gp_register_row (regnum)
     int regnum;
{
  /* do values for GP (int) regs */
  char raw_buffer[MAX_REGISTER_RAW_SIZE];
  int ncols = (OR1K_64BIT_IMPLEMENTATION ? 4 : 8);	/* display cols per row */
  int col, byte;
  int start_regnum = regnum;
  int numregs = NUM_REGS;
 
 
  /* For GP registers, we print a separate row of names above the vals */
  printf_filtered ("     ");
  for (col = 0; col < ncols && regnum < numregs; regnum++)
    {
      if (*REGISTER_NAME (regnum) == '\0')
	continue;		/* unused register */
      if (OR1K_IS_VF(regnum))
	break;			/* end the row: reached VF register */
      printf_filtered (OR1K_64BIT_IMPLEMENTATION ? "%17s" : "%9s",
		       REGISTER_NAME (regnum));
      col++;
    }
  printf_filtered ("\n      ");
 
  regnum = start_regnum;	/* go back to start of row */
 
  /* now print the values in hex, 4 or 8 to the row */
  for (col = 0; col < ncols && regnum < numregs; regnum++)
    {
      if (*REGISTER_NAME (regnum) == '\0')
	continue;		/* unused register */
      if (OR1K_IS_VF(regnum))
	break;			/* end row: reached VF register */
      /* OK: get the data in raw format.  */
      if (read_relative_register_raw_bytes (regnum, raw_buffer))
	error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum));
      /* pad small registers */
      for (byte = 0; byte < (OR1K_GPR_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++)
	printf_filtered ("  ");
      /* Now print the register value in hex, endian order. */
      if (TARGET_BYTE_ORDER == BIG_ENDIAN)
	for (byte = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum);
	     byte < REGISTER_RAW_SIZE (regnum);
	     byte++)
	  printf_filtered ("%02x", (unsigned char) raw_buffer[byte]);
      else
	for (byte = REGISTER_VIRTUAL_SIZE (regnum) - 1;
	     byte >= 0;
	     byte--)
	  printf_filtered ("%02x", (unsigned char) raw_buffer[byte]);
      printf_filtered (" ");
      col++;
    }
  if (col > 0)			/* ie. if we actually printed anything... */
    printf_filtered ("\n");
 
  return regnum;
}
 
/* Replacement for generic do_registers_info.  
   Print regs in pretty columns.  */
static void
print_register (regnum, all)
     int regnum, all;
{
  int offset;
  char raw_buffer[MAX_REGISTER_RAW_SIZE];
 
  /* Get the data in raw format.  */
  if (read_relative_register_raw_bytes (regnum, raw_buffer))
    {
      printf_filtered ("%s: [Invalid]", REGISTER_NAME (regnum));
      return;
    }
 
  /* If virtual format is floating, print it that way.  */
  if (OR1K_IS_VF (regnum))
    do_vf_register (regnum);
  else
    {
      int byte;
      printf_filtered ("%-16s\t", REGISTER_NAME (regnum));
 
      /* pad small registers */
      for (byte = 0; byte < (OR1K_GPR_REGSIZE - REGISTER_VIRTUAL_SIZE (regnum)); byte++)
	printf_filtered ("  ");
      /* Now print the register value in hex, endian order. */
      if (TARGET_BYTE_ORDER == BIG_ENDIAN)
	for (byte = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum);
	     byte < REGISTER_RAW_SIZE (regnum);
	     byte++)
	  printf_filtered ("%02x", (unsigned char) raw_buffer[byte]);
      else
	for (byte = REGISTER_VIRTUAL_SIZE (regnum) - 1;
	     byte >= 0;
	     byte--)
	  printf_filtered ("%02x", (unsigned char) raw_buffer[byte]);
      printf_filtered (" ");
    }
}
 
/* DO_REGISTERS_INFO: called by "info register" command */
 
void
or1k_do_registers_info (regnum, fpregs)
     int regnum;
     int fpregs;
{
  if (fpregs && !or1k_implementation.vf_present)
    {
      warning ("VF register set not present in this implementation.");
      fpregs = 0;
    }
  if (regnum != -1)		/* do one specified register */
    {
      if (*(REGISTER_NAME (regnum)) == '\0')
	error ("Not a valid register for the current processor type");
 
      print_register (regnum, 0);
      printf_filtered ("\n");
    }
  else
    /* do all (or most) registers */
    {
      regnum = 0;
      while (regnum < NUM_REGS)
	{
	  if (OR1K_IS_VF (regnum))
	    if (fpregs)		/* true for "INFO ALL-REGISTERS" command */
	      regnum = do_vf_register (regnum);	/* FP regs */
	    else
	      regnum++; 	/* skip floating point regs */
	  else
	    regnum = do_gp_register_row (regnum);	/* GP (int) regs */
	}
    }
}
 
/* Given the address at which to insert a breakpoint (BP_ADDR),
   what will that breakpoint be?
 
   For or1k, we have a breakpoint instruction. Since all or1k
   instructions are 32 bits, this is all we need, regardless of
   address. K is not used.  */
 
unsigned char *
or1k_breakpoint_from_pc (bp_addr, bp_size)
     CORE_ADDR * bp_addr;
     int *bp_size;
{ 
  static char breakpoint[] = BRK_INSTR_STRUCT;
  *bp_size = OR1K_INSTLEN;
  return breakpoint;
}
 
/* Return the string for a signal.  Replacement for target_signal_to_string (sig).  */
char
*or1k_signal_to_string (sig)
     enum target_signal sig;
{
  if ((sig >= TARGET_SIGNAL_FIRST) && (sig <= TARGET_SIGNAL_LAST))
    return or1k_signals[sig].string;
  else
    if (sig <= TARGET_SIGNAL_LAST + NUM_OR1K_SIGNALS)
      return or1k_signals[sig - TARGET_SIGNAL_LAST].string;
    else
      return 0/* signals[TARGET_SIGNAL_UNKNOWN].string*/;
}
 
/* Return the name for a signal.  */
char *
or1k_signal_to_name (sig)
     enum target_signal sig;
{
  if (sig >= TARGET_SIGNAL_LAST)
    if (sig <= TARGET_SIGNAL_LAST + NUM_OR1K_SIGNALS)
      return or1k_signals[sig - TARGET_SIGNAL_LAST].name;
    else
    /* I think the code which prints this will always print it along with
       the string, so no need to be verbose.  */
      return "?";
  if (sig == TARGET_SIGNAL_UNKNOWN)
    return "?";
  return 0/*!!!signals[sig].name*/;
}
 
/* Given a name, return its signal.  */
enum target_signal
or1k_signal_from_name (name)
     char *name;
{
  enum target_signal sig;
 
  /* It's possible we also should allow "SIGCLD" as well as "SIGCHLD"
     for TARGET_SIGNAL_SIGCHLD.  SIGIOT, on the other hand, is more
     questionable; seems like by now people should call it SIGABRT
     instead.  */
 
  /* This ugly cast brought to you by the native VAX compiler.  */
  for (sig = TARGET_SIGNAL_FIRST;
       or1k_signal_to_name (sig) != NULL;
       sig = (enum target_signal) ((int) sig + 1))
    if (STREQ (name, or1k_signal_to_name (sig)))
      return sig;
  return TARGET_SIGNAL_UNKNOWN;
}
 
/* Given a return value in `regbuf' with a type `valtype', extract and
   copy its value into `valbuf'. */
void
or1k_extract_return_value (valtype, regbuf, valbuf)
     struct type *valtype;
     char regbuf[REGISTER_BYTES];
     char *valbuf;
{
  if (TYPE_CODE_FLT == TYPE_CODE (valtype))
    memcpy (valbuf, &regbuf[REGISTER_BYTE (VFRV_REGNUM)], TYPE_LENGTH (valtype));
  else
    memcpy (valbuf, &regbuf[REGISTER_BYTE (RV_REGNUM)], TYPE_LENGTH (valtype));
}
 
/* The or1k cc defines the following
   prologue:
00000000 <_proc1>:
   0:	d7 e1 17 e4 	l.sw 0xffffffe4(r1),r2
   4:	9c 41 00 00 	l.addi r2,r1,0x0
   8:	9c 21 ff e8 	l.addi r1,r1,0xffffffe8
   c:	d7 e2 1f f8 	l.sw 0xfffffff8(r2),r3
  10:	d7 e2 27 f4 	l.sw 0xfffffff4(r2),r4
  14:	84 82 ff f8 	l.lwz r4,0xfffffff8(r2)
  18:	9d 24 00 00 	l.addi r9,r4,0x0
  1c:	00 00 00 02 	l.j 0x2
  20:	15 00 00 00 	l.nop 
 
00000024 <_L2>:
  24:	84 41 ff fc 	l.lwz r2,0xfffffffc(r1)
  28:	48 00 58 00 	l.jalr r11
  2c:	9c 21 00 18 	l.addi r1,r1,0x18 */
 
CORE_ADDR
or1k_skip_prologue (CORE_ADDR pc)
{
  unsigned long inst;
  CORE_ADDR skip_pc;
  CORE_ADDR func_addr, func_end;
  struct symtab_and_line sal;
  int i;
  int offset = 0;
 
  for (i = 0; i < MAX_GPR_REGS; i++)
    or1k_saved_reg_addr[i] = -1;
 
  /* Is there a prologue?  */
  inst = or1k_fetch_instruction (pc);
  if (inst & 0xfc1ff800 != 0xd4011000) return pc; /* l.sw I(r1),r2 */
  or1k_saved_reg_addr[2] = offset++;
  inst = or1k_fetch_instruction (pc + OR1K_INSTLEN);
  if (inst & 0xFFFF0000 != 0x9c410000) return pc; /* l.addi r2,r1,I */
  pc += 2 * OR1K_INSTLEN;
  inst = or1k_fetch_instruction (pc);
  if (inst & 0xFFFF0000 != 0x9c210000) return pc; /* l.addi r1,r1,I */
  pc += OR1K_INSTLEN;
 
  /* Skip stored registers.  */
  inst = or1k_fetch_instruction (pc);
  while (inst & 0xfc1ff800 != 0xd4020000)         /* l.sw 0x0(r2),rx */
    {
      /* get saved reg. */
      or1k_saved_reg_addr[(inst >> 11) & 0x1f] = offset++;
      pc += OR1K_INSTLEN;
      inst = or1k_fetch_instruction (pc);
    }
  return pc;
}
 
/* Determines whether this function has frame.  */
 
int
or1k_frameless_function_invocation (struct frame_info *fi)
{
  CORE_ADDR func_start, after_prologue;
  int frameless;
  func_start = (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET);
  after_prologue = SKIP_PROLOGUE (func_start);
 
  /* If we don't skip pc, we don't have even shortest possible  prologue.  */
  frameless = (after_prologue <= func_start);
  return frameless;
}
 
/* Given a GDB frame, determine the address of the calling function's frame.
   This will be used to create a new GDB frame struct, and then
   INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame. */
 
CORE_ADDR
or1k_frame_chain (frame)
     struct frame_info *frame;
{
  CORE_ADDR fp;
  if (USE_GENERIC_DUMMY_FRAMES)
    {
      if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
	return frame->frame;	/* dummy frame same as caller's frame */
    }
 
  if (inside_entry_file (frame->pc) ||
      frame->pc == entry_point_address ())
    return 0;
 
  if (frame->signal_handler_caller)
    fp = read_memory_integer (frame->frame, 4);
  else if (frame->next != NULL
	   && frame->next->signal_handler_caller
	   && FRAMELESS_FUNCTION_INVOCATION (frame))
    /* A frameless function interrupted by a signal did not change the
       frame pointer.  */
    fp = FRAME_FP (frame);
  else
    fp = read_memory_integer (frame->frame, 4);
 
  if (USE_GENERIC_DUMMY_FRAMES)
    {
      CORE_ADDR fpp, lr;
 
      lr = read_register (LR_REGNUM);
      if (lr == entry_point_address ())
	if (fp != 0 && (fpp = read_memory_integer (fp, 4)) != 0)
	  if (PC_IN_CALL_DUMMY (lr, fpp, fpp))
	    return fpp;
    }
 
  return fp;
}
 
/* The code to store, into a struct frame_saved_regs,
   the addresses of the saved registers of frame described by FRAME_INFO.
   This includes special registers such as pc and fp saved in special
   ways in the stack frame.  sp is even more special:
   the address we return for it IS the sp for the next frame.  */
void
or1k_init_saved_regs (struct frame_info *fi)
{
  CORE_ADDR frame_addr;
  int i;
  frame_saved_regs_zalloc (fi);
 
  /* Skip prologue sets or1k_saved_reg_addr[], we will use it later.  */
  or1k_skip_prologue (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET);
 
  for (i = 0; i < NUM_GPR_REGS+NUM_VF_REGS; i++)
    if (or1k_saved_reg_addr[i] >= 0)
      fi->saved_regs[i] = fi->frame + or1k_saved_reg_addr[i];
}
 
 
static CORE_ADDR
read_next_frame_reg (fi, regno)
     struct frame_info *fi;
     int regno;
{
  for (; fi; fi = fi->next)
    {
      /* We have to get the saved sp from the sigcontext
         if it is a signal handler frame.  */
      if (regno == SP_REGNUM && !fi->signal_handler_caller)
	return fi->frame;
      else
	{
	  if (fi->saved_regs == NULL)
	    or1k_init_saved_regs (fi);
	  if (fi->saved_regs[regno])
	    return read_memory_integer (ADDR_BITS_REMOVE (fi->saved_regs[regno]), OR1K_GPR_REGSIZE);
	}
    }
  return read_register (regno);
}
 
/* Find the caller of this frame.  We do this by seeing if LR_REGNUM
   is saved in the stack anywhere, otherwise we get it from the
   registers.  */
 
CORE_ADDR
or1k_frame_saved_pc (fi)
     struct frame_info *fi;
{
  CORE_ADDR saved_pc;
  /* We have to get the saved pc from the sigcontext
     if it is a signal handler frame.  */
  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
    saved_pc = read_memory_integer (fi->frame, OR1K_GPR_REGSIZE);
  else
    saved_pc = read_next_frame_reg (fi, PC_REGNUM);
 
  return ADDR_BITS_REMOVE (saved_pc);
}
 
/* Discard from the stack the innermost frame, restoring all registers.  */
 
void
or1k_pop_frame ()
{
  register int regnum;
  struct frame_info *frame = get_current_frame ();
  CORE_ADDR new_sp = FRAME_FP (frame);
 
  write_register (PC_REGNUM, FRAME_SAVED_PC (frame));
  if (frame->saved_regs == NULL)
    or1k_init_saved_regs (frame);
  for (regnum = 0; regnum < NUM_REGS; regnum++)    {
      if (regnum != SP_REGNUM && regnum != PC_REGNUM
	  && frame->saved_regs[regnum] >= 0)
	write_register (regnum,
			read_memory_integer (frame->saved_regs[regnum],
					     OR1K_GPR_REGSIZE));
    }
  write_register (SP_REGNUM, new_sp);
  flush_cached_frames ();
}
 
CORE_ADDR
or1k_push_arguments (nargs, args, sp, struct_return, struct_addr)
     int nargs;
     value_ptr *args;
     CORE_ADDR sp;
     int struct_return;
     CORE_ADDR struct_addr;
{
  int argreg;
  int float_argreg;
  int argnum;
  int len = 0;
  int stack_offset = 0;
 
  /* Initialize the integer and float register pointers.  */
  argreg = A0_REGNUM;
  float_argreg = VFA0_REGNUM;
 
  /* The struct_return pointer occupies the RV value register.  */
  if (struct_return)
    write_register (RV_REGNUM, struct_addr);
 
  /* Now load as many as possible of the first arguments into
     registers, and push the rest onto the stack.  Loop thru args
     from first to last.  */
  for (argnum = 0; argnum < nargs; argnum++)
    {
      char *val;
      char valbuf[MAX_REGISTER_RAW_SIZE];
      value_ptr arg = args[argnum];
      struct type *arg_type = check_typedef (VALUE_TYPE (arg));
      int len = TYPE_LENGTH (arg_type);
      enum type_code typecode = TYPE_CODE (arg_type);
 
      /* The EABI passes structures that do not fit in a register by
         reference. In all other cases, pass the structure by value.  */
      if (len > OR1K_GPR_REGSIZE &&
	  (typecode == TYPE_CODE_STRUCT || typecode == TYPE_CODE_UNION))
	{
	  store_address (valbuf, OR1K_GPR_REGSIZE, VALUE_ADDRESS (arg));
	  typecode = TYPE_CODE_PTR;
	  len = OR1K_GPR_REGSIZE;
	  val = valbuf;
	}
      else
	{
	  val = (char *) VALUE_CONTENTS (arg);
 
	  if (typecode == TYPE_CODE_FLT
	      /* Doubles are not stored in regs on 32b target.  */
	      && len <= OR1K_VF_REGSIZE
	      && OR1K_VF_PRESENT)
	    {
	      if (float_argreg <= OR1K_LAST_FP_ARG_REGNUM)
		{
		  CORE_ADDR regval = extract_address (val, len);
		  write_register (float_argreg++, regval);
		}
	      else
		{
		  write_memory ((CORE_ADDR) sp, val, OR1K_VF_REGSIZE);	      
		  sp -= OR1K_STACK_ALIGN;
		}
	    }
	  else
	    {	
	      if (argreg <= OR1K_LAST_ARG_REGNUM)
		{
		  CORE_ADDR regval = extract_address (val, len);
		  write_register (argreg++, regval);
		}
	      else
		{
		  write_memory ((CORE_ADDR) sp, val, OR1K_GPR_REGSIZE);	      
		  sp -= OR1K_STACK_ALIGN;
		}
	    }
	}
    }
 
  /* Return adjusted stack pointer.  */
  return sp;
}
 
/* Return nonzero when instruction has delay slot.  */
static int
is_delayed (insn)
     unsigned long insn;
{
  int i;
  for (i = 0; i < num_opcodes; ++i)
    if ((or32_opcodes[i].flags & OR32_IF_DELAY)
	&& (or32_opcode_match (insn, or32_opcodes[i].encoding)))
      break;
  return (i < num_opcodes);
}
 
int
or1k_step_skips_delay (pc)
     CORE_ADDR pc;
{
  char buf[OR1K_INSTLEN];
 
  if (target_read_memory (pc, buf, OR1K_INSTLEN) != 0)
    /* If error reading memory, guess that it is not a delayed branch.  */
    return 0;
  return is_delayed ((unsigned long) extract_unsigned_integer (buf, OR1K_INSTLEN));
}
 
CORE_ADDR
or1k_push_return_address (pc, sp)
     CORE_ADDR pc;
     CORE_ADDR sp;
{
  /* Set the return address register to point to the entry
     point of the program, where a breakpoint lies in wait.  */
  write_register (LR_REGNUM, CALL_DUMMY_ADDRESS ());
  return sp;
}
 
/* Root of all "set or1k "/"show or1k " commands. This will eventually be
   used for all OR1K-specific commands.  */
 
static void show_or1k_command PARAMS ((char *, int));
static void
show_or1k_command (args, from_tty)
     char *args;
     int from_tty;
{
  help_list (showor1kcmdlist, "show or1k ", all_commands, gdb_stdout);
}
 
static void set_or1k_command PARAMS ((char *, int));
static void
set_or1k_command (args, from_tty)
     char *args;
     int from_tty;
{
  printf_unfiltered ("\"set or1k\" must be followed by an appropriate subcommand.\n");
  help_list (setor1kcmdlist, "set or1k ", all_commands, gdb_stdout);
}
 
static char *
parse_spr_params (args, group, index)
		  char *args;
		  int *group, *index;
{
  *index = -1;
  if (args)
    {
      int i; 
      char *ptr_c;
      /* Check if group number was supplied.  */
      ptr_c = args;
      while (*ptr_c != ' ' && *ptr_c != 0)
	ptr_c++;
      *ptr_c = 0;
 
      *group = (int) strtoul (args, &ptr_c, 0);
      if (*ptr_c != 0)
	{
	  *group = OR1K_NUM_SPR_GROUPS;
	  /* check for group name */
	  for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++)
	    if (strcasecmp (or1k_group_names[i], args) == 0)
	      {
		*group = i;
		break;
	      }
	  /* Invalid group => check all register names in all groups.  */
	  if (*group >= OR1K_NUM_SPR_GROUPS)
	    {	      
	      for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++)
		{
		  int regno;
		  regno = or1k_regno_from_name (i, args);
		  if (regno >= 0)
		    {
		      *group = i;
		      *index = regno;
		    }
		}
	    }
	}
      if (*group < 0 || *group >= OR1K_NUM_SPR_GROUPS)
	error ("Invalid group or register.\n");
 
      if (*index < 0)
	{
	  args += strlen(args) + 1;
	  ptr_c = args;
	  while (*ptr_c != ' ' && *ptr_c != 0)
	    ptr_c++;
	  *ptr_c = 0;
	  *index = (int) strtoul (args, &ptr_c, 0);
	  if (*ptr_c != 0)
	    *index = or1k_regno_from_name (*group, args);
 
	  if (*index < 0)
	    {
	      for (i = 0; i < or1k_spr_valid_aliases[*group]; i++)
		printf_unfiltered ("%s\t", or1k_spr_register_name (SPR_REG(*group, i)));
	      printf_unfiltered ("\n");
	      return args + strlen(args) + 1;
	    }
	}
    }
  else
  /* No parameters - print groups */
    {
      int i;
      printf_unfiltered ("No parameter supplied. Valid groups are:\n");
      for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++)
	printf_unfiltered ("%s\t", or1k_group_names[i]);
      printf_unfiltered ("\nSingle register name or register name or number after the group can be also supplied.\n");
    }
  return args + strlen(args) + 1;
}
 
/* SPR register info.  */
 
void
info_spr_command (char *args, int from_tty)
{
  int group, index;
  parse_spr_params (args, &group, &index);
  if (index >= 0)
    {
      printf_unfiltered ("%s.%s (SPR%i_%i) set to %i(%X), was:%i(%X)\n", or1k_group_names[group], 
			 or1k_spr_register_name (SPR_REG(group, index)), group, index,
			 or1k_read_spr_reg (SPR_REG(group, index)));
    }
}
 
/* Set SPR register.  */
 
void
spr_command (char *args, int from_tty)
{
  int group, index;
  char *nargs = parse_spr_params (args, &group, &index);
  /* Any arguments left?  */
  if (args + strlen(args) >= nargs)
    error ("Invalid register value.");
  if (index >= 0)
    {
      unsigned long prev;
      unsigned long value;
      char *ptr_c;
 
      prev = or1k_read_spr_reg (SPR_REG(group, index));
 
      ptr_c = nargs;
      while (*ptr_c != ' ' && *ptr_c != 0)
	ptr_c++;
      *ptr_c = 0;
      value = strtoul (nargs, &ptr_c, 0);
      if (*ptr_c != 0)
	error ("Invalid register value.");
      printf_unfiltered ("%s.%s (SPR%i_%i) set to %i(%X), was:%i(%X)\n", or1k_group_names[group], 
			 or1k_spr_register_name (SPR_REG(group, index)), group, index,
			 value, value, prev, prev);      
    }
}
 
/* Calls extended command on target.  */
 
void
sim_command (char *args, int from_tty)
{
  or1k_sim_cmd (args, from_tty);
}
 
/* ARGSUSED */
/* accessflag:  hw_write:  watch write, 
                hw_read:   watch read, 
		hw_access: watch access (read or write) */
static void
hwatch_command (arg, from_tty)
     char *arg;
     int from_tty;
{
  struct expression *exp;
  int i;
  int nfree;
  /* Parse arguments.  */
  exp = parse_exp_1 (&arg, 0, 0);
 
  dump_prefix_expression (exp, gdb_stdout, "expr1");
 
  /* Now we have to find out if given prefix expression matches
     our HW based support. It may take up to
     or1k_implementation.num_matchpoints - or1k_implementation.num_used_matchpoints. */
  nfree = or1k_implementation.num_matchpoints - or1k_implementation.num_used_matchpoints;
  //printf_unfiltered ("%s\n", exp->elts[1].internalvar->name);
  free (exp);
}
 
void
_initialize_or1k_tdep ()
{
  struct cmd_list_element *c;
  /* Add root prefix command for all "set or1k"/"show or1k" commands */
  add_prefix_cmd ("or1k", no_class, set_or1k_command,
		  "Various OR1K specific commands.",
		  &setor1kcmdlist, "set or1k ", 0, &setlist);
 
  add_prefix_cmd ("or1k", no_class, show_or1k_command,
		  "Various OR1K specific commands.",
		  &showor1kcmdlist, "show or1k ", 0, &showlist);
 
  /* Commands to show information about the sprs.  */
  add_info ("spr", info_spr_command, "Show information about the spr registers.");
  add_com ("hwatch", class_breakpoint, hwatch_command, "Set hardware watchpoint.");
  add_com ("spr", class_support, spr_command, "Set specified SPR register.");
  add_com ("sim", class_obscure, sim_command,
	   "Send a extended command to the simulator.");
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.