From d50dd5ab9567cc308e412c5e9e775dc8e15fb509 Mon Sep 17 00:00:00 2001 From: Tat-Chee Wan Date: Fri, 3 Feb 2012 23:57:04 +0100 Subject: merge armdebug rc1 This enables the use of GDB or GDB based debuggers to debug the code running on the NXT brick using the USB connection. --- AT91SAM7S256/SAM7S256/Include/Cstartup.S | 19 +- AT91SAM7S256/SAM7S256/Include/sam7s256.c | 6 + AT91SAM7S256/SAM7S256/gcc/Makefile | 11 +- AT91SAM7S256/SAM7S256/gcc/nxt.ld | 24 + AT91SAM7S256/Source/c_comm.c | 14 + AT91SAM7S256/Source/c_comm.h | 3 + AT91SAM7S256/armdebug/.gitignore | 41 + AT91SAM7S256/armdebug/.project | 11 + AT91SAM7S256/armdebug/AUTHORS | 6 + AT91SAM7S256/armdebug/COPYING | 9 + AT91SAM7S256/armdebug/Debugger/_c_arm_macros.h | 88 ++ AT91SAM7S256/armdebug/Debugger/abort_handler.S | 108 ++ AT91SAM7S256/armdebug/Debugger/debug_comm.S | 555 +++++++ AT91SAM7S256/armdebug/Debugger/debug_hexutils.S | 459 ++++++ AT91SAM7S256/armdebug/Debugger/debug_internals.h | 393 +++++ AT91SAM7S256/armdebug/Debugger/debug_macros.h | 463 ++++++ AT91SAM7S256/armdebug/Debugger/debug_opcodes.S | 1499 ++++++++++++++++++ .../armdebug/Debugger/debug_runlooptasks.S | 415 +++++ .../armdebug/Debugger/debug_runlooptasks.h | 63 + AT91SAM7S256/armdebug/Debugger/debug_stack.ld | 15 + AT91SAM7S256/armdebug/Debugger/debug_stub.S | 1586 ++++++++++++++++++++ AT91SAM7S256/armdebug/Debugger/debug_stub.h | 151 ++ AT91SAM7S256/armdebug/Debugger/debug_test.S | 160 ++ AT91SAM7S256/armdebug/Debugger/debug_test.h | 38 + AT91SAM7S256/armdebug/Debugger/undef_handler.S | 147 ++ AT91SAM7S256/armdebug/Doxyfile | 243 +++ AT91SAM7S256/armdebug/GNU-GPLv2.txt | 340 +++++ AT91SAM7S256/armdebug/Host/README | 21 + AT91SAM7S256/armdebug/Host/gdb-commands.txt | 43 + AT91SAM7S256/armdebug/Host/nxt-gdb-server.py | 254 ++++ AT91SAM7S256/armdebug/LEGO_Open_Source_License.doc | Bin 0 -> 40960 bytes AT91SAM7S256/armdebug/README | 16 + AT91SAM7S256/armdebug/SConscript | 13 + AT91SAM7S256/armdebug/SConstruct | 182 +++ AT91SAM7S256/scripts/armnxtgdbserver | 29 + 35 files changed, 7417 insertions(+), 8 deletions(-) create mode 100644 AT91SAM7S256/armdebug/.gitignore create mode 100644 AT91SAM7S256/armdebug/.project create mode 100644 AT91SAM7S256/armdebug/AUTHORS create mode 100644 AT91SAM7S256/armdebug/COPYING create mode 100644 AT91SAM7S256/armdebug/Debugger/_c_arm_macros.h create mode 100644 AT91SAM7S256/armdebug/Debugger/abort_handler.S create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_comm.S create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_hexutils.S create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_internals.h create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_macros.h create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_opcodes.S create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.h create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_stack.ld create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_stub.S create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_stub.h create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_test.S create mode 100644 AT91SAM7S256/armdebug/Debugger/debug_test.h create mode 100644 AT91SAM7S256/armdebug/Debugger/undef_handler.S create mode 100644 AT91SAM7S256/armdebug/Doxyfile create mode 100644 AT91SAM7S256/armdebug/GNU-GPLv2.txt create mode 100644 AT91SAM7S256/armdebug/Host/README create mode 100644 AT91SAM7S256/armdebug/Host/gdb-commands.txt create mode 100755 AT91SAM7S256/armdebug/Host/nxt-gdb-server.py create mode 100644 AT91SAM7S256/armdebug/LEGO_Open_Source_License.doc create mode 100644 AT91SAM7S256/armdebug/README create mode 100644 AT91SAM7S256/armdebug/SConscript create mode 100644 AT91SAM7S256/armdebug/SConstruct create mode 100755 AT91SAM7S256/scripts/armnxtgdbserver diff --git a/AT91SAM7S256/SAM7S256/Include/Cstartup.S b/AT91SAM7S256/SAM7S256/Include/Cstartup.S index b60ba2c..e3e996e 100644 --- a/AT91SAM7S256/SAM7S256/Include/Cstartup.S +++ b/AT91SAM7S256/SAM7S256/Include/Cstartup.S @@ -136,16 +136,22 @@ FIQ_Handler_Entry: /* end of fiqhandler */ Reset_Addr: .word InitReset -Undef_Addr: .word Undef_Handler +Undef_Addr: .word undef_handler /* BKPT instruction trap */ SWI_Addr: .word SWI_Handler /*SWI_Addr: .word SoftwareInterruptASM*/ /*in swi_handler.S */ -PAbt_Addr: .word PAbt_Handler -DAbt_Addr: .word DAbt_Handler +PAbt_Addr: .word prefetch_abort_handler +DAbt_Addr: .word data_abort_handler IRQ_Addr: .word IRQ_Handler_Entry - + + .global default_undef_handler +default_undef_handler: Undef_Handler: B Undef_Handler SWI_Handler: B SWI_Handler + .global default_prefetch_abort_handler +default_prefetch_abort_handler: PAbt_Handler: B PAbt_Handler + .global default_data_abort_handler +default_data_abort_handler: DAbt_Handler: B DAbt_Handler @@ -255,6 +261,7 @@ already_remapped: .EQU ARM_MODE_FIQ, 0x11 .EQU ARM_MODE_IRQ, 0x12 .EQU ARM_MODE_SVC, 0x13 + .EQU ARM_MODE_ABT, 0x17 .EQU I_BIT, 0x80 .EQU F_BIT, 0x40 @@ -264,6 +271,10 @@ already_remapped: //*-------------------------------*/ mov r0, sp /* see (**) */ +/*- Set up Abort Mode Stack for Debugger*/ + msr CPSR_c, #ARM_MODE_ABT | I_BIT | F_BIT + ldr sp, =__abort_stack_top__ + /*- Set up Fast Interrupt Mode and set FIQ Mode Stack*/ msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT mov sp, r0 diff --git a/AT91SAM7S256/SAM7S256/Include/sam7s256.c b/AT91SAM7S256/SAM7S256/Include/sam7s256.c index cc22ca3..8ff0ab4 100644 --- a/AT91SAM7S256/SAM7S256/Include/sam7s256.c +++ b/AT91SAM7S256/SAM7S256/Include/sam7s256.c @@ -11,6 +11,9 @@ // // Platform C // +#ifdef __ARMDEBUG__ +#include "debug_stub.h" +#endif void main(void) { @@ -18,6 +21,9 @@ void main(void) { HARDWAREInit; mSchedInit(); +#ifdef __ARMDEBUG__ + dbg__bkpt_init(); +#endif while(TRUE == mSchedCtrl()) { OSWatchdogWrite; diff --git a/AT91SAM7S256/SAM7S256/gcc/Makefile b/AT91SAM7S256/SAM7S256/gcc/Makefile index ad40886..e96e153 100644 --- a/AT91SAM7S256/SAM7S256/gcc/Makefile +++ b/AT91SAM7S256/SAM7S256/gcc/Makefile @@ -1,5 +1,6 @@ BASE = ../.. SRCDIR = $(BASE)/Source +DBGDIR = $(BASE)/armdebug/Debugger CPUINCDIR = $(BASE)/SAM7S256/Include GIT_VERSION := $(shell git rev-parse --short=7 HEAD) @@ -17,21 +18,23 @@ THUMB_SOURCES = c_button.c c_cmd.c c_comm.c c_display.c c_input.c c_ioctrl.c \ abort.c errno.c sbrk.c strtod.c sscanf.c \ Cstartup_SAM7.c -ASM_ARM_SOURCE = Cstartup.S +ASM_ARM_SOURCE = Cstartup.S abort_handler.S undef_handler.S debug_hexutils.S \ + debug_stub.S debug_comm.S debug_opcodes.S debug_runlooptasks.S ASM_THUMB_SOURCE = vpath %.c $(SRCDIR) vpath %.c $(CPUINCDIR) vpath %.c lib -vpath %.S $(CPUINCDIR) +vpath %.S $(CPUINCDIR) $(DBGDIR) -INCLUDES = +INCLUDES = -I../../armdebug/Debugger MCU = arm7tdmi +DEBUG_DEFINES = -D__ARMDEBUG__ STARTOFUSERFLASH_DEFINES = -DSTARTOFUSERFLASH_FROM_LINKER=1 VERSION_DEFINES = -DCUSTOM_FIRMWAREVERSION=\"$(CUSTOM_FIRMWAREVERSION)\" DEFINES = -DPROTOTYPE_PCB_4 -DNEW_MENU -DROM_RUN -DVECTORS_IN_RAM \ - $(STARTOFUSERFLASH_DEFINES) $(VERSION_DEFINES) + $(STARTOFUSERFLASH_DEFINES) $(VERSION_DEFINES) $(DEBUG_DEFINES) OPTIMIZE = -Os -fno-strict-aliasing \ -ffunction-sections -fdata-sections WARNINGS = -Wall -W -Wundef -Wno-unused -Wno-format diff --git a/AT91SAM7S256/SAM7S256/gcc/nxt.ld b/AT91SAM7S256/SAM7S256/gcc/nxt.ld index d63944e..9b7171f 100644 --- a/AT91SAM7S256/SAM7S256/gcc/nxt.ld +++ b/AT91SAM7S256/SAM7S256/gcc/nxt.ld @@ -87,6 +87,30 @@ SECTIONS __STARTOFUSERFLASH_FROM_LINKER = ALIGN (LOADADDR (.data) + SIZEOF (.data), 0x100); + /* + * The various debugger stacks. + */ + .stack : ALIGN(8) { + /* abort stack */ + __abort_stack_bottom__ = . ; + . += 0x80; /* 128 byte abort mode stack. */ + __abort_stack__ = . ; + __abort_stack_top__ = . ; + + /* debugger state */ + __debugger_stack_bottom__ = . ; + . += 0x48; /* 16 user mode registers + SPSR + UNDEF Next Instruction Address */ + __debugger_stack__ = . ; + __debugger_stack_top__ = . ; + + /* breakpoints */ + __breakpoints_start__ = . ; + . += 0x40; /* Single Stepping Breakpoint + 7 Breakpoints */ + __breakpoints_end__ = . ; + } > DATA + + __breakpoints_num__ = (__breakpoints_end__ - __breakpoints_start__) / 8; + /* .bss section which is used for uninitialized data */ .bss (NOLOAD) : { diff --git a/AT91SAM7S256/Source/c_comm.c b/AT91SAM7S256/Source/c_comm.c index ee0c6ae..1411b5d 100644 --- a/AT91SAM7S256/Source/c_comm.c +++ b/AT91SAM7S256/Source/c_comm.c @@ -26,6 +26,9 @@ #include "d_bt.h" #include #include +#ifdef __ARMDEBUG__ +#include "debug_stub.h" +#endif enum { @@ -422,6 +425,17 @@ UWORD cCommInterprete(UBYTE *pInBuf, UBYTE *pOutBuf, UBYTE *pLength, UBYTE C } break; +#ifdef __ARMDEBUG__ + case DEBUG_CMD: + { + ReturnStatus = cCommHandleDebug(&(pInBuf[0]), CmdBit, MsgLength); /* Pass everything (incl. message command byte) to function */ + /* Check that Debug Command does not expect reply */ + ReturnStatus = (0 == ((pInBuf[0]) & NO_REPLY_BIT)); + *pLength = 0; + } + break; +#endif + default: { diff --git a/AT91SAM7S256/Source/c_comm.h b/AT91SAM7S256/Source/c_comm.h index a1e112c..ac24b02 100644 --- a/AT91SAM7S256/Source/c_comm.h +++ b/AT91SAM7S256/Source/c_comm.h @@ -67,6 +67,9 @@ enum DIRECT_CMD = 0x00, SYSTEM_CMD = 0x01, REPLY_CMD = 0x02, +#ifdef __ARMDEBUG__ + DEBUG_CMD = 0x0d, +#endif NO_REPLY_BIT = 0x80 }; diff --git a/AT91SAM7S256/armdebug/.gitignore b/AT91SAM7S256/armdebug/.gitignore new file mode 100644 index 0000000..46f8223 --- /dev/null +++ b/AT91SAM7S256/armdebug/.gitignore @@ -0,0 +1,41 @@ +# Ignore tag +MASTER-REPO_DO-NOT-DELETE +*.lst +*.objdump +.DS_Store + +# Generally annoying things. +*.[oa] +*.pyc +*.bin +*.elf +*.rxe +*.map +*.orig +*.log +*~ +*.swp +\#*\# +.\#* + +# Python distutils creates this when building. +pynxt/build/ + +# XCode build stuff +FantomModule/build/ +*mode1v3 +*pbxuser + +# SCons cruft +.sconsign.dblite +.sconf_temp +build_flags.py + +# Precommit hooks drop a commit.msg file if they fail. +commit.msg + +# The option-cache +scons.options + +# pyfantom related +pyfantom.py diff --git a/AT91SAM7S256/armdebug/.project b/AT91SAM7S256/armdebug/.project new file mode 100644 index 0000000..15b12fc --- /dev/null +++ b/AT91SAM7S256/armdebug/.project @@ -0,0 +1,11 @@ + + + armdebug + + + + + + + + diff --git a/AT91SAM7S256/armdebug/AUTHORS b/AT91SAM7S256/armdebug/AUTHORS new file mode 100644 index 0000000..169c2b6 --- /dev/null +++ b/AT91SAM7S256/armdebug/AUTHORS @@ -0,0 +1,6 @@ +The following people have contributed code, in various quantities, to armdebug. +A big thanks to all of them, armdebug is what it is in part thanks to each of +them. In alphabetical order: + +Nicolas Schodet +Tat Chee Wan diff --git a/AT91SAM7S256/armdebug/COPYING b/AT91SAM7S256/armdebug/COPYING new file mode 100644 index 0000000..86fae60 --- /dev/null +++ b/AT91SAM7S256/armdebug/COPYING @@ -0,0 +1,9 @@ +The armdebug project is dual licensed. + +You can either use the GNU GPLv2 license in GNU-GPLv2.txt, +or else the "LEGO Open Source License" in LEGO_Open_Source_License.doc +to redistribute the code. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff --git a/AT91SAM7S256/armdebug/Debugger/_c_arm_macros.h b/AT91SAM7S256/armdebug/Debugger/_c_arm_macros.h new file mode 100644 index 0000000..025542e --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/_c_arm_macros.h @@ -0,0 +1,88 @@ +/** @file _c_arm_macros.h + * @brief Define macros to support shared C and ASM headers + * + */ + +/* Copyright (C) 2010 the NxOS developers + * + * Module Developed by: TC Wan + * + * Thanks to Bartli (forum post @ embdev.net ARM programming with GCC/GNU tools forum) + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + +#ifndef __C_ARM_MACROS__ +#define __C_ARM_MACROS__ + + +#ifdef __ASSEMBLY__ + +#define NULL 0x0 +#define FALSE 0 +#define TRUE ~FALSE + +#define TYPEDEF @ +#define FUNCDEF @ + + .set last_enum_value, 0 + .macro enum_val name + .equiv \name, last_enum_value + .set last_enum_value, last_enum_value + 1 + .endm + +#define ENUM_BEGIN .set last_enum_value, 0 + +#define ENUM_VAL(name) enum_val name +#define ENUM_VALASSIGN(name, value) \ + .set last_enum_value, value ;\ + enum_val name +#define ENUM_END(enum_name) + +#else /* C Defines */ +/** Macro to control typedef generation + * + */ +#define TYPEDEF typedef + +/** Macro to control extern generation + * + */ +#ifndef FUNCDEF +#define FUNCDEF extern +#endif + +/** Macro to control typedef enum generation + * + */ +#define ENUM_BEGIN typedef enum { + +/** Macro to specify enum instance (auto value assignment) + * + */ +#define ENUM_VAL(name) name, + +/** Macro to control enum specification and value assignment +* +*/ +#define ENUM_VALASSIGN(name, value) name = value, + +/** Macro to control enum named type generation + * + */ +#define ENUM_END(enum_name) } enum_name; + +#endif + +/* Example of how to use the ENUM definition macros +ENUM_BEGIN +ENUM_VAL(INIT) +ENUM_VAL(RESET) +ENUM_VAL(CONFIGURED) +ENUM_END(enum_label) +*/ + +#endif /* __C_ARM_MACROS__ */ diff --git a/AT91SAM7S256/armdebug/Debugger/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 + * + * 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 new file mode 100644 index 0000000..4c23912 --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_comm.S @@ -0,0 +1,555 @@ +/** @file debug_comm.S + * @brief GDB Server communications support routines + * + */ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + +#define __ASSEMBLY__ +#include "debug_macros.h" +#include "debug_stub.h" +#include "debug_internals.h" + + .extern dbg__sendCommMsg + + /* Hexutils function references */ + .extern hex2char + .extern char2hex + .extern byte2ascii + .extern halfword2ascii_be + .extern halfword2ascii_le + .extern word2ascii_be + .extern word2ascii_le + .extern ascii2hex_varlen_be + .extern ascii2byte + .extern ascii2halfword_be + .extern ascii2halfword_le + .extern ascii2word_be + .extern ascii2word_le + + +.bss +.align 4 + + .global debug_InCommBuf + .global debug_OutCommBuf +debug_InCommBuf: + .space USB_BUFSIZE,0 +debug_OutCommBuf: + .space USB_BUFSIZE,0 + +debug_msgRxBufPtr: + .word 0x0 +debug_msgTxBufPtr: + .word 0x0 + +debug_msgRxBuf_AppendPtr: + .word 0x0 +debug_msgTxBuf_AppendPtr: + .word 0x0 + + .equ RXAPPENDPTR_OFFSET, (debug_msgRxBuf_AppendPtr - debug_msgRxBufPtr) + .equ TXAPPENDPTR_OFFSET, (debug_msgTxBuf_AppendPtr - debug_msgTxBufPtr) + +debug_segmentRxNum: /* Current Rx Segment Number */ + .word 0x0 + +/* Comm Channel and NXT Received Message Length is now common to both NxOS and NXT Firmware */ +debug_nxtMsgLength: + .word 0x0 + + .global debug_nxtCommChannel +debug_nxtCommChannel: + .word 0x0 + + .global debug_nxtCommOverrun +debug_nxtCommOverrun: + .word 0x0 + + .equ NXTCOMMCHANNEL_OFFSET, (debug_nxtCommChannel - debug_nxtMsgLength) + .equ NXTCOMMOVERRUN_OFFSET, (debug_nxtCommOverrun - debug_nxtMsgLength) + +.data +.align 4 + +nxt_commcmd_header: + .byte NXT_GDBMSG_TELEGRAMTYPE, 0x00, 0x00 /* padded to 3 bytes */ + +.code 32 +.text +.align 4 +/* Debugger Communications Routines + * It does not make sense to pass information from the Debugger Module to the Comm. link one character + * at a time, especially if we're not using a native serial interface (e.g., EIA-232). Consequently + * a Message interface has been defined. This can still call getChar() and putChar() subroutines + * if so desired, but it'll be a purely internal matter. + * + * Message Format + * Since we need to use EP1&2 (Bulk channels) to communicate with the PC Host, the messages should + * follow the NXT Direct Commands message structure (this will allow for interoperability with NXT Firmware + * in addition to NxOS). The maximum length of any USB communications via the Bulk channel is 64 bytes. + * There is a one byte Telegram Type field which identifies the type of telegram, followed by the + * Telegram header and actual message. + * + * The LEGO Mindstorms Communications Protocol Direct Commands GDB Message format (including all headers) + * is as follows: + * + * GDB Command + * =========== + * Byte 0: Telegram Type Field (0x8d Direct Command, No response required) | NXT Msg Header + * Byte 1: Segment No (1-255, 0: Last Segment; limit is MSG_NUMSEGMENTS) | + * Byte 2: Telegram Size (Len of USB Buffer - 3, max is MSG_SEGMENTSIZE) | + * Byte 3-N: Message data | GDB Command + * + * The GDB Command (of size M) has the following format: + * Offset 0: '+'/'-' Command Received Status (Optional) + * Offset 1/0: '$' + * Offset 2/1: GDB Command char + * Offset 3 - (M-4): Command packet info + * Offset M-3: '#' + * Offset M-2: MSB of Checksum + * Offset M-1: LSB of Checksum + * + * To be safe, we assume that the Command Received Status is always sent by the GDB server. Therefore, + * The maximum size of a GDB Command packet is MSGBUF_SIZE - 5 ('+'/'-', '$', '#', 2 byte checksum) + * + * GDB Response + * ============ + * Byte 0: Telegram Type Field (0x8d Direct Command, No response required) | NXT Msg Header + * Byte 1: Segment No (1-255, 0: Last Segment; limit is MSG_NUMSEGMENTS) | + * Byte 2: Telegram Size (Len of USB Buffer - 3, max is MSG_SEGMENTSIZE) | + * Byte 3-N: Message data | GDB Response + * + * The GDB Retransmission Request has the following format: + * Offset 0: '-' Command Received Status + * + * The GDB Response (of size M) has the following format: + * Offset 0: '+' Command Received Status + * Offset 1: '$' + * Offset 2 - (M-4): Response packet info + * Offset M-3: '#' + * Offset M-2: MSB of Checksum + * Offset M-1: LSB of Checksum + * + * The maximum size of a GDB Response packet is MSGBUF_SIZE - 5 ('+', '$', '#', 2 byte checksum) + * + * Note: The Telegram Size is the actual size of the Message Data portion + * (i.e., excludes the three header bytes, includes the GDB Command/Response Packet checksum bytes + * in the last segment) + */ + + .global dbg__comm_init +/* dbg__comm_init + * Initialize communications channel. + * On Entry: + * R0: MSG Rx Buf Pointer + * R1: MSG Tx Buf Pointer + */ + +dbg__comm_init: + stmfd sp!, {lr} + ldr r2, =debug_msgRxBufPtr + stmia r2!, {r0, r1} /* debug_msgRxBufPtr and debug_msgTxBufPtr */ + stmia r2!, {r0, r1} /* debug_msgRxBuf_AppendPtr and debug_msgTxBuf_AppendPtr */ + bl _dbg__comm_readbuf_reset + ldr r1, =debug_nxtMsgLength + mov r0, #0 + str r0, [r1, #NXTCOMMCHANNEL_OFFSET] /* Clear NXT Channel on INIT */ + ldmfd sp!, {pc} + + +_dbg__comm_readbuf_reset: + ldr r1, =debug_nxtMsgLength + mov r0, #0 + str r0, [r1] /* Clear Received Comm Message Length */ + bx lr + + .global dbg__copyNxtDebugMsg +/* dbg__copyNxtDebugMsg + * Copy NXT Debug Message to our own Buffers, indicate Msg Received status. + * Note: This routine is now used by both NXT Firmware and NxOS + * On Entry: + * R0: NXT Input Buf Pointer + * R1: NXT Communications Channel Enum (CmdBit) + * R2: NXT Raw Message Length + * On Exit: + * R0-R3: Destroyed + */ +dbg__copyNxtDebugMsg: + ldr r3, =debug_nxtMsgLength + str r1, [r3, #NXTCOMMCHANNEL_OFFSET] /* save Communications Channel first */ + ldr r1, [r3] /* Check if there's an unread message in the buffer */ + cmp r1, #0 + beq cont_dbg__copyNxtDebugMsg /* No unread message, so continue */ +exit_dbg__NxtDebugMsgOverrun: + ldr r1, [r3, #NXTCOMMOVERRUN_OFFSET] + add r1, r1, #1 + str r1, [r3, #NXTCOMMOVERRUN_OFFSET] /* update message overrun stats */ + b exit_dbg__copyNxtDebugMsg +cont_dbg__copyNxtDebugMsg: + str r2, [r3] + ldr r1, =debug_InCommBuf + _dbg_memcpy r1, r0, r2, r3 /* r3: scratch register */ +exit_dbg__copyNxtDebugMsg: + bx lr + +/* _dbg_reset_msgTxBuf_AppendPtr + * Internal variable to reset pointers. + * On Exit: + * R0: debug_msgTxBuf_AppendPtr + * R1: destroyed + */ +_dbg_reset_msgTxBuf_AppendPtr: + ldr r1, =debug_msgTxBufPtr /* Should not be modified */ + ldr r0, [r1] + str r0, [r1, #TXAPPENDPTR_OFFSET] + mov pc, lr + +/* _dbg__commHasMsg + * Internal Segment Reassembly Routine. + * On exit: + * r0: !0: (Availale Telegram Message Size), 0: no incoming message/segment + * r1: message segment number + */ +_dbg__commHasMsg: + stmfd sp!, {lr} + ldr r0, =debug_nxtMsgLength + ldr r0, [r0] /* R0 contains the Comm Buffer Size, including the NXT Direct Command Header */ + + ldr r2, =debug_InCommBuf + ldrb r1, [r2, #NXT_MSG_TELEGRAMTYPE_OFFSET] + cmp r1, #NXT_GDBMSG_TELEGRAMTYPE + bne invalid_CommMsg /* Invalid telegram type, ignore */ + + ldrb r1, [r2, #NXT_MSG_TELEGRAMSIZE_OFFSET] + sub r0, r0, r1 /* Comm Buffer Size - Telegram Size = 3 (header size) */ + cmp r0, #NXT_GDBMSG_START /* Start offset is equal to header size */ + bne invalid_CommMsg /* Invalid Message Length, ignore */ + + mov r0, r1 /* Telegram Message Size */ + ldrb r1, [r2, #NXT_MSG_SEGNUM_OFFSET] + b _exit_dbg__commHasMsg + +invalid_CommMsg: + bl _dbg__comm_readbuf_reset /* Next Comm telegram transaction */ + mov r0, #0 +_exit_dbg__commHasMsg: + ldmfd sp!, {pc} + +/* _copy_msg_from_commbuf + * Internal Comm buffer copy routine, handles segment reassembly. + * On entry: + * r0: number of bytes to copy + * r1: segment number + * On exit: + * r0: cummulative message length + * r1: segment number + * r2, r3: Destroyed + */ +_copy_msg_from_commbuf: + stmfd sp!, {r1,r4,r5,r6,lr} + movs r4, r0 + beq _exit_copy_msg_from_commbuf + + ldr r6, =debug_msgRxBufPtr /* Address of Pointers */ + ldr r5, [r6] /* Rx buffer Start Address */ + ldr r2, [r6, #RXAPPENDPTR_OFFSET] /* Append Pointer */ + + sub r3, r2, r5 /* r3: current length of message */ + add r3, r3, r4 /* new cummulative length of message */ + cmp r3, #MSGBUF_SIZE + movhi r4, #0 /* Buffer overflow! */ + strhi r5, [r6, #RXAPPENDPTR_OFFSET] /* Reset AppendPtr to beginning of Rx Buffer */ + bhi _exit_copy_msg_from_commbuf + + ldr r3, =debug_InCommBuf + add r3, r3, #NXT_GDBMSG_START + _dbg_memcpy r2, r3, r4, r0 /* r2 updated to point to next empty char slot in Rx buffer */ + sub r4, r2, r5 /* r4: cummulative length of message */ + + /* Update debug_msgRxBuf_AppendPtr */ + teq r1, #0 /* Check if this is last segment (segment 0) */ + streq r5, [r6, #RXAPPENDPTR_OFFSET] /* Reset AppendPtr to beginning of Rx Buffer if so */ + strne r2, [r6, #RXAPPENDPTR_OFFSET] /* Otherwise, update Append Pointer to receive next segment */ + +_exit_copy_msg_from_commbuf: + bl _dbg__comm_readbuf_reset /* Next Comm telegram transaction */ + mov r0, r4 /* Return cummulative message length in R0 */ + ldmfd sp!, {r1,r4,r5,r6,pc} /* Return segment number in R1 */ + + +/* _msgbuf_checksum + * Internal routine to calculate checksum character buffer. + * On entry: + * r0: pointer to character buffer to checksum (assume ASCIIZ terminated) + * On exit: + * r0: pointer to character buffer after ASCIIZ + * r1: checksum (8-bit binary) + * r2: message length + * r3: destroyed + */ +_msgbuf_checksum: + mov r1, #0 /* clear checksum */ + mov r2, #0 /* clear length */ +1: ldrb r3, [r0], #1 /* Iterate through buffer */ + add r1, r1, r3 /* cummulative sum of char */ + teq r3, #0 + addne r2, r2, #1 /* increment message length */ + bne 1b /* until ASCIIZ found */ + and r1, #BYTE0 /* Modulo 256 */ + mov pc, lr + + .global dbg__getDebugMsg +/* dbg__getDebugMsg + * Retrieve pending Debugger Message if available (Non-Blocking). + * On entry: + * No parameters (assume pointers were initialized previously using dbg__comm_init) + * On exit: + * r0: >0 = Valid GDB Message Length (incl '$', excluding '#' and checksum), + * 0 = no valid message (yet), -1 = error + * r1: GDB Message Buffer Pointer (incl '$', excluding '#' and checksum) + * r2, r3: Destroyed + * Note: If GDB Message were returned, it is ASCIIZ terminated, does not include '#' and checksum + */ +dbg__getDebugMsg: + stmfd sp!, {r4,r5,lr} + bl _dbg__commHasMsg /* r0: message length, r1: segment number */ + teq r0, #0 + beq exit_dbg__getDebugMsg /* no new message, exit with R0 = 0 */ + + ldr r4, =debug_segmentRxNum + ldr r2, [r4] /* Get current Segment Number */ + add r2, r2, #1 /* Expected Segment Number for comparison */ + teq r1, #0 + streq r1, [r4] /* Update current Segment Number with 0 since it is the last segment */ + beq _hasMsg2Copy + cmp r1, #MSG_NUMSEGMENTS /* Segment Number < MSG_NUMSEGMENTS? */ + bhs _invalid_segment + teq r1, r2 /* Valid Segment Number, check against Expected Segment Number */ + beq _hasMsg2Copy /* Segment Number matches Expected Segment Number, update buffers */ + +_invalid_segment: + bl _dbg__comm_readbuf_reset /* Invalid, Next Comm telegram transaction */ + mov r0, #0 /* Reset Segment Number */ + str r0, [r4] /* Update current Segment Number with 0 to prepare for new message */ + b exit_dbg__getMsgError /* Exit with error */ + +_hasMsg2Copy: + str r1, [r4] /* Update current Segment Number */ + bl _copy_msg_from_commbuf /* r0: cummulative message length, r1: segment number */ + teq r1, #0 + movne r0, #0 /* Incomplete message, ignore for now */ + bne exit_dbg__getDebugMsg /* Message not complete yet, exit */ + + /* Check for valid GDB message */ + mov r4, r0 /* keep message length in R4, assume to be within MSGBUF_SIZE */ + ldr r5, =debug_msgRxBufPtr + ldr r5, [r5] /* Rx buffer Start Address */ + +/* Need to account for Packet Acknowledgement */ +1: ldrb r0, [r5] + teq r0, #MSGBUF_CTRLC /* Look for Ctrl-C */ + moveq r0, r4 /* If found, set R0 to current message length */ + beq exit_dbg__getDebugMsg /* and return */ + teq r0, #MSGBUF_NAKCHAR /* Look for '-' */ + beq exit_dbg__getMsgError /* 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 */ + beq 1b /* Skip all Packet Acknowledgements */ + + /* Note: Here we assume that we won't get a single ACK '+' or NAK '-' character message. + * If we do, it'll be flagged as an error + */ + subs r2, r4, #MSGBUF_CHKSUMOFFSET /* Look for '#': Message Length - 3 = '#' offset */ + blt exit_dbg__getMsgError /* Message Length is too short, exit with error */ + ldrb r0, [r5, r2] + teq r0, #MSGBUF_CHKSUMCHAR + bne exit_dbg__getMsgError /* No checksum char '#', exit with error */ + + mov r1, #0 + strb r1, [r5, r2] /* Zero out '#' char for checksum calc later */ + +#ifdef CHECK_GDBSTARTCHAR + /* Checked in dbg__bkpt_waitCMD */ + ldrb r0, [r5] + teq r0, #MSGBUF_STARTCHAR /* Look for '$' */ + bne exit_dbg__getMsgError /* No start char '$', exit with error */ +#endif + + add r0, r5, #1 /* Checksum packet data (excl '$') */ + bl _msgbuf_checksum /* R2: length (excl '$'), R1: calculated checksum, R0: pointer to checksum in receive buffer */ + mov r3, r1 /* Keep calculated checksum in R3 (R1 destroyed by ascii2byte) */ + bl ascii2byte /* R0: received checksum, R1: address of next buffer location */ + teq r0, r3 /* Compare calculated checksum in R3 against received checksum in R0 */ + bne exit_dbg__getMsgError /* Checksums do not match, exit with error */ + + subeq r0, r4, #MSGBUF_CHKSUMOFFSET /* Update message length (incl '$') as return parameter */ + add r2, r2, #1 /* expected message length (from _msgbuf_checksum) */ + teq r0, r2 + beq exit_dbg__getDebugMsg /* Valid length, return */ + +exit_dbg__getMsgError: + /* 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} + + +/* _copy_msg_to_commbuf + * Internal Comm buffer copy routine, handles segment fragmentation. + * On entry: + * r0: number of bytes to copy + * r1: segment number + * On exit: + * r0: cummulative message length + * r1: segment number + * r2, r3: Destroyed + */ +_copy_msg_to_commbuf: + stmfd sp!, {r1,r4,r5,r6,lr} + ldr r6, =debug_msgTxBufPtr /* Address of Pointers */ + ldr r5, [r6, #TXAPPENDPTR_OFFSET] /* Retrieve Tx Append Pointer */ + + movs r4, r0 + beq _exit_copy_msg_to_commbuf + +#ifdef CHECK_TXLEN + add r0, r4, #NXT_GDBMSG_START /* offset = header size */ + cmp r0, #USB_BUFSIZE + bhi _exit_copy_msg_to_commbuf /* We let calling routine detect problem (segment number will increment) */ +#endif + + /* Fill in Comm Message Header */ + ldr r3, =debug_OutCommBuf + mov r2, #NXT_GDBMSG_TELEGRAMTYPE + strb r2, [r3], #1 /* Telegram type */ + strb r1, [r3], #1 /* Segment Number */ + strb r0, [r3], #1 /* Message Length */ + + mov r2, r5 /* Copy to R2 for updating */ + mov r1, r4 /* actual GDB message fragment length (exclude Comm header) */ + _dbg_memcpy r3, r2, r1, r0 /* This copies over the message fragment, r3, r2 updated */ + mov r5, r2 /* Updated Tx Append Pointer, keep in R5 for now */ + + add r0, r4, #NXT_GDBMSG_START /* Total Comm Buffer Size for Tx (NXT_GDBMSG_START offset = header size) */ + bl dbg__sendCommMsg /* Common interface routine to commnuncations drivers */ + cmp r0, #TRUE + ldrne r5, [r6, #TXAPPENDPTR_OFFSET] /* Tx failed, Retrieve Original Tx Append Pointer */ + streq r5, [r6, #TXAPPENDPTR_OFFSET] /* Tx succeeded, Update Tx Append Pointer to new position */ + +_exit_copy_msg_to_commbuf: + ldr r6, [r6] /* Retrieve Tx Buffer Start Address */ + sub r0, r5, r6 /* Return calculated cummulative message length (R0) */ + ldmfd sp!, {r1,r4,r5,r6,pc} /* Return segment number in R1 */ + + .global dbg__putDebugMsg +/* dbg__putDebugMsg + * Sends Debugger Message from calling routine after appending checksum (Blocking) . + * On entry: + * No parameters (assume pointers were initialized previously using dbg__comm_init) + * On exit: + * r0: status (0: success, -1: error) + * Note: GDB Message to be sent must be ASCIIZ terminated, does not include '#' and checksum + * Response packets start with '+' followed by '$' (2 bytes prefix) + */ +dbg__putDebugMsg: + stmfd sp!, {r4,r5,lr} + /* Perform Checksum Calculation */ + ldr r5, =debug_msgTxBufPtr /* R5: data structure base pointer */ + ldr r4, [r5] /* Tx buffer Start Address */ + str r4, [r5, #TXAPPENDPTR_OFFSET] /* Reset Tx buffer Append Pointer */ + add r0, r4, #2 /* skip '+' and '$' */ + bl _msgbuf_checksum /* R2: length (excl '+' and '$'), R1: calculated checksum, R0: pointer to checksum in tx buffer */ + +#ifdef CHECK_TXLEN + add r2, r2, #2 /* r2: returned length from _msgbuf_checksum, added with prefix length */ + sub r3, r0, r4 /* r3: calculated length from pointers (incl. prefix length) */ + teq r2, r3 + bne exit_dbg__putMsgError +#endif + + mov r3, #MSGBUF_CHKSUMCHAR + strb r3, [r0, #-1] /* Insert '#' */ + bl byte2ascii /* On return, R0 points to location after checksum bytes, R1 is original pointer to checksum */ + sub r4, r0, r4 /* R4 = Calculated total message length (incl '+' and '$', '#' and checksum bytes */ + cmp r4, #MSG_SEGMENTSIZE /* If total message length > MSG_SEGMENTSIZE */ + mov r1, #0 /* Initialize Segment Number = 0 (last segment) first */ + mov r0, #0 /* Initial cummulative message length */ + mov r5, #0 /* Previous cummulative message length */ + + /* We assume unsigned message lengths, so the arithmetic MUST NOT result in negative values */ +_cont_putMsg: + cmp r4, r0 + movls r0, #0 /* R0: Exit status (success) */ + bls exit_dbg__putDebugMsg /* If Total message length (r4) <= Cummulative message length (r0), we're done */ + add r2, r0, #MSG_SEGMENTSIZE /* R2: calculate new Max cummulative message length */ + cmp r4, r2 /* Check total message length (R4) against new Max cummulative message length (R2) */ + subls r0, r4, r0 /* if total message length (R4) <= new Max cummulative message length (R2), send remainder */ + movls r1, #0 /* Flag as last segment (Segment Number = 0) */ + movhi r0, #MSG_SEGMENTSIZE /* else send MSG_SEGMENTSIZE bytes */ + addhi r1, r1, #1 /* Increment Segment Number */ + cmp r1, #MSG_NUMSEGMENTS + bhs exit_dbg__putMsgError /* If Segment Number >= MSG_NUMSEGMENTS, flag error */ + bl _copy_msg_to_commbuf /* R0: cummulative message length, R1: segment number */ + teq r5, r0 /* Check if we managed to transmit the previous message */ + beq exit_dbg__putMsgError /* No, flag error */ + movne r5, r0 /* Update previous cummulative message length */ + b _cont_putMsg + +exit_dbg__putMsgError: + mov r0, #MSGBUF_MSGERROR +exit_dbg__putDebugMsg: + ldmfd sp!, {r4,r5,pc} + + .global dbg__sendAckOrNak +/* dbg__sendAckOrNak + * Send Ack (for successful receipt of message) + * or Nak (for Retransmission due to received message Checksum error) (Blocking) . + * On entry: + * No parameters (assume pointers were initialized previously using dbg__comm_init) + * On exit: + * r0: status (0: success, -1: error) + * r1: destroyed + * Note: An Ack Or Nak is indicated by '+' or '-', which is prepended with the Comm header and sent (without checksum) + * Sending Ack is only done for Continue and Step commands, where GDB does not expect any replies. + */ +dbg__sendAckOrNak: + stmfd sp!, {lr} + ldr r1, =debug_msgTxBufPtr /* R2: data structure base pointer */ + ldr r0, [r1] /* Tx buffer Start Address */ + str r0, [r1, #TXAPPENDPTR_OFFSET] /* Reset Tx buffer Append Pointer */ + + mov r1, #0 /* Initialize Segment Number = 0 (last segment) */ + mov r0, #1 /* Retransmission message length = 1 */ + bl _copy_msg_to_commbuf /* R0: cummulative message length, R1: segment number */ + cmp r0, #1 /* Check if we managed to transmit the previous message */ + moveq r0, #0 /* R0: Exit status (success) */ + movne r0, #MSGBUF_MSGERROR /* R0: Exit status (error) */ + ldmfd sp!, {pc} + diff --git a/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S b/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S new file mode 100644 index 0000000..267406f --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_hexutils.S @@ -0,0 +1,459 @@ +/** @file debug_hexutils.S + * @brief GDB hexadecimal conversion utility routines + * + */ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + + +#define __ASSEMBLY__ + +#include "debug_internals.h" + +.data +.align 4 + +hex2char_lut: + /* .ascii "0123456789ABCDEF" */ + /* Need to use lowercase hex chars to avoid confusion with GDB Error (E NN) response */ + .ascii "0123456789abcdef" + +/* Macros + */ + + +/* _hex2char_lut + * Internal routine to intialize the LUT address pointer + */ + .macro _hex2char_lut addrptr + ldr \addrptr, =hex2char_lut + .endm + +/* _hex2char_cont + * Internal routine that assumes that the LUT has been loaded. + * This macro accepts a byte sized hex value as a parameter register(7:0) and returns the + * ASCII equivalent in in the same register(7:0) + * The second parameter is the LUT address pointer register to use (assumed to be initialized) + * WARNING: Assumes that the value in register is sanity checked before invoking macro + */ + .macro _hex2char_cont reg, addrptr + ldrb \reg, [\addrptr, \reg] + .endm + +/* _hex2char + * This macro accepts a byte sized hex value as a parameter register(7:0) and returns the + * ASCII equivalent in in the same register(7:0) + * The second parameter is the LUT address pointer register to use (register content is destroyed) + * WARNING: Assumes that the value in register is sanity checked before invoking macro + */ + .macro _hex2char reg, addrptr + _hex2char_lut \addrptr + _hex2char_cont \reg, \addrptr + .endm + +/* _char2hex + * This macro accepts an ASCII char as a parameter register(7:0) and returns the + * equivalent byte sized hex value in in the same register(7:0) + * WARNING: Assumes that the char in register is a valid hex char before invoking macro + */ + .macro _char2hex reg + cmp \reg, #'A' /* If Alpha */ + bichs \reg, \reg, #ASCII_LOWER2UPPER_MASK /* Convert to Uppercase */ + subhs \reg, \reg, #7 /* Adjustment to allow for subtraction with 0x30 */ + sub \reg, \reg, #0x30 /* get final hex value */ + .endm + + +.code 32 +.text +.align 4 + + +/* Utility Routines + * GDB requires command parameters to be specified as Big Endian values. + * However, the read/write register command expect the register contents to be specified in target byte order. + * Hence we need both versions of multibyte conversion routines for word sized values. + */ + +/* hex2char + * This routine accepts a byte sized hex value in R0(7:0) and returns the + * ASCII equivalent in R0(7:0) + */ + .global hex2char + +hex2char: + stmfd sp!, {r1,lr} + and r0, #NIBBLE0 /* make sure that input is sane */ + _hex2char r0, r1 + ldmfd sp!, {r1,pc} + +/* char2hex + * This routine accepts an ASCII character in R0(7:0) and returns the + * equivalent byte sized hex value in R0(7:0). + * It accepts lowercase and uppercase ASCII Hex char inputs. + * Invalid inputs return -1 as the value +* On entry: + * R0: ASCII character + * On exit: + * R0: Hex value + */ + .global char2hex + +char2hex: + and r0, r0, #BYTE0 /* make sure that input is sane */ + cmp r0, #'0' + blo char2hex_error + cmp r0, #'9' + bls perform_char2hex + cmp r0, #'A' + blo char2hex_error + cmp r0, #'F' + bls perform_char2hex + cmp r0, #'a' + blo char2hex_error + cmp r0, #'f' + bhi char2hex_error + /* Validated Hex Char */ +perform_char2hex: + _char2hex r0 /* Return hex value in R0 */ + bx lr + +char2hex_error: + mov r0, #-1 /* Set Return value to Error value */ + bx lr + +/* byte2ascii_cont + * (Shared routine, does not perform sanity checks) + * On entry: + * R0: ASCII buffer pointer + * R1[7:0]: byte value + * On exit: + * R0: Address of next empty char slot in buffer + * R1: Destroyed + * + * This routine accepts an ASCII buffer pointer in R0 and a byte value in R1, + * and stores the ASCII equivalent byte value in the buffer pointed to by R0. + * Note: On return, R0 points to next empty char slot in buffer + */ +byte2ascii_cont: + stmfd sp!, {r2,r3,r4, lr} + lsl r2, r1, #24 /* Keep copy of input byte value R1[7:0], shifted to MSB R2[31:24] */ + mov r4, #2 /* Loop counter */ + _hex2char_lut r3 /* initialize LUT pointer */ +1: ror r2, r2, #28 /* Rotate MSNibble R2[31:28] into LSNibble position R2[3:0] */ + and r1, r2, #NIBBLE0 /* Mask out everything else, store Nibble in R1 */ + _hex2char_cont r1, r3 /* Convert nibble to ASCII char */ + strb r1, [r0], #1 + subs r4, r4, #1 /* decrement loop counter */ + bne 1b + ldmfd sp!, {r2,r3,r4, pc} + +/* byte2ascii + * On entry: + * R0: ASCII buffer pointer + * R1[7:0]: Byte value + * On exit: + * R0: Address of next empty char slot in buffer + * R1: Original Address of Buffer + * + * This routine accepts an ASCII buffer pointer in R0 and a byte value in R1, + * and stores the ASCII equivalent byte value in the buffer pointed to by R0. + * Note: On return, R0 points to the next empty char slot in buffer + */ + .global byte2ascii + +byte2ascii: + stmfd sp!, {r0, lr} /* Keep ASCII buffer pointer */ + and r1, #BYTE0 /* sanitize input */ + bl byte2ascii_cont + ldmfd sp!, {r1, pc} /* return original string pointer in R1 */ + +/* halfword2ascii_be + * Big Endian version of halfword2ascii conversion routine + * On entry: + * R0: ASCII buffer pointer + * R1[15:0]: Halfword value + * On exit: + * R0: Address of next empty char slot in buffer + * R1: Original Address of Buffer + * + * This routine accepts an ASCII buffer pointer in R0 and a halfword value in R1, + * and stores the ASCII equivalent halfword value in the buffer pointed to by R0. + * Note: On return, R0 points to the next empty char slot in buffer + */ + .global halfword2ascii_be +halfword2ascii_be: + stmfd sp!, {r0,r2,r3, lr} /* Keep ASCII buffer pointer */ + mov r3, #2 /* Loop Counter */ + mov r2, r1, lsl #16 /* copy of input halfword value R1[15:0], shifted to MSH R2[31:16] */ + b _conv_byte2ascii_be /* goto Byte conversion loop */ + +/* halfword2ascii_le + * Little Endian version of halfword2ascii conversion routine + * On entry: + * R0: ASCII buffer pointer + * R1[15:0]: Halfword value + * On exit: + * R0: Address of next empty char slot in buffer + * R1: Original Address of Buffer + * + * This routine accepts an ASCII buffer pointer in R0 and a halfword value in R1, + * and stores the ASCII equivalent halfword value in the buffer pointed to by R0. + * Note: On return, R0 points to the next empty char slot in buffer + */ + .global halfword2ascii_le +halfword2ascii_le: + stmfd sp!, {r0,r2,r3, lr} /* Keep ASCII buffer pointer */ + mov r3, #2 /* Loop Counter */ + b _conv_byte2ascii_le /* goto Byte conversion loop */ + + +/* word2ascii_be + * Big Endian version of word2ascii conversion routine + * On entry: + * R0: ASCII buffer pointer + * R1[31:0]: Word value + * On exit: + * R0: Address of next empty char slot in buffer + * R1: Original Address of Buffer + * + * This routine accepts an ASCII buffer pointer in R0 and a word value in R1, + * and stores the ASCII equivalent word value in the buffer pointed to by R0. + * Note: On return, R0 points to the next empty char slot in buffer + */ + .global word2ascii_be +word2ascii_be: + stmfd sp!, {r0,r2,r3, lr} /* Keep ASCII buffer pointer */ + mov r2, r1 /* copy of input word value R1[31:0] */ + mov r3, #4 /* Loop Counter */ + + /* Fall through to byte coversion loop */ + + +/* Big Endian Multibyte Convert: Rotate then convert */ +_conv_byte2ascii_be: + ror r2, r2, #24 /* Rotate MSB R2[31:24] into LSB position R2[7:0] */ + and r1, r2, #BYTE0 /* Copy byte value in R2[7:0] into R1 */ + bl byte2ascii_cont /* R0: next ASCII buffer location pointer, R1: destroyed */ + subs r3, r3, #1 + bne _conv_byte2ascii_be + ldmfd sp!, {r1,r2,r3, pc} + +/* word2ascii_le + * Little Endian version of word2ascii conversion routine + * On entry: + * R0: ASCII buffer pointer + * R1[31:0]: Word value + * On exit: + * R0: Address of next empty char slot in buffer + * R1: Original Address of Buffer + * + * This routine accepts an ASCII buffer pointer in R0 and a word value in R1, + * and stores the ASCII equivalent word value in the buffer pointed to by R0. + * Note: On return, R0 points to the next empty char slot in buffer + */ + .global word2ascii_le +word2ascii_le: + stmfd sp!, {r0,r2,r3, lr} /* Keep ASCII buffer pointer */ + mov r2, r1 /* copy of input word value R1[31:0] */ + mov r3, #4 /* Loop Counter */ + + /* Fall through to byte coversion loop */ + +/* Little Endian Multibyte Convert: Convert then rotate */ +_conv_byte2ascii_le: + and r1, r2, #BYTE0 /* Copy byte value in R2[7:0] into R1 */ + bl byte2ascii_cont /* R0: next ASCII buffer location pointer, R1: destroyed */ + ror r2, r2, #8 /* Rotate LSB+1 R2[15:8] into LSB position R2[7:0] */ + subs r3, r3, #1 + bne _conv_byte2ascii_le + ldmfd sp!, {r1,r2,r3, pc} + + +/* ascii2hex_varlen_be + * Big Endian version of ascii2hex_varlen conversion routine + * (There is no Little Endian Version) + * On entry: + * R0: ASCII buffer pointer + * On exit: + * R0: Hex value + * R1: Address of next char slot in buffer + * + * This routine accepts an ASCII buffer pointer in R0, + * and returns the hex value in R0 for up to 8 Hex characters. + * Note: On return, R1 points to the ASCII buffer location after the hex value chars. + */ + .global ascii2hex_varlen_be + +ascii2hex_varlen_be: + stmfd sp!, {r2,r3, lr} + mov r3, #CMD_REG_REGPARAMLEN /* Set max count to 8 (Max Register size) */ + mov r1, r0 /* Use R1 as ASCII buffer pointer */ + mov r2, #0 /* Initialize Cummulative Results */ +2: ldrb r0, [r1] /* Load ASCII char for Hex Value */ + bl char2hex /* on return, hex value in R0, -1 for error */ + cmp r0, #-1 + beq _exit_ascii2hex_varlen + orr r2, r0, r2, lsl #4 /* combined byte value */ + subs r3, r3, #1 /* Decrement Counter */ + add r1, r1, #1 /* Go to next char slot */ + bne 2b +_exit_ascii2hex_varlen: + mov r0, r2 /* Return results in R0 */ + ldmfd sp!, {r2,r3, pc} + + +/* ascii2byte + * On entry: + * R0: ASCII buffer pointer + * On exit: + * R0[7:0]: Byte value + * R1: Address of next char slot in buffer + * + * This routine accepts an ASCII buffer pointer in R0, + * and returns the byte value in R0[7:0]. + * Note: On return, R1 points to the ASCII buffer location after the current 2 chars. + * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars, + * otherwise it will return invalid results. + */ + .global ascii2byte + +ascii2byte: + stmfd sp!, {r2, lr} + mov r1, r0 /* Use R1 as ASCII buffer pointer */ + ldrb r0, [r1], #1 /* Load ASCII char for MSN */ + bl char2hex /* on return, hex value in R0, -1 for error (ignored) */ + mov r2, r0, lsl #4 /* Intermediate Results register */ + ldrb r0, [r1], #1 /* Load ASCII char for LSN */ + bl char2hex /* on return, hex value in R0, -1 for error (ignored) */ + orr r0, r2, r0 /* combined byte value */ + ldmfd sp!, {r2, pc} + +/* ascii2halfword_be + * Big Endian version of ascii2halfword conversion routine + * On entry: + * R0: ASCII buffer pointer + * On exit: + * R0[15:0]: Halfword value + * R1: Address of next char slot in buffer + * + * This routine accepts an ASCII buffer pointer in R0, + * and returns the Halfword value in R0[15:0]. + * Note: On return, R1 points to the ASCII buffer location after the current 4 chars. + * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars, + * otherwise it will return invalid results. + */ + .global ascii2halfword_be + +ascii2halfword_be: + stmfd sp!, {r2,r3, lr} + mov r3, #2 /* Loop counter */ + b _conv_ascii2byte_be + +/* ascii2halfword_le + * Little Endian version of ascii2halfword conversion routine + * On entry: + * R0: ASCII buffer pointer + * On exit: + * R0[15:0]: Halfword value + * R1: Address of next char slot in buffer + * + * This routine accepts an ASCII buffer pointer in R0, + * and returns the Halfword value in R0[15:0]. + * Note: On return, R1 points to the ASCII buffer location after the current 4 chars. + * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars, + * otherwise it will return invalid results. + */ + .global ascii2halfword_le + +ascii2halfword_le: + stmfd sp!, {r2,r3, lr} + mov r3, #2 /* Loop counter */ + b _conv_ascii2byte_le + + +/* ascii2word_be + * Big Endian version of ascii2word conversion routine + * On entry: + * R0: ASCII buffer pointer + * On exit: + * R0[31:0]: Word value + * R1: Address of next char slot in buffer + * + * This routine accepts an ASCII buffer pointer in R0, + * and returns the word value in R0[31:0]. + * Note: On return, R1 points to the ASCII buffer location after the current 8 chars. + * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars, + * otherwise it will return invalid results. + */ + .global ascii2word_be + +ascii2word_be: + stmfd sp!, {r2,r3, lr} + mov r3, #4 /* Loop counter */ + + /* Fall through to byte coversion loop */ + +_conv_ascii2byte_be: + teq r0, #0 + beq _exit_conv_ascii2byte_be /* exit if NULL pointer in R0 */ + mov r2, #0 /* Initialize Cummulative value */ +2: bl ascii2byte + orr r2, r0, r2, lsl #8 /* Merge current byte with cummulative value */ + mov r0, r1 /* Copy next char pointer to R0 for next byte */ + subs r3, r3, #1 + bne 2b + mov r0, r2 /* Copy it to R0 as return value */ + +_exit_conv_ascii2byte_be: + ldmfd sp!, {r2,r3, pc} /* return hex value in R0 */ + +/* ascii2word_le + * Litle Endian version of ascii2word conversion routine + * On entry: + * R0: ASCII buffer pointer + * On exit: + * R0[31:0]: Word value + * R1: Address of next char slot in buffer + * + * This routine accepts an ASCII buffer pointer in R0, + * and returns the word value in R0[31:0]. + * Note: On return, R1 points to the ASCII buffer location after the current 8 chars. + * WARNING: This routine assumes that the input buffer was sanitized and contains valid Hex chars, + * otherwise it will return invalid results. + */ + .global ascii2word_le + +ascii2word_le: + stmfd sp!, {r2,r3, lr} + mov r3, #4 /* Loop counter */ + + /* Fall through to byte coversion loop */ + +_conv_ascii2byte_le: + teq r0, #0 + beq _exit_conv_ascii2byte_le /* exit if NULL pointer in R0 */ + push {r3} /* Need to keep couter for final value adjustment */ + mov r2, #0 /* Initialize Cummulative value */ +2: bl ascii2byte + orr r2, r0, r2, ror #8 /* Merge current byte with cummulative value */ + mov r0, r1 /* Copy next char pointer to R0 for next byte */ + subs r3, r3, #1 + bne 2b + /* Cummulative value done, need to rotate it into the correct position for return value */ + pop {r3} /* retrieve counter */ + rsb r3, r3, #5 /* 5 - count */ + lsl r3, r3, #3 /* [(5-count) x 8] bits to rotate */ + mov r0, r2, ror r3 /* Copy it to R0 as return value */ + +_exit_conv_ascii2byte_le: + ldmfd sp!, {r2,r3, pc} /* return hex value in R0 */ + diff --git a/AT91SAM7S256/armdebug/Debugger/debug_internals.h b/AT91SAM7S256/armdebug/Debugger/debug_internals.h new file mode 100644 index 0000000..e187b82 --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_internals.h @@ -0,0 +1,393 @@ +/** @file debug_internals.h + * @brief Shared C/ASM header file for debugger internal constants + * + */ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + +#ifndef __DEBUG_INTERNALS_H__ +#define __DEBUG_INTERNALS_H__ + +#include "_c_arm_macros.h" + + +/** @addtogroup debugger */ +/*@{*/ + + +/* Declarations go here. */ +/** @name Debug Message Constants. + * + * Debug Message Values + */ +/*@{*/ + +/* + * USB Buffer Sizes: Ctrl Intr Iso Bulk + * Full Speed Device 64 64 1023 64 + * High Speed Device 64 1024 1024 512 + */ + +#define USB_BUFSIZE 64 /* USB Buffer size for AT91SAM7S */ + +#define NXT_MSG_TELEGRAMTYPE_OFFSET 0 /* NXT Direct Command/Response Header */ +#define NXT_MSG_SEGNUM_OFFSET 1 +#define NXT_MSG_TELEGRAMSIZE_OFFSET 2 + +#define NXT_GDBMSG_TELEGRAMTYPE 0x8d /* GDB debugger specific, no Response required */ + +#define NXT_GDBMSG_START 3 /* Offset into USB Telegram buffer */ + +#define MSG_NUMSEGMENTS 3 /* For packet transfers */ +#define MSG_SEGMENTSIZE (USB_BUFSIZE - NXT_GDBMSG_START) /* 61 bytes per segment */ +#define MSGBUF_SIZE (MSG_SEGMENTSIZE*MSG_NUMSEGMENTS) /* Debug Message Buffer Size, 61 x 3 = 183 chars = ~80 bytes of actual data */ +#define MSGBUF_CHKSUMOFFSET 3 /* to be subtracted from message length */ +#define MSGBUF_IN_OVERHEADLEN 5 /* For calculating max message data length (exclude ASCIIZ char) */ +#define MSGBUF_OUT_OVERHEADLEN 5 /* For calculating max message data length (exclude ASCIIZ char) */ + +#define MSGBUF_CTRLC 0x03 /* For Out of Band Signaling: not implemented yet */ +#define MSGBUF_STARTCHAR '$' +#define MSGBUF_ACKCHAR '+' +#define MSGBUF_NAKCHAR '-' +#define MSGBUF_ERRCHAR 'E' +#define MSGBUF_SIGCHAR 'S' +#define MSGBUF_SETCHAR '=' +#define MSGBUF_CHKSUMCHAR '#' +#define MSGBUF_SEPCHAR ',' +#define MSGBUF_ARGCHAR ':' +#define MSGBUF_MSGERROR -1 +/*@}*/ + +/** @name Debug Command Lookup Constants. + * + * Debug Command Lookup + */ +/*@{*/ + +#define CMDINDEX_OUTOFRANGE -1 +/*@}*/ + +/** @name Debug Register Command Constants. + * + * Debug Register Command + */ +/*@{*/ +#define CMD_REG_NUMREGS 17 +#define CMD_REG_GETONE_MINPARAMLEN 1 +#define CMD_REG_GETONE_MAXPARAMLEN 2 +#define CMD_REG_GETALL_PARAMLEN 0 +#define CMD_REG_REGPARAMLEN 8 /* 32-bit ASCII Hex Value */ +#define CMD_REG_SETONE_MINPARAMLEN (2 + CMD_REG_REGPARAMLEN) +#define CMD_REG_SETONE_MAXPARAMLEN (3 + CMD_REG_REGPARAMLEN) +#define CMD_REG_SETALL_PARAMLEN (CMD_REG_NUMREGS*CMD_REG_REGPARAMLEN) +#define CMD_KILL_PARAMLEN 0 +#define CMD_DETACH_PARAMLEN 0 + +/*@}*/ + +/** @name Debug Memory Command Constants. + * + * Debug Memory Command + * FIXME: These limits are not enforced by the GDB client, it truncates addresses and lengths to remove leading '0's + * The PARAMLEN constants would probably be removed + */ +/*@{*/ +#define CMD_NUMITEMS_PARAMLEN 4 /* 16-bit ASCII Hex Value */ +#define CMD_MEM_READ_PARAMLEN (CMD_REG_REGPARAMLEN + CMD_NUMITEMS_PARAMLEN + 1) /* Address length is equivalent to reg param len */ +#define CMD_MEM_WRITE_MINPARAMLEN (CMD_REG_REGPARAMLEN + CMD_NUMITEMS_PARAMLEN + 2) /* Address length is equivalent to reg param len */ +#define CMD_MEM_SEPCHAR_OFFSET CMD_REG_REGPARAMLEN /* Address length is equivalent to reg param len */ +#define CMD_MEM_MAXOUTBUFLEN (MSGBUF_SIZE - MSGBUF_OUT_OVERHEADLEN) +#define CMD_MEM_MAXREADBYTES (CMD_MEM_MAXOUTBUFLEN/2) +#define CMD_MEM_MAXINBUFLEN (MSGBUF_SIZE - MSGBUF_IN_OVERHEADLEN) +#define CMD_MEM_MAXWRITEBYTES ((CMD_MEM_MAXINBUFLEN - CMD_MEM_WRITE_MINPARAMLEN)/2) +/*@}*/ + +/** @name Debug Continue and Step Command Constants. + * + * Debug Continue and Step Command + */ +/*@{*/ +#define CMD_CONTINUE_MINPARAMLEN 0 +#define CMD_STEP_MINPARAMLEN 0 +/*@}*/ + +/** @name Debug 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. + * + * Debug Breakpoint Command + */ +/*@{*/ + +#define CMD_BKPT_INSERT_MINPARAMLEN 5 +#define CMD_BKPT_REMOVE_MINPARAMLEN 5 + + +#define CMD_BKPT_TYPE_BREAK_MEMORY 0 +#define CMD_BKPT_TYPE_BREAK_HARD 1 /* Not supported */ +#define CMD_BKPT_TYPE_WATCH_WRITE 2 /* Not supported (yet) */ +#define CMD_BKPT_TYPE_WATCH_READ 3 /* Not supported (yet) */ +#define CMD_BKPT_TYPE_WATCH_ACCESS 4 /* Not supported (yet) */ + +#define CMD_BKPT_KIND_THUMB 2 +#define CMD_BKPT_KIND_THUMB2 3 /* Not supported */ +#define CMD_BKPT_KIND_ARM 4 + +#define CMD_BKPT_NOTFOUND -1 + +/*@}*/ + +/** @name Debug Stack Constants. + * + * Debug Stack Manipulation Values + */ +/*@{*/ +#define DBGSTACK_NEXTINSTR_INDEX 0 /* Next Instruction Address is at index 0 from bottom of Debug Stack */ +#define DBGSTACK_USERCPSR_INDEX 1 /* User CPSR (SPSR_UNDEF) is at index 1 from bottom of Debug Stack */ +#define DBGSTACK_USERREG_INDEX 2 /* R0 starts at index 2 from bottom of Debug Stack */ +#define DBGSTACK_USERSP_INDEX (DBGSTACK_USERREG_INDEX + REG_SP) /* SP is R13 */ +#define DBGSTACK_USERLR_INDEX (DBGSTACK_USERREG_INDEX + REG_LR) /* LR is R14 */ +#define DBGSTACK_USERPC_INDEX (DBGSTACK_USERREG_INDEX + REG_PC) /* PC is R15 */ +/*@}*/ + + +/** @name Exception Handler Vector Definitions. + * + * Exception Handler Vectors. + */ +/*@{*/ + +#define RESET_VECTOR 0x00000000 +#define UNDEF_VECTOR 0x00000004 +#define SVC_VECTOR 0x00000008 +#define PABRT_VECTOR 0x0000000C +#define DABRT_VECTOR 0x00000010 +#define RESERVED_VECTOR 0x00000014 +#define IRQ_VECTOR 0x00000018 +#define FIQ_VECTOR 0x0000001C + + +/*@}*/ + + +/** @name Bitmask Definitions. + * + * Various Bitmasks used for data manipulation. + */ +/*@{*/ +#define BKPT_STATE_THUMB_FLAG 0x01 /* Flag Thumb Breakpoint */ +#define ASCII_LOWER2UPPER_MASK 0x20 /* ASCII Conversion bitmask */ +#define NIBBLE0 0x0000000F /* Nibble 0 word(3:0) */ +#define NIBBLE1 0x000000F0 /* Nibble 1 word(7:4) */ +#define NIBBLE2 0x00000F00 /* Nibble 2 word(11:8) */ +#define NIBBLE3 0x0000F000 /* Nibble 3 word(15:12) */ +#define NIBBLE4 0x000F0000 /* Nibble 4 word(19:16) */ +#define NIBBLE5 0x00F00000 /* Nibble 5 word(23:20) */ +#define NIBBLE6 0x0F000000 /* Nibble 6 word(27:24) */ +#define NIBBLE7 0xF0000000 /* Nibble 7 word(31:28) */ +#define BYTE0 0x000000FF /* Byte 0 word(7:0) */ +#define BYTE1 0x0000FF00 /* Byte 1 word(15:8) */ +#define BYTE2 0x00FF0000 /* Byte 2 word(23:16) */ +#define BYTE3 0xFF000000 /* Byte 3 word(31:24) */ +#define HLFWRD0 0x0000FFFF /* Halfword 0 word(15:0) */ +#define HLFWRD1 0xFFFF0000 /* Halfword 0 word(31:16) */ +/*@}*/ + +/** @name CPSR Bit Definitions. + * + * Various Bit definitions for accessing the CPSR register. + */ +/*@{*/ +#define CPSR_THUMB 0x00000020 +#define CPSR_FIQ 0x00000040 +#define CPSR_IRQ 0x00000080 +#define CPSR_MODE 0x0000001F +#define CPSR_COND 0xF0000000 + +/* ARM Exception Modes */ +#define MODE_USR 0x10 /* User mode */ +#define MODE_FIQ 0x11 /* FIQ mode */ +#define MODE_IRQ 0x12 /* IRQ mode */ +#define MODE_SVC 0x13 /* Supervisor mode */ +#define MODE_ABT 0x17 /* Abort mode */ +#define MODE_UND 0x1B /* Undefined mode */ +#define MODE_SYS 0x1F /* System mode */ + +/* Condition Flags + * b31 b30 b29 b28 + * N Z C V + */ +#define CPSR_NFLAG 0x80000000 +#define CPSR_ZFLAG 0x40000000 +#define CPSR_CFLAG 0x20000000 +#define CPSR_VFLAG 0x10000000 + + +/* + * 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 + * + * Debugger State. + * The enums must be consecutive, starting from 0 + */ +ENUM_BEGIN +ENUM_VALASSIGN(DBG_RESET, 0) /**< Initial State. */ +ENUM_VAL(DBG_INIT) /**< Debugger Initialized. */ +ENUM_VAL(DBG_CONFIGURED) /**< Debugger has been configured by GDB Server */ +ENUM_END(dbg_state_t) + +/** Breakpoint Type Enums + * + * Breakpoint Type. + * The enums must be consecutive, starting from 0 + */ +ENUM_BEGIN +ENUM_VALASSIGN(DBG_AUTO_BKPT,0) /**< 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. + * The enums must be consecutive, starting from 1 + */ +/* FIXME: Need to validate against the ecos-generic-stub.c Error enums */ +ENUM_BEGIN +ENUM_VALASSIGN(MSG_ERRIMPL, 0) /**< Stub (not implemented) Error. */ +ENUM_VAL(MSG_ERRINLENGTH) /**< Message Write Length Error. */ +ENUM_VAL(MSG_ERROUTLENGTH) /**< Message Read Length Error. */ +ENUM_VAL(MSG_ERRFORMAT) /**< Message Format Error. */ +ENUM_VAL(MSG_UNKNOWNCMD) /**< Unrecognized Command Error. */ +ENUM_VAL(MSG_UNKNOWNPARAM) /**< Unrecognized Parameter Error. */ +ENUM_VAL(MSG_UNKNOWNBRKPT) /**< Unrecognized Breakpoint Error. */ +ENUM_END(dbg_msg_errno) + +/** Register Enums + * + * Register Enums. + * Refer to eCOS's arm_stub.h for enum values + */ +ENUM_BEGIN +ENUM_VALASSIGN(REG_R0, 0) /**< User Reg R0 */ +ENUM_VAL(REG_R1) /**< User Reg R1 */ +ENUM_VAL(REG_R2) /**< User Reg R2 */ +ENUM_VAL(REG_R3) /**< User Reg R3 */ +ENUM_VAL(REG_R4) /**< User Reg R4 */ +ENUM_VAL(REG_R5) /**< User Reg R5 */ +ENUM_VAL(REG_R6) /**< User Reg R6 */ +ENUM_VAL(REG_R7) /**< User Reg R7 */ +ENUM_VAL(REG_R8) /**< User Reg R8 */ +ENUM_VAL(REG_R9) /**< User Reg R9 */ +ENUM_VAL(REG_R10) /**< User Reg R10 */ +ENUM_VAL(REG_R11) /**< User Reg R11 */ +ENUM_VAL(REG_R12) /**< User Reg R12 */ +ENUM_VAL(REG_SP) /**< Previous Mode SP (R13) */ +ENUM_VAL(REG_LR) /**< Previous Mode LR (R14) */ +ENUM_VAL(REG_PC) /**< Program Counter (R15) */ +ENUM_VALASSIGN(REG_FPSCR, 24) /**< Previous Mode FPSCR (dummy) */ +ENUM_VAL(REG_CPSR) /**< Previous Mode CPSR */ + +ENUM_END(register_enum_t) + +/** 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 new file mode 100644 index 0000000..8d63e46 --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_macros.h @@ -0,0 +1,463 @@ +/** @file debug_macros.h + * @brief internal macros used by debug_stub routines + * + */ + +/* Copyright (C) 2007-2010 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + +#ifndef __DEBUG_MACROS_H__ +#define __DEBUG_MACROS_H__ + + + +/** @addtogroup debug_macros */ +/*@{*/ + +/* _dbg_jumpTableHandler + * Call Jump Table Routine based on Index + * On entry: + * jumptableaddr is the address (constant) of the Jump Table + * jumpreg is the register used to perform the indirect jump + * indexreg contains jump table index value + */ + .macro _dbg_jumpTableHandler jumptableaddr, jumpreg, indexreg + + ldr \jumpreg, =\jumptableaddr + ldr \jumpreg, [\jumpreg, \indexreg, lsl #2] + mov lr, pc + bx \jumpreg /* Call Command Handler Routine */ + .endm + + +/* _dbg_thumbDecodeEntry + * Load Thumb Instruction Decoder Entry + * On entry: + * instrreg is the register to load the instruction into + * instrmask is the register to load the instruction mask into + * codehandler is the register to load the code handling routine into + * indexreg contains decode table index value + * NOTE: instrreg, instrmask, codehandler must be in increasing register number order + */ + .macro _dbg_thumbDecodeEntry instrreg, instrmask, codehandler, indexreg + + ldr \instrmask, =debug_thumbDecodeTable /* Temporary register */ + add \instrmask, \instrmask, \indexreg, lsl #3 + ldm \instrmask, {\instrreg, \codehandler} /* LSHW: IID, MSHW: IBM */ + mov \instrmask, \instrreg, lsr #16 + mov \instrreg, \instrreg, lsl #16 + mov \instrreg, \instrreg, lsr #16 /* Keep HLFWORD0 containing instruction */ + .endm + +/* _dbg_armDecodeEntry + * Load ARM Instruction Decoder Entry + * On entry: + * instrreg is the register to load the instruction into + * instrmask is the register to load the instruction mask into + * codehandler is the register to load the code handling routine into + * indexreg contains decode table index value + * NOTE: instrreg, instrmask, codehandler must be in increasing register number order + */ + .macro _dbg_armDecodeEntry instrreg, instrmask, codehandler, indexreg + + ldr \instrmask, =debug_armDecodeTable /* Temporary register */ + add \instrmask, \instrmask, \indexreg, lsl #3 + add \instrmask, \instrmask, \indexreg, lsl #2 /* 12 byte entries */ + ldm \instrmask, {\instrreg, \instrmask, \codehandler} + .endm + +/* _asciiz + * Terminate string given string buffer pointer in \strptr + * scratchreg is used as a scratch register (destroyed) + * + */ + .macro _asciiz strptr, scratchreg + mov \scratchreg, #0 /* ASCIIZ character */ + strb \scratchreg, [\strptr] /* Terminate ASCII string */ + .endm + + +/* _dbg_stpcpy + * _dbg_stpcpy macro + * On entry: + * deststrptr: Destination string + * sourcestrptr: Source string + * scratchreg: scratch register for copying + * On exit: + * deststrptr: Pointer to ASCIIZ character in destination string + * sourcestrptr: Pointer to next character slot in source string (after ASCIIZ) + * scratchreg: destroyed + */ + .macro _dbg_stpcpy deststrptr, sourcestrptr, scratchreg +1: ldrb \scratchreg, [\sourcestrptr], #1 + strb \scratchreg, [\deststrptr], #1 + teq \scratchreg, #0 + bne 1b + sub \deststrptr, \deststrptr, #1 /* Adjust Destination string pointer to point at ASCIIZ character */ + .endm + +/* _dbg_memcpy + * _dbg_stpcpy macro + * On entry: + * deststrptr: Destination string + * sourcestrptr: Source string + * sizereg: Number of bytes to copy + * scratchreg: scratch register for copying + * On exit: + * deststrptr: Pointer to next character slot in destination string + * sourcestrptr: Pointer to next character slot in source string + * sizereg, scratchreg: destroyed + */ + .macro _dbg_memcpy deststrptr, sourcestrptr, sizereg, scratchreg +1: ldrb \scratchreg, [\sourcestrptr], #1 + strb \scratchreg, [\deststrptr], #1 + subs \sizereg, \sizereg, #1 + bne 1b + .endm + +/* _dbg_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 + * R2-R3: destroyed + */ + .macro _dbg_outputAckOnlyFlag + ldr r2, =debug_AckOnlyFlag /* ASCIIZ terminated */ + _dbg_CopyMsg2OutputBuf + .endm + + +/* _dbg_outputRetransmitFlag + * Return Flag ('-') for Checksum Error (retransmission needed) + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R2-R3: destroyed + */ + .macro _dbg_outputRetransmitFlag + 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 + * R2-R3: destroyed + */ + .macro _dbg_outputMsgValidResponse + ldr r2, =debug_ValidResponsePrefix + _dbg_CopyMsg2OutputBuf + .endm + +/* _dbg_outputMsgStatusOk + * Return Message with Ok ('+$OK') status + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R2-R3: destroyed + */ + .macro _dbg_outputMsgStatusOk + ldr r2, =debug_OkResponse /* ASCIIZ terminated */ + _dbg_CopyMsg2OutputBuf + .endm + +/* _dbg_outputMsgCurrTID + * Return Message with Default Thread ID ('+$QC0') + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * 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: + * R1: error code + * On exit: + * R0: Pointer to Output Buffer ASCIIZ location + * R1-R3: destroyed + */ + .macro _dbg_outputMsgStatusErr + 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-R3: destroyed + */ + .macro _dbg_outputMsgStatusErrCode errcode + mov r1, #\errcode + _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-R3: destroyed + */ + .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 + _dbg_outputMsgStatusSig + .endm + + +/* _regenum2index + * Convert register enum to debugger stack index + * + * On entry: + * indexenum: enum representing Register to access + * indexreg: register to be used to store the debugger stack index value (0-max index) + * On exit: + * indexreg contains debugger stack index value (0-max index) + */ + .macro _regenum2index indexenum, indexreg + add \indexreg, \indexenum, #DBGSTACK_USERREG_INDEX /* Convert register index to Debug Stack index */ + .endm + +/* _getdbgregisterfromindex + * Retrieve register contents from debugger stack given index + * + * On entry: + * indexreg contains debugger stack index value (0-max index) + * On exit: + * indexreg: Breakpoint index (preserved) + * contentsreg: Register Contents for given index + */ + .macro _getdbgregisterfromindex indexreg, contentsreg + ldr \contentsreg, =__debugger_stack_bottom__ + ldr \contentsreg, [\contentsreg, \indexreg, lsl #2] + .endm + +/* _setdbgregisterfromindex + * Store register contents to debugger stack given index + * + * On entry: + * indexreg contains debugger stack index value (0-max index) + * contentsreg: Register Contents for given index + * addressreg: Scratch register for address pointer + * On exit: + * indexreg: Breakpoint index (preserved) + * contentsreg: Register Contents for given index + */ + .macro _setdbgregisterfromindex indexreg, contentsreg, addressreg + ldr \addressreg, =__debugger_stack_bottom__ + str \contentsreg, [\addressreg, \indexreg, lsl #2] + .endm + +/* _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 + * + * On entry: + * indexreg contains breakpoint index value + * On exit: + * indexreg: Breakpoint index (preserved) + * addrreg: Breakpoint Entry Address + */ + .macro _index2bkptindex_addr indexreg, addrreg + ldr \addrreg, =__breakpoints_start__ + add \addrreg, \addrreg, \indexreg, lsl #3 /* Calculate Breakpoint Entry Address */ + .endm + +/* _dbg_getstate + * Get Debugger State + * On exit: + * reg: Debugger State enum + */ + .macro _dbg_getstate reg + ldr \reg, =debug_state + ldrb \reg, [\reg] + .endm + +/* _dbg_setstate + * Set Debugger State to given value + * On exit: + * r0, r1: destroyed + */ + .macro _dbg_setstate state + mov r0, #\state + ldr r1, =debug_state + strb r0, [r1] + .endm + +/* _dbg_getmode + * Get Debugger Mode + * On exit: + * reg: Debugger Mode (Boolean) + */ + .macro _dbg_getmode reg + ldr \reg, =debug_mode + ldrb \reg, [\reg] + .endm + +/* _dbg_setmode + * Set Debugger Mode to given value + * On exit: + * r0, r1: destroyed + */ + .macro _dbg_setmode mode + mov r0, #\mode + ldr r1, =debug_mode + strb r0, [r1] + .endm + +/* _dbg_get_bkpt_type + * Get Breakpoint Type + * On exit: + * reg: Breakpoint Type + */ + .macro _dbg_get_bkpt_type reg + ldr \reg, =debug_bkpt_type + ldrb \reg, [\reg] + .endm + +/* _dbg_set_bkpt_type + * Set Breakpoint Type 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_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: + * reg: Breakpoint index + */ + .macro _dbg_getcurrbkpt_index reg + ldr \reg, =debug_curr_breakpoint + ldrb \reg, [\reg] + .endm + +/* _dbg_setcurrbkpt_index + * Set current breakpoint index + * On exit: + * r1: destroyed + */ + .macro _dbg_setcurrbkpt_index reg + ldr r1, =debug_curr_breakpoint + strb \reg, [r1] + .endm + + /*@}*/ + +#endif /* __DEBUG_MACROS_H__ */ diff --git a/AT91SAM7S256/armdebug/Debugger/debug_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 + * + * 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<> 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 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 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 . 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 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 new file mode 100644 index 0000000..3bcf35a --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.S @@ -0,0 +1,415 @@ +/** @file debug_runlooptasks.S + * @brief GDB Server platform Run Loop + * + */ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + +/* + * This file contains platform specific code. + * This include ABORT Mode Debugger Run Loop operation, + * as well as Debugger Interfacing code to the platform code. + */ + +/* + * The Debugger has to implement a Run Loop in ABORT mode + * since the hardware is still running. Consequently, + * the communications subsystems such as USB (and Bluetooth?) + * which is used to communicate with the Host needs to be + * serviced in order for actual data transmission and reception + * to take place. Currently we're reusing the platform's + * communication routines to do the actual tx/rx, so it means + * that it is not possible to set breakpoints in those modules. + * In addition, since the platform communication modules may + * handle other tasks, it is currently possible to enter an + * indeterminate state where certain communication messages trigger + * a platform response which cannot be handled by the Debugger Run Loop. + * The alternative is to implement our own communications routines, but + * that will take even more code. + * + * FIXME: It may become necessary to hack the platform communications + * routines to detect that we're in the Debugger Run Loop and not the + * normal run loop to avoid system crashes, but the current goal is to + * have as minimal changes to the platform code as possible. + * + * Since there are two Run Loops for the platform, the way in which + * they interact is as follows: + * + * [Platform Run Loop] - DBG_INIT/ GDB Cmd/ BKPT -> [Debugger Run Loop] + * \ <------ GO/ STEP/ CONT ----- / + * ... ... + * ... Handle GDB Cmd/Resp + * ... ... + * {normal runloop {communications / + * processing} watchdog routines} + * ^-------v v-------^ + * + * The Platform will invoke dbg__bkpt_init() after hardware and system initialization, + * before entering the Platform Run Loop. This configures the Debugger, but does not + * invoke the Debugger Run Loop unless a Manual Breakpoint is found in the platform code. + * + * Subsequently, the Debugger Run Loop will be triggered by Breakpoints, or + * when the communications subsystem receives a GDB Command. + * + * The Debugger Run Loop is actually dbg__bkpt_waitCMD(), this file contains + * the Run Loop Tasks which needs to be invoked periodically by the Run Loop, + * to minimize the coupling between the ARMDEBUG modules and the Platform. + * + * Note: The Debugger Run Loop does not handle Hardware Shutdown, it is + * assumed that we wouldn't need to do so in Debug Mode. + * + */ +#define __ASSEMBLY__ + +#define REBOOT_POWERDOWN +#include "debug_runlooptasks.h" + +#include "debug_internals.h" +#include "debug_macros.h" +#include "debug_stub.h" + + .code 32 + .align 4 + .global dbg__runloopTasks + .global dbg__reboot + .global dbg__display_abort_info + .global dbg__sendCommMsg + +#ifdef __NXOS__ +/**************************************************************************** + * + * NxOS Run Loop + * + ****************************************************************************/ +dbg__runloopTasks: +/* Currently, there's nothing that needs to be done in the NxOS Run Loop */ + push {lr} + mov r0, #1 /* 1 ms delay */ + bl nx_systick_wait_ms + pop {pc} + +#else +/**************************************************************************** + * + * NXT Firmware Run Loop + * + ****************************************************************************/ +dbg__runloopTasks: + push {lr} + /* FIXME: Add necessary cXXXCtrl calls here */ + bl cCommCtrl + /* OSWatchdogWrite is a NULL function in the NXT Firmware?! */ + pop {pc} +#endif + +#ifdef __NXOS__ +/**************************************************************************** + * + * NxOS Reboot Routine + * + ****************************************************************************/ + dbg__reboot: +#ifdef REBOOT_POWERDOWN + b nx_core_halt /* Shutdown Brick, won't return */ +#else + b nx_core_reset /* Reboot Brick, won't return */ +#endif + +#else +/**************************************************************************** + * + * NXT Firmware Reboot Routine + * + ****************************************************************************/ +dbg__reboot: + /* Powerdown Sequence + dIOCtrlSetPower((POWERDOWN>>8)); + dIOCtrlTransfer(); + + Reboot Sequence + dIOCtrlSetPower((UBYTE)(BOOT>>8)); + dIOCtrlSetPwm((UBYTE)BOOT); + dIOCtrlTransfer(); + */ + + /* We implement the powerdown sequence for now */ + +#ifdef REBOOT_POWERDOWN + /* Powerdown sequence */ + ldr r0, =((POWERDOWN >> 8) & 0xFF) + ldr r1, =dIOCtrlSetPower + mov lr,pc + bx r1 +#else + /* Reboot sequence: this forces SAMBA mode??!! */ + ldr r0, =((BOOT >> 8) & 0xFF) + ldr r1, =dIOCtrlSetPower + mov lr,pc + bx r1 + + ldr r0, =(BOOT & 0xFF) + ldr r1, =dIOCtrlSetPwm + mov lr,pc + bx r1 +#endif + +_dbg__reboot_wait: + ldr r1, =dIOCtrlTransfer + mov lr,pc + bx r1 + + b _dbg__reboot_wait /* Wait for AVR... */ +#endif + +#ifdef __NXOS__ +/**************************************************************************** + * + * NxOS Abort Info LCD Display Routine + * + ****************************************************************************/ +/* On entry: + * r0: abort type + * On exit: + * r0-r3: destroyed + */ +dbg__display_abort_info: + push {lr} + _getdbgregister DBGSTACK_USERPC_INDEX, r1 /* Retrieve User PC into R2 */ + _getdbgregister DBGSTACK_USERCPSR_INDEX, r2 /* Retrieve User CPSR into R2 */ + bl nx__abort_info /* void nx__abort_info(U32 data, U32 pc, U32 cpsr); */ + pop {pc} + +#else +/**************************************************************************** + * + * NXT Firmware Abort Info LCD Display Routine + * + ****************************************************************************/ +dbg__display_abort_info: +/* FIXME: Inteface with NXT Firmware LCD Display routines */ + push {lr} + pop {pc} +#endif + +#ifdef __NXOS__ + .extern debug_OutCommBuf +/**************************************************************************** + * + * NxOS Communications Driver Interface Routine + * + ****************************************************************************/ +/* dbg__sendCommMsg + * Internal send routine (interfaces with drivers). + * On entry: + * R0: Total Message Buffer length + * On exit: + * R0: Tx Status (TRUE if data sent) + * R1-R3: Destroyed + */ +dbg__sendCommMsg: + stmfd sp!, {r4, lr} + mov r4, r0 /* Keep Comm Buffer length in R4 */ + /* Check USB bus status, transmit message if possible */ + bl nx_usb_is_connected /* R0 = TRUE (#1) if USB is ready */ + teq r0, #0 /* FALSE == #0; + We can't check for True condition since values + used by C-Compiler & ARMDEBUG are different */ + beq dbg__sendCommMsgFailed + + /* Actual transmission (blocking) */ + ldr r0, =debug_OutCommBuf /* data pointer parameter */ + mov r1, r4 /* Comm buffer length */ + bl nx_usb_write + +1: bl nx_usb_data_written /* R0 = True if data has been sent */ + teq r0, #0 /* FALSE == #0; + We can't check for True condition since values + used by C-Compiler & ARMDEBUG are different */ + /* FIXME: implement timeout */ + beq 1b /* Busy Wait Loop */ + + mov r0, #TRUE + b exit_dbg__sendCommMsg +dbg__sendCommMsgFailed: + mov r0, #FALSE + +exit_dbg__sendCommMsg: + ldmfd sp!, {r4, pc} + + +#else +/**************************************************************************** + * + * NXT Firmware Communications Driver Interface Routine + * + ****************************************************************************/ +/* dbg__sendCommMsg + * Internal send routine (interfaces with drivers). + * On entry: + * R0: Total Message Buffer length + * On exit: + R0: Tx Status (TRUE if data sent) + */ +dbg__sendCommMsg: + stmfd sp!, {r4, lr} + mov r4, r0 /* Keep Comm Buffer length in R4 */ + ldr r0, =debug_nxtCommChannel + ldr r0, [r0] /* Get Channel Enum */ + teq r0, #BT_CMD_READY + beq dbg__sendBTMsg + teq r0, #USB_CMD_READY + beq dbg__sendUSBMsg + b dbg__sendCommMsgFailed /* Channel Enum Doesn't Match, shouldn't happen? */ + +dbg__sendBTMsg: + /* NXT BT routines do not have any configuration checks */ + ldr r0, =debug_OutCommBuf /* data pointer parameter */ + mov r1, r4 /* BT Bytes to Send */ + mov r2, r4 /* BT Message Size */ + bl dBtSendMsg /* Send it via Bluetooth (complete message) */ + mov r0, #TRUE /* Always flag Success */ + b exit_dbg__sendCommMsg + +dbg__sendUSBMsg: + /* Check USB bus status, transmit message if possible */ + bl dUsbIsConfigured /* R0: UByte status, TRUE / FALSE */ + teq r0, #nxt_UBYTE_TRUE + bne dbg__sendCommMsgFailed + + /* Actual transmission (blocking) */ + ldr r0, =debug_OutCommBuf /* data pointer parameter */ + mov r1, r4 /* Comm buffer length */ + bl dUsbWrite /* call NXT Firmware USB driver, return 0: done, !0: remaining chars */ + teq r0, #0 /* Tx done if returned length is 0 */ + moveq r0, #TRUE /* Convert NXT firmware return value to our Status (TRUE/FALSE) */ + beq exit_dbg__sendCommMsg +dbg__sendCommMsgFailed: + mov r0, #FALSE + +exit_dbg__sendCommMsg: + ldmfd sp!, {r4, pc} +#endif + + +#ifdef __NXOS__ +/**************************************************************************** + * + * GDB Debugger Invocation Routine for NxOS + * + ****************************************************************************/ + .code 32 + .align 4 + + .extern dbg__install_singlestep + .extern dbg__activate_singlestep + .extern irq_stack_frame_address + .global nxos__handleDebug +/* nxos__handleDebug + * Prepare to switch to Debug Mode + * int nxos__handleDebug(U8 *buffer, comm_chan_t channel, U32 length); + * + * This routine is called from NxOS Fantom library to setup + * Single Step Breakpoint in preparation for Debugger invocation if we're in + * normal execution mode. + * + * It returns to complete the IRQ handling normally, after which the single + * step breakpoint will be triggered, and the incoming GDB message will then + * be processed in the dbg__bkpt_waitCMD() loop. + * + * If we're in Debugger Mode already, then just return and let the + * dbg__bkpt_waitCMD() loop handle it normally. + * + * If we're operating in normal NxOS mode, return True (!0) + * If we're already in Debugger Mode, return False (0) + */ +nxos__handleDebug: + push {lr} + /* This routine is called from nx__irq_handler() via fantom_filter_packet(). + * The operating mode should already have been configured by the IRQ interrupt handler. + * + * The IRQ Stack Frame Pointer will contains the LR and SPSR from the topmost interrupted task + * if it is non-zero (NxOS supports nested IRQs) + */ + bl dbg__copyNxtDebugMsg /* Copy to Debugger Message Buffer, Remember Comm Channel */ + mov r0, #FALSE /* Setup Default Return value (False) */ + _dbg_getmode r1 /* Get Debug Mode */ + cmp r1, #(TRUE & BYTE0) /* Confine it to Byte size */ + /* If Debug Mode is TRUE, this means that we're already running the Debugger */ + beq exit_nxos__handleDebug /* Yes, return False */ + + /* Retrieve ISR Return Address */ + ldr r3, =irq_stack_frame_address + ldr r3, [r3] /* Get Interrupt Stack Pointer */ + teq r3, #0 + beq exit_nxos__handleDebug /* NULL Interrupt Stack Frame Pointer, exit (status: False) */ + +nxos_switch2debug: + /* Since the Interrupt Stack Frame Pointer points to the top of the stack frame, + * we'll have to use Load Empty Ascending Stack (LDMEA == LDMDB) to access the variables + */ + ldmdb r3, {r1,r2} /* R1: LR, R2: SPSR */ + tst r2, #CPSR_THUMB /* Check for Thumb Mode */ + orrne r1, r1, #1 /* Configure for Thumb Single Step Breakpoint */ + bl dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ + bl dbg__activate_singlestep + mov r0, #TRUE /* We're going to switch to Debug Mode (via Single Step Breakpoint) */ + +exit_nxos__handleDebug: + pop {r1} + bx r1 /* In case we have Interworking from different caller mode */ + +#else + +/**************************************************************************** + * + * GDB Debugger Invocation Routine for NXT Firmware + * + ****************************************************************************/ + .code 16 + .align 2 + + .extern dbg__copyNxtDebugMsg + .global cCommHandleDebug + .thumb_func +/* cCommHandleDebug + * Switch Mode to Debugger. + * Used by NXT Firmware only + * + * UWORD cCommHandleDebug(UBYTE *pInBuf, UBYTE CmdBit, UWORD MsgLength); + * + * This routine is called from cCommInterprete either in normal operation mode (SVC) + * or else when we're in debug mode (ABORT) which uses the cCommCtrl() routine to handle + * I/O with the Host. + * + * On entry, the message is copied from the NXT buffer into our own buffers. + * + * If this is accessed from normal operation mode, we need to switch mode to + * ABORT mode to handle the incoming message using a Manual Breakpoint instruction. + * When DEBUG is exited, the execution resumes from the instruction following the Breakpoint. + */ +cCommHandleDebug: +/* Arg Registers are not preserved since this is invoked explicitly */ + push {lr} /* store arg registers */ + bl dbg__copyNxtDebugMsg /* Copy to Debugger Message Buffer, Remember Comm Channel */ + _dbg_getmode r0 /* Get Debug Mode */ + cmp r0, #(TRUE & BYTE0) /* Confine it to Byte size */ + + /* If Debug Mode is TRUE, this means that we're already running the Debugger */ + beq _cCommHandleDebug_cont + /* Else, we're in normal operation mode (SVC), or other mode (??!) and need to force a switch to Debug mode */ + dbg__bkpt_thumb +_cCommHandleDebug_cont: + mov r0, #0 /* FIXME: Return Status */ + pop {r1} /* Can't Pop LR directly */ + bx r1 /* Safe code: actually we should be able to Pop PC since the caller is Thumb Mode */ + + .ltorg +#endif diff --git a/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.h b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.h new file mode 100644 index 0000000..f55311e --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_runlooptasks.h @@ -0,0 +1,63 @@ +/** @file debug_runlooptasks.h + * @brief Shared C/ASM header file for debugger communications + * + */ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + +#ifndef __DEBUG_RUNLOOPTASKS_H__ +#define __DEBUG_RUNLOOPTASKS_H__ + +#include "_c_arm_macros.h" + +/* This is a place holder header file to allow for interfacing with C Routines in either + * NxOS or NXT Firmware. + * + * Since the header files from the original source trees were meant for C programs, we can't + * include them directly. Here we just use .extern to reference the routines. + */ + +#ifdef __NXOS__ + .extern nx__abort_info + .extern nx_systick_wait_ms + + .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 */ + +#endif + +#endif diff --git a/AT91SAM7S256/armdebug/Debugger/debug_stack.ld b/AT91SAM7S256/armdebug/Debugger/debug_stack.ld new file mode 100644 index 0000000..8fc4cb7 --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_stack.ld @@ -0,0 +1,15 @@ +/* The following linker definitions should be placed in the stack section */ + + /* debugger state */ + __debugger_stack_bottom__ = . ; + . += 0x48; /* 16 previous mode registers + SPSR + UNDEF Next Instruction Address */ + __debugger_stack__ = .; + __debugger_stack_top__ = . ; + + /* breakpoints */ + __breakpoints_start__ = . ; + . += 0x40; /* Single Stepping Breakpoint + 7 Breakpoints */ + __breakpoints_end__ = . ; + +/* Symbols */ + __breakpoints_num__ = (__breakpoints_end__ - __breakpoints_start__) / 8; diff --git a/AT91SAM7S256/armdebug/Debugger/debug_stub.S b/AT91SAM7S256/armdebug/Debugger/debug_stub.S new file mode 100644 index 0000000..51bb0c6 --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_stub.S @@ -0,0 +1,1586 @@ +/** @file debug_stub.S + * @brief ARM Breakpoint Debugger support routines + * + */ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + + /* GDB sparc-stub.c comments header included below to document GDB Server Remote protocol */ + /* This header has been modified to include additional commands not documented in the header stub */ + + /**************************************************************************** + + THIS SOFTWARE IS NOT COPYRIGHTED + + HP offers the following for use in the public domain. HP makes no + warranty with regard to the software or it's performance and the + user accepts the software "AS IS" with all faults. + + HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD + TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +****************************************************************************/ + +/**************************************************************************** + * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ + * + * Module name: remcom.c $ + * Revision: 1.34 $ + * Date: 91/03/09 12:29:49 $ + * Contributor: Lake Stevens Instrument Division$ + * + * Description: low level support for gdb debugger. $ + * + * Considerations: only works on target hardware $ + * + * Written by: Glenn Engel $ + * ModuleState: Experimental $ + * + * NOTES: See Below $ + * + * Modified for SPARC by Stu Grossman, Cygnus Support. + * + * This code has been extensively tested on the Fujitsu SPARClite demo board. + * + * To enable debugger support, two things need to happen. One, a + * call to set_debug_traps() is necessary in order to allow any breakpoints + * or error conditions to be properly intercepted and reported to gdb. + * Two, a breakpoint needs to be generated to begin communication. This + * is most easily accomplished by a call to breakpoint(). Breakpoint() + * simulates a breakpoint by executing a trap #1. + * + ************* + * + * The following gdb commands are supported: + * + * command function Return value + * + * g return the value of the CPU registers hex data or ENN + * GrrrrRRRR.. set the value of the CPU registers OK or ENN + * where register values are given as + * 32-bit hex values in the sequence: + * User R0, R1, ..., R15, CPSR + * px get the value of one register (x) hex data or ENN + * Px=rrrr set the value of one register (x) to OK or ENN + * 32-bit hex value rrrr. + * x = ['0','F'] for R0-R15, ['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 + * MAA..AA,LLLL:bb..bb + * Write LLLL bytes at address AA.AA OK or ENN + * + * D Detach (equivalent to continue Ack Only + * at current address) + * c Resume at current address SNN ( signal NN) + * cAA..AA Continue at address AA..AA SNN + * + * s Step one instruction SNN + * sAA..AA Step one instruction from AA..AA SNN + * + * k kill + * + * ? What was the last sigval ? SNN (signal NN) + * + * zt,AA..AA,k Remove a Breakpoint of type t at addr OK or ENN + * AA..AA of kind k + * Zt,AA..AA,k Insert a Breakpoint of type t at addr OK or ENN + * AA..AA of kind k + * t 0: memory breakpoint + * 1: hardware breakpoint + * 2: write watchpoint + * 3: read watchpoint + * 4: access watchpoint + * k: 2 (16-bit Thumb), 3 (32-bit Thumb2) + * or 4 (32-bit ARM) for t=[0,1] + * Num. bytes to watch for t=[2,4] + * + * All commands and responses are sent with a packet which includes a + * checksum. A packet consists of + * + * $#. + * + * where + * :: + * :: < two hex digits computed as modulo 256 sum of > + * + * When a packet is received, it is first acknowledged with either '+' or '-'. + * '+' indicates a successful transfer. '-' indicates a failed transfer. + * + * Example: + * + * Host: Reply: + * $m0,10#2a +$00010203040506070809101112131415#42 + * + ****************************************************************************/ + /* Modified GDB Server Remote Protocol definition from GDB's sparc-stub.c Comment Header included above + * Additional commands from GDB Reference Appendix D.2 + * + * Note: ARMDEBUG can only implement Memory Breakpoints t=0. Hardware breakpoints requires a JTAG debugger. + * Currently, watchpoints are not implemented as they require hardware support as well (need verification). + * + * GDB requires command parameters to be specified as Big Endian values. + * However, the read/write register command expect the register contents to be specified in target byte order. + * The default target byte order is Little Endian for the AT91SAM7xxx processor in the NXT. + * If Big Endian target byte order is required, the __BIG_ENDIAN__ preprocessor label should be defined. + */ + +/* FIXME: The Hex value arguments passed by GDB does not have fixed lengths! Although the standard says + * there should be x digits, it does not follow this requirement. e.g., register index. + */ + + +#define __ASSEMBLY__ +#include "debug_stub.h" +#include "debug_internals.h" +#include "debug_macros.h" + + /* Opcode Parser function reference */ + .extern dbg_following_instruction_addr + + /* Hexutils function references */ + .extern hex2char + .extern char2hex + .extern byte2ascii + .extern halfword2ascii_be + .extern halfword2ascii_le + .extern word2ascii_be + .extern word2ascii_le + .extern ascii2hex_varlen_be + .extern ascii2byte + .extern ascii2halfword_be + .extern ascii2halfword_le + .extern ascii2word_be + .extern ascii2word_le + +/* Macro definitions */ + +/* _check_msgseparator + * Look for separator ',' + * On entry: + * bufferptr: points to the parameter buffer [can't be R0] + * On exit: + * R0: destroyed + * bufferptr: points to the next character location in the parameter buffer + * Flags: Updated + */ + + .macro _check_msgseparator bufferptr + ldrb r0, [\bufferptr], #1 /* get separator */ + cmp r0, #MSGBUF_SEPCHAR + .endm + +/* _check_msgargument + * Look for argument ':' + * On entry: + * bufferptr: points to the parameter buffer [can't be R0] + * On exit: + * R0: destroyed + * bufferptr: points to the next character location in the parameter buffer + * Flags: Updated + */ + + .macro _check_msgargument bufferptr + ldrb r0, [\bufferptr], #1 /* get separator */ + cmp r0, #MSGBUF_ARGCHAR + .endm + +/* _check_msgassignment + * Look for assignment '=' + * On entry: + * bufferptr: points to the parameter buffer [can't be R0] + * On exit: + * R0: destroyed + * bufferptr: points to the next character location in the parameter buffer + * Flags: Updated + */ + + .macro _check_msgassignment bufferptr + ldrb r0, [\bufferptr], #1 /* get separator */ + cmp r0, #MSGBUF_SETCHAR + .endm + +.bss +.align 4 +debug_InMsgBuf: + .space MSGBUF_SIZE,0 +debug_OutMsgBuf: + .space MSGBUF_SIZE,0 + + /* Make Debugger State accessible from other modules */ + .global debug_state + .global debug_mode + .global debug_bkpt_type + .global debug_curr_breakpoint + +debug_state: + .byte 0x0 /* dbg_state_t variable */ +debug_mode: + .byte 0x0 /* Boolean variable */ +debug_bkpt_type: + .byte 0x0 /* bkpt_type_t variable */ +debug_curr_breakpoint: + .byte 0x0 + +.data +.align 4 +debug_RetransmitFlag: + .byte '-',0 + +debug_AckOnlyFlag: + .byte '+',0 + +debug_ValidResponsePrefix: + .byte '+','$',0 + +debug_ErrorResponsePrefix: + .byte '+','$','E',0 + +debug_SignalResponsePrefix: + .byte '+','$','S',0 + +debug_OkResponse: + .byte '+','$','O','K',0 + +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 + +/* Command Handlers + * On entry: + * R0: Input Message Parameter Buffer address pointer (points to contents after '$' and '') + */ +.align 4 +debug_cmdJumpTable: + .word _dbg__cmd_GetAllRegs /* 'g' */ + .word _dbg__cmd_SetAllRegs /* 'G' */ + .word _dbg__cmd_GetOneReg /* 'p' */ + .word _dbg__cmd_SetOneReg /* 'P' */ + .word _dbg__cmd_ReadMem /* 'm' */ + .word _dbg__cmd_WriteMem /* 'M' */ + .word _dbg__cmd_Detach /* 'D' */ + .word _dbg__cmd_Continue /* 'c' */ +#ifdef __NXOS__ + .word _dbg__cmd_Step /* 's' */ +#else + /* NXT Firmware does not support Stepping */ + .word _dbg__nop /* 's' */ +#endif + .word _dbg__cmd_Kill /* 'k' */ + .word _dbg__cmd_RemoveBreakpoint /* 'z' */ + .word _dbg__cmd_InsertBreakpoint /* 'Z' */ + .word _dbg__cmd_Status /* '?' */ + .word _dbg__cmd_Query /* 'q' */ + .word _dbg__nop /* 'Q' */ + .word 0 + +.code 32 +.text +.align 4 + .extern __breakpoints_num__ + .extern dbg__getDebugMsg /* Read a message from the communications link */ + .extern dbg__putDebugMsg /* Write a message to the communications link */ + .extern dbg__sendAckOrNak /* Send Ack or Nak to indicate success/failure of message receipt */ + .extern dbg__runloopTasks /* Platform specific Run Loop processing */ + + +/* The Debugger Interface can handle a total of (n-1) Breakpoint States and 1 Single Stepping State, + * where n is a power of 2. The value of n is given by __breakpoints_num__ defined in the linker file. + * + * In addition, a Debugger Stack contains the User Mode Register Stack Frame + SPSR + Bkpt Instr Addr. + * These are currently stored in the .stack area in RAM, so there is no fixed address + * location that is used for this purpose. + * + * The Breakpoint feature assumes that the program is executed in RAM. It is not possible + * to set dynamic breakpoints for programs executed from Flash in the AT91SAM7S which lacks + * instruction breakpointing support in hardware without using JTAG. The only type of breakpoints + * that can be supported in Flash based programs are Static (predefined) breakpoints inserted into + * the code. + * + * Each Breakpoint State i is a struct comprising the Breakpoint Address + Memory Contents + * stored in 8 bytes as: + * [High Memory Address] + * ADDR [i*8+4]: Memory Contents (32 bits) + * ADDR [i*8]: Breakpoint Address (31 bits, b0 = THUMB flag [not implemented yet]) + * [Low Memory Address] + * + * A Non-zero Breakpoint Address means that the breakpoint is active, whereas the memory contents + * contains the instruction which resided at that address initially (now replaced by a BKPT + * instruction). + * Note: Currently it is not possible to resume execution of a program with breakpoints enabled + * after a RESET, since the RESET will clear all contents of the stack, destroying the instruction + * contained in a given breakpoint. + * Fortunately the NXT will also need to reload the program into RAM so this is not expected to be + * an issue. + * + * The Memory Map for the Debugger State is as follows: + * + * [High Memory Address] __breakpoints_end__ + * Breakpoint 07 State + * Breakpoint 06 State + * ... + * Breakpoint 02 State + * Breakpoint 01 State + * Single Step State __debugger_stack__ / __breakpoints_start__ + * Previous Mode R15 + * Previous Mode R14 + * Previous Mode R13 + * ... + * User Mode R02 + * User Mode R01 + * User Mode R00 + * Previous Mode CPSR (UNDEF SPSR) + * UNDEF Next Instr Addr __debugger_stack_bottom__ + * [Low Memory Address] + * + * Each Breakpoint State will initially be zeroed. + * + */ + /* FIXME: The Debugger Stack Frame is probably not 100% consistent with the order that + GDB expects in the g/G messages. CSPR is probably located above R15 */ + +/**************************************************************************** + * + * GDB Debugger Init and Breakpoint Handler Routines + * + ****************************************************************************/ + .code 32 + .align 4 +/* dbg__bkpt_init + * 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 + mov r2, #0 + ldr r1, =debug_curr_breakpoint + strb r2, [r1] + ldr r0, =debug_InMsgBuf + strb r2, [r0] + ldr r1, =debug_OutMsgBuf + strb r2, [r1] + bl dbg__comm_init /* Pass R0: Rx Buffer, R1: Tx Buffer to comm submodule */ + +/* FIXME: Initialize other stuff here */ + _dbg_setstate DBG_INIT + _dbg_setmode FALSE /* Debug Mode = False */ + pop {lr} + bx lr /* Must return via BX; may have been called from Thumb mode (NXT Firmware) */ + + +/* _dbg__flush_icache + * Flush the Instruction cache + * Defined by GDB Stub, but not needed for ARMv4T architecture + */ +_dbg__flush_icache: + /* nop */ + bx lr + +/* _dbg__switch2undefmode + * Common internal routine to return execution to user program + */ +_dbg__switch2undefmode: + bl _dbg__flush_icache + msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Configure Undef Mode */ + _dbg_setmode FALSE /* Debug Mode = False */ + ldr lr, =resume_execution + mov pc, lr /* Exit via UNDEF mode */ + +/* 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 + +/* 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: +/* b dbg__bkpt_waitCMD */ + +dbg__bkpt_offset_outofrange: +/* b dbg__bkpt_waitCMD */ + + .global dbg__bkpt_waitCMD +/* dbg__bkpt_waitCMD + * GDB Stub Remote Command Handler + */ + +/**************************************************************************** + * + * GDB Server Command Processing Routines + * + ****************************************************************************/ +dbg__bkpt_waitCMD: + /* We enter this code section when a Breakpoint Triggers */ + _dbg_setmode TRUE /* Debug Mode = True */ + msr cpsr_c, #(MODE_ABT) /* Re-enable Interrupts */ + + _dbg_getstate r0 + cmp r0, #DBG_CONFIGURED + blo dbg__bkpt_waitCMD_cont /* Not configured yet, don't send Breakpoint Signal Response */ + bl _dbg__cmd_Status /* Send signal response to the GDB server */ + +dbg__bkpt_waitCMD_cont: + bl dbg__runloopTasks /* Execute housekeeping tasks while in ABRT mode */ + bl dbg__getDebugMsg /* Read new message from Debugger, buflen in R0, 0 if none, -1 if error, msgbuf pointer in R1 */ + cmp r0, #0 + beq dbg__bkpt_waitCMD_cont /* No message yet, do housekeeping tasks */ + bgt _proc_command /* valid message, process it */ + bl __dbg__procChecksumError /* Message invalid, checksum error? */ + b dbg__bkpt_waitCMD_cont + +_proc_command: +/* Message now has Ctrl-C or $\0 */ + mov r4, r1 /* Use R4 as buffer pointer */ + ldrb r0, [r4], #1 /* Look for Ctrl-C or '$' */ + teq r0, #MSGBUF_CTRLC + bne _dbg_check_gdb_command + /* Ctrl-C detected, do nothing (wait for next command from GDB) */ +#if 0 + /* On entering the Debugger via Ctrl-C, _dbg__cmd_Status has already sent a reply, so just keep quiet */ + bl __dbg__procAckOnly /* send Ack */ +#endif + b dbg__bkpt_waitCMD_cont + +_dbg_check_gdb_command: + teq r0, #MSGBUF_STARTCHAR + movne 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 */ + mov r1, #CMDINDEX_OUTOFRANGE + teq r0, r1 + bne _dbg__cmdExists /* Found valid command, execute it */ +_dbg_unknown_command: + bl _dbg__nop /* Command character not recognized, send empty response to GDB server */ + b dbg__bkpt_waitCMD_cont + +#if 0 + moveq r1, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */ + beq _dbg__cmdError /* Send response to GDB server */ +#endif + +_dbg__cmdExists: + mov r3, r0 /* put Command Handler Index in R3 */ + mov r0, r4 /* R0 now contains Input Message Buffer Parameter Pointer (previously in R4) */ + _dbg_jumpTableHandler debug_cmdJumpTable, r2, r3 /* Call Command Handler Routine, use R2 as jump address pointer */ + b dbg__bkpt_waitCMD_cont + +_dbg__cmdError: + _dbg_outputMsgStatusErr + bl dbg__putDebugMsg /* Send error response to the GDB server */ + b dbg__bkpt_waitCMD_cont + + +/* __dbg__procOkOnly + * Send OK to GDB due to Detach + * On entry: + * None + * On exit: + * r0-r3: destroyed + */ +__dbg__procOkOnly: + stmfd sp!, {lr} + _dbg_outputMsgStatusOk /* Acknowledge Detach command from GDB server */ +_cont_procOkOnly: + bl dbg__putDebugMsg /* Send OK response to the GDB server */ + cmp r0, #0 + beq _cont_procOkOnly_exit /* Sending of OK succeeded */ + bl dbg__runloopTasks /* Service run loop tasks */ + b _cont_procOkOnly /* Retry OK transmission */ +_cont_procOkOnly_exit: + ldmfd sp!, {pc} + + +/* __dbg__procAckOnly + * Send Ack to GDB due to Continue or Step + * On entry: + * None + * On exit: + * r0-r3: destroyed + */ +__dbg__procAckOnly: + stmfd sp!, {lr} + _dbg_outputAckOnlyFlag + b _cont_sendAckOrNak /* Acknowledge Continue or Step command from GDB server */ + +/* __dbg__procChecksumError + * Request Retransmission from GDB due to Checksum error + * On entry: + * None + * On exit: + * r0-r3: destroyed + */ +__dbg__procChecksumError: + stmfd sp!, {lr} + _dbg_outputRetransmitFlag + /* b _cont_sendAckOrNak */ /* Acknowledge Continue or Step command from GDB server */ + +_cont_sendAckOrNak: + bl dbg__sendAckOrNak /* send Ack or Nak to GDB server */ + cmp r0, #0 + beq _cont_sendAckOrNak_exit /* Sending of Ack or Nak succeeded */ + bl dbg__runloopTasks /* Service run loop tasks */ + b _cont_sendAckOrNak /* Retry Ack or Nak transmission */ +_cont_sendAckOrNak_exit: + ldmfd sp!, {pc} + +/* _dbg__cmdChar2Index + * Convert Command Character to Jump Table Index + * On entry: + * r0: command character + * On exit: + * r0: jump table index (-1 for command not found) + * R1: destroyed + * R2: destroyed + * R3: destroyed + */ +_dbg__cmdChar2Index: + mov r1, r0 /* Copy command character to r1 */ + mov r0, #0 /* Clear return value */ + ldr r3, =debug_cmdIndexTable /* Convert command to index using r3 as Index Lookup Address Pointer */ +1: ldrb r2, [r3, r0] /* Get table entry */ + teq r2, #0 + moveq r0, #CMDINDEX_OUTOFRANGE /* End of Index Table, Not found */ + beq _exit_cmdIndexTable + teq r1, r2 + addne r0, #1 /* Increment Index */ + bne 1b /* No match, skip to next command char */ +_exit_cmdIndexTable: + bx lr + +/* __dbg__cmdParamLen + * Determines the length of the parameter buffer for a given command + * On entry: + * R0: parameter buffer pointer (contents after '$' and '') + * On exit: + * R0: Address of parameter buffer (preserved) + * R1: length + */ +__dbg__cmdParamLen: + stmfd sp!, {r0,r2,lr} /* R2: scratch register */ + mov r1, #0 +1: ldrb r2, [r0], #1 + teq r2, #0 + addne r1, r1, #1 + bne 1b + ldmfd sp!, {r0,r2,pc} + +/* __dbg__procCmdOk + * Common subroutine exit stub to return Command Ok Status for Command Handlers + * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack. + * + */ +__dbg__procCmdOk: + _dbg_outputMsgStatusOk + b __dbg__sendDebugMsgExit + +/* __dbg__procUnimplementedError + * Common subroutine exit stub to handle Unimplemented GDB Command Error + * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack. + * Note: GDB Remote Protocol specifies returning blank message ('+$') + * + */ +__dbg__procUnimplementedError: + _dbg_outputMsgValidResponse + b __dbg__sendDebugMsgExit + +/* __dbg__procCmdParamError + * Common subroutine exit stub to handle Command Parameter Error for Command Handlers + * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack. + * + */ +__dbg__procCmdParamError: + mov r1, #MSG_UNKNOWNPARAM + b __dbg__procErrorMsg + +/* __dbg__procCmdReturnInputLengthError + * Common subroutine exit stub to handle Command Input Length Error for Command Handlers + * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack. + * + */ +__dbg__procCmdReturnInputLengthError: + mov r1, #MSG_ERRINLENGTH + b __dbg__procErrorMsg + +/* __dbg__procCmdReturnOutputLengthError + * Common subroutine exit stub to handle Command Return Output Error for Command Handlers + * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack. + * + */ +__dbg__procCmdReturnOutputLengthError: + mov r1, #MSG_ERROUTLENGTH + b __dbg__procErrorMsg + +/* __dbg__procBreakpointAddrError + * Common subroutine exit stub to handle Breakpoint Address Error for Breakpoint Insert/Remove Handlers + * DO NOT CALL THIS STUB DIRECTLY! It Assumes that the return address is in the stack. + * + */ +__dbg__procBreakpointAddrError: + mov r1, #MSG_UNKNOWNBRKPT +/* b __dbg__procErrorMsg */ + + +__dbg__procErrorMsg: + _dbg_outputMsgStatusErr + /* b __dbg__sendDebugMsgExit */ + +__dbg__sendDebugMsgExit: + bl dbg__putDebugMsg /* Send error response to the GDB server */ + ldmfd sp!, {pc} + +/* _dbg__cmd_Status + * Status Command Handler + * On entry: + * r0: parameter buffer (contents after '$' and '') + * On exit: + * r0, r1, r2, r3: destroyed + */ +_dbg__cmd_Status: + stmfd sp!, {lr} + _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 + * Query Command Handler + * On entry: + * r0: parameter buffer (contents after '$' and '') + * [varied, see GDB General Packets query docs] + * http://sourceware.org/gdb/current/onlinedocs/gdb/General-Query-Packets.html + * On exit: + * r0, r1, r2, r3: destroyed + */ +_dbg__cmd_Query: + stmfd sp!, {r0,r1, lr} + _dbg_setstate DBG_CONFIGURED /* We have exchanged query messages with the GDB server */ + 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 + * Get One Register Value Command Handler + * Valid command parameter x is from '0' to 'F' for User Mode Registers R0-R15, + * '18' for FPSCR (dummy), and '19' for CPSR + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * x + * On exit: + * r0, r1, r2, r3, r4: destroyed + * + */ +_dbg__cmd_GetOneReg: + stmfd sp!, {lr} + bl __dbg__cmdParamLen + cmp r1, #CMD_REG_GETONE_MINPARAMLEN /* Check for correct length */ + blo __dbg__procCmdParamError /* Unexpected input, report error */ + cmp r1, #CMD_REG_GETONE_MAXPARAMLEN /* Check for correct length */ + bhi __dbg__procCmdParamError /* Unexpected input, report error */ + bl ascii2hex_varlen_be /* convert ASCII reg enum to Hex (in R0), R1 has address of next buffer char */ + +_dbg__proc_getRegister: + mov r4, r0 /* Keep register index safe */ + _dbg_outputMsgValidResponse /* R0: address of output message buffer data pointer (after response prefix) */ + 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 */ + ldmfd sp!, {pc} + +/* _dbg_outputOneRegValue + * Given Register Enum (0-F: R0-R15, 0x19: CPSR, OtherVal: dummy), output hex char to buffer + * On entry: + * r0: output message buffer pointer + * r1: register enum (0-F, 0x19) + * On exit: + * r0: updated (points to next character slot at end of Output Buffer) + * r1: original output message buffer pointer + * r2: destroyed + */ +_dbg_outputOneRegValue: + stmfd sp!, {lr} + cmp r1, #REG_PC + addls r2, r1, #DBGSTACK_USERREG_INDEX /* Convert register enum to Debug Stack index */ + bls _retrieve_RegVal + + cmp r1, #REG_CPSR + moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */ + beq _retrieve_RegVal + + 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_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 F0-F7, FPSCR */ + +_retrieve_RegVal: + _getdbgregisterfromindex r2, r1 /* Retrieve Register contents into R1 */ + +_output2buffer: + +#ifdef __BIG_ENDIAN__ + bl word2ascii_be /* Convert and put hex chars into Output Message Buffer */ +#else + bl word2ascii_le /* Convert and put hex chars into Output Message Buffer */ +#endif + +_exit_dbg_outputOneRegValue: + ldmfd sp!, {pc} + +/* _dbg__cmd_GetAllRegs + * Get All Register Values Command Handler + * Output Buffer returns register values in the order: User R0, R1, R2, ..., R15 + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * (no parameters) + * On exit: + * r0, r1, r2, r3: destroyed + */ +_dbg__cmd_GetAllRegs: + stmfd sp!, {lr} + bl __dbg__cmdParamLen + teq r1, #CMD_REG_GETALL_PARAMLEN /* Check for correct length */ + bne __dbg__procCmdParamError /* Unexpected input, report error */ + + _dbg_outputMsgValidResponse /* R0: address of output message buffer data pointer (after response prefix) */ + + /* We must return R0-R15, then CPSR */ + mov r3, #REG_R0 /* Output User Register Values first */ +1: mov r1, r3 + bl _dbg_outputOneRegValue /* update output buffer */ + add r3, r3, #1 /* increment index */ + cmp r3, #REG_PC + bls 1b /* process all the registers */ +#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} + +/* _dbg_setOneRegValue + * Given Register Enum (0-F: R0-R15, 0x19: CPSR, OtherVal: dummy), output hex char to buffer + * On entry: + * r0: parameter buffer pointer + * r1: register enum (0-F, 0x19) + * On exit: + * r0: (Updated) Address of parameter in buffer + * r1, r2, r3: destroyed + * + * FIXME: This routine assumes that the input buffer contains exactly 8-Hex digits for each register value. + */ +_dbg_setOneRegValue: + stmfd sp!, {lr} + cmp r1, #REG_PC + addls r2, r1, #DBGSTACK_USERREG_INDEX /* Convert register enum to Debug Stack index */ + bls _store_RegVal + + cmp r1, #REG_CPSR + moveq r2, #DBGSTACK_USERCPSR_INDEX /* convert register enum to Debug Stack index */ + beq _store_RegVal + + bhi _exit_dbg_setOneRegValue /* No match (reg enum > REG_CPSR), skip */ + +#if 0 + cmp r1, #REG_FPSCR + bne _exit_dbg_setOneRegValue /* No match, skip */ +#endif + +_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 + +_store_RegVal: +#ifdef __BIG_ENDIAN__ + bl ascii2word_be +#else + bl ascii2word_le +#endif + /* R0: value, R1: pointer to next char in buffer */ + _setdbgregisterfromindex r2, r0, r3 /* Set Register contents in R0, using index in R2, and scratch register R3 */ +_done_store_RegVal: + mov r0, r1 /* Copy buffer pointer to next parameter to R0 for return value */ +_exit_dbg_setOneRegValue: + ldmfd sp!, {pc} + + +/* _dbg__cmd_SetOneReg + * Set One Register Value Command Handler + * Valid command parameter x is from '0' to 'F' for User Mode Registers R0-R15, + * '18' for FPSCR (dummy), and '19' for CPSR + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * x=rrrr + * On exit: + * r0, r1, r2, r3, r4: destroyed + * + */ +_dbg__cmd_SetOneReg: + stmfd sp!, {lr} + bl __dbg__cmdParamLen + cmp r1, #CMD_REG_SETONE_MINPARAMLEN /* Check for correct length */ + blo __dbg__procCmdParamError /* Unexpected input, report error */ + cmp r1, #CMD_REG_SETONE_MAXPARAMLEN /* Check for correct length */ + bhi __dbg__procCmdParamError /* Unexpected input, report error */ + + /* 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 '=' */ + +_dbg__proc_setRegister: + mov r0, r1 /* move parameter buffer pointer to R0 */ + mov r1, r4 /* and retrieve enum to R1 to call _dbg_setOneRegValue */ + bl _dbg_setOneRegValue + b __dbg__procCmdOk + +/* _dbg__cmd_SetAllReg + * Set All Register Values Command Handler + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * rrrrRRRRrrrr... (17 registers) + * On exit: + * r0, r1, r2, r3, r4: destroyed + * + */ +_dbg__cmd_SetAllRegs: + /* Assumes that the registers are in the sequence R0, R1, ... R15 */ + stmfd sp!, {lr} + bl __dbg__cmdParamLen /* R0: pointer to parameters in buffer */ + teq r1, #CMD_REG_SETALL_PARAMLEN /* Check for correct length */ + bne __dbg__procCmdParamError /* Unexpected input, report error */ + mov r4, #REG_R0 /* R4: register enum, starting with enum for R0 */ +1: mov r1, r4 /* Copy enum to R1; R0 already points to current parameter */ + bl _dbg_setOneRegValue /* R0: next parameter address pointer */ + add r4, r4, #1 /* increment index */ + cmp r4, #REG_PC + bls 1b + + ldrb r0, [r0] + teq r0, #0 /* Look for ASCIIZ character to terminate loop */ + beq __dbg__procCmdOk + bne __dbg__procCmdParamError /* Unexpected input, report error */ + +/* _dbg__nop + * NOP Command Handler (placeholder) + * On entry: + * r0: parameter buffer (contents after '$' and '') + * On exit: + * r0, r1, r2, r3: destroyed + */ +_dbg__nop: + stmfd sp!, {lr} + b __dbg__procUnimplementedError + +/* _dbg__cmd_ReadMem + * Read Memory Contents Command Handler + * Output Buffer returns memory contents + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * AA..AA,LLLL + * On exit: + * r0, r1, r2, r3, r4, r5: destroyed + */ +_dbg__cmd_ReadMem: + stmfd sp!, {lr} + bl __dbg__cmdParamLen +#if 0 + teq r1, #CMD_MEM_READ_PARAMLEN /* Check for correct length */ + bne __dbg__procCmdParamError /* Unexpected input, report error */ + bl ascii2word_be /* convert ASCII address location to Hex (in R0), R1 has address of next buffer char */ +#endif + bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */ + mov 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 */ + bl ascii2hex_varlen_be /* convert ASCII length to Hex (in R0), R1 has address of next buffer char */ + cmp r0, #CMD_MEM_MAXREADBYTES /* Don't overflow our buffer (2 x CMD_MEM_MAXREADBYTES) */ + bhi __dbg__procCmdReturnOutputLengthError /* Requested Length greater than buffer size, return error */ + mov r4, r0 /* Keep numbytes in R4 */ + /* FIXME: Should validate the address? */ + + _dbg_outputMsgValidResponse /* R0: address of output message buffer data pointer (after response prefix) */ +1: ldrb r1, [r5], #1 + bl byte2ascii /* update output buffer */ + subs r4, r4, #1 + bne 1b + + _asciiz r0, r1 + bl dbg__putDebugMsg /* Send response to the GDB server */ + ldmfd sp!, {pc} + + +/* _dbg__cmd_WriteMem + * Write Memory Contents Command Handler + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * AA..AA,LLLL::bb..bb + * On exit: + * r0, r1, r2, r3, r4: destroyed + */ +_dbg__cmd_WriteMem: + stmfd sp!, {lr} + bl __dbg__cmdParamLen +#if 0 + cmp r1, #CMD_MEM_WRITE_MINPARAMLEN /* Check for correct (minimum) length */ + blo __dbg__procCmdParamError /* Unexpected input, report error */ + sub r4, r1, #CMD_MEM_WRITE_MINPARAMLEN /* R4: Number of ASCII Hex chars for byte writes */ + bl ascii2word_be /* convert ASCII address location to Hex (in R0), R1 has address of next buffer char */ +#endif + bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */ + mov r3, r0 /* Keep Address location in R3 */ + _check_msgseparator r1 + bne __dbg__procCmdParamError /* Can't find ',' */ + mov r0, r1 /* move buffer pointer to R0 for subsequent processing */ + bl ascii2hex_varlen_be /* convert ASCII length to Hex (in R0), R1 has address of next buffer char */ + cmp r0, r4, asr #1 /* is Number of bytes to write == (number of ASCII Hex Chars / 2)? */ + bne __dbg__procCmdParamError /* Number of bytes does not match argument length */ + cmp r0, #CMD_MEM_MAXWRITEBYTES /* Don't overflow our buffer (2 x CMD_MEM_MAXWRITEBYTES) */ + bhi __dbg__procCmdReturnInputLengthError /* Requested Length greater than buffer size, return error */ + mov r4, r0 /* Keep numbytes in R4 */ + /* FIXME: Should validate the address? */ + _check_msgargument r1 + bne __dbg__procCmdParamError /* Can't find ':' */ + +1: mov r0, r1 + bl ascii2byte /* convert ASCII Hex value into byte value */ + strb r0, [r3], #1 /* Store into memory location */ + subs r4, r4, #1 + bne 1b + b __dbg__procCmdOk + +/* _dbg__cmd_Detach + * Detach User Program Execution Command Handler + * Treat this as being equivalent to 'Continue' without any arguments + * + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * (No Parameters) + * On exit: + * r0-r7: destroyed + * Note: This routine does not return to caller. Instead it switches + * operating mode to UNDEF and returns to previously active program + */ +_dbg__cmd_Detach: + stmfd sp!, {lr} /* In case unexpected parameters were received */ + bl __dbg__cmdParamLen + teq r1, #CMD_DETACH_PARAMLEN /* Check for correct length */ + bne __dbg__procCmdParamError /* Unexpected input, report error */ + + ldmfd sp!, {lr} /* Cleanup stack, since we won't return to the Debugger Run Loop */ + _dbg_setstate DBG_INIT /* Reset the Debug State */ + bl __dbg__procOkOnly /* send OK to keep GDB server happy */ + b _dbg__cont_check_breakpoint_type /* Continue from current PC */ + +/* _dbg__cmd_Continue + * Continue User Program Execution Command Handler + * Setup breakpoints before resuming execution of program. + * + * If Address is specified, update the next instruction address to specified address + * + * If this is a Normal Breakpoint, then we resume from current (Breakpoint) exception address + * Else (it is a Manual Breakpoint or Address Specified) + * We need to resume from the next instruction address + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * Optional: AA..AA + * On exit: + * r0-r7: destroyed + * Note: This routine does not return to caller. Instead it switches + * operating mode to UNDEF and returns to previously active program + */ +_dbg__cmd_Continue: + /* Don't put anything on the stack, we won't return to the Debugger Run Loop */ + bl __dbg__cmdParamLen + cmp r1, #CMD_CONTINUE_MINPARAMLEN /* Check for correct parameter length */ + bne _dbg__cont_fromAddr /* Address is specified */ + bl __dbg__procAckOnly /* send Ack to keep GDB server happy */ + b _dbg__cont_check_breakpoint_type /* Continue from current PC */ + +_dbg__cont_fromAddr: + bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */ + /* Continue from Specified Address */ + _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 + +_dbg__cont_check_breakpoint_type: + _dbg_get_bkpt_type r0 + teq r0, #DBG_MANUAL_BKPT_ARM + beq _dbg__cont_is_manual_bkpt_or_address_specified + teq r0, #DBG_MANUAL_BKPT_THUMB + beq _dbg__cont_is_manual_bkpt_or_address_specified + +_dbg__cont_is_normal_breakpoint: + _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 + +/* _dbg__cmd_Step + * Step User Program Execution Command Handler + * Setup breakpoints before resuming execution of program. + * + * If Address is specified, update the next instruction address to specified address + * + * If this is a Normal Breakpoint, then we need to install a Step Breakpoint at next instruction address + * and resume from current (Breakpoint) exception address + * Else (it is a Manual Breakpoint or Address specified) + * We need to install a Step Breakpoint at the following instruction address (after the next instruction address) + * and resume from the next instruction address + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * Optional: AA..AA + * On exit: + * r0-r7: destroyed + * Note: This routine does not return to caller. Instead it switches + * operating mode to UNDEF and returns to previously active program + */ +_dbg__cmd_Step: + /* Don't put anything on the stack, we won't return to the Debugger Run Loop */ + bl __dbg__cmdParamLen + cmp r1, #CMD_STEP_MINPARAMLEN /* Check for correct parameter length */ + beq _dbg__step_check_breakpoint_type /* Step from current PC */ + +_dbg__step_fromAddr: + bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */ + /* Step from Specified Address */ + _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: + _dbg_get_bkpt_type r0 + teq r0, #DBG_MANUAL_BKPT_ARM + beq _dbg__step_is_manual_bkpt + teq r0, #DBG_MANUAL_BKPT_THUMB + beq _dbg__step_is_manual_bkpt + +_dbg__step_is_normal_breakpoint: + _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: + _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__activate_singlestep +#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 + * Kill User Program Execution Command Handler + * Kill Program, this is accomplished by rebooting the Brick + * + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * (No Parameters) + * On exit: + * r0-r7: destroyed + * Note: This routine does not return to caller. Instead it calls + * the relevant system routine to reboot the Brick + */ +_dbg__cmd_Kill: + stmfd sp!, {lr} /* In case unexpected parameters were received */ + bl __dbg__cmdParamLen + teq r1, #CMD_KILL_PARAMLEN /* Check for correct length */ + bne __dbg__procCmdParamError /* Unexpected input, report error */ + + bl __dbg__procAckOnly /* send Ack to keep GDB server happy */ + b dbg__reboot /* Goodbye.... */ + +/* _dbg__proc_brkpt_params + * Process Breakpoint Parameters + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * t,AA..AA,k + * On exit: + * r0: non-zero = breakpoint address; 0 = parameter error + * r1: destroyed + * r2: destroyed + * r3: destroyed + */ +_dbg__proc_brkpt_params: + /* FIXME: Add support for watchpoints */ + stmfd sp!, {lr} + mov r3, r0 /* Keep parameter buffer address in R3 */ + ldrb r0, [r3], #1 /* get breakpoint type t */ + bl char2hex + cmp r0, #CMD_BKPT_TYPE_BREAK_MEMORY + bne _dbg__proc_brkpt_params_error /* We only support memory breakpoints for now */ + _check_msgseparator r3 + bne _dbg__proc_brkpt_params_error /* Something wrong with the parameters */ + mov r0, r3 /* Check Address */ + bl ascii2hex_varlen_be /* convert ASCII address to Hex (in R0), R1 has address of next buffer char */ + mov r3, r0 /* Keep breakpoint address in R3 */ + _check_msgseparator r1 + bne _dbg__proc_brkpt_params_error /* Something wrong with the parameters */ + ldrb r0, [r1], #1 /* get breakpoint kind k */ + bl char2hex + cmp r0, #CMD_BKPT_KIND_THUMB + orreq r3, r3, #1 /* Mark Thumb breakpoints */ + beq _exit_dbg__proc_brkpt_params + cmp r0, #CMD_BKPT_KIND_ARM + beq _exit_dbg__proc_brkpt_params /* ARM breakpoint */ + +_dbg__proc_brkpt_params_error: + mov r3, #0 /* Unrecognized breakpoint type */ +_exit_dbg__proc_brkpt_params: + mov r0, r3 /* return breakpoint address */ + ldmfd sp!, {pc} + +/* _dbg__cmd_InsertBreakpoint + * Add Breakpoint + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * t,AA..AA,k + * On exit: + * r0, r1, r2, r3: destroyed + */ +_dbg__cmd_InsertBreakpoint: + stmfd sp!, {lr} + bl __dbg__cmdParamLen + teq r1, #CMD_BKPT_INSERT_MINPARAMLEN /* Check for correct length */ + blo __dbg__procCmdParamError /* Unexpected input, report error */ + bl _dbg__proc_brkpt_params /* R0: Breakpoint Address */ + teq r0, #0 + beq __dbg__procBreakpointAddrError /* Thumb2 instructions, or unknown kind */ + mov r3, r0 /* Keep breakpoint address in R3 */ + mov r0, #0 /* Empty Breakpoint entry */ + bl _dbg_find_breakpoint_slot /* Look for an available breakpoint slot, return index in R0 */ + cmp r0, #CMD_BKPT_NOTFOUND + beq __dbg__procBreakpointAddrError /* No empty slot! */ + mov r1, r3 /* Move breakpoint address to R1 */ + bl _dbg__install_one_breakpoint /* r0: index, r1: instruction address */ + b __dbg__procCmdOk + +/* _dbg__cmd_RemoveBreakpoint + * Remove Breakpoint + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * t,AA..AA,k + * On exit: + * r0, r1, r2, r3: destroyed + */ +_dbg__cmd_RemoveBreakpoint: + stmfd sp!, {lr} + bl __dbg__cmdParamLen + teq r1, #CMD_BKPT_REMOVE_MINPARAMLEN /* Check for correct length */ + blo __dbg__procCmdParamError /* Unexpected input, report error */ + bl _dbg__proc_brkpt_params /* R0: Breakpoint Address */ + teq r0, #0 + beq __dbg__procBreakpointAddrError /* Thumb2 instructions, or unknown kind */ + bl _dbg_find_breakpoint_slot /* Look for matching breakpoint slot, return index in R0 */ + cmp r0, #CMD_BKPT_NOTFOUND + beq __dbg__procBreakpointAddrError /* Specified Breakpoint not found! */ + _index2bkptindex_addr r0, r1 /* Calculate Breakpoint Entry Address */ + mov r0, r1 /* Move it to R0 for subroutine call */ + bl _dbg__clear_one_breakpoint /* R0: address of breakpoint to clear */ + b __dbg__procCmdOk + +/**************************************************************************** + * + * Breakpoint Manipulation Routines + * + ****************************************************************************/ +/* _dbg_find_breakpoint_slot + * Find the matching Breakpoint Slot. + * This is both used to find empty slots (pass R0=0x0000) or + * occupied slots (pass R0=) + * + * On Entry: + * R0: Breakpoint Address + * On Exit: + * R0: Matching Index (-1: not found) + * + * NOTE: This routine performs exact match, i.e., breakpoint address MUST be configured + * for ARM or Thumb (bit 0 clear/set) as appropriate + */ + +_dbg_find_breakpoint_slot: + stmfd sp!, {r1,r2,r3, lr} + mov r1, #1 /* Only consider Breakpoints 1-7 */ + ldr r3, =__breakpoints_num__ +1: + _index2bkptindex_addr r1, r2 /* Calculate Breakpoint Entry Address */ + ldr r2, [r2] /* Get actual breakpoint entry (instruction address) */ + cmp r0, r2 + beq _found_breakpoint_slot + add r1, r1, #1 /* no match, check next */ + cmp r1, r3 + blo 1b /* continue checking only if we don't exceed __breakpoints_num__ */ + +_notfound_breakpoint_slot: + mov r1, #CMD_BKPT_NOTFOUND +_found_breakpoint_slot: + mov r0, r1 /* Return value in R0 */ + ldmfd sp!, {r1,r2,r3, pc} + +/* _dbg__clear_singlestep + * Clear the Single Step Breakpoint + */ +_dbg__clear_singlestep: + ldr r0, =__breakpoints_start__ /* Single Step Breakpoint is at the beginning of the Breakpoint State Struct */ +/* b _dbg__clear_one_breakpoint */ + +/* _dbg__clear_one_breakpoint + * On entry, R0 contains the Breakpoint State slot address to be cleared + * + */ +_dbg__clear_one_breakpoint: + mov r1, #0 + mov r2, #0 + stmea r0!, {r1, r2} /* clear Breakpoint state */ + bx lr + +/* _dbg__clear_breakpoints + * Routine iterates through the array of breakpoints (incl single step breakpoint) and clears the breakpoint + */ +_dbg__clear_breakpoints: + stmfd sp!, {lr} + ldr r0, =__breakpoints_start__ /* Single Step Breakpoint is at the beginning of the Breakpoint State Struct */ + ldr r3, =__breakpoints_end__ /* start from top of the table */ +3: bl _dbg__clear_one_breakpoint + cmp r0, r3 + blo 3b + ldmfd sp!, {pc} + + .global dbg__install_singlestep +/* dbg__install_singlestep + * Install the Single Step Breakpoint + * + * On entry: + * R1: Instruction Address (31 bits, b0 = THUMB flag) + * On exit: + * R0: Breakpoint index (preserved) + * R1: Instruction Address (preserved) + * R2: Breakpoint Instruction + * R3: Breakpoint Entry address + */ +dbg__install_singlestep: + mov r0, #0 +/* b _dbg__install_one_breakpoint */ + +/* _dbg__install_one_breakpoint + * Install breakpoint entry into Breakpoint State Table + * + * On entry: + * R0: Breakpoint index (assumed valid) + * R1: Instruction Address (31 bits, b0 = THUMB flag) + * On exit: + * R0: Breakpoint index (preserved) + * R1: Instruction Address (preserved) + * R2: Breakpoint Instruction + * R3: Breakpoint Entry address + */ +_dbg__install_one_breakpoint: +/* Check for Thumb bit */ + tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ +/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ + 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 + + +/* _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 */ + _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */ + ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 + bxeq lr /* Exit if not active */ +/* b _dbg__restore_one_breakpoint */ + +/* _dbg__restore_one_breakpoint + * Restores the contents to memory for one breakpoint + * + * On entry: + * R0: Breakpoint index (assumed valid) [not used -- can be used for validating BKPT] + * R1: Breakpoint Address (assumed valid) + * R2: Breakpoint Instruction (assumed valid) + * 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 */ + tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ +/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ + streq r2, [r1] /* if 0: restore ARM instruction to address location */ + bicne r1, #BKPT_STATE_THUMB_FLAG /* else, clear Thumb Flag */ + strneh r2, [r1] /* store Thumb instruction */ + bx lr + +/* _dbg__restore_breakpoints + * Routine iterates through the array of breakpoints (incl single step breakpoint) and restores the contents to memory + * Only Active breakpoints (i.e., Non-zero Address) are processed. + * + * On entry: + * None + * On exit: + * R0-R6: Destroyed + */ +_dbg__restore_breakpoints: + stmfd sp!, {lr} + 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 */ + _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */ + ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 + bxeq lr /* Exit if not active */ +/* b _dbg__activate_one_breakpoint */ + +/* _dbg__activate_one_breakpoint + * Activate one breakpoint to memory + * + * On entry: + * R0: Breakpoint index (assumed valid) + * R1: Breakpoint Address (assumed valid) + * R2: Breakpoint Instruction (assumed valid) + * On exit: + * R0: Breakpoint index (preserved) + * R1-R3: Destroyed + */ +_dbg__activate_one_breakpoint: +/* Check for Thumb bit */ + tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ + bne _nx_is_thumb_bp +_nx_is_arm_bp: +/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ + ldr r3, [r1] /* if 0: load ARM instruction from address location */ + teq r2, r3 /* check that the two instructions are identical */ + bne _dbg__breakpoint_invalid_arm + ldr r2, =BKPT32_INSTR /* ARM BKPT instruction */ + orr r2, r2, r0 /* Merge Breakpoint index */ + str r2, [r1] /* Store it into memory location */ +_dbg__breakpoint_invalid_arm: + bx lr +_nx_is_thumb_bp: + bic r1, #BKPT_STATE_THUMB_FLAG /* else, clear Thumb Flag */ + ldrh r3, [r1] /* load Thumb instruction from address location */ + teq r2, r3 /* check that the two instructions are identical */ + bne _dbg__breakpoint_invalid_thumb + ldr r2, =BKPT16_INSTR /* Thumb BKPT instruction */ + orr r2, r2, r0 /* Merge Breakpoint index */ + strh r2, [r1] /* Store it into memory location */ +_dbg__breakpoint_invalid_thumb: + bx lr + +/* _dbg__activate_breakpoints + * Routine iterates through the array of breakpoints (incl single step breakpoint) and activates them + * Only Active breakpoints (i.e., Non-zero Address) are processed. + * + * On entry: + * None + * On exit: + * R0-R6: Destroyed + */ +_dbg__activate_breakpoints: + stmfd sp!, {lr} + ldr r6, =_dbg__activate_one_breakpoint + b __dbg__iterate_breakpoint_array + + +/* __dbg__iterate_breakpoint_array + * 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) + * + */ +__dbg__iterate_breakpoint_array: + 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 r5!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 /* Is it active? */ + movne lr, pc + bxne r6 /* active entry */ + cmp r5, r4 + bhi 4b /* if (pointer > start of Breakpoint Table address), get next slot */ + ldmfd sp!, {pc} + diff --git a/AT91SAM7S256/armdebug/Debugger/debug_stub.h b/AT91SAM7S256/armdebug/Debugger/debug_stub.h new file mode 100644 index 0000000..6807ac1 --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_stub.h @@ -0,0 +1,151 @@ +/** @file debug_stub.h + * @brief Shared C/ASM header file for debugger stub + * + */ + +/* Copyright (C) 2007-2010 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + +#ifndef __DEBUG_STUB_H__ +#define __DEBUG_STUB_H__ + +#include "_c_arm_macros.h" + +/** @name BKPT suppport constants + * + * ARM and Thumb Breakpoint Instructions. + */ +/*@{*/ + +#define __ARM6OR7__ + +#ifdef __ARM6OR7__ +#define BKPT32_INSTR 0xE7200070 /* ARM6 and ARM7 does not trap unused opcodes (BKPT overlap with control instructions), \ + CPU has unpredictable behavior. Ref: Steve Furber, ARM SoC Architecture 2nd Ed, pg. 143 */ +#else +#define BKPT32_INSTR 0xE1200070 /* ARM BKPT instruction, will work in ARMv5T and above */ +#endif + +#define BKPT32_ENUM_MASK 0x000FFF0F /* ARM BKPT Enum Mask */ +#define BKPT32_AUTO_BKPT 0x00080000 /* 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 /* RESERVED: Thumb BKPT Auto-Step Flag (for CONT support) */ +#define BKPT16_MANUAL_BKPT 0x007F /* Manually inserted Thumb Breakpoint */ +/*@}*/ + +#ifndef __ASSEMBLY__ + +/* Define C stuff */ +/** @defgroup debug_public */ +/*@{*/ + + +/** Initialize Debugger. + * Equivalent to GDB set_debug_traps() routine + */ +FUNCDEF void dbg__bkpt_init(void); + +#ifdef __NXOS__ + +/** Communication Channel Enums + * + * Communication Channel Enums. + */ +ENUM_BEGIN +ENUM_VALASSIGN(COMM_USB, 1) /**< USB Communications */ +ENUM_VAL(COMM_BT) /**< Bluetooth Communications */ +ENUM_END(comm_chan_t) + +/** Enable switch to Debugger Mode from NxOS operational mode + * Returns 0 if no mode switch needed (already in Debug mode) + * !0 if mode switch will happen + * Used by NxOS only + */ +/* Note: This platform specific routine is found in debug_runlooptasks.S */ +FUNCDEF int nxos__handleDebug(U8 *buffer, comm_chan_t channel, U32 length); +#else +/** Switch Mode to Debugger. + * Used by NXT Firmware only + */ +/* Note: This platform specific routine is found in debug_runlooptasks.S */ +FUNCDEF UWORD cCommHandleDebug(UBYTE *pInBuf, UBYTE CmdBit, UWORD MsgLength); +#endif + +/** Debugger Handler Routine (called by Exception Handler Trap). + * Equivalent to GDB handle_exception() routine + */ +FUNCDEF void dbg__bkpt_handler(void); + +/** dbg_breakpoint_arm. + * Equivalent to GDB breakpoint() routine for ARM code + */ +/* FUNCDEF void dbg_breakpoint_arm(void); */ +static inline void dbg_breakpoint_arm(void) +{ + asm volatile (".word %a0" + : /* Output (empty) */ + : "X" (BKPT32_INSTR | BKPT32_MANUAL_BKPT) + ); +} + +#if 0 /* Old asm definitions, in case gas does not recognize %a0 operand */ + +#ifdef __ARM6OR7__ +static inline void dbg_breakpoint_arm(void) { asm volatile (".word 0xE727FF7F" /* (BKPT32_INSTR | BKPT32_MANUAL_BKPT) */ ); } +#else +static inline void dbg_breakpoint_arm(void) { asm volatile (".word 0xE127FF7F" /* (BKPT32_INSTR | BKPT32_MANUAL_BKPT) */ ); } +#endif + +#endif + +/** dbg_breakpoint_thumb. + * Equivalent to GDB breakpoint() routine for Thumb code + */ +/* FUNCDEF void dbg_breakpoint_thumb(void); */ +static inline void dbg_breakpoint_thumb(void) +{ + asm volatile (".hword %a0" + : /* Output (empty) */ + : "X" (BKPT16_INSTR | BKPT16_MANUAL_BKPT) + ); +} + +#if 0 /* Old asm definitions, in case gas does not recognize %a0 operand */ + +static inline void dbg_breakpoint_thumb(void) { asm volatile (".hword 0xBE7F" /* (BKPT16_INSTR | BKPT16_MANUAL_BKPT) */); } + +#endif + +/*@}*/ + +#else +/* Define Assembly stuff */ + +/* dbg__bkpt_arm + * GDB breakpoint() for ARM mode + */ + .macro dbg__bkpt_arm + .word (BKPT32_INSTR | BKPT32_MANUAL_BKPT) + .endm + +/* dbg__bkpt_thumb + * GDB breakpoint() for Thumb mode + */ + .macro dbg__bkpt_thumb + .hword (BKPT16_INSTR | BKPT16_MANUAL_BKPT) + .endm + +#endif + /*@}*/ + +#endif /* __DEBUG_STUB_H__ */ diff --git a/AT91SAM7S256/armdebug/Debugger/debug_test.S b/AT91SAM7S256/armdebug/Debugger/debug_test.S new file mode 100644 index 0000000..7f8c85f --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_test.S @@ -0,0 +1,160 @@ +/** @file debug_test.S + * @brief Test Routines to trigger ARM and Thumb Manual Breakpoints + * + */ + +/* Copyright (C) 2007-2011 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ +#define __ASSEMBLY__ +#include "debug_stub.h" + +.text +.align 4 +.code 32 + +/********************************************** + * dbg__test_arm_bkpt Test Routine + * + */ + .global dbg__test_arm_bkpt +dbg__test_arm_bkpt: + stmfd sp!,{lr} + dbg__bkpt_arm /* Trigger ARM Manual Breakpoint */ + ldmfd sp!,{pc} + + +/********************************************** + * dbg__test_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 + * + */ + .global dbg__test_thumb_bkpt +dbg__test_thumb_bkpt: + stmfd sp!,{lr} +/* ldr r0, =_thumb_entry + orr r0, r0, #1 @ Set Thumb mode + mov lr, pc + bx r0 +*/ + bl _thumb_entry + ldmfd sp!,{pc} + +.code 16 +.thumb_func +_thumb_entry: + dbg__bkpt_thumb + bx lr + + +/********************************************** + * 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 new file mode 100644 index 0000000..1c004e7 --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/debug_test.h @@ -0,0 +1,38 @@ +/** @file debug_test.h + * @brief C header file for debugger test routines + * + */ + +/* Copyright (C) 2007-2010 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * See COPYING for redistribution license + * + */ + +#ifndef __DEBUG_TEST_H__ +#define __DEBUG_TEST_H__ + +#include "_c_arm_macros.h" + +#ifndef __ASSEMBLY__ + +/* Define C stuff */ +/** @defgroup debug_public */ +/*@{*/ + +FUNCDEF void dbg__test_arm_bkpt(void); +FUNCDEF void dbg__test_thumb_bkpt(void); + +FUNCDEF void dbg__test_arm_instrstep(void); +FUNCDEF void dbg__test_thumb_instrstep(void); + + /*@}*/ + +#endif + + +#endif /* __DEBUG_TEST_H__ */ diff --git a/AT91SAM7S256/armdebug/Debugger/undef_handler.S b/AT91SAM7S256/armdebug/Debugger/undef_handler.S new file mode 100644 index 0000000..412fd18 --- /dev/null +++ b/AT91SAM7S256/armdebug/Debugger/undef_handler.S @@ -0,0 +1,147 @@ + +/* Copyright (C) 2007-2010 the NxOS developers + * + * Module Developed by: TC Wan + * + * See AUTHORS for a full list of the developers. + * + * Redistribution of this file is permitted under + * the terms of the GNU Public License (GPL) version 2. + */ +#define __ASSEMBLY__ +#include "debug_stub.h" +#include "debug_internals.h" + + +.text +.code 32 +.align 0 + + .extern dbg__thumb_bkpt_handler + .extern dbg__arm_bkpt_handler + .extern default_undef_handler + + .global undef_handler + +undef_handler: +/* Remote GDB Debugger relies on BKPT instruction being trapped here + * In ARMv4t, it is an Illegal (Undefined) Instruction. + * On triggering, lr (R14) contains the previous mode's pc (R15). + * Based on example in Hohl, "ARM Assembly Language: Fundamentals and Techniques" + * Chapter 11, Example 11.1. + */ + /* 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. + * + * We will also store UNDEF LR (next instruction pointer) and UNDEF SPSR to the stack. + * + * For the handler, once the user registers have been stored in the DEBUG stack, the + * registers will be used as follows: + * + * R0: UNDEF LR, then UNDEF instruction address, finally UNDEF instruction word / BKPT index + * R1: SPSR + * R2: Mode + * R3: Debug Stack Pointer (for Banked R13-R14 update) + */ + ldr sp, =__debugger_stack__ + stmfd sp, {r0-r15}^ /* Save workspace, previous mode's pc via 'S' flag, R13-R15: placeholders */ + mov r3, sp /* Use R3 to write Banked R13-R14, and actual PC of UNDEF instruction */ + sub sp, sp, #(4*16) /* Need to manually update SP(undef) */ + + mov r0, lr /* Keep Next Instruction address after UNDEF instruction in R0 */ + mrs r1, spsr /* Copy SPSR to r1 */ + stmfd sp!, {r0,r1} /* Save User's Next Instr Pointer (in UNDEF LR) and previous mode's CPSR to stack */ + + tst r1, #CPSR_THUMB /* Check for Thumb Mode */ + subne r0, r0, #2 /* Is Thumb instruction, adjust PC for UNDEF instruction address */ + subeq r0, r0, #4 /* Is ARM instruction, adjust PC for UNDEF instruction address */ + str r0, [r3, #-4]! /* Save PC to stack (R15 slot) */ + + and r2, r1, #CPSR_MODE /* Get previous mode */ + teq r2, #MODE_USR + beq _skip_banked_registers /* Can't switch back if we're in User mode! */ + +_store_prev_mode_banked_regs: + /* FIXME: We don't handle FIQ properly! */ + + orr r2, #(CPSR_FIQ | CPSR_IRQ) /* Disable Interrupts */ + msr cpsr_c, r2 /* Switch to previous mode */ + stmfd r3!, {sp, lr} /* Store Previous Mode's LR (R14), SP (R13) via R3 */ + msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Revert to Undef Mode */ + +_skip_banked_registers: + tst r1, #CPSR_THUMB /* Check for Thumb Mode */ + beq _is_arm /* Clear, so it's ARM mode */ +_is_thumb: + ldrh r0, [r0] /* load UNDEF instruction into r0 */ + ldr r1, =BKPT16_ENUM_MASK /* Thumb BKPT enum mask */ + bic r2, r0, r1 /* leave only opcode */ + ldr r1, =BKPT16_INSTR /* check for Thumb Breakpoint Instruction */ + teq r2, r1 + bne default_undef_handler + ldr r1, =BKPT16_ENUM_MASK /* get Thumb BKPT Enum Mask */ + ldr r2, =dbg__thumb_bkpt_handler /* handle BKPT, BKPT index in r0 */ + b _exit_undef_handler +_is_arm: + ldr r0, [r0] /* load UNDEF instruction into r0 */ + ldr r1, =BKPT32_ENUM_MASK /* ARM BKPT enum mask */ + bic r2, r0, r1 /* leave only opcode */ + ldr r1, =BKPT32_INSTR /* check for ARM Breakpoint Instruction */ + teq r2, r1 + bne default_undef_handler + ldr r1, =BKPT32_ENUM_MASK /* get ARM BKPT Enum Mask */ + ldr r2, =dbg__arm_bkpt_handler /* handle BKPT, BKPT index in r0 */ +_exit_undef_handler: + and r0, r1, r0 /* Keep index value */ + msr cpsr_c, #(MODE_ABT | CPSR_FIQ | CPSR_IRQ) /* Switch to Abort Mode, Disable Interrupts */ + ldr sp, =__abort_stack__ /* Reinitialize stack pointer each time a Breakpoint happens */ + bic sp, sp, #7 + mov pc, r2 /* Invoke Debugger */ + + .global resume_execution + +resume_execution: +/* + * This routine is called by the Debugger prior to returning control to + * the executing program. + * It updates the SPSR_UNDEF with the Debug Stack value, and + * restores all registers R0-R14 to the previously active mode. + * Then, it uses the Next Instruction Address Pointer to return + * execution control to the previously executing program. + */ +/* On Entry, SP(undef) points to the Next Instruction Address. + * If the instruction which triggered the Breakpoint need to be + * reexecuted, it should be placed in the Next Instruction Address slot + * by ABORT mode before coming here + */ + ldr lr, =__debugger_stack_bottom__ /* Use LR(undef) for Debug Stack Access */ + add r1, lr, #(DBGSTACK_USERSP_INDEX*4) /* Use R1 for Previous Mode SP (R13) and LR (R14) access */ + ldr r0, [lr, #(DBGSTACK_USERCPSR_INDEX*4)]! /* LR updated, Retrieve SPSR into R0 */ + msr spsr, r0 /* Update SPSR for return to program being debugged */ + and r0, r0, #CPSR_MODE /* Get previous mode */ + teq r0, #MODE_USR + bne _restore_prev_mode_banked_regs /* Can't switch back if we're in User mode! */ + + /* Previous mode was User Mode */ + ldmed lr, {r0-r14}^ /* We use LDMED since LR is pointing to USERCPSR not R0 */ + b _really_resume_execution + +_restore_prev_mode_banked_regs: + /* FIXME: We don't handle FIQ properly! */ + orr r0, #(CPSR_FIQ | CPSR_IRQ) /* Disable Interrupts */ + msr cpsr_c, r0 /* Switch to previous mode */ + ldmfd r1, {sp, lr} /* Restore Previous Mode's LR (R14), SP (R13) via R1 */ + msr cpsr_c, #(MODE_UND | CPSR_FIQ | CPSR_IRQ) /* Revert to Undef Mode */ + ldmed lr, {r0-r12} /* We use LDMED since LR is pointing to USERCPSR not R0 */ + +_really_resume_execution: + ldmfd sp, {pc}^ /* Exit to Previous Mode using Next Instruction Address */ + + + + diff --git a/AT91SAM7S256/armdebug/Doxyfile b/AT91SAM7S256/armdebug/Doxyfile new file mode 100644 index 0000000..6266354 --- /dev/null +++ b/AT91SAM7S256/armdebug/Doxyfile @@ -0,0 +1,243 @@ +# Doxyfile 1.5.3-20071008 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "NxOS Debugger" +PROJECT_NUMBER = +OUTPUT_DIRECTORY = ../doc/debug +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +#DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = YES +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = YES +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = . +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.h +RECURSIVE = YES +EXCLUDE = at91sam7s256.h +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 1 +GENERATE_TREEVIEW = YES +TREEVIEW_WIDTH = 280 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +#MACRO_EXPANSION = NO +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = NO +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/AT91SAM7S256/armdebug/GNU-GPLv2.txt b/AT91SAM7S256/armdebug/GNU-GPLv2.txt new file mode 100644 index 0000000..5b6e7c6 --- /dev/null +++ b/AT91SAM7S256/armdebug/GNU-GPLv2.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/AT91SAM7S256/armdebug/Host/README b/AT91SAM7S256/armdebug/Host/README new file mode 100644 index 0000000..23d95c9 --- /dev/null +++ b/AT91SAM7S256/armdebug/Host/README @@ -0,0 +1,21 @@ +The nxt-gdb-server.py script is initially developed by Nicolas Schodet. + +It depends on the following libraries: + - nxt-python v2.1.x http://code.google.com/p/nxt-python/ + - pyusb v0.4x http://pyusb.wiki.sourceforge.net + - libusb v0.1.x http://libusb.org/ + +Currently, it does not work with libusb v1.x, on Mac OSX, it causes segfaults. + + Installation + ============ + + There is no specific installation requirements (at this moment). Just run the python script + in a terminal window. + + Usage + ===== + + 1. Connect the USB cable from the PC Host to the NXT + 2. start nxt-gdb-server.py + 3. start arm-none-eabi-gdb, configured as remote for port 2828 (default) diff --git a/AT91SAM7S256/armdebug/Host/gdb-commands.txt b/AT91SAM7S256/armdebug/Host/gdb-commands.txt new file mode 100644 index 0000000..3135a1e --- /dev/null +++ b/AT91SAM7S256/armdebug/Host/gdb-commands.txt @@ -0,0 +1,43 @@ +# This file contains hand coded GDB commands for testing the GDB Server <-> NXT interface + +# Display all Registers +$g#67 + +# Display R0 +$p0#A0 + +# Display R1 +$p1#A1 + +# Display PC +$pF#B6 + +# Display FPSCR (dummy) +$p18#D9 + +# Display User CPSR +$p19#DA + +# Query Status +$?#3F + +# Query Thread +$qC#B4 + +# Set R1 to 0xAA +$P1=000000AA#60 + +# Read 16 bytes of Memory from 0x00201d74 (padding bytes after debug_mode + 4 bytes of debug_InUSBBuf) +$m00201D74,0010#FC + +# Write 2 bytes of memory to 0x00201d74 (padding bytes after debug_mode) +$M00201D74,0002:AA55#03 + +# Write 2 bytes of memory to 0x00201d74 (padding bytes after debug_mode) +$M00201D74,0002:9966#F5 + +# GDB Read Instruction at Address (PC) ++$m1001de,4#58 + +# Continue Execution +$c#63 diff --git a/AT91SAM7S256/armdebug/Host/nxt-gdb-server.py b/AT91SAM7S256/armdebug/Host/nxt-gdb-server.py new file mode 100755 index 0000000..197c27a --- /dev/null +++ b/AT91SAM7S256/armdebug/Host/nxt-gdb-server.py @@ -0,0 +1,254 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 the NxOS developers +# +# Module Developed by: Nicolas Schodet +# TC Wan +# +# See AUTHORS for a full list of the developers. +# +# See COPYING for redistribution license +# +# Exchange GDB messages with the NXT brick. +# +# Every message is encapsulated with the debug command and message length. +# This can be used by the firmware to make the distinction between debug +# messages and regular messages. +# +import nxt.locator +import socket +import optparse +import select +try: + import pyfantom +except ImportError: + import usb +import struct +import sys + +CTRLC = chr(3) +NAKCHAR = '-' +ACKCHAR = '+' +STATUS_QUERY = "$?#3F" +DEFAULT_PORT = 2828 +SELECT_TIMEOUT = 0.1 +DEBUG = False +DEBUG2 = False +NXT_RECV_ERR = -1 + +# Libusb 0.12.x blocks on USB reads +LIBUSB_RECEIVE_BLOCKING = True + +class NXTGDBServer: + + # Socket read size. + recv_size = 1024 + + # Maximum message size. + pack_size = 61 + + # Debug command header, no reply. + debug_command = 0x8d + + def __init__ (self, port, nowait): + """Initialise server.""" + self.nowait = nowait + self.port = port + self.in_buf = '' + self.brick = None + + def pack (self, data, segment_no): + """Return packed data to send to NXT.""" + # Insert command and length. + assert len (data) <= self.pack_size + return struct.pack ('BBB', self.debug_command, segment_no, len (data)) + data + + def unpack (self, data): + """Return unpacked data from NXT.""" + # May be improved, for now, check command and announced length. + if len (data) == 0: + return '', 0 # No message, exit + if len (data) < 3: + return '', NXT_RECV_ERR + header, body = data[0:3], data[3:] + command, segment_no, length = struct.unpack ('BBB', header) + if command != self.debug_command or length != len (body): + return '', NXT_RECV_ERR + return body, segment_no + + def segment (self, data): + """Split messages in GDB commands and make segments with each command.""" + segs = [ ] + self.in_buf += data + + # Find ACK '+' + end = self.in_buf.find (ACKCHAR) + while end == 0: + self.in_buf = self.in_buf[end+1:] # Strip out any leading ACKCHAR + if DEBUG2: + print "stripped ACK, remain: ", self.in_buf + end = self.in_buf.find (ACKCHAR) + + # Find NAK '-' + end = self.in_buf.find (NAKCHAR) + if end == 0: + msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] + segs.append (self.pack (msg, 0)) + end = self.in_buf.find (NAKCHAR) + + # Find Ctrl-C (assumed to be by itself and not following a normal command) + end = self.in_buf.find (CTRLC) + if end >= 0: + msg, self.in_buf = self.in_buf[0:end+1], self.in_buf[end+1:] + assert len (msg) <= self.pack_size, "Ctrl-C Command Packet too long!" + segs.append (self.pack (msg, 0)) + end = self.in_buf.find (CTRLC) + + end = self.in_buf.find ('#') + # Is # found and enough place for the checkum? + while end >= 0 and end < len (self.in_buf) - 2: + msg, self.in_buf = self.in_buf[0:end + 3], self.in_buf[end + 3:] + i = 0 + gdbprefix = msg[i] + while gdbprefix in [ACKCHAR]: + # Ignore any '+' + i += 1 + gdbprefix = msg[i] + if DEBUG2: + print "Checking '", gdbprefix, "'" + assert gdbprefix == '$', "not a GDB command" + # Make segments. + seg_no = 0 + while msg: + seg, msg = msg[0:self.pack_size], msg[self.pack_size:] + seg_no += 1 + if not msg: # Last segment. + seg_no = 0 + segs.append (self.pack (seg, seg_no)) + # Look for next one. + end = self.in_buf.find ('#') + return segs + + def reassemble (self, sock): + msg = '' + prev_segno = 0 + segno = NXT_RECV_ERR # force initial pass through while loop + while segno != 0: + try: + s, segno = self.unpack (sock.recv ()) + if len (s) == 0: + if segno == 0 and prev_segno == 0: + return '' # No message pending + else: + segno = NXT_RECV_ERR # Keep waiting for segments + # Ignore error packets + if segno >= 0: + # Check segno, if non-zero it must be monotonically increasing from 1, otherwise 0 + if segno > 0: + assert segno == prev_segno + 1, "segno = %s, prev_segno = %s" % (segno, prev_segno) + prev_segno = segno + msg += s + except usb.USBError as e: + # Some pyusb are buggy, ignore some "errors". + if e.args != ('No error', ): + raise e + return msg + + def run (self): + """Endless run loop.""" + # Create the listening socket. + s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) + s.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.bind (('', self.port)) + s.listen (1) + while True: + # We should open the NXT connection first, otherwise Python startup delay + # may cause GDB to misbehave + if not self.nowait: + dummy = raw_input('Waiting...Press when NXT GDB Stub is ready. ') + # Open connection to the NXT brick. + self.brick = nxt.locator.find_one_brick () + self.brick.sock.debug = DEBUG + # Wait for a connection. + print "Waiting for GDB connection on port %s..." % self.port + client, addr = s.accept () + print "Client from", addr + # Work loop, wait for a message from client socket or NXT brick. + while client is not None: + data = '' + # Wait for a message from client or timeout. + rlist, wlist, xlist = select.select ([ client ], [ ], [ ], + SELECT_TIMEOUT) + for c in rlist: + assert c is client + # Data from client, read it and forward it to NXT brick. + data = client.recv (self.recv_size) + data = data.strip() + if len (data) > 0: + #if len (data) == 1 and data.find(CTRLC) >= 0: + # print "CTRL-C Received!" + # data = STATUS_QUERY + if DEBUG: + if data[0] == CTRLC: + print "[GDB->NXT] " + else: + print "[GDB->NXT] %s" % data + segments = self.segment (data) + data = '' + for seg in segments: + try: + self.brick.sock.send (seg) + except usb.USBError as e: + # Some pyusb are buggy, ignore some "errors". + if e.args != ('No error', ): + raise e + if segments != [] and LIBUSB_RECEIVE_BLOCKING: + if DEBUG2: + print "Accessing Blocking sock.recv()" + data = self.reassemble (self.brick.sock) + else: + client.close () + client = None + if not LIBUSB_RECEIVE_BLOCKING: + if DEBUG2: + print "Accessing Non-Blocking sock.recv()" + data = self.reassemble (self.brick.sock) + + # Is there something from NXT brick? + if data: + if DEBUG: + print "[NXT->GDB] %s" % data + if client: + client.send (data) + data = '' + self.brick.sock.close() + print "Connection closed." + if self.nowait: + break + +if __name__ == '__main__': + # Read options from command line. + parser = optparse.OptionParser (description = """ + Gateway between the GNU debugger and a NXT brick. + """) + parser.add_option ('-p', '--port', type = 'int', default = DEFAULT_PORT, + help = "server listening port (default: %default)", metavar = "PORT") + parser.add_option ('-v', '--verbose', action='store_true', dest='verbose', default = False, + help = "verbose mode (default: %default)") + parser.add_option ('-n', '--nowait', action='store_true', dest='nowait', default = False, + help = "Don't wait for NXT GDB Stub Setup before connecting (default: %default)") + (options, args) = parser.parse_args () + if args: + parser.error ("Too many arguments") + # Run. + try: + DEBUG = options.verbose + if DEBUG: + print "Debug Mode Enabled!" + server = NXTGDBServer (options.port, options.nowait) + server.run () + except KeyboardInterrupt: + print "\n\nException caught. Bye!" + if server.brick is not None: + server.brick.sock.close() + sys.exit() diff --git a/AT91SAM7S256/armdebug/LEGO_Open_Source_License.doc b/AT91SAM7S256/armdebug/LEGO_Open_Source_License.doc new file mode 100644 index 0000000..94b65e6 Binary files /dev/null and b/AT91SAM7S256/armdebug/LEGO_Open_Source_License.doc differ diff --git a/AT91SAM7S256/armdebug/README b/AT91SAM7S256/armdebug/README new file mode 100644 index 0000000..4660b1e --- /dev/null +++ b/AT91SAM7S256/armdebug/README @@ -0,0 +1,16 @@ +Introduction +============ +armdebug is an ARM Assembly Language Instruction debugger for the NXT. +It is intended for embedding in the NXT firmware (e.g. NXT Improved Firmware), +as well as for use with NxOS. + +Contents +======== +The various folders contents are as follows: +Debugger: GDB client driver for NXT (need to be embedded in firmware code) +Host: GDB Server for PC Host + +LICENSES +======== +The armdebug code is dual-licensed. Please see COPYING for more details. +Other projects included in this repository have their respective licenses. diff --git a/AT91SAM7S256/armdebug/SConscript b/AT91SAM7S256/armdebug/SConscript new file mode 100644 index 0000000..c495847 --- /dev/null +++ b/AT91SAM7S256/armdebug/SConscript @@ -0,0 +1,13 @@ +# This scons build script is used by NxOS + +from glob import glob + +Import('env') + + +for source in glob('Debugger/*.[cS]'): + obj = env.Object(source.split('.')[0], source) + env.Append(NXOS_DEBUG=obj) + +if env['WITH_DOXYGEN']: + env.Doxygen('Doxyfile') diff --git a/AT91SAM7S256/armdebug/SConstruct b/AT91SAM7S256/armdebug/SConstruct new file mode 100644 index 0000000..fa88d7a --- /dev/null +++ b/AT91SAM7S256/armdebug/SConstruct @@ -0,0 +1,182 @@ +# -*- mode: python -*- +############################################################### +# This scons build script is used to check the armdebug project +# code for syntax errors. It does not build working executable +# code since it links to external routines. +############################################################### + +import os +import os.path +import new +from glob import glob + +############################################################### +# Utility functions. +############################################################### + +# Similar to env.WhereIs, but always searches os.environ. +def find_on_path(filename): + paths = os.environ.get('PATH') + if not paths: + return None + for p in paths.split(':'): + path = os.path.abspath(os.path.join(p, filename)) + if os.path.isfile(path): + return p + return None + +# Run the given gcc binary, and parses its output to work out the gcc +# version. +def determine_gcc_version(gcc_binary): + stdout = os.popen('%s --version' % gcc_binary) + gcc_output = stdout.read().split() + stdout.close() + grab_next = False + for token in gcc_output: + if grab_next: + return token + elif token[-1] == ')': + grab_next = True + return None + +# Check that a given cross-compiler tool exists. If it does, the path is +# added to the build environment, and the given environment variable is +# set to the tool name. +# +# This is used to check for the presence of a working cross-compiler +# toolchain, and to properly set up the environment to do it. See below +# in the configuration section for details. +def CheckTool(context, envname, toolname=None, hostprefix=None): + toolname = toolname or envname.lower() + if hostprefix is None: + hostprefix = '%s-' % context.env['CROSS_COMPILE_HOST'] + toolname = '%s%s' % (hostprefix, toolname) + context.Message("Checking for %s..." % toolname) + toolpath = find_on_path(toolname) + if not toolpath: + context.Result('not found') + return False + else: + context.Result('ok') + context.env[envname] = toolname + context.env.AppendENVPath('PATH', toolpath) + return True + +# Find the correct variant and version of libgcc.a in the cross-compiler +# toolchain. +def CheckLibGcc(context, gccname): + context.Message("Locating a cross-compiled libgcc...") + toolpath = find_on_path(gccname) + if not toolpath: + context.Result("%s not found" % toolname) + return False + gcc_version = determine_gcc_version(gccname) + if not gcc_version: + context.Result("Could not determine gcc version") + return False + gcc_install_dir = os.path.split(os.path.normpath(toolpath))[0] + for libdir in ['interwork', 'thumb', '']: + libgcc_path = os.path.join(gcc_install_dir, 'lib', 'gcc', + context.env['CROSS_COMPILE_HOST'], + gcc_version, libdir, 'libgcc.a') + if os.path.isfile(libgcc_path): + break + if not os.path.isfile(libgcc_path): + context.Result("libgcc.a not found") + return False + context.Result("ok - " + libgcc_path) + context.env.Append(LIBGCC=libgcc_path) + return True + +def CheckDoxygen(context): + context.Message("Looking for Doxygen...") + doxypath = find_on_path('doxygen') + if doxypath: + context.Result("ok") + context.env.AppendENVPath('PATH', doxypath) + context.env['WITH_DOXYGEN'] = True + else: + context.Result("not found") + context.env['WITH_DOXYGEN'] = False + + + +############################################################### +# Options that can be provided on the commandline +############################################################### + +opts = Variables('scons.options', ARGUMENTS) + +opts.Add(PathVariable('gccprefix', + 'Prefix of the cross-gcc to use (by default arm-none-eabi)', + 'arm-none-eabi', PathVariable.PathAccept)) + +Help(''' +Type: 'scons' to build object files. + + - To use another cross-gcc than arm-none-eabi-gcc: + scons gccprefix=arm-softfloat-eabi + +Options are saved persistent in the file 'scons.options'. That means +after you have called e.g. 'scons gccprefix=arm-softfloat-eabi' it's enough +to call only 'scons' to build both using the new gcc version again. +''') + +############################################################### +# Construct and configure a cross-compiler environment +############################################################### +env = Environment(options = opts, + tools = ['gcc', 'as', 'gnulink', 'ar'], + toolpath = ['scons_tools'], + LIBGCC = [], CPPPATH = '#', + WITH_DOXYGEN = False) +opts.Update(env) +opts.Save('scons.options', env) + +if not env.GetOption('clean'): + conf = Configure(env, custom_tests = {'CheckTool': CheckTool, + 'CheckLibGcc': CheckLibGcc, + 'CheckDoxygen': CheckDoxygen}) + conf.env['CROSS_COMPILE_HOST'] = env['gccprefix'] + if not (conf.CheckTool('CC', 'gcc') and conf.CheckTool('AR') and + conf.CheckTool('OBJCOPY') and conf.CheckTool('LINK', 'ld') and + conf.CheckLibGcc(conf.env['CC'])): + print "Missing or incomplete arm-elf toolchain, cannot continue!" + Exit(1) + env = conf.Finish() + +mycflags = ['-mcpu=arm7tdmi', '-Os', '-Wextra', '-Wall', '-Werror', + '-Wno-div-by-zero', '-Wfloat-equal', '-Wshadow', + '-Wpointer-arith', '-Wbad-function-cast', + '-Wmissing-prototypes', '-ffreestanding', + '-fsigned-char', '-ffunction-sections', '-std=gnu99', + '-fdata-sections', '-fomit-frame-pointer', '-msoft-float'] +myasflags = ['-Wall', '-Werror', '-Os']; +if str(env['LIBGCC']).find('interwork') != -1: + mycflags.append('-mthumb-interwork') + myasflags.append('-Wa,-mcpu=arm7tdmi,-mfpu=softfpa,-mthumb-interwork') +elif str(env['LIBGCC']).find('thumb') != -1: + mycflags.append('-mthumb') + myasflags.append('-Wa,-mcpu=arm7tdmi,-mfpu=softfpa,-mthumb') +else: + myasflags.append('-Wa,-mcpu=arm7tdmi,-mfpu=softfpa') +mycflags.append('-g') +mycflags.append('-ggdb') +# Big Endian Output (disabled by default) +#mycflags.append('-D__BIG_ENDIAN__') +# Test build for NxOS (Comment out for NXT Firmware) +mycflags.append('-D__NXOS__') + +myasflags.append('-g') +myasflags.append('-ggdb') +# Big Endian Output (disabled by default) +#mycflags.append('-D__BIG_ENDIAN__') +# Test build for NxOS (Comment out for NXT Firmware) +myasflags.append('-D__NXOS__') + +env.Replace(CCFLAGS = mycflags, ASFLAGS = myasflags ) + +# Build the baseplate, and all selected application kernels. + +numProcs = os.sysconf('SC_NPROCESSORS_ONLN') +SConscript(['SConscript'], 'numProcs env CheckTool') diff --git a/AT91SAM7S256/scripts/armnxtgdbserver b/AT91SAM7S256/scripts/armnxtgdbserver new file mode 100755 index 0000000..1acac65 --- /dev/null +++ b/AT91SAM7S256/scripts/armnxtgdbserver @@ -0,0 +1,29 @@ +#!/bin/sh +# If using Apple's python, use the following to enable 32-bit python +# arch -i386 does not work reliably except with specific python versions +# python2.6 and python2.7 is known to work with 'arch -i386' +# +# Apple recommends the use of the following Environment Variable to control +# 32-bit vs. 64-bit python selection +# export VERSIONER_PYTHON_PREFER_32_BIT="yes" + +DARWIN=`uname` +PYTHON=python +PYTHONVER=`$PYTHON --version` + +GDBSERVER=../armdebug/Host/nxt-gdb-server.py +if [ $DARWIN == "Darwin" ]; then + echo "$PYTHONVER Running on Mac OSX Platform!" + EXP="export VERSIONER_PYTHON_PREFER_32_BIT=yes" + ARCH="arch -i386" +else + echo "$PYTHONVER Running on Default Platform!" + EXP= + ARCH= +fi +# Debugging Info +# echo "dirname:" `dirname $0` +# echo "basename:" `basename $0` +cd `dirname $0` +#echo $EXP; $ARCH $PYTHON $GDBSERVER $* +$EXP; $ARCH $PYTHON $GDBSERVER $* -- cgit v1.2.3