Add support for new target, Toshiba Media Processor (MeP).
authorKevin Buettner <kevinb@redhat.com>
Fri, 23 Feb 2007 22:50:41 +0000 (22:50 +0000)
committerKevin Buettner <kevinb@redhat.com>
Fri, 23 Feb 2007 22:50:41 +0000 (22:50 +0000)
gdb/ChangeLog
gdb/Makefile.in
gdb/config/mep/mep.mt [new file with mode: 0644]
gdb/configure.tgt
gdb/mep-tdep.c [new file with mode: 0644]

index a1bdf895169b6eade5e68c499e6cfc00fe69b866..cdcbdda7cf0f9a3c972a314d3adeaba041ea5a79 100644 (file)
@@ -1,3 +1,13 @@
+2007-02-23  Kevin Buettner  <kevinb@redhat.com>
+
+       From Jim Blandy, Dave Brolley, Kevin Buettner, Don Howard, and
+       Richard Sandiford:
+       * Makefile.in (elf_mep_h, mep_desc_h, mep_opc_h): New variables.
+       (mep-tdep.o): New rule.
+       * configure.tgt (mep-*-*): New target.
+       * mep-tdep.c: New file.
+       * config/mep/mep.mt: New file.
+
 2007-02-22  Markus Deuling  <deuling@de.ibm.com>
 
        * infrun.c (inferior_stop_reason, print_stop_reason): Remove
index 5047ffb1b73baf2dfd56097224612e773321a1ac..4b9f988869d77b8964b15d1c53f1e4978ca3494e 100644 (file)
@@ -592,6 +592,7 @@ elf_arm_h = $(INCLUDE_DIR)/elf/arm.h $(elf_reloc_macros_h)
 elf_bfd_h =    $(BFD_SRC)/elf-bfd.h
 elf_frv_h =    $(INCLUDE_DIR)/elf/frv.h $(elf_reloc_macros_h)
 elf_m32c_h =    $(INCLUDE_DIR)/elf/m32c.h $(elf_reloc_macros_h)
+elf_mep_h =     $(INCLUDE_DIR)/elf/mep.h $(elf_reloc_macros_h)
 libaout_h =    $(BFD_SRC)/libaout.h
 libiberty_h =  $(INCLUDE_DIR)/libiberty.h
 libbfd_h =     $(BFD_SRC)/libbfd.h
@@ -603,6 +604,8 @@ readline_h =        $(READLINE_SRC)/readline.h
 readline_tilde_h =     $(READLINE_SRC)/tilde.h
 readline_history_h =   $(READLINE_SRC)/history.h
 frv_desc_h =   $(OPCODES_SRC)/frv-desc.h
+mep_desc_h =   $(OPCODES_SRC)/mep-desc.h
+mep_opc_h =    $(OPCODES_SRC)/mep-opc.h
 sh_opc_h =     $(OPCODES_SRC)/sh-opc.h
 gdb_callback_h = $(INCLUDE_DIR)/gdb/callback.h
 gdb_sim_arm_h =        $(INCLUDE_DIR)/gdb/sim-arm.h
@@ -2357,6 +2360,13 @@ memattr.o: memattr.c $(defs_h) $(command_h) $(gdbcmd_h) $(memattr_h) \
        $(target_h) $(value_h) $(language_h) $(vec_h) $(gdb_string_h)
 mem-break.o: mem-break.c $(defs_h) $(symtab_h) $(breakpoint_h) $(inferior_h) \
        $(target_h)
+mep-tdep.o: $(defs_h) $(frame_h) $(frame_unwind_h) $(frame_base_h) \
+       $(symtab_h) $(gdbtypes_h) $(gdbcmd_h) $(gdbcore_h) $(gdb_string_h) \
+       $(value_h) $(inferior_h) $(dis_asm_h) $(symfile_h) $(objfiles_h) \
+       $(language_h) $(arch_utils_h) $(regcache_h) $(remote_h) \
+       $(floatformat_h) $(sim_regno_h) $(disasm_h) $(trad_frame_h) \
+       $(reggroups_h) $(elf_bfd_h) $(elf_mep_h) $(gdb_assert_h) \
+       $(mep_desc_h) $(mep_opc_h) $(prologue_value_h) $(infcall_h)
 mingw-hdep.o: mingw-hdep.c $(defs_h) $(serial_h) $(gdb_assert_h) \
        $(gdb_select_h) $(gdb_string_h)
 minsyms.o: minsyms.c $(defs_h) $(gdb_string_h) $(symtab_h) $(bfd_h) \
diff --git a/gdb/config/mep/mep.mt b/gdb/config/mep/mep.mt
new file mode 100644 (file)
index 0000000..584ec4b
--- /dev/null
@@ -0,0 +1,3 @@
+# Target: Toshiba Media Processor (MEP)
+TDEPFILES= mep-tdep.o prologue-value.o
+# No sim needed. Target uses SID.
index 3682b4620d9aa4465732dea3163a543723beecd6..94cd6bb81f1337185a62935b9ecf331d01b1edbd 100644 (file)
@@ -141,6 +141,8 @@ m68*-*-uclinux*)    gdb_target=monitor ;;
 
 m88*-*-openbsd*)       gdb_target=obsd ;;
 
+mep-*-*)               gdb_target=mep ;;
+
 mips*-*-pe)            gdb_target=wince ;;
 mips*-sgi-irix5*)      gdb_target=irix5 ;;
 mips*-sgi-irix6*)      gdb_target=irix6 ;;
diff --git a/gdb/mep-tdep.c b/gdb/mep-tdep.c
new file mode 100644 (file)
index 0000000..46c8310
--- /dev/null
@@ -0,0 +1,2509 @@
+/* Target-dependent code for the Toshiba MeP for GDB, the GNU debugger.
+
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
+
+   Contributed by Red Hat, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "gdb_string.h"
+#include "value.h"
+#include "inferior.h"
+#include "dis-asm.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "language.h"
+#include "arch-utils.h"
+#include "regcache.h"
+#include "remote.h"
+#include "floatformat.h"
+#include "sim-regno.h"
+#include "disasm.h"
+#include "trad-frame.h"
+#include "reggroups.h"
+#include "elf-bfd.h"
+#include "elf/mep.h"
+#include "prologue-value.h"
+#include "opcode/cgen-bitset.h"
+#include "infcall.h"
+
+#include "gdb_assert.h"
+
+/* Get the user's customized MeP coprocessor register names from
+   libopcodes.  */
+#include "opcodes/mep-desc.h"
+#include "opcodes/mep-opc.h"
+
+\f
+/* The gdbarch_tdep structure.  */
+
+/* A quick recap for GDB hackers not familiar with the whole Toshiba
+   Media Processor story:
+
+   The MeP media engine is a configureable processor: users can design
+   their own coprocessors, implement custom instructions, adjust cache
+   sizes, select optional standard facilities like add-and-saturate
+   instructions, and so on.  Then, they can build custom versions of
+   the GNU toolchain to support their customized chips.  The
+   MeP-Integrator program (see utils/mep) takes a GNU toolchain source
+   tree, and a config file pointing to various files provided by the
+   user describing their customizations, and edits the source tree to
+   produce a compiler that can generate their custom instructions, an
+   assembler that can assemble them and recognize their custom
+   register names, and so on.
+
+   Furthermore, the user can actually specify several of these custom
+   configurations, called 'me_modules', and get a toolchain which can
+   produce code for any of them, given a compiler/assembler switch;
+   you say something like 'gcc -mconfig=mm_max' to generate code for
+   the me_module named 'mm_max'.
+
+   GDB, in particular, needs to:
+
+   - use the coprocessor control register names provided by the user
+     in their hardware description, in expressions, 'info register'
+     output, and disassembly,
+
+   - know the number, names, and types of the coprocessor's
+     general-purpose registers, adjust the 'info all-registers' output
+     accordingly, and print error messages if the user refers to one
+     that doesn't exist
+
+   - allow access to the control bus space only when the configuration
+     actually has a control bus, and recognize which regions of the
+     control bus space are actually populated,
+
+   - disassemble using the user's provided mnemonics for their custom
+     instructions, and
+
+   - recognize whether the $hi and $lo registers are present, and
+     allow access to them only when they are actually there.
+
+   There are three sources of information about what sort of me_module
+   we're actually dealing with:
+
+   - A MeP executable file indicates which me_module it was compiled
+     for, and libopcodes has tables describing each module.  So, given
+     an executable file, we can find out about the processor it was
+     compiled for.
+
+   - There are SID command-line options to select a particular
+     me_module, overriding the one specified in the ELF file.  SID
+     provides GDB with a fake read-only register, 'module', which
+     indicates which me_module GDB is communicating with an instance
+     of.
+
+   - There are SID command-line options to enable or disable certain
+     optional processor features, overriding the defaults for the
+     selected me_module.  The MeP $OPT register indicates which
+     options are present on the current processor.  */
+
+
+struct gdbarch_tdep
+{
+  /* A CGEN cpu descriptor for this BFD architecture and machine.
+
+     Note: this is *not* customized for any particular me_module; the
+     MeP libopcodes machinery actually puts off module-specific
+     customization until the last minute.  So this contains
+     information about all supported me_modules.  */
+  CGEN_CPU_DESC cpu_desc;
+
+  /* The me_module index from the ELF file we used to select this
+     architecture, or CONFIG_NONE if there was none.
+
+     Note that we should prefer to use the me_module number available
+     via the 'module' register, whenever we're actually talking to a
+     real target.
+
+     In the absence of live information, we'd like to get the
+     me_module number from the ELF file.  But which ELF file: the
+     executable file, the core file, ... ?  The answer is, "the last
+     ELF file we used to set the current architecture".  Thus, we
+     create a separate instance of the gdbarch structure for each
+     me_module value mep_gdbarch_init sees, and store the me_module
+     value from the ELF file here.  */
+  CONFIG_ATTR me_module;
+};
+
+
+\f
+/* Getting me_module information from the CGEN tables.  */
+
+
+/* Find an entry in the DESC's hardware table whose name begins with
+   PREFIX, and whose ISA mask intersects COPRO_ISA_MASK, but does not
+   intersect with GENERIC_ISA_MASK.  If there is no matching entry,
+   return zero.  */
+static const CGEN_HW_ENTRY *
+find_hw_entry_by_prefix_and_isa (CGEN_CPU_DESC desc,
+                                 const char *prefix,
+                                 CGEN_BITSET *copro_isa_mask,
+                                 CGEN_BITSET *generic_isa_mask)
+{
+  int prefix_len = strlen (prefix);
+  int i;
+
+  for (i = 0; i < desc->hw_table.num_entries; i++)
+    {
+      const CGEN_HW_ENTRY *hw = desc->hw_table.entries[i];
+      if (strncmp (prefix, hw->name, prefix_len) == 0)
+        {
+          CGEN_BITSET *hw_isa_mask
+            = ((CGEN_BITSET *)
+               &CGEN_ATTR_CGEN_HW_ISA_VALUE (CGEN_HW_ATTRS (hw)));
+
+          if (cgen_bitset_intersect_p (hw_isa_mask, copro_isa_mask)
+              && ! cgen_bitset_intersect_p (hw_isa_mask, generic_isa_mask))
+            return hw;
+        }
+    }
+
+  return 0;
+}
+
+
+/* Find an entry in DESC's hardware table whose type is TYPE.  Return
+   zero if there is none.  */
+static const CGEN_HW_ENTRY *
+find_hw_entry_by_type (CGEN_CPU_DESC desc, CGEN_HW_TYPE type)
+{
+  int i;
+
+  for (i = 0; i < desc->hw_table.num_entries; i++)
+    {
+      const CGEN_HW_ENTRY *hw = desc->hw_table.entries[i];
+
+      if (hw->type == type)
+        return hw;
+    }
+
+  return 0;
+}
+
+
+/* Return the CGEN hardware table entry for the coprocessor register
+   set for ME_MODULE, whose name prefix is PREFIX.  If ME_MODULE has
+   no such register set, return zero.  If ME_MODULE is the generic
+   me_module CONFIG_NONE, return the table entry for the register set
+   whose hardware type is GENERIC_TYPE.  */
+static const CGEN_HW_ENTRY *
+me_module_register_set (CONFIG_ATTR me_module,
+                        const char *prefix,
+                        CGEN_HW_TYPE generic_type)
+{
+  /* This is kind of tricky, because the hardware table is constructed
+     in a way that isn't very helpful.  Perhaps we can fix that, but
+     here's how it works at the moment:
+
+     The configuration map, `mep_config_map', is indexed by me_module
+     number, and indicates which coprocessor and core ISAs that
+     me_module supports.  The 'core_isa' mask includes all the core
+     ISAs, and the 'cop_isa' mask includes all the coprocessor ISAs.
+     The entry for the generic me_module, CONFIG_NONE, has an empty
+     'cop_isa', and its 'core_isa' selects only the standard MeP
+     instruction set.
+
+     The CGEN CPU descriptor's hardware table, desc->hw_table, has
+     entries for all the register sets, for all me_modules.  Each
+     entry has a mask indicating which ISAs use that register set.
+     So, if an me_module supports some coprocessor ISA, we can find
+     applicable register sets by scanning the hardware table for
+     register sets whose masks include (at least some of) those ISAs.
+
+     Each hardware table entry also has a name, whose prefix says
+     whether it's a general-purpose ("h-cr") or control ("h-ccr")
+     coprocessor register set.  It might be nicer to have an attribute
+     indicating what sort of register set it was, that we could use
+     instead of pattern-matching on the name.
+
+     When there is no hardware table entry whose mask includes a
+     particular coprocessor ISA and whose name starts with a given
+     prefix, then that means that that coprocessor doesn't have any
+     registers of that type.  In such cases, this function must return
+     a null pointer.
+
+     Coprocessor register sets' masks may or may not include the core
+     ISA for the me_module they belong to.  Those generated by a2cgen
+     do, but the sample me_module included in the unconfigured tree,
+     'ccfx', does not.
+
+     There are generic coprocessor register sets, intended only for
+     use with the generic me_module.  Unfortunately, their masks
+     include *all* ISAs --- even those for coprocessors that don't
+     have such register sets.  This makes detecting the case where a
+     coprocessor lacks a particular register set more complicated.
+
+     So, here's the approach we take:
+
+     - For CONFIG_NONE, we return the generic coprocessor register set.
+
+     - For any other me_module, we search for a register set whose
+       mask contains any of the me_module's coprocessor ISAs,
+       specifically excluding the generic coprocessor register sets.  */
+
+  CGEN_CPU_DESC desc = gdbarch_tdep (current_gdbarch)->cpu_desc;
+  const CGEN_HW_ENTRY *hw;
+
+  if (me_module == CONFIG_NONE)
+    hw = find_hw_entry_by_type (desc, generic_type);
+  else
+    {
+      CGEN_BITSET *cop = &mep_config_map[me_module].cop_isa;
+      CGEN_BITSET *core = &mep_config_map[me_module].core_isa;
+      CGEN_BITSET *generic = &mep_config_map[CONFIG_NONE].core_isa;
+      CGEN_BITSET *cop_and_core;
+
+      /* The coprocessor ISAs include the ISA for the specific core which
+        has that coprocessor.  */
+      cop_and_core = cgen_bitset_copy (cop);
+      cgen_bitset_union (cop, core, cop_and_core);
+      hw = find_hw_entry_by_prefix_and_isa (desc, prefix, cop_and_core, generic);
+    }
+
+  return hw;
+}
+
+
+/* Given a hardware table entry HW representing a register set, return
+   a pointer to the keyword table with all the register names.  If HW
+   is NULL, return NULL, to propage the "no such register set" info
+   along.  */
+static CGEN_KEYWORD *
+register_set_keyword_table (const CGEN_HW_ENTRY *hw)
+{
+  if (! hw)
+    return NULL;
+
+  /* Check that HW is actually a keyword table.  */
+  gdb_assert (hw->asm_type == CGEN_ASM_KEYWORD);
+
+  /* The 'asm_data' field of a register set's hardware table entry
+     refers to a keyword table.  */
+  return (CGEN_KEYWORD *) hw->asm_data;
+}
+
+
+/* Given a keyword table KEYWORD and a register number REGNUM, return
+   the name of the register, or "" if KEYWORD contains no register
+   whose number is REGNUM.  */
+static char *
+register_name_from_keyword (CGEN_KEYWORD *keyword_table, int regnum)
+{
+  const CGEN_KEYWORD_ENTRY *entry
+    = cgen_keyword_lookup_value (keyword_table, regnum);
+
+  if (entry)
+    {
+      char *name = entry->name;
+
+      /* The CGEN keyword entries for register names include the
+         leading $, which appears in MeP assembly as well as in GDB.
+         But we don't want to return that; GDB core code adds that
+         itself.  */
+      if (name[0] == '$')
+        name++;
+
+      return name;
+    }
+  else
+    return "";
+}
+
+  
+/* Masks for option bits in the OPT special-purpose register.  */
+enum {
+  MEP_OPT_DIV = 1 << 25,        /* 32-bit divide instruction option */
+  MEP_OPT_MUL = 1 << 24,        /* 32-bit multiply instruction option */
+  MEP_OPT_BIT = 1 << 23,        /* bit manipulation instruction option */
+  MEP_OPT_SAT = 1 << 22,        /* saturation instruction option */
+  MEP_OPT_CLP = 1 << 21,        /* clip instruction option */
+  MEP_OPT_MIN = 1 << 20,        /* min/max instruction option */
+  MEP_OPT_AVE = 1 << 19,        /* average instruction option */
+  MEP_OPT_ABS = 1 << 18,        /* absolute difference instruction option */
+  MEP_OPT_LDZ = 1 << 16,        /* leading zero instruction option */
+  MEP_OPT_VL64 = 1 << 6,        /* 64-bit VLIW operation mode option */
+  MEP_OPT_VL32 = 1 << 5,        /* 32-bit VLIW operation mode option */
+  MEP_OPT_COP = 1 << 4,         /* coprocessor option */
+  MEP_OPT_DSP = 1 << 2,         /* DSP option */
+  MEP_OPT_UCI = 1 << 1,         /* UCI option */
+  MEP_OPT_DBG = 1 << 0,         /* DBG function option */
+};
+
+
+/* Given the option_mask value for a particular entry in
+   mep_config_map, produce the value the processor's OPT register
+   would use to represent the same set of options.  */
+static unsigned int
+opt_from_option_mask (unsigned int option_mask)
+{
+  /* A table mapping OPT register bits onto CGEN config map option
+     bits.  */
+  struct {
+    unsigned int opt_bit, option_mask_bit;
+  } bits[] = {
+    { MEP_OPT_DIV, 1 << CGEN_INSN_OPTIONAL_DIV_INSN },
+    { MEP_OPT_MUL, 1 << CGEN_INSN_OPTIONAL_MUL_INSN },
+    { MEP_OPT_DIV, 1 << CGEN_INSN_OPTIONAL_DIV_INSN },
+    { MEP_OPT_DBG, 1 << CGEN_INSN_OPTIONAL_DEBUG_INSN },
+    { MEP_OPT_LDZ, 1 << CGEN_INSN_OPTIONAL_LDZ_INSN },
+    { MEP_OPT_ABS, 1 << CGEN_INSN_OPTIONAL_ABS_INSN },
+    { MEP_OPT_AVE, 1 << CGEN_INSN_OPTIONAL_AVE_INSN },
+    { MEP_OPT_MIN, 1 << CGEN_INSN_OPTIONAL_MINMAX_INSN },
+    { MEP_OPT_CLP, 1 << CGEN_INSN_OPTIONAL_CLIP_INSN },
+    { MEP_OPT_SAT, 1 << CGEN_INSN_OPTIONAL_SAT_INSN },
+    { MEP_OPT_UCI, 1 << CGEN_INSN_OPTIONAL_UCI_INSN },
+    { MEP_OPT_DSP, 1 << CGEN_INSN_OPTIONAL_DSP_INSN },
+    { MEP_OPT_COP, 1 << CGEN_INSN_OPTIONAL_CP_INSN },
+  };
+
+  int i;
+  unsigned int opt = 0;
+
+  for (i = 0; i < (sizeof (bits) / sizeof (bits[0])); i++)
+    if (option_mask & bits[i].option_mask_bit)
+      opt |= bits[i].opt_bit;
+
+  return opt;
+}
+
+
+/* Return the value the $OPT register would use to represent the set
+   of options for ME_MODULE.  */
+static unsigned int
+me_module_opt (CONFIG_ATTR me_module)
+{
+  return opt_from_option_mask (mep_config_map[me_module].option_mask);
+}
+
+
+/* Return the width of ME_MODULE's coprocessor data bus, in bits.
+   This is either 32 or 64.  */
+static int
+me_module_cop_data_bus_width (CONFIG_ATTR me_module)
+{
+  if (mep_config_map[me_module].option_mask
+      & (1 << CGEN_INSN_OPTIONAL_CP64_INSN))
+    return 64;
+  else
+    return 32;
+}
+
+
+/* Return true if ME_MODULE is big-endian, false otherwise.  */
+static int
+me_module_big_endian (CONFIG_ATTR me_module)
+{
+  return mep_config_map[me_module].big_endian;
+}
+
+
+/* Return the name of ME_MODULE, or NULL if it has no name.  */
+static const char *
+me_module_name (CONFIG_ATTR me_module)
+{
+  /* The default me_module has "" as its name, but it's easier for our
+     callers to test for NULL.  */
+  if (! mep_config_map[me_module].name
+      || mep_config_map[me_module].name[0] == '\0')
+    return NULL;
+  else
+    return mep_config_map[me_module].name;
+}
+\f
+/* Register set.  */
+
+
+/* The MeP spec defines the following registers:
+   16 general purpose registers (r0-r15) 
+   32 control/special registers (csr0-csr31)
+   32 coprocessor general-purpose registers (c0 -- c31)
+   64 coprocessor control registers (ccr0 -- ccr63)
+
+   For the raw registers, we assign numbers here explicitly, instead
+   of letting the enum assign them for us; the numbers are a matter of
+   external protocol, and shouldn't shift around as things are edited.
+
+   We access the control/special registers via pseudoregisters, to
+   enforce read-only portions that some registers have.
+
+   We access the coprocessor general purpose and control registers via
+   pseudoregisters, to make sure they appear in the proper order in
+   the 'info all-registers' command (which uses the register number
+   ordering), and also to allow them to be renamed and resized
+   depending on the me_module in use.
+
+   The MeP allows coprocessor general-purpose registers to be either
+   32 or 64 bits long, depending on the configuration.  Since we don't
+   want the format of the 'g' packet to vary from one core to another,
+   the raw coprocessor GPRs are always 64 bits.  GDB doesn't allow the
+   types of registers to change (see the implementation of
+   register_type), so we have four banks of pseudoregisters for the
+   coprocessor gprs --- 32-bit vs. 64-bit, and integer
+   vs. floating-point --- and we show or hide them depending on the
+   configuration.  */
+enum
+{
+  MEP_FIRST_RAW_REGNUM = 0,
+
+  MEP_FIRST_GPR_REGNUM = 0,
+  MEP_R0_REGNUM = 0,
+  MEP_R1_REGNUM = 1,
+  MEP_R2_REGNUM = 2,
+  MEP_R3_REGNUM = 3,
+  MEP_R4_REGNUM = 4,
+  MEP_R5_REGNUM = 5,
+  MEP_R6_REGNUM = 6,
+  MEP_R7_REGNUM = 7,
+  MEP_R8_REGNUM = 8,
+  MEP_R9_REGNUM = 9,
+  MEP_R10_REGNUM = 10,
+  MEP_R11_REGNUM = 11,
+  MEP_R12_REGNUM = 12,
+  MEP_FP_REGNUM = MEP_R8_REGNUM,
+  MEP_R13_REGNUM = 13,
+  MEP_TP_REGNUM = MEP_R13_REGNUM,      /* (r13) Tiny data pointer */
+  MEP_R14_REGNUM = 14,
+  MEP_GP_REGNUM = MEP_R14_REGNUM,      /* (r14) Global pointer */
+  MEP_R15_REGNUM = 15,
+  MEP_SP_REGNUM = MEP_R15_REGNUM,      /* (r15) Stack pointer */
+  MEP_LAST_GPR_REGNUM = MEP_R15_REGNUM,
+
+  /* The raw control registers.  These are the values as received via
+     the remote protocol, directly from the target; we only let user
+     code touch the via the pseudoregisters, which enforce read-only
+     bits.  */
+  MEP_FIRST_RAW_CSR_REGNUM = 16,
+  MEP_RAW_PC_REGNUM    = 16,    /* Program counter */
+  MEP_RAW_LP_REGNUM    = 17,    /* Link pointer */
+  MEP_RAW_SAR_REGNUM   = 18,    /* Raw shift amount */
+  MEP_RAW_CSR3_REGNUM  = 19,    /* csr3: reserved */
+  MEP_RAW_RPB_REGNUM   = 20,    /* Raw repeat begin address */
+  MEP_RAW_RPE_REGNUM   = 21,    /* Repeat end address */
+  MEP_RAW_RPC_REGNUM   = 22,    /* Repeat count */
+  MEP_RAW_HI_REGNUM    = 23, /* Upper 32 bits of result of 64 bit mult/div */
+  MEP_RAW_LO_REGNUM    = 24, /* Lower 32 bits of result of 64 bit mult/div */
+  MEP_RAW_CSR9_REGNUM  = 25,    /* csr3: reserved */
+  MEP_RAW_CSR10_REGNUM = 26,    /* csr3: reserved */
+  MEP_RAW_CSR11_REGNUM = 27,    /* csr3: reserved */
+  MEP_RAW_MB0_REGNUM   = 28,    /* Raw modulo begin address 0 */
+  MEP_RAW_ME0_REGNUM   = 29,    /* Raw modulo end address 0 */
+  MEP_RAW_MB1_REGNUM   = 30,    /* Raw modulo begin address 1 */
+  MEP_RAW_ME1_REGNUM   = 31,    /* Raw modulo end address 1 */
+  MEP_RAW_PSW_REGNUM   = 32,    /* Raw program status word */
+  MEP_RAW_ID_REGNUM    = 33,    /* Raw processor ID/revision */
+  MEP_RAW_TMP_REGNUM   = 34,    /* Temporary */
+  MEP_RAW_EPC_REGNUM   = 35,    /* Exception program counter */
+  MEP_RAW_EXC_REGNUM   = 36,    /* Raw exception cause */
+  MEP_RAW_CFG_REGNUM   = 37,    /* Raw processor configuration*/
+  MEP_RAW_CSR22_REGNUM = 38,    /* csr3: reserved */
+  MEP_RAW_NPC_REGNUM   = 39,    /* Nonmaskable interrupt PC */
+  MEP_RAW_DBG_REGNUM   = 40,    /* Raw debug */
+  MEP_RAW_DEPC_REGNUM  = 41,    /* Debug exception PC */
+  MEP_RAW_OPT_REGNUM   = 42,    /* Raw options */
+  MEP_RAW_RCFG_REGNUM  = 43,    /* Raw local ram config */
+  MEP_RAW_CCFG_REGNUM  = 44,    /* Raw cache config */
+  MEP_RAW_CSR29_REGNUM = 45,    /* csr3: reserved */
+  MEP_RAW_CSR30_REGNUM = 46,    /* csr3: reserved */
+  MEP_RAW_CSR31_REGNUM = 47,    /* csr3: reserved */
+  MEP_LAST_RAW_CSR_REGNUM = MEP_RAW_CSR31_REGNUM,
+
+  /* The raw coprocessor general-purpose registers.  These are all 64
+     bits wide.  */
+  MEP_FIRST_RAW_CR_REGNUM = 48,
+  MEP_LAST_RAW_CR_REGNUM = MEP_FIRST_RAW_CR_REGNUM + 31,
+
+  MEP_FIRST_RAW_CCR_REGNUM = 80,
+  MEP_LAST_RAW_CCR_REGNUM = MEP_FIRST_RAW_CCR_REGNUM + 63,
+
+  /* The module number register.  This is the index of the me_module
+     of which the current target is an instance.  (This is not a real
+     MeP-specified register; it's provided by SID.)  */
+  MEP_MODULE_REGNUM,
+
+  MEP_LAST_RAW_REGNUM = MEP_MODULE_REGNUM,
+
+  MEP_NUM_RAW_REGS = MEP_LAST_RAW_REGNUM + 1,
+
+  /* Pseudoregisters.  See mep_pseudo_register_read and
+     mep_pseudo_register_write.  */
+  MEP_FIRST_PSEUDO_REGNUM = MEP_NUM_RAW_REGS,
+
+  /* We have a pseudoregister for every control/special register, to
+     implement registers with read-only bits.  */
+  MEP_FIRST_CSR_REGNUM = MEP_FIRST_PSEUDO_REGNUM,
+  MEP_PC_REGNUM = MEP_FIRST_CSR_REGNUM, /* Program counter */
+  MEP_LP_REGNUM,                /* Link pointer */
+  MEP_SAR_REGNUM,               /* shift amount */
+  MEP_CSR3_REGNUM,              /* csr3: reserved */
+  MEP_RPB_REGNUM,               /* repeat begin address */
+  MEP_RPE_REGNUM,               /* Repeat end address */
+  MEP_RPC_REGNUM,               /* Repeat count */
+  MEP_HI_REGNUM,  /* Upper 32 bits of the result of 64 bit mult/div */
+  MEP_LO_REGNUM,  /* Lower 32 bits of the result of 64 bit mult/div */
+  MEP_CSR9_REGNUM,              /* csr3: reserved */
+  MEP_CSR10_REGNUM,             /* csr3: reserved */
+  MEP_CSR11_REGNUM,             /* csr3: reserved */
+  MEP_MB0_REGNUM,               /* modulo begin address 0 */
+  MEP_ME0_REGNUM,               /* modulo end address 0 */
+  MEP_MB1_REGNUM,               /* modulo begin address 1 */
+  MEP_ME1_REGNUM,               /* modulo end address 1 */
+  MEP_PSW_REGNUM,               /* program status word */
+  MEP_ID_REGNUM,                /* processor ID/revision */
+  MEP_TMP_REGNUM,               /* Temporary */
+  MEP_EPC_REGNUM,               /* Exception program counter */
+  MEP_EXC_REGNUM,               /* exception cause */
+  MEP_CFG_REGNUM,               /* processor configuration*/
+  MEP_CSR22_REGNUM,             /* csr3: reserved */
+  MEP_NPC_REGNUM,               /* Nonmaskable interrupt PC */
+  MEP_DBG_REGNUM,               /* debug */
+  MEP_DEPC_REGNUM,              /* Debug exception PC */
+  MEP_OPT_REGNUM,               /* options */
+  MEP_RCFG_REGNUM,              /* local ram config */
+  MEP_CCFG_REGNUM,              /* cache config */
+  MEP_CSR29_REGNUM,             /* csr3: reserved */
+  MEP_CSR30_REGNUM,             /* csr3: reserved */
+  MEP_CSR31_REGNUM,             /* csr3: reserved */
+  MEP_LAST_CSR_REGNUM = MEP_CSR31_REGNUM,
+
+  /* The 32-bit integer view of the coprocessor GPR's.  */
+  MEP_FIRST_CR32_REGNUM,
+  MEP_LAST_CR32_REGNUM = MEP_FIRST_CR32_REGNUM + 31,
+
+  /* The 32-bit floating-point view of the coprocessor GPR's.  */
+  MEP_FIRST_FP_CR32_REGNUM,
+  MEP_LAST_FP_CR32_REGNUM = MEP_FIRST_FP_CR32_REGNUM + 31,
+
+  /* The 64-bit integer view of the coprocessor GPR's.  */
+  MEP_FIRST_CR64_REGNUM,
+  MEP_LAST_CR64_REGNUM = MEP_FIRST_CR64_REGNUM + 31,
+
+  /* The 64-bit floating-point view of the coprocessor GPR's.  */
+  MEP_FIRST_FP_CR64_REGNUM,
+  MEP_LAST_FP_CR64_REGNUM = MEP_FIRST_FP_CR64_REGNUM + 31,
+
+  MEP_FIRST_CCR_REGNUM,
+  MEP_LAST_CCR_REGNUM = MEP_FIRST_CCR_REGNUM + 63,
+
+  MEP_LAST_PSEUDO_REGNUM = MEP_LAST_CCR_REGNUM,
+
+  MEP_NUM_PSEUDO_REGS = (MEP_LAST_PSEUDO_REGNUM - MEP_LAST_RAW_REGNUM),
+
+  MEP_NUM_REGS = MEP_NUM_RAW_REGS + MEP_NUM_PSEUDO_REGS
+};
+
+
+#define IN_SET(set, n) \
+  (MEP_FIRST_ ## set ## _REGNUM <= (n) && (n) <= MEP_LAST_ ## set ## _REGNUM)
+
+#define IS_GPR_REGNUM(n)     (IN_SET (GPR,     (n)))
+#define IS_RAW_CSR_REGNUM(n) (IN_SET (RAW_CSR, (n)))
+#define IS_RAW_CR_REGNUM(n)  (IN_SET (RAW_CR,  (n)))
+#define IS_RAW_CCR_REGNUM(n) (IN_SET (RAW_CCR, (n)))
+
+#define IS_CSR_REGNUM(n)     (IN_SET (CSR,     (n)))
+#define IS_CR32_REGNUM(n)    (IN_SET (CR32,    (n)))
+#define IS_FP_CR32_REGNUM(n) (IN_SET (FP_CR32, (n)))
+#define IS_CR64_REGNUM(n)    (IN_SET (CR64,    (n)))
+#define IS_FP_CR64_REGNUM(n) (IN_SET (FP_CR64, (n)))
+#define IS_CR_REGNUM(n)      (IS_CR32_REGNUM (n) || IS_FP_CR32_REGNUM (n) \
+                              || IS_CR64_REGNUM (n) || IS_FP_CR64_REGNUM (n))
+#define IS_CCR_REGNUM(n)     (IN_SET (CCR,     (n)))
+
+#define IS_RAW_REGNUM(n)     (IN_SET (RAW,     (n)))
+#define IS_PSEUDO_REGNUM(n)  (IN_SET (PSEUDO,  (n)))
+
+#define NUM_REGS_IN_SET(set) \
+  (MEP_LAST_ ## set ## _REGNUM - MEP_FIRST_ ## set ## _REGNUM + 1)
+
+#define MEP_GPR_SIZE (4)        /* Size of a MeP general-purpose register.  */
+#define MEP_PSW_SIZE (4)        /* Size of the PSW register.  */
+#define MEP_LP_SIZE (4)         /* Size of the LP register.  */
+
+
+/* Many of the control/special registers contain bits that cannot be
+   written to; some are entirely read-only.  So we present them all as
+   pseudoregisters.
+
+   The following table describes the special properties of each CSR.  */
+struct mep_csr_register
+{
+  /* The number of this CSR's raw register.  */
+  int raw;
+
+  /* The number of this CSR's pseudoregister.  */
+  int pseudo;
+
+  /* A mask of the bits that are writeable: if a bit is set here, then
+     it can be modified; if the bit is clear, then it cannot.  */
+  LONGEST writeable_bits;
+};
+
+
+/* mep_csr_registers[i] describes the i'th CSR.
+   We just list the register numbers here explicitly to help catch
+   typos.  */
+#define CSR(name) MEP_RAW_ ## name ## _REGNUM, MEP_ ## name ## _REGNUM
+struct mep_csr_register mep_csr_registers[] = {
+  { CSR(PC),    0xffffffff },   /* manual says r/o, but we can write it */
+  { CSR(LP),    0xffffffff },
+  { CSR(SAR),   0x0000003f },
+  { CSR(CSR3),  0xffffffff },
+  { CSR(RPB),   0xfffffffe },
+  { CSR(RPE),   0xffffffff },
+  { CSR(RPC),   0xffffffff },
+  { CSR(HI),    0xffffffff },
+  { CSR(LO),    0xffffffff },
+  { CSR(CSR9),  0xffffffff },
+  { CSR(CSR10), 0xffffffff },
+  { CSR(CSR11), 0xffffffff },
+  { CSR(MB0),   0x0000ffff },
+  { CSR(ME0),   0x0000ffff },
+  { CSR(MB1),   0x0000ffff },
+  { CSR(ME1),   0x0000ffff },
+  { CSR(PSW),   0x000003ff },
+  { CSR(ID),    0x00000000 },
+  { CSR(TMP),   0xffffffff },
+  { CSR(EPC),   0xffffffff },
+  { CSR(EXC),   0x000030f0 },
+  { CSR(CFG),   0x00c0001b },
+  { CSR(CSR22), 0xffffffff },
+  { CSR(NPC),   0xffffffff },
+  { CSR(DBG),   0x00000580 },
+  { CSR(DEPC),  0xffffffff },
+  { CSR(OPT),   0x00000000 },
+  { CSR(RCFG),  0x00000000 },
+  { CSR(CCFG),  0x00000000 },
+  { CSR(CSR29), 0xffffffff },
+  { CSR(CSR30), 0xffffffff },
+  { CSR(CSR31), 0xffffffff },
+};
+
+
+/* If R is the number of a raw register, then mep_raw_to_pseudo[R] is
+   the number of the corresponding pseudoregister.  Otherwise,
+   mep_raw_to_pseudo[R] == R.  */
+static int mep_raw_to_pseudo[MEP_NUM_REGS];
+
+/* If R is the number of a pseudoregister, then mep_pseudo_to_raw[R]
+   is the number of the underlying raw register.  Otherwise
+   mep_pseudo_to_raw[R] == R.  */
+static int mep_pseudo_to_raw[MEP_NUM_REGS];
+
+static void
+mep_init_pseudoregister_maps (void)
+{
+  int i;
+
+  /* Verify that mep_csr_registers covers all the CSRs, in order.  */
+  gdb_assert (ARRAY_SIZE (mep_csr_registers) == NUM_REGS_IN_SET (CSR));
+  gdb_assert (ARRAY_SIZE (mep_csr_registers) == NUM_REGS_IN_SET (RAW_CSR));
+
+  /* Verify that the raw and pseudo ranges have matching sizes.  */
+  gdb_assert (NUM_REGS_IN_SET (RAW_CSR) == NUM_REGS_IN_SET (CSR));
+  gdb_assert (NUM_REGS_IN_SET (RAW_CR)  == NUM_REGS_IN_SET (CR32));
+  gdb_assert (NUM_REGS_IN_SET (RAW_CR)  == NUM_REGS_IN_SET (CR64));
+  gdb_assert (NUM_REGS_IN_SET (RAW_CCR) == NUM_REGS_IN_SET (CCR));
+
+  for (i = 0; i < ARRAY_SIZE (mep_csr_registers); i++)
+    {
+      struct mep_csr_register *r = &mep_csr_registers[i];
+
+      gdb_assert (r->pseudo == MEP_FIRST_CSR_REGNUM + i);
+      gdb_assert (r->raw    == MEP_FIRST_RAW_CSR_REGNUM + i);
+    }
+
+  /* Set up the initial  raw<->pseudo mappings.  */
+  for (i = 0; i < MEP_NUM_REGS; i++)
+    {
+      mep_raw_to_pseudo[i] = i;
+      mep_pseudo_to_raw[i] = i;
+    }
+
+  /* Add the CSR raw<->pseudo mappings.  */
+  for (i = 0; i < ARRAY_SIZE (mep_csr_registers); i++)
+    {
+      struct mep_csr_register *r = &mep_csr_registers[i];
+
+      mep_raw_to_pseudo[r->raw] = r->pseudo;
+      mep_pseudo_to_raw[r->pseudo] = r->raw;
+    }
+
+  /* Add the CR raw<->pseudo mappings.  */
+  for (i = 0; i < NUM_REGS_IN_SET (RAW_CR); i++)
+    {
+      int raw = MEP_FIRST_RAW_CR_REGNUM + i;
+      int pseudo32 = MEP_FIRST_CR32_REGNUM + i;
+      int pseudofp32 = MEP_FIRST_FP_CR32_REGNUM + i;
+      int pseudo64 = MEP_FIRST_CR64_REGNUM + i;
+      int pseudofp64 = MEP_FIRST_FP_CR64_REGNUM + i;
+
+      /* Truly, the raw->pseudo mapping depends on the current module.
+         But we use the raw->pseudo mapping when we read the debugging
+         info; at that point, we don't know what module we'll actually
+         be running yet.  So, we always supply the 64-bit register
+         numbers; GDB knows how to pick a smaller value out of a
+         larger register properly.  */
+      mep_raw_to_pseudo[raw] = pseudo64;
+      mep_pseudo_to_raw[pseudo32] = raw;
+      mep_pseudo_to_raw[pseudofp32] = raw;
+      mep_pseudo_to_raw[pseudo64] = raw;
+      mep_pseudo_to_raw[pseudofp64] = raw;
+    }
+
+  /* Add the CCR raw<->pseudo mappings.  */
+  for (i = 0; i < NUM_REGS_IN_SET (CCR); i++)
+    {
+      int raw = MEP_FIRST_RAW_CCR_REGNUM + i;
+      int pseudo = MEP_FIRST_CCR_REGNUM + i;
+      mep_raw_to_pseudo[raw] = pseudo;
+      mep_pseudo_to_raw[pseudo] = raw;
+    }
+}
+
+
+static int
+mep_debug_reg_to_regnum (int debug_reg)
+{
+  /* The debug info uses the raw register numbers.  */
+  return mep_raw_to_pseudo[debug_reg];
+}
+
+
+/* Return the size, in bits, of the coprocessor pseudoregister
+   numbered PSEUDO.  */
+static int
+mep_pseudo_cr_size (int pseudo)
+{
+  if (IS_CR32_REGNUM (pseudo)
+      || IS_FP_CR32_REGNUM (pseudo))
+    return 32;
+  else if (IS_CR64_REGNUM (pseudo)
+           || IS_FP_CR64_REGNUM (pseudo))
+    return 64;
+  else
+    gdb_assert (0);
+}
+
+
+/* If the coprocessor pseudoregister numbered PSEUDO is a
+   floating-point register, return non-zero; if it is an integer
+   register, return zero.  */
+static int
+mep_pseudo_cr_is_float (int pseudo)
+{
+  return (IS_FP_CR32_REGNUM (pseudo)
+          || IS_FP_CR64_REGNUM (pseudo));
+}
+
+
+/* Given a coprocessor GPR pseudoregister number, return its index
+   within that register bank.  */
+static int
+mep_pseudo_cr_index (int pseudo)
+{
+  if (IS_CR32_REGNUM (pseudo))
+    return pseudo - MEP_FIRST_CR32_REGNUM;
+  else if (IS_FP_CR32_REGNUM (pseudo))
+      return pseudo - MEP_FIRST_FP_CR32_REGNUM;
+  else if (IS_CR64_REGNUM (pseudo))
+      return pseudo - MEP_FIRST_CR64_REGNUM;
+  else if (IS_FP_CR64_REGNUM (pseudo))
+      return pseudo - MEP_FIRST_FP_CR64_REGNUM;
+  else
+    gdb_assert (0);
+}
+
+
+/* Return the me_module index describing the current target.
+
+   If the current target has registers (e.g., simulator, remote
+   target), then this uses the value of the 'module' register, raw
+   register MEP_MODULE_REGNUM.  Otherwise, this retrieves the value
+   from the ELF header's e_flags field of the current executable
+   file.  */
+static CONFIG_ATTR
+current_me_module ()
+{
+  if (target_has_registers)
+    return read_register (MEP_MODULE_REGNUM);
+  else
+    return gdbarch_tdep (current_gdbarch)->me_module;
+}
+
+
+/* Return the set of options for the current target, in the form that
+   the OPT register would use.
+
+   If the current target has registers (e.g., simulator, remote
+   target), then this is the actual value of the OPT register.  If the
+   current target does not have registers (e.g., an executable file),
+   then use the 'module_opt' field we computed when we build the
+   gdbarch object for this module.  */
+static unsigned int
+current_options ()
+{
+  if (target_has_registers)
+    return read_register (MEP_OPT_REGNUM);
+  else
+    return me_module_opt (current_me_module ());
+}
+
+
+/* Return the width of the current me_module's coprocessor data bus,
+   in bits.  This is either 32 or 64.  */
+static int
+current_cop_data_bus_width ()
+{
+  return me_module_cop_data_bus_width (current_me_module ());
+}
+
+
+/* Return the keyword table of coprocessor general-purpose register
+   names appropriate for the me_module we're dealing with.  */
+static CGEN_KEYWORD *
+current_cr_names ()
+{
+  const CGEN_HW_ENTRY *hw
+    = me_module_register_set (current_me_module (), "h-cr-", HW_H_CR);
+
+  return register_set_keyword_table (hw);
+}
+
+
+/* Return non-zero if the coprocessor general-purpose registers are
+   floating-point values, zero otherwise.  */
+static int
+current_cr_is_float ()
+{
+  const CGEN_HW_ENTRY *hw
+    = me_module_register_set (current_me_module (), "h-cr-", HW_H_CR);
+
+  return CGEN_ATTR_CGEN_HW_IS_FLOAT_VALUE (CGEN_HW_ATTRS (hw));
+}
+
+
+/* Return the keyword table of coprocessor control register names
+   appropriate for the me_module we're dealing with.  */
+static CGEN_KEYWORD *
+current_ccr_names ()
+{
+  const CGEN_HW_ENTRY *hw
+    = me_module_register_set (current_me_module (), "h-ccr-", HW_H_CCR);
+
+  return register_set_keyword_table (hw);
+}
+
+
+static const char *
+mep_register_name (int regnr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);  
+
+  /* General-purpose registers.  */
+  static const char *gpr_names[] = {
+    "r0",   "r1",   "r2",   "r3",   /* 0 */
+    "r4",   "r5",   "r6",   "r7",   /* 4 */
+    "fp",   "r9",   "r10",  "r11",  /* 8 */
+    "r12",  "tp",   "gp",   "sp"    /* 12 */
+  };
+
+  /* Special-purpose registers.  */
+  static const char *csr_names[] = {
+    "pc",   "lp",   "sar",  "",     /* 0  csr3: reserved */ 
+    "rpb",  "rpe",  "rpc",  "hi",   /* 4 */
+    "lo",   "",     "",     "",     /* 8  csr9-csr11: reserved */
+    "mb0",  "me0",  "mb1",  "me1",  /* 12 */
+
+    "psw",  "id",   "tmp",  "epc",  /* 16 */
+    "exc",  "cfg",  "",     "npc",  /* 20  csr22: reserved */
+    "dbg",  "depc", "opt",  "rcfg", /* 24 */
+    "ccfg", "",     "",     ""      /* 28  csr29-csr31: reserved */
+  };
+
+  if (IS_GPR_REGNUM (regnr))
+    return gpr_names[regnr - MEP_R0_REGNUM];
+  else if (IS_CSR_REGNUM (regnr))
+    {
+      /* The 'hi' and 'lo' registers are only present on processors
+         that have the 'MUL' or 'DIV' instructions enabled.  */
+      if ((regnr == MEP_HI_REGNUM || regnr == MEP_LO_REGNUM)
+          && (! (current_options () & (MEP_OPT_MUL | MEP_OPT_DIV))))
+        return "";
+
+      return csr_names[regnr - MEP_FIRST_CSR_REGNUM];
+    }
+  else if (IS_CR_REGNUM (regnr))
+    {
+      CGEN_KEYWORD *names;
+      int cr_size;
+      int cr_is_float;
+
+      /* Does this module have a coprocessor at all?  */
+      if (! (current_options () & MEP_OPT_COP))
+        return "";
+
+      names = current_cr_names ();
+      if (! names)
+        /* This module's coprocessor has no general-purpose registers.  */
+        return "";
+
+      cr_size = current_cop_data_bus_width ();
+      if (cr_size != mep_pseudo_cr_size (regnr))
+        /* This module's coprocessor's GPR's are of a different size.  */
+        return "";
+
+      cr_is_float = current_cr_is_float ();
+      /* The extra ! operators ensure we get boolean equality, not
+         numeric equality.  */
+      if (! cr_is_float != ! mep_pseudo_cr_is_float (regnr))
+        /* This module's coprocessor's GPR's are of a different type.  */
+        return "";
+
+      return register_name_from_keyword (names, mep_pseudo_cr_index (regnr));
+    }
+  else if (IS_CCR_REGNUM (regnr))
+    {
+      /* Does this module have a coprocessor at all?  */
+      if (! (current_options () & MEP_OPT_COP))
+        return "";
+
+      {
+        CGEN_KEYWORD *names = current_ccr_names ();
+
+        if (! names)
+          /* This me_module's coprocessor has no control registers.  */
+          return "";
+
+        return register_name_from_keyword (names, regnr-MEP_FIRST_CCR_REGNUM);
+      }
+    }
+
+  /* It might be nice to give the 'module' register a name, but that
+     would affect the output of 'info all-registers', which would
+     disturb the test suites.  So we leave it invisible.  */
+  else
+    return NULL;
+}
+
+
+/* Custom register groups for the MeP.  */
+static struct reggroup *mep_csr_reggroup; /* control/special */
+static struct reggroup *mep_cr_reggroup;  /* coprocessor general-purpose */
+static struct reggroup *mep_ccr_reggroup; /* coprocessor control */
+
+
+static int
+mep_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+                         struct reggroup *group)
+{
+  /* Filter reserved or unused register numbers.  */
+  {
+    const char *name = mep_register_name (regnum);
+
+    if (! name || name[0] == '\0')
+      return 0;
+  }
+
+  /* We could separate the GPRs and the CSRs.  Toshiba has approved of
+     the existing behavior, so we'd want to run that by them.  */
+  if (group == general_reggroup)
+    return (IS_GPR_REGNUM (regnum)
+            || IS_CSR_REGNUM (regnum));
+
+  /* Everything is in the 'all' reggroup, except for the raw CSR's.  */
+  else if (group == all_reggroup)
+    return (IS_GPR_REGNUM (regnum)
+            || IS_CSR_REGNUM (regnum)
+            || IS_CR_REGNUM (regnum)
+            || IS_CCR_REGNUM (regnum));
+
+  /* All registers should be saved and restored, except for the raw
+     CSR's.
+
+     This is probably right if the coprocessor is something like a
+     floating-point unit, but would be wrong if the coprocessor is
+     something that does I/O, where register accesses actually cause
+     externally-visible actions.  But I get the impression that the
+     coprocessor isn't supposed to do things like that --- you'd use a
+     hardware engine, perhaps.  */
+  else if (group == save_reggroup || group == restore_reggroup)
+    return (IS_GPR_REGNUM (regnum)
+            || IS_CSR_REGNUM (regnum)
+            || IS_CR_REGNUM (regnum)
+            || IS_CCR_REGNUM (regnum));
+
+  else if (group == mep_csr_reggroup)
+    return IS_CSR_REGNUM (regnum);
+  else if (group == mep_cr_reggroup)
+    return IS_CR_REGNUM (regnum);
+  else if (group == mep_ccr_reggroup)
+    return IS_CCR_REGNUM (regnum);
+  else
+    return 0;
+}
+
+
+static struct type *
+mep_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  /* Coprocessor general-purpose registers may be either 32 or 64 bits
+     long.  So for them, the raw registers are always 64 bits long (to
+     keep the 'g' packet format fixed), and the pseudoregisters vary
+     in length.  */
+  if (IS_RAW_CR_REGNUM (reg_nr))
+    return builtin_type_uint64;
+
+  /* Since GDB doesn't allow registers to change type, we have two
+     banks of pseudoregisters for the coprocessor general-purpose
+     registers: one that gives a 32-bit view, and one that gives a
+     64-bit view.  We hide or show one or the other depending on the
+     current module.  */
+  if (IS_CR_REGNUM (reg_nr))
+    {
+      int size = mep_pseudo_cr_size (reg_nr);
+      if (size == 32)
+        {
+          if (mep_pseudo_cr_is_float (reg_nr))
+            return builtin_type_float;
+          else
+            return builtin_type_uint32;
+        }
+      else if (size == 64)
+        {
+          if (mep_pseudo_cr_is_float (reg_nr))
+            return builtin_type_double;
+          else
+            return builtin_type_uint64;
+        }
+      else
+        gdb_assert (0);
+    }
+
+  /* All other registers are 32 bits long.  */
+  else
+    return builtin_type_uint32;
+}
+
+
+static CORE_ADDR
+mep_read_pc (ptid_t ptid)
+{
+  ptid_t saved_ptid;
+  CORE_ADDR pc;
+
+  saved_ptid = inferior_ptid;
+  inferior_ptid = ptid;
+
+  pc = read_register (MEP_PC_REGNUM);
+
+  inferior_ptid = saved_ptid;
+  return pc;
+}
+
+static void
+mep_write_pc (CORE_ADDR pc, ptid_t ptid)
+{
+  ptid_t saved_ptid;
+
+  saved_ptid = inferior_ptid;
+  inferior_ptid = ptid;
+
+  write_register (MEP_PC_REGNUM, pc);
+
+  inferior_ptid = saved_ptid;
+}
+
+
+static void
+mep_pseudo_cr32_read (struct gdbarch *gdbarch,
+                      struct regcache *regcache,
+                      int cookednum,
+                      void *buf)
+{
+  /* Read the raw register into a 64-bit buffer, and then return the
+     appropriate end of that buffer.  */
+  int rawnum = mep_pseudo_to_raw[cookednum];
+  char buf64[8];
+
+  gdb_assert (TYPE_LENGTH (register_type (gdbarch, rawnum)) == sizeof (buf64));
+  gdb_assert (TYPE_LENGTH (register_type (gdbarch, cookednum)) == 4);
+  regcache_raw_read (regcache, rawnum, buf64);
+  /* Slow, but legible.  */
+  store_unsigned_integer (buf, 4, extract_unsigned_integer (buf64, 8));
+}
+
+
+static void
+mep_pseudo_cr64_read (struct gdbarch *gdbarch,
+                      struct regcache *regcache,
+                      int cookednum,
+                      void *buf)
+{
+  regcache_raw_read (regcache, mep_pseudo_to_raw[cookednum], buf);
+}
+
+
+static void
+mep_pseudo_register_read (struct gdbarch *gdbarch,
+                          struct regcache *regcache,
+                          int cookednum,
+                          gdb_byte *buf)
+{
+  if (IS_CSR_REGNUM (cookednum)
+      || IS_CCR_REGNUM (cookednum))
+    regcache_raw_read (regcache, mep_pseudo_to_raw[cookednum], buf);
+  else if (IS_CR32_REGNUM (cookednum)
+           || IS_FP_CR32_REGNUM (cookednum))
+    mep_pseudo_cr32_read (gdbarch, regcache, cookednum, buf);
+  else if (IS_CR64_REGNUM (cookednum)
+           || IS_FP_CR64_REGNUM (cookednum))
+    mep_pseudo_cr64_read (gdbarch, regcache, cookednum, buf);
+  else
+    gdb_assert (0);
+}
+
+
+static void
+mep_pseudo_csr_write (struct gdbarch *gdbarch,
+                      struct regcache *regcache,
+                      int cookednum,
+                      const void *buf)
+{
+  int size = register_size (gdbarch, cookednum);
+  struct mep_csr_register *r
+    = &mep_csr_registers[cookednum - MEP_FIRST_CSR_REGNUM];
+
+  if (r->writeable_bits == 0)
+    /* A completely read-only register; avoid the read-modify-
+       write cycle, and juts ignore the entire write.  */
+    ;
+  else
+    {
+      /* A partially writeable register; do a read-modify-write cycle.  */
+      ULONGEST old_bits;
+      ULONGEST new_bits;
+      ULONGEST mixed_bits;
+          
+      regcache_raw_read_unsigned (regcache, r->raw, &old_bits);
+      new_bits = extract_unsigned_integer (buf, size);
+      mixed_bits = ((r->writeable_bits & new_bits)
+                    | (~r->writeable_bits & old_bits));
+      regcache_raw_write_unsigned (regcache, r->raw, mixed_bits);
+    }
+}
+                      
+
+static void
+mep_pseudo_cr32_write (struct gdbarch *gdbarch,
+                       struct regcache *regcache,
+                       int cookednum,
+                       const void *buf)
+{
+  /* Expand the 32-bit value into a 64-bit value, and write that to
+     the pseudoregister.  */
+  int rawnum = mep_pseudo_to_raw[cookednum];
+  char buf64[8];
+  
+  gdb_assert (TYPE_LENGTH (register_type (gdbarch, rawnum)) == sizeof (buf64));
+  gdb_assert (TYPE_LENGTH (register_type (gdbarch, cookednum)) == 4);
+  /* Slow, but legible.  */
+  store_unsigned_integer (buf64, 8, extract_unsigned_integer (buf, 4));
+  regcache_raw_write (regcache, rawnum, buf64);
+}
+
+
+static void
+mep_pseudo_cr64_write (struct gdbarch *gdbarch,
+                     struct regcache *regcache,
+                     int cookednum,
+                     const void *buf)
+{
+  regcache_raw_write (regcache, mep_pseudo_to_raw[cookednum], buf);
+}
+
+
+static void
+mep_pseudo_register_write (struct gdbarch *gdbarch,
+                           struct regcache *regcache,
+                           int cookednum,
+                           const gdb_byte *buf)
+{
+  if (IS_CSR_REGNUM (cookednum))
+    mep_pseudo_csr_write (gdbarch, regcache, cookednum, buf);
+  else if (IS_CR32_REGNUM (cookednum)
+           || IS_FP_CR32_REGNUM (cookednum))
+    mep_pseudo_cr32_write (gdbarch, regcache, cookednum, buf);
+  else if (IS_CR64_REGNUM (cookednum)
+           || IS_FP_CR64_REGNUM (cookednum))
+    mep_pseudo_cr64_write (gdbarch, regcache, cookednum, buf);
+  else if (IS_CCR_REGNUM (cookednum))
+    regcache_raw_write (regcache, mep_pseudo_to_raw[cookednum], buf);
+  else
+    gdb_assert (0);
+}
+
+
+\f
+/* Disassembly.  */
+
+/* The mep disassembler needs to know about the section in order to
+   work correctly. */
+int 
+mep_gdb_print_insn (bfd_vma pc, disassemble_info * info)
+{
+  struct obj_section * s = find_pc_section (pc);
+
+  if (s)
+    {
+      /* The libopcodes disassembly code uses the section to find the
+         BFD, the BFD to find the ELF header, the ELF header to find
+         the me_module index, and the me_module index to select the
+         right instructions to print.  */
+      info->section = s->the_bfd_section;
+      info->arch = bfd_arch_mep;
+       
+      return print_insn_mep (pc, info);
+    }
+  
+  return 0;
+}
+
+\f
+/* Prologue analysis.  */
+
+
+/* The MeP has two classes of instructions: "core" instructions, which
+   are pretty normal RISC chip stuff, and "coprocessor" instructions,
+   which are mostly concerned with moving data in and out of
+   coprocessor registers, and branching on coprocessor condition
+   codes.  There's space in the instruction set for custom coprocessor
+   instructions, too.
+
+   Instructions can be 16 or 32 bits long; the top two bits of the
+   first byte indicate the length.  The coprocessor instructions are
+   mixed in with the core instructions, and there's no easy way to
+   distinguish them; you have to completely decode them to tell one
+   from the other.
+
+   The MeP also supports a "VLIW" operation mode, where instructions
+   always occur in fixed-width bundles.  The bundles are either 32
+   bits or 64 bits long, depending on a fixed configuration flag.  You
+   decode the first part of the bundle as normal; if it's a core
+   instruction, and there's any space left in the bundle, the
+   remainder of the bundle is a coprocessor instruction, which will
+   execute in parallel with the core instruction.  If the first part
+   of the bundle is a coprocessor instruction, it occupies the entire
+   bundle.
+
+   So, here are all the cases:
+
+   - 32-bit VLIW mode:
+     Every bundle is four bytes long, and naturally aligned, and can hold
+     one or two instructions:
+     - 16-bit core instruction; 16-bit coprocessor instruction
+       These execute in parallel.       
+     - 32-bit core instruction
+     - 32-bit coprocessor instruction
+
+   - 64-bit VLIW mode:
+     Every bundle is eight bytes long, and naturally aligned, and can hold
+     one or two instructions:
+     - 16-bit core instruction; 48-bit (!) coprocessor instruction
+       These execute in parallel.       
+     - 32-bit core instruction; 32-bit coprocessor instruction
+       These execute in parallel.       
+     - 64-bit coprocessor instruction
+
+   Now, the MeP manual doesn't define any 48- or 64-bit coprocessor
+   instruction, so I don't really know what's up there; perhaps these
+   are always the user-defined coprocessor instructions.  */
+
+
+/* Return non-zero if PC is in a VLIW code section, zero
+   otherwise.  */
+static int
+mep_pc_in_vliw_section (CORE_ADDR pc)
+{
+  struct obj_section *s = find_pc_section (pc);
+  if (s)
+    return (s->the_bfd_section->flags & SEC_MEP_VLIW);
+  return 0;
+}
+
+
+/* Set *INSN to the next core instruction at PC, and return the
+   address of the next instruction.
+
+   The MeP instruction encoding is endian-dependent.  16- and 32-bit
+   instructions are encoded as one or two two-byte parts, and each
+   part is byte-swapped independently.  Thus:
+
+      void
+      foo (void)
+      {
+        asm ("movu $1, 0x123456");
+        asm ("sb $1,0x5678($2)");
+        asm ("clip $1, 19");
+      }
+
+   compiles to this big-endian code:
+
+       0:      d1 56 12 34     movu $1,0x123456
+       4:      c1 28 56 78     sb $1,22136($2)
+       8:      f1 01 10 98     clip $1,0x13
+       c:      70 02           ret
+
+   and this little-endian code:
+
+       0:      56 d1 34 12     movu $1,0x123456
+       4:      28 c1 78 56     sb $1,22136($2)
+       8:      01 f1 98 10     clip $1,0x13
+       c:      02 70           ret
+
+   Instructions are returned in *INSN in an endian-independent form: a
+   given instruction always appears in *INSN the same way, regardless
+   of whether the instruction stream is big-endian or little-endian.
+
+   *INSN's most significant 16 bits are the first (i.e., at lower
+   addresses) 16 bit part of the instruction.  Its least significant
+   16 bits are the second (i.e., higher-addressed) 16 bit part of the
+   instruction, or zero for a 16-bit instruction.  Both 16-bit parts
+   are fetched using the current endianness.
+
+   So, the *INSN values for the instruction sequence above would be
+   the following, in either endianness:
+
+       0xd1561234       movu $1,0x123456     
+       0xc1285678      sb $1,22136($2)
+       0xf1011098      clip $1,0x13
+       0x70020000              ret
+
+   (In a sense, it would be more natural to return 16-bit instructions
+   in the least significant 16 bits of *INSN, but that would be
+   ambiguous.  In order to tell whether you're looking at a 16- or a
+   32-bit instruction, you have to consult the major opcode field ---
+   the most significant four bits of the instruction's first 16-bit
+   part.  But if we put 16-bit instructions at the least significant
+   end of *INSN, then you don't know where to find the major opcode
+   field until you know if it's a 16- or a 32-bit instruction ---
+   which is where we started.)
+
+   If PC points to a core / coprocessor bundle in a VLIW section, set
+   *INSN to the core instruction, and return the address of the next
+   bundle.  This has the effect of skipping the bundled coprocessor
+   instruction.  That's okay, since coprocessor instructions aren't
+   significant to prologue analysis --- for the time being,
+   anyway.  */
+
+static CORE_ADDR 
+mep_get_insn (CORE_ADDR pc, long *insn)
+{
+  int pc_in_vliw_section;
+  int vliw_mode;
+  int insn_len;
+  char buf[2];
+
+  *insn = 0;
+
+  /* Are we in a VLIW section?  */
+  pc_in_vliw_section = mep_pc_in_vliw_section (pc);
+  if (pc_in_vliw_section)
+    {
+      /* Yes, find out which bundle size.  */
+      vliw_mode = current_options () & (MEP_OPT_VL32 | MEP_OPT_VL64);
+
+      /* If PC is in a VLIW section, but the current core doesn't say
+         that it supports either VLIW mode, then we don't have enough
+         information to parse the instruction stream it contains.
+         Since the "undifferentiated" standard core doesn't have
+         either VLIW mode bit set, this could happen.
+
+         But it shouldn't be an error to (say) set a breakpoint in a
+         VLIW section, if you know you'll never reach it.  (Perhaps
+         you have a script that sets a bunch of standard breakpoints.)
+
+         So we'll just return zero here, and hope for the best.  */
+      if (! (vliw_mode & (MEP_OPT_VL32 | MEP_OPT_VL64)))
+        return 0;
+
+      /* If both VL32 and VL64 are set, that's bogus, too.  */
+      if (vliw_mode == (MEP_OPT_VL32 | MEP_OPT_VL64))
+        return 0;
+    }
+  else
+    vliw_mode = 0;
+
+  read_memory (pc, buf, sizeof (buf));
+  *insn = extract_unsigned_integer (buf, 2) << 16;
+
+  /* The major opcode --- the top four bits of the first 16-bit
+     part --- indicates whether this instruction is 16 or 32 bits
+     long.  All 32-bit instructions have a major opcode whose top
+     two bits are 11; all the rest are 16-bit instructions.  */
+  if ((*insn & 0xc0000000) == 0xc0000000)
+    {
+      /* Fetch the second 16-bit part of the instruction.  */
+      read_memory (pc + 2, buf, sizeof (buf));
+      *insn = *insn | extract_unsigned_integer (buf, 2);
+    }
+
+  /* If we're in VLIW code, then the VLIW width determines the address
+     of the next instruction.  */
+  if (vliw_mode)
+    {
+      /* In 32-bit VLIW code, all bundles are 32 bits long.  We ignore the
+         coprocessor half of a core / copro bundle.  */
+      if (vliw_mode == MEP_OPT_VL32)
+        insn_len = 4;
+
+      /* In 64-bit VLIW code, all bundles are 64 bits long.  We ignore the
+         coprocessor half of a core / copro bundle.  */
+      else if (vliw_mode == MEP_OPT_VL64)
+        insn_len = 8;
+
+      /* We'd better be in either core, 32-bit VLIW, or 64-bit VLIW mode.  */
+      else
+        gdb_assert (0);
+    }
+  
+  /* Otherwise, the top two bits of the major opcode are (again) what
+     we need to check.  */
+  else if ((*insn & 0xc0000000) == 0xc0000000)
+    insn_len = 4;
+  else
+    insn_len = 2;
+
+  return pc + insn_len;
+}
+
+
+/* Sign-extend the LEN-bit value N.  */
+#define SEXT(n, len) ((((int) (n)) ^ (1 << ((len) - 1))) - (1 << ((len) - 1)))
+
+/* Return the LEN-bit field at POS from I.  */
+#define FIELD(i, pos, len) (((i) >> (pos)) & ((1 << (len)) - 1))
+
+/* Like FIELD, but sign-extend the field's value.  */
+#define SFIELD(i, pos, len) (SEXT (FIELD ((i), (pos), (len)), (len)))
+
+
+/* Macros for decoding instructions.
+
+   Remember that 16-bit instructions are placed in bits 16..31 of i,
+   not at the least significant end; this means that the major opcode
+   field is always in the same place, regardless of the width of the
+   instruction.  As a reminder of this, we show the lower 16 bits of a
+   16-bit instruction as xxxx_xxxx_xxxx_xxxx.  */
+
+/* SB Rn,(Rm)                0000_nnnn_mmmm_1000 */
+/* SH Rn,(Rm)                0000_nnnn_mmmm_1001 */
+/* SW Rn,(Rm)                0000_nnnn_mmmm_1010 */
+
+/* SW Rn,disp16(Rm)          1100_nnnn_mmmm_1010 dddd_dddd_dddd_dddd */
+#define IS_SW(i)             (((i) & 0xf00f0000) == 0xc00a0000)
+/* SB Rn,disp16(Rm)          1100_nnnn_mmmm_1000 dddd_dddd_dddd_dddd */
+#define IS_SB(i)             (((i) & 0xf00f0000) == 0xc0080000)
+/* SH Rn,disp16(Rm)          1100_nnnn_mmmm_1001 dddd_dddd_dddd_dddd */
+#define IS_SH(i)             (((i) & 0xf00f0000) == 0xc0090000)
+#define SWBH_32_BASE(i)       (FIELD (i, 20, 4))
+#define SWBH_32_SOURCE(i)     (FIELD (i, 24, 4))
+#define SWBH_32_OFFSET(i)     (SFIELD (i, 0, 16))
+
+/* SW Rn,disp7.align4(SP)     0100_nnnn_0ddd_dd10 xxxx_xxxx_xxxx_xxxx */
+#define IS_SW_IMMD(i)        (((i) & 0xf0830000) == 0x40020000)
+#define SW_IMMD_SOURCE(i)     (FIELD (i, 24, 4))
+#define SW_IMMD_OFFSET(i)     (FIELD (i, 18, 5) << 2)
+
+/* SW Rn,(Rm)                 0000_nnnn_mmmm_1010 xxxx_xxxx_xxxx_xxxx */
+#define IS_SW_REG(i)         (((i) & 0xf00f0000) == 0x000a0000)
+#define SW_REG_SOURCE(i)      (FIELD (i, 24, 4))
+#define SW_REG_BASE(i)        (FIELD (i, 20, 4))
+
+/* ADD3 Rl,Rn,Rm              1001_nnnn_mmmm_llll xxxx_xxxx_xxxx_xxxx */
+#define IS_ADD3_16_REG(i)     (((i) & 0xf0000000) == 0x90000000)
+#define ADD3_16_REG_SRC1(i)   (FIELD (i, 20, 4))               /* n */
+#define ADD3_16_REG_SRC2(i)   (FIELD (i, 24, 4))               /* m */
+
+/* ADD3 Rn,Rm,imm16           1100_nnnn_mmmm_0000 iiii_iiii_iiii_iiii */
+#define IS_ADD3_32(i)        (((i) & 0xf00f0000) == 0xc0000000)
+#define ADD3_32_TARGET(i)     (FIELD (i, 24, 4))
+#define ADD3_32_SOURCE(i)     (FIELD (i, 20, 4))
+#define ADD3_32_OFFSET(i)     (SFIELD (i, 0, 16))
+
+/* ADD3 Rn,SP,imm7.align4     0100_nnnn_0iii_ii00 xxxx_xxxx_xxxx_xxxx */
+#define IS_ADD3_16(i)                (((i) & 0xf0830000) == 0x40000000)
+#define ADD3_16_TARGET(i)     (FIELD (i, 24, 4))
+#define ADD3_16_OFFSET(i)     (FIELD (i, 18, 5) << 2)
+
+/* ADD Rn,imm6               0110_nnnn_iiii_ii00 xxxx_xxxx_xxxx_xxxx */
+#define IS_ADD(i)            (((i) & 0xf0030000) == 0x60000000)
+#define ADD_TARGET(i)        (FIELD (i, 24, 4))
+#define ADD_OFFSET(i)         (SFIELD (i, 18, 6))
+
+/* LDC Rn,imm5               0111_nnnn_iiii_101I xxxx_xxxx_xxxx_xxxx
+                              imm5 = I||i[7:4] */
+#define IS_LDC(i)            (((i) & 0xf00e0000) == 0x700a0000)
+#define LDC_IMM(i)            ((FIELD (i, 16, 1) << 4) | FIELD (i, 20, 4))
+#define LDC_TARGET(i)         (FIELD (i, 24, 4))
+
+/* LW Rn,disp16(Rm)           1100_nnnn_mmmm_1110 dddd_dddd_dddd_dddd  */
+#define IS_LW(i)              (((i) & 0xf00f0000) == 0xc00e0000)
+#define LW_TARGET(i)          (FIELD (i, 24, 4))
+#define LW_BASE(i)            (FIELD (i, 20, 4))
+#define LW_OFFSET(i)          (SFIELD (i, 0, 16))
+
+/* MOV Rn,Rm                 0000_nnnn_mmmm_0000 xxxx_xxxx_xxxx_xxxx */
+#define IS_MOV(i)            (((i) & 0xf00f0000) == 0x00000000)
+#define MOV_TARGET(i)        (FIELD (i, 24, 4))
+#define MOV_SOURCE(i)        (FIELD (i, 20, 4))
+
+
+/* This structure holds the results of a prologue analysis.  */
+struct mep_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[MEP_NUM_REGS];
+};
+
+/* Return non-zero if VALUE is an incoming argument register.  */
+
+static int
+is_arg_reg (pv_t value)
+{
+  return (value.kind == pvk_register
+          && MEP_R1_REGNUM <= value.reg && value.reg <= MEP_R4_REGNUM
+          && value.k == 0);
+}
+
+/* Return non-zero if a store of REG's current value VALUE to ADDR is
+   probably spilling an argument register to its stack slot in STACK.
+   Such instructions should be included in the prologue, if possible.
+
+   The store is a spill if:
+   - the value being stored is REG's original value;
+   - the value has not already been stored somewhere in STACK; and
+   - ADDR is a stack slot's address (e.g., relative to the original
+     value of the SP).  */
+static int
+is_arg_spill (pv_t value, pv_t addr, struct pv_area *stack)
+{
+  return (is_arg_reg (value)
+          && pv_is_register (addr, MEP_SP_REGNUM)
+          && ! pv_area_find_reg (stack, current_gdbarch, value.reg, 0));
+}
+
+
+/* Function for finding saved registers in a 'struct pv_area'; we pass
+   this to pv_area_scan.
+
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset in RESULT_UNTYPED.  */
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct mep_prologue *result = (struct mep_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, MEP_SP_REGNUM)
+      && size == register_size (current_gdbarch, value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+static void
+mep_analyze_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
+                      struct mep_prologue *result)
+{
+  CORE_ADDR pc;
+  unsigned long insn;
+  int rn;
+  int found_lp = 0;
+  pv_t reg[MEP_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < MEP_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (MEP_SP_REGNUM);
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      CORE_ADDR next_pc;
+      pv_t pre_insn_fp, pre_insn_sp;
+
+      next_pc = mep_get_insn (pc, &insn);
+
+      /* A zero return from mep_get_insn means that either we weren't
+         able to read the instruction from memory, or that we don't
+         have enough information to be able to reliably decode it.  So
+         we'll store here and hope for the best.  */
+      if (! next_pc)
+        break;
+
+      /* Note the current values of the SP and FP, so we can tell if
+         this instruction changed them, below.  */
+      pre_insn_fp = reg[MEP_FP_REGNUM];
+      pre_insn_sp = reg[MEP_SP_REGNUM];
+
+      if (IS_ADD (insn))
+        {
+          int rn = ADD_TARGET (insn);
+          CORE_ADDR imm6 = ADD_OFFSET (insn);
+
+          reg[rn] = pv_add_constant (reg[rn], imm6);
+        }
+      else if (IS_ADD3_16 (insn))
+       {
+          int rn = ADD3_16_TARGET (insn);
+          int imm7 = ADD3_16_OFFSET (insn);
+
+          reg[rn] = pv_add_constant (reg[MEP_SP_REGNUM], imm7);
+        }
+      else if (IS_ADD3_32 (insn))
+       {
+          int rn = ADD3_32_TARGET (insn);
+          int rm = ADD3_32_SOURCE (insn);
+          int imm16 = ADD3_32_OFFSET (insn);
+
+          reg[rn] = pv_add_constant (reg[rm], imm16);
+       }
+      else if (IS_SW_REG (insn))
+        {
+          int rn = SW_REG_SOURCE (insn);
+          int rm = SW_REG_BASE (insn);
+
+          /* If simulating this store would require us to forget
+             everything we know about the stack frame in the name of
+             accuracy, it would be better to just quit now.  */
+          if (pv_area_store_would_trash (stack, reg[rm]))
+            break;
+          
+          if (is_arg_spill (reg[rn], reg[rm], stack))
+            after_last_frame_setup_insn = next_pc;
+
+          pv_area_store (stack, reg[rm], 4, reg[rn]);
+        }
+      else if (IS_SW_IMMD (insn))
+        {
+          int rn = SW_IMMD_SOURCE (insn);
+          int offset = SW_IMMD_OFFSET (insn);
+          pv_t addr = pv_add_constant (reg[MEP_SP_REGNUM], offset);
+
+          /* If simulating this store would require us to forget
+             everything we know about the stack frame in the name of
+             accuracy, it would be better to just quit now.  */
+          if (pv_area_store_would_trash (stack, addr))
+            break;
+
+          if (is_arg_spill (reg[rn], addr, stack))
+            after_last_frame_setup_insn = next_pc;
+
+          pv_area_store (stack, addr, 4, reg[rn]);
+        }
+      else if (IS_MOV (insn))
+       {
+          int rn = MOV_TARGET (insn);
+          int rm = MOV_SOURCE (insn);
+
+          reg[rn] = reg[rm];
+
+         if (pv_is_register (reg[rm], rm) && is_arg_reg (reg[rm]))
+           after_last_frame_setup_insn = next_pc;
+       }
+      else if (IS_SB (insn) || IS_SH (insn) || IS_SW (insn))
+       {
+          int rn = SWBH_32_SOURCE (insn);
+          int rm = SWBH_32_BASE (insn);
+          int disp = SWBH_32_OFFSET (insn);
+          int size = (IS_SB (insn) ? 1
+                      : IS_SH (insn) ? 2
+                      : IS_SW (insn) ? 4
+                      : (gdb_assert (0), 1));
+          pv_t addr = pv_add_constant (reg[rm], disp);
+
+          if (pv_area_store_would_trash (stack, addr))
+            break;
+
+          if (is_arg_spill (reg[rn], addr, stack))
+            after_last_frame_setup_insn = next_pc;
+
+          pv_area_store (stack, addr, size, reg[rn]);
+       }
+      else if (IS_LDC (insn))
+       {
+          int rn = LDC_TARGET (insn);
+          int cr = LDC_IMM (insn) + MEP_FIRST_CSR_REGNUM;
+
+          reg[rn] = reg[cr];
+       }
+      else if (IS_LW (insn))
+        {
+          int rn = LW_TARGET (insn);
+          int rm = LW_BASE (insn);
+          int offset = LW_OFFSET (insn);
+          pv_t addr = pv_add_constant (reg[rm], offset);
+
+          reg[rn] = pv_area_fetch (stack, addr, 4);
+        }
+      else
+        /* We've hit some instruction we don't know how to simulate.
+           Strictly speaking, we should set every value we're
+           tracking to "unknown".  But we'll be optimistic, assume
+           that we have enough information already, and stop
+           analysis here.  */
+        break;
+
+      /* If this instruction changed the FP or decreased the SP (i.e.,
+         allocated more stack space), then this may be a good place to
+         declare the prologue finished.  However, there are some
+         exceptions:
+
+         - If the instruction just changed the FP back to its original
+           value, then that's probably a restore instruction.  The
+           prologue should definitely end before that.  
+
+         - If the instruction increased the value of the SP (that is,
+           shrunk the frame), then it's probably part of a frame
+           teardown sequence, and the prologue should end before that.  */
+
+      if (! pv_is_identical (reg[MEP_FP_REGNUM], pre_insn_fp))
+        {
+          if (! pv_is_register_k (reg[MEP_FP_REGNUM], MEP_FP_REGNUM, 0))
+            after_last_frame_setup_insn = next_pc;
+        }
+      else if (! pv_is_identical (reg[MEP_SP_REGNUM], pre_insn_sp))
+        {
+          /* The comparison of constants looks odd, there, because .k
+             is unsigned.  All it really means is that the new value
+             is lower than it was before the instruction.  */
+          if (pv_is_register (pre_insn_sp, MEP_SP_REGNUM)
+              && pv_is_register (reg[MEP_SP_REGNUM], MEP_SP_REGNUM)
+              && ((pre_insn_sp.k - reg[MEP_SP_REGNUM].k)
+                  < (reg[MEP_SP_REGNUM].k - pre_insn_sp.k)))
+            after_last_frame_setup_insn = next_pc;
+        }
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[MEP_SP_REGNUM], MEP_SP_REGNUM))
+    result->frame_size = reg[MEP_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[MEP_FP_REGNUM], MEP_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[MEP_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+
+  do_cleanups (back_to);
+}
+
+
+static CORE_ADDR
+mep_skip_prologue (CORE_ADDR pc)
+{
+  char *name;
+  CORE_ADDR func_addr, func_end;
+  struct mep_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (! find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  mep_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+
+\f
+/* Breakpoints.  */
+
+static const unsigned char *
+mep_breakpoint_from_pc (CORE_ADDR * pcptr, int *lenptr)
+{
+  static unsigned char breakpoint[] = { 0x70, 0x32 };
+  *lenptr = sizeof (breakpoint);
+  return breakpoint;
+}
+
+
+\f
+/* Frames and frame unwinding.  */
+
+
+static struct mep_prologue *
+mep_analyze_frame_prologue (struct frame_info *next_frame,
+                            void **this_prologue_cache)
+{
+  if (! *this_prologue_cache)
+    {
+      CORE_ADDR func_start, stop_addr;
+
+      *this_prologue_cache 
+        = FRAME_OBSTACK_ZALLOC (struct mep_prologue);
+
+      func_start = frame_func_unwind (next_frame);
+      stop_addr = frame_pc_unwind (next_frame);
+
+      /* If we couldn't find any function containing the PC, then
+         just initialize the prologue cache, but don't do anything.  */
+      if (! func_start)
+        stop_addr = func_start;
+
+      mep_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+    }
+
+  return *this_prologue_cache;
+}
+
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+static CORE_ADDR
+mep_frame_base (struct frame_info *next_frame,
+                void **this_prologue_cache)
+{
+  struct mep_prologue *p
+    = mep_analyze_frame_prologue (next_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp
+        = frame_unwind_register_unsigned (next_frame, MEP_FP_REGNUM);
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp
+        = frame_unwind_register_unsigned (next_frame, MEP_SP_REGNUM);
+      return sp - p->frame_size;
+    }
+}
+
+
+static void
+mep_frame_this_id (struct frame_info *next_frame,
+                   void **this_prologue_cache,
+                   struct frame_id *this_id)
+{
+  *this_id = frame_id_build (mep_frame_base (next_frame, this_prologue_cache),
+                             frame_func_unwind (next_frame));
+}
+
+
+static void
+mep_frame_prev_register (struct frame_info *next_frame,
+                         void **this_prologue_cache,
+                         int regnum, int *optimizedp,
+                         enum lval_type *lvalp, CORE_ADDR *addrp,
+                         int *realnump, gdb_byte *bufferp)
+{
+  struct mep_prologue *p
+    = mep_analyze_frame_prologue (next_frame, this_prologue_cache);
+
+  /* There are a number of complications in unwinding registers on the
+     MeP, having to do with core functions calling VLIW functions and
+     vice versa.
+
+     The least significant bit of the link register, LP.LTOM, is the
+     VLIW mode toggle bit: it's set if a core function called a VLIW
+     function, or vice versa, and clear when the caller and callee
+     were both in the same mode.
+
+     So, if we're asked to unwind the PC, then we really want to
+     unwind the LP and clear the least significant bit.  (Real return
+     addresses are always even.)  And if we want to unwind the program
+     status word (PSW), we need to toggle PSW.OM if LP.LTOM is set.
+
+     Tweaking the register values we return in this way means that the
+     bits in BUFFERP[] are not the same as the bits you'd find at
+     ADDRP in the inferior, so we make sure lvalp is not_lval when we
+     do this.  */
+  if (regnum == MEP_PC_REGNUM)
+    {
+      mep_frame_prev_register (next_frame, this_prologue_cache, MEP_LP_REGNUM,
+                               optimizedp, lvalp, addrp, realnump, bufferp);
+      store_unsigned_integer (bufferp, MEP_LP_SIZE, 
+                              (extract_unsigned_integer (bufferp, MEP_LP_SIZE)
+                               & ~1));
+      *lvalp = not_lval;
+    }
+  else
+    {
+      CORE_ADDR frame_base = mep_frame_base (next_frame, this_prologue_cache);
+      int reg_size = register_size (get_frame_arch (next_frame), regnum);
+
+      /* Our caller's SP is our frame base.  */
+      if (regnum == MEP_SP_REGNUM)
+        {
+          *optimizedp = 0;
+          *lvalp = not_lval;
+          *addrp = 0;
+          *realnump = -1;
+          if (bufferp)
+            store_unsigned_integer (bufferp, reg_size, frame_base);
+        }
+
+      /* If prologue analysis says we saved this register somewhere,
+         return a description of the stack slot holding it.  */
+      else if (p->reg_offset[regnum] != 1)
+        {
+          *optimizedp = 0;
+          *lvalp = lval_memory;
+          *addrp = frame_base + p->reg_offset[regnum];
+          *realnump = -1;
+          if (bufferp)
+            get_frame_memory (next_frame, *addrp, bufferp, reg_size);
+        }
+
+      /* Otherwise, presume we haven't changed the value of this
+         register, and get it from the next frame.  */
+      else
+        frame_register_unwind (next_frame, regnum,
+                               optimizedp, lvalp, addrp, realnump, bufferp);
+
+      /* If we need to toggle the operating mode, do so.  */
+      if (regnum == MEP_PSW_REGNUM)
+        {
+          int lp_optimized;
+          enum lval_type lp_lval;
+          CORE_ADDR lp_addr;
+          int lp_realnum;
+          char lp_buffer[MEP_LP_SIZE];
+
+          /* Get the LP's value, too.  */
+          frame_register_unwind (next_frame, MEP_LP_REGNUM,
+                                 &lp_optimized, &lp_lval, &lp_addr,
+                                 &lp_realnum, lp_buffer);
+
+          /* If LP.LTOM is set, then toggle PSW.OM.  */
+          if (extract_unsigned_integer (lp_buffer, MEP_LP_SIZE) & 0x1)
+            store_unsigned_integer
+              (bufferp, MEP_PSW_SIZE,
+               (extract_unsigned_integer (bufferp, MEP_PSW_SIZE) ^ 0x1000));
+          *lvalp = not_lval;
+        }
+    }
+}
+
+
+static const struct frame_unwind mep_frame_unwind = {
+  NORMAL_FRAME,
+  mep_frame_this_id,
+  mep_frame_prev_register
+};
+
+
+static const struct frame_unwind *
+mep_frame_sniffer (struct frame_info *next_frame)
+{
+  return &mep_frame_unwind;
+}
+
+
+/* Our general unwinding function can handle unwinding the PC.  */
+static CORE_ADDR
+mep_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, MEP_PC_REGNUM);
+}
+
+
+/* Our general unwinding function can handle unwinding the SP.  */
+static CORE_ADDR
+mep_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, MEP_SP_REGNUM);
+}
+
+
+\f
+/* Return values.  */
+
+
+static int
+mep_use_struct_convention (struct type *type)
+{
+  return (TYPE_LENGTH (type) > MEP_GPR_SIZE);
+}
+
+
+static void
+mep_extract_return_value (struct gdbarch *arch,
+                          struct type *type,
+                          struct regcache *regcache,
+                          gdb_byte *valbuf)
+{
+  int byte_order = gdbarch_byte_order (arch);
+
+  /* Values that don't occupy a full register appear at the less
+     significant end of the value.  This is the offset to where the
+     value starts.  */
+  int offset;
+
+  /* Return values > MEP_GPR_SIZE bytes are returned in memory,
+     pointed to by R0.  */
+  gdb_assert (TYPE_LENGTH (type) <= MEP_GPR_SIZE);
+
+  if (byte_order == BFD_ENDIAN_BIG)
+    offset = MEP_GPR_SIZE - TYPE_LENGTH (type);
+  else
+    offset = 0;
+
+  /* Return values that do fit in a single register are returned in R0. */
+  regcache_cooked_read_part (regcache, MEP_R0_REGNUM,
+                             offset, TYPE_LENGTH (type),
+                             valbuf);
+}
+
+
+static void
+mep_store_return_value (struct gdbarch *arch,
+                        struct type *type,
+                        struct regcache *regcache,
+                        const gdb_byte *valbuf)
+{
+  int byte_order = gdbarch_byte_order (arch);
+
+  /* Values that fit in a single register go in R0.  */
+  if (TYPE_LENGTH (type) <= MEP_GPR_SIZE)
+    {
+      /* Values that don't occupy a full register appear at the least
+         significant end of the value.  This is the offset to where the
+         value starts.  */
+      int offset;
+
+      if (byte_order == BFD_ENDIAN_BIG)
+        offset = MEP_GPR_SIZE - TYPE_LENGTH (type);
+      else
+        offset = 0;
+
+      regcache_cooked_write_part (regcache, MEP_R0_REGNUM,
+                                  offset, TYPE_LENGTH (type),
+                                  valbuf);
+    }
+
+  /* Return values larger than a single register are returned in
+     memory, pointed to by R0.  Unfortunately, we can't count on R0
+     pointing to the return buffer, so we raise an error here. */
+  else
+    error ("GDB cannot set return values larger than four bytes; "
+           "the Media Processor's\n"
+           "calling conventions do not provide enough information "
+           "to do this.\n"
+           "Try using the 'return' command with no argument.");
+}
+
+enum return_value_convention
+mep_return_value (struct gdbarch *gdbarch, struct type *type,
+                 struct regcache *regcache, gdb_byte *readbuf,
+                 const gdb_byte *writebuf)
+{
+  if (mep_use_struct_convention (type))
+    {
+      if (readbuf)
+       {
+         ULONGEST addr;
+         /* Although the address of the struct buffer gets passed in R1, it's
+            returned in R0.  Fetch R0's value and then read the memory
+            at that address.  */
+         regcache_raw_read_unsigned (regcache, MEP_R0_REGNUM, &addr);
+         read_memory (addr, readbuf, TYPE_LENGTH (type));
+       }
+      if (writebuf)
+       {
+         /* Return values larger than a single register are returned in
+            memory, pointed to by R0.  Unfortunately, we can't count on R0
+            pointing to the return buffer, so we raise an error here. */
+         error ("GDB cannot set return values larger than four bytes; "
+                "the Media Processor's\n"
+                "calling conventions do not provide enough information "
+                "to do this.\n"
+                "Try using the 'return' command with no argument.");
+       }
+      return RETURN_VALUE_ABI_RETURNS_ADDRESS;
+    }
+
+  if (readbuf)
+    mep_extract_return_value (gdbarch, type, regcache, readbuf);
+  if (writebuf)
+    mep_store_return_value (gdbarch, type, regcache, writebuf);
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+\f
+/* Inferior calls.  */
+
+
+static CORE_ADDR
+mep_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  /* Require word alignment.  */
+  return sp & -4;
+}
+
+
+/* From "lang_spec2.txt":
+
+   4.2 Calling conventions
+
+   4.2.1 Core register conventions
+
+   - Parameters should be evaluated from left to right, and they
+     should be held in $1,$2,$3,$4 in order. The fifth parameter or
+     after should be held in the stack. If the size is larger than 4
+     bytes in the first four parameters, the pointer should be held in
+     the registers instead. If the size is larger than 4 bytes in the
+     fifth parameter or after, the pointer should be held in the stack.
+
+   - Return value of a function should be held in register $0. If the
+     size of return value is larger than 4 bytes, $1 should hold the
+     pointer pointing memory that would hold the return value. In this
+     case, the first parameter should be held in $2, the second one in
+     $3, and the third one in $4, and the forth parameter or after
+     should be held in the stack.
+
+   [This doesn't say so, but arguments shorter than four bytes are
+   passed in the least significant end of a four-byte word when
+   they're passed on the stack.]  */
+
+
+/* Traverse the list of ARGC arguments ARGV; for every ARGV[i] too
+   large to fit in a register, save it on the stack, and place its
+   address in COPY[i].  SP is the initial stack pointer; return the
+   new stack pointer.  */
+static CORE_ADDR
+push_large_arguments (CORE_ADDR sp, int argc, struct value **argv,
+                      CORE_ADDR copy[])
+{
+  int i;
+
+  for (i = 0; i < argc; i++)
+    {
+      unsigned arg_len = TYPE_LENGTH (value_type (argv[i]));
+
+      if (arg_len > MEP_GPR_SIZE)
+        {
+          /* Reserve space for the copy, and then round the SP down, to
+             make sure it's all aligned properly.  */
+          sp = (sp - arg_len) & -4;
+          write_memory (sp, value_contents (argv[i]), arg_len);
+          copy[i] = sp;
+        }
+    }
+
+  return sp;
+}
+
+
+static CORE_ADDR
+mep_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+                     struct regcache *regcache, CORE_ADDR bp_addr,
+                     int argc, struct value **argv, CORE_ADDR sp,
+                     int struct_return,
+                     CORE_ADDR struct_addr)
+{
+  CORE_ADDR *copy = (CORE_ADDR *) alloca (argc * sizeof (copy[0]));
+  CORE_ADDR func_addr = find_function_addr (function, NULL);
+  int i;
+
+  /* The number of the next register available to hold an argument.  */
+  int arg_reg;
+
+  /* The address of the next stack slot available to hold an argument.  */
+  CORE_ADDR arg_stack;
+
+  /* The address of the end of the stack area for arguments.  This is
+     just for error checking.  */
+  CORE_ADDR arg_stack_end;
+  
+  sp = push_large_arguments (sp, argc, argv, copy);
+
+  /* Reserve space for the stack arguments, if any.  */
+  arg_stack_end = sp;
+  if (argc + (struct_addr ? 1 : 0) > 4)
+    sp -= ((argc + (struct_addr ? 1 : 0)) - 4) * MEP_GPR_SIZE;
+
+  arg_reg = MEP_R1_REGNUM;
+  arg_stack = sp;
+
+  /* If we're returning a structure by value, push the pointer to the
+     buffer as the first argument.  */
+  if (struct_return)
+    {
+      regcache_cooked_write_unsigned (regcache, arg_reg, struct_addr);
+      arg_reg++;
+    }
+
+  for (i = 0; i < argc; i++)
+    {
+      unsigned arg_size = TYPE_LENGTH (value_type (argv[i]));
+      ULONGEST value;
+
+      /* Arguments that fit in a GPR get expanded to fill the GPR.  */
+      if (arg_size <= MEP_GPR_SIZE)
+        value = extract_unsigned_integer (value_contents (argv[i]),
+                                          TYPE_LENGTH (value_type (argv[i])));
+
+      /* Arguments too large to fit in a GPR get copied to the stack,
+         and we pass a pointer to the copy.  */
+      else
+        value = copy[i];
+
+      /* We use $1 -- $4 for passing arguments, then use the stack.  */
+      if (arg_reg <= MEP_R4_REGNUM)
+        {
+          regcache_cooked_write_unsigned (regcache, arg_reg, value);
+          arg_reg++;
+        }
+      else
+        {
+          char buf[MEP_GPR_SIZE];
+          store_unsigned_integer (buf, MEP_GPR_SIZE, value);
+          write_memory (arg_stack, buf, MEP_GPR_SIZE);
+          arg_stack += MEP_GPR_SIZE;
+        }
+    }
+
+  gdb_assert (arg_stack <= arg_stack_end);
+
+  /* Set the return address.  */
+  regcache_cooked_write_unsigned (regcache, MEP_LP_REGNUM, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, MEP_SP_REGNUM, sp);
+  
+  return sp;
+}
+
+
+static struct frame_id
+mep_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+  return frame_id_build (mep_unwind_sp (gdbarch, next_frame),
+                         frame_pc_unwind (next_frame));
+}
+
+
+\f
+/* Initialization.  */
+
+
+static struct gdbarch *
+mep_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+
+  /* Which me_module are we building a gdbarch object for?  */
+  CONFIG_ATTR me_module;
+
+  /* If we have a BFD in hand, figure out which me_module it was built
+     for.  Otherwise, use the no-particular-me_module code.  */
+  if (info.abfd)
+    {
+      /* The way to get the me_module code depends on the object file
+         format.  At the moment, we only know how to handle ELF.  */
+      if (bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+        me_module = elf_elfheader (info.abfd)->e_flags & EF_MEP_INDEX_MASK;
+      else
+        me_module = CONFIG_NONE;
+    }
+  else
+    me_module = CONFIG_NONE;
+
+  /* If we're setting the architecture from a file, check the
+     endianness of the file against that of the me_module.  */
+  if (info.abfd)
+    {
+      /* The negations on either side make the comparison treat all
+         non-zero (true) values as equal.  */
+      if (! bfd_big_endian (info.abfd) != ! me_module_big_endian (me_module))
+        {
+          const char *module_name = me_module_name (me_module);
+          const char *module_endianness
+            = me_module_big_endian (me_module) ? "big" : "little";
+          const char *file_name = bfd_get_filename (info.abfd);
+          const char *file_endianness
+            = bfd_big_endian (info.abfd) ? "big" : "little";
+          
+          fputc_unfiltered ('\n', gdb_stderr);
+          if (module_name)
+            warning ("the MeP module '%s' is %s-endian, but the executable\n"
+                     "%s is %s-endian.",
+                     module_name, module_endianness,
+                     file_name, file_endianness);
+          else
+            warning ("the selected MeP module is %s-endian, but the "
+                     "executable\n"
+                     "%s is %s-endian.",
+                     module_endianness, file_name, file_endianness);
+        }
+    }
+
+  /* Find a candidate among the list of architectures we've created
+     already.  info->bfd_arch_info needs to match, but we also want
+     the right me_module: the ELF header's e_flags field needs to
+     match as well.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info); 
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    if (gdbarch_tdep (arches->gdbarch)->me_module == me_module)
+      return arches->gdbarch;
+
+  tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+  gdbarch = gdbarch_alloc (&info, tdep);
+
+  /* Get a CGEN CPU descriptor for this architecture.  */
+  {
+    const char *mach_name = info.bfd_arch_info->printable_name;
+    enum cgen_endian endian = (info.byte_order == BFD_ENDIAN_BIG
+                               ? CGEN_ENDIAN_BIG
+                               : CGEN_ENDIAN_LITTLE);
+
+    tdep->cpu_desc = mep_cgen_cpu_open (CGEN_CPU_OPEN_BFDMACH, mach_name,
+                                        CGEN_CPU_OPEN_ENDIAN, endian,
+                                        CGEN_CPU_OPEN_END);
+  }
+
+  tdep->me_module = me_module;
+
+  /* Register set.  */
+  set_gdbarch_read_pc (gdbarch, mep_read_pc);
+  set_gdbarch_write_pc (gdbarch, mep_write_pc);
+  set_gdbarch_num_regs (gdbarch, MEP_NUM_RAW_REGS);
+  set_gdbarch_sp_regnum (gdbarch, MEP_SP_REGNUM);
+  set_gdbarch_register_name (gdbarch, mep_register_name);
+  set_gdbarch_register_type (gdbarch, mep_register_type);
+  set_gdbarch_num_pseudo_regs (gdbarch, MEP_NUM_PSEUDO_REGS);
+  set_gdbarch_pseudo_register_read (gdbarch, mep_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, mep_pseudo_register_write);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, mep_debug_reg_to_regnum);
+  set_gdbarch_stab_reg_to_regnum (gdbarch, mep_debug_reg_to_regnum);
+
+  set_gdbarch_register_reggroup_p (gdbarch, mep_register_reggroup_p);
+  reggroup_add (gdbarch, all_reggroup);
+  reggroup_add (gdbarch, general_reggroup);
+  reggroup_add (gdbarch, save_reggroup);
+  reggroup_add (gdbarch, restore_reggroup);
+  reggroup_add (gdbarch, mep_csr_reggroup);
+  reggroup_add (gdbarch, mep_cr_reggroup);
+  reggroup_add (gdbarch, mep_ccr_reggroup);
+
+  /* Disassembly.  */
+  set_gdbarch_print_insn (gdbarch, mep_gdb_print_insn); 
+
+  /* Breakpoints.  */
+  set_gdbarch_breakpoint_from_pc (gdbarch, mep_breakpoint_from_pc);
+  set_gdbarch_decr_pc_after_break (gdbarch, 0);
+  set_gdbarch_skip_prologue (gdbarch, mep_skip_prologue);
+
+  /* Frames and frame unwinding.  */
+  frame_unwind_append_sniffer (gdbarch, mep_frame_sniffer);
+  set_gdbarch_unwind_pc (gdbarch, mep_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, mep_unwind_sp);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_frame_args_skip (gdbarch, 0);
+
+  /* Return values.  */
+  set_gdbarch_return_value (gdbarch, mep_return_value);
+  
+  /* Inferior function calls.  */
+  set_gdbarch_frame_align (gdbarch, mep_frame_align);
+  set_gdbarch_push_dummy_call (gdbarch, mep_push_dummy_call);
+  set_gdbarch_unwind_dummy_id (gdbarch, mep_unwind_dummy_id);
+
+  return gdbarch;
+}
+
+
+void
+_initialize_mep_tdep (void)
+{
+  mep_csr_reggroup = reggroup_new ("csr", USER_REGGROUP);
+  mep_cr_reggroup  = reggroup_new ("cr", USER_REGGROUP); 
+  mep_ccr_reggroup = reggroup_new ("ccr", USER_REGGROUP);
+
+  register_gdbarch_init (bfd_arch_mep, mep_gdbarch_init);
+
+  mep_init_pseudoregister_maps ();
+}