aboutsummaryrefslogtreecommitdiff
path: root/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
diff options
context:
space:
mode:
authorTat-Chee Wan2012-02-03 23:57:04 +0100
committerNicolas Schodet2012-02-11 17:30:42 +0100
commitd50dd5ab9567cc308e412c5e9e775dc8e15fb509 (patch)
treeb7d30c1025fb34e65a04d15701c53ee2ca071dec /AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
parentceb0cbf65a11aed7662eb41ae66157e60ff61d60 (diff)
merge armdebug rc1
This enables the use of GDB or GDB based debuggers to debug the code running on the NXT brick using the USB connection.
Diffstat (limited to 'AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S')
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S415
1 files changed, 415 insertions, 0 deletions
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
new file mode 100644
index 0000000..3bcf35a
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
@@ -0,0 +1,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