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