1238104Sdes/* Remote target communications for the Macraigor Systems BDM Wiggler
2238104Sdes   talking to a Motorola PPC 8xx ADS board
3238104Sdes   Copyright 1996, 1997, 1998, 1999, 2000, 2001
4238104Sdes   Free Software Foundation, Inc.
5238104Sdes
6238104Sdes   This file is part of GDB.
7238104Sdes
8238104Sdes   This program is free software; you can redistribute it and/or modify
9238104Sdes   it under the terms of the GNU General Public License as published by
10238104Sdes   the Free Software Foundation; either version 2 of the License, or
11238104Sdes   (at your option) any later version.
12238104Sdes
13238104Sdes   This program is distributed in the hope that it will be useful,
14238104Sdes   but WITHOUT ANY WARRANTY; without even the implied warranty of
15238104Sdes   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16238104Sdes   GNU General Public License for more details.
17238104Sdes
18238104Sdes   You should have received a copy of the GNU General Public License
19238104Sdes   along with this program; if not, write to the Free Software
20238104Sdes   Foundation, Inc., 59 Temple Place - Suite 330,
21238104Sdes   Boston, MA 02111-1307, USA.  */
22238104Sdes
23238104Sdes#include "defs.h"
24238104Sdes#include "gdbcore.h"
25238104Sdes#include "gdb_string.h"
26238104Sdes#include <fcntl.h>
27238104Sdes#include "frame.h"
28238104Sdes#include "inferior.h"
29238104Sdes#include "bfd.h"
30238104Sdes#include "symfile.h"
31238104Sdes#include "target.h"
32238104Sdes#include "gdbcmd.h"
33238104Sdes#include "objfiles.h"
34238104Sdes#include "gdb-stabs.h"
35238104Sdes#include <sys/types.h>
36238104Sdes#include "serial.h"
37238104Sdes#include "ocd.h"
38238104Sdes#include "ppc-tdep.h"
39238104Sdes#include "regcache.h"
40238104Sdes
41238104Sdesstatic void bdm_ppc_open (char *name, int from_tty);
42238104Sdes
43238104Sdesstatic ptid_t bdm_ppc_wait (ptid_t ptid,
44238104Sdes                            struct target_waitstatus *target_status);
45238104Sdes
46238104Sdesstatic void bdm_ppc_fetch_registers (int regno);
47238104Sdes
48238104Sdesstatic void bdm_ppc_store_registers (int regno);
49238104Sdes
50238104Sdesextern struct target_ops bdm_ppc_ops;	/* Forward decl */
51238104Sdes
52238104Sdes/*#define BDM_NUM_REGS 71 */
53238104Sdes#define BDM_NUM_REGS 24
54238104Sdes
55238104Sdes#define BDM_REGMAP \
56238104Sdes	2048, 2049, 2050, 2051, 2052, 2053, 2054, 2055, /* r0-r7 */ \
57238104Sdes	2056, 2057, 2058, 2059, 2060, 2061, 2062, 2063, /* r8-r15 */ \
58238104Sdes	2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, /* r16-r23 */ \
59238104Sdes	2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, /* r24-r31 */ \
60238104Sdes\
61238104Sdes	2080, 2082, 2084, 2086, 2088, 2090, 2092, 2094, /* fp0->fp8 */ \
62238104Sdes	2096, 2098, 2100, 2102, 2104, 2106, 2108, 2110, /* fp0->fp8 */ \
63238104Sdes	2112, 2114, 2116, 2118, 2120, 2122, 2124, 2126, /* fp0->fp8 */ \
64238104Sdes	2128, 2130, 2132, 2134, 2136, 2138, 2140, 2142, /* fp0->fp8 */ \
65238104Sdes\
66238104Sdes	26,        /* pc (SRR0 (SPR 26)) */ \
67238104Sdes	2146,      /* ps (MSR) */ \
68238104Sdes	2144,      /* cnd (CR) */ \
69238104Sdes	8,         /* lr (SPR 8) */ \
70238104Sdes	9,         /* cnt (CTR (SPR 9)) */ \
71238104Sdes	1,         /* xer (SPR 1) */ \
72238104Sdes	0,			/* mq (SPR 0) */
73238104Sdes
74238104Sdes
75238104Sdeschar nowatchdog[4] =
76238104Sdes{0xff, 0xff, 0xff, 0x88};
77238104Sdes
78238104Sdes/* Open a connection to a remote debugger.
79238104Sdes   NAME is the filename used for communication.  */
80238104Sdes
81238104Sdesstatic void
82238104Sdesbdm_ppc_open (char *name, int from_tty)
83238104Sdes{
84238104Sdes  CORE_ADDR watchdogaddr = 0xff000004;
85238104Sdes
86238104Sdes  ocd_open (name, from_tty, OCD_TARGET_MOTO_PPC, &bdm_ppc_ops);
87238104Sdes
88238104Sdes  /* We want interrupts to drop us into debugging mode. */
89238104Sdes  /* Modify the DER register to accomplish this. */
90238104Sdes  ocd_write_bdm_register (149, 0x20024000);
91238104Sdes
92238104Sdes  /* Disable watchdog timer on the board */
93238104Sdes  ocd_write_bytes (watchdogaddr, nowatchdog, 4);
94238104Sdes}
95238104Sdes
96238104Sdes/* Wait until the remote machine stops, then return,
97238104Sdes   storing status in STATUS just as `wait' would.
98238104Sdes   Returns "pid" (though it's not clear what, if anything, that
99238104Sdes   means in the case of this target).  */
100238104Sdes
101238104Sdesstatic ptid_t
102238104Sdesbdm_ppc_wait (ptid_t ptid, struct target_waitstatus *target_status)
103238104Sdes{
104  int stop_reason;
105
106  target_status->kind = TARGET_WAITKIND_STOPPED;
107
108  stop_reason = ocd_wait ();
109
110  if (stop_reason)
111    {
112      target_status->value.sig = TARGET_SIGNAL_INT;
113      return inferior_ptid;
114    }
115
116  target_status->value.sig = TARGET_SIGNAL_TRAP;	/* XXX for now */
117
118#if 0
119  {
120    unsigned long ecr, der;
121
122    ecr = ocd_read_bdm_register (148);	/* Read the exception cause register */
123    der = ocd_read_bdm_register (149);	/* Read the debug enables register */
124    fprintf_unfiltered (gdb_stdout, "ecr = 0x%x, der = 0x%x\n", ecr, der);
125  }
126#endif
127
128  return inferior_ptid;
129}
130
131static int bdm_regmap[] =
132{BDM_REGMAP};
133
134/* Read the remote registers into regs.
135   Fetch register REGNO, or all registers if REGNO == -1
136
137   The Wiggler uses the following codes to access the registers:
138
139   0 -> 1023            SPR 0 -> 1023
140   0 - SPR 0 - MQ
141   1 - SPR 1 - XER
142   8 - SPR 8 - LR
143   9 - SPR 9 - CTR (known as cnt in GDB)
144   26 - SPR 26 - SRR0 - pc
145   1024 -> 2047         DCR 0 -> DCR 1023 (IBM PPC 4xx only)
146   2048 -> 2079         R0 -> R31
147   2080 -> 2143         FP0 -> FP31 (64 bit regs) (IBM PPC 5xx only)
148   2144                 CR (known as cnd in GDB)
149   2145                 FPCSR
150   2146                 MSR (known as ps in GDB)
151 */
152
153static void
154bdm_ppc_fetch_registers (int regno)
155{
156  int i;
157  unsigned char *regs, *beginregs, *endregs, *almostregs;
158  unsigned char midregs[32];
159  unsigned char mqreg[1];
160  int first_regno, last_regno;
161  int first_bdm_regno, last_bdm_regno;
162  int reglen, beginreglen, endreglen;
163
164#if 1
165  for (i = 0; i < (FPLAST_REGNUM - FP0_REGNUM + 1); i++)
166    {
167      midregs[i] = -1;
168    }
169  mqreg[0] = -1;
170#endif
171
172  if (regno == -1)
173    {
174      first_regno = 0;
175      last_regno = NUM_REGS - 1;
176
177      first_bdm_regno = 0;
178      last_bdm_regno = BDM_NUM_REGS - 1;
179    }
180  else
181    {
182      first_regno = regno;
183      last_regno = regno;
184
185      first_bdm_regno = bdm_regmap[regno];
186      last_bdm_regno = bdm_regmap[regno];
187    }
188
189  if (first_bdm_regno == -1)
190    {
191      supply_register (first_regno, NULL);
192      return;			/* Unsupported register */
193    }
194
195#if 1
196  /* Can't ask for floating point regs on ppc 8xx, also need to
197     avoid asking for the mq register. */
198  if (first_regno == last_regno)	/* only want one reg */
199    {
200/*      printf("Asking for register %d\n", first_regno); */
201
202      /* if asking for an invalid register */
203      if ((first_regno == gdbarch_tdep (current_gdbarch)->ppc_mq_regnum)
204          || (first_regno == gdbarch_tdep (current_gdbarch)->ppc_fpscr_regnum)
205	  || ((first_regno >= FP0_REGNUM) && (first_regno <= FPLAST_REGNUM)))
206	{
207/*          printf("invalid reg request!\n"); */
208	  supply_register (first_regno, NULL);
209	  return;		/* Unsupported register */
210	}
211      else
212	{
213	  regs = ocd_read_bdm_registers (first_bdm_regno,
214					 last_bdm_regno, &reglen);
215	}
216    }
217  else
218    /* want all regs */
219    {
220/*      printf("Asking for registers %d to %d\n", first_regno, last_regno); */
221      beginregs = ocd_read_bdm_registers (first_bdm_regno,
222					  FP0_REGNUM - 1, &beginreglen);
223      endregs = (strcat (midregs,
224			 ocd_read_bdm_registers (FPLAST_REGNUM + 1,
225					  last_bdm_regno - 1, &endreglen)));
226      almostregs = (strcat (beginregs, endregs));
227      regs = (strcat (almostregs, mqreg));
228      reglen = beginreglen + 32 + endreglen + 1;
229    }
230
231#endif
232#if 0
233  regs = ocd_read_bdm_registers (first_bdm_regno, last_bdm_regno, &reglen);
234#endif
235
236  for (i = first_regno; i <= last_regno; i++)
237    {
238      int bdm_regno, regoffset;
239
240      bdm_regno = bdm_regmap[i];
241      if (bdm_regno != -1)
242	{
243	  regoffset = bdm_regno - first_bdm_regno;
244
245	  if (regoffset >= reglen / 4)
246	    continue;
247
248	  supply_register (i, regs + 4 * regoffset);
249	}
250      else
251	supply_register (i, NULL);	/* Unsupported register */
252    }
253}
254
255/* Store register REGNO, or all registers if REGNO == -1, from the contents
256   of REGISTERS.  FIXME: ignores errors.  */
257
258static void
259bdm_ppc_store_registers (int regno)
260{
261  int i;
262  int first_regno, last_regno;
263  int first_bdm_regno, last_bdm_regno;
264
265  if (regno == -1)
266    {
267      first_regno = 0;
268      last_regno = NUM_REGS - 1;
269
270      first_bdm_regno = 0;
271      last_bdm_regno = BDM_NUM_REGS - 1;
272    }
273  else
274    {
275      first_regno = regno;
276      last_regno = regno;
277
278      first_bdm_regno = bdm_regmap[regno];
279      last_bdm_regno = bdm_regmap[regno];
280    }
281
282  if (first_bdm_regno == -1)
283    return;			/* Unsupported register */
284
285  for (i = first_regno; i <= last_regno; i++)
286    {
287      int bdm_regno;
288
289      bdm_regno = bdm_regmap[i];
290
291      /* only attempt to write if it's a valid ppc 8xx register */
292      /* (need to avoid FP regs and MQ reg) */
293      if ((i != gdbarch_tdep (current_gdbarch)->ppc_mq_regnum)
294          && (i != gdbarch_tdep (current_gdbarch)->ppc_fpscr_regnum)
295          && ((i < FP0_REGNUM) || (i > FPLAST_REGNUM)))
296	{
297/*          printf("write valid reg %d\n", bdm_regno); */
298	  ocd_write_bdm_registers (bdm_regno, deprecated_registers + DEPRECATED_REGISTER_BYTE (i), 4);
299	}
300/*
301   else if (i == gdbarch_tdep (current_gdbarch)->ppc_mq_regnum)
302   printf("don't write invalid reg %d (PPC_MQ_REGNUM)\n", bdm_regno);
303   else
304   printf("don't write invalid reg %d\n", bdm_regno);
305 */
306    }
307}
308
309/* Define the target subroutine names */
310
311struct target_ops bdm_ppc_ops;
312
313static void
314init_bdm_ppc_ops (void)
315{
316  bdm_ppc_ops.to_shortname = "ocd";
317  bdm_ppc_ops.to_longname = "Remote target with On-Chip Debugging";
318  bdm_ppc_ops.to_doc = "Use a remote target with On-Chip Debugging.  To use a target box;\n\
319specify the serial device it is connected to (e.g. /dev/ttya).  To use\n\
320a wiggler, specify wiggler and then the port it is connected to\n\
321(e.g. wiggler lpt1).";		/* to_doc */
322  bdm_ppc_ops.to_open = bdm_ppc_open;
323  bdm_ppc_ops.to_close = ocd_close;
324  bdm_ppc_ops.to_detach = ocd_detach;
325  bdm_ppc_ops.to_resume = ocd_resume;
326  bdm_ppc_ops.to_wait = bdm_ppc_wait;
327  bdm_ppc_ops.to_fetch_registers = bdm_ppc_fetch_registers;
328  bdm_ppc_ops.to_store_registers = bdm_ppc_store_registers;
329  bdm_ppc_ops.to_prepare_to_store = ocd_prepare_to_store;
330  bdm_ppc_ops.to_xfer_memory = ocd_xfer_memory;
331  bdm_ppc_ops.to_files_info = ocd_files_info;
332  bdm_ppc_ops.to_insert_breakpoint = ocd_insert_breakpoint;
333  bdm_ppc_ops.to_remove_breakpoint = ocd_remove_breakpoint;
334  bdm_ppc_ops.to_kill = ocd_kill;
335  bdm_ppc_ops.to_load = ocd_load;
336  bdm_ppc_ops.to_create_inferior = ocd_create_inferior;
337  bdm_ppc_ops.to_mourn_inferior = ocd_mourn;
338  bdm_ppc_ops.to_thread_alive = ocd_thread_alive;
339  bdm_ppc_ops.to_stop = ocd_stop;
340  bdm_ppc_ops.to_stratum = process_stratum;
341  bdm_ppc_ops.to_has_all_memory = 1;
342  bdm_ppc_ops.to_has_memory = 1;
343  bdm_ppc_ops.to_has_stack = 1;
344  bdm_ppc_ops.to_has_registers = 1;
345  bdm_ppc_ops.to_has_execution = 1;
346  bdm_ppc_ops.to_magic = OPS_MAGIC;
347}				/* init_bdm_ppc_ops */
348
349extern initialize_file_ftype _initialize_bdm_ppc; /* -Wmissing-prototypes */
350
351void
352_initialize_bdm_ppc (void)
353{
354  init_bdm_ppc_ops ();
355  add_target (&bdm_ppc_ops);
356}
357