From b85ec27ff755f28770fc6ae17d1d22f69f42d45b Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Sat, 6 Aug 2011 00:39:58 +0200 Subject: gcc: add support for unwinder The unwinder is not really wanted, but it can be included on some version of gcc. In this case, it needs some special sections and the abort function. --- AT91SAM7S256/SAM7S256/gcc/Makefile | 2 +- AT91SAM7S256/SAM7S256/gcc/lib/abort.c | 32 ++++++++++++++++++++++++++++++++ AT91SAM7S256/SAM7S256/gcc/nxt.ld | 7 +++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 AT91SAM7S256/SAM7S256/gcc/lib/abort.c diff --git a/AT91SAM7S256/SAM7S256/gcc/Makefile b/AT91SAM7S256/SAM7S256/gcc/Makefile index 7ad3156..65b6ecf 100644 --- a/AT91SAM7S256/SAM7S256/gcc/Makefile +++ b/AT91SAM7S256/SAM7S256/gcc/Makefile @@ -14,7 +14,7 @@ THUMB_SOURCES = c_button.c c_cmd.c c_comm.c c_display.c c_input.c c_ioctrl.c \ d_ioctrl.c d_loader.c d_lowspeed.c d_output.c d_sound.c \ d_timer.c d_usb.c \ m_sched.c \ - errno.c sbrk.c strtod.c sscanf.c \ + abort.c errno.c sbrk.c strtod.c sscanf.c \ Cstartup_SAM7.c ASM_ARM_SOURCE = Cstartup.S diff --git a/AT91SAM7S256/SAM7S256/gcc/lib/abort.c b/AT91SAM7S256/SAM7S256/gcc/lib/abort.c new file mode 100644 index 0000000..26d47e7 --- /dev/null +++ b/AT91SAM7S256/SAM7S256/gcc/lib/abort.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 Nicolas Schodet + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* Provide an abort function, could be used by various library function. */ + +void +abort (void) +{ + /* Wait for ever, nothing better to do. */ + while (1) + ; +} + diff --git a/AT91SAM7S256/SAM7S256/gcc/nxt.ld b/AT91SAM7S256/SAM7S256/gcc/nxt.ld index 8e5f0cb..d63944e 100644 --- a/AT91SAM7S256/SAM7S256/gcc/nxt.ld +++ b/AT91SAM7S256/SAM7S256/gcc/nxt.ld @@ -51,6 +51,13 @@ SECTIONS PROVIDE(__dtors_end__ = .); } >CODE + __exidx_start = . ; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } >CODE + __exidx_end = . ; + . = ALIGN(4); _etext = . ; -- cgit v1.2.3 From ceb0cbf65a11aed7662eb41ae66157e60ff61d60 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Tue, 9 Aug 2011 23:48:50 +0200 Subject: gcc: add debug information --- AT91SAM7S256/SAM7S256/gcc/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AT91SAM7S256/SAM7S256/gcc/Makefile b/AT91SAM7S256/SAM7S256/gcc/Makefile index 65b6ecf..ad40886 100644 --- a/AT91SAM7S256/SAM7S256/gcc/Makefile +++ b/AT91SAM7S256/SAM7S256/gcc/Makefile @@ -36,8 +36,8 @@ OPTIMIZE = -Os -fno-strict-aliasing \ -ffunction-sections -fdata-sections WARNINGS = -Wall -W -Wundef -Wno-unused -Wno-format THUMB_INTERWORK = -mthumb-interwork -CFLAGS = -mcpu=$(MCU) $(THUMB) $(THUMB_INTERWORK) $(WARNINGS) $(OPTIMIZE) -ASFLAGS = -mcpu=$(MCU) $(THUMB) $(THUMB_INTERWORK) +CFLAGS = -g -mcpu=$(MCU) $(THUMB) $(THUMB_INTERWORK) $(WARNINGS) $(OPTIMIZE) +ASFLAGS = -g -mcpu=$(MCU) $(THUMB) $(THUMB_INTERWORK) CPPFLAGS = $(INCLUDES) $(DEFINES) -MMD LDSCRIPT = nxt.ld LDFLAGS = -nostdlib -T $(LDSCRIPT) -Wl,--gc-sections -- cgit v1.2.3 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 From 2e770cc4395ae7a39315a55b84b4936250b6c18b Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Sat, 4 Feb 2012 01:01:57 +0100 Subject: make armdebug compilation conditional Set ARMDEBUG to y in the Makefile to enable armdebug compilation. --- AT91SAM7S256/SAM7S256/Include/Cstartup.S | 11 +++++++++++ AT91SAM7S256/SAM7S256/Include/sam7s256.c | 4 ++-- AT91SAM7S256/SAM7S256/gcc/Makefile | 22 ++++++++++++++++------ AT91SAM7S256/Source/c_comm.c | 4 ++-- AT91SAM7S256/Source/c_comm.h | 2 +- 5 files changed, 32 insertions(+), 11 deletions(-) diff --git a/AT91SAM7S256/SAM7S256/Include/Cstartup.S b/AT91SAM7S256/SAM7S256/Include/Cstartup.S index e3e996e..8a6a540 100644 --- a/AT91SAM7S256/SAM7S256/Include/Cstartup.S +++ b/AT91SAM7S256/SAM7S256/Include/Cstartup.S @@ -136,11 +136,20 @@ FIQ_Handler_Entry: /* end of fiqhandler */ Reset_Addr: .word InitReset +#ifdef ARMDEBUG Undef_Addr: .word undef_handler /* BKPT instruction trap */ +#else +Undef_Addr: .word Undef_Handler +#endif SWI_Addr: .word SWI_Handler /*SWI_Addr: .word SoftwareInterruptASM*/ /*in swi_handler.S */ +#ifdef ARMDEBUG PAbt_Addr: .word prefetch_abort_handler DAbt_Addr: .word data_abort_handler +#else +PAbt_Addr: .word PAbt_Handler +DAbt_Addr: .word DAbt_Handler +#endif IRQ_Addr: .word IRQ_Handler_Entry .global default_undef_handler @@ -271,9 +280,11 @@ already_remapped: //*-------------------------------*/ mov r0, sp /* see (**) */ +#ifdef ARMDEBUG /*- Set up Abort Mode Stack for Debugger*/ msr CPSR_c, #ARM_MODE_ABT | I_BIT | F_BIT ldr sp, =__abort_stack_top__ +#endif /*- Set up Fast Interrupt Mode and set FIQ Mode Stack*/ msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT diff --git a/AT91SAM7S256/SAM7S256/Include/sam7s256.c b/AT91SAM7S256/SAM7S256/Include/sam7s256.c index 8ff0ab4..b2657d5 100644 --- a/AT91SAM7S256/SAM7S256/Include/sam7s256.c +++ b/AT91SAM7S256/SAM7S256/Include/sam7s256.c @@ -11,7 +11,7 @@ // // Platform C // -#ifdef __ARMDEBUG__ +#ifdef ARMDEBUG #include "debug_stub.h" #endif @@ -21,7 +21,7 @@ void main(void) { HARDWAREInit; mSchedInit(); -#ifdef __ARMDEBUG__ +#ifdef ARMDEBUG dbg__bkpt_init(); #endif while(TRUE == mSchedCtrl()) diff --git a/AT91SAM7S256/SAM7S256/gcc/Makefile b/AT91SAM7S256/SAM7S256/gcc/Makefile index e96e153..f236a08 100644 --- a/AT91SAM7S256/SAM7S256/gcc/Makefile +++ b/AT91SAM7S256/SAM7S256/gcc/Makefile @@ -8,6 +8,9 @@ CUSTOM_FIRMWAREVERSION = $(GIT_VERSION) TARGET = nxt_firmware +# Set to 'y' to enable embedded debuger. +ARMDEBUG = n + ARM_SOURCES = THUMB_SOURCES = c_button.c c_cmd.c c_comm.c c_display.c c_input.c c_ioctrl.c \ c_loader.c c_lowspeed.c c_output.c c_sound.c c_ui.c \ @@ -18,23 +21,21 @@ 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 abort_handler.S undef_handler.S debug_hexutils.S \ - debug_stub.S debug_comm.S debug_opcodes.S debug_runlooptasks.S +ASM_ARM_SOURCE = Cstartup.S ASM_THUMB_SOURCE = vpath %.c $(SRCDIR) vpath %.c $(CPUINCDIR) vpath %.c lib -vpath %.S $(CPUINCDIR) $(DBGDIR) +vpath %.S $(CPUINCDIR) -INCLUDES = -I../../armdebug/Debugger +INCLUDES = 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) $(DEBUG_DEFINES) + $(STARTOFUSERFLASH_DEFINES) $(VERSION_DEFINES) OPTIMIZE = -Os -fno-strict-aliasing \ -ffunction-sections -fdata-sections WARNINGS = -Wall -W -Wundef -Wno-unused -Wno-format @@ -46,6 +47,15 @@ LDSCRIPT = nxt.ld LDFLAGS = -nostdlib -T $(LDSCRIPT) -Wl,--gc-sections LDLIBS = -lc -lm -lgcc +ifeq ($(ARMDEBUG),y) +ASM_ARM_SOURCE += abort_handler.S undef_handler.S debug_hexutils.S \ + debug_stub.S debug_comm.S debug_opcodes.S \ + debug_runlooptasks.S +vpath %.S $(DBGDIR) +DEFINES += -DARMDEBUG +INCLUDES += -I../../armdebug/Debugger +endif + CROSS_COMPILE = arm-none-eabi- CC = $(CROSS_COMPILE)gcc OBJDUMP = $(CROSS_COMPILE)objdump diff --git a/AT91SAM7S256/Source/c_comm.c b/AT91SAM7S256/Source/c_comm.c index 1411b5d..176a1ff 100644 --- a/AT91SAM7S256/Source/c_comm.c +++ b/AT91SAM7S256/Source/c_comm.c @@ -26,7 +26,7 @@ #include "d_bt.h" #include #include -#ifdef __ARMDEBUG__ +#ifdef ARMDEBUG #include "debug_stub.h" #endif @@ -425,7 +425,7 @@ UWORD cCommInterprete(UBYTE *pInBuf, UBYTE *pOutBuf, UBYTE *pLength, UBYTE C } break; -#ifdef __ARMDEBUG__ +#ifdef ARMDEBUG case DEBUG_CMD: { ReturnStatus = cCommHandleDebug(&(pInBuf[0]), CmdBit, MsgLength); /* Pass everything (incl. message command byte) to function */ diff --git a/AT91SAM7S256/Source/c_comm.h b/AT91SAM7S256/Source/c_comm.h index ac24b02..06137b2 100644 --- a/AT91SAM7S256/Source/c_comm.h +++ b/AT91SAM7S256/Source/c_comm.h @@ -67,7 +67,7 @@ enum DIRECT_CMD = 0x00, SYSTEM_CMD = 0x01, REPLY_CMD = 0x02, -#ifdef __ARMDEBUG__ +#ifdef ARMDEBUG DEBUG_CMD = 0x0d, #endif NO_REPLY_BIT = 0x80 -- cgit v1.2.3 From 99a4c90dee42104638933096728bebc45e28bf1a Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Sat, 4 Feb 2012 12:19:57 +0100 Subject: do not reserve space for stacks if armdebug is disabled --- AT91SAM7S256/SAM7S256/Include/Cstartup.S | 13 +++++++++++++ AT91SAM7S256/SAM7S256/gcc/nxt.ld | 6 +++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/AT91SAM7S256/SAM7S256/Include/Cstartup.S b/AT91SAM7S256/SAM7S256/Include/Cstartup.S index 8a6a540..0293251 100644 --- a/AT91SAM7S256/SAM7S256/Include/Cstartup.S +++ b/AT91SAM7S256/SAM7S256/Include/Cstartup.S @@ -460,5 +460,18 @@ AT91F_Spurious_handler: .size AT91F_Spurious_handler, . - AT91F_Spurious_handler .endfunc +/*------------------------------------------------------------------------------ +//*- Various debugger stacks. +//*-------------------------------*/ + +#ifdef ARMDEBUG +.section .stack.abort, "aw", %nobits + .space 0x80; /* 128 byte abort mode stack. */ +.section .stack.debugger, "aw", %nobits + .space 0x48; /* 16 user mode registers + SPSR + UNDEF Next Instruction Address */ +.section .breakpoints, "aw", %nobits + .space 0x40; /* Single Stepping Breakpoint + 7 Breakpoints */ +#endif + .end diff --git a/AT91SAM7S256/SAM7S256/gcc/nxt.ld b/AT91SAM7S256/SAM7S256/gcc/nxt.ld index 9b7171f..e54bc5d 100644 --- a/AT91SAM7S256/SAM7S256/gcc/nxt.ld +++ b/AT91SAM7S256/SAM7S256/gcc/nxt.ld @@ -93,19 +93,19 @@ SECTIONS .stack : ALIGN(8) { /* abort stack */ __abort_stack_bottom__ = . ; - . += 0x80; /* 128 byte abort mode stack. */ + KEEP(*(.stack.abort)) __abort_stack__ = . ; __abort_stack_top__ = . ; /* debugger state */ __debugger_stack_bottom__ = . ; - . += 0x48; /* 16 user mode registers + SPSR + UNDEF Next Instruction Address */ + KEEP(*(.stack.debugger)) __debugger_stack__ = . ; __debugger_stack_top__ = . ; /* breakpoints */ __breakpoints_start__ = . ; - . += 0x40; /* Single Stepping Breakpoint + 7 Breakpoints */ + KEEP(*(.breakpoints)) __breakpoints_end__ = . ; } > DATA -- cgit v1.2.3