From patchwork Sun Nov 27 06:16:44 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stafford Horne X-Patchwork-Id: 17971 Received: (qmail 96988 invoked by alias); 27 Nov 2016 06:18:00 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 96568 invoked by uid 89); 27 Nov 2016 06:17:41 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=1.2 required=5.0 tests=AWL, BAYES_50, FREEMAIL_FROM, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=no version=3.3.2 spammy=frameless, scott, rise, recognition X-HELO: mail-pg0-f67.google.com Received: from mail-pg0-f67.google.com (HELO mail-pg0-f67.google.com) (74.125.83.67) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 27 Nov 2016 06:17:18 +0000 Received: by mail-pg0-f67.google.com with SMTP id 3so9670360pgd.0 for ; Sat, 26 Nov 2016 22:17:17 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=qm43UQjmlwHWCciiyh81JFyQakWmnbRWqp+nubvvbJc=; b=CghDK66UbsTVLEaoDpeZQitjQh60RhBFxZPUUkKig/w3MrDQxUUmAEUq4XLkqjXh3m U+fkoOZguunVayAYzI8S399s7iEr0jrnlZv4E14V8vFNwA5Tl5UfUz8qUBP5ch0a1omj K4AOEMdhZ8iqRFwYt8jhsd0NHGqcF/xWjPVPcLuqhV3G1QDzf+jLqqtanD4pPai7nJAL iqiGFL5c1cvSN/lad7NMwS4YFz5Bsqk1figgNX0GdsNBsifMnb8RcMIFOxtx9LzMMNPi CkYS6UI03IC9CGcj+lBYVMOwuN1R5xFAAOrKZ/L6f4dWdgQazTTYO1lZeaRIgOQNFWwu D6WQ== X-Gm-Message-State: AKaTC00cccON+KkkOR57EsgYtZtjoKoIHOf3GK85rX5MIs8L3zP4/sLzOD8LRNFqI1s6GA== X-Received: by 10.84.176.100 with SMTP id u91mr34825170plb.7.1480227434048; Sat, 26 Nov 2016 22:17:14 -0800 (PST) Received: from lianli.shorne-pla.net (z107.124-45-178.ppp.wakwak.ne.jp. [124.45.178.107]) by smtp.gmail.com with ESMTPSA id r124sm60335152pgr.6.2016.11.26.22.17.11 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 26 Nov 2016 22:17:12 -0800 (PST) Received: from lianli.shorne-pla.net (localhost [127.0.0.1]) by lianli.shorne-pla.net (8.15.2/8.15.2) with ESMTPS id uAR6H965011144 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Sun, 27 Nov 2016 15:17:09 +0900 Received: (from shorne@localhost) by lianli.shorne-pla.net (8.15.2/8.15.2/Submit) id uAR6H9Jn011143; Sun, 27 Nov 2016 15:17:09 +0900 From: Stafford Horne To: gdb-patches@sourceware.org Cc: openrisc@lists.librecores.org, Franck Jullien Subject: [PATCH v2 2/4] gdb: Add OpenRISC or1k and or1knd target support Date: Sun, 27 Nov 2016 15:16:44 +0900 Message-Id: In-Reply-To: References: In-Reply-To: References: X-IsSubscribed: yes From: Franck Jullien 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 * gdb.texinfo (Embedded Processors): Add openrisc to suppress error. 2013-01-31 Franck Jullien * gdb.texinfo: Add / merge OpenRISC documentation from old svn. 2008-08-13 Jeremy Bennett * gdb.texinfo: Sections relating to OpenRISC 1000 rewritten gdb/ChangeLog: 2016-11-23 Stafford Horne 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 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 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 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 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 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 * or1k-tdep.c (or1k_regset_firom_core_section) : Silence gcc warning by using %z format for size_t. 2013-02-22 Franck Jullien * or1k-tdep.c (or1k_push_dummy_code) : Use or1k_frame_align to align the stack pointer. 2013-02-17 Franck Jullien 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 * 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 * 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 * or1k-tdep.c (or1k_skip_prologue): Add a check for NULL pointer while comparing debugformat to "dwarf". 2013-01-31 Franck Jullien * 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 * 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 : #define added. 2008-11-08 Jeremy Bennett * 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 * 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 * 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 + + Contributor Franck Jullien + + 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 . */ + +/*----------------------------------------------------------------------------- + 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 + +#include "dis-asm.h" +#include "opcodes/or1k-desc.h" +#include "opcodes/or1k-opc.h" + + + +/* 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 + - %b: Match 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 () */ + + + + +/* 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() */ + + + + +/* 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() */ + + + +/* 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_ 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 + -> | + -> + -> | + @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: |\n" + " |\n" + " \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 + + 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 . */ + + +#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 */