OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [gdb/] [m68k-stub.c] - Blame information for rev 1782

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.