Add support to GDB for the Renesas rl78 architecture.
authorKevin Buettner <kevinb@redhat.com>
Sat, 4 Feb 2012 06:05:50 +0000 (06:05 +0000)
committerKevin Buettner <kevinb@redhat.com>
Sat, 4 Feb 2012 06:05:50 +0000 (06:05 +0000)
gdb/ChangeLog
gdb/configure.tgt
gdb/rl78-tdep.c [new file with mode: 0644]
include/gdb/ChangeLog
include/gdb/sim-rl78.h [new file with mode: 0644]
sim/rl78/ChangeLog
sim/rl78/Makefile.in
sim/rl78/gdb-if.c [new file with mode: 0644]

index 9fb261a3552fca1c2c8ddc49b53c75e3c36aecf6..397f54d4bc393035640253c735cdfec25252307f 100644 (file)
@@ -1,3 +1,8 @@
+2012-02-03  Kevin Buettner  <kevinb@redhat.com>
+
+       * configure.tgt (rl78-*-elf): New target.
+       * rl78-tdep.c: New file.
+
 2012-02-03  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
 
        * remote.c (remote_rcmd): Use getpkt_sane to detect timeout
index fa7ae4e9b7fd9e5311696f1563968dc9aedefdfb..5e97ab4e702392edccd612e7c19c60bca2331acb 100644 (file)
@@ -418,6 +418,12 @@ s390*-*-*)
        build_gdbserver=yes
        ;;
 
+rl78-*-elf)
+       # Target: Renesas rl78
+       gdb_target_obs="rl78-tdep.o"
+       gdb_sim=../sim/rl78/libsim.a
+       ;;
+
 rx-*-elf)
        # Target: Renesas RX
        gdb_target_obs="rx-tdep.o"
diff --git a/gdb/rl78-tdep.c b/gdb/rl78-tdep.c
new file mode 100644 (file)
index 0000000..6e4d784
--- /dev/null
@@ -0,0 +1,1035 @@
+/* Target-dependent code for the Renesas RL78 for GDB, the GNU debugger.
+
+   Copyright (C) 2011-2012 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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/rl78.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+
+#include "elf/rl78.h"
+#include "elf-bfd.h"
+
+/* Register Banks.  */
+
+enum
+{
+  RL78_BANK0 = 0,
+  RL78_BANK1 = 1,
+  RL78_BANK2 = 2,
+  RL78_BANK3 = 3,
+  RL78_NUMBANKS = 4,
+  RL78_REGS_PER_BANK = 8
+};
+
+/* Register Numbers.  */
+
+enum
+{
+  /* All general purpose registers are 8 bits wide.  */
+  RL78_BANK0_R0_REGNUM = 0,
+  RL78_BANK0_R1_REGNUM,
+  RL78_BANK0_R2_REGNUM,
+  RL78_BANK0_R3_REGNUM,
+  RL78_BANK0_R4_REGNUM,
+  RL78_BANK0_R5_REGNUM,
+  RL78_BANK0_R6_REGNUM,
+  RL78_BANK0_R7_REGNUM,
+
+  RL78_BANK1_R0_REGNUM,
+  RL78_BANK1_R1_REGNUM,
+  RL78_BANK1_R2_REGNUM,
+  RL78_BANK1_R3_REGNUM,
+  RL78_BANK1_R4_REGNUM,
+  RL78_BANK1_R5_REGNUM,
+  RL78_BANK1_R6_REGNUM,
+  RL78_BANK1_R7_REGNUM,
+
+  RL78_BANK2_R0_REGNUM,
+  RL78_BANK2_R1_REGNUM,
+  RL78_BANK2_R2_REGNUM,
+  RL78_BANK2_R3_REGNUM,
+  RL78_BANK2_R4_REGNUM,
+  RL78_BANK2_R5_REGNUM,
+  RL78_BANK2_R6_REGNUM,
+  RL78_BANK2_R7_REGNUM,
+
+  RL78_BANK3_R0_REGNUM,
+  RL78_BANK3_R1_REGNUM,
+  RL78_BANK3_R2_REGNUM,
+  RL78_BANK3_R3_REGNUM,
+  RL78_BANK3_R4_REGNUM,
+  RL78_BANK3_R5_REGNUM,
+  RL78_BANK3_R6_REGNUM,
+  RL78_BANK3_R7_REGNUM,
+
+  RL78_PSW_REGNUM,     /* 8 bits */
+  RL78_ES_REGNUM,      /* 8 bits */
+  RL78_CS_REGNUM,      /* 8 bits */
+  RL78_PC_REGNUM,      /* 20 bits; we'll use 32 bits for it.  */
+
+  /* Fixed address SFRs (some of those above are SFRs too.) */
+  RL78_SPL_REGNUM,     /* 8 bits; lower half of SP */
+  RL78_SPH_REGNUM,     /* 8 bits; upper half of SP */
+  RL78_PMC_REGNUM,     /* 8 bits */
+  RL78_MEM_REGNUM,     /* 8 bits ?? */
+
+  RL78_NUM_REGS,
+
+  /* Pseudo registers.  */
+  RL78_BANK0_RP0_REGNUM = RL78_NUM_REGS,
+  RL78_BANK0_RP1_REGNUM,
+  RL78_BANK0_RP2_REGNUM,
+  RL78_BANK0_RP3_REGNUM,
+
+  RL78_BANK1_RP0_REGNUM,
+  RL78_BANK1_RP1_REGNUM,
+  RL78_BANK1_RP2_REGNUM,
+  RL78_BANK1_RP3_REGNUM,
+
+  RL78_BANK2_RP0_REGNUM,
+  RL78_BANK2_RP1_REGNUM,
+  RL78_BANK2_RP2_REGNUM,
+  RL78_BANK2_RP3_REGNUM,
+
+  RL78_BANK3_RP0_REGNUM,
+  RL78_BANK3_RP1_REGNUM,
+  RL78_BANK3_RP2_REGNUM,
+  RL78_BANK3_RP3_REGNUM,
+
+  RL78_SP_REGNUM,
+
+  RL78_X_REGNUM,
+  RL78_A_REGNUM,
+  RL78_C_REGNUM,
+  RL78_B_REGNUM,
+  RL78_E_REGNUM,
+  RL78_D_REGNUM,
+  RL78_L_REGNUM,
+  RL78_H_REGNUM,
+
+  RL78_AX_REGNUM,
+  RL78_BC_REGNUM,
+  RL78_DE_REGNUM,
+  RL78_HL_REGNUM,
+  RL78_NUM_TOTAL_REGS,
+  RL78_NUM_PSEUDO_REGS = RL78_NUM_TOTAL_REGS - RL78_NUM_REGS
+};
+
+/* Architecture specific data.  */
+
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+
+  struct type *rl78_void,
+              *rl78_uint8,
+             *rl78_int8,
+             *rl78_uint16,
+             *rl78_int16,
+             *rl78_uint32,
+             *rl78_int32,
+             *rl78_data_pointer,
+             *rl78_code_pointer;
+};
+
+/* This structure holds the results of a prologue analysis.  */
+
+struct rl78_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[RL78_NUM_TOTAL_REGS];
+};
+
+/* Implement the "register_type" gdbarch method.  */
+
+static struct type *
+rl78_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  if (reg_nr == RL78_PC_REGNUM)
+    return tdep->rl78_code_pointer;
+  else if (reg_nr <= RL78_MEM_REGNUM
+           || (RL78_X_REGNUM <= reg_nr && reg_nr <= RL78_H_REGNUM))
+    return tdep->rl78_int8;
+  else
+    return tdep->rl78_data_pointer;
+}
+
+/* Implement the "register_name" gdbarch method.  */
+
+static const char *
+rl78_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] =
+  {
+    "bank0_r0",
+    "bank0_r1",
+    "bank0_r2",
+    "bank0_r3",
+    "bank0_r4",
+    "bank0_r5",
+    "bank0_r6",
+    "bank0_r7",
+
+    "bank1_r0",
+    "bank1_r1",
+    "bank1_r2",
+    "bank1_r3",
+    "bank1_r4",
+    "bank1_r5",
+    "bank1_r6",
+    "bank1_r7",
+
+    "bank2_r0",
+    "bank2_r1",
+    "bank2_r2",
+    "bank2_r3",
+    "bank2_r4",
+    "bank2_r5",
+    "bank2_r6",
+    "bank2_r7",
+
+    "bank3_r0",
+    "bank3_r1",
+    "bank3_r2",
+    "bank3_r3",
+    "bank3_r4",
+    "bank3_r5",
+    "bank3_r6",
+    "bank3_r7",
+
+    "psw",
+    "es",
+    "cs",
+    "pc",
+
+    "spl",
+    "sph",
+    "pmc",
+    "mem",
+
+    "bank0_rp0",
+    "bank0_rp1",
+    "bank0_rp2",
+    "bank0_rp3",
+
+    "bank1_rp0",
+    "bank1_rp1",
+    "bank1_rp2",
+    "bank1_rp3",
+
+    "bank2_rp0",
+    "bank2_rp1",
+    "bank2_rp2",
+    "bank2_rp3",
+
+    "bank3_rp0",
+    "bank3_rp1",
+    "bank3_rp2",
+    "bank3_rp3",
+
+    "sp",
+
+    "x",
+    "a",
+    "c",
+    "b",
+    "e",
+    "d",
+    "l",
+    "h",
+
+    "ax",
+    "bc",
+    "de",
+    "hl"
+  };
+
+  return reg_names[regnr];
+}
+
+/* Strip bits to form an instruction address.  (When fetching a
+   32-bit address from the stack, the high eight bits are garbage.
+   This function strips off those unused bits.)  */
+
+static CORE_ADDR
+rl78_make_instruction_address (CORE_ADDR addr)
+{
+  return addr & 0xffffff;
+}
+
+/* Set / clear bits necessary to make a data address.  */
+
+static CORE_ADDR
+rl78_make_data_address (CORE_ADDR addr)
+{
+  return (addr & 0xffff) | 0xf0000;
+}
+
+/* Implement the "pseudo_register_read" gdbarch method.  */
+
+static enum register_status
+rl78_pseudo_register_read (struct gdbarch *gdbarch,
+                           struct regcache *regcache,
+                           int reg, gdb_byte *buffer)
+{
+  enum register_status status;
+
+  if (RL78_BANK0_RP0_REGNUM <= reg && reg <= RL78_BANK3_RP3_REGNUM)
+    {
+      int raw_regnum = 2 * (reg - RL78_BANK0_RP0_REGNUM)
+                       + RL78_BANK0_R0_REGNUM;
+
+      status = regcache_raw_read (regcache, raw_regnum, buffer);
+      if (status == REG_VALID)
+       status = regcache_raw_read (regcache, raw_regnum + 1, buffer + 1);
+    }
+  else if (reg == RL78_SP_REGNUM)
+    {
+      status = regcache_raw_read (regcache, RL78_SPL_REGNUM, buffer);
+      if (status == REG_VALID)
+       status = regcache_raw_read (regcache, RL78_SPH_REGNUM, buffer + 1);
+    }
+  else if (RL78_X_REGNUM <= reg && reg <= RL78_H_REGNUM)
+    {
+      ULONGEST psw;
+
+      status = regcache_raw_read_unsigned (regcache, RL78_PSW_REGNUM, &psw);
+      if (status == REG_VALID)
+       {
+         /* RSB0 is at bit 3; RSBS1 is at bit 5.  */
+         int bank = ((psw >> 3) & 1) | ((psw >> 4) & 1);
+         int raw_regnum = RL78_BANK0_R0_REGNUM + bank * RL78_REGS_PER_BANK
+                          + (reg - RL78_X_REGNUM);
+         status = regcache_raw_read (regcache, raw_regnum, buffer);
+       }
+    }
+  else if (RL78_AX_REGNUM <= reg && reg <= RL78_HL_REGNUM)
+    {
+      ULONGEST psw;
+
+      status = regcache_raw_read_unsigned (regcache, RL78_PSW_REGNUM, &psw);
+      if (status == REG_VALID)
+       {
+         /* RSB0 is at bit 3; RSBS1 is at bit 5.  */
+         int bank = ((psw >> 3) & 1) | ((psw >> 4) & 1);
+         int raw_regnum = RL78_BANK0_R0_REGNUM + bank * RL78_REGS_PER_BANK
+                          + 2 * (reg - RL78_AX_REGNUM);
+         status = regcache_raw_read (regcache, raw_regnum, buffer);
+         if (status == REG_VALID)
+           status = regcache_raw_read (regcache, raw_regnum + 1,
+                                       buffer + 1);
+       }
+    }
+  else
+    gdb_assert_not_reached ("invalid pseudo register number");
+  return status;
+}
+
+/* Implement the "pseudo_register_write" gdbarch method.  */
+
+static void
+rl78_pseudo_register_write (struct gdbarch *gdbarch,
+                            struct regcache *regcache,
+                            int reg, const gdb_byte *buffer)
+{
+  if (RL78_BANK0_RP0_REGNUM <= reg && reg <= RL78_BANK3_RP3_REGNUM)
+    {
+      int raw_regnum = 2 * (reg - RL78_BANK0_RP0_REGNUM)
+                       + RL78_BANK0_R0_REGNUM;
+
+      regcache_raw_write (regcache, raw_regnum, buffer);
+      regcache_raw_write (regcache, raw_regnum + 1, buffer + 1);
+    }
+  else if (reg == RL78_SP_REGNUM)
+    {
+      regcache_raw_write (regcache, RL78_SPL_REGNUM, buffer);
+      regcache_raw_write (regcache, RL78_SPH_REGNUM, buffer + 1);
+    }
+  else if (RL78_X_REGNUM <= reg && reg <= RL78_H_REGNUM)
+    {
+      ULONGEST psw;
+      int bank;
+      int raw_regnum;
+
+      regcache_raw_read_unsigned (regcache, RL78_PSW_REGNUM, &psw);
+      bank = ((psw >> 3) & 1) | ((psw >> 4) & 1);
+      /* RSB0 is at bit 3; RSBS1 is at bit 5.  */
+      raw_regnum = RL78_BANK0_R0_REGNUM + bank * RL78_REGS_PER_BANK
+                  + (reg - RL78_X_REGNUM);
+      regcache_raw_write (regcache, raw_regnum, buffer);
+    }
+  else if (RL78_AX_REGNUM <= reg && reg <= RL78_HL_REGNUM)
+    {
+      ULONGEST psw;
+      int bank, raw_regnum;
+
+      regcache_raw_read_unsigned (regcache, RL78_PSW_REGNUM, &psw);
+      bank = ((psw >> 3) & 1) | ((psw >> 4) & 1);
+      /* RSB0 is at bit 3; RSBS1 is at bit 5.  */
+      raw_regnum = RL78_BANK0_R0_REGNUM + bank * RL78_REGS_PER_BANK
+                  + 2 * (reg - RL78_AX_REGNUM);
+      regcache_raw_write (regcache, raw_regnum, buffer);
+      regcache_raw_write (regcache, raw_regnum + 1, buffer + 1);
+    }
+  else
+    gdb_assert_not_reached ("invalid pseudo register number");
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+
+const gdb_byte *
+rl78_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
+                         int *lenptr)
+{
+  /* The documented BRK instruction is actually a two byte sequence,
+     {0x61, 0xcc}, but instructions may be as short as one byte.
+     Correspondence with Renesas revealed that the one byte sequence
+     0xff is used when a one byte breakpoint instruction is required.  */
+  static gdb_byte breakpoint[] = { 0xff };
+
+  *lenptr = sizeof breakpoint;
+  return breakpoint;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+
+struct rl78_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Fetch a byte on behalf of the opcode decoder.  HANDLE contains
+   the memory address of the next byte to fetch.  If successful,
+   the address in the handle is updated and the byte fetched is
+   returned as the value of the function.  If not successful, -1
+   is returned.  */
+
+static int
+rl78_get_opcode_byte (void *handle)
+{
+  struct rl78_get_opcode_byte_handle *opcdata = handle;
+  int status;
+  gdb_byte byte;
+
+  status = target_read_memory (opcdata->pc, &byte, 1);
+  if (status == 0)
+    {
+      opcdata->pc += 1;
+      return byte;
+    }
+  else
+    return -1;
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed 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.  */
+
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size,
+                 pv_t value)
+{
+  struct rl78_prologue *result = (struct rl78_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, RL78_SP_REGNUM)
+      && size == register_size (target_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
+rl78_analyze_prologue (CORE_ADDR start_pc,
+                      CORE_ADDR limit_pc, struct rl78_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  int rn;
+  pv_t reg[RL78_NUM_TOTAL_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int bank = 0;
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < RL78_NUM_TOTAL_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (RL78_SP_REGNUM, gdbarch_addr_bit (target_gdbarch));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  /* The call instruction has saved the return address on the stack.  */
+  reg[RL78_SP_REGNUM] = pv_add_constant (reg[RL78_SP_REGNUM], -4);
+  pv_area_store (stack, reg[RL78_SP_REGNUM], 4, reg[RL78_PC_REGNUM]);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      int bytes_read;
+      struct rl78_get_opcode_byte_handle opcode_handle;
+      RL78_Opcode_Decoded opc;
+
+      opcode_handle.pc = pc;
+      bytes_read = rl78_decode_opcode (pc, &opc, rl78_get_opcode_byte,
+                                    &opcode_handle);
+      next_pc = pc + bytes_read;
+
+      if (opc.id == RLO_sel)
+       {
+         bank = opc.op[1].addend;
+       }
+      else if (opc.id == RLO_mov
+               && opc.op[0].type == RL78_Operand_PreDec
+               && opc.op[0].reg == RL78_Reg_SP
+              && opc.op[1].type == RL78_Operand_Register)
+       {
+         int rsrc = (bank * RL78_REGS_PER_BANK) 
+                  + 2 * (opc.op[1].reg - RL78_Reg_AX);
+
+         reg[RL78_SP_REGNUM] = pv_add_constant (reg[RL78_SP_REGNUM], -1);
+         pv_area_store (stack, reg[RL78_SP_REGNUM], 1, reg[rsrc]);
+         reg[RL78_SP_REGNUM] = pv_add_constant (reg[RL78_SP_REGNUM], -1);
+         pv_area_store (stack, reg[RL78_SP_REGNUM], 1, reg[rsrc + 1]);
+         after_last_frame_setup_insn = next_pc;
+       }
+      else if (opc.id == RLO_sub
+               && opc.op[0].type == RL78_Operand_Register
+              && opc.op[0].reg == RL78_Reg_SP
+              && opc.op[1].type == RL78_Operand_Immediate)
+       {
+         int addend = opc.op[1].addend;
+
+         reg[RL78_SP_REGNUM] = pv_add_constant (reg[RL78_SP_REGNUM],
+                                                -addend);
+         after_last_frame_setup_insn = next_pc;
+       }
+      else
+       {
+         /* Terminate the prologue scan.  */
+         break;
+       }
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[RL78_SP_REGNUM], RL78_SP_REGNUM))
+    result->frame_size = reg[RL78_SP_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);
+}
+
+/* Implement the "addr_bits_remove" gdbarch method.  */
+
+static CORE_ADDR
+rl78_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+  return addr & 0xffffff;
+}
+
+/* Implement the "address_to_pointer" gdbarch method.  */
+
+static void
+rl78_address_to_pointer (struct gdbarch *gdbarch,
+                        struct type *type, gdb_byte *buf, CORE_ADDR addr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  store_unsigned_integer (buf, TYPE_LENGTH (type), byte_order,
+                          addr & 0xffffff);
+}
+
+/* Implement the "pointer_to_address" gdbarch method.  */
+
+static CORE_ADDR
+rl78_pointer_to_address (struct gdbarch *gdbarch,
+                         struct type *type, const gdb_byte *buf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR addr
+    = extract_unsigned_integer (buf, TYPE_LENGTH (type), byte_order);
+
+  /* Is it a code address?  */
+  if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC
+      || TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD
+      || TYPE_CODE_SPACE (TYPE_TARGET_TYPE (type))
+      || TYPE_LENGTH (type) == 4)
+    return rl78_make_instruction_address (addr);
+  else
+    return rl78_make_data_address (addr);
+}
+
+/* Implement the "skip_prologue" gdbarch method.  */
+
+static CORE_ADDR
+rl78_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  char *name;
+  CORE_ADDR func_addr, func_end;
+  struct rl78_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;
+
+  rl78_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Implement the "unwind_pc" gdbarch method.  */
+
+static CORE_ADDR
+rl78_unwind_pc (struct gdbarch *arch, struct frame_info *next_frame)
+{
+  return rl78_addr_bits_remove
+           (arch, frame_unwind_register_unsigned (next_frame,
+                                                 RL78_PC_REGNUM));
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+
+static CORE_ADDR
+rl78_unwind_sp (struct gdbarch *arch, struct frame_info *next_frame)
+{
+  return frame_unwind_register_unsigned (next_frame, RL78_SP_REGNUM);
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+
+static struct rl78_prologue *
+rl78_analyze_frame_prologue (struct frame_info *this_frame,
+                          void **this_prologue_cache)
+{
+  if (!*this_prologue_cache)
+    {
+      CORE_ADDR func_start, stop_addr;
+
+      *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct rl78_prologue);
+
+      func_start = get_frame_func (this_frame);
+      stop_addr = get_frame_pc (this_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;
+
+      rl78_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+    }
+
+  return *this_prologue_cache;
+}
+
+/* Given a frame and a prologue cache, return this frame's base.  */
+
+static CORE_ADDR
+rl78_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct rl78_prologue *p
+    = rl78_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR sp = get_frame_register_unsigned (this_frame, RL78_SP_REGNUM);
+
+  return rl78_make_data_address (sp - p->frame_size);
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+
+static void
+rl78_this_id (struct frame_info *this_frame,
+             void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id = frame_id_build (rl78_frame_base (this_frame,
+                                              this_prologue_cache),
+                            get_frame_func (this_frame));
+}
+
+/* Implement the "frame_prev_register" method for unwinding frames.  */
+
+static struct value *
+rl78_prev_register (struct frame_info *this_frame,
+                    void **this_prologue_cache, int regnum)
+{
+  struct rl78_prologue *p
+    = rl78_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = rl78_frame_base (this_frame, this_prologue_cache);
+
+  if (regnum == RL78_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  else if (regnum == RL78_SPL_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum,
+                                      (frame_base & 0xff));
+
+  else if (regnum == RL78_SPH_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum,
+                                      ((frame_base >> 8) & 0xff));
+
+  /* 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)
+    {
+      struct value *rv =
+        frame_unwind_got_memory (this_frame, regnum,
+                                frame_base + p->reg_offset[regnum]);
+
+      if (regnum == RL78_PC_REGNUM)
+       {
+         ULONGEST pc = rl78_make_instruction_address (value_as_long (rv));
+
+         return frame_unwind_got_constant (this_frame, regnum, pc);
+       }
+      return rv;
+    }
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+    return frame_unwind_got_register (this_frame, regnum, regnum);
+}
+
+static const struct frame_unwind rl78_unwind =
+{
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  rl78_this_id,
+  rl78_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "dwarf_reg_to_regnum" gdbarch method.  */
+
+static int
+rl78_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
+{
+  if (0 <= reg && reg <= 31)
+    {
+      if ((reg & 1) == 0)
+        /* Map even registers to their 16-bit counterparts.  This
+          is usually what is required from the DWARF info.  */
+       return (reg >> 1) + RL78_BANK0_RP0_REGNUM;
+      else
+       return reg;
+    }
+  else if (reg == 32)
+    return RL78_SP_REGNUM;
+  else if (reg == 33)
+    return RL78_PC_REGNUM;
+  else
+    internal_error (__FILE__, __LINE__,
+                    _("Undefined dwarf2 register mapping of reg %d"),
+                   reg);
+}
+
+/* Implement the "return_value" gdbarch method.  */
+
+static enum return_value_convention
+rl78_return_value (struct gdbarch *gdbarch,
+                  struct type *func_type,
+                  struct type *valtype,
+                  struct regcache *regcache,
+                  gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (valtype_len > 8)
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = RL78_BANK1_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+       {
+         regcache_cooked_read_unsigned (regcache, argreg, &u);
+         store_unsigned_integer (readbuf + offset, 1, byte_order, u);
+         valtype_len -= 1;
+         offset += 1;
+         argreg++;
+       }
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = RL78_BANK1_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+       {
+         u = extract_unsigned_integer (writebuf + offset, 1, byte_order);
+         regcache_cooked_write_unsigned (regcache, argreg, u);
+         valtype_len -= 1;
+         offset += 1;
+         argreg++;
+       }
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+
+/* Implement the "frame_align" gdbarch method.  */
+
+static CORE_ADDR
+rl78_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
+{
+  return rl78_make_data_address (align_down (sp, 2));
+}
+
+
+/* Implement the "dummy_id" gdbarch method.  */
+
+static struct frame_id
+rl78_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (rl78_make_data_address
+                      (get_frame_register_unsigned
+                       (this_frame, RL78_SP_REGNUM)),
+                   get_frame_pc (this_frame));
+}
+
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+
+static CORE_ADDR
+rl78_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+                     struct regcache *regcache, CORE_ADDR bp_addr,
+                     int nargs, struct value **args, CORE_ADDR sp,
+                     int struct_return, CORE_ADDR struct_addr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  gdb_byte buf[4];
+  int i;
+
+  /* Push arguments in reverse order.  */
+  for (i = nargs - 1; i >= 0; i--)
+    {
+      struct type *value_type = value_enclosing_type (args[i]);
+      int len = TYPE_LENGTH (value_type);
+      int container_len = (len + 1) & ~1;
+      int offset;
+
+      sp -= container_len;
+      write_memory (rl78_make_data_address (sp),
+                    value_contents_all (args[i]), len);
+    }
+
+  /* Store struct value address.  */
+  if (struct_return)
+    {
+      store_unsigned_integer (buf, 2, byte_order, struct_addr);
+      sp -= 2;
+      write_memory (rl78_make_data_address (sp), buf, 2);
+    }
+
+  /* Store return address.  */
+  sp -= 4;
+  store_unsigned_integer (buf, 4, byte_order, bp_addr);
+  write_memory (rl78_make_data_address (sp), buf, 4);
+
+  /* Finally, update the stack pointer...  */
+  regcache_cooked_write_unsigned (regcache, RL78_SP_REGNUM, sp);
+
+  /* DWARF2/GCC uses the stack address *before* the function call as a
+     frame's CFA.  */
+  return rl78_make_data_address (sp + 4);
+}
+
+/* Allocate and initialize a gdbarch object.  */
+
+static struct gdbarch *
+rl78_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  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)->elf_flags != elf_flags)
+       continue;
+
+      return arches->gdbarch;
+    }
+
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+  gdbarch = gdbarch_alloc (&info, tdep);
+  tdep->elf_flags = elf_flags;
+
+  /* Initialize types.  */
+  tdep->rl78_void = arch_type (gdbarch, TYPE_CODE_VOID, 1, "void");
+  tdep->rl78_uint8 = arch_integer_type (gdbarch, 8, 1, "uint8_t");
+  tdep->rl78_int8 = arch_integer_type (gdbarch, 8, 0, "int8_t");
+  tdep->rl78_uint16 = arch_integer_type (gdbarch, 16, 1, "uint16_t");
+  tdep->rl78_int16 = arch_integer_type (gdbarch, 16, 0, "int16_t");
+  tdep->rl78_uint32 = arch_integer_type (gdbarch, 32, 1, "uint32_t");
+  tdep->rl78_int32 = arch_integer_type (gdbarch, 32, 0, "int32_t");
+
+  tdep->rl78_data_pointer
+    = arch_type (gdbarch, TYPE_CODE_PTR, 16 / TARGET_CHAR_BIT,
+                 xstrdup ("rl78_data_addr_t"));
+  TYPE_TARGET_TYPE (tdep->rl78_data_pointer) = tdep->rl78_void;
+  TYPE_UNSIGNED (tdep->rl78_data_pointer) = 1;
+
+  tdep->rl78_code_pointer
+    = arch_type (gdbarch, TYPE_CODE_PTR, 32 / TARGET_CHAR_BIT,
+                 xstrdup ("rl78_code_addr_t"));
+  TYPE_TARGET_TYPE (tdep->rl78_code_pointer) = tdep->rl78_void;
+  TYPE_UNSIGNED (tdep->rl78_code_pointer) = 1;
+
+  /* Registers.  */
+  set_gdbarch_num_regs (gdbarch, RL78_NUM_REGS);
+  set_gdbarch_num_pseudo_regs (gdbarch, RL78_NUM_PSEUDO_REGS);
+  set_gdbarch_register_name (gdbarch, rl78_register_name);
+  set_gdbarch_register_type (gdbarch, rl78_register_type);
+  set_gdbarch_pc_regnum (gdbarch, RL78_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, RL78_SP_REGNUM);
+  set_gdbarch_pseudo_register_read (gdbarch, rl78_pseudo_register_read);
+  set_gdbarch_pseudo_register_write (gdbarch, rl78_pseudo_register_write);
+  set_gdbarch_dwarf2_reg_to_regnum (gdbarch, rl78_dwarf_reg_to_regnum);
+
+  /* Data types.  */
+  set_gdbarch_char_signed (gdbarch, 0);
+  set_gdbarch_short_bit (gdbarch, 16);
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_ptr_bit (gdbarch, 16);
+  set_gdbarch_addr_bit (gdbarch, 32);
+  set_gdbarch_float_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 32);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_pointer_to_address (gdbarch, rl78_pointer_to_address);
+  set_gdbarch_address_to_pointer (gdbarch, rl78_address_to_pointer);
+  set_gdbarch_addr_bits_remove (gdbarch, rl78_addr_bits_remove);
+
+  /* Breakpoints.  */
+  set_gdbarch_breakpoint_from_pc (gdbarch, rl78_breakpoint_from_pc);
+  set_gdbarch_decr_pc_after_break (gdbarch, 1);
+
+  /* Disassembly.  */
+  set_gdbarch_print_insn (gdbarch, print_insn_rl78);
+
+  /* Frames, prologues, etc.  */
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_skip_prologue (gdbarch, rl78_skip_prologue);
+  set_gdbarch_unwind_pc (gdbarch, rl78_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, rl78_unwind_sp);
+  set_gdbarch_frame_align (gdbarch, rl78_frame_align);
+  frame_unwind_append_unwinder (gdbarch, &rl78_unwind);
+
+  /* Dummy frames, return values.  */
+  set_gdbarch_dummy_id (gdbarch, rl78_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, rl78_push_dummy_call);
+  set_gdbarch_return_value (gdbarch, rl78_return_value);
+
+  /* Virtual tables.  */
+  set_gdbarch_vbit_in_delta (gdbarch, 1);
+
+  return gdbarch;
+}
+
+/* Register the above initialization routine.  */
+
+void
+_initialize_rl78_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_rl78, rl78_gdbarch_init);
+}
index 9ce3db9141665eb47df388028e5adbbf286c218e..a2ab59f0f6576e10ebd6351b6cdfb6afa6b7f544 100644 (file)
@@ -1,3 +1,7 @@
+2012-02-03  Kevin Buettner  <kevinb@redhat.com>
+
+       * sim-rl78.h: New file.
+
 2011-12-03  Mike Frysinger  <vapier@gentoo.org>
 
        * callback.h (cb_get_string): New prototype.
diff --git a/include/gdb/sim-rl78.h b/include/gdb/sim-rl78.h
new file mode 100644 (file)
index 0000000..941ee04
--- /dev/null
@@ -0,0 +1,76 @@
+/* sim-rx.h --- interface between rl78 simulator and GDB.
+
+   Copyright 2011-2012 Free Software Foundation, Inc.
+
+   Contributed by Red Hat.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#if !defined (SIM_RL78_H)
+#define SIM_RL78_H
+
+enum sim_rl78_regnum
+{
+  sim_rl78_bank0_r0_regnum,
+  sim_rl78_bank0_r1_regnum,
+  sim_rl78_bank0_r2_regnum,
+  sim_rl78_bank0_r3_regnum,
+  sim_rl78_bank0_r4_regnum,
+  sim_rl78_bank0_r5_regnum,
+  sim_rl78_bank0_r6_regnum,
+  sim_rl78_bank0_r7_regnum,
+
+  sim_rl78_bank1_r0_regnum,
+  sim_rl78_bank1_r1_regnum,
+  sim_rl78_bank1_r2_regnum,
+  sim_rl78_bank1_r3_regnum,
+  sim_rl78_bank1_r4_regnum,
+  sim_rl78_bank1_r5_regnum,
+  sim_rl78_bank1_r6_regnum,
+  sim_rl78_bank1_r7_regnum,
+
+  sim_rl78_bank2_r0_regnum,
+  sim_rl78_bank2_r1_regnum,
+  sim_rl78_bank2_r2_regnum,
+  sim_rl78_bank2_r3_regnum,
+  sim_rl78_bank2_r4_regnum,
+  sim_rl78_bank2_r5_regnum,
+  sim_rl78_bank2_r6_regnum,
+  sim_rl78_bank2_r7_regnum,
+
+  sim_rl78_bank3_r0_regnum,
+  sim_rl78_bank3_r1_regnum,
+  sim_rl78_bank3_r2_regnum,
+  sim_rl78_bank3_r3_regnum,
+  sim_rl78_bank3_r4_regnum,
+  sim_rl78_bank3_r5_regnum,
+  sim_rl78_bank3_r6_regnum,
+  sim_rl78_bank3_r7_regnum,
+
+  sim_rl78_psw_regnum,
+  sim_rl78_es_regnum,
+  sim_rl78_cs_regnum,
+  sim_rl78_pc_regnum,
+
+  sim_rl78_spl_regnum,
+  sim_rl78_sph_regnum,
+  sim_rl78_pmc_regnum,
+  sim_rl78_mem_regnum,
+
+  sim_rl78_num_regs
+};
+
+#endif /* SIM_RL78_H */
index ad557fb53d00b28d6a56b089bac573dd4ee61b94..444d036670edc29364264c181be8481c0188481d 100644 (file)
@@ -1,3 +1,8 @@
+2012-02-03  Kevin Buettner  <kevinb@redhat.com>
+
+       * Makefile.in (SIM_OBJS): Add gdb-if.o.
+       * gdb-if.c: New file.
+
 2011-12-03  Mike Frysinger  <vapier@gentoo.org>
 
        * aclocal.m4: New file.
index 47c59c1c6076483a6453dd8a29299abc822284b9..70c767b176e9db78538d9fb861171e5d64d1199b 100644 (file)
@@ -32,6 +32,7 @@ SIM_OBJS = \
        mem.o \
        cpu.o \
        rl78.o \
+       gdb-if.o \
        trace.o
 
 ## COMMON_POST_CONFIG_FRAG
diff --git a/sim/rl78/gdb-if.c b/sim/rl78/gdb-if.c
new file mode 100644 (file)
index 0000000..e7c1277
--- /dev/null
@@ -0,0 +1,573 @@
+/* gdb-if.c -- sim interface to GDB.
+
+Copyright (C) 2011-2012 Free Software Foundation, Inc.
+Contributed by Red Hat, Inc.
+
+This file is part of the GNU simulators.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include <stdio.h>
+#include <assert.h>
+#include <signal.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "ansidecl.h"
+#include "gdb/callback.h"
+#include "gdb/remote-sim.h"
+#include "gdb/signals.h"
+#include "gdb/sim-rl78.h"
+
+#include "cpu.h"
+#include "mem.h"
+#include "load.h"
+#include "trace.h"
+
+/* Ideally, we'd wrap up all the minisim's data structures in an
+   object and pass that around.  However, neither GDB nor run needs
+   that ability.
+
+   So we just have one instance, that lives in global variables, and
+   each time we open it, we re-initialize it.  */
+
+struct sim_state
+{
+  const char *message;
+};
+
+static struct sim_state the_minisim = {
+  "This is the sole rl78 minisim instance."
+};
+
+static int open;
+
+static unsigned char hw_breakpoints[MEM_SIZE/8];
+
+static struct host_callback_struct *host_callbacks;
+
+/* Open an instance of the sim.  For this sim, only one instance
+   is permitted.  If sim_open() is called multiple times, the sim
+   will be reset.  */
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind,
+         struct host_callback_struct *callback,
+         struct bfd *abfd, char **argv)
+{
+  if (open)
+    fprintf (stderr, "rl78 minisim: re-opened sim\n");
+
+  /* The 'run' interface doesn't use this function, so we don't care
+     about KIND; it's always SIM_OPEN_DEBUG.  */
+  if (kind != SIM_OPEN_DEBUG)
+    fprintf (stderr, "rl78 minisim: sim_open KIND != SIM_OPEN_DEBUG: %d\n",
+            kind);
+
+  /* We use this for the load command.  Perhaps someday, it'll be used
+     for syscalls too.  */
+  host_callbacks = callback;
+
+  /* We don't expect any command-line arguments.  */
+
+  init_cpu ();
+  trace = 0;
+
+  sim_disasm_init (abfd);
+  open = 1;
+  return &the_minisim;
+}
+
+/* Verify the sim descriptor.  Just print a message if the descriptor
+   doesn't match.  Nothing bad will happen if the descriptor doesn't
+   match because all of the state is global.  But if it doesn't
+   match, that means there's a problem with the caller.  */
+
+static void
+check_desc (SIM_DESC sd)
+{
+  if (sd != &the_minisim)
+    fprintf (stderr, "rl78 minisim: desc != &the_minisim\n");
+}
+
+/* Close the sim.  */
+
+void
+sim_close (SIM_DESC sd, int quitting)
+{
+  check_desc (sd);
+
+  /* Not much to do.  At least free up our memory.  */
+  init_mem ();
+
+  open = 0;
+}
+
+/* Open the program to run; print a message if the program cannot
+   be opened.  */
+
+static bfd *
+open_objfile (const char *filename)
+{
+  bfd *prog = bfd_openr (filename, 0);
+
+  if (!prog)
+    {
+      fprintf (stderr, "Can't read %s\n", filename);
+      return 0;
+    }
+
+  if (!bfd_check_format (prog, bfd_object))
+    {
+      fprintf (stderr, "%s not a rl78 program\n", filename);
+      return 0;
+    }
+
+  return prog;
+}
+
+/* Load a program.  */
+
+SIM_RC
+sim_load (SIM_DESC sd, char *prog, struct bfd *abfd, int from_tty)
+{
+  check_desc (sd);
+
+  if (!abfd)
+    abfd = open_objfile (prog);
+  if (!abfd)
+    return SIM_RC_FAIL;
+
+  rl78_load (abfd, host_callbacks, "sim");
+
+  return SIM_RC_OK;
+}
+
+/* Create inferior.  */
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd, char **argv, char **env)
+{
+  check_desc (sd);
+
+  if (abfd)
+    rl78_load (abfd, 0, "sim");
+
+  return SIM_RC_OK;
+}
+
+/* Read memory.  */
+
+int
+sim_read (SIM_DESC sd, SIM_ADDR mem, unsigned char *buf, int length)
+{
+  check_desc (sd);
+
+  if (mem >= MEM_SIZE)
+    return 0;
+  else if (mem + length > MEM_SIZE)
+    length = MEM_SIZE - mem;
+
+  mem_get_blk (mem, buf, length);
+  return length;
+}
+
+/* Write memory.  */
+
+int
+sim_write (SIM_DESC sd, SIM_ADDR mem, const unsigned char *buf, int length)
+{
+  check_desc (sd);
+
+  if (mem >= MEM_SIZE)
+    return 0;
+  else if (mem + length > MEM_SIZE)
+    length = MEM_SIZE - mem;
+
+  mem_put_blk (mem, buf, length);
+  return length;
+}
+
+/* Read the LENGTH bytes at BUF as an little-endian value.  */
+
+static SI
+get_le (unsigned char *buf, int length)
+{
+  SI acc = 0;
+
+  while (--length >= 0)
+    acc = (acc << 8) + buf[length];
+
+  return acc;
+}
+
+/* Store VAL as a little-endian value in the LENGTH bytes at BUF.  */
+
+static void
+put_le (unsigned char *buf, int length, SI val)
+{
+  int i;
+
+  for (i = 0; i < length; i++)
+    {
+      buf[i] = val & 0xff;
+      val >>= 8;
+    }
+}
+
+/* Verify that REGNO is in the proper range.  Return 0 if not and
+   something non-zero if so.  */
+
+static int
+check_regno (enum sim_rl78_regnum regno)
+{
+  return 0 <= regno && regno < sim_rl78_num_regs;
+}
+
+/* Return the size of the register REGNO.  */
+
+static size_t
+reg_size (enum sim_rl78_regnum regno)
+{
+  size_t size;
+
+  if (regno == sim_rl78_pc_regnum)
+    size = 4;
+  else
+    size = 1;
+
+  return size;
+}
+
+/* Return the register address associated with the register specified by
+   REGNO.  */
+
+static unsigned long
+reg_addr (enum sim_rl78_regnum regno)
+{
+  if (sim_rl78_bank0_r0_regnum <= regno
+      && regno <= sim_rl78_bank0_r7_regnum)
+    return 0xffef8 + (regno - sim_rl78_bank0_r0_regnum);
+  else if (sim_rl78_bank1_r0_regnum <= regno
+           && regno <= sim_rl78_bank1_r7_regnum)
+    return 0xffef0 + (regno - sim_rl78_bank1_r0_regnum);
+  else if (sim_rl78_bank2_r0_regnum <= regno
+           && regno <= sim_rl78_bank2_r7_regnum)
+    return 0xffee8 + (regno - sim_rl78_bank2_r0_regnum);
+  else if (sim_rl78_bank3_r0_regnum <= regno
+           && regno <= sim_rl78_bank3_r7_regnum)
+    return 0xffee0 + (regno - sim_rl78_bank3_r0_regnum);
+  else if (regno == sim_rl78_psw_regnum)
+    return 0xffffa;
+  else if (regno == sim_rl78_es_regnum)
+    return 0xffffd;
+  else if (regno == sim_rl78_cs_regnum)
+    return 0xffffc;
+  /* Note: We can't handle PC here because it's not memory mapped.  */
+  else if (regno == sim_rl78_spl_regnum)
+    return 0xffff8;
+  else if (regno == sim_rl78_sph_regnum)
+    return 0xffff9;
+  else if (regno == sim_rl78_pmc_regnum)
+    return 0xffffe;
+  else if (regno == sim_rl78_mem_regnum)
+    return 0xfffff;
+
+  return 0;
+}
+
+/* Fetch the contents of the register specified by REGNO, placing the
+   contents in BUF.  The length LENGTH must match the sim's internal
+   notion of the register's size.  */
+
+int
+sim_fetch_register (SIM_DESC sd, int regno, unsigned char *buf, int length)
+{
+  size_t size;
+  SI val;
+
+  check_desc (sd);
+
+  if (!check_regno (regno))
+    return 0;
+
+  size = reg_size (regno);
+
+  if (length != size)
+    return 0;
+
+  if (regno == sim_rl78_pc_regnum)
+    val = pc;
+  else
+    val = memory[reg_addr (regno)];
+
+  put_le (buf, length, val);
+
+  return size;
+}
+
+/* Store the value stored in BUF to the register REGNO.  The length
+   LENGTH must match the sim's internal notion of the register size.  */
+
+int
+sim_store_register (SIM_DESC sd, int regno, unsigned char *buf, int length)
+{
+  size_t size;
+  SI val;
+
+  check_desc (sd);
+
+  if (!check_regno (regno))
+    return -1;
+
+  size = reg_size (regno);
+
+  if (length != size)
+    return -1;
+
+  val = get_le (buf, length);
+
+  if (regno == sim_rl78_pc_regnum)
+    pc = val;
+  else
+    memory[reg_addr (regno)] = val;
+  return size;
+}
+
+/* Print out message associated with "info target".  */
+
+void
+sim_info (SIM_DESC sd, int verbose)
+{
+  check_desc (sd);
+
+  printf ("The rl78 minisim doesn't collect any statistics.\n");
+}
+
+static volatile int stop;
+static enum sim_stop reason;
+int siggnal;
+
+
+/* Given a signal number used by the rl78 bsp (that is, newlib),
+   return the corresponding signal numbers.  */
+
+int
+rl78_signal_to_target (int sig)
+{
+  switch (sig)
+    {
+    case 4:
+      return TARGET_SIGNAL_ILL;
+
+    case 5:
+      return TARGET_SIGNAL_TRAP;
+
+    case 10:
+      return TARGET_SIGNAL_BUS;
+
+    case 11:
+      return TARGET_SIGNAL_SEGV;
+
+    case 24:
+      return TARGET_SIGNAL_XCPU;
+      break;
+
+    case 2:
+      return TARGET_SIGNAL_INT;
+
+    case 8:
+      return TARGET_SIGNAL_FPE;
+      break;
+
+    case 6:
+      return TARGET_SIGNAL_ABRT;
+    }
+
+  return 0;
+}
+
+
+/* Take a step return code RC and set up the variables consulted by
+   sim_stop_reason appropriately.  */
+
+void
+handle_step (int rc)
+{
+  if (RL78_STEPPED (rc) || RL78_HIT_BREAK (rc))
+    {
+      reason = sim_stopped;
+      siggnal = TARGET_SIGNAL_TRAP;
+    }
+  else if (RL78_STOPPED (rc))
+    {
+      reason = sim_stopped;
+      siggnal = rl78_signal_to_target (RL78_STOP_SIG (rc));
+    }
+  else
+    {
+      assert (RL78_EXITED (rc));
+      reason = sim_exited;
+      siggnal = RL78_EXIT_STATUS (rc);
+    }
+}
+
+
+/* Resume execution after a stop.  */
+
+void
+sim_resume (SIM_DESC sd, int step, int sig_to_deliver)
+{
+  int rc;
+
+  check_desc (sd);
+
+  if (sig_to_deliver != 0)
+    {
+      fprintf (stderr,
+              "Warning: the rl78 minisim does not implement "
+              "signal delivery yet.\n" "Resuming with no signal.\n");
+    }
+
+      /* We don't clear 'stop' here, because then we would miss
+         interrupts that arrived on the way here.  Instead, we clear
+         the flag in sim_stop_reason, after GDB has disabled the
+         interrupt signal handler.  */
+  for (;;)
+    {
+      if (stop)
+       {
+         stop = 0;
+         reason = sim_stopped;
+         siggnal = TARGET_SIGNAL_INT;
+         break;
+       }
+
+      if (hw_breakpoints[pc >> 3]
+          && (hw_breakpoints[pc >> 3] & (1 << (pc & 0x7))))
+       {
+         reason = sim_stopped;
+         siggnal = TARGET_SIGNAL_TRAP;
+         break;
+       }
+      rc = setjmp (decode_jmp_buf);
+      if (rc == 0)
+       rc = decode_opcode ();
+
+      if (!RL78_STEPPED (rc) || step)
+       {
+         handle_step (rc);
+         break;
+       }
+    }
+}
+
+/* Stop the sim.  */
+
+int
+sim_stop (SIM_DESC sd)
+{
+  stop = 1;
+
+  return 1;
+}
+
+/* Fetch the stop reason and signal.  */
+
+void
+sim_stop_reason (SIM_DESC sd, enum sim_stop *reason_p, int *sigrc_p)
+{
+  check_desc (sd);
+
+  *reason_p = reason;
+  *sigrc_p = siggnal;
+}
+
+/* Execute the sim-specific command associated with GDB's "sim ..."
+   command.  */
+
+void
+sim_do_command (SIM_DESC sd, char *cmd)
+{
+  char *args;
+
+  check_desc (sd);
+
+  if (cmd == NULL)
+    {
+      cmd = "";
+      args = "";
+    }
+  else
+    {
+      char *p = cmd;
+
+      /* Skip leading whitespace.  */
+      while (isspace (*p))
+       p++;
+
+      /* Find the extent of the command word.  */
+      for (p = cmd; *p; p++)
+       if (isspace (*p))
+         break;
+
+      /* Null-terminate the command word, and record the start of any
+        further arguments.  */
+      if (*p)
+       {
+         *p = '\0';
+         args = p + 1;
+         while (isspace (*args))
+           args++;
+       }
+      else
+       args = p;
+    }
+
+  if (strcmp (cmd, "trace") == 0)
+    {
+      if (strcmp (args, "on") == 0)
+       trace = 1;
+      else if (strcmp (args, "off") == 0)
+       trace = 0;
+      else
+       printf ("The 'sim trace' command expects 'on' or 'off' "
+               "as an argument.\n");
+    }
+  else if (strcmp (cmd, "verbose") == 0)
+    {
+      if (strcmp (args, "on") == 0)
+       verbose = 1;
+      else if (strcmp (args, "noisy") == 0)
+       verbose = 2;
+      else if (strcmp (args, "off") == 0)
+       verbose = 0;
+      else
+       printf ("The 'sim verbose' command expects 'on', 'noisy', or 'off'"
+               " as an argument.\n");
+    }
+  else
+    printf ("The 'sim' command expects either 'trace' or 'verbose'"
+           " as a subcommand.\n");
+}
+
+/* Stub for command completion.  */
+
+char **
+sim_complete_command (SIM_DESC sd, char *text, char *word)
+{
+    return NULL;
+}
This page took 0.043683 seconds and 4 git commands to generate.