146283Sdfr/* Remote target communications for the Macraigor Systems BDM Wiggler
246283Sdfr   talking to a Motorola PPC 8xx ADS board
398944Sobrien   Copyright 1996, 1997, 1998, 1999, 2000, 2001
498944Sobrien   Free Software Foundation, Inc.
546283Sdfr
698944Sobrien   This file is part of GDB.
746283Sdfr
898944Sobrien   This program is free software; you can redistribute it and/or modify
998944Sobrien   it under the terms of the GNU General Public License as published by
1098944Sobrien   the Free Software Foundation; either version 2 of the License, or
1198944Sobrien   (at your option) any later version.
1246283Sdfr
1398944Sobrien   This program is distributed in the hope that it will be useful,
1498944Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
1598944Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1698944Sobrien   GNU General Public License for more details.
1746283Sdfr
1898944Sobrien   You should have received a copy of the GNU General Public License
1998944Sobrien   along with this program; if not, write to the Free Software
2098944Sobrien   Foundation, Inc., 59 Temple Place - Suite 330,
2198944Sobrien   Boston, MA 02111-1307, USA.  */
2246283Sdfr
2346283Sdfr#include "defs.h"
2446283Sdfr#include "gdbcore.h"
2546283Sdfr#include "gdb_string.h"
2646283Sdfr#include <fcntl.h>
2746283Sdfr#include "frame.h"
2846283Sdfr#include "inferior.h"
2946283Sdfr#include "bfd.h"
3046283Sdfr#include "symfile.h"
3146283Sdfr#include "target.h"
3246283Sdfr#include "gdbcmd.h"
3346283Sdfr#include "objfiles.h"
3446283Sdfr#include "gdb-stabs.h"
3546283Sdfr#include <sys/types.h>
3646283Sdfr#include "serial.h"
3746283Sdfr#include "ocd.h"
3898944Sobrien#include "ppc-tdep.h"
3998944Sobrien#include "regcache.h"
4046283Sdfr
4198944Sobrienstatic void bdm_ppc_open (char *name, int from_tty);
4246283Sdfr
4398944Sobrienstatic ptid_t bdm_ppc_wait (ptid_t ptid,
4498944Sobrien                            struct target_waitstatus *target_status);
4546283Sdfr
4698944Sobrienstatic void bdm_ppc_fetch_registers (int regno);
4746283Sdfr
4898944Sobrienstatic void bdm_ppc_store_registers (int regno);
4946283Sdfr
5046283Sdfrextern struct target_ops bdm_ppc_ops;	/* Forward decl */
5146283Sdfr
5298944Sobrien/*#define BDM_NUM_REGS 71 */
5346283Sdfr#define BDM_NUM_REGS 24
5446283Sdfr
5546283Sdfr#define BDM_REGMAP \
5646283Sdfr	2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, /* r0-r7 */ \
5746283Sdfr	2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, /* r8-r15 */ \
5846283Sdfr	2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, /* r16-r23 */ \
5946283Sdfr	2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, /* r24-r31 */ \
6046283Sdfr\
6146283Sdfr	2080, 2082, 2084, 2086, 2088, 2090, 2092, 2094, /* fp0->fp8 */ \
6246283Sdfr	2096, 2098, 2100, 2102, 2104, 2106, 2108, 2110, /* fp0->fp8 */ \
6346283Sdfr	2112, 2114, 2116, 2118, 2120, 2122, 2124, 2126, /* fp0->fp8 */ \
6446283Sdfr	2128, 2130, 2132, 2134, 2136, 2138, 2140, 2142, /* fp0->fp8 */ \
6546283Sdfr\
6646283Sdfr	26,        /* pc (SRR0 (SPR 26)) */ \
6746283Sdfr	2146,      /* ps (MSR) */ \
6846283Sdfr	2144,      /* cnd (CR) */ \
6946283Sdfr	8,         /* lr (SPR 8) */ \
7046283Sdfr	9,         /* cnt (CTR (SPR 9)) */ \
7146283Sdfr	1,         /* xer (SPR 1) */ \
7298944Sobrien	0,			/* mq (SPR 0) */
7346283Sdfr
7446283Sdfr
7598944Sobrienchar nowatchdog[4] =
7698944Sobrien{0xff, 0xff, 0xff, 0x88};
7798944Sobrien
7846283Sdfr/* Open a connection to a remote debugger.
7946283Sdfr   NAME is the filename used for communication.  */
8046283Sdfr
8146283Sdfrstatic void
8298944Sobrienbdm_ppc_open (char *name, int from_tty)
8346283Sdfr{
8446283Sdfr  CORE_ADDR watchdogaddr = 0xff000004;
8546283Sdfr
8646283Sdfr  ocd_open (name, from_tty, OCD_TARGET_MOTO_PPC, &bdm_ppc_ops);
8746283Sdfr
8846283Sdfr  /* We want interrupts to drop us into debugging mode. */
8946283Sdfr  /* Modify the DER register to accomplish this. */
9046283Sdfr  ocd_write_bdm_register (149, 0x20024000);
9146283Sdfr
9246283Sdfr  /* Disable watchdog timer on the board */
9346283Sdfr  ocd_write_bytes (watchdogaddr, nowatchdog, 4);
9446283Sdfr}
9546283Sdfr
9646283Sdfr/* Wait until the remote machine stops, then return,
9746283Sdfr   storing status in STATUS just as `wait' would.
9846283Sdfr   Returns "pid" (though it's not clear what, if anything, that
9946283Sdfr   means in the case of this target).  */
10046283Sdfr
10198944Sobrienstatic ptid_t
10298944Sobrienbdm_ppc_wait (ptid_t ptid, struct target_waitstatus *target_status)
10346283Sdfr{
10446283Sdfr  int stop_reason;
10546283Sdfr
10646283Sdfr  target_status->kind = TARGET_WAITKIND_STOPPED;
10746283Sdfr
10846283Sdfr  stop_reason = ocd_wait ();
10946283Sdfr
11046283Sdfr  if (stop_reason)
11146283Sdfr    {
11246283Sdfr      target_status->value.sig = TARGET_SIGNAL_INT;
11398944Sobrien      return inferior_ptid;
11446283Sdfr    }
11546283Sdfr
11698944Sobrien  target_status->value.sig = TARGET_SIGNAL_TRAP;	/* XXX for now */
11746283Sdfr
11846283Sdfr#if 0
11946283Sdfr  {
12046283Sdfr    unsigned long ecr, der;
12146283Sdfr
12298944Sobrien    ecr = ocd_read_bdm_register (148);	/* Read the exception cause register */
12398944Sobrien    der = ocd_read_bdm_register (149);	/* Read the debug enables register */
12446283Sdfr    fprintf_unfiltered (gdb_stdout, "ecr = 0x%x, der = 0x%x\n", ecr, der);
12546283Sdfr  }
12646283Sdfr#endif
12746283Sdfr
12898944Sobrien  return inferior_ptid;
12946283Sdfr}
13046283Sdfr
13198944Sobrienstatic int bdm_regmap[] =
13298944Sobrien{BDM_REGMAP};
13346283Sdfr
13446283Sdfr/* Read the remote registers into regs.
13546283Sdfr   Fetch register REGNO, or all registers if REGNO == -1
13646283Sdfr
13746283Sdfr   The Wiggler uses the following codes to access the registers:
13846283Sdfr
13998944Sobrien   0 -> 1023            SPR 0 -> 1023
14098944Sobrien   0 - SPR 0 - MQ
14198944Sobrien   1 - SPR 1 - XER
14298944Sobrien   8 - SPR 8 - LR
14398944Sobrien   9 - SPR 9 - CTR (known as cnt in GDB)
14498944Sobrien   26 - SPR 26 - SRR0 - pc
14598944Sobrien   1024 -> 2047         DCR 0 -> DCR 1023 (IBM PPC 4xx only)
14698944Sobrien   2048 -> 2079         R0 -> R31
14798944Sobrien   2080 -> 2143         FP0 -> FP31 (64 bit regs) (IBM PPC 5xx only)
14898944Sobrien   2144                 CR (known as cnd in GDB)
14998944Sobrien   2145                 FPCSR
15098944Sobrien   2146                 MSR (known as ps in GDB)
15146283Sdfr */
15246283Sdfr
15346283Sdfrstatic void
15498944Sobrienbdm_ppc_fetch_registers (int regno)
15546283Sdfr{
15646283Sdfr  int i;
15746283Sdfr  unsigned char *regs, *beginregs, *endregs, *almostregs;
15846283Sdfr  unsigned char midregs[32];
15946283Sdfr  unsigned char mqreg[1];
16046283Sdfr  int first_regno, last_regno;
16146283Sdfr  int first_bdm_regno, last_bdm_regno;
16246283Sdfr  int reglen, beginreglen, endreglen;
16346283Sdfr
16446283Sdfr#if 1
16546283Sdfr  for (i = 0; i < (FPLAST_REGNUM - FP0_REGNUM + 1); i++)
16646283Sdfr    {
16746283Sdfr      midregs[i] = -1;
16846283Sdfr    }
16946283Sdfr  mqreg[0] = -1;
17046283Sdfr#endif
17146283Sdfr
17246283Sdfr  if (regno == -1)
17346283Sdfr    {
17446283Sdfr      first_regno = 0;
17546283Sdfr      last_regno = NUM_REGS - 1;
17646283Sdfr
17746283Sdfr      first_bdm_regno = 0;
17846283Sdfr      last_bdm_regno = BDM_NUM_REGS - 1;
17946283Sdfr    }
18046283Sdfr  else
18146283Sdfr    {
18246283Sdfr      first_regno = regno;
18346283Sdfr      last_regno = regno;
18446283Sdfr
18598944Sobrien      first_bdm_regno = bdm_regmap[regno];
18698944Sobrien      last_bdm_regno = bdm_regmap[regno];
18746283Sdfr    }
18846283Sdfr
18946283Sdfr  if (first_bdm_regno == -1)
19046283Sdfr    {
19146283Sdfr      supply_register (first_regno, NULL);
19246283Sdfr      return;			/* Unsupported register */
19346283Sdfr    }
19446283Sdfr
19546283Sdfr#if 1
19646283Sdfr  /* Can't ask for floating point regs on ppc 8xx, also need to
19746283Sdfr     avoid asking for the mq register. */
19846283Sdfr  if (first_regno == last_regno)	/* only want one reg */
19946283Sdfr    {
20046283Sdfr/*      printf("Asking for register %d\n", first_regno); */
20146283Sdfr
20246283Sdfr      /* if asking for an invalid register */
20398944Sobrien      if ((first_regno == gdbarch_tdep (current_gdbarch)->ppc_mq_regnum)
204130803Smarcel          || (first_regno == gdbarch_tdep (current_gdbarch)->ppc_fpscr_regnum)
20598944Sobrien	  || ((first_regno >= FP0_REGNUM) && (first_regno <= FPLAST_REGNUM)))
20646283Sdfr	{
20746283Sdfr/*          printf("invalid reg request!\n"); */
20898944Sobrien	  supply_register (first_regno, NULL);
20998944Sobrien	  return;		/* Unsupported register */
21098944Sobrien	}
21146283Sdfr      else
21246283Sdfr	{
21398944Sobrien	  regs = ocd_read_bdm_registers (first_bdm_regno,
21498944Sobrien					 last_bdm_regno, &reglen);
21598944Sobrien	}
21646283Sdfr    }
21798944Sobrien  else
21898944Sobrien    /* want all regs */
21946283Sdfr    {
22046283Sdfr/*      printf("Asking for registers %d to %d\n", first_regno, last_regno); */
22146283Sdfr      beginregs = ocd_read_bdm_registers (first_bdm_regno,
22298944Sobrien					  FP0_REGNUM - 1, &beginreglen);
22398944Sobrien      endregs = (strcat (midregs,
22498944Sobrien			 ocd_read_bdm_registers (FPLAST_REGNUM + 1,
22598944Sobrien					  last_bdm_regno - 1, &endreglen)));
22646283Sdfr      almostregs = (strcat (beginregs, endregs));
22746283Sdfr      regs = (strcat (almostregs, mqreg));
22846283Sdfr      reglen = beginreglen + 32 + endreglen + 1;
22946283Sdfr    }
23046283Sdfr
23146283Sdfr#endif
23246283Sdfr#if 0
23346283Sdfr  regs = ocd_read_bdm_registers (first_bdm_regno, last_bdm_regno, &reglen);
23446283Sdfr#endif
23546283Sdfr
23646283Sdfr  for (i = first_regno; i <= last_regno; i++)
23746283Sdfr    {
23846283Sdfr      int bdm_regno, regoffset;
23946283Sdfr
24098944Sobrien      bdm_regno = bdm_regmap[i];
24146283Sdfr      if (bdm_regno != -1)
24246283Sdfr	{
24346283Sdfr	  regoffset = bdm_regno - first_bdm_regno;
24446283Sdfr
24546283Sdfr	  if (regoffset >= reglen / 4)
24646283Sdfr	    continue;
24746283Sdfr
24846283Sdfr	  supply_register (i, regs + 4 * regoffset);
24946283Sdfr	}
25046283Sdfr      else
25198944Sobrien	supply_register (i, NULL);	/* Unsupported register */
25246283Sdfr    }
25346283Sdfr}
25446283Sdfr
25546283Sdfr/* Store register REGNO, or all registers if REGNO == -1, from the contents
25646283Sdfr   of REGISTERS.  FIXME: ignores errors.  */
25746283Sdfr
25846283Sdfrstatic void
25998944Sobrienbdm_ppc_store_registers (int regno)
26046283Sdfr{
26146283Sdfr  int i;
26246283Sdfr  int first_regno, last_regno;
26346283Sdfr  int first_bdm_regno, last_bdm_regno;
26446283Sdfr
26546283Sdfr  if (regno == -1)
26646283Sdfr    {
26746283Sdfr      first_regno = 0;
26846283Sdfr      last_regno = NUM_REGS - 1;
26946283Sdfr
27046283Sdfr      first_bdm_regno = 0;
27146283Sdfr      last_bdm_regno = BDM_NUM_REGS - 1;
27246283Sdfr    }
27346283Sdfr  else
27446283Sdfr    {
27546283Sdfr      first_regno = regno;
27646283Sdfr      last_regno = regno;
27746283Sdfr
27898944Sobrien      first_bdm_regno = bdm_regmap[regno];
27998944Sobrien      last_bdm_regno = bdm_regmap[regno];
28046283Sdfr    }
28146283Sdfr
28246283Sdfr  if (first_bdm_regno == -1)
28346283Sdfr    return;			/* Unsupported register */
28446283Sdfr
28546283Sdfr  for (i = first_regno; i <= last_regno; i++)
28646283Sdfr    {
28746283Sdfr      int bdm_regno;
28846283Sdfr
28998944Sobrien      bdm_regno = bdm_regmap[i];
29046283Sdfr
29146283Sdfr      /* only attempt to write if it's a valid ppc 8xx register */
29246283Sdfr      /* (need to avoid FP regs and MQ reg) */
293130803Smarcel      if ((i != gdbarch_tdep (current_gdbarch)->ppc_mq_regnum)
294130803Smarcel          && (i != gdbarch_tdep (current_gdbarch)->ppc_fpscr_regnum)
295130803Smarcel          && ((i < FP0_REGNUM) || (i > FPLAST_REGNUM)))
29646283Sdfr	{
29746283Sdfr/*          printf("write valid reg %d\n", bdm_regno); */
298130803Smarcel	  ocd_write_bdm_registers (bdm_regno, deprecated_registers + DEPRECATED_REGISTER_BYTE (i), 4);
29998944Sobrien	}
30046283Sdfr/*
30198944Sobrien   else if (i == gdbarch_tdep (current_gdbarch)->ppc_mq_regnum)
30298944Sobrien   printf("don't write invalid reg %d (PPC_MQ_REGNUM)\n", bdm_regno);
30398944Sobrien   else
30498944Sobrien   printf("don't write invalid reg %d\n", bdm_regno);
30598944Sobrien */
30646283Sdfr    }
30746283Sdfr}
30846283Sdfr
30946283Sdfr/* Define the target subroutine names */
31046283Sdfr
31198944Sobrienstruct target_ops bdm_ppc_ops;
31246283Sdfr
31398944Sobrienstatic void
31498944Sobrieninit_bdm_ppc_ops (void)
31546283Sdfr{
31698944Sobrien  bdm_ppc_ops.to_shortname = "ocd";
31798944Sobrien  bdm_ppc_ops.to_longname = "Remote target with On-Chip Debugging";
31898944Sobrien  bdm_ppc_ops.to_doc = "Use a remote target with On-Chip Debugging.  To use a target box;\n\
31946283Sdfrspecify the serial device it is connected to (e.g. /dev/ttya).  To use\n\
32046283Sdfra wiggler, specify wiggler and then the port it is connected to\n\
32198944Sobrien(e.g. wiggler lpt1).";		/* to_doc */
32298944Sobrien  bdm_ppc_ops.to_open = bdm_ppc_open;
32398944Sobrien  bdm_ppc_ops.to_close = ocd_close;
32498944Sobrien  bdm_ppc_ops.to_detach = ocd_detach;
32598944Sobrien  bdm_ppc_ops.to_resume = ocd_resume;
32698944Sobrien  bdm_ppc_ops.to_wait = bdm_ppc_wait;
32798944Sobrien  bdm_ppc_ops.to_fetch_registers = bdm_ppc_fetch_registers;
32898944Sobrien  bdm_ppc_ops.to_store_registers = bdm_ppc_store_registers;
32998944Sobrien  bdm_ppc_ops.to_prepare_to_store = ocd_prepare_to_store;
33098944Sobrien  bdm_ppc_ops.to_xfer_memory = ocd_xfer_memory;
33198944Sobrien  bdm_ppc_ops.to_files_info = ocd_files_info;
33298944Sobrien  bdm_ppc_ops.to_insert_breakpoint = ocd_insert_breakpoint;
33398944Sobrien  bdm_ppc_ops.to_remove_breakpoint = ocd_remove_breakpoint;
33498944Sobrien  bdm_ppc_ops.to_kill = ocd_kill;
33598944Sobrien  bdm_ppc_ops.to_load = ocd_load;
33698944Sobrien  bdm_ppc_ops.to_create_inferior = ocd_create_inferior;
33798944Sobrien  bdm_ppc_ops.to_mourn_inferior = ocd_mourn;
33898944Sobrien  bdm_ppc_ops.to_thread_alive = ocd_thread_alive;
33998944Sobrien  bdm_ppc_ops.to_stop = ocd_stop;
34098944Sobrien  bdm_ppc_ops.to_stratum = process_stratum;
34198944Sobrien  bdm_ppc_ops.to_has_all_memory = 1;
34298944Sobrien  bdm_ppc_ops.to_has_memory = 1;
34398944Sobrien  bdm_ppc_ops.to_has_stack = 1;
34498944Sobrien  bdm_ppc_ops.to_has_registers = 1;
34598944Sobrien  bdm_ppc_ops.to_has_execution = 1;
34698944Sobrien  bdm_ppc_ops.to_magic = OPS_MAGIC;
34798944Sobrien}				/* init_bdm_ppc_ops */
34846283Sdfr
349130803Smarcelextern initialize_file_ftype _initialize_bdm_ppc; /* -Wmissing-prototypes */
350130803Smarcel
35146283Sdfrvoid
35298944Sobrien_initialize_bdm_ppc (void)
35346283Sdfr{
35498944Sobrien  init_bdm_ppc_ops ();
35546283Sdfr  add_target (&bdm_ppc_ops);
35646283Sdfr}
357