source: rtems/c/src/lib/libbsp/m68k/ods68302/startup/m68k-stub.c @ 12a17af3

4.104.114.84.95
Last change on this file since 12a17af3 was 0074691a, checked in by Joel Sherrill <joel.sherrill@…>, on 07/31/97 at 22:13:29

Merged very large and much appreciated patch from Chris Johns
<cjohns@…>. This patch includes the ods68302 bsp,
the RTEMS++ class library, and the rtems++ test.

  • 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 ****************************************************************************/
107
108#include <stdio.h>
109#include <string.h>
110#include <setjmp.h>
111
112#include <bsp.h>
113#include <debugport.h>
114
115/************************************************************************
116 *
117 * external low-level support routines
118 */
119typedef void (*ExceptionHook)(int);   /* pointer to function with int parm */
120typedef void (*Function)(void);       /* pointer to a function */
121
122/* assign an exception handler */
123Function exceptionHandler(int vector,  Function handler);
124extern ExceptionHook exceptionHook;  /* hook variable for errors/exceptions */
125
126int putDebugChar(char ch);
127char getDebugChar(void);
128
129/************************/
130/* FORWARD DECLARATIONS */
131/************************/
132static int hex(char ch);
133static void getpacket(char *buffer);
134static void putpacket(char *buffer);
135static char* mem2hex(char *mem, char *buf, int count);
136static char* hex2mem(char *buf, char *mem, int count);
137static void handle_buserror(void);
138static int computeSignal(int exceptionVector);
139static int hexToInt(char **ptr, int *intValue);
140       void handle_exception(int exceptionVector);
141static void initializeRemcomErrorFrame(void);
142
143void set_debug_traps(void);
144void breakpoint(void);
145
146/************************************************************************/
147/* BUFMAX defines the maximum number of characters in inbound/outbound buffers*/
148/* at least NUMREGBYTES*2 are needed for register packets */
149#define BUFMAX 400
150
151static char initialized;  /* boolean flag. != 0 means we've been initialized */
152
153int remote_debug;
154/*  debug >  0 prints ill-formed commands in valid packets & checksum errors */
155
156static const char hexchars[]="0123456789abcdef";
157
158/* there are 180 bytes of registers on a 68020 w/68881      */
159/* many of the fpa registers are 12 byte (96 bit) registers */
160#define NUMREGBYTES 180
161enum regnames {D0,D1,D2,D3,D4,D5,D6,D7,
162               A0,A1,A2,A3,A4,A5,A6,A7,
163               PS,PC,
164               FP0,FP1,FP2,FP3,FP4,FP5,FP6,FP7,
165               FPCONTROL,FPSTATUS,FPIADDR
166              };
167
168
169/* We keep a whole frame cache here.  "Why?", I hear you cry, "doesn't
170   GDB handle that sort of thing?"  Well, yes, I believe the only
171   reason for this cache is to save and restore floating point state
172   (fsave/frestore).  A cleaner way to do this would be to make the
173 fsave data part of the registers which GDB deals with like any
174   other registers.  This should not be a performance problem if the
175   ability to read individual registers is added to the protocol.  */
176
177typedef struct FrameStruct
178{
179    struct FrameStruct  *previous;
180    int       exceptionPC;      /* pc value when this frame created */
181    int       exceptionVector;  /* cpu vector causing exception     */
182    short     frameSize;        /* size of cpu frame in words       */
183    short     sr;               /* for 68000, this not always sr    */
184    int       pc;
185    short     format;
186    int       fsaveHeader;
187    int       morejunk[0];        /* exception frame, fp save... */
188} Frame;
189
190#define FRAMESIZE 500
191int gdbFrameStack[FRAMESIZE];
192static Frame *lastFrame;
193
194/*
195 * these should not be static cuz they can be used outside this module
196 */
197int registers[NUMREGBYTES/4];
198int superStack;
199
200#define STACKSIZE 10000
201int remcomStack[STACKSIZE/sizeof(int)];
202static int* stackPtr = &remcomStack[STACKSIZE/sizeof(int) - 1];
203
204/*
205 * In many cases, the system will want to continue exception processing
206 * when a continue command is given. 
207 * oldExceptionHook is a function to invoke in this case.
208 */
209
210static ExceptionHook oldExceptionHook;
211
212#if defined(__mc68020__)
213/* the size of the exception stack on the 68020 varies with the type of
214 * exception.  The following table is the number of WORDS used
215 * for each exception format.
216 */
217const short exceptionSize[] = { 4,4,6,4,4,4,4,4,29,10,16,46,12,4,4,4 };
218#endif
219
220#if defined(__mc68332__)
221static const short exceptionSize[] = { 4,4,6,4,4,4,4,4,4,4,4,4,16,4,4,4 };
222#endif
223
224/************* jump buffer used for setjmp/longjmp **************************/
225jmp_buf remcomEnv;
226
227/***************************  ASSEMBLY CODE MACROS *************************/
228/*                                                                         */
229
230#if defined(__HAVE_68881__)
231
232/* do an fsave, then remember the address to begin a restore from */
233#define SAVE_FP_REGS() \
234       asm(" fsave   %a0@-");   \
235       asm(" fmovemx %fp0-%fp7,registers+72");  \
236       asm(" fmoveml %fpcr/%fpsr/%fpi,registers+168");
237
238#define RESTORE_FP_REGS() \
239asm("                                                 \n\
240    fmoveml  registers+168,%fpcr/%fpsr/%fpi           \n\
241    fmovemx  registers+72,%fp0-%fp7                   \n\
242    cmpl     #-1,%a0@     |  skip frestore flag set ? \n\
243    beq      skip_frestore                            \n\
244    frestore %a0@+                                    \n\
245skip_frestore:                                        \n\
246");
247
248#else
249
250#define SAVE_FP_REGS()
251#define RESTORE_FP_REGS()
252
253#endif /* __HAVE_68881__ */
254
255void return_to_super(void);
256void return_to_user(void);
257
258asm("
259       .text
260
261       .globl return_to_super
262       .align 4
263return_to_super:
264        movel   registers+60,%sp     /* get new stack pointer */       
265        movel   lastFrame,%a0        /* get last frame info  */             
266        bra     return_to_any
267
268        .globl return_to_user
269        .align 4
270
271return_to_user:
272        movel   registers+60,%a0     /* get usp */                         
273        movel   %a0,%usp             /* set usp */                             
274        movel   superStack,%sp       /* get original stack pointer */       
275
276return_to_any:
277        movel   lastFrame,%a0        /* get last frame info  */             
278        movel   %a0@+,lastFrame      /* link in previous frame     */       
279        addql   #8,%a0               /* skip over pc, vector#*/             
280        movew   %a0@+,%d0            /* get # of words in cpu frame */       
281        addw    %d0,%a0              /* point to end of data        */       
282        addw    %d0,%a0              /* point to end of data        */       
283        movel   %a0,%a1                                                   
284#                                                                       
285# copy the stack frame                                                 
286        subql   #1,%d0
287
288copyUserLoop:                                                               
289        movew   %a1@-,%sp@-                                               
290        dbf     %d0,copyUserLoop                                             
291");                                                                     
292        RESTORE_FP_REGS()                                             
293asm("
294        moveml  registers,%d0-%d7/%a0-%a6
295        rte                          /* pop and go! */
296");
297
298#define DISABLE_INTERRUPTS() asm("   oriw   #0x0700,%sr");
299#define BREAKPOINT()         asm("   trap   #1");
300
301/* this function is called immediately when a level 7 interrupt occurs */
302/* if the previous interrupt level was 7 then we're already servicing  */
303/* this interrupt and an rte is in order to return to the debugger.    */
304/* For the 68000, the offset for sr is 6 due to the jsr return address */
305asm("
306        .text
307        .globl _debug_level7
308        .align 4
309
310_debug_level7:
311        movew   %d0,%sp@-
312");
313
314#if defined(__mc68020__) || defined(__mc68332__)
315asm("
316        movew   %sp@(2),%d0
317");
318#else
319asm("
320        movew   %sp@(6),%d0
321");
322#endif
323asm("
324        andiw   #0x700,%d0
325          cmpiw   #0x700,%d0
326          beq     _already7
327        movew   %sp@+,%d0       
328        bra     _catchException
329_already7:
330              movew   %sp@+,%d0
331");
332#if defined (__m68000__) && !defined(__mc68020__)
333asm("
334        lea     %sp@(4),%sp");       /* pull off 68000 return address */
335#endif
336asm("
337        rte
338");
339
340extern void _catchException(void);
341
342#if defined(__mc68020__) || defined(__mc68332__)
343/* This function is called when a 68020 exception occurs.  It saves
344 * all the cpu and fpcp regs in the _registers array, creates a frame on a
345 * linked list of frames which has the cpu and fpcp stack frames needed
346 * to properly restore the context of these processors, and invokes
347 * an exception handler (remcom_handler).
348 *
349 * stack on entry:                       stack on exit:
350 *   N bytes of junk                     exception # MSWord
351 *   Exception Format Word               exception # MSWord
352 *   Program counter LSWord             
353 *   Program counter MSWord             
354 *   Status Register                   
355 *                                       
356 *                                       
357 */
358asm("
359        .text
360
361        .globl _catchException
362        .align 4
363_catchException:
364");
365
366DISABLE_INTERRUPTS();
367
368asm("
369        moveml  %d0-%d7/%a0-%a6,registers /* save registers        */
370        movel   lastFrame,%a0             /* last frame pointer */
371");
372SAVE_FP_REGS();       
373asm("
374        lea     registers,%a5   /* get address of registers     */
375        movew   %sp@,%d1        /* get status register          */
376        movew   %d1,%a5@(66)    /* save sr      */     
377        movel   %sp@(2),%a4     /* save pc in %a4 for later use  */
378        movel   %a4,%a5@(68)    /* save pc in _regisers[]       */
379
380#
381# figure out how many bytes in the stack frame
382#
383        movew   %sp@(6),%d0         /* get '020 exception format        */
384        movew   %d0,%d2         /* make a copy of format word   */
385        andiw   #0xf000,%d0     /* mask off format type         */
386        rolw    #5,%d0          /* rotate into the low byte *2  */
387        lea     exceptionSize,%a1   
388        addw    %d0,%a1         /* index into the table         */
389        movew   %a1@,%d0        /* get number of words in frame */
390        movew   %d0,%d3         /* save it                      */
391        subw    %d0,%a0         /* adjust save pointer          */
392        subw    %d0,%a0         /* adjust save pointer(bytes)   */
393        movel   %a0,%a1         /* copy save pointer            */
394        subql   #1,%d0          /* predecrement loop counter    */
395#
396# copy the frame
397#
398saveFrameLoop:
399              movew   %sp@+,%a1@+
400        dbf     %d0,saveFrameLoop
401#
402# now that the stack has been clenaed,
403# save the %a7 in use at time of exception
404
405        movel   %sp,superStack  /* save supervisor %sp           */
406        andiw   #0x2000,%d1     /* were we in supervisor mode ? */
407        beq     userMode       
408        movel   %a7,%a5@(60)    /* save %a7                  */
409        bra     a7saveDone
410userMode: 
411        movel   %usp,%a1       
412        movel   %a1,%a5@(60)    /* save user stack pointer      */
413a7saveDone:
414
415#
416# save size of frame
417        movew   %d3,%a0@-
418
419#
420# compute exception number
421        andl    #0xfff,%d2        /* mask off vector offset     */
422        lsrw    #2,%d2                /* divide by 4 to get vect num    */
423        movel   %d2,%a0@-       /* save it                      */
424#
425# save pc causing exception
426        movel   %a4,%a0@-
427#
428# save old frame link and set the new value
429        movel   lastFrame,%a1       /* last frame pointer */
430        movel   %a1,%a0@-                   /* save pointer to prev frame       */
431        movel   %a0,lastFrame
432
433        movel   %d2,%sp@-                   /* push exception num           */
434        movel   exceptionHook,%a0  /* get address of handler */
435        jbsr    %a0@            /* and call it */
436        clrl    %sp@            /* replace exception num parm with frame ptr */
437        jbsr     _returnFromException   /* jbsr, but never returns */
438
439");
440
441#else /* mc68000 */
442
443/* This function is called when an exception occurs.  It translates the
444 * return address found on the stack into an exception vector # which
445 * is then handled by either handle_exception or a system handler.
446 * _catchException provides a front end for both. 
447 *
448 * stack on entry:                       stack on exit:
449 *   Program counter MSWord              exception # MSWord
450 *   Program counter LSWord              exception # MSWord
451 *   Status Register                     
452 *   Return Address  MSWord             
453 *   Return Address  LSWord             
454 */
455asm("
456        .text
457        .globl _catchException
458        .align 4
459_catchException:
460");
461DISABLE_INTERRUPTS();
462asm("
463        moveml  %d0-%d7/%a0-%a6,registers  /* save registers               */
464        movel   lastFrame,%a0   /* last frame pointer */
465");
466
467SAVE_FP_REGS();       
468asm("
469        moveq.l #0,%d2
470        movew   %sp@+,%d2
471        lea     registers,%a5    /* get address of registers     */
472
473        moveql  #3,%d3           /* assume a three word frame     */
474
475        cmpiw   #3,%d2           /* bus error or address error ? */
476        bgt     normal           /* if >3 then normal error      */
477        movel   %sp@+,%a0@-      /* copy error info to frame buff*/
478        movel   %sp@+,%a0@-      /* these are never used         */
479        moveql  #7,%d3           /* this is a 7 word frame       */
480     
481normal:   
482        movew   %sp@+,%d1         /* pop status register          */
483        movel   %sp@+,%a4         /* pop program counter          */
484
485        cmpiw   #33,%d2           /* trap #1, breakpoint ? */
486        bne     not_breakpoint
487
488        subql   #2,%a4            /* trap leaves the pc after the trap */
489
490not_breakpoint:
491        movew   %d1,%a5@(66)      /* save sr                    */     
492        movel   %a4,%a5@(68)      /* save pc in _regisers[]             */
493        movel   %a4,%a0@-         /* copy pc to frame buffer      */
494        movew   %d1,%a0@-         /* copy sr to frame buffer      */
495
496        movel   %sp,superStack    /* save supervisor %sp          */
497
498        andiw   #0x2000,%d1      /* were we in supervisor mode ? */
499        beq     userMode       
500        movel   %a7,%a5@(60)      /* save %a7                  */
501        bra     saveDone             
502userMode:
503        movel   %usp,%a1        /* save user stack pointer      */
504        movel   %a1,%a5@(60)      /* save user stack pointer    */
505saveDone:
506
507        movew   %d3,%a0@-         /* push frame size in words     */
508        movel   %d2,%a0@-         /* push vector number           */
509        movel   %a4,%a0@-         /* push exception pc            */
510
511#
512# save old frame link and set the new value
513#
514        movel   lastFrame,%a1   /* last frame pointer */
515        movel   %a1,%a0@-               /* save pointer to prev frame   */
516        movel   %a0,lastFrame
517
518        movel   %d2,%sp@-               /* push exception num           */
519        movel   exceptionHook,%a0  /* get address of handler */
520
521        jbsr    %a0@             /* and call it */
522        clrl    %sp@             /* replace exception num parm with frame ptr */
523        jbsr     _returnFromException   /* jbsr, but never returns */
524");
525#endif
526
527
528/*
529 * remcomHandler is a front end for handle_exception.  It moves the
530 * stack pointer into an area reserved for debugger use in case the
531 * breakpoint happened in supervisor mode.
532 */
533asm("remcomHandler:");
534asm("           addl    #4,%sp");        /* pop off return address     */
535asm("           movel   %sp@+,%d0");      /* get the exception number   */
536asm("           movel   stackPtr,%sp"); /* move to remcom stack area  */
537asm("           movel   %d0,%sp@-");    /* push exception onto stack  */
538asm("           jbsr    handle_exception");    /* this never returns */
539asm("           rts");                  /* return */
540
541void _returnFromException(Frame *frame)
542{
543  /* if no passed in frame, use the last one */
544  if (! frame)
545  {
546    frame = lastFrame;
547    frame->frameSize = 4;
548    frame->format = 0;
549    frame->fsaveHeader = -1; /* restore regs, but we dont have fsave info*/
550  }
551
552#if defined(__m68000__) && !defined(__mc68020__)
553  /* a 68000 cannot use the internal info pushed onto a bus error
554   * or address error frame when doing an RTE so don't put this info
555   * onto the stack or the stack will creep every time this happens.
556   */
557  frame->frameSize=3;
558#endif
559
560  /* throw away any frames in the list after this frame */
561  lastFrame = frame;
562
563  frame->sr = registers[(int) PS];
564  frame->pc = registers[(int) PC];
565
566  if (registers[(int) PS] & 0x2000)
567  {
568    /* return to supervisor mode... */
569    return_to_super();
570  }
571  else
572  { /* return to user mode */
573    return_to_user();
574  }
575}
576
577int hex(char ch)
578{
579  if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
580  if ((ch >= '0') && (ch <= '9')) return (ch-'0');
581  if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
582  return (-1);
583}
584
585/* scan for the sequence $<data>#<checksum>     */
586void getpacket(char *buffer)
587{
588  unsigned char checksum;
589  unsigned char xmitcsum;
590  int  i;
591  int  count;
592  char ch;
593 
594  do {
595    /* wait around for the start character, ignore all other characters */
596    while ((ch = (getDebugChar() & 0x7f)) != '$');
597    checksum = 0;
598    xmitcsum = -1;
599   
600    count = 0;
601   
602    /* now, read until a # or end of buffer is found */
603    while (count < BUFMAX) {
604      ch = getDebugChar() & 0x7f;
605      if (ch == '#') break;
606      checksum = checksum + ch;
607      buffer[count] = ch;
608      count = count + 1;
609    }
610    buffer[count] = 0;
611
612    if (ch == '#') {
613      xmitcsum = hex(getDebugChar() & 0x7f) << 4;
614      xmitcsum += hex(getDebugChar() & 0x7f);
615      if ((remote_debug ) && (checksum != xmitcsum)) {
616        debug_port_printf ("bad checksum.  My count = 0x%x, sent=0x%x. buf=%s\n",
617                           checksum,xmitcsum,buffer);
618      }
619     
620      if (checksum != xmitcsum) putDebugChar('-');  /* failed checksum */
621      else {
622        putDebugChar('+');  /* successful transfer */
623        /* if a sequence char is present, reply the sequence ID */
624        if (buffer[2] == ':') {
625          putDebugChar( buffer[0] );
626          putDebugChar( buffer[1] );
627          /* remove sequence chars from buffer */
628          count = strlen(buffer);
629          for (i=3; i <= count; i++) buffer[i-3] = buffer[i];
630        }
631      }
632    }
633  } while (checksum != xmitcsum); 
634}
635
636/* send the packet in buffer.  The host get's one chance to read it. 
637   This routine does not wait for a positive acknowledge.  */
638
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
1027
1028void initializeRemcomErrorFrame()
1029{
1030    lastFrame = ((Frame *) &gdbFrameStack[FRAMESIZE-1]) - 1;
1031    lastFrame->previous = lastFrame;
1032}
1033
1034/* this function is used to set up exception handlers for tracing and
1035   breakpoints */
1036void set_debug_traps()
1037{
1038  extern void _debug_level7(void);
1039  extern void remcomHandler(void);
1040 
1041  int exception;
1042
1043  initializeRemcomErrorFrame();
1044  stackPtr  = &remcomStack[STACKSIZE/sizeof(int) - 1];
1045
1046  registers[ PC ] = 0x400;
1047  registers[ PS ] = 0x2700;
1048 
1049  for (exception = 2; exception <= 30; exception++)
1050      exceptionHandler(exception,_catchException);   
1051
1052  /* level 7 interrupt              */
1053  exceptionHandler(31,_debug_level7);   
1054 
1055  for (exception = 32; exception <= 47; exception++)
1056    exceptionHandler(exception,_catchException);   
1057
1058  /* exclude the unassigned, reserved vector locations */
1059 
1060  for (exception = 64; exception <= 255; exception++)
1061    exceptionHandler(exception,_catchException);   
1062
1063  if (oldExceptionHook != (ExceptionHook) remcomHandler)
1064  {
1065      oldExceptionHook = exceptionHook;
1066      exceptionHook    = (ExceptionHook) remcomHandler;
1067  }
1068 
1069  initialized = 1;
1070
1071#if defined(UPDATE_DISPLAY) 
1072  UPDATE_DISPLAY("gdb ");
1073#endif 
1074}
1075
1076/* This function will generate a breakpoint exception.  It is used at the
1077   beginning of a program to sync up with a debugger and can be used
1078   otherwise as a quick means to stop program execution and "break" into
1079   the debugger. */
1080   
1081void breakpoint()
1082{
1083  if (initialized) BREAKPOINT();
1084}
Note: See TracBrowser for help on using the repository browser.