source: rtems/c/src/lib/libbsp/m68k/ods68302/startup/m68k-stub.c @ 94e6d84

4.104.115
Last change on this file since 94e6d84 was d4b4664b, checked in by Ralf Corsepius <ralf.corsepius@…>, on 11/29/09 at 14:59:41

Whitespace removal.

  • Property mode set to 100644
File size: 35.2 KB
Line 
1/****************************************************************************
2
3                THIS SOFTWARE IS NOT COPYRIGHTED
4
5   HP offers the following for use in the public domain.  HP makes no
6   warranty with regard to the software or it's performance and the
7   user accepts the software "AS IS" with all faults.
8
9   HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
10   TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
11   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
12
13****************************************************************************/
14
15/****************************************************************************
16 *  Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
17 *
18 *  Module name: remcom.c $
19 *  Revision: 1.34 $
20 *  Date: 91/03/09 12:29:49 $
21 *  Contributor:     Lake Stevens Instrument Division$
22 *
23 *  Description:     low level support for gdb debugger. $
24 *
25 *  Considerations:  only works on target hardware $
26 *
27 *  Written by:      Glenn Engel $
28 *  ModuleState:     Experimental $
29 *
30 *  NOTES:           See Below $
31 *
32 *  To enable debugger support, two things need to happen.  One, a
33 *  call to set_debug_traps() is necessary in order to allow any breakpoints
34 *  or error conditions to be properly intercepted and reported to gdb.
35 *  Two, a breakpoint needs to be generated to begin communication.  This
36 *  is most easily accomplished by a call to breakpoint().  Breakpoint()
37 *  simulates a breakpoint by executing a trap #1.  The breakpoint instruction
38 *  is hardwired to trap #1 because not to do so is a compatibility problem--
39 *  there either should be a standard breakpoint instruction, or the protocol
40 *  should be extended to provide some means to communicate which breakpoint
41 *  instruction is in use (or have the stub insert the breakpoint).
42 *
43 *  Some explanation is probably necessary to explain how exceptions are
44 *  handled.  When an exception is encountered the 68000 pushes the current
45 *  program counter and status register onto the supervisor stack and then
46 *  transfers execution to a location specified in it's vector table.
47 *  The handlers for the exception vectors are hardwired to jmp to an address
48 *  given by the relation:  (exception - 256) * 6.  These are decending
49 *  addresses starting from -6, -12, -18, ...  By allowing 6 bytes for
50 *  each entry, a jsr, jmp, bsr, ... can be used to enter the exception
51 *  handler.  Using a jsr to handle an exception has an added benefit of
52 *  allowing a single handler to service several exceptions and use the
53 *  return address as the key differentiation.  The vector number can be
54 *  computed from the return address by [ exception = (addr + 1530) / 6 ].
55 *  The sole purpose of the routine _catchException is to compute the
56 *  exception number and push it on the stack in place of the return address.
57 *  The external function exceptionHandler() is
58 *  used to attach a specific handler to a specific m68k exception.
59 *  For 68020 machines, the ability to have a return address around just
60 *  so the vector can be determined is not necessary because the '020 pushes an
61 *  extra word onto the stack containing the vector offset
62 *
63 *  Because gdb will sometimes write to the stack area to execute function
64 *  calls, this program cannot rely on using the supervisor stack so it
65 *  uses it's own stack area reserved in the int array remcomStack.
66 *
67 *************
68 *
69 *    The following gdb commands are supported:
70 *
71 * command          function                               Return value
72 *
73 *    g             return the value of the CPU registers  hex data or ENN
74 *    G             set the value of the CPU registers     OK or ENN
75 *
76 *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
77 *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
78 *
79 *    c             Resume at current address              SNN   ( signal NN)
80 *    cAA..AA       Continue at address AA..AA             SNN
81 *
82 *    s             Step one instruction                   SNN
83 *    sAA..AA       Step one instruction from AA..AA       SNN
84 *
85 *    k             kill
86 *
87 *    ?             What was the last sigval ?             SNN   (signal NN)
88 *
89 * All commands and responses are sent with a packet which includes a
90 * checksum.  A packet consists of
91 *
92 * $<packet info>#<checksum>.
93 *
94 * where
95 * <packet info> :: <characters representing the command or response>
96 * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
97 *
98 * When a packet is received, it is first acknowledged with either '+' or '-'.
99 * '+' indicates a successful transfer.  '-' indicates a failed transfer.
100 *
101 * Example:
102 *
103 * Host:                  Reply:
104 * $m0,10#2a               +$00010203040506070809101112131415#42
105 *
106 *  $Id$
107 *
108 ****************************************************************************/
109
110#include <stdio.h>
111#include <string.h>
112#include <setjmp.h>
113
114#include <bsp.h>
115#include <debugport.h>
116
117/************************************************************************
118 *
119 * external low-level support routines
120 */
121typedef void (*ExceptionHook)(int);   /* pointer to function with int parm */
122typedef void (*Function)(void);       /* pointer to a function */
123
124/* assign an exception handler */
125Function exceptionHandler(int vector,  Function handler);
126extern ExceptionHook exceptionHook;  /* hook variable for errors/exceptions */
127
128int putDebugChar(char ch);
129char getDebugChar(void);
130
131/************************/
132/* FORWARD DECLARATIONS */
133/************************/
134static int hex(char ch);
135static void getpacket(char *buffer);
136static void putpacket(char *buffer);
137static char* mem2hex(char *mem, char *buf, int count);
138static char* hex2mem(char *buf, char *mem, int count);
139static void handle_buserror(void);
140static int computeSignal(int exceptionVector);
141static int hexToInt(char **ptr, int *intValue);
142       void handle_exception(int exceptionVector);
143static void initializeRemcomErrorFrame(void);
144
145void set_debug_traps(void);
146void breakpoint(void);
147
148/************************************************************************/
149/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
150/* at least NUMREGBYTES*2 are needed for register packets */
151#define BUFMAX 400
152
153static bool initialized = false;  /* boolean flag. != 0 means we've been initialized */
154
155int remote_debug;
156/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
157
158static const char hexchars[]="0123456789abcdef";
159
160/* there are 180 bytes of registers on a 68020 w/68881      */
161/* many of the fpa registers are 12 byte (96 bit) registers */
162#define NUMREGBYTES 180
163enum regnames {D0,D1,D2,D3,D4,D5,D6,D7,
164               A0,A1,A2,A3,A4,A5,A6,A7,
165               PS,PC,
166               FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7,
167               FPCONTROL,FPSTATUS,FPIADDR
168              };
169
170
171/* We keep a whole frame cache here.  "Why?", I hear you cry, "doesn't
172   GDB handle that sort of thing?"  Well, yes, I believe the only
173   reason for this cache is to save and restore floating point state
174   (fsave/frestore).  A cleaner way to do this would be to make the
175 fsave data part of the registers which GDB deals with like any
176   other registers.  This should not be a performance problem if the
177   ability to read individual registers is added to the protocol.  */
178
179typedef struct FrameStruct
180{
181    struct FrameStruct  *previous;
182    int       exceptionPC;      /* pc value when this frame created */
183    int       exceptionVector;  /* cpu vector causing exception     */
184    short     frameSize;        /* size of cpu frame in words       */
185    short     sr;               /* for 68000, this not always sr    */
186    int       pc;
187    short     format;
188    int       fsaveHeader;
189    int       morejunk[0];        /* exception frame, fp save... */
190} Frame;
191
192#define FRAMESIZE 500
193int gdbFrameStack[FRAMESIZE];
194static Frame *lastFrame;
195
196/*
197 * these should not be static cuz they can be used outside this module
198 */
199int registers[NUMREGBYTES/4];
200int superStack;
201
202#define STACKSIZE 10000
203int remcomStack[STACKSIZE/sizeof(int)];
204static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
205
206/*
207 * In many cases, the system will want to continue exception processing
208 * when a continue command is given.
209 * oldExceptionHook is a function to invoke in this case.
210 */
211
212static ExceptionHook oldExceptionHook;
213
214#if (defined(__mc68020__) && !defined(__mcpu32__))
215/* the size of the exception stack on the 68020 varies with the type of
216 * exception.  The following table is the number of WORDS used
217 * for each exception format.
218 */
219const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 };
220#endif
221
222#if defined(__mc68332__)
223static const short exceptionSize[] = { 4,4,6,4,4,4,4,4,4,4,4,4,16,4,4,4 };
224#endif
225
226/************* jump buffer used for setjmp/longjmp **************************/
227jmp_buf remcomEnv;
228
229/***************************  ASSEMBLY CODE MACROS *************************/
230/*                                                                         */
231
232#if defined(__HAVE_68881__)
233
234/* do an fsave, then remember the address to begin a restore from */
235#define SAVE_FP_REGS() \
236       asm(" fsave   %a0@-");   \
237       asm(" fmovemx %fp0-%fp7,registers+72");  \
238       asm(" fmoveml %fpcr/%fpsr/%fpi,registers+168");
239
240#define RESTORE_FP_REGS() \
241asm("                                                 \n\
242    fmoveml  registers+168,%fpcr/%fpsr/%fpi           \n\
243    fmovemx  registers+72,%fp0-%fp7                   \n\
244    cmpl     #-1,%a0@     |  skip frestore flag set ? \n\
245    beq      skip_frestore                            \n\
246    frestore %a0@+                                    \n\
247skip_frestore:                                        \n\
248");
249
250#else
251
252#define SAVE_FP_REGS()
253#define RESTORE_FP_REGS()
254
255#endif /* __HAVE_68881__ */
256
257void return_to_super(void);
258void return_to_user(void);
259
260asm("\n\
261       .text\n\
262\n\
263       .globl return_to_super\n\
264       .align 4\n\
265return_to_super:\n\
266        movel   registers+60,%sp     /* get new stack pointer */        \n\
267        movel   lastFrame,%a0        /* get last frame info  */         \n\
268        bra     return_to_any\n\
269\n\
270        .globl return_to_user\n\
271        .align 4\n\
272\n\
273return_to_user:\n\
274        movel   registers+60,%a0     /* get usp */                      \n\
275        movel   %a0,%usp             /* set usp */                              \n\
276        movel   superStack,%sp       /* get original stack pointer */        \n\
277\n\
278return_to_any:\n\
279        movel   lastFrame,%a0        /* get last frame info  */              \n\
280        movel   %a0@+,lastFrame      /* link in previous frame     */        \n\
281        addql   #8,%a0               /* skip over pc, vector#*/              \n\
282        movew   %a0@+,%d0            /* get # of words in cpu frame */       \n\
283        addw    %d0,%a0              /* point to end of data        */       \n\
284        addw    %d0,%a0              /* point to end of data        */       \n\
285        movel   %a0,%a1                                                   \n\
286#                                                                       \n\
287# copy the stack frame                                                  \n\
288        subql   #1,%d0\n\
289\n\
290copyUserLoop:                                                               \n\
291        movew   %a1@-,%sp@-                                               \n\
292        dbf     %d0,copyUserLoop                                             \n\
293");
294        RESTORE_FP_REGS()
295asm("\n\
296        moveml  registers,%d0-%d7/%a0-%a6\n\
297        rte                          /* pop and go! */\n\
298");
299
300#define DISABLE_INTERRUPTS() asm("   oriw   #0x0700,%sr");
301#define BREAKPOINT()         asm("   trap   #1");
302
303/* this function is called immediately when a level 7 interrupt occurs */
304/* if the previous interrupt level was 7 then we're already servicing  */
305/* this interrupt and an rte is in order to return to the debugger.    */
306/* For the 68000, the offset for sr is 6 due to the jsr return address */
307asm("\n\
308        .text\n\
309        .globl _debug_level7\n\
310        .align 4\n\
311\n\
312_debug_level7:\n\
313        movew   %d0,%sp@-\n\
314");
315
316#if (defined(__mc68020__) && !defined(__mcpu32__)) || defined(__mc68332__)
317asm("\n\
318        movew   %sp@(2),%d0\n\
319");
320#else
321asm("\n\
322        movew   %sp@(6),%d0\n\
323");
324#endif
325asm("\n\
326        andiw   #0x700,%d0\n\
327          cmpiw   #0x700,%d0\n\
328          beq     _already7\n\
329        movew   %sp@+,%d0       \n\
330        bra     _catchException\n\
331_already7:\n\
332              movew   %sp@+,%d0\n\
333");
334#if defined (__mc68000__) && !(defined(__mc68020__) && !defined(__mcpu32__))
335asm("\n\
336        lea     %sp@(4),%sp");       /* pull off 68000 return address */
337#endif
338asm("\n\
339        rte\n\
340");
341
342extern void _catchException(void);
343
344#if (defined(__mc68020__) && !defined(__mcpu32__)) || defined(__mc68332__)
345/* This function is called when a 68020 exception occurs.  It saves
346 * all the cpu and fpcp regs in the _registers array, creates a frame on a
347 * linked list of frames which has the cpu and fpcp stack frames needed
348 * to properly restore the context of these processors, and invokes
349 * an exception handler (remcom_handler).
350 *
351 * stack on entry:                       stack on exit:
352 *   N bytes of junk                     exception # MSWord
353 *   Exception Format Word               exception # MSWord
354 *   Program counter LSWord
355 *   Program counter MSWord
356 *   Status Register
357 *
358 *
359 */
360asm(" \n\
361        .text\n\
362\n\
363        .globl _catchException\n\
364        .align 4\n\
365_catchException:\n\
366");
367
368DISABLE_INTERRUPTS();
369
370asm("\n\
371        moveml  %d0-%d7/%a0-%a6,registers /* save registers        */\n\
372        movel   lastFrame,%a0             /* last frame pointer */\n\
373");
374SAVE_FP_REGS();
375asm("\n\
376        lea     registers,%a5   /* get address of registers     */\n\
377        movew   %sp@,%d1        /* get status register          */\n\
378        movew   %d1,%a5@(66)    /* save sr      */      \n\
379        movel   %sp@(2),%a4     /* save pc in %a4 for later use  */\n\
380        movel   %a4,%a5@(68)    /* save pc in _regisers[]       */\n\
381\n\
382#\n\
383# figure out how many bytes in the stack frame\n\
384#\n\
385        movew   %sp@(6),%d0         /* get '020 exception format        */\n\
386        movew   %d0,%d2         /* make a copy of format word   */\n\
387        andiw   #0xf000,%d0     /* mask off format type         */\n\
388        rolw    #5,%d0          /* rotate into the low byte *2  */\n\
389        lea     exceptionSize,%a1   \n\
390        addw    %d0,%a1         /* index into the table         */\n\
391        movew   %a1@,%d0        /* get number of words in frame */\n\
392        movew   %d0,%d3         /* save it                      */\n\
393        subw    %d0,%a0         /* adjust save pointer          */\n\
394        subw    %d0,%a0         /* adjust save pointer(bytes)   */\n\
395        movel   %a0,%a1         /* copy save pointer            */\n\
396        subql   #1,%d0          /* predecrement loop counter    */\n\
397#\n\
398# copy the frame\n\
399#\n\
400saveFrameLoop:\n\
401              movew   %sp@+,%a1@+\n\
402        dbf     %d0,saveFrameLoop\n\
403#\n\
404# now that the stack has been clenaed,\n\
405# save the %a7 in use at time of exception\n\
406\n\
407        movel   %sp,superStack  /* save supervisor %sp           */\n\
408        andiw   #0x2000,%d1     /* were we in supervisor mode ? */\n\
409        beq     userMode       \n\
410        movel   %a7,%a5@(60)    /* save %a7                  */\n\
411        bra     a7saveDone\n\
412userMode:  \n\
413        movel   %usp,%a1        \n\
414        movel   %a1,%a5@(60)    /* save user stack pointer      */\n\
415a7saveDone:\n\
416\n\
417#\n\
418# save size of frame\n\
419        movew   %d3,%a0@-\n\
420\n\
421#\n\
422# compute exception number\n\
423        andl    #0xfff,%d2        /* mask off vector offset     */\n\
424        lsrw    #2,%d2                /* divide by 4 to get vect num    */\n\
425        movel   %d2,%a0@-       /* save it                      */\n\
426#\n\
427# save pc causing exception\n\
428        movel   %a4,%a0@-\n\
429#\n\
430# save old frame link and set the new value\n\
431        movel   lastFrame,%a1       /* last frame pointer */\n\
432        movel   %a1,%a0@-                   /* save pointer to prev frame       */\n\
433        movel   %a0,lastFrame\n\
434\n\
435        movel   %d2,%sp@-                   /* push exception num           */\n\
436        movel   exceptionHook,%a0  /* get address of handler */\n\
437        jbsr    %a0@            /* and call it */\n\
438        clrl    %sp@            /* replace exception num parm with frame ptr */\n\
439        jbsr     _returnFromException   /* jbsr, but never returns */\n\
440\n\
441");
442
443#else /* mc68000 */
444
445/* This function is called when an exception occurs.  It translates the
446 * return address found on the stack into an exception vector # which
447 * is then handled by either handle_exception or a system handler.
448 * _catchException provides a front end for both.
449 *
450 * stack on entry:                       stack on exit:
451 *   Program counter MSWord              exception # MSWord
452 *   Program counter LSWord              exception # MSWord
453 *   Status Register
454 *   Return Address  MSWord
455 *   Return Address  LSWord
456 */
457asm("\n\
458        .text\n\
459        .globl _catchException\n\
460        .align 4\n\
461_catchException:\n\
462");
463DISABLE_INTERRUPTS();
464asm("\n\
465        moveml  %d0-%d7/%a0-%a6,registers  /* save registers               */\n\
466        movel   lastFrame,%a0   /* last frame pointer */\n\
467");
468
469SAVE_FP_REGS();
470asm("\n\
471        moveq.l #0,%d2\n\
472        movew   %sp@+,%d2\n\
473        lea     registers,%a5    /* get address of registers     */\n\
474\n\
475        moveql  #3,%d3           /* assume a three word frame     */\n\
476\n\
477        cmpiw   #3,%d2           /* bus error or address error ? */\n\
478        bgt     normal           /* if >3 then normal error      */\n\
479        movel   %sp@+,%a0@-      /* copy error info to frame buff*/\n\
480        movel   %sp@+,%a0@-      /* these are never used         */\n\
481        moveql  #7,%d3           /* this is a 7 word frame       */\n\
482     \n\
483normal:   \n\
484        movew   %sp@+,%d1         /* pop status register          */\n\
485        movel   %sp@+,%a4         /* pop program counter          */\n\
486\n\
487        cmpiw   #33,%d2           /* trap #1, breakpoint ? */\n\
488        bne     not_breakpoint\n\
489\n\
490        subql   #2,%a4            /* trap leaves the pc after the trap */\n\
491\n\
492not_breakpoint:\n\
493        movew   %d1,%a5@(66)      /* save sr                    */      \n\
494        movel   %a4,%a5@(68)      /* save pc in _regisers[]             */\n\
495        movel   %a4,%a0@-         /* copy pc to frame buffer      */\n\
496        movew   %d1,%a0@-         /* copy sr to frame buffer      */\n\
497\n\
498        movel   %sp,superStack    /* save supervisor %sp          */\n\
499\n\
500        andiw   #0x2000,%d1      /* were we in supervisor mode ? */\n\
501        beq     userMode       \n\
502        movel   %a7,%a5@(60)      /* save %a7                  */\n\
503        bra     saveDone             \n\
504userMode:\n\
505        movel   %usp,%a1        /* save user stack pointer      */\n\
506        movel   %a1,%a5@(60)      /* save user stack pointer    */\n\
507saveDone:\n\
508\n\
509        movew   %d3,%a0@-         /* push frame size in words     */\n\
510        movel   %d2,%a0@-         /* push vector number           */\n\
511        movel   %a4,%a0@-         /* push exception pc            */\n\
512\n\
513#\n\
514# save old frame link and set the new value\n\
515#\n\
516        movel   lastFrame,%a1   /* last frame pointer */\n\
517        movel   %a1,%a0@-               /* save pointer to prev frame   */\n\
518        movel   %a0,lastFrame\n\
519\n\
520        movel   %d2,%sp@-               /* push exception num           */\n\
521        movel   exceptionHook,%a0  /* get address of handler */\n\
522\n\
523        jbsr    %a0@             /* and call it */\n\
524        clrl    %sp@             /* replace exception num parm with frame ptr */\n\
525        jbsr     _returnFromException   /* jbsr, but never returns */\n\
526");
527#endif
528
529/*
530 * remcomHandler is a front end for handle_exception.  It moves the
531 * stack pointer into an area reserved for debugger use in case the
532 * breakpoint happened in supervisor mode.
533 */
534asm("remcomHandler:");
535asm("           addl    #4,%sp");        /* pop off return address     */
536asm("           movel   %sp@+,%d0");      /* get the exception number   */
537asm("           movel   stackPtr,%sp"); /* move to remcom stack area  */
538asm("           movel   %d0,%sp@-");    /* push exception onto stack  */
539asm("           jbsr    handle_exception");    /* this never returns */
540asm("           rts");                  /* return */
541
542void _returnFromException(Frame *frame)
543{
544  /* if no passed in frame, use the last one */
545  if (! frame)
546  {
547    frame = lastFrame;
548    frame->frameSize = 4;
549    frame->format = 0;
550    frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info*/
551  }
552
553#if defined(__mc68000__) && !(defined(__mc68020__) && !defined(__mcpu32__))
554  /* a 68000 cannot use the internal info pushed onto a bus error
555   * or address error frame when doing an RTE so don't put this info
556   * onto the stack or the stack will creep every time this happens.
557   */
558  frame->frameSize=3;
559#endif
560
561  /* throw away any frames in the list after this frame */
562  lastFrame = frame;
563
564  frame->sr = registers[(int) PS];
565  frame->pc = registers[(int) PC];
566
567  if (registers[(int) PS] & 0x2000)
568  {
569    /* return to supervisor mode... */
570    return_to_super();
571  }
572  else
573  { /* return to user mode */
574    return_to_user();
575  }
576}
577
578int hex(char ch)
579{
580  if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
581  if ((ch >= '0') && (ch <= '9')) return (ch-'0');
582  if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
583  return (-1);
584}
585
586/* scan for the sequence $<data>#<checksum>     */
587void getpacket(char *buffer)
588{
589  unsigned char checksum;
590  unsigned char xmitcsum;
591  int  i;
592  int  count;
593  char ch;
594
595  do {
596    /* wait around for the start character, ignore all other characters */
597    while ((ch = (getDebugChar() & 0x7f)) != '$');
598    checksum = 0;
599    xmitcsum = -1;
600
601    count = 0;
602
603    /* now, read until a # or end of buffer is found */
604    while (count < BUFMAX) {
605      ch = getDebugChar() & 0x7f;
606      if (ch == '#') break;
607      checksum = checksum + ch;
608      buffer[count] = ch;
609      count = count + 1;
610    }
611    buffer[count] = 0;
612
613    if (ch == '#') {
614      xmitcsum = hex(getDebugChar() & 0x7f) << 4;
615      xmitcsum += hex(getDebugChar() & 0x7f);
616      if ((remote_debug ) && (checksum != xmitcsum)) {
617        debug_port_printf ("bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
618                           checksum,xmitcsum,buffer);
619      }
620
621      if (checksum != xmitcsum) putDebugChar('-');  /* failed checksum */
622      else {
623        putDebugChar('+');  /* successful transfer */
624        /* if a sequence char is present, reply the sequence ID */
625        if (buffer[2] == ':') {
626          putDebugChar( buffer[0] );
627          putDebugChar( buffer[1] );
628          /* remove sequence chars from buffer */
629          count = strlen(buffer);
630          for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
631        }
632      }
633    }
634  } while (checksum != xmitcsum);
635}
636
637/* send the packet in buffer.  The host get's one chance to read it.
638   This routine does not wait for a positive acknowledge.  */
639
640void
641putpacket(char *buffer)
642{
643  unsigned char checksum;
644  int  count;
645  char ch;
646
647  /*  $<packet info>#<checksum>. */
648  do {
649    putDebugChar('$');
650    checksum = 0;
651    count    = 0;
652
653    while ((ch=buffer[count])) {
654      if (! putDebugChar(ch)) return;
655      checksum += ch;
656      count += 1;
657    }
658
659    putDebugChar('#');
660    putDebugChar(hexchars[checksum >> 4]);
661    putDebugChar(hexchars[checksum % 16]);
662
663  } while (1 == 0);  /* (getDebugChar() != '+'); */
664
665}
666
667char  remcomInBuffer[BUFMAX];
668char  remcomOutBuffer[BUFMAX];
669static short error;
670
671/* convert the memory pointed to by mem into hex, placing result in buf */
672/* return a pointer to the last char put in buf (null) */
673char *mem2hex(char *mem, char *buf, int count)
674{
675  int i;
676  unsigned char ch;
677
678  if (remote_debug)
679    debug_port_printf("mem=0x%x, count=0x%x\n", mem, count);
680
681  for (i=0;i<count;i++) {
682    ch = *mem++;
683    *buf++ = hexchars[ch >> 4];
684    *buf++ = hexchars[ch % 16];
685  }
686  *buf = 0;
687  return(buf);
688}
689
690/* convert the hex array pointed to by buf into binary to be placed in mem */
691/* return a pointer to the character AFTER the last byte written */
692char *hex2mem(char *buf, char *mem, int count)
693{
694  int i;
695  unsigned char ch;
696
697  if (remote_debug)
698    debug_port_printf("mem=0x%x, count=0x%x\n", mem, count);
699
700  for (i=0;i<count;i++) {
701    ch = hex(*buf++) << 4;
702    ch = ch + hex(*buf++);
703    *mem++ = ch;
704  }
705  return(mem);
706}
707
708/* a bus error has occurred, perform a longjmp
709   to return execution and allow handling of the error */
710
711void handle_buserror()
712{
713  longjmp(remcomEnv,1);
714}
715
716/* this function takes the 68000 exception number and attempts to
717   translate this number into a unix compatible signal value */
718int computeSignal(int exceptionVector)
719{
720  int sigval;
721  switch (exceptionVector) {
722    case 2 : sigval = 10; break; /* bus error           */
723    case 3 : sigval = 10; break; /* address error       */
724    case 4 : sigval = 4;  break; /* illegal instruction */
725    case 5 : sigval = 8;  break; /* zero divide         */
726    case 6 : sigval = 8; break; /* chk instruction     */
727    case 7 : sigval = 8; break; /* trapv instruction   */
728    case 8 : sigval = 11; break; /* privilege violation */
729    case 9 : sigval = 5;  break; /* trace trap          */
730    case 10: sigval = 4;  break; /* line 1010 emulator  */
731    case 11: sigval = 4;  break; /* line 1111 emulator  */
732
733      /* Coprocessor protocol violation.  Using a standard MMU or FPU
734         this cannot be triggered by software.  Call it a SIGBUS.  */
735    case 13: sigval = 10;  break;
736
737    case 31: sigval = 2;  break; /* interrupt           */
738    case 33: sigval = 5;  break; /* breakpoint          */
739
740      /* This is a trap #8 instruction.  Apparently it is someone's software
741         convention for some sort of SIGFPE condition.  Whose?  How many
742         people are being screwed by having this code the way it is?
743         Is there a clean solution?  */
744    case 40: sigval = 8;  break; /* floating point err  */
745
746    case 48: sigval = 8;  break; /* floating point err  */
747    case 49: sigval = 8;  break; /* floating point err  */
748    case 50: sigval = 8;  break; /* zero divide         */
749    case 51: sigval = 8;  break; /* underflow           */
750    case 52: sigval = 8;  break; /* operand error       */
751    case 53: sigval = 8;  break; /* overflow            */
752    case 54: sigval = 8;  break; /* NAN                 */
753    default:
754      sigval = 7;         /* "software generated"*/
755  }
756  return (sigval);
757}
758
759/**********************************************/
760/* WHILE WE FIND NICE HEX CHARS, BUILD AN INT */
761/* RETURN NUMBER OF CHARS PROCESSED           */
762/**********************************************/
763int hexToInt(char **ptr, int *intValue)
764{
765  int numChars = 0;
766  int hexValue;
767
768  *intValue = 0;
769
770  while (**ptr)
771  {
772    hexValue = hex(**ptr);
773    if (hexValue >=0)
774    {
775      *intValue = (*intValue <<4) | hexValue;
776      numChars ++;
777    }
778    else
779      break;
780
781    (*ptr)++;
782  }
783
784  return (numChars);
785}
786
787/*
788 * This function does all command procesing for interfacing to gdb.
789 */
790void handle_exception(int exceptionVector)
791{
792  int    sigval;
793  int    addr, length;
794  char * ptr;
795  int    newPC;
796  Frame  *frame;
797
798  if (remote_debug)
799    printf("vector=%d, sr=0x%x, pc=0x%x\n",
800           exceptionVector,
801           registers[ PS ],
802           registers[ PC ]);
803
804  /* reply to host that an exception has occurred */
805  sigval = computeSignal( exceptionVector );
806  remcomOutBuffer[0] = 'S';
807  remcomOutBuffer[1] =  hexchars[sigval >> 4];
808  remcomOutBuffer[2] =  hexchars[sigval % 16];
809  remcomOutBuffer[3] = 0;
810
811  putpacket(remcomOutBuffer);
812
813  while (1==1) {
814    error = 0;
815    remcomOutBuffer[0] = 0;
816    getpacket(remcomInBuffer);
817    switch (remcomInBuffer[0]) {
818      case '?' :   remcomOutBuffer[0] = 'S';
819        remcomOutBuffer[1] =  hexchars[sigval >> 4];
820        remcomOutBuffer[2] =  hexchars[sigval % 16];
821        remcomOutBuffer[3] = 0;
822        break;
823      case 'd' :
824        remote_debug = !(remote_debug);  /* toggle debug flag */
825        debug_port_printf("debug mode ");
826        if (remote_debug)
827        {
828          debug_port_printf("on\n");
829        }
830        else
831        {
832          debug_port_printf("off\n");
833        }
834        break;
835      case 'g' : /* return the value of the CPU registers */
836        mem2hex((char*) registers, remcomOutBuffer, NUMREGBYTES);
837        break;
838      case 'G' : /* set the value of the CPU registers - return OK */
839        hex2mem(&remcomInBuffer[1], (char*) registers, NUMREGBYTES);
840        strcpy(remcomOutBuffer,"OK");
841        break;
842
843        /* mAA..AA,LLLL  Read LLLL bytes at address AA..AA */
844      case 'm' :
845        if (setjmp(remcomEnv) == 0)
846        {
847          exceptionHandler(2,handle_buserror);
848
849          /* TRY TO READ %x,%x.  IF SUCCEED, SET PTR = 0 */
850          ptr = &remcomInBuffer[1];
851          if (hexToInt(&ptr,&addr))
852            if (*(ptr++) == ',')
853              if (hexToInt(&ptr,&length))
854              {
855                ptr = 0;
856                mem2hex((char*) addr, remcomOutBuffer, length);
857              }
858
859          if (ptr)
860          {
861            strcpy(remcomOutBuffer,"E01");
862            if (remote_debug)
863              printf("malformed read memory command: %s",remcomInBuffer);
864          }
865        }
866        else {
867          exceptionHandler(2,_catchException);
868          strcpy(remcomOutBuffer,"E03");
869          if (remote_debug)
870            printf("bus error");
871        }
872
873        /* restore handler for bus error */
874        exceptionHandler(2,_catchException);
875        break;
876
877        /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
878      case 'M' :
879        if (setjmp(remcomEnv) == 0) {
880          exceptionHandler(2,handle_buserror);
881
882          /* TRY TO READ '%x,%x:'.  IF SUCCEED, SET PTR = 0 */
883          ptr = &remcomInBuffer[1];
884          if (hexToInt(&ptr,&addr))
885            if (*(ptr++) == ',')
886              if (hexToInt(&ptr,&length))
887                if (*(ptr++) == ':')
888                {
889                  hex2mem(ptr, (char*) addr, length);
890                  ptr = 0;
891                  strcpy(remcomOutBuffer,"OK");
892                }
893          if (ptr)
894          {
895            strcpy(remcomOutBuffer,"E02");
896            if (remote_debug)
897              printf("malformed write memory command: %s",remcomInBuffer);
898                      }
899        }
900        else {
901          exceptionHandler(2,_catchException);
902          strcpy(remcomOutBuffer,"E03");
903          if (remote_debug)
904            printf("bus error");
905        }
906
907        /* restore handler for bus error */
908        exceptionHandler(2,_catchException);
909        break;
910
911        /* cAA..AA    Continue at address AA..AA(optional) */
912        /* sAA..AA   Step one instruction from AA..AA(optional) */
913      case 'c' :
914      case 's' :
915        /* try to read optional parameter, pc unchanged if no parm */
916        ptr = &remcomInBuffer[1];
917        if (hexToInt(&ptr,&addr))
918          registers[ PC ] = addr;
919
920        newPC = registers[ PC];
921
922        /* clear the trace bit */
923        registers[ PS ] &= 0x7fff;
924
925        /* set the trace bit if we're stepping */
926        if (remcomInBuffer[0] == 's') registers[ PS ] |= 0x8000;
927
928        /*
929         * look for newPC in the linked list of exception frames.
930         * if it is found, use the old frame it.  otherwise,
931         * fake up a dummy frame in returnFromException().
932         */
933        if (remote_debug) debug_port_printf("new pc = 0x%x\n",newPC);
934
935        frame = lastFrame;
936        while (frame)
937        {
938          if (remote_debug)
939            debug_port_printf("frame at 0x%x has pc=0x%x, except#=%d\n",
940                              frame,frame->exceptionPC,
941                              (unsigned int) frame->exceptionVector);
942          if (frame->exceptionPC == newPC) break;  /* bingo! a match */
943          /*
944           * for a breakpoint instruction, the saved pc may
945           * be off by two due to re-executing the instruction
946           * replaced by the trap instruction.  Check for this.
947           */
948          if ((frame->exceptionVector == 33) &&
949              (frame->exceptionPC == newPC)) break;
950          if (frame == frame->previous)
951          {
952                  frame = 0; /* no match found */
953                  break;
954          }
955          frame = frame->previous;
956        }
957
958        /*
959         * If we found a match for the PC AND we are not returning
960         * as a result of a breakpoint (33),
961         * trace exception (9), nmi (31), jmp to
962         * the old exception handler as if this code never ran.
963         */
964        if (frame)
965        {
966          if ((frame->exceptionVector != 9)  &&
967              (frame->exceptionVector != 31) &&
968              (frame->exceptionVector != 33))
969          {
970            /*
971             * invoke the previous handler.
972             */
973            if (oldExceptionHook)
974              (*oldExceptionHook) (frame->exceptionVector);
975            newPC = registers[ PC ];    /* pc may have changed  */
976            if (newPC != frame->exceptionPC)
977            {
978              if (remote_debug)
979                debug_port_printf("frame at 0x%x has pc=0x%x, except#=%d\n",
980                                  frame,frame->exceptionPC,
981                                  (unsigned int) frame->exceptionVector);
982              /* re-use the last frame, we're skipping it (longjump?)*/
983              frame = (Frame *) 0;
984              _returnFromException( frame );  /* this is a jump */
985            }
986          }
987        }
988
989          /* if we couldn't find a frame, create one */
990        if (frame == 0)
991        {
992          frame = lastFrame -1 ;
993
994          /* by using a bunch of print commands with breakpoints,
995             it's possible for the frame stack to creep down.  If it creeps
996             too far, give up and reset it to the top.  Normal use should
997             not see this happen.
998             */
999          if ((unsigned int) (frame-2) < (unsigned int) &gdbFrameStack)
1000          {
1001            initializeRemcomErrorFrame();
1002            frame = lastFrame;
1003          }
1004          frame->previous = lastFrame;
1005          lastFrame = frame;
1006          frame = 0;  /* null so _return... will properly initialize it */
1007        }
1008
1009        _returnFromException( frame ); /* this is a jump */
1010
1011        break;
1012
1013        /* kill the program */
1014      case 'k' :
1015        /* reset the board */
1016        WATCHDOG_TRIGGER();
1017        while (1 == 1);
1018        break;
1019
1020    } /* switch */
1021
1022    /* reply to the request */
1023    putpacket(remcomOutBuffer);
1024  }
1025}
1026
1027void initializeRemcomErrorFrame()
1028{
1029    lastFrame = ((Frame *) &gdbFrameStack[FRAMESIZE-1]) - 1;
1030    lastFrame->previous = lastFrame;
1031}
1032
1033/* this function is used to set up exception handlers for tracing and
1034   breakpoints */
1035void set_debug_traps()
1036{
1037  extern void _debug_level7(void);
1038  extern void remcomHandler(void);
1039
1040  int exception;
1041
1042  initializeRemcomErrorFrame();
1043  stackPtr  = &remcomStack[STACKSIZE/sizeof(int) - 1];
1044
1045  registers[ PC ] = 0x400;
1046  registers[ PS ] = 0x2700;
1047
1048  for (exception = 2; exception <= 30; exception++)
1049      exceptionHandler(exception,_catchException);
1050
1051  /* level 7 interrupt              */
1052  exceptionHandler(31,_debug_level7);
1053
1054  for (exception = 32; exception <= 47; exception++)
1055    exceptionHandler(exception,_catchException);
1056
1057  /* exclude the unassigned, reserved vector locations */
1058
1059  for (exception = 64; exception <= 255; exception++)
1060    exceptionHandler(exception,_catchException);
1061
1062  if (oldExceptionHook != (ExceptionHook) remcomHandler)
1063  {
1064      oldExceptionHook = exceptionHook;
1065      exceptionHook    = (ExceptionHook) remcomHandler;
1066  }
1067
1068  initialized = true;
1069
1070#if defined(UPDATE_DISPLAY)
1071  UPDATE_DISPLAY("gdb ");
1072#endif
1073}
1074
1075/* This function will generate a breakpoint exception.  It is used at the
1076   beginning of a program to sync up with a debugger and can be used
1077   otherwise as a quick means to stop program execution and "break" into
1078   the debugger. */
1079
1080void breakpoint()
1081{
1082  if (initialized) BREAKPOINT();
1083}
Note: See TracBrowser for help on using the repository browser.