summaryrefslogtreecommitdiff
path: root/AT91SAM7S256/armdebug
diff options
context:
space:
mode:
Diffstat (limited to 'AT91SAM7S256/armdebug')
-rw-r--r--AT91SAM7S256/armdebug/.gitignore41
-rw-r--r--AT91SAM7S256/armdebug/.project11
-rw-r--r--AT91SAM7S256/armdebug/AUTHORS6
-rw-r--r--AT91SAM7S256/armdebug/COPYING9
-rw-r--r--AT91SAM7S256/armdebug/Debugger/_c_arm_macros.h88
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_comm.S615
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_comm.h53
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_hexutils.S457
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_internals.h303
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_macros.h386
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S288
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_stack.ld15
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_stub.S2976
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_stub.h151
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_test.S53
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_test.h35
-rw-r--r--AT91SAM7S256/armdebug/Debugger/undef_handler.S147
-rw-r--r--AT91SAM7S256/armdebug/Doxyfile243
-rw-r--r--AT91SAM7S256/armdebug/GNU-GPLv2.txt340
-rw-r--r--AT91SAM7S256/armdebug/Host/README21
-rw-r--r--AT91SAM7S256/armdebug/Host/gdb-commands.txt43
-rwxr-xr-xAT91SAM7S256/armdebug/Host/nxt-gdb-server.py208
-rwxr-xr-xAT91SAM7S256/armdebug/Host/pyenv-nxt-gdb-server3
-rw-r--r--AT91SAM7S256/armdebug/LEGO_Open_Source_License.docbin0 -> 40960 bytes
-rw-r--r--AT91SAM7S256/armdebug/README16
-rw-r--r--AT91SAM7S256/armdebug/SConscript13
-rw-r--r--AT91SAM7S256/armdebug/SConstruct182
27 files changed, 6703 insertions, 0 deletions
diff --git a/AT91SAM7S256/armdebug/.gitignore b/AT91SAM7S256/armdebug/.gitignore
new file mode 100644
index 0000000..46f8223
--- /dev/null
+++ b/AT91SAM7S256/armdebug/.gitignore
@@ -0,0 +1,41 @@
+# Ignore tag
+MASTER-REPO_DO-NOT-DELETE
+*.lst
+*.objdump
+.DS_Store
+
+# Generally annoying things.
+*.[oa]
+*.pyc
+*.bin
+*.elf
+*.rxe
+*.map
+*.orig
+*.log
+*~
+*.swp
+\#*\#
+.\#*
+
+# Python distutils creates this when building.
+pynxt/build/
+
+# XCode build stuff
+FantomModule/build/
+*mode1v3
+*pbxuser
+
+# SCons cruft
+.sconsign.dblite
+.sconf_temp
+build_flags.py
+
+# Precommit hooks drop a commit.msg file if they fail.
+commit.msg
+
+# The option-cache
+scons.options
+
+# pyfantom related
+pyfantom.py
diff --git a/AT91SAM7S256/armdebug/.project b/AT91SAM7S256/armdebug/.project
new file mode 100644
index 0000000..15b12fc
--- /dev/null
+++ b/AT91SAM7S256/armdebug/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>armdebug</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/AT91SAM7S256/armdebug/AUTHORS b/AT91SAM7S256/armdebug/AUTHORS
new file mode 100644
index 0000000..169c2b6
--- /dev/null
+++ b/AT91SAM7S256/armdebug/AUTHORS
@@ -0,0 +1,6 @@
+The following people have contributed code, in various quantities, to armdebug.
+A big thanks to all of them, armdebug is what it is in part thanks to each of
+them. In alphabetical order:
+
+Nicolas Schodet <nico (at) ni.fr.eu.org>
+Tat Chee Wan <tcwan (at) cs.usm.my>
diff --git a/AT91SAM7S256/armdebug/COPYING b/AT91SAM7S256/armdebug/COPYING
new file mode 100644
index 0000000..86fae60
--- /dev/null
+++ b/AT91SAM7S256/armdebug/COPYING
@@ -0,0 +1,9 @@
+The armdebug project is dual licensed.
+
+You can either use the GNU GPLv2 license in GNU-GPLv2.txt,
+or else the "LEGO Open Source License" in LEGO_Open_Source_License.doc
+to redistribute the code.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/AT91SAM7S256/armdebug/Debugger/_c_arm_macros.h b/AT91SAM7S256/armdebug/Debugger/_c_arm_macros.h
new file mode 100644
index 0000000..025542e
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/_c_arm_macros.h
@@ -0,0 +1,88 @@
+/** @file _c_arm_macros.h
+ * @brief Define macros to support shared C and ASM headers
+ *
+ */
+
+/* Copyright (C) 2010 the NxOS developers
+ *
+ * Module Developed by: TC Wan <tcwan@cs.usm.my>
+ *
+ * Thanks to Bartli (forum post @ embdev.net ARM programming with GCC/GNU tools forum)
+ *
+ * See AUTHORS for a full list of the developers.
+ *
+ * See COPYING for redistribution license
+ *
+ */
+
+#ifndef __C_ARM_MACROS__
+#define __C_ARM_MACROS__
+
+
+#ifdef __ASSEMBLY__
+
+#define NULL 0x0
+#define FALSE 0
+#define TRUE ~FALSE
+
+#define TYPEDEF @
+#define FUNCDEF @
+
+ .set last_enum_value, 0
+ .macro enum_val name
+ .equiv \name, last_enum_value
+ .set last_enum_value, last_enum_value + 1
+ .endm
+
+#define ENUM_BEGIN .set last_enum_value, 0
+
+#define ENUM_VAL(name) enum_val name
+#define ENUM_VALASSIGN(name, value) \
+ .set last_enum_value, value ;\
+ enum_val name
+#define ENUM_END(enum_name)
+
+#else /* C Defines */
+/** Macro to control typedef generation
+ *
+ */
+#define TYPEDEF typedef
+
+/** Macro to control extern generation
+ *
+ */
+#ifndef FUNCDEF
+#define FUNCDEF extern
+#endif
+
+/** Macro to control typedef enum generation
+ *
+ */
+#define ENUM_BEGIN typedef enum {
+
+/** Macro to specify enum instance (auto value assignment)
+ *
+ */
+#define ENUM_VAL(name) name,
+
+/** Macro to control enum specification and value assignment
+*
+*/
+#define ENUM_VALASSIGN(name, value) name = value,
+
+/** Macro to control enum named type generation
+ *
+ */
+#define ENUM_END(enum_name) } enum_name;
+
+#endif
+
+/* Example of how to use the ENUM definition macros
+ENUM_BEGIN
+ENUM_VAL(INIT)
+ENUM_VAL(RESET)
+ENUM_VAL(CONFIGURED)
+ENUM_END(enum_label)
+*/
+
+#endif /* __C_ARM_MACROS__ */
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_comm.S b/AT91SAM7S256/armdebug/Debugger/debug_comm.S
new file mode 100644
index 0000000..570fedc
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_comm.S
@@ -0,0 +1,615 @@
+/** @file debug_comm.S
+ * @brief GDB Server communications support routines
+ *
+ */
+
+/* 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
+ *
+ */
+
+
+/* #define __NXOS__ */ /* Defined externally in SConstruct */
+
+#define __ASSEMBLY__
+#include "debug_macros.h"
+#include "debug_stub.h"
+#include "debug_internals.h"
+#include "debug_comm.h"
+
+ /* Hexutils function references */
+ .extern hex2char
+ .extern char2hex
+ .extern byte2ascii
+ .extern halfword2ascii_be
+ .extern halfword2ascii_le
+ .extern word2ascii_be
+ .extern word2ascii_le
+ .extern ascii2hex_varlen_be
+ .extern ascii2byte
+ .extern ascii2halfword_be
+ .extern ascii2halfword_le
+ .extern ascii2word_be
+ .extern ascii2word_le
+
+
+.bss
+.align 4
+
+debug_InCommBuf:
+ .space USB_BUFSIZE,0
+debug_OutCommBuf:
+ .space USB_BUFSIZE,0
+
+debug_msgRxBufPtr:
+ .word 0x0
+debug_msgTxBufPtr:
+ .word 0x0
+
+debug_msgRxBuf_AppendPtr:
+ .word 0x0
+debug_msgTxBuf_AppendPtr:
+ .word 0x0
+
+ .equ RXAPPENDPTR_OFFSET, (debug_msgRxBuf_AppendPtr - debug_msgRxBufPtr)
+ .equ TXAPPENDPTR_OFFSET, (debug_msgTxBuf_AppendPtr - debug_msgTxBufPtr)
+
+debug_segmentRxNum: /* Current Rx Segment Number */
+ .word 0x0
+
+debug_nxtMsgLength: /* NXT Firmware Received Message Length */
+ .word 0x0
+
+/* Comm Channel is now common to both NxOS and NXT Firmware */
+ .global debug_nxtCommChannel
+debug_nxtCommChannel:
+ .word 0x0
+
+ .equ NXTCOMMCHANNEL_OFFSET, (debug_nxtCommChannel - debug_nxtMsgLength)
+
+.data
+.align 4
+
+nxt_commcmd_header:
+ .byte NXT_GDBMSG_TELEGRAMTYPE, 0x00, 0x00 /* padded to 3 bytes */
+
+.code 32
+.text
+.align 4
+/* Debugger Communications Routines
+ * It does not make sense to pass information from the Debugger Module to the Comm. link one character
+ * at a time, especially if we're not using a native serial interface (e.g., EIA-232). Consequently
+ * a Message interface has been defined. This can still call getChar() and putChar() subroutines
+ * if so desired, but it'll be a purely internal matter.
+ *
+ * Message Format
+ * Since we need to use EP1&2 (Bulk channels) to communicate with the PC Host, the messages should
+ * follow the NXT Direct Commands message structure (this will allow for interoperability with NXT Firmware
+ * in addition to NxOS). The maximum length of any USB communications via the Bulk channel is 64 bytes.
+ * There is a one byte Telegram Type field which identifies the type of telegram, followed by the
+ * Telegram header and actual message.
+ *
+ * The LEGO Mindstorms Communications Protocol Direct Commands GDB Message format (including all headers)
+ * is as follows:
+ *
+ * GDB Command
+ * ===========
+ * Byte 0: Telegram Type Field (0x8d Direct Command, No response required) | NXT Msg Header
+ * Byte 1: Segment No (1-255, 0: Last Segment; limit is MSG_NUMSEGMENTS) |
+ * Byte 2: Telegram Size (Len of USB Buffer - 3, max is MSG_SEGMENTSIZE) |
+ * Byte 3-N: Message data | GDB Command
+ *
+ * The GDB Command (of size M) has the following format:
+ * Offset 0: '+'/'-' Command Received Status (Optional)
+ * Offset 1/0: '$'
+ * Offset 2/1: GDB Command char
+ * Offset 3 - (M-4): Command packet info
+ * Offset M-3: '#'
+ * Offset M-2: MSB of Checksum
+ * Offset M-1: LSB of Checksum
+ *
+ * To be safe, we assume that the Command Received Status is always sent by the GDB server. Therefore,
+ * The maximum size of a GDB Command packet is MSGBUF_SIZE - 5 ('+'/'-', '$', '#', 2 byte checksum)
+ *
+ * GDB Response
+ * ============
+ * Byte 0: Telegram Type Field (0x8d Direct Command, No response required) | NXT Msg Header
+ * Byte 1: Segment No (1-255, 0: Last Segment; limit is MSG_NUMSEGMENTS) |
+ * Byte 2: Telegram Size (Len of USB Buffer - 3, max is MSG_SEGMENTSIZE) |
+ * Byte 3-N: Message data | GDB Response
+ *
+ * The GDB Retransmission Request has the following format:
+ * Offset 0: '-' Command Received Status
+ *
+ * The GDB Response (of size M) has the following format:
+ * Offset 0: '+' Command Received Status
+ * Offset 1: '$'
+ * Offset 2 - (M-4): Response packet info
+ * Offset M-3: '#'
+ * Offset M-2: MSB of Checksum
+ * Offset M-1: LSB of Checksum
+ *
+ * The maximum size of a GDB Response packet is MSGBUF_SIZE - 5 ('+', '$', '#', 2 byte checksum)
+ *
+ * Note: The Telegram Size is the actual size of the Message Data portion
+ * (i.e., excludes the three header bytes, includes the GDB Command/Response Packet checksum bytes
+ * in the last segment)
+ */
+
+ .global dbg__comm_init
+/* dbg__comm_init
+ * Initialize communications channel.
+ * On Entry:
+ * R0: MSG Rx Buf Pointer
+ * R1: MSG Tx Buf Pointer
+ */
+
+dbg__comm_init:
+ stmfd sp!, {lr}
+ ldr r2, =debug_msgRxBufPtr
+ stmia r2!, {r0, r1} /* debug_msgRxBufPtr and debug_msgTxBufPtr */
+ stmia r2!, {r0, r1} /* debug_msgRxBuf_AppendPtr and debug_msgTxBuf_AppendPtr */
+ bl _dbg__comm_readbuf_reset
+ ldr r1, =debug_nxtMsgLength
+ mov r0, #0
+ str r0, [r1, #NXTCOMMCHANNEL_OFFSET] /* Clear NXT Channel on INIT */
+ ldmfd sp!, {pc}
+
+#ifdef __NXOS__
+_dbg__comm_readbuf_reset:
+ stmfd sp!, {lr}
+ ldr r0, =debug_InCommBuf
+ mov r1, #USB_BUFSIZE
+ ldr r2, =fantom_init
+ mov lr, pc
+ bx r2
+#if 0
+ ldr r1, =debug_nxtMsgLength
+ mov r0, #0
+ str r0, [r1] /* Clear NxOS Received Message Length */
+#endif
+ ldmfd sp!, {pc}
+#else
+_dbg__comm_readbuf_reset:
+ ldr r1, =debug_nxtMsgLength
+ mov r0, #0
+ str r0, [r1] /* Clear NXT Received Message Length */
+ bx lr
+
+ .global dbg__copyNxtDebugMsg
+/* dbg__copyNxtDebugMsg
+ * Copy NXT Firmware Debug Message to our own Buffers, indicate Msg Received status.
+ * On Entry:
+ * R0: NXT Input Buf Pointer
+ * R1: NXT Communications Channel Enum (CmdBit)
+ * R2: NXT Raw Message Length
+ * On Exit:
+ * R0-R3: Destroyed
+ */
+dbg__copyNxtDebugMsg:
+ ldr r3, =debug_nxtMsgLength
+ str r1, [r3, #NXTCOMMCHANNEL_OFFSET]
+ str r2, [r3]
+ ldr r1, =debug_InCommBuf
+/* FIXME: We can probably save some cycles and buffer space by using the
+ * NXT comms buffer specified in R0 directly without copying to internal buffers
+ */
+ _dbg_memcpy r1, r0, r2, r3 /* r3: scratch register */
+ bx lr
+#endif
+
+/* _dbg_reset_msgTxBuf_AppendPtr
+ * Internal variable to reset pointers.
+ * On Exit:
+ * R0: debug_msgTxBuf_AppendPtr
+ * R1: destroyed
+ */
+_dbg_reset_msgTxBuf_AppendPtr:
+ ldr r1, =debug_msgTxBufPtr /* Should not be modified */
+ ldr r0, [r1]
+ str r0, [r1, #TXAPPENDPTR_OFFSET]
+ mov pc, lr
+
+/* _dbg__commHasMsg
+ * Internal Segment Reassembly Routine.
+ * On exit:
+ * r0: !0: (Availale Telegram Message Size), 0: no incoming message/segment
+ * r1: message segment number
+ */
+_dbg__commHasMsg:
+ stmfd sp!, {lr}
+#ifdef __NXOS__
+ ldr r2, =nx_usb_fantom_data_read
+ mov lr,pc
+ bx r2 /* Number of bytes read in R0 */
+ /* Note: The return value in R0 is the Comm Buffer Size, includes NXT Direct Command Header */
+#else
+ ldr r0, =debug_nxtMsgLength
+ ldr r0, [r0] /* R0 contains the Comm Buffer Size, including the NXT Direct Command Header */
+#endif
+
+ ldr r2, =debug_InCommBuf
+ ldrb r1, [r2, #NXT_MSG_TELEGRAMTYPE_OFFSET]
+ cmp r1, #NXT_GDBMSG_TELEGRAMTYPE
+ bne invalid_CommMsg /* Invalid telegram type, ignore */
+
+ ldrb r1, [r2, #NXT_MSG_TELEGRAMSIZE_OFFSET]
+ sub r0, r0, r1 /* Comm Buffer Size - Telegram Size = 3 (header size) */
+ cmp r0, #NXT_GDBMSG_START /* Start offset is equal to header size */
+ bne invalid_CommMsg /* Invalid Message Length, ignore */
+
+ mov r0, r1 /* Telegram Message Size */
+ ldrb r1, [r2, #NXT_MSG_SEGNUM_OFFSET]
+ b _exit_dbg__commHasMsg
+
+invalid_CommMsg:
+ bl _dbg__comm_readbuf_reset /* Next Comm telegram transaction */
+ mov r0, #0
+_exit_dbg__commHasMsg:
+ ldmfd sp!, {pc}
+
+/* _copy_msg_from_commbuf
+ * Internal Comm buffer copy routine, handles segment reassembly.
+ * On entry:
+ * r0: number of bytes to copy
+ * r1: segment number
+ * On exit:
+ * r0: cummulative message length
+ * r1: segment number
+ * r2, r3: Destroyed
+ */
+_copy_msg_from_commbuf:
+ stmfd sp!, {r1,r4,r5,r6,lr}
+ movs r4, r0
+ beq _exit_copy_msg_from_commbuf
+
+ ldr r6, =debug_msgRxBufPtr /* Address of Pointers */
+ ldr r5, [r6] /* Rx buffer Start Address */
+ ldr r2, [r6, #RXAPPENDPTR_OFFSET] /* Append Pointer */
+
+ sub r3, r2, r5 /* r3: current length of message */
+ add r3, r3, r4 /* new cummulative length of message */
+ cmp r3, #MSGBUF_SIZE
+ movhi r4, #0 /* Buffer overflow! */
+ strhi r5, [r6, #RXAPPENDPTR_OFFSET] /* Reset AppendPtr to beginning of Rx Buffer */
+ bhi _exit_copy_msg_from_commbuf
+
+ ldr r3, =debug_InCommBuf
+ add r3, r3, #NXT_GDBMSG_START
+ _dbg_memcpy r2, r3, r4, r0 /* r2 updated to point to next empty char slot in Rx buffer */
+ sub r4, r2, r5 /* r4: cummulative length of message */
+
+ /* Update debug_msgRxBuf_AppendPtr */
+ teq r1, #0 /* Check if this is last segment (segment 0) */
+ streq r5, [r6, #RXAPPENDPTR_OFFSET] /* Reset AppendPtr to beginning of Rx Buffer if so */
+ strne r2, [r6, #RXAPPENDPTR_OFFSET] /* Otherwise, update Append Pointer to receive next segment */
+
+_exit_copy_msg_from_commbuf:
+ bl _dbg__comm_readbuf_reset /* Next Comm telegram transaction */
+ mov r0, r4 /* Return cummulative message length in R0 */
+ ldmfd sp!, {r1,r4,r5,r6,pc} /* Return segment number in R1 */
+
+
+/* _msgbuf_checksum
+ * Internal routine to calculate checksum character buffer.
+ * On entry:
+ * r0: pointer to character buffer to checksum (assume ASCIIZ terminated)
+ * On exit:
+ * r0: pointer to character buffer after ASCIIZ
+ * r1: checksum (8-bit binary)
+ * r2: message length
+ * r3: destroyed
+ */
+_msgbuf_checksum:
+ mov r1, #0 /* clear checksum */
+ mov r2, #0 /* clear length */
+1: ldrb r3, [r0], #1 /* Iterate through buffer */
+ add r1, r1, r3 /* cummulative sum of char */
+ teq r3, #0
+ addne r2, r2, #1 /* increment message length */
+ bne 1b /* until ASCIIZ found */
+ and r1, #BYTE0 /* Modulo 256 */
+ mov pc, lr
+
+ .global dbg__getDebugMsg
+/* dbg__getDebugMsg
+ * Retrieve pending Debugger Message if available (Non-Blocking).
+ * On entry:
+ * No parameters (assume pointers were initialized previously using dbg__comm_init)
+ * On exit:
+ * r0: >0 = Valid GDB Message Length (incl '$', excluding '#' and checksum),
+ * 0 = no valid message (yet), -1 = error
+ * r1: GDB Message Buffer Pointer (incl '$', excluding '#' and checksum)
+ * r2, r3: Destroyed
+ * Note: If GDB Message were returned, it is ASCIIZ terminated, does not include '#' and checksum
+ */
+dbg__getDebugMsg:
+ stmfd sp!, {r4,r5,lr}
+ bl _dbg__commHasMsg /* r0: message length, r1: segment number */
+ teq r0, #0
+ beq exit_dbg__getDebugMsg /* no new message, exit with R0 = 0 */
+
+ ldr r4, =debug_segmentRxNum
+ ldr r2, [r4] /* Get current Segment Number */
+ add r2, r2, #1 /* Expected Segment Number for comparison */
+ teq r1, #0
+ streq r1, [r4] /* Update current Segment Number with 0 since it is the last segment */
+ beq _hasMsg2Copy
+ cmp r1, #MSG_NUMSEGMENTS /* Segment Number < MSG_NUMSEGMENTS? */
+ bhs _invalid_segment
+ teq r1, r2 /* Valid Segment Number, check against Expected Segment Number */
+ beq _hasMsg2Copy /* Segment Number matches Expected Segment Number, update buffers */
+
+_invalid_segment:
+ bl _dbg__comm_readbuf_reset /* Invalid, Next Comm telegram transaction */
+ mov r0, #0 /* Reset Segment Number */
+ str r0, [r4] /* Update current Segment Number with 0 to prepare for new message */
+ b exit_dbg__getMsgError /* Exit with error */
+
+_hasMsg2Copy:
+ str r1, [r4] /* Update current Segment Number */
+ bl _copy_msg_from_commbuf /* r0: cummulative message length, r1: segment number */
+ teq r1, #0
+ movne r0, #0 /* Incomplete message, ignore for now */
+ bne exit_dbg__getDebugMsg /* Message not complete yet, exit */
+
+ /* Check for valid GDB message */
+ mov r4, r0 /* keep message length in R4, assume to be within MSGBUF_SIZE */
+ ldr r5, =debug_msgRxBufPtr
+ ldr r5, [r5] /* Rx buffer Start Address */
+
+/* Need to account for Packet Acknowledgement */
+1: ldrb r0, [r5]
+ teq r0, #MSGBUF_CTRLC /* Look for Ctrl-C */
+ moveq r0, r4 /* If found, set R0 to current message length */
+ beq exit_dbg__getDebugMsg /* and return */
+ teq r0, #MSGBUF_NAKCHAR /* Look for '-' */
+ beq exit_dbg__getMsgError /* FIXME: We can't handle retransmission, flag message error */
+ teq r0, #MSGBUF_ACKCHAR /* Look for '+' */
+ addeq r5, r5, #1 /* Adjust Buffer Start Pointer (excl '+') */
+ subeq r4, r4, #1 /* Adjust Message Length */
+ beq 1b /* Skip all Packet Acknowledgements */
+
+ /* Note: Here we assume that we won't get a single ACK '+' or NAK '-' character message.
+ * If we do, it'll be flagged as an error
+ */
+ subs r2, r4, #MSGBUF_CHKSUMOFFSET /* Look for '#': Message Length - 3 = '#' offset */
+ blt exit_dbg__getMsgError /* Message Length is too short, exit with error */
+ ldrb r0, [r5, r2]
+ teq r0, #MSGBUF_CHKSUMCHAR
+ bne exit_dbg__getMsgError /* No checksum char '#', exit with error */
+
+ mov r1, #0
+ strb r1, [r5, r2] /* Zero out '#' char for checksum calc later */
+
+#ifdef CHECK_GDBSTARTCHAR
+ /* Checked in dbg__bkpt_waitCMD */
+ ldrb r0, [r5]
+ teq r0, #MSGBUF_STARTCHAR /* Look for '$' */
+ bne exit_dbg__getMsgError /* No start char '$', exit with error */
+#endif
+
+ add r0, r5, #1 /* Checksum packet data (excl '$') */
+ bl _msgbuf_checksum /* R2: length (excl '$'), R1: calculated checksum, R0: pointer to checksum in receive buffer */
+ mov r3, r1 /* Keep calculated checksum in R3 (R1 destroyed by ascii2byte) */
+ bl ascii2byte /* R0: received checksum, R1: address of next buffer location */
+ teq r0, r3 /* Compare calculated checksum in R3 against received checksum in R0 */
+ bne exit_dbg__getMsgError /* Checksums do not match, exit with error */
+
+ subeq r0, r4, #MSGBUF_CHKSUMOFFSET /* Update message length (incl '$') as return parameter */
+ add r2, r2, #1 /* expected message length (from _msgbuf_checksum) */
+ teq r0, r2
+ beq exit_dbg__getDebugMsg /* Valid length, return */
+
+exit_dbg__getMsgError:
+ mov r0, #MSGBUF_MSGERROR
+exit_dbg__getDebugMsg:
+ mov r1, r5 /* Return GDB Message Buffer Pointer in R1 */
+ ldmfd sp!, {r4,r5,pc}
+
+/* _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 */
+#ifdef __NXOS__
+ /* 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 */
+#else
+ 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
+#endif
+
+_dbg__sendCommMsgFailed:
+ mov r0, #FALSE
+
+_exit_dbg__sendCommMsg:
+ ldmfd sp!, {r4, pc}
+
+
+/* _copy_msg_to_commbuf
+ * Internal Comm buffer copy routine, handles segment fragmentation.
+ * On entry:
+ * r0: number of bytes to copy
+ * r1: segment number
+ * On exit:
+ * r0: cummulative message length
+ * r1: segment number
+ * r2, r3: Destroyed
+ */
+_copy_msg_to_commbuf:
+ stmfd sp!, {r1,r4,r5,r6,lr}
+ ldr r6, =debug_msgTxBufPtr /* Address of Pointers */
+ ldr r5, [r6, #TXAPPENDPTR_OFFSET] /* Retrieve Tx Append Pointer */
+
+ movs r4, r0
+ beq _exit_copy_msg_to_commbuf
+
+#ifdef CHECK_TXLEN
+ add r0, r4, #NXT_GDBMSG_START /* offset = header size */
+ cmp r0, #USB_BUFSIZE
+ bhi _exit_copy_msg_to_commbuf /* We let calling routine detect problem (segment number will increment) */
+#endif
+
+ /* Fill in Comm Message Header */
+ ldr r3, =debug_OutCommBuf
+ mov r2, #NXT_GDBMSG_TELEGRAMTYPE
+ strb r2, [r3], #1 /* Telegram type */
+ strb r1, [r3], #1 /* Segment Number */
+ strb r0, [r3], #1 /* Message Length */
+
+ mov r2, r5 /* Copy to R2 for updating */
+ mov r1, r4 /* actual GDB message fragment length (exclude Comm header) */
+ _dbg_memcpy r3, r2, r1, r0 /* This copies over the message fragment, r3, r2 updated */
+ mov r5, r2 /* Updated Tx Append Pointer, keep in R5 for now */
+
+ add r0, r4, #NXT_GDBMSG_START /* Total Comm Buffer Size for Tx (NXT_GDBMSG_START offset = header size) */
+ bl _dbg__sendCommMsg /* Common interface routine to commnuncations drivers */
+ cmp r0, #TRUE
+ ldrne r5, [r6, #TXAPPENDPTR_OFFSET] /* Tx failed, Retrieve Original Tx Append Pointer */
+ streq r5, [r6, #TXAPPENDPTR_OFFSET] /* Tx succeeded, Update Tx Append Pointer to new position */
+
+_exit_copy_msg_to_commbuf:
+ ldr r6, [r6] /* Retrieve Tx Buffer Start Address */
+ sub r0, r5, r6 /* Return calculated cummulative message length (R0) */
+ ldmfd sp!, {r1,r4,r5,r6,pc} /* Return segment number in R1 */
+
+ .global dbg__putDebugMsg
+/* dbg__putDebugMsg
+ * Sends Debugger Message from calling routine after appending checksum (Blocking) .
+ * On entry:
+ * No parameters (assume pointers were initialized previously using dbg__comm_init)
+ * On exit:
+ * r0: status (0: success, -1: error)
+ * Note: GDB Message to be sent must be ASCIIZ terminated, does not include '#' and checksum
+ * Response packets start with '+' followed by '$' (2 bytes prefix)
+ */
+dbg__putDebugMsg:
+ stmfd sp!, {r4,r5,lr}
+ /* Perform Checksum Calculation */
+ ldr r5, =debug_msgTxBufPtr /* R5: data structure base pointer */
+ ldr r4, [r5] /* Tx buffer Start Address */
+ str r4, [r5, #TXAPPENDPTR_OFFSET] /* Reset Tx buffer Append Pointer */
+ add r0, r4, #2 /* skip '+' and '$' */
+ bl _msgbuf_checksum /* R2: length (excl '+' and '$'), R1: calculated checksum, R0: pointer to checksum in tx buffer */
+
+#ifdef CHECK_TXLEN
+ add r2, r2, #2 /* r2: returned length from _msgbuf_checksum, added with prefix length */
+ sub r3, r0, r4 /* r3: calculated length from pointers (incl. prefix length) */
+ teq r2, r3
+ bne exit_dbg__putMsgError
+#endif
+
+ mov r3, #MSGBUF_CHKSUMCHAR
+ strb r3, [r0, #-1] /* Insert '#' */
+ bl byte2ascii /* On return, R0 points to location after checksum bytes, R1 is original pointer to checksum */
+ sub r4, r0, r4 /* R4 = Calculated total message length (incl '+' and '$', '#' and checksum bytes */
+ cmp r4, #MSG_SEGMENTSIZE /* If total message length > MSG_SEGMENTSIZE */
+ mov r1, #0 /* Initialize Segment Number = 0 (last segment) first */
+ mov r0, #0 /* Initial cummulative message length */
+ mov r5, #0 /* Previous cummulative message length */
+
+ /* We assume unsigned message lengths, so the arithmetic MUST NOT result in negative values */
+_cont_putMsg:
+ cmp r4, r0
+ movls r0, #0 /* R0: Exit status (success) */
+ bls exit_dbg__putDebugMsg /* If Total message length (r4) <= Cummulative message length (r0), we're done */
+ add r2, r0, #MSG_SEGMENTSIZE /* R2: calculate new Max cummulative message length */
+ cmp r4, r2 /* Check total message length (R4) against new Max cummulative message length (R2) */
+ subls r0, r4, r0 /* if total message length (R4) <= new Max cummulative message length (R2), send remainder */
+ movls r1, #0 /* Flag as last segment (Segment Number = 0) */
+ movhi r0, #MSG_SEGMENTSIZE /* else send MSG_SEGMENTSIZE bytes */
+ addhi r1, r1, #1 /* Increment Segment Number */
+ cmp r1, #MSG_NUMSEGMENTS
+ bhs exit_dbg__putMsgError /* If Segment Number >= MSG_NUMSEGMENTS, flag error */
+ bl _copy_msg_to_commbuf /* R0: cummulative message length, R1: segment number */
+ teq r5, r0 /* Check if we managed to transmit the previous message */
+ beq exit_dbg__putMsgError /* No, flag error */
+ movne r5, r0 /* Update previous cummulative message length */
+ b _cont_putMsg
+
+exit_dbg__putMsgError:
+ mov r0, #MSGBUF_MSGERROR
+exit_dbg__putDebugMsg:
+ ldmfd sp!, {r4,r5,pc}
+
+ .global dbg__sendAckOrNak
+/* dbg__sendAckOrNak
+ * Send Ack (for successful receipt of message)
+ * or Nak (for Retransmission due to received message Checksum error) (Blocking) .
+ * On entry:
+ * No parameters (assume pointers were initialized previously using dbg__comm_init)
+ * On exit:
+ * r0: status (0: success, -1: error)
+ * r1: destroyed
+ * Note: An Ack Or Nak is indicated by '+' or '-', which is prepended with the Comm header and sent (without checksum)
+ * Sending Ack is only done for Continue and Step commands, where GDB does not expect any replies.
+ */
+dbg__sendAckOrNak:
+ stmfd sp!, {lr}
+ ldr r1, =debug_msgTxBufPtr /* R2: data structure base pointer */
+ ldr r0, [r1] /* Tx buffer Start Address */
+ str r0, [r1, #TXAPPENDPTR_OFFSET] /* Reset Tx buffer Append Pointer */
+
+ mov r1, #0 /* Initialize Segment Number = 0 (last segment) */
+ mov r0, #1 /* Retransmission message length = 1 */
+ bl _copy_msg_to_commbuf /* R0: cummulative message length, R1: segment number */
+ cmp r0, #1 /* Check if we managed to transmit the previous message */
+ moveq r0, #0 /* R0: Exit status (success) */
+ movne r0, #MSGBUF_MSGERROR /* R0: Exit status (error) */
+ ldmfd sp!, {pc}
+
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_comm.h b/AT91SAM7S256/armdebug/Debugger/debug_comm.h
new file mode 100644
index 0000000..7553240
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_comm.h
@@ -0,0 +1,53 @@
+/** @file debug_comm.h
+ * @brief Shared C/ASM header file for debugger communications
+ *
+ */
+
+/* Copyright (C) 2007-2010 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
+ *
+ */
+
+#ifndef __DEBUG_COMM_H__
+#define __DEBUG_COMM_H__
+
+#include "_c_arm_macros.h"
+
+/* This is a place holder header file to allow for interfacing with C Routines in either
+ * NxOS or NXT Firmware.
+ *
+ * Since the header files from the original source trees were meant for C programs, we can't
+ * include them directly. Here we just use .extern to reference the routines.
+ */
+
+#ifdef __NXOS__
+
+ .extern nx_usb_is_connected
+ .extern nx_usb_can_write
+ .extern nx_usb_write
+ .extern nx_usb_data_written
+ .extern nx_usb_read
+ .extern nx_usb_data_read
+
+#else /* NXT Firmware */
+
+ .extern cCommInit
+ .extern cCommCtrl
+ .extern cCommExit
+ .extern dUsbWrite
+ .extern dUsbRead
+ .extern dUsbIsConfigured
+ .extern dBtSendMsg
+ .equ nxt_UBYTE_TRUE, 1
+ .equ nxt_UBYTE_FALSE, 0
+ .equ USB_CMD_READY, 0x01 /* From c_comm.iom */
+ .equ BT_CMD_READY, 0x02 /* From c_comm.iom */
+
+#endif
+
+#endif
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S b/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S
new file mode 100644
index 0000000..d54445b
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S
@@ -0,0 +1,457 @@
+/** @file debug_hexutils.S
+ * @brief GDB hexadecimal conversion utility routines
+ *
+ */
+
+/* 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
+ *
+ */
+
+
+#define __ASSEMBLY__
+
+#include "debug_internals.h"
+
+.data
+.align 4
+
+hex2char_lut:
+ .ascii "0123456789ABCDEF"
+
+/* Macros
+ */
+
+
+/* _hex2char_lut
+ * Internal routine to intialize the LUT address pointer
+ */
+ .macro _hex2char_lut addrptr
+ ldr \addrptr, =hex2char_lut
+ .endm
+
+/* _hex2char_cont
+ * Internal routine that assumes that the LUT has been loaded.
+ * This macro accepts a byte sized hex value as a parameter register(7:0) and returns the
+ * ASCII equivalent in in the same register(7:0)
+ * The second parameter is the LUT address pointer register to use (assumed to be initialized)
+ * WARNING: Assumes that the value in register is sanity checked before invoking macro
+ */
+ .macro _hex2char_cont reg, addrptr
+ ldrb \reg, [\addrptr, \reg]
+ .endm
+
+/* _hex2char
+ * This macro accepts a byte sized hex value as a parameter register(7:0) and returns the
+ * ASCII equivalent in in the same register(7:0)
+ * The second parameter is the LUT address pointer register to use (register content is destroyed)
+ * WARNING: Assumes that the value in register is sanity checked before invoking macro
+ */
+ .macro _hex2char reg, addrptr
+ _hex2char_lut \addrptr
+ _hex2char_cont \reg, \addrptr
+ .endm
+
+/* _char2hex
+ * This macro accepts an ASCII char as a parameter register(7:0) and returns the
+ * equivalent byte sized hex value in in the same register(7:0)
+ * WARNING: Assumes that the char in register is a valid hex char before invoking macro
+ */
+ .macro _char2hex reg
+ cmp \reg, #'A' /* If Alpha */
+ bichs \reg, \reg, #ASCII_LOWER2UPPER_MASK /* Convert to Uppercase */
+ subhs \reg, \reg, #7 /* Adjustment to allow for subtraction with 0x30 */
+ sub \reg, \reg, #0x30 /* get final hex value */
+ .endm
+
+
+.code 32
+.text
+.align 4
+
+
+/* Utility Routines
+ * GDB requires command parameters to be specified as Big Endian values.
+ * However, the read/write register command expect the register contents to be specified in target byte order.
+ * Hence we need both versions of multibyte conversion routines for word sized values.
+ */
+
+/* hex2char
+ * This routine accepts a byte sized hex value in R0(7:0) and returns the
+ * ASCII equivalent in R0(7:0)
+ */
+ .global hex2char
+
+hex2char:
+ stmfd sp!, {r1,lr}
+ and r0, #NIBBLE0 /* make sure that input is sane */
+ _hex2char r0, r1
+ ldmfd sp!, {r1,pc}
+
+/* char2hex
+ * This routine accepts an ASCII character in R0(7:0) and returns the
+ * equivalent byte sized hex value in R0(7:0).
+ * It accepts lowercase and uppercase ASCII Hex char inputs.
+ * Invalid inputs return -1 as the value
+* On entry:
+ * R0: ASCII character
+ * On exit:
+ * R0: Hex value
+ */
+ .global char2hex
+
+char2hex:
+ and r0, r0, #BYTE0 /* make sure that input is sane */
+ cmp r0, #'0'
+ blo char2hex_error
+ cmp r0, #'9'
+ bls perform_char2hex
+ cmp r0, #'A'
+ blo char2hex_error
+ cmp r0, #'F'
+ bls perform_char2hex
+ cmp r0, #'a'
+ blo char2hex_error
+ cmp r0, #'f'
+ bhi char2hex_error
+ /* Validated Hex Char */
+perform_char2hex:
+ _char2hex r0 /* Return hex value in R0 */
+ bx lr
+
+char2hex_error:
+ mov r0, #-1 /* Set Return value to Error value */
+ bx lr
+
+/* byte2ascii_cont
+ * (Shared routine, does not perform sanity checks)
+ * On entry:
+ * R0: ASCII buffer pointer
+ * R1[7:0]: byte value
+ * On exit:
+ * R0: Address of next empty char slot in buffer
+ * R1: Destroyed
+ *
+ * This routine accepts an ASCII buffer pointer in R0 and a byte value in R1,
+ * and stores the ASCII equivalent byte value in the buffer pointed to by R0.
+ * Note: On return, R0 points to next empty char slot in buffer
+ */
+byte2ascii_cont:
+ stmfd sp!, {r2,r3,r4, lr}
+ lsl r2, r1, #24 /* Keep copy of input byte value R1[7:0], shifted to MSB R2[31:24] */
+ mov r4, #2 /* Loop counter */
+ _hex2char_lut r3 /* initialize LUT pointer */
+1: ror r2, r2, #28 /* Rotate MSNibble R2[31:28] into LSNibble position R2[3:0] */
+ and r1, r2, #NIBBLE0 /* Mask out everything else, store Nibble in R1 */
+ _hex2char_cont r1, r3 /* Convert nibble to ASCII char */
+ strb r1, [r0], #1
+ subs r4, r4, #1 /* decrement loop counter */
+ bne 1b
+ ldmfd sp!, {r2,r3,r4, pc}
+
+/* byte2ascii
+ * On entry:
+ * R0: ASCII buffer pointer
+ * R1[7:0]: Byte value
+ * On exit:
+ * R0: Address of next empty char slot in buffer
+ * R1: Original Address of Buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0 and a byte value in R1,
+ * and stores the ASCII equivalent byte value in the buffer pointed to by R0.
+ * Note: On return, R0 points to the next empty char slot in buffer
+ */
+ .global byte2ascii
+
+byte2ascii:
+ stmfd sp!, {r0, lr} /* Keep ASCII buffer pointer */
+ and r1, #BYTE0 /* sanitize input */
+ bl byte2ascii_cont
+ ldmfd sp!, {r1, pc} /* return original string pointer in R1 */
+
+/* halfword2ascii_be
+ * Big Endian version of halfword2ascii conversion routine
+ * On entry:
+ * R0: ASCII buffer pointer
+ * R1[15:0]: Halfword value
+ * On exit:
+ * R0: Address of next empty char slot in buffer
+ * R1: Original Address of Buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0 and a halfword value in R1,
+ * and stores the ASCII equivalent halfword value in the buffer pointed to by R0.
+ * Note: On return, R0 points to the next empty char slot in buffer
+ */
+ .global halfword2ascii_be
+halfword2ascii_be:
+ stmfd sp!, {r0,r2,r3, lr} /* Keep ASCII buffer pointer */
+ mov r3, #2 /* Loop Counter */
+ mov r2, r1, lsl #16 /* copy of input halfword value R1[15:0], shifted to MSH R2[31:16] */
+ b _conv_byte2ascii_be /* goto Byte conversion loop */
+
+/* halfword2ascii_le
+ * Little Endian version of halfword2ascii conversion routine
+ * On entry:
+ * R0: ASCII buffer pointer
+ * R1[15:0]: Halfword value
+ * On exit:
+ * R0: Address of next empty char slot in buffer
+ * R1: Original Address of Buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0 and a halfword value in R1,
+ * and stores the ASCII equivalent halfword value in the buffer pointed to by R0.
+ * Note: On return, R0 points to the next empty char slot in buffer
+ */
+ .global halfword2ascii_le
+halfword2ascii_le:
+ stmfd sp!, {r0,r2,r3, lr} /* Keep ASCII buffer pointer */
+ mov r3, #2 /* Loop Counter */
+ b _conv_byte2ascii_le /* goto Byte conversion loop */
+
+
+/* word2ascii_be
+ * Big Endian version of word2ascii conversion routine
+ * On entry:
+ * R0: ASCII buffer pointer
+ * R1[31:0]: Word value
+ * On exit:
+ * R0: Address of next empty char slot in buffer
+ * R1: Original Address of Buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0 and a word value in R1,
+ * and stores the ASCII equivalent word value in the buffer pointed to by R0.
+ * Note: On return, R0 points to the next empty char slot in buffer
+ */
+ .global word2ascii_be
+word2ascii_be:
+ stmfd sp!, {r0,r2,r3, lr} /* Keep ASCII buffer pointer */
+ mov r2, r1 /* copy of input word value R1[31:0] */
+ mov r3, #4 /* Loop Counter */
+
+ /* Fall through to byte coversion loop */
+
+
+/* Big Endian Multibyte Convert: Rotate then convert */
+_conv_byte2ascii_be:
+ ror r2, r2, #24 /* Rotate MSB R2[31:24] into LSB position R2[7:0] */
+ and r1, r2, #BYTE0 /* Copy byte value in R2[7:0] into R1 */
+ bl byte2ascii_cont /* R0: next ASCII buffer location pointer, R1: destroyed */
+ subs r3, r3, #1
+ bne _conv_byte2ascii_be
+ ldmfd sp!, {r1,r2,r3, pc}
+
+/* word2ascii_le
+ * Little Endian version of word2ascii conversion routine
+ * On entry:
+ * R0: ASCII buffer pointer
+ * R1[31:0]: Word value
+ * On exit:
+ * R0: Address of next empty char slot in buffer
+ * R1: Original Address of Buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0 and a word value in R1,
+ * and stores the ASCII equivalent word value in the buffer pointed to by R0.
+ * Note: On return, R0 points to the next empty char slot in buffer
+ */
+ .global word2ascii_le
+word2ascii_le:
+ stmfd sp!, {r0,r2,r3, lr} /* Keep ASCII buffer pointer */
+ mov r2, r1 /* copy of input word value R1[31:0] */
+ mov r3, #4 /* Loop Counter */
+
+ /* Fall through to byte coversion loop */
+
+/* Little Endian Multibyte Convert: Convert then rotate */
+_conv_byte2ascii_le:
+ and r1, r2, #BYTE0 /* Copy byte value in R2[7:0] into R1 */
+ bl byte2ascii_cont /* R0: next ASCII buffer location pointer, R1: destroyed */
+ ror r2, r2, #8 /* Rotate LSB+1 R2[15:8] into LSB position R2[7:0] */
+ subs r3, r3, #1
+ bne _conv_byte2ascii_le
+ ldmfd sp!, {r1,r2,r3, pc}
+
+
+/* ascii2hex_varlen_be
+ * Big Endian version of ascii2hex_varlen conversion routine
+ * (There is no Little Endian Version)
+ * On entry:
+ * R0: ASCII buffer pointer
+ * On exit:
+ * R0: Hex value
+ * R1: Address of next char slot in buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0,
+ * and returns the hex value in R0 for up to 8 Hex characters.
+ * Note: On return, R1 points to the ASCII buffer location after the hex value chars.
+ */
+ .global ascii2hex_varlen_be
+
+ascii2hex_varlen_be:
+ stmfd sp!, {r2,r3, lr}
+ mov r3, #CMD_REG_REGPARAMLEN /* Set max count to 8 (Max Register size) */
+ mov r1, r0 /* Use R1 as ASCII buffer pointer */
+ mov r2, #0 /* Initialize Cummulative Results */
+2: ldrb r0, [r1] /* Load ASCII char for Hex Value */
+ bl char2hex /* on return, hex value in R0, -1 for error */
+ cmp r0, #-1
+ beq _exit_ascii2hex_varlen
+ orr r2, r0, r2, lsl #4 /* combined byte value */
+ subs r3, r3, #1 /* Decrement Counter */
+ add r1, r1, #1 /* Go to next char slot */
+ bne 2b
+_exit_ascii2hex_varlen:
+ mov r0, r2 /* Return results in R0 */
+ ldmfd sp!, {r2,r3, pc}
+
+
+/* ascii2byte
+ * On entry:
+ * R0: ASCII buffer pointer
+ * On exit:
+ * R0[7:0]: Byte value
+ * R1: Address of next char slot in buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0,
+ * and returns the byte value in R0[7:0].
+ * Note: On return, R1 points to the ASCII buffer location after the current 2 chars.
+ * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars,
+ * otherwise it will return invalid results.
+ */
+ .global ascii2byte
+
+ascii2byte:
+ stmfd sp!, {r2, lr}
+ mov r1, r0 /* Use R1 as ASCII buffer pointer */
+ ldrb r0, [r1], #1 /* Load ASCII char for MSN */
+ bl char2hex /* on return, hex value in R0, -1 for error (ignored) */
+ mov r2, r0, lsl #4 /* Intermediate Results register */
+ ldrb r0, [r1], #1 /* Load ASCII char for LSN */
+ bl char2hex /* on return, hex value in R0, -1 for error (ignored) */
+ orr r0, r2, r0 /* combined byte value */
+ ldmfd sp!, {r2, pc}
+
+/* ascii2halfword_be
+ * Big Endian version of ascii2halfword conversion routine
+ * On entry:
+ * R0: ASCII buffer pointer
+ * On exit:
+ * R0[15:0]: Halfword value
+ * R1: Address of next char slot in buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0,
+ * and returns the Halfword value in R0[15:0].
+ * Note: On return, R1 points to the ASCII buffer location after the current 4 chars.
+ * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars,
+ * otherwise it will return invalid results.
+ */
+ .global ascii2halfword_be
+
+ascii2halfword_be:
+ stmfd sp!, {r2,r3, lr}
+ mov r3, #2 /* Loop counter */
+ b _conv_ascii2byte_be
+
+/* ascii2halfword_le
+ * Little Endian version of ascii2halfword conversion routine
+ * On entry:
+ * R0: ASCII buffer pointer
+ * On exit:
+ * R0[15:0]: Halfword value
+ * R1: Address of next char slot in buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0,
+ * and returns the Halfword value in R0[15:0].
+ * Note: On return, R1 points to the ASCII buffer location after the current 4 chars.
+ * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars,
+ * otherwise it will return invalid results.
+ */
+ .global ascii2halfword_le
+
+ascii2halfword_le:
+ stmfd sp!, {r2,r3, lr}
+ mov r3, #2 /* Loop counter */
+ b _conv_ascii2byte_le
+
+
+/* ascii2word_be
+ * Big Endian version of ascii2word conversion routine
+ * On entry:
+ * R0: ASCII buffer pointer
+ * On exit:
+ * R0[31:0]: Word value
+ * R1: Address of next char slot in buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0,
+ * and returns the word value in R0[31:0].
+ * Note: On return, R1 points to the ASCII buffer location after the current 8 chars.
+ * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars,
+ * otherwise it will return invalid results.
+ */
+ .global ascii2word_be
+
+ascii2word_be:
+ stmfd sp!, {r2,r3, lr}
+ mov r3, #4 /* Loop counter */
+
+ /* Fall through to byte coversion loop */
+
+_conv_ascii2byte_be:
+ teq r0, #0
+ beq _exit_conv_ascii2byte_be /* exit if NULL pointer in R0 */
+ mov r2, #0 /* Initialize Cummulative value */
+2: bl ascii2byte
+ orr r2, r0, r2, lsl #8 /* Merge current byte with cummulative value */
+ mov r0, r1 /* Copy next char pointer to R0 for next byte */
+ subs r3, r3, #1
+ bne 2b
+ mov r0, r2 /* Copy it to R0 as return value */
+
+_exit_conv_ascii2byte_be:
+ ldmfd sp!, {r2,r3, pc} /* return hex value in R0 */
+
+/* ascii2word_le
+ * Litle Endian version of ascii2word conversion routine
+ * On entry:
+ * R0: ASCII buffer pointer
+ * On exit:
+ * R0[31:0]: Word value
+ * R1: Address of next char slot in buffer
+ *
+ * This routine accepts an ASCII buffer pointer in R0,
+ * and returns the word value in R0[31:0].
+ * Note: On return, R1 points to the ASCII buffer location after the current 8 chars.
+ * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars,
+ * otherwise it will return invalid results.
+ */
+ .global ascii2word_le
+
+ascii2word_le:
+ stmfd sp!, {r2,r3, lr}
+ mov r3, #4 /* Loop counter */
+
+ /* Fall through to byte coversion loop */
+
+_conv_ascii2byte_le:
+ teq r0, #0
+ beq _exit_conv_ascii2byte_le /* exit if NULL pointer in R0 */
+ push {r3} /* Need to keep couter for final value adjustment */
+ mov r2, #0 /* Initialize Cummulative value */
+2: bl ascii2byte
+ orr r2, r0, r2, ror #8 /* Merge current byte with cummulative value */
+ mov r0, r1 /* Copy next char pointer to R0 for next byte */
+ subs r3, r3, #1
+ bne 2b
+ /* Cummulative value done, need to rotate it into the correct position for return value */
+ pop {r3} /* retrieve counter */
+ rsb r3, r3, #5 /* 5 - count */
+ lsl r3, r3, #3 /* [(5-count) x 8] bits to rotate */
+ mov r0, r2, ror r3 /* Copy it to R0 as return value */
+
+_exit_conv_ascii2byte_le:
+ ldmfd sp!, {r2,r3, pc} /* return hex value in R0 */
+
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_internals.h b/AT91SAM7S256/armdebug/Debugger/debug_internals.h
new file mode 100644
index 0000000..c7f5d16
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_internals.h
@@ -0,0 +1,303 @@
+/** @file debug_internals.h
+ * @brief Shared C/ASM header file for debugger internal constants
+ *
+ */
+
+/* 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
+ *
+ */
+
+#ifndef __DEBUG_INTERNALS_H__
+#define __DEBUG_INTERNALS_H__
+
+#include "_c_arm_macros.h"
+
+
+/** @addtogroup debugger */
+/*@{*/
+
+
+/* Declarations go here. */
+/** @name Debug Message Constants.
+ *
+ * Debug Message Values
+ */
+/*@{*/
+
+/*
+ * USB Buffer Sizes: Ctrl Intr Iso Bulk
+ * Full Speed Device 64 64 1023 64
+ * High Speed Device 64 1024 1024 512
+ */
+
+#define USB_BUFSIZE 64 /* USB Buffer size for AT91SAM7S */
+
+#define NXT_MSG_TELEGRAMTYPE_OFFSET 0 /* NXT Direct Command/Response Header */
+#define NXT_MSG_SEGNUM_OFFSET 1
+#define NXT_MSG_TELEGRAMSIZE_OFFSET 2
+
+#define NXT_GDBMSG_TELEGRAMTYPE 0x8d /* GDB debugger specific, no Response required */
+
+#define NXT_GDBMSG_START 3 /* Offset into USB Telegram buffer */
+
+#define MSG_NUMSEGMENTS 3 /* For packet transfers */
+#define MSG_SEGMENTSIZE (USB_BUFSIZE - NXT_GDBMSG_START) /* 61 bytes per segment */
+#define MSGBUF_SIZE (MSG_SEGMENTSIZE*MSG_NUMSEGMENTS) /* Debug Message Buffer Size, 61 x 3 = 183 chars = ~80 bytes of actual data */
+#define MSGBUF_CHKSUMOFFSET 3 /* to be subtracted from message length */
+#define MSGBUF_IN_OVERHEADLEN 5 /* For calculating max message data length (exclude ASCIIZ char) */
+#define MSGBUF_OUT_OVERHEADLEN 5 /* For calculating max message data length (exclude ASCIIZ char) */
+
+#define MSGBUF_CTRLC 0x03 /* For Out of Band Signaling: not implemented yet */
+#define MSGBUF_STARTCHAR '$'
+#define MSGBUF_ACKCHAR '+'
+#define MSGBUF_NAKCHAR '-'
+#define MSGBUF_ERRCHAR 'E'
+#define MSGBUF_SIGCHAR 'S'
+#define MSGBUF_SETCHAR '='
+#define MSGBUF_CHKSUMCHAR '#'
+#define MSGBUF_SEPCHAR ','
+#define MSGBUF_ARGCHAR ':'
+#define MSGBUF_MSGERROR -1
+/*@}*/
+
+/** @name Debug Command Lookup Constants.
+ *
+ * Debug Command Lookup
+ */
+/*@{*/
+
+#define CMDINDEX_OUTOFRANGE -1
+/*@}*/
+
+/** @name Debug Register Command Constants.
+ *
+ * Debug Register Command
+ */
+/*@{*/
+#define CMD_REG_NUMREGS 17
+#define CMD_REG_GETONE_MINPARAMLEN 1
+#define CMD_REG_GETONE_MAXPARAMLEN 2
+#define CMD_REG_GETALL_PARAMLEN 0
+#define CMD_REG_REGPARAMLEN 8 /* 32-bit ASCII Hex Value */
+#define CMD_REG_SETONE_MINPARAMLEN (2 + CMD_REG_REGPARAMLEN)
+#define CMD_REG_SETONE_MAXPARAMLEN (3 + CMD_REG_REGPARAMLEN)
+#define CMD_REG_SETALL_PARAMLEN (CMD_REG_NUMREGS*CMD_REG_REGPARAMLEN)
+#define CMD_KILL_PARAMLEN 0
+#define CMD_DETACH_PARAMLEN 0
+
+/*@}*/
+
+/** @name Debug Memory Command Constants.
+ *
+ * Debug Memory Command
+ * FIXME: These limits are not enforced by the GDB client, it truncates addresses and lengths to remove leading '0's
+ * The PARAMLEN constants would probably be removed
+ */
+/*@{*/
+#define CMD_NUMITEMS_PARAMLEN 4 /* 16-bit ASCII Hex Value */
+#define CMD_MEM_READ_PARAMLEN (CMD_REG_REGPARAMLEN + CMD_NUMITEMS_PARAMLEN + 1) /* Address length is equivalent to reg param len */
+#define CMD_MEM_WRITE_MINPARAMLEN (CMD_REG_REGPARAMLEN + CMD_NUMITEMS_PARAMLEN + 2) /* Address length is equivalent to reg param len */
+#define CMD_MEM_SEPCHAR_OFFSET CMD_REG_REGPARAMLEN /* Address length is equivalent to reg param len */
+#define CMD_MEM_MAXOUTBUFLEN (MSGBUF_SIZE - MSGBUF_OUT_OVERHEADLEN)
+#define CMD_MEM_MAXREADBYTES (CMD_MEM_MAXOUTBUFLEN/2)
+#define CMD_MEM_MAXINBUFLEN (MSGBUF_SIZE - MSGBUF_IN_OVERHEADLEN)
+#define CMD_MEM_MAXWRITEBYTES ((CMD_MEM_MAXINBUFLEN - CMD_MEM_WRITE_MINPARAMLEN)/2)
+/*@}*/
+
+/** @name Debug Continue and Step Command Constants.
+ *
+ * Debug Continue and Step Command
+ */
+/*@{*/
+#define CMD_CONTINUE_MINPARAMLEN 0
+#define CMD_STEP_MINPARAMLEN 0
+/*@}*/
+
+
+
+/** @name Debug Breakpoint Command Constants.
+ *
+ * Debug Breakpoint Command
+ */
+/*@{*/
+
+#define CMD_BKPT_INSERT_MINPARAMLEN 5
+#define CMD_BKPT_REMOVE_MINPARAMLEN 5
+
+
+#define CMD_BKPT_TYPE_BREAK_MEMORY 0
+#define CMD_BKPT_TYPE_BREAK_HARD 1 /* Not supported */
+#define CMD_BKPT_TYPE_WATCH_WRITE 2 /* Not supported (yet) */
+#define CMD_BKPT_TYPE_WATCH_READ 3 /* Not supported (yet) */
+#define CMD_BKPT_TYPE_WATCH_ACCESS 4 /* Not supported (yet) */
+
+#define CMD_BKPT_KIND_THUMB 2
+#define CMD_BKPT_KIND_THUMB2 3 /* Not supported */
+#define CMD_BKPT_KIND_ARM 4
+
+#define CMD_BKPT_NOTFOUND -1
+
+/*@}*/
+
+/** @name Debug Stack Constants.
+ *
+ * Debug Stack Manipulation Values
+ */
+/*@{*/
+#define DBGSTACK_NEXTINSTR_INDEX 0 /* Next Instruction Address is at index 0 from bottom of Debug Stack */
+#define DBGSTACK_USERCPSR_INDEX 1 /* User CPSR (SPSR_UNDEF) is at index 1 from bottom of Debug Stack */
+#define DBGSTACK_USERREG_INDEX 2 /* R0 starts at index 2 from bottom of Debug Stack */
+#define DBGSTACK_USERSP_INDEX (DBGSTACK_USERREG_INDEX + REG_SP) /* SP is R13 */
+#define DBGSTACK_USERLR_INDEX (DBGSTACK_USERREG_INDEX + REG_LR) /* LR is R14 */
+#define DBGSTACK_USERPC_INDEX (DBGSTACK_USERREG_INDEX + REG_PC) /* PC is R15 */
+/*@}*/
+
+
+/** @name Exception Handler Vector Definitions.
+ *
+ * Exception Handler Vectors.
+ */
+/*@{*/
+
+#define RESET_VECTOR 0x00000000
+#define UNDEF_VECTOR 0x00000004
+#define SVC_VECTOR 0x00000008
+#define PABRT_VECTOR 0x0000000C
+#define DABRT_VECTOR 0x00000010
+#define RESERVED_VECTOR 0x00000014
+#define IRQ_VECTOR 0x00000018
+#define FIQ_VECTOR 0x0000001C
+
+
+/*@}*/
+
+
+/** @name Bitmask Definitions.
+ *
+ * Various Bitmasks used for data manipulation.
+ */
+/*@{*/
+#define BKPT_STATE_THUMB_FLAG 0x01 /* Flag Thumb Breakpoint */
+#define ASCII_LOWER2UPPER_MASK 0x20 /* ASCII Conversion bitmask */
+#define NIBBLE0 0x0000000F /* Nibble 0 word(3:0) */
+#define NIBBLE1 0x000000F0 /* Nibble 1 word(7:4) */
+#define NIBBLE2 0x00000F00 /* Nibble 2 word(11:8) */
+#define NIBBLE3 0x0000F000 /* Nibble 3 word(15:12) */
+#define NIBBLE4 0x000F0000 /* Nibble 4 word(19:16) */
+#define NIBBLE5 0x00F00000 /* Nibble 5 word(23:20) */
+#define NIBBLE6 0x0F000000 /* Nibble 6 word(27:24) */
+#define NIBBLE7 0xF0000000 /* Nibble 7 word(31:28) */
+#define BYTE0 0x000000FF /* Byte 0 word(7:0) */
+#define BYTE1 0x0000FF00 /* Byte 1 word(15:8) */
+#define BYTE2 0x00FF0000 /* Byte 2 word(23:16) */
+#define BYTE3 0xFF000000 /* Byte 3 word(31:24) */
+#define HLFWRD0 0x0000FFFF /* Halfword 0 word(15:0) */
+#define HLFWRD1 0xFFFF0000 /* Halfword 0 word(31:16) */
+/*@}*/
+
+/** @name CPSR Bit Definitions.
+ *
+ * Various Bit definitions for accessing the CPSR register.
+ */
+/*@{*/
+#define CPSR_THUMB 0x00000020
+#define CPSR_FIQ 0x00000040
+#define CPSR_IRQ 0x00000080
+#define CPSR_MODE 0x0000001F
+#define CPSR_COND 0xF0000000
+
+/* ARM Exception Modes */
+#define MODE_USR 0x10 /* User mode */
+#define MODE_FIQ 0x11 /* FIQ mode */
+#define MODE_IRQ 0x12 /* IRQ mode */
+#define MODE_SVC 0x13 /* Supervisor mode */
+#define MODE_ABT 0x17 /* Abort mode */
+#define MODE_UND 0x1B /* Undefined mode */
+#define MODE_SYS 0x1F /* System mode */
+
+/* Condition Flags
+ * b31 b30 b29 b28
+ * N Z C V
+ */
+#define CPSR_NFLAG 0x80000000
+#define CPSR_ZFLAG 0x40000000
+#define CPSR_CFLAG 0x20000000
+#define CPSR_VFLAG 0x10000000
+
+/*@}*/
+
+/** Debugger State Enums
+ *
+ * Debugger State.
+ * The enums must be consecutive, starting from 0
+ */
+ENUM_BEGIN
+ENUM_VALASSIGN(DBG_RESET, 0) /**< Initial State. */
+ENUM_VAL(DBG_INIT) /**< Debugger Initialized. */
+ENUM_VAL(DBG_CONFIGURED) /**< Debugger has been configured by GDB Server */
+ENUM_END(dbg_state_t)
+
+/** Breakpoint Type Enums
+ *
+ * Breakpoint Type.
+ * The enums must be consecutive, starting from 0
+ */
+ENUM_BEGIN
+ENUM_VALASSIGN(DBG_AUTO_BKPT,0) /**< Auto Breakpoint (Instruction resume after breakpoint). */
+ENUM_VAL(DBG_MANUAL_BKPT_ARM) /**< Manual ARM Breakpoint. */
+ENUM_VAL(DBG_NORMAL_BKPT_ARM) /**< Normal ARM Breakpoint (Single Step, Normal). */
+ENUM_VAL(DBG_MANUAL_BKPT_THUMB) /**< Manual Thumb Breakpoint. */
+ENUM_VAL(DBG_NORMAL_BKPT_THUMB) /**< Normal Thumb Breakpoint (Single Step, Normal). */
+ENUM_END(bkpt_type_t)
+
+/** Debugger Message Error Enums
+ *
+ * Debugger Error Message Enums.
+ * The enums must be consecutive, starting from 1
+ */
+/* FIXME: Need to validate against the ecos-generic-stub.c Error enums */
+ENUM_BEGIN
+ENUM_VALASSIGN(MSG_ERRIMPL, 0) /**< Stub (not implemented) Error. */
+ENUM_VAL(MSG_ERRINLENGTH) /**< Message Write Length Error. */
+ENUM_VAL(MSG_ERROUTLENGTH) /**< Message Read Length Error. */
+ENUM_VAL(MSG_ERRFORMAT) /**< Message Format Error. */
+ENUM_VAL(MSG_UNKNOWNCMD) /**< Unrecognized Command Error. */
+ENUM_VAL(MSG_UNKNOWNPARAM) /**< Unrecognized Parameter Error. */
+ENUM_VAL(MSG_UNKNOWNBRKPT) /**< Unrecognized Breakpoint Error. */
+ENUM_END(dbg_msg_errno)
+
+/** Register Enums
+ *
+ * Register Enums.
+ * Refer to eCOS's arm_stub.h for enum values
+ */
+ENUM_BEGIN
+ENUM_VALASSIGN(REG_R0, 0) /**< User Reg R0 */
+ENUM_VAL(REG_R1) /**< User Reg R1 */
+ENUM_VAL(REG_R2) /**< User Reg R2 */
+ENUM_VAL(REG_R3) /**< User Reg R3 */
+ENUM_VAL(REG_R4) /**< User Reg R4 */
+ENUM_VAL(REG_R5) /**< User Reg R5 */
+ENUM_VAL(REG_R6) /**< User Reg R6 */
+ENUM_VAL(REG_R7) /**< User Reg R7 */
+ENUM_VAL(REG_R8) /**< User Reg R8 */
+ENUM_VAL(REG_R9) /**< User Reg R9 */
+ENUM_VAL(REG_R10) /**< User Reg R10 */
+ENUM_VAL(REG_R11) /**< User Reg R11 */
+ENUM_VAL(REG_R12) /**< User Reg R12 */
+ENUM_VAL(REG_SP) /**< Previous Mode SP (R13) */
+ENUM_VAL(REG_LR) /**< Previous Mode LR (R14) */
+ENUM_VAL(REG_PC) /**< Program Counter (R15) */
+ENUM_VALASSIGN(REG_FPSCR, 24) /**< Previous Mode FPSCR (dummy) */
+ENUM_VAL(REG_CPSR) /**< Previous Mode CPSR */
+
+ENUM_END(register_enum_t)
+
+
+#endif /* __DEBUG_INTERNALS_H__ */
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_macros.h b/AT91SAM7S256/armdebug/Debugger/debug_macros.h
new file mode 100644
index 0000000..75d6299
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_macros.h
@@ -0,0 +1,386 @@
+/** @file debug_macros.h
+ * @brief internal macros used by debug_stub routines
+ *
+ */
+
+/* Copyright (C) 2007-2010 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
+ *
+ */
+
+#ifndef __DEBUG_MACROS_H__
+#define __DEBUG_MACROS_H__
+
+
+
+/** @addtogroup debug_macros */
+/*@{*/
+
+/* _dbg_jumpTableHandler
+ * Call Jump Table Routine based on Index
+ * On entry:
+ * jumptableaddr is the address (constant) of the Jump Table
+ * jumpreg is the register used to perform the indirect jump
+ * indexreg contains jump table index value
+ */
+ .macro _dbg_jumpTableHandler jumptableaddr, jumpreg, indexreg
+
+ ldr \jumpreg, =\jumptableaddr
+ ldr \jumpreg, [\jumpreg, \indexreg, lsl #2]
+ mov lr, pc
+ bx \jumpreg /* Call Command Handler Routine */
+ .endm
+
+
+/* _dbg_thumbDecodeEntry
+ * Load Thumb Instruction Decoder Entry
+ * On entry:
+ * instrreg is the register to load the instruction into
+ * instrmask is the register to load the instruction mask into
+ * codehandler is the register to load the code handling routine into
+ * indexreg contains decode table index value
+ * NOTE: instrreg, instrmask, codehandler must be in increasing register number order
+ */
+ .macro _dbg_thumbDecodeEntry instrreg, instrmask, codehandler, indexreg
+
+ ldr \instrmask, =debug_thumbDecodeTable /* Temporary register */
+ add \instrmask, \instrmask, \indexreg, lsl #3
+ ldm \instrmask, {\instrreg, \codehandler} /* LSHW: IID, MSHW: IBM */
+ mov \instrmask, \instrreg, lsr #16
+ mov \instrreg, \instrreg, lsl #16
+ mov \instrreg, \instrreg, lsr #16 /* Keep HLFWORD0 containing instruction */
+ .endm
+
+/* _dbg_armDecodeEntry
+ * Load ARM Instruction Decoder Entry
+ * On entry:
+ * instrreg is the register to load the instruction into
+ * instrmask is the register to load the instruction mask into
+ * codehandler is the register to load the code handling routine into
+ * indexreg contains decode table index value
+ * NOTE: instrreg, instrmask, codehandler must be in increasing register number order
+ */
+ .macro _dbg_armDecodeEntry instrreg, instrmask, codehandler, indexreg
+
+ ldr \instrmask, =debug_thumbDecodeTable /* Temporary register */
+ add \instrmask, \instrmask, \indexreg, lsl #3
+ add \instrmask, \instrmask, \indexreg, lsl #2 /* 12 byte entries */
+ ldm \instrmask, {\instrreg, \instrmask, \codehandler}
+ .endm
+
+/* _asciiz
+ * Terminate string given string buffer pointer in \strptr
+ * scratchreg is used as a scratch register (destroyed)
+ *
+ */
+ .macro _asciiz strptr, scratchreg
+ mov \scratchreg, #0 /* ASCIIZ character */
+ strb \scratchreg, [\strptr] /* Terminate ASCII string */
+ .endm
+
+
+/* _dbg_stpcpy
+ * _dbg_stpcpy macro
+ * On entry:
+ * deststrptr: Destination string
+ * sourcestrptr: Source string
+ * scratchreg: scratch register for copying
+ * On exit:
+ * deststrptr: Pointer to ASCIIZ character in destination string
+ * sourcestrptr: Pointer to next character slot in source string (after ASCIIZ)
+ * scratchreg: destroyed
+ */
+ .macro _dbg_stpcpy deststrptr, sourcestrptr, scratchreg
+1: ldrb \scratchreg, [\sourcestrptr], #1
+ strb \scratchreg, [\deststrptr], #1
+ teq \scratchreg, #0
+ bne 1b
+ sub \deststrptr, \deststrptr, #1 /* Adjust Destination string pointer to point at ASCIIZ character */
+ .endm
+
+/* _dbg_memcpy
+ * _dbg_stpcpy macro
+ * On entry:
+ * deststrptr: Destination string
+ * sourcestrptr: Source string
+ * sizereg: Number of bytes to copy
+ * scratchreg: scratch register for copying
+ * On exit:
+ * deststrptr: Pointer to next character slot in destination string
+ * sourcestrptr: Pointer to next character slot in source string
+ * sizereg, scratchreg: destroyed
+ */
+ .macro _dbg_memcpy deststrptr, sourcestrptr, sizereg, scratchreg
+1: ldrb \scratchreg, [\sourcestrptr], #1
+ strb \scratchreg, [\deststrptr], #1
+ subs \sizereg, \sizereg, #1
+ bne 1b
+ .endm
+
+/* _dbg_outputAckOnlyFlag
+ * Return Flag ('+') for Continue or Step
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R1: destroyed
+ * R2: destroyed
+ */
+ .macro _dbg_outputAckOnlyFlag
+ ldr r0, =debug_OutMsgBuf
+ ldr r1, =debug_AckOnlyFlag /* ASCIIZ terminated */
+ _dbg_stpcpy r0, r1, r2
+ .endm
+
+
+/* _dbg_outputRetransmitFlag
+ * Return Flag ('-') for Checksum Error (retransmission needed)
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R1: destroyed
+ * R2: destroyed
+ */
+ .macro _dbg_outputRetransmitFlag
+ ldr r0, =debug_OutMsgBuf
+ ldr r1, =debug_RetransmitFlag /* ASCIIZ terminated */
+ _dbg_stpcpy r0, r1, r2
+ .endm
+
+/* _dbg_outputMsgValidResponse
+ * Return Message with valid response ('+$')
+ * On exit:
+ * R0: Pointer to Output Buffer next character slot location
+ * R1: destroyed
+ * R2: destroyed
+ */
+ .macro _dbg_outputMsgValidResponse
+ ldr r0, =debug_OutMsgBuf
+ ldr r1, =debug_ValidResponsePrefix
+ _dbg_stpcpy r0, r1, r2
+ .endm
+
+
+/* _dbg_outputMsgStatusOk
+ * Return Message with Ok ('+$OK') status
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R1: destroyed
+ * R2: destroyed
+ */
+ .macro _dbg_outputMsgStatusOk
+ ldr r0, =debug_OutMsgBuf
+ ldr r1, =debug_OkResponse /* ASCIIZ terminated */
+ _dbg_stpcpy r0, r1, r2
+ .endm
+
+/* __dbg_outputErrMsg
+ * Internal Routine called to generate error messages
+ * Return Message with Error ('+$ENN') status
+ * On entry:
+ * R1: error code
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R1: destroyed
+ * R2: destroyed
+ * R3: destroyed
+ */
+ .macro __dbg_outputErrMsg
+ ldr r0, =debug_OutMsgBuf
+ ldr r2, =debug_ErrorResponsePrefix
+ _dbg_stpcpy r0, r2, r3
+ bl byte2ascii /* R0 points to buffer position after byte value */
+ _asciiz r0, r1
+ .endm
+
+/* _dbg_outputMsgStatusErr
+ * Return Message with Error ('+$ENN') status
+ * On entry:
+ * R0: error code
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R1: destroyed
+ * R2: destroyed
+ * R3: destroyed
+ */
+ .macro _dbg_outputMsgStatusErr
+ mov r1, r0
+ __dbg_outputErrMsg
+ .endm
+
+/* _dbg_outputMsgStatusErrCode
+ * Return Message with Error ('+$ENN') status
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R1: destroyed
+ * R2: destroyed
+ */
+ .macro _dbg_outputMsgStatusErrCode errcode
+ mov r1, #\errcode
+ __dbg_outputErrMsg
+ .endm
+
+/* _dbg_outputMsgStatusSig
+ * Return Message with Signal ('+$SNN') status
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R1: destroyed
+ * R2: destroyed
+ */
+ .macro _dbg_outputMsgStatusSig statuscode
+ ldr r0, =debug_OutMsgBuf
+ ldr r1, =debug_SignalResponsePrefix
+ _dbg_stpcpy r0, r1, r2
+ mov r1, #\statuscode
+ bl byte2ascii /* R0 points to buffer position after byte value */
+ _asciiz r0, r1
+ .endm
+
+/* _regenum2index
+ * Convert register enum to debugger stack index
+ *
+ * On entry:
+ * indexenum: enum representing Register to access
+ * indexreg: register to be used to store the debugger stack index value (0-max index)
+ * On exit:
+ * indexreg contains debugger stack index value (0-max index)
+ */
+ .macro _regenum2index indexenum, indexreg
+ add \indexreg, \indexenum, #DBGSTACK_USERREG_INDEX /* Convert register index to Debug Stack index */
+ .endm
+
+/* _getdbgregisterfromindex
+ * Retrieve register contents from debugger stack given index
+ *
+ * On entry:
+ * indexreg contains debugger stack index value (0-max index)
+ * On exit:
+ * indexreg: Breakpoint index (preserved)
+ * contentsreg: Register Contents for given index
+ */
+ .macro _getdbgregisterfromindex indexreg, contentsreg
+ ldr \contentsreg, =__debugger_stack_bottom__
+ ldr \contentsreg, [\contentsreg, \indexreg, lsl #2]
+ .endm
+
+/* _setdbgregisterfromindex
+ * Store register contents to debugger stack given index
+ *
+ * On entry:
+ * indexreg contains debugger stack index value (0-max index)
+ * contentsreg: Register Contents for given index
+ * addressreg: Scratch register for address pointer
+ * On exit:
+ * indexreg: Breakpoint index (preserved)
+ * contentsreg: Register Contents for given index
+ */
+ .macro _setdbgregisterfromindex indexreg, contentsreg, addressreg
+ ldr \addressreg, =__debugger_stack_bottom__
+ str \contentsreg, [\addressreg, \indexreg, lsl #2]
+ .endm
+
+
+/* _index2bkptindex_addr
+ * Convert Breakpoint index to breakpoing entry address
+ *
+ * On entry:
+ * indexreg contains breakpoint index value
+ * On exit:
+ * indexreg: Breakpoint index (preserved)
+ * addrreg: Breakpoint Entry Address
+ */
+ .macro _index2bkptindex_addr indexreg, addrreg
+ ldr \addrreg, =__breakpoints_start__
+ add \addrreg, \addrreg, \indexreg, lsl #3 /* Calculate Breakpoint Entry Address */
+ .endm
+
+/* _dbg_getstate
+ * Get Debugger State
+ * On exit:
+ * reg: Debugger State enum
+ */
+ .macro _dbg_getstate reg
+ ldr \reg, =debug_state
+ ldrb \reg, [\reg]
+ .endm
+
+/* _dbg_setstate
+ * Set Debugger State to given value
+ * On exit:
+ * r0, r1: destroyed
+ */
+ .macro _dbg_setstate state
+ mov r0, #\state
+ ldr r1, =debug_state
+ strb r0, [r1]
+ .endm
+
+/* _dbg_getmode
+ * Get Debugger Mode
+ * On exit:
+ * reg: Debugger Mode (Boolean)
+ */
+ .macro _dbg_getmode reg
+ ldr \reg, =debug_mode
+ ldrb \reg, [\reg]
+ .endm
+
+/* _dbg_setmode
+ * Set Debugger Mode to given value
+ * On exit:
+ * r0, r1: destroyed
+ */
+ .macro _dbg_setmode mode
+ mov r0, #\mode
+ ldr r1, =debug_mode
+ strb r0, [r1]
+ .endm
+
+/* _dbg_get_bkpt_type
+ * Get Breakpoint Type
+ * On exit:
+ * reg: Breakpoint Type
+ */
+ .macro _dbg_get_bkpt_type reg
+ ldr \reg, =debug_bkpt_type
+ ldrb \reg, [\reg]
+ .endm
+
+/* _dbg_set_bkpt_type
+ * Set Breakpoint Type to given value
+ * On exit:
+ * r0, r1: destroyed
+ */
+ .macro _dbg_set_bkpt_type bkpt_type
+ mov r0, #\bkpt_type
+ ldr r1, =debug_bkpt_type
+ strb r0, [r1]
+ .endm
+
+
+
+/* _dbg_getcurrbkpt_index
+ * Get current breakpoint index
+ * On exit:
+ * reg: Breakpoint index
+ */
+ .macro _dbg_getcurrbkpt_index reg
+ ldr \reg, =debug_curr_breakpoint
+ ldrb \reg, [\reg]
+ .endm
+
+/* _dbg_setcurrbkpt_index
+ * Set current breakpoint index
+ * On exit:
+ * r1: destroyed
+ */
+ .macro _dbg_setcurrbkpt_index reg
+ ldr r1, =debug_curr_breakpoint
+ strb \reg, [r1]
+ .endm
+
+ /*@}*/
+
+#endif /* __DEBUG_MACROS_H__ */
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
new file mode 100644
index 0000000..f00e99d
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
@@ -0,0 +1,288 @@
+/** @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__
+
+#include "debug_internals.h"
+#include "debug_macros.h"
+#include "debug_stub.h"
+
+ .code 32
+ .align 4
+ .global dbg__runloopTasks
+ .global dbg__reboot
+
+#ifdef __NXOS__
+/****************************************************************************
+ *
+ * NxOS Run Loop
+ *
+ ****************************************************************************/
+dbg__runloopTasks:
+/* Currently, there's nothing that needs to be done in the NxOS Run Loop */
+ bx lr
+
+#else
+/****************************************************************************
+ *
+ * NXT Firmware Run Loop
+ *
+ ****************************************************************************/
+ .extern cCommCtrl
+
+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__
+ .extern nx_core_reset
+/****************************************************************************
+ *
+ * NxOS Reboot Routine
+ *
+ ****************************************************************************/
+ dbg__reboot:
+ b nx_core_reset /* Reboot Brick, won't return */
+
+#else
+ .extern dIOCtrlSetPower
+ .extern dIOCtrlSetPwm
+ .extern dIOCtrlTransfer
+ .equ BOOT, 0xA55A
+ .equ POWERDOWN, 0x5A00
+/****************************************************************************
+ *
+ * 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 */
+
+#if 1
+ /* Powerdown sequence */
+ ldr r0, =((POWERDOWN >> 8) & 0xFF)
+ ldr r1, =dIOCtrlSetPower
+ mov lr,pc
+ bx r1
+#endif
+
+#if 0
+ /* 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__
+/****************************************************************************
+ *
+ * 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(comm_chan_t channel);
+ *
+ * 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)
+ */
+
+ ldr r3, =debug_nxtCommChannel
+ str r0, [r3] /* Keep track of which communications link was used (USB/Bluetooth) */
+
+ /* Check our current operating mode */
+ mov r0, #FALSE /* Setup Default Return value (False) */
+ mrs r3, cpsr /* Copy CPSR to r3 */
+ and r3, r3, #CPSR_MODE /* Get current mode */
+ teq r3, #MODE_ABT /* Are we in Abort (Debug) mode? */
+ 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 /* setup Debugger Message Buffers, validate input, CPSR returned in R0 */
+ _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
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_stack.ld b/AT91SAM7S256/armdebug/Debugger/debug_stack.ld
new file mode 100644
index 0000000..8fc4cb7
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_stack.ld
@@ -0,0 +1,15 @@
+/* The following linker definitions should be placed in the stack section */
+
+ /* debugger state */
+ __debugger_stack_bottom__ = . ;
+ . += 0x48; /* 16 previous mode registers + SPSR + UNDEF Next Instruction Address */
+ __debugger_stack__ = .;
+ __debugger_stack_top__ = . ;
+
+ /* breakpoints */
+ __breakpoints_start__ = . ;
+ . += 0x40; /* Single Stepping Breakpoint + 7 Breakpoints */
+ __breakpoints_end__ = . ;
+
+/* Symbols */
+ __breakpoints_num__ = (__breakpoints_end__ - __breakpoints_start__) / 8;
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_stub.S b/AT91SAM7S256/armdebug/Debugger/debug_stub.S
new file mode 100644
index 0000000..e32c2dc
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_stub.S
@@ -0,0 +1,2976 @@
+/** @file debug_stub.S
+ * @brief ARM Breakpoint Debugger support routines
+ *
+ */
+
+/* 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
+ *
+ */
+
+ /* GDB sparc-stub.c comments header included below to document GDB Server Remote protocol */
+ /* This header has been modified to include additional commands not documented in the header stub */
+
+ /****************************************************************************
+
+ THIS SOFTWARE IS NOT COPYRIGHTED
+
+ HP offers the following for use in the public domain. HP makes no
+ warranty with regard to the software or it's performance and the
+ user accepts the software "AS IS" with all faults.
+
+ HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
+ TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+****************************************************************************/
+
+/****************************************************************************
+ * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
+ *
+ * Module name: remcom.c $
+ * Revision: 1.34 $
+ * Date: 91/03/09 12:29:49 $
+ * Contributor: Lake Stevens Instrument Division$
+ *
+ * Description: low level support for gdb debugger. $
+ *
+ * Considerations: only works on target hardware $
+ *
+ * Written by: Glenn Engel $
+ * ModuleState: Experimental $
+ *
+ * NOTES: See Below $
+ *
+ * Modified for SPARC by Stu Grossman, Cygnus Support.
+ *
+ * This code has been extensively tested on the Fujitsu SPARClite demo board.
+ *
+ * To enable debugger support, two things need to happen. One, a
+ * call to set_debug_traps() is necessary in order to allow any breakpoints
+ * or error conditions to be properly intercepted and reported to gdb.
+ * Two, a breakpoint needs to be generated to begin communication. This
+ * is most easily accomplished by a call to breakpoint(). Breakpoint()
+ * simulates a breakpoint by executing a trap #1.
+ *
+ *************
+ *
+ * The following gdb commands are supported:
+ *
+ * command function Return value
+ *
+ * g return the value of the CPU registers hex data or ENN
+ * GrrrrRRRR.. set the value of the CPU registers OK or ENN
+ * where register values are given as
+ * 32-bit hex values in the sequence:
+ * User R0, R1, ..., R15, CPSR
+ * px get the value of one register (x) hex data or ENN
+ * Px=rrrr set the value of one register (x) to OK or ENN
+ * 32-bit hex value rrrr.
+ * x = ['0','F'] for R0-R15,
+ * '18' for FPSCR (dummy), '19' for User CPSR
+ *
+ * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
+ * MAA..AA,LLLL:bb..bb
+ * Write LLLL bytes at address AA.AA OK or ENN
+ *
+ * D Detach (equivalent to continue Ack Only
+ * at current address)
+ * c Resume at current address SNN ( signal NN)
+ * cAA..AA Continue at address AA..AA SNN
+ *
+ * s Step one instruction SNN
+ * sAA..AA Step one instruction from AA..AA SNN
+ *
+ * k kill
+ *
+ * ? What was the last sigval ? SNN (signal NN)
+ *
+ * zt,AA..AA,k Remove a Breakpoint of type t at addr OK or ENN
+ * AA..AA of kind k
+ * Zt,AA..AA,k Insert a Breakpoint of type t at addr OK or ENN
+ * AA..AA of kind k
+ * t 0: memory breakpoint
+ * 1: hardware breakpoint
+ * 2: write watchpoint
+ * 3: read watchpoint
+ * 4: access watchpoint
+ * k: 2 (16-bit Thumb), 3 (32-bit Thumb2)
+ * or 4 (32-bit ARM) for t=[0,1]
+ * Num. bytes to watch for t=[2,4]
+ *
+ * All commands and responses are sent with a packet which includes a
+ * checksum. A packet consists of
+ *
+ * $<packet info>#<checksum>.
+ *
+ * where
+ * <packet info> :: <characters representing the command or response>
+ * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
+ *
+ * When a packet is received, it is first acknowledged with either '+' or '-'.
+ * '+' indicates a successful transfer. '-' indicates a failed transfer.
+ *
+ * Example:
+ *
+ * Host: Reply:
+ * $m0,10#2a +$00010203040506070809101112131415#42
+ *
+ ****************************************************************************/
+ /* Modified GDB Server Remote Protocol definition from GDB's sparc-stub.c Comment Header included above
+ * Additional commands from GDB Reference Appendix D.2
+ *
+ * Note: ARMDEBUG can only implement Memory Breakpoints t=0. Hardware breakpoints requires a JTAG debugger.
+ * Currently, watchpoints are not implemented as they require hardware support as well (need verification).
+ *
+ * GDB requires command parameters to be specified as Big Endian values.
+ * However, the read/write register command expect the register contents to be specified in target byte order.
+ * The default target byte order is Little Endian for the AT91SAM7xxx processor in the NXT.
+ * If Big Endian target byte order is required, the __BIG_ENDIAN__ preprocessor label should be defined.
+ */
+
+/* FIXME: The Hex value arguments passed by GDB does not have fixed lengths! Although the standard says
+ * there should be x digits, it does not follow this requirement. e.g., register index.
+ */
+
+
+#define __ASSEMBLY__
+#include "debug_stub.h"
+#include "debug_internals.h"
+#include "debug_macros.h"
+
+ /* Hexutils function references */
+ .extern hex2char
+ .extern char2hex
+ .extern byte2ascii
+ .extern halfword2ascii_be
+ .extern halfword2ascii_le
+ .extern word2ascii_be
+ .extern word2ascii_le
+ .extern ascii2hex_varlen_be
+ .extern ascii2byte
+ .extern ascii2halfword_be
+ .extern ascii2halfword_le
+ .extern ascii2word_be
+ .extern ascii2word_le
+
+/* Macro definitions */
+
+/* _check_msgseparator
+ * Look for separator ','
+ * On entry:
+ * bufferptr: points to the parameter buffer [can't be R0]
+ * On exit:
+ * R0: destroyed
+ * bufferptr: points to the next character location in the parameter buffer
+ * Flags: Updated
+ */
+
+ .macro _check_msgseparator bufferptr
+ ldrb r0, [\bufferptr], #1 /* get separator */
+ cmp r0, #MSGBUF_SEPCHAR
+ .endm
+
+/* _check_msgargument
+ * Look for argument ':'
+ * On entry:
+ * bufferptr: points to the parameter buffer [can't be R0]
+ * On exit:
+ * R0: destroyed
+ * bufferptr: points to the next character location in the parameter buffer
+ * Flags: Updated
+ */
+
+ .macro _check_msgargument bufferptr
+ ldrb r0, [\bufferptr], #1 /* get separator */
+ cmp r0, #MSGBUF_ARGCHAR
+ .endm
+
+/* _check_msgassignment
+ * Look for assignment '='
+ * On entry:
+ * bufferptr: points to the parameter buffer [can't be R0]
+ * On exit:
+ * R0: destroyed
+ * bufferptr: points to the next character location in the parameter buffer
+ * Flags: Updated
+ */
+
+ .macro _check_msgassignment bufferptr
+ ldrb r0, [\bufferptr], #1 /* get separator */
+ cmp r0, #MSGBUF_SETCHAR
+ .endm
+
+.bss
+.align 4
+debug_InMsgBuf:
+ .space MSGBUF_SIZE,0
+debug_OutMsgBuf:
+ .space MSGBUF_SIZE,0
+
+ /* Make Debugger State accessible from other modules */
+ .global debug_state
+ .global debug_mode
+ .global debug_bkpt_type
+ .global debug_curr_breakpoint
+
+debug_state:
+ .byte 0x0 /* dbg_state_t variable */
+debug_mode:
+ .byte 0x0 /* Boolean variable */
+debug_bkpt_type:
+ .byte 0x0 /* bkpt_type_t variable */
+debug_curr_breakpoint:
+ .byte 0x0
+
+.data
+.align 4
+debug_RetransmitFlag:
+ .byte '-',0
+
+debug_AckOnlyFlag:
+ .byte '+',0
+
+debug_ValidResponsePrefix:
+ .byte '+','$',0
+
+debug_ErrorResponsePrefix:
+ .byte '+','$','E',0
+
+debug_SignalResponsePrefix:
+ .byte '+','$','S',0
+
+debug_OkResponse:
+ .byte '+','$','O','K',0
+
+/* The CmdIndexTable and CmdJumpTable must be kept in sync */
+debug_cmdIndexTable:
+ .byte 'g','G','p','P','m','M','D','c','s','k','z','Z','?','q','Q',0
+
+/* Command Handlers
+ * On entry:
+ * R0: Input Message Parameter Buffer address pointer (points to contents after '$' and '<cmdchar>')
+ */
+.align 4
+debug_cmdJumpTable:
+ .word _dbg__cmd_GetAllRegs /* 'g' */
+ .word _dbg__cmd_SetAllRegs /* 'G' */
+ .word _dbg__cmd_GetOneReg /* 'p' */
+ .word _dbg__cmd_SetOneReg /* 'P' */
+ .word _dbg__cmd_ReadMem /* 'm' */
+ .word _dbg__cmd_WriteMem /* 'M' */
+ .word _dbg__cmd_Detach /* 'D' */
+ .word _dbg__cmd_Continue /* 'c' */
+#ifdef __NXOS__
+ .word _dbg__cmd_Step /* 's' */
+#else
+ /* NXT Firmware does not support Stepping */
+ .word _dbg__nop /* 's' */
+#endif
+ .word _dbg__cmd_Kill /* 'k' */
+ .word _dbg__cmd_RemoveBreakpoint /* 'z' */
+ .word _dbg__cmd_InsertBreakpoint /* 'Z' */
+ .word _dbg__cmd_Status /* '?' */
+ .word _dbg__cmd_Query /* 'q' */
+ .word _dbg__nop /* 'Q' */
+ .word 0
+
+/* Rm Shifted Shift Type Jump Table
+ * On entry:
+ * R0: Register Rm
+ * R1: Shift/Rotate Amount
+ * On exit:
+ * R0: RmShifted result
+ *
+ */
+debug_regShiftJumpTable:
+ .word _reg_lsl /* 00 */
+ .word _reg_lsr /* 01 */
+ .word _reg_asr /* 02 */
+ .word _reg_ror /* 03 */
+ .word _reg_rrx /* 04 */
+
+/* Data Processing Instruction Jump Table
+ * On entry:
+ * R0: Register Rn (Operand 1) value
+ * R1: Operand 2 value
+ * R2: Default Next Instruction Address
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: Calculated result
+ * R1, R2, R3: Destroyed
+ *
+ */
+debug_dataInstrJumpTable:
+ .word _opcode_and /* 00 */
+ .word _opcode_eor /* 01 */
+ .word _opcode_sub /* 02 */
+ .word _opcode_rsb /* 03 */
+ .word _opcode_add /* 04 */
+ .word _opcode_adc /* 05 */
+ .word _opcode_sbc /* 06 */
+ .word _opcode_rsc /* 07 */
+ .word _opcode_tst /* 08 */
+ .word _opcode_teq /* 09 */
+ .word _opcode_cmp /* 0A */
+ .word _opcode_cmn /* 0B */
+ .word _opcode_orr /* 0C */
+ .word _opcode_mov /* 0D */
+ .word _opcode_bic /* 0E */
+ .word _opcode_mvn /* 0F */
+
+
+/*
+ * To determine the next instruction to execute, we need to check current (breakpointed) instruction
+ * and determine whether it will be executed or not. This necessitates a mini instruction decoder
+ * that can check the type of instruction, as well as if it'll affect the PC.
+ * The instruction decoder used here is table based. Each entry in the table consists of:
+ * Instruction Identifier (IID), Instruction Bitmask (IBM), Instruction Handler Address (IHA)
+ * Null entries are placed at the end of the table.
+ *
+ * This allows for a flexible approach to handling instructions that we're interested in, at the expense
+ * of memory usage.
+ *
+ * For ARM, the IID & IBM are both 4 bytes, whereas the Thumb IID & IBM are 2 bytes.
+ * The IHA is always 4 bytes.
+ */
+
+/* ARM Instruction Decode Table
+ * .word IID, IBM, IHA (12 bytes)
+ */
+
+debug_armDecodeTable:
+ .word 0x0000f000, 0x0c00f000, _arm_data_instr_handler /* Data Processing instr with Rd = R15 */
+ .word 0x012fff10, 0x0ffffff0, _arm_bx_blx_handler /* BX or BLX. Note v4t does not have BLX instr */
+ .word 0x0410f000, 0x0410f000, _arm_ldr_pc_handler /* LDR with Rd = PC */
+/* .word 0x06000010, 0x0e000010, _arm_undef_handler */ /* Undefined instr: shouldn't occur, as it would've been trapped already. See _dbg_following_instruction_addr */
+ .word 0x08108000, 0x0e108000, _arm_ldm_pc_handler /* LDM {pc} */
+ .word 0x0a000000, 0x0e000000, _arm_b_bl_blx_handler /* B, BL or BLX. Note v4t does not have BLX instr */
+ .word 0x0c000000, 0x0c000000, _arm_coproc_swi_handler /* Coprocessor instr or SWI */
+ .word 0x0,0x0,0x0 /* Null Entry */
+
+/* Thumb Instruction Decode Table
+ * .hword IID, IBM
+ * .word IHA (8 bytes)
+ */
+
+debug_thumbDecodeTable:
+ .hword 0x4700, 0xff07
+ .word _thumb_bx_blx_handler /* BX or BLX. Note: b7 (H1) is not matched in the mask */
+ .hword 0xbd00, 0xff00
+ .word _thumb_poppc_handler /* PUSH/POP, specifically POP {Rlist,PC} */
+ .hword 0xd000, 0xf000
+ .word _thumb_bcond_swi_handler /* B<cond> or SWI */
+ .hword 0xe000, 0xf800
+ .word _thumb_b_handler /* B */
+ .hword 0xf000, 0xf000
+ .word _thumb_long_bl_blx_handler /* Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr */
+ .hword 0x0,0x0
+ .word 0x0 /* Null Entry */
+
+/* ARM Condition Code Mapping Table
+ * Converts Instruction encoding to SPSR Flags.
+ * b31 b30 b29 b28
+ * N Z C V
+ * Indexed according to Instruction Encoding order (pg 30, Table 6, ATMEL ARM7TDMI Data Sheet)
+ * Condition Code stored in MSN(set), LSN(clr) order
+ * Note1: 0x00 = AL. NV is deprecated, treat as AL
+ * Note2: 0xFF indicates that the condition checks needs to be handled separately (complex checks)
+ *
+ * EQ: Z set
+ * NE: Z clr
+ * HS/CS: C set
+ * LO/CC: C clr
+ * MI: N set
+ * PL: N clr
+ * VS: V set
+ * VC: V clr
+ * HI: C set AND Z clr
+ * LS: C clr AND Z set
+ */
+
+
+debug_armCondCodeTable:
+ /* EQ, NE, HS/CS, LO/CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV */
+ .byte 0x40, 0x04, 0x20, 0x02, 0x80, 0x08, 0x10, 0x01, 0x24, 0x42, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00
+
+/* ARM Complex Condition Code Mapping Table
+ * Converts Instruction encoding to SPSR Flags.
+ * b31 b30 b29 b28
+ * N Z C V
+ * Indexed according to Instruction Encoding order (pg 30, Table 6, ATMEL ARM7TDMI Data Sheet)
+ * for GE, LT, GT and LE instructions only
+ * Condition Code stored in the following order:
+ * b7 b6 b5 b4 b3 b2 b1 b0
+ * - - - ANDOR - Z set AND N==V (bit set = 1)
+ * - - - ANDOR - Z clr OR N!=V (bit clr = 0)
+ *
+ * GE: N == V
+ * LT: N != V
+ * GT: Z clr AND (N == V)
+ * LE: Z set OR (N != V)
+ */
+
+#define COMPLEX_CONDCODE_START 0x0A
+#define COMPLEX_CONDCODE_NEQV_MASK 0x01
+#define COMPLEX_CONDCODE_AND_MASK 0x02
+#define COMPLEX_CONDCODE_ZSET_MASK 0x04
+#define COMPLEX_CONDCODE_ANDOR_MASK 0x10
+
+#define COMPLEX_CONDCODE_NFLAG 0x08
+#define COMPLEX_CONDCODE_ZFLAG 0x04
+#define COMPLEX_CONDCODE_CFLAG 0x02
+#define COMPLEX_CONDCODE_VFLAG 0x01
+
+
+debug_armComplexCCTable:
+ /* GE, LT, GT, LE */
+ .byte 0x01, 0x00, 0x15, 0x12
+
+.code 32
+.text
+.align 4
+ .extern __breakpoints_num__
+ .extern dbg__getDebugMsg /* Read a message from the communications link */
+ .extern dbg__putDebugMsg /* Write a message to the communications link */
+ .extern dbg__sendAckOrNak /* Send Ack or Nak to indicate success/failure of message receipt */
+ .extern dbg__runloopTasks /* Platform specific Run Loop processing */
+
+
+/* The Debugger Interface can handle a total of (n-1) Breakpoint States and 1 Single Stepping State,
+ * where n is a power of 2. The value of n is given by __breakpoints_num__ defined in the linker file.
+ *
+ * In addition, a Debugger Stack contains the User Mode Register Stack Frame + SPSR + Bkpt Instr Addr.
+ * These are currently stored in the .stack area in RAM, so there is no fixed address
+ * location that is used for this purpose.
+ *
+ * The Breakpoint feature assumes that the program is executed in RAM. It is not possible
+ * to set dynamic breakpoints for programs executed from Flash in the AT91SAM7S which lacks
+ * instruction breakpointing support in hardware without using JTAG. The only type of breakpoints
+ * that can be supported in Flash based programs are Static (predefined) breakpoints inserted into
+ * the code.
+ *
+ * Each Breakpoint State i is a struct comprising the Breakpoint Address + Memory Contents
+ * stored in 8 bytes as:
+ * [High Memory Address]
+ * ADDR [i*8+4]: Memory Contents (32 bits)
+ * ADDR [i*8]: Breakpoint Address (31 bits, b0 = THUMB flag [not implemented yet])
+ * [Low Memory Address]
+ *
+ * A Non-zero Breakpoint Address means that the breakpoint is active, whereas the memory contents
+ * contains the instruction which resided at that address initially (now replaced by a BKPT <index>
+ * instruction).
+ * Note: Currently it is not possible to resume execution of a program with breakpoints enabled
+ * after a RESET, since the RESET will clear all contents of the stack, destroying the instruction
+ * contained in a given breakpoint.
+ * Fortunately the NXT will also need to reload the program into RAM so this is not expected to be
+ * an issue.
+ *
+ * The Memory Map for the Debugger State is as follows:
+ *
+ * [High Memory Address] __breakpoints_end__
+ * Breakpoint 07 State
+ * Breakpoint 06 State
+ * ...
+ * Breakpoint 02 State
+ * Breakpoint 01 State
+ * Single Step State __debugger_stack__ / __breakpoints_start__
+ * Previous Mode R15
+ * Previous Mode R14
+ * Previous Mode R13
+ * ...
+ * User Mode R02
+ * User Mode R01
+ * User Mode R00
+ * Previous Mode CPSR (UNDEF SPSR)
+ * UNDEF Next Instr Addr __debugger_stack_bottom__
+ * [Low Memory Address]
+ *
+ * Each Breakpoint State will initially be zeroed.
+ *
+ */
+ /* FIXME: The Debugger Stack Frame is probably not 100% consistent with the order that
+ GDB expects in the g/G messages. CSPR is probably located above R15 */
+
+/****************************************************************************
+ *
+ * GDB Debugger Init and Breakpoint Handler Routines
+ *
+ ****************************************************************************/
+ .code 32
+ .align 4
+ .global dbg__bkpt_init
+/* dbg__bkpt_init
+ * GDB set_debug_traps() routine
+ */
+dbg__bkpt_init:
+ push {lr}
+ bl _dbg__clear_breakpoints
+ mov r2, #0
+ ldr r1, =debug_curr_breakpoint
+ strb r2, [r1]
+ ldr r0, =debug_InMsgBuf
+ strb r2, [r0]
+ ldr r1, =debug_OutMsgBuf
+ strb r2, [r1]
+ bl dbg__comm_init /* Pass R0: Rx Buffer, R1: Tx Buffer to comm submodule */
+
+/* FIXME: Initialize other stuff here */
+ _dbg_setstate DBG_INIT
+ _dbg_setmode FALSE /* Debug Mode = False */
+ pop {lr}
+ bx lr /* Must return via BX; may have been called from Thumb mode (NXT Firmware) */
+
+
+/* _dbg__flush_icache
+ * Flush the Instruction cache
+ * Defined by GDB Stub, but not needed for ARMv4T architecture
+ */
+_dbg__flush_icache:
+ /* nop */
+ bx lr
+
+
+ .global dbg__thumb_bkpt_handler
+/* dbg__thumb_bkpt_handler
+ * GDB handle_exception() routine (Thumb Mode)
+ */
+dbg__thumb_bkpt_handler:
+/* On entry, r0 contains breakpoint index value */
+ /* mov r4, #BKPT16_AUTO_BKPT Redundant?! */
+ and r4, r0, #BKPT16_AUTO_BKPT /* keep AUTO flag value in r4 */
+ bic r0, r0, #BKPT16_AUTO_BKPT /* mask out AUTO flag */
+ _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */
+ ldr r1, =BKPT16_MANUAL_BKPT
+ teq r0, r1
+ beq _process_manual_breakpoint_thumb
+ ldr r1, =__breakpoints_num__
+ cmp r0, r1 /* Sanity check that index is in range */
+ bhs dbg__bkpt_offset_outofrange
+/* Valid index value found */
+ teq r4, #0 /* Check if AUTO flag set */
+ bne _process_auto_breakpoint
+/* else */
+ _dbg_set_bkpt_type DBG_NORMAL_BKPT_THUMB
+ b _process_normal_breakpoint
+
+ .global dbg__arm_bkpt_handler
+/* dbg__arm_bkpt_handler
+ * GDB handle_exception() routine (ARM Mode)
+ */
+dbg__arm_bkpt_handler:
+/* On entry, r0 contains breakpoint index value */
+ /* mov r4, #BKPT32_AUTO_BKPT Redundant?! */
+ and r4, r0, #BKPT32_AUTO_BKPT /* keep AUTO flag value in r4 */
+ bic r0, r0, #BKPT32_AUTO_BKPT /* mask out AUTO flag */
+ _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */
+ ldr r1, =BKPT32_MANUAL_BKPT
+ teq r0, r1
+ beq _process_manual_breakpoint_arm
+ ldr r1, =__breakpoints_num__
+ cmp r0, r1 /* Sanity check that index is in range */
+ bhs dbg__bkpt_offset_outofrange
+/* Valid index value found */
+ teq r4, #0 /* Check if AUTO flag set */
+ bne _process_auto_breakpoint
+/* else */
+ _dbg_set_bkpt_type DBG_NORMAL_BKPT_ARM
+/* b _process_normal_breakpoint */
+
+_process_normal_breakpoint:
+ bl _dbg__restore_breakpoints /* includes restoring single step */
+/* bl _dbg__restore_singlestep */
+ bl _dbg__clear_singlestep
+ bl _dbg__flush_icache
+ b dbg__bkpt_waitCMD
+
+_process_auto_breakpoint:
+/* Load Auto BKPT for Breakpoint index given in r0 */
+ _index2bkptindex_addr r0, r1 /* Calculate Breakpoint Entry Address */
+ ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */
+ teq r1, #0 /* Check that Breakpoint is active */
+ beq dbg__bkpt_inactive
+ bl _dbg__activate_one_breakpoint
+ bl _dbg__restore_singlestep
+ bl _dbg__clear_singlestep
+ _dbg_set_bkpt_type DBG_AUTO_BKPT
+ b _dbg__switch2undefmode
+
+/* _dbg__switch2undefmode
+ * Common internal routine to return execution to user program
+ */
+_dbg__switch2undefmode:
+ bl _dbg__flush_icache
+ msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Configure Undef Mode */
+ _dbg_setmode FALSE /* Debug Mode = False */
+ ldr lr, =resume_execution
+ mov pc, lr /* Exit via UNDEF mode */
+
+_process_manual_breakpoint_thumb:
+ _dbg_set_bkpt_type DBG_MANUAL_BKPT_THUMB
+ b dbg__bkpt_waitCMD
+
+_process_manual_breakpoint_arm:
+ _dbg_set_bkpt_type DBG_MANUAL_BKPT_ARM
+/* b dbg__bkpt_waitCMD */
+
+dbg__bkpt_inactive:
+/* b dbg__bkpt_waitCMD */
+
+dbg__bkpt_offset_outofrange:
+/* b dbg__bkpt_waitCMD */
+
+ .global dbg__bkpt_waitCMD
+/* dbg__bkpt_waitCMD
+ * GDB Stub Remote Command Handler
+ */
+
+/****************************************************************************
+ *
+ * GDB Server Command Processing Routines
+ *
+ ****************************************************************************/
+dbg__bkpt_waitCMD:
+ /* We enter this code section when a Breakpoint Triggers */
+ _dbg_setmode TRUE /* Debug Mode = True */
+ msr cpsr_c, #(MODE_ABT) /* Re-enable Interrupts */
+
+ _dbg_getstate r0
+ cmp r0, #DBG_CONFIGURED
+ blo dbg__bkpt_waitCMD_cont /* Not configured yet, don't send Breakpoint Signal Response */
+ bl _dbg__cmd_Status /* Send signal response to the GDB server */
+
+dbg__bkpt_waitCMD_cont:
+ bl dbg__runloopTasks /* Execute housekeeping tasks while in ABRT mode */
+ bl dbg__getDebugMsg /* Read new message from Debugger, buflen in R0, 0 if none, -1 if error, msgbuf pointer in R1 */
+ cmp r0, #0
+ beq dbg__bkpt_waitCMD_cont /* No message yet, do housekeeping tasks */
+ bgt _proc_command /* valid message, process it */
+ bl __dbg__procChecksumError /* Message invalid, checksum error? */
+ b dbg__bkpt_waitCMD_cont
+
+_proc_command:
+/* Message now has Ctrl-C or $<packet info>\0 */
+ mov r4, r1 /* Use R4 as buffer pointer */
+ ldrb r0, [r4], #1 /* Look for Ctrl-C or '$' */
+ teq r0, #MSGBUF_CTRLC
+ bne _dbg_check_gdb_command
+ /* Ctrl-C detected, do nothing (wait for next command from GDB) */
+#if 0
+ /* On entering the Debugger via Ctrl-C, _dbg__cmd_Status has already sent a reply, so just keep quiet */
+ bl __dbg__procAckOnly /* send Ack */
+#endif
+ b dbg__bkpt_waitCMD_cont
+
+_dbg_check_gdb_command:
+ teq r0, #MSGBUF_STARTCHAR
+ movne r0, #MSG_ERRFORMAT /* Message Format invalid (not '$') */
+ bne _dbg__cmdError /* Shouldn't happen */
+ ldrb r0, [r4], #1 /* Look for command char */
+ bl _dbg__cmdChar2Index /* Index in R0 */
+ mov r1, #CMDINDEX_OUTOFRANGE
+ teq r0, r1
+ bne _dbg__cmdExists /* Found valid command, execute it */
+_dbg_unknown_command:
+ bl _dbg__nop /* Command character not recognized, send empty response to GDB server */
+ b dbg__bkpt_waitCMD_cont
+
+#if 0
+ moveq r0, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */
+ beq _dbg__cmdError /* Send response to GDB server */
+#endif
+
+_dbg__cmdExists:
+ mov r3, r0 /* put Command Handler Index in R3 */
+ mov r0, r4 /* R0 now contains Input Message Buffer Parameter Pointer (previously in R4) */
+ _dbg_jumpTableHandler debug_cmdJumpTable, r2, r3 /* Call Command Handler Routine, use R2 as jump address pointer */
+ b dbg__bkpt_waitCMD_cont
+
+_dbg__cmdError:
+ _dbg_outputMsgStatusErr
+ bl dbg__putDebugMsg /* Send error response to the GDB server */
+ b dbg__bkpt_waitCMD_cont
+
+
+/* __dbg__procOkOnly
+ * Send OK to GDB due to Detach
+ * On entry:
+ * None
+ * On exit:
+ * r0-r3: destroyed
+ */
+__dbg__procOkOnly:
+ stmfd sp!, {lr}
+ _dbg_outputMsgStatusOk /* Acknowledge Detach command from GDB server */
+_cont_procOkOnly:
+ bl dbg__putDebugMsg /* Send OK response to the GDB server */
+ cmp r0, #0
+ beq _cont_procOkOnly_exit /* Sending of OK succeeded */
+ bl dbg__runloopTasks /* Service run loop tasks */
+ b _cont_procOkOnly /* Retry OK transmission */
+_cont_procOkOnly_exit:
+ ldmfd sp!, {pc}
+
+
+/* __dbg__procAckOnly
+ * Send Ack to GDB due to Continue or Step
+ * On entry:
+ * None
+ * On exit:
+ * r0-r3: destroyed
+ */
+__dbg__procAckOnly:
+ stmfd sp!, {lr}
+ _dbg_outputAckOnlyFlag
+ b _cont_sendAckOrNak /* Acknowledge Continue or Step command from GDB server */
+
+/* __dbg__procChecksumError
+ * Request Retransmission from GDB due to Checksum error
+ * On entry:
+ * None
+ * On exit:
+ * r0-r3: destroyed
+ */
+__dbg__procChecksumError:
+ stmfd sp!, {lr}
+ _dbg_outputRetransmitFlag
+ /* b _cont_sendAckOrNak */ /* Acknowledge Continue or Step command from GDB server */
+
+_cont_sendAckOrNak:
+ bl dbg__sendAckOrNak /* send Ack or Nak to GDB server */
+ cmp r0, #0
+ beq _cont_sendAckOrNak_exit /* Sending of Ack or Nak succeeded */
+ bl dbg__runloopTasks /* Service run loop tasks */
+ b _cont_sendAckOrNak /* Retry Ack or Nak transmission */
+_cont_sendAckOrNak_exit:
+ ldmfd sp!, {pc}
+
+/* _dbg__cmdChar2Index
+ * Convert Command Character to Jump Table Index
+ * On entry:
+ * r0: command character
+ * On exit:
+ * r0: jump table index (-1 for command not found)
+ * R1: destroyed
+ * R2: destroyed
+ * R3: destroyed
+ */
+_dbg__cmdChar2Index:
+ mov r1, r0 /* Copy command character to r1 */
+ mov r0, #0 /* Clear return value */
+ ldr r3, =debug_cmdIndexTable /* Convert command to index using r3 as Index Lookup Address Pointer */
+1: ldrb r2, [r3, r0] /* Get table entry */
+ teq r2, #0
+ moveq r0, #CMDINDEX_OUTOFRANGE /* End of Index Table, Not found */
+ beq _exit_cmdIndexTable
+ teq r1, r2
+ addne r0, #1 /* Increment Index */
+ bne 1b /* No match, skip to next command char */
+_exit_cmdIndexTable:
+ bx lr
+
+/* __dbg__cmdParamLen
+ * Determines the length of the parameter buffer for a given command
+ * On entry:
+ * R0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * On exit:
+ * R0: Address of parameter buffer (preserved)
+ * R1: length
+ */
+__dbg__cmdParamLen:
+ stmfd sp!, {r0,r2,lr} /* R2: scratch register */
+ mov r1, #0
+1: ldrb r2, [r0], #1
+ teq r2, #0
+ addne r1, r1, #1
+ bne 1b
+ ldmfd sp!, {r0,r2,pc}
+
+/* __dbg__procCmdOk
+ * Common subroutine exit stub to return Command Ok Status for Command Handlers
+ * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack.
+ *
+ */
+__dbg__procCmdOk:
+ _dbg_outputMsgStatusOk
+ b __dbg__sendDebugMsgExit
+
+/* __dbg__procUnimplementedError
+ * Common subroutine exit stub to handle Unimplemented GDB Command Error
+ * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack.
+ * Note: GDB Remote Protocol specifies returning blank message ('+$')
+ *
+ */
+__dbg__procUnimplementedError:
+ _dbg_outputMsgValidResponse
+ b __dbg__sendDebugMsgExit
+
+/* __dbg__procCmdParamError
+ * Common subroutine exit stub to handle Command Parameter Error for Command Handlers
+ * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack.
+ *
+ */
+__dbg__procCmdParamError:
+ mov r1, #MSG_UNKNOWNPARAM
+ b __dbg__procErrorMsg
+
+/* __dbg__procCmdReturnInputLengthError
+ * Common subroutine exit stub to handle Command Input Length Error for Command Handlers
+ * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack.
+ *
+ */
+__dbg__procCmdReturnInputLengthError:
+ mov r1, #MSG_ERRINLENGTH
+ b __dbg__procErrorMsg
+
+/* __dbg__procCmdReturnOutputLengthError
+ * Common subroutine exit stub to handle Command Return Output Error for Command Handlers
+ * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack.
+ *
+ */
+__dbg__procCmdReturnOutputLengthError:
+ mov r1, #MSG_ERROUTLENGTH
+ b __dbg__procErrorMsg
+
+/* __dbg__procBreakpointAddrError
+ * Common subroutine exit stub to handle Breakpoint Address Error for Breakpoint Insert/Remove Handlers
+ * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack.
+ *
+ */
+__dbg__procBreakpointAddrError:
+ mov r1, #MSG_UNKNOWNBRKPT
+ b __dbg__procErrorMsg
+
+
+__dbg__procErrorMsg:
+ __dbg_outputErrMsg
+ /* b __dbg__sendDebugMsgExit */
+
+__dbg__sendDebugMsgExit:
+ bl dbg__putDebugMsg /* Send error response to the GDB server */
+ ldmfd sp!, {pc}
+
+/* _dbg__cmd_Status
+ * Status Command Handler
+ * On entry:
+ * r0: parameter buffer (contents after '$' and '<cmdchar>')
+ * On exit:
+ * r0, r1, r2, r3: destroyed
+ */
+_dbg__cmd_Status:
+ stmfd sp!, {lr}
+ _dbg_outputMsgStatusSig 0x0 /* FIXME: Dummy Signal number */
+ b __dbg__sendDebugMsgExit
+
+/* _dbg__cmd_Query
+ * Query Command Handler
+ * On entry:
+ * r0: parameter buffer (contents after '$' and '<cmdchar>')
+ * [varied, see GDB General Packets query docs]
+ * http://sourceware.org/gdb/current/onlinedocs/gdb/General-Query-Packets.html
+ * On exit:
+ * r0, r1, r2, r3: destroyed
+ */
+_dbg__cmd_Query:
+ stmfd sp!, {lr}
+ _dbg_setstate DBG_CONFIGURED /* We have exchanged query messages with the GDB server */
+ b __dbg__procUnimplementedError /* FIXME: return an empty message to GDB (no modifiable settings) */
+
+
+/* _dbg__cmd_GetOneReg
+ * Get One Register Value Command Handler
+ * Valid command parameter x is from '0' to 'F' for User Mode Registers R0-R15,
+ * '18' for FPSCR (dummy), and '19' for CPSR
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * x
+ * On exit:
+ * r0, r1, r2, r3: destroyed
+ *
+ */
+_dbg__cmd_GetOneReg:
+ stmfd sp!, {lr}
+ bl __dbg__cmdParamLen
+ cmp r1, #CMD_REG_GETONE_MINPARAMLEN /* Check for correct length */
+ blo __dbg__procCmdParamError /* Unexpected input, report error */
+ cmp r1, #CMD_REG_GETONE_MAXPARAMLEN /* Check for correct length */
+ bhi __dbg__procCmdParamError /* Unexpected input, report error */
+ bl ascii2hex_varlen_be /* convert ASCII reg enum to Hex (in R0), R1 has address of next buffer char */
+
+_dbg__proc_getRegister:
+ mov r3, r0 /* Keep register index safe */
+ _dbg_outputMsgValidResponse /* R0: address of output message buffer data pointer (after response prefix) */
+ mov r1, r3 /* Move register index value to R1 */
+ bl _dbg_outputOneRegValue /* update output buffer */
+ _asciiz r0, r1
+ bl dbg__putDebugMsg /* Send response to the GDB server */
+ ldmfd sp!, {pc}
+
+/* _dbg_outputOneRegValue
+ * Given Register Enum (0-F: R0-R15, 0x19: CPSR, OtherVal: dummy), output hex char to buffer
+ * On entry:
+ * r0: output message buffer pointer
+ * r1: register enum (0-F, 0x19)
+ * On exit:
+ * r0: updated (points to next character slot at end of Output Buffer)
+ * r1: original output message buffer pointer
+ * r2: destroyed
+ */
+_dbg_outputOneRegValue:
+ stmfd sp!, {lr}
+ cmp r1, #REG_PC
+ addls r2, r1, #DBGSTACK_USERREG_INDEX /* Convert register enum to Debug Stack index */
+ bls _retrieve_RegVal
+
+ cmp r1, #REG_CPSR
+ moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */
+ beq _retrieve_RegVal
+
+ cmp r1, #REG_FPSCR
+ bne _exit_dbg_outputOneRegValue /* No match, skip */
+
+_output_dummy_fpscr:
+ /* Output Dummy FPSCR value */
+ mov r1, #0
+ b _output2buffer /* Output all zeros for FPSCR */
+
+_retrieve_RegVal:
+ _getdbgregisterfromindex r2, r1 /* Retrieve Register contents into R1 */
+
+_output2buffer:
+
+#ifdef __BIG_ENDIAN__
+ bl word2ascii_be /* Convert and put hex chars into Output Message Buffer */
+#else
+ bl word2ascii_le /* Convert and put hex chars into Output Message Buffer */
+#endif
+
+_exit_dbg_outputOneRegValue:
+ ldmfd sp!, {pc}
+
+/* _dbg__cmd_GetAllRegs
+ * Get All Register Values Command Handler
+ * Output Buffer returns register values in the order: User R0, R1, R2, ..., R15, CPSR
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * <NULL> (no parameters)
+ * On exit:
+ * r0, r1, r2, r3: destroyed
+ */
+_dbg__cmd_GetAllRegs:
+ stmfd sp!, {lr}
+ bl __dbg__cmdParamLen
+ teq r1, #CMD_REG_GETALL_PARAMLEN /* Check for correct length */
+ bne __dbg__procCmdParamError /* Unexpected input, report error */
+
+ _dbg_outputMsgValidResponse /* R0: address of output message buffer data pointer (after response prefix) */
+
+ /* We must return R0-R15, then CPSR */
+ mov r3, #REG_R0 /* Output User Register Values first */
+1: mov r1, r3
+ bl _dbg_outputOneRegValue /* update output buffer */
+ add r3, r3, #1 /* increment index */
+ cmp r3, #REG_PC
+ bls 1b /* process all the registers */
+_get_cpsr:
+ mov r1, #REG_CPSR /* Output User CPSR Value last */
+ bl _dbg_outputOneRegValue /* update output buffer */
+
+ _asciiz r0, r1
+ bl dbg__putDebugMsg /* Send response to the GDB server */
+ ldmfd sp!, {pc}
+
+/* _dbg_setOneRegValue
+ * Given Register Enum (0-F: R0-R15, 0x19: CPSR, OtherVal: dummy), output hex char to buffer
+ * On entry:
+ * r0: parameter buffer pointer
+ * r1: register enum (0-F, 0x19)
+ * On exit:
+ * r0: (Updated) Address of parameter in buffer
+ * r1, r2, r3: destroyed
+ */
+_dbg_setOneRegValue:
+ stmfd sp!, {lr}
+ cmp r1, #REG_PC
+ addls r2, r1, #DBGSTACK_USERREG_INDEX /* Convert register enum to Debug Stack index */
+ bls _store_RegVal
+
+ cmp r1, #REG_CPSR
+ moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */
+ beq _store_RegVal
+
+ cmp r1, #REG_FPSCR
+ bne _exit_dbg_setOneRegValue /* No match, skip */
+ /* FIXME: If we get SetAllRegs with FP reg values, this will not skip pass the FP regs! */
+
+_set_dummy_fpscr:
+ /* Set dummy FPSCR value (ignored) */
+ add r1, r0, #CMD_REG_REGPARAMLEN /* Just increment the pointer */
+ b _done_store_RegVal
+
+_store_RegVal:
+#ifdef __BIG_ENDIAN__
+ bl ascii2word_be
+#else
+ bl ascii2word_le
+#endif
+ /* R0: value, R1: pointer to next char in buffer */
+ _setdbgregisterfromindex r2, r0, r3 /* Set Register contents in R0, using index in R2, and scratch register R3 */
+_done_store_RegVal:
+ mov r0, r1 /* Copy buffer pointer to next parameter to R0 for return value */
+_exit_dbg_setOneRegValue:
+ ldmfd sp!, {pc}
+
+
+/* _dbg__cmd_SetOneReg
+ * Set One Register Value Command Handler
+ * Valid command parameter x is from '0' to 'F' for User Mode Registers R0-R15,
+ * '18' for FPSCR (dummy), and '19' for CPSR
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * x=rrrr
+ * On exit:
+ * r0, r1, r2, r3, r4: destroyed
+ *
+ */
+_dbg__cmd_SetOneReg:
+ stmfd sp!, {lr}
+ bl __dbg__cmdParamLen
+ cmp r1, #CMD_REG_SETONE_MINPARAMLEN /* Check for correct length */
+ blo __dbg__procCmdParamError /* Unexpected input, report error */
+ cmp r1, #CMD_REG_SETONE_MAXPARAMLEN /* Check for correct length */
+ bhi __dbg__procCmdParamError /* Unexpected input, report error */
+
+ bl ascii2hex_varlen_be /* convert ASCII reg enum to Hex (in R0), R1 has address of next buffer char */
+ mov r4, r0 /* Keep enum in R4 */
+ _check_msgassignment r1 /* R1 points to next char in buffer */
+ bne __dbg__procCmdParamError /* Can't find '=' */
+
+_dbg__proc_setRegister:
+ mov r0, r1 /* move parameter buffer pointer to R0 */
+ mov r1, r4 /* and retrieve enum to R1 to call _dbg_setOneRegValue */
+ bl _dbg_setOneRegValue
+ b __dbg__procCmdOk
+
+/* _dbg__cmd_SetAllReg
+ * Set All Register Values Command Handler
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * rrrrRRRRrrrr... (17 registers)
+ * On exit:
+ * r0, r1, r2, r3, r4: destroyed
+ *
+ */
+_dbg__cmd_SetAllRegs:
+ /* Assumes that the registers are in the sequence R0, R1, ... R15, CPSR */
+ stmfd sp!, {lr}
+ bl __dbg__cmdParamLen /* R0: pointer to parameters in buffer */
+ teq r1, #CMD_REG_SETALL_PARAMLEN /* Check for correct length */
+ bne __dbg__procCmdParamError /* Unexpected input, report error */
+ mov r4, #REG_R0 /* R4: register enum, starting with enum for R0 */
+1: mov r1, r4 /* Copy enum to R1; R0 already points to current parameter */
+ bl _dbg_setOneRegValue /* R0: next parameter address pointer */
+ add r4, r4, #1 /* increment index */
+ cmp r4, #REG_PC
+ bls 1b
+
+_set_cpsr:
+#if 0
+ /* GDB was not happy when this was added */
+ /* Read dummy FPSCR value (ignored) */
+#ifdef __BIG_ENDIAN__
+ bl ascii2word_be
+#else
+ bl ascii2word_le
+#endif
+ mov r0, r1 /* Copy buffer pointer to next parameter to R0 for return value */
+#endif
+
+ mov r1, #REG_CPSR /* Use CPSR enum */
+ bl _dbg_setOneRegValue /* R0: next parameter address pointer */
+ ldrb r0, [r0]
+ teq r0, #0 /* Look for ASCIIZ character to terminate loop */
+ beq __dbg__procCmdOk
+ bne __dbg__procCmdParamError /* Unexpected input, report error */
+
+/* _dbg__nop
+ * NOP Command Handler (placeholder)
+ * On entry:
+ * r0: parameter buffer (contents after '$' and '<cmdchar>')
+ * On exit:
+ * r0, r1, r2, r3: destroyed
+ */
+_dbg__nop:
+ stmfd sp!, {lr}
+ b __dbg__procUnimplementedError
+
+/* _dbg__cmd_ReadMem
+ * Read Memory Contents Command Handler
+ * Output Buffer returns memory contents
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * AA..AA,LLLL
+ * On exit:
+ * r0, r1, r2, r3, r4: destroyed
+ */
+_dbg__cmd_ReadMem:
+ stmfd sp!, {lr}
+ bl __dbg__cmdParamLen
+#if 0
+ teq r1, #CMD_MEM_READ_PARAMLEN /* Check for correct length */
+ bne __dbg__procCmdParamError /* Unexpected input, report error */
+ bl ascii2word_be /* convert ASCII address location to Hex (in R0), R1 has address of next buffer char */
+#endif
+ bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */
+ mov r3, r0 /* Keep Address location in R3 */
+ _check_msgseparator r1
+ bne __dbg__procCmdParamError /* Can't find ',' */
+ mov r0, r1 /* move buffer pointer to R0 for subsequent processing */
+ bl ascii2hex_varlen_be /* convert ASCII length to Hex (in R0), R1 has address of next buffer char */
+ cmp r0, #CMD_MEM_MAXREADBYTES /* Don't overflow our buffer (2 x CMD_MEM_MAXREADBYTES) */
+ bhi __dbg__procCmdReturnOutputLengthError /* Requested Length greater than buffer size, return error */
+ mov r4, r0 /* Keep numbytes in R4 */
+ /* FIXME: Should validate the address? */
+
+ _dbg_outputMsgValidResponse /* R0: address of output message buffer data pointer (after response prefix) */
+1: ldrb r1, [r3], #1
+ bl byte2ascii /* update output buffer */
+ subs r4, r4, #1
+ bne 1b
+
+ _asciiz r0, r1
+ bl dbg__putDebugMsg /* Send response to the GDB server */
+ ldmfd sp!, {pc}
+
+
+/* _dbg__cmd_WriteMem
+ * Write Memory Contents Command Handler
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * AA..AA,LLLL::bb..bb
+ * On exit:
+ * r0, r1, r2, r3, r4: destroyed
+ */
+_dbg__cmd_WriteMem:
+ stmfd sp!, {lr}
+ bl __dbg__cmdParamLen
+#if 0
+ cmp r1, #CMD_MEM_WRITE_MINPARAMLEN /* Check for correct (minimum) length */
+ blo __dbg__procCmdParamError /* Unexpected input, report error */
+ sub r4, r1, #CMD_MEM_WRITE_MINPARAMLEN /* R4: Number of ASCII Hex chars for byte writes */
+ bl ascii2word_be /* convert ASCII address location to Hex (in R0), R1 has address of next buffer char */
+#endif
+ bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */
+ mov r3, r0 /* Keep Address location in R3 */
+ _check_msgseparator r1
+ bne __dbg__procCmdParamError /* Can't find ',' */
+ mov r0, r1 /* move buffer pointer to R0 for subsequent processing */
+ bl ascii2hex_varlen_be /* convert ASCII length to Hex (in R0), R1 has address of next buffer char */
+ cmp r0, r4, asr #1 /* is Number of bytes to write == (number of ASCII Hex Chars / 2)? */
+ bne __dbg__procCmdParamError /* Number of bytes does not match argument length */
+ cmp r0, #CMD_MEM_MAXWRITEBYTES /* Don't overflow our buffer (2 x CMD_MEM_MAXWRITEBYTES) */
+ bhi __dbg__procCmdReturnInputLengthError /* Requested Length greater than buffer size, return error */
+ mov r4, r0 /* Keep numbytes in R4 */
+ /* FIXME: Should validate the address? */
+ _check_msgargument r1
+ bne __dbg__procCmdParamError /* Can't find ':' */
+
+1: mov r0, r1
+ bl ascii2byte /* convert ASCII Hex value into byte value */
+ strb r0, [r3], #1 /* Store into memory location */
+ subs r4, r4, #1
+ bne 1b
+ b __dbg__procCmdOk
+
+/* _dbg__cmd_Detach
+ * Detach User Program Execution Command Handler
+ * Treat this as being equivalent to 'Continue' without any arguments
+ *
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * <NULL> (No Parameters)
+ * On exit:
+ * r0-r7: destroyed
+ * Note: This routine does not return to caller. Instead it switches
+ * operating mode to UNDEF and returns to previously active program
+ */
+_dbg__cmd_Detach:
+ stmfd sp!, {lr} /* In case unexpected parameters were received */
+ bl __dbg__cmdParamLen
+ teq r1, #CMD_DETACH_PARAMLEN /* Check for correct length */
+ bne __dbg__procCmdParamError /* Unexpected input, report error */
+
+ ldmfd sp!, {lr} /* Cleanup stack, since we won't return to the Debugger Run Loop */
+ _dbg_setstate DBG_INIT /* Reset the Debug State */
+ bl __dbg__procOkOnly /* send OK to keep GDB server happy */
+ b _dbg__cont_check_breakpoint_type /* Continue from current PC */
+
+/* _dbg__cmd_Continue
+ * Continue User Program Execution Command Handler
+ * Setup breakpoints before resuming execution of program.
+ *
+ * If Address is specified, update the next instruction address to specified address
+ *
+ * If this is a Normal Breakpoint, then we need to install an Autobreakpoint at next instruction address
+ * and resume from current (Breakpoint) exception address
+ * Else (it is a Manual Breakpoint or Address Specified)
+ * We need to resume from the next instruction address
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * Optional: AA..AA
+ * On exit:
+ * r0-r7: destroyed
+ * Note: This routine does not return to caller. Instead it switches
+ * operating mode to UNDEF and returns to previously active program
+ */
+_dbg__cmd_Continue:
+ /* Don't put anything on the stack, we won't return to the Debugger Run Loop */
+ bl __dbg__cmdParamLen
+ cmp r1, #CMD_CONTINUE_MINPARAMLEN /* Check for correct parameter length */
+ bne _dbg__cont_fromAddr /* Address is specified */
+ bl __dbg__procAckOnly /* send Ack to keep GDB server happy */
+ b _dbg__cont_check_breakpoint_type /* Continue from current PC */
+
+_dbg__cont_fromAddr:
+ bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */
+ /* Continue from Specified Address */
+ mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */
+ _setdbgregisterfromindex r2, r0, r1 /* Set Register contents in R0, using index in R2, and scratch register R1 */
+ bl __dbg__procAckOnly /* send Ack to keep GDB server happy */
+ b _dbg__cont_is_manual_bkpt_or_address_specified
+
+_dbg__cont_check_breakpoint_type:
+ _dbg_get_bkpt_type r0
+ teq r0, #DBG_MANUAL_BKPT_ARM
+ beq _dbg__cont_is_manual_bkpt_or_address_specified
+ teq r0, #DBG_MANUAL_BKPT_THUMB
+ beq _dbg__cont_is_manual_bkpt_or_address_specified
+
+_dbg__cont_is_normal_breakpoint:
+/* FIXME: _dbg_following_instruction_addr doesn't actually work currently.
+ This breaks normal breakpoints which need to determine the next instruction to execute
+ (for placing the autobreakpoint) prior to returning.
+*/
+ mov r2, #DBGSTACK_USERPC_INDEX /* Retrieve Aborted Instruction PC from the Debug Stack */
+ _getdbgregisterfromindex r2, r0 /* Retrieve Register contents into R0 */
+ mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */
+ _setdbgregisterfromindex r2, r0, r1 /* Set Register contents in R0, using index in R2, and scratch register R1 */
+ bl _dbg_following_instruction_addr /* following instruction address returned in r1 */
+ bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */
+ _dbg_getcurrbkpt_index r0 /* load current breakpoint index in memory */
+ bl _dbg__activate_autobreakpoint /* pass next instruction address in r1 */
+ b _dbg__switch2undefmode
+
+_dbg__cont_is_manual_bkpt_or_address_specified:
+ bl _dbg__activate_breakpoints /* Restore exisiting breakpoints */
+ b _dbg__switch2undefmode
+
+/* _dbg__cmd_Step
+ * Step User Program Execution Command Handler
+ * Setup breakpoints before resuming execution of program.
+ *
+ * If Address is specified, update the next instruction address to specified address
+ *
+ * If this is a Normal Breakpoint, then we need to install a Step Breakpoint at next instruction address
+ * and resume from current (Breakpoint) exception address
+ * Else (it is a Manual Breakpoint or Address specified)
+ * We need to install a Step Breakpoint at the following instruction address (after the next instruction address)
+ * and resume from the next instruction address
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * Optional: AA..AA
+ * On exit:
+ * r0-r7: destroyed
+ * Note: This routine does not return to caller. Instead it switches
+ * operating mode to UNDEF and returns to previously active program
+ */
+_dbg__cmd_Step:
+ /* Don't put anything on the stack, we won't return to the Debugger Run Loop */
+ bl __dbg__cmdParamLen
+ cmp r1, #CMD_STEP_MINPARAMLEN /* Check for correct parameter length */
+ beq _dbg__step_check_breakpoint_type /* Step from current PC */
+
+_dbg__step_fromAddr:
+ bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */
+ /* Step from Specified Address */
+ mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */
+ _setdbgregisterfromindex r2, r0, r1 /* Set Register contents in R0, using index in R2, and scratch register R1 */
+ b _dbg__step_is_manual_bkpt_or_address_specified
+
+_dbg__step_check_breakpoint_type:
+ _dbg_get_bkpt_type r0
+ teq r0, #DBG_MANUAL_BKPT_ARM
+ beq _dbg__step_is_manual_bkpt
+ teq r0, #DBG_MANUAL_BKPT_THUMB
+ beq _dbg__step_is_manual_bkpt
+
+_dbg__step_is_normal_breakpoint:
+/* FIXME: _dbg_following_instruction_addr doesn't actually work currently.
+ This breaks normal breakpoints which need to determine the next instruction to execute
+ (for placing the autobreakpoint) prior to returning.
+*/
+ mov r2, #DBGSTACK_USERPC_INDEX /* Retrieve Aborted Instruction PC from the Debug Stack */
+ _getdbgregisterfromindex r2, r0 /* Retrieve Register contents into R0 */
+ mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */
+ _setdbgregisterfromindex r2, r0, r1 /* Set Register contents in R0, using index in R2, and scratch register R1 */
+ b _dbg__step_is_manual_bkpt_or_address_specified
+
+_dbg__step_is_manual_bkpt:
+ mov r2, #DBGSTACK_NEXTINSTR_INDEX /* The Next Instruction Pointer for Resume is in index 0 of the Debug Stack */
+ _getdbgregisterfromindex r2, r0 /* Retrieve Register contents into R1 */
+ /* b _dbg__step_is_manual_bkpt_or_address_specified */
+
+_dbg__step_is_manual_bkpt_or_address_specified:
+ bl _dbg_following_instruction_addr /* following instruction address returned in r1 */
+ bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */
+ bl dbg__activate_singlestep
+ bl __dbg__procAckOnly /* send Ack to keep GDB server happy */
+ b _dbg__switch2undefmode
+
+/* _dbg__cmd_Kill
+ * Kill User Program Execution Command Handler
+ * Kill Program, this is accomplished by rebooting the Brick
+ *
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * <NULL> (No Parameters)
+ * On exit:
+ * r0-r7: destroyed
+ * Note: This routine does not return to caller. Instead it calls
+ * the relevant system routine to reboot the Brick
+ */
+_dbg__cmd_Kill:
+ stmfd sp!, {lr} /* In case unexpected parameters were received */
+ bl __dbg__cmdParamLen
+ teq r1, #CMD_KILL_PARAMLEN /* Check for correct length */
+ bne __dbg__procCmdParamError /* Unexpected input, report error */
+
+ bl __dbg__procAckOnly /* send Ack to keep GDB server happy */
+ b dbg__reboot /* Goodbye.... */
+
+/* _dbg__proc_brkpt_params
+ * Process Breakpoint Parameters
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * t,AA..AA,k
+ * On exit:
+ * r0: non-zero = breakpoint address; 0 = parameter error
+ * r1: destroyed
+ * r2: destroyed
+ * r3: destroyed
+ */
+_dbg__proc_brkpt_params:
+ /* FIXME: Add support for watchpoints */
+ stmfd sp!, {lr}
+ mov r3, r0 /* Keep parameter buffer address in R3 */
+ ldrb r0, [r3], #1 /* get breakpoint type t */
+ bl char2hex
+ cmp r0, #CMD_BKPT_TYPE_BREAK_MEMORY
+ bne _dbg__proc_brkpt_params_error /* We only support memory breakpoints for now */
+ _check_msgseparator r3
+ bne _dbg__proc_brkpt_params_error /* Something wrong with the parameters */
+ mov r0, r3 /* Check Address */
+ bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */
+ mov r3, r0 /* Keep breakpoint address in R3 */
+ _check_msgseparator r1
+ bne _dbg__proc_brkpt_params_error /* Something wrong with the parameters */
+ ldrb r0, [r1], #1 /* get breakpoint kind k */
+ bl char2hex
+ cmp r0, #CMD_BKPT_KIND_THUMB
+ orreq r3, r3, #1 /* Mark Thumb breakpoints */
+ beq _exit_dbg__proc_brkpt_params
+ cmp r0, #CMD_BKPT_KIND_ARM
+ beq _exit_dbg__proc_brkpt_params /* ARM breakpoint */
+
+_dbg__proc_brkpt_params_error:
+ mov r3, #0 /* Unrecognized breakpoint type */
+_exit_dbg__proc_brkpt_params:
+ mov r0, r3 /* return breakpoint address */
+ ldmfd sp!, {pc}
+
+/* _dbg__cmd_InsertBreakpoint
+ * Add Breakpoint
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * t,AA..AA,k
+ * On exit:
+ * r0, r1, r2, r3: destroyed
+ */
+_dbg__cmd_InsertBreakpoint:
+ stmfd sp!, {lr}
+ bl __dbg__cmdParamLen
+ teq r1, #CMD_BKPT_INSERT_MINPARAMLEN /* Check for correct length */
+ blo __dbg__procCmdParamError /* Unexpected input, report error */
+ bl _dbg__proc_brkpt_params /* R0: Breakpoint Address */
+ teq r0, #0
+ beq __dbg__procBreakpointAddrError /* Thumb2 instructions, or unknown kind */
+ mov r3, r0 /* Keep breakpoint address in R3 */
+ mov r0, #0 /* Empty Breakpoint entry */
+ bl _dbg_find_breakpoint_slot /* Look for an available breakpoint slot, return index in R0 */
+ cmp r0, #CMD_BKPT_NOTFOUND
+ beq __dbg__procBreakpointAddrError /* No empty slot! */
+ mov r1, r3 /* Move breakpoint address to R1 */
+ bl _dbg__install_one_breakpoint /* r0: index, r1: instruction address */
+ b __dbg__procCmdOk
+
+/* _dbg__cmd_RemoveBreakpoint
+ * Remove Breakpoint
+ * On entry:
+ * r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
+ * t,AA..AA,k
+ * On exit:
+ * r0, r1, r2, r3: destroyed
+ */
+_dbg__cmd_RemoveBreakpoint:
+ stmfd sp!, {lr}
+ bl __dbg__cmdParamLen
+ teq r1, #CMD_BKPT_REMOVE_MINPARAMLEN /* Check for correct length */
+ blo __dbg__procCmdParamError /* Unexpected input, report error */
+ bl _dbg__proc_brkpt_params /* R0: Breakpoint Address */
+ teq r0, #0
+ beq __dbg__procBreakpointAddrError /* Thumb2 instructions, or unknown kind */
+ bl _dbg_find_breakpoint_slot /* Look for matching breakpoint slot, return index in R0 */
+ cmp r0, #CMD_BKPT_NOTFOUND
+ beq __dbg__procBreakpointAddrError /* Specified Breakpoint not found! */
+ _index2bkptindex_addr r0, r1 /* Calculate Breakpoint Entry Address */
+ mov r0, r1 /* Move it to R0 for subroutine call */
+ bl _dbg__clear_one_breakpoint /* R0: address of breakpoint to clear */
+ b __dbg__procCmdOk
+
+
+
+
+/****************************************************************************
+// Selected Routines from the eCos arm_stub.c related to next instruction address
+// determination in ARM processors.
+
+//========================================================================
+//
+// arm_stub.c
+//
+// Helper functions for stub, generic to all ARM processors
+//
+//========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later
+// version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with eCos; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+// As a special exception, if other files instantiate templates or use
+// macros or inline functions from this file, or you compile this file
+// and link it with other works to produce a work based on this file,
+// this file does not by itself cause the resulting work to be covered by
+// the GNU General Public License. However the source code for this file
+// must still be made available in accordance with section (3) of the GNU
+// General Public License v2.
+//
+// This exception does not invalidate any other reasons why a work based
+// on this file might be covered by the GNU General Public License.
+// -------------------------------------------
+// ####ECOSGPLCOPYRIGHTEND####
+//========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): Red Hat, gthomas
+// Contributors: Red Hat, gthomas, jskov
+// Date: 1998-11-26
+// Purpose:
+// Description: Helper functions for stub, generic to all ARM processors
+// Usage:
+//
+//####DESCRIPTIONEND####
+//
+//========================================================================
+
+
+static int
+ins_will_execute(unsigned long ins)
+{
+ unsigned long psr = get_register(PS); // condition codes
+ int res = 0;
+ switch ((ins & 0xF0000000) >> 28) {
+ case 0x0: // EQ
+ res = (psr & PS_Z) != 0;
+ break;
+ case 0x1: // NE
+ res = (psr & PS_Z) == 0;
+ break;
+ case 0x2: // CS
+ res = (psr & PS_C) != 0;
+ break;
+ case 0x3: // CC
+ res = (psr & PS_C) == 0;
+ break;
+ case 0x4: // MI
+ res = (psr & PS_N) != 0;
+ break;
+ case 0x5: // PL
+ res = (psr & PS_N) == 0;
+ break;
+ case 0x6: // VS
+ res = (psr & PS_V) != 0;
+ break;
+ case 0x7: // VC
+ res = (psr & PS_V) == 0;
+ break;
+ case 0x8: // HI
+ res = ((psr & PS_C) != 0) && ((psr & PS_Z) == 0);
+ break;
+ case 0x9: // LS
+ res = ((psr & PS_C) == 0) || ((psr & PS_Z) != 0);
+ break;
+ case 0xA: // GE
+ res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) ||
+ ((psr & (PS_N|PS_V)) == 0);
+ break;
+ case 0xB: // LT
+ res = ((psr & (PS_N|PS_V)) == PS_N) ||
+ ((psr & (PS_N|PS_V)) == PS_V);
+ break;
+ case 0xC: // GT
+ res = ((psr & (PS_N|PS_V)) == (PS_N|PS_V)) ||
+ ((psr & (PS_N|PS_V)) == 0);
+ res = ((psr & PS_Z) == 0) && res;
+ break;
+ case 0xD: // LE
+ res = ((psr & (PS_N|PS_V)) == PS_N) ||
+ ((psr & (PS_N|PS_V)) == PS_V);
+ res = ((psr & PS_Z) == PS_Z) || res;
+ break;
+ case 0xE: // AL
+ res = TRUE;
+ break;
+ case 0xF: // NV
+ if (((ins & 0x0E000000) >> 24) == 0xA)
+ res = TRUE;
+ else
+ res = FALSE;
+ break;
+ }
+ return res;
+}
+
+static unsigned long
+RmShifted(int shift)
+{
+ unsigned long Rm = get_register(shift & 0x00F);
+ int shift_count;
+ if ((shift & 0x010) == 0) {
+ shift_count = (shift & 0xF80) >> 7;
+ } else {
+ shift_count = get_register((shift & 0xF00) >> 8);
+ }
+ switch ((shift & 0x060) >> 5) {
+ case 0x0: // Logical left
+ Rm <<= shift_count;
+ break;
+ case 0x1: // Logical right
+ Rm >>= shift_count;
+ break;
+ case 0x2: // Arithmetic right
+ Rm = (unsigned long)((long)Rm >> shift_count);
+ break;
+ case 0x3: // Rotate right
+ if (shift_count == 0) {
+ // Special case, RORx
+ Rm >>= 1;
+ if (get_register(PS) & PS_C) Rm |= 0x80000000;
+ } else {
+ Rm = (Rm >> shift_count) | (Rm << (32-shift_count));
+ }
+ break;
+ }
+ return Rm;
+}
+
+// Decide the next instruction to be executed for a given instruction
+static unsigned long *
+target_ins(unsigned long *pc, unsigned long ins)
+{
+ unsigned long new_pc, offset, op2;
+ unsigned long Rn;
+ int i, reg_count, c;
+
+ switch ((ins & 0x0C000000) >> 26) {
+ case 0x0:
+ // BX or BLX
+ if ((ins & 0x0FFFFFD0) == 0x012FFF10) {
+ new_pc = (unsigned long)get_register(ins & 0x0000000F);
+ return ((unsigned long *)new_pc);
+ }
+ // Data processing
+ new_pc = (unsigned long)(pc+1);
+ if ((ins & 0x0000F000) == 0x0000F000) {
+ // Destination register is PC
+ if ((ins & 0x0FBF0000) != 0x010F0000) {
+ Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16);
+ if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch!
+ if ((ins & 0x02000000) == 0) {
+ op2 = RmShifted(ins & 0x00000FFF);
+ } else {
+ op2 = ins & 0x000000FF;
+ i = (ins & 0x00000F00) >> 8; // Rotate count
+ op2 = (op2 >> (i*2)) | (op2 << (32-(i*2)));
+ }
+ switch ((ins & 0x01E00000) >> 21) {
+ case 0x0: // AND
+ new_pc = Rn & op2;
+ break;
+ case 0x1: // EOR
+ new_pc = Rn ^ op2;
+ break;
+ case 0x2: // SUB
+ new_pc = Rn - op2;
+ break;
+ case 0x3: // RSB
+ new_pc = op2 - Rn;
+ break;
+ case 0x4: // ADD
+ new_pc = Rn + op2;
+ break;
+ case 0x5: // ADC
+ c = (get_register(PS) & PS_C) != 0;
+ new_pc = Rn + op2 + c;
+ break;
+ case 0x6: // SBC
+ c = (get_register(PS) & PS_C) != 0;
+ new_pc = Rn - op2 + c - 1;
+ break;
+ case 0x7: // RSC
+ c = (get_register(PS) & PS_C) != 0;
+ new_pc = op2 - Rn +c - 1;
+ break;
+ case 0x8: // TST
+ case 0x9: // TEQ
+ case 0xA: // CMP
+ case 0xB: // CMN
+ break; // PC doesn't change
+ case 0xC: // ORR
+ new_pc = Rn | op2;
+ break;
+ case 0xD: // MOV
+ new_pc = op2;
+ break;
+ case 0xE: // BIC
+ new_pc = Rn & ~op2;
+ break;
+ case 0xF: // MVN
+ new_pc = ~op2;
+ break;
+ }
+ }
+ }
+ return ((unsigned long *)new_pc);
+ case 0x1:
+ if ((ins & 0x02000010) == 0x02000010) {
+ // Undefined!
+ return (pc+1);
+ } else {
+ if ((ins & 0x00100000) == 0) {
+ // STR
+ return (pc+1);
+ } else {
+ // LDR
+ if ((ins & 0x0000F000) != 0x0000F000) {
+ // Rd not PC
+ return (pc+1);
+ } else {
+ Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16);
+ if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch!
+ if (ins & 0x01000000) {
+ // Add/subtract offset before
+ if ((ins & 0x02000000) == 0) {
+ // Immediate offset
+ if (ins & 0x00800000) {
+ // Add offset
+ Rn += (ins & 0x00000FFF);
+ } else {
+ // Subtract offset
+ Rn -= (ins & 0x00000FFF);
+ }
+ } else {
+ // Offset is in a register
+ if (ins & 0x00800000) {
+ // Add offset
+ Rn += RmShifted(ins & 0x00000FFF);
+ } else {
+ // Subtract offset
+ Rn -= RmShifted(ins & 0x00000FFF);
+ }
+ }
+ }
+ return ((unsigned long *)*(unsigned long *)Rn);
+ }
+ }
+ }
+ return (pc+1);
+ case 0x2: // Branch, LDM/STM
+ if ((ins & 0x02000000) == 0) {
+ // LDM/STM
+ if ((ins & 0x00100000) == 0) {
+ // STM
+ return (pc+1);
+ } else {
+ // LDM
+ if ((ins & 0x00008000) == 0) {
+ // PC not in list
+ return (pc+1);
+ } else {
+ Rn = (unsigned long)get_register((ins & 0x000F0000) >> 16);
+ if ((ins & 0x000F0000) == 0x000F0000) Rn += 8; // PC prefetch!
+ offset = ins & 0x0000FFFF;
+ reg_count = 0;
+ for (i = 0; i < 15; i++) {
+ if (offset & (1<<i)) reg_count++;
+ }
+ if (ins & 0x00800000) {
+ // Add offset
+ Rn += reg_count*4;
+ } else {
+ // Subtract offset
+ Rn -= 4;
+ }
+ return ((unsigned long *)*(unsigned long *)Rn);
+ }
+ }
+ } else {
+ // Branch
+ if (ins_will_execute(ins)) {
+ offset = (ins & 0x00FFFFFF) << 2;
+ if (ins & 0x00800000) offset |= 0xFC000000; // sign extend
+ new_pc = (unsigned long)(pc+2) + offset;
+ // If its BLX, make new_pc a thumb address.
+ if ((ins & 0xFE000000) == 0xFA000000) {
+ if ((ins & 0x01000000) == 0x01000000)
+ new_pc |= 2;
+ new_pc = MAKE_THUMB_ADDR(new_pc);
+ }
+ return ((unsigned long *)new_pc);
+ } else {
+ // Falls through
+ return (pc+1);
+ }
+ }
+ case 0x3: // Coprocessor & SWI
+ if (((ins & 0x03000000) == 0x03000000) && ins_will_execute(ins)) {
+ // SWI
+ return (unsigned long *)(CYGNUM_HAL_VECTOR_SOFTWARE_INTERRUPT * 4);
+ } else {
+ return (pc+1);
+ }
+ default:
+ // Never reached - but fixes compiler warning.
+ return 0;
+ }
+}
+
+// FIXME: target_ins also needs to check for CPSR/THUMB being set and
+// set the thumb bit accordingly.
+
+static unsigned long
+target_thumb_ins(unsigned long pc, unsigned short ins)
+{
+ unsigned long new_pc = MAKE_THUMB_ADDR(pc+2); // default is fall-through
+ // to next thumb instruction
+ unsigned long offset, arm_ins, sp;
+ int i;
+
+ switch ((ins & 0xf000) >> 12) {
+ case 0x4:
+ // Check for BX or BLX
+ if ((ins & 0xff07) == 0x4700)
+ new_pc = (unsigned long)get_register((ins & 0x00078) >> 3);
+ break;
+ case 0xb:
+ // push/pop
+ // Look for "pop {...,pc}"
+ if ((ins & 0xf00) == 0xd00) {
+ // find PC
+ sp = (unsigned long)get_register(SP);
+
+ for (offset = i = 0; i < 8; i++)
+ if (ins & (1 << i))
+ offset += 4;
+
+ new_pc = *(cyg_uint32 *)(sp + offset);
+
+ if (!v5T_semantics())
+ new_pc = MAKE_THUMB_ADDR(new_pc);
+ }
+ break;
+ case 0xd:
+ // Bcc | SWI
+ // Use ARM function to check condition
+ arm_ins = ((unsigned long)(ins & 0x0f00)) << 20;
+ if ((arm_ins & 0xF0000000) == 0xF0000000) {
+ // SWI
+ new_pc = CYGNUM_HAL_VECTOR_SOFTWARE_INTERRUPT * 4;
+ } else if (ins_will_execute(arm_ins)) {
+ offset = (ins & 0x00FF) << 1;
+ if (ins & 0x0080) offset |= 0xFFFFFE00; // sign extend
+ new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset);
+ }
+ break;
+ case 0xe:
+ // check for B
+ if ((ins & 0x0800) == 0) {
+ offset = (ins & 0x07FF) << 1;
+ if (ins & 0x0400) offset |= 0xFFFFF800; // sign extend
+ new_pc = MAKE_THUMB_ADDR((unsigned long)(pc+4) + offset);
+ }
+ break;
+ case 0xf:
+ // BL/BLX (4byte instruction!)
+ // First instruction (bit 11 == 0) holds top-part of offset
+ if ((ins & 0x0800) == 0) {
+ offset = (ins & 0x07FF) << 12;
+ if (ins & 0x0400) offset |= 0xFF800000; // sign extend
+ // Get second instruction
+ // Second instruction (bit 11 == 1) holds bottom-part of offset
+ ins = *(unsigned short*)(pc+2);
+ // Check for BL/BLX
+ if ((ins & 0xE800) == 0xE800) {
+ offset |= (ins & 0x07ff) << 1;
+ new_pc = (unsigned long)(pc+4) + offset;
+ // If its BLX, force a full word alignment
+ // Otherwise, its a thumb address.
+ if (!(ins & 0x1000))
+ new_pc &= ~3;
+ else
+ new_pc = MAKE_THUMB_ADDR(new_pc);
+ }
+ }
+ break;
+ }
+
+ return new_pc;
+}
+
+void __single_step (void)
+{
+ unsigned long pc = get_register(PC);
+ unsigned long cpsr = get_register(PS);
+
+ // Calculate address of next instruction to be executed
+ if (cpsr & CPSR_THUMB_ENABLE) {
+ // thumb
+ ss_saved_pc = target_thumb_ins(pc, *(unsigned short*)pc);
+ } else {
+ // ARM
+ unsigned long curins = *(unsigned long*)pc;
+ if (ins_will_execute(curins)) {
+ // Decode instruction to decide what the next PC will be
+ ss_saved_pc = (unsigned long) target_ins((unsigned long*)pc,
+ curins);
+ } else {
+ // The current instruction will not execute (the conditions
+ // don't hold)
+ ss_saved_pc = pc+4;
+ }
+ }
+
+ // Set breakpoint according to type
+ if (IS_THUMB_ADDR(ss_saved_pc)) {
+ // Thumb instruction
+ unsigned long t_pc = UNMAKE_THUMB_ADDR(ss_saved_pc);
+ ss_saved_thumb_instr = *(unsigned short*)t_pc;
+ *(unsigned short*)t_pc = HAL_BREAKINST_THUMB;
+ } else {
+ // ARM instruction
+ ss_saved_instr = *(unsigned long*)ss_saved_pc;
+ *(unsigned long*)ss_saved_pc = HAL_BREAKINST_ARM;
+ }
+}
+
+ ****************************************************************************/
+
+/* _dbg_following_instruction_addr
+ * Determine the address of the following instruction to execute.
+ * On entry:
+ * R0: Address of the instruction to be (re)executed
+ * On exit:
+ * R0: Destroyed
+ * R1: Following Instruction Address (31 bits, b0 = THUMB flag)
+ * R2-R7: Destroyed
+ *
+ * Here we make use of the Debugger Stack which contains the address of the aborted instruction that will be reexecuted
+ * when we resume the program.
+ *
+ * If it is a Manual Breakpoint inserted into the code, then we will need to update the aborted instruction
+ * address to skip the current aborted instruction and resume execution at the next instruction address,
+ * and the next instruction address to be returned to the calling routine is the following instruction
+ * address instead.
+ *
+ * We need to check the aborted instruction type, to see if it is a branch instruction, before we can determine
+ * the next instruction address (for inserting a Breakpoint).
+ */
+_dbg_following_instruction_addr:
+ stmfd sp!, {lr}
+/* We assume that any BKPT instructions in the code will be Manual Breakpoints,
+ * i.e., the Debugger does not leave stray Single Step / Auto / Normal breakpoints in memory
+ */
+ mov r6, r0 /* Keep instruction address in R6 */
+ mov r2, #DBGSTACK_USERCPSR_INDEX /* Retrieve User CPSR */
+ _getdbgregisterfromindex r2, r1 /* Retrieve Register contents into R1 */
+ and r4, r1, #CPSR_THUMB /* store Thumb Mode status in R4 */
+ mov r5, r1, lsr #28 /* store CPSR condition flags in R5[3:0] */
+
+_dbg_get_aborted_instr:
+1: teq r4, #0 /* Check if it is ARM or Thumb instruction */
+ ldrneh r0, [r6] /* Load Thumb instruction opcode using Addr in R6 into R0 */
+ ldrne r2, =(BKPT16_INSTR | BKPT16_MANUAL_BKPT) /* check for Thumb Manual Breakpoint Instruction */
+ ldreq r0, [r6] /* Load ARM instruction opcode using Addr in R6 into R0 */
+ ldreq r2, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */
+ teq r0, r2 /* Is instruction opcode (R0) == Manual Breakpoint opcode (R2)? */
+ bne 2f /* Not Manual breakpoint */
+ teq r4, #0 /* Check if it is ARM or Thumb Manual Breakpoint */
+ addne r6, r6, #2 /* Is Manual Breakpoint, Skip to next Thumb instruction */
+ addeq r6, r6, #4 /* Is Manual Breakpoint, Skip to next ARM instruction */
+ b 1b /* To protect against a sequence of Manual Breakpoint Instructions */
+
+/* Here, R0 contains the instruction opcode which will be (re)executed when program resumes.
+ * We need to dissect it to see if it is a branch instruction.
+ * For ARM instructions, we also need to evaluate the current (breakpointed) instruction to see if it'll execute.
+ * If not, then the following instruction is at the address following the address of the opcode in R0 (Default Following Instruction Address).
+ */
+2:
+ teq r4, #0 /* Check if it is ARM or Thumb instruction */
+ beq _following_instr_is_arm
+_following_instr_is_thumb:
+ add r6, r6, #2 /* Store following Thumb instruction address to R1 */
+ orr r6, r6, #BKPT_STATE_THUMB_FLAG /* Set b0 to indicate Thumb instruction */
+ /* R0: Candidate Instruction Opcode
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Following Instruction Address (PC+2)
+ */
+ bl _eval_thumb_instruction /* following address is either ARM or Thumb */
+ /* We must set this the Thumb bit only within the instruction handler since BX would switch modes */
+ b _exit_dbg_following_instruction_addr
+
+_following_instr_is_arm:
+ add r6, r6, #4 /* Store following ARM instruction address to R1 */
+ /* R0: Candidate Instruction Opcode
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Following Instruction Address (PC+4)
+ */
+ bl _eval_arm_instruction
+
+_exit_dbg_following_instruction_addr:
+ mov r1, r0 /* Return Actual Following Instruction Address in R1 (B0 set to indicate Thumb mode) */
+ ldmfd sp!, {pc}
+
+
+/* _eval_arm_instruction
+ * Evaluate ARM instruction to determine following instruction address
+ * On entry:
+ * R0: instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Following Instruction Address (PC+4)
+ * On exit:
+ * R0: following instruction address (B0 set to indicate Thumb mode)
+ * R1-R7: destroyed
+ */
+_eval_arm_instruction:
+ stmfd sp!, {lr}
+ mov r4, r0 /* Keep Instruction Opcode in R4 */
+ bl _dbg_check_arm_condcode
+ teq r0, #FALSE
+ moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */
+ bne _exit_eval_arm_instruction
+
+_will_execute_arm_instr:
+ mov r0, r4 /* Copy instruction opcode to R0 as Code Handler parameter */
+ mov r1, #0 /* initialize ARM Decode Entry Table index register */
+1:
+ _dbg_armDecodeEntry r2, r3, r4, r1 /* instrreg (R2), instrmask (R3), codehandler (R4), indexreg (R1) */
+ teq r2, #0 /* Check for Null Entry (End of Table marker) */
+ moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */
+ beq _exit_eval_arm_instruction
+ and r7, r0, r3 /* Use R7 to check masked instruction opcode (from R0) to see if it matches template (in R2) */
+ teq r7, r2
+ addne r1, r1, #1 /* No match, so keep looking */
+ bne 1b
+
+_call_arm_code_handler:
+ mov r1, r6 /* Copy Default Following Instruction Address to R1 as Code Handler Parameter */
+ mov lr, pc
+ bx r4 /* Call Code Handler with R0: Instruction Opcode, R1: Default Following Instruction Address */
+_exit_eval_arm_instruction:
+ /* Returned Following Address Instruction in R0 (B0 set to indicate Thumb mode) */
+ ldmfd sp!, {pc}
+
+/* _eval_thumb_instruction
+ * Evaluate Thumb instruction to determine following instruction address
+ * On entry:
+ * R0: instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Following Instruction Address (PC+2)
+ * On exit:
+ * R0: following instruction address (B0 set to indicate Thumb mode)
+ * R1-R7: destroyed
+ */
+_eval_thumb_instruction:
+ stmfd sp!, {lr}
+#if 0
+ mov r4, r0 /* Keep Instruction Opcode in R4 */
+ /* Only B<cond> instructions are conditionally executed, deal with it in that Code Handler */
+ bl _dbg_check_thumb_condcode
+ teq r0, #FALSE
+ moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */
+ bne _exit_eval_thumb_instruction
+
+_will_execute_thumb_instr:
+ mov r0, r4 /* Copy instruction opcode to R0 as Code Handler parameter */
+#endif
+ mov r1, #0 /* initialize Thumb Decode Entry Table index register */
+1:
+ _dbg_thumbDecodeEntry r2, r3, r4, r1 /* instrreg (R2), instrmask (R3), codehandler (R4), indexreg (R1) */
+ teq r2, #0 /* Check for Null Entry (End of Table marker) */
+ moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */
+ beq _exit_eval_thumb_instruction
+
+ and r7, r0, r3 /* Use R5 to check masked instruction opcode (from R0) to see if it matches template (in R2) */
+ teq r7, r2
+ addne r1, r1, #1 /* No match, so keep looking */
+ bne 1b
+
+_call_thumb_code_handler:
+ mov r1, r6 /* Copy Default Following Instruction Address to R1 as Code Handler Parameter */
+ mov lr, pc
+ bx r4 /* Call Code Handler with R0: Instruction Opcode, R1: Default Following Instruction Address */
+_exit_eval_thumb_instruction:
+ /* Returned Following Address Instruction in R0 */
+ ldmfd sp!, {pc}
+
+
+/****************************************************************************
+ *
+ * Instruction Decode Routines
+ *
+ ****************************************************************************/
+
+/* _dbg_check_arm_condcode
+ * Check ARM conditional execution code
+ * On entry:
+ * R0: instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: will_execute (boolean)
+ * R1-R3: Destroyed
+ */
+
+_dbg_check_arm_condcode:
+ stmfd sp!, {r6,lr} /* Use R6 as temporary will_execute variable */
+ mov r6, #TRUE
+ mov r0, r0, lsr #28 /* convert condition code to index (0-F) */
+ ldr r2, =debug_armCondCodeTable
+ ldrb r1, [r2, r0] /* Get condition code mask */
+/*
+ * The following check is unnecessary as it is covered by the set/clear checking algorithm
+ teq r1, #0
+ beq _dbg_check_arm_condcode_exit
+*/
+ teq r1, #0xFF
+ bne _dbg_check_bits_set
+
+
+/*
+ * Complex Checks:
+ *
+ * will_execute = TRUE [default condition]
+ * If (N == V) bit set
+ * will_execute = (N == V)
+ * else
+ * will_execute = (N != V)
+ *
+ * If (ANDOR bit) set
+ * z_cond = ((Z XOR Z set) == 0)
+ * If (AND bit set)
+ * will_execute = will_execute && z_cond
+ * else
+ * will_execute = will_execute || z_cond
+ */
+_dbg_cond_complex_check:
+ sub r1, r0, #COMPLEX_CONDCODE_START /* Convert complex condition code to new index (0-3) */
+ ldr r2, =debug_armComplexCCTable
+ ldrb r1, [r2, r1] /* Get complex condition code bitmap */
+
+ /* Use r2 to store N, r3 to store V */
+ tst r5, #COMPLEX_CONDCODE_NFLAG
+ moveq r2, #FALSE
+ movne r2, #TRUE /* r2 = N flag */
+ tst r5, #COMPLEX_CONDCODE_VFLAG
+ moveq r3, #FALSE
+ movne r3, #TRUE /* r3 = V flag */
+ eor r2, r2, r3 /* r2 = (N xor V): 0 if equal, 0xFF if not equal */
+ tst r1, #COMPLEX_CONDCODE_NEQV_MASK
+ mvnne r6, r1 /* If (N == V) bit set, will_execute (r6) = TRUE if (N == V) [r2 == 0] -> invert r2 */
+ moveq r6, r1 /* else (N == V) bit clr, will_execute (r6) = TRUE if (N != V) [r2 == 0xFF] */
+
+ tst r1, #COMPLEX_CONDCODE_ANDOR_MASK
+ beq _dbg_check_arm_condcode_exit /* No additional checks needed, exit */
+
+ /* Use r2 to store Z, r3 to store Z set */
+ and r2, r5, #COMPLEX_CONDCODE_ZFLAG /* r2 = Z flag */
+ and r3, r1, #COMPLEX_CONDCODE_ZSET_MASK /* r3 = Z set */
+ eors r2, r2, r3 /* r2 = (Z xor Z set): 0 if matched, non-zero if not matched */
+ moveq r2, #TRUE
+ movne r2, #FALSE /* r2 (z_cond): TRUE if matched, FALSE if not matched */
+
+ tst r1, #COMPLEX_CONDCODE_AND_MASK
+ andne r6, r6, r2 /* If AND bit set, will_execute = will_execute && z_cond */
+ orreq r6, r6, r2 /* else, will_execute = will_execute || z_cond */
+ b _dbg_check_arm_condcode_exit
+
+
+/*
+ * Simple Checks:
+ *
+ * will_execute = TRUE [default condition, equivalent to 0x00 (AL) ]
+ * If (SetBitMask is Non-Zero)
+ * will_execute = ((cond_code & SetBitMask) == SetBitMask)
+ * If will_execute && (ClearBitMask is Non-Zero)
+ * will_execute = will_execute && ((cond_code | ~ClearBitMask) == ~ClearBitMask)
+ */
+
+_dbg_check_bits_set:
+ movs r0, r1, lsr #4 /* R0: bits set */
+ beq _dbg_check_bits_clear
+ and r2, r5, r0 /* Check bits set IF bitmask non-zero */
+ teq r2, r0 /* ((cond_code & SetBitMask) == SetBitMask)? */
+ movne r6, #FALSE /* No, so will_execute = FALSE */
+ bne _dbg_check_arm_condcode_exit
+
+_dbg_check_bits_clear:
+ ands r1, r1, #NIBBLE0 /* R1: bits clear */
+ beq _dbg_check_arm_condcode_exit
+ mvn r1, r1 /* Invert Bitmask */
+ orr r2, r5, r1 /* Check bits clear IF bitmask non-zero */
+ teq r2, r1 /* ((cond_code | ~ClearBitMask) == ~ClearBitMask)? */
+ movne r6, #FALSE /* No, so will_execute = FALSE */
+ bne _dbg_check_arm_condcode_exit
+
+
+_dbg_check_arm_condcode_exit:
+ mov r0, r6 /* Update return value */
+ ldmfd sp!, {r6, pc}
+
+
+/* _arm_rmshifted_val
+ * Calculate value of Shifted Rm (operand)
+ * On entry:
+ * R0[11:0]: Shifted Rm operand
+ * On exit:
+ * R0: value of Shifted Rm
+ * R1, R2, R3: destroyed
+ */
+_arm_rmshifted_val:
+ stmfd sp!, {lr}
+ ldr r3, =(NIBBLE2|BYTE0)
+ and r3, r0, r3 /* 12 bit Shifted Register operand, copied to R3 */
+ and r2, r3, #NIBBLE0 /* Register Rn Enum in R2 */
+ _regenum2index r2, r2 /* Convert Enum into Index in R2 */
+ _getdbgregisterfromindex r2, r0 /* Retrieve Register Rn contents from Index (R2) into R0 */
+
+ tst r3, #0x10 /* B4: Immediate (0) or Register (1) shift count */
+ /* check bitshift op */
+ and r3, r3, #0x60 /* shift type */
+ mov r3, r3, lsr #5 /* convert into shift type jumptable index */
+ bne _arm_get_reg_shift /* Flags set previously via TST r3 (B4) */
+_arm_calc_const_shift:
+ movs r1, r3, lsr #7 /* Immediate shift count, 5 bit unsigned value in R1 */
+ bne _arm_calc_shifted_rm_val /* Non-zero shift count, process normally */
+ /* Must check for RRX == ROR #0 */
+ teq r3, #0x3 /* ROR == 0x3 */
+ addeq r3, r3, #1
+ b _arm_calc_shifted_rm_val
+
+_arm_get_reg_shift:
+ mov r2, r3, lsr #8 /* Register-based shift count, 4 bit register enum in R2 */
+ _regenum2index r2, r2 /* Convert Enum into Index in R2 */
+ _getdbgregisterfromindex r2, r1 /* Retrieve Register value (shift count) from Index (R2) into R1 */
+
+_arm_calc_shifted_rm_val:
+ _dbg_jumpTableHandler debug_regShiftJumpTable, r2, r3 /* Calculate RmShifted value from R0: Rn Register val, R1: Shift/Rotate val */
+ ldmfd sp!, {pc}
+
+/* Rm Shifted Shift Type Jump Table Routines
+ * On entry:
+ * R0: Register Rm
+ * R1: Shift/Rotate Amount
+ * On exit:
+ * R0: RmShifted result
+ * R1, R2: destroyed
+ *
+ */
+_reg_lsl:
+ lsl r0, r0, r1
+ bx lr
+
+_reg_lsr:
+ lsr r0, r0, r1
+ bx lr
+
+_reg_asr:
+ asr r0, r0, r1
+ bx lr
+
+_reg_ror:
+ ror r0, r0, r1
+ bx lr
+
+_reg_rrx:
+ moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */
+ _getdbgregisterfromindex r2, r1 /* Retrieve CPSR contents from Index (R2) into R1 */
+ ands r1, r1, #CPSR_CFLAG /* Keep C Flag */
+ movne r1, #0x80000000 /* Set B31 if C Flag set */
+ lsr r0, r0, #1 /* Rm >> 1 */
+ orr r0, r0, r1 /* Put C flag into B31 */
+ bx lr
+
+
+/* _arm_data_instr_handler
+ * ARM Data Processing Instruction with Rd == R15
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+4)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address
+ * R1-R7: Destroyed
+ */
+_arm_data_instr_handler:
+ stmfd sp!, {lr}
+ mov r6, r1 /* save Following Instruction Address in R6 */
+ ldr r1, =0x0FBF0000
+ and r4, r0, r1 /* Keep instruction Opcode in R4 */
+ ldr r1, =0x010F0000
+ cmp r4, r1 /* Check for MSR / MRS instruction */
+
+_arm_is_msr_mrs_instr:
+ moveq r0, r6 /* Copy default next instruciton address to R0 */
+ beq _exit_arm_data_instr_handler /* Return default next instruction address */
+
+ /* Not MSR / MRS, so process normally */
+_arm_normal_data_instr:
+ and r4, r0, #0x01E00000 /* Mask Instruction Opcode into R4[24:21] */
+ lsr r4, r4, #21 /* Shift Data Processing Opcode into R4[3:0] */
+ and r7, r0, #0x000F0000 /* Store Rn (Operand 1) Register Enum into R7[19:16] */
+ lsr r7, r7, #16 /* Shift into R7[3:0] */
+
+_arm_check_operand2_type:
+ tst r0, #0x02000000 /* Check for Immediate (1) or Register (0) Operand 2 */
+ beq _arm_op2_is_reg
+
+_arm_op2_is_imm:
+ and r1, r0, #BYTE0 /* 8 bit unsigned constant in R1 */
+ and r2, r0, #NIBBLE2 /* (rotate count / 2) in R2[11:8] */
+ lsr r2, r2, #7 /* actual rotate count in R2[4:0] */
+ ror r1, r1, r2 /* Rotated constant in R1 */
+ b _arm_get_operand1_val
+
+_arm_op2_is_reg:
+ ldr r1, =(NIBBLE2|BYTE0)
+ and r0, r0, r1 /* 12 bit register operand in R1 */
+ bl _arm_rmshifted_val /* R0 contains the Rm shifted val */
+ mov r1, r0 /* move to R1 for later processing */
+
+_arm_get_operand1_val:
+ _regenum2index r7, r1 /* Convert Enum into Index in R1 */
+ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R4 */
+ teq r7, #REG_PC /* Check if it is PC relative */
+ addeq r0, r0, #8 /* adjust for PC relative (+8) */
+
+_arm_calc_data_instr_val:
+ mov r2, r6 /* Retrieve Following Instruction Address in R6 to R2 */
+ /* Calculate data instruction value from R0: Rn Register (Op1) val, R1: Operand 2 val, R2: Default Next Instr Addr */
+ _dbg_jumpTableHandler debug_dataInstrJumpTable, r6, r4 /* Next Instruction Address in R0 */
+_exit_arm_data_instr_handler:
+ ldmfd sp!, {pc}
+
+
+/* Data Processing Instruction Jump Table Routines
+ * On entry:
+ * R0: Register Rn (Operand 1) value
+ * R1: Operand 2 value
+ * R2: Default Next Instruction Address (PC+4)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: Calculated result
+ * R1, R2, R3: Destroyed
+ *
+ */
+_opcode_and:
+ and r0, r0, r1
+ bx lr
+
+_opcode_eor:
+ eor r0, r0, r1
+ bx lr
+
+_opcode_sub:
+ sub r0, r0, r1
+ bx lr
+
+_opcode_rsb:
+ rsb r0, r0, r1
+ bx lr
+
+_opcode_add:
+ add r0, r0, r1
+ bx lr
+
+_opcode_adc:
+ /* Op1 + Op2 + C */
+#if 0
+ moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */
+ _getdbgregisterfromindex r2, r3 /* Retrieve CPSR contents from Index (R2) into R3 */
+ ands r3, r3, #CPSR_CFLAG /* Keep C Flag, NE if C set */
+#endif
+ tst r5, #0x02 /* R5[3:0] is shifted CPSR value */
+ add r0, r0, r1
+ addne r0, r0, #1 /* Add C if set */
+ bx lr
+
+_opcode_sbc:
+ /* Op1 - Op2 + C - 1 */
+#if 0
+ moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */
+ _getdbgregisterfromindex r2, r3 /* Retrieve CPSR contents from Index (R2) into R3 */
+ ands r3, r3, #CPSR_CFLAG /* Keep C Flag, NE if C set */
+#endif
+ tst r5, #0x02 /* R5[3:0] is shifted CPSR value */
+ sub r0, r0, r1
+ subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */
+ bx lr
+
+_opcode_rsc:
+ /* Op2 - Op1 + C - 1 */
+#if 0
+ moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */
+ _getdbgregisterfromindex r2, r3 /* Retrieve CPSR contents from Index (R2) into R3 */
+ ands r3, r3, #CPSR_CFLAG /* Keep C Flag, NE if C set */
+#endif
+ tst r5, #0x02 /* R5[3:0] is shifted CPSR value */
+ rsb r0, r0, r1
+ subeq r0, r0, #1 /* If C clear, subtract 1, else (C - 1) = 0 */
+ bx lr
+
+_opcode_tst:
+_opcode_teq:
+_opcode_cmp:
+_opcode_cmn:
+ mov r0, r2 /* Next Instruction Address is not modified */
+ bx lr
+
+_opcode_orr:
+ orr r0, r0, r1
+ bx lr
+
+_opcode_mov:
+ mov r0, r1 /* Operand 1 is ignored */
+ bx lr
+
+_opcode_bic:
+ bic r0, r0, r1
+ bx lr
+
+_opcode_mvn:
+ mvn r0, r1 /* Operand 1 is ignored */
+ bx lr
+
+
+/* _arm_bx_blx_handler
+ * BX or BLX Rm Handler. Note v4t does not have BLX instr
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+4)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address (B0 set to indicate Thumb mode)
+ * R1, R2: destroyed
+ */
+_arm_bx_blx_handler:
+ stmfd sp!, {lr}
+ and r0, r0, #NIBBLE0 /* Register Rn Enum in R0 */
+ _regenum2index r0, r1 /* Convert Enum into Index in R1 */
+ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */
+ /* Here, the register value would have B0 set to indicate switch to Thumb mode */
+#if 0
+ bic r0, #0x01 /* Clear R0[0] since it is used to indicates Thumb mode */
+#endif
+ ldmfd sp!, {pc}
+
+/* _arm_ldr_pc_handler
+ * LDR with Rd = PC
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+4)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address
+ * R1, R2, R3, R4, R5: destroyed
+ */
+
+_arm_ldr_pc_handler:
+ stmfd sp!, {lr}
+ mov r5, r0 /* Keep a copy of the instruction in R5 */
+ and r0, r0, #NIBBLE4 /* Register Rn Enum in R0[19:16] */
+ lsr r0, r0, #16 /* Move Rn Enum to R0[3:0] */
+ _regenum2index r0, r1 /* Convert Enum into Index in R1 */
+ _getdbgregisterfromindex r1, r4 /* Retrieve Register contents from Index (R1) into R4 */
+ teq r0, #REG_PC /* Check if it is PC relative */
+ addeq r4, r4, #8 /* adjust for PC relative (+8) */
+ tst r5, #0x01000000 /* Pre (1) or Post (0) Indexed */
+ beq _exit_arm_ldr_pc_handler /* If Post-Indexed, just return value of Rn */
+ /* Pre-Indexed */
+ ldr r0, =(NIBBLE2|BYTE0)
+ and r0, r5, r0 /* 12 bit Immediate value or Shifted Reg operand */
+ tst r5, #0x02000000 /* Immediate (0) or Register (1) */
+ beq _calc_ldr_pc_offset /* Immediate value is already in R0 */
+
+_get_shiftedreg_val:
+ bl _arm_rmshifted_val /* Convert Rm shifted operand into value in R0 */
+
+_calc_ldr_pc_offset:
+ tst r5, #0x00800000 /* Add (1) or Subtract (0) */
+ addne r4, r4, r0 /* If Add, R2 = Rn + value */
+ subeq r4, r4, r0 /* If Sub, R2 = Rn - value */
+
+_exit_arm_ldr_pc_handler:
+ mov r0, r4 /* Return next instruction address in R0 */
+ ldmfd sp!, {pc}
+
+
+/* _arm_ldm_pc_handler
+ * LDM {pc}
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+4)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address
+ * R1, R2, R3: destroyed
+ *
+ * FIXME: The algorithm from eCos arm_stub.c does not deal with the Pre/Post-Indexed addressing (P) bit.
+ */
+_arm_ldm_pc_handler:
+ stmfd sp!, {lr}
+ and r3, r0, #0x000F0000 /* Store Rn (Operand 1) Register Enum into R3[19:16] */
+ lsr r3, r3, #16 /* Shift into R3[3:0] */
+
+_arm_get_Rn_val:
+ _regenum2index r3, r2 /* Convert Enum into Index in R2 */
+ _getdbgregisterfromindex r2, r1 /* Retrieve Register contents from Index (R2) into R1 */
+ teq r3, #REG_PC /* Check if it is PC relative */
+ addeq r1, r1, #8 /* adjust Rn (R1) for PC relative (+8) */
+
+_arm_get_regcount:
+ mov r2, #0 /* Initialize reg_count (R2) to 0 */
+ mov r3, r0, lsl #16 /* Keep HLFWORD0 containing vector bits in R3[31:16] */
+ /* This shortens the checking to a max of 16 iterations, since the PC bit should be set */
+1: movs r3, r3, lsl #1 /* count number of '1' bits */
+ addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */
+ bne 1b /* continue until vector is empty */
+
+_arm_check_updown_offset:
+ tst r0, #0x00800000 /* Check Up (1) or Down (0) */
+ addne r1, r1, r2, lsl #2 /* Ascending: Rn (R1) += reg_count (R2) x 4 */
+ subeq r1, r1, #4 /* Descending: Rn (R1) -= 4 */
+ ldr r0, [r1] /* Retrieve stack content for new PC value */
+ ldmfd sp!, {pc}
+
+
+
+/* _arm_b_bl_blx_handler
+ * B, BL or BLX <offset>. Note v4t does not have BLX instr
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+4)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address
+ * R1, R2, R3: destroyed
+ */
+
+_arm_b_bl_blx_handler:
+ stmfd sp!, {lr}
+#ifndef __ARM6OR7__
+ /* armv5t or later, has BLX support */
+ mov r3, r0 /* Copy instruction to R3 */
+#endif
+
+_arm_b_bl_blx_get_offset:
+ and r0, r0, #(BYTE2|BYTE1|BYTE0) /* Encoded Branch offset in R0[23:0] */
+ lsl r0, r0, #(32-24) /* Shift to R0[31:8] */
+ asr r0, r0, #(32-25) /* Actual Signed offset = Encode Offset x 2 in R0[25:0] */
+ add r1, r1, #4 /* R1: (PC+4) + 4 */
+ add r0, r0, r1 /* Calculate Branch Target Address R0: (PC+8) + signed offset */
+
+#ifndef __ARM6OR7__
+ /* armv5t or later, has BLX support */
+ and r2, r3, #0xFE000000 /* Mask out Condition Code and Opcode */
+ teq r2, #0xFA000000 /* Look for BLX */
+ bne _exit_arm_b_bl_blx_handler /* No, it is a B/BL instruction */
+ tst r3, #0x01000000 /* H bit for Thumb Halfword Address */
+ orrne r0, r0, #0x02 /* Set Halfword Address R0[1] */
+ orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */
+#endif
+
+_exit_arm_b_bl_blx_handler:
+ ldmfd sp!, {pc}
+
+/* _arm_coproc_swi_handler
+ * SVC (SWI) or Coprocessor instruction
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+4)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address
+ * R1, R2: destroyed
+ */
+
+_arm_coproc_swi_handler:
+ and r2, r0, #0x0F000000
+ teq r2, #0x0F000000 /* SVC (SWI) instruction */
+
+_arm_swi_instr:
+ ldreq r0, =SVC_VECTOR /* Return SVC Vector Address */
+ beq _exit_arm_coproc_swi_handler
+
+_arm_coproc_instr:
+ mov r0, r1 /* Use default Following Instruction Address */
+_exit_arm_coproc_swi_handler:
+ bx lr
+
+
+/* _thumb_bx_blx_handler
+ * BX or BLX Handler. Note: b7 (H1) is not matched in the mask (should be 0); armv4t does not support BLX.
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+2)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address (B0 set to indicate Thumb mode)
+ * R1: destroyed
+ */
+_thumb_bx_blx_handler:
+ stmfd sp!, {lr}
+ and r0, r0, #0x78 /* Register Rn Enum in R0[6:3] (Hi-Reg indicated by B6) */
+ mov r0, r0, lsr #3 /* Shift Rn Enum to R0[3:0] */
+ _regenum2index r0, r1 /* Convert Enum into Index in R1 */
+ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */
+ /* Here, the register value would have R0[0] set to indicate switch to Thumb mode */
+ ldmfd sp!, {pc}
+
+/* _thumb_poppc_handler
+ * PUSH/POP, specifically POP {Rlist,PC}
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+2)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address (B0 set to indicate Thumb mode)
+ * R1: destroyed
+ */
+_thumb_poppc_handler:
+ stmfd sp!, {lr}
+
+_thumb_get_SP_val:
+ mov r2, #DBGSTACK_USERSP_INDEX /* Set Register Index (R2) to SP Index */
+ _getdbgregisterfromindex r2, r1 /* Retrieve SP contents from Index (R2) into R1 */
+
+_thumb_get_regcount:
+ mov r2, #0 /* Initialize reg_count (R2) to 0 */
+ mov r3, r0, lsl #24 /* Keep BYTE0 containing vector bits in R3[31:24] */
+ /* This shortens the checking to a max of 8 iterations */
+1: movs r3, r3, lsl #1 /* count number of '1' bits */
+ addcs r2, r2, #1 /* increment reg_count (R2) if C Flag set */
+ add r1, r1, #4 /* Walk the stack to locate the PUSHed LR (POP PC) value */
+ bne 1b /* continue until vector is empty */
+ ldr r0, [r1] /* Retrieve new PC value */
+#if 0
+ /* PC Value should have B0 set */
+ orr r0, r0, #0x01 /* Force R0[0] since it is used to indicates Thumb mode */
+#endif
+ ldmfd sp!, {pc}
+
+
+/* _thumb_bcond_swi_handler
+ * B<cond> or SWI (SVC)
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+2)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address (B0 set to indicate Thumb mode)
+ * R1-R6: destroyed
+ */
+_thumb_bcond_swi_handler:
+ mov r4, r0 /* Keep instruction in R4 */
+ and r2, r0, #0x0F00 /* Keep Condition Code R2[11:8] */
+ teq r2, #0x0F00 /* SVC (SWI) instruction */
+_thumb_swi_instr:
+ ldreq r0, =SVC_VECTOR /* Return SVC Vector Address */
+ beq _exit_thumb_bcond_swi_handler /* Switch to ARM mode for SVC */
+_thum_bcond_unused_instr:
+ teq r2, #0x0E00
+ moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */
+ beq _exit_thumb_bcond_instr
+
+_thumb_bcond_instr:
+ mov r6, r1 /* Store Default Following Instruction Address in R6 */
+ lsl r0, r2, #(32-12) /* Shift condition code in R2[11:8] to R0[31:28] to match ARM cond-code format */
+ bl _dbg_check_arm_condcode /* Use ARM condition code checking routine to test (R4, R6 unchanged) */
+ teq r0, #FALSE
+ moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */
+ beq _exit_thumb_bcond_instr
+
+_thumb_calc_bcond_offset:
+ lsl r0, r4, #(32-8) /* Shift 8-bit offset in R4[7:0] to R0[31:24] */
+ asr r0, r0, #(32-9) /* Convert into 9-bit signed offset in R0[8:0] */
+ add r0, r6, r0 /* PC+2 + signed offset */
+ add r0, r0, #2 /* PC+4 + signed offset */
+_exit_thumb_bcond_instr:
+ orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */
+_exit_thumb_bcond_swi_handler:
+ bx lr
+
+/* _thumb_b_handler
+ * B
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+2)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address (B0 set to indicate Thumb mode)
+ * R1: destroyed
+ * Note: The signed offset is 12-bits (encoded value x 2)
+ */
+_thumb_b_handler:
+ stmfd sp!, {lr}
+ lsl r0, r0, #(32-11) /* Shift 11-bit offset in R0[10:0] to R0[31:21] */
+ asr r0, r0, #(32-12) /* Convert into 12-bit signed offset in R0[11:0] */
+ add r0, r1, r0 /* PC+2 + signed offset */
+ add r0, r0, #2 /* PC+4 + signed offset */
+ orr r0, r0, #0x01 /* Set R0[0] since it is used to indicates Thumb mode */
+ ldmfd sp!, {pc}
+
+
+/* _thumb_long_bl_blx_handler
+ * Long BL or BLX (4 bytes) Note: b11 (H) indicates 1st or 2nd instr; armv4t does not support BLX.
+ * On entry:
+ * R0: instruction to be executed
+ * R1: Default Following Instruction Address (PC+2)
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: following instruction address (B0 set to indicate Thumb mode)
+ * R1, R2, R3: destroyed
+ * Note: The BL instruction (0xFxxx) should be in pairs (Dual 16-bit instructions).
+ * The first instruction should have (H=0) to indicate the upper 11 bits of the encoded offset
+ * The second instruction should have (H=1) to indicate the lower 11 bits of the encoded offset
+ * The signed offset is 23 bits (encoded value x 2)
+ *
+ * Note2: The BLX instruction (0xExxx) encodes the first instruciton using BL (0xFxxx) with H=0,
+ * while the second instruction has a different opcode value (0xExxx), with H=1.
+ * BLX is only used to switch to an ARM target.
+ */
+_thumb_long_bl_blx_handler:
+ stmfd sp!, {lr}
+ tst r0, #0x0800 /* Check H bit */
+ bne _return_default_thumb_following_instr /* H=1 as first instruction shouldn't happen */
+
+_thumb_is_1st_bl_blx_instruction:
+ lsl r0, r0, #(32-11) /* Shift 11-bit offset in R0[10:0] to R0[31:21] */
+ asr r0, r0, #(32-23) /* Convert into 12-bit signed offset in R0[22:12] */
+ ldrh r3, [r1] /* Get second instruction in pair into R3 */
+ tst r3, #0x0800 /* Check H bit */
+ beq _exit_thumb_long_bl_blx_handler /* H=0 as second instruction shouldn't happen */
+
+ lsl r2, r3, #(32-11) /* Shift 11-bit offset in R3[10:0] to R2[31:21] */
+ lsr r2, r2, #(32-12) /* Convert into 12-bit unsigned offset in R2[11:0] */
+ orr r0, r0, r2 /* Combine offsets */
+ add r0, r1, r0 /* PC+2 + signed offset */
+ add r0, r0, #2 /* PC+4 + signed offset */
+
+_thumb_is_2nd_bl_blx_instruction:
+ and r3, r3, #0x0F000 /* Keep instruction opcode in R3 */
+
+ cmp r3, #0x0F000 /* Look for BL */
+ orreq r0, r0, #0x01 /* Match, set R0[0] since it is used to indicates Thumb mode */
+ beq _exit_thumb_long_bl_blx_handler
+
+#ifndef __ARM6OR7__
+ /* v5t or higher architecture */
+ cmp r3, #0x0E000 /* Look for BLX */
+ biceq r0, r0, #0x03 /* Match, Force ARM address */
+ beq _exit_thumb_long_bl_blx_handler
+#endif
+
+_return_default_thumb_following_instr:
+ mov r0, r1 /* Return default Following Instruction Address */
+
+_exit_thumb_long_bl_blx_handler:
+ ldmfd sp!, {pc}
+
+
+/****************************************************************************
+ *
+ * Breakpoint Manipulation Routines
+ *
+ ****************************************************************************/
+/* _dbg_find_breakpoint_slot
+ * Find the matching Breakpoint Slot.
+ * This is both used to find empty slots (pass R0=0x0000) or
+ * occupied slots (pass R0=<brkpt addr>)
+ *
+ * On Entry:
+ * R0: Breakpoint Address
+ * On Exit:
+ * R0: Matching Index (-1: not found)
+ *
+ * NOTE: This routine performs exact match, i.e., breakpoint address MUST be configured
+ * for ARM or Thumb (bit 0 clear/set) as appropriate
+ */
+
+_dbg_find_breakpoint_slot:
+ stmfd sp!, {r1,r2,r3, lr}
+ mov r1, #1 /* Only consider Breakpoints 1-7 */
+ ldr r3, =__breakpoints_num__
+1:
+ _index2bkptindex_addr r1, r2 /* Calculate Breakpoint Entry Address */
+ ldr r2, [r2] /* Get actual breakpoint entry (instruction address) */
+ cmp r0, r2
+ beq _found_breakpoint_slot
+ add r1, r1, #1 /* no match, check next */
+ cmp r1, r3
+ blo 1b /* continue checking only if we don't exceed __breakpoints_num__ */
+
+_notfound_breakpoint_slot:
+ mov r1, #CMD_BKPT_NOTFOUND
+_found_breakpoint_slot:
+ mov r0, r1 /* Return value in R0 */
+ ldmfd sp!, {r1,r2,r3, pc}
+
+/* _dbg__clear_singlestep
+ * Clear the Single Step Breakpoint
+ */
+_dbg__clear_singlestep:
+ ldr r0, =__breakpoints_start__ /* Single Step Breakpoint is at the beginning of the Breakpoint State Struct */
+/* b _dbg__clear_one_breakpoint */
+
+/* _dbg__clear_one_breakpoint
+ * On entry, R0 contains the Breakpoint State slot address to be cleared
+ *
+ */
+_dbg__clear_one_breakpoint:
+ mov r1, #0
+ mov r2, #0
+ stmea r0!, {r1, r2} /* clear Breakpoint state */
+ bx lr
+
+/* _dbg__clear_breakpoints
+ * Routine iterates through the array of breakpoints (incl single step breakpoint) and clears the breakpoint
+ */
+_dbg__clear_breakpoints:
+ stmfd sp!, {lr}
+ ldr r0, =__breakpoints_start__ /* Single Step Breakpoint is at the beginning of the Breakpoint State Struct */
+ ldr r3, =__breakpoints_end__ /* start from top of the table */
+3: bl _dbg__clear_one_breakpoint
+ cmp r0, r3
+ blo 3b
+ ldmfd sp!, {pc}
+
+ .global dbg__install_singlestep
+/* dbg__install_singlestep
+ * Install the Single Step Breakpoint
+ * On entry:
+ * R1: Instruction Address (31 bits, b0 = THUMB flag)
+ */
+dbg__install_singlestep:
+ mov r0, #0
+/* b _dbg__install_one_breakpoint */
+
+/* _dbg__install_one_breakpoint
+ * Install breakpoint entry into Breakpoint State Table
+ * On entry:
+ * R0: Breakpoint index (assumed valid)
+ * R1: Instruction Address (31 bits, b0 = THUMB flag)
+ *
+ * On exit:
+ * R2: Breakpoint Instruction
+ * R3: Breakpoint Entry address
+ */
+_dbg__install_one_breakpoint:
+/* Check for Thumb bit */
+ tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */
+/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */
+ ldreq r2, [r1] /* if 0: load ARM instruction from address location */
+ ldrneh r2, [r1] /* else load Thumb instruction */
+ _index2bkptindex_addr r0, r3 /* Calculate Breakpoint Entry Address */
+ stm r3, {r1, r2}
+ bx lr
+
+
+/* _dbg__restore_singlestep
+ * Restores the contents of the single step breakpoint to memory
+ */
+_dbg__restore_singlestep:
+ mov r0, #0 /* single step breakpoint index */
+ _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */
+ ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */
+ teq r1, #0
+ bxeq lr /* Exit if not active */
+/* b _dbg__restore_one_breakpoint */
+
+/* _dbg__restore_one_breakpoint
+ * Restores the contents to memory for one breakpoint
+ * On entry:
+ * R0: Breakpoint index (assumed valid) [not used -- can be used for validating BKPT]
+ * R1: Breakpoint Address (assumed valid)
+ * R2: Breakpoint Instruction (assumed valid)
+ */
+_dbg__restore_one_breakpoint:
+/* Check for Thumb bit */
+ tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */
+/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */
+ streq r2, [r1] /* if 0: restore ARM instruction to address location */
+ bicne r1, #BKPT_STATE_THUMB_FLAG /* else, clear Thumb Flag */
+ strneh r2, [r1] /* store Thumb instruction */
+ bx lr
+
+/* _dbg__restore_breakpoints
+ * Routine iterates through the array of breakpoints (incl single step breakpoint) and restores the contents to memory
+ * Only Active breakpoints (i.e., Non-zero Address) are processed.
+ */
+_dbg__restore_breakpoints:
+ stmfd sp!, {lr}
+ ldr r5, =_dbg__restore_one_breakpoint
+ b __dbg__iterate_breakpoint_array
+
+ .global dbg__activate_singlestep
+/* dbg__activate_singlestep
+ * Activate the single step breakpoint to memory
+ */
+dbg__activate_singlestep:
+ mov r0, #0 /* single step breakpoint index */
+ _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */
+ ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */
+ teq r1, #0
+ bxeq lr /* Exit if not active */
+/* b _dbg__activate_one_breakpoint */
+
+/* _dbg__activate_one_breakpoint
+ * Activate one breakpoint to memory
+ * On entry:
+ * R0: Breakpoint index (assumed valid)
+ * R1: Breakpoint Address (assumed valid)
+ * R2: Breakpoint Instruction (assumed valid)
+ */
+_dbg__activate_one_breakpoint:
+/* Check for Thumb bit */
+ tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */
+ bne _nx_is_thumb_bp
+_nx_is_arm_bp:
+/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */
+ ldr r3, [r1] /* if 0: load ARM instruction from address location */
+ teq r2, r3 /* check that the two instructions are identical */
+ bne _dbg__breakpoint_invalid_arm
+ ldr r2, =BKPT32_INSTR /* ARM BKPT instruction */
+ orr r2, r2, r0 /* Merge Breakpoint index */
+ str r2, [r1] /* Store it into memory location */
+_dbg__breakpoint_invalid_arm:
+ bx lr
+_nx_is_thumb_bp:
+ bic r1, #BKPT_STATE_THUMB_FLAG /* else, clear Thumb Flag */
+ ldrh r3, [r1] /* load Thumb instruction from address location */
+ teq r2, r3 /* check that the two instructions are identical */
+ bne _dbg__breakpoint_invalid_thumb
+ ldr r2, =BKPT16_INSTR /* Thumb BKPT instruction */
+ orr r2, r2, r0 /* Merge Breakpoint index */
+ strh r2, [r1] /* Store it into memory location */
+_dbg__breakpoint_invalid_thumb:
+ bx lr
+
+/* _dbg__activate_breakpoints
+ * Routine iterates through the array of breakpoints (incl single step breakpoint) and activates them
+ * Only Active breakpoints (i.e., Non-zero Address) are processed.
+ */
+_dbg__activate_breakpoints:
+ stmfd sp!, {lr}
+ ldr r5, =_dbg__activate_one_breakpoint
+ b __dbg__iterate_breakpoint_array
+
+
+/* __dbg__iterate_breakpoint_array
+ * Common routine iterates through the array of breakpoints (incl single step breakpoint)
+ * and executes routine given in R5, passing:
+ * R0: Breakpoint index
+ * R1: Breakpoint Address
+ * R2: Breakpoint Instruction
+ *
+ * On Entry:
+ * Assumes that lr has been push to stack (routine can't be called directly)
+ *
+ * Only Active breakpoints (i.e., Non-zero Address entries) are processed.
+ */
+__dbg__iterate_breakpoint_array:
+ ldr r4, =__breakpoints_end__ /* start from top of the table (Assume __breakpoints_end__ > __breakpoints_start__) */
+ ldr r3, =__breakpoints_start__ /* end address check */
+ ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */
+4: sub r0, r0, #1 /* Decrement breakpoint index in r0 */
+ ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */
+ teq r1, #0 /* Is it active? */
+ movne lr, pc
+ bxne r5 /* active entry */
+ cmp r4, r3
+ bhi 4b /* if (pointer > start of Breakpoint Table address), get next slot */
+ ldmfd sp!, {pc}
+
+/* _dbg__activate_autobreakpoint
+ * Activate all other breakpoints except current breakpoint, activate auto breakpoint in next instr slot
+ * On entry:
+ * R0: Current Breakpoint index (assumed valid)
+ * R1: Next Instruction address (for AUTO Breakpoint) [Not used, assume Single Step Breakpoint already has correct info]
+ */
+_dbg__activate_autobreakpoint:
+ stmfd sp!, {lr}
+ mov r5, r0 /* Keep Current Breakpoint Index in r5 */
+ ldr r4, =__breakpoints_end__ /* start from top of the table */
+ ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */
+4: subs r0, r0, #1 /* Decrement breakpoint index in r0 */
+ ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */
+ bls 5f /* Flag set by subs instruction previously. Reached Single Step, go activate AUTO Breakpoint */
+ teq r0, r5 /* Is it the Current Breakpoint? */
+ beq 4b /* Yes, so skip */
+ teq r1, #0 /* Is it active? */
+ blne _dbg__activate_one_breakpoint /* active entry */
+ b 4b /* Next iteration */
+5:
+/* Here, r1: Breakpoint Address, r2: Breakpoint Instruction */
+ tst r1, #BKPT_STATE_THUMB_FLAG /* Check for Thumb bit -- 1: Thumb instruction */
+ orreq r0, r5, #BKPT32_AUTO_BKPT /* Is ARM Instruction, merge AUTO flag with Current Breakpoint Index */
+ orrne r0, r5, #BKPT16_AUTO_BKPT /* Is Thumb Instruction, merge AUTO flag with Current Breakpoint Index */
+ bl _dbg__activate_one_breakpoint /* Activate AUTO Breakpoint */
+ ldmfd sp!, {pc}
+
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_stub.h b/AT91SAM7S256/armdebug/Debugger/debug_stub.h
new file mode 100644
index 0000000..a4cbdda
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_stub.h
@@ -0,0 +1,151 @@
+/** @file debug_stub.h
+ * @brief Shared C/ASM header file for debugger stub
+ *
+ */
+
+/* Copyright (C) 2007-2010 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
+ *
+ */
+
+#ifndef __DEBUG_STUB_H__
+#define __DEBUG_STUB_H__
+
+#include "_c_arm_macros.h"
+
+/** @name BKPT suppport constants
+ *
+ * ARM and Thumb Breakpoint Instructions.
+ */
+/*@{*/
+
+#define __ARM6OR7__
+
+#ifdef __ARM6OR7__
+#define BKPT32_INSTR 0xE7200070 /* ARM6 and ARM7 does not trap unused opcodes (BKPT overlap with control instructions), \
+ CPU has unpredictable behavior. Ref: Steve Furber, ARM SoC Architecture 2nd Ed, pg. 143 */
+#else
+#define BKPT32_INSTR 0xE1200070 /* ARM BKPT instruction, will work in ARMv5T and above */
+#endif
+
+#define BKPT32_ENUM_MASK 0x000FFF0F /* ARM BKPT Enum Mask */
+#define BKPT32_AUTO_BKPT 0x00080000 /* ARM BKPT Auto-Step Flag (for CONT support) */
+#define BKPT32_MANUAL_BKPT 0x0007FF0F /* Manually inserted ARM Breakpoint */
+
+#define BKPT16_INSTR 0xBE00 /* Thumb BKPT instruction */
+#define BKPT16_ENUM_MASK 0x00FF /* Thumb BKPT Enum Mask */
+#define BKPT16_AUTO_BKPT 0x0080 /* Thumb BKPT Auto-Step Flag (for CONT support) */
+#define BKPT16_MANUAL_BKPT 0x007F /* Manually inserted Thumb Breakpoint */
+/*@}*/
+
+#ifndef __ASSEMBLY__
+
+/* Define C stuff */
+/** @defgroup debug_public */
+/*@{*/
+
+
+/** Initialize Debugger.
+ * Equivalent to GDB set_debug_traps() routine
+ */
+FUNCDEF void dbg__bkpt_init(void);
+
+#ifdef __NXOS__
+
+/** Communication Channel Enums
+ *
+ * Communication Channel Enums.
+ */
+ENUM_BEGIN
+ENUM_VALASSIGN(COMM_USB, 1) /**< USB Communications */
+ENUM_VAL(COMM_BT) /**< Bluetooth Communications */
+ENUM_END(comm_chan_t)
+
+/** Enable switch to Debugger Mode from NxOS operational mode
+ * Returns 0 if no mode switch needed (already in Debug mode)
+ * !0 if mode switch will happen
+ * Used by NxOS only
+ */
+FUNCDEF int nxos__handleDebug(comm_chan_t channel);
+#endif
+
+#ifndef __NXOS__
+/** Switch Mode to Debugger.
+ * Used by NXT Firmware only
+ */
+FUNCDEF UWORD cCommHandleDebug(UBYTE *pInBuf, UBYTE CmdBit, UWORD MsgLength);
+#endif
+
+/** Debugger Handler Routine (called by Exception Handler Trap).
+ * Equivalent to GDB handle_exception() routine
+ */
+FUNCDEF void dbg__bkpt_handler(void);
+
+/** dbg_breakpoint_arm.
+ * Equivalent to GDB breakpoint() routine for ARM code
+ */
+/* FUNCDEF void dbg_breakpoint_arm(void); */
+static inline void dbg_breakpoint_arm(void)
+{
+ asm volatile (".word %a0"
+ : /* Output (empty) */
+ : "X" (BKPT32_INSTR | BKPT32_MANUAL_BKPT)
+ );
+}
+
+#if 0 /* Old asm definitions, in case gas does not recognize %a0 operand */
+
+#ifdef __ARM6OR7__
+static inline void dbg_breakpoint_arm(void) { asm volatile (".word 0xE727FF7F" /* (BKPT32_INSTR | BKPT32_MANUAL_BKPT) */ ); }
+#else
+static inline void dbg_breakpoint_arm(void) { asm volatile (".word 0xE127FF7F" /* (BKPT32_INSTR | BKPT32_MANUAL_BKPT) */ ); }
+#endif
+
+#endif
+
+/** dbg_breakpoint_thumb.
+ * Equivalent to GDB breakpoint() routine for Thumb code
+ */
+/* FUNCDEF void dbg_breakpoint_thumb(void); */
+static inline void dbg_breakpoint_thumb(void)
+{
+ asm volatile (".hword %a0"
+ : /* Output (empty) */
+ : "X" (BKPT16_INSTR | BKPT16_MANUAL_BKPT)
+ );
+}
+
+#if 0 /* Old asm definitions, in case gas does not recognize %a0 operand */
+
+static inline void dbg_breakpoint_thumb(void) { asm volatile (".hword 0xBE7F" /* (BKPT16_INSTR | BKPT16_MANUAL_BKPT) */); }
+
+#endif
+
+/*@}*/
+
+#else
+/* Define Assembly stuff */
+
+/* dbg__bkpt_arm
+ * GDB breakpoint() for ARM mode
+ */
+ .macro dbg__bkpt_arm
+ .word (BKPT32_INSTR | BKPT32_MANUAL_BKPT)
+ .endm
+
+/* dbg__bkpt_thumb
+ * GDB breakpoint() for Thumb mode
+ */
+ .macro dbg__bkpt_thumb
+ .hword (BKPT16_INSTR | BKPT16_MANUAL_BKPT)
+ .endm
+
+#endif
+ /*@}*/
+
+#endif /* __DEBUG_STUB_H__ */
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_test.S b/AT91SAM7S256/armdebug/Debugger/debug_test.S
new file mode 100644
index 0000000..91e19d2
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_test.S
@@ -0,0 +1,53 @@
+/** @file debug_test.S
+ * @brief Test Routines to trigger ARM and Thumb Manual Breakpoints
+ *
+ */
+
+/* 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
+ *
+ */
+#define __ASSEMBLY__
+#include "debug_stub.h"
+
+.text
+.align 4
+.code 32
+
+/**********************************************
+ * dbg__test_arm_bkpt Test Routine
+ *
+ */
+ .global dbg__test_arm_bkpt
+dbg__test_arm_bkpt:
+ stmfd sp!,{lr}
+ dbg__bkpt_arm /* Trigger ARM Manual Breakpoint */
+ ldmfd sp!,{pc}
+
+/**********************************************
+ * dbg__test_thumb_bkpt Test Routine
+ *
+ */
+ .global dbg__test_thumb_bkpt
+dbg__test_thumb_bkpt:
+ stmfd sp!,{lr}
+/* ldr r0, =_thumb_entry
+ orr r0, r0, #1 @ Set Thumb mode
+ mov lr, pc
+ bx r0
+*/
+ bl _thumb_entry
+ ldmfd sp!,{pc}
+
+.code 16
+.thumb_func
+_thumb_entry:
+ dbg__bkpt_thumb
+ bx lr
+
+.end
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_test.h b/AT91SAM7S256/armdebug/Debugger/debug_test.h
new file mode 100644
index 0000000..6680f58
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_test.h
@@ -0,0 +1,35 @@
+/** @file debug_test.h
+ * @brief C header file for debugger test routines
+ *
+ */
+
+/* Copyright (C) 2007-2010 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
+ *
+ */
+
+#ifndef __DEBUG_TEST_H__
+#define __DEBUG_TEST_H__
+
+#include "_c_arm_macros.h"
+
+#ifndef __ASSEMBLY__
+
+/* Define C stuff */
+/** @defgroup debug_public */
+/*@{*/
+
+FUNCDEF void dbg__test_arm_bkpt(void);
+FUNCDEF void dbg__test_thumb_bkpt(void);
+
+ /*@}*/
+
+#endif
+
+
+#endif /* __DEBUG_TEST_H__ */
diff --git a/AT91SAM7S256/armdebug/Debugger/undef_handler.S b/AT91SAM7S256/armdebug/Debugger/undef_handler.S
new file mode 100644
index 0000000..11d3cbc
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/undef_handler.S
@@ -0,0 +1,147 @@
+
+/* Copyright (C) 2007-2010 the NxOS developers
+ *
+ * Module Developed by: TC Wan <tcwan@cs.usm.my>
+ *
+ * See AUTHORS for a full list of the developers.
+ *
+ * Redistribution of this file is permitted under
+ * the terms of the GNU Public License (GPL) version 2.
+ */
+#define __ASSEMBLY__
+#include "debug_stub.h"
+#include "debug_internals.h"
+
+
+.text
+.code 32
+.align 0
+
+ .extern dbg__thumb_bkpt_handler
+ .extern dbg__arm_bkpt_handler
+ .extern default_undef_handler
+
+ .global undef_handler
+
+undef_handler:
+/* Remote GDB Debugger relies on BKPT instruction being trapped here
+ * In ARMv4t, it is an Illegal (Undefined) Instruction.
+ * On triggering, lr (R14) contains the previous mode's pc (R15).
+ * Based on example in Hohl, "ARM Assembly Language: Fundamentals and Techniques"
+ * Chapter 11, Example 11.1.
+ * Note: The handler is not AAPCS compliant (8 byte-alignment and stack, etc.)
+ */
+ /* We assume that the UNDEF stack holds only one stack frame and we will overwrite it.
+ * On entry, LR_undef points to one instruction past the UNDEF instruction.
+ *
+ * For the purpose of Debugging, the stack frame should present the PC (R15) as the address
+ * of the instruction that triggered the Breakpoint. Hence we need to adjust R15
+ * to point to the address of the UNDEF instruction. This is what the JTAG debugger
+ * does. (In the ARM hardware, the PC would point to UNDEF+2 instruction address
+ * since it has a three stage pipeline).
+ *
+ * We will also store UNDEF LR (next instruction pointer) and UNDEF SPSR to the stack.
+ *
+ * For the handler, once the user registers have been stored in the debug stack, the
+ * registers will be used as follows:
+ *
+ * R0: UNDEF LR, then UNDEF instruction address, finally UNDEF instruction word / BKPT index
+ * R1: SPSR
+ * R2: Mode
+ * R3: Debug Stack Pointer (for Banked R13-R14 update)
+ */
+ ldr sp, =__debugger_stack__
+ stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */
+ mov r3, sp /* Use R3 to write Banked R13-R14, and actual PC of UNDEF instruction */
+ sub sp, sp, #(4*16) /* Need to manually update SP(undef) */
+
+ mov r0, lr /* Keep Next Instruction address after UNDEF instruction in R0 */
+ mrs r1, spsr /* Copy SPSR to r1 */
+ stmfd sp!, {r0,r1} /* Save User's Next Instr Pointer (in UNDEF LR) and previous mode's CPSR to stack */
+
+ tst r1, #CPSR_THUMB /* Check for Thumb Mode */
+ subne r0, r0, #2 /* Is Thumb instruction, adjust PC for UNDEF instruction address */
+ subeq r0, r0, #4 /* Is ARM instruction, adjust PC for UNDEF instruction address */
+ str r0, [r3, #-4]! /* Save PC to stack (R15 slot) */
+
+ and r2, r1, #CPSR_MODE /* Get previous mode */
+ teq r2, #MODE_USR
+ beq _skip_banked_registers /* Can't switch back if we're in User mode! */
+
+_store_prev_mode_banked_regs:
+ /* FIXME: We don't handle FIQ properly! */
+
+ orr r2, #(CPSR_FIQ | CPSR_IRQ) /* Disable Interrupts */
+ msr cpsr_c, r2 /* Switch to previous mode */
+ stmfd r3!, {sp, lr} /* Store Previous Mode's LR (R14), SP (R13) via R3 */
+ msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Revert to Undef Mode */
+
+_skip_banked_registers:
+ tst r1, #CPSR_THUMB /* Check for Thumb Mode */
+ beq _is_arm /* Clear, so it's ARM mode */
+_is_thumb:
+ ldrh r0, [r0] /* load UNDEF instruction into r0 */
+ ldr r1, =BKPT16_ENUM_MASK /* Thumb BKPT enum mask */
+ bic r2, r0, r1 /* leave only opcode */
+ ldr r1, =BKPT16_INSTR /* check for Thumb Breakpoint Instruction */
+ teq r2, r1
+ bne default_undef_handler
+ ldr r1, =BKPT16_ENUM_MASK /* get Thumb BKPT Enum Mask */
+ ldr r2, =dbg__thumb_bkpt_handler /* handle BKPT, BKPT index in r0 */
+ b _exit_undef_handler
+_is_arm:
+ ldr r0, [r0] /* load UNDEF instruction into r0 */
+ ldr r1, =BKPT32_ENUM_MASK /* ARM BKPT enum mask */
+ bic r2, r0, r1 /* leave only opcode */
+ ldr r1, =BKPT32_INSTR /* check for ARM Breakpoint Instruction */
+ teq r2, r1
+ bne default_undef_handler
+ ldr r1, =BKPT32_ENUM_MASK /* get ARM BKPT Enum Mask */
+ ldr r2, =dbg__arm_bkpt_handler /* handle BKPT, BKPT index in r0 */
+_exit_undef_handler:
+ and r0, r1, r0 /* Keep index value */
+ msr cpsr_c, #(MODE_ABT | CPSR_FIQ | CPSR_IRQ) /* Switch to Abort Mode, Disable Interrupts */
+ mov pc, r2 /* Invoke Debugger */
+
+ .global resume_execution
+
+resume_execution:
+/*
+ * This routine is called by the Debugger prior to returning control to
+ * the executing program.
+ * It updates the SPSR_UNDEF with the Debug Stack value, and
+ * restores all registers R0-R14 to the previously active mode.
+ * Then, it uses the Next Instruction Address Pointer to return
+ * execution control to the previously executing program.
+ */
+/* On Entry, SP(undef) points to the Next Instruction Address.
+ * If the instruction which triggered the Breakpoint need to be
+ * reexecuted, it should be placed in the Next Instruction Address slot
+ * by ABORT mode before coming here
+ */
+ ldr lr, =__debugger_stack_bottom__ /* Use LR(undef) for Debug Stack Access */
+ add r1, lr, #(DBGSTACK_USERSP_INDEX*4) /* Use R1 for Previous Mode SP (R13) and LR (R14) access */
+ ldr r0, [lr, #(DBGSTACK_USERCPSR_INDEX*4)]! /* LR updated, Retrieve SPSR into R0 */
+ msr spsr, r0 /* Update SPSR for return to program being debugged */
+ and r0, r0, #CPSR_MODE /* Get previous mode */
+ teq r0, #MODE_USR
+ bne _restore_prev_mode_banked_regs /* Can't switch back if we're in User mode! */
+
+ /* Previous mode was User Mode */
+ ldmed lr, {r0-r14}^ /* We use LDMED since LR is pointing to USERCPSR not R0 */
+ b _really_resume_execution
+
+_restore_prev_mode_banked_regs:
+ /* FIXME: We don't handle FIQ properly! */
+ orr r0, #(CPSR_FIQ | CPSR_IRQ) /* Disable Interrupts */
+ msr cpsr_c, r0 /* Switch to previous mode */
+ ldmfd r1, {sp, lr} /* Restore Previous Mode's LR (R14), SP (R13) via R1 */
+ msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Revert to Undef Mode */
+ ldmed lr, {r0-r12} /* We use LDMED since LR is pointing to USERCPSR not R0 */
+
+_really_resume_execution:
+ ldmfd sp, {pc}^ /* Exit to Previous Mode using Next Instruction Address */
+
+
+
+
diff --git a/AT91SAM7S256/armdebug/Doxyfile b/AT91SAM7S256/armdebug/Doxyfile
new file mode 100644
index 0000000..6266354
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Doxyfile
@@ -0,0 +1,243 @@
+# Doxyfile 1.5.3-20071008
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = "NxOS Debugger"
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY = ../doc/debug
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+#DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+BUILTIN_STL_SUPPORT = NO
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = YES
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = .
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.h
+RECURSIVE = YES
+EXCLUDE = at91sam7s256.h
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+HTML_DYNAMIC_SECTIONS = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 1
+GENERATE_TREEVIEW = YES
+TREEVIEW_WIDTH = 280
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+#MACRO_EXPANSION = NO
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+MSCGEN_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = YES
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/AT91SAM7S256/armdebug/GNU-GPLv2.txt b/AT91SAM7S256/armdebug/GNU-GPLv2.txt
new file mode 100644
index 0000000..5b6e7c6
--- /dev/null
+++ b/AT91SAM7S256/armdebug/GNU-GPLv2.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/AT91SAM7S256/armdebug/Host/README b/AT91SAM7S256/armdebug/Host/README
new file mode 100644
index 0000000..23d95c9
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Host/README
@@ -0,0 +1,21 @@
+The nxt-gdb-server.py script is initially developed by Nicolas Schodet.
+
+It depends on the following libraries:
+ - nxt-python v2.1.x http://code.google.com/p/nxt-python/
+ - pyusb v0.4x http://pyusb.wiki.sourceforge.net
+ - libusb v0.1.x http://libusb.org/
+
+Currently, it does not work with libusb v1.x, on Mac OSX, it causes segfaults.
+
+ Installation
+ ============
+
+ There is no specific installation requirements (at this moment). Just run the python script
+ in a terminal window.
+
+ Usage
+ =====
+
+ 1. Connect the USB cable from the PC Host to the NXT
+ 2. start nxt-gdb-server.py
+ 3. start arm-none-eabi-gdb, configured as remote for port 2828 (default)
diff --git a/AT91SAM7S256/armdebug/Host/gdb-commands.txt b/AT91SAM7S256/armdebug/Host/gdb-commands.txt
new file mode 100644
index 0000000..3135a1e
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Host/gdb-commands.txt
@@ -0,0 +1,43 @@
+# This file contains hand coded GDB commands for testing the GDB Server <-> NXT interface
+
+# Display all Registers
+$g#67
+
+# Display R0
+$p0#A0
+
+# Display R1
+$p1#A1
+
+# Display PC
+$pF#B6
+
+# Display FPSCR (dummy)
+$p18#D9
+
+# Display User CPSR
+$p19#DA
+
+# Query Status
+$?#3F
+
+# Query Thread
+$qC#B4
+
+# Set R1 to 0xAA
+$P1=000000AA#60
+
+# Read 16 bytes of Memory from 0x00201d74 (padding bytes after debug_mode + 4 bytes of debug_InUSBBuf)
+$m00201D74,0010#FC
+
+# Write 2 bytes of memory to 0x00201d74 (padding bytes after debug_mode)
+$M00201D74,0002:AA55#03
+
+# Write 2 bytes of memory to 0x00201d74 (padding bytes after debug_mode)
+$M00201D74,0002:9966#F5
+
+# GDB Read Instruction at Address (PC)
++$m1001de,4#58
+
+# Continue Execution
+$c#63
diff --git a/AT91SAM7S256/armdebug/Host/nxt-gdb-server.py b/AT91SAM7S256/armdebug/Host/nxt-gdb-server.py
new file mode 100755
index 0000000..7de81b7
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Host/nxt-gdb-server.py
@@ -0,0 +1,208 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2011 the NxOS developers
+#
+# Module Developed by: Nicolas Schodet
+# TC Wan
+#
+# See AUTHORS for a full list of the developers.
+#
+# See COPYING for redistribution license
+#
+# Exchange GDB messages with the NXT brick.
+#
+# Every message is encapsulated with the debug command and message length.
+# This can be used by the firmware to make the distinction between debug
+# messages and regular messages.
+#
+import nxt.locator
+import socket
+import optparse
+import select
+#import usb
+import pyfantom
+import struct
+
+CTRLC = chr(3)
+STATUS_QUERY = "$?#3F"
+DEFAULT_PORT = 2828
+SELECT_TIMEOUT = 0.1
+DEBUG = True
+DEBUG2 = False
+NXT_RECV_ERR = -1
+
+# Libusb 0.12.x blocks on USB reads
+LIBUSB_RECEIVE_BLOCKING = True
+
+class NXTGDBServer:
+
+ # Socket read size.
+ recv_size = 1024
+
+ # Maximum message size.
+ pack_size = 61
+
+ # Debug command header, no reply.
+ debug_command = 0x8d
+
+ def __init__ (self, port):
+ """Initialise server."""
+ self.port = port
+ self.in_buf = ''
+
+ def pack (self, data, segment_no):
+ """Return packed data to send to NXT."""
+ # Insert command and length.
+ assert len (data) <= self.pack_size
+ return struct.pack ('BBB', self.debug_command, segment_no, len (data)) + data
+
+ def unpack (self, data):
+ """Return unpacked data from NXT."""
+ # May be improved, for now, check command and announced length.
+ if len (data) == 0:
+ return '', 0 # No message, exit
+ if len (data) < 3:
+ return '', NXT_RECV_ERR
+ header, body = data[0:3], data[3:]
+ command, segment_no, length = struct.unpack ('BBB', header)
+ if command != self.debug_command or length != len (body):
+ return '', NXT_RECV_ERR
+ return body, segment_no
+
+ def segment (self, data):
+ """Split datas in GDB commands and make segments with each command."""
+ segs = [ ]
+ self.in_buf += data
+ # Find Ctrl-C (assumed to be by itself and not following a normal command)
+ end = self.in_buf.find (CTRLC)
+ if end >= 0:
+ msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:]
+ assert len (msg) <= self.pack_size, "Ctrl-C Command Packet too long!"
+ segs.append (self.pack (msg, 0))
+ end = self.in_buf.find (CTRLC)
+
+ end = self.in_buf.find ('#')
+ # Is # found and enough place for the checkum?
+ while end >= 0 and end < len (self.in_buf) - 2:
+ msg, self.in_buf = self.in_buf[0:end + 3], self.in_buf[end + 3:]
+ i = 0
+ gdbprefix = msg[i]
+ while gdbprefix in ['+', '-']:
+ # Ignore any '+' or '-'
+ i += 1
+ gdbprefix = msg[i]
+ if DEBUG2:
+ print "Checking '", gdbprefix, "'"
+ assert gdbprefix == '$', "not a GDB command"
+ # Make segments.
+ seg_no = 0
+ while msg:
+ seg, msg = msg[0:self.pack_size], msg[self.pack_size:]
+ seg_no += 1
+ if not msg: # Last segment.
+ seg_no = 0
+ segs.append (self.pack (seg, seg_no))
+ # Look for next one.
+ end = self.in_buf.find ('#')
+ return segs
+
+ def reassemble (self, sock):
+ msg = ''
+ prev_segno = 0
+ segno = NXT_RECV_ERR # force initial pass through while loop
+ while segno != 0:
+ try:
+ s, segno = self.unpack (sock.recv ())
+ if len (s) == 0:
+ if segno == 0 and prev_segno == 0:
+ return '' # No message pending
+ else:
+ segno = NXT_RECV_ERR # Keep waiting for segments
+ # Ignore error packets
+ if segno >= 0:
+ # Check segno, if non-zero it must be monotonically increasing from 1, otherwise 0
+ if segno > 0:
+ assert segno == prev_segno + 1, "segno = %s, prev_segno = %s" % (segno, prev_segno)
+ prev_segno = segno
+ msg += s
+ except usb.USBError as e:
+ # Some pyusb are buggy, ignore some "errors".
+ if e.args != ('No error', ):
+ raise e
+ return msg
+
+ def run (self):
+ """Endless run loop."""
+ # Create the listening socket.
+ s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
+ s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ s.bind (('', self.port))
+ s.listen (1)
+ # Open connection to the NXT brick.
+ brick = nxt.locator.find_one_brick (method=nxt.Method(usb=False, bluetooth=False, fantomusb=True, fantombt=False))
+ brick.sock.debug = DEBUG
+ print "Waiting for GDB connection on port %s..." % self.port
+ while True:
+ # Wait for a connection.
+ client, addr = s.accept ()
+ print "Client from", addr
+ # Work loop, wait for a message from client socket or NXT brick.
+ while client is not None:
+ data = ''
+ # Wait for a message from client or timeout.
+ rlist, wlist, xlist = select.select ([ client ], [ ], [ ],
+ SELECT_TIMEOUT)
+ for c in rlist:
+ assert c is client
+ # Data from client, read it and forward it to NXT brick.
+ data = client.recv (self.recv_size)
+ data = data.strip()
+ if len (data) > 0:
+ #if len (data) == 1 and data.find(CTRLC) >= 0:
+ # print "CTRL-C Received!"
+ # data = STATUS_QUERY
+ if DEBUG:
+ print "[GDB->NXT] %s" % data
+ segments = self.segment (data)
+ data = ''
+ for seg in segments:
+ try:
+ brick.sock.send (seg)
+ except usb.USBError as e:
+ # Some pyusb are buggy, ignore some "errors".
+ if e.args != ('No error', ):
+ raise e
+ if segments != [] and LIBUSB_RECEIVE_BLOCKING:
+ if DEBUG2:
+ print "Accessing Blocking sock.recv()"
+ data = self.reassemble (brick.sock)
+ else:
+ client.close ()
+ client = None
+ if not LIBUSB_RECEIVE_BLOCKING:
+ if DEBUG2:
+ print "Accessing Non-Blocking sock.recv()"
+ data = self.reassemble (brick.sock)
+
+ # Is there something from NXT brick?
+ if data:
+ if DEBUG:
+ print "[NXT->GDB] %s" % data
+ if client:
+ client.send (data)
+ data = ''
+ print "Connection closed, waiting for GDB connection on port %s..." % self.port
+
+if __name__ == '__main__':
+ # Read options from command line.
+ parser = optparse.OptionParser (description = """
+ Gateway between the GNU debugger and a NXT brick.
+ """)
+ parser.add_option ('-p', '--port', type = 'int', default = DEFAULT_PORT,
+ help = "server listening port (default: %default)", metavar = "PORT")
+ (options, args) = parser.parse_args ()
+ if args:
+ parser.error ("Too many arguments")
+ # Run.
+ s = NXTGDBServer (options.port)
+ s.run ()
diff --git a/AT91SAM7S256/armdebug/Host/pyenv-nxt-gdb-server b/AT91SAM7S256/armdebug/Host/pyenv-nxt-gdb-server
new file mode 100755
index 0000000..b98c2d8
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Host/pyenv-nxt-gdb-server
@@ -0,0 +1,3 @@
+#!/bin/sh
+export PYTHONPATH=~/svnrepo/nxt-python:~/gitrepo/pyfantom
+arch -i386 /usr/bin/python2.6 ~/gitrepo/armdebug/Host/nxt-gdb-server.py
diff --git a/AT91SAM7S256/armdebug/LEGO_Open_Source_License.doc b/AT91SAM7S256/armdebug/LEGO_Open_Source_License.doc
new file mode 100644
index 0000000..94b65e6
--- /dev/null
+++ b/AT91SAM7S256/armdebug/LEGO_Open_Source_License.doc
Binary files differ
diff --git a/AT91SAM7S256/armdebug/README b/AT91SAM7S256/armdebug/README
new file mode 100644
index 0000000..4660b1e
--- /dev/null
+++ b/AT91SAM7S256/armdebug/README
@@ -0,0 +1,16 @@
+Introduction
+============
+armdebug is an ARM Assembly Language Instruction debugger for the NXT.
+It is intended for embedding in the NXT firmware (e.g. NXT Improved Firmware),
+as well as for use with NxOS.
+
+Contents
+========
+The various folders contents are as follows:
+Debugger: GDB client driver for NXT (need to be embedded in firmware code)
+Host: GDB Server for PC Host
+
+LICENSES
+========
+The armdebug code is dual-licensed. Please see COPYING for more details.
+Other projects included in this repository have their respective licenses.
diff --git a/AT91SAM7S256/armdebug/SConscript b/AT91SAM7S256/armdebug/SConscript
new file mode 100644
index 0000000..c495847
--- /dev/null
+++ b/AT91SAM7S256/armdebug/SConscript
@@ -0,0 +1,13 @@
+# This scons build script is used by NxOS
+
+from glob import glob
+
+Import('env')
+
+
+for source in glob('Debugger/*.[cS]'):
+ obj = env.Object(source.split('.')[0], source)
+ env.Append(NXOS_DEBUG=obj)
+
+if env['WITH_DOXYGEN']:
+ env.Doxygen('Doxyfile')
diff --git a/AT91SAM7S256/armdebug/SConstruct b/AT91SAM7S256/armdebug/SConstruct
new file mode 100644
index 0000000..fa88d7a
--- /dev/null
+++ b/AT91SAM7S256/armdebug/SConstruct
@@ -0,0 +1,182 @@
+# -*- mode: python -*-
+###############################################################
+# This scons build script is used to check the armdebug project
+# code for syntax errors. It does not build working executable
+# code since it links to external routines.
+###############################################################
+
+import os
+import os.path
+import new
+from glob import glob
+
+###############################################################
+# Utility functions.
+###############################################################
+
+# Similar to env.WhereIs, but always searches os.environ.
+def find_on_path(filename):
+ paths = os.environ.get('PATH')
+ if not paths:
+ return None
+ for p in paths.split(':'):
+ path = os.path.abspath(os.path.join(p, filename))
+ if os.path.isfile(path):
+ return p
+ return None
+
+# Run the given gcc binary, and parses its output to work out the gcc
+# version.
+def determine_gcc_version(gcc_binary):
+ stdout = os.popen('%s --version' % gcc_binary)
+ gcc_output = stdout.read().split()
+ stdout.close()
+ grab_next = False
+ for token in gcc_output:
+ if grab_next:
+ return token
+ elif token[-1] == ')':
+ grab_next = True
+ return None
+
+# Check that a given cross-compiler tool exists. If it does, the path is
+# added to the build environment, and the given environment variable is
+# set to the tool name.
+#
+# This is used to check for the presence of a working cross-compiler
+# toolchain, and to properly set up the environment to do it. See below
+# in the configuration section for details.
+def CheckTool(context, envname, toolname=None, hostprefix=None):
+ toolname = toolname or envname.lower()
+ if hostprefix is None:
+ hostprefix = '%s-' % context.env['CROSS_COMPILE_HOST']
+ toolname = '%s%s' % (hostprefix, toolname)
+ context.Message("Checking for %s..." % toolname)
+ toolpath = find_on_path(toolname)
+ if not toolpath:
+ context.Result('not found')
+ return False
+ else:
+ context.Result('ok')
+ context.env[envname] = toolname
+ context.env.AppendENVPath('PATH', toolpath)
+ return True
+
+# Find the correct variant and version of libgcc.a in the cross-compiler
+# toolchain.
+def CheckLibGcc(context, gccname):
+ context.Message("Locating a cross-compiled libgcc...")
+ toolpath = find_on_path(gccname)
+ if not toolpath:
+ context.Result("%s not found" % toolname)
+ return False
+ gcc_version = determine_gcc_version(gccname)
+ if not gcc_version:
+ context.Result("Could not determine gcc version")
+ return False
+ gcc_install_dir = os.path.split(os.path.normpath(toolpath))[0]
+ for libdir in ['interwork', 'thumb', '']:
+ libgcc_path = os.path.join(gcc_install_dir, 'lib', 'gcc',
+ context.env['CROSS_COMPILE_HOST'],
+ gcc_version, libdir, 'libgcc.a')
+ if os.path.isfile(libgcc_path):
+ break
+ if not os.path.isfile(libgcc_path):
+ context.Result("libgcc.a not found")
+ return False
+ context.Result("ok - " + libgcc_path)
+ context.env.Append(LIBGCC=libgcc_path)
+ return True
+
+def CheckDoxygen(context):
+ context.Message("Looking for Doxygen...")
+ doxypath = find_on_path('doxygen')
+ if doxypath:
+ context.Result("ok")
+ context.env.AppendENVPath('PATH', doxypath)
+ context.env['WITH_DOXYGEN'] = True
+ else:
+ context.Result("not found")
+ context.env['WITH_DOXYGEN'] = False
+
+
+
+###############################################################
+# Options that can be provided on the commandline
+###############################################################
+
+opts = Variables('scons.options', ARGUMENTS)
+
+opts.Add(PathVariable('gccprefix',
+ 'Prefix of the cross-gcc to use (by default arm-none-eabi)',
+ 'arm-none-eabi', PathVariable.PathAccept))
+
+Help('''
+Type: 'scons' to build object files.
+
+ - To use another cross-gcc than arm-none-eabi-gcc:
+ scons gccprefix=arm-softfloat-eabi
+
+Options are saved persistent in the file 'scons.options'. That means
+after you have called e.g. 'scons gccprefix=arm-softfloat-eabi' it's enough
+to call only 'scons' to build both using the new gcc version again.
+''')
+
+###############################################################
+# Construct and configure a cross-compiler environment
+###############################################################
+env = Environment(options = opts,
+ tools = ['gcc', 'as', 'gnulink', 'ar'],
+ toolpath = ['scons_tools'],
+ LIBGCC = [], CPPPATH = '#',
+ WITH_DOXYGEN = False)
+opts.Update(env)
+opts.Save('scons.options', env)
+
+if not env.GetOption('clean'):
+ conf = Configure(env, custom_tests = {'CheckTool': CheckTool,
+ 'CheckLibGcc': CheckLibGcc,
+ 'CheckDoxygen': CheckDoxygen})
+ conf.env['CROSS_COMPILE_HOST'] = env['gccprefix']
+ if not (conf.CheckTool('CC', 'gcc') and conf.CheckTool('AR') and
+ conf.CheckTool('OBJCOPY') and conf.CheckTool('LINK', 'ld') and
+ conf.CheckLibGcc(conf.env['CC'])):
+ print "Missing or incomplete arm-elf toolchain, cannot continue!"
+ Exit(1)
+ env = conf.Finish()
+
+mycflags = ['-mcpu=arm7tdmi', '-Os', '-Wextra', '-Wall', '-Werror',
+ '-Wno-div-by-zero', '-Wfloat-equal', '-Wshadow',
+ '-Wpointer-arith', '-Wbad-function-cast',
+ '-Wmissing-prototypes', '-ffreestanding',
+ '-fsigned-char', '-ffunction-sections', '-std=gnu99',
+ '-fdata-sections', '-fomit-frame-pointer', '-msoft-float']
+myasflags = ['-Wall', '-Werror', '-Os'];
+if str(env['LIBGCC']).find('interwork') != -1:
+ mycflags.append('-mthumb-interwork')
+ myasflags.append('-Wa,-mcpu=arm7tdmi,-mfpu=softfpa,-mthumb-interwork')
+elif str(env['LIBGCC']).find('thumb') != -1:
+ mycflags.append('-mthumb')
+ myasflags.append('-Wa,-mcpu=arm7tdmi,-mfpu=softfpa,-mthumb')
+else:
+ myasflags.append('-Wa,-mcpu=arm7tdmi,-mfpu=softfpa')
+mycflags.append('-g')
+mycflags.append('-ggdb')
+# Big Endian Output (disabled by default)
+#mycflags.append('-D__BIG_ENDIAN__')
+# Test build for NxOS (Comment out for NXT Firmware)
+mycflags.append('-D__NXOS__')
+
+myasflags.append('-g')
+myasflags.append('-ggdb')
+# Big Endian Output (disabled by default)
+#mycflags.append('-D__BIG_ENDIAN__')
+# Test build for NxOS (Comment out for NXT Firmware)
+myasflags.append('-D__NXOS__')
+
+env.Replace(CCFLAGS = mycflags, ASFLAGS = myasflags )
+
+# Build the baseplate, and all selected application kernels.
+
+numProcs = os.sysconf('SC_NPROCESSORS_ONLN')
+SConscript(['SConscript'], 'numProcs env CheckTool')