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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [gdb/] [or1k-tdep.c] - Rev 1771

Go to most recent revision | 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 "demangle.h"
#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] = {
  80,   0,   0, 6, 4, 3,
  22, 16, 1, 3, 2, 8
};
 
/* Generated reg names (max valid alias index).
   See or1k_spr_reg_name.  */
int or1k_spr_valid_aliases[OR1K_NUM_SPR_GROUPS] = {
  2047+1, 2047+1, 2047+1, 258+1, 257+1, 257+1,
  78+1, 263+1, 16+1, 18+1, 256+1, 7+1
};
 
/* Register names.  */
char *or1k_reg_names[] = {
 
  /* group 0 - general*/
  "VR", "UPR", "CPUCFGR", "DMMUCFGR", "IMMUCFGR", "DCCFGR", "ICCFGR", "DCFGR",
  "PCCFGR", "SPR0_9", "SPR0_10", "SPR0_11", "SPR0_12", "SPR0_13", "SPR0_14", "SPR0_15",
  "NPC", "SR", "PPC", "SPR0_19", "SPR0_20", "SPR0_21", "SPR0_22", "SPR0_23",
  "SPR0_24", "SPR0_25", "SPR0_26", "SPR0_27", "SPR0_28", "SPR0_29", "SPR0_30", "SPR0_31", 
  "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", "ICBIR", "ICBLR",
 
  /* group 5 - MAC */
  "SPR5_0", "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",
 
  /* group 7 - performance counters unit */
  "PCCR0",  "PCCR1", "PCCR2", "PCCR3", "PCCR4", "PCCR5", "PCCR6", "PCCR7",
  "PCCMR0", "PCMR1", "PCMR2", "PCMR3", "PCMR4", "PCMR5", "PCMR6", "PCMR7",
 
  /* group 8 - power management */
  "PMR",
 
  /* group 9 - PIC */
  "PICMR", /* now-defunct PICPR */ "SPR9_1", "PICSR",
  /* group 10 - tick timer */
  "TTMR", "TTCR",
 
  /* group 11 - configuration */
  "CPUCFGR", "DMMUCFGR", "IMMUCFGR", "DCCFGR", "ICCFGR", "SPR11_5", "DCFGR", "PCCFGR"
};
 
static char *or1k_gdb_reg_names[] = {
 
  /* general purpose registers */
  "R0",  "R1",  "R2",  "R3",  "R4",  "R5",  "R6",  "R7",
  "R8",  "R9",  "R10", "R11", "R12", "R13", "R14", "R15",
  "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
  "R24", "R25", "R26", "R27", "R28", "R29", "R30", "R31",
 
  /* Modified by CZ 12/09/01 */
  /* 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", "ExPC", "ExEAR", "ExSR"
};
 
static char *or1k_group_names[] = {
  "SYS", "DMMU", "IMMU", "DCACHE", "ICACHE", "MAC", "DEBUG", "PERF",
  "POWER", "PIC", "TIMER", "CONFIG"
};
 
/* Table of or1k signals.  */
static struct
  {
  char *name;
  char *string;
  } or1k_signals [NUM_OR1K_SIGNALS + 1] =
  {
    {"RSTE", "Reset Exception"},
    {"BUSE", "Bus Error" },
    {"DFPE", "Data Page Fault Exception"},
    {"IFPE", "Instruction Page Fault Exception"},
    {"LPINTE", "Low Priority Interrupt Exception"},
    {"AE", "Alignment Exception"},
    {"ILINSE" "Illegal Instruction" },
    {"HPINTE", "High Priority Interrupt Exception"},
    {"DME", "DTLB Miss Exception"},
    {"IME", "ITLB Miss Exception"},
    {"RE", "Range Exception"},
    {"SCE", "SCE Exception"},
    {"BRKPTE", "Breakpoint Exception"},
    {NULL, NULL}
  };
 
const char *compare_to_names[NUM_CT_NAMES] =
  {
    "DISABLED", "FETCH", "LEA", "SEA", "LDATA", "SDATA", "AEA", "ADATA"
  };
 
const char *or1k_record_names[MAX_RECORD_NAMES] = 
  {
    "PC", "LSEA", "LDATA", "SDATA", "READSPR", "WRITESPR", "INSTR"
  };   
 
const char *or1k_is_names[MAX_IS_NAMES] =
  {
    "IF_NONE", "IF_NORMAL", "IF_BRANCH", "IF_DELAY"
  };
 
const char *or1k_ls_names[MAX_LS_NAMES] =
  {
    "LS_NONE", " ", "LBZ", "LBS", "LHZ", "LHS", "LWZ", "LWS",
    " ", " ", "SB", " ", "SH", " ", "SW", " "
  };
 
/* *INDENT-ON* */
 
/* The list of available "set or1k " and "show or1k " commands */
static struct cmd_list_element *htrace_cmdlist = NULL;
static struct cmd_list_element *htrace_mode_cmdlist = NULL;
 
struct htrace_struct or1k_htrace;
struct hwatch_struct or1k_hwatch[MAX_HW_WATCHES];
int num_hw_watches = 0;
 
/* Trace data.  */
char trace_filename[TRACE_FILENAME_SIZE] = "trace.dat";
 
/* Size of trace file in records.  */
int trace_size = 0;
 
/* Previous values for buffer display.  */
static int prev_length = 10;
static int prev_from = 0;
 
/* Converts regno to sprno.  or1k debug unit has GPRs mapped to SPRs,
   which are not compact, so we are mapping them for GDB.  */
/* Rewritten by CZ 12/09/01 */
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_START);
 
  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_START);
 
  switch(regno)
    {
    case PS_REGNUM:         return SR_SPRNUM;
    case PC_REGNUM:         return PC_SPRNUM;
    /*case CCR_REGNUM:        return CCR_SPRNUM(CURRENT_CID);*/
    case EPCR_REGNUM:        return EPCR_SPRNUM(CURRENT_CID);
    /*case EAR_REGNUM:        return EAR_SPRNUM(CURRENT_CID);
    case ESR_REGNUM:        return ESR_SPRNUM(CURRENT_CID);*/
    default:
      error("Invalid register number!");
      break;
    }
 
  return 0;
}
 
/* 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:
 
      /* Generate upper names.  */
      if (index >= SPR_GPR_START)
	{
	  if (index < SPR_VFPR_START)
	    sprintf (tmp_name, "GPR%i", index - SPR_GPR_START);
	  else
	    sprintf (tmp_name, "VFR%i", index - SPR_VFPR_START);
	  return (char *)&tmp_name;
	}
    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:
    case 2:
      strcpy (tmp_name, (group == 1)?"D":"I");
      switch (index)
	{
	case 16:
	  return strcat (tmp_name, "MMUCR");
	case 17:
	  return strcat (tmp_name, "MMUPR");
	case 18:
	  return strcat (tmp_name, "TLBEIR");
	case 24:
	  return strcat (tmp_name, "ATBMR0");
	case 25:
	  return strcat (tmp_name, "ATBMR1");
	case 26:
	  return strcat (tmp_name, "ATBMR2");
	case 27:
	  return strcat (tmp_name, "ATBMR3");
	case 28:
	  return strcat (tmp_name, "ATBTR0");
	case 29:
	  return strcat (tmp_name, "ATBTR0");
	case 30:
	  return strcat (tmp_name, "ATBTR0");
	case 31:
	  return strcat (tmp_name, "ATBTR0");
	default:
	  if (index >= 1024) {
	    index -= 1024;
	    sprintf (tmp_name, "%sTLBW%iMR%i", (group == 1)?"D":"I", index / 128, index % 128);
	    return (char *)&tmp_name;
	  }	  
	  sprintf (tmp_name, "SPR%i_%i", group, index);
	  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;
}
 
/* Returns gdb register name.  */
 
char *
or1k_register_name (regno)
     int regno;
{
  return or1k_gdb_reg_names[regno];
}
 
/* Utility function to display vf regs.  */
 
static int
do_vf_register (regnum)
     int regnum;
{
  /* do values for FP (float) regs */
  char *raw_buffer;
 
   /* doubles extracted from raw hex data */
  double doub, flt;
  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);
 
  if (inv1)
    printf_filtered (" %-5s flt: <invalid float>", REGISTER_NAME (regnum));
  else
    printf_filtered (" %-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];
 
  /* display cols per row */
  int ncols = (OR1K_64BIT_IMPLEMENTATION ? 4 : 8);
  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++)
    {
      /* unused register? */
      if (*REGISTER_NAME (regnum) == '\0')
	continue;		
 
      /* end row: reached VF register? */
      if (OR1K_IS_VF(regnum))
	break;			
 
      /* 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++;
    }
 
  /* ie. if we actually printed anything... */
  if (col > 0)		    
    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))
	    /* true for "INFO ALL-REGISTERS" command */
	    if (fpregs)		
	      /* FP regs */
	      regnum = do_vf_register (regnum);	
	    else
	      /* skip floating point regs */
	      regnum++; 	
	  else
	    /* GP (int) regs */
	    regnum = do_gp_register_row (regnum);	
	}
    }
}
 
/* 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).  NOT USED.  */
 
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;
}
 
/* 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;
}
 
/* Given a name, return its signal.  NOT USED.  */
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));
}
 
/* Given a register index, return the first byte of the register within a remote
   protocol packet.  This applies only to serial targets, not jtag or sim. */
int
or1k_register_byte(regnum)
     int regnum;
{
  int byte_offset;
 
  byte_offset = 0;
  if (regnum < MAX_GPR_REGS) {
    if (regnum < NUM_GPR_REGS)
      return byte_offset + regnum * OR1K_GPR_REGSIZE;
    else
      return -1;
  }
 
  byte_offset += NUM_GPR_REGS * OR1K_GPR_REGSIZE;
  regnum -= MAX_GPR_REGS;
  if (regnum < MAX_VF_REGS) {
    if (regnum < NUM_VF_REGS)
      return byte_offset + regnum * OR1K_VF_REGSIZE;
    else
      return -1;
  }
 
  /* Must be PC, SR, or EPC */
  byte_offset += NUM_VF_REGS * OR1K_VF_REGSIZE;
  regnum -= MAX_VF_REGS;
  if (regnum < 3)
    return byte_offset + regnum * OR1K_SPR_REGSIZE;
 
  /* Illegal register */
  return -1;
}
 
/* Number of bytes of storage in the actual machine representation for
   register N.  NOTE: This indirectly defines the register size
   transfered by the GDB protocol.  If we have 64bit processor
   implementation, GPR register raw size is 8B, otherwise 4B.  */
int
or1k_register_raw_size(int regnum)
{
  int byte_offset;
 
  if (regnum < MAX_GPR_REGS) {
    if (regnum < NUM_GPR_REGS)
      return OR1K_GPR_REGSIZE;
    else
      return 0;
  }
 
  regnum -= MAX_GPR_REGS;
  if (regnum < MAX_VF_REGS) {
    if (regnum < NUM_VF_REGS)
      return OR1K_VF_REGSIZE;
    else
      return 0;
  }
 
  /* Must be PC, SR, or EPC */
  regnum -= MAX_VF_REGS;
  if (regnum < 3)
    return OR1K_SPR_REGSIZE;
 
  /* Illegal register */
  return 0;
}  
 
/* Extra arch-specific data tied to frame */
struct frame_extra_info
{
  /* Size of stack frame, in bytes.  Produced by skip_prologue() */
  int frame_size;
 
  /* List of frame offsets of all registers saved in a function's
     prologue.  This is deduced by skip_prologue().  Offset is in bytes,
     relative to sp.  If value is -1, corresponding reg is not saved by
     the prologue code. */
  int saved_reg_frame_offset[NUM_REGS];
 
  /* Address of first instruction after the last prologue instruction;
     Note that there may be instructions from the function's body
     intermingled with the prologue.
     If value is -1, not initialized. */
  CORE_ADDR after_prologue;
};
 
/* Initialize arch-specific frame data */
void
or1k_init_extra_frame_info (int fromleaf, struct frame_info *frame)
{
  int i;
 
  frame->extra_info = (struct frame_extra_info *)
    frame_obstack_alloc (sizeof (struct frame_extra_info));
 
  frame->extra_info->after_prologue = -1;
  frame->extra_info->frame_size = -1;
  for (i = 0; i < NUM_REGS; i++)
    frame->extra_info->saved_reg_frame_offset[i] = -1;
}
 
/* For stack frame sizes less than 0x8000, the or1k version of gcc
   emits the following prologue:
 
     l.addi    r1, r1, -<STACK_FRAME_SIZE>
     l.sw      <FP_OFFSET>(r1),r2
     l.addi    r2, r1, <STACK_FRAME_SIZE>
 
     ; Save regs that will be clobbered     
     l.sw      <OFFSET_Rx>(r1),rx
     l.sw      <OFFSET_Ry>(r1),ry
     ; ...
 
*/
 
/* FIXME: Does not work with frames greater than 0x7fff in size */
 
/* If pframeless is non-NULL, only parse enough of the prologue to
   determine if a function has a frame or not and return the result in
   *pframeless.  This may save some remote transactions with the
   target. */
CORE_ADDR
or1k_skip_prologue (CORE_ADDR pc, struct frame_info *fi)
{
  unsigned long insn;
  CORE_ADDR skip_pc;
  CORE_ADDR func_addr, func_end;
  struct symtab_and_line sal;
  int i, frameless;
  int offset = 0;
  int rB, immediate, immediate_hi;
  int* saved_reg_frame_offset;
 
  /* Check to see if prologue analysis is cached from prior call */
  if (fi && fi->extra_info->after_prologue != -1)
    return fi->extra_info->after_prologue;
 
  if (fi)
    saved_reg_frame_offset = &fi->extra_info->saved_reg_frame_offset[0];
 
  /* Is there a prologue?  */
  insn = or1k_fetch_instruction (pc);
  if ((insn & 0xFFFF0000) != 0x9c210000) /* l.addi r1,r1,I */
    goto done;
 
  pc += OR1K_INSTLEN;
 
  insn = or1k_fetch_instruction (pc);
  if ((insn & 0xfc1ff800) != 0xd4011000) /* l.sw I(r1),r2 */
    goto done;
  immediate_hi = (insn & 0x03E00000) >> 10;
  immediate    = (insn & 0x000007FF) | immediate_hi;
  pc += OR1K_INSTLEN;
  if (fi)
    saved_reg_frame_offset[2] = immediate;
 
  insn = or1k_fetch_instruction (pc);
  if ((insn & 0xFFFF0000) != 0x9c410000) /* l.addi r2,r1,I */
    goto done;
  if (fi)
    fi->extra_info->frame_size = insn & 0xFFFF;
  pc += OR1K_INSTLEN;
 
  /* Skip stored registers.  */
  insn = or1k_fetch_instruction (pc);
  while ((insn & 0xfc1f0000) == 0xd4010000)  /* l.sw I(r1),rx */
    {
      rB           = (insn & 0x0000F800) >> 11;
      immediate_hi = (insn & 0x03E00000) >> 10;
      immediate    = (insn & 0x000007FF) | immediate_hi;
 
      /* get saved reg. */
      if (fi)
	saved_reg_frame_offset[rB] = immediate;
      pc += OR1K_INSTLEN;
      insn = or1k_fetch_instruction (pc);
    }
 done:
  if (fi)
    fi->extra_info->after_prologue = pc;
  return pc;
}
 
/* Determines whether this function has frame.  */
 
int
or1k_frameless_function_invocation (struct frame_info *fi)
{
  int frameless;
  CORE_ADDR func_start, after_prologue;
  func_start = (get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET);
 
  /* If we don't skip pc, we don't have even shortest possible  prologue.  */
  after_prologue = or1k_skip_prologue (func_start, fi);
  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 = 0;
  if (USE_GENERIC_DUMMY_FRAMES)
    {
      if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
	/* dummy frame same as caller's frame */
	return frame->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
    {
      unsigned long func_pc = get_pc_function_start(frame->pc);
      unsigned long insn = read_memory_integer(func_pc,4);
      int i;
      int offset = 0;
 
      /* The first instruction should tell us the number of bytes
	 in our frame. If it isn't we're in trouble because
	 the function is without a prologue... */
      if ((insn & 0xFFFF0000) == 0x9c210000) /* l.addi r1,r1,I */
	{
	  /* Sign extend immediate */
	  int immediate = (long)(insn << 16) >> 16;
          int frame_size = -immediate;
 
	  /* Look for the storage of the frame pointer in the
	     function prologue.. */
	  unsigned long insn = read_memory_integer(func_pc+4,4);
 
	  /* If bits are 31 - 26 are %110101,
	     and bits 20 - 16 are %00001,
	     and bits 15 - 11 are %00010,
	     then our frame pointer lies at the offset specified
	     by bits [25-21][10-0]. */
 
	  int code = insn >> 26;
	  int r1    = (insn & 0x001F0000) >> 16;
	  int r2    = (insn & 0x0000F800) >> 11;
	  int idx_h = (insn & 0x03E00000) >> 10;
	  int idx   = (insn & 0x000007FF) | idx_h;
 
	  if(code == 0x35 && r1 == 1 && r2 == 2)
	    {
	      offset = idx - frame_size;
	      fp = read_memory_integer (frame->frame + offset, 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)
{
  int i;
  CORE_ADDR frame_addr;
  CORE_ADDR func_pc = get_pc_function_start ((fi)->pc) + FUNCTION_START_OFFSET;
  int pc_found = 0;
 
  frame_saved_regs_zalloc (fi);
 
  /* Skip prologue sets frame_size and register frame save offsets
     which will both be used shortly. */
  or1k_skip_prologue (func_pc, fi);
 
  /* If the frame_size is less than 0, we have hit an assembly
     routine which we can't traverse beyond. Let's give up here,
     because attempting to continue will only lead to trouble. */
  if(fi->extra_info->frame_size < 0)
    {
      printf("Found a function without a prologue at 0x%08x\n",func_pc);
      printf("Frame pc was at 0x%08x\n",fi->pc);
      return;
    }
 
  for (i = 0; i < NUM_GPR_REGS + NUM_VF_REGS; i++)
    if (fi->extra_info->saved_reg_frame_offset[i] >= 0)
      fi->saved_regs[i] = 
	fi->frame + (fi->extra_info->saved_reg_frame_offset[i] - fi->extra_info->frame_size);
 
  /* We want to make sure we fill in the PC with the value of the
     r9 register from the NEXT frame, and that the value of r1 is
     the correct value of r1 for the next frame, which can be
     calculated by adding the frame_size to the frame pointer. */
  fi->saved_regs[1] = fi->frame - fi->extra_info->frame_size;
 
  if(fi->saved_regs[LR_REGNUM])
    fi->saved_regs[PC_REGNUM] = read_memory_integer(fi->saved_regs[LR_REGNUM],4);
  else
    fi->saved_regs[PC_REGNUM] = read_register(LR_REGNUM);
}
 
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])
	    {
	      if(regno == SP_REGNUM || regno == PC_REGNUM)
		return fi->saved_regs[regno];
	      else
		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.  */
 
int
is_delayed (insn)
     unsigned long insn;
{
  int index;
  index = insn_decode (insn);
  return or32_opcodes[index].flags & OR32_IF_DELAY;
}
 
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;
}
 
/* Parses args for spr name and puts result into group and index.  */
 
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;
		      break;
		    }
		}
	    }
	}
      if (*group < 0 || *group >= OR1K_NUM_SPR_GROUPS)
	error ("Invalid group or register.\n");
 
      if (*index < 0)
	{
	  printf ("a'%s'\n", args);
	  args += strlen(args) + 1;
	  printf ("b'%s'\n", args);
	  if (*args != 0)
	    {
	      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)
	    {
	      printf_filtered ("No register supplied. Valid registers are:\n");
	      for (i = 0; i < or1k_spr_valid_aliases[*group]; i++)
		{
		  char reg_name[16];
		  char *gen_name = or1k_spr_register_name (SPR_REG(*group, i));
		  sprintf (reg_name, "SPR%i_%i", *group, i);
		  if (strcmp (reg_name, gen_name) != 0) 
		    printf_filtered ("%s\t", gen_name);
		}
	      printf_filtered ("\n");
	      return args + strlen(args) + 1;
	    }
	}
    }
  else
    {
      /* No parameters - print groups */
      int i;
      printf_filtered ("No parameter supplied. Valid groups are:\n");
      for (i = 0; i < OR1K_NUM_SPR_GROUPS; i++)
	printf_filtered ("%s\t", or1k_group_names[i]);
      printf_filtered ("\nSingle register name or register name or number after the group can be also supplied.\n");
      return args;
    }
  return args + strlen(args) + 1;
}
 
/* SPR register info.  */
 
void
info_spr_command (args, from_tty)
     char *args;
     int from_tty;
{
  int group, index;
  parse_spr_params (args, &group, &index);
  if (index >= 0)
    {
      unsigned long value = or1k_read_spr_reg (SPR_REG(group, index));
      printf_unfiltered ("%s.%s = SPR%i_%i = %i(%x)\n", or1k_group_names[group], 
			 or1k_spr_register_name (SPR_REG(group, index)), group, index, value, value);
    }
}
 
void
info_trace_command (args, from_tty)
     char *args;
     int from_tty;
{
  unsigned char i;
  int j;
  printf_filtered ("        add      insn     res     time\n");
  i = or1k_read_spr_reg (SPR_REG(6, 255));
  for (j = 0; j < 256; j++, i++)
    printf_filtered ("%03d %03u %08x %08x %08x %08x\n", 255 - j, i, 
                      or1k_read_spr_reg (SPR_REG(6, 0x100 + i)),
                      or1k_read_spr_reg (SPR_REG(6, 0x200 + i)),
                      or1k_read_spr_reg (SPR_REG(6, 0x300 + i)),
                      or1k_read_spr_reg (SPR_REG(6, 0x400 + i)));
 
}
 
/* Set SPR register.  */
 
void
spr_command (args, from_tty)
     char *args;
     int from_tty;
{
  int group, index;
  char *nargs = parse_spr_params (args, &group, &index);
  if (index >= 0)
    {
      unsigned long prev;
      unsigned long value;
      char *ptr_c;
 
      /* Any arguments left?  */
      if (args + strlen(args) >= nargs)
	error ("Invalid register value.");
 
      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.");
			or1k_write_spr_reg (SPR_REG(group, index), 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 (args, from_tty)
     char *args;
     int from_tty;
{
  or1k_sim_cmd (args, from_tty);
}
 
 
static union exp_element exp_error;
 
/* Parses compare variable and returns it into ct.  */
 
union exp_element * or1k_parse_ct (exp, ct)
     union exp_element *exp;
     int *ct;
{
  int i;
  if (exp->opcode != OP_INTERNALVAR)
    error ("Valid lvalue expected.");
  exp++;
 
  for (i = 1; i < NUM_CT_NAMES; i++)
    if (strcasecmp (compare_to_names[i], exp->internalvar->name) == 0) break;
 
  if (i >= NUM_CT_NAMES)
    error ("Invalid compare to operand.");
  *ct = i;
  exp++;
 
  if (exp->opcode != OP_INTERNALVAR)
    return &exp_error;
  exp++;
  return exp;
}
 
/* Parses compare value and returns it into cv.  */
 
union exp_element * or1k_parse_cv (exp, cv)
     union exp_element *exp;
     unsigned int *cv;
{
  switch (exp->opcode)
    {
    case UNOP_IND:
      exp++;
      exp = or1k_parse_cv (exp, cv);   
      *cv = or1k_fetch_word (*cv);
      break;
    case OP_LONG:
      exp += 2;
      *cv = exp->longconst;
      exp += 2;
      break;
    case OP_REGISTER:
      exp++;
      *cv = read_register (exp->longconst);
      exp += 2;
      break;
    default:
      error ("Value expected.");
    }
  return exp;
}
 
/* Parse conditional.
   Puts freshly allocated array of matchpoints into match.  */
 
union exp_element *
or1k_parse_cond (exp, match, nmatch)
     union exp_element *exp;
     struct matchpoint **match;
     int *nmatch;
{
  unsigned int ct;
  *match = (struct matchpoint *) malloc (sizeof (struct matchpoint));
  *nmatch = 1;
  switch (exp->opcode)
    {
    case BINOP_EQUAL:
      (*match)->dcr.cc = CC_EQUAL;
      break;
    case BINOP_NOTEQUAL:
      (*match)->dcr.cc = CC_NEQUAL;
      break;
    case BINOP_LESS:
      (*match)->dcr.cc = CC_LESS;
      break;
    case BINOP_GTR:
      (*match)->dcr.cc = CC_GREAT;
      break;
    case BINOP_LEQ:
      (*match)->dcr.cc = CC_LESSE;
      break;
    case BINOP_GEQ:
      (*match)->dcr.cc = CC_GREATE;
      break;
    case BINOP_BITWISE_AND:
      (*match)->dcr.cc = CC_MASKED;
      break;
    default:
      return &exp_error;
    }
 
  exp++;
  (*match)->dcr.dp = 1;
  (*match)->dcr.sc = 0;
  if (exp->opcode == OP_INTERNALVAR)
    {
      exp = or1k_parse_ct (exp, &ct);
      exp = or1k_parse_cv (exp, &(*match)->dvr);
    }
  else
    {
      exp = or1k_parse_cv (exp, &(*match)->dvr);
      exp = or1k_parse_ct (exp, &ct);
    }
 
  (*match)->dcr.ct = ct;
  (*match)->chain_type = CHAINING_NONE;
  (*match)->cause_breakpoint = 0;
  return exp;
}
 
/* Parses expression with && or || operators.
   Puts freshly allocated array of matchpoints into match.
   valid & 1: && is allowed,
   valid & 2: || is allowed.  */
 
union exp_element *
or1k_parse_any (exp, match, nmatch, valid)
     union exp_element *exp;
     struct matchpoint **match;
     int *nmatch;
     int valid;
{
  union exp_element *tmp;
  int first_and_only = 0, first_or_only = 0;
  struct matchpoint *tmp_match1, *tmp_match2, *tmpm;
  int tmp_nmatch1, tmp_nmatch2, tmpn;
 
  switch (exp->opcode)
    {
    case BINOP_LOGICAL_AND:
      if (!(valid & 1))
	return &exp_error;
      exp++;
 
      /* Parse first argument.  */
      tmp = or1k_parse_any (exp, &tmp_match1, &tmp_nmatch1, 1);
      if (tmp == &exp_error)
	exp = or1k_parse_any (exp, &tmp_match1, &tmp_nmatch1, valid);
      else
	{
	  /* and_only successful */
	  exp = tmp;
	  first_and_only = 1;
	}
      if (exp == &exp_error)
	return &exp_error;
 
      /* Parse second argument.  */
      if (first_and_only)
	exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, valid);
      else
	exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, 1);
 
      if (exp == &exp_error)
	return &exp_error;
 
      if (first_and_only)
	{ 
	  /* Exchange structures, so that and_only is listed last.  */
	  struct matchpoint *tmpm = tmp_match1;
	  int tmpn = tmp_nmatch1;
	  tmp_match1 = tmp_match2;
	  tmp_nmatch1 = tmp_nmatch2;
	  tmp_match2 = tmpm;	  
	  tmp_nmatch2 = tmpn;
	}
 
      *nmatch = tmp_nmatch1 + tmp_nmatch2;
      *match = (struct matchpoint *)malloc (*nmatch * sizeof (struct matchpoint));
      memcpy (*match, tmp_match1, tmp_nmatch1 * sizeof (struct matchpoint));
      free (tmp_match1);
      tmp_match2[0].chain_type = CHAINING_AND;
      memcpy (*match + tmp_nmatch1, tmp_match2, tmp_nmatch2 * sizeof (struct matchpoint));
      free (tmp_match2);
      return exp;
 
    case BINOP_LOGICAL_OR:
      if (!(valid & 2))
	return &exp_error;
      exp++;
 
      /* Parse first argument.  */
      tmp = or1k_parse_any (exp, &tmp_match1, &tmp_nmatch1, 2);
      if (tmp == &exp_error)
	exp = or1k_parse_any (exp, &tmp_match1, &tmp_nmatch1, valid);
      else
	{
	  /* and_only successful */
	  exp = tmp;
	  first_or_only = 1;
	}
      if (exp == &exp_error)
	return &exp_error;
 
      /* Parse second argument.  */
      if (first_or_only)
	exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, valid);
      else
	exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, 2);
 
      if (exp == &exp_error)
	return &exp_error;
 
      if (first_or_only)
	{ 
	  /* Exchange structures, so that and_only is listed first.  */
	  struct matchpoint *tmpm = tmp_match1;
	  int tmpn = tmp_nmatch1;
	  tmp_match1 = tmp_match2;
	  tmp_nmatch1 = tmp_nmatch2;
	  tmp_match2 = tmpm;	  
	  tmp_nmatch2 = tmpn;
	}
 
      *nmatch = tmp_nmatch1 + tmp_nmatch2;
      *match = (struct matchpoint *)malloc (*nmatch * sizeof (struct matchpoint));
      memcpy (*match, tmp_match1, tmp_nmatch1 * sizeof (struct matchpoint));
      free (tmp_match1);
      tmp_match2[0].chain_type = CHAINING_OR;
      memcpy (*match + tmp_nmatch1, tmp_match2, tmp_nmatch2 * sizeof (struct matchpoint));
      free (tmp_match2);
      return exp;
 
    default:
      return or1k_parse_cond (exp, match, nmatch);
    }
}
 
/* Parses sequence of ||s.
   Puts freshly allocated array of matchpoints into match.  */
 
union exp_element *
or1k_parse_or (exp, match, nmatch, set_break)
     union exp_element *exp;
     struct matchpoint **match;
     int *nmatch;
     int set_break;
{ 
  struct matchpoint *tmp_match1, *tmp_match2;
  int tmp_nmatch1, tmp_nmatch2;
 
  switch (exp->opcode)
    {
    case BINOP_LOGICAL_OR:
      exp++;
      exp = or1k_parse_or (exp, &tmp_match1, &tmp_nmatch1);
      if (exp == &exp_error)
	return &exp_error;
 
      exp = or1k_parse_any (exp, &tmp_match2, &tmp_nmatch2, 3);
      if (set_break)
	{
	  tmp_match1[tmp_nmatch1 - 1].cause_breakpoint = 1;
	  tmp_match2[tmp_nmatch2 - 1].cause_breakpoint = 1;
	}
      *nmatch = tmp_nmatch1 + tmp_nmatch2;
      *match = (struct matchpoint *)malloc (*nmatch * sizeof (struct matchpoint));
      memcpy (*match, tmp_match1, tmp_nmatch1 * sizeof (struct matchpoint));
      free (tmp_match1);
      memcpy (*match + tmp_nmatch1, tmp_match2, tmp_nmatch2 * sizeof (struct matchpoint));
      free (tmp_match2);
      return exp;
 
    default:
      return or1k_parse_any (exp, match, nmatch, 3);
      if (set_break)
	(*match)[*nmatch - 1].cause_breakpoint = 1;
    }
}
 
/* Prints single matchpoint from specified struct.  */
 
static void 
print_matchpoint_struct (mp)
     struct matchpoint *mp;
{
  printf_filtered ("%-6s (%i) %u, ON=%i, chain_type=%i, cause break=%i\n", compare_to_names[mp->dcr.ct],
		   mp->dcr.cc, mp->dvr, mp->dcr.dp, mp->chain_type, mp->cause_breakpoint);
}
 
/* Build watchpoint(s) based on given structure.  */
 
static void
set_matchpoints (match, nmatch)
     struct matchpoint *match;
     int nmatch;
{
  int i;
  debug_regs_changed = 1;
  sift_matchpoints ();
  for (i = 0; i < nmatch; i++)
    {
      int num = or1k_implementation.num_used_matchpoints;
      dcr[num] = match[i].dcr;
      dvr[num] = match[i].dvr;
 
      /* Set chaining bits.  */ 
      dmr1 &= ~(3 << (2 * num));
      dmr1 |= match[i].chain_type << (2 * num);
 
      /* Set watchpoint bits */
      dmr2 &= 1 << num;
      dmr2 |= match[i].cause_breakpoint << num;
      matchpoint_user_count[i]++;
      or1k_implementation.num_used_matchpoints++;
    }
}
 
/* Returns nonzero, if matchpoints [start .. start+nmatch-1] are
   equal to match record. */
 
static int
matchpoint_matches (start, match, nmatch)
     int start;
     struct matchpoint *match;
     int nmatch;
{
  int i;
  if (nmatch + start >= or1k_implementation.num_matchpoints)
    return 0;
 
  for (i = 0; i < nmatch; i++)
    {
      int j = i + start;
 
      /* Everything exept cause breakpoint must match.  */
      if (dcr[j].dp != match[i].dcr.dp
	  || dcr[j].ct != match[i].dcr.ct
	  || dcr[j].cc != match[i].dcr.cc
	  || dcr[j].sc != match[i].dcr.sc
	  || dvr[j] != match[i].dvr
	  || match[i].chain_type != (dmr1 >> (2 * j)) & 3)
	return 0;
    }
  return 1;
}
 
static void
hwatch_command (arg, from_tty)
     char *arg;
     int from_tty;
{
  struct expression *exp;
  int i, nfree, nmatch, remove = 0;
  struct matchpoint *match;
 
  if (arg == NULL)
    arg = "";
  if (strncasecmp ("remove ", arg, 7) == 0)
    {
      arg += 7;
      remove = 1;
    }
 
  /* Parse arguments.  */
  exp = parse_exp_1 (&arg, 0, 0);
 
#ifdef DEBUG
  dump_prefix_expression (exp, gdb_stdout, "expr1");
#endif  
 
  if (or1k_parse_or (&exp->elts[0], &match, &nmatch, 1) == &exp_error)
    error ("Watchpoint too complex.");
 
  for (i = 0; i < nmatch; i++)
    print_matchpoint_struct (&match[i]);
 
  if (remove)
    {
      int start = -1;
      int cleared = 0;
 
      if (num_hw_watches <= 0)
	error ("No extended hardware supported watchpoints present.");
 
      for (i = 0; i < num_hw_watches; i++)
	if (matchpoint_matches (or1k_hwatch[i].matchpoint_start, match, nmatch))
	  {
	    start = or1k_hwatch[i].matchpoint_start;
	    break;
	  }
 
      if (start < 0)
	error ("Watchpoint not found.");
 
      for (i = 0; i < nmatch; i++)
	{
	  int j = start + i;
	  if (--matchpoint_user_count[j] <= 0)
	    {
	      debug_regs_changed = 1;
	      memset (&dcr[j], 0, sizeof (dcr[j]));
	      or1k_implementation.num_used_matchpoints--;
	      cleared = 1;
	    }
	}
      if (!cleared)
	warning ("No matchpoint(s) freed. Resources are busy.");
    }
  else
    {
      if (num_hw_watches >= MAX_HW_WATCHES)
	error ("Number of watchpoints too large.");
 
      /* 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;
 
      if (nmatch > nfree)
	error ("Not enough free matchpoint resources.");
 
      /* Build watchpoint(s) based on just built structure.  */
      or1k_hwatch[num_hw_watches].matchpoint_start = or1k_implementation.num_used_matchpoints;
      set_matchpoints (match, nmatch);
      num_hw_watches++;
      printf_unfiltered ("Watchpoint successfully allocated.\n");
    }
  free (match);
  free (exp);
}
 
static void
htrace_command (args, from_tty)
     char *args;
     int from_tty;
{
  help_list (htrace_cmdlist, "htrace ", all_commands, gdb_stdout);
}
 
static void
htrace_mode_command (args, from_tty)
     char *args;
     int from_tty;
{
  help_list (htrace_mode_cmdlist, "htrace mode ", all_commands, gdb_stdout);
}
 
static void
htrace_mode_contin_command (args, from_tty)
     char *args;
     int from_tty;
{
  or1k_htrace.moder.contin = 1;
  printf_unfiltered ("Continuous trace mode set.\n");
}
 
static void
htrace_mode_suspend_command (args, from_tty)
     char *args;
     int from_tty;
{
  or1k_htrace.moder.contin = 0;
  printf_unfiltered ("Suspend trace mode set.\n");
}
 
static void print_event_struct (event, stop)
     struct htrace_event_struct *event;
     int stop;
{
  int i;
  if (event->operation == TRIGOP_ANY)
    if (stop)
      printf_filtered ("not active");
    else
      printf_filtered ("always active");
  else
    {
      char *comma;
      if (event->operation == TRIGOP_AND)
	comma = "&(";
      else
	comma = "|(";
 
      if (event->is_valid)
	{
	  printf_filtered ("%s%s", comma, or1k_is_names[event->is_trig]);
	  comma = ", ";
	}
      if (event->ls_valid)
	{
	  printf_filtered ("%s%s", comma, or1k_ls_names[event->ls_trig]);
	  comma = ", ";
	}
      if (event->bp_valid)
	{
	  printf_filtered ("%sbreak", comma);
	  comma = ", ";
	}
      if (event->wp_valid)
	for (i = 0; i < 11; i++)
	  if ((event->wp_trig >> i) & 1)
	    {
	      printf_filtered ("%sWP%i", comma, i);
	      comma = ", ";
	    }
      if (comma[0] == ',')
	printf_filtered (")");
      else
	printf_filtered ("not active");
    }
}
 
static void
print_record_struct (record)
     struct htrace_record_struct *record;
{
  int i;
  char *comma = "";
  for (i = 0; i < MAX_RECORD_NAMES; i++)
    {
      if ((record->rec >> i)&1)
	{
	  printf_filtered ("%s%s", comma, or1k_record_names[i]);
	  comma = ", ";
	}
    }
  if (!*comma)
    printf_unfiltered ("none");
}
 
static void
htrace_info_command (args, from_tty)
     char *args;
     int from_tty;
{
  int i;
  printf_filtered ("Trace trigger: ");
  print_event_struct (&or1k_htrace.trig, 0);
  printf_filtered ("\nTrace qualifier: ");
  print_event_struct (&or1k_htrace.qual, 0);
  for (i = 0; i < MAX_MATCHPOINTS; i++)
    {
      printf_filtered ("\n WP%i records: ", i);
      print_record_struct (&or1k_htrace.recwp[i]);
    }
  printf_filtered ("\n BP records: ");
  print_record_struct (&or1k_htrace.recbp);
  printf_filtered ("\nTrace stop: ");
  print_event_struct (&or1k_htrace.stop, 1);
  printf_filtered ("\n");
}
 
/* Parses event from given string.
   Result is placed into event structure, and previously allocated
   resources are freed.  Parameter stop is nonzero, when we are parsing
   for stop criteria.  */
 
static void
parse_event (args, event, stop)
     char *args;
     struct htrace_event_struct *event;
     int stop;
{
  int i, op_type = 0, was_last_op = 1, any = 0;
 
  /* Release previous resources.  */
  for (i = 0; i < MAX_MATCHPOINTS; i++)
    {
      if ((event->wp_trig << i) & 1)
	if (--matchpoint_user_count[i] <= 0)
	  {
	    memset (&dcr[i], 0, sizeof (dcr[i]));
	    debug_regs_changed = 1;
	    or1k_implementation.num_used_matchpoints--;
	  }
    }
 
  event->is_valid = event->is_trig = 0;
  event->ls_valid = event->ls_trig = 0;
  event->bp_valid = event->bp_trig = 0;
  event->wp_valid = event->wp_trig = 0;
 
  if (args == NULL)
    args = "";
  while (*args == ' ')
    args++;
 
  while (*args != '\0')
    {
      if (strncasecmp ("breakpoint", args, 10) == 0)
	{
	  if (!was_last_op)
	    error ("Syntax error.");
	  was_last_op = 0;
	  event->bp_valid = event->bp_trig = 1;
	}
      else if (!stop && strncasecmp ("any", args, 3) == 0
	       || stop && strncasecmp ("none", args, 4) == 0)
	{
	  if (!was_last_op)
	    error ("Syntax error.");
	  was_last_op = 0;
	  any = 1;
	}
      else if (strncasecmp ("||", args, 2) == 0)
	{
	  if (op_type == TRIGOP_AND)
	    error ("Only one type of logical operator allowed at a time.");
	  op_type = TRIGOP_OR;
	  if (was_last_op)
	    error ("Syntax error.");
	  was_last_op = 1;
	  args += 2;
	}
      else if (strncasecmp ("&&", args, 2) == 0)
	{
	  if (op_type == TRIGOP_OR)
	    error ("Only one type of logical operator allowed at a time.");
	  op_type = TRIGOP_AND;
	  if (was_last_op)
	    error ("Syntax error.");
	  was_last_op = 1;
	  args += 2;
	}
      else
	{
	  int found = 0;
	  if (!was_last_op)
	    error ("Syntax error.");
	  was_last_op = 0;
 
	  /* Search through is and ls tables for a match.  */
	  for (i = 0; i < MAX_IS_NAMES; i++)
	    if (strncasecmp (args, or1k_is_names[i], strlen (or1k_is_names[i])) == 0)
	      {
		event->is_valid	= 1;
		event->is_trig = i;
		args +=  strlen (or1k_is_names[i]);
		found = 1;
		break;
	      }
	  if (!found)
	    {
	      for (i = 0; i < MAX_LS_NAMES; i++)
		if (strncasecmp (args, or1k_ls_names[i], strlen (or1k_ls_names[i])) == 0)
		  {
		    event->ls_valid = 1;
		    event->ls_trig = i;
		    args +=  strlen (or1k_ls_names[i]);
		    found = 1;
		    break;
		  }
	    }
	  if (!found)
	    {
	      /* No special name was found => parse expression.  */
	      struct expression *exp;
	      struct matchpoint *match;
	      int nmatch, nfree;
 
	      exp = parse_exp_1 (&args, 0, 0);
 
	      if (or1k_parse_any (&exp->elts[0], &match, &nmatch, 3) == &exp_error)
		error ("Expression too complex.");
	      for (i = 0; i < nmatch; i++)
		print_matchpoint_struct (&match[i]);
 
	      /* 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;
 
	      if (nmatch > nfree)
		error ("Not enough free matchpoint resources.");
 
	      /* Build matchpoint(s) based on just built structure.  */
	      set_matchpoints (match, nmatch);
	      event->wp_valid = 1;
	      event->wp_trig |= 1 << (or1k_implementation.num_used_matchpoints - 1);
	      printf_unfiltered ("Watchpoint successfully allocated.\n");
	      free (match);
	      free (exp);
	      found = 1;
	    }
	  if (!found)
	    warning ("Invalid event at '%s'", args);
	}
      while (*args == ' ') args++;
    }
  if (any)
    event->operation = TRIGOP_ANY;
  else
    {
      if (op_type == 0)
	op_type = TRIGOP_AND;
      event->operation = op_type;
    }
}
 
static void
htrace_trigger_command (args, from_tty)
     char *args;
     int from_tty;
{
  parse_event (args, &or1k_htrace.trig, 0);
  printf_filtered ("Trace starts, when:\n");
  print_event_struct (&or1k_htrace.trig, 0);
  printf_filtered ("\n");
}
 
static void
htrace_qualifier_command (args, from_tty)
     char *args;
     int from_tty;
{
  parse_event (args, &or1k_htrace.qual, 0);
  printf_filtered ("Trace records, when:\n");
  print_event_struct (&or1k_htrace.qual, 0);
  printf_filtered ("\n");
}
 
static void
htrace_stop_command (args, from_tty)
     char *args;
     int from_tty;
{
  parse_event (args, &or1k_htrace.stop, 1);
  printf_filtered ("Trace stops, when:\n");
  print_event_struct (&or1k_htrace.stop, 1);
  printf_filtered ("\n");
}
 
static void
htrace_clear_records_command (args, from_tty)
     char *args;
     int from_tty;
{
  int i, j, cleared = 0;
 
  /* Clear all. */
  for (i = 0; i < MAX_MATCHPOINTS; i++)
    {
      for (j = 0; j < MAX_MATCHPOINTS; j++)
	{
	  if ((or1k_htrace.wp_record_uses[i] << j) & 1)
	    if (--matchpoint_user_count[j] <= 0)
	    {
	      memset (&dcr[j], 0, sizeof (dcr[j]));
	      debug_regs_changed = 1;
	      cleared = 1;
	      or1k_implementation.num_used_matchpoints--;
	    }
	}
      or1k_htrace.wp_record_uses[i] = 0;
    }
  if (!cleared)
    warning ("No matchpoints freed. Resources are busy.");
}
 
/* Syntax: htrace record {data}* when {expr} */
 
static void
htrace_record_command (args, from_tty)
     char *args;
     int from_tty;
{
  struct expression *exp;
  int i, nfree, nmatch, wp;
  struct matchpoint *match;
  unsigned int recdata = 0;
  char *c;
 
  if (args == '\0')
    error ( "Please specify data to record, e.g.:\n"
	    "htrace record PC SDATA when $SEA == 100\n"
	    "htrace record when $SEA == 100 to remove record");
 
  for (i = 0; *args != '\0' && strncasecmp ("when ", args, 5); i++)
    {
      int j, found = 0;
      for (j = 0; j < MAX_RECORD_NAMES; j++)
	if (strncasecmp (args, or1k_record_names[j], strlen (or1k_record_names[j])) == 0)
	  {
	    recdata |= 1 << j;
	    found = 1;
	    break;
	  }
      if (!found)
	warning ("Invalid record data name at '%s'.", args);
      while (*args != ' ' && *args != '\0') args++;
      while (*args == ' ') args++;
    }
 
  if (strncasecmp ("when ", args, 5) != 0)
    if (*args == '\0')
      {
	warning ("Condition not set. Assuming breakpoint.");
	wp = -1;
      }
    else
      error ("Syntax error.");
  else
    {
      args += 5;
      if (strcasecmp ("breakpoint", args) == 0)
	wp = -1;
      else
	{
	  /* Parse arguments.  */
	  exp = parse_exp_1 (&args, 0, 0);
 
#ifdef DEBUG
	  dump_prefix_expression (exp, gdb_stdout, "expr1");
#endif
	  if (or1k_parse_any (&exp->elts[0], &match, &nmatch, 3) == &exp_error)
	    error ("Expression too complex.");
 
	  for (i = 0; i < nmatch; i++)
	    print_matchpoint_struct (&match[i]);
 
	  if (recdata)
	    {
	      /* 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;
 
	      if (nmatch > nfree)
		error ("Not enough free matchpoint resources.");
 
	      wp = or1k_implementation.num_used_matchpoints - 1;
	      or1k_htrace.wp_record_uses[wp] = 0;
	      for (i = or1k_implementation.num_used_matchpoints; i <= wp; i++)
		or1k_htrace.wp_record_uses[wp] |= 1 << i;
	      set_matchpoints (match, nmatch);	  
	    }
	  else
	    {
	      /* Remove record. */
	      int start = -1, cleared = 0;
 
	      for (i = 0; i < MAX_MATCHPOINTS; i++)
		{
		  int mp_start = 0, j;
		  j = or1k_htrace.wp_record_uses[i];
		  while (j > 0 && j & 1 == 0)
		    mp_start++;
 
		  if (matchpoint_matches (mp_start, match, nmatch))
		    {
		      start = mp_start;
		      or1k_htrace.wp_record_uses[i] = 0;
		      break;
		    }
		}
	      if (start < 0)
		error ("Record with such expression not found.");
 
	      for (i = 0; i < nmatch; i++)
		{
		  int j = i + start;
		  if (--matchpoint_user_count[j] <= 0)
		    {
		      memset (&dcr[j], 0, sizeof (dcr[j]));
		      debug_regs_changed = 1;
		      cleared = 1;
		    }
		}
	      if (!cleared)
		warning ("No matchpoint(s) freed.");
	    }
	}
    }
 
  /* If we reached this point we have matchpoints set, and wp
     holds the value of that watchpoint.  wp == -1, if breakpoint
     was specified.  */
  if (wp < 0)
    or1k_htrace.recbp.rec = recdata;
  else
    or1k_htrace.recwp[wp].rec = recdata;
 
  if (recdata)
    {
      printf_unfiltered ("Data");
      for (i = 0; i < MAX_RECORD_NAMES; i++)
	if ((recdata >> i) & 1)
	  printf_unfiltered (" %s,", or1k_record_names[i]);
    }
  else
    printf_unfiltered ("No data");
  if (wp < 0)
    printf_unfiltered (" will be recorded when breakpoint occurs\n");
  else
    printf_unfiltered (" will be recorded when watchpoint #%i occurs\n", wp);
}
 
static void
htrace_enable_command (args, from_tty)
     char *args;
     int from_tty;
{
  or1k_htrace.moder.trace_enable = 1;
  printf_unfiltered ("HW Trace enabled.\n");
}
 
static void
htrace_disable_command (args, from_tty)
     char *args;
     int from_tty;
{
  or1k_htrace.moder.trace_enable = 0;
  printf_unfiltered ("HW Trace disabled.\n");
}
 
static void
htrace_rewind_command (args, from_tty)
     char *args;
     int from_tty;
{
  FILE *f;
  if (args != NULL && *args != '\0')
    strncpy (TRACE_FILENAME, args, TRACE_FILENAME_SIZE);
 
  /* Just empty it.  */
  if ((f = fopen (TRACE_FILENAME, "wb+")) == NULL)
    error ("Cannot open trace file.");
  fclose (f);
  printf_unfiltered ("Trace data cleared.\n");
}
 
static void
print_data_struct (pos, data)
     unsigned int pos;
     struct htrace_data_struct *data;
{
  struct symbol *func;
  char *funname = NULL;
 
  if (data->type < 4)
    {
      /* Determine function name - copied from stack.c  */
      func = find_pc_function (data->data);
      if (func)
	{
	  struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (data->data);
	  if (msymbol != NULL
	      && (SYMBOL_VALUE_ADDRESS (msymbol)
		  > BLOCK_START (SYMBOL_BLOCK_VALUE (func))))
	    funname = SYMBOL_NAME (msymbol);
	  else
	    {
	      char *demangled;
	      funname = SYMBOL_NAME (func);
	      if (SYMBOL_LANGUAGE (func) == language_cplus)
		{
		  demangled = cplus_demangle (funname, DMGL_ANSI);
		  if (demangled == NULL)
		    funname = SYMBOL_SOURCE_NAME (func);
		}
	    }
	}
      else
	{
	  struct minimal_symbol *msymbol = lookup_minimal_symbol_by_pc (data->data);
	  if (msymbol != NULL)
	    funname = SYMBOL_NAME (msymbol);
	}
    }
 
  printf_filtered ("%06X%c %-8s %08X", pos, data->valid ? '>' : ':',
		   or1k_record_names[data->type], data->data);
  if (funname)
    printf_filtered (" (%s)\n", funname);
  else
    printf_filtered ("\n");
}
 
/* Prints out trace buffer.  */
 
static void
htrace_print_command (args, from_tty)
     char *args;
     int from_tty;
{
  int i, from = 0, length = prev_length;
  FILE *f;
  struct htrace_data_struct *td;
 
  if (args == NULL) args = "";
  while (*args == ' ') args++;
  if (*args == '\0')
    {
      /* We will display buffer further. */
      from = prev_from + prev_length;
    }
  else
    {
      /* Display buffer range.  */
      int numbers = 0;
      char *cnum = args;
      while (*args != ' ' && *args != '\0')
	args++;
 
      /* Any arguments?  */
      if (*args == '\0')
	numbers = 1;
      else
	{
	  *args = 0;
	  args++;
	  numbers = 2;
	}
      from = strtoul (cnum, &cnum, 0);
      if (*cnum != 0)
	error ("Invalid from value.");
      if (from < 0) from += trace_size;
      if (numbers == 2)
	{
	  while (*args == ' ') args++;
	  length = strtoul (cnum, &cnum, 0);
	  if (*args != 0)
	    error ("Invalid length value.");
	  if (length < 0)
	    {
	      from += length;
	      length = -length;
	    }
	}
    }
 
  if (from >= trace_size)
    from = trace_size - 1;
  if (from < 0)
    from = 0;
  if (from + length >= trace_size)
    length = trace_size - from;
 
  prev_length = length;
  prev_from = from;
  if (length == 0)
    error ("Nothing to print.");
 
  printf_filtered ("Trace buffer %06x:%06x (size = %i)\n", from, from + length - 1, length);
  if ((f = fopen (TRACE_FILENAME, "rb")) == NULL)
    error ("Cannot open trace file.");
  if (fseek (f, TRACE_DATA_SIZE * from, SEEK_SET))
    error ("Error reading trace file.");
  td = (struct htrace_data_struct *) malloc (TRACE_DATA_SIZE * length);
  length = fread (td, TRACE_DATA_SIZE, length, f);
  for (i = 0; i < length; i++)
    print_data_struct (from + i, &td[i]); 
  fclose (f);
}
 
int print_insn_big_or32 (bfd_vma,struct disassemble_info*);
int print_insn_little_or32 (bfd_vma,struct disassemble_info*);
 
void
_initialize_or1k_tdep ()
{
  build_automata ();
  /* Added by CZ 26/06/01 */
  if(TARGET_BYTE_ORDER == BIG_ENDIAN)
    tm_print_insn = print_insn_big_or32;
  else
    tm_print_insn = print_insn_little_or32;
 
  /* Commands to show and set sprs.  */
  add_info ("spr", info_spr_command, "Show information about the spr registers.");
  add_info ("trace", info_trace_command, "Display trace buffer contents.");
  add_com ("spr", class_support, spr_command, "Set specified SPR register.");
 
  /* hwatch command.  */
  add_com ("hwatch", class_breakpoint, hwatch_command, "Set hardware watch"
	   "point.\nExample: ($LEA == my_var)&&($LDATA < 50)||($SEA == my_"
	   "var)&&($SDATA >= 50).\nSee OR1k Architecture document for more"
	   " info.");
 
  /* htrace commands.  */
  add_prefix_cmd ("htrace", class_breakpoint, htrace_command,
		  "Group of commands for handling hardware assisted trace\n\n"
		  "See OR1k Architecture and gdb for or1k documents for more info.",
		  &htrace_cmdlist, "htrace ", 0, &cmdlist);
  add_cmd ("info", class_breakpoint, htrace_info_command, "Display information about HW trace.",
	   &htrace_cmdlist);
  add_alias_cmd ("i", "info", class_breakpoint, 1, &htrace_cmdlist);
  add_cmd ("trigger", class_breakpoint, htrace_trigger_command, "Set starting criteria for trace.",
	   &htrace_cmdlist);
  add_alias_cmd ("t", "trigger", class_breakpoint, 1, &htrace_cmdlist);
  add_cmd ("qualifier", class_breakpoint, htrace_qualifier_command, "Set acquisition qualifier for HW trace.",
	   &htrace_cmdlist);
  add_alias_cmd ("q", "qualifier", class_breakpoint, 1, &htrace_cmdlist);
  add_cmd ("stop", class_breakpoint, htrace_stop_command, "Set HW trace stopping criteria.",
	   &htrace_cmdlist);
  add_alias_cmd ("s", "stop", class_breakpoint, 1, &htrace_cmdlist);
  add_cmd ("record", class_breakpoint, htrace_record_command, "Sets data to be recorded when expression occurs.",
	   &htrace_cmdlist);
  add_alias_cmd ("r", "record", class_breakpoint, 1, &htrace_cmdlist);
  add_cmd ("clear records", class_breakpoint, htrace_clear_records_command,
	   "Disposes all matchpoints used by records.", &htrace_cmdlist);
  add_cmd ("enable", class_breakpoint, htrace_enable_command, "Enables the HW trace.", &htrace_cmdlist);
  add_alias_cmd ("e", "enable", class_breakpoint, 1, &htrace_cmdlist);
  add_cmd ("disable", class_breakpoint, htrace_disable_command, "Disables the HW trace.", &htrace_cmdlist);
  add_alias_cmd ("d", "disable", class_breakpoint, 1, &htrace_cmdlist);
  add_cmd ("rewind", class_breakpoint, htrace_rewind_command, "Clears currently recorded trace data.\n"
	   "If filename is specified, new trace file is made and any newly collected data\n"
	   "will be written there.", &htrace_cmdlist);
  add_cmd ("print", class_breakpoint, htrace_print_command,
	   "Prints trace buffer, using current record configuration.\n"
	   "htrace print [<start> [<len>]]\n"
	   "htrace print"
	   , &htrace_cmdlist);
  add_alias_cmd ("p", "print", class_breakpoint, 1, &htrace_cmdlist);
  add_prefix_cmd ("mode", class_breakpoint, htrace_mode_command,
	   "Configures the HW trace.\n"
	   "htrace mode [continuous|suspend]"
	   , &htrace_mode_cmdlist, "htrace mode ", 0, &htrace_cmdlist);
  add_alias_cmd ("m", "mode", class_breakpoint, 1, &htrace_cmdlist);
  add_cmd ("continuous", class_breakpoint, htrace_mode_contin_command,
	   "Set continuous trace mode.\n", &htrace_mode_cmdlist);
  add_cmd ("suspend", class_breakpoint, htrace_mode_suspend_command,
	   "Set suspend trace mode.\n", &htrace_mode_cmdlist);
 
  /* Extra functions supported by simulator.  */
  add_com ("sim", class_obscure, sim_command,
	   "Send a extended command to the simulator.");
}
 
 

Go to most recent revision | 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.