From aeb4312340c07721ec9f914d67ccd4fc21385e46 Mon Sep 17 00:00:00 2001 From: Kevin Buettner Date: Fri, 23 Feb 2007 22:50:41 +0000 Subject: [PATCH] Add support for new target, Toshiba Media Processor (MeP). --- gdb/ChangeLog | 10 + gdb/Makefile.in | 10 + gdb/config/mep/mep.mt | 3 + gdb/configure.tgt | 2 + gdb/mep-tdep.c | 2509 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 2534 insertions(+) create mode 100644 gdb/config/mep/mep.mt create mode 100644 gdb/mep-tdep.c diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a1bdf895169..cdcbdda7cf0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2007-02-23 Kevin Buettner + + 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 * infrun.c (inferior_stop_reason, print_stop_reason): Remove diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5047ffb1b73..4b9f988869d 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -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 index 00000000000..584ec4b9d5a --- /dev/null +++ b/gdb/config/mep/mep.mt @@ -0,0 +1,3 @@ +# Target: Toshiba Media Processor (MEP) +TDEPFILES= mep-tdep.o prologue-value.o +# No sim needed. Target uses SID. diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 3682b4620d9..94cd6bb81f1 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -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 index 00000000000..46c83103f8f --- /dev/null +++ b/gdb/mep-tdep.c @@ -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" + + +/* 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; +}; + + + +/* 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; +} + +/* 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); +} + + + +/* 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; +} + + +/* 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; +} + + + +/* 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; +} + + + +/* 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); +} + + + +/* 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; +} + + +/* 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)); +} + + + +/* 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 (); +} -- 2.30.2