This commit was generated by cvs2svn to track changes on a CVS vendor
[platform/upstream/binutils.git] / gdb / sparclet-rom.c
1 /* Remote target glue for the SPARC Sparclet ROM monitor.
2    Copyright 1995, 1996 Free Software Foundation, Inc.
3
4    This file is part of GDB.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place - Suite 330,
19    Boston, MA 02111-1307, USA.  */
20
21
22 #include "defs.h"
23 #include "gdbcore.h"
24 #include "target.h"
25 #include "monitor.h"
26 #include "serial.h"
27 #include "srec.h"
28 #include "symtab.h"
29 #include "symfile.h"            /* for generic_load */
30 #include <time.h>
31
32 extern void report_transfer_performance PARAMS ((unsigned long, time_t, time_t));
33
34 static struct target_ops sparclet_ops;
35
36 static void sparclet_open PARAMS ((char *args, int from_tty));
37
38 /* This array of registers need to match the indexes used by GDB.
39    This exists because the various ROM monitors use different strings
40    than does GDB, and don't necessarily support all the registers
41    either. So, typing "info reg sp" becomes a "r30".  */
42
43 /*PSR 0x00000080  impl ver icc AW LE EE EC EF PIL S PS ET CWP  WIM
44    0x0  0x0 0x0  0  0  0  0  0 0x0 1  0  0 0x00 0x2
45    0000010
46    INS        LOCALS       OUTS      GLOBALS
47    0  0x00000000  0x00000000  0x00000000  0x00000000
48    1  0x00000000  0x00000000  0x00000000  0x00000000
49    2  0x00000000  0x00000000  0x00000000  0x00000000
50    3  0x00000000  0x00000000  0x00000000  0x00000000
51    4  0x00000000  0x00000000  0x00000000  0x00000000
52    5  0x00000000  0x00001000  0x00000000  0x00000000
53    6  0x00000000  0x00000000  0x123f0000  0x00000000
54    7  0x00000000  0x00000000  0x00000000  0x00000000
55    pc:  0x12010000 0x00000000    unimp
56    npc: 0x12010004 0x00001000    unimp     0x1000
57    tbr: 0x00000000
58    y:   0x00000000
59  */
60 /* these correspond to the offsets from tm-* files from config directories */
61
62 /* is wim part of psr?? */
63 /* monitor wants lower case */
64 static char *sparclet_regnames[NUM_REGS] = REGISTER_NAMES;
65
66
67 /* Function: sparclet_supply_register
68    Just returns with no action.
69    This function is required, because parse_register_dump (monitor.c)
70    expects to be able to call it.  If we don't supply something, it will
71    call a null pointer and core-dump.  Since this function does not 
72    actually do anything, GDB will request the registers individually.  */
73
74 static void
75 sparclet_supply_register (regname, regnamelen, val, vallen)
76      char *regname;
77      int regnamelen;
78      char *val;
79      int vallen;
80 {
81   return;
82 }
83
84 static void
85 sparclet_load (desc, file, hashmark)
86      serial_t desc;
87      char *file;
88      int hashmark;
89 {
90   bfd *abfd;
91   asection *s;
92   int i;
93   CORE_ADDR load_offset;
94   time_t start_time, end_time;
95   unsigned long data_count = 0;
96
97   /* enable user to specify address for downloading as 2nd arg to load */
98
99   i = sscanf (file, "%*s 0x%lx", &load_offset);
100   if (i >= 1)
101     {
102       char *p;
103
104       for (p = file; *p != '\000' && !isspace (*p); p++);
105
106       *p = '\000';
107     }
108   else
109     load_offset = 0;
110
111   abfd = bfd_openr (file, 0);
112   if (!abfd)
113     {
114       printf_filtered ("Unable to open file %s\n", file);
115       return;
116     }
117
118   if (bfd_check_format (abfd, bfd_object) == 0)
119     {
120       printf_filtered ("File is not an object file\n");
121       return;
122     }
123
124   start_time = time (NULL);
125
126   for (s = abfd->sections; s; s = s->next)
127     if (s->flags & SEC_LOAD)
128       {
129         bfd_size_type section_size;
130         bfd_vma vma;
131
132         vma = bfd_get_section_vma (abfd, s) + load_offset;
133         section_size = bfd_section_size (abfd, s);
134
135         data_count += section_size;
136
137         printf_filtered ("%s\t: 0x%4x .. 0x%4x  ",
138                          bfd_get_section_name (abfd, s), vma,
139                          vma + section_size);
140         gdb_flush (gdb_stdout);
141
142         monitor_printf ("load c r %x %x\r", vma, section_size);
143
144         monitor_expect ("load: loading ", NULL, 0);
145         monitor_expect ("\r", NULL, 0);
146
147         for (i = 0; i < section_size; i += 2048)
148           {
149             int numbytes;
150             char buf[2048];
151
152             numbytes = min (sizeof buf, section_size - i);
153
154             bfd_get_section_contents (abfd, s, buf, i, numbytes);
155
156             SERIAL_WRITE (desc, buf, numbytes);
157
158             if (hashmark)
159               {
160                 putchar_unfiltered ('#');
161                 gdb_flush (gdb_stdout);
162               }
163           }                     /* Per-packet (or S-record) loop */
164
165         monitor_expect_prompt (NULL, 0);
166
167         putchar_unfiltered ('\n');
168       }                         /* Loadable sections */
169
170   monitor_printf ("reg pc %x\r", bfd_get_start_address (abfd));
171   monitor_expect_prompt (NULL, 0);
172   monitor_printf ("reg npc %x\r", bfd_get_start_address (abfd) + 4);
173   monitor_expect_prompt (NULL, 0);
174
175   monitor_printf ("run\r");
176
177   end_time = time (NULL);
178
179   if (hashmark)
180     putchar_unfiltered ('\n');
181
182   report_transfer_performance (data_count, start_time, end_time);
183
184   pop_target ();
185   push_remote_target (monitor_get_dev_name (), 1);
186
187   return_to_top_level (RETURN_QUIT);
188 }
189
190 /* Define the monitor command strings. Since these are passed directly
191    through to a printf style function, we may include formatting
192    strings. We also need a CR or LF on the end.  */
193
194 /* need to pause the monitor for timing reasons, so slow it down */
195
196 static char *sparclet_inits[] =
197 {"\n\r\r\n", NULL};
198
199 static struct monitor_ops sparclet_cmds;
200
201 static void
202 init_sparclet_cmds (void)
203 {
204   sparclet_cmds.flags = MO_CLR_BREAK_USES_ADDR |
205     MO_HEX_PREFIX |
206     MO_NO_ECHO_ON_OPEN |
207     MO_NO_ECHO_ON_SETMEM |
208     MO_RUN_FIRST_TIME |
209     MO_GETMEM_READ_SINGLE;      /* flags */
210   sparclet_cmds.init = sparclet_inits;  /* Init strings */
211   sparclet_cmds.cont = "cont\r";        /* continue command */
212   sparclet_cmds.step = "step\r";        /* single step */
213   sparclet_cmds.stop = "\r";    /* break interrupts the program */
214   sparclet_cmds.set_break = "+bp %x\r";         /* set a breakpoint */
215   sparclet_cmds.clr_break = "-bp %x\r";         /* can't use "br" because only 2 hw bps are supported */
216   sparclet_cmds.clr_all_break = "-bp %x\r";     /* clear a breakpoint */
217   "-bp\r";                      /* clear all breakpoints */
218   sparclet_cmds.fill = "fill %x -n %x -v %x -b\r";      /* fill (start length val) */
219   /* can't use "fi" because it takes words, not bytes */
220   /* ex [addr] [-n count] [-b|-s|-l]          default: ex cur -n 1 -b */
221   sparclet_cmds.setmem.cmdb = "ex %x -b\r%x\rq\r";      /* setmem.cmdb (addr, value) */
222   sparclet_cmds.setmem.cmdw = "ex %x -s\r%x\rq\r";      /* setmem.cmdw (addr, value) */
223   sparclet_cmds.setmem.cmdl = "ex %x -l\r%x\rq\r";      /* setmem.cmdl (addr, value) */
224   sparclet_cmds.setmem.cmdll = NULL;    /* setmem.cmdll (addr, value) */
225   sparclet_cmds.setmem.resp_delim = NULL;       /*": " *//* setmem.resp_delim */
226   sparclet_cmds.setmem.term = NULL;     /*"? " *//* setmem.term */
227   sparclet_cmds.setmem.term_cmd = NULL;         /*"q\r" *//* setmem.term_cmd */
228   /* since the parsing of multiple bytes is difficult due to
229      interspersed addresses, we'll only read 1 value at a time,
230      even tho these can handle a count */
231   /* we can use -n to set count to read, but may have to parse? */
232   sparclet_cmds.getmem.cmdb = "ex %x -n 1 -b\r";        /* getmem.cmdb (addr, #bytes) */
233   sparclet_cmds.getmem.cmdw = "ex %x -n 1 -s\r";        /* getmem.cmdw (addr, #swords) */
234   sparclet_cmds.getmem.cmdl = "ex %x -n 1 -l\r";        /* getmem.cmdl (addr, #words) */
235   sparclet_cmds.getmem.cmdll = NULL;    /* getmem.cmdll (addr, #dwords) */
236   sparclet_cmds.getmem.resp_delim = ": ";       /* getmem.resp_delim */
237   sparclet_cmds.getmem.term = NULL;     /* getmem.term */
238   sparclet_cmds.getmem.term_cmd = NULL;         /* getmem.term_cmd */
239   sparclet_cmds.setreg.cmd = "reg %s 0x%x\r";   /* setreg.cmd (name, value) */
240   sparclet_cmds.setreg.resp_delim = NULL;       /* setreg.resp_delim */
241   sparclet_cmds.setreg.term = NULL;     /* setreg.term */
242   sparclet_cmds.setreg.term_cmd = NULL;         /* setreg.term_cmd */
243   sparclet_cmds.getreg.cmd = "reg %s\r";        /* getreg.cmd (name) */
244   sparclet_cmds.getreg.resp_delim = " ";        /* getreg.resp_delim */
245   sparclet_cmds.getreg.term = NULL;     /* getreg.term */
246   sparclet_cmds.getreg.term_cmd = NULL;         /* getreg.term_cmd */
247   sparclet_cmds.dump_registers = "reg\r";       /* dump_registers */
248   sparclet_cmds.register_pattern = "\\(\\w+\\)=\\([0-9a-fA-F]+\\)";     /* register_pattern */
249   sparclet_cmds.supply_register = sparclet_supply_register;     /* supply_register */
250   sparclet_cmds.load_routine = sparclet_load;   /* load_routine */
251   sparclet_cmds.load = NULL;    /* download command (srecs on console) */
252   sparclet_cmds.loadresp = NULL;        /* load response */
253   sparclet_cmds.prompt = "monitor>";    /* monitor command prompt */
254   /* yikes!  gdb core dumps without this delimitor!! */
255   sparclet_cmds.line_term = "\r";       /* end-of-command delimitor */
256   sparclet_cmds.cmd_end = NULL; /* optional command terminator */
257   sparclet_cmds.target = &sparclet_ops;         /* target operations */
258   sparclet_cmds.stopbits = SERIAL_1_STOPBITS;   /* number of stop bits */
259   sparclet_cmds.regnames = sparclet_regnames;   /* registers names */
260   sparclet_cmds.magic = MONITOR_OPS_MAGIC;      /* magic */
261 };
262
263 static void
264 sparclet_open (args, from_tty)
265      char *args;
266      int from_tty;
267 {
268   monitor_open (args, &sparclet_cmds, from_tty);
269 }
270
271 void
272 _initialize_sparclet ()
273 {
274   int i;
275   init_sparclet_cmds ();
276
277   for (i = 0; i < NUM_REGS; i++)
278     if (sparclet_regnames[i][0] == 'c' ||
279         sparclet_regnames[i][0] == 'a')
280       sparclet_regnames[i] = 0; /* mon can't report c* or a* regs */
281
282   sparclet_regnames[0] = 0;     /* mon won't report %G0 */
283
284   init_monitor_ops (&sparclet_ops);
285   sparclet_ops.to_shortname = "sparclet";       /* for the target command */
286   sparclet_ops.to_longname = "SPARC Sparclet monitor";
287   /* use SW breaks; target only supports 2 HW breakpoints */
288   sparclet_ops.to_insert_breakpoint = memory_insert_breakpoint;
289   sparclet_ops.to_remove_breakpoint = memory_remove_breakpoint;
290
291   sparclet_ops.to_doc =
292     "Use a board running the Sparclet debug monitor.\n\
293 Specify the serial device it is connected to (e.g. /dev/ttya).";
294
295   sparclet_ops.to_open = sparclet_open;
296   add_target (&sparclet_ops);
297 }