1/* Remote target glue for the ROM68K ROM monitor.
2   Copyright 1988, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001
3   Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330,
20   Boston, MA 02111-1307, USA.  */
21
22#include "defs.h"
23#include "gdbcore.h"
24#include "target.h"
25#include "monitor.h"
26#include "serial.h"
27#include "regcache.h"
28#include "value.h"
29
30#include "m68k-tdep.h"
31
32static void rom68k_open (char *args, int from_tty);
33
34/* Return true if C is a hex digit.
35   We can't use isxdigit here: that is affected by the current locale;
36   ROM68K is not.  */
37static int
38is_hex_digit (int c)
39{
40  return (('0' <= c && c <= '9')
41          || ('a' <= c && c <= 'f')
42          || ('A' <= c && c <= 'F'));
43}
44
45
46/* Convert hex digit A to a number.  */
47static int
48hex_digit_value (int a)
49{
50  if (a >= '0' && a <= '9')
51    return a - '0';
52  else if (a >= 'a' && a <= 'f')
53    return a - 'a' + 10;
54  else if (a >= 'A' && a <= 'F')
55    return a - 'A' + 10;
56  else
57    error ("Invalid hex digit %d", a);
58}
59
60
61/* Return true iff C is a whitespace character.
62   We can't use isspace here: that is affected by the current locale;
63   ROM68K is not.  */
64static int
65is_whitespace (int c)
66{
67  return (c == ' '
68          || c == '\r'
69          || c == '\n'
70          || c == '\t'
71          || c == '\f');
72}
73
74
75/* Parse a string of hex digits starting at HEX, supply them as the
76   value of register REGNO, skip any whitespace, and return a pointer
77   to the next character.
78
79   There is a function in monitor.c, monitor_supply_register, which is
80   supposed to do this job.  However, there is some rather odd stuff
81   in there (whitespace characters don't terminate numbers, for
82   example) that is incorrect for ROM68k.  It's basically impossible
83   to safely tweak monitor_supply_register --- it's used by a zillion
84   other monitors; who knows what behaviors they're depending on.  So
85   instead, we'll just use our own function, which can behave exactly
86   the way we want it to.  */
87static char *
88rom68k_supply_one_register (int regno, unsigned char *hex)
89{
90  ULONGEST value;
91  unsigned char regbuf[MAX_REGISTER_SIZE];
92
93  value = 0;
94  while (*hex != '\0')
95    if (is_hex_digit (*hex))
96      value = (value * 16) + hex_digit_value (*hex++);
97    else
98      break;
99
100  /* Skip any whitespace.  */
101  while (is_whitespace (*hex))
102    hex++;
103
104  store_unsigned_integer (regbuf, DEPRECATED_REGISTER_RAW_SIZE (regno), value);
105  supply_register (regno, regbuf);
106
107  return hex;
108}
109
110
111static void
112rom68k_supply_register (char *regname, int regnamelen, char *val, int vallen)
113{
114  int numregs;
115  int regno;
116
117  numregs = 1;
118  regno = -1;
119
120  if (regnamelen == 2)
121    switch (regname[0])
122      {
123      case 'S':
124	if (regname[1] == 'R')
125	  regno = PS_REGNUM;
126	break;
127      case 'P':
128	if (regname[1] == 'C')
129	  regno = PC_REGNUM;
130	break;
131      case 'D':
132	if (regname[1] != 'R')
133	  break;
134	regno = M68K_D0_REGNUM;
135	numregs = 8;
136	break;
137      case 'A':
138	if (regname[1] != 'R')
139	  break;
140	regno = M68K_A0_REGNUM;
141	numregs = 7;
142	break;
143      }
144  else if (regnamelen == 3)
145    switch (regname[0])
146      {
147      case 'I':
148	if (regname[1] == 'S' && regname[2] == 'P')
149	  regno = SP_REGNUM;
150      }
151
152  if (regno >= 0)
153    while (numregs-- > 0)
154      val = rom68k_supply_one_register (regno++, val);
155}
156
157/* This array of registers need to match the indexes used by GDB.
158   This exists because the various ROM monitors use different strings
159   than does GDB, and don't necessarily support all the registers
160   either. So, typing "info reg sp" becomes a "r30".  */
161
162static const char *
163rom68k_regname (int index)
164{
165
166  static char *regnames[] =
167  {
168    "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
169    "A0", "A1", "A2", "A3", "A4", "A5", "A6", "ISP",
170    "SR", "PC"
171  };
172
173  if ((index >= (sizeof (regnames) / sizeof(regnames[0])))
174       || (index < 0) || (index >= NUM_REGS))
175    return NULL;
176  else
177    return regnames[index];
178
179}
180
181/* Define the monitor command strings. Since these are passed directly
182   through to a printf style function, we may include formatting
183   strings. We also need a CR or LF on the end.  */
184
185static struct target_ops rom68k_ops;
186
187static char *rom68k_inits[] =
188{".\r\r", NULL};		/* Exits pm/pr & download cmds */
189
190static struct monitor_ops rom68k_cmds;
191
192static void
193init_rom68k_cmds (void)
194{
195  rom68k_cmds.flags = MO_PRINT_PROGRAM_OUTPUT;
196  rom68k_cmds.init = rom68k_inits;	/* monitor init string */
197  rom68k_cmds.cont = "go\r";
198  rom68k_cmds.step = "st\r";
199  rom68k_cmds.stop = NULL;
200  rom68k_cmds.set_break = "db %x\r";
201  rom68k_cmds.clr_break = "cb %x\r";
202  rom68k_cmds.clr_all_break = "cb *\r";
203  rom68k_cmds.fill = "fm %x %x %x\r";
204  rom68k_cmds.setmem.cmdb = "pm %x %x\r";
205  rom68k_cmds.setmem.cmdw = "pm.w %x %x\r";
206  rom68k_cmds.setmem.cmdl = "pm.l %x %x\r";
207  rom68k_cmds.setmem.cmdll = NULL;
208  rom68k_cmds.setmem.resp_delim = NULL;
209  rom68k_cmds.setmem.term = NULL;
210  rom68k_cmds.setmem.term_cmd = NULL;
211  rom68k_cmds.getmem.cmdb = "dm %x %x\r";
212  rom68k_cmds.getmem.cmdw = "dm.w %x %x\r";
213  rom68k_cmds.getmem.cmdl = "dm.l %x %x\r";
214  rom68k_cmds.getmem.cmdll = NULL;
215  rom68k_cmds.getmem.resp_delim = "  ";
216  rom68k_cmds.getmem.term = NULL;
217  rom68k_cmds.getmem.term_cmd = NULL;
218  rom68k_cmds.setreg.cmd = "pr %s %x\r";
219  rom68k_cmds.setreg.resp_delim = NULL;
220  rom68k_cmds.setreg.term = NULL;
221  rom68k_cmds.setreg.term_cmd = NULL;
222  rom68k_cmds.getreg.cmd = "pr %s\r";
223  rom68k_cmds.getreg.resp_delim = ":  ";
224  rom68k_cmds.getreg.term = "= ";
225  rom68k_cmds.getreg.term_cmd = ".\r";
226  rom68k_cmds.dump_registers = "dr\r";
227  rom68k_cmds.register_pattern =
228    "\\(\\w+\\)=\\([0-9a-fA-F]+\\( +[0-9a-fA-F]+\\b\\)*\\)";
229  rom68k_cmds.supply_register = rom68k_supply_register;
230  rom68k_cmds.load_routine = NULL;
231  rom68k_cmds.load = "dc\r";
232  rom68k_cmds.loadresp = "Waiting for S-records from host... ";
233  rom68k_cmds.prompt = "ROM68K :-> ";
234  rom68k_cmds.line_term = "\r";
235  rom68k_cmds.cmd_end = ".\r";
236  rom68k_cmds.target = &rom68k_ops;
237  rom68k_cmds.stopbits = SERIAL_1_STOPBITS;
238  rom68k_cmds.regnames = NULL;
239  rom68k_cmds.regname = rom68k_regname;
240  rom68k_cmds.magic = MONITOR_OPS_MAGIC;
241}				/* init_rom68k_cmds */
242
243static void
244rom68k_open (char *args, int from_tty)
245{
246  monitor_open (args, &rom68k_cmds, from_tty);
247}
248
249extern initialize_file_ftype _initialize_rom68k; /* -Wmissing-prototypes */
250
251void
252_initialize_rom68k (void)
253{
254  init_rom68k_cmds ();
255  init_monitor_ops (&rom68k_ops);
256
257  rom68k_ops.to_shortname = "rom68k";
258  rom68k_ops.to_longname = "Rom68k debug monitor for the IDP Eval board";
259  rom68k_ops.to_doc = "Debug on a Motorola IDP eval board running the ROM68K monitor.\n\
260Specify the serial device it is connected to (e.g. /dev/ttya).";
261  rom68k_ops.to_open = rom68k_open;
262
263  add_target (&rom68k_ops);
264}
265