m32r-stub.c revision 1.1 1 1.1 christos /****************************************************************************
2 1.1 christos
3 1.1 christos THIS SOFTWARE IS NOT COPYRIGHTED
4 1.1 christos
5 1.1 christos HP offers the following for use in the public domain. HP makes no
6 1.1 christos warranty with regard to the software or it's performance and the
7 1.1 christos user accepts the software "AS IS" with all faults.
8 1.1 christos
9 1.1 christos HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10 1.1 christos TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11 1.1 christos OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12 1.1 christos
13 1.1 christos ****************************************************************************/
14 1.1 christos
15 1.1 christos /****************************************************************************
16 1.1 christos * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17 1.1 christos *
18 1.1 christos * Module name: remcom.c $
19 1.1 christos * Revision: 1.34 $
20 1.1 christos * Date: 91/03/09 12:29:49 $
21 1.1 christos * Contributor: Lake Stevens Instrument Division$
22 1.1 christos *
23 1.1 christos * Description: low level support for gdb debugger. $
24 1.1 christos *
25 1.1 christos * Considerations: only works on target hardware $
26 1.1 christos *
27 1.1 christos * Written by: Glenn Engel $
28 1.1 christos * ModuleState: Experimental $
29 1.1 christos *
30 1.1 christos * NOTES: See Below $
31 1.1 christos *
32 1.1 christos * Modified for M32R by Michael Snyder, Cygnus Support.
33 1.1 christos *
34 1.1 christos * To enable debugger support, two things need to happen. One, a
35 1.1 christos * call to set_debug_traps() is necessary in order to allow any breakpoints
36 1.1 christos * or error conditions to be properly intercepted and reported to gdb.
37 1.1 christos * Two, a breakpoint needs to be generated to begin communication. This
38 1.1 christos * is most easily accomplished by a call to breakpoint(). Breakpoint()
39 1.1 christos * simulates a breakpoint by executing a trap #1.
40 1.1 christos *
41 1.1 christos * The external function exceptionHandler() is
42 1.1 christos * used to attach a specific handler to a specific M32R vector number.
43 1.1 christos * It should use the same privilege level it runs at. It should
44 1.1 christos * install it as an interrupt gate so that interrupts are masked
45 1.1 christos * while the handler runs.
46 1.1 christos *
47 1.1 christos * Because gdb will sometimes write to the stack area to execute function
48 1.1 christos * calls, this program cannot rely on using the supervisor stack so it
49 1.1 christos * uses it's own stack area reserved in the int array remcomStack.
50 1.1 christos *
51 1.1 christos *************
52 1.1 christos *
53 1.1 christos * The following gdb commands are supported:
54 1.1 christos *
55 1.1 christos * command function Return value
56 1.1 christos *
57 1.1 christos * g return the value of the CPU registers hex data or ENN
58 1.1 christos * G set the value of the CPU registers OK or ENN
59 1.1 christos *
60 1.1 christos * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
61 1.1 christos * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
62 1.1 christos * XAA..AA,LLLL: Write LLLL binary bytes at address OK or ENN
63 1.1 christos * AA..AA
64 1.1 christos *
65 1.1 christos * c Resume at current address SNN ( signal NN)
66 1.1 christos * cAA..AA Continue at address AA..AA SNN
67 1.1 christos *
68 1.1 christos * s Step one instruction SNN
69 1.1 christos * sAA..AA Step one instruction from AA..AA SNN
70 1.1 christos *
71 1.1 christos * k kill
72 1.1 christos *
73 1.1 christos * ? What was the last sigval ? SNN (signal NN)
74 1.1 christos *
75 1.1 christos * All commands and responses are sent with a packet which includes a
76 1.1 christos * checksum. A packet consists of
77 1.1 christos *
78 1.1 christos * $<packet info>#<checksum>.
79 1.1 christos *
80 1.1 christos * where
81 1.1 christos * <packet info> :: <characters representing the command or response>
82 1.1 christos * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>>
83 1.1 christos *
84 1.1 christos * When a packet is received, it is first acknowledged with either '+' or '-'.
85 1.1 christos * '+' indicates a successful transfer. '-' indicates a failed transfer.
86 1.1 christos *
87 1.1 christos * Example:
88 1.1 christos *
89 1.1 christos * Host: Reply:
90 1.1 christos * $m0,10#2a +$00010203040506070809101112131415#42
91 1.1 christos *
92 1.1 christos ****************************************************************************/
93 1.1 christos
94 1.1 christos
95 1.1 christos /************************************************************************
96 1.1 christos *
97 1.1 christos * external low-level support routines
98 1.1 christos */
99 1.1 christos extern void putDebugChar (); /* write a single character */
100 1.1 christos extern int getDebugChar (); /* read and return a single char */
101 1.1 christos extern void exceptionHandler (); /* assign an exception handler */
102 1.1 christos
103 1.1 christos /*****************************************************************************
104 1.1 christos * BUFMAX defines the maximum number of characters in inbound/outbound buffers
105 1.1 christos * at least NUMREGBYTES*2 are needed for register packets
106 1.1 christos */
107 1.1 christos #define BUFMAX 400
108 1.1 christos
109 1.1 christos static char initialized; /* boolean flag. != 0 means we've been initialized */
110 1.1 christos
111 1.1 christos int remote_debug;
112 1.1 christos /* debug > 0 prints ill-formed commands in valid packets & checksum errors */
113 1.1 christos
114 1.1 christos static const unsigned char hexchars[] = "0123456789abcdef";
115 1.1 christos
116 1.1 christos #define NUMREGS 24
117 1.1 christos
118 1.1 christos /* Number of bytes of registers. */
119 1.1 christos #define NUMREGBYTES (NUMREGS * 4)
120 1.1 christos enum regnames
121 1.1 christos { R0, R1, R2, R3, R4, R5, R6, R7,
122 1.1 christos R8, R9, R10, R11, R12, R13, R14, R15,
123 1.1 christos PSW, CBR, SPI, SPU, BPC, PC, ACCL, ACCH
124 1.1 christos };
125 1.1 christos
126 1.1 christos enum SYS_calls
127 1.1 christos {
128 1.1 christos SYS_null,
129 1.1 christos SYS_exit,
130 1.1 christos SYS_open,
131 1.1 christos SYS_close,
132 1.1 christos SYS_read,
133 1.1 christos SYS_write,
134 1.1 christos SYS_lseek,
135 1.1 christos SYS_unlink,
136 1.1 christos SYS_getpid,
137 1.1 christos SYS_kill,
138 1.1 christos SYS_fstat,
139 1.1 christos SYS_sbrk,
140 1.1 christos SYS_fork,
141 1.1 christos SYS_execve,
142 1.1 christos SYS_wait4,
143 1.1 christos SYS_link,
144 1.1 christos SYS_chdir,
145 1.1 christos SYS_stat,
146 1.1 christos SYS_utime,
147 1.1 christos SYS_chown,
148 1.1 christos SYS_chmod,
149 1.1 christos SYS_time,
150 1.1 christos SYS_pipe
151 1.1 christos };
152 1.1 christos
153 1.1 christos static int registers[NUMREGS];
154 1.1 christos
155 1.1 christos #define STACKSIZE 8096
156 1.1 christos static unsigned char remcomInBuffer[BUFMAX];
157 1.1 christos static unsigned char remcomOutBuffer[BUFMAX];
158 1.1 christos static int remcomStack[STACKSIZE / sizeof (int)];
159 1.1 christos static int *stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
160 1.1 christos
161 1.1 christos static unsigned int save_vectors[18]; /* previous exception vectors */
162 1.1 christos
163 1.1 christos /* Indicate to caller of mem2hex or hex2mem that there has been an error. */
164 1.1 christos static volatile int mem_err = 0;
165 1.1 christos
166 1.1 christos /* Store the vector number here (since GDB only gets the signal
167 1.1 christos number through the usual means, and that's not very specific). */
168 1.1 christos int gdb_m32r_vector = -1;
169 1.1 christos
170 1.1 christos #if 0
171 1.1 christos #include "syscall.h" /* for SYS_exit, SYS_write etc. */
172 1.1 christos #endif
173 1.1 christos
174 1.1 christos /* Global entry points:
175 1.1 christos */
176 1.1 christos
177 1.1 christos extern void handle_exception (int);
178 1.1 christos extern void set_debug_traps (void);
179 1.1 christos extern void breakpoint (void);
180 1.1 christos
181 1.1 christos /* Local functions:
182 1.1 christos */
183 1.1 christos
184 1.1 christos static int computeSignal (int);
185 1.1 christos static void putpacket (unsigned char *);
186 1.1 christos static unsigned char *getpacket (void);
187 1.1 christos
188 1.1 christos static unsigned char *mem2hex (unsigned char *, unsigned char *, int, int);
189 1.1 christos static unsigned char *hex2mem (unsigned char *, unsigned char *, int, int);
190 1.1 christos static int hexToInt (unsigned char **, int *);
191 1.1 christos static unsigned char *bin2mem (unsigned char *, unsigned char *, int, int);
192 1.1 christos static void stash_registers (void);
193 1.1 christos static void restore_registers (void);
194 1.1 christos static int prepare_to_step (int);
195 1.1 christos static int finish_from_step (void);
196 1.1 christos static unsigned long crc32 (unsigned char *, int, unsigned long);
197 1.1 christos
198 1.1 christos static void gdb_error (char *, char *);
199 1.1 christos static int gdb_putchar (int), gdb_puts (char *), gdb_write (char *, int);
200 1.1 christos
201 1.1 christos static unsigned char *strcpy (unsigned char *, const unsigned char *);
202 1.1 christos static int strlen (const unsigned char *);
203 1.1 christos
204 1.1 christos /*
205 1.1 christos * This function does all command procesing for interfacing to gdb.
206 1.1 christos */
207 1.1 christos
208 1.1 christos void
209 1.1 christos handle_exception (int exceptionVector)
210 1.1 christos {
211 1.1 christos int sigval, stepping;
212 1.1 christos int addr, length, i;
213 1.1 christos unsigned char *ptr;
214 1.1 christos unsigned char buf[16];
215 1.1 christos int binary;
216 1.1 christos
217 1.1 christos if (!finish_from_step ())
218 1.1 christos return; /* "false step": let the target continue */
219 1.1 christos
220 1.1 christos gdb_m32r_vector = exceptionVector;
221 1.1 christos
222 1.1 christos if (remote_debug)
223 1.1 christos {
224 1.1 christos mem2hex ((unsigned char *) &exceptionVector, buf, 4, 0);
225 1.1 christos gdb_error ("Handle exception %s, ", buf);
226 1.1 christos mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0);
227 1.1 christos gdb_error ("PC == 0x%s\n", buf);
228 1.1 christos }
229 1.1 christos
230 1.1 christos /* reply to host that an exception has occurred */
231 1.1 christos sigval = computeSignal (exceptionVector);
232 1.1 christos
233 1.1 christos ptr = remcomOutBuffer;
234 1.1 christos
235 1.1 christos *ptr++ = 'T'; /* notify gdb with signo, PC, FP and SP */
236 1.1 christos *ptr++ = hexchars[sigval >> 4];
237 1.1 christos *ptr++ = hexchars[sigval & 0xf];
238 1.1 christos
239 1.1 christos *ptr++ = hexchars[PC >> 4];
240 1.1 christos *ptr++ = hexchars[PC & 0xf];
241 1.1 christos *ptr++ = ':';
242 1.1 christos ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0); /* PC */
243 1.1 christos *ptr++ = ';';
244 1.1 christos
245 1.1 christos *ptr++ = hexchars[R13 >> 4];
246 1.1 christos *ptr++ = hexchars[R13 & 0xf];
247 1.1 christos *ptr++ = ':';
248 1.1 christos ptr = mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0); /* FP */
249 1.1 christos *ptr++ = ';';
250 1.1 christos
251 1.1 christos *ptr++ = hexchars[R15 >> 4];
252 1.1 christos *ptr++ = hexchars[R15 & 0xf];
253 1.1 christos *ptr++ = ':';
254 1.1 christos ptr = mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0); /* SP */
255 1.1 christos *ptr++ = ';';
256 1.1 christos *ptr++ = 0;
257 1.1 christos
258 1.1 christos if (exceptionVector == 0) /* simulated SYS call stuff */
259 1.1 christos {
260 1.1 christos mem2hex ((unsigned char *) ®isters[PC], buf, 4, 0);
261 1.1 christos switch (registers[R0])
262 1.1 christos {
263 1.1 christos case SYS_exit:
264 1.1 christos gdb_error ("Target program has exited at %s\n", buf);
265 1.1 christos ptr = remcomOutBuffer;
266 1.1 christos *ptr++ = 'W';
267 1.1 christos sigval = registers[R1] & 0xff;
268 1.1 christos *ptr++ = hexchars[sigval >> 4];
269 1.1 christos *ptr++ = hexchars[sigval & 0xf];
270 1.1 christos *ptr++ = 0;
271 1.1 christos break;
272 1.1 christos case SYS_open:
273 1.1 christos gdb_error ("Target attempts SYS_open call at %s\n", buf);
274 1.1 christos break;
275 1.1 christos case SYS_close:
276 1.1 christos gdb_error ("Target attempts SYS_close call at %s\n", buf);
277 1.1 christos break;
278 1.1 christos case SYS_read:
279 1.1 christos gdb_error ("Target attempts SYS_read call at %s\n", buf);
280 1.1 christos break;
281 1.1 christos case SYS_write:
282 1.1 christos if (registers[R1] == 1 || /* write to stdout */
283 1.1 christos registers[R1] == 2) /* write to stderr */
284 1.1 christos { /* (we can do that) */
285 1.1 christos registers[R0] =
286 1.1 christos gdb_write ((void *) registers[R2], registers[R3]);
287 1.1 christos return;
288 1.1 christos }
289 1.1 christos else
290 1.1 christos gdb_error ("Target attempts SYS_write call at %s\n", buf);
291 1.1 christos break;
292 1.1 christos case SYS_lseek:
293 1.1 christos gdb_error ("Target attempts SYS_lseek call at %s\n", buf);
294 1.1 christos break;
295 1.1 christos case SYS_unlink:
296 1.1 christos gdb_error ("Target attempts SYS_unlink call at %s\n", buf);
297 1.1 christos break;
298 1.1 christos case SYS_getpid:
299 1.1 christos gdb_error ("Target attempts SYS_getpid call at %s\n", buf);
300 1.1 christos break;
301 1.1 christos case SYS_kill:
302 1.1 christos gdb_error ("Target attempts SYS_kill call at %s\n", buf);
303 1.1 christos break;
304 1.1 christos case SYS_fstat:
305 1.1 christos gdb_error ("Target attempts SYS_fstat call at %s\n", buf);
306 1.1 christos break;
307 1.1 christos default:
308 1.1 christos gdb_error ("Target attempts unknown SYS call at %s\n", buf);
309 1.1 christos break;
310 1.1 christos }
311 1.1 christos }
312 1.1 christos
313 1.1 christos putpacket (remcomOutBuffer);
314 1.1 christos
315 1.1 christos stepping = 0;
316 1.1 christos
317 1.1 christos while (1 == 1)
318 1.1 christos {
319 1.1 christos remcomOutBuffer[0] = 0;
320 1.1 christos ptr = getpacket ();
321 1.1 christos binary = 0;
322 1.1 christos switch (*ptr++)
323 1.1 christos {
324 1.1 christos default: /* Unknown code. Return an empty reply message. */
325 1.1 christos break;
326 1.1 christos case 'R':
327 1.1 christos if (hexToInt (&ptr, &addr))
328 1.1 christos registers[PC] = addr;
329 1.1 christos strcpy (remcomOutBuffer, "OK");
330 1.1 christos break;
331 1.1 christos case '!':
332 1.1 christos strcpy (remcomOutBuffer, "OK");
333 1.1 christos break;
334 1.1 christos case 'X': /* XAA..AA,LLLL:<binary data>#cs */
335 1.1 christos binary = 1;
336 1.1 christos case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
337 1.1 christos /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
338 1.1 christos {
339 1.1 christos if (hexToInt (&ptr, &addr))
340 1.1 christos if (*(ptr++) == ',')
341 1.1 christos if (hexToInt (&ptr, &length))
342 1.1 christos if (*(ptr++) == ':')
343 1.1 christos {
344 1.1 christos mem_err = 0;
345 1.1 christos if (binary)
346 1.1 christos bin2mem (ptr, (unsigned char *) addr, length, 1);
347 1.1 christos else
348 1.1 christos hex2mem (ptr, (unsigned char *) addr, length, 1);
349 1.1 christos if (mem_err)
350 1.1 christos {
351 1.1 christos strcpy (remcomOutBuffer, "E03");
352 1.1 christos gdb_error ("memory fault", "");
353 1.1 christos }
354 1.1 christos else
355 1.1 christos {
356 1.1 christos strcpy (remcomOutBuffer, "OK");
357 1.1 christos }
358 1.1 christos ptr = 0;
359 1.1 christos }
360 1.1 christos if (ptr)
361 1.1 christos {
362 1.1 christos strcpy (remcomOutBuffer, "E02");
363 1.1 christos }
364 1.1 christos }
365 1.1 christos break;
366 1.1 christos case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
367 1.1 christos /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
368 1.1 christos if (hexToInt (&ptr, &addr))
369 1.1 christos if (*(ptr++) == ',')
370 1.1 christos if (hexToInt (&ptr, &length))
371 1.1 christos {
372 1.1 christos ptr = 0;
373 1.1 christos mem_err = 0;
374 1.1 christos mem2hex ((unsigned char *) addr, remcomOutBuffer, length,
375 1.1 christos 1);
376 1.1 christos if (mem_err)
377 1.1 christos {
378 1.1 christos strcpy (remcomOutBuffer, "E03");
379 1.1 christos gdb_error ("memory fault", "");
380 1.1 christos }
381 1.1 christos }
382 1.1 christos if (ptr)
383 1.1 christos {
384 1.1 christos strcpy (remcomOutBuffer, "E01");
385 1.1 christos }
386 1.1 christos break;
387 1.1 christos case '?':
388 1.1 christos remcomOutBuffer[0] = 'S';
389 1.1 christos remcomOutBuffer[1] = hexchars[sigval >> 4];
390 1.1 christos remcomOutBuffer[2] = hexchars[sigval % 16];
391 1.1 christos remcomOutBuffer[3] = 0;
392 1.1 christos break;
393 1.1 christos case 'd':
394 1.1 christos remote_debug = !(remote_debug); /* toggle debug flag */
395 1.1 christos break;
396 1.1 christos case 'g': /* return the value of the CPU registers */
397 1.1 christos mem2hex ((unsigned char *) registers, remcomOutBuffer, NUMREGBYTES,
398 1.1 christos 0);
399 1.1 christos break;
400 1.1 christos case 'P': /* set the value of a single CPU register - return OK */
401 1.1 christos {
402 1.1 christos int regno;
403 1.1 christos
404 1.1 christos if (hexToInt (&ptr, ®no) && *ptr++ == '=')
405 1.1 christos if (regno >= 0 && regno < NUMREGS)
406 1.1 christos {
407 1.1 christos int stackmode;
408 1.1 christos
409 1.1 christos hex2mem (ptr, (unsigned char *) ®isters[regno], 4, 0);
410 1.1 christos /*
411 1.1 christos * Since we just changed a single CPU register, let's
412 1.1 christos * make sure to keep the several stack pointers consistant.
413 1.1 christos */
414 1.1 christos stackmode = registers[PSW] & 0x80;
415 1.1 christos if (regno == R15) /* stack pointer changed */
416 1.1 christos { /* need to change SPI or SPU */
417 1.1 christos if (stackmode == 0)
418 1.1 christos registers[SPI] = registers[R15];
419 1.1 christos else
420 1.1 christos registers[SPU] = registers[R15];
421 1.1 christos }
422 1.1 christos else if (regno == SPU) /* "user" stack pointer changed */
423 1.1 christos {
424 1.1 christos if (stackmode != 0) /* stack in user mode: copy SP */
425 1.1 christos registers[R15] = registers[SPU];
426 1.1 christos }
427 1.1 christos else if (regno == SPI) /* "interrupt" stack pointer changed */
428 1.1 christos {
429 1.1 christos if (stackmode == 0) /* stack in interrupt mode: copy SP */
430 1.1 christos registers[R15] = registers[SPI];
431 1.1 christos }
432 1.1 christos else if (regno == PSW) /* stack mode may have changed! */
433 1.1 christos { /* force SP to either SPU or SPI */
434 1.1 christos if (stackmode == 0) /* stack in user mode */
435 1.1 christos registers[R15] = registers[SPI];
436 1.1 christos else /* stack in interrupt mode */
437 1.1 christos registers[R15] = registers[SPU];
438 1.1 christos }
439 1.1 christos strcpy (remcomOutBuffer, "OK");
440 1.1 christos break;
441 1.1 christos }
442 1.1 christos strcpy (remcomOutBuffer, "E01");
443 1.1 christos break;
444 1.1 christos }
445 1.1 christos case 'G': /* set the value of the CPU registers - return OK */
446 1.1 christos hex2mem (ptr, (unsigned char *) registers, NUMREGBYTES, 0);
447 1.1 christos strcpy (remcomOutBuffer, "OK");
448 1.1 christos break;
449 1.1 christos case 's': /* sAA..AA Step one instruction from AA..AA(optional) */
450 1.1 christos stepping = 1;
451 1.1 christos case 'c': /* cAA..AA Continue from address AA..AA(optional) */
452 1.1 christos /* try to read optional parameter, pc unchanged if no parm */
453 1.1 christos if (hexToInt (&ptr, &addr))
454 1.1 christos registers[PC] = addr;
455 1.1 christos
456 1.1 christos if (stepping) /* single-stepping */
457 1.1 christos {
458 1.1 christos if (!prepare_to_step (0)) /* set up for single-step */
459 1.1 christos {
460 1.1 christos /* prepare_to_step has already emulated the target insn:
461 1.1 christos Send SIGTRAP to gdb, don't resume the target at all. */
462 1.1 christos ptr = remcomOutBuffer;
463 1.1 christos *ptr++ = 'T'; /* Simulate stopping with SIGTRAP */
464 1.1 christos *ptr++ = '0';
465 1.1 christos *ptr++ = '5';
466 1.1 christos
467 1.1 christos *ptr++ = hexchars[PC >> 4]; /* send PC */
468 1.1 christos *ptr++ = hexchars[PC & 0xf];
469 1.1 christos *ptr++ = ':';
470 1.1 christos ptr = mem2hex ((unsigned char *) ®isters[PC], ptr, 4, 0);
471 1.1 christos *ptr++ = ';';
472 1.1 christos
473 1.1 christos *ptr++ = hexchars[R13 >> 4]; /* send FP */
474 1.1 christos *ptr++ = hexchars[R13 & 0xf];
475 1.1 christos *ptr++ = ':';
476 1.1 christos ptr =
477 1.1 christos mem2hex ((unsigned char *) ®isters[R13], ptr, 4, 0);
478 1.1 christos *ptr++ = ';';
479 1.1 christos
480 1.1 christos *ptr++ = hexchars[R15 >> 4]; /* send SP */
481 1.1 christos *ptr++ = hexchars[R15 & 0xf];
482 1.1 christos *ptr++ = ':';
483 1.1 christos ptr =
484 1.1 christos mem2hex ((unsigned char *) ®isters[R15], ptr, 4, 0);
485 1.1 christos *ptr++ = ';';
486 1.1 christos *ptr++ = 0;
487 1.1 christos
488 1.1 christos break;
489 1.1 christos }
490 1.1 christos }
491 1.1 christos else /* continuing, not single-stepping */
492 1.1 christos {
493 1.1 christos /* OK, about to do a "continue". First check to see if the
494 1.1 christos target pc is on an odd boundary (second instruction in the
495 1.1 christos word). If so, we must do a single-step first, because
496 1.1 christos ya can't jump or return back to an odd boundary! */
497 1.1 christos if ((registers[PC] & 2) != 0)
498 1.1 christos prepare_to_step (1);
499 1.1 christos }
500 1.1 christos
501 1.1 christos return;
502 1.1 christos
503 1.1 christos case 'D': /* Detach */
504 1.1 christos #if 0
505 1.1 christos /* I am interpreting this to mean, release the board from control
506 1.1 christos by the remote stub. To do this, I am restoring the original
507 1.1 christos (or at least previous) exception vectors.
508 1.1 christos */
509 1.1 christos for (i = 0; i < 18; i++)
510 1.1 christos exceptionHandler (i, save_vectors[i]);
511 1.1 christos putpacket ("OK");
512 1.1 christos return; /* continue the inferior */
513 1.1 christos #else
514 1.1 christos strcpy (remcomOutBuffer, "OK");
515 1.1 christos break;
516 1.1 christos #endif
517 1.1 christos case 'q':
518 1.1 christos if (*ptr++ == 'C' &&
519 1.1 christos *ptr++ == 'R' && *ptr++ == 'C' && *ptr++ == ':')
520 1.1 christos {
521 1.1 christos unsigned long start, len, our_crc;
522 1.1 christos
523 1.1 christos if (hexToInt (&ptr, (int *) &start) &&
524 1.1 christos *ptr++ == ',' && hexToInt (&ptr, (int *) &len))
525 1.1 christos {
526 1.1 christos remcomOutBuffer[0] = 'C';
527 1.1 christos our_crc = crc32 ((unsigned char *) start, len, 0xffffffff);
528 1.1 christos mem2hex ((char *) &our_crc,
529 1.1 christos &remcomOutBuffer[1], sizeof (long), 0);
530 1.1 christos } /* else do nothing */
531 1.1 christos } /* else do nothing */
532 1.1 christos break;
533 1.1 christos
534 1.1 christos case 'k': /* kill the program */
535 1.1 christos continue;
536 1.1 christos } /* switch */
537 1.1 christos
538 1.1 christos /* reply to the request */
539 1.1 christos putpacket (remcomOutBuffer);
540 1.1 christos }
541 1.1 christos }
542 1.1 christos
543 1.1 christos /* qCRC support */
544 1.1 christos
545 1.1 christos /* Table used by the crc32 function to calcuate the checksum. */
546 1.1 christos static unsigned long crc32_table[256] = { 0, 0 };
547 1.1 christos
548 1.1 christos static unsigned long
549 1.1 christos crc32 (unsigned char *buf, int len, unsigned long crc)
550 1.1 christos {
551 1.1 christos if (!crc32_table[1])
552 1.1 christos {
553 1.1 christos /* Initialize the CRC table and the decoding table. */
554 1.1 christos int i, j;
555 1.1 christos unsigned long c;
556 1.1 christos
557 1.1 christos for (i = 0; i < 256; i++)
558 1.1 christos {
559 1.1 christos for (c = i << 24, j = 8; j > 0; --j)
560 1.1 christos c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
561 1.1 christos crc32_table[i] = c;
562 1.1 christos }
563 1.1 christos }
564 1.1 christos
565 1.1 christos while (len--)
566 1.1 christos {
567 1.1 christos crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
568 1.1 christos buf++;
569 1.1 christos }
570 1.1 christos return crc;
571 1.1 christos }
572 1.1 christos
573 1.1 christos static int
574 1.1 christos hex (unsigned char ch)
575 1.1 christos {
576 1.1 christos if ((ch >= 'a') && (ch <= 'f'))
577 1.1 christos return (ch - 'a' + 10);
578 1.1 christos if ((ch >= '0') && (ch <= '9'))
579 1.1 christos return (ch - '0');
580 1.1 christos if ((ch >= 'A') && (ch <= 'F'))
581 1.1 christos return (ch - 'A' + 10);
582 1.1 christos return (-1);
583 1.1 christos }
584 1.1 christos
585 1.1 christos /* scan for the sequence $<data>#<checksum> */
586 1.1 christos
587 1.1 christos unsigned char *
588 1.1 christos getpacket (void)
589 1.1 christos {
590 1.1 christos unsigned char *buffer = &remcomInBuffer[0];
591 1.1 christos unsigned char checksum;
592 1.1 christos unsigned char xmitcsum;
593 1.1 christos int count;
594 1.1 christos char ch;
595 1.1 christos
596 1.1 christos while (1)
597 1.1 christos {
598 1.1 christos /* wait around for the start character, ignore all other characters */
599 1.1 christos while ((ch = getDebugChar ()) != '$')
600 1.1 christos ;
601 1.1 christos
602 1.1 christos retry:
603 1.1 christos checksum = 0;
604 1.1 christos xmitcsum = -1;
605 1.1 christos count = 0;
606 1.1 christos
607 1.1 christos /* now, read until a # or end of buffer is found */
608 1.1 christos while (count < BUFMAX - 1)
609 1.1 christos {
610 1.1 christos ch = getDebugChar ();
611 1.1 christos if (ch == '$')
612 1.1 christos goto retry;
613 1.1 christos if (ch == '#')
614 1.1 christos break;
615 1.1 christos checksum = checksum + ch;
616 1.1 christos buffer[count] = ch;
617 1.1 christos count = count + 1;
618 1.1 christos }
619 1.1 christos buffer[count] = 0;
620 1.1 christos
621 1.1 christos if (ch == '#')
622 1.1 christos {
623 1.1 christos ch = getDebugChar ();
624 1.1 christos xmitcsum = hex (ch) << 4;
625 1.1 christos ch = getDebugChar ();
626 1.1 christos xmitcsum += hex (ch);
627 1.1 christos
628 1.1 christos if (checksum != xmitcsum)
629 1.1 christos {
630 1.1 christos if (remote_debug)
631 1.1 christos {
632 1.1 christos unsigned char buf[16];
633 1.1 christos
634 1.1 christos mem2hex ((unsigned char *) &checksum, buf, 4, 0);
635 1.1 christos gdb_error ("Bad checksum: my count = %s, ", buf);
636 1.1 christos mem2hex ((unsigned char *) &xmitcsum, buf, 4, 0);
637 1.1 christos gdb_error ("sent count = %s\n", buf);
638 1.1 christos gdb_error (" -- Bad buffer: \"%s\"\n", buffer);
639 1.1 christos }
640 1.1 christos putDebugChar ('-'); /* failed checksum */
641 1.1 christos }
642 1.1 christos else
643 1.1 christos {
644 1.1 christos putDebugChar ('+'); /* successful transfer */
645 1.1 christos
646 1.1 christos /* if a sequence char is present, reply the sequence ID */
647 1.1 christos if (buffer[2] == ':')
648 1.1 christos {
649 1.1 christos putDebugChar (buffer[0]);
650 1.1 christos putDebugChar (buffer[1]);
651 1.1 christos
652 1.1 christos return &buffer[3];
653 1.1 christos }
654 1.1 christos
655 1.1 christos return &buffer[0];
656 1.1 christos }
657 1.1 christos }
658 1.1 christos }
659 1.1 christos }
660 1.1 christos
661 1.1 christos /* send the packet in buffer. */
662 1.1 christos
663 1.1 christos static void
664 1.1 christos putpacket (unsigned char *buffer)
665 1.1 christos {
666 1.1 christos unsigned char checksum;
667 1.1 christos int count;
668 1.1 christos char ch;
669 1.1 christos
670 1.1 christos /* $<packet info>#<checksum>. */
671 1.1 christos do
672 1.1 christos {
673 1.1 christos putDebugChar ('$');
674 1.1 christos checksum = 0;
675 1.1 christos count = 0;
676 1.1 christos
677 1.1 christos while (ch = buffer[count])
678 1.1 christos {
679 1.1 christos putDebugChar (ch);
680 1.1 christos checksum += ch;
681 1.1 christos count += 1;
682 1.1 christos }
683 1.1 christos putDebugChar ('#');
684 1.1 christos putDebugChar (hexchars[checksum >> 4]);
685 1.1 christos putDebugChar (hexchars[checksum % 16]);
686 1.1 christos }
687 1.1 christos while (getDebugChar () != '+');
688 1.1 christos }
689 1.1 christos
690 1.1 christos /* Address of a routine to RTE to if we get a memory fault. */
691 1.1 christos
692 1.1 christos static void (*volatile mem_fault_routine) () = 0;
693 1.1 christos
694 1.1 christos static void
695 1.1 christos set_mem_err (void)
696 1.1 christos {
697 1.1 christos mem_err = 1;
698 1.1 christos }
699 1.1 christos
700 1.1 christos /* Check the address for safe access ranges. As currently defined,
701 1.1 christos this routine will reject the "expansion bus" address range(s).
702 1.1 christos To make those ranges useable, someone must implement code to detect
703 1.1 christos whether there's anything connected to the expansion bus. */
704 1.1 christos
705 1.1 christos static int
706 1.1 christos mem_safe (unsigned char *addr)
707 1.1 christos {
708 1.1 christos #define BAD_RANGE_ONE_START ((unsigned char *) 0x600000)
709 1.1 christos #define BAD_RANGE_ONE_END ((unsigned char *) 0xa00000)
710 1.1 christos #define BAD_RANGE_TWO_START ((unsigned char *) 0xff680000)
711 1.1 christos #define BAD_RANGE_TWO_END ((unsigned char *) 0xff800000)
712 1.1 christos
713 1.1 christos if (addr < BAD_RANGE_ONE_START)
714 1.1 christos return 1; /* safe */
715 1.1 christos if (addr < BAD_RANGE_ONE_END)
716 1.1 christos return 0; /* unsafe */
717 1.1 christos if (addr < BAD_RANGE_TWO_START)
718 1.1 christos return 1; /* safe */
719 1.1 christos if (addr < BAD_RANGE_TWO_END)
720 1.1 christos return 0; /* unsafe */
721 1.1 christos }
722 1.1 christos
723 1.1 christos /* These are separate functions so that they are so short and sweet
724 1.1 christos that the compiler won't save any registers (if there is a fault
725 1.1 christos to mem_fault, they won't get restored, so there better not be any
726 1.1 christos saved). */
727 1.1 christos static int
728 1.1 christos get_char (unsigned char *addr)
729 1.1 christos {
730 1.1 christos #if 1
731 1.1 christos if (mem_fault_routine && !mem_safe (addr))
732 1.1 christos {
733 1.1 christos mem_fault_routine ();
734 1.1 christos return 0;
735 1.1 christos }
736 1.1 christos #endif
737 1.1 christos return *addr;
738 1.1 christos }
739 1.1 christos
740 1.1 christos static void
741 1.1 christos set_char (unsigned char *addr, unsigned char val)
742 1.1 christos {
743 1.1 christos #if 1
744 1.1 christos if (mem_fault_routine && !mem_safe (addr))
745 1.1 christos {
746 1.1 christos mem_fault_routine ();
747 1.1 christos return;
748 1.1 christos }
749 1.1 christos #endif
750 1.1 christos *addr = val;
751 1.1 christos }
752 1.1 christos
753 1.1 christos /* Convert the memory pointed to by mem into hex, placing result in buf.
754 1.1 christos Return a pointer to the last char put in buf (null).
755 1.1 christos If MAY_FAULT is non-zero, then we should set mem_err in response to
756 1.1 christos a fault; if zero treat a fault like any other fault in the stub. */
757 1.1 christos
758 1.1 christos static unsigned char *
759 1.1 christos mem2hex (unsigned char *mem, unsigned char *buf, int count, int may_fault)
760 1.1 christos {
761 1.1 christos int i;
762 1.1 christos unsigned char ch;
763 1.1 christos
764 1.1 christos if (may_fault)
765 1.1 christos mem_fault_routine = set_mem_err;
766 1.1 christos for (i = 0; i < count; i++)
767 1.1 christos {
768 1.1 christos ch = get_char (mem++);
769 1.1 christos if (may_fault && mem_err)
770 1.1 christos return (buf);
771 1.1 christos *buf++ = hexchars[ch >> 4];
772 1.1 christos *buf++ = hexchars[ch % 16];
773 1.1 christos }
774 1.1 christos *buf = 0;
775 1.1 christos if (may_fault)
776 1.1 christos mem_fault_routine = 0;
777 1.1 christos return (buf);
778 1.1 christos }
779 1.1 christos
780 1.1 christos /* Convert the hex array pointed to by buf into binary to be placed in mem.
781 1.1 christos Return a pointer to the character AFTER the last byte written. */
782 1.1 christos
783 1.1 christos static unsigned char *
784 1.1 christos hex2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
785 1.1 christos {
786 1.1 christos int i;
787 1.1 christos unsigned char ch;
788 1.1 christos
789 1.1 christos if (may_fault)
790 1.1 christos mem_fault_routine = set_mem_err;
791 1.1 christos for (i = 0; i < count; i++)
792 1.1 christos {
793 1.1 christos ch = hex (*buf++) << 4;
794 1.1 christos ch = ch + hex (*buf++);
795 1.1 christos set_char (mem++, ch);
796 1.1 christos if (may_fault && mem_err)
797 1.1 christos return (mem);
798 1.1 christos }
799 1.1 christos if (may_fault)
800 1.1 christos mem_fault_routine = 0;
801 1.1 christos return (mem);
802 1.1 christos }
803 1.1 christos
804 1.1 christos /* Convert the binary stream in BUF to memory.
805 1.1 christos
806 1.1 christos Gdb will escape $, #, and the escape char (0x7d).
807 1.1 christos COUNT is the total number of bytes to write into
808 1.1 christos memory. */
809 1.1 christos static unsigned char *
810 1.1 christos bin2mem (unsigned char *buf, unsigned char *mem, int count, int may_fault)
811 1.1 christos {
812 1.1 christos int i;
813 1.1 christos unsigned char ch;
814 1.1 christos
815 1.1 christos if (may_fault)
816 1.1 christos mem_fault_routine = set_mem_err;
817 1.1 christos for (i = 0; i < count; i++)
818 1.1 christos {
819 1.1 christos /* Check for any escaped characters. Be paranoid and
820 1.1 christos only unescape chars that should be escaped. */
821 1.1 christos if (*buf == 0x7d)
822 1.1 christos {
823 1.1 christos switch (*(buf + 1))
824 1.1 christos {
825 1.1 christos case 0x3: /* # */
826 1.1 christos case 0x4: /* $ */
827 1.1 christos case 0x5d: /* escape char */
828 1.1 christos buf++;
829 1.1 christos *buf |= 0x20;
830 1.1 christos break;
831 1.1 christos default:
832 1.1 christos /* nothing */
833 1.1 christos break;
834 1.1 christos }
835 1.1 christos }
836 1.1 christos
837 1.1 christos set_char (mem++, *buf++);
838 1.1 christos
839 1.1 christos if (may_fault && mem_err)
840 1.1 christos return mem;
841 1.1 christos }
842 1.1 christos
843 1.1 christos if (may_fault)
844 1.1 christos mem_fault_routine = 0;
845 1.1 christos return mem;
846 1.1 christos }
847 1.1 christos
848 1.1 christos /* this function takes the m32r exception vector and attempts to
849 1.1 christos translate this number into a unix compatible signal value */
850 1.1 christos
851 1.1 christos static int
852 1.1 christos computeSignal (int exceptionVector)
853 1.1 christos {
854 1.1 christos int sigval;
855 1.1 christos switch (exceptionVector)
856 1.1 christos {
857 1.1 christos case 0:
858 1.1 christos sigval = 23;
859 1.1 christos break; /* I/O trap */
860 1.1 christos case 1:
861 1.1 christos sigval = 5;
862 1.1 christos break; /* breakpoint */
863 1.1 christos case 2:
864 1.1 christos sigval = 5;
865 1.1 christos break; /* breakpoint */
866 1.1 christos case 3:
867 1.1 christos sigval = 5;
868 1.1 christos break; /* breakpoint */
869 1.1 christos case 4:
870 1.1 christos sigval = 5;
871 1.1 christos break; /* breakpoint */
872 1.1 christos case 5:
873 1.1 christos sigval = 5;
874 1.1 christos break; /* breakpoint */
875 1.1 christos case 6:
876 1.1 christos sigval = 5;
877 1.1 christos break; /* breakpoint */
878 1.1 christos case 7:
879 1.1 christos sigval = 5;
880 1.1 christos break; /* breakpoint */
881 1.1 christos case 8:
882 1.1 christos sigval = 5;
883 1.1 christos break; /* breakpoint */
884 1.1 christos case 9:
885 1.1 christos sigval = 5;
886 1.1 christos break; /* breakpoint */
887 1.1 christos case 10:
888 1.1 christos sigval = 5;
889 1.1 christos break; /* breakpoint */
890 1.1 christos case 11:
891 1.1 christos sigval = 5;
892 1.1 christos break; /* breakpoint */
893 1.1 christos case 12:
894 1.1 christos sigval = 5;
895 1.1 christos break; /* breakpoint */
896 1.1 christos case 13:
897 1.1 christos sigval = 5;
898 1.1 christos break; /* breakpoint */
899 1.1 christos case 14:
900 1.1 christos sigval = 5;
901 1.1 christos break; /* breakpoint */
902 1.1 christos case 15:
903 1.1 christos sigval = 5;
904 1.1 christos break; /* breakpoint */
905 1.1 christos case 16:
906 1.1 christos sigval = 10;
907 1.1 christos break; /* BUS ERROR (alignment) */
908 1.1 christos case 17:
909 1.1 christos sigval = 2;
910 1.1 christos break; /* INTerrupt */
911 1.1 christos default:
912 1.1 christos sigval = 7;
913 1.1 christos break; /* "software generated" */
914 1.1 christos }
915 1.1 christos return (sigval);
916 1.1 christos }
917 1.1 christos
918 1.1 christos /**********************************************/
919 1.1 christos /* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
920 1.1 christos /* RETURN NUMBER OF CHARS PROCESSED */
921 1.1 christos /**********************************************/
922 1.1 christos static int
923 1.1 christos hexToInt (unsigned char **ptr, int *intValue)
924 1.1 christos {
925 1.1 christos int numChars = 0;
926 1.1 christos int hexValue;
927 1.1 christos
928 1.1 christos *intValue = 0;
929 1.1 christos while (**ptr)
930 1.1 christos {
931 1.1 christos hexValue = hex (**ptr);
932 1.1 christos if (hexValue >= 0)
933 1.1 christos {
934 1.1 christos *intValue = (*intValue << 4) | hexValue;
935 1.1 christos numChars++;
936 1.1 christos }
937 1.1 christos else
938 1.1 christos break;
939 1.1 christos (*ptr)++;
940 1.1 christos }
941 1.1 christos return (numChars);
942 1.1 christos }
943 1.1 christos
944 1.1 christos /*
945 1.1 christos Table of branch instructions:
946 1.1 christos
947 1.1 christos 10B6 RTE return from trap or exception
948 1.1 christos 1FCr JMP jump
949 1.1 christos 1ECr JL jump and link
950 1.1 christos 7Fxx BRA branch
951 1.1 christos FFxxxxxx BRA branch (long)
952 1.1 christos B09rxxxx BNEZ branch not-equal-zero
953 1.1 christos Br1rxxxx BNE branch not-equal
954 1.1 christos 7Dxx BNC branch not-condition
955 1.1 christos FDxxxxxx BNC branch not-condition (long)
956 1.1 christos B0Arxxxx BLTZ branch less-than-zero
957 1.1 christos B0Crxxxx BLEZ branch less-equal-zero
958 1.1 christos 7Exx BL branch and link
959 1.1 christos FExxxxxx BL branch and link (long)
960 1.1 christos B0Drxxxx BGTZ branch greater-than-zero
961 1.1 christos B0Brxxxx BGEZ branch greater-equal-zero
962 1.1 christos B08rxxxx BEQZ branch equal-zero
963 1.1 christos Br0rxxxx BEQ branch equal
964 1.1 christos 7Cxx BC branch condition
965 1.1 christos FCxxxxxx BC branch condition (long)
966 1.1 christos */
967 1.1 christos
968 1.1 christos static int
969 1.1 christos isShortBranch (unsigned char *instr)
970 1.1 christos {
971 1.1 christos unsigned char instr0 = instr[0] & 0x7F; /* mask off high bit */
972 1.1 christos
973 1.1 christos if (instr0 == 0x10 && instr[1] == 0xB6) /* RTE */
974 1.1 christos return 1; /* return from trap or exception */
975 1.1 christos
976 1.1 christos if (instr0 == 0x1E || instr0 == 0x1F) /* JL or JMP */
977 1.1 christos if ((instr[1] & 0xF0) == 0xC0)
978 1.1 christos return 2; /* jump thru a register */
979 1.1 christos
980 1.1 christos if (instr0 == 0x7C || instr0 == 0x7D || /* BC, BNC, BL, BRA */
981 1.1 christos instr0 == 0x7E || instr0 == 0x7F)
982 1.1 christos return 3; /* eight bit PC offset */
983 1.1 christos
984 1.1 christos return 0;
985 1.1 christos }
986 1.1 christos
987 1.1 christos static int
988 1.1 christos isLongBranch (unsigned char *instr)
989 1.1 christos {
990 1.1 christos if (instr[0] == 0xFC || instr[0] == 0xFD || /* BRA, BNC, BL, BC */
991 1.1 christos instr[0] == 0xFE || instr[0] == 0xFF) /* 24 bit relative */
992 1.1 christos return 4;
993 1.1 christos if ((instr[0] & 0xF0) == 0xB0) /* 16 bit relative */
994 1.1 christos {
995 1.1 christos if ((instr[1] & 0xF0) == 0x00 || /* BNE, BEQ */
996 1.1 christos (instr[1] & 0xF0) == 0x10)
997 1.1 christos return 5;
998 1.1 christos if (instr[0] == 0xB0) /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ, BEQZ */
999 1.1 christos if ((instr[1] & 0xF0) == 0x80 || (instr[1] & 0xF0) == 0x90 ||
1000 1.1 christos (instr[1] & 0xF0) == 0xA0 || (instr[1] & 0xF0) == 0xB0 ||
1001 1.1 christos (instr[1] & 0xF0) == 0xC0 || (instr[1] & 0xF0) == 0xD0)
1002 1.1 christos return 6;
1003 1.1 christos }
1004 1.1 christos return 0;
1005 1.1 christos }
1006 1.1 christos
1007 1.1 christos /* if address is NOT on a 4-byte boundary, or high-bit of instr is zero,
1008 1.1 christos then it's a 2-byte instruction, else it's a 4-byte instruction. */
1009 1.1 christos
1010 1.1 christos #define INSTRUCTION_SIZE(addr) \
1011 1.1 christos ((((int) addr & 2) || (((unsigned char *) addr)[0] & 0x80) == 0) ? 2 : 4)
1012 1.1 christos
1013 1.1 christos static int
1014 1.1 christos isBranch (unsigned char *instr)
1015 1.1 christos {
1016 1.1 christos if (INSTRUCTION_SIZE (instr) == 2)
1017 1.1 christos return isShortBranch (instr);
1018 1.1 christos else
1019 1.1 christos return isLongBranch (instr);
1020 1.1 christos }
1021 1.1 christos
1022 1.1 christos static int
1023 1.1 christos willBranch (unsigned char *instr, int branchCode)
1024 1.1 christos {
1025 1.1 christos switch (branchCode)
1026 1.1 christos {
1027 1.1 christos case 0:
1028 1.1 christos return 0; /* not a branch */
1029 1.1 christos case 1:
1030 1.1 christos return 1; /* RTE */
1031 1.1 christos case 2:
1032 1.1 christos return 1; /* JL or JMP */
1033 1.1 christos case 3: /* BC, BNC, BL, BRA (short) */
1034 1.1 christos case 4: /* BC, BNC, BL, BRA (long) */
1035 1.1 christos switch (instr[0] & 0x0F)
1036 1.1 christos {
1037 1.1 christos case 0xC: /* Branch if Condition Register */
1038 1.1 christos return (registers[CBR] != 0);
1039 1.1 christos case 0xD: /* Branch if NOT Condition Register */
1040 1.1 christos return (registers[CBR] == 0);
1041 1.1 christos case 0xE: /* Branch and Link */
1042 1.1 christos case 0xF: /* Branch (unconditional) */
1043 1.1 christos return 1;
1044 1.1 christos default: /* oops? */
1045 1.1 christos return 0;
1046 1.1 christos }
1047 1.1 christos case 5: /* BNE, BEQ */
1048 1.1 christos switch (instr[1] & 0xF0)
1049 1.1 christos {
1050 1.1 christos case 0x00: /* Branch if r1 equal to r2 */
1051 1.1 christos return (registers[instr[0] & 0x0F] == registers[instr[1] & 0x0F]);
1052 1.1 christos case 0x10: /* Branch if r1 NOT equal to r2 */
1053 1.1 christos return (registers[instr[0] & 0x0F] != registers[instr[1] & 0x0F]);
1054 1.1 christos default: /* oops? */
1055 1.1 christos return 0;
1056 1.1 christos }
1057 1.1 christos case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ */
1058 1.1 christos switch (instr[1] & 0xF0)
1059 1.1 christos {
1060 1.1 christos case 0x80: /* Branch if reg equal to zero */
1061 1.1 christos return (registers[instr[1] & 0x0F] == 0);
1062 1.1 christos case 0x90: /* Branch if reg NOT equal to zero */
1063 1.1 christos return (registers[instr[1] & 0x0F] != 0);
1064 1.1 christos case 0xA0: /* Branch if reg less than zero */
1065 1.1 christos return (registers[instr[1] & 0x0F] < 0);
1066 1.1 christos case 0xB0: /* Branch if reg greater or equal to zero */
1067 1.1 christos return (registers[instr[1] & 0x0F] >= 0);
1068 1.1 christos case 0xC0: /* Branch if reg less than or equal to zero */
1069 1.1 christos return (registers[instr[1] & 0x0F] <= 0);
1070 1.1 christos case 0xD0: /* Branch if reg greater than zero */
1071 1.1 christos return (registers[instr[1] & 0x0F] > 0);
1072 1.1 christos default: /* oops? */
1073 1.1 christos return 0;
1074 1.1 christos }
1075 1.1 christos default: /* oops? */
1076 1.1 christos return 0;
1077 1.1 christos }
1078 1.1 christos }
1079 1.1 christos
1080 1.1 christos static int
1081 1.1 christos branchDestination (unsigned char *instr, int branchCode)
1082 1.1 christos {
1083 1.1 christos switch (branchCode)
1084 1.1 christos {
1085 1.1 christos default:
1086 1.1 christos case 0: /* not a branch */
1087 1.1 christos return 0;
1088 1.1 christos case 1: /* RTE */
1089 1.1 christos return registers[BPC] & ~3; /* pop BPC into PC */
1090 1.1 christos case 2: /* JL or JMP */
1091 1.1 christos return registers[instr[1] & 0x0F] & ~3; /* jump thru a register */
1092 1.1 christos case 3: /* BC, BNC, BL, BRA (short, 8-bit relative offset) */
1093 1.1 christos return (((int) instr) & ~3) + ((char) instr[1] << 2);
1094 1.1 christos case 4: /* BC, BNC, BL, BRA (long, 24-bit relative offset) */
1095 1.1 christos return ((int) instr +
1096 1.1 christos ((((char) instr[1] << 16) | (instr[2] << 8) | (instr[3])) <<
1097 1.1 christos 2));
1098 1.1 christos case 5: /* BNE, BEQ (16-bit relative offset) */
1099 1.1 christos case 6: /* BNEZ, BLTZ, BLEZ, BGTZ, BGEZ ,BEQZ (ditto) */
1100 1.1 christos return ((int) instr + ((((char) instr[2] << 8) | (instr[3])) << 2));
1101 1.1 christos }
1102 1.1 christos
1103 1.1 christos /* An explanatory note: in the last three return expressions, I have
1104 1.1 christos cast the most-significant byte of the return offset to char.
1105 1.1 christos What this accomplishes is sign extension. If the other
1106 1.1 christos less-significant bytes were signed as well, they would get sign
1107 1.1 christos extended too and, if negative, their leading bits would clobber
1108 1.1 christos the bits of the more-significant bytes ahead of them. There are
1109 1.1 christos other ways I could have done this, but sign extension from
1110 1.1 christos odd-sized integers is always a pain. */
1111 1.1 christos }
1112 1.1 christos
1113 1.1 christos static void
1114 1.1 christos branchSideEffects (unsigned char *instr, int branchCode)
1115 1.1 christos {
1116 1.1 christos switch (branchCode)
1117 1.1 christos {
1118 1.1 christos case 1: /* RTE */
1119 1.1 christos return; /* I <THINK> this is already handled... */
1120 1.1 christos case 2: /* JL (or JMP) */
1121 1.1 christos case 3: /* BL (or BC, BNC, BRA) */
1122 1.1 christos case 4:
1123 1.1 christos if ((instr[0] & 0x0F) == 0x0E) /* branch/jump and link */
1124 1.1 christos registers[R14] = (registers[PC] & ~3) + 4;
1125 1.1 christos return;
1126 1.1 christos default: /* any other branch has no side effects */
1127 1.1 christos return;
1128 1.1 christos }
1129 1.1 christos }
1130 1.1 christos
1131 1.1 christos static struct STEPPING_CONTEXT
1132 1.1 christos {
1133 1.1 christos int stepping; /* true when we've started a single-step */
1134 1.1 christos unsigned long target_addr; /* the instr we're trying to execute */
1135 1.1 christos unsigned long target_size; /* the size of the target instr */
1136 1.1 christos unsigned long noop_addr; /* where we've inserted a no-op, if any */
1137 1.1 christos unsigned long trap1_addr; /* the trap following the target instr */
1138 1.1 christos unsigned long trap2_addr; /* the trap at a branch destination, if any */
1139 1.1 christos unsigned short noop_save; /* instruction overwritten by our no-op */
1140 1.1 christos unsigned short trap1_save; /* instruction overwritten by trap1 */
1141 1.1 christos unsigned short trap2_save; /* instruction overwritten by trap2 */
1142 1.1 christos unsigned short continue_p; /* true if NOT returning to gdb after step */
1143 1.1 christos } stepping;
1144 1.1 christos
1145 1.1 christos /* Function: prepare_to_step
1146 1.1 christos Called from handle_exception to prepare the user program to single-step.
1147 1.1 christos Places a trap instruction after the target instruction, with special
1148 1.1 christos extra handling for branch instructions and for instructions in the
1149 1.1 christos second half-word of a word.
1150 1.1 christos
1151 1.1 christos Returns: True if we should actually execute the instruction;
1152 1.1 christos False if we are going to emulate executing the instruction,
1153 1.1 christos in which case we simply report to GDB that the instruction
1154 1.1 christos has already been executed. */
1155 1.1 christos
1156 1.1 christos #define TRAP1 0x10f1; /* trap #1 instruction */
1157 1.1 christos #define NOOP 0x7000; /* noop instruction */
1158 1.1 christos
1159 1.1 christos static unsigned short trap1 = TRAP1;
1160 1.1 christos static unsigned short noop = NOOP;
1161 1.1 christos
1162 1.1 christos static int
1163 1.1 christos prepare_to_step (continue_p)
1164 1.1 christos int continue_p; /* if this isn't REALLY a single-step (see below) */
1165 1.1 christos {
1166 1.1 christos unsigned long pc = registers[PC];
1167 1.1 christos int branchCode = isBranch ((unsigned char *) pc);
1168 1.1 christos unsigned char *p;
1169 1.1 christos
1170 1.1 christos /* zero out the stepping context
1171 1.1 christos (paranoia -- it should already be zeroed) */
1172 1.1 christos for (p = (unsigned char *) &stepping;
1173 1.1 christos p < ((unsigned char *) &stepping) + sizeof (stepping); p++)
1174 1.1 christos *p = 0;
1175 1.1 christos
1176 1.1 christos if (branchCode != 0) /* next instruction is a branch */
1177 1.1 christos {
1178 1.1 christos branchSideEffects ((unsigned char *) pc, branchCode);
1179 1.1 christos if (willBranch ((unsigned char *) pc, branchCode))
1180 1.1 christos registers[PC] = branchDestination ((unsigned char *) pc, branchCode);
1181 1.1 christos else
1182 1.1 christos registers[PC] = pc + INSTRUCTION_SIZE (pc);
1183 1.1 christos return 0; /* branch "executed" -- just notify GDB */
1184 1.1 christos }
1185 1.1 christos else if (((int) pc & 2) != 0) /* "second-slot" instruction */
1186 1.1 christos {
1187 1.1 christos /* insert no-op before pc */
1188 1.1 christos stepping.noop_addr = pc - 2;
1189 1.1 christos stepping.noop_save = *(unsigned short *) stepping.noop_addr;
1190 1.1 christos *(unsigned short *) stepping.noop_addr = noop;
1191 1.1 christos /* insert trap after pc */
1192 1.1 christos stepping.trap1_addr = pc + 2;
1193 1.1 christos stepping.trap1_save = *(unsigned short *) stepping.trap1_addr;
1194 1.1 christos *(unsigned short *) stepping.trap1_addr = trap1;
1195 1.1 christos }
1196 1.1 christos else /* "first-slot" instruction */
1197 1.1 christos {
1198 1.1 christos /* insert trap after pc */
1199 1.1 christos stepping.trap1_addr = pc + INSTRUCTION_SIZE (pc);
1200 1.1 christos stepping.trap1_save = *(unsigned short *) stepping.trap1_addr;
1201 1.1 christos *(unsigned short *) stepping.trap1_addr = trap1;
1202 1.1 christos }
1203 1.1 christos /* "continue_p" means that we are actually doing a continue, and not
1204 1.1 christos being requested to single-step by GDB. Sometimes we have to do
1205 1.1 christos one single-step before continuing, because the PC is on a half-word
1206 1.1 christos boundary. There's no way to simply resume at such an address. */
1207 1.1 christos stepping.continue_p = continue_p;
1208 1.1 christos stepping.stepping = 1; /* starting a single-step */
1209 1.1 christos return 1;
1210 1.1 christos }
1211 1.1 christos
1212 1.1 christos /* Function: finish_from_step
1213 1.1 christos Called from handle_exception to finish up when the user program
1214 1.1 christos returns from a single-step. Replaces the instructions that had
1215 1.1 christos been overwritten by traps or no-ops,
1216 1.1 christos
1217 1.1 christos Returns: True if we should notify GDB that the target stopped.
1218 1.1 christos False if we only single-stepped because we had to before we
1219 1.1 christos could continue (ie. we were trying to continue at a
1220 1.1 christos half-word boundary). In that case don't notify GDB:
1221 1.1 christos just "continue continuing". */
1222 1.1 christos
1223 1.1 christos static int
1224 1.1 christos finish_from_step (void)
1225 1.1 christos {
1226 1.1 christos if (stepping.stepping) /* anything to do? */
1227 1.1 christos {
1228 1.1 christos int continue_p = stepping.continue_p;
1229 1.1 christos unsigned char *p;
1230 1.1 christos
1231 1.1 christos if (stepping.noop_addr) /* replace instr "under" our no-op */
1232 1.1 christos *(unsigned short *) stepping.noop_addr = stepping.noop_save;
1233 1.1 christos if (stepping.trap1_addr) /* replace instr "under" our trap */
1234 1.1 christos *(unsigned short *) stepping.trap1_addr = stepping.trap1_save;
1235 1.1 christos if (stepping.trap2_addr) /* ditto our other trap, if any */
1236 1.1 christos *(unsigned short *) stepping.trap2_addr = stepping.trap2_save;
1237 1.1 christos
1238 1.1 christos for (p = (unsigned char *) &stepping; /* zero out the stepping context */
1239 1.1 christos p < ((unsigned char *) &stepping) + sizeof (stepping); p++)
1240 1.1 christos *p = 0;
1241 1.1 christos
1242 1.1 christos return !(continue_p);
1243 1.1 christos }
1244 1.1 christos else /* we didn't single-step, therefore this must be a legitimate stop */
1245 1.1 christos return 1;
1246 1.1 christos }
1247 1.1 christos
1248 1.1 christos struct PSWreg
1249 1.1 christos { /* separate out the bit flags in the PSW register */
1250 1.1 christos int pad1:16;
1251 1.1 christos int bsm:1;
1252 1.1 christos int bie:1;
1253 1.1 christos int pad2:5;
1254 1.1 christos int bc:1;
1255 1.1 christos int sm:1;
1256 1.1 christos int ie:1;
1257 1.1 christos int pad3:5;
1258 1.1 christos int c:1;
1259 1.1 christos } *psw;
1260 1.1 christos
1261 1.1 christos /* Upon entry the value for LR to save has been pushed.
1262 1.1 christos We unpush that so that the value for the stack pointer saved is correct.
1263 1.1 christos Upon entry, all other registers are assumed to have not been modified
1264 1.1 christos since the interrupt/trap occured. */
1265 1.1 christos
1266 1.1 christos asm ("\n\
1267 1.1 christos stash_registers:\n\
1268 1.1 christos push r0\n\
1269 1.1 christos push r1\n\
1270 1.1 christos seth r1, #shigh(registers)\n\
1271 1.1 christos add3 r1, r1, #low(registers)\n\
1272 1.1 christos pop r0 ; r1\n\
1273 1.1 christos st r0, @(4,r1)\n\
1274 1.1 christos pop r0 ; r0\n\
1275 1.1 christos st r0, @r1\n\
1276 1.1 christos addi r1, #4 ; only add 4 as subsequent saves are `pre inc'\n\
1277 1.1 christos st r2, @+r1\n\
1278 1.1 christos st r3, @+r1\n\
1279 1.1 christos st r4, @+r1\n\
1280 1.1 christos st r5, @+r1\n\
1281 1.1 christos st r6, @+r1\n\
1282 1.1 christos st r7, @+r1\n\
1283 1.1 christos st r8, @+r1\n\
1284 1.1 christos st r9, @+r1\n\
1285 1.1 christos st r10, @+r1\n\
1286 1.1 christos st r11, @+r1\n\
1287 1.1 christos st r12, @+r1\n\
1288 1.1 christos st r13, @+r1 ; fp\n\
1289 1.1 christos pop r0 ; lr (r14)\n\
1290 1.1 christos st r0, @+r1\n\
1291 1.1 christos st sp, @+r1 ; sp contains right value at this point\n\
1292 1.1 christos mvfc r0, cr0\n\
1293 1.1 christos st r0, @+r1 ; cr0 == PSW\n\
1294 1.1 christos mvfc r0, cr1\n\
1295 1.1 christos st r0, @+r1 ; cr1 == CBR\n\
1296 1.1 christos mvfc r0, cr2\n\
1297 1.1 christos st r0, @+r1 ; cr2 == SPI\n\
1298 1.1 christos mvfc r0, cr3\n\
1299 1.1 christos st r0, @+r1 ; cr3 == SPU\n\
1300 1.1 christos mvfc r0, cr6\n\
1301 1.1 christos st r0, @+r1 ; cr6 == BPC\n\
1302 1.1 christos st r0, @+r1 ; PC == BPC\n\
1303 1.1 christos mvfaclo r0\n\
1304 1.1 christos st r0, @+r1 ; ACCL\n\
1305 1.1 christos mvfachi r0\n\
1306 1.1 christos st r0, @+r1 ; ACCH\n\
1307 1.1 christos jmp lr");
1308 1.1 christos
1309 1.1 christos /* C routine to clean up what stash_registers did.
1310 1.1 christos It is called after calling stash_registers.
1311 1.1 christos This is separate from stash_registers as we want to do this in C
1312 1.1 christos but doing stash_registers in C isn't straightforward. */
1313 1.1 christos
1314 1.1 christos static void
1315 1.1 christos cleanup_stash (void)
1316 1.1 christos {
1317 1.1 christos psw = (struct PSWreg *) ®isters[PSW]; /* fields of PSW register */
1318 1.1 christos psw->sm = psw->bsm; /* fix up pre-trap values of psw fields */
1319 1.1 christos psw->ie = psw->bie;
1320 1.1 christos psw->c = psw->bc;
1321 1.1 christos registers[CBR] = psw->bc; /* fix up pre-trap "C" register */
1322 1.1 christos
1323 1.1 christos #if 0 /* FIXME: Was in previous version. Necessary?
1324 1.1 christos (Remember that we use the "rte" insn to return from the
1325 1.1 christos trap/interrupt so the values of bsm, bie, bc are important. */
1326 1.1 christos psw->bsm = psw->bie = psw->bc = 0; /* zero post-trap values */
1327 1.1 christos #endif
1328 1.1 christos
1329 1.1 christos /* FIXME: Copied from previous version. This can probably be deleted
1330 1.1 christos since methinks stash_registers has already done this. */
1331 1.1 christos registers[PC] = registers[BPC]; /* pre-trap PC */
1332 1.1 christos
1333 1.1 christos /* FIXME: Copied from previous version. Necessary? */
1334 1.1 christos if (psw->sm) /* copy R15 into (psw->sm ? SPU : SPI) */
1335 1.1 christos registers[SPU] = registers[R15];
1336 1.1 christos else
1337 1.1 christos registers[SPI] = registers[R15];
1338 1.1 christos }
1339 1.1 christos
1340 1.1 christos asm ("\n\
1341 1.1 christos restore_and_return:\n\
1342 1.1 christos seth r0, #shigh(registers+8)\n\
1343 1.1 christos add3 r0, r0, #low(registers+8)\n\
1344 1.1 christos ld r2, @r0+ ; restore r2\n\
1345 1.1 christos ld r3, @r0+ ; restore r3\n\
1346 1.1 christos ld r4, @r0+ ; restore r4\n\
1347 1.1 christos ld r5, @r0+ ; restore r5\n\
1348 1.1 christos ld r6, @r0+ ; restore r6\n\
1349 1.1 christos ld r7, @r0+ ; restore r7\n\
1350 1.1 christos ld r8, @r0+ ; restore r8\n\
1351 1.1 christos ld r9, @r0+ ; restore r9\n\
1352 1.1 christos ld r10, @r0+ ; restore r10\n\
1353 1.1 christos ld r11, @r0+ ; restore r11\n\
1354 1.1 christos ld r12, @r0+ ; restore r12\n\
1355 1.1 christos ld r13, @r0+ ; restore r13\n\
1356 1.1 christos ld r14, @r0+ ; restore r14\n\
1357 1.1 christos ld r15, @r0+ ; restore r15\n\
1358 1.1 christos ld r1, @r0+ ; restore cr0 == PSW\n\
1359 1.1 christos mvtc r1, cr0\n\
1360 1.1 christos ld r1, @r0+ ; restore cr1 == CBR (no-op, because it's read only)\n\
1361 1.1 christos mvtc r1, cr1\n\
1362 1.1 christos ld r1, @r0+ ; restore cr2 == SPI\n\
1363 1.1 christos mvtc r1, cr2\n\
1364 1.1 christos ld r1, @r0+ ; restore cr3 == SPU\n\
1365 1.1 christos mvtc r1, cr3\n\
1366 1.1 christos addi r0, #4 ; skip BPC\n\
1367 1.1 christos ld r1, @r0+ ; restore cr6 (BPC) == PC\n\
1368 1.1 christos mvtc r1, cr6\n\
1369 1.1 christos ld r1, @r0+ ; restore ACCL\n\
1370 1.1 christos mvtaclo r1\n\
1371 1.1 christos ld r1, @r0+ ; restore ACCH\n\
1372 1.1 christos mvtachi r1\n\
1373 1.1 christos seth r0, #shigh(registers)\n\
1374 1.1 christos add3 r0, r0, #low(registers)\n\
1375 1.1 christos ld r1, @(4,r0) ; restore r1\n\
1376 1.1 christos ld r0, @r0 ; restore r0\n\
1377 1.1 christos rte");
1378 1.1 christos
1379 1.1 christos /* General trap handler, called after the registers have been stashed.
1380 1.1 christos NUM is the trap/exception number. */
1381 1.1 christos
1382 1.1 christos static void
1383 1.1 christos process_exception (int num)
1384 1.1 christos {
1385 1.1 christos cleanup_stash ();
1386 1.1 christos asm volatile ("\n\
1387 1.1 christos seth r1, #shigh(stackPtr)\n\
1388 1.1 christos add3 r1, r1, #low(stackPtr)\n\
1389 1.1 christos ld r15, @r1 ; setup local stack (protect user stack)\n\
1390 1.1 christos mv r0, %0\n\
1391 1.1 christos bl handle_exception\n\
1392 1.1 christos bl restore_and_return"::"r" (num):"r0", "r1");
1393 1.1 christos }
1394 1.1 christos
1395 1.1 christos void _catchException0 ();
1396 1.1 christos
1397 1.1 christos asm ("\n\
1398 1.1 christos _catchException0:\n\
1399 1.1 christos push lr\n\
1400 1.1 christos bl stash_registers\n\
1401 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1402 1.1 christos ldi r0, #0\n\
1403 1.1 christos bl process_exception");
1404 1.1 christos
1405 1.1 christos void _catchException1 ();
1406 1.1 christos
1407 1.1 christos asm ("\n\
1408 1.1 christos _catchException1:\n\
1409 1.1 christos push lr\n\
1410 1.1 christos bl stash_registers\n\
1411 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1412 1.1 christos bl cleanup_stash\n\
1413 1.1 christos seth r1, #shigh(stackPtr)\n\
1414 1.1 christos add3 r1, r1, #low(stackPtr)\n\
1415 1.1 christos ld r15, @r1 ; setup local stack (protect user stack)\n\
1416 1.1 christos seth r1, #shigh(registers + 21*4) ; PC\n\
1417 1.1 christos add3 r1, r1, #low(registers + 21*4)\n\
1418 1.1 christos ld r0, @r1\n\
1419 1.1 christos addi r0, #-4 ; back up PC for breakpoint trap.\n\
1420 1.1 christos st r0, @r1 ; FIXME: what about bp in right slot?\n\
1421 1.1 christos ldi r0, #1\n\
1422 1.1 christos bl handle_exception\n\
1423 1.1 christos bl restore_and_return");
1424 1.1 christos
1425 1.1 christos void _catchException2 ();
1426 1.1 christos
1427 1.1 christos asm ("\n\
1428 1.1 christos _catchException2:\n\
1429 1.1 christos push lr\n\
1430 1.1 christos bl stash_registers\n\
1431 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1432 1.1 christos ldi r0, #2\n\
1433 1.1 christos bl process_exception");
1434 1.1 christos
1435 1.1 christos void _catchException3 ();
1436 1.1 christos
1437 1.1 christos asm ("\n\
1438 1.1 christos _catchException3:\n\
1439 1.1 christos push lr\n\
1440 1.1 christos bl stash_registers\n\
1441 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1442 1.1 christos ldi r0, #3\n\
1443 1.1 christos bl process_exception");
1444 1.1 christos
1445 1.1 christos void _catchException4 ();
1446 1.1 christos
1447 1.1 christos asm ("\n\
1448 1.1 christos _catchException4:\n\
1449 1.1 christos push lr\n\
1450 1.1 christos bl stash_registers\n\
1451 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1452 1.1 christos ldi r0, #4\n\
1453 1.1 christos bl process_exception");
1454 1.1 christos
1455 1.1 christos void _catchException5 ();
1456 1.1 christos
1457 1.1 christos asm ("\n\
1458 1.1 christos _catchException5:\n\
1459 1.1 christos push lr\n\
1460 1.1 christos bl stash_registers\n\
1461 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1462 1.1 christos ldi r0, #5\n\
1463 1.1 christos bl process_exception");
1464 1.1 christos
1465 1.1 christos void _catchException6 ();
1466 1.1 christos
1467 1.1 christos asm ("\n\
1468 1.1 christos _catchException6:\n\
1469 1.1 christos push lr\n\
1470 1.1 christos bl stash_registers\n\
1471 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1472 1.1 christos ldi r0, #6\n\
1473 1.1 christos bl process_exception");
1474 1.1 christos
1475 1.1 christos void _catchException7 ();
1476 1.1 christos
1477 1.1 christos asm ("\n\
1478 1.1 christos _catchException7:\n\
1479 1.1 christos push lr\n\
1480 1.1 christos bl stash_registers\n\
1481 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1482 1.1 christos ldi r0, #7\n\
1483 1.1 christos bl process_exception");
1484 1.1 christos
1485 1.1 christos void _catchException8 ();
1486 1.1 christos
1487 1.1 christos asm ("\n\
1488 1.1 christos _catchException8:\n\
1489 1.1 christos push lr\n\
1490 1.1 christos bl stash_registers\n\
1491 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1492 1.1 christos ldi r0, #8\n\
1493 1.1 christos bl process_exception");
1494 1.1 christos
1495 1.1 christos void _catchException9 ();
1496 1.1 christos
1497 1.1 christos asm ("\n\
1498 1.1 christos _catchException9:\n\
1499 1.1 christos push lr\n\
1500 1.1 christos bl stash_registers\n\
1501 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1502 1.1 christos ldi r0, #9\n\
1503 1.1 christos bl process_exception");
1504 1.1 christos
1505 1.1 christos void _catchException10 ();
1506 1.1 christos
1507 1.1 christos asm ("\n\
1508 1.1 christos _catchException10:\n\
1509 1.1 christos push lr\n\
1510 1.1 christos bl stash_registers\n\
1511 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1512 1.1 christos ldi r0, #10\n\
1513 1.1 christos bl process_exception");
1514 1.1 christos
1515 1.1 christos void _catchException11 ();
1516 1.1 christos
1517 1.1 christos asm ("\n\
1518 1.1 christos _catchException11:\n\
1519 1.1 christos push lr\n\
1520 1.1 christos bl stash_registers\n\
1521 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1522 1.1 christos ldi r0, #11\n\
1523 1.1 christos bl process_exception");
1524 1.1 christos
1525 1.1 christos void _catchException12 ();
1526 1.1 christos
1527 1.1 christos asm ("\n\
1528 1.1 christos _catchException12:\n\
1529 1.1 christos push lr\n\
1530 1.1 christos bl stash_registers\n\
1531 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1532 1.1 christos ldi r0, #12\n\
1533 1.1 christos bl process_exception");
1534 1.1 christos
1535 1.1 christos void _catchException13 ();
1536 1.1 christos
1537 1.1 christos asm ("\n\
1538 1.1 christos _catchException13:\n\
1539 1.1 christos push lr\n\
1540 1.1 christos bl stash_registers\n\
1541 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1542 1.1 christos ldi r0, #13\n\
1543 1.1 christos bl process_exception");
1544 1.1 christos
1545 1.1 christos void _catchException14 ();
1546 1.1 christos
1547 1.1 christos asm ("\n\
1548 1.1 christos _catchException14:\n\
1549 1.1 christos push lr\n\
1550 1.1 christos bl stash_registers\n\
1551 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1552 1.1 christos ldi r0, #14\n\
1553 1.1 christos bl process_exception");
1554 1.1 christos
1555 1.1 christos void _catchException15 ();
1556 1.1 christos
1557 1.1 christos asm ("\n\
1558 1.1 christos _catchException15:\n\
1559 1.1 christos push lr\n\
1560 1.1 christos bl stash_registers\n\
1561 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1562 1.1 christos ldi r0, #15\n\
1563 1.1 christos bl process_exception");
1564 1.1 christos
1565 1.1 christos void _catchException16 ();
1566 1.1 christos
1567 1.1 christos asm ("\n\
1568 1.1 christos _catchException16:\n\
1569 1.1 christos push lr\n\
1570 1.1 christos bl stash_registers\n\
1571 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1572 1.1 christos ldi r0, #16\n\
1573 1.1 christos bl process_exception");
1574 1.1 christos
1575 1.1 christos void _catchException17 ();
1576 1.1 christos
1577 1.1 christos asm ("\n\
1578 1.1 christos _catchException17:\n\
1579 1.1 christos push lr\n\
1580 1.1 christos bl stash_registers\n\
1581 1.1 christos ; Note that at this point the pushed value of `lr' has been popped\n\
1582 1.1 christos ldi r0, #17\n\
1583 1.1 christos bl process_exception");
1584 1.1 christos
1585 1.1 christos
1586 1.1 christos /* this function is used to set up exception handlers for tracing and
1587 1.1 christos breakpoints */
1588 1.1 christos void
1589 1.1 christos set_debug_traps (void)
1590 1.1 christos {
1591 1.1 christos /* extern void remcomHandler(); */
1592 1.1 christos int i;
1593 1.1 christos
1594 1.1 christos for (i = 0; i < 18; i++) /* keep a copy of old vectors */
1595 1.1 christos if (save_vectors[i] == 0) /* only copy them the first time */
1596 1.1 christos save_vectors[i] = getExceptionHandler (i);
1597 1.1 christos
1598 1.1 christos stackPtr = &remcomStack[STACKSIZE / sizeof (int) - 1];
1599 1.1 christos
1600 1.1 christos exceptionHandler (0, _catchException0);
1601 1.1 christos exceptionHandler (1, _catchException1);
1602 1.1 christos exceptionHandler (2, _catchException2);
1603 1.1 christos exceptionHandler (3, _catchException3);
1604 1.1 christos exceptionHandler (4, _catchException4);
1605 1.1 christos exceptionHandler (5, _catchException5);
1606 1.1 christos exceptionHandler (6, _catchException6);
1607 1.1 christos exceptionHandler (7, _catchException7);
1608 1.1 christos exceptionHandler (8, _catchException8);
1609 1.1 christos exceptionHandler (9, _catchException9);
1610 1.1 christos exceptionHandler (10, _catchException10);
1611 1.1 christos exceptionHandler (11, _catchException11);
1612 1.1 christos exceptionHandler (12, _catchException12);
1613 1.1 christos exceptionHandler (13, _catchException13);
1614 1.1 christos exceptionHandler (14, _catchException14);
1615 1.1 christos exceptionHandler (15, _catchException15);
1616 1.1 christos exceptionHandler (16, _catchException16);
1617 1.1 christos /* exceptionHandler (17, _catchException17); */
1618 1.1 christos
1619 1.1 christos initialized = 1;
1620 1.1 christos }
1621 1.1 christos
1622 1.1 christos /* This function will generate a breakpoint exception. It is used at the
1623 1.1 christos beginning of a program to sync up with a debugger and can be used
1624 1.1 christos otherwise as a quick means to stop program execution and "break" into
1625 1.1 christos the debugger. */
1626 1.1 christos
1627 1.1 christos #define BREAKPOINT() asm volatile (" trap #2");
1628 1.1 christos
1629 1.1 christos void
1630 1.1 christos breakpoint (void)
1631 1.1 christos {
1632 1.1 christos if (initialized)
1633 1.1 christos BREAKPOINT ();
1634 1.1 christos }
1635 1.1 christos
1636 1.1 christos /* STDOUT section:
1637 1.1 christos Stuff pertaining to simulating stdout by sending chars to gdb to be echoed.
1638 1.1 christos Functions: gdb_putchar(char ch)
1639 1.1 christos gdb_puts(char *str)
1640 1.1 christos gdb_write(char *str, int len)
1641 1.1 christos gdb_error(char *format, char *parm)
1642 1.1 christos */
1643 1.1 christos
1644 1.1 christos /* Function: gdb_putchar(int)
1645 1.1 christos Make gdb write a char to stdout.
1646 1.1 christos Returns: the char */
1647 1.1 christos
1648 1.1 christos static int
1649 1.1 christos gdb_putchar (int ch)
1650 1.1 christos {
1651 1.1 christos char buf[4];
1652 1.1 christos
1653 1.1 christos buf[0] = 'O';
1654 1.1 christos buf[1] = hexchars[ch >> 4];
1655 1.1 christos buf[2] = hexchars[ch & 0x0F];
1656 1.1 christos buf[3] = 0;
1657 1.1 christos putpacket (buf);
1658 1.1 christos return ch;
1659 1.1 christos }
1660 1.1 christos
1661 1.1 christos /* Function: gdb_write(char *, int)
1662 1.1 christos Make gdb write n bytes to stdout (not assumed to be null-terminated).
1663 1.1 christos Returns: number of bytes written */
1664 1.1 christos
1665 1.1 christos static int
1666 1.1 christos gdb_write (char *data, int len)
1667 1.1 christos {
1668 1.1 christos char *buf, *cpy;
1669 1.1 christos int i;
1670 1.1 christos
1671 1.1 christos buf = remcomOutBuffer;
1672 1.1 christos buf[0] = 'O';
1673 1.1 christos i = 0;
1674 1.1 christos while (i < len)
1675 1.1 christos {
1676 1.1 christos for (cpy = buf + 1;
1677 1.1 christos i < len && cpy < buf + sizeof (remcomOutBuffer) - 3; i++)
1678 1.1 christos {
1679 1.1 christos *cpy++ = hexchars[data[i] >> 4];
1680 1.1 christos *cpy++ = hexchars[data[i] & 0x0F];
1681 1.1 christos }
1682 1.1 christos *cpy = 0;
1683 1.1 christos putpacket (buf);
1684 1.1 christos }
1685 1.1 christos return len;
1686 1.1 christos }
1687 1.1 christos
1688 1.1 christos /* Function: gdb_puts(char *)
1689 1.1 christos Make gdb write a null-terminated string to stdout.
1690 1.1 christos Returns: the length of the string */
1691 1.1 christos
1692 1.1 christos static int
1693 1.1 christos gdb_puts (char *str)
1694 1.1 christos {
1695 1.1 christos return gdb_write (str, strlen (str));
1696 1.1 christos }
1697 1.1 christos
1698 1.1 christos /* Function: gdb_error(char *, char *)
1699 1.1 christos Send an error message to gdb's stdout.
1700 1.1 christos First string may have 1 (one) optional "%s" in it, which
1701 1.1 christos will cause the optional second string to be inserted. */
1702 1.1 christos
1703 1.1 christos static void
1704 1.1 christos gdb_error (char *format, char *parm)
1705 1.1 christos {
1706 1.1 christos char buf[400], *cpy;
1707 1.1 christos int len;
1708 1.1 christos
1709 1.1 christos if (remote_debug)
1710 1.1 christos {
1711 1.1 christos if (format && *format)
1712 1.1 christos len = strlen (format);
1713 1.1 christos else
1714 1.1 christos return; /* empty input */
1715 1.1 christos
1716 1.1 christos if (parm && *parm)
1717 1.1 christos len += strlen (parm);
1718 1.1 christos
1719 1.1 christos for (cpy = buf; *format;)
1720 1.1 christos {
1721 1.1 christos if (format[0] == '%' && format[1] == 's') /* include second string */
1722 1.1 christos {
1723 1.1 christos format += 2; /* advance two chars instead of just one */
1724 1.1 christos while (parm && *parm)
1725 1.1 christos *cpy++ = *parm++;
1726 1.1 christos }
1727 1.1 christos else
1728 1.1 christos *cpy++ = *format++;
1729 1.1 christos }
1730 1.1 christos *cpy = '\0';
1731 1.1 christos gdb_puts (buf);
1732 1.1 christos }
1733 1.1 christos }
1734 1.1 christos
1735 1.1 christos static unsigned char *
1736 1.1 christos strcpy (unsigned char *dest, const unsigned char *src)
1737 1.1 christos {
1738 1.1 christos unsigned char *ret = dest;
1739 1.1 christos
1740 1.1 christos if (dest && src)
1741 1.1 christos {
1742 1.1 christos while (*src)
1743 1.1 christos *dest++ = *src++;
1744 1.1 christos *dest = 0;
1745 1.1 christos }
1746 1.1 christos return ret;
1747 1.1 christos }
1748 1.1 christos
1749 1.1 christos static int
1750 1.1 christos strlen (const unsigned char *src)
1751 1.1 christos {
1752 1.1 christos int ret;
1753 1.1 christos
1754 1.1 christos for (ret = 0; *src; src++)
1755 1.1 christos ret++;
1756 1.1 christos
1757 1.1 christos return ret;
1758 1.1 christos }
1759 1.1 christos
1760 1.1 christos #if 0
1761 1.1 christos void
1762 1.1 christos exit (code)
1763 1.1 christos int code;
1764 1.1 christos {
1765 1.1 christos _exit (code);
1766 1.1 christos }
1767 1.1 christos
1768 1.1 christos int
1769 1.1 christos atexit (void *p)
1770 1.1 christos {
1771 1.1 christos return 0;
1772 1.1 christos }
1773 1.1 christos
1774 1.1 christos void
1775 1.1 christos abort (void)
1776 1.1 christos {
1777 1.1 christos _exit (1);
1778 1.1 christos }
1779 1.1 christos #endif
1780