From: Stafford Horne <shorne@gmail.com>
To: gdb-patches@sourceware.org
Cc: openrisc@lists.librecores.org, Franck Jullien <franck.jullien@gmail.com>
Subject: [PATCH v2 2/4] gdb: Add OpenRISC or1k and or1knd target support
Date: Sun, 27 Nov 2016 06:18:00 -0000 [thread overview]
Message-ID: <f6acbadf23ddacc9c5b335a2de3b2919793f96af.1480216015.git.shorne@gmail.com> (raw)
In-Reply-To: <cover.1480216015.git.shorne@gmail.com>
In-Reply-To: <cover.1480216015.git.shorne@gmail.com>
From: Franck Jullien <franck.jullien@gmail.com>
This patch prepates the current GDB port of the openrisc processor from
https://github.com/openrisc/binutils-gdb for upstream merging.
Testing has been done with a cgen sim provided in a separate patch. This
has been tested with 2 toolchains. GCC [1] 5.4.0 from the openrisc
project with Newlib [2] and GCC 5.4.0 with Musl [3] 1.1.4.
It supports or1knd (no delay slot target).
The default target is or1k (with delay slot).
You can change the target arch with:
(gdb) set architecture or1knd
The target architecture is assumed to be or1knd
[1] https://github.com/openrisc/or1k-gcc
[2] https://github.com/openrisc/newlib
[3] https://github.com/openrisc/musl-cross
gdb/doc/ChangeLog:
2016-03-13 Stefan Wallentowitz <stefan@wallentowitz.de>
* gdb.texinfo (Embedded Processors): Add openrisc to suppress error.
2013-01-31 Franck Jullien <franck.jullien@gmail.com>
* gdb.texinfo: Add / merge OpenRISC documentation from old svn.
2008-08-13 Jeremy Bennett <jeremy.bennett@embecosm.com>
* gdb.texinfo: Sections relating to OpenRISC 1000 rewritten
gdb/ChangeLog:
2016-11-23 Stafford Horne <shorne@gmail.com>
Updates after Yao Qi's breakpoint refactor.
* or1k-tdep.c (or1k_breakpoint_kind_from_pc): New function.
(or1k_sw_breakpoint_from_kind): New function.
(or1k_breakpoint_from_pc): Remove.
(or1k_gdbarch_init): Use new functions.
2016-11-23 Stafford Horne <shorne@gmail.com>
Corelow is no longer needed for or1k as its in by default.
* configure.tgt: Remove corelow.o for or1k linux.
2016-11-16 Stafford Horne <shorne@gmail.com>
Updates after rebase to upstream master.
* or1k-tdep.c (or1k_fetch_instruction): Dont pass status
directly to memory_error as they are different types.
(or1k_pseudo_register_read): Return proper typed REG_UNKNOWN.
(or1k_frame_cache): Cast result to trad_frame_cache.
(or1k_gdbarch_init): Init gdbarch_tdep with XNEW.
2016-05-22 Stafford Horne <shorne@gmail.com>
Upstream merge fixes.
* or1k-tdep.c (or1k_return_value): Fix return conventions
handling of arrays and literals to match gcc.
(or1k_push_dummy_call): Properly handle vararg dummy args by
pushing a pointer to args as per conventions.
2016-03-13 Stefan Wallentowitz <stefan@wallentowitz.de>
Upstream merge fixes.
* or1k-tdep.c (or1k_analyse_inst): Change fatal to throw_quit.
(or1k_skip_prologue): Use SYMTAB_COMPUNIT and
COMPUNIT_DEBUGFORMAT.
(or1k_frame_cache): Change fatal to throw_quit.
(or1k_regset_from_core_section): Remove.
(or1k_iterate_over_regset_sections): Create, blank
implementation.
2013-10-01 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
Upstream merge fixes.
* or1k-tdep.c (or1k_fetch_instruction): Change char to gdb_byte
to prevent pointer signedness error.
(or1k_push_dummy_code): Likewise.
2013-03-15 Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
* or1k-tdep.c (or1k_regset_firom_core_section) : Silence gcc
warning by using %z format for size_t.
2013-02-22 Franck Jullien <franck.jullien@gmail.com>
* or1k-tdep.c (or1k_push_dummy_code) : Use or1k_frame_align to
align the stack pointer.
2013-02-17 Franck Jullien <franck.jullien@gmail.com>
Add target descriptor support.
* or1k-tdep.c (or1k_register_name): Conditionally pull register
names from tdesc_register_name if we can.
(or1k_registers_info): Fetch register via target_fetch_registers
if it is not cached.
(or1k_register_reggroup_p): Check register groups in target
descriptor before falling back to default reg groups.
(create_register_group): New Function.
(get_feature_registers): New Function.
(or1k_gdbarch_init): Init the register details from target_desc.
(_initialize_or1k_tdep): Tell remote we support target
description xml.
2013-02-16 Franck Jullien <franck.jullien@gmail.com>
* or1k-tdep.c: Use OR1K_NUM_REGS_CACHED.
* or1k-tdep.h: Add OR1K_NUM_REGS_CACHED.
Add OR1K_MAX_SPR_REGS.
2013-02-14 Franck Jullien <franck.jullien@gmail.com>
* or1k-tdep.c (or1k_push_dummy_code): New function.
(or1k_gdbarch_init): Override default behavior and call dummy
from the stack. Set the push_dummy_code handler to
or1k_push_dummy_code.
2013-02-13 Franck Jullien <franck.jullien@gmail.com>
* or1k-tdep.c (or1k_skip_prologue): Add a check for NULL
pointer while comparing debugformat to "dwarf".
2013-01-31 Franck Jullien <franck.jullien@gmail.com>
* or1k-tdesc.c : Add file for or1k support from old svn
* or1k-tdesc.h : Add file for or1k support from old svn
* configure.tgt : Add or1k targets from old svn
2010-06-30 Jeremy Bennett <jeremy.bennett@embecosm.com>
* or1k-tdep.c (or1k_fetch_instruction): Logic flow made clearer.
(or1k_analyse_inst, or1k_analyse_L_addi)
(or1k_analyse_l_sw): Added.
(or1k_frame_size, or1k_frame_fp_loc, or1k_frame_size_check)
(or1k_link_address, or1k_get_saved_reg): Removed.
(or1k_skip_prologue, or1k_frame_unwind_cache): Rewritten to use
or1k_analyse_inst functions.
* or1k_tdep.h <OR1K_FIRST_SAVED_REGNUM, OR1K_INSTBITLEN>: #define
added.
2008-11-08 Jeremy Bennett <jeremy.bennett@embecosm.com>
* or1k-tdep.c (or1k_read_spr, or1k_write_spr): Moved here from
remote-or1k.c and made local to this file. Rewritten to use
commands via the target remote command (to_rcmd) function.
* or1k-tdep.c (or1k_spr_command). Invalidates register cache when
SPR is written.
* or1k-tdep.h: or1k_read_spr and Or1k_write_spr are removed as
global functions.
* or1k-tdep.c (or1k_read_spr, or1k_write_spr). Functions removed
and made local to or1k-tdep.c. All or1k-tdep.c references to these
functions changed to use or1k_jtag_read_spr and
or1k_jtag_write_spr (for which these were only wrappers).
* or1k-tdep.c (or1k_rcmd): Function added to process SPR access
requests.
2008-10-23 Jeremy Bennett <jeremy.bennett@embecosm.com>
* or1k-tdep.h, or1k-tdep.c: Extend the number of registers to
include the PPC as well as the NPC
2008-07-30 Jeremy Bennett <jeremy.bennett@embecosm.com>
* or1k-tdep.c: New file, based on the OpenCores 5.3 port
* or1k-tdep.h: New file, based on the OpenCores 5.3 port
* configure.tgt: Updated description of OpenRISC 1000 files
---
gdb/configure.tgt | 26 +
gdb/doc/gdb.texinfo | 103 ++
gdb/or1k-tdep.c | 3285 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/or1k-tdep.h | 434 +++++++
4 files changed, 3848 insertions(+)
create mode 100644 gdb/or1k-tdep.c
create mode 100644 gdb/or1k-tdep.h
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 79473c9..3a3df97 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -421,6 +421,32 @@ nios2*-*-*)
gdb_target_obs="nios2-tdep.o"
;;
+or1k-*-linux*)
+ # Target: OpenCores OpenRISC 1000 32-bit implementation for Linux
+ gdb_target_obs="or1k-tdep.o"
+ gdb_sim=../sim/or1k/libsim.a
+ build_gdbserver=yes
+ ;;
+
+or1k-*-*)
+ # Target: OpenCores OpenRISC 1000 32-bit implementation bare metal
+ gdb_target_obs="or1k-tdep.o"
+ gdb_sim=../sim/or1k/libsim.a
+ ;;
+
+or1knd-*-linux*)
+ # Target: OpenCores OpenRISC 1000 32-bit implementation for Linux, without delay slot
+ gdb_target_obs="or1k-tdep.o"
+ gdb_sim=../sim/or1k/libsim.a
+ build_gdbserver=yes
+ ;;
+
+or1knd-*-*)
+ # Target: OpenCores OpenRISC 1000 32-bit implementation bare metal, without delay slot
+ gdb_target_obs="or1k-tdep.o"
+ gdb_sim=../sim/or1k/libsim.a
+ ;;
+
powerpc*-*-freebsd*)
# Target: FreeBSD/powerpc
gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppc64-tdep.o \
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6ad2754..296534b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -541,6 +541,10 @@ Steve Tjiang, John Newlin, and Scott Foehner.
Michael Eager and staff of Xilinx, Inc., contributed support for the
Xilinx MicroBlaze architecture.
+The original port to the OpenRISC 1000 is believed to be due to
+Alessandro Forin and Per Bothner. More recent ports have been the work
+of Jeremy Bennett.
+
@node Sample Session
@chapter A Sample @value{GDBN} Session
@@ -22022,6 +22026,7 @@ acceptable commands.
* M68K:: Motorola M68K
* MicroBlaze:: Xilinx MicroBlaze
* MIPS Embedded:: MIPS Embedded
+* OpenRISC 1000:: OpenRISC 1000 (or1k)
* PowerPC Embedded:: PowerPC Embedded
* AVR:: Atmel AVR
* CRIS:: CRIS
@@ -22228,6 +22233,104 @@ As usual, you can inquire about the @code{mipsfpu} variable with
@samp{show mipsfpu}.
@end table
+@node OpenRISC 1000
+@subsection OpenRISC 1000
+@cindex OpenRISC 1000
+
+Previous versions of @value{GDBN} supported remote connection via a
+proprietary JTAG protocol using the @samp{target jtag} command. Support
+for this has now been dropped.
+
+
+@table @code
+
+@kindex target remote
+@item target remote
+
+This is now the only way to connect to a remote OpenRISC 1000
+target. This is supported by @dfn{Or1ksim}, the OpenRISC 1000
+architectural simulator, Verilator and Icarus Verilog
+simulations. @dfn{Remote serial protocol} servers are also available to
+drive various hardware implementations via JTAG.
+Connects to remote JTAG server.
+
+Example: @code{target remote :51000}
+
+@kindex target sim
+@item target sim
+
+@dfn{Or1ksim}, the OpenRISC 1000 architectural simulator is now
+incorporated within @value{GDBN} as a simulator target. It is started
+in quiet mode with 8M of memory starting at address 0. It is possible
+to pass arguments to extend this configuration using the @samp{-f}
+option to @samp{target sim}. However for more complex use, the user is
+advised to run @dfn{Or1ksim} separately, with its own configuration
+file, and connect using @samp{target remote}
+
+Example: @code{target sim}
+
+@kindex info spr
+@item info or1k spr
+Displays groups.
+
+@item info spr @var{group}
+@itemx info spr @var{groupno}
+Displays register names in selected group.
+
+@item info spr @var{group} @var{register}
+@itemx info spr @var{register}
+@itemx info spr @var{groupno} @var{registerno}
+@itemx info spr @var{registerno}
+Shows information about specified spr register.
+
+Example: @code{info spr DRR}
+
+@code{DEBUG.DRR = SPR6_21 = 0 (0x0)}
+
+@kindex spr
+@item spr @var{group} @var{register} @var{value}
+@itemx spr @var{register @var{value}}
+@itemx spr @var{groupno} @var{registerno @var{value}}
+@itemx spr @var{registerno @var{value}}
+Writes @var{value} to specified spr register.
+
+Example: spr PICMR 0x24
+@end table
+
+The use of @samp{info} and @samp{spr} commands is anachronistic. At
+some time in the future they will be replaced by @samp{info register @var{spr | group name}}
+and @samp{set $spr=@var{value}}.
+
+There are some known problems with the current implementation
+@cindex OpenRISC 1000 known problems
+
+@enumerate
+
+@item
+@cindex OpenRISC 1000 known problems, hardware breakpoints and watchpoints
+Some OpenRISC 1000 targets support hardware breakpoints and watchpoints.
+Consult the target documentation for details. @value{GDBN} is not
+perfect in handling of watchpoints. It is possible to allocate hardware
+watchpoints and not discover until running that sufficient watchpoints
+are not available. It is also possible that GDB will report watchpoints
+being hit spuriously. This can be down to the assembly code having
+additional memory accesses that are not obviously reflected in the
+source code.
+
+@item
+@cindex OpenRISC 1000 known problems, architectural compatability
+The OpenRISC 1000 architecture has evolved since the first port of @value{GDBN}. In particular the structure of the Unit Present register has
+changed and the CPU Configuration register has been added. The port of
+@value{GDBN} version @value{GDBVN} uses the @emph{current}
+specification of the OpenRISC 1000.
+
+@end enumerate
+
+@cindex Bugs, reporting
+@cindex Reporting bugs
+Reports of bugs are much welcomed. Please report problems through the
+OpenRISC tracker at @uref{http://opencores.org/openrisc,downloads}.
+
@node PowerPC Embedded
@subsection PowerPC Embedded
diff --git a/gdb/or1k-tdep.c b/gdb/or1k-tdep.c
new file mode 100644
index 0000000..3592ac9
--- /dev/null
+++ b/gdb/or1k-tdep.c
@@ -0,0 +1,3285 @@
+/* Target-dependent code for the 32-bit OpenRISC 1000, for the GNU Debugger.
+
+ Copyright 1988-2008, Free Software Foundation, Inc.
+ Copyright (C) 2008, 2010 Embecosm Limited
+
+ Contributed by Alessandro Forin(af@cs.cmu.edu at CMU
+ and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin.
+
+ Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
+
+ Contributor Franck Jullien <elec4fun@gmail.com>
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+/*-----------------------------------------------------------------------------
+ This version for the OpenRISC 1000 architecture is a rewrite by Jeremy
+ Bennett of the old GDB 5.3 interface to make use of gdbarch for GDB 6.8. It
+ has since been updated for GDB 7.2 and GDB 7.5.
+
+ The code tries to follow the GDB coding style.
+
+ Commenting is Doxygen compatible.
+
+ Notes on the GDB 7.5 version
+ ============================
+
+ This version is just an upgrade of the previous port. It does use CGEN
+ for instruction lookup in or1k_single_step_through_delay as the new toolchain
+ is CGEN based.
+
+ This version is compatible with or1knd target (no delay slot version of the
+ toolchain). We check in bfd_arch_info if the mach is bfd_mach_or1k or
+ bfd_mach_or1knd to choose if or1k_single_step_through_delay must be
+ implemented.
+
+ Notes on the GDB 7.2 version
+ ============================
+
+ The primary change is to support the new GCC 4.5.1 compiler, which no
+ longer adds preceding underscores to global values and uses DWARF2 as its
+ default debug format.
+
+ This version now supports Or1ksim integrated as a simulator library, so
+ "target sim" will work. It does require Or1ksim to be available as a
+ library at configuration time, with the Or1ksim installation directory
+ specified by the argument --with-or1ksim.
+
+ The ad-hoc prologue analysis, which was always a weak point has been
+ stripped out and replaced with code based on the generic approach in
+ prologue-value.c and prologue-value.h.
+
+ The objective with this version is to get reasonable results on regression
+ testing. Something the older versions never achieved.
+
+ Notes on the GDB 6.8 version
+ ============================
+
+ Much has been stripped out in the interests of getting a basic working
+ system. This is described as the OpenRISC 1000 target architecture, so
+ should work with 32 and 64 bit versions of that architecture and should
+ work whether or not they have floating point and/or vector registers,
+ although to date it has only been tested with the 32-bit integer
+ archtiecture.
+
+ The info trace command has been removed. The meaning of this is not clear -
+ it relies on a value in register 255 of the debug group, which is
+ undocumented.
+
+ All the hardware trace has been removed for the time being. The new debug
+ interface does not support hardware trace, so there is no plan to reinstate
+ this functionality.
+
+ Support for multiple contexts (which was rudimentary, and not working) has
+ been removed. */
+/*---------------------------------------------------------------------------*/
+
+#include "defs.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 "regcache.h"
+
+#include "or1k-tdep.h"
+
+#include "safe-ctype.h"
+#include "block.h"
+#include "reggroups.h"
+#include "arch-utils.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "dwarf2-frame.h"
+#include "trad-frame.h"
+#include "regset.h"
+#include "remote.h"
+#include "target-descriptions.h"
+
+#include <inttypes.h>
+
+#include "dis-asm.h"
+#include "opcodes/or1k-desc.h"
+#include "opcodes/or1k-opc.h"
+
+\f
+
+/* Enum describing different kinds of breakpoints for or1k */
+
+enum or1k_breakpoint_kind
+{
+ /* 32-bit standard OpenRISC breakpoint */
+ OR1K_BP_KIND_OR1K = 2,
+};
+
+/* The gdbarch_tdep structure. */
+
+/*! OR1K specific per-architecture information. Replaces
+ struct_or1k_implementation. A lot of this info comes from the config regs,
+ so cannot be put in place until we have the actual target. Up until then
+ we have reasonable defaults. */
+struct gdbarch_tdep
+{
+ unsigned int num_matchpoints; /* Total matchpoints available. */
+ unsigned int num_gpr_regs; /* Number of general registers. */
+ int bytes_per_word;
+ int bytes_per_address;
+ CGEN_CPU_DESC gdb_cgen_cpu_desc;
+};
+
+/* Support functions for the architecture definition */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Get an instruction
+
+ This reads from memory. The old version relied on the frame, this relies
+ just on the architecture. The old version also guaranteed not to get a
+ software breakpoint if one had been set. However that seems to happen just
+ before execution and is removed immediately after, so we believe should not
+ happen. The old function from GDB 6.8 to do this has been deleted.
+
+ @param[in] gdbarch Architecture for which we are getting the instruction.
+ @param[in] addr Address from which to get the instruction
+
+ @return The instruction */
+/*---------------------------------------------------------------------------*/
+
+static ULONGEST
+or1k_fetch_instruction (struct gdbarch *gdbarch,
+ CORE_ADDR addr)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ gdb_byte buf[OR1K_INSTLEN];
+
+ if (target_read_memory (addr, buf, OR1K_INSTLEN))
+ {
+ memory_error (TARGET_XFER_E_IO, addr);
+ }
+
+ return extract_unsigned_integer (buf, OR1K_INSTLEN, byte_order);
+
+} /* or1k_fetch_instruction() */
+
+
+/*---------------------------------------------------------------------------*/
+/*!Generic function to read bits from an instruction
+
+ printf style. Basic syntax
+
+ or1k_analyse_inst (inst, format, &arg1, &arg2 ...)
+
+ Format string can contain the following characters:
+
+ - SPACE: Ignored, just for layout
+ - 0: Match with a zero bit
+ - 1: Match with a one bit
+ - %<n>b: Match <n> bits to the next argument (n decimal)
+
+ If the arg corresponding to a bit field is non-null, the value will be
+ assigned to that argument (using NULL allows fields to be skipped).
+
+ Any bad string will cause a fatal error. These are constant strings, so
+ should be correct.
+
+ The bit field must be 32 bits long. A failure here will cause a fatal error
+ for the same reason.
+
+ @note The format string is presented MS field to LS field, left to
+ right. This means that it is read lowest numbered char first.
+
+ @note Some of the arg fields may be populated, even if recognition
+ ultimately fails.
+
+ @param[in] inst The instruction to analyse
+ @param[in] format The format string
+ @param[out] ... Argument fields
+
+ @return 1 (TRUE) if the instruction matches, 0 (FALSE) otherwise. */
+/*---------------------------------------------------------------------------*/
+static int
+or1k_analyse_inst (uint32_t inst,
+ const char *format,
+ ...)
+{
+ /* Break out each field in turn, validating as we go. */
+ va_list ap;
+
+ int i;
+ int iptr = 0; /* Instruction pointer */
+
+ va_start (ap, format);
+
+ for (i = 0; 0 != format[i];)
+ {
+ const char *start_ptr;
+ char *end_ptr;
+
+ uint32_t bits; /* Bit substring of interest */
+ uint32_t width; /* Substring width */
+ uint32_t *arg_ptr;
+
+ switch (format[i])
+ {
+ case ' ': i++; break; /* Formatting: ignored */
+
+ case '0': case '1': /* Constant bit field */
+ bits = (inst >> (OR1K_INSTBITLEN - iptr - 1)) & 0x1;
+
+ if ((format[i] - '0') != bits)
+ {
+ return 0;
+ }
+
+ iptr++;
+ i++;
+ break;
+
+ case '%': /* Bit field */
+ i++;
+ start_ptr = &(format[i]);
+ width = strtoul (start_ptr, &end_ptr, 10);
+
+ /* Check we got something, and if so skip on */
+ if (start_ptr == end_ptr)
+ {
+ throw_quit ("bitstring \"%s\" at offset %d has no length field.\n",
+ format, i);
+ }
+
+ i += end_ptr - start_ptr;
+
+ /* Look for and skip the terminating 'b'. If it's not there, we
+ still give a fatal error, because these are fixed strings that
+ just should not be wrong. */
+ if ('b' != format[i++])
+ {
+ throw_quit ("bitstring \"%s\" at offset %d has no terminating 'b'.\n",
+ format, i);
+ }
+
+ /* Break out the field. There is a special case with a bit width of
+ 32. */
+ if (32 == width)
+ {
+ bits = inst;
+ }
+ else
+ {
+ bits = (inst >> (OR1K_INSTBITLEN - iptr - width)) & ((1 << width) - 1);
+ }
+
+ arg_ptr = va_arg (ap, uint32_t *);
+ *arg_ptr = bits;
+ iptr += width;
+ break;
+
+ default:
+ throw_quit ("invalid character in bitstring \"%s\" at offset %d.\n",
+ format, i);
+ break;
+ }
+ }
+
+ /* Is the length OK? */
+ gdb_assert (OR1K_INSTBITLEN == iptr);
+
+ return 1; /* We succeeded */
+
+} /* or1k_analyse_inst () */
+
+
+/*---------------------------------------------------------------------------*/
+/*!Analyse a l.addi instruction
+
+ General form is:
+
+ l.addi rD,rA,I
+
+ Makes use of the generic analysis function (@see or1k_analyse_inst ()).
+
+ @param[in] inst The instruction to analyse.
+ @param[out] rd_ptr Pointer to the rD value.
+ @param[out] ra_ptr Pointer to the rA value.
+ @param[out] simm_ptr Pointer to the signed immediate value.
+
+ @return 1 (TRUE) if the instruction matches, 0 (FALSE) otherwise. */
+/*---------------------------------------------------------------------------*/
+static int
+or1k_analyse_l_addi (uint32_t inst,
+ unsigned int *rd_ptr,
+ unsigned int *ra_ptr,
+ int *simm_ptr)
+{
+ /* Instruction fields */
+ uint32_t rd, ra, i;
+
+ if (or1k_analyse_inst (inst, "10 0111 %5b %5b %16b", &rd, &ra, &i))
+ {
+ /* Found it. Construct the result fields */
+ *rd_ptr = (unsigned int) rd;
+ *ra_ptr = (unsigned int) ra;
+ *simm_ptr = (int) (((i & 0x8000) == 0x8000) ? 0xffff0000 | i : i);
+
+ return 1; /* Success */
+ }
+ else
+ {
+ return 0; /* Failure */
+ }
+} /* or1k_analyse_l_addi () */
+
+
+/*---------------------------------------------------------------------------*/
+/*!Analyse a l.sw instruction
+
+ General form is:
+
+ l.sw I(rA),rB
+
+ Makes use of the generic analysis function (@see or1k_analyse_inst ()).
+
+ @param[in] inst The instruction to analyse.
+ @param[out] simm_ptr Pointer to the signed immediate value.
+ @param[out] ra_ptr Pointer to the rA value.
+ @param[out] rb_ptr Pointer to the rB value.
+
+ @return 1 (TRUE) if the instruction matches, 0 (FALSE) otherwise. */
+/*---------------------------------------------------------------------------*/
+static int
+or1k_analyse_l_sw (uint32_t inst,
+ int *simm_ptr,
+ unsigned int *ra_ptr,
+ unsigned int *rb_ptr)
+{
+ /* Instruction fields */
+ uint32_t ihi, ilo, ra, rb;
+
+ if (or1k_analyse_inst (inst, "11 0101 %5b %5b %5b %11b", &ihi, &ra, &rb,
+ &ilo))
+
+ {
+ /* Found it. Construct the result fields */
+ *simm_ptr = (int) ((ihi << 11) | ilo);
+ *simm_ptr |= ((ihi & 0x10) == 0x10) ? 0xffff0000 : 0;
+
+ *ra_ptr = (unsigned int) ra;
+ *rb_ptr = (unsigned int) rb;
+
+ return 1; /* Success */
+ }
+ else
+ {
+ return 0; /* Failure */
+ }
+} /* or1k_analyse_l_sw () */
+
+
+\f
+
+/* Functions defining the architecture */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Determine the return convention used for a given type
+
+ Optionally, fetch or set the return value via "readbuf" or "writebuf"
+ respectively using "regcache" for the register values.
+
+ The OpenRISC 1000 returns scalar values via R11 and (for 64 bit values on
+ 32 bit architectures) R12. Structs and unions are returned by reference,
+ with the address in R11
+
+ The result returned is independent of the function type, so we ignore that.
+
+ Throughout use read_memory(), not target_read_memory(), since the address
+ may be invalid and we want an error reported (read_memory() is
+ target_read_memory() with error reporting).
+
+ @todo This implementation is labelled OR1K, but in fact is just for the 32
+ bit version, OR1K. This should be made explicit
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] functype The type of the function to be called (may be NULL)
+ @param[in] valtype The type of the entity to be returned
+ @param[in] regcache The register cache
+ @param[in] readbuf Buffer into which the return value should be written
+ @param[out] writebuf Buffer from which the return value should be written
+
+ @return The type of return value */
+/*---------------------------------------------------------------------------*/
+
+static enum return_value_convention
+or1k_return_value (struct gdbarch *gdbarch,
+ struct value *functype,
+ struct type *valtype,
+ struct regcache *regcache,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ enum type_code rv_type = TYPE_CODE (valtype);
+ unsigned int rv_size = TYPE_LENGTH (valtype);
+ unsigned int bpw = (gdbarch_tdep (gdbarch))->bytes_per_word;
+
+ /* Deal with struct/union as addresses. If an array won't fit in a single
+ register it is returned as address. Anything larger than 2 registers needs
+ to also be passed as address (this is from gcc default_return_in_memory) */
+ if ((TYPE_CODE_STRUCT == rv_type) || (TYPE_CODE_UNION == rv_type) ||
+ ((TYPE_CODE_ARRAY == rv_type) && rv_size > bpw) ||
+ (rv_size > 2*bpw))
+ {
+ if (readbuf)
+ {
+ ULONGEST tmp;
+
+ regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM, &tmp);
+ read_memory (tmp, readbuf, rv_size);
+ }
+ if (writebuf)
+ {
+ ULONGEST tmp;
+
+ regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM, &tmp);
+ write_memory (tmp, writebuf, rv_size);
+ }
+
+ return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+ }
+
+ if (rv_size <= bpw)
+ {
+ /* up to one word scalars are returned in R11 */
+ if (readbuf)
+ {
+ ULONGEST tmp;
+
+ regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM, &tmp);
+ store_unsigned_integer (readbuf, rv_size, byte_order, tmp);
+
+ }
+ if (writebuf)
+ {
+ gdb_byte buf[4]; /* TODO - fixed const! */
+ memset (buf, 0, sizeof (buf)); /* Zero pad if < bpw bytes */
+
+ if (BFD_ENDIAN_BIG == byte_order)
+ {
+ memcpy (buf + sizeof (buf) - rv_size, writebuf, rv_size);
+ }
+ else
+ {
+ memcpy (buf, writebuf, rv_size);
+ }
+
+ regcache_cooked_write (regcache, OR1K_RV_REGNUM, buf);
+ }
+ }
+ else
+ {
+ /* 2 word scalars are returned in r11/r12 (with the MS word in r11). */
+ if (readbuf)
+ {
+ ULONGEST tmp_lo;
+ ULONGEST tmp_hi;
+ ULONGEST tmp;
+
+ regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM , &tmp_hi);
+ regcache_cooked_read_unsigned (regcache, OR1K_RV_REGNUM + 1, &tmp_lo);
+ tmp = (tmp_hi << (bpw * 8)) | tmp_lo;
+
+ store_unsigned_integer (readbuf, rv_size, byte_order, tmp);
+ }
+ if (writebuf)
+ {
+ gdb_byte buf_lo[4]; /* TODO - fixed const! */
+ gdb_byte buf_hi[4]; /* TODO - fixed const! */
+
+ memset (buf_lo, 0, sizeof (buf_lo)); /* Zero pad if < bpw bytes */
+ memset (buf_hi, 0, sizeof (buf_hi)); /* Zero pad if < bpw bytes */
+
+ /* This is cheating. We assume that we fit in 2 words exactly, which
+ wouldn't work if we had (say) a 6-byte scalar type on a big
+ endian architecture (with the OpenRISC 1000 usually is). */
+ memcpy (buf_hi, writebuf, rv_size - bpw);
+ memcpy (buf_lo, writebuf + bpw, bpw);
+
+ regcache_cooked_write (regcache, OR1K_RV_REGNUM, buf_hi);
+ regcache_cooked_write (regcache, OR1K_RV_REGNUM + 1, buf_lo);
+ }
+ }
+
+ return RETURN_VALUE_REGISTER_CONVENTION;
+
+} /* or1k_return_value() */
+
+
+
+/*----------------------------------------------------------------------------*/
+/*!Determine the kind of breakpoint based on the current pc
+
+ Given the pc address, return the type of breapoint that should be used.
+ For or1k we only use one type which is a 32-bit trap instruction.
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] pcptr The program counter address in question
+
+ @return The breakpoint type */
+/*----------------------------------------------------------------------------*/
+
+static int
+or1k_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr)
+{
+ return OR1K_BP_KIND_OR1K;
+} /* or1k_breakpoint_kind_from_pc() */
+
+/*----------------------------------------------------------------------------*/
+/*!Determine the instruction to use for a breakpoint.
+
+ 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.
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] kind The kind of breakpoint to be returned
+ @param[out] size The size of instruction selected
+
+ @return The chosen breakpoint instruction */
+/*---------------------------------------------------------------------------*/
+
+static const gdb_byte *
+or1k_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
+{
+
+ switch (kind)
+ {
+ case OR1K_BP_KIND_OR1K:
+ {
+ static const gdb_byte breakpoint[] = OR1K_BRK_INSTR_STRUCT;
+
+ *size = OR1K_INSTLEN;
+ return breakpoint;
+ }
+ default:
+ gdb_assert_not_reached ("unexpected or1k breakpoint kind");
+ };
+} /* or1k_sw_breakpoint_from_kind() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Determine if we are executing a delay slot
+
+ Looks at the instruction at the previous instruction to see if it was one
+ with a delay slot. But it also has to be the address prior to NPC, because
+ we may have just taken an exception.
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] this_frame Information about THIS frame
+
+ @return 1 (true) if this instruction is executing a delay slot, 0 (false)
+ otherwise. */
+/*--------------------------------------------------------------------------*/
+
+static int
+or1k_single_step_through_delay (struct gdbarch *gdbarch,
+ struct frame_info *this_frame)
+{
+ struct regcache *regcache = get_current_regcache ();
+ ULONGEST val;
+ CORE_ADDR ppc;
+ CORE_ADDR npc;
+ CGEN_FIELDS tmp_fields;
+ const CGEN_INSN *insns;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* Get and the previous and current instruction addresses. If they are not
+ adjacent, we cannot be in a delay slot. */
+ regcache_cooked_read_unsigned (regcache, OR1K_PPC_REGNUM, &val);
+ ppc = (CORE_ADDR) val;
+ regcache_cooked_read_unsigned (regcache, OR1K_NPC_REGNUM, &val);
+ npc = (CORE_ADDR) val;
+
+ if (0x4 != (npc - ppc))
+ {
+ return 0;
+ }
+
+ insns = cgen_lookup_insn (tdep->gdb_cgen_cpu_desc,
+ NULL,
+ or1k_fetch_instruction (gdbarch, ppc),
+ NULL,
+ 32,
+ &tmp_fields,
+ 0);
+
+ /* TODO: we should add a delay slot flag to the CGEN_INSN and remove
+ * this hard coded test. */
+ return ((CGEN_INSN_NUM(insns) == OR1K_INSN_L_J) ||
+ (CGEN_INSN_NUM(insns) == OR1K_INSN_L_JAL) ||
+ (CGEN_INSN_NUM(insns) == OR1K_INSN_L_JR) ||
+ (CGEN_INSN_NUM(insns) == OR1K_INSN_L_JALR) ||
+ (CGEN_INSN_NUM(insns) == OR1K_INSN_L_BNF) ||
+ (CGEN_INSN_NUM(insns) == OR1K_INSN_L_BF));
+
+} /* or1k_single_step_through_delay() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Read a pseudo register
+
+ Since we have no pseudo registers this is a null function for now.
+
+ @todo The floating point and vector registers ought to be done as
+ pseudo-registers.
+
+ @param[in] gdbarch The GDB architecture to consider
+ @param[in] regcache The cached register values as an array
+ @param[in] regnum The register to read
+ @param[out] buf A buffer to put the result in */
+/*---------------------------------------------------------------------------*/
+
+static enum register_status
+or1k_pseudo_register_read (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum,
+ gdb_byte *buf)
+{
+ return REG_UNKNOWN;
+} /* or1k_pseudo_register_read() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Write a pseudo register
+
+ Since we have no pseudo registers this is a null function for now.
+
+ @todo The floating point and vector registers ought to be done as
+ pseudo-registers.
+
+ @param[in] gdbarch The GDB architecture to consider
+ @param[in] regcache The cached register values as an array
+ @param[in] regnum The register to read
+ @param[in] buf A buffer with the value to write */
+/*---------------------------------------------------------------------------*/
+
+static void
+or1k_pseudo_register_write (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum,
+ const gdb_byte *buf)
+{
+ return;
+
+} /* or1k_pseudo_register_write() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Return the register name for the OpenRISC 1000 architecture
+
+ This version converted to ANSI C, made static and incorporates the static
+ table of register names (this is the only place it is referenced).
+
+ @todo The floating point and vector registers ought to be done as
+ pseudo-registers.
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] regnum The register number
+
+ @return The textual name of the register */
+/*---------------------------------------------------------------------------*/
+
+static const char *
+or1k_register_name (struct gdbarch *gdbarch,
+ int regnum)
+{
+ static char *or1k_gdb_reg_names[OR1K_NUM_REGS_CACHED] =
+ {
+ /* 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",
+
+ /* previous program counter, next program counter and status register */
+ "ppc", "npc", "sr"
+
+ /* Floating point and vector registers may appear as pseudo registers in
+ the future. */
+ };
+
+ /* If we have a target description, use it */
+ if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+ return tdesc_register_name (gdbarch, regnum);
+ else
+ {
+ if (0 <= regnum && regnum < OR1K_NUM_REGS_CACHED)
+ {
+ return or1k_gdb_reg_names[regnum];
+ }
+ else
+ return NULL;
+ }
+
+} /* or1k_register_name() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Identify the type of a register
+
+ @todo I don't fully understand exactly what this does, but I think this
+ makes sense!
+
+ @param[in] arch The GDB architecture to consider
+ @param[in] regnum The register to identify
+
+ @return The type of the register */
+/*---------------------------------------------------------------------------*/
+
+static struct type *
+or1k_register_type (struct gdbarch *arch,
+ int regnum)
+{
+ static struct type *void_func_ptr = NULL;
+ static struct type *void_ptr = NULL;
+
+ /* Set up the static pointers once, the first time*/
+ if (NULL == void_func_ptr)
+ {
+ struct type *void_type = builtin_type (arch)->builtin_void;
+
+ void_ptr = lookup_pointer_type (void_type);
+ void_func_ptr = lookup_pointer_type (lookup_function_type (void_type));
+ }
+
+ if((regnum >= 0) && (regnum < OR1K_TOTAL_NUM_REGS))
+ {
+ switch (regnum)
+ {
+ case OR1K_PPC_REGNUM:
+ case OR1K_NPC_REGNUM:
+ return void_func_ptr; /* Pointer to code */
+
+ case OR1K_SP_REGNUM:
+ case OR1K_FP_REGNUM:
+ return void_ptr; /* Pointer to data */
+
+ default:
+ return builtin_type (arch)->builtin_uint32; /* Data */
+ }
+ }
+
+ internal_error (__FILE__, __LINE__,
+ _("or1k_register_type: illegal register number %d"), regnum);
+
+} /* or1k_register_type() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Handle the "info register" command
+
+ Print the identified register, unless it is -1, in which case print all
+ the registers. If all is 1 means all registers, otherwise only the core
+ GPRs.
+
+ @todo At present all registers are printed with the default method. Should
+ there be something special for FP registers?
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] file File handle for use with any custom I/O
+ @param[in] frame Frame info for use with custom output
+ @param[in] regnum Register of interest, or -1 if all registers
+ @param[in] all 1 if all means all, 0 if all means just GPRs
+
+ @return The aligned stack frame address */
+/*---------------------------------------------------------------------------*/
+
+static void
+or1k_registers_info (struct gdbarch *gdbarch,
+ struct ui_file *file,
+ struct frame_info *frame,
+ int regnum,
+ int all)
+{
+ struct regcache *regcache = get_current_regcache ();
+
+ if (-1 == regnum)
+ {
+ /* Do all (valid) registers */
+ unsigned int lim = all ? OR1K_NUM_REGS_CACHED : OR1K_MAX_GPR_REGS;
+
+ for (regnum = 0; regnum < lim; regnum++) {
+ if ('\0' != *(or1k_register_name (gdbarch, regnum)))
+ {
+ or1k_registers_info (gdbarch, file, frame, regnum, all);
+ }
+ }
+ }
+ else
+ {
+ /* Do one specified register - if it is part of this architecture */
+ if ((regnum < OR1K_NUM_REGS_CACHED)
+ && ('\0' == *(or1k_register_name (gdbarch, regnum))))
+ {
+ error ("Not a valid register for the current processor type");
+ }
+ else
+ {
+ /* If the register is not in the g/G packet, fetch it from the
+ * target with a p/P packet.
+ */
+ if (regnum >= OR1K_NUM_REGS_CACHED)
+ target_fetch_registers (regcache, regnum);
+
+ default_print_registers_info (gdbarch, file, frame, regnum, all);
+ }
+ }
+} /* or1k_registers_info() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Identify if a register belongs to a specified group
+
+ Return true if the specified register is a member of the specified
+ register group.
+
+ These are the groups of registers that can be displayed via "info reg".
+
+ @todo The Vector and Floating Point registers ought to be displayed as
+ pseudo-registers.
+
+ @param[in] gdbarch The GDB architecture to consider
+ @param[in] regnum The register to consider
+ @param[in] group The group to consider
+
+ @return True (1) if regnum is a member of group */
+/*---------------------------------------------------------------------------*/
+
+static int
+or1k_register_reggroup_p (struct gdbarch *gdbarch,
+ int regnum,
+ struct reggroup *group)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ /* All register group */
+ if (group == all_reggroup)
+ {
+ return ((regnum >= 0) &&
+ (regnum < OR1K_NUM_REGS_CACHED) &&
+ (or1k_register_name (gdbarch, regnum)[0] != '\0'));
+ }
+
+ /* For now everything except the PC */
+ if (group == general_reggroup)
+ {
+ return ((regnum >= OR1K_ZERO_REGNUM) &&
+ (regnum < tdep->num_gpr_regs) &&
+ (regnum != OR1K_PPC_REGNUM) &&
+ (regnum != OR1K_NPC_REGNUM));
+ }
+
+ if (group == float_reggroup)
+ {
+ return 0; /* No float regs. */
+ }
+
+ if (group == vector_reggroup)
+ {
+ return 0; /* No vector regs. */
+ }
+
+ if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+ {
+ if ((tdesc_register_in_reggroup_p (gdbarch, regnum, group)) != 1)
+ return 0;
+ else
+ return 1;
+ }
+ else
+ /* For any that are not handled above. */
+ return default_register_reggroup_p (gdbarch, regnum, group);
+
+} /* or1k_register_reggroup_p() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Is this one of the registers used for passing arguments?
+
+ These are r3-r8 in the API.
+
+ @param[in] regnum The register to consider
+
+ @return Non-zero (TRUE) if it is an argument register, zero (FALSE)
+ otherwise. */
+/*----------------------------------------------------------------------------*/
+static int
+or1k_is_arg_reg (unsigned int regnum)
+{
+ return (OR1K_FIRST_ARG_REGNUM <= regnum) && (regnum <= OR1K_LAST_ARG_REGNUM);
+
+} /* or1k_is_arg_reg () */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Is this a callee saved register?
+
+ These are r10, r12, r14, r16, r18, r20, r22, r24, r26, r28 and r30 in the
+ API.
+
+ @param[in] regnum The register to consider
+
+ @return Non-zero (TRUE) if it is a callee saved register, zero (FALSE)
+ otherwise. */
+/*----------------------------------------------------------------------------*/
+static int
+or1k_is_callee_saved_reg (unsigned int regnum)
+{
+ return (OR1K_FIRST_SAVED_REGNUM <= regnum) && (0 == regnum % 2);
+
+} /* or1k_is_callee_saved_reg () */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Skip a function prolog
+
+ If the input address, PC, is in a function prologue, return the address of
+ the end of the prologue, otherwise return the input address.
+
+ @see For details of the stack frame, see the function
+ or1k_frame_cache().
+
+ @note The old version of this function used to use skip_prologue_using_sal
+ to skip the prologue without checking if it had actually worked. It
+ doesn't for STABS, so we had better check for a valid result.
+
+ This function reuses the helper functions from or1k_frame_cache() to
+ locate the various parts of the prolog, any or all of which may be missing.
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] pc Current program counter
+
+ @return The address of the end of the prolog if the PC is in a function
+ prologue, otherwise the input address. */
+/*----------------------------------------------------------------------------*/
+static CORE_ADDR
+or1k_skip_prologue (struct gdbarch *gdbarch,
+ CORE_ADDR pc)
+{
+ CORE_ADDR start_pc;
+ CORE_ADDR addr;
+ uint32_t inst;
+
+ unsigned int ra, rb, rd; /* For instruction analysis */
+ int simm;
+
+ int frame_size = 0;
+
+ /* Try using SAL first if we have symbolic information available. This only
+ works for DWARF 2, not STABS. */
+ if (find_pc_partial_function (pc, NULL, &start_pc, NULL))
+ {
+ CORE_ADDR prologue_end = skip_prologue_using_sal( gdbarch, pc );
+
+ if (0 != prologue_end)
+ {
+ struct symtab_and_line prologue_sal = find_pc_line (start_pc, 0);
+ struct compunit_symtab *compunit = SYMTAB_COMPUNIT(prologue_sal.symtab);
+ const char *debug_format = COMPUNIT_DEBUGFORMAT(compunit);
+
+ if ((NULL != debug_format) && (strlen ("dwarf") <= strlen (debug_format))
+ && (0 == strncasecmp ("dwarf", debug_format, strlen ("dwarf"))))
+ {
+ return (prologue_end > pc) ? prologue_end : pc;
+ }
+ }
+ }
+
+ /* Look to see if we can find any of the standard prologue sequence. All
+ quite difficult, since any or all of it may be missing. So this is just a
+ best guess! */
+ addr = pc; /* Where we have got to */
+ inst = or1k_fetch_instruction (gdbarch, addr);
+
+ /* Look for the new stack pointer being set up. */
+ if (or1k_analyse_l_addi (inst, &rd, &ra, &simm) &&
+ (OR1K_SP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) &&
+ (simm < 0) && (0 == (simm % 4)))
+ {
+ frame_size = -simm;
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+ }
+
+ /* Look for the frame pointer being manipulated. */
+ if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
+ (OR1K_SP_REGNUM == ra) && (OR1K_FP_REGNUM == rb) &&
+ (simm >= 0) && (0 == (simm % 4)))
+ {
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+
+ gdb_assert (or1k_analyse_l_addi (inst, &rd, &ra, &simm) &&
+ (OR1K_FP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) &&
+ (simm == frame_size));
+
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+ }
+
+ /* Look for the link register being saved */
+ if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
+ (OR1K_SP_REGNUM == ra) && (OR1K_LR_REGNUM == rb) &&
+ (simm >= 0) && (0 == (simm % 4)))
+ {
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+ }
+
+ /* Look for arguments or callee-saved register being saved. The register
+ must be one of the arguments (r3-r8) or the 10 callee saved registers
+ (r10, r12, r14, r16, r18, r20, r22, r24, r26, r28, r30). The base
+ register must be the FP (for the args) or the SP (for the callee_saved
+ registers). */
+ while (1)
+ {
+ if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
+ (((OR1K_FP_REGNUM == ra) && or1k_is_arg_reg (rb)) ||
+ ((OR1K_SP_REGNUM == ra) && or1k_is_callee_saved_reg (rb))) &&
+ (0 == (simm % 4)))
+ {
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+ }
+ else
+ {
+ /* Nothing else to look for. We have found the end of the prologue. */
+ return addr;
+ }
+ }
+} /* or1k_skip_prologue() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Align the stack frame
+
+ OpenRISC 1000 uses a falling stack frame, so this aligns down to the
+ nearest 8 bytes. Useful when we'be building a dummy frame.
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] sp Current stack pointer
+
+ @return The aligned stack frame address */
+/*---------------------------------------------------------------------------*/
+
+static CORE_ADDR
+or1k_frame_align (struct gdbarch *gdbarch,
+ CORE_ADDR sp)
+{
+ return align_down (sp, OR1K_STACK_ALIGN);
+
+} /* or1k_frame_align() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Unwind the program counter from a stack frame
+
+ This just uses the built in frame unwinder
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] next_frame Frame info for the NEXT frame
+
+ @return The program counter for THIS frame */
+/*---------------------------------------------------------------------------*/
+
+static CORE_ADDR
+or1k_unwind_pc (struct gdbarch *gdbarch,
+ struct frame_info *next_frame)
+{
+ CORE_ADDR pc;
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "or1k_unwind_pc, next_frame=%d\n",
+ frame_relative_level (next_frame));
+ }
+
+ pc = frame_unwind_register_unsigned (next_frame, OR1K_NPC_REGNUM);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "or1k_unwind_pc, pc=0x%p\n", (void *) pc);
+ }
+
+ return pc;
+
+} /* or1k_unwind_pc() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Unwind the stack pointer from a stack frame
+
+ This just uses the built in frame unwinder
+
+ @param[in] gdbarch The GDB architecture being used
+ @param[in] next_frame Frame info for the NEXT frame
+
+ @return The stack pointer for THIS frame */
+/*---------------------------------------------------------------------------*/
+
+static CORE_ADDR
+or1k_unwind_sp (struct gdbarch *gdbarch,
+ struct frame_info *next_frame)
+{
+ CORE_ADDR sp;
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "or1k_unwind_sp, next_frame=%d\n",
+ frame_relative_level (next_frame));
+ }
+
+ sp = frame_unwind_register_unsigned (next_frame, OR1K_SP_REGNUM);
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "or1k_unwind_sp, sp=0x%p\n", (void *) sp);
+ }
+
+ return sp;
+
+} /* or1k_unwind_sp() */
+
+/*----------------------------------------------------------------------------*/
+/*!Provides return address for dummy call
+
+ Provides an address on the stack where to put a breakpoint as return
+ address for function. bp_addr is the address to which the function should
+ return (which is breakpointed, so gdb can regain control, hence the name).
+
+ @param[in] gdbarch The architecture to use
+ @param[in] sp The stack pointer
+ @param[in] function Pointer to the function that will be called
+ @param[in] args The arguments
+ @param[in] nargs Number of ags to push
+ @param[in] value_type Type of the function result
+ @param[in] real_pc Resume address
+ @param[in] bp_addr Breakpoint address
+ @param[in] regcache The register cache to use
+
+ @return The breakpoint address */
+/*---------------------------------------------------------------------------*/
+
+static CORE_ADDR
+or1k_push_dummy_code (struct gdbarch *gdbarch,
+ CORE_ADDR sp,
+ CORE_ADDR function,
+ struct value **args,
+ int nargs,
+ struct type *value_type,
+ CORE_ADDR *real_pc,
+ CORE_ADDR *bp_addr,
+ struct regcache *regcache)
+{
+ CORE_ADDR bp_slot;
+
+ /* Reserve enough room on the stack for our breakpoint instruction. */
+ bp_slot = sp - 4;
+ /* Store the address of that breakpoint */
+ *bp_addr = bp_slot;
+ /* keeping the stack aligned. */
+ sp = or1k_frame_align (gdbarch, bp_slot);
+ /* The call starts at the callee's entry point. */
+ *real_pc = function;
+
+ return sp;
+
+} /* or1k_push_dummy_code() */
+
+/*----------------------------------------------------------------------------*/
+/*!Create a dummy stack frame
+
+ The arguments are placed in registers and/or pushed on the stack as per the
+ OR1K ABI.
+
+ @param[in] gdbarch The architecture to use
+ @param[in] function Pointer to the function that will be called
+ @param[in] regcache The register cache to use
+ @param[in] bp_addr Breakpoint address
+ @param[in] nargs Number of ags to push
+ @param[in] args The arguments
+ @param[in] sp The stack pointer
+ @param[in] struct_return True (1) if this returns a structure
+ @param[in] struct_addr Address for returning structures
+
+ @return The updated stack pointer */
+/*---------------------------------------------------------------------------*/
+
+static CORE_ADDR
+or1k_push_dummy_call (struct gdbarch *gdbarch,
+ struct value *function,
+ struct regcache *regcache,
+ CORE_ADDR bp_addr,
+ int nargs,
+ struct value **args,
+ CORE_ADDR sp,
+ int struct_return,
+ CORE_ADDR struct_addr)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ int argreg;
+ int argnum;
+ int first_stack_arg;
+ int stack_offset = 0;
+ int heap_offset = 0;
+ CORE_ADDR heap_sp = sp - 128;
+
+ unsigned int bpa = (gdbarch_tdep (gdbarch))->bytes_per_address;
+ unsigned int bpw = (gdbarch_tdep (gdbarch))->bytes_per_word;
+ struct type *func_type = value_type (function);
+
+ /* Return address */
+ regcache_cooked_write_unsigned (regcache, OR1K_LR_REGNUM, bp_addr);
+
+ /* Register for the next argument */
+ argreg = OR1K_FIRST_ARG_REGNUM;
+
+ /* Location for a returned structure. This is passed as a silent first
+ argument. */
+ if (struct_return)
+ {
+ regcache_cooked_write_unsigned (regcache, OR1K_FIRST_ARG_REGNUM,
+ struct_addr);
+ argreg++;
+ }
+
+ /* Put as many args as possible in registers */
+ for (argnum = 0; argnum < nargs; argnum++)
+ {
+ const gdb_byte *val;
+ gdb_byte valbuf[sizeof (ULONGEST)];
+
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (value_type (arg));
+ int len = arg_type->length;
+ enum type_code typecode = arg_type->main_type->code;
+
+ if (TYPE_VARARGS (func_type) && argnum >= TYPE_NFIELDS(func_type))
+ {
+ break; /* end or regular args, varargs go to stack */
+ }
+
+ /* Extract the value, either a reference or the data */
+ if ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode) || (len > bpw*2))
+ {
+ CORE_ADDR valaddr = value_address (arg);
+
+ /* if the arg is fabricated (i.e. 3*i, instead of i) valaddr is undefined */
+ if (valaddr == 0) {
+ /* The argument needs to be copied into the target space. Since
+ the bottom of the stack is reserved for function arguments
+ we store this at the these at the top growing down. */
+ heap_offset += align_up (len, bpw);
+ valaddr = heap_sp + heap_offset;
+
+ write_memory (valaddr, value_contents(arg), len);
+ }
+
+ /* The ABI passes all structures by reference, so get its address. */
+ store_unsigned_integer (valbuf, bpa, byte_order, valaddr);
+ len = bpa;
+ val = valbuf;
+ }
+ else
+ {
+ /* Everything else, we just get the value. */
+ val = value_contents (arg);
+ }
+
+ /* Stick the value in a register */
+ if(len > bpw)
+ {
+ /* Big scalars use two registers, but need NOT be pair aligned. */
+
+ if (argreg <= (OR1K_LAST_ARG_REGNUM - 1))
+ {
+ ULONGEST regval = extract_unsigned_integer (val, len, byte_order);
+
+ unsigned int bits_per_word = bpw * 8;
+ ULONGEST mask = (((ULONGEST) 1) << bits_per_word) - 1;
+ ULONGEST lo = regval & mask;
+ ULONGEST hi = regval >> bits_per_word;
+
+ regcache_cooked_write_unsigned (regcache, argreg, hi);
+ regcache_cooked_write_unsigned (regcache, argreg + 1, lo);
+ argreg += 2;
+ }
+ else
+ {
+ /* Run out of regs */
+ break;
+ }
+ }
+ else if (argreg <= OR1K_LAST_ARG_REGNUM)
+ {
+ /* Smaller scalars fit in a single register */
+ regcache_cooked_write_unsigned (regcache, argreg,
+ extract_unsigned_integer (val, len,
+ byte_order));
+ argreg++;
+ }
+ else
+ {
+ /* Run out of regs */
+ break;
+ }
+ }
+
+ first_stack_arg = argnum;
+
+ /* If we get here with argnum < nargs, then arguments remain to be placed on
+ the stack. This is tricky, since they must be pushed in reverse order and
+ the stack in the end must be aligned. The only solution is to do it in
+ two stages, the first to compute the stack size, the second to save the
+ args. */
+
+ for (argnum = first_stack_arg; argnum < nargs; argnum++)
+ {
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (value_type (arg));
+ int len = arg_type->length;
+ enum type_code typecode = arg_type->main_type->code;
+
+ if ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode) || (len > bpw*2))
+ {
+ /* Structures are passed as addresses */
+ sp -= bpa;
+ }
+ else
+ {
+ /* Big scalars use more than one word. Code here allows for future
+ quad-word entities (e.g. long double) */
+ sp -= align_up(len, bpw);
+ }
+
+ /* ensure our dummy heap doesn't touch the stack, this could only happen
+ if we have many arguments including fabricated arguments */
+ gdb_assert(heap_offset == 0 || ((heap_sp + heap_offset) < sp));
+ }
+
+ sp = gdbarch_frame_align (gdbarch, sp);
+ stack_offset = 0;
+
+ /* Push the remaining args on the stack */
+ for (argnum = first_stack_arg; argnum < nargs; argnum++)
+ {
+ const gdb_byte *val;
+ gdb_byte valbuf[sizeof (ULONGEST) ];
+
+ struct value *arg = args[argnum];
+ struct type *arg_type = check_typedef (value_type (arg));
+ int len = arg_type->length;
+ enum type_code typecode = arg_type->main_type->code;
+ /* The EABI passes structures that do not fit in a register by
+ reference. In all other cases, pass the structure by value. */
+ if ((TYPE_CODE_STRUCT == typecode) || (TYPE_CODE_UNION == typecode) || (len > bpw*2))
+ {
+ store_unsigned_integer (valbuf, bpa, byte_order, value_address (arg));
+ len = bpa;
+ val = valbuf;
+ }
+ else
+ {
+ val = value_contents (arg);
+ }
+
+ while (len > 0)
+ {
+ int partial_len = (len < bpw ? len : bpw);
+
+ write_memory (sp + stack_offset, val, partial_len);
+ stack_offset += align_up (partial_len, bpw);
+ len -= partial_len;
+ val += partial_len;
+ }
+ }
+
+ /* Save the updated stack pointer */
+ regcache_cooked_write_unsigned (regcache, OR1K_SP_REGNUM, sp);
+
+ if (heap_offset > 0) {
+ sp = heap_sp;
+ }
+
+ return sp;
+
+} /* or1k_push_dummy_call() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Return the frame ID for a dummy stack frame
+
+ Tear down a dummy frame created by or1k_push_dummy_call(). This data has to
+ be constructed manually from the data in our hand.
+
+ The stack pointer and program counter can be obtained from the frame info.
+
+ @param[in] gdbarch The architecture to use
+ @param[in] this_frame Information about this frame
+
+ @return Frame ID of this frame */
+/*---------------------------------------------------------------------------*/
+
+static struct frame_id
+or1k_dummy_id (struct gdbarch *gdbarch,
+ struct frame_info *this_frame)
+{
+ return frame_id_build (get_frame_sp (this_frame), get_frame_pc (this_frame));
+
+} /* or1k_dummy_id() */
+
+
+\f
+
+/* Support functions for frame handling */
+
+/* -------------------------------------------------------------------------- */
+/*!Initialize a prologue cache
+
+ This function is changed from its GDB 6.8 version (named
+ or1k_frame_unwind_cache), in that it is based on THIS frame, not the NEXT
+ frame.
+
+ We build a cache, saying where registers of the PREV frame can be found
+ from the data so far set up in this THIS.
+
+ We also compute a unique ID for this frame, based on the function start
+ address and the stack pointer (as it will be, even if it has yet to be
+ computed.
+
+ STACK FORMAT
+ ============
+
+ The OR1K has a falling stack frame and a simple prolog. The Stack pointer
+ is R1 and the frame pointer R2. The frame base is therefore the address
+ held in R2 and the stack pointer (R1) is the frame base of the NEXT frame.
+
+ @verbatim
+ l.addi r1,r1,-frame_size # SP now points to end of new stack frame
+ @endverbatim
+
+ The stack pointer may not be set up in a frameless function (e.g. a simple
+ leaf function).
+
+ @verbatim
+ l.sw fp_loc(r1),r2 # old FP saved in new stack frame
+ l.addi r2,r1,frame_size # FP now points to base of new stack frame
+ @endverbatim
+
+ The frame pointer is not necessarily saved right at the end of the stack
+ frame - OR1K saves enough space for any args to called functions right at
+ the end (this is a difference from the Architecture Manual).
+
+ @verbatim
+ l.sw lr_loc(r1),r9 # Link (return) address
+ @endverbatim
+
+ The link register is usally saved at fp_loc - 4. It may not be saved at all
+ in a leaf function.
+
+ @verbatim
+ l.sw reg_loc(r1),ry # Save any callee saved regs
+ @endverbatim
+
+ The offsets x for the callee saved registers generally (always?) rise in
+ increments of 4, starting at fp_loc + 4. If the frame pointer is omitted
+ (an option to GCC), then it may not be saved at all. There may be no callee
+ saved registers.
+
+ So in summary none of this may be present. However what is present seems
+ always to follow this fixed order, and occur before any substantive code
+ (it is possible for GCC to have more flexible scheduling of the prologue,
+ but this does not seem to occur for OR1K).
+
+ ANALYSIS
+ ========
+
+ This prolog is used, even for -O3 with GCC.
+
+ All this analysis must allow for the possibility that the PC is in the
+ middle of the prologue. Data in the cache should only be set up insofar as
+ it has been computed.
+
+ HOWEVER. The frame_id must be created with the SP *as it will be* at the
+ end of the Prologue. Otherwise a recursive call, checking the frame with
+ the PC at the start address will end up with the same frame_id as the
+ caller.
+
+ A suite of "helper" routines are used, allowing reuse for
+ or1k_skip_prologue().
+
+ Reportedly, this is only valid for frames less than 0x7fff in size.
+
+ @param[in] this_frame Our stack frame.
+ @param[in,out] prologue_cache The prologue cache. If not supplied, we
+ build it.
+
+ @return The prolog cache (duplicates the return through the argument) */
+/* ---------------------------------------------------------------------------*/
+static struct trad_frame_cache *
+or1k_frame_cache (struct frame_info *this_frame,
+ void **prologue_cache)
+{
+ struct gdbarch *gdbarch;
+ struct trad_frame_cache *info;
+
+ CORE_ADDR this_pc;
+ CORE_ADDR this_sp;
+ CORE_ADDR this_sp_for_id;
+ int frame_size = 0;
+
+ CORE_ADDR start_addr;
+ CORE_ADDR end_addr;
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "or1k_frame_cache, prologue_cache = 0x%p\n",
+ *prologue_cache);
+ }
+
+ /* Nothing to do if we already have this info */
+ if (NULL != *prologue_cache)
+ {
+ return (struct trad_frame_cache *) *prologue_cache;
+ }
+
+ /* Get a new prologue cache and populate it with default values */
+ info = trad_frame_cache_zalloc (this_frame);
+ *prologue_cache = info;
+
+ /* Find the start address of THIS function (which is a NORMAL frame, even if
+ the NEXT frame is the sentinel frame) and the end of its prologue. */
+ this_pc = get_frame_pc (this_frame);
+ find_pc_partial_function (this_pc, NULL, &start_addr, NULL);
+
+ /* Get the stack pointer if we have one (if there's no process executing yet
+ we won't have a frame. */
+ this_sp = (NULL == this_frame) ? 0 :
+ get_frame_register_unsigned (this_frame,
+ OR1K_SP_REGNUM);
+
+ /* Return early if GDB couldn't find the function. */
+ if (start_addr == 0)
+ {
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, " couldn't find function\n");
+ }
+
+ /* JPB: 28-Apr-11. This is a temporary patch, to get round GDB crashing
+ right at the beginning. Build the frame ID as best we can. */
+ trad_frame_set_id (info, frame_id_build (this_sp, this_pc));
+
+ return info;
+ }
+
+
+ /* The default frame base of THIS frame (for ID purposes only - frame base
+ is an overloaded term) is its stack pointer. For now we use the value of
+ the SP register in THIS frame. However if the PC is in the prologue of
+ THIS frame, before the SP has been set up, then the value will actually
+ be that of the PREV frame, and we'll need to adjust it later. */
+ trad_frame_set_this_base (info, this_sp);
+ this_sp_for_id = this_sp;
+
+ /* The default is to find the PC of the PREVIOUS frame in the link register
+ of this frame. This may be changed if we find the link register was saved
+ on the stack. */
+ trad_frame_set_reg_realreg (info, OR1K_NPC_REGNUM, OR1K_LR_REGNUM);
+
+ /* We should only examine code that is in the prologue. This is all code up
+ to (but not including) end_addr. We should only populate the cache while
+ the address is up to (but not including) the PC or end_addr, whichever is
+ first. */
+ gdbarch = get_frame_arch (this_frame);
+ end_addr = or1k_skip_prologue (gdbarch, start_addr);
+
+ /* All the following analysis only occurs if we are in the prologue and have
+ executed the code. Check we have a sane prologue size, and if zero we
+ are frameless and can give up here. */
+ if (end_addr < start_addr)
+ {
+ throw_quit ("end addr 0x%08x is less than start addr 0x%08x\n",
+ (unsigned int) end_addr, (unsigned int) start_addr);
+ }
+
+ if (end_addr == start_addr)
+ {
+ frame_size = 0;
+ }
+ else
+ {
+ /* have a frame. Look for the various components */
+ CORE_ADDR addr = start_addr; /* Where we have got to */
+ uint32_t inst = or1k_fetch_instruction (gdbarch, addr);
+
+ unsigned int ra, rb, rd; /* For instruction analysis */
+ int simm;
+
+ /* Look for the new stack pointer being set up. */
+ if (or1k_analyse_l_addi (inst, &rd, &ra, &simm) &&
+ (OR1K_SP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) &&
+ (simm < 0) && (0 == (simm % 4)))
+ {
+ frame_size = -simm;
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+
+ /* If the PC has not actually got to this point, then the frame base
+ will be wrong, and we adjust it.
+
+ If we are past this point, then we need to populate the stack
+ accoringly. */
+ if (this_pc <= addr)
+ {
+ /* Only do if executing */
+ if (0 != this_sp)
+ {
+ this_sp_for_id = this_sp + frame_size;
+ trad_frame_set_this_base (info, this_sp_for_id);
+ }
+ }
+ else
+ {
+ /* We are past this point, so the stack pointer of the PREV
+ frame is frame_size greater than the stack pointer of THIS
+ frame. */
+ trad_frame_set_reg_value (info, OR1K_SP_REGNUM,
+ this_sp + frame_size);
+ }
+ }
+
+ /* From now on we are only populating the cache, so we stop once we get
+ to either the end OR the current PC. */
+ end_addr = (this_pc < end_addr) ? this_pc : end_addr;
+
+ /* Look for the frame pointer being manipulated. */
+ if ((addr < end_addr) &&
+ or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
+ (OR1K_SP_REGNUM == ra) && (OR1K_FP_REGNUM == rb) &&
+ (simm >= 0) && (0 == (simm % 4)))
+ {
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+
+ /* At this stage, we can find the frame pointer of the PREVIOUS
+ frame on the stack of the current frame. */
+ trad_frame_set_reg_addr (info, OR1K_FP_REGNUM, this_sp + simm);
+
+ /* Look for the new frame pointer being set up */
+ if (addr < end_addr)
+ {
+ gdb_assert (or1k_analyse_l_addi (inst, &rd, &ra, &simm) &&
+ (OR1K_FP_REGNUM == rd) && (OR1K_SP_REGNUM == ra) &&
+ (simm == frame_size));
+
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+
+ /* If we have got this far, the stack pointer of the PREVIOUS
+ frame is the frame pointer of THIS frame. */
+ trad_frame_set_reg_realreg (info, OR1K_SP_REGNUM, OR1K_FP_REGNUM);
+ }
+ }
+
+ /* Look for the link register being saved */
+ if ((addr < end_addr) &&
+ or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
+ (OR1K_SP_REGNUM == ra) && (OR1K_LR_REGNUM == rb) &&
+ (simm >= 0) && (0 == (simm % 4)))
+ {
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+
+ /* If the link register is saved in the THIS frame, it holds the
+ value of the PC in the PREVIOUS frame. This overwrites the
+ previous information about finding the PC in the link
+ register. */
+ trad_frame_set_reg_addr (info, OR1K_NPC_REGNUM, this_sp + simm);
+ }
+
+ /* Look for arguments or callee-saved register being saved. The register
+ must be one of the arguments (r3-r8) or the 10 callee saved registers
+ (r10, r12, r14, r16, r18, r20, r22, r24, r26, r28, r30). The base
+ register must be the FP (for the args) or the SP (for the
+ callee_saved registers). */
+ while (addr < end_addr)
+ {
+ if (or1k_analyse_l_sw (inst, &simm, &ra, &rb) &&
+ (((OR1K_FP_REGNUM == ra) && or1k_is_arg_reg (rb)) ||
+ ((OR1K_SP_REGNUM == ra) && or1k_is_callee_saved_reg (rb))) &&
+ (0 == (simm % 4)))
+ {
+ addr += OR1K_INSTLEN;
+ inst = or1k_fetch_instruction (gdbarch, addr);
+
+ /* The register in the PREVIOUS frame can be found at this
+ location in THIS frame */
+ trad_frame_set_reg_addr (info, rb, this_sp + simm);
+ }
+ else
+ {
+ break; /* Not a register save instruction */
+ }
+ }
+ }
+
+ /* Build the frame ID */
+ trad_frame_set_id (info, frame_id_build (this_sp_for_id, start_addr));
+
+ if (frame_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, " this_sp_for_id = 0x%p\n",
+ (void *) this_sp_for_id);
+ fprintf_unfiltered (gdb_stdlog, " start_addr = 0x%p\n",
+ (void *) start_addr);
+ }
+
+ return info;
+
+} /* or1k_frame_cache() */
+
+
+/* -------------------------------------------------------------------------- */
+/*!Find the frame ID of this frame
+
+ This function has changed since GDB 6.8 to use THIS frame, rather than the
+ NEXT frame.
+
+ Given a GDB frame, return its frame_id.
+
+ @param[in] this_frame Our frame, for which the ID is wanted.
+ @param[in] prologue_cache Any cached prologue for THIS function.
+ @param[out] this_id Frame ID of our own frame.
+
+ @return Frame ID for THIS frame */
+/* ------------------------------------------------------------------------- */
+static void
+or1k_frame_this_id (struct frame_info *this_frame,
+ void **prologue_cache,
+ struct frame_id *this_id)
+{
+ struct trad_frame_cache *info =
+ or1k_frame_cache (this_frame, prologue_cache);
+
+ trad_frame_get_id (info, this_id);
+
+} /* or1k_frame_this_id() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Get a register from the PREVIOUS frame
+
+ This function has changed from GDB 6.8. It now takes a reference to THIS
+ frame, not the NEXT frame. It returns it results via a structure, not its
+ argument list.
+
+ Given a pointer to the THIS frame, return the details of a register in the
+ PREVIOUS frame.
+
+ @param[in] this_frame The stack frame under consideration
+ @param[in] prologue_cache Any cached prologue associated with THIS frame,
+ which may therefore tell us about registers in
+ the PREVIOUS frame.
+ @param[in] regnum The register of interest in the PREVIOUS frame
+
+ @return A value structure representing the register. */
+/* -------------------------------------------------------------------------- */
+static struct value *
+or1k_frame_prev_register (struct frame_info *this_frame,
+ void **prologue_cache,
+ int regnum)
+{
+ struct trad_frame_cache *info = or1k_frame_cache (this_frame,
+ prologue_cache);
+
+ return trad_frame_get_register (info, this_frame, regnum);
+
+} /* or1k_frame_prev_register() */
+
+
+/* -------------------------------------------------------------------------- */
+/*!Structure defining the OR1K frame unwind functions
+
+ Must be global (to this file), since referred to by multiple functions.
+
+ Since we are the fallback unwinder, we use the default frame sniffer, which
+ always accepts the frame
+
+ This applies to NORMAL frames only. We provide the following functions.
+ - to give the ID of THIS frame
+ - to give the details of a register in PREVIOUS frame
+ - a frame sniffer. */
+/* -------------------------------------------------------------------------- */
+static const struct frame_unwind or1k_frame_unwind = {
+ .type = NORMAL_FRAME,
+ .stop_reason = default_frame_unwind_stop_reason,
+ .this_id = or1k_frame_this_id,
+ .prev_register = or1k_frame_prev_register,
+ .unwind_data = NULL,
+ .sniffer = default_frame_sniffer,
+ .dealloc_cache = NULL,
+ .prev_arch = NULL
+};
+
+
+#if 0
+/*----------------------------------------------------------------------------*/
+/*!Return the base address of the frame
+
+ The implementations has changed since GDB 6.8, since we are now provided
+ with the address of THIS frame, rather than the NEXT frame.
+
+ For the OR1K, the base address is the frame pointer
+
+ @param[in] this_frame The current stack frame.
+ @param[in] prologue_cache Any cached prologue for THIS function.
+
+ @return The frame base address */
+/*---------------------------------------------------------------------------*/
+
+static CORE_ADDR
+or1k_frame_base_address (struct frame_info *this_frame,
+ void **prologue_cache)
+{
+ return (CORE_ADDR) get_frame_register_unsigned (this_frame, OR1K_FP_REGNUM);
+
+} /* or1k_frame_base_address() */
+
+
+/* -------------------------------------------------------------------------- */
+/*!Identify our frame base sniffer functions
+
+ This function just identifies our family of frame sniffing functions.
+
+ @param[in] this_frame The frame of THIS function. Not used here.
+
+ @return A pointer to a struct identifying the frame base sniffing
+ functions. */
+/* -------------------------------------------------------------------------- */
+static const struct frame_base *
+or1k_frame_base_sniffer (struct frame_info *this_frame)
+{
+ /* Structure defining how the frame base is to be identified. */
+ static const struct frame_base or1k_frame_base =
+ {
+ .unwind = &or1k_frame_unwind,
+ .this_base = or1k_frame_base_address,
+ .this_locals = or1k_frame_base_address,
+ .this_args = or1k_frame_base_address
+ };
+
+ return &or1k_frame_base;
+
+} /* or1k_frame_base_sniffer () */
+#endif
+
+/* Iterate over core file register note sections. */
+static void
+or1k_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
+{
+ // TODO: Do we need to put something here? (wallento)
+}
+
+/* -------------------------------------------------------------------------- */
+/*!Create a register group based on a group name.
+
+ We create a group only if group_name is not already a register group name.
+
+ @param[in] gdbarch The GDB architecture we are using.
+ @param[in] group_name Name of the new register group.
+
+ @return 1 if the group has been created, 0 otherwise. */
+/* -------------------------------------------------------------------------- */
+static int
+create_register_group (struct gdbarch *gdbarch, const char *group_name)
+{
+ struct reggroup *group;
+ static int first = 1;
+ int group_exist = 0;
+
+ if (group_name == NULL)
+ return 0;
+
+ if (!first)
+ {
+ for (group = reggroup_next (gdbarch, NULL);
+ group != NULL; group = reggroup_next (gdbarch, group))
+ {
+ if (strcmp (group_name, reggroup_name (group)) == 0)
+ group_exist = 1;
+ }
+
+ if (!group_exist)
+ {
+ /* If the group doesn't exist, create it */
+ reggroup_add (gdbarch, reggroup_new (group_name, USER_REGGROUP));
+ return 1;
+ }
+ }
+ else
+ {
+ /* reggroup_next cannot be called during architecture. However,
+ * a first call to reggroup_add execute reggroups_init and then
+ * reggroup_next can be use. We assume the first group name we
+ * create does not exist.
+ */
+ reggroup_add (gdbarch, reggroup_new (group_name, USER_REGGROUP));
+ first = 0;
+ }
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/*!Register all reg found in a feature section.
+
+ Register all reg found in a feature section and create a group for each
+ new register group name found in the tdesc file.
+
+ @param[in] feature The feature to search for registers.
+ @param[out] tdesc_data The target descriptor data to fill.
+ @param[out] reg_index Register index in tdesc_data.
+ @param[in] gdbarch The GDB architecture we are using.
+
+ @return Number of registers found, -1 if error. */
+/* -------------------------------------------------------------------------- */
+static int
+get_feature_registers (const struct tdesc_feature *feature,
+ struct tdesc_arch_data *tdesc_data, int *reg_index,
+ struct gdbarch *gdbarch)
+{
+ int valid_p;
+ int i;
+ char *name;
+ char *group_name;
+
+ if (feature)
+ {
+ valid_p = 1;
+ i = 0;
+ while (1)
+ {
+ name = tdesc_find_register_name (feature, i);
+ if (name)
+ {
+ valid_p &=
+ tdesc_numbered_register (feature, tdesc_data, (*reg_index)++,
+ name);
+ if (valid_p)
+ {
+ group_name = tdesc_find_register_group_name (feature, i);
+ if (group_name)
+ create_register_group (gdbarch, group_name);
+ }
+ i++;
+ }
+ else
+ break;
+ }
+
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return -1;
+ }
+
+ return i;
+
+ }
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/*!Architecture initialization for OpenRISC 1000
+
+ Looks for a candidate architecture in the list of architectures supplied
+ using the info supplied. If none match, create a new architecture.
+
+ @param[in] info Information about the target architecture
+ @param[in] arches The list of currently know architectures
+
+ @return A structure describing the target architecture */
+/* -------------------------------------------------------------------------- */
+static struct gdbarch *
+or1k_gdbarch_init (struct gdbarch_info info,
+ struct gdbarch_list *arches)
+{
+ static struct frame_base or1k_frame_base;
+ struct gdbarch *gdbarch;
+ struct gdbarch_tdep *tdep;
+ const struct bfd_arch_info *binfo;
+ struct tdesc_arch_data *tdesc_data = NULL;
+
+ int i;
+ int reg_index = 0;
+ int retval;
+ int group;
+
+ /* Find a candidate among the list of pre-declared architectures. */
+ arches = gdbarch_list_lookup_by_info (arches, &info);
+ if (NULL != arches)
+ {
+ return arches->gdbarch;
+ }
+
+ /* None found, create a new architecture from the information
+ provided. Can't initialize all the target dependencies until we actually
+ know which target we are talking to, but put in some defaults for now. */
+
+ binfo = info.bfd_arch_info;
+ tdep = XNEW (struct gdbarch_tdep);
+ tdep->num_matchpoints = OR1K_MAX_MATCHPOINTS;
+ tdep->num_gpr_regs = OR1K_MAX_GPR_REGS;
+ tdep->bytes_per_word = binfo->bits_per_word / binfo->bits_per_byte;
+ tdep->bytes_per_address = binfo->bits_per_address / binfo->bits_per_byte;
+ gdbarch = gdbarch_alloc (&info, tdep);
+
+ /* Target data types. */
+ set_gdbarch_short_bit (gdbarch, 16);
+ set_gdbarch_int_bit (gdbarch, 32);
+ set_gdbarch_long_bit (gdbarch, 32);
+ set_gdbarch_long_long_bit (gdbarch, 64);
+ set_gdbarch_float_bit (gdbarch, 32);
+ set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+ set_gdbarch_double_bit (gdbarch, 64);
+ set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+ set_gdbarch_long_double_bit (gdbarch, 64);
+ set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+ set_gdbarch_ptr_bit (gdbarch, binfo->bits_per_address);
+ set_gdbarch_addr_bit (gdbarch, binfo->bits_per_address);
+ set_gdbarch_char_signed (gdbarch, 1);
+
+ /* Information about the target architecture */
+ set_gdbarch_return_value (gdbarch, or1k_return_value);
+ set_gdbarch_breakpoint_kind_from_pc (gdbarch, or1k_breakpoint_kind_from_pc);
+ set_gdbarch_sw_breakpoint_from_kind (gdbarch, or1k_sw_breakpoint_from_kind);
+ set_gdbarch_have_nonsteppable_watchpoint
+ (gdbarch, 1);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_or1k);
+
+ /* Register architecture */
+ set_gdbarch_pseudo_register_read (gdbarch, or1k_pseudo_register_read);
+ set_gdbarch_pseudo_register_write (gdbarch, or1k_pseudo_register_write);
+ set_gdbarch_num_regs (gdbarch, OR1K_NUM_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, OR1K_NUM_PSEUDO_REGS);
+ set_gdbarch_sp_regnum (gdbarch, OR1K_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, OR1K_NPC_REGNUM);
+ set_gdbarch_ps_regnum (gdbarch, OR1K_SR_REGNUM);
+ set_gdbarch_deprecated_fp_regnum (gdbarch, OR1K_FP_REGNUM);
+
+ /* Functions to supply register information */
+ set_gdbarch_register_name (gdbarch, or1k_register_name);
+ set_gdbarch_register_type (gdbarch, or1k_register_type);
+ set_gdbarch_print_registers_info (gdbarch, or1k_registers_info);
+ set_gdbarch_register_reggroup_p (gdbarch, or1k_register_reggroup_p);
+
+ /* Functions to analyse frames */
+ set_gdbarch_skip_prologue (gdbarch, or1k_skip_prologue);
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+ set_gdbarch_frame_align (gdbarch, or1k_frame_align);
+ set_gdbarch_frame_red_zone_size (gdbarch, OR1K_FRAME_RED_ZONE_SIZE);
+
+ /* Functions to access frame data */
+ set_gdbarch_unwind_pc (gdbarch, or1k_unwind_pc);
+ set_gdbarch_unwind_sp (gdbarch, or1k_unwind_sp);
+
+ /* Functions handling dummy frames */
+ set_gdbarch_call_dummy_location (gdbarch, ON_STACK);
+ set_gdbarch_push_dummy_code (gdbarch, or1k_push_dummy_code);
+ set_gdbarch_push_dummy_call (gdbarch, or1k_push_dummy_call);
+ set_gdbarch_dummy_id (gdbarch, or1k_dummy_id);
+
+#if 0
+ /* Set up sniffers for the frame base. Use DWARF debug info if available,
+ otherwise use our own sniffer. */
+ frame_base_append_sniffer (gdbarch, dwarf2_frame_base_sniffer);
+ frame_base_append_sniffer (gdbarch, or1k_frame_base_sniffer);
+#endif
+
+ /* Handle core files */
+ set_gdbarch_iterate_over_regset_sections (gdbarch, or1k_iterate_over_regset_sections);
+
+ /* Frame unwinders. Use DWARF debug info if available, otherwise use our
+ own unwinder. */
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &or1k_frame_unwind);
+
+ /* Get a CGEN CPU descriptor for this architecture. */
+ {
+
+ const char *mach_name = binfo->printable_name;
+ enum cgen_endian endian = (info.byte_order == BFD_ENDIAN_BIG
+ ? CGEN_ENDIAN_BIG
+ : CGEN_ENDIAN_LITTLE);
+
+ tdep->gdb_cgen_cpu_desc = or1k_cgen_cpu_open (CGEN_CPU_OPEN_BFDMACH, mach_name,
+ CGEN_CPU_OPEN_ENDIAN, endian,
+ CGEN_CPU_OPEN_END);
+
+ or1k_cgen_init_asm (tdep->gdb_cgen_cpu_desc);
+ }
+
+ /* If this mach as delay slot */
+ if (binfo->mach == bfd_mach_or1k)
+ {
+ set_gdbarch_single_step_through_delay
+ (gdbarch, or1k_single_step_through_delay);
+ }
+
+ /* Check any target description for validity. */
+ if (tdesc_has_registers (info.target_desc))
+ {
+
+ const struct tdesc_feature *feature;
+ int total_regs = 0;
+ int nb_features;
+ char feature_name[30];
+
+ tdesc_data = tdesc_data_alloc ();
+
+ /* OpenRisc architecture manual define a maximum of 32 registers groups */
+ for (group = 0; group < 32; group++)
+ {
+
+ sprintf (feature_name, "org.gnu.gdb.or1k.group%d", group);
+ feature = tdesc_find_feature (info.target_desc, feature_name);
+
+ retval =
+ get_feature_registers (feature, tdesc_data, ®_index, gdbarch);
+
+ if (retval < 0)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+ else
+ {
+ total_regs += retval;
+ if (retval && gdbarch_debug)
+ fprintf_unfiltered (gdb_stdout,
+ "Found %4d registers in feature %s\n",
+ retval, feature_name);
+ }
+ }
+ if (gdbarch_debug)
+ fprintf_unfiltered (gdb_stdout,
+ "Found %4d registers in the tdesc file\n",
+ total_regs);
+
+ if (!total_regs)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+ }
+
+ if (tdesc_data)
+ {
+ tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+
+ /* Override the normal target description methods to handle our
+ dual real and pseudo registers. */
+ set_gdbarch_register_name (gdbarch, or1k_register_name);
+ set_gdbarch_register_reggroup_p (gdbarch, or1k_register_reggroup_p);
+
+ set_gdbarch_register_name (gdbarch, or1k_register_name);
+ set_gdbarch_sp_regnum (gdbarch, OR1K_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, OR1K_NPC_REGNUM);
+ set_gdbarch_num_pseudo_regs (gdbarch, OR1K_NUM_PSEUDO_REGS);
+ }
+
+ return gdbarch;
+
+} /* or1k_gdbarch_init() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Dump the target specific data for this architecture
+
+ @param[in] gdbarch The architecture of interest
+ @param[in] file Where to dump the data */
+/*---------------------------------------------------------------------------*/
+
+static void
+or1k_dump_tdep (struct gdbarch *gdbarch,
+ struct ui_file *file)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (NULL == tdep)
+ {
+ return; /* Nothing to report */
+ }
+
+ fprintf_unfiltered (file, "or1k_dump_tdep: %d matchpoints available\n",
+ tdep->num_matchpoints);
+ fprintf_unfiltered (file, "or1k_dump_tdep: %d general purpose registers\n",
+ tdep->num_gpr_regs);
+ fprintf_unfiltered (file, "or1k_dump_tdep: %d bytes per word\n",
+ tdep->bytes_per_word);
+ fprintf_unfiltered (file, "or1k_dump_tdep: %d bytes per address\n",
+ tdep->bytes_per_address);
+
+} /* or1k_dump_tdep() */
+
+
+\f
+/* Functions to add extra commands to GDB */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Returns a special purpose register group name
+
+ @param[in] group The SPR group number
+
+ @return The SPR name (pointer to the name argument) */
+/*---------------------------------------------------------------------------*/
+
+static const char *
+or1k_spr_group_name (int group)
+{
+ static const char *or1k_group_names[OR1K_NUM_SPGS] =
+ {
+ "SYS",
+ "DMMU",
+ "IMMU",
+ "DCACHE",
+ "ICACHE",
+ "MAC",
+ "DEBUG",
+ "PERF",
+ "POWER",
+ "PIC",
+ "TIMER",
+ "FPU"
+ };
+
+ if ((0 <= group) && (group < OR1K_NUM_SPGS))
+ {
+ return or1k_group_names[group];
+ }
+ else
+ {
+ return "";
+ }
+} /* or1k_spr_group_name() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Returns a special purpose register name
+
+ @param[in] group The SPR group
+ @param[in] index The index within the SPR group
+ @param[out] name Array to put the name in
+
+ @return The SPR name (pointer to the name argument) */
+/*---------------------------------------------------------------------------*/
+
+static char *
+or1k_spr_register_name (int group,
+ int index,
+ char *name)
+{
+ char di;
+
+ switch (group)
+ {
+
+ case OR1K_SPG_SYS:
+ /* 1:1 names */
+ switch (index)
+ {
+ case OR1K_SPG_SYS_VR: sprintf (name, "VR" ); return name;
+ case OR1K_SPG_SYS_UPR: sprintf (name, "UPR" ); return name;
+ case OR1K_SPG_SYS_CPUCFGR: sprintf (name, "CPUCFGR" ); return name;
+ case OR1K_SPG_SYS_DMMUCFGR: sprintf (name, "DMMUCFGR"); return name;
+ case OR1K_SPG_SYS_IMMUCFGR: sprintf (name, "IMMUCFGR"); return name;
+ case OR1K_SPG_SYS_DCCFGR: sprintf (name, "DCCFGR" ); return name;
+ case OR1K_SPG_SYS_ICCFGR: sprintf (name, "ICCFGR" ); return name;
+ case OR1K_SPG_SYS_DCFGR: sprintf (name, "DCFGR" ); return name;
+ case OR1K_SPG_SYS_PCCFGR: sprintf (name, "PCCFGR" ); return name;
+ case OR1K_SPG_SYS_NPC: sprintf (name, "NPC" ); return name;
+ case OR1K_SPG_SYS_SR: sprintf (name, "SR" ); return name;
+ case OR1K_SPG_SYS_PPC: sprintf (name, "PPC" ); return name;
+ case OR1K_SPG_SYS_FPCSR: sprintf (name, "FPCSR" ); return name;
+ }
+
+ /* Exception PC regs */
+ if((OR1K_SPG_SYS_EPCR <= index) &&
+ (index <= OR1K_SPG_SYS_EPCR_END))
+ {
+ sprintf (name, "EPCR%d", index - OR1K_SPG_SYS_EPCR);
+ return name;
+ }
+
+ /* Exception EA regs */
+ if((OR1K_SPG_SYS_EEAR <= index) &&
+ (index <= OR1K_SPG_SYS_EEAR_END))
+ {
+ sprintf (name, "EEAR%d", index - OR1K_SPG_SYS_EEAR);
+ return name;
+ }
+
+ /* Exception SR regs */
+ if((OR1K_SPG_SYS_ESR <= index) &&
+ (index <= OR1K_SPG_SYS_ESR_END))
+ {
+ sprintf (name, "ESR%d", index - OR1K_SPG_SYS_ESR);
+ return name;
+ }
+
+ /* GPRs */
+ if((OR1K_SPG_SYS_GPR <= index) &&
+ (index <= OR1K_SPG_SYS_GPR_END))
+ {
+ sprintf (name, "GPR%d", index - OR1K_SPG_SYS_GPR);
+ return name;
+ }
+
+ break;
+
+ case OR1K_SPG_DMMU:
+ case OR1K_SPG_IMMU:
+ /* MMU registers. Use DMMU constants throughout, but these are identical
+ to the corresponding IMMU constants */
+ di = OR1K_SPG_DMMU == group ? 'D' : 'I';
+
+ /* 1:1 names */
+ switch (index)
+ {
+ case OR1K_SPG_DMMU_DMMUCR:
+ sprintf (name, "%cMMUCR", di); return name;
+ case OR1K_SPG_DMMU_DMMUPR:
+ sprintf (name, "%cMMUPR", di); return name;
+ case OR1K_SPG_DMMU_DTLBEIR:
+ sprintf (name, "%cTLBEIR", di); return name;
+ }
+
+ /* ATB Match registers */
+ if((OR1K_SPG_DMMU_DATBMR <= index) &&
+ (index <= OR1K_SPG_DMMU_DATBMR_END))
+ {
+ sprintf (name, "%cATBMR%d", di, index - OR1K_SPG_DMMU_DATBMR);
+ return name;
+ }
+
+ /* ATB Translate registers */
+ if((OR1K_SPG_DMMU_DATBTR <= index) &&
+ (index <= OR1K_SPG_DMMU_DATBTR_END))
+ {
+ sprintf (name, "%cATBTR%d", di, index - OR1K_SPG_DMMU_DATBTR);
+ return name;
+ }
+
+ /* TLB Way 1 Match registers */
+ if((OR1K_SPG_DMMU_DTLBW1MR <= index) &&
+ (index <= OR1K_SPG_DMMU_DTLBW1MR_END))
+ {
+ sprintf (name, "%cTLBW1MR%d", di, index - OR1K_SPG_DMMU_DTLBW1MR);
+ return name;
+ }
+
+ /* TLB Way 1 Translate registers */
+ if((OR1K_SPG_DMMU_DTLBW1TR <= index) &&
+ (index <= OR1K_SPG_DMMU_DTLBW1TR_END))
+ {
+ sprintf (name, "%cTLBW1TR%d", di, index - OR1K_SPG_DMMU_DTLBW1TR);
+ return name;
+ }
+
+ /* TLB Way 2 Match registers */
+ if((OR1K_SPG_DMMU_DTLBW2MR <= index) &&
+ (index <= OR1K_SPG_DMMU_DTLBW2MR_END))
+ {
+ sprintf (name, "%cTLBW2MR%d", di, index - OR1K_SPG_DMMU_DTLBW2MR);
+ return name;
+ }
+
+ /* TLB Way 2 Translate registers */
+ if((OR1K_SPG_DMMU_DTLBW2TR <= index) &&
+ (index <= OR1K_SPG_DMMU_DTLBW2TR_END))
+ {
+ sprintf (name, "%cTLBW2TR%d", di, index - OR1K_SPG_DMMU_DTLBW2TR);
+ return name;
+ }
+
+ /* TLB Way 3 Match registers */
+ if((OR1K_SPG_DMMU_DTLBW3MR <= index) &&
+ (index <= OR1K_SPG_DMMU_DTLBW3MR_END))
+ {
+ sprintf (name, "%cTLBW3MR%d", di, index - OR1K_SPG_DMMU_DTLBW3MR);
+ return name;
+ }
+
+ /* TLB Way 3 Translate registers */
+ if((OR1K_SPG_DMMU_DTLBW3TR <= index) &&
+ (index <= OR1K_SPG_DMMU_DTLBW3TR_END))
+ {
+ sprintf (name, "%cTLBW3TR%d", di, index - OR1K_SPG_DMMU_DTLBW3TR);
+ return name;
+ }
+
+ break;
+
+ case OR1K_SPG_DC:
+ /* Data cache registers. These do not have an exact correspondence with
+ their instruction cache counterparts, so must be done separately. */
+
+ /* 1:1 names */
+ switch (index)
+ {
+ case OR1K_SPG_DC_DCCR: sprintf (name, "DCCR" ); return name;
+ case OR1K_SPG_DC_DCBPR: sprintf (name, "DCBPR"); return name;
+ case OR1K_SPG_DC_DCBFR: sprintf (name, "DCBFR"); return name;
+ case OR1K_SPG_DC_DCBIR: sprintf (name, "DCBIR"); return name;
+ case OR1K_SPG_DC_DCBWR: sprintf (name, "DCBWR"); return name;
+ case OR1K_SPG_DC_DCBLR: sprintf (name, "DCBLR"); return name;
+ }
+
+ break;
+
+ case OR1K_SPG_IC:
+ /* Instruction cache registers */
+
+ /* 1:1 names */
+ switch (index)
+ {
+ case OR1K_SPG_IC_ICCR: sprintf (name, "ICCR" ); return name;
+ case OR1K_SPG_IC_ICBPR: sprintf (name, "ICBPR"); return name;
+ case OR1K_SPG_IC_ICBIR: sprintf (name, "ICBIR"); return name;
+ case OR1K_SPG_IC_ICBLR: sprintf (name, "ICBLR"); return name;
+ }
+
+ break;
+
+ case OR1K_SPG_MAC:
+ /* MAC registers */
+
+ /* 1:1 names */
+ switch (index)
+ {
+ case OR1K_SPG_MAC_MACLO: sprintf (name, "MACLO"); return name;
+ case OR1K_SPG_MAC_MACHI: sprintf (name, "MACHI"); return name;
+ }
+
+ break;
+
+ case OR1K_SPG_DEBUG:
+ /* Debug registers */
+
+ /* Debug Value registers */
+ if((OR1K_SPG_DEBUG_DVR <= index) &&
+ (index <= OR1K_SPG_DEBUG_DVR_END))
+ {
+ sprintf (name, "DVR%d", index - OR1K_SPG_DEBUG_DVR);
+ return name;
+ }
+
+ /* Debug Control registers */
+ if((OR1K_SPG_DEBUG_DCR <= index) &&
+ (index <= OR1K_SPG_DEBUG_DCR_END))
+ {
+ sprintf (name, "DCR%d", index - OR1K_SPG_DEBUG_DCR);
+ return name;
+ }
+
+ /* 1:1 names */
+ switch (index)
+ {
+ case OR1K_SPG_DEBUG_DMR1: sprintf (name, "DMR1" ); return name;
+ case OR1K_SPG_DEBUG_DMR2: sprintf (name, "DMR2" ); return name;
+ case OR1K_SPG_DEBUG_DCWR0: sprintf (name, "DCWR0"); return name;
+ case OR1K_SPG_DEBUG_DCWR1: sprintf (name, "DCWR1"); return name;
+ case OR1K_SPG_DEBUG_DSR: sprintf (name, "DSR" ); return name;
+ case OR1K_SPG_DEBUG_DRR: sprintf (name, "DRR" ); return name;
+ }
+
+ break;
+
+ case OR1K_SPG_PC:
+ /* Performance Counter registers */
+
+ /* Performance Counters Count registers */
+ if((OR1K_SPG_PC_PCCR <= index) &&
+ (index <= OR1K_SPG_PC_PCCR_END))
+ {
+ sprintf (name, "PCCR%d", index - OR1K_SPG_PC_PCCR);
+ return name;
+ }
+
+ /* Performance Counters Mode registers */
+ if((OR1K_SPG_PC_PCMR <= index) &&
+ (index <= OR1K_SPG_PC_PCMR_END))
+ {
+ sprintf (name, "PCMR%d", index - OR1K_SPG_PC_PCMR);
+ return name;
+ }
+
+ break;
+
+ case OR1K_SPG_PM:
+ /* Power Management registers */
+
+ /* 1:1 names */
+ switch (index)
+ {
+ case OR1K_SPG_PM_PMR: sprintf (name, "PMR"); return name;
+ }
+
+ break;
+
+ case OR1K_SPG_PIC:
+ /* Programmable Interrupt Controller registers */
+
+ /* 1:1 names */
+ switch (index)
+ {
+ case OR1K_SPG_PIC_PICMR: sprintf (name, "PICMR"); return name;
+ case OR1K_SPG_PIC_PICSR: sprintf (name, "PICSR"); return name;
+ }
+
+ break;
+
+ case OR1K_SPG_TT:
+ /* Tick Timer registers */
+
+ /* 1:1 names */
+ switch (index)
+ {
+ case OR1K_SPG_TT_TTMR: sprintf (name, "TTMR"); return name;
+ case OR1K_SPG_TT_TTCR: sprintf (name, "TTCR"); return name;
+ }
+
+ break;
+
+ case OR1K_SPG_FPU:
+
+ break;
+ }
+
+ /* Not a recognized register */
+ strcpy (name, "");
+ return name;
+
+} /* or1k_spr_register_name() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Get SPR group number from a name
+
+ @param[in] group_name SPR register group
+
+ @return The index, or negative if no match. */
+/*----------------------------------------------------------------------------*/
+
+static int
+or1k_groupnum_from_name (char *group_name)
+{
+ int group;
+
+ for (group = 0; group < OR1K_NUM_SPGS; group++)
+ {
+ if (0 == strcasecmp (group_name, or1k_spr_group_name (group)))
+ {
+ return group;
+ }
+ }
+
+ return -1;
+
+} /* or1k_groupnum_from_name() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Get register index in special purpose register group from name
+
+ The name may either be SPR<group_num>_<index> or a known unique name. In
+ either case the group number must match the supplied group number.
+
+ @param[in] group SPR register group
+ @param[in] name Register name
+
+ @return The index, or negative if no match. */
+/*----------------------------------------------------------------------------*/
+
+static int
+or1k_regnum_from_name (int group,
+ char *name)
+{
+ /* Last valid register in each group. */
+ static const int or1k_spr_group_last[OR1K_NUM_SPGS] =
+ {
+ OR1K_SPG_SYS_LAST,
+ OR1K_SPG_DMMU_LAST,
+ OR1K_SPG_IMMU_LAST,
+ OR1K_SPG_DC_LAST,
+ OR1K_SPG_IC_LAST,
+ OR1K_SPG_MAC_LAST,
+ OR1K_SPG_DEBUG_LAST,
+ OR1K_SPG_PC_LAST,
+ OR1K_SPG_PM_LAST,
+ OR1K_SPG_PIC_LAST,
+ OR1K_SPG_TT_LAST,
+ OR1K_SPG_FPU_LAST
+ };
+
+ int i;
+ char spr_name[32];
+
+ if (0 == strcasecmp (name, "SPR"))
+ {
+ char *ptr_c;
+
+ /* Skip SPR */
+ name += 3;
+
+ /* Get group number */
+ i = (int) strtoul (name, &ptr_c, 10);
+ if (*ptr_c != '_' || i != group)
+ {
+ return -1;
+ }
+
+ /* Get index */
+ ptr_c++;
+ i = (int) strtoul (name, &ptr_c, 10);
+ if (*ptr_c)
+ {
+ return -1;
+ }
+ else
+ {
+ return i;
+ }
+ }
+
+ /* Look for a "known" name in this group */
+ for (i = 0; i <= or1k_spr_group_last[group]; i++)
+ {
+ char *s = or1k_spr_register_name (group, i, spr_name);
+
+ if (0 == strcasecmp (name, s))
+ {
+ return i;
+ }
+ }
+
+ /* Failure */
+ return -1;
+
+} /* or1k_regnum_from_name() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Get the next token from a string
+
+ I can't believe there isn't a library argument for this, but strtok is
+ deprecated.
+
+ Take a string and find the start of the next token and its length. A token
+ is anything containing non-blank characters.
+
+ @param[in] str The string to look at (may be NULL).
+ @param[out] tok Pointer to the start of the token within str. May be NULL
+ if this result is not wanted (e.g. just the length is
+ wanted. If no token is found will be the NULL char at the
+ end of the string, if the original str was NULL, this will
+ be NULL.
+
+ @return The length of the token found */
+/*----------------------------------------------------------------------------*/
+
+static int
+or1k_tokenize (char *str,
+ char **tok)
+{
+ char *ptr;
+ int len;
+
+ /* Deal with NULL argument */
+ if (NULL == str)
+ {
+ if (NULL != tok)
+ {
+ *tok = NULL;
+ }
+ return 0;
+ }
+
+ /* Find the start */
+ for (ptr = str; ISBLANK (*ptr) ; ptr++)
+ {
+ continue;
+ }
+
+ /* Return the start pointer if requested */
+ if (NULL != tok)
+ {
+ *tok = ptr;
+ }
+
+ /* Find the end and put in EOS */
+ for (len = 0; ('\0' != ptr[len]) && (!ISBLANK (ptr[len])); len++)
+ {
+ continue;
+ }
+
+ return len;
+
+} /* or1k_tokenize() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Parses args for spr commands
+
+ Determines the special purpose register (SPR) name and puts result into
+ group and index
+
+ Syntax is:
+
+ @verbatim
+ <spr_args> -> <group_ref> | <reg_name>
+ <group_ref> -> <group_id> <index>
+ <group_id> -> <group_num> | <group_name>
+ @endverbatim
+
+ Where the indices/names have to be valid.
+
+ So to parse, we look for 1 or 2 args. If 1 it must be a unique register
+ name. If 2, the first must be a group number or name and the second an
+ index within that group.
+
+ Also responsible for providing diagnostics if the arguments do not match.
+
+ Rewritten for GDB 6.8 to use the new UI calls and remove assorted
+ bugs. Syntax also slightly restricted to be more comprehensible.
+
+ @param[in] arg_str The argument string
+ @param[out] group The group this SPR belongs in, or -1 to indicate
+ failure
+ @param[out] index Index of the register within the group, or -1 to
+ indicate the whole group
+ @param[in] is_set 1 (true) if we are called from the "spr" command (so
+ there is an extra arg) rather than the "info spr"
+ command. Needed to distinguish between the case where
+ info is sought from a register specified as group and
+ index and setting a uniquely identified register to a
+ value.
+
+ @return A pointer to any remaining args */
+/*---------------------------------------------------------------------------*/
+
+static char *
+or1k_parse_spr_params (char *arg_str,
+ int *group,
+ int *index,
+ int is_set)
+{
+ struct {
+ char *str;
+ int len;
+ unsigned long int val;
+ int is_num;
+ } arg[3] = {
+ {
+ .str = NULL,
+ .len = 0,
+ .val = 0,
+ .is_num = 0,
+ },
+ {
+ .str = NULL,
+ .len = 0,
+ .val = 0,
+ .is_num = 0,
+ },
+ {
+ .str = NULL,
+ .len = 0,
+ .val = 0,
+ .is_num = 0,
+ }
+ };
+
+ int num_args;
+ char *trailer = arg_str;
+ char *tmp_str;
+ int i;
+ struct ui_out *uiout = current_uiout;
+ char spr_name[32];
+
+ /* Break out the arguments. Note that the strings are NOT null terminated
+ (we don't want to change arg_str), so we must rely on len. The stroul
+ call will still work, since there is always a non-digit char (possibly EOS)
+ after the last digit. */
+ if (NULL == arg_str)
+ {
+ num_args = 0;
+ }
+ else
+ {
+ for (num_args = 0; num_args < 3; num_args++)
+ {
+ arg[num_args].len = or1k_tokenize (trailer, &(arg[num_args].str));
+ trailer = arg[num_args].str + arg[num_args].len;
+
+ if (0 == arg[num_args].len)
+ {
+ break;
+ }
+ }
+ }
+
+ /* Patch nulls into the arg strings and see about values. Couldn't do this
+ earlier, since we needed the next char clean to check later args. This
+ means advancing trailer, UNLESS it was already at EOS */
+
+ if((NULL != arg_str) && ('\0' != *trailer))
+ {
+ trailer++;
+ }
+
+ for (i = 0; i < num_args; i++)
+ {
+ (arg[i].str)[arg[i].len] = '\0';
+ errno = 0;
+ arg[i].val = strtoul (arg[i].str, &tmp_str, 0);
+ arg[i].is_num = (0 == errno) && ('\0' == *tmp_str);
+ }
+
+ /* Deal with the case where we are setting a register, so the final argument
+ should be disregarded (it is the trailer). Do this anyway if we get a
+ third argument */
+ if ((is_set & (num_args > 0)) || (num_args > 2))
+ {
+ trailer = arg[num_args - 1].str;
+ num_args--;
+ }
+
+ /* Deal with different numbers of args */
+
+ switch (num_args)
+ {
+
+ case 0:
+ ui_out_message (uiout, 0,
+ "Usage: <command> <register> |\n"
+ " <command> <group> |\n"
+ " <command> <group> <index>\n"
+ "Valid groups are:\n");
+ for (i = 0; i < OR1K_NUM_SPGS; i++)
+ {
+ ui_out_field_string (uiout, NULL, or1k_spr_group_name (i));
+ ui_out_spaces (uiout, 1);
+ ui_out_wrap_hint (uiout, NULL);
+ }
+ ui_out_field_string (uiout, NULL, "\n");
+
+ *index = -1;
+ return trailer;
+
+ case 1:
+ /* See if it is a numeric group */
+ if (arg[0].is_num)
+ {
+ if (arg[0].val < OR1K_NUM_SPGS)
+ {
+ *group = arg[0].val;
+ *index = -1;
+ return trailer;
+ }
+ else
+ {
+ ui_out_message (uiout, 0,
+ "Group index should be in the range 0 - %d\n",
+ OR1K_NUM_SPGS);
+ *group = -1;
+ *index = -1;
+ return trailer;
+ }
+ }
+
+ /* Is is it a group name? */
+ *group = or1k_groupnum_from_name (arg[0].str);
+ if (*group >= 0)
+ {
+ *index = -1;
+ return trailer;
+ }
+
+ /* See if it is a valid register name in any group */
+ for (*group = 0; *group < OR1K_NUM_SPGS; (*group)++)
+ {
+ *index = or1k_regnum_from_name (*group, arg[0].str);
+
+ if (*index >= 0)
+ {
+ return trailer;
+ }
+ }
+
+ /* Couldn't find it - print out a rude message */
+ ui_out_message (uiout, 0,
+ "Group or register name not recognized.\n"
+ "Valid groups are:\n");
+ for (i = 0; i < OR1K_NUM_SPGS; i++)
+ {
+ ui_out_field_string (uiout, NULL, or1k_spr_group_name (i));
+ ui_out_spaces (uiout, 1);
+ ui_out_wrap_hint (uiout, NULL);
+ }
+ ui_out_field_string (uiout, NULL, "\n");
+
+ *group = -1;
+ *index = -1;
+ return trailer;
+
+ case 2:
+ /* See if first arg is a numeric group */
+ if (arg[0].is_num)
+ {
+ if (arg[0].val < OR1K_NUM_SPGS)
+ {
+ *group = arg[0].val;
+ *index = -1;
+ }
+ else
+ {
+ ui_out_message (uiout, 0,
+ "Group index should be in the range 0 - %d\n",
+ OR1K_NUM_SPGS - 1);
+ *group = -1;
+ *index = -1;
+ return trailer;
+ }
+ }
+ else
+ {
+ /* Is is it a group name? */
+ *group = or1k_groupnum_from_name (arg[0].str);
+ if (*group >= 0)
+ {
+ *index = -1;
+ }
+ else
+ {
+ ui_out_message (uiout, 0,
+ "Group name not recognized.\n"
+ "Valid groups are:\n");
+ for (i = 0; i < OR1K_NUM_SPGS; i++)
+ {
+ ui_out_field_string (uiout, NULL, or1k_spr_group_name (i));
+ ui_out_spaces (uiout, 1);
+ ui_out_wrap_hint (uiout, NULL);
+ }
+ ui_out_field_string (uiout, NULL, "\n");
+
+ *group = -1;
+ *index = -1;
+ return trailer;
+ }
+ }
+
+ /* Is second arg an index or name? */
+ if (arg[1].is_num)
+ {
+ if (arg[1].val < OR1K_SPG_SIZE)
+ {
+ /* Check this really is a register */
+ if (0 != strlen (or1k_spr_register_name (*group, arg[1].val,
+ spr_name)))
+ {
+ *index = arg[1].val;
+ return trailer;
+ }
+ else
+ {
+ ui_out_message (uiout, 0,
+ "No valid register at that index in group\n");
+ *group = -1;
+ *index = -1;
+ return trailer;
+ }
+ }
+ else
+ {
+ ui_out_message (uiout, 0,
+ "Register index should be in the range 0 - %d\n",
+ OR1K_SPG_SIZE - 1);
+ *group = -1;
+ *index = -1;
+ return trailer;
+ }
+ }
+
+ /* Must be a name */
+ *index = or1k_regnum_from_name (*group, arg[1].str);
+
+ if (*index >= 0)
+ {
+ return trailer;
+ }
+
+ /* Couldn't find it - print out a rude message */
+ ui_out_message (uiout, 0, "Register name not recognized in group.\n");
+ *group = -1;
+ *index = -1;
+ return trailer;
+
+ default:
+ /* Anything else is an error */
+ ui_out_message (uiout, 0, "Unable to parse arguments\n");
+ *group = -1;
+ *index = -1;
+ return trailer;
+ }
+} /* or1k_parse_spr_params() */
+
+
+/*---------------------------------------------------------------------------*/
+/*!Read a special purpose register from the target
+
+ This has to be done using the target remote command "readspr"
+
+ @param[in] regnum The register to read
+
+ @return The value read */
+/*---------------------------------------------------------------------------*/
+
+static ULONGEST
+or1k_read_spr (unsigned int regnum)
+{
+ struct ui_file *uibuf = mem_fileopen ();
+ char cmd[sizeof ("readspr ffff")];
+ unsigned long int data;
+ char *res;
+ long int len;
+
+ /* Create the command string and pass it to target remote command function */
+ sprintf (cmd, "readspr %4x", regnum);
+ target_rcmd (cmd, uibuf);
+
+ /* Get the output for the UI file as a string */
+ res = ui_file_xstrdup (uibuf, &len);
+ sscanf (res, "%lx", &data);
+
+ /* Tidy up */
+ xfree (res);
+ ui_file_delete (uibuf);
+
+ return (ULONGEST)data;
+
+} /* or1k_read_spr() */
+
+
+/*---------------------------------------------------------------------------*/
+/*!Write a special purpose register on the target
+
+ This has to be done using the target remote command "writespr"
+
+ Since the SPRs may map to GPR's or the other GDB register (PPC, NPC, SR),
+ any register cache is flushed.
+
+ @param[in] regnum The register to write
+ @param[in] data The value to write */
+/*---------------------------------------------------------------------------*/
+
+static void
+or1k_write_spr (unsigned int regnum,
+ ULONGEST data)
+{
+ struct ui_file *uibuf = mem_fileopen ();
+ char cmd[sizeof ("writespr ffff ffffffff")];
+ char *res;
+ long int len;
+
+ /* Create the command string and pass it to target remote command function */
+ sprintf (cmd, "writespr %4x %8llx", regnum, (long long unsigned int)data);
+ target_rcmd (cmd, uibuf);
+
+ /* Flush the register cache */
+ registers_changed ();
+
+ /* We ignore the result - Rcmd can put out its own error messages. Just
+ tidy up */
+ ui_file_delete (uibuf);
+
+} /* or1k_write_spr() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Show the value of a special purpose register or group
+
+ This is a custom extension to the GDB info command.
+
+ @param[in] args
+ @param[in] from_tty True (1) if GDB is running from a TTY, false (0)
+ otherwise. */
+/*---------------------------------------------------------------------------*/
+
+static void
+or1k_info_spr_command (char *args,
+ int from_tty)
+{
+ int group;
+ int index;
+ struct ui_out *uiout = current_uiout;
+ char spr_name[32];
+
+ or1k_parse_spr_params (args, &group, &index, 0);
+
+ if (group < 0)
+ {
+ return; /* Couldn't parse the args */
+ }
+
+ if (index >= 0)
+ {
+ ULONGEST value = or1k_read_spr (OR1K_SPR (group, index));
+
+ ui_out_field_fmt (uiout, NULL, "%s.%s = SPR%i_%i = %llu (0x%llx)\n",
+ or1k_spr_group_name (group),
+ or1k_spr_register_name (group, index, spr_name), group,
+ index, (long long unsigned int)value, (long long unsigned int)value);
+ }
+ else
+ {
+ /* Print all valid registers in the group */
+ for (index = 0; index < OR1K_SPG_SIZE; index++)
+ {
+ if (0 != strlen (or1k_spr_register_name (group, index, spr_name)))
+ {
+ ULONGEST value = or1k_read_spr (OR1K_SPR (group, index));
+
+ ui_out_field_fmt (uiout, NULL,
+ "%s.%s = SPR%i_%i = %llu (0x%llx)\n",
+ or1k_spr_group_name (group),
+ or1k_spr_register_name (group, index, spr_name),
+ group, index, (long long unsigned int)value, (long long unsigned int)value);
+ }
+ }
+ }
+} /* or1k_info_spr_command() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Set a special purpose register
+
+ This is a custom command added to GDB.
+
+ @param[in] args
+ @param[in] from_tty True (1) if GDB is running from a TTY, false (0)
+ otherwise. */
+/*---------------------------------------------------------------------------*/
+
+static void
+or1k_spr_command (char *args,
+ int from_tty)
+{
+ int group;
+ int index;
+ char *tmp_str;
+ char *nargs = or1k_parse_spr_params (args, &group, &index, 1);
+ struct ui_out *uiout = current_uiout;
+ ULONGEST old_val;
+ ULONGEST new_val;
+
+ char spr_name[32];
+
+ /* Do we have a valid register spec? */
+ if (index < 0)
+ {
+ return; /* Parser will have printed the error message */
+ }
+
+ /* Do we have a value to set? */
+
+ errno = 0;
+ new_val = (ULONGEST)strtoul (nargs, &tmp_str, 0);
+
+ if((0 != errno) || ('\0' != *tmp_str))
+ {
+ ui_out_message (uiout, 0, "Invalid value - register not changed\n");
+ return;
+ }
+
+ old_val = or1k_read_spr (OR1K_SPR (group, index));
+
+ or1k_write_spr (OR1K_SPR (group, index) , new_val);
+
+ ui_out_field_fmt (uiout, NULL,
+ "%s.%s (SPR%i_%i) set to %llu (0x%llx), "
+ "was: %llu (0x%llx)\n",
+ or1k_spr_group_name (group),
+ or1k_spr_register_name (group, index, spr_name) , group,
+ index, (long long unsigned int)new_val, (long long unsigned int)new_val, (long long unsigned int)old_val, (long long unsigned int)old_val);
+
+} /* or1k_spr_command() */
+
+
+/*----------------------------------------------------------------------------*/
+/*!Main entry point for target architecture initialization
+
+ In this version initializes the architecture via
+ registers_gdbarch_init(). Add a command to set and show special purpose
+ registers. */
+/*---------------------------------------------------------------------------*/
+
+extern initialize_file_ftype _initialize_or1k_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_or1k_tdep (void)
+{
+ /* Register this architecture. We should do this for or16 and or64 when
+ they have their BFD defined. */
+ gdbarch_register (bfd_arch_or1k, or1k_gdbarch_init, or1k_dump_tdep);
+
+ /* Tell remote stub that we support XML target description. */
+ register_remote_support_xml ("or1k");
+
+ /* Commands to show and set special purpose registers */
+ add_info ("spr", or1k_info_spr_command,
+ "Show the value of a special purpose register");
+ add_com ("spr", class_support, or1k_spr_command,
+ "Set a special purpose register");
+
+} /* _initialize_or1k_tdep() */
diff --git a/gdb/or1k-tdep.h b/gdb/or1k-tdep.h
new file mode 100644
index 0000000..f0afc8f
--- /dev/null
+++ b/gdb/or1k-tdep.h
@@ -0,0 +1,434 @@
+/* Definitions to target GDB to OpenRISC 1000 32-bit targets.
+
+ Copyright 2001 Free Software Foundation, Inc.
+ Copyright (C) 2008, 2010 Embecosm Limited
+
+ Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
+
+ 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 3 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, see <http://www.gnu.org/licenses/>. */
+
+
+#ifndef OR1K_TDEP__H
+#define OR1K_TDEP__H
+
+#ifndef TARGET_OR1K
+#define TARGET_OR1K
+#endif
+
+/*-----------------------------------------------------------------------------
+ This version for the OpenRISC 1000 architecture is a rewrite by Jeremy
+ Bennett of the old GDB 5.3 interface to make use of gdbarch for GDB 6.8.
+
+ The code tries to follow the GDB coding style. All OR1K specific globals
+ should have names beginning ork1_ or OR1K_.
+
+ Commenting is Doxygen compatible.
+
+ Much has been stripped out. See the files or1k-tdep.c, remote-or1k.c and
+ or1k-jtag.c for details of what has changed.
+ --------------------------------------------------------------------------*/
+
+
+/*! Byte array for the TRAP instruction used for breakpoints */
+#define OR1K_BRK_INSTR_STRUCT {0x21, 0x00, 0x00, 0x01}
+/*! Numeric instruction used for a breakpoint */
+#define OR1K_BRK_INSTR 0x21000001
+
+/*! Numeric instruction used for a l.nop NOP_EXIT */
+#define OR1K_NOP_EXIT 0x15000001
+
+/* Special purpose groups */
+
+#define OR1K_SPG_SIZE_BITS 11
+#define OR1K_SPG_SIZE (1 << OR1K_SPG_SIZE_BITS)
+
+#define OR1K_SPG_SYS 0
+#define OR1K_SPG_DMMU 1
+#define OR1K_SPG_IMMU 2
+#define OR1K_SPG_DC 3
+#define OR1K_SPG_IC 4
+#define OR1K_SPG_MAC 5
+#define OR1K_SPG_DEBUG 6
+#define OR1K_SPG_PC 7
+#define OR1K_SPG_PM 8
+#define OR1K_SPG_PIC 9
+#define OR1K_SPG_TT 10
+#define OR1K_SPG_FPU 11
+
+#define OR1K_NUM_SPGS (OR1K_SPG_FPU + 1)
+
+/* Special register group offsets */
+
+#define OR1K_SPG_SYS_VR 0
+#define OR1K_SPG_SYS_UPR 1
+#define OR1K_SPG_SYS_CPUCFGR 2
+#define OR1K_SPG_SYS_DMMUCFGR 3
+#define OR1K_SPG_SYS_IMMUCFGR 4
+#define OR1K_SPG_SYS_DCCFGR 5
+#define OR1K_SPG_SYS_ICCFGR 6
+#define OR1K_SPG_SYS_DCFGR 7
+#define OR1K_SPG_SYS_PCCFGR 8
+#define OR1K_SPG_SYS_NPC 16
+#define OR1K_SPG_SYS_SR 17
+#define OR1K_SPG_SYS_PPC 18
+#define OR1K_SPG_SYS_FPCSR 20
+#define OR1K_SPG_SYS_EPCR 32
+#define OR1K_SPG_SYS_EPCR_END (OR1K_SPG_SYS_EPCR + 15)
+#define OR1K_SPG_SYS_EEAR 48
+#define OR1K_SPG_SYS_EEAR_END (OR1K_SPG_SYS_EEAR + 15)
+#define OR1K_SPG_SYS_ESR 64
+#define OR1K_SPG_SYS_ESR_END (OR1K_SPG_SYS_ESR + 15)
+#define OR1K_SPG_SYS_GPR 1024
+#define OR1K_SPG_SYS_GPR_END (OR1K_SPG_SYS_GPR + OR1K_MAX_GPR_REGS)
+#define OR1K_SPG_SYS_LAST OR1K_SPG_SYS_GPR_END
+
+#define OR1K_SPG_DMMU_DMMUCR 0
+#define OR1K_SPG_DMMU_DMMUPR 1
+#define OR1K_SPG_DMMU_DTLBEIR 2
+#define OR1K_SPG_DMMU_DATBMR 4
+#define OR1K_SPG_DMMU_DATBMR_END (OR1K_SPG_DMMU_DATBMR + 3)
+#define OR1K_SPG_DMMU_DATBTR 8
+#define OR1K_SPG_DMMU_DATBTR_END (OR1K_SPG_DMMU_DATBTR + 3)
+#define OR1K_SPG_DMMU_DTLBW0MR 512
+#define OR1K_SPG_DMMU_DTLBW0MR_END (OR1K_SPG_DMMU_DTLBW0MR + 127)
+#define OR1K_SPG_DMMU_DTLBW0TR 640
+#define OR1K_SPG_DMMU_DTLBW0TR_END (OR1K_SPG_DMMU_DTLBW0TR + 127)
+#define OR1K_SPG_DMMU_DTLBW1MR 768
+#define OR1K_SPG_DMMU_DTLBW1MR_END (OR1K_SPG_DMMU_DTLBW1MR + 127)
+#define OR1K_SPG_DMMU_DTLBW1TR 896
+#define OR1K_SPG_DMMU_DTLBW1TR_END (OR1K_SPG_DMMU_DTLBW1TR + 127)
+#define OR1K_SPG_DMMU_DTLBW2MR 1024
+#define OR1K_SPG_DMMU_DTLBW2MR_END (OR1K_SPG_DMMU_DTLBW2MR + 127)
+#define OR1K_SPG_DMMU_DTLBW2TR 1152
+#define OR1K_SPG_DMMU_DTLBW2TR_END (OR1K_SPG_DMMU_DTLBW2TR + 127)
+#define OR1K_SPG_DMMU_DTLBW3MR 1280
+#define OR1K_SPG_DMMU_DTLBW3MR_END (OR1K_SPG_DMMU_DTLBW3MR + 127)
+#define OR1K_SPG_DMMU_DTLBW3TR 1408
+#define OR1K_SPG_DMMU_DTLBW3TR_END (OR1K_SPG_DMMU_DTLBW3TR + 127)
+#define OR1K_SPG_DMMU_LAST OR1K_SPG_DMMU_DTLBW3TR_END
+
+#define OR1K_SPG_IMMU_IMMUCR 0
+#define OR1K_SPG_IMMU_IMMUPR 1
+#define OR1K_SPG_IMMU_ITLBEIR 2
+#define OR1K_SPG_IMMU_IATBMR 4
+#define OR1K_SPG_IMMU_IATBMR_END (OR1K_SPG_IMMU_IATBMR + 3)
+#define OR1K_SPG_IMMU_IATBTR 8
+#define OR1K_SPG_IMMU_IATBTR_END (OR1K_SPG_IMMU_IATBTR + 3)
+#define OR1K_SPG_IMMU_ITLBW0MR 512
+#define OR1K_SPG_IMMU_ITLBW0MR_END (OR1K_SPG_IMMU_ITLBW0MR + 127)
+#define OR1K_SPG_IMMU_ITLBW0TR 640
+#define OR1K_SPG_IMMU_ITLBW0TR_END (OR1K_SPG_IMMU_ITLBW0TR + 127)
+#define OR1K_SPG_IMMU_ITLBW1MR 768
+#define OR1K_SPG_IMMU_ITLBW1MR_END (OR1K_SPG_IMMU_ITLBW1MR + 127)
+#define OR1K_SPG_IMMU_ITLBW1TR 896
+#define OR1K_SPG_IMMU_ITLBW1TR_END (OR1K_SPG_IMMU_ITLBW1TR + 127)
+#define OR1K_SPG_IMMU_ITLBW2MR 1024
+#define OR1K_SPG_IMMU_ITLBW2MR_END (OR1K_SPG_IMMU_ITLBW2MR + 127)
+#define OR1K_SPG_IMMU_ITLBW2TR 1152
+#define OR1K_SPG_IMMU_ITLBW2TR_END (OR1K_SPG_IMMU_ITLBW2TR + 127)
+#define OR1K_SPG_IMMU_ITLBW3MR 1280
+#define OR1K_SPG_IMMU_ITLBW3MR_END (OR1K_SPG_IMMU_ITLBW3MR + 127)
+#define OR1K_SPG_IMMU_ITLBW3TR 1408
+#define OR1K_SPG_IMMU_ITLBW3TR_END (OR1K_SPG_IMMU_ITLBW3TR + 127)
+#define OR1K_SPG_IMMU_LAST OR1K_SPG_IMMU_ITLBW3TR_END
+
+#define OR1K_SPG_DC_DCCR 0
+#define OR1K_SPG_DC_DCBPR 1
+#define OR1K_SPG_DC_DCBFR 2
+#define OR1K_SPG_DC_DCBIR 3
+#define OR1K_SPG_DC_DCBWR 4
+#define OR1K_SPG_DC_DCBLR 5
+#define OR1K_SPG_DC_LAST OR1K_SPG_DC_DCBLR
+
+#define OR1K_SPG_IC_ICCR 0
+#define OR1K_SPG_IC_ICBPR 1
+#define OR1K_SPG_IC_ICBIR 2
+#define OR1K_SPG_IC_ICBLR 3
+#define OR1K_SPG_IC_LAST OR1K_SPG_IC_ICBLR
+
+#define OR1K_SPG_MAC_MACLO 1
+#define OR1K_SPG_MAC_MACHI 2
+#define OR1K_SPG_MAC_LAST OR1K_SPG_MAC_MACHI
+
+#define OR1K_SPG_DEBUG_DVR 0
+#define OR1K_SPG_DEBUG_DVR_END (OR1K_SPG_DEBUG_DVR + 7)
+#define OR1K_SPG_DEBUG_DCR 8
+#define OR1K_SPG_DEBUG_DCR_END (OR1K_SPG_DEBUG_DCR + 7)
+#define OR1K_SPG_DEBUG_DMR1 16
+#define OR1K_SPG_DEBUG_DMR2 17
+#define OR1K_SPG_DEBUG_DCWR0 18
+#define OR1K_SPG_DEBUG_DCWR1 19
+#define OR1K_SPG_DEBUG_DSR 20
+#define OR1K_SPG_DEBUG_DRR 21
+#define OR1K_SPG_DEBUG_LAST OR1K_SPG_DEBUG_DRR
+
+#define OR1K_SPG_PC_PCCR 0
+#define OR1K_SPG_PC_PCCR_END (OR1K_SPG_PC_PCCR + 7)
+#define OR1K_SPG_PC_PCMR 8
+#define OR1K_SPG_PC_PCMR_END (OR1K_SPG_PC_PCMR + 7)
+#define OR1K_SPG_PC_LAST OR1K_SPG_PC_PCMR_END
+
+#define OR1K_SPG_PM_PMR 0
+#define OR1K_SPG_PM_LAST OR1K_SPG_PM_PMR
+
+#define OR1K_SPG_PIC_PICMR 0
+#define OR1K_SPG_PIC_PICSR 2
+#define OR1K_SPG_PIC_LAST OR1K_SPG_PIC_PICSR
+
+#define OR1K_SPG_TT_TTMR 0
+#define OR1K_SPG_TT_TTCR 1
+#define OR1K_SPG_TT_LAST OR1K_SPG_TT_TTCR
+
+#define OR1K_SPG_FPU_LAST -1
+
+
+/* Define absolute SPR values from group and index */
+#define OR1K_SPR(group, index) (((group) << OR1K_SPG_SIZE_BITS) + (index))
+
+/* System group registers */
+#define OR1K_VR_SPRNUM OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_VR)
+#define OR1K_UPR_SPRNUM OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_UPR)
+#define OR1K_CPUCFGR_SPRNUM OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_CPUCFGR)
+#define OR1K_DCFGR_SPRNUM OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_DCFGR)
+#define OR1K_NPC_SPRNUM OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_NPC)
+#define OR1K_SR_SPRNUM OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_SR)
+#define OR1K_PPC_SPRNUM OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_PPC)
+#define OR1K_EPCR_SPRNUM OR1K_SPR (OR1K_SPG_SYS, OR1K_SPG_SYS_EPCR)
+
+/* Debug group registers */
+#define OR1K_DVR0_SPRNUM OR1K_SPR (OR1K_SPG_DEBUG, OR1K_SPG_DEBUG_DVR)
+#define OR1K_DCR0_SPRNUM OR1K_SPR (OR1K_SPG_DEBUG, OR1K_SPG_DEBUG_DCR)
+#define OR1K_DMR1_SPRNUM OR1K_SPR (OR1K_SPG_DEBUG, OR1K_SPG_DEBUG_DMR1)
+#define OR1K_DMR2_SPRNUM OR1K_SPR (OR1K_SPG_DEBUG, OR1K_SPG_DEBUG_DMR2)
+#define OR1K_DCWR0_SPRNUM OR1K_SPR (OR1K_SPG_DEBUG, OR1K_SPG_DEBUG_DCWR0)
+#define OR1K_DCWR1_SPRNUM OR1K_SPR (OR1K_SPG_DEBUG, OR1K_SPG_DEBUG_DCWR0)
+#define OR1K_DSR_SPRNUM OR1K_SPR (OR1K_SPG_DEBUG, OR1K_SPG_DEBUG_DSR)
+#define OR1K_DRR_SPRNUM OR1K_SPR (OR1K_SPG_DEBUG, OR1K_SPG_DEBUG_DRR)
+
+/* General Purpose Registers */
+#define OR1K_ZERO_REGNUM 0
+#define OR1K_SP_REGNUM 1
+#define OR1K_FP_REGNUM 2
+#define OR1K_FIRST_ARG_REGNUM 3
+#define OR1K_LAST_ARG_REGNUM 8
+#define OR1K_LR_REGNUM 9
+#define OR1K_FIRST_SAVED_REGNUM 10
+#define OR1K_RV_REGNUM 11
+#define OR1K_PPC_REGNUM (OR1K_MAX_GPR_REGS + 0)
+#define OR1K_NPC_REGNUM (OR1K_MAX_GPR_REGS + 1)
+#define OR1K_SR_REGNUM (OR1K_MAX_GPR_REGS + 2)
+
+/* Defines for Debug Control Register bits */
+
+#define OR1K_DCR_DP 0x0000001 /* DVR/DCR Present */
+#define OR1K_DCR_CC 0x000000e /* Compare condition */
+#define OR1K_DCR_CC_OFF 1 /* Compare condition offset */
+#define OR1K_DCR_SC 0x0000010 /* Signed compare */
+#define OR1K_DCR_CT 0x00000e0 /* Compare type */
+#define OR1K_DCR_CT_OFF 5 /* Compare type offset */
+
+/* Defines for Debug Mode Register 1 bits. */
+#define OR1K_DMR1_CW 0x00000003 /* Mask for CW bits */
+#define OR1K_DMR1_CW_AND 0x00000001 /* Chain watchpoint 0 AND */
+#define OR1K_DMR1_CW_OR 0x00000002 /* Chain watchpoint 0 OR */
+#define OR1K_DMR1_CW_SZ 2 /* Number of bits for each WP */
+#define OR1K_DMR1_ST 0x00400000 /* Single-step trace */
+#define OR1K_DMR1_BT 0x00800000 /* Branch trace */
+
+/* Defines for Debug Mode Register 2 bits. */
+#define OR1K_DMR2_WCE0 0x00000001 /* Watchpoint counter enable 0 */
+#define OR1K_DMR2_WCE1 0x00000002 /* Watchpoint counter enable 1 */
+#define OR1K_DMR2_AWTC_MASK 0x00000ffc /* Assign watchpoints to ctr mask */
+#define OR1K_DMR2_WGB_MASK 0x003ff000 /* Watchpoints generaing brk mask */
+#define OR1K_DMR2_WBS_MASK 0xffc00000 /* Watchpoint brkpt status mask */
+#define OR1K_DMR2_AWTC_OFF 2 /* Assign watchpoints to ctr offset */
+#define OR1K_DMR2_WGB_OFF 12 /* Watchpoints generating brk offset */
+#define OR1K_DMR2_WBS_OFF 22 /* Watchpoint brkpt status offset */
+
+/* Defines for Debug Stop Register. */
+#define OR1K_DSR_RSTE 0x00000001 /* Reset exception */
+#define OR1K_DSR_BUSEE 0x00000002 /* Bus error exception */
+#define OR1K_DSR_DPFE 0x00000004 /* Data page fault exception */
+#define OR1K_DSR_IPFE 0x00000008 /* Instrution page fault exception */
+#define OR1K_DSR_TTE 0x00000010 /* Tick timer exception */
+#define OR1K_DSR_AE 0x00000020 /* Alignment exception */
+#define OR1K_DSR_IIE 0x00000040 /* Illegal instruction exception */
+#define OR1K_DSR_INTE 0x00000080 /* Interrupt exception */
+#define OR1K_DSR_DME 0x00000100 /* DTLB miss exception */
+#define OR1K_DSR_IME 0x00000200 /* ITLB miss exception */
+#define OR1K_DSR_RE 0x00000400 /* Range exception */
+#define OR1K_DSR_SCE 0x00000800 /* System call exception */
+#define OR1K_DSR_FPE 0x00001000 /* Floating point exception */
+#define OR1K_DSR_TE 0x00002000 /* Trap exception */
+
+/* Defines for Debug Reason Register bits */
+#define OR1K_DRR_RSTE 0x00000001 /* Reset exception */
+#define OR1K_DRR_BUSEE 0x00000002 /* Bus error exception */
+#define OR1K_DRR_DPFE 0x00000004 /* Data page fault exception */
+#define OR1K_DRR_IPFE 0x00000008 /* Instrution page fault exception */
+#define OR1K_DRR_TTE 0x00000010 /* Tick timer exception */
+#define OR1K_DRR_AE 0x00000020 /* Alignment exception */
+#define OR1K_DRR_IIE 0x00000040 /* Illegal instruction exception */
+#define OR1K_DRR_INTE 0x00000080 /* Interrupt exception */
+#define OR1K_DRR_DME 0x00000100 /* DTLB miss exception */
+#define OR1K_DRR_IME 0x00000200 /* ITLB miss exception */
+#define OR1K_DRR_RE 0x00000400 /* Range exception */
+#define OR1K_DRR_SCE 0x00000800 /* System call exception */
+#define OR1K_DRR_FPE 0x00001000 /* Floating point exception */
+#define OR1K_DRR_TE 0x00002000 /* Trap exception */
+
+/* Bit definitions for the Unit Present Register */
+#define OR1K_SPR_UPR_UP 0x00000001 /* UPR present */
+#define OR1K_SPR_UPR_DCP 0x00000002 /* Data cache present */
+#define OR1K_SPR_UPR_ICP 0x00000004 /* Instruction cache present */
+#define OR1K_SPR_UPR_DMP 0x00000008 /* Data MMU present */
+#define OR1K_SPR_UPR_IMP 0x00000010 /* Instruction MMU present */
+#define OR1K_SPR_UPR_MP 0x00000020 /* MAC present */
+#define OR1K_SPR_UPR_DUP 0x00000040 /* Debug unit present */
+#define OR1K_SPR_UPR_PCUP 0x00000080 /* Perf counters unit present */
+#define OR1K_SPR_UPR_PMP 0x00000100 /* Power management present */
+#define OR1K_SPR_UPR_PICP 0x00000200 /* PIC present */
+#define OR1K_SPR_UPR_TTP 0x00000400 /* Tick timer present */
+
+/* Bit definitions for the CPU Configuration Register */
+#define OR1K_SPR_CPUCFGR_NSGF 0x0000000f /* Number of shadow GPR files */
+#define OR1K_SPR_CPUCFGR_CGF 0x00000010 /* Custom GPR file */
+#define OR1K_SPR_CPUCFGR_OB32S 0x00000020 /* ORBIS32 supported */
+#define OR1K_SPR_CPUCFGR_OB64S 0x00000040 /* ORBIS64 supported */
+#define OR1K_SPR_CPUCFGR_OF32S 0x00000080 /* ORFPX32 supported */
+#define OR1K_SPR_CPUCFGR_OF64S 0x00000100 /* ORFPX64 supported */
+#define OR1K_SPR_CPUCFGR_OV64S 0x00000400 /* ORVDX64 supported */
+
+/* Bit definitions for the Debug configuration register */
+#define OR1K_SPR_DCFGR_NDP 0x00000007 /* Number of matchpoints */
+#define OR1K_SPR_DCFGR_WPCI 0x00000008 /* Watchpoint ctrs implemented */
+
+/* Properties of the architecture. GDB mapping of registers is all the GPRs
+ and SPRs followed by the PPC, NPC and SR at the end. Red zone is the area
+ past the end of the stack reserved for exception handlers etc. */
+#define OR1K_MAX_GPR_REGS 32
+#define OR1K_MAX_SPR_REGS (32 * 2048)
+#define OR1K_NUM_PSEUDO_REGS 0
+#define OR1K_NUM_REGS_CACHED (OR1K_MAX_GPR_REGS + 3)
+#define OR1K_NUM_REGS (OR1K_NUM_REGS_CACHED + OR1K_MAX_SPR_REGS)
+#define OR1K_TOTAL_NUM_REGS (OR1K_NUM_REGS + OR1K_NUM_PSEUDO_REGS)
+#define OR1K_MAX_MATCHPOINTS 8
+#define OR1K_MAX_HW_WATCHES OR1K_MAX_MATCHPOINTS
+#define OR1K_STACK_ALIGN 4
+#define OR1K_INSTLEN 4
+#define OR1K_INSTBITLEN (OR1K_INSTLEN * 8)
+#define OR1K_NUM_TAP_RECORDS 8
+#define OR1K_FRAME_RED_ZONE_SIZE 2536
+
+/* OR1K exception vectors */
+
+#define OR1K_RESET_VECTOR 0x100
+#define OR1K_BUSERR_VECTOR 0x200
+#define OR1K_DPF_VECTOR 0x300
+#define OR1K_IPF_VECTOR 0x400
+#define OR1K_TT_VECTOR 0x500
+#define OR1K_ALIGN_VECTOR 0x600
+#define OR1K_ILL_VECTOR 0x700
+#define OR1K_EXT_VECTOR 0x800
+#define OR1K_DTLB_VECTOR 0x900
+#define OR1K_ITLB_VECTOR 0xa00
+#define OR1K_RANGE_VECTOR 0xb00
+#define OR1K_SYS_VECTOR 0xc00
+#define OR1K_FP_VECTOR 0xd00
+#define OR1K_TRAP_VECTOR 0xe00
+
+/* Constants and macros to break out instruction fields. I'd expect these in
+ the assembler header, but they aren't there (for now). */
+
+#define OR1K_SEXT16(v) (((v) & 0x00008000) ? ((v) - 0x00010000) : (v))
+#define OR1K_SEXT26(v) (((v) & 0x02000000) ? ((v) - 0x04000000) : (v))
+
+#define OR1K_OPCODE1(i) (((i) & 0xfc000000) >> 26)
+#define OR1K_OPCODE2(i) ((((i) & 0xfc000000) >> 20) | \
+ (((i) & 0x00000300) >> 6) | \
+ ((i) & 0x0000000f))
+#define OR1K_OPCODE3(i) ((((i) & 0xfc000000) >> 24) | \
+ (((i) & 0x000000c0) >> 6))
+#define OR1K_OPCODE4(i) ((((i) & 0xfc000000) >> 18) | \
+ (((i) & 0x000003c0) >> 2) | \
+ ((i) & 0x0000000f))
+#define OR1K_OPCODE5(i) (((i) & 0xffff0000) >> 16)
+#define OR1K_OPCODE6(i) (((i) & 0xff000000) >> 24)
+#define OR1K_OPCODE7(i) (((i) & 0xfc000000) >> 21)
+#define OR1K_D_REG(i) (((i) & 0x03e00000) >> 21)
+#define OR1K_A_REG(i) (((i) & 0x001f0000) >> 16)
+#define OR1K_B_REG(i) (((i) & 0x0000f800) >> 11)
+#define OR1K_IMM(i) (OR1K_SEXT16((i) & 0x0000ffff))
+#define OR1K_IMM2(i) (OR1K_SEXT16((((i) & 0x03e00000) >> 10) | \
+ ((i) & 0x000003ff)))
+#define OR1K_OFFSET(i) (OR1K_SEXT26((i) & 0x03ffffff) ))
+#define OR1K_SHIFT(i) ((i) & 0x0000003f)
+
+/* The instruction opcodes */
+
+#define OR1K_OP_ADD 0xe00 /* Type 2 */
+#define OR1K_OP_ADDC 0xe01 /* Type 2 */
+#define OR1K_OP_ADDI 0x27 /* Type 1 */
+#define OR1K_OP_AND 0xe03 /* Type 2 */
+#define OR1K_OP_ANDI 0x29 /* Type 1 */
+#define OR1K_OP_BF 0x04 /* Type 1 */
+#define OR1K_OP_BNF 0x03 /* Type 1 */
+#define OR1K_OP_TRAP 0x2100 /* Type 5 */
+#define OR1K_OP_J 0x00 /* Type 1 */
+#define OR1K_OP_JAL 0x01 /* Type 1 */
+#define OR1K_OP_JALR 0x12 /* Type 1 */
+#define OR1K_OP_JR 0x11 /* Type 1 */
+#define OR1K_OP_LBS 0x24 /* Type 1 */
+#define OR1K_OP_LBZ 0x23 /* Type 1 */
+#define OR1K_OP_LHS 0x26 /* Type 1 */
+#define OR1K_OP_LHZ 0x25 /* Type 1 */
+#define OR1K_OP_LWS 0x22 /* Type 1 */
+#define OR1K_OP_LWZ 0x21 /* Type 1 */
+#define OR1K_OP_MFSPR 0x07 /* Type 1 */
+#define OR1K_OP_MOVHI 0x06 /* Type 1 */
+#define OR1K_OP_MTSPR 0x10 /* Type 1 */
+#define OR1K_OP_MUL 0xe36 /* Type 2 */
+#define OR1K_OP_MULI 0x2c /* Type 1 */
+#define OR1K_OP_MULU 0xe3b /* Type 2 */
+#define OR1K_OP_NOP 0x15 /* Type 6 */
+#define OR1K_OP_OR 0xe04 /* Type 2 */
+#define OR1K_OP_ORI 0x2a /* Type 1 */
+#define OR1K_OP_RFE 0x09 /* Type 1 */
+#define OR1K_OP_RORI 0xe3 /* Type 3 */
+#define OR1K_OP_SB 0x36 /* Type 1 */
+#define OR1K_OP_SFEQ 0x720 /* Type 7 */
+#define OR1K_OP_SFGES 0x72b /* Type 7 */
+#define OR1K_OP_SFGEU 0x723 /* Type 7 */
+#define OR1K_OP_SFGTS 0x72a /* Type 7 */
+#define OR1K_OP_SFGTU 0x722 /* Type 7 */
+#define OR1K_OP_SFLES 0x72d /* Type 7 */
+#define OR1K_OP_SFLEU 0x725 /* Type 7 */
+#define OR1K_OP_SFLTS 0x72c /* Type 7 */
+#define OR1K_OP_SFLTU 0x724 /* Type 7 */
+#define OR1K_OP_SFNE 0x721 /* Type 7 */
+#define OR1K_OP_SLL 0x3808 /* Type 4 */
+#define OR1K_OP_SLLI 0xe0 /* Type 3 */
+#define OR1K_OP_SRA 0x3828 /* Type 4 */
+#define OR1K_OP_SRAI 0xe2 /* Type 3 */
+#define OR1K_OP_SRL 0x3818 /* Type 4 */
+#define OR1K_OP_SRLI 0xe1 /* Type 3 */
+#define OR1K_OP_SUB 0xe02 /* Type 2 */
+#define OR1K_OP_SW 0x35 /* Type 1 */
+#define OR1K_OP_SYS 0x2000 /* Type 5 */
+#define OR1K_OP_XOR 0xe05 /* Type 2 */
+#define OR1K_OP_XORI 0x2b /* Type 1 */
+
+#endif /* OR1K_TDEP__H */
--
2.7.4
next prev parent reply other threads:[~2016-11-27 6:18 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-11-27 6:18 [PATCH v2 0/4] gdb: Port for OpenRISC Stafford Horne
2016-11-27 6:17 ` [PATCH v2 1/4] gdb: Add tdesc_find_register functions Stafford Horne
2016-11-27 6:42 ` Mike Frysinger
2016-11-27 7:09 ` Stafford Horne
2016-11-27 6:17 ` [PATCH v2 3/4] gdb: testsuite: Add or1k l.nop inscruction Stafford Horne
2016-11-27 6:17 ` [PATCH v2 4/4] Add gdb for or1k build Stafford Horne
2016-11-27 6:18 ` Stafford Horne [this message]
2016-11-29 10:06 ` [PATCH v2 2/4] gdb: Add OpenRISC or1k and or1knd target support Yao Qi
2016-12-22 16:11 ` Stafford Horne
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f6acbadf23ddacc9c5b335a2de3b2919793f96af.1480216015.git.shorne@gmail.com \
--to=shorne@gmail.com \
--cc=franck.jullien@gmail.com \
--cc=gdb-patches@sourceware.org \
--cc=openrisc@lists.librecores.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox