aboutsummaryrefslogtreecommitdiff
path: root/AT91SAM7S256/armdebug/Debugger
diff options
context:
space:
mode:
authorTat-Chee Wan (USM)2011-08-08 09:04:24 +0800
committerTat-Chee Wan (USM)2011-08-08 09:04:24 +0800
commit627bfbd9b437abf97a3609469f989f1a171975a8 (patch)
tree0fd28561c48b5d1ec03679f60248dc0efb851b34 /AT91SAM7S256/armdebug/Debugger
parent9d56c34fdd00926936b019ee34b648fbc74a0575 (diff)
parent2d73bfd4a555acbb40523a02fa2dc9043e5f0444 (diff)
Merge branch 'master' of ssh://svc.cs.usm.my/~/gitrepo-bare/armdebug
Diffstat (limited to 'AT91SAM7S256/armdebug/Debugger')
-rw-r--r--AT91SAM7S256/armdebug/Debugger/abort_handler.S108
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_comm.S19
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_hexutils.S4
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_internals.h100
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_macros.h195
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_opcodes.S1499
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S47
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.h39
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_stub.S1870
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_stub.h4
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_test.S107
-rw-r--r--AT91SAM7S256/armdebug/Debugger/debug_test.h3
-rw-r--r--AT91SAM7S256/armdebug/Debugger/undef_handler.S62
13 files changed, 2307 insertions, 1750 deletions
diff --git a/AT91SAM7S256/armdebug/Debugger/abort_handler.S b/AT91SAM7S256/armdebug/Debugger/abort_handler.S
new file mode 100644
index 0000000..f4d1bd0
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/abort_handler.S
@@ -0,0 +1,108 @@
+
+/* 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.
+ *
+ * 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"
+
+#define PREFETCH_OFFSET 4
+#define DATA_OFFSET 8
+
+/* Trap Abort Exceptions.
+ * 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: This routine closely mirrors the undef_handler routine, since we will store
+ * the ABORT stack frame in the UNDEF stack.
+ * In addition, since ARMDEBUG uses Abort mode, if the ABORT occurs while the
+ * debugger is running, the value of SP_abort is not valid. This should not happen
+ * in any case (it is a BUG if ARMDEBUG triggers an ABORT).
+ *
+ * We assume that the DEBUG stack holds only one stack frame and we will overwrite it.
+ * On entry, LR_undef contains the PC+4 for Prefetch Abort, and PC+8 for Data Abort.
+ *
+ * For the purpose of Debugging, the stack frame should present the PC (R15) as the address
+ * of the instruction that triggered the Abort. Hence we need to adjust R15
+ * to point to the address of the ABORTed instruction.
+ *
+ * We will also store ABORT LR (next instruction pointer) and ABORT 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: ABORT LR, then ABORT instruction address
+ * R1: SPSR
+ * R2: PC Offset, then Mode
+ * R3: DEBUG Stack Pointer (for Banked R13-R14 update)
+ * R4: Abort Type Enum
+ */
+
+.text
+.code 32
+.align 0
+
+ .extern dbg__display_abort_info
+ .extern dbg__abort_exception_handler
+ .extern default_prefetch_abort_handler
+ .extern default_data_abort_handler
+
+ .global prefetch_abort_handler
+ .global data_abort_handler
+
+prefetch_abort_handler:
+ ldr sp, =__debugger_stack__
+ stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */
+ mov r2, #PREFETCH_OFFSET
+ mov r4, #DISP_ABORT_PREFETCH /* Display Abort Info Type */
+ mov r5, #DBG_ABORT_PREFETCH /* Debugger Abort Type */
+ b _common_abort_handler
+
+data_abort_handler:
+ ldr sp, =__debugger_stack__
+ stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */
+ mov r2, #DATA_OFFSET
+ mov r4, #DISP_ABORT_DATA /* Display Abort Info Type */
+ mov r5, #DBG_ABORT_DATA /* Debugger Abort Type */
+
+_common_abort_handler:
+ sub r0, lr, r2 /* R0: Adjust PC to ABORTed instruction address */
+ str r0, [sp, #-4] /* Save ABORTed Instruction PC to stack (R15 slot) */
+ sub r3, sp, #4 /* Use R3 to write Banked R13-R14 of ABORT instruction, update R3 to point to R14 slot */
+
+ mrs r1, spsr /* Copy SPSR to r1 */
+ tst r1, #CPSR_THUMB /* Check for Thumb Mode */
+ addne r0, r0, #2 /* Is Thumb instruction, adjust PC for ABORT next instruction address */
+ addeq r0, r0, #4 /* Is ARM instruction, adjust PC for ABORT next instruction address */
+ sub sp, sp, #(4*16) /* Need to manually update SP(abort) */
+ stmfd sp!, {r0,r1} /* Save ABORTed Next Instr Pointer (in R0) and previous mode's CPSR to stack */
+
+ and r2, r1, #CPSR_MODE /* Get previous mode */
+ teq r2, #MODE_USR
+ beq _exit_abort_handler /* 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_ABT | CPSR_FIQ | CPSR_IRQ) /* Revert to ABORT Mode */
+
+_exit_abort_handler:
+ ldr sp, =__abort_stack__ /* Reinitialize stack pointer each time an Abort happens */
+ bic sp, sp, #7
+ mov r0, r4 /* Copy Display Abort Type Enum to R0 */
+ bl dbg__display_abort_info /* Display Abort Type to LCD */
+ mov r0, r5 /* Copy Debugger Abort Type Enum to R0 */
+ b dbg__abort_exception_handler /* Invoke Debugger */
+
+
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_comm.S b/AT91SAM7S256/armdebug/Debugger/debug_comm.S
index e237999..4c23912 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_comm.S
+++ b/AT91SAM7S256/armdebug/Debugger/debug_comm.S
@@ -360,7 +360,7 @@ _hasMsg2Copy:
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 */
+ beq exit_dbg__getMsgError /* Error from Host, Retransmit previous message */
teq r0, #MSGBUF_ACKCHAR /* Look for '+' */
addeq r5, r5, #1 /* Adjust Buffer Start Pointer (excl '+') */
subeq r4, r4, #1 /* Adjust Message Length */
@@ -398,7 +398,24 @@ _hasMsg2Copy:
beq exit_dbg__getDebugMsg /* Valid length, return */
exit_dbg__getMsgError:
+ /* We must first clear the existing message checksum */
+ ldr r1, =debug_msgTxBufPtr /* R5: data structure base pointer */
+ ldr r1, [r1] /* Tx buffer Start Address */
+
+1: ldrb r0, [r1], #1
+ teq r0, #MSGBUF_CHKSUMCHAR
+ bne 1b
+
+ mov r0, #0 /* ASCIIZ */
+ strb r0, [r1, #-1] /* Pointer R1 is now one past the MSGBUF_CHKSUMCHAR */
+
+ bl dbg__putDebugMsg /* Retransmit message */
+ mov r0, #0 /* Flag no message received */
+
+#if 0
mov r0, #MSGBUF_MSGERROR
+#endif
+
exit_dbg__getDebugMsg:
mov r1, r5 /* Return GDB Message Buffer Pointer in R1 */
ldmfd sp!, {r4,r5,pc}
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S b/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S
index d54445b..267406f 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S
+++ b/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S
@@ -22,7 +22,9 @@
.align 4
hex2char_lut:
- .ascii "0123456789ABCDEF"
+ /* .ascii "0123456789ABCDEF" */
+ /* Need to use lowercase hex chars to avoid confusion with GDB Error (E NN) response */
+ .ascii "0123456789abcdef"
/* Macros
*/
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_internals.h b/AT91SAM7S256/armdebug/Debugger/debug_internals.h
index c7f5d16..e187b82 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_internals.h
+++ b/AT91SAM7S256/armdebug/Debugger/debug_internals.h
@@ -119,6 +119,19 @@
#define CMD_STEP_MINPARAMLEN 0
/*@}*/
+/** @name Debug Query Command Constants.
+ *
+ * Debug Query Command
+ */
+/*@{*/
+#define CMD_QUERY_MINPARAMLEN 0
+#define CMD_QUERY_CURRTID_PARAMLEN 1
+#define CMD_QUERY_FTINFO_PARAMLEN 11
+#define CMD_QUERY_STINFO_PARAMLEN 11
+#define CMD_QUERY_CURRTID_CHAR 'C'
+#define CMD_QUERY_FTINFO_CHAR 'f'
+#define CMD_QUERY_STINFO_CHAR 's'
+/*@}*/
/** @name Debug Breakpoint Command Constants.
@@ -167,12 +180,12 @@
#define RESET_VECTOR 0x00000000
#define UNDEF_VECTOR 0x00000004
-#define SVC_VECTOR 0x00000008
+#define SVC_VECTOR 0x00000008
#define PABRT_VECTOR 0x0000000C
#define DABRT_VECTOR 0x00000010
#define RESERVED_VECTOR 0x00000014
-#define IRQ_VECTOR 0x00000018
-#define FIQ_VECTOR 0x0000001C
+#define IRQ_VECTOR 0x00000018
+#define FIQ_VECTOR 0x0000001C
/*@}*/
@@ -210,7 +223,7 @@
#define CPSR_FIQ 0x00000040
#define CPSR_IRQ 0x00000080
#define CPSR_MODE 0x0000001F
-#define CPSR_COND 0xF0000000
+#define CPSR_COND 0xF0000000
/* ARM Exception Modes */
#define MODE_USR 0x10 /* User mode */
@@ -230,6 +243,44 @@
#define CPSR_CFLAG 0x20000000
#define CPSR_VFLAG 0x10000000
+
+/*
+ * ARM Opcode Masks (for Parser)
+ */
+#define ARM_DATA_INSTR_MASK 0x0FBF0000
+#define ARM_DATA_INSTR_MSRMRS 0x010F0000
+#define ARM_DATA_INSTR_NORMAL 0x01E00000
+#define ARM_DATA_INSTR_IMMREG 0x02000000
+
+#define ARM_LDR_INSTR_REGIMM 0x02000000
+#define ARM_LDR_INSTR_PREPOST 0x01000000
+#define ARM_LDR_INSTR_UPDOWN 0x00800000
+
+#define ARM_LDM_INSTR_PREPOST 0x01000000
+#define ARM_LDM_INSTR_UPDOWN 0x00800000
+
+#define ARM_BLX_INSTR_MASK 0xFE000000
+#define ARM_BLX_INSTR_BLX 0xFA000000
+#define ARM_BLX_INSTR_HBIT 0x01000000
+
+#define ARM_SWI_INSTR_MASK 0x0F000000
+#define ARM_SWI_INSTR_VAL 0x0F000000
+
+
+/*
+ * Thumb Opcode Masks (for Parser)
+ */
+#define THUMB_BLX_INSTR_REG_RNMASK 0x0078
+
+#define THUMB_BCOND_SWI_INSTR_CONDMASK 0x0F00
+#define THUMB_BCOND_SWI_COND_UNUSED 0x0E00
+#define THUMB_BCOND_SWI_INSTR_SWI 0x0F00
+
+#define THUMB_BLX_INSTR_IMM_HBIT 0x0800
+#define THUMB_BLX_INSTR_IMM_MASK 0xF000
+#define THUMB_BLX_INSTR_IMM_BL 0xF000
+#define THUMB_BLX_INSTR_IMM_BLX 0xE000
+
/*@}*/
/** Debugger State Enums
@@ -249,13 +300,40 @@ ENUM_END(dbg_state_t)
* The enums must be consecutive, starting from 0
*/
ENUM_BEGIN
-ENUM_VALASSIGN(DBG_AUTO_BKPT,0) /**< Auto Breakpoint (Instruction resume after breakpoint). */
+ENUM_VALASSIGN(DBG_AUTO_BKPT,0) /**< RESERVED: 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_VAL(DBG_ABORT_PREFETCH) /**< Prefetch Abort. */
+ENUM_VAL(DBG_ABORT_DATA) /**< Data Abort. */
ENUM_END(bkpt_type_t)
+/** Debugger Message Signal Enums
+ *
+ * Debugger Signal Message Enums.
+ * The enums must be consecutive, starting from 0
+ */
+/* Need to sync with the Signal enums in ecos-common-hal_stub.c */
+ENUM_BEGIN
+ENUM_VALASSIGN(MSG_SIG_DEFAULT, 0) /**< Default Signal Response. */
+ENUM_VAL(MSG_SIG_HUP) /**< Hangup Signal Response. */
+ENUM_VAL(MSG_SIG_INT) /**< Interrupt Signal Response. */
+ENUM_VAL(MSG_SIG_QUIT) /**< Quit Signal Response. */
+ENUM_VAL(MSG_SIG_ILL) /**< Illegal Instruction Signal Response (not reset when caught). */
+ENUM_VAL(MSG_SIG_TRAP) /**< Trace Trap Signal Response (not reset when caught). */
+ENUM_VAL(MSG_SIG_ABRT) /**< Abort Signal Response (replace SIGIOT). */
+ENUM_VAL(MSG_SIG_EMT) /**< EMT Instruciton Signal Response. */
+ENUM_VAL(MSG_SIG_FPE) /**< Floating Point Exception Signal Response. */
+ENUM_VAL(MSG_SIG_KILL) /**< Kill Signal Response (cannot be caught or ignored). */
+ENUM_VAL(MSG_SIG_BUS) /**< Bus Error Signal Response. */
+ENUM_VAL(MSG_SIG_SEGV) /**< Segmentation Violation Signal Response. */
+ENUM_VAL(MSG_SIG_SYS) /**< Bad Argument to System Call Signal Response. */
+ENUM_VAL(MSG_SIG_PIPE) /**< Write on a Pipe with No Reader Signal Response. */
+ENUM_VAL(MSG_SIG_ALRM) /**< Alarm Clock Signal Response. */
+ENUM_VAL(MSG_SIG_TERM) /**< Software Termination Signal from Kill Signal Response. */
+ENUM_END(dbg_msg_signo)
+
/** Debugger Message Error Enums
*
* Debugger Error Message Enums.
@@ -299,5 +377,17 @@ ENUM_VAL(REG_CPSR) /**< Previous Mode CPSR */
ENUM_END(register_enum_t)
+/** Abort Type Enums
+ *
+ * Abort Type used for interfacing with LCD Display routine.
+ * The enums must be consecutive, starting from 0
+ * Note: The values must align with those defined in NxOS's _abort.h
+ */
+ENUM_BEGIN
+ENUM_VALASSIGN(DISP_ABORT_PREFETCH,0) /**< Prefetch Abort. */
+ENUM_VAL(DISP_ABORT_DATA) /**< Data Abort. */
+ENUM_VAL(DISP_ABORT_SPURIOUS) /**< Spurious IRQ. */
+ENUM_VAL(DISP_ABORT_ILLEGAL) /**< Illegal Instruction. */
+ENUM_END(abort_type_t)
#endif /* __DEBUG_INTERNALS_H__ */
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_macros.h b/AT91SAM7S256/armdebug/Debugger/debug_macros.h
index 75d6299..8d63e46 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_macros.h
+++ b/AT91SAM7S256/armdebug/Debugger/debug_macros.h
@@ -67,7 +67,7 @@
*/
.macro _dbg_armDecodeEntry instrreg, instrmask, codehandler, indexreg
- ldr \instrmask, =debug_thumbDecodeTable /* Temporary register */
+ ldr \instrmask, =debug_armDecodeTable /* Temporary register */
add \instrmask, \instrmask, \indexreg, lsl #3
add \instrmask, \instrmask, \indexreg, lsl #2 /* 12 byte entries */
ldm \instrmask, {\instrreg, \instrmask, \codehandler}
@@ -122,17 +122,44 @@
bne 1b
.endm
+/* _dbg_CopyMsg2OutputBuf
+ * Copies source message to output buffer
+ * On entry:
+ * R2: source message buffer (ASCIIZ terminated)
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R2-R3: destroyed
+ */
+ .macro _dbg_CopyMsg2OutputBuf
+ ldr r0, =debug_OutMsgBuf
+ _dbg_stpcpy r0, r2, r3
+ .endm
+
+/* _dbg_CopyMsg2OutputBuf_withParam
+ * Internal Routine called to output message with parameters
+ * Return Message with byte-sized parameter
+ * On entry:
+ * R1: byte-sized param
+ * R2: source message buffer (ASCIIZ terminated)
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R1-R3: destroyed
+ */
+ .macro _dbg_CopyMsg2OutputBuf_withParam
+ _dbg_CopyMsg2OutputBuf /* R1 unchanged */
+ bl byte2ascii /* R0 points to buffer position after byte value */
+ _asciiz r0, r1
+ .endm
+
/* _dbg_outputAckOnlyFlag
* Return Flag ('+') for Continue or Step
* On exit:
* R0: Pointer to Output Buffer ASCIIZ location
- * R1: destroyed
- * R2: destroyed
+ * R2-R3: destroyed
*/
.macro _dbg_outputAckOnlyFlag
- ldr r0, =debug_OutMsgBuf
- ldr r1, =debug_AckOnlyFlag /* ASCIIZ terminated */
- _dbg_stpcpy r0, r1, r2
+ ldr r2, =debug_AckOnlyFlag /* ASCIIZ terminated */
+ _dbg_CopyMsg2OutputBuf
.endm
@@ -140,104 +167,117 @@
* Return Flag ('-') for Checksum Error (retransmission needed)
* On exit:
* R0: Pointer to Output Buffer ASCIIZ location
- * R1: destroyed
- * R2: destroyed
+ * R2-R3: destroyed
*/
.macro _dbg_outputRetransmitFlag
- ldr r0, =debug_OutMsgBuf
- ldr r1, =debug_RetransmitFlag /* ASCIIZ terminated */
- _dbg_stpcpy r0, r1, r2
+ ldr r2, =debug_RetransmitFlag /* ASCIIZ terminated */
+ _dbg_CopyMsg2OutputBuf
.endm
/* _dbg_outputMsgValidResponse
* Return Message with valid response ('+$')
* On exit:
* R0: Pointer to Output Buffer next character slot location
- * R1: destroyed
- * R2: destroyed
+ * R2-R3: destroyed
*/
.macro _dbg_outputMsgValidResponse
- ldr r0, =debug_OutMsgBuf
- ldr r1, =debug_ValidResponsePrefix
- _dbg_stpcpy r0, r1, r2
+ ldr r2, =debug_ValidResponsePrefix
+ _dbg_CopyMsg2OutputBuf
.endm
-
/* _dbg_outputMsgStatusOk
* Return Message with Ok ('+$OK') status
* On exit:
* R0: Pointer to Output Buffer ASCIIZ location
- * R1: destroyed
- * R2: destroyed
+ * R2-R3: destroyed
*/
.macro _dbg_outputMsgStatusOk
- ldr r0, =debug_OutMsgBuf
- ldr r1, =debug_OkResponse /* ASCIIZ terminated */
- _dbg_stpcpy r0, r1, r2
+ ldr r2, =debug_OkResponse /* ASCIIZ terminated */
+ _dbg_CopyMsg2OutputBuf
.endm
-/* __dbg_outputErrMsg
- * Internal Routine called to generate error messages
- * Return Message with Error ('+$ENN') status
- * On entry:
- * R1: error code
- * On exit:
+/* _dbg_outputMsgCurrTID
+ * Return Message with Default Thread ID ('+$QC0')
+ * 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
+ * R2-R3: destroyed
+ */
+ .macro _dbg_outputMsgCurrTID
+ ldr r2, =debug_ThreadIDResponse /* ASCIIZ terminated */
+ _dbg_CopyMsg2OutputBuf
+ .endm
+
+/* _dbg_outputMsgFirstThreadInfo
+ * Return Message with Default Current Thread ID ('+$m0')
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R2-R3: destroyed
+ */
+ .macro _dbg_outputMsgFirstThreadInfo
+ ldr r2, =debug_FirstThreadInfoResponse /* ASCIIZ terminated */
+ _dbg_CopyMsg2OutputBuf
+ .endm
+
+/* _dbg_outputMsgSubsequentThreadInfo
+ * Return Message with Default Current Thread ID ('+$m0')
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R2-R3: destroyed
+ */
+ .macro _dbg_outputMsgSubsequentThreadInfo
+ ldr r2, =debug_SubsequentThreadInfoResponse /* ASCIIZ terminated */
+ _dbg_CopyMsg2OutputBuf
+ .endm
/* _dbg_outputMsgStatusErr
* Return Message with Error ('+$ENN') status
* On entry:
- * R0: error code
+ * R1: error code
* On exit:
* R0: Pointer to Output Buffer ASCIIZ location
- * R1: destroyed
- * R2: destroyed
- * R3: destroyed
+ * R1-R3: destroyed
*/
.macro _dbg_outputMsgStatusErr
- mov r1, r0
- __dbg_outputErrMsg
+ ldr r2, =debug_ErrorResponsePrefix
+ _dbg_CopyMsg2OutputBuf_withParam
.endm
/* _dbg_outputMsgStatusErrCode
* Return Message with Error ('+$ENN') status
* On exit:
* R0: Pointer to Output Buffer ASCIIZ location
- * R1: destroyed
- * R2: destroyed
+ * R1-R3: destroyed
*/
.macro _dbg_outputMsgStatusErrCode errcode
mov r1, #\errcode
- __dbg_outputErrMsg
+ _dbg_outputMsgStatusErr
.endm
/* _dbg_outputMsgStatusSig
* Return Message with Signal ('+$SNN') status
+ * On entry:
+ * R1: signal code
* On exit:
* R0: Pointer to Output Buffer ASCIIZ location
- * R1: destroyed
- * R2: destroyed
+ * R1-R3: destroyed
*/
- .macro _dbg_outputMsgStatusSig statuscode
- ldr r0, =debug_OutMsgBuf
- ldr r1, =debug_SignalResponsePrefix
- _dbg_stpcpy r0, r1, r2
+ .macro _dbg_outputMsgStatusSig
+ ldr r2, =debug_SignalResponsePrefix
+ _dbg_CopyMsg2OutputBuf_withParam
+ .endm
+
+/* _dbg_outputMsgStatusSigCode
+ * Return Message with Signal ('+$SNN') status
+ * On exit:
+ * R0: Pointer to Output Buffer ASCIIZ location
+ * R1-R3: destroyed
+ */
+ .macro _dbg_outputMsgStatusSigCode statuscode
mov r1, #\statuscode
- bl byte2ascii /* R0 points to buffer position after byte value */
- _asciiz r0, r1
+ _dbg_outputMsgStatusSig
.endm
+
/* _regenum2index
* Convert register enum to debugger stack index
*
@@ -281,6 +321,34 @@
str \contentsreg, [\addressreg, \indexreg, lsl #2]
.endm
+/* _getdbgregister
+ * Retrieve register contents from debugger stack given immediate index value
+ *
+ * On entry:
+ * indexval contains debugger stack index value (0-max index)
+ * On exit:
+ * contentsreg: Register Contents for given index
+ */
+ .macro _getdbgregister indexval, contentsreg
+ ldr \contentsreg, =__debugger_stack_bottom__
+ ldr \contentsreg, [\contentsreg, #(\indexval << 2)]
+ .endm
+
+/* _setdbgregister
+ * Store register contents to debugger stack given immediate index value
+ *
+ * On entry:
+ * indexval contains debugger stack index value (0-max index)
+ * contentsreg: Register Contents for given index
+ * addressreg: Scratch register for address pointer
+ * On exit:
+ * contentsreg: Register Contents for given index
+ * addressreg: Destroyed
+ */
+ .macro _setdbgregister indexval, contentsreg, addressreg
+ ldr \addressreg, =__debugger_stack_bottom__
+ str \contentsreg, [\addressreg, #(\indexval << 2)]
+ .endm
/* _index2bkptindex_addr
* Convert Breakpoint index to breakpoing entry address
@@ -349,18 +417,27 @@
.endm
/* _dbg_set_bkpt_type
+ * Set Breakpoint Type using value in reg
+ * On exit:
+ * reg: destroyed
+ * r1: destroyed
+ */
+ .macro _dbg_set_bkpt_type reg
+ ldr r1, =debug_bkpt_type
+ strb \reg, [r1]
+ .endm
+
+/* _dbg_set_bkpt_type_val
* Set Breakpoint Type to given value
* On exit:
* r0, r1: destroyed
*/
- .macro _dbg_set_bkpt_type bkpt_type
+ .macro _dbg_set_bkpt_type_val bkpt_type
mov r0, #\bkpt_type
ldr r1, =debug_bkpt_type
strb r0, [r1]
.endm
-
-
/* _dbg_getcurrbkpt_index
* Get current breakpoint index
* On exit:
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_opcodes.S b/AT91SAM7S256/armdebug/Debugger/debug_opcodes.S
new file mode 100644
index 0000000..307da8b
--- /dev/null
+++ b/AT91SAM7S256/armdebug/Debugger/debug_opcodes.S
@@ -0,0 +1,1499 @@
+/** @file debug_opcodes.S
+ * @brief ARM Debugger Opcode Parsing 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
+ *
+ */
+
+/* WARNING: The following excepted code from eCos arm_stub.c has bugs in
+ * the next instruction address calculation logic. The C code has not been
+ * updated since it is only used for documentation purposes.
+ *
+ * Correct code behavior should be determined from the ARMDEBUG source code
+ * whenever there is conflict in the algorithms.
+ *
+ * Of note: ARM and Thumb mode BX PC handling (missing PC+8/PC+4 adjustment).
+ * LDM PC handling (missing Pre/Post Incr/Decr adjustment).
+ */
+/****************************************************************************
+// 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;
+ }
+}
+
+ ****************************************************************************/
+
+#define __ASSEMBLY__
+#include "debug_stub.h"
+#include "debug_internals.h"
+#include "debug_macros.h"
+
+.data
+.align 4
+/* 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)
+ */
+
+/* WARNING: The sequence of matching instructions is important!
+ * Always check from more specific to more general IBMs
+ * for instructions sharing common opcode prefix bits.
+ */
+debug_armDecodeTable:
+ .word 0x012fff10, 0x0ffffff0, _arm_bx_blx_handler /* [Prefix:00] BX or BLX. Note v4t does not have BLX instr */
+ .word 0x0000f000, 0x0c00f000, _arm_data_instr_handler /* [Prefix:00] Data Processing instr with Rd = R15 */
+/* .word 0x06000010, 0x0e000010, _arm_undef_handler */ /* [Prefix:01] Undefined instr: shouldn't occur, as it would've been trapped already. See _dbg_following_instruction_addr */
+ .word 0x0410f000, 0x0410f000, _arm_ldr_pc_handler /* [Prefix:01] LDR with Rd = PC */
+ .word 0x08108000, 0x0e108000, _arm_ldm_pc_handler /* [Prefix:10] LDM {pc} */
+ .word 0x0a000000, 0x0e000000, _arm_b_bl_blx_handler /* [Prefix:10] B, BL or BLX. Note v4t does not have BLX instr */
+ .word 0x0c000000, 0x0c000000, _arm_coproc_swi_handler /* [Prefix:11] Coprocessor instr or SWI */
+ .word 0x0,0x0,0x0 /* Null Entry */
+
+/* Thumb Instruction Decode Table
+ * .hword IID, IBM
+ * .word IHA (8 bytes)
+ */
+
+/* WARNING: The sequence of matching instructions is important!
+ * Always check from more specific to more general IBMs
+ * for instructions sharing common opcode prefix bits.
+ */
+debug_thumbDecodeTable:
+ .hword 0x4700, 0xff07
+ .word _thumb_bx_blx_handler /* [Prefix:01] BX or BLX. Note: Link (L:b7) is not checked in the mask */
+ .hword 0xbd00, 0xff00
+ .word _thumb_poppc_handler /* [Prefix:10] PUSH/POP, specifically POP {Rlist,PC} */
+ .hword 0xd000, 0xf000
+ .word _thumb_bcond_swi_handler /* [Prefix:11] B<cond> or SWI */
+ .hword 0xe000, 0xf800
+ .word _thumb_b_handler /* [Prefix:11] B */
+ .hword 0xf000, 0xf000
+ .word _thumb_long_bl_blx_handler /* [Prefix:11] 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
+ */
+
+
+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, 0xFF, 0xFF, 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 HI, LS, GE, LT, GT and LE instructions only
+ * Condition Code stored in the following order:
+ * b7 b6 b5 b4 b3 b2 b1 b0
+ * AND CHKZ CHKC CHKNV - Z set C set N==V (bit set = 1)
+ * OR - - - - Z clr C clr N!=V (bit clr = 0)
+ *
+ * HI: C set AND Z clr
+ * LS: C clr OR Z set
+ * GE: N == V
+ * LT: N != V
+ * GT: Z clr AND (N == V)
+ * LE: Z set OR (N != V)
+ */
+
+#define COMPLEX_CONDCODE_START 0x08
+#define COMPLEX_CONDCODE_NEQV_MASK 0x01
+#define COMPLEX_CONDCODE_CSET_MASK 0x02
+#define COMPLEX_CONDCODE_ZSET_MASK 0x04
+#define COMPLEX_CONDCODE_CHKNV_MASK 0x10
+#define COMPLEX_CONDCODE_CHKC_MASK 0x20
+#define COMPLEX_CONDCODE_CHKZ_MASK 0x40
+#define COMPLEX_CONDCODE_ANDOR_MASK 0x80
+
+#define COMPLEX_CONDCODE_NFLAG 0x08
+#define COMPLEX_CONDCODE_ZFLAG 0x04
+#define COMPLEX_CONDCODE_CFLAG 0x02
+#define COMPLEX_CONDCODE_VFLAG 0x01
+
+
+debug_armComplexCCTable:
+ /* HI, LS, GE, LT, GT, LE */
+ .byte 0xE2, 0x64, 0x11, 0x10, 0xD1, 0x54
+
+.code 32
+.text
+.align 4
+
+/* 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).
+ */
+ .global dbg_following_instruction_addr
+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 */
+ _getdbgregister DBGSTACK_USERCPSR_INDEX, r1 /* Retrieve User CPSR into R1 */
+ and r0, r1, #CPSR_THUMB /* store Thumb Mode status in R0 */
+ mov r5, r1, lsr #28 /* store CPSR condition flags in R5[3:0] */
+
+_dbg_get_aborted_instr:
+1: teq r0, #0 /* Check if it is ARM or Thumb instruction */
+ ldrneh r4, [r6] /* Load Thumb instruction opcode using Addr in R6 into R4 */
+ ldrne r2, =(BKPT16_INSTR | BKPT16_MANUAL_BKPT) /* check for Thumb Manual Breakpoint Instruction */
+ ldreq r4, [r6] /* Load ARM instruction opcode using Addr in R6 into R4 */
+ ldreq r2, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */
+ teq r4, r2 /* Is instruction opcode (R4) == Manual Breakpoint opcode (R2)? */
+ bne 2f /* Not Manual breakpoint */
+ teq r0, #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, R4 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 R4 (Default Following Instruction Address in R6).
+ */
+2:
+ teq r0, #0 /* Check if current instruction is ARM or Thumb instruction */
+ beq _following_instr_addr_for_arm
+_following_instr_addr_for_thumb:
+ add r6, r6, #2 /* Store default following Thumb instruction address to R6 */
+#if 0
+ /* Flag Thumb instruction only within the instruction handler */
+ orr r6, r6, #BKPT_STATE_THUMB_FLAG /* Set b0 to indicate Thumb instruction */
+#endif
+ /* R4: 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_addr_for_arm:
+ add r6, r6, #4 /* Store default following ARM instruction address to R6 */
+ /* R4: 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:
+ * R4: Opcode of 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}
+ bl _dbg_check_arm_condcode /* Returns R0: will_execute (boolean) */
+ teq r0, #FALSE
+ moveq r0, r6 /* If False (don't execute), so use Default Following Instruction Address */
+ beq _exit_eval_arm_instruction /* and Return to caller */
+
+_will_execute_arm_instr:
+ mov r0, #0 /* initialize ARM Decode Entry Table index register */
+1:
+ _dbg_armDecodeEntry r1, r2, r3, r0 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */
+ teq r1, #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, r4, r2 /* Use R7 to check masked instruction opcode (from R4) to see if it matches template (in R1) */
+ teq r7, r1
+ addne r0, r0, #1 /* No match, so keep looking */
+ bne 1b
+
+_call_arm_code_handler:
+ mov lr, pc
+ bx r3 /* Call Code Handler with R4: Instruction Opcode, R5[3:0]: CPSR, R6: 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:
+ * R4: Opcode of 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}
+ /* Only B<cond> instructions are conditionally executed, deal with it in that Code Handler */
+ mov r0, #0 /* initialize Thumb Decode Entry Table index register */
+1:
+ _dbg_thumbDecodeEntry r1, r2, r3, r0 /* instrreg (R1), instrmask (R2), codehandler (R3), indexreg (R0) */
+ teq r1, #0 /* Check for Null Entry (End of Table marker) */
+ moveq r0, r6 /* End of Table, no match found, so use Default Following Instruction Address */
+ orreq r0, r0, #BKPT_STATE_THUMB_FLAG /* Set R0[0] to flag Thumb mode */
+ beq _exit_eval_thumb_instruction
+
+ and r7, r4, r2 /* Use R5 to check masked instruction opcode (from R4) to see if it matches template (in R1) */
+ teq r7, r1
+ addne r0, r0, #1 /* No match, so keep looking */
+ bne 1b
+
+_call_thumb_code_handler:
+ mov lr, pc
+ bx r3 /* Call Code Handler with R4: Instruction Opcode, R5[3:0]: CPSR, R6: 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:
+ * R4: Opcode of instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * On exit:
+ * R0: will_execute (boolean)
+ * R1-R3: Destroyed
+ */
+
+_dbg_check_arm_condcode:
+ mov r0, #TRUE /* Default will_execute value */
+ mov r3, r4, lsr #28 /* convert opcode's condition code to index (0-F) */
+ ldr r2, =debug_armCondCodeTable
+ ldrb r1, [r2, r3] /* Get condition code mask */
+/*
+ * The following check is unnecessary as it is covered by the _dbg_cond_simple_checks checking algorithm
+ teq r1, #0
+ beq _dbg_check_arm_condcode_exit
+*/
+ teq r1, #0xFF
+ bne _dbg_cond_simple_checks
+
+
+/*
+ * Complex Checks:
+ * We assume that CHKNV and CHKC are mutually exclusive.
+ * In addition, it is possible for CHKNV, CHKC and CHKZ to
+ * be cleared, in which case it'll return True (default)
+ *
+ *
+ * will_execute = TRUE [default condition]
+ * If (CHKNV) set
+ * // Only N/V, and Z flags are involved
+ * NEQV_Flag = (N == V)
+ * will_execute = (NEQV_Flag == NEQV_Mask)
+ *
+ * If (CHKC) set
+ * // Only C and Z flags are involved
+ * will_execute = (C_Flag == CSet_Mask)
+ *
+ * If (CHKZ) set
+ * z_match = (Z_Flag == ZSet_Mask)
+ * If (AND bit set)
+ * will_execute = will_execute && z_match
+ * else
+ * will_execute = will_execute || z_match
+ *
+ */
+_dbg_cond_complex_checks:
+ sub r3, r3, #COMPLEX_CONDCODE_START /* Convert complex condition code in R3 to new index (0-3) */
+ ldr r2, =debug_armComplexCCTable
+ ldrb r1, [r2, r3] /* Get complex condition code bitmap in R1 */
+
+_cond_check_nv:
+ tst r1, #COMPLEX_CONDCODE_CHKNV_MASK
+ beq _cond_check_c /* CHECKNV not set, so skip */
+ ands r2, r5, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* Is (N == V == 0)? */
+ teqne r2, #(COMPLEX_CONDCODE_NFLAG | COMPLEX_CONDCODE_VFLAG) /* No, Is (N == V == 1)? */
+
+ moveq r2, #COMPLEX_CONDCODE_NEQV_MASK /* EQ: Either (N == V == 0) or (N == V == 1), set R2: COMPLEX_CONDCODE_NEQV_MASK */
+ movne r2, #0 /* NE: N != V, clear R2 */
+ and r3, r1, #COMPLEX_CONDCODE_NEQV_MASK /* R3: Extract NEQV Mask Value */
+ teq r2, r3 /* Does N/V Condition match NEQV Mask value? */
+ movne r0, #FALSE /* No, so will_execute = FALSE (for now) */
+ b _cond_check_z
+
+#if 0
+ bne _cond_nnev /* No, so (N != V) */
+
+ /* EQ: Either (N == V == 0) or (N == V == 1) */
+_cond_neqv:
+ tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */
+ moveq r0, #FALSE /* No, so will_execute = FALSE (for now) */
+ b _cond_check_z
+
+ /* Else, N != V */
+_cond_nnev:
+ tst r1, #COMPLEX_CONDCODE_NEQV_MASK /* Is (N == V) mask set? */
+ movne r0, #FALSE /* Yes, so will_execute = FALSE (for now) */
+ b _cond_check_z
+#endif
+
+_cond_check_c:
+ tst r1, #COMPLEX_CONDCODE_CHKC_MASK
+ beq _cond_check_z /* CHECKC not set, so skip */
+
+ /* Use R2 to store C Flag, R3 to store CSet Mask */
+ and r2, r5, #COMPLEX_CONDCODE_CFLAG /* r2 = C flag */
+ and r3, r1, #COMPLEX_CONDCODE_CSET_MASK /* r3 = CSet mask */
+ teq r2, r3 /* Does C flag == CSet mask */
+ movne r0, #FALSE /* No, so C flag failed match */
+
+_cond_check_z:
+ tst r1, #COMPLEX_CONDCODE_CHKZ_MASK
+ beq _dbg_check_arm_condcode_exit /* No additional checks needed, exit */
+
+ /* Use R2 to store Z Flag, R3 to store ZSet Mask */
+ and r2, r5, #COMPLEX_CONDCODE_ZFLAG /* r2 = Z flag */
+ and r3, r1, #COMPLEX_CONDCODE_ZSET_MASK /* r3 = ZSet mask */
+ teq r2, r3 /* Does Z flag == ZSet mask */
+ moveq r3, #TRUE /* Zero, so z flag matched */
+ movne r3, #FALSE /* Non-zero, so z flag failed match */
+
+_cond_andor:
+ tst r1, #COMPLEX_CONDCODE_ANDOR_MASK /* Is ANDOR mask set? */
+ andne r0, r0, r3 /* Yes, so AND with will_execute */
+ orreq r0, r0, r3 /* No, so OR with will_execute */
+ b _dbg_check_arm_condcode_exit /* Return will_execute (R0) */
+
+/*
+ * Simple Checks:
+ * We take advantage of the fact that only 1 bit would be set
+ * in the bitmask, by generating the corresponding actual
+ * CondSet[7:4], CondClr[3:0] value for comparison.
+ *
+ * will_execute = TRUE [default condition, equivalent to 0x00 (AL) ]
+ * Generate CondSetClr[7:0] from CPSR[3:0]
+ * will_execute = ((CondSetClr & BitMask) == BitMask)
+ *
+ */
+_dbg_cond_simple_checks:
+ eor r2, r5, #NIBBLE0 /* R2: CondClr[3:0] = Invert CPSR[3:0] */
+ orr r2, r2, r5, lsl #4 /* R2: CondSet[7:4] | CondClr[3:0] */
+ and r2, r2, r1 /* R2: CondSetClr[7:0] & Bitmask */
+ teq r2, r1 /* ((cond_code & SetBitMask) == SetBitMask)? */
+ movne r0, #FALSE /* Not equal, check failed */
+
+_dbg_check_arm_condcode_exit:
+ bx lr /* Return to caller */
+
+/* _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: 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:
+ _getdbgregister DBGSTACK_USERCPSR_INDEX, r1 /* Retrieve CPSR contents 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:
+ * R4: Opcode of instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Following Instruction Address (PC+4)
+ * On exit:
+ * R0: following instruction address
+ * R1-R7: Destroyed
+ */
+_arm_data_instr_handler:
+ stmfd sp!, {lr}
+ ldr r1, =ARM_DATA_INSTR_MASK
+ and r3, r4, r1 /* Keep base instruction Opcode in R3 */
+ ldr r1, =ARM_DATA_INSTR_MSRMRS
+ teq r3, 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_check_operand2_type:
+ tst r4, #ARM_DATA_INSTR_IMMREG /* Check for Immediate (1) or Register (0) Operand 2 */
+ beq _arm_op2_is_reg
+
+_arm_op2_is_imm:
+ and r1, r4, #BYTE0 /* 8 bit unsigned constant in R1 */
+ and r2, r4, #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, r4, r1 /* 12 bit register operand in R1 */
+ bl _arm_rmshifted_val /* R0 contains the Rm shifted val */
+ mov r1, r0 /* R1: Operand2 val */
+
+_arm_get_operand1_val:
+ bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */
+
+_arm_calc_data_instr_val:
+ and r3, r4, #ARM_DATA_INSTR_NORMAL /* Mask Instruction Opcode into R3[24:21] */
+ lsr r3, r3, #21 /* Shift Data Processing Opcode into R3[3:0] */
+ /* Calculate data instruction value from R0: Register Rn (Operand1) val, R1: Operand2 val, R5[3:0]: CPSR, R6: Default Next Instr Addr */
+ _dbg_jumpTableHandler debug_dataInstrJumpTable, r2, r3 /* Next Instruction Address in R0 */
+_exit_arm_data_instr_handler:
+ ldmfd sp!, {pc}
+
+/* _dbg_data_instr_retrieve_op1val
+ * Retrieve Data Instruction Operand 1 value
+ * On entry:
+ * R4: Opcode of instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Next Instruction Address (PC+4)
+ * On exit:
+ * R0: Register Rn (Operand 1) value
+ * R2, R3: Destroyed
+ *
+ */
+_dbg_data_instr_retrieve_op1val:
+ and r3, r4, #NIBBLE4 /* Store Rn (Operand1) Register Enum into R3[19:16] */
+ lsr r3, r3, #16 /* Shift into R3[3:0] */
+ _regenum2index r3, r2 /* Convert Enum into Index in R2 */
+ _getdbgregisterfromindex r2, r0 /* Retrieve Register contents from Index (R2) into R0 */
+ teq r3, #REG_PC /* Check if it is PC relative */
+ addeq r0, r0, #8 /* R0: Register Rn (Operand1) val; adjust for PC relative (+8) */
+ bx lr
+
+/* Data Processing Instruction Jump Table Routines
+ * On entry:
+ * R0: Register Rn (Operand 1) value
+ * R1: Operand 2 value
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Next Instruction Address (PC+4)
+ * 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 */
+ tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */
+ add r0, r0, r1
+ addne r0, r0, #1 /* Add C if set */
+ bx lr
+
+_opcode_sbc:
+ /* Op1 - Op2 + C - 1 */
+ tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */
+ 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 */
+ tst r5, #(CPSR_CFLAG>> 28) /* R5[3:0] is shifted CPSR value: Test C Flag */
+ 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, r6 /* 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:
+ * R4: Opcode of 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,R2: destroyed
+ */
+_arm_bx_blx_handler:
+ stmfd sp!, {lr}
+ and r2, r4, #NIBBLE0 /* Register Rn Enum in R2 */
+ _regenum2index r2, r1 /* Convert Enum into Index in R1 */
+ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */
+ teq r2, #REG_PC
+ addeq r0, r0, #8 /* Adjust PC relative register value (for BX PC) */
+ /* Here, the register value would have B0 set to indicate switch to Thumb mode */
+ ldmfd sp!, {pc}
+
+/* _arm_ldr_pc_handler
+ * LDR with Rd = PC
+ * On entry:
+ * R4: Opcode of instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Following Instruction Address (PC+4)
+ * On exit:
+ * R0: following instruction address
+ * R1, R2, R3, R4, R5: destroyed
+ */
+
+_arm_ldr_pc_handler:
+ stmfd sp!, {lr}
+
+ mov r1, #0 /* R1: Post-Indexed Offset (cleared) */
+ tst r4, #ARM_LDR_INSTR_PREPOST /* Pre (1) or Post (0) Indexed */
+ beq _get_rn_val /* If Post-Indexed, just use Rn directly */
+
+ /* Pre-Indexed */
+ ldr r0, =(NIBBLE2|BYTE0)
+ and r0, r4, r0 /* R0: 12 bit Immediate value or Shifted Reg operand */
+ tst r4, #ARM_LDR_INSTR_REGIMM /* Register (1) or Immediate (0) */
+ beq _calc_ldr_pc_offset /* Immediate value is already in R0 */
+
+_get_shiftedreg_val:
+ bl _arm_rmshifted_val /* Convert Rm shifted operand in R0 into value in R0 */
+
+_calc_ldr_pc_offset:
+ mov r1, r0 /* Keep Offset in R1 */
+_get_rn_val:
+ bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */
+_calc_op1val_with_offset:
+ tst r4, #ARM_LDR_INSTR_UPDOWN /* Add (1) or Subtract (0) */
+ addne r0, r0, r1 /* If Add, R0 = Rn + Offset */
+ subeq r0, r0, r1 /* If Sub, R0 = Rn - Offset */
+
+_get_ldr_pc_val_from_mem:
+ ldr r0, [r0] /* Retrieve value from Memory at address given in R0 */
+ ldmfd sp!, {pc}
+
+/* _arm_ldm_pc_handler
+ * LDM {pc}
+ * On entry:
+ * R4: Opcode of instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Following Instruction Address (PC+4)
+ * On exit:
+ * R0: following instruction address
+ * R2, R3: destroyed
+ *
+ * Note: The algorithm from eCos arm_stub.c does not deal with the Pre/Post-Indexed addressing (P) bit.
+ * The algorithm here loads different content using LDM based on the value of the P bit.
+ */
+_arm_ldm_pc_handler:
+ stmfd sp!, {lr}
+ bl _dbg_data_instr_retrieve_op1val /* R0: Register Rn (Operand1) val */
+
+_arm_get_regcount:
+ mov r2, #0 /* Initialize reg_count (R2) to 0 */
+ mov r3, r4, 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 */
+
+ /* Pre-Incr: Rn += reg_count x 4
+ * Post-Incr: Rn += (reg_count - 1) x 4
+ * Pre-Decr: Rn -= 4
+ * Post-Decr: Rn
+ */
+
+_arm_check_updown_offset:
+ tst r4, #ARM_LDM_INSTR_UPDOWN /* Check Up (1) or Down (0) */
+ beq _arm_check_prepost_decr
+
+_arm_check_prepost_incr:
+ tst r4, #ARM_LDM_INSTR_PREPOST /* Check Pre (1) or Post (0) */
+ subeq r2, r2, #1 /* Post-Incr: Decrement reg_count in R2 */
+ add r0, r0, r2, lsl #2 /* Increment Offset: Rn (R0) += reg_count (R2) x 4 */
+ b _get_ldm_pc_val_from_mem
+
+_arm_check_prepost_decr:
+ tst r4, #ARM_LDM_INSTR_PREPOST /* Check Pre (1) or Post (0) */
+ /* Post-Decr: Rn unchanged */
+ subne r0, r0, #4 /* Pre-Decr: Rn (R0) -= 4 */
+
+_get_ldm_pc_val_from_mem:
+ ldr r0, [r0] /* 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:
+ * R4: Opcode of instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Following Instruction Address (PC+4)
+ * On exit:
+ * R0: following instruction address
+ * R1: destroyed
+ */
+
+_arm_b_bl_blx_handler:
+ stmfd sp!, {lr}
+
+_arm_b_bl_blx_get_offset:
+ and r0, r4, #(BYTE2|BYTE1|BYTE0) /* Encoded Branch offset in R4[23:0] */
+ lsl r0, r0, #(32-24) /* Shift to R0[31:8] */
+ asr r0, r0, #(32-26) /* Actual Signed offset = Encode Offset x 4 in R0[25:0] */
+ add r1, r6, #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 r1, r4, #ARM_BLX_INSTR_MASK /* Mask out Condition Code and Opcode */
+ teq r1, #ARM_BLX_INSTR_BLX /* Look for BLX */
+ bne _exit_arm_b_bl_blx_handler /* No, it is a B/BL instruction */
+ tst r4, #ARM_BLX_INSTR_HBIT /* H bit for Thumb Halfword Address */
+ orrne r0, r0, #0x02 /* Set Halfword Address R0[1] */
+ orr r0, r0, #BKPT_STATE_THUMB_FLAG /* Set R0[0] since BLX instr used to switch to Thumb mode */
+#endif
+
+_exit_arm_b_bl_blx_handler:
+ ldmfd sp!, {pc}
+
+/* _arm_coproc_swi_handler
+ * SVC (SWI) or Coprocessor instruction
+ * On entry:
+ * R4: Opcode of instruction to be executed
+ * R5[3:0]: CPSR condition codes
+ * R6: Default Following Instruction Address (PC+4)
+ * On exit:
+ * R0: following instruction address
+ */
+
+_arm_coproc_swi_handler:
+ and r0, r4, #ARM_SWI_INSTR_MASK
+ teq r0, #ARM_SWI_INSTR_VAL /* SVC (SWI) instruction */
+
+ ldreq r0, =SVC_VECTOR /* SWI: Return SVC Vector Address */
+ movne r0, r6 /* CoProc: Use default Following Instruction Address */
+_exit_arm_coproc_swi_handler:
+ bx lr
+
+/* _thumb_bx_blx_handler
+ * BX or BLX Handler. Note: Link (L:b7) is not checked in the mask; armv4t does not support BLX.
+ * On entry:
+ * R4: Opcode of 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, R2: destroyed
+ */
+_thumb_bx_blx_handler:
+ stmfd sp!, {lr}
+ and r2, r4, #THUMB_BLX_INSTR_REG_RNMASK /* Register Rn Enum in R2[6:3] (Hi-Reg indicated by B6) */
+ mov r2, r2, lsr #3 /* Shift Rn Enum to R2[3:0] */
+ _regenum2index r2, r1 /* Convert Enum into Index in R1 */
+ _getdbgregisterfromindex r1, r0 /* Retrieve Register contents from Index (R1) into R0 */
+ teq r2, #REG_PC
+ addeq r0, r0, #4 /* Adjust PC relative register value (for BX PC) */
+ /* 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:
+ * R4: Opcode of 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-R3: destroyed
+ */
+_thumb_poppc_handler:
+ stmfd sp!, {lr}
+
+_thumb_get_SP_val:
+ _getdbgregister DBGSTACK_USERSP_INDEX, r1 /* Retrieve SP contents into R1 */
+
+_thumb_get_regcount:
+ mov r3, r4, lsl #24 /* Keep BYTE0 containing vector bits in R3[31:24] */
+ /* POP is equivalent to LDMFD. Load PC is encoded in b8,
+ * the 8-bit vector is for Lo registers.
+ * This shortens the checking to a max of 8 iterations
+ */
+1: movs r3, r3, lsl #1 /* count number of '1' bits */
+ addcs 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, #BKPT_STATE_THUMB_FLAG /* 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:
+ * R4: Opcode of 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-R3: destroyed
+ */
+_thumb_bcond_swi_handler:
+ stmfd sp!, {lr}
+ and r2, r4, #THUMB_BCOND_SWI_INSTR_CONDMASK /* Keep Condition Code R2[11:8] */
+ teq r2, #THUMB_BCOND_SWI_INSTR_SWI /* 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, #THUMB_BCOND_SWI_COND_UNUSED
+ moveq r0, r6 /* False (don't execute), so use Default Following Instruction Address */
+ beq _exit_thumb_bcond_instr
+
+_thumb_bcond_instr:
+ stmfd sp!, {r4} /* Preserve Opcode in R4 */
+ lsl r4, 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) */
+ ldmfd sp!, {r4} /* Restore Opcode in R4 */
+ 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, #BKPT_STATE_THUMB_FLAG /* Set R0[0] since it is used to indicates Thumb mode */
+_exit_thumb_bcond_swi_handler:
+ ldmfd sp!, {pc}
+
+/* _thumb_b_handler
+ * B
+ * On entry:
+ * R4: Opcode of 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: destroyed
+ * Note: The signed offset is 12-bits (encoded value x 2)
+ */
+_thumb_b_handler:
+ stmfd sp!, {lr}
+ lsl r0, r4, #(32-11) /* Shift 11-bit offset in R4[10:0] to R0[31:21] */
+ asr r0, r0, #(32-12) /* Convert into 12-bit signed offset in R0[11:0] */
+ add r0, r6, r0 /* PC+2 + signed offset */
+ add r0, r0, #2 /* PC+4 + signed offset */
+ orr r0, r0, #BKPT_STATE_THUMB_FLAG /* 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:
+ * R4: Opcode of 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, R2, R3: destroyed
+ * R6: Subseqent Instruction Address (PC+4) if first instruction is valid, else unchanged (PC+2)
+ * 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}
+_thumb_check_1st_bl_blx_instruction:
+ tst r4, #THUMB_BLX_INSTR_IMM_HBIT /* Check H bit */
+ bne _return_default_thumb_following_instr /* H=1 as first instruction shouldn't happen */
+_thumb_check_2nd_bl_blx_instruction:
+ ldrh r3, [r6] /* Get second instruction in pair at PC+2 into R3 */
+ add r6, r6, #2 /* Skip to Subsequent Instruction (PC+4) */
+ tst r3, #THUMB_BLX_INSTR_IMM_HBIT /* Check H bit */
+ beq _return_default_thumb_following_instr /* H=0 as second instruction shouldn't happen */
+
+_thumb_concat_branch_offset:
+ lsl r0, r4, #(32-11) /* Shift first instruction 11-bit offset in R4[10:0] to R0[31:21] */
+ asr r0, r0, #(32-23) /* Convert into 12-bit signed offset in R0[22:12] */
+ lsl r2, r3, #(32-11) /* Shift second instruction 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, r6, r0 /* PC+4 + signed offset */
+
+_thumb_check_bl_blx_pair:
+ and r3, r3, #THUMB_BLX_INSTR_IMM_MASK /* Keep second instruction opcode in R3 */
+ teq r3, #THUMB_BLX_INSTR_IMM_BL /* Look for BL */
+ beq _flag_thumb_instr_addr /* Return BL target address in R0 */
+
+#ifndef __ARM6OR7__
+ /* v5t or higher architecture */
+ teq r3, #THUMB_BLX_INSTR_IMM_BLX /* Look for BLX */
+ biceq r0, r0, #0x03 /* Match, Force ARM address */
+ beq _exit_thumb_long_bl_blx_handler
+#endif
+
+_return_default_thumb_following_instr:
+ /* FIXME: This assumes that once the 4-byte sequence check fails, it will return PC+4,
+ * regardless of whether the second instruction is a valid BL/BLX instruction or not.
+ */
+ mov r0, r6 /* Return default Following/Subsequent Instruction Address */
+_flag_thumb_instr_addr:
+ orr r0, r0, #BKPT_STATE_THUMB_FLAG /* Set R0[0] since it is used to indicates Thumb mode */
+
+_exit_thumb_long_bl_blx_handler:
+ ldmfd sp!, {pc}
+
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
index 75c477c..3bcf35a 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
+++ b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S
@@ -80,6 +80,7 @@
.align 4
.global dbg__runloopTasks
.global dbg__reboot
+ .global dbg__display_abort_info
.global dbg__sendCommMsg
#ifdef __NXOS__
@@ -90,7 +91,10 @@
****************************************************************************/
dbg__runloopTasks:
/* Currently, there's nothing that needs to be done in the NxOS Run Loop */
- bx lr
+ push {lr}
+ mov r0, #1 /* 1 ms delay */
+ bl nx_systick_wait_ms
+ pop {pc}
#else
/****************************************************************************
@@ -113,7 +117,11 @@ dbg__runloopTasks:
*
****************************************************************************/
dbg__reboot:
+#ifdef REBOOT_POWERDOWN
+ b nx_core_halt /* Shutdown Brick, won't return */
+#else
b nx_core_reset /* Reboot Brick, won't return */
+#endif
#else
/****************************************************************************
@@ -161,6 +169,35 @@ _dbg__reboot_wait:
b _dbg__reboot_wait /* Wait for AVR... */
#endif
+#ifdef __NXOS__
+/****************************************************************************
+ *
+ * NxOS Abort Info LCD Display Routine
+ *
+ ****************************************************************************/
+/* On entry:
+ * r0: abort type
+ * On exit:
+ * r0-r3: destroyed
+ */
+dbg__display_abort_info:
+ push {lr}
+ _getdbgregister DBGSTACK_USERPC_INDEX, r1 /* Retrieve User PC into R2 */
+ _getdbgregister DBGSTACK_USERCPSR_INDEX, r2 /* Retrieve User CPSR into R2 */
+ bl nx__abort_info /* void nx__abort_info(U32 data, U32 pc, U32 cpsr); */
+ pop {pc}
+
+#else
+/****************************************************************************
+ *
+ * NXT Firmware Abort Info LCD Display Routine
+ *
+ ****************************************************************************/
+dbg__display_abort_info:
+/* FIXME: Inteface with NXT Firmware LCD Display routines */
+ push {lr}
+ pop {pc}
+#endif
#ifdef __NXOS__
.extern debug_OutCommBuf
@@ -174,7 +211,8 @@ _dbg__reboot_wait:
* On entry:
* R0: Total Message Buffer length
* On exit:
- R0: Tx Status (TRUE if data sent)
+ * R0: Tx Status (TRUE if data sent)
+ * R1-R3: Destroyed
*/
dbg__sendCommMsg:
stmfd sp!, {r4, lr}
@@ -191,12 +229,15 @@ dbg__sendCommMsg:
mov r1, r4 /* Comm buffer length */
bl nx_usb_write
-1: bl nx_usb_data_written /* R0 = True if data has been sent */
+1: bl nx_usb_data_written /* R0 = True if data has been sent */
teq r0, #0 /* FALSE == #0;
We can't check for True condition since values
used by C-Compiler & ARMDEBUG are different */
/* FIXME: implement timeout */
beq 1b /* Busy Wait Loop */
+
+ mov r0, #TRUE
+ b exit_dbg__sendCommMsg
dbg__sendCommMsgFailed:
mov r0, #FALSE
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.h b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.h
index 360e0d1..f55311e 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.h
+++ b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.h
@@ -26,34 +26,37 @@
*/
#ifdef __NXOS__
+ .extern nx__abort_info
+ .extern nx_systick_wait_ms
- .extern nx_usb_is_connected
+ .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
.extern nx_core_reset
+ .extern nx_core_halt
#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 */
-
- .extern dIOCtrlSetPower
- .extern dIOCtrlSetPwm
- .extern dIOCtrlTransfer
- .equ BOOT, 0xA55A /* from c_ioctrl.iom */
- .equ POWERDOWN, 0x5A00 /* from c_ioctrl.iom */
+ .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 */
+
+ .extern dIOCtrlSetPower
+ .extern dIOCtrlSetPwm
+ .extern dIOCtrlTransfer
+ .equ BOOT, 0xA55A /* from c_ioctrl.iom */
+ .equ POWERDOWN, 0x5A00 /* from c_ioctrl.iom */
#endif
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_stub.S b/AT91SAM7S256/armdebug/Debugger/debug_stub.S
index e32c2dc..51bb0c6 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_stub.S
+++ b/AT91SAM7S256/armdebug/Debugger/debug_stub.S
@@ -72,7 +72,7 @@
* 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,
+ * x = ['0','F'] for R0-R15, ['10','17'] for F0-F7 (dummy)
* '18' for FPSCR (dummy), '19' for User CPSR
*
* mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
@@ -144,6 +144,9 @@
#include "debug_internals.h"
#include "debug_macros.h"
+ /* Opcode Parser function reference */
+ .extern dbg_following_instruction_addr
+
/* Hexutils function references */
.extern hex2char
.extern char2hex
@@ -248,6 +251,14 @@ debug_SignalResponsePrefix:
debug_OkResponse:
.byte '+','$','O','K',0
+debug_ThreadIDResponse:
+ .byte '+','$','Q','C','0',0 /* 0: Any thread */
+
+debug_FirstThreadInfoResponse:
+ .byte '+','$','m','0',0 /* 0: One default thread */
+debug_SubsequentThreadInfoResponse:
+ .byte '+','$','l',0 /* End of Thread List */
+
/* 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
@@ -280,158 +291,6 @@ debug_cmdJumpTable:
.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
@@ -504,10 +363,14 @@ debug_armComplexCCTable:
****************************************************************************/
.code 32
.align 4
- .global dbg__bkpt_init
/* dbg__bkpt_init
- * GDB set_debug_traps() routine
+ * GDB set_debug_traps() routine
+ * On entry:
+ * None
+ * On exit:
+ * r0-r3: destroyed
*/
+ .global dbg__bkpt_init
dbg__bkpt_init:
push {lr}
bl _dbg__clear_breakpoints
@@ -532,74 +395,8 @@ dbg__bkpt_init:
* 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
+ /* nop */
+ bx lr
/* _dbg__switch2undefmode
* Common internal routine to return execution to user program
@@ -611,12 +408,69 @@ _dbg__switch2undefmode:
ldr lr, =resume_execution
mov pc, lr /* Exit via UNDEF mode */
-_process_manual_breakpoint_thumb:
- _dbg_set_bkpt_type DBG_MANUAL_BKPT_THUMB
+/* dbg__abort_exception_handler
+ * Handle Abort Exceptions
+ * On entry:
+ * r0: Abort Type Enum
+ * On exit:
+ * routine does not 'exit' in the normal sense
+ */
+ .global dbg__abort_exception_handler
+dbg__abort_exception_handler:
+ _dbg_set_bkpt_type r0 /* Set Breakpoint Type given value in R0 */
b dbg__bkpt_waitCMD
-_process_manual_breakpoint_arm:
- _dbg_set_bkpt_type DBG_MANUAL_BKPT_ARM
+/* dbg__thumb_bkpt_handler
+ * GDB handle_exception() routine (Thumb Mode)
+ * On entry:
+ * r0: Breakpoint index value
+ * On exit:
+ * routine does not 'exit' in the normal sense
+ */
+ .global dbg__thumb_bkpt_handler
+dbg__thumb_bkpt_handler:
+ /* On entry, r0 contains breakpoint index value */
+ _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */
+ ldr r1, =BKPT16_MANUAL_BKPT
+ teq r0, r1
+ moveq r0, #DBG_MANUAL_BKPT_THUMB /* Manual Thumb Breakpoint, process it */
+ beq _restore_normal_breakpoints
+
+_process_normal_breakpoint_thumb:
+ ldr r1, =__breakpoints_num__
+ cmp r0, r1 /* Sanity check that index is in range */
+ bhs dbg__bkpt_offset_outofrange /* Exceeded Offset Range */
+ mov r0, #DBG_NORMAL_BKPT_THUMB /* It is a valid normal breakpoint */
+ b _restore_normal_breakpoints
+
+/* dbg__arm_bkpt_handler
+ * GDB handle_exception() routine (ARM Mode)
+ * On entry:
+ * r0: breakpoint index value
+ * On exit:
+ * routine does not 'exit' in the normal sense
+ */
+ .global dbg__arm_bkpt_handler
+dbg__arm_bkpt_handler:
+ /* On entry, r0 contains breakpoint index value */
+ _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */
+ ldr r1, =BKPT32_MANUAL_BKPT
+ teq r0, r1
+ moveq r0, #DBG_MANUAL_BKPT_ARM /* Manual ARM Breakpoint, process it */
+ beq _restore_normal_breakpoints
+
+_process_normal_breakpoint_arm:
+ ldr r1, =__breakpoints_num__
+ cmp r0, r1 /* Sanity check that index is in range */
+ bhs dbg__bkpt_offset_outofrange /* Exceeded Offset Range */
+ mov r0, #DBG_NORMAL_BKPT_ARM /* It is a valid normal breakpoint */
+/* b _restore_normal_breakpoints */
+
+_restore_normal_breakpoints:
+ _dbg_set_bkpt_type r0 /* Set Breakpoint Type given value in R0 */
+ bl _dbg__restore_breakpoints /* includes restoring single step */
+ bl _dbg__clear_singlestep
+ bl _dbg__flush_icache
/* b dbg__bkpt_waitCMD */
dbg__bkpt_inactive:
@@ -669,7 +523,7 @@ _proc_command:
_dbg_check_gdb_command:
teq r0, #MSGBUF_STARTCHAR
- movne r0, #MSG_ERRFORMAT /* Message Format invalid (not '$') */
+ movne r1, #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 */
@@ -681,7 +535,7 @@ _dbg_unknown_command:
b dbg__bkpt_waitCMD_cont
#if 0
- moveq r0, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */
+ moveq r1, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */
beq _dbg__cmdError /* Send response to GDB server */
#endif
@@ -844,11 +698,11 @@ __dbg__procCmdReturnOutputLengthError:
*/
__dbg__procBreakpointAddrError:
mov r1, #MSG_UNKNOWNBRKPT
- b __dbg__procErrorMsg
+/* b __dbg__procErrorMsg */
__dbg__procErrorMsg:
- __dbg_outputErrMsg
+ _dbg_outputMsgStatusErr
/* b __dbg__sendDebugMsgExit */
__dbg__sendDebugMsgExit:
@@ -864,7 +718,20 @@ __dbg__sendDebugMsgExit:
*/
_dbg__cmd_Status:
stmfd sp!, {lr}
- _dbg_outputMsgStatusSig 0x0 /* FIXME: Dummy Signal number */
+ _dbg_get_bkpt_type r0
+_check_data_abort_exception:
+ teq r0, #DBG_ABORT_DATA
+ moveq r1, #MSG_SIG_BUS /* Bus Error */
+ beq _exit_dmg__cmd_Status
+_check_prefetch_abort_exception:
+ teq r0, #DBG_ABORT_PREFETCH
+ moveq r1, #MSG_SIG_ABRT /* FIMXE: Look for a better Signal number */
+ beq _exit_dmg__cmd_Status
+_default_breakpoint_exception:
+ mov r1, #MSG_SIG_DEFAULT /* Dummy Signal number */
+
+_exit_dmg__cmd_Status:
+ _dbg_outputMsgStatusSig
b __dbg__sendDebugMsgExit
/* _dbg__cmd_Query
@@ -877,9 +744,38 @@ _dbg__cmd_Status:
* r0, r1, r2, r3: destroyed
*/
_dbg__cmd_Query:
- stmfd sp!, {lr}
+ stmfd sp!, {r0,r1, 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) */
+ ldmfd sp!, {r0, r1} /* Restore parameters needed for subsequent processing */
+ bl __dbg__cmdParamLen
+ cmp r1, #CMD_QUERY_MINPARAMLEN
+ beq _dbg__cmd_Query_default
+
+ ldrb r2, [r0] /* Get First Query Param Char */
+_dbg__cmd_Query_check_C:
+ teq r2, #CMD_QUERY_CURRTID_CHAR /* Handle Current Thread ID Query */
+ bne _dbg__cmd_Query_check_fThreadInfo
+ cmp r1, #CMD_QUERY_CURRTID_PARAMLEN
+ bne _dbg__cmd_Query_default
+ _dbg_outputMsgCurrTID
+ b __dbg__sendDebugMsgExit
+_dbg__cmd_Query_check_fThreadInfo:
+ teq r2, #CMD_QUERY_FTINFO_CHAR /* Handle fThreadInfo Query */
+ bne _dbg__cmd_Query_check_sThreadInfo
+ cmp r1, #CMD_QUERY_FTINFO_PARAMLEN
+ bne _dbg__cmd_Query_default
+ _dbg_outputMsgFirstThreadInfo
+ b __dbg__sendDebugMsgExit
+_dbg__cmd_Query_check_sThreadInfo:
+ teq r2, #CMD_QUERY_STINFO_CHAR /* Handle sThreadInfo ID Query */
+ bne _dbg__cmd_Query_default
+ cmp r1, #CMD_QUERY_STINFO_PARAMLEN
+ bne _dbg__cmd_Query_default
+ _dbg_outputMsgSubsequentThreadInfo
+ b __dbg__sendDebugMsgExit
+
+_dbg__cmd_Query_default:
+ b __dbg__procUnimplementedError /* FIXME: return an empty message to GDB (no modifiable settings) */
/* _dbg__cmd_GetOneReg
@@ -890,7 +786,7 @@ _dbg__cmd_Query:
* r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
* x
* On exit:
- * r0, r1, r2, r3: destroyed
+ * r0, r1, r2, r3, r4: destroyed
*
*/
_dbg__cmd_GetOneReg:
@@ -903,9 +799,9 @@ _dbg__cmd_GetOneReg:
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 */
+ mov r4, 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 */
+ mov r1, r4 /* Move register index value to R1 */
bl _dbg_outputOneRegValue /* update output buffer */
_asciiz r0, r1
bl dbg__putDebugMsg /* Send response to the GDB server */
@@ -931,13 +827,18 @@ _dbg_outputOneRegValue:
moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */
beq _retrieve_RegVal
+ bhi _exit_dbg_outputOneRegValue /* No match (reg enum > REG_CPSR), skip */
+
+#if 0
cmp r1, #REG_FPSCR
bne _exit_dbg_outputOneRegValue /* No match, skip */
+#endif
-_output_dummy_fpscr:
- /* Output Dummy FPSCR value */
+_output_dummy_regval:
+ /* Output Dummy Register value (for F0-F7, FPSR) */
+ /* FIXME: F0-F7 expects output value that is more than 32-bits */
mov r1, #0
- b _output2buffer /* Output all zeros for FPSCR */
+ b _output2buffer /* Output all zeros for F0-F7, FPSCR */
_retrieve_RegVal:
_getdbgregisterfromindex r2, r1 /* Retrieve Register contents into R1 */
@@ -955,7 +856,7 @@ _exit_dbg_outputOneRegValue:
/* _dbg__cmd_GetAllRegs
* Get All Register Values Command Handler
- * Output Buffer returns register values in the order: User R0, R1, R2, ..., R15, CPSR
+ * Output Buffer returns register values in the order: User R0, R1, R2, ..., R15
* On entry:
* r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
* <NULL> (no parameters)
@@ -977,10 +878,12 @@ _dbg__cmd_GetAllRegs:
add r3, r3, #1 /* increment index */
cmp r3, #REG_PC
bls 1b /* process all the registers */
+#if 0
_get_cpsr:
+ /* GDB will query for CPSR value specifically */
mov r1, #REG_CPSR /* Output User CPSR Value last */
bl _dbg_outputOneRegValue /* update output buffer */
-
+#endif
_asciiz r0, r1
bl dbg__putDebugMsg /* Send response to the GDB server */
ldmfd sp!, {pc}
@@ -993,6 +896,8 @@ _get_cpsr:
* On exit:
* r0: (Updated) Address of parameter in buffer
* r1, r2, r3: destroyed
+ *
+ * FIXME: This routine assumes that the input buffer contains exactly 8-Hex digits for each register value.
*/
_dbg_setOneRegValue:
stmfd sp!, {lr}
@@ -1004,11 +909,15 @@ _dbg_setOneRegValue:
moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */
beq _store_RegVal
+ bhi _exit_dbg_setOneRegValue /* No match (reg enum > REG_CPSR), skip */
+
+#if 0
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! */
+#endif
-_set_dummy_fpscr:
+_set_dummy_regval:
+ /* FIXME: This assumes that we will never get FP reg values (96-bits) in this routine */
/* Set dummy FPSCR value (ignored) */
add r1, r0, #CMD_REG_REGPARAMLEN /* Just increment the pointer */
b _done_store_RegVal
@@ -1046,7 +955,14 @@ _dbg__cmd_SetOneReg:
cmp r1, #CMD_REG_SETONE_MAXPARAMLEN /* Check for correct length */
bhi __dbg__procCmdParamError /* Unexpected input, report error */
+ /* FIXME: We can't set FP regs.
+ * Fortunately the values required by FP regs are 96 bits (24 nibbles)
+ * so it fails the CMD_REG_SETONE_MAXPARAMLEN check
+ */
+
bl ascii2hex_varlen_be /* convert ASCII reg enum to Hex (in R0), R1 has address of next buffer char */
+ cmp r0, #REG_FPSCR
+ beq __dbg__procCmdParamError /* Don't allow setting of FPSCR */
mov r4, r0 /* Keep enum in R4 */
_check_msgassignment r1 /* R1 points to next char in buffer */
bne __dbg__procCmdParamError /* Can't find '=' */
@@ -1067,7 +983,7 @@ _dbg__proc_setRegister:
*
*/
_dbg__cmd_SetAllRegs:
- /* Assumes that the registers are in the sequence R0, R1, ... R15, CPSR */
+ /* Assumes that the registers are in the sequence R0, R1, ... R15 */
stmfd sp!, {lr}
bl __dbg__cmdParamLen /* R0: pointer to parameters in buffer */
teq r1, #CMD_REG_SETALL_PARAMLEN /* Check for correct length */
@@ -1079,20 +995,6 @@ _dbg__cmd_SetAllRegs:
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
@@ -1116,7 +1018,7 @@ _dbg__nop:
* r0: parameter buffer pointer (contents after '$' and '<cmdchar>')
* AA..AA,LLLL
* On exit:
- * r0, r1, r2, r3, r4: destroyed
+ * r0, r1, r2, r3, r4, r5: destroyed
*/
_dbg__cmd_ReadMem:
stmfd sp!, {lr}
@@ -1127,7 +1029,7 @@ _dbg__cmd_ReadMem:
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 */
+ mov r5, r0 /* Keep Address location in R5 */
_check_msgseparator r1
bne __dbg__procCmdParamError /* Can't find ',' */
mov r0, r1 /* move buffer pointer to R0 for subsequent processing */
@@ -1138,7 +1040,7 @@ _dbg__cmd_ReadMem:
/* FIXME: Should validate the address? */
_dbg_outputMsgValidResponse /* R0: address of output message buffer data pointer (after response prefix) */
-1: ldrb r1, [r3], #1
+1: ldrb r1, [r5], #1
bl byte2ascii /* update output buffer */
subs r4, r4, #1
bne 1b
@@ -1216,8 +1118,7 @@ _dbg__cmd_Detach:
*
* 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
+ * If this is a Normal Breakpoint, then we 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:
@@ -1239,8 +1140,7 @@ _dbg__cmd_Continue:
_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 */
+ _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */
bl __dbg__procAckOnly /* send Ack to keep GDB server happy */
b _dbg__cont_is_manual_bkpt_or_address_specified
@@ -1252,20 +1152,11 @@ _dbg__cont_check_breakpoint_type:
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
-
+ _getdbgregister DBGSTACK_USERPC_INDEX, r0 /* Retrieve Aborted Instruction PC from the Debug Stack into R0 */
+ _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */
+ /* GDB knows to Step from a breakpointed instruction before continuing when
+ * Continue is issued, so it is safe to activate all defined breakpoints and continue.
+ */
_dbg__cont_is_manual_bkpt_or_address_specified:
bl _dbg__activate_breakpoints /* Restore exisiting breakpoints */
b _dbg__switch2undefmode
@@ -1298,8 +1189,7 @@ _dbg__cmd_Step:
_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 */
+ _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume using contents of R0, and scratch register R1 */
b _dbg__step_is_manual_bkpt_or_address_specified
_dbg__step_check_breakpoint_type:
@@ -1310,26 +1200,22 @@ _dbg__step_check_breakpoint_type:
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 */
+ _getdbgregister DBGSTACK_USERPC_INDEX, r0 /* Retrieve Aborted Instruction PC from the Debug Stack into R0 */
+ _setdbgregister DBGSTACK_NEXTINSTR_INDEX, r0, r1 /* Set Next Instruction Pointer for Resume usinh contents in R0, 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 */
+ _getdbgregister DBGSTACK_NEXTINSTR_INDEX, r0 /* Retrieve Next Instruction Pointer for Resume 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_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 */
+#if 0
+ /* Disable ACK transmit, let the next Breakpoint generate the Signal Response */
+ bl __dbg__procAckOnly /* send Ack to keep GDB server happy */
+#endif
b _dbg__switch2undefmode
/* _dbg__cmd_Kill
@@ -1442,1298 +1328,6 @@ _dbg__cmd_RemoveBreakpoint:
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
@@ -2804,8 +1398,14 @@ _dbg__clear_breakpoints:
.global dbg__install_singlestep
/* dbg__install_singlestep
* Install the Single Step Breakpoint
+ *
* On entry:
* R1: Instruction Address (31 bits, b0 = THUMB flag)
+ * On exit:
+ * R0: Breakpoint index (preserved)
+ * R1: Instruction Address (preserved)
+ * R2: Breakpoint Instruction
+ * R3: Breakpoint Entry address
*/
dbg__install_singlestep:
mov r0, #0
@@ -2813,11 +1413,13 @@ dbg__install_singlestep:
/* _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:
+ * R0: Breakpoint index (preserved)
+ * R1: Instruction Address (preserved)
* R2: Breakpoint Instruction
* R3: Breakpoint Entry address
*/
@@ -2825,8 +1427,9 @@ _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 */
+ bic r2, r1, #BKPT_STATE_THUMB_FLAG /* R2: Instruction Address; clear Thumb Flag for accessing Memory */
+ ldreq r2, [r2] /* if 0: load ARM instruction from address location */
+ ldrneh r2, [r2] /* else load Thumb instruction */
_index2bkptindex_addr r0, r3 /* Calculate Breakpoint Entry Address */
stm r3, {r1, r2}
bx lr
@@ -2834,6 +1437,11 @@ _dbg__install_one_breakpoint:
/* _dbg__restore_singlestep
* Restores the contents of the single step breakpoint to memory
+ *
+ * On entry:
+ * None
+ * On exit:
+ * R0-R2: Destroyed
*/
_dbg__restore_singlestep:
mov r0, #0 /* single step breakpoint index */
@@ -2845,10 +1453,15 @@ _dbg__restore_singlestep:
/* _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)
+ * On exit:
+ * R0: Breakpoint index (preserved)
+ * R1: B0 cleared if Thumb Instruction Address
+ * R2: Breakpoint Instruction (preserved)
*/
_dbg__restore_one_breakpoint:
/* Check for Thumb bit */
@@ -2862,15 +1475,25 @@ _dbg__restore_one_breakpoint:
/* _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.
+ *
+ * On entry:
+ * None
+ * On exit:
+ * R0-R6: Destroyed
*/
_dbg__restore_breakpoints:
stmfd sp!, {lr}
- ldr r5, =_dbg__restore_one_breakpoint
+ ldr r6, =_dbg__restore_one_breakpoint
b __dbg__iterate_breakpoint_array
.global dbg__activate_singlestep
/* dbg__activate_singlestep
* Activate the single step breakpoint to memory
+ *
+ * On entry:
+ * None
+ * On exit:
+ * R0-R3: Destroyed
*/
dbg__activate_singlestep:
mov r0, #0 /* single step breakpoint index */
@@ -2882,10 +1505,14 @@ dbg__activate_singlestep:
/* _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)
+ * On exit:
+ * R0: Breakpoint index (preserved)
+ * R1-R3: Destroyed
*/
_dbg__activate_one_breakpoint:
/* Check for Thumb bit */
@@ -2915,62 +1542,45 @@ _dbg__breakpoint_invalid_thumb:
/* _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.
+ *
+ * On entry:
+ * None
+ * On exit:
+ * R0-R6: Destroyed
*/
_dbg__activate_breakpoints:
stmfd sp!, {lr}
- ldr r5, =_dbg__activate_one_breakpoint
+ ldr r6, =_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:
+ * WARNING: DO NOT CALL THIS ROUTINE DIRECTLY.
+ * Internal Routine, assumes that lr has been push to stack
+ *
+ * Common routine to iterate through the array of breakpoints (incl single step breakpoint)
+ * Only Active breakpoints (i.e., Non-zero Address entries) are processed.
+ *
+ * On Entry:
* R0: Breakpoint index
* R1: Breakpoint Address
* R2: Breakpoint Instruction
+ * R6: Handler Routine
+ * On exit:
+ * R0-R5: Destroyed
+ * R6: Handler routine (preserved)
*
- * 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 r5, =__breakpoints_end__ /* start from top of the table (Assume __breakpoints_end__ > __breakpoints_start__) */
+ ldr r4, =__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 */
+ ldmea r5!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */
teq r1, #0 /* Is it active? */
movne lr, pc
- bxne r5 /* active entry */
- cmp r4, r3
+ bxne r6 /* active entry */
+ cmp r5, r4
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
index 11b348e..6807ac1 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_stub.h
+++ b/AT91SAM7S256/armdebug/Debugger/debug_stub.h
@@ -34,12 +34,12 @@
#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_AUTO_BKPT 0x00080000 /* RESERVED: 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_AUTO_BKPT 0x0080 /* RESERVED: Thumb BKPT Auto-Step Flag (for CONT support) */
#define BKPT16_MANUAL_BKPT 0x007F /* Manually inserted Thumb Breakpoint */
/*@}*/
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_test.S b/AT91SAM7S256/armdebug/Debugger/debug_test.S
index 91e19d2..7f8c85f 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_test.S
+++ b/AT91SAM7S256/armdebug/Debugger/debug_test.S
@@ -29,6 +29,58 @@ dbg__test_arm_bkpt:
dbg__bkpt_arm /* Trigger ARM Manual Breakpoint */
ldmfd sp!,{pc}
+
+/**********************************************
+ * dbg__test_arm_instrstep Test Routine
+ * Used to test GDB Stepping command
+ * This routine exercises the mov, add, ldr, ldm, b, bl,
+ * and bx instructions which modify the PC (R15)
+ * In addition, conditional instructions are also evaluated.
+ *
+ */
+ .global dbg__test_arm_instrstep
+dbg__test_arm_instrstep:
+ stmfd sp!, {lr}
+ bl dbg__test_arm_instr_sub1
+ ldr r1, =test_arm_3 /* R1: pointer to test_arm_3 */
+ ldr r2, =test_arm_2 /* R2: pointer to test_arm_2 */
+ mov pc, r1
+
+test_arm_1:
+ subs r0, r0, #1
+ addne pc, r2, #4 /* If R0 > 0, keep branching to a new location */
+ /* else R0 == 0 */
+ b exit_dbg__test_arm_instrstep
+
+test_arm_2:
+ sub r0, r0, #1
+ cmp r0, #5
+ bgt test_arm_1
+ ldrle pc, =exit_dbg__test_arm_instrstep
+ b exit_dbg__test_arm_instrstep
+
+test_arm_3:
+ sub r0, r0, #1
+ teq r0, #8
+ beq test_arm_1
+ ldrne r3, =test_arm_3
+ bx r3
+
+exit_dbg__test_arm_instrstep:
+ bl dbg__test_thumb_instr_sub1
+ ldmfd sp!, {pc}
+
+ .global dbg__test_arm_instr_sub1
+dbg__test_arm_instr_sub1:
+ mov r0, #10
+ bx lr
+
+ .global dbg__test_arm_instr_sub1
+dbg__test_arm_instr_sub2:
+ stmfd sp!, {r4, lr}
+ mov r0, #TRUE
+ ldmfd sp!, {r4, pc}
+
/**********************************************
* dbg__test_thumb_bkpt Test Routine
*
@@ -50,4 +102,59 @@ _thumb_entry:
dbg__bkpt_thumb
bx lr
+
+/**********************************************
+ * dbg__test_thumb_instrstep Test Routine
+ * Used to test GDB Stepping command
+ *
+ */
+ .global dbg__test_thumb_instrstep
+.thumb_func
+dbg__test_thumb_instrstep:
+ push {lr}
+ bl dbg__test_thumb_instr_sub1
+ bl dbg__test_thumb_instr_sub2
+
+test_thumb_1:
+ sub r0, #1
+ bne test_thumb_2
+ /* else R0 == 0 */
+ b exit_dbg__test_thumb_instrstep
+
+test_thumb_2:
+ sub r0, #1
+ cmp r0, #5
+ bls test_thumb_1
+ bhi test_thumb_3
+ beq test_thumb_2
+ b test_thumb_1
+
+test_thumb_3:
+ sub r0, #1
+ cmp r0, #0xB
+ blo load_test_thumb_1
+ ldr r2, =test_thumb_3+1 /* Need to set Thumb bit */
+ b exit_test_thumb_3
+load_test_thumb_1:
+ ldr r2, =test_thumb_1+1 /* Need to set Thumb bit */
+exit_test_thumb_3:
+ bx r2
+
+exit_dbg__test_thumb_instrstep:
+ bl dbg__test_arm_instr_sub1
+ pop {r1}
+ bx r1
+
+.thumb_func
+dbg__test_thumb_instr_sub1:
+ mov r0, #0x0F
+ bx lr
+
+.thumb_func
+dbg__test_thumb_instr_sub2:
+ push {lr}
+ mov r1, #FALSE
+ pop {pc}
+
+
.end
diff --git a/AT91SAM7S256/armdebug/Debugger/debug_test.h b/AT91SAM7S256/armdebug/Debugger/debug_test.h
index 6680f58..1c004e7 100644
--- a/AT91SAM7S256/armdebug/Debugger/debug_test.h
+++ b/AT91SAM7S256/armdebug/Debugger/debug_test.h
@@ -27,6 +27,9 @@
FUNCDEF void dbg__test_arm_bkpt(void);
FUNCDEF void dbg__test_thumb_bkpt(void);
+FUNCDEF void dbg__test_arm_instrstep(void);
+FUNCDEF void dbg__test_thumb_instrstep(void);
+
/*@}*/
#endif
diff --git a/AT91SAM7S256/armdebug/Debugger/undef_handler.S b/AT91SAM7S256/armdebug/Debugger/undef_handler.S
index 11d3cbc..412fd18 100644
--- a/AT91SAM7S256/armdebug/Debugger/undef_handler.S
+++ b/AT91SAM7S256/armdebug/Debugger/undef_handler.S
@@ -29,20 +29,18 @@ undef_handler:
* 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.
+ /* We assume that the DEBUG 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).
+ * does.
*
* 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
+ * 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
@@ -71,37 +69,39 @@ undef_handler:
_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 */
+ 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 */
+ 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
+ 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 */
+ 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 */
+ and r0, r1, r0 /* Keep index value */
+ msr cpsr_c, #(MODE_ABT | CPSR_FIQ | CPSR_IRQ) /* Switch to Abort Mode, Disable Interrupts */
+ ldr sp, =__abort_stack__ /* Reinitialize stack pointer each time a Breakpoint happens */
+ bic sp, sp, #7
+ mov pc, r2 /* Invoke Debugger */
.global resume_execution