1/* Remote debugging interface for DINK32 (PowerPC) ROM monitor for
2   GDB, the GNU debugger.
3   Copyright 1997, 1999, 2000, 2001 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 "symfile.h" /* For generic_load() */
28#include "inferior.h" /* For write_pc() */
29#include "regcache.h"
30
31static void dink32_open (char *args, int from_tty);
32
33static void
34dink32_supply_register (char *regname, int regnamelen, char *val, int vallen)
35{
36  int regno = 0;
37
38  if (regnamelen < 2 || regnamelen > 4)
39    return;
40
41  switch (regname[0])
42    {
43    case 'R':
44      if (regname[1] < '0' || regname[1] > '9')
45	return;
46      if (regnamelen == 2)
47	regno = regname[1] - '0';
48      else if (regnamelen == 3 && regname[2] >= '0' && regname[2] <= '9')
49	regno = (regname[1] - '0') * 10 + (regname[2] - '0');
50      else
51	return;
52      break;
53    case 'F':
54      if (regname[1] != 'R' || regname[2] < '0' || regname[2] > '9')
55	return;
56      if (regnamelen == 3)
57	regno = 32 + regname[2] - '0';
58      else if (regnamelen == 4 && regname[3] >= '0' && regname[3] <= '9')
59	regno = 32 + (regname[2] - '0') * 10 + (regname[3] - '0');
60      else
61	return;
62      break;
63    case 'I':
64      if (regnamelen != 2 || regname[1] != 'P')
65	return;
66      regno = 64;
67      break;
68    case 'M':
69      if (regnamelen != 3 || regname[1] != 'S' || regname[2] != 'R')
70	return;
71      regno = 65;
72      break;
73    case 'C':
74      if (regnamelen != 2 || regname[1] != 'R')
75	return;
76      regno = 66;
77      break;
78    case 'S':
79      if (regnamelen != 4 || regname[1] != 'P' || regname[2] != 'R')
80	return;
81      else if (regname[3] == '8')
82	regno = 67;
83      else if (regname[3] == '9')
84	regno = 68;
85      else if (regname[3] == '1')
86	regno = 69;
87      else if (regname[3] == '0')
88	regno = 70;
89      else
90	return;
91      break;
92    default:
93      return;
94    }
95
96  monitor_supply_register (regno, val);
97}
98
99/* This array of registers needs to match the indexes used by GDB. The
100   whole reason this exists is because the various ROM monitors use
101   different names than GDB does, and don't support all the registers
102   either.  */
103
104static char *dink32_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  "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
112  "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
113  "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
114  "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
115
116  "srr0", "msr", "cr", "lr", "ctr", "xer", "xer"
117};
118
119static struct target_ops dink32_ops;
120
121static char *dink32_inits[] =
122{"\r", NULL};
123
124static struct monitor_ops dink32_cmds;
125
126static void
127dink32_open (char *args, int from_tty)
128{
129  monitor_open (args, &dink32_cmds, from_tty);
130}
131
132extern initialize_file_ftype _initialize_dink32_rom; /* -Wmissing-prototypes */
133
134void
135_initialize_dink32_rom (void)
136{
137  dink32_cmds.flags = MO_HEX_PREFIX | MO_GETMEM_NEEDS_RANGE | MO_FILL_USES_ADDR | MO_HANDLE_NL | MO_32_REGS_PAIRED | MO_SETREG_INTERACTIVE | MO_SETMEM_INTERACTIVE | MO_GETMEM_16_BOUNDARY | MO_CLR_BREAK_1_BASED | MO_SREC_ACK | MO_SREC_ACK_ROTATE;
138  dink32_cmds.init = dink32_inits;
139  dink32_cmds.cont = "go +\r";
140  dink32_cmds.step = "tr +\r";
141  dink32_cmds.set_break = "bp 0x%x\r";
142  dink32_cmds.clr_break = "bp %d\r";
143#if 0				/* Would need to follow strict alignment rules.. */
144  dink32_cmds.fill = "mf %x %x %x\r";
145#endif
146  dink32_cmds.setmem.cmdb = "mm -b %x\r";
147  dink32_cmds.setmem.cmdw = "mm -w %x\r";
148  dink32_cmds.setmem.cmdl = "mm %x\r";
149  dink32_cmds.setmem.term = " ?  ";
150  dink32_cmds.getmem.cmdb = "md %x\r";
151  dink32_cmds.getmem.resp_delim = "        ";
152  dink32_cmds.setreg.cmd = "rm %s\r";
153  dink32_cmds.setreg.term = " ?  ";
154  dink32_cmds.getreg.cmd = "rd %s\r";
155  dink32_cmds.getreg.resp_delim = ": ";
156  dink32_cmds.dump_registers = "rd r\r";
157  dink32_cmds.register_pattern = "\\(\\w+\\) +=\\([0-9a-fA-F]+\\b\\)";
158  dink32_cmds.supply_register = dink32_supply_register;
159  /* S-record download, via "keyboard port".  */
160  dink32_cmds.load = "dl -k\r";
161  dink32_cmds.loadresp = "Set Input Port : set to Keyboard Port\r";
162  dink32_cmds.prompt = "DINK32_603 >>";
163  dink32_cmds.line_term = "\r";
164  dink32_cmds.target = &dink32_ops;
165  dink32_cmds.stopbits = SERIAL_1_STOPBITS;
166  dink32_cmds.regnames = dink32_regnames;
167  dink32_cmds.magic = MONITOR_OPS_MAGIC;
168
169  init_monitor_ops (&dink32_ops);
170
171  dink32_ops.to_shortname = "dink32";
172  dink32_ops.to_longname = "DINK32 monitor";
173  dink32_ops.to_doc = "Debug using the DINK32 monitor.\n\
174Specify the serial device it is connected to (e.g. /dev/ttya).";
175  dink32_ops.to_open = dink32_open;
176
177  add_target (&dink32_ops);
178}
179