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

Subversion Repositories or1k

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

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, 2,
  23, 16, 1, 3, 2, 8};
 
int or1k_group_name_start[OR1K_NUM_SPR_GROUPS] = {
  0,   0,   0, 253, 254, 256,
  32, 248, 16, 16, 255, 0};
 
/* 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,
  79+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",
  "PC", "SR", "SPR0_18", "SPR0_19", "SPR0_20", "SPR0_21", "SPR0_22", "SPR0_23",
  "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", "DCBIR", "DCBPR", "DCBFR", "DCBWR", "DCBLR",
 
  /* group 4 - Instruction cache */
  "ICCR", "ICBLR", "ICBIR", "ICBPR",
 
  /* 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",  "DIR",
 
  /* group 7 - performance counters unit */
  "PCCM0", "PCMR1", "PCMR2", "PCMR3", "PCMR4", "PCMR5", "PCMR6", "PCMR7",
  "PCCR0", "PCCR1", "PCCR2", "PCCR3", "PCCR4", "PCCR5", "PCCR6", "PCCR7",
 
  /* group 8 - power management */
  "PMR",
 
  /* group 9 - PIC */
  "PICMR", "PICPR",
 
  /* 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 */
  "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}
  };
 
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;
 
/* 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];
 
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.  */
 
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);
  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:
 
      /* 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 - or1k_group_name_start[group]];
      }
 
      /* 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));
}
 
/* 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))
	/* 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
    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)
{
  int i;
  CORE_ADDR frame_addr;
  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;
}
 
/* 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;
		    }
		}
	    }
	}
      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);
	  else *index = -1;
 
	  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)
    {
      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 (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.");
      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 ()
{
 
  /* 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_com ("spr", class_support, spr_command, "Set specified SPR register.");
 
  /* hwatch command.  */
  add_com ("hwatch", class_breakpoint, hwatch_command, "Set hardware watchpoint.\n\
Example: ($LEA == my_var)&&($LDATA < 50)||($SEA == my_var)&&($SDATA >= 50).\n\
See 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.