1/* Remote debugging interface for PPCbug (PowerPC) Rom monitor
2   for GDB, the GNU debugger.
3   Copyright (C) 1995, 1998, 1999, 2000, 2001, 2007
4   Free Software Foundation, Inc.
5
6   Written by Stu Grossman of Cygnus Support
7
8   This file is part of GDB.
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 3 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
22
23#include "defs.h"
24#include "gdbcore.h"
25#include "target.h"
26#include "monitor.h"
27#include "serial.h"
28#include "regcache.h"
29
30static void
31ppcbug_supply_register (struct regcache *regcache, char *regname,
32			int regnamelen, char *val, int vallen)
33{
34  int regno = 0;
35
36  if (regnamelen < 2 || regnamelen > 4)
37    return;
38
39  switch (regname[0])
40    {
41    case 'R':
42      if (regname[1] < '0' || regname[1] > '9')
43	return;
44      if (regnamelen == 2)
45	regno = regname[1] - '0';
46      else if (regnamelen == 3 && regname[2] >= '0' && regname[2] <= '9')
47	regno = (regname[1] - '0') * 10 + (regname[2] - '0');
48      else
49	return;
50      break;
51    case 'F':
52      if (regname[1] != 'R' || regname[2] < '0' || regname[2] > '9')
53	return;
54      if (regnamelen == 3)
55	regno = 32 + regname[2] - '0';
56      else if (regnamelen == 4 && regname[3] >= '0' && regname[3] <= '9')
57	regno = 32 + (regname[2] - '0') * 10 + (regname[3] - '0');
58      else
59	return;
60      break;
61    case 'I':
62      if (regnamelen != 2 || regname[1] != 'P')
63	return;
64      regno = 64;
65      break;
66    case 'M':
67      if (regnamelen != 3 || regname[1] != 'S' || regname[2] != 'R')
68	return;
69      regno = 65;
70      break;
71    case 'C':
72      if (regnamelen != 2 || regname[1] != 'R')
73	return;
74      regno = 66;
75      break;
76    case 'S':
77      if (regnamelen != 4 || regname[1] != 'P' || regname[2] != 'R')
78	return;
79      else if (regname[3] == '8')
80	regno = 67;
81      else if (regname[3] == '9')
82	regno = 68;
83      else if (regname[3] == '1')
84	regno = 69;
85      else if (regname[3] == '0')
86	regno = 70;
87      else
88	return;
89      break;
90    default:
91      return;
92    }
93
94  monitor_supply_register (regcache, regno, val);
95}
96
97/*
98 * This array of registers needs to match the indexes used by GDB. The
99 * whole reason this exists is because the various ROM monitors use
100 * different names than GDB does, and don't support all the
101 * registers either. So, typing "info reg sp" becomes an "A7".
102 */
103
104static char *ppcbug_regnames[] =
105{
106  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
107  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
108  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
109  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
110
111  "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
112  "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
113  "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23",
114  "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31",
115
116/* pc      ps      cnd     lr      cnt     xer     mq */
117  "ip", "msr", "cr", "spr8", "spr9", "spr1", "spr0"
118};
119
120/*
121 * Define the monitor command strings. Since these are passed directly
122 * through to a printf style function, we need can include formatting
123 * strings. We also need a CR or LF on the end.
124 */
125
126static struct target_ops ppcbug_ops0;
127static struct target_ops ppcbug_ops1;
128
129static char *ppcbug_inits[] =
130{"\r", NULL};
131
132static void
133init_ppc_cmds (char *LOAD_CMD,
134	       struct monitor_ops *OPS,
135	       struct target_ops *targops)
136{
137  OPS->flags = MO_CLR_BREAK_USES_ADDR | MO_HANDLE_NL;
138  OPS->init = ppcbug_inits;	/* Init strings */
139  OPS->cont = "g\r";		/* continue command */
140  OPS->step = "t\r";		/* single step */
141  OPS->stop = NULL;		/* interrupt command */
142  OPS->set_break = "br %x\r";	/* set a breakpoint */
143  OPS->clr_break = "nobr %x\r";	/* clear a breakpoint */
144  OPS->clr_all_break = "nobr\r";	/* clear all breakpoints */
145  OPS->fill = "bf %x:%x %x;b\r";	/* fill (start count val) */
146  OPS->setmem.cmdb = "ms %x %02x\r";	/* setmem.cmdb (addr, value) */
147  OPS->setmem.cmdw = "ms %x %04x\r";	/* setmem.cmdw (addr, value) */
148  OPS->setmem.cmdl = "ms %x %08x\r";	/* setmem.cmdl (addr, value) */
149  OPS->setmem.cmdll = NULL;	/* setmem.cmdll (addr, value) */
150  OPS->setmem.resp_delim = NULL;	/* setreg.resp_delim */
151  OPS->setmem.term = NULL;	/* setreg.term */
152  OPS->setmem.term_cmd = NULL;	/* setreg.term_cmd */
153  OPS->getmem.cmdb = "md %x:%x;b\r";	/* getmem.cmdb (addr, len) */
154  OPS->getmem.cmdw = "md %x:%x;b\r";	/* getmem.cmdw (addr, len) */
155  OPS->getmem.cmdl = "md %x:%x;b\r";	/* getmem.cmdl (addr, len) */
156  OPS->getmem.cmdll = NULL;	/* getmem.cmdll (addr, len) */
157  OPS->getmem.resp_delim = " ";	/* getmem.resp_delim */
158  OPS->getmem.term = NULL;	/* getmem.term */
159  OPS->getmem.term_cmd = NULL;	/* getmem.term_cmd */
160  OPS->setreg.cmd = "rs %s %x\r";	/* setreg.cmd (name, value) */
161  OPS->setreg.resp_delim = NULL;	/* setreg.resp_delim */
162  OPS->setreg.term = NULL;	/* setreg.term */
163  OPS->setreg.term_cmd = NULL;	/* setreg.term_cmd */
164  OPS->getreg.cmd = "rs %s\r";	/* getreg.cmd (name) */
165  OPS->getreg.resp_delim = "=";	/* getreg.resp_delim */
166  OPS->getreg.term = NULL;	/* getreg.term */
167  OPS->getreg.term_cmd = NULL;	/* getreg.term_cmd */
168  OPS->register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)";		/* register_pattern */
169  OPS->supply_register = ppcbug_supply_register;
170  OPS->dump_registers = "rd\r";	/* dump all registers */
171  OPS->load_routine = NULL;	/* load_routine (defaults to SRECs) */
172  OPS->load = LOAD_CMD;		/* download command */
173  OPS->loadresp = NULL;		/* load response */
174  OPS->prompt = "PPC1-Bug>";	/* monitor command prompt */
175  OPS->line_term = "\r";	/* end-of-line terminator */
176  OPS->cmd_end = NULL;		/* optional command terminator */
177  OPS->target = targops;	/* target operations */
178  OPS->stopbits = SERIAL_1_STOPBITS;	/* number of stop bits */
179  OPS->regnames = ppcbug_regnames;	/* registers names */
180  OPS->magic = MONITOR_OPS_MAGIC;	/* magic */
181}
182
183
184static struct monitor_ops ppcbug_cmds0;
185static struct monitor_ops ppcbug_cmds1;
186
187static void
188ppcbug_open0 (char *args, int from_tty)
189{
190  monitor_open (args, &ppcbug_cmds0, from_tty);
191}
192
193static void
194ppcbug_open1 (char *args, int from_tty)
195{
196  monitor_open (args, &ppcbug_cmds1, from_tty);
197}
198
199extern initialize_file_ftype _initialize_ppcbug_rom; /* -Wmissing-prototypes */
200
201void
202_initialize_ppcbug_rom (void)
203{
204  init_ppc_cmds ("lo 0\r", &ppcbug_cmds0, &ppcbug_ops0);
205  init_ppc_cmds ("lo 1\r", &ppcbug_cmds1, &ppcbug_ops1);
206  init_monitor_ops (&ppcbug_ops0);
207
208  ppcbug_ops0.to_shortname = "ppcbug";
209  ppcbug_ops0.to_longname = "PowerPC PPCBug monitor on port 0";
210  ppcbug_ops0.to_doc = "Debug via the PowerPC PPCBug monitor using port 0.\n\
211Specify the serial device it is connected to (e.g. /dev/ttya).";
212  ppcbug_ops0.to_open = ppcbug_open0;
213
214  add_target (&ppcbug_ops0);
215
216  init_monitor_ops (&ppcbug_ops1);
217
218  ppcbug_ops1.to_shortname = "ppcbug1";
219  ppcbug_ops1.to_longname = "PowerPC PPCBug monitor on port 1";
220  ppcbug_ops1.to_doc = "Debug via the PowerPC PPCBug monitor using port 1.\n\
221Specify the serial device it is connected to (e.g. /dev/ttya).";
222  ppcbug_ops1.to_open = ppcbug_open1;
223
224  add_target (&ppcbug_ops1);
225}
226