aboutsummaryrefslogtreecommitdiff
path: root/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
blob: 3bcf35a311a87aa0557ee06389d2a0f3bed548f0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
/** @file debug_runlooptasks.S
 *  @brief GDB Server platform Run Loop
 *
 */

/* Copyright (C) 2007-2011 the NxOS developers
 *
 * Module Developed by: TC Wan <tcwan@cs.usm.my>
 *
 * See AUTHORS for a full list of the developers.
 *
 * See COPYING for redistribution license
 *
 */

/*
 * This file contains platform specific code.
 * This include ABORT Mode Debugger Run Loop operation,
 * as well as Debugger Interfacing code to the platform code.
 */

/*
 * The Debugger has to implement a Run Loop in ABORT mode
 * since the hardware is still running. Consequently,
 * the communications subsystems such as USB (and Bluetooth?)
 * which is used to communicate with the Host needs to be
 * serviced in order for actual data transmission and reception
 * to take place. Currently we're reusing the platform's
 * communication routines to do the actual tx/rx, so it means
 * that it is not possible to set breakpoints in those modules.
 * In addition, since the platform communication modules may
 * handle other tasks, it is currently possible to enter an
 * indeterminate state where certain communication messages trigger
 * a platform response which cannot be handled by the Debugger Run Loop.
 * The alternative is to implement our own communications routines, but
 * that will take even more code.
 *
 * FIXME: It may become necessary to hack the platform communications
 * routines to detect that we're in the Debugger Run Loop and not the
 * normal run loop to avoid system crashes, but the current goal is to
 * have as minimal changes to the platform code as possible.
 *
 * Since there are two Run Loops for the platform, the way in which
 * they interact is as follows:
 *
 * [Platform Run Loop]  - DBG_INIT/ GDB Cmd/ BKPT ->  [Debugger Run Loop]
 *                    \ <------ GO/ STEP/ CONT ----- /
 *        ...                                                 ...
 *        ...                                         Handle GDB Cmd/Resp
 *        ...                                                 ...
 *   {normal runloop                                  {communications /
 *    processing}                                      watchdog routines}
 * ^-------v                                                      v-------^
 *
 * The Platform will invoke dbg__bkpt_init() after hardware and system initialization,
 * before entering the Platform Run Loop. This configures the Debugger, but does not
 * invoke the Debugger Run Loop unless a Manual Breakpoint is found in the platform code.
 *
 * Subsequently, the Debugger Run Loop will be triggered by Breakpoints, or
 * when the communications subsystem receives a GDB Command.
 *
 * The Debugger Run Loop is actually dbg__bkpt_waitCMD(), this file contains
 * the Run Loop Tasks which needs to be invoked periodically by the Run Loop,
 * to minimize the coupling between the ARMDEBUG modules and the Platform.
 *
 * Note: The Debugger Run Loop does not handle Hardware Shutdown, it is
 * assumed that we wouldn't need to do so in Debug Mode.
 *
 */
#define __ASSEMBLY__

#define REBOOT_POWERDOWN
#include "debug_runlooptasks.h"

#include "debug_internals.h"
#include "debug_macros.h"
#include "debug_stub.h"

	.code 32
	.align 4
    .global dbg__runloopTasks
	.global	dbg__reboot
	.global dbg__display_abort_info
 	.global dbg__sendCommMsg

#ifdef __NXOS__
/****************************************************************************
 *
 * NxOS Run Loop
 *
 ****************************************************************************/
dbg__runloopTasks:
/* Currently, there's nothing that needs to be done in the NxOS Run Loop */
	push	{lr}
	mov		r0, #1				/* 1 ms delay */
	bl		nx_systick_wait_ms
    pop		{pc}

#else
/****************************************************************************
 *
 * NXT Firmware Run Loop
 *
 ****************************************************************************/
dbg__runloopTasks:
    push    {lr}
    /* FIXME: Add necessary cXXXCtrl calls here */
    bl      cCommCtrl
    /* OSWatchdogWrite is a NULL function in the NXT Firmware?! */
    pop     {pc}
#endif

#ifdef __NXOS__
/****************************************************************************
 *
 * NxOS Reboot Routine
 *
 ****************************************************************************/
 dbg__reboot:
#ifdef REBOOT_POWERDOWN
	b	    nx_core_halt		/* Shutdown Brick, won't return */
#else
	b	    nx_core_reset		/* Reboot Brick, won't return */
#endif

#else
/****************************************************************************
 *
 * NXT Firmware Reboot Routine
 *
 ****************************************************************************/
dbg__reboot:
	/* Powerdown Sequence
      	dIOCtrlSetPower((POWERDOWN>>8));
		dIOCtrlTransfer();

	   Reboot Sequence
      	dIOCtrlSetPower((UBYTE)(BOOT>>8));
      	dIOCtrlSetPwm((UBYTE)BOOT);
  		dIOCtrlTransfer();
	*/

	/* We implement the powerdown sequence for now */

#ifdef REBOOT_POWERDOWN
	/* Powerdown sequence */
	ldr		r0, =((POWERDOWN >> 8) & 0xFF)
	ldr		r1, =dIOCtrlSetPower
	mov		lr,pc
	bx		r1
#else
	/* Reboot sequence: this forces SAMBA mode??!! */
	ldr		r0, =((BOOT >> 8) & 0xFF)
	ldr		r1, =dIOCtrlSetPower
	mov		lr,pc
	bx		r1

	ldr		r0, =(BOOT & 0xFF)
	ldr		r1, =dIOCtrlSetPwm
	mov		lr,pc
	bx		r1
#endif

_dbg__reboot_wait:
	ldr		r1, =dIOCtrlTransfer
	mov		lr,pc
	bx		r1

	b		_dbg__reboot_wait						/* Wait for AVR... */
#endif

#ifdef __NXOS__
/****************************************************************************
 *
 * NxOS Abort Info LCD Display Routine
 *
 ****************************************************************************/
/*		On entry:
 *			r0: abort type
 *		On exit:
 *			r0-r3: destroyed
 */
dbg__display_abort_info:
	push	{lr}
    _getdbgregister DBGSTACK_USERPC_INDEX, r1           /* Retrieve User PC into R2 */
    _getdbgregister DBGSTACK_USERCPSR_INDEX, r2         /* Retrieve User CPSR into R2 */
	bl		nx__abort_info		/* void nx__abort_info(U32 data, U32 pc, U32 cpsr); */
    pop		{pc}

#else
/****************************************************************************
 *
 * NXT Firmware Abort Info LCD Display Routine
 *
 ****************************************************************************/
dbg__display_abort_info:
/* FIXME: Inteface with NXT Firmware LCD Display routines */
    push    {lr}
    pop     {pc}
#endif

#ifdef __NXOS__
	.extern debug_OutCommBuf
/****************************************************************************
 *
 * NxOS Communications Driver Interface Routine
 *
 ****************************************************************************/
/* dbg__sendCommMsg
 *      Internal send routine (interfaces with drivers).
 *      On entry:
 *          R0: Total Message Buffer length
 *      On exit:
 *           R0: Tx Status (TRUE if data sent)
 *			 R1-R3: Destroyed
 */
dbg__sendCommMsg:
    stmfd   sp!, {r4, lr}
    mov     r4, r0                              /* Keep Comm Buffer length in R4 */
    /* Check USB bus status, transmit message if possible */
    bl      nx_usb_is_connected                 /* R0 = TRUE (#1) if USB is ready */
    teq     r0, #0								/* FALSE == #0;
    											   We can't check for True condition since values
    											   used by C-Compiler & ARMDEBUG are different */
    beq     dbg__sendCommMsgFailed

    /* Actual transmission (blocking) */
    ldr     r0, =debug_OutCommBuf                /* data pointer parameter */
    mov     r1, r4                              /* Comm buffer length */
    bl      nx_usb_write

1: 	bl      nx_usb_data_written                 /* R0 = True if data has been sent */
    teq     r0, #0								/* FALSE == #0;
    											   We can't check for True condition since values
    											   used by C-Compiler & ARMDEBUG are different */
    /* FIXME: implement timeout */
    beq     1b                                  /* Busy Wait Loop */

    mov     r0, #TRUE
    b		exit_dbg__sendCommMsg
dbg__sendCommMsgFailed:
    mov     r0, #FALSE

exit_dbg__sendCommMsg:
    ldmfd   sp!, {r4, pc}


#else
/****************************************************************************
 *
 * NXT Firmware Communications Driver Interface Routine
 *
 ****************************************************************************/
/* dbg__sendCommMsg
 *      Internal send routine (interfaces with drivers).
 *      On entry:
 *          R0: Total Message Buffer length
 *      On exit:
            R0: Tx Status (TRUE if data sent)
 */
dbg__sendCommMsg:
    stmfd   sp!, {r4, lr}
    mov     r4, r0                              /* Keep Comm Buffer length in R4 */
    ldr     r0, =debug_nxtCommChannel
    ldr     r0, [r0]                            /* Get Channel Enum */
    teq     r0, #BT_CMD_READY
    beq     dbg__sendBTMsg
    teq     r0, #USB_CMD_READY
    beq     dbg__sendUSBMsg
    b       dbg__sendCommMsgFailed                 /* Channel Enum Doesn't Match, shouldn't happen? */

dbg__sendBTMsg:
    /* NXT BT routines do not have any configuration checks */
    ldr     r0, =debug_OutCommBuf                /* data pointer parameter */
    mov     r1, r4                              /* BT Bytes to Send */
    mov     r2, r4                              /* BT Message Size */
    bl      dBtSendMsg                          /* Send it via Bluetooth (complete message) */
    mov     r0, #TRUE                           /* Always flag Success */
    b       exit_dbg__sendCommMsg

dbg__sendUSBMsg:
    /* Check USB bus status, transmit message if possible */
    bl      dUsbIsConfigured                    /* R0: UByte status, TRUE / FALSE */
    teq     r0, #nxt_UBYTE_TRUE
    bne     dbg__sendCommMsgFailed

    /* Actual transmission (blocking) */
    ldr     r0, =debug_OutCommBuf                /* data pointer parameter */
    mov     r1, r4                              /* Comm buffer length */
    bl      dUsbWrite                           /* call NXT Firmware USB driver, return 0: done, !0: remaining chars */
    teq     r0, #0                              /* Tx done if returned length is 0 */
    moveq   r0, #TRUE                           /* Convert NXT firmware return value to our Status (TRUE/FALSE) */
    beq     exit_dbg__sendCommMsg
dbg__sendCommMsgFailed:
    mov     r0, #FALSE

exit_dbg__sendCommMsg:
    ldmfd   sp!, {r4, pc}
#endif


#ifdef __NXOS__
/****************************************************************************
 *
 * GDB Debugger Invocation Routine for NxOS
 *
 ****************************************************************************/
	.code 32
	.align 4

	.extern dbg__install_singlestep
	.extern dbg__activate_singlestep
	.extern irq_stack_frame_address
	.global nxos__handleDebug
/* nxos__handleDebug
 * 		Prepare to switch to Debug Mode
 * int nxos__handleDebug(U8 *buffer, comm_chan_t channel, U32 length);
 *
 * This routine is called from NxOS Fantom library to setup
 * Single Step Breakpoint in preparation for Debugger invocation if we're in
 * normal execution mode.
 *
 * It returns to complete the IRQ handling normally, after which the single
 * step breakpoint will be triggered, and the incoming GDB message will then
 * be processed in the dbg__bkpt_waitCMD() loop.
 *
 * If we're in Debugger Mode already, then just return and let the
 * dbg__bkpt_waitCMD() loop handle it normally.
 *
 * If we're operating in normal NxOS mode, return True (!0)
 * If we're already in Debugger Mode, return False (0)
 */
nxos__handleDebug:
		push {lr}
		/* This routine is called from nx__irq_handler() via fantom_filter_packet().
		 * The operating mode should already have been configured by the IRQ interrupt handler.
		 *
		 * The IRQ Stack Frame Pointer will contains the LR and SPSR from the topmost interrupted task
		 * if it is non-zero (NxOS supports nested IRQs)
		 */
        bl    dbg__copyNxtDebugMsg  	/* Copy to Debugger Message Buffer, Remember Comm Channel */
 		mov		r0, #FALSE				/* Setup Default Return value (False) */
        _dbg_getmode r1             	/* Get Debug Mode */
        cmp   r1, #(TRUE & BYTE0)		/* Confine it to Byte size */
        /* If Debug Mode is TRUE, this means that we're already running the Debugger */
 		beq		exit_nxos__handleDebug	/* Yes, return False */

		/* Retrieve ISR Return Address */
        ldr     r3, =irq_stack_frame_address
        ldr		r3, [r3]				/* Get Interrupt Stack Pointer */
        teq		r3, #0
        beq		exit_nxos__handleDebug	/* NULL Interrupt Stack Frame Pointer, exit (status: False) */

nxos_switch2debug:
		/* Since the Interrupt Stack Frame Pointer points to the top of the stack frame,
		 * we'll have to use Load Empty Ascending Stack (LDMEA == LDMDB) to access the variables
		 */
        ldmdb   r3, {r1,r2}				/* R1: LR, R2: SPSR */
 		tst		r2, #CPSR_THUMB			/* Check for Thumb Mode */
 		orrne	r1, r1, #1				/* Configure for Thumb Single Step Breakpoint */
	    bl  	dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */
		bl		dbg__activate_singlestep
		mov	    r0, #TRUE				/* We're going to switch to Debug Mode (via Single Step Breakpoint) */

exit_nxos__handleDebug:
		pop	  {r1}
    	bx    r1						/* In case we have Interworking from different caller mode */

#else

/****************************************************************************
 *
 * GDB Debugger Invocation Routine for NXT Firmware
 *
 ****************************************************************************/
    .code 16
    .align 2

    .extern dbg__copyNxtDebugMsg
    .global cCommHandleDebug
    .thumb_func
/* cCommHandleDebug
 * Switch Mode to Debugger.
 *      Used by NXT Firmware only
 *
 * UWORD cCommHandleDebug(UBYTE *pInBuf, UBYTE CmdBit, UWORD MsgLength);
 *
 * This routine is called from cCommInterprete either in normal operation mode (SVC)
 * or else when we're in debug mode (ABORT) which uses the cCommCtrl() routine to handle
 * I/O with the Host.
 *
 * On entry, the message is copied from the NXT buffer into our own buffers.
 *
 * If this is accessed from normal operation mode, we need to switch mode to
 * ABORT mode to handle the incoming message using a Manual Breakpoint instruction.
 * When DEBUG is exited, the execution resumes from the instruction following the Breakpoint.
 */
cCommHandleDebug:
/* Arg Registers are not preserved since this is invoked explicitly */
        push  {lr}                      /* store arg registers */
        bl    dbg__copyNxtDebugMsg  	/* Copy to Debugger Message Buffer, Remember Comm Channel */
        _dbg_getmode r0             	/* Get Debug Mode */
        cmp   r0, #(TRUE & BYTE0)		/* Confine it to Byte size */

        /* If Debug Mode is TRUE, this means that we're already running the Debugger */
		beq	  _cCommHandleDebug_cont
        /* Else, we're in normal operation mode (SVC), or other mode (??!) and need to force a switch to Debug mode */
        dbg__bkpt_thumb
_cCommHandleDebug_cont:
        mov   r0, #0                   /* FIXME: Return Status */
        pop	  {r1}					   /* Can't Pop LR directly */
        bx    r1					   /* Safe code: actually we should be able to Pop PC since the caller is Thumb Mode */

        .ltorg
#endif