From 81cf690ce0be1ed2d18eab25b09433630025f60b Mon Sep 17 00:00:00 2001 From: TC Wan Date: Wed, 1 Dec 2010 13:39:08 +0800 Subject: new repository --- .gitignore | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fb49c59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# 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/ + +# Files generated during a NxOS build. +nxos/base/_font.h +nxos/doc/*/ + +# The TVM port has a whole SVN checkout not managed by hg. +nxos/systems/tvm/tvm/ + +# SCons cruft +nxos/.sconsign.dblite +nxos/.sconf_temp +nxos/build_flags.py + +# Precommit hooks drop a commit.msg file if they fail. +commit.msg + +# The option-cache +scons.options -- cgit v1.2.3 From e77bdeea663d2a89034da6a2c368e3909fd0a14b Mon Sep 17 00:00:00 2001 From: TC Wan Date: Mon, 29 Nov 2010 18:17:55 +0800 Subject: initial debugger commit. This is non working code taken from my private NxOS repository --- AT91SAM7S256/Debugger/_c_arm_macros.h | 149 ++++ AT91SAM7S256/Debugger/debug_comm.S | 286 +++++++ AT91SAM7S256/Debugger/debug_stub.S | 1332 +++++++++++++++++++++++++++++++++ AT91SAM7S256/Debugger/debug_stub.h | 149 ++++ AT91SAM7S256/Debugger/types.h | 46 ++ 5 files changed, 1962 insertions(+) create mode 100644 AT91SAM7S256/Debugger/_c_arm_macros.h create mode 100644 AT91SAM7S256/Debugger/debug_comm.S create mode 100644 AT91SAM7S256/Debugger/debug_stub.S create mode 100644 AT91SAM7S256/Debugger/debug_stub.h create mode 100644 AT91SAM7S256/Debugger/types.h diff --git a/AT91SAM7S256/Debugger/_c_arm_macros.h b/AT91SAM7S256/Debugger/_c_arm_macros.h new file mode 100644 index 0000000..f356a25 --- /dev/null +++ b/AT91SAM7S256/Debugger/_c_arm_macros.h @@ -0,0 +1,149 @@ +/** @file _c_arm_macros.h + * @brief Define macros to support shared C and ASM headers + * + */ + +/* Copyright (C) 2007,2009 the NxOS developers + * Thanks to Bartli (forum post @ embdev.net ARM programming with GCC/GNU tools forum) + * + * 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. + */ + +#ifndef __NXOS_BASE_C_ARM_MACROS__ +#define __NXOS_BASE_C_ARM_MACROS__ + +#ifdef __ASSEMBLY__ + +#define NULL 0x0 /* Stick the definition here instead of making types.h messy */ +#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) + +/** Macro to define driver ioctl table + * First five table entries are predefined + * 0: init + * 1: shutdown + * 2: sleep + * 3: wakeup + * 4: poll + * + */ +#define DRIVER_IOCTL(driver) \ +/* Dummy sleep and wakeup routines for now */ ;\ + .set driver ## _sleep, NULL ;\ + .set driver ## _wakeup, NULL ;\ + .set driver ## _poll, NULL ;\ +.data ;\ + .align 4 ;\ + .global driver ## _ioctl ;\ +driver ## _ioctl: ;\ + .word driver ## _init ;\ + .word driver ## _shutdown ;\ + .word driver ## _sleep ;\ + .word driver ## _wakeup ;\ + .word driver ## _poll ;\ + .set num_ ## driver ## _cmds, 5 + +/** Macro to define additional driver ioctl commands + * Be careful to follow the sequence defined for the CMD enums + * The first CMD should have an enum value of 5 + * + */ +#define DRIVER_CMD(driver, cmd) \ + .word driver ## _ ## cmd ;\ + .set num_ ## driver ## _cmds, num_ ## driver ## _cmds + 1 + +/** Macro to define driver state + * MUST BE DEFINED AFTER DRIVER_IOCTL section + * @param driver name of driver + * @param driverenum enum value of driver (in [31:25]) + * + * The number of commands for driver (in [24:17]) -- derived from num_driver_cmds + * + * Format of driver_state table: + * driver signature (driverenum << 24 | numcommands << 16) + * driver parameters (per device instance) + */ +#define DRIVER_STATE(driver, driverenum) \ +.bss ;\ + .global driver ## _state ;\ +driver ## _state: ;\ + .set driver ## _signature, (driverenum << 24) | (num_ ## driver ## _cmds << 16) ;\ + .word NULL /* driver_signature */ + + +/** Macro to define actual driver routine in .S + * On entry: + * r0 - address of driver_state + * r1-r3 - parameters (variable) + * r12 - number of parameters (IPC scratch register) + * Stack - parameters (variable) + */ +#define DRIVER_ROUTINE(driver, cmd) \ + .global driver ## _ ## cmd ## ;\ +driver ## _ ## cmd ## : + +#else +/** 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 + +ENUM_BEGIN +ENUM_VAL(INIT) /**< Driver Init Routine. */ +ENUM_VAL(SHUTDOWN) /**< Driver Shutdown Routine. */ +ENUM_VAL(SLEEP) /**< Driver Sleep Routine. */ +ENUM_VAL(WAKEUP) /**< Driver Wakeup Routine. */ +ENUM_VAL(POLL) /**< Driver Poll Routine. */ +ENUM_END(nx_driver_default_cmd) + + +#endif /* __NXOS_BASE_C_ARM_MACROS__ */ diff --git a/AT91SAM7S256/Debugger/debug_comm.S b/AT91SAM7S256/Debugger/debug_comm.S new file mode 100644 index 0000000..d6eaaa8 --- /dev/null +++ b/AT91SAM7S256/Debugger/debug_comm.S @@ -0,0 +1,286 @@ + +/* 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" + +.data +.align 4 + +hex2char_lut: + .ascii "0123456789ABCDEF" + +/* Macros + */ + +/* _asciiz + * Terminate string given string buffer pointer in \addrptr + * reg is used as a scratch register (destroyed) + * + */ + .macro _asciiz reg, strptr + mov \reg, #0 /* NULL character */ + strb \reg, [\strptr] /* Terminate ASCIIZ string */ + .endm + +/* _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 + */ + +/* 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, #0x000F /* 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) + */ + .global char2hex + +char2hex: + and r0, #0x00FF /* make sure that input is sane */ + cmp r0, #'0' + blo exit_char2hex + cmp r0, #'F' + bhi exit_char2hex + _char2hex r0 +exit_char2hex: + bx lr + +/* byte2ascii_cont + * This routine accepts a byte value in R0(7:0), and a ASCII buffer pointer in R1, + * and stores the ASCII equivalent byte value in the buffer pointed to by R1. + * Note: On return, R1 points to next empty char slot in buffer (i.e., R1 is modified) + * and R0 is destroyed. + */ +byte2ascii_cont: + stmfd sp!, {r2,r3,r4, lr} + mov r2, r0, lsl #24 /* Keep copy of input byte value R0(7:0), shifted to MSB R2(31:24) */ + mov r4, #2 /* Loop counter */ + _hex2char_lut r3 /* initialize LUT pointer */ +1: mov r0, r2, ror #28 /* Rotate MSNibble R2(31:28) into LSNibble position R0(3:0) */ + and r0, r0, #NIBBLE0 /* Mask out everything else */ + _hex2char_cont r0, r3 /* Convert nibble to ASCII char */ + strb r0, [r1], #1 + subs r4, r4, #1 /* decrement loop counter */ + bne 1b + ldmfd sp!, {r2,r3,r4, pc} + +/* byte2ascii + * This routine accepts a byte value in R0(7:0), and a ASCII buffer pointer in R1, + * and stores the ASCII equivalent byte value in the buffer pointed to by R1. + * Note: On return, R1 points to the end of the ASCIIZ string (i.e. NULL character) + */ + .global byte2ascii + +byte2ascii: + stmfd sp!, {r1, lr} /* Keep ASCII buffer pointer */ + and r0, #BYTE0 /* sanitize input */ + bl byte2ascii_cont + _asciiz r0, r1 + ldmfd sp!, {r0, pc} /* return string pointer in R0 */ + +/* halfword2ascii + * This routine accepts a halfword value in R0(15:0), and a ASCII buffer pointer in R1, + * and returns the ASCIIZ equivalent byte value in the buffer pointed to by R0. + * Note: On return, R1 points to the end of the ASCIIZ string (i.e. NULL character) + */ + .global halfword2ascii +halfword2ascii: + stmfd sp!, {r1,r2,r3, lr} /* Keep ASCII buffer pointer */ + mov r2, r0, lsl #16 /* copy of input halfword value R0(15:0), shifted to MSH R2(31:16) */ + mov r3, #2 /* Loop Counter */ + b _conv_byte2ascii /* goto Byte conversion loop */ + +/* word2ascii + * This routine accepts a word value in R0(31:0), and a ASCII buffer pointer in R1, + * and returns the ASCIIZ equivalent byte value in the buffer pointed to by R0. + * Note: On return, R1 points to the end of the ASCIIZ string (i.e. NULL character) + */ + .global word2ascii +word2ascii: + stmfd sp!, {r1,r2,r3, lr} /* Keep ASCII buffer pointer */ + mov r2, r0 /* copy of input word value R0(31:0) */ + mov r3, #4 /* Loop Counter */ + + /* Fall through to byte coversion loop */ + +_conv_byte2ascii: + mov r0, r2, ror #24 /* Rotate MSB R2(31:24) into LSB position R0(7:0) */ + and r0, #BYTE0 /* Mask out everything else */ + bl byte2ascii_cont + subs r3, r3, #1 + bne _conv_byte2ascii + _asciiz r0, r1 + ldmfd sp!, {r0,r2,r3, pc} + + +/* ascii2byte + * 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,r3, lr} + mov r3, #2 /* Loop counter */ + b _conv_ascii2byte + +/* ascii2halfword + * This routine accepts an ASCII buffer pointer in R0, + * and returns the word 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 + +ascii2halfword: + stmfd sp!, {r2,r3, lr} + mov r3, #4 /* Loop counter */ + b _conv_ascii2byte + + +/* ascii2word + * 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 + +ascii2word: + stmfd sp!, {r2,r3, lr} + mov r3, #8 /* Loop counter */ + + /* Fall through to byte coversion loop */ + +_conv_ascii2byte: + teq r0, #0 + beq _exit_conv_ascii2byte /* exit if NULL pointer in R0 */ + mov r0, r1 /* Copy of ASCII buffer pointer */ + mov r2, #0 /* Initialize results */ +2: ldrb r0, [r1], #1 /* Load ASCII char */ + bl char2hex /* on return, hex value in R0 */ + orr r2, r0, r2, lsl #4 /* merge Nibble into results */ + subs r3, r3, #1 + bne 2b + mov r0, r2 /* Copy it to R0 as return value */ +_exit_conv_ascii2byte: + ldmfd sp!, {r2,r3, pc} /* return hex value in R0 */ + + + + +/* 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. + * + */ + .global dbg__hasDebugMsg +/* dbg__hasDebugMsg + * Checks for pending Debugger Message (Non-Blocking). + * On exit: + * r0: Boolean (0: no pending message, 1: has pending message) + */ +dbg__hasDebugMsg: + bx lr + + .global dbg__getDebugMsg +/* dbg__getDebugMsg + * Returns Debugger Message to calling routine after verifying and removing checksum (Blocking). + * On entry: + * r0: address of message buffer + * r1: maximum size of message buffer (incl NULL character) + * On exit: + * r0: address of message buffer with NULL terminated message, excluding '#' + * (NULL if message error) + * + */ +dbg__getDebugMsg: + bx lr + + .global dbg__putDebugMsg +/* dbg__putDebugMsg + * Sends Debugger Message from calling routine after appending checksum (Blocking) . + * On entry: + * r0: address of message buffer with NULL terminated message, without '#' + * On exit: + * r0: status (0: success, -1: error) + */ +dbg__putDebugMsg: + bx lr + + +/* Private functions (if needed) */ +_dbg__getChar: +_dbg__putChar: + bx lr diff --git a/AT91SAM7S256/Debugger/debug_stub.S b/AT91SAM7S256/Debugger/debug_stub.S new file mode 100644 index 0000000..3aa2cb7 --- /dev/null +++ b/AT91SAM7S256/Debugger/debug_stub.S @@ -0,0 +1,1332 @@ + +/* 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. + */ + + /* 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 from R0 to R15 + * 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. + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * 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) + * + * 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 */ + + +/* FIXME: What about setting/clearing Breakpoints? */ + +#define __ASSEMBLY__ +#include "debug_stub.h" + +.bss +.align 4 +debug_state: + .word 0x0 +debug_curr_breakpoint: + .word 0x0 +debug_InMsgBuf: + .space MSGBUF_SIZE,0 +debug_OutMsgBuf: + .space MSGBUF_SIZE,0 + +.data +.align 4 +debug_ValidResponsePrefix: + .byte '+','$',0 + +debug_ErrorResponsePrefix: + .byte '-','$','E',0 + +debug_SignalResponsePrefix: + .byte '+','$','S',0 + +debug_OkResponse: + .byte '+','$','O','K',0 + +/* The CmdIndexTable and CmdJumpTable must be kept in sync */ +debug_cmdIndexTable: + .byte 'g','G','p','P','m','M','c','s','k','?',0 + +/* Command Handlers expect the address pointer to the parameter buffer (contents after '$' and '') in R0 + * and the Output Message Buffer Address in R1 + */ +debug_cmdJumpTable: + .word _dbg__procGetRegs /* 'g' */ + .word _dbg__procSetRegs /* 'G' */ + .word _dbg__procGetOneReg /* 'p' */ + .word _dbg__procSetOneReg /* 'P' */ + .word _dbg__nop /* 'm' */ + .word _dbg__nop /* 'M' */ + .word _dbg__nop /* 'c' */ + .word _dbg__nop /* 's' */ + .word _dbg__nop /* 'k' */ + .word _dbg__nop /* '?' */ + .word 0 + + +.code 32 +.text +.align 4 + .extern __breakpoints_num__ + .extern dbg__hasDebugMsg /* Check for message from the communications link */ + .extern dbg__getDebugMsg /* Read a message from the communications link */ + .extern dbg__putDebugMsg /* Write a message to the communications link */ + +/* _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_stpcpy + * _dbg_stpcpy macro + * On entry: + * deststrptr: Destination string [Cannot be R0] + * sourcestrptr: Source string [Cannot be R0] + * On exit: + * deststrptr: Pointer to NULL character in destination string + * R0: destroyed + */ + .macro _dbg_stpcpy deststrptr, sourcestrptr +1: ldrb r0, [\sourcestrptr], #1 + strb r0, [\deststrptr], #1 + teq r0, #0 + bne 1b + sub \deststrptr, \deststrptr, #1 /* Adjust Destination string pointer to point at NULL character */ + .endm + +/* _dbg_outputMsgValidResponse + * Return Message with valid response ('+$') + * On exit: + * R0: destroyed + * R1: points to NULL character after the prefix + * R2: destroyed + */ + .macro _dbg_outputMsgValidResponse + ldr r1, =debug_OutMsgBuf + ldr r2, =debug_ValidResponsePrefix + _dbg_stpcpy r1, r2 + .endm + + +/* _dbg_outputMsgStatusOk + * Return Message with Ok ('+OK') status + * On exit: + * R0: destroyed + * R1: destroyed + * R2: destroyed + */ + .macro _dbg_outputMsgStatusOk + ldr r1, =debug_OutMsgBuf + ldr r2, =debug_OkResponse + _dbg_stpcpy r1, r2 + .endm + +/* _dbg_outputMsgStatusErr + * Return Message with Error ('-ENN') status + * On entry: + * R0: register containing error value (byte) + * On exit: + * R0: destroyed + * R1: destroyed + * R2: destroyed + * R3: destroyed + */ + .macro _dbg_outputMsgStatusErr + mov r3, r0 + ldr r1, =debug_OutMsgBuf + ldr r2, =debug_ErrorResponsePrefix + _dbg_stpcpy r1, r2 + mov r0, r3 + bl byte2ascii /* R1 points to NULL character after the prefix */ + .endm + +/* _dbg_outputMsgStatusSig + * Return Message with Signal ('+SNN') status + * On entry: + * R0: register containing error value (byte) + * On exit: + * R0: destroyed + * R1: destroyed + * R2: destroyed + * R3: destroyed + */ + .macro _dbg_outputMsgStatusSig + mov r3, r0 + ldr r1, =debug_OutMsgBuf + ldr r2, =debug_SignalResponsePrefix + _dbg_stpcpy r1, r2 + mov r0, r3 + bl byte2ascii /* R1 points to NULL character after the prefix */ + .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 + ldr \reg, [\reg] + .endm + +/* _dbg_setstate + * Set Debugger State to given value + * On exit: + * r0, r1: destroyed + */ + .macro _dbg_setstate state + ldr r0, =\state + ldr r1, =debug_state + str 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 + ldr \reg, [\reg] + .endm + +/* _dbg_setcurrbkpt_index + * Set current breakpoint index + * On exit: + * r1: destroyed + */ + .macro _dbg_setcurrbkpt_index reg + ldr r1, =debug_curr_breakpoint + str \reg, [r1] + .endm + +/* _dbg_getabortedinstr_addr + * Get aborted instruction address + * On exit: + * reg: aborted instruction address + */ + .macro _dbg_getabortedinstr_addr reg + ldr \reg, =__debugger_stack_bottom__ + ldr \reg, [\reg] + .endm + +/* _dbg_setabortedinstr_addr + * Set aborted instruction address + * On exit: + * r1: destroyed + */ + .macro _dbg_setabortedinstr_addr reg + ldr r1, =__debugger_stack_bottom__ + str \reg, [r1] + .endm + + + +/* 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 breakpoints for programs executed from Flash in the AT91SAM7S which lacks a hardware + * Debug interface. + * + * 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__ + * User Mode R15 + * User Mode R14 + * ... + * User Mode R02 + * User Mode R01 + * User Mode R00 + * User Mode CPSR (UNDEF SPSR) + * Bkpt Instr Addr __debugger_stack_bottom__ + * [Low Memory Address] + * + * Each Breakpoint State will initially be zeroed. + * + */ + +/**************************************************************************** + * + * GDB Debugger Init and Breakpoint Handler Routines + * + ****************************************************************************/ + + .global dbg__bkpt_init +/* dbg__bkpt_init + * GDB set_debug_traps() routine + */ +dbg__bkpt_init: + stmfd sp!, {lr} + bl _dbg__clear_breakpoints + mov r0, #0 + ldr r1, =debug_curr_breakpoint + str r0, [r1] + ldr r1, =debug_InMsgBuf + strb r0, [r1] + ldr r1, =debug_OutMsgBuf + strb r0, [r1] + +/* FIXME: Initialize other stuff here */ + _dbg_setstate DBG_INIT + ldmfd sp!, {pc} + + +/* _dbg__flush_icache + * Flush the Instruction cache + * Defined by GDB Stub, but not needed for ARMv4T architecture + */ +_dbg__flush_icache: + /* nop */ + bx lr + + + .global dbg__bkpt_handler +/* dbg__bkpt_handler + * GDB handle_exception() routine + */ +dbg__bkpt_handler: +/* On entry, r0 contains breakpoint index value */ +/* FIXME: Currently we only deal with ARM mode, Thumb mode checks are missing! */ + mov r4, #BKPT32_AUTO_BKPT + and r4, r0, #BKPT32_AUTO_BKPT /* keep AUTO flag value in r4 */ + bic r0, r0, #BKPT32_AUTO_BKPT /* mask out AUTO flag */ + _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ + ldr r1, =BKPT32_MANUAL_BKPT + teq r0, r1 + beq _process_manual_breakpoint + ldr r1, =__breakpoints_num__ + cmp r0, r1 /* Sanity check that index is in range */ + bhs dbg__bkpt_offset_outofrange +/* Valid index value found */ + teq r4, #0 /* Check if AUTO flag set */ + bne _process_auto_breakpoint +/* else */ + bl _dbg__restore_breakpoints + bl _dbg__restore_singlestep + bl _dbg__clear_singlestep + bl _dbg__flush_icache + _dbg_setstate DBG_NORMAL_BKPT_ARM + b dbg__bkpt_waitCMD + +_process_auto_breakpoint: +/* Load Auto BKPT for Breakpoint index given in r0 */ + _index2bkptindex_addr r0, r1 /* Calculate Breakpoint Entry Address */ + ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 /* Check that Breakpoint is active */ + beq dbg__bkpt_inactive + bl _dbg__activate_one_breakpoint + bl _dbg__restore_singlestep + bl _dbg__clear_singlestep + b __dbg__resume_execution + +_process_manual_breakpoint: + _dbg_setstate DBG_MANUAL_BKPT_ARM +/* b dbg__bkpt_waitCMD */ + +dbg__bkpt_inactive: +/* b dbg__bkpt_waitCMD */ + +dbg__bkpt_offset_outofrange: +/* b dbg__bkpt_waitCMD */ + + .global dbg__bkpt_waitCMD +/* dbg__bkpt_waitCMD + * GDB Stub Remote Command Handler + */ + +/**************************************************************************** + * + * GDB Server Command Processing Routines + * + ****************************************************************************/ +dbg__bkpt_waitCMD: +1: bl dbg__hasDebugMsg /* Check for messages */ + beq 1b /* Busy wait */ + bl dbg__getDebugMsg /* Read new message from Debugger, message buffer addr in R0, NULL if error */ + teq r0, #0 + moveq r0, #MSG_ERRCHKSUM /* Message invalid, checksum error? */ + beq _dbg__cmdError /* Send response to GDB server */ +/* Message now has $\0 */ + mov r4, r0 /* Use R4 as Message Buffer pointer */ + ldrb r0, [r4], #1 /* Look for '$' */ + teq r0, #MSGBUF_STARTCHAR + beq _dbg__cmdError /* Shouldn't happen */ + ldrb r0, [r4], #1 /* Look for command char */ + bl _dbg__cmdChar2Index /* Index in R0 */ + ldr r1, =MSGBUF_CMDINDEX_OUTOFRANGE_VAL + teq r0, r1 + moveq r0, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */ + beq _dbg__cmdError /* Send response to GDB server */ + +_dbg__cmdValid: + stmfd sp!, {r0, r4} + _dbg_outputMsgValidResponse /* Setup R1 with address of output message buffer data pointer (after response prefix) */ + ldmfd sp!, {r3} /* Command Handler Index */ + ldmfd sp!, {r0} /* R1 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 + +_dbg__cmdError: + _dbg_outputMsgStatusErr + bl dbg__putDebugMsg /* Send error response to the GDB server */ + b dbg__bkpt_waitCMD + + +/* _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) + */ +_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], #1 /* Get table entry */ + teq r2, #0 + moveq r0, #MSGBUF_CMDINDEX_OUTOFRANGE_VAL /* 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__procGetOneReg + * Get One Register Value Command Handler + * On entry: + * r0: parameter buffer (contents after '$' and '') + * r1: output message buffer + */ +_dbg__procGetOneReg: + bx lr + +/* _dbg__nop + * NOP Command Handler (placeholder) + * On entry: + * r0: parameter buffer (contents after '$' and '') + * r1: output message buffer + */ +_dbg__nop: + bx lr /* Dummy, just return */ + + +/* dbg__cmd_install_breakpoint + * Configure Breakpoint + * On entry: + * r0: index of breakpoint to install + * r1: instruction address to install + */ +dbg__cmd_install_breakpoint: + bl _dbg__install_one_breakpoint /* r0: index, r1: instruction address */ + b dbg__bkpt_waitCMD + +/* dbg__cmd_clear_breakpoint + * Clear Breakpoint + * On entry: + * r0: index of breakpoint to clear + */ +dbg__cmd_clear_breakpoint: + _index2bkptindex_addr r0, r0 /* Calculate Breakpoint Entry Address */ + bl _dbg__clear_one_breakpoint + b dbg__bkpt_waitCMD + + +/* dbg__cmd_run + * Continue execution of program + */ +dbg__cmd_run: + bl _dbg__activate_breakpoints + b __dbg__resume_execution + +/* dbg__cmd_step + * Single Step execution of program + */ +dbg__cmd_step: + bl _dbg_next_instruction_addr /* next instruction address returned in r1 */ + bl _dbg__install_singlestep /* Setup Single Step */ + bl _dbg__activate_singlestep + b __dbg__resume_execution + +/* dbg__cmd_cont + * Continue execution of program. + * If this is a Normal Breakpoint, then we need to install an Autobreakpoint at next instruction address + * and resume from current (Breakpoint) exception address + * Else (it is a Manual Breakpoint) + * We need to resume from the next instruction address + */ +dbg__cmd_cont: +/* FIXME: What happens if we call this when we did not stop at a Breakpoint previously? */ + _dbg_getstate r0 + ldr r1, =DBG_MANUAL_BKPT_ARM + teq r0, r1 + beq __dbg_is_manual_breakpoint + + bl _dbg_next_instruction_addr /* next instruction address returned in r1 */ + bl _dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ + _dbg_getcurrbkpt_index r0 /* load current breakpoint index in memory */ + bl _dbg__activate_autobreakpoint /* pass next instruction address in r1 */ + b __dbg__resume_execution + +__dbg_is_manual_breakpoint: + bl _dbg_next_instruction_addr /* Skip Manual Breakpoint Instruction(s) */ + bl _dbg__activate_breakpoints + b __dbg__resume_execution + +/**************************************************************************** +// 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; + } +} + + ****************************************************************************/ + + +/* _dbg_next_instruction_addr + * Determine the address of the next instruction to execute. + * On exit: + * R1: Instruction Address (31 bits, b0 = THUMB flag) + * + * Here we make use of the Debugger Stack which contains the address of the aborted instruction that will be reexecuted + * when we resume the program. + * + * If it is a Manual Breakpoint inserted into the code, then we will need to update the aborted instruction + * address to skip the current aborted instruction and resume execution at the next instruction address, + * and the next instruction address to be returned to the calling routine is the following instruction + * address instead. + * + * We need to check the aborted instruction type, to see if it is a branch instruction, before we can determine + * the next instruction address (for inserting a Breakpoint). + */ +_dbg_next_instruction_addr: +/* FIXME: Currently we only deal with ARM mode, Thumb mode checks are missing! */ +/* 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 + */ + _dbg_getabortedinstr_addr r2 /* Retrieve aborted instruction address */ +1: ldr r0, [r2] /* Read actual instruction from memory */ + ldr r1, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */ + teq r0, r1 + bne 2f /* Not Manual breakpoint */ + add r2, r2, #4 /* Is Manual Breakpoint, Skip to next ARM instruction */ + _dbg_setabortedinstr_addr r2 /* Update aborted instruction address */ + b 1b /* To protect against a sequence of Manual Breakpoint Instructions */ + +/* Here, r0 contains the instruction which will be reexecuted when program resumes. We need to dissect it to see if + * it is a branch instruction. + */ +2: +@@@@@@@@@ + bx lr + +/* __dbg__resume_execution + * cleanup, resume execution of program. + * Restore User Mode Regsiters from Debugger Stack, and resume execution from aborted instruction + */ +__dbg__resume_execution: +@@@@@@ + bl _dbg__flush_icache + b __dbg__resume_execution + + + +/**************************************************************************** + * + * Breakpoint Manipulation Routines + * + ****************************************************************************/ + +/* _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} + +/* _dbg__install_singlestep + * Install the Single Step Breakpoint + * On entry: + * R1: Instruction Address (31 bits, b0 = THUMB flag) + */ +_dbg__install_singlestep: + mov r0, #0 +/* b _dbg__install_one_breakpoint */ + +/* _dbg__install_one_breakpoint + * Install breakpoint entry into Breakpoint State Table + * On entry: + * R0: Breakpoint index (assumed valid) + * R1: Instruction Address (31 bits, b0 = THUMB flag) + * + * On exit: + * R2: Breakpoint Instruction + * R3: Breakpoint Entry address + */ +_dbg__install_one_breakpoint: +/* Check for Thumb bit */ + tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ +/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ + ldreq r2, [r1] /* if 0: load ARM instruction from address location */ + ldrneh r2, [r1] /* else load Thumb instruction */ + _index2bkptindex_addr r0, r3 /* Calculate Breakpoint Entry Address */ + stm r3, {r1, r2} + bx lr + + +/* _dbg__restore_singlestep + * Restores the contents of the single step breakpoint to memory + */ +_dbg__restore_singlestep: + mov r0, #0 /* single step breakpoint index */ + _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */ + ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 + bxeq lr /* Exit if not active */ +/* b _dbg__restore_one_breakpoint */ + +/* _dbg__restore_one_breakpoint + * Restores the contents to memory for one breakpoint + * On entry: + * R0: Breakpoint index (assumed valid) [not used -- can be used for validating BKPT] + * R1: Breakpoint Address (assumed valid) + * R2: Breakpoint Instruction (assumed valid) + */ +_dbg__restore_one_breakpoint: +/* Check for Thumb bit */ + tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ +/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ + streq r2, [r1] /* if 0: restore ARM instruction to address location */ + bicne r1, #BKPT_STATE_THUMB_FLAG /* else, clear Thumb Flag */ + strneh r2, [r1] /* store Thumb instruction */ + bx lr + +/* _dbg__restore_breakpoints + * Routine iterates through the array of breakpoints (incl single step breakpoint) and restores the contents to memory + * Only Active breakpoints (i.e., Non-zero Address) are processed. + */ +_dbg__restore_breakpoints: + stmfd sp!, {lr} + ldr r5, =_dbg__restore_one_breakpoint + b __dbg__iterate_breakpoint_array + +/* _dbg__activate_singlestep + * Activate the single step breakpoint to memory + */ +_dbg__activate_singlestep: + mov r0, #0 /* single step breakpoint index */ + _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */ + ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 + bxeq lr /* Exit if not active */ +/* b _dbg__activate_one_breakpoint */ + +/* _dbg__activate_one_breakpoint + * Activate one breakpoint to memory + * On entry: + * R0: Breakpoint index (assumed valid) + * R1: Breakpoint Address (assumed valid) + * R2: Breakpoint Instruction (assumed valid) + */ +_dbg__activate_one_breakpoint: +/* Check for Thumb bit */ + tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ + bne _nx_is_thumb_bp +_nx_is_arm_bp: +/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ + ldr r3, [r1] /* if 0: load ARM instruction from address location */ + teq r2, r3 /* check that the two instructions are identical */ + bne _dbg__breakpoint_invalid_arm + ldr r2, =BKPT32_INSTR /* ARM BKPT instruction */ + and 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 */ + and r2, r2, r0 /* Merge Breakpoint index */ + strh r2, [r1] /* Store it into memory location */ +_dbg__breakpoint_invalid_thumb: + bx lr + +/* _dbg__activate_breakpoints + * Routine iterates through the array of breakpoints (incl single step breakpoint) and activates them + * Only Active breakpoints (i.e., Non-zero Address) are processed. + */ +_dbg__activate_breakpoints: + stmfd sp!, {lr} + ldr r5, =_dbg__activate_one_breakpoint + b __dbg__iterate_breakpoint_array + + +/* __dbg__iterate_breakpoint_array + * Common routine iterates through the array of breakpoints (incl single step breakpoint) + * and executes routine given in R5, passing: + * R0: Breakpoint index + * R1: Breakpoint Address + * R2: Breakpoint Instruction + * + * On Entry: + * Assumes that lr has been push to stack (routine can't be called directly) + * + * Only Active breakpoints (i.e., Non-zero Address entries) are processed. + */ +__dbg__iterate_breakpoint_array: + ldr r4, =__breakpoints_end__ /* start from top of the table (Assume __breakpoints_end__ > __breakpoints_start__) */ + ldr r3, =__breakpoints_start__ /* end address check */ + ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */ +4: sub r0, r0, #1 /* Decrement breakpoint index in r0 */ + ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 /* Is it active? */ + movne lr, pc + bxne r5 /* active entry */ + cmp r4, r3 + bhi 4b /* if (pointer > start of Breakpoint Table address), get next slot */ + ldmfd sp!, {pc} + +/* _dbg__activate_autobreakpoint + * Activate all other breakpoints except current breakpoint, activate auto breakpoint in next instr slot + * On entry: + * R0: Current Breakpoint index (assumed valid) + * R1: Next Instruction address (for AUTO Breakpoint) [Not used, assume Single Step Breakpoint already has correct info] + */ +_dbg__activate_autobreakpoint: + stmfd sp!, {lr} + mov r5, r0 /* Keep Current Breakpoint Index in r5 */ + ldr r4, =__breakpoints_end__ /* start from top of the table */ + ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */ +4: subs r0, r0, #1 /* Decrement breakpoint index in r0 */ + ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + bls 5f /* Flag set by subs instruction previously. Reached Single Step, go activate AUTO Breakpoint */ + teq r0, r5 /* Is it the Current Breakpoint? */ + beq 4b /* Yes, so skip */ + teq r1, #0 /* Is it active? */ + blne _dbg__activate_one_breakpoint /* active entry */ + b 4b /* Next iteration */ +5: +/* Here, r1: Breakpoint Address, r2: Breakpoint Instruction */ + tst r1, #BKPT_STATE_THUMB_FLAG /* Check for Thumb bit -- 1: Thumb instruction */ + orreq r0, r5, #BKPT32_AUTO_BKPT /* Is ARM Instruction, merge AUTO flag with Current Breakpoint Index */ + orrne r0, r5, #BKPT16_AUTO_BKPT /* Is Thumb Instruction, merge AUTO flag with Current Breakpoint Index */ + bl _dbg__activate_one_breakpoint /* Activate AUTO Breakpoint */ + ldmfd sp!, {pc} + diff --git a/AT91SAM7S256/Debugger/debug_stub.h b/AT91SAM7S256/Debugger/debug_stub.h new file mode 100644 index 0000000..15f087f --- /dev/null +++ b/AT91SAM7S256/Debugger/debug_stub.h @@ -0,0 +1,149 @@ +/** @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. + * + * Redistribution of this file is permitted under + * the terms of the GNU Public License (GPL) version 2. + */ + +#ifndef __DEBUG_STUB_H__ +#define __DEBUG_STUB_H__ + +#include "_c_arm_macros.h" + +#ifndef __ASSEMBLY__ +#include "types.h" +#endif + +/** @addtogroup debugger */ +/*@{*/ + + +/* Declarations go here. */ +/** @name Debug Message Constants. + * + * Debug Message Values + */ +/*@{*/ +#define MSGBUF_SIZE 256 /* Debug Message Buffer Size */ +#define MSGBUF_STARTCHAR '$' +#define MSGBUF_ACKCHAR '+' +#define MSGBUF_NAKCHAR '-' +#define MSGBUF_ERRCHAR 'E' +#define MSGBUF_SIGCHAR 'S' +#define MSG_ERRCHKSUM 1 +#define MSG_UNKNOWNCMD 2 +#define MSGBUF_CMDINDEX_OUTOFRANGE_VAL -1 + +/*@}*/ + +/** @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 BKPT suppport constants + * + * ARM and Thumb Breakpoint Instructions. + */ +/*@{*/ +#define BKPT32_INSTR 0xE1200070 /* ARM BKPT instruction */ +#define BKPT32_ENUM_MASK 0x000FFF0F /* ARM BKPT Enum Mask */ +#define BKPT32_AUTO_BKPT 0x00080000 /* ARM BKPT Auto-Step Flag (for CONT support) */ +#define BKPT32_MANUAL_BKPT 0x0007FF0F /* Manually inserted ARM Breakpoint */ + +#define BKPT16_INSTR 0xBE00 /* Thumb BKPT instruction (not supported currently) */ +#define BKPT16_ENUM_MASK 0x00FF /* Thumb BKPT Enum Mask */ +#define BKPT16_AUTO_BKPT 0x0080 /* Thumb BKPT Auto-Step Flag (for CONT support) */ +#define BKPT16_MANUAL_BKPT 0x007F /* Manually inserted Thumb Breakpoint */ +/*@}*/ + +/** 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_MANUAL_BKPT_ARM) /**< Manual ARM Breakpoint. */ +ENUM_VAL(DBG_NORMAL_BKPT_ARM) /**< Normal ARM Breakpoint (Single Step, Normal). */ +ENUM_VAL(DBG_MANUAL_BKPT_THUMB) /**< Manual Thumb Breakpoint. */ +ENUM_VAL(DBG_NORMAL_BKPT_THUMB) /**< Normal Thumb Breakpoint (Single Step, Normal). */ +ENUM_END(dbg_state_t) + +#ifndef __ASSEMBLY__ + +/* Define C stuff */ +/** @defgroup debug_public */ +/*@{*/ + + +/** Initialize Debugger. + * Equivalent to GDB set_debug_traps() routine + */ +FUNCDEF void dbg__bkpt_init(void); + +/** 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 inline void dbg_breakpoint_arm(void) { asm volatile (".word BKPT32_INSTR | BKPT32_MANUAL_BKPT") } + +/** dbg_breakpoint_thumb. + * Equivalent to GDB breakpoint() routine for Thumb code + */ +FUNCDEF inline void dbg_breakpoint_thumb(void) { asm volatile (".hword BKPT16_INSTR | BKPT16_MANUAL_BKPT") } + +/*@}*/ + +#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_arm + * 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/Debugger/types.h b/AT91SAM7S256/Debugger/types.h new file mode 100644 index 0000000..3a1d4cb --- /dev/null +++ b/AT91SAM7S256/Debugger/types.h @@ -0,0 +1,46 @@ +/** @file types.h + * @brief Basic type definitions for the Arm7 platform. + */ + +/* Copyright (c) 2007,2008 the NxOS developers + * + * 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. + */ + +#ifndef __NXOS_BASE_TYPES_H__ +#define __NXOS_BASE_TYPES_H__ + +/** @addtogroup typesAndUtils */ +/*@{*/ + +typedef unsigned char U8; /**< Unsigned 8-bit integer. */ +typedef signed char S8; /**< Signed 8-bit integer. */ +typedef unsigned short U16; /**< Unsigned 16-bit integer. */ +typedef signed short S16; /**< Signed 16-bit integer. */ +typedef unsigned long U32; /**< Unsigned 32-bit integer. */ +typedef signed long S32; /**< Signed 32-bit integer. */ + +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ U32 /**< Used to go conform with gcc, otherwise we are + risking an error because of conflicting types for size_t */ +#endif +typedef __SIZE_TYPE__ size_t; /**< Abstract size type, needed by the memory allocator. */ + +typedef U8 bool; /**< Boolean data type. */ +#define FALSE (0) /**< False boolean value. */ +#define TRUE (!FALSE) /**< True boolean value. */ + +#ifndef NULL +/** Definition of the NULL pointer. */ +#define NULL ((void*)0) +#endif + +/** A function that takes no arguments and returns nothing. */ +typedef void (*nx_closure_t)(void); + +/*@}*/ + +#endif -- cgit v1.2.3 From b5a5c69833107e68e7f612702d90870a681a63fb Mon Sep 17 00:00:00 2001 From: TC Wan Date: Mon, 29 Nov 2010 18:38:45 +0800 Subject: fixed comment regarding hardware debugging support --- AT91SAM7S256/Debugger/debug_stub.S | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/AT91SAM7S256/Debugger/debug_stub.S b/AT91SAM7S256/Debugger/debug_stub.S index 3aa2cb7..f9c7f9a 100644 --- a/AT91SAM7S256/Debugger/debug_stub.S +++ b/AT91SAM7S256/Debugger/debug_stub.S @@ -340,13 +340,15 @@ debug_cmdJumpTable: /* 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. + * 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 breakpoints for programs executed from Flash in the AT91SAM7S which lacks a hardware - * Debug interface. + * 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: -- cgit v1.2.3 From e77f061f50a25ac3dcbfb245f4c61fde2e7505ed Mon Sep 17 00:00:00 2001 From: TC Wan Date: Tue, 30 Nov 2010 13:24:12 +0800 Subject: initial get register handler Implemented Get Register Handler --- AT91SAM7S256/Debugger/debug_comm.S | 4 +- AT91SAM7S256/Debugger/debug_stub.S | 119 +++++++++++++++++++++++++++++++++---- AT91SAM7S256/Debugger/debug_stub.h | 25 +++++++- 3 files changed, 131 insertions(+), 17 deletions(-) diff --git a/AT91SAM7S256/Debugger/debug_comm.S b/AT91SAM7S256/Debugger/debug_comm.S index d6eaaa8..af69391 100644 --- a/AT91SAM7S256/Debugger/debug_comm.S +++ b/AT91SAM7S256/Debugger/debug_comm.S @@ -89,7 +89,7 @@ hex2char_lut: hex2char: stmfd sp!, {r1,lr} - and r0, #0x000F /* make sure that input is sane */ + and r0, #NIBBLE0 /* make sure that input is sane */ _hex2char r0, r1 ldmfd sp!, {r1,pc} @@ -100,7 +100,7 @@ hex2char: .global char2hex char2hex: - and r0, #0x00FF /* make sure that input is sane */ + and r0, #BYTE0 /* make sure that input is sane */ cmp r0, #'0' blo exit_char2hex cmp r0, #'F' diff --git a/AT91SAM7S256/Debugger/debug_stub.S b/AT91SAM7S256/Debugger/debug_stub.S index f9c7f9a..34bda59 100644 --- a/AT91SAM7S256/Debugger/debug_stub.S +++ b/AT91SAM7S256/Debugger/debug_stub.S @@ -63,10 +63,12 @@ * 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 from R0 to R15 + * 32-bit hex values in the sequence: + * User CPSR, R0, R1, ..., R15 * 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, '!' for User CPSR * * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN @@ -136,8 +138,9 @@ debug_OkResponse: debug_cmdIndexTable: .byte 'g','G','p','P','m','M','c','s','k','?',0 -/* Command Handlers expect the address pointer to the parameter buffer (contents after '$' and '') in R0 - * and the Output Message Buffer Address in R1 +/* Command Handlers + * On entry: + * R0: Input Message Parameter Buffer address pointer (points to contents after '$' and '') */ debug_cmdJumpTable: .word _dbg__procGetRegs /* 'g' */ @@ -259,6 +262,19 @@ debug_cmdJumpTable: bl byte2ascii /* R1 points to NULL character after the prefix */ .endm +/* _index2dbgstackaddr + * Convert debugger stack index to Debugger Stack register address + * + * On entry: + * indexreg contains debugger stack index value (0-max entries) + * On exit: + * indexreg: Breakpoint index (preserved) + * addrreg: Debugger Stack Register Address + */ + .macro _index2dbgstackaddr indexreg, addrreg + ldr \addrreg, =__debugger_stack_bottom__ + add \addrreg, \addrreg, \indexreg, lsl #2 /* Calculate Debugger Stack Register Address */ + .endm /* _index2bkptindex_addr * Convert Breakpoint index to breakpoing entry address @@ -494,7 +510,8 @@ dbg__bkpt_waitCMD: mov r4, r0 /* Use R4 as Message Buffer pointer */ ldrb r0, [r4], #1 /* Look for '$' */ teq r0, #MSGBUF_STARTCHAR - beq _dbg__cmdError /* Shouldn't happen */ + movne r0, #MSG_ERRFORMAT /* Message Format invalid (not '$') */ + bne _dbg__cmdError /* Shouldn't happen */ ldrb r0, [r4], #1 /* Look for command char */ bl _dbg__cmdChar2Index /* Index in R0 */ ldr r1, =MSGBUF_CMDINDEX_OUTOFRANGE_VAL @@ -502,11 +519,9 @@ dbg__bkpt_waitCMD: moveq r0, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */ beq _dbg__cmdError /* Send response to GDB server */ -_dbg__cmdValid: - stmfd sp!, {r0, r4} - _dbg_outputMsgValidResponse /* Setup R1 with address of output message buffer data pointer (after response prefix) */ - ldmfd sp!, {r3} /* Command Handler Index */ - ldmfd sp!, {r0} /* R1 now contains Input Message Buffer Parameter Pointer (previously in R4) */ +_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 @@ -522,12 +537,15 @@ _dbg__cmdError: * 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], #1 /* Get table entry */ +1: ldrb r2, [r3, r0] /* Get table entry */ teq r2, #0 moveq r0, #MSGBUF_CMDINDEX_OUTOFRANGE_VAL /* End of Index Table, Not found */ beq _exit_cmdIndexTable @@ -537,15 +555,90 @@ _dbg__cmdChar2Index: _exit_cmdIndexTable: bx lr +/* __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 r0, #MSG_UNKNOWNPARAM + _dbg_outputMsgStatusErr + bl dbg__putDebugMsg /* Send error response to the GDB server */ + ldmfd sp!, {pc} + + /* _dbg__procGetOneReg * Get One Register Value Command Handler + * Valid register parameter is from '0' to 'F' for User Mode Registers R0-R15 + * CPSR register parameer is '!' * On entry: - * r0: parameter buffer (contents after '$' and '') - * r1: output message buffer + * r0: parameter buffer pointer (contents after '$' and '') + * */ _dbg__procGetOneReg: - bx lr + stmfd sp!, {lr} + ldrb r2, [r0, #1] /* char after parameter value (Should be NULL character) */ + ldrb r0, [r0] /* Retrieve register index parameter to R0 */ + teq r2, #0 /* Check for NULL */ + bne __dbg__procCmdParamError /* Unexpected input, report error */ + teq r0, #MSGBUF_CPSRREG /* Check for CPSR register indicator */ + moveq r0, #DBGSTACK_USERCPSR_OFFSET /* Put offset from User Registers (-1) into index, so that after adjustment it points to CPSR slot */ + beq _dbg__procRegister /* Handle User CPSR */ + bl char2hex /* Convert to Hex value (assume input is valid) */ + cmp r0, #NIBBLE0 /* sanity check, (though it is not foolproof as input char in 0x0-0xF (ctrl-chars) will pass through) */ + bhi __dbg__procCmdParamError /* Non-hex char, report error */ + +_dbg__procRegister: + mov r3, r0 /* Keep register index safe */ + _dbg_outputMsgValidResponse /* Setup R1 with address of output message buffer data pointer (after response prefix) */ + mov r0, r3 /* Restore register index value */ + bl _dbg_outputOneRegValue /* update output buffer */ + bl dbg__putDebugMsg /* Send response to the GDB server */ + ldmfd sp!, {pc} + +/* _dbg_outputOneRegValue + * Given Register Index (-1: CPSR, 0-F: R0-R15), output hex char to buffer + * On entry: + * r0: register index (-1, 0-F) + * r1: output message buffer pointer + * On exit: + * r0: output message buffer pointer + * r1: updated (points to NULL character at end of Output Buffer) + * r2: destroyed + */ +_dbg_outputOneRegValue: + stmfd sp!, {lr} + add r2, r0, #DBGSTACK_USERREG_INDEX /* Convert register index to Debug Stack index */ + _index2dbgstackaddr r2, r0 /* Calculate address pointer to relevant register, result in R0 */ + ldr r0, [r0] /* Retrieve Register contents into R0 */ + bl word2ascii /* Convert and put hex chars into Output Message Buffer */ + ldmfd sp!, {pc} + +/* _dbg__procGetRegs + * Get All Register Values Command Handler + * Output Buffer returns register values in the order: User CPSR, R0, R1, R2, ..., R15 + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + */ +_dbg__procGetRegs: + stmfd sp!, {lr} + ldrb r0, [r0] /* Retrieve register index parameter to R0 */ + teq r0, #0 /* Check for NULL */ + bne __dbg__procCmdParamError /* Unexpected input, report error */ + + _dbg_outputMsgValidResponse /* Setup R1 with address of output message buffer data pointer (after response prefix) */ + mov r3, #DBGSTACK_USERCPSR_OFFSET /* Output User CPSR Value first */ +1: mov r0, r3 + bl _dbg_outputOneRegValue /* update output buffer */ + add r3, r3, #1 /* increment index */ + cmp r3, #0xF + ble 1b /* process all the registers */ + + bl dbg__putDebugMsg /* Send response to the GDB server */ + ldmfd sp!, {pc} + /* _dbg__nop * NOP Command Handler (placeholder) diff --git a/AT91SAM7S256/Debugger/debug_stub.h b/AT91SAM7S256/Debugger/debug_stub.h index 15f087f..9a120e5 100644 --- a/AT91SAM7S256/Debugger/debug_stub.h +++ b/AT91SAM7S256/Debugger/debug_stub.h @@ -38,10 +38,18 @@ #define MSGBUF_NAKCHAR '-' #define MSGBUF_ERRCHAR 'E' #define MSGBUF_SIGCHAR 'S' -#define MSG_ERRCHKSUM 1 -#define MSG_UNKNOWNCMD 2 +#define MSGBUF_CPSRREG '!' #define MSGBUF_CMDINDEX_OUTOFRANGE_VAL -1 +/*@}*/ +/** @name Debug Stack Constants. + * + * Debug Stack Manipulation Values + */ +/*@{*/ +#define DBGSTACK_USERCPSR_OFFSET (DBGSTACK_USERCPSR_INDEX-DBGSTACK_USERREG_INDEX) /* = -1, offset for calculating Debug Stack index */ +#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 */ /*@}*/ /** @name Bitmask Definitions. @@ -97,6 +105,19 @@ ENUM_VAL(DBG_MANUAL_BKPT_THUMB) /**< Manual Thumb Breakpoint. */ ENUM_VAL(DBG_NORMAL_BKPT_THUMB) /**< Normal Thumb Breakpoint (Single Step, Normal). */ ENUM_END(dbg_state_t) +/** Debugger Message Error Enums + * + * Debugger Error Message Enums. + * The enums must be consecutive, starting from 1 + */ +ENUM_BEGIN +ENUM_VALASSIGN(MSG_ERRCHKSUM, 1) /**< Checksum Error. */ +ENUM_VAL(MSG_ERRFORMAT) /**< Message Format Error. */ +ENUM_VAL(MSG_UNKNOWNCMD) /**< Unrecognized Command Error. */ +ENUM_VAL(MSG_UNKNOWNPARAM) /**< Unrecognized Parameter Error. */ +ENUM_END(dbg_msg_errno) + + #ifndef __ASSEMBLY__ /* Define C stuff */ -- cgit v1.2.3 From 6512a0b005edffc1e37b252e3a8262964ab2110a Mon Sep 17 00:00:00 2001 From: TC Wan Date: Tue, 30 Nov 2010 15:36:42 +0800 Subject: added interrupt handler and prelim support for thumb instructions Added Interrupt Handler routine for UNDEF exception. This should be integrated with the NXT Interrupt handlers. Updated debugger to have preliminary Thumb mode support. --- AT91SAM7S256/Debugger/debug_stub.S | 80 ++++++++++++++++++++++++++--------- AT91SAM7S256/Debugger/debug_stub.h | 15 ++++++- AT91SAM7S256/Debugger/undef_handler.S | 71 +++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 20 deletions(-) create mode 100644 AT91SAM7S256/Debugger/undef_handler.S diff --git a/AT91SAM7S256/Debugger/debug_stub.S b/AT91SAM7S256/Debugger/debug_stub.S index 34bda59..98bc968 100644 --- a/AT91SAM7S256/Debugger/debug_stub.S +++ b/AT91SAM7S256/Debugger/debug_stub.S @@ -440,20 +440,42 @@ _dbg__flush_icache: bx lr - .global dbg__bkpt_handler -/* dbg__bkpt_handler - * GDB handle_exception() routine + .global dbg__thumb_bkpt_handler +/* dbg__thumb_bkpt_handler + * GDB handle_exception() routine (Thumb Mode) */ -dbg__bkpt_handler: +dbg__thumb_bkpt_handler: +/* On entry, r0 contains breakpoint index value */ + mov r4, #BKPT16_AUTO_BKPT + and r4, r0, #BKPT16_AUTO_BKPT /* keep AUTO flag value in r4 */ + bic r0, r0, #BKPT16_AUTO_BKPT /* mask out AUTO flag */ + _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ + ldr r1, =BKPT16_MANUAL_BKPT + teq r0, r1 + beq _process_manual_breakpoint_thumb + ldr r1, =__breakpoints_num__ + cmp r0, r1 /* Sanity check that index is in range */ + bhs dbg__bkpt_offset_outofrange +/* Valid index value found */ + teq r4, #0 /* Check if AUTO flag set */ + bne _process_auto_breakpoint +/* else */ + _dbg_setstate DBG_NORMAL_BKPT_THUMB + b _process_normal_breakpoint + + .global dbg__arm_bkpt_handler +/* dbg__arm_bkpt_handler + * GDB handle_exception() routine (ARM Mode) + */ +dbg__arm_bkpt_handler: /* On entry, r0 contains breakpoint index value */ -/* FIXME: Currently we only deal with ARM mode, Thumb mode checks are missing! */ mov r4, #BKPT32_AUTO_BKPT and r4, r0, #BKPT32_AUTO_BKPT /* keep AUTO flag value in r4 */ bic r0, r0, #BKPT32_AUTO_BKPT /* mask out AUTO flag */ _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ ldr r1, =BKPT32_MANUAL_BKPT teq r0, r1 - beq _process_manual_breakpoint + beq _process_manual_breakpoint_arm ldr r1, =__breakpoints_num__ cmp r0, r1 /* Sanity check that index is in range */ bhs dbg__bkpt_offset_outofrange @@ -461,11 +483,14 @@ dbg__bkpt_handler: teq r4, #0 /* Check if AUTO flag set */ bne _process_auto_breakpoint /* else */ + _dbg_setstate DBG_NORMAL_BKPT_ARM +/* b _process_normal_breakpoint */ + +_process_normal_breakpoint: bl _dbg__restore_breakpoints bl _dbg__restore_singlestep bl _dbg__clear_singlestep bl _dbg__flush_icache - _dbg_setstate DBG_NORMAL_BKPT_ARM b dbg__bkpt_waitCMD _process_auto_breakpoint: @@ -479,7 +504,11 @@ _process_auto_breakpoint: bl _dbg__clear_singlestep b __dbg__resume_execution -_process_manual_breakpoint: +_process_manual_breakpoint_thumb: + _dbg_setstate DBG_MANUAL_BKPT_THUMB + b dbg__bkpt_waitCMD + +_process_manual_breakpoint_arm: _dbg_setstate DBG_MANUAL_BKPT_ARM /* b dbg__bkpt_waitCMD */ @@ -644,10 +673,13 @@ _dbg__procGetRegs: * NOP Command Handler (placeholder) * On entry: * r0: parameter buffer (contents after '$' and '') - * r1: output message buffer */ _dbg__nop: - bx lr /* Dummy, just return */ + stmfd sp!, {lr} + mov r0, #MSG_ERRIMPL /* Stub, not implemented yet */ + _dbg_outputMsgStatusErr + bl dbg__putDebugMsg /* Send error response to the GDB server */ + ldmfd sp!, {pc} /* dbg__cmd_install_breakpoint @@ -1188,18 +1220,28 @@ void __single_step (void) * the next instruction address (for inserting a Breakpoint). */ _dbg_next_instruction_addr: -/* FIXME: Currently we only deal with ARM mode, Thumb mode checks are missing! */ /* 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 */ - _dbg_getabortedinstr_addr r2 /* Retrieve aborted instruction address */ -1: ldr r0, [r2] /* Read actual instruction from memory */ - ldr r1, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */ - teq r0, r1 - bne 2f /* Not Manual breakpoint */ - add r2, r2, #4 /* Is Manual Breakpoint, Skip to next ARM instruction */ - _dbg_setabortedinstr_addr r2 /* Update aborted instruction address */ - b 1b /* To protect against a sequence of Manual Breakpoint Instructions */ + + mov r2, #DBGSTACK_USERCPSR_INDEX /* Retrieve User CPSR */ + _index2dbgstackaddr r2, r0 /* Calculate address pointer to relevant register, result in R0 */ + ldr r0, [r0] /* Retrieve Register contents into R0 */ + and r4, r0, #CPSR_THUMB /* store Thumb Mode status in R4 */ + + _dbg_getabortedinstr_addr r2 /* Retrieve aborted instruction address */ +1: teq r4, #0 /* Check if it is ARM or Thumb instruction */ + ldrneh r0, [r2] + ldrne r1, =(BKPT16_INSTR | BKPT16_MANUAL_BKPT) /* check for Thumb Manual Breakpoint Instruction */ + ldreq r0, [r2] + ldreq r1, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */ + teq r0, r1 + bne 2f /* Not Manual breakpoint */ + teq r4, #0 /* Check if it is ARM or Thumb instruction */ + addne r2, r2, #2 /* Is Manual Breakpoint, Skip to next Thumb instruction */ + addeq r2, r2, #4 /* Is Manual Breakpoint, Skip to next ARM instruction */ + _dbg_setabortedinstr_addr r2 /* Update aborted instruction address */ + b 1b /* To protect against a sequence of Manual Breakpoint Instructions */ /* Here, r0 contains the instruction which will be reexecuted when program resumes. We need to dissect it to see if * it is a branch instruction. diff --git a/AT91SAM7S256/Debugger/debug_stub.h b/AT91SAM7S256/Debugger/debug_stub.h index 9a120e5..7849d56 100644 --- a/AT91SAM7S256/Debugger/debug_stub.h +++ b/AT91SAM7S256/Debugger/debug_stub.h @@ -39,6 +39,7 @@ #define MSGBUF_ERRCHAR 'E' #define MSGBUF_SIGCHAR 'S' #define MSGBUF_CPSRREG '!' +#define MSGBUF_SETCHAR '=' #define MSGBUF_CMDINDEX_OUTOFRANGE_VAL -1 /*@}*/ @@ -75,6 +76,17 @@ #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 + +/*@}*/ + /** @name BKPT suppport constants * * ARM and Thumb Breakpoint Instructions. @@ -111,7 +123,8 @@ ENUM_END(dbg_state_t) * The enums must be consecutive, starting from 1 */ ENUM_BEGIN -ENUM_VALASSIGN(MSG_ERRCHKSUM, 1) /**< Checksum Error. */ +ENUM_VALASSIGN(MSG_ERRIMPL, 0) /**< Stub (not implemented) Error. */ +ENUM_VAL(MSG_ERRCHKSUM) /**< Checksum Error. */ ENUM_VAL(MSG_ERRFORMAT) /**< Message Format Error. */ ENUM_VAL(MSG_UNKNOWNCMD) /**< Unrecognized Command Error. */ ENUM_VAL(MSG_UNKNOWNPARAM) /**< Unrecognized Parameter Error. */ diff --git a/AT91SAM7S256/Debugger/undef_handler.S b/AT91SAM7S256/Debugger/undef_handler.S new file mode 100644 index 0000000..c160179 --- /dev/null +++ b/AT91SAM7S256/Debugger/undef_handler.S @@ -0,0 +1,71 @@ + +/* 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" + +#define MODE_SVC 0x13 /* Supervisor mode. */ + +.text +.code 32 +.align 0 + + .extern dbg__thumb_bkpt_handler + .extern dbg__arm_bkpt_handler + + .global undef_handler + +undef_handler: +/* Remote GDB Debugger relies on BKPT instruction being trapped here + In ARMv4t, it is an Illegal (Undefined) Instruction. + On triggering, lr (R14) contains the previous mode's pc (R15). + Based on example in Hohl, "ARM Assembly Language: Fundamentals and Techniques" + Chapter 11, Example 11.1. + Note: The handler is not AAPCS compliant (8 byte-alignment and stack, etc.) + */ + /* We assume that the UNDEF stack has been setup previously + On entry, LR_undef points to one instruction past the UNDEF instruction + */ + ldr sp, =__debugger_stack__ + stmfd sp, {r0-r15}^ /* Save workspace, user mode's pc via 'S' flag */ + sub sp, sp, #(4*16) /* Need to manually update SP(undef) */ + mrs r1, spsr /* Copy SPSR to r0 */ + sub r0, lr, #-4 /* LR points to instruction after UNDEF instruction */ + stmfd sp!, {r0,r1} /* Save UNDEF instruction addr and previous mode's CPSR to stack */ + 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 */ + and r0, r1, r0 /* Keep index value */ + msr cpsr_c, #(MODE_SVC) /* Configure Supervisor Mode */ + ldr lr, =dbg__thumb_bkpt_handler /* handle BKPT, BKPT index in r0 */ + mov pc, lr /* Invoke Debugger State (Supervisor Mode) */ +_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 */ + and r0, r1, r0 /* Keep index value */ + msr cpsr_c, #(MODE_SVC) /* Configure Supervisor Mode */ + ldr lr, =dbg__arm_bkpt_handler /* handle BKPT, BKPT index in r0 */ + mov pc, lr /* Invoke Debugger State (Supervisor Mode) */ + + +default_undef_handler: + b default_undef_handler /* Infinite loop */ -- cgit v1.2.3 From 238f1f715c01d052a9dc19db079c1f97bcd3b53c Mon Sep 17 00:00:00 2001 From: TC Wan Date: Tue, 30 Nov 2010 15:56:53 +0800 Subject: added linker definitions to support debugger The contents of this file should be merged with the NXT Firmware linker file. --- AT91SAM7S256/Debugger/debug_stack.ld | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 AT91SAM7S256/Debugger/debug_stack.ld diff --git a/AT91SAM7S256/Debugger/debug_stack.ld b/AT91SAM7S256/Debugger/debug_stack.ld new file mode 100644 index 0000000..df27512 --- /dev/null +++ b/AT91SAM7S256/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 user mode registers + SPSR + BKPT Instr Addr */ + __debugger_stack__ = .; + __debugger_stack_top__ = . ; + + /* breakpoints */ + __breakpoints_start__ = . ; + . += 0x40; /* Single Stepping Breakpoint + 7 Breakpoints */ + __breakpoints_end__ = . ; + +/* Symbols */ + __breakpoints_num__ = (__breakpoints_end__ - __breakpoints_start__) / 8; -- cgit v1.2.3 From 3d5bdf9fba6442332030e68df2aa7880a894842d Mon Sep 17 00:00:00 2001 From: TC Wan Date: Wed, 1 Dec 2010 13:40:54 +0800 Subject: restructure repository --- AT91SAM7S256/Debugger/_c_arm_macros.h | 149 ---- AT91SAM7S256/Debugger/debug_comm.S | 286 ------- AT91SAM7S256/Debugger/debug_stack.ld | 15 - AT91SAM7S256/Debugger/debug_stub.S | 1469 --------------------------------- AT91SAM7S256/Debugger/debug_stub.h | 183 ---- AT91SAM7S256/Debugger/types.h | 46 -- AT91SAM7S256/Debugger/undef_handler.S | 71 -- Debugger/_c_arm_macros.h | 149 ++++ Debugger/debug_comm.S | 286 +++++++ Debugger/debug_stack.ld | 15 + Debugger/debug_stub.S | 1469 +++++++++++++++++++++++++++++++++ Debugger/debug_stub.h | 183 ++++ Debugger/types.h | 46 ++ Debugger/undef_handler.S | 71 ++ 14 files changed, 2219 insertions(+), 2219 deletions(-) delete mode 100644 AT91SAM7S256/Debugger/_c_arm_macros.h delete mode 100644 AT91SAM7S256/Debugger/debug_comm.S delete mode 100644 AT91SAM7S256/Debugger/debug_stack.ld delete mode 100644 AT91SAM7S256/Debugger/debug_stub.S delete mode 100644 AT91SAM7S256/Debugger/debug_stub.h delete mode 100644 AT91SAM7S256/Debugger/types.h delete mode 100644 AT91SAM7S256/Debugger/undef_handler.S create mode 100644 Debugger/_c_arm_macros.h create mode 100644 Debugger/debug_comm.S create mode 100644 Debugger/debug_stack.ld create mode 100644 Debugger/debug_stub.S create mode 100644 Debugger/debug_stub.h create mode 100644 Debugger/types.h create mode 100644 Debugger/undef_handler.S diff --git a/AT91SAM7S256/Debugger/_c_arm_macros.h b/AT91SAM7S256/Debugger/_c_arm_macros.h deleted file mode 100644 index f356a25..0000000 --- a/AT91SAM7S256/Debugger/_c_arm_macros.h +++ /dev/null @@ -1,149 +0,0 @@ -/** @file _c_arm_macros.h - * @brief Define macros to support shared C and ASM headers - * - */ - -/* Copyright (C) 2007,2009 the NxOS developers - * Thanks to Bartli (forum post @ embdev.net ARM programming with GCC/GNU tools forum) - * - * 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. - */ - -#ifndef __NXOS_BASE_C_ARM_MACROS__ -#define __NXOS_BASE_C_ARM_MACROS__ - -#ifdef __ASSEMBLY__ - -#define NULL 0x0 /* Stick the definition here instead of making types.h messy */ -#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) - -/** Macro to define driver ioctl table - * First five table entries are predefined - * 0: init - * 1: shutdown - * 2: sleep - * 3: wakeup - * 4: poll - * - */ -#define DRIVER_IOCTL(driver) \ -/* Dummy sleep and wakeup routines for now */ ;\ - .set driver ## _sleep, NULL ;\ - .set driver ## _wakeup, NULL ;\ - .set driver ## _poll, NULL ;\ -.data ;\ - .align 4 ;\ - .global driver ## _ioctl ;\ -driver ## _ioctl: ;\ - .word driver ## _init ;\ - .word driver ## _shutdown ;\ - .word driver ## _sleep ;\ - .word driver ## _wakeup ;\ - .word driver ## _poll ;\ - .set num_ ## driver ## _cmds, 5 - -/** Macro to define additional driver ioctl commands - * Be careful to follow the sequence defined for the CMD enums - * The first CMD should have an enum value of 5 - * - */ -#define DRIVER_CMD(driver, cmd) \ - .word driver ## _ ## cmd ;\ - .set num_ ## driver ## _cmds, num_ ## driver ## _cmds + 1 - -/** Macro to define driver state - * MUST BE DEFINED AFTER DRIVER_IOCTL section - * @param driver name of driver - * @param driverenum enum value of driver (in [31:25]) - * - * The number of commands for driver (in [24:17]) -- derived from num_driver_cmds - * - * Format of driver_state table: - * driver signature (driverenum << 24 | numcommands << 16) - * driver parameters (per device instance) - */ -#define DRIVER_STATE(driver, driverenum) \ -.bss ;\ - .global driver ## _state ;\ -driver ## _state: ;\ - .set driver ## _signature, (driverenum << 24) | (num_ ## driver ## _cmds << 16) ;\ - .word NULL /* driver_signature */ - - -/** Macro to define actual driver routine in .S - * On entry: - * r0 - address of driver_state - * r1-r3 - parameters (variable) - * r12 - number of parameters (IPC scratch register) - * Stack - parameters (variable) - */ -#define DRIVER_ROUTINE(driver, cmd) \ - .global driver ## _ ## cmd ## ;\ -driver ## _ ## cmd ## : - -#else -/** 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 - -ENUM_BEGIN -ENUM_VAL(INIT) /**< Driver Init Routine. */ -ENUM_VAL(SHUTDOWN) /**< Driver Shutdown Routine. */ -ENUM_VAL(SLEEP) /**< Driver Sleep Routine. */ -ENUM_VAL(WAKEUP) /**< Driver Wakeup Routine. */ -ENUM_VAL(POLL) /**< Driver Poll Routine. */ -ENUM_END(nx_driver_default_cmd) - - -#endif /* __NXOS_BASE_C_ARM_MACROS__ */ diff --git a/AT91SAM7S256/Debugger/debug_comm.S b/AT91SAM7S256/Debugger/debug_comm.S deleted file mode 100644 index af69391..0000000 --- a/AT91SAM7S256/Debugger/debug_comm.S +++ /dev/null @@ -1,286 +0,0 @@ - -/* 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" - -.data -.align 4 - -hex2char_lut: - .ascii "0123456789ABCDEF" - -/* Macros - */ - -/* _asciiz - * Terminate string given string buffer pointer in \addrptr - * reg is used as a scratch register (destroyed) - * - */ - .macro _asciiz reg, strptr - mov \reg, #0 /* NULL character */ - strb \reg, [\strptr] /* Terminate ASCIIZ string */ - .endm - -/* _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 - */ - -/* 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) - */ - .global char2hex - -char2hex: - and r0, #BYTE0 /* make sure that input is sane */ - cmp r0, #'0' - blo exit_char2hex - cmp r0, #'F' - bhi exit_char2hex - _char2hex r0 -exit_char2hex: - bx lr - -/* byte2ascii_cont - * This routine accepts a byte value in R0(7:0), and a ASCII buffer pointer in R1, - * and stores the ASCII equivalent byte value in the buffer pointed to by R1. - * Note: On return, R1 points to next empty char slot in buffer (i.e., R1 is modified) - * and R0 is destroyed. - */ -byte2ascii_cont: - stmfd sp!, {r2,r3,r4, lr} - mov r2, r0, lsl #24 /* Keep copy of input byte value R0(7:0), shifted to MSB R2(31:24) */ - mov r4, #2 /* Loop counter */ - _hex2char_lut r3 /* initialize LUT pointer */ -1: mov r0, r2, ror #28 /* Rotate MSNibble R2(31:28) into LSNibble position R0(3:0) */ - and r0, r0, #NIBBLE0 /* Mask out everything else */ - _hex2char_cont r0, r3 /* Convert nibble to ASCII char */ - strb r0, [r1], #1 - subs r4, r4, #1 /* decrement loop counter */ - bne 1b - ldmfd sp!, {r2,r3,r4, pc} - -/* byte2ascii - * This routine accepts a byte value in R0(7:0), and a ASCII buffer pointer in R1, - * and stores the ASCII equivalent byte value in the buffer pointed to by R1. - * Note: On return, R1 points to the end of the ASCIIZ string (i.e. NULL character) - */ - .global byte2ascii - -byte2ascii: - stmfd sp!, {r1, lr} /* Keep ASCII buffer pointer */ - and r0, #BYTE0 /* sanitize input */ - bl byte2ascii_cont - _asciiz r0, r1 - ldmfd sp!, {r0, pc} /* return string pointer in R0 */ - -/* halfword2ascii - * This routine accepts a halfword value in R0(15:0), and a ASCII buffer pointer in R1, - * and returns the ASCIIZ equivalent byte value in the buffer pointed to by R0. - * Note: On return, R1 points to the end of the ASCIIZ string (i.e. NULL character) - */ - .global halfword2ascii -halfword2ascii: - stmfd sp!, {r1,r2,r3, lr} /* Keep ASCII buffer pointer */ - mov r2, r0, lsl #16 /* copy of input halfword value R0(15:0), shifted to MSH R2(31:16) */ - mov r3, #2 /* Loop Counter */ - b _conv_byte2ascii /* goto Byte conversion loop */ - -/* word2ascii - * This routine accepts a word value in R0(31:0), and a ASCII buffer pointer in R1, - * and returns the ASCIIZ equivalent byte value in the buffer pointed to by R0. - * Note: On return, R1 points to the end of the ASCIIZ string (i.e. NULL character) - */ - .global word2ascii -word2ascii: - stmfd sp!, {r1,r2,r3, lr} /* Keep ASCII buffer pointer */ - mov r2, r0 /* copy of input word value R0(31:0) */ - mov r3, #4 /* Loop Counter */ - - /* Fall through to byte coversion loop */ - -_conv_byte2ascii: - mov r0, r2, ror #24 /* Rotate MSB R2(31:24) into LSB position R0(7:0) */ - and r0, #BYTE0 /* Mask out everything else */ - bl byte2ascii_cont - subs r3, r3, #1 - bne _conv_byte2ascii - _asciiz r0, r1 - ldmfd sp!, {r0,r2,r3, pc} - - -/* ascii2byte - * 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,r3, lr} - mov r3, #2 /* Loop counter */ - b _conv_ascii2byte - -/* ascii2halfword - * This routine accepts an ASCII buffer pointer in R0, - * and returns the word 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 - -ascii2halfword: - stmfd sp!, {r2,r3, lr} - mov r3, #4 /* Loop counter */ - b _conv_ascii2byte - - -/* ascii2word - * 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 - -ascii2word: - stmfd sp!, {r2,r3, lr} - mov r3, #8 /* Loop counter */ - - /* Fall through to byte coversion loop */ - -_conv_ascii2byte: - teq r0, #0 - beq _exit_conv_ascii2byte /* exit if NULL pointer in R0 */ - mov r0, r1 /* Copy of ASCII buffer pointer */ - mov r2, #0 /* Initialize results */ -2: ldrb r0, [r1], #1 /* Load ASCII char */ - bl char2hex /* on return, hex value in R0 */ - orr r2, r0, r2, lsl #4 /* merge Nibble into results */ - subs r3, r3, #1 - bne 2b - mov r0, r2 /* Copy it to R0 as return value */ -_exit_conv_ascii2byte: - ldmfd sp!, {r2,r3, pc} /* return hex value in R0 */ - - - - -/* 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. - * - */ - .global dbg__hasDebugMsg -/* dbg__hasDebugMsg - * Checks for pending Debugger Message (Non-Blocking). - * On exit: - * r0: Boolean (0: no pending message, 1: has pending message) - */ -dbg__hasDebugMsg: - bx lr - - .global dbg__getDebugMsg -/* dbg__getDebugMsg - * Returns Debugger Message to calling routine after verifying and removing checksum (Blocking). - * On entry: - * r0: address of message buffer - * r1: maximum size of message buffer (incl NULL character) - * On exit: - * r0: address of message buffer with NULL terminated message, excluding '#' - * (NULL if message error) - * - */ -dbg__getDebugMsg: - bx lr - - .global dbg__putDebugMsg -/* dbg__putDebugMsg - * Sends Debugger Message from calling routine after appending checksum (Blocking) . - * On entry: - * r0: address of message buffer with NULL terminated message, without '#' - * On exit: - * r0: status (0: success, -1: error) - */ -dbg__putDebugMsg: - bx lr - - -/* Private functions (if needed) */ -_dbg__getChar: -_dbg__putChar: - bx lr diff --git a/AT91SAM7S256/Debugger/debug_stack.ld b/AT91SAM7S256/Debugger/debug_stack.ld deleted file mode 100644 index df27512..0000000 --- a/AT91SAM7S256/Debugger/debug_stack.ld +++ /dev/null @@ -1,15 +0,0 @@ -/* The following linker definitions should be placed in the stack section */ - - /* debugger state */ - __debugger_stack_bottom__ = . ; - . += 0x48; /* 16 user mode registers + SPSR + BKPT Instr Addr */ - __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/Debugger/debug_stub.S b/AT91SAM7S256/Debugger/debug_stub.S deleted file mode 100644 index 98bc968..0000000 --- a/AT91SAM7S256/Debugger/debug_stub.S +++ /dev/null @@ -1,1469 +0,0 @@ - -/* 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. - */ - - /* 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 CPSR, R0, R1, ..., R15 - * 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, '!' for User CPSR - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * - * 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) - * - * 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 */ - - -/* FIXME: What about setting/clearing Breakpoints? */ - -#define __ASSEMBLY__ -#include "debug_stub.h" - -.bss -.align 4 -debug_state: - .word 0x0 -debug_curr_breakpoint: - .word 0x0 -debug_InMsgBuf: - .space MSGBUF_SIZE,0 -debug_OutMsgBuf: - .space MSGBUF_SIZE,0 - -.data -.align 4 -debug_ValidResponsePrefix: - .byte '+','$',0 - -debug_ErrorResponsePrefix: - .byte '-','$','E',0 - -debug_SignalResponsePrefix: - .byte '+','$','S',0 - -debug_OkResponse: - .byte '+','$','O','K',0 - -/* The CmdIndexTable and CmdJumpTable must be kept in sync */ -debug_cmdIndexTable: - .byte 'g','G','p','P','m','M','c','s','k','?',0 - -/* Command Handlers - * On entry: - * R0: Input Message Parameter Buffer address pointer (points to contents after '$' and '') - */ -debug_cmdJumpTable: - .word _dbg__procGetRegs /* 'g' */ - .word _dbg__procSetRegs /* 'G' */ - .word _dbg__procGetOneReg /* 'p' */ - .word _dbg__procSetOneReg /* 'P' */ - .word _dbg__nop /* 'm' */ - .word _dbg__nop /* 'M' */ - .word _dbg__nop /* 'c' */ - .word _dbg__nop /* 's' */ - .word _dbg__nop /* 'k' */ - .word _dbg__nop /* '?' */ - .word 0 - - -.code 32 -.text -.align 4 - .extern __breakpoints_num__ - .extern dbg__hasDebugMsg /* Check for message from the communications link */ - .extern dbg__getDebugMsg /* Read a message from the communications link */ - .extern dbg__putDebugMsg /* Write a message to the communications link */ - -/* _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_stpcpy - * _dbg_stpcpy macro - * On entry: - * deststrptr: Destination string [Cannot be R0] - * sourcestrptr: Source string [Cannot be R0] - * On exit: - * deststrptr: Pointer to NULL character in destination string - * R0: destroyed - */ - .macro _dbg_stpcpy deststrptr, sourcestrptr -1: ldrb r0, [\sourcestrptr], #1 - strb r0, [\deststrptr], #1 - teq r0, #0 - bne 1b - sub \deststrptr, \deststrptr, #1 /* Adjust Destination string pointer to point at NULL character */ - .endm - -/* _dbg_outputMsgValidResponse - * Return Message with valid response ('+$') - * On exit: - * R0: destroyed - * R1: points to NULL character after the prefix - * R2: destroyed - */ - .macro _dbg_outputMsgValidResponse - ldr r1, =debug_OutMsgBuf - ldr r2, =debug_ValidResponsePrefix - _dbg_stpcpy r1, r2 - .endm - - -/* _dbg_outputMsgStatusOk - * Return Message with Ok ('+OK') status - * On exit: - * R0: destroyed - * R1: destroyed - * R2: destroyed - */ - .macro _dbg_outputMsgStatusOk - ldr r1, =debug_OutMsgBuf - ldr r2, =debug_OkResponse - _dbg_stpcpy r1, r2 - .endm - -/* _dbg_outputMsgStatusErr - * Return Message with Error ('-ENN') status - * On entry: - * R0: register containing error value (byte) - * On exit: - * R0: destroyed - * R1: destroyed - * R2: destroyed - * R3: destroyed - */ - .macro _dbg_outputMsgStatusErr - mov r3, r0 - ldr r1, =debug_OutMsgBuf - ldr r2, =debug_ErrorResponsePrefix - _dbg_stpcpy r1, r2 - mov r0, r3 - bl byte2ascii /* R1 points to NULL character after the prefix */ - .endm - -/* _dbg_outputMsgStatusSig - * Return Message with Signal ('+SNN') status - * On entry: - * R0: register containing error value (byte) - * On exit: - * R0: destroyed - * R1: destroyed - * R2: destroyed - * R3: destroyed - */ - .macro _dbg_outputMsgStatusSig - mov r3, r0 - ldr r1, =debug_OutMsgBuf - ldr r2, =debug_SignalResponsePrefix - _dbg_stpcpy r1, r2 - mov r0, r3 - bl byte2ascii /* R1 points to NULL character after the prefix */ - .endm - -/* _index2dbgstackaddr - * Convert debugger stack index to Debugger Stack register address - * - * On entry: - * indexreg contains debugger stack index value (0-max entries) - * On exit: - * indexreg: Breakpoint index (preserved) - * addrreg: Debugger Stack Register Address - */ - .macro _index2dbgstackaddr indexreg, addrreg - ldr \addrreg, =__debugger_stack_bottom__ - add \addrreg, \addrreg, \indexreg, lsl #2 /* Calculate Debugger Stack Register Address */ - .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 - ldr \reg, [\reg] - .endm - -/* _dbg_setstate - * Set Debugger State to given value - * On exit: - * r0, r1: destroyed - */ - .macro _dbg_setstate state - ldr r0, =\state - ldr r1, =debug_state - str 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 - ldr \reg, [\reg] - .endm - -/* _dbg_setcurrbkpt_index - * Set current breakpoint index - * On exit: - * r1: destroyed - */ - .macro _dbg_setcurrbkpt_index reg - ldr r1, =debug_curr_breakpoint - str \reg, [r1] - .endm - -/* _dbg_getabortedinstr_addr - * Get aborted instruction address - * On exit: - * reg: aborted instruction address - */ - .macro _dbg_getabortedinstr_addr reg - ldr \reg, =__debugger_stack_bottom__ - ldr \reg, [\reg] - .endm - -/* _dbg_setabortedinstr_addr - * Set aborted instruction address - * On exit: - * r1: destroyed - */ - .macro _dbg_setabortedinstr_addr reg - ldr r1, =__debugger_stack_bottom__ - str \reg, [r1] - .endm - - - -/* 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__ - * User Mode R15 - * User Mode R14 - * ... - * User Mode R02 - * User Mode R01 - * User Mode R00 - * User Mode CPSR (UNDEF SPSR) - * Bkpt Instr Addr __debugger_stack_bottom__ - * [Low Memory Address] - * - * Each Breakpoint State will initially be zeroed. - * - */ - -/**************************************************************************** - * - * GDB Debugger Init and Breakpoint Handler Routines - * - ****************************************************************************/ - - .global dbg__bkpt_init -/* dbg__bkpt_init - * GDB set_debug_traps() routine - */ -dbg__bkpt_init: - stmfd sp!, {lr} - bl _dbg__clear_breakpoints - mov r0, #0 - ldr r1, =debug_curr_breakpoint - str r0, [r1] - ldr r1, =debug_InMsgBuf - strb r0, [r1] - ldr r1, =debug_OutMsgBuf - strb r0, [r1] - -/* FIXME: Initialize other stuff here */ - _dbg_setstate DBG_INIT - ldmfd sp!, {pc} - - -/* _dbg__flush_icache - * Flush the Instruction cache - * Defined by GDB Stub, but not needed for ARMv4T architecture - */ -_dbg__flush_icache: - /* nop */ - bx lr - - - .global dbg__thumb_bkpt_handler -/* dbg__thumb_bkpt_handler - * GDB handle_exception() routine (Thumb Mode) - */ -dbg__thumb_bkpt_handler: -/* On entry, r0 contains breakpoint index value */ - mov r4, #BKPT16_AUTO_BKPT - and r4, r0, #BKPT16_AUTO_BKPT /* keep AUTO flag value in r4 */ - bic r0, r0, #BKPT16_AUTO_BKPT /* mask out AUTO flag */ - _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ - ldr r1, =BKPT16_MANUAL_BKPT - teq r0, r1 - beq _process_manual_breakpoint_thumb - ldr r1, =__breakpoints_num__ - cmp r0, r1 /* Sanity check that index is in range */ - bhs dbg__bkpt_offset_outofrange -/* Valid index value found */ - teq r4, #0 /* Check if AUTO flag set */ - bne _process_auto_breakpoint -/* else */ - _dbg_setstate DBG_NORMAL_BKPT_THUMB - b _process_normal_breakpoint - - .global dbg__arm_bkpt_handler -/* dbg__arm_bkpt_handler - * GDB handle_exception() routine (ARM Mode) - */ -dbg__arm_bkpt_handler: -/* On entry, r0 contains breakpoint index value */ - mov r4, #BKPT32_AUTO_BKPT - and r4, r0, #BKPT32_AUTO_BKPT /* keep AUTO flag value in r4 */ - bic r0, r0, #BKPT32_AUTO_BKPT /* mask out AUTO flag */ - _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ - ldr r1, =BKPT32_MANUAL_BKPT - teq r0, r1 - beq _process_manual_breakpoint_arm - ldr r1, =__breakpoints_num__ - cmp r0, r1 /* Sanity check that index is in range */ - bhs dbg__bkpt_offset_outofrange -/* Valid index value found */ - teq r4, #0 /* Check if AUTO flag set */ - bne _process_auto_breakpoint -/* else */ - _dbg_setstate DBG_NORMAL_BKPT_ARM -/* b _process_normal_breakpoint */ - -_process_normal_breakpoint: - bl _dbg__restore_breakpoints - bl _dbg__restore_singlestep - bl _dbg__clear_singlestep - bl _dbg__flush_icache - b dbg__bkpt_waitCMD - -_process_auto_breakpoint: -/* Load Auto BKPT for Breakpoint index given in r0 */ - _index2bkptindex_addr r0, r1 /* Calculate Breakpoint Entry Address */ - ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ - teq r1, #0 /* Check that Breakpoint is active */ - beq dbg__bkpt_inactive - bl _dbg__activate_one_breakpoint - bl _dbg__restore_singlestep - bl _dbg__clear_singlestep - b __dbg__resume_execution - -_process_manual_breakpoint_thumb: - _dbg_setstate DBG_MANUAL_BKPT_THUMB - b dbg__bkpt_waitCMD - -_process_manual_breakpoint_arm: - _dbg_setstate DBG_MANUAL_BKPT_ARM -/* b dbg__bkpt_waitCMD */ - -dbg__bkpt_inactive: -/* b dbg__bkpt_waitCMD */ - -dbg__bkpt_offset_outofrange: -/* b dbg__bkpt_waitCMD */ - - .global dbg__bkpt_waitCMD -/* dbg__bkpt_waitCMD - * GDB Stub Remote Command Handler - */ - -/**************************************************************************** - * - * GDB Server Command Processing Routines - * - ****************************************************************************/ -dbg__bkpt_waitCMD: -1: bl dbg__hasDebugMsg /* Check for messages */ - beq 1b /* Busy wait */ - bl dbg__getDebugMsg /* Read new message from Debugger, message buffer addr in R0, NULL if error */ - teq r0, #0 - moveq r0, #MSG_ERRCHKSUM /* Message invalid, checksum error? */ - beq _dbg__cmdError /* Send response to GDB server */ -/* Message now has $\0 */ - mov r4, r0 /* Use R4 as Message Buffer pointer */ - ldrb r0, [r4], #1 /* Look for '$' */ - teq r0, #MSGBUF_STARTCHAR - movne r0, #MSG_ERRFORMAT /* Message Format invalid (not '$') */ - bne _dbg__cmdError /* Shouldn't happen */ - ldrb r0, [r4], #1 /* Look for command char */ - bl _dbg__cmdChar2Index /* Index in R0 */ - ldr r1, =MSGBUF_CMDINDEX_OUTOFRANGE_VAL - teq r0, r1 - moveq r0, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */ - beq _dbg__cmdError /* Send response to GDB server */ - -_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 - -_dbg__cmdError: - _dbg_outputMsgStatusErr - bl dbg__putDebugMsg /* Send error response to the GDB server */ - b dbg__bkpt_waitCMD - - -/* _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, #MSGBUF_CMDINDEX_OUTOFRANGE_VAL /* 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__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 r0, #MSG_UNKNOWNPARAM - _dbg_outputMsgStatusErr - bl dbg__putDebugMsg /* Send error response to the GDB server */ - ldmfd sp!, {pc} - - - -/* _dbg__procGetOneReg - * Get One Register Value Command Handler - * Valid register parameter is from '0' to 'F' for User Mode Registers R0-R15 - * CPSR register parameer is '!' - * On entry: - * r0: parameter buffer pointer (contents after '$' and '') - * - */ -_dbg__procGetOneReg: - stmfd sp!, {lr} - ldrb r2, [r0, #1] /* char after parameter value (Should be NULL character) */ - ldrb r0, [r0] /* Retrieve register index parameter to R0 */ - teq r2, #0 /* Check for NULL */ - bne __dbg__procCmdParamError /* Unexpected input, report error */ - teq r0, #MSGBUF_CPSRREG /* Check for CPSR register indicator */ - moveq r0, #DBGSTACK_USERCPSR_OFFSET /* Put offset from User Registers (-1) into index, so that after adjustment it points to CPSR slot */ - beq _dbg__procRegister /* Handle User CPSR */ - bl char2hex /* Convert to Hex value (assume input is valid) */ - cmp r0, #NIBBLE0 /* sanity check, (though it is not foolproof as input char in 0x0-0xF (ctrl-chars) will pass through) */ - bhi __dbg__procCmdParamError /* Non-hex char, report error */ - -_dbg__procRegister: - mov r3, r0 /* Keep register index safe */ - _dbg_outputMsgValidResponse /* Setup R1 with address of output message buffer data pointer (after response prefix) */ - mov r0, r3 /* Restore register index value */ - bl _dbg_outputOneRegValue /* update output buffer */ - bl dbg__putDebugMsg /* Send response to the GDB server */ - ldmfd sp!, {pc} - -/* _dbg_outputOneRegValue - * Given Register Index (-1: CPSR, 0-F: R0-R15), output hex char to buffer - * On entry: - * r0: register index (-1, 0-F) - * r1: output message buffer pointer - * On exit: - * r0: output message buffer pointer - * r1: updated (points to NULL character at end of Output Buffer) - * r2: destroyed - */ -_dbg_outputOneRegValue: - stmfd sp!, {lr} - add r2, r0, #DBGSTACK_USERREG_INDEX /* Convert register index to Debug Stack index */ - _index2dbgstackaddr r2, r0 /* Calculate address pointer to relevant register, result in R0 */ - ldr r0, [r0] /* Retrieve Register contents into R0 */ - bl word2ascii /* Convert and put hex chars into Output Message Buffer */ - ldmfd sp!, {pc} - -/* _dbg__procGetRegs - * Get All Register Values Command Handler - * Output Buffer returns register values in the order: User CPSR, R0, R1, R2, ..., R15 - * On entry: - * r0: parameter buffer pointer (contents after '$' and '') - */ -_dbg__procGetRegs: - stmfd sp!, {lr} - ldrb r0, [r0] /* Retrieve register index parameter to R0 */ - teq r0, #0 /* Check for NULL */ - bne __dbg__procCmdParamError /* Unexpected input, report error */ - - _dbg_outputMsgValidResponse /* Setup R1 with address of output message buffer data pointer (after response prefix) */ - mov r3, #DBGSTACK_USERCPSR_OFFSET /* Output User CPSR Value first */ -1: mov r0, r3 - bl _dbg_outputOneRegValue /* update output buffer */ - add r3, r3, #1 /* increment index */ - cmp r3, #0xF - ble 1b /* process all the registers */ - - bl dbg__putDebugMsg /* Send response to the GDB server */ - ldmfd sp!, {pc} - - -/* _dbg__nop - * NOP Command Handler (placeholder) - * On entry: - * r0: parameter buffer (contents after '$' and '') - */ -_dbg__nop: - stmfd sp!, {lr} - mov r0, #MSG_ERRIMPL /* Stub, not implemented yet */ - _dbg_outputMsgStatusErr - bl dbg__putDebugMsg /* Send error response to the GDB server */ - ldmfd sp!, {pc} - - -/* dbg__cmd_install_breakpoint - * Configure Breakpoint - * On entry: - * r0: index of breakpoint to install - * r1: instruction address to install - */ -dbg__cmd_install_breakpoint: - bl _dbg__install_one_breakpoint /* r0: index, r1: instruction address */ - b dbg__bkpt_waitCMD - -/* dbg__cmd_clear_breakpoint - * Clear Breakpoint - * On entry: - * r0: index of breakpoint to clear - */ -dbg__cmd_clear_breakpoint: - _index2bkptindex_addr r0, r0 /* Calculate Breakpoint Entry Address */ - bl _dbg__clear_one_breakpoint - b dbg__bkpt_waitCMD - - -/* dbg__cmd_run - * Continue execution of program - */ -dbg__cmd_run: - bl _dbg__activate_breakpoints - b __dbg__resume_execution - -/* dbg__cmd_step - * Single Step execution of program - */ -dbg__cmd_step: - bl _dbg_next_instruction_addr /* next instruction address returned in r1 */ - bl _dbg__install_singlestep /* Setup Single Step */ - bl _dbg__activate_singlestep - b __dbg__resume_execution - -/* dbg__cmd_cont - * Continue execution of program. - * If this is a Normal Breakpoint, then we need to install an Autobreakpoint at next instruction address - * and resume from current (Breakpoint) exception address - * Else (it is a Manual Breakpoint) - * We need to resume from the next instruction address - */ -dbg__cmd_cont: -/* FIXME: What happens if we call this when we did not stop at a Breakpoint previously? */ - _dbg_getstate r0 - ldr r1, =DBG_MANUAL_BKPT_ARM - teq r0, r1 - beq __dbg_is_manual_breakpoint - - bl _dbg_next_instruction_addr /* next instruction address returned in r1 */ - bl _dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ - _dbg_getcurrbkpt_index r0 /* load current breakpoint index in memory */ - bl _dbg__activate_autobreakpoint /* pass next instruction address in r1 */ - b __dbg__resume_execution - -__dbg_is_manual_breakpoint: - bl _dbg_next_instruction_addr /* Skip Manual Breakpoint Instruction(s) */ - bl _dbg__activate_breakpoints - b __dbg__resume_execution - -/**************************************************************************** -// 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; - } -} - - ****************************************************************************/ - - -/* _dbg_next_instruction_addr - * Determine the address of the next instruction to execute. - * On exit: - * R1: Instruction Address (31 bits, b0 = THUMB flag) - * - * Here we make use of the Debugger Stack which contains the address of the aborted instruction that will be reexecuted - * when we resume the program. - * - * If it is a Manual Breakpoint inserted into the code, then we will need to update the aborted instruction - * address to skip the current aborted instruction and resume execution at the next instruction address, - * and the next instruction address to be returned to the calling routine is the following instruction - * address instead. - * - * We need to check the aborted instruction type, to see if it is a branch instruction, before we can determine - * the next instruction address (for inserting a Breakpoint). - */ -_dbg_next_instruction_addr: -/* 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 r2, #DBGSTACK_USERCPSR_INDEX /* Retrieve User CPSR */ - _index2dbgstackaddr r2, r0 /* Calculate address pointer to relevant register, result in R0 */ - ldr r0, [r0] /* Retrieve Register contents into R0 */ - and r4, r0, #CPSR_THUMB /* store Thumb Mode status in R4 */ - - _dbg_getabortedinstr_addr r2 /* Retrieve aborted instruction address */ -1: teq r4, #0 /* Check if it is ARM or Thumb instruction */ - ldrneh r0, [r2] - ldrne r1, =(BKPT16_INSTR | BKPT16_MANUAL_BKPT) /* check for Thumb Manual Breakpoint Instruction */ - ldreq r0, [r2] - ldreq r1, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */ - teq r0, r1 - bne 2f /* Not Manual breakpoint */ - teq r4, #0 /* Check if it is ARM or Thumb instruction */ - addne r2, r2, #2 /* Is Manual Breakpoint, Skip to next Thumb instruction */ - addeq r2, r2, #4 /* Is Manual Breakpoint, Skip to next ARM instruction */ - _dbg_setabortedinstr_addr r2 /* Update aborted instruction address */ - b 1b /* To protect against a sequence of Manual Breakpoint Instructions */ - -/* Here, r0 contains the instruction which will be reexecuted when program resumes. We need to dissect it to see if - * it is a branch instruction. - */ -2: -@@@@@@@@@ - bx lr - -/* __dbg__resume_execution - * cleanup, resume execution of program. - * Restore User Mode Regsiters from Debugger Stack, and resume execution from aborted instruction - */ -__dbg__resume_execution: -@@@@@@ - bl _dbg__flush_icache - b __dbg__resume_execution - - - -/**************************************************************************** - * - * Breakpoint Manipulation Routines - * - ****************************************************************************/ - -/* _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} - -/* _dbg__install_singlestep - * Install the Single Step Breakpoint - * On entry: - * R1: Instruction Address (31 bits, b0 = THUMB flag) - */ -_dbg__install_singlestep: - mov r0, #0 -/* b _dbg__install_one_breakpoint */ - -/* _dbg__install_one_breakpoint - * Install breakpoint entry into Breakpoint State Table - * On entry: - * R0: Breakpoint index (assumed valid) - * R1: Instruction Address (31 bits, b0 = THUMB flag) - * - * On exit: - * R2: Breakpoint Instruction - * R3: Breakpoint Entry address - */ -_dbg__install_one_breakpoint: -/* Check for Thumb bit */ - tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ -/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ - ldreq r2, [r1] /* if 0: load ARM instruction from address location */ - ldrneh r2, [r1] /* else load Thumb instruction */ - _index2bkptindex_addr r0, r3 /* Calculate Breakpoint Entry Address */ - stm r3, {r1, r2} - bx lr - - -/* _dbg__restore_singlestep - * Restores the contents of the single step breakpoint to memory - */ -_dbg__restore_singlestep: - mov r0, #0 /* single step breakpoint index */ - _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */ - ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ - teq r1, #0 - bxeq lr /* Exit if not active */ -/* b _dbg__restore_one_breakpoint */ - -/* _dbg__restore_one_breakpoint - * Restores the contents to memory for one breakpoint - * On entry: - * R0: Breakpoint index (assumed valid) [not used -- can be used for validating BKPT] - * R1: Breakpoint Address (assumed valid) - * R2: Breakpoint Instruction (assumed valid) - */ -_dbg__restore_one_breakpoint: -/* Check for Thumb bit */ - tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ -/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ - streq r2, [r1] /* if 0: restore ARM instruction to address location */ - bicne r1, #BKPT_STATE_THUMB_FLAG /* else, clear Thumb Flag */ - strneh r2, [r1] /* store Thumb instruction */ - bx lr - -/* _dbg__restore_breakpoints - * Routine iterates through the array of breakpoints (incl single step breakpoint) and restores the contents to memory - * Only Active breakpoints (i.e., Non-zero Address) are processed. - */ -_dbg__restore_breakpoints: - stmfd sp!, {lr} - ldr r5, =_dbg__restore_one_breakpoint - b __dbg__iterate_breakpoint_array - -/* _dbg__activate_singlestep - * Activate the single step breakpoint to memory - */ -_dbg__activate_singlestep: - mov r0, #0 /* single step breakpoint index */ - _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */ - ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ - teq r1, #0 - bxeq lr /* Exit if not active */ -/* b _dbg__activate_one_breakpoint */ - -/* _dbg__activate_one_breakpoint - * Activate one breakpoint to memory - * On entry: - * R0: Breakpoint index (assumed valid) - * R1: Breakpoint Address (assumed valid) - * R2: Breakpoint Instruction (assumed valid) - */ -_dbg__activate_one_breakpoint: -/* Check for Thumb bit */ - tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ - bne _nx_is_thumb_bp -_nx_is_arm_bp: -/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ - ldr r3, [r1] /* if 0: load ARM instruction from address location */ - teq r2, r3 /* check that the two instructions are identical */ - bne _dbg__breakpoint_invalid_arm - ldr r2, =BKPT32_INSTR /* ARM BKPT instruction */ - and 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 */ - and r2, r2, r0 /* Merge Breakpoint index */ - strh r2, [r1] /* Store it into memory location */ -_dbg__breakpoint_invalid_thumb: - bx lr - -/* _dbg__activate_breakpoints - * Routine iterates through the array of breakpoints (incl single step breakpoint) and activates them - * Only Active breakpoints (i.e., Non-zero Address) are processed. - */ -_dbg__activate_breakpoints: - stmfd sp!, {lr} - ldr r5, =_dbg__activate_one_breakpoint - b __dbg__iterate_breakpoint_array - - -/* __dbg__iterate_breakpoint_array - * Common routine iterates through the array of breakpoints (incl single step breakpoint) - * and executes routine given in R5, passing: - * R0: Breakpoint index - * R1: Breakpoint Address - * R2: Breakpoint Instruction - * - * On Entry: - * Assumes that lr has been push to stack (routine can't be called directly) - * - * Only Active breakpoints (i.e., Non-zero Address entries) are processed. - */ -__dbg__iterate_breakpoint_array: - ldr r4, =__breakpoints_end__ /* start from top of the table (Assume __breakpoints_end__ > __breakpoints_start__) */ - ldr r3, =__breakpoints_start__ /* end address check */ - ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */ -4: sub r0, r0, #1 /* Decrement breakpoint index in r0 */ - ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ - teq r1, #0 /* Is it active? */ - movne lr, pc - bxne r5 /* active entry */ - cmp r4, r3 - bhi 4b /* if (pointer > start of Breakpoint Table address), get next slot */ - ldmfd sp!, {pc} - -/* _dbg__activate_autobreakpoint - * Activate all other breakpoints except current breakpoint, activate auto breakpoint in next instr slot - * On entry: - * R0: Current Breakpoint index (assumed valid) - * R1: Next Instruction address (for AUTO Breakpoint) [Not used, assume Single Step Breakpoint already has correct info] - */ -_dbg__activate_autobreakpoint: - stmfd sp!, {lr} - mov r5, r0 /* Keep Current Breakpoint Index in r5 */ - ldr r4, =__breakpoints_end__ /* start from top of the table */ - ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */ -4: subs r0, r0, #1 /* Decrement breakpoint index in r0 */ - ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ - bls 5f /* Flag set by subs instruction previously. Reached Single Step, go activate AUTO Breakpoint */ - teq r0, r5 /* Is it the Current Breakpoint? */ - beq 4b /* Yes, so skip */ - teq r1, #0 /* Is it active? */ - blne _dbg__activate_one_breakpoint /* active entry */ - b 4b /* Next iteration */ -5: -/* Here, r1: Breakpoint Address, r2: Breakpoint Instruction */ - tst r1, #BKPT_STATE_THUMB_FLAG /* Check for Thumb bit -- 1: Thumb instruction */ - orreq r0, r5, #BKPT32_AUTO_BKPT /* Is ARM Instruction, merge AUTO flag with Current Breakpoint Index */ - orrne r0, r5, #BKPT16_AUTO_BKPT /* Is Thumb Instruction, merge AUTO flag with Current Breakpoint Index */ - bl _dbg__activate_one_breakpoint /* Activate AUTO Breakpoint */ - ldmfd sp!, {pc} - diff --git a/AT91SAM7S256/Debugger/debug_stub.h b/AT91SAM7S256/Debugger/debug_stub.h deleted file mode 100644 index 7849d56..0000000 --- a/AT91SAM7S256/Debugger/debug_stub.h +++ /dev/null @@ -1,183 +0,0 @@ -/** @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. - * - * Redistribution of this file is permitted under - * the terms of the GNU Public License (GPL) version 2. - */ - -#ifndef __DEBUG_STUB_H__ -#define __DEBUG_STUB_H__ - -#include "_c_arm_macros.h" - -#ifndef __ASSEMBLY__ -#include "types.h" -#endif - -/** @addtogroup debugger */ -/*@{*/ - - -/* Declarations go here. */ -/** @name Debug Message Constants. - * - * Debug Message Values - */ -/*@{*/ -#define MSGBUF_SIZE 256 /* Debug Message Buffer Size */ -#define MSGBUF_STARTCHAR '$' -#define MSGBUF_ACKCHAR '+' -#define MSGBUF_NAKCHAR '-' -#define MSGBUF_ERRCHAR 'E' -#define MSGBUF_SIGCHAR 'S' -#define MSGBUF_CPSRREG '!' -#define MSGBUF_SETCHAR '=' -#define MSGBUF_CMDINDEX_OUTOFRANGE_VAL -1 - -/*@}*/ -/** @name Debug Stack Constants. - * - * Debug Stack Manipulation Values - */ -/*@{*/ -#define DBGSTACK_USERCPSR_OFFSET (DBGSTACK_USERCPSR_INDEX-DBGSTACK_USERREG_INDEX) /* = -1, offset for calculating Debug Stack index */ -#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 */ -/*@}*/ - -/** @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 - -/*@}*/ - -/** @name BKPT suppport constants - * - * ARM and Thumb Breakpoint Instructions. - */ -/*@{*/ -#define BKPT32_INSTR 0xE1200070 /* ARM BKPT instruction */ -#define BKPT32_ENUM_MASK 0x000FFF0F /* ARM BKPT Enum Mask */ -#define BKPT32_AUTO_BKPT 0x00080000 /* ARM BKPT Auto-Step Flag (for CONT support) */ -#define BKPT32_MANUAL_BKPT 0x0007FF0F /* Manually inserted ARM Breakpoint */ - -#define BKPT16_INSTR 0xBE00 /* Thumb BKPT instruction (not supported currently) */ -#define BKPT16_ENUM_MASK 0x00FF /* Thumb BKPT Enum Mask */ -#define BKPT16_AUTO_BKPT 0x0080 /* Thumb BKPT Auto-Step Flag (for CONT support) */ -#define BKPT16_MANUAL_BKPT 0x007F /* Manually inserted Thumb Breakpoint */ -/*@}*/ - -/** 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_MANUAL_BKPT_ARM) /**< Manual ARM Breakpoint. */ -ENUM_VAL(DBG_NORMAL_BKPT_ARM) /**< Normal ARM Breakpoint (Single Step, Normal). */ -ENUM_VAL(DBG_MANUAL_BKPT_THUMB) /**< Manual Thumb Breakpoint. */ -ENUM_VAL(DBG_NORMAL_BKPT_THUMB) /**< Normal Thumb Breakpoint (Single Step, Normal). */ -ENUM_END(dbg_state_t) - -/** Debugger Message Error Enums - * - * Debugger Error Message Enums. - * The enums must be consecutive, starting from 1 - */ -ENUM_BEGIN -ENUM_VALASSIGN(MSG_ERRIMPL, 0) /**< Stub (not implemented) Error. */ -ENUM_VAL(MSG_ERRCHKSUM) /**< Checksum Error. */ -ENUM_VAL(MSG_ERRFORMAT) /**< Message Format Error. */ -ENUM_VAL(MSG_UNKNOWNCMD) /**< Unrecognized Command Error. */ -ENUM_VAL(MSG_UNKNOWNPARAM) /**< Unrecognized Parameter Error. */ -ENUM_END(dbg_msg_errno) - - -#ifndef __ASSEMBLY__ - -/* Define C stuff */ -/** @defgroup debug_public */ -/*@{*/ - - -/** Initialize Debugger. - * Equivalent to GDB set_debug_traps() routine - */ -FUNCDEF void dbg__bkpt_init(void); - -/** 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 inline void dbg_breakpoint_arm(void) { asm volatile (".word BKPT32_INSTR | BKPT32_MANUAL_BKPT") } - -/** dbg_breakpoint_thumb. - * Equivalent to GDB breakpoint() routine for Thumb code - */ -FUNCDEF inline void dbg_breakpoint_thumb(void) { asm volatile (".hword BKPT16_INSTR | BKPT16_MANUAL_BKPT") } - -/*@}*/ - -#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_arm - * 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/Debugger/types.h b/AT91SAM7S256/Debugger/types.h deleted file mode 100644 index 3a1d4cb..0000000 --- a/AT91SAM7S256/Debugger/types.h +++ /dev/null @@ -1,46 +0,0 @@ -/** @file types.h - * @brief Basic type definitions for the Arm7 platform. - */ - -/* Copyright (c) 2007,2008 the NxOS developers - * - * 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. - */ - -#ifndef __NXOS_BASE_TYPES_H__ -#define __NXOS_BASE_TYPES_H__ - -/** @addtogroup typesAndUtils */ -/*@{*/ - -typedef unsigned char U8; /**< Unsigned 8-bit integer. */ -typedef signed char S8; /**< Signed 8-bit integer. */ -typedef unsigned short U16; /**< Unsigned 16-bit integer. */ -typedef signed short S16; /**< Signed 16-bit integer. */ -typedef unsigned long U32; /**< Unsigned 32-bit integer. */ -typedef signed long S32; /**< Signed 32-bit integer. */ - -#ifndef __SIZE_TYPE__ -#define __SIZE_TYPE__ U32 /**< Used to go conform with gcc, otherwise we are - risking an error because of conflicting types for size_t */ -#endif -typedef __SIZE_TYPE__ size_t; /**< Abstract size type, needed by the memory allocator. */ - -typedef U8 bool; /**< Boolean data type. */ -#define FALSE (0) /**< False boolean value. */ -#define TRUE (!FALSE) /**< True boolean value. */ - -#ifndef NULL -/** Definition of the NULL pointer. */ -#define NULL ((void*)0) -#endif - -/** A function that takes no arguments and returns nothing. */ -typedef void (*nx_closure_t)(void); - -/*@}*/ - -#endif diff --git a/AT91SAM7S256/Debugger/undef_handler.S b/AT91SAM7S256/Debugger/undef_handler.S deleted file mode 100644 index c160179..0000000 --- a/AT91SAM7S256/Debugger/undef_handler.S +++ /dev/null @@ -1,71 +0,0 @@ - -/* 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" - -#define MODE_SVC 0x13 /* Supervisor mode. */ - -.text -.code 32 -.align 0 - - .extern dbg__thumb_bkpt_handler - .extern dbg__arm_bkpt_handler - - .global undef_handler - -undef_handler: -/* Remote GDB Debugger relies on BKPT instruction being trapped here - In ARMv4t, it is an Illegal (Undefined) Instruction. - On triggering, lr (R14) contains the previous mode's pc (R15). - Based on example in Hohl, "ARM Assembly Language: Fundamentals and Techniques" - Chapter 11, Example 11.1. - Note: The handler is not AAPCS compliant (8 byte-alignment and stack, etc.) - */ - /* We assume that the UNDEF stack has been setup previously - On entry, LR_undef points to one instruction past the UNDEF instruction - */ - ldr sp, =__debugger_stack__ - stmfd sp, {r0-r15}^ /* Save workspace, user mode's pc via 'S' flag */ - sub sp, sp, #(4*16) /* Need to manually update SP(undef) */ - mrs r1, spsr /* Copy SPSR to r0 */ - sub r0, lr, #-4 /* LR points to instruction after UNDEF instruction */ - stmfd sp!, {r0,r1} /* Save UNDEF instruction addr and previous mode's CPSR to stack */ - 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 */ - and r0, r1, r0 /* Keep index value */ - msr cpsr_c, #(MODE_SVC) /* Configure Supervisor Mode */ - ldr lr, =dbg__thumb_bkpt_handler /* handle BKPT, BKPT index in r0 */ - mov pc, lr /* Invoke Debugger State (Supervisor Mode) */ -_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 */ - and r0, r1, r0 /* Keep index value */ - msr cpsr_c, #(MODE_SVC) /* Configure Supervisor Mode */ - ldr lr, =dbg__arm_bkpt_handler /* handle BKPT, BKPT index in r0 */ - mov pc, lr /* Invoke Debugger State (Supervisor Mode) */ - - -default_undef_handler: - b default_undef_handler /* Infinite loop */ diff --git a/Debugger/_c_arm_macros.h b/Debugger/_c_arm_macros.h new file mode 100644 index 0000000..f356a25 --- /dev/null +++ b/Debugger/_c_arm_macros.h @@ -0,0 +1,149 @@ +/** @file _c_arm_macros.h + * @brief Define macros to support shared C and ASM headers + * + */ + +/* Copyright (C) 2007,2009 the NxOS developers + * Thanks to Bartli (forum post @ embdev.net ARM programming with GCC/GNU tools forum) + * + * 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. + */ + +#ifndef __NXOS_BASE_C_ARM_MACROS__ +#define __NXOS_BASE_C_ARM_MACROS__ + +#ifdef __ASSEMBLY__ + +#define NULL 0x0 /* Stick the definition here instead of making types.h messy */ +#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) + +/** Macro to define driver ioctl table + * First five table entries are predefined + * 0: init + * 1: shutdown + * 2: sleep + * 3: wakeup + * 4: poll + * + */ +#define DRIVER_IOCTL(driver) \ +/* Dummy sleep and wakeup routines for now */ ;\ + .set driver ## _sleep, NULL ;\ + .set driver ## _wakeup, NULL ;\ + .set driver ## _poll, NULL ;\ +.data ;\ + .align 4 ;\ + .global driver ## _ioctl ;\ +driver ## _ioctl: ;\ + .word driver ## _init ;\ + .word driver ## _shutdown ;\ + .word driver ## _sleep ;\ + .word driver ## _wakeup ;\ + .word driver ## _poll ;\ + .set num_ ## driver ## _cmds, 5 + +/** Macro to define additional driver ioctl commands + * Be careful to follow the sequence defined for the CMD enums + * The first CMD should have an enum value of 5 + * + */ +#define DRIVER_CMD(driver, cmd) \ + .word driver ## _ ## cmd ;\ + .set num_ ## driver ## _cmds, num_ ## driver ## _cmds + 1 + +/** Macro to define driver state + * MUST BE DEFINED AFTER DRIVER_IOCTL section + * @param driver name of driver + * @param driverenum enum value of driver (in [31:25]) + * + * The number of commands for driver (in [24:17]) -- derived from num_driver_cmds + * + * Format of driver_state table: + * driver signature (driverenum << 24 | numcommands << 16) + * driver parameters (per device instance) + */ +#define DRIVER_STATE(driver, driverenum) \ +.bss ;\ + .global driver ## _state ;\ +driver ## _state: ;\ + .set driver ## _signature, (driverenum << 24) | (num_ ## driver ## _cmds << 16) ;\ + .word NULL /* driver_signature */ + + +/** Macro to define actual driver routine in .S + * On entry: + * r0 - address of driver_state + * r1-r3 - parameters (variable) + * r12 - number of parameters (IPC scratch register) + * Stack - parameters (variable) + */ +#define DRIVER_ROUTINE(driver, cmd) \ + .global driver ## _ ## cmd ## ;\ +driver ## _ ## cmd ## : + +#else +/** 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 + +ENUM_BEGIN +ENUM_VAL(INIT) /**< Driver Init Routine. */ +ENUM_VAL(SHUTDOWN) /**< Driver Shutdown Routine. */ +ENUM_VAL(SLEEP) /**< Driver Sleep Routine. */ +ENUM_VAL(WAKEUP) /**< Driver Wakeup Routine. */ +ENUM_VAL(POLL) /**< Driver Poll Routine. */ +ENUM_END(nx_driver_default_cmd) + + +#endif /* __NXOS_BASE_C_ARM_MACROS__ */ diff --git a/Debugger/debug_comm.S b/Debugger/debug_comm.S new file mode 100644 index 0000000..af69391 --- /dev/null +++ b/Debugger/debug_comm.S @@ -0,0 +1,286 @@ + +/* 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" + +.data +.align 4 + +hex2char_lut: + .ascii "0123456789ABCDEF" + +/* Macros + */ + +/* _asciiz + * Terminate string given string buffer pointer in \addrptr + * reg is used as a scratch register (destroyed) + * + */ + .macro _asciiz reg, strptr + mov \reg, #0 /* NULL character */ + strb \reg, [\strptr] /* Terminate ASCIIZ string */ + .endm + +/* _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 + */ + +/* 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) + */ + .global char2hex + +char2hex: + and r0, #BYTE0 /* make sure that input is sane */ + cmp r0, #'0' + blo exit_char2hex + cmp r0, #'F' + bhi exit_char2hex + _char2hex r0 +exit_char2hex: + bx lr + +/* byte2ascii_cont + * This routine accepts a byte value in R0(7:0), and a ASCII buffer pointer in R1, + * and stores the ASCII equivalent byte value in the buffer pointed to by R1. + * Note: On return, R1 points to next empty char slot in buffer (i.e., R1 is modified) + * and R0 is destroyed. + */ +byte2ascii_cont: + stmfd sp!, {r2,r3,r4, lr} + mov r2, r0, lsl #24 /* Keep copy of input byte value R0(7:0), shifted to MSB R2(31:24) */ + mov r4, #2 /* Loop counter */ + _hex2char_lut r3 /* initialize LUT pointer */ +1: mov r0, r2, ror #28 /* Rotate MSNibble R2(31:28) into LSNibble position R0(3:0) */ + and r0, r0, #NIBBLE0 /* Mask out everything else */ + _hex2char_cont r0, r3 /* Convert nibble to ASCII char */ + strb r0, [r1], #1 + subs r4, r4, #1 /* decrement loop counter */ + bne 1b + ldmfd sp!, {r2,r3,r4, pc} + +/* byte2ascii + * This routine accepts a byte value in R0(7:0), and a ASCII buffer pointer in R1, + * and stores the ASCII equivalent byte value in the buffer pointed to by R1. + * Note: On return, R1 points to the end of the ASCIIZ string (i.e. NULL character) + */ + .global byte2ascii + +byte2ascii: + stmfd sp!, {r1, lr} /* Keep ASCII buffer pointer */ + and r0, #BYTE0 /* sanitize input */ + bl byte2ascii_cont + _asciiz r0, r1 + ldmfd sp!, {r0, pc} /* return string pointer in R0 */ + +/* halfword2ascii + * This routine accepts a halfword value in R0(15:0), and a ASCII buffer pointer in R1, + * and returns the ASCIIZ equivalent byte value in the buffer pointed to by R0. + * Note: On return, R1 points to the end of the ASCIIZ string (i.e. NULL character) + */ + .global halfword2ascii +halfword2ascii: + stmfd sp!, {r1,r2,r3, lr} /* Keep ASCII buffer pointer */ + mov r2, r0, lsl #16 /* copy of input halfword value R0(15:0), shifted to MSH R2(31:16) */ + mov r3, #2 /* Loop Counter */ + b _conv_byte2ascii /* goto Byte conversion loop */ + +/* word2ascii + * This routine accepts a word value in R0(31:0), and a ASCII buffer pointer in R1, + * and returns the ASCIIZ equivalent byte value in the buffer pointed to by R0. + * Note: On return, R1 points to the end of the ASCIIZ string (i.e. NULL character) + */ + .global word2ascii +word2ascii: + stmfd sp!, {r1,r2,r3, lr} /* Keep ASCII buffer pointer */ + mov r2, r0 /* copy of input word value R0(31:0) */ + mov r3, #4 /* Loop Counter */ + + /* Fall through to byte coversion loop */ + +_conv_byte2ascii: + mov r0, r2, ror #24 /* Rotate MSB R2(31:24) into LSB position R0(7:0) */ + and r0, #BYTE0 /* Mask out everything else */ + bl byte2ascii_cont + subs r3, r3, #1 + bne _conv_byte2ascii + _asciiz r0, r1 + ldmfd sp!, {r0,r2,r3, pc} + + +/* ascii2byte + * 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,r3, lr} + mov r3, #2 /* Loop counter */ + b _conv_ascii2byte + +/* ascii2halfword + * This routine accepts an ASCII buffer pointer in R0, + * and returns the word 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 + +ascii2halfword: + stmfd sp!, {r2,r3, lr} + mov r3, #4 /* Loop counter */ + b _conv_ascii2byte + + +/* ascii2word + * 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 + +ascii2word: + stmfd sp!, {r2,r3, lr} + mov r3, #8 /* Loop counter */ + + /* Fall through to byte coversion loop */ + +_conv_ascii2byte: + teq r0, #0 + beq _exit_conv_ascii2byte /* exit if NULL pointer in R0 */ + mov r0, r1 /* Copy of ASCII buffer pointer */ + mov r2, #0 /* Initialize results */ +2: ldrb r0, [r1], #1 /* Load ASCII char */ + bl char2hex /* on return, hex value in R0 */ + orr r2, r0, r2, lsl #4 /* merge Nibble into results */ + subs r3, r3, #1 + bne 2b + mov r0, r2 /* Copy it to R0 as return value */ +_exit_conv_ascii2byte: + ldmfd sp!, {r2,r3, pc} /* return hex value in R0 */ + + + + +/* 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. + * + */ + .global dbg__hasDebugMsg +/* dbg__hasDebugMsg + * Checks for pending Debugger Message (Non-Blocking). + * On exit: + * r0: Boolean (0: no pending message, 1: has pending message) + */ +dbg__hasDebugMsg: + bx lr + + .global dbg__getDebugMsg +/* dbg__getDebugMsg + * Returns Debugger Message to calling routine after verifying and removing checksum (Blocking). + * On entry: + * r0: address of message buffer + * r1: maximum size of message buffer (incl NULL character) + * On exit: + * r0: address of message buffer with NULL terminated message, excluding '#' + * (NULL if message error) + * + */ +dbg__getDebugMsg: + bx lr + + .global dbg__putDebugMsg +/* dbg__putDebugMsg + * Sends Debugger Message from calling routine after appending checksum (Blocking) . + * On entry: + * r0: address of message buffer with NULL terminated message, without '#' + * On exit: + * r0: status (0: success, -1: error) + */ +dbg__putDebugMsg: + bx lr + + +/* Private functions (if needed) */ +_dbg__getChar: +_dbg__putChar: + bx lr diff --git a/Debugger/debug_stack.ld b/Debugger/debug_stack.ld new file mode 100644 index 0000000..df27512 --- /dev/null +++ b/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 user mode registers + SPSR + BKPT Instr Addr */ + __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/Debugger/debug_stub.S b/Debugger/debug_stub.S new file mode 100644 index 0000000..98bc968 --- /dev/null +++ b/Debugger/debug_stub.S @@ -0,0 +1,1469 @@ + +/* 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. + */ + + /* 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 CPSR, R0, R1, ..., R15 + * 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, '!' for User CPSR + * + * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN + * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN + * + * 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) + * + * 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 */ + + +/* FIXME: What about setting/clearing Breakpoints? */ + +#define __ASSEMBLY__ +#include "debug_stub.h" + +.bss +.align 4 +debug_state: + .word 0x0 +debug_curr_breakpoint: + .word 0x0 +debug_InMsgBuf: + .space MSGBUF_SIZE,0 +debug_OutMsgBuf: + .space MSGBUF_SIZE,0 + +.data +.align 4 +debug_ValidResponsePrefix: + .byte '+','$',0 + +debug_ErrorResponsePrefix: + .byte '-','$','E',0 + +debug_SignalResponsePrefix: + .byte '+','$','S',0 + +debug_OkResponse: + .byte '+','$','O','K',0 + +/* The CmdIndexTable and CmdJumpTable must be kept in sync */ +debug_cmdIndexTable: + .byte 'g','G','p','P','m','M','c','s','k','?',0 + +/* Command Handlers + * On entry: + * R0: Input Message Parameter Buffer address pointer (points to contents after '$' and '') + */ +debug_cmdJumpTable: + .word _dbg__procGetRegs /* 'g' */ + .word _dbg__procSetRegs /* 'G' */ + .word _dbg__procGetOneReg /* 'p' */ + .word _dbg__procSetOneReg /* 'P' */ + .word _dbg__nop /* 'm' */ + .word _dbg__nop /* 'M' */ + .word _dbg__nop /* 'c' */ + .word _dbg__nop /* 's' */ + .word _dbg__nop /* 'k' */ + .word _dbg__nop /* '?' */ + .word 0 + + +.code 32 +.text +.align 4 + .extern __breakpoints_num__ + .extern dbg__hasDebugMsg /* Check for message from the communications link */ + .extern dbg__getDebugMsg /* Read a message from the communications link */ + .extern dbg__putDebugMsg /* Write a message to the communications link */ + +/* _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_stpcpy + * _dbg_stpcpy macro + * On entry: + * deststrptr: Destination string [Cannot be R0] + * sourcestrptr: Source string [Cannot be R0] + * On exit: + * deststrptr: Pointer to NULL character in destination string + * R0: destroyed + */ + .macro _dbg_stpcpy deststrptr, sourcestrptr +1: ldrb r0, [\sourcestrptr], #1 + strb r0, [\deststrptr], #1 + teq r0, #0 + bne 1b + sub \deststrptr, \deststrptr, #1 /* Adjust Destination string pointer to point at NULL character */ + .endm + +/* _dbg_outputMsgValidResponse + * Return Message with valid response ('+$') + * On exit: + * R0: destroyed + * R1: points to NULL character after the prefix + * R2: destroyed + */ + .macro _dbg_outputMsgValidResponse + ldr r1, =debug_OutMsgBuf + ldr r2, =debug_ValidResponsePrefix + _dbg_stpcpy r1, r2 + .endm + + +/* _dbg_outputMsgStatusOk + * Return Message with Ok ('+OK') status + * On exit: + * R0: destroyed + * R1: destroyed + * R2: destroyed + */ + .macro _dbg_outputMsgStatusOk + ldr r1, =debug_OutMsgBuf + ldr r2, =debug_OkResponse + _dbg_stpcpy r1, r2 + .endm + +/* _dbg_outputMsgStatusErr + * Return Message with Error ('-ENN') status + * On entry: + * R0: register containing error value (byte) + * On exit: + * R0: destroyed + * R1: destroyed + * R2: destroyed + * R3: destroyed + */ + .macro _dbg_outputMsgStatusErr + mov r3, r0 + ldr r1, =debug_OutMsgBuf + ldr r2, =debug_ErrorResponsePrefix + _dbg_stpcpy r1, r2 + mov r0, r3 + bl byte2ascii /* R1 points to NULL character after the prefix */ + .endm + +/* _dbg_outputMsgStatusSig + * Return Message with Signal ('+SNN') status + * On entry: + * R0: register containing error value (byte) + * On exit: + * R0: destroyed + * R1: destroyed + * R2: destroyed + * R3: destroyed + */ + .macro _dbg_outputMsgStatusSig + mov r3, r0 + ldr r1, =debug_OutMsgBuf + ldr r2, =debug_SignalResponsePrefix + _dbg_stpcpy r1, r2 + mov r0, r3 + bl byte2ascii /* R1 points to NULL character after the prefix */ + .endm + +/* _index2dbgstackaddr + * Convert debugger stack index to Debugger Stack register address + * + * On entry: + * indexreg contains debugger stack index value (0-max entries) + * On exit: + * indexreg: Breakpoint index (preserved) + * addrreg: Debugger Stack Register Address + */ + .macro _index2dbgstackaddr indexreg, addrreg + ldr \addrreg, =__debugger_stack_bottom__ + add \addrreg, \addrreg, \indexreg, lsl #2 /* Calculate Debugger Stack Register Address */ + .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 + ldr \reg, [\reg] + .endm + +/* _dbg_setstate + * Set Debugger State to given value + * On exit: + * r0, r1: destroyed + */ + .macro _dbg_setstate state + ldr r0, =\state + ldr r1, =debug_state + str 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 + ldr \reg, [\reg] + .endm + +/* _dbg_setcurrbkpt_index + * Set current breakpoint index + * On exit: + * r1: destroyed + */ + .macro _dbg_setcurrbkpt_index reg + ldr r1, =debug_curr_breakpoint + str \reg, [r1] + .endm + +/* _dbg_getabortedinstr_addr + * Get aborted instruction address + * On exit: + * reg: aborted instruction address + */ + .macro _dbg_getabortedinstr_addr reg + ldr \reg, =__debugger_stack_bottom__ + ldr \reg, [\reg] + .endm + +/* _dbg_setabortedinstr_addr + * Set aborted instruction address + * On exit: + * r1: destroyed + */ + .macro _dbg_setabortedinstr_addr reg + ldr r1, =__debugger_stack_bottom__ + str \reg, [r1] + .endm + + + +/* 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__ + * User Mode R15 + * User Mode R14 + * ... + * User Mode R02 + * User Mode R01 + * User Mode R00 + * User Mode CPSR (UNDEF SPSR) + * Bkpt Instr Addr __debugger_stack_bottom__ + * [Low Memory Address] + * + * Each Breakpoint State will initially be zeroed. + * + */ + +/**************************************************************************** + * + * GDB Debugger Init and Breakpoint Handler Routines + * + ****************************************************************************/ + + .global dbg__bkpt_init +/* dbg__bkpt_init + * GDB set_debug_traps() routine + */ +dbg__bkpt_init: + stmfd sp!, {lr} + bl _dbg__clear_breakpoints + mov r0, #0 + ldr r1, =debug_curr_breakpoint + str r0, [r1] + ldr r1, =debug_InMsgBuf + strb r0, [r1] + ldr r1, =debug_OutMsgBuf + strb r0, [r1] + +/* FIXME: Initialize other stuff here */ + _dbg_setstate DBG_INIT + ldmfd sp!, {pc} + + +/* _dbg__flush_icache + * Flush the Instruction cache + * Defined by GDB Stub, but not needed for ARMv4T architecture + */ +_dbg__flush_icache: + /* nop */ + bx lr + + + .global dbg__thumb_bkpt_handler +/* dbg__thumb_bkpt_handler + * GDB handle_exception() routine (Thumb Mode) + */ +dbg__thumb_bkpt_handler: +/* On entry, r0 contains breakpoint index value */ + mov r4, #BKPT16_AUTO_BKPT + and r4, r0, #BKPT16_AUTO_BKPT /* keep AUTO flag value in r4 */ + bic r0, r0, #BKPT16_AUTO_BKPT /* mask out AUTO flag */ + _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ + ldr r1, =BKPT16_MANUAL_BKPT + teq r0, r1 + beq _process_manual_breakpoint_thumb + ldr r1, =__breakpoints_num__ + cmp r0, r1 /* Sanity check that index is in range */ + bhs dbg__bkpt_offset_outofrange +/* Valid index value found */ + teq r4, #0 /* Check if AUTO flag set */ + bne _process_auto_breakpoint +/* else */ + _dbg_setstate DBG_NORMAL_BKPT_THUMB + b _process_normal_breakpoint + + .global dbg__arm_bkpt_handler +/* dbg__arm_bkpt_handler + * GDB handle_exception() routine (ARM Mode) + */ +dbg__arm_bkpt_handler: +/* On entry, r0 contains breakpoint index value */ + mov r4, #BKPT32_AUTO_BKPT + and r4, r0, #BKPT32_AUTO_BKPT /* keep AUTO flag value in r4 */ + bic r0, r0, #BKPT32_AUTO_BKPT /* mask out AUTO flag */ + _dbg_setcurrbkpt_index r0 /* keep current breakpoint index in memory */ + ldr r1, =BKPT32_MANUAL_BKPT + teq r0, r1 + beq _process_manual_breakpoint_arm + ldr r1, =__breakpoints_num__ + cmp r0, r1 /* Sanity check that index is in range */ + bhs dbg__bkpt_offset_outofrange +/* Valid index value found */ + teq r4, #0 /* Check if AUTO flag set */ + bne _process_auto_breakpoint +/* else */ + _dbg_setstate DBG_NORMAL_BKPT_ARM +/* b _process_normal_breakpoint */ + +_process_normal_breakpoint: + bl _dbg__restore_breakpoints + bl _dbg__restore_singlestep + bl _dbg__clear_singlestep + bl _dbg__flush_icache + b dbg__bkpt_waitCMD + +_process_auto_breakpoint: +/* Load Auto BKPT for Breakpoint index given in r0 */ + _index2bkptindex_addr r0, r1 /* Calculate Breakpoint Entry Address */ + ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 /* Check that Breakpoint is active */ + beq dbg__bkpt_inactive + bl _dbg__activate_one_breakpoint + bl _dbg__restore_singlestep + bl _dbg__clear_singlestep + b __dbg__resume_execution + +_process_manual_breakpoint_thumb: + _dbg_setstate DBG_MANUAL_BKPT_THUMB + b dbg__bkpt_waitCMD + +_process_manual_breakpoint_arm: + _dbg_setstate DBG_MANUAL_BKPT_ARM +/* b dbg__bkpt_waitCMD */ + +dbg__bkpt_inactive: +/* b dbg__bkpt_waitCMD */ + +dbg__bkpt_offset_outofrange: +/* b dbg__bkpt_waitCMD */ + + .global dbg__bkpt_waitCMD +/* dbg__bkpt_waitCMD + * GDB Stub Remote Command Handler + */ + +/**************************************************************************** + * + * GDB Server Command Processing Routines + * + ****************************************************************************/ +dbg__bkpt_waitCMD: +1: bl dbg__hasDebugMsg /* Check for messages */ + beq 1b /* Busy wait */ + bl dbg__getDebugMsg /* Read new message from Debugger, message buffer addr in R0, NULL if error */ + teq r0, #0 + moveq r0, #MSG_ERRCHKSUM /* Message invalid, checksum error? */ + beq _dbg__cmdError /* Send response to GDB server */ +/* Message now has $\0 */ + mov r4, r0 /* Use R4 as Message Buffer pointer */ + ldrb r0, [r4], #1 /* Look for '$' */ + teq r0, #MSGBUF_STARTCHAR + movne r0, #MSG_ERRFORMAT /* Message Format invalid (not '$') */ + bne _dbg__cmdError /* Shouldn't happen */ + ldrb r0, [r4], #1 /* Look for command char */ + bl _dbg__cmdChar2Index /* Index in R0 */ + ldr r1, =MSGBUF_CMDINDEX_OUTOFRANGE_VAL + teq r0, r1 + moveq r0, #MSG_UNKNOWNCMD /* Out of range, Command character not recognized */ + beq _dbg__cmdError /* Send response to GDB server */ + +_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 + +_dbg__cmdError: + _dbg_outputMsgStatusErr + bl dbg__putDebugMsg /* Send error response to the GDB server */ + b dbg__bkpt_waitCMD + + +/* _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, #MSGBUF_CMDINDEX_OUTOFRANGE_VAL /* 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__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 r0, #MSG_UNKNOWNPARAM + _dbg_outputMsgStatusErr + bl dbg__putDebugMsg /* Send error response to the GDB server */ + ldmfd sp!, {pc} + + + +/* _dbg__procGetOneReg + * Get One Register Value Command Handler + * Valid register parameter is from '0' to 'F' for User Mode Registers R0-R15 + * CPSR register parameer is '!' + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + * + */ +_dbg__procGetOneReg: + stmfd sp!, {lr} + ldrb r2, [r0, #1] /* char after parameter value (Should be NULL character) */ + ldrb r0, [r0] /* Retrieve register index parameter to R0 */ + teq r2, #0 /* Check for NULL */ + bne __dbg__procCmdParamError /* Unexpected input, report error */ + teq r0, #MSGBUF_CPSRREG /* Check for CPSR register indicator */ + moveq r0, #DBGSTACK_USERCPSR_OFFSET /* Put offset from User Registers (-1) into index, so that after adjustment it points to CPSR slot */ + beq _dbg__procRegister /* Handle User CPSR */ + bl char2hex /* Convert to Hex value (assume input is valid) */ + cmp r0, #NIBBLE0 /* sanity check, (though it is not foolproof as input char in 0x0-0xF (ctrl-chars) will pass through) */ + bhi __dbg__procCmdParamError /* Non-hex char, report error */ + +_dbg__procRegister: + mov r3, r0 /* Keep register index safe */ + _dbg_outputMsgValidResponse /* Setup R1 with address of output message buffer data pointer (after response prefix) */ + mov r0, r3 /* Restore register index value */ + bl _dbg_outputOneRegValue /* update output buffer */ + bl dbg__putDebugMsg /* Send response to the GDB server */ + ldmfd sp!, {pc} + +/* _dbg_outputOneRegValue + * Given Register Index (-1: CPSR, 0-F: R0-R15), output hex char to buffer + * On entry: + * r0: register index (-1, 0-F) + * r1: output message buffer pointer + * On exit: + * r0: output message buffer pointer + * r1: updated (points to NULL character at end of Output Buffer) + * r2: destroyed + */ +_dbg_outputOneRegValue: + stmfd sp!, {lr} + add r2, r0, #DBGSTACK_USERREG_INDEX /* Convert register index to Debug Stack index */ + _index2dbgstackaddr r2, r0 /* Calculate address pointer to relevant register, result in R0 */ + ldr r0, [r0] /* Retrieve Register contents into R0 */ + bl word2ascii /* Convert and put hex chars into Output Message Buffer */ + ldmfd sp!, {pc} + +/* _dbg__procGetRegs + * Get All Register Values Command Handler + * Output Buffer returns register values in the order: User CPSR, R0, R1, R2, ..., R15 + * On entry: + * r0: parameter buffer pointer (contents after '$' and '') + */ +_dbg__procGetRegs: + stmfd sp!, {lr} + ldrb r0, [r0] /* Retrieve register index parameter to R0 */ + teq r0, #0 /* Check for NULL */ + bne __dbg__procCmdParamError /* Unexpected input, report error */ + + _dbg_outputMsgValidResponse /* Setup R1 with address of output message buffer data pointer (after response prefix) */ + mov r3, #DBGSTACK_USERCPSR_OFFSET /* Output User CPSR Value first */ +1: mov r0, r3 + bl _dbg_outputOneRegValue /* update output buffer */ + add r3, r3, #1 /* increment index */ + cmp r3, #0xF + ble 1b /* process all the registers */ + + bl dbg__putDebugMsg /* Send response to the GDB server */ + ldmfd sp!, {pc} + + +/* _dbg__nop + * NOP Command Handler (placeholder) + * On entry: + * r0: parameter buffer (contents after '$' and '') + */ +_dbg__nop: + stmfd sp!, {lr} + mov r0, #MSG_ERRIMPL /* Stub, not implemented yet */ + _dbg_outputMsgStatusErr + bl dbg__putDebugMsg /* Send error response to the GDB server */ + ldmfd sp!, {pc} + + +/* dbg__cmd_install_breakpoint + * Configure Breakpoint + * On entry: + * r0: index of breakpoint to install + * r1: instruction address to install + */ +dbg__cmd_install_breakpoint: + bl _dbg__install_one_breakpoint /* r0: index, r1: instruction address */ + b dbg__bkpt_waitCMD + +/* dbg__cmd_clear_breakpoint + * Clear Breakpoint + * On entry: + * r0: index of breakpoint to clear + */ +dbg__cmd_clear_breakpoint: + _index2bkptindex_addr r0, r0 /* Calculate Breakpoint Entry Address */ + bl _dbg__clear_one_breakpoint + b dbg__bkpt_waitCMD + + +/* dbg__cmd_run + * Continue execution of program + */ +dbg__cmd_run: + bl _dbg__activate_breakpoints + b __dbg__resume_execution + +/* dbg__cmd_step + * Single Step execution of program + */ +dbg__cmd_step: + bl _dbg_next_instruction_addr /* next instruction address returned in r1 */ + bl _dbg__install_singlestep /* Setup Single Step */ + bl _dbg__activate_singlestep + b __dbg__resume_execution + +/* dbg__cmd_cont + * Continue execution of program. + * If this is a Normal Breakpoint, then we need to install an Autobreakpoint at next instruction address + * and resume from current (Breakpoint) exception address + * Else (it is a Manual Breakpoint) + * We need to resume from the next instruction address + */ +dbg__cmd_cont: +/* FIXME: What happens if we call this when we did not stop at a Breakpoint previously? */ + _dbg_getstate r0 + ldr r1, =DBG_MANUAL_BKPT_ARM + teq r0, r1 + beq __dbg_is_manual_breakpoint + + bl _dbg_next_instruction_addr /* next instruction address returned in r1 */ + bl _dbg__install_singlestep /* Setup Single Step, next instruction address returned in r1 */ + _dbg_getcurrbkpt_index r0 /* load current breakpoint index in memory */ + bl _dbg__activate_autobreakpoint /* pass next instruction address in r1 */ + b __dbg__resume_execution + +__dbg_is_manual_breakpoint: + bl _dbg_next_instruction_addr /* Skip Manual Breakpoint Instruction(s) */ + bl _dbg__activate_breakpoints + b __dbg__resume_execution + +/**************************************************************************** +// 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; + } +} + + ****************************************************************************/ + + +/* _dbg_next_instruction_addr + * Determine the address of the next instruction to execute. + * On exit: + * R1: Instruction Address (31 bits, b0 = THUMB flag) + * + * Here we make use of the Debugger Stack which contains the address of the aborted instruction that will be reexecuted + * when we resume the program. + * + * If it is a Manual Breakpoint inserted into the code, then we will need to update the aborted instruction + * address to skip the current aborted instruction and resume execution at the next instruction address, + * and the next instruction address to be returned to the calling routine is the following instruction + * address instead. + * + * We need to check the aborted instruction type, to see if it is a branch instruction, before we can determine + * the next instruction address (for inserting a Breakpoint). + */ +_dbg_next_instruction_addr: +/* 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 r2, #DBGSTACK_USERCPSR_INDEX /* Retrieve User CPSR */ + _index2dbgstackaddr r2, r0 /* Calculate address pointer to relevant register, result in R0 */ + ldr r0, [r0] /* Retrieve Register contents into R0 */ + and r4, r0, #CPSR_THUMB /* store Thumb Mode status in R4 */ + + _dbg_getabortedinstr_addr r2 /* Retrieve aborted instruction address */ +1: teq r4, #0 /* Check if it is ARM or Thumb instruction */ + ldrneh r0, [r2] + ldrne r1, =(BKPT16_INSTR | BKPT16_MANUAL_BKPT) /* check for Thumb Manual Breakpoint Instruction */ + ldreq r0, [r2] + ldreq r1, =(BKPT32_INSTR | BKPT32_MANUAL_BKPT) /* check for ARM Manual Breakpoint Instruction */ + teq r0, r1 + bne 2f /* Not Manual breakpoint */ + teq r4, #0 /* Check if it is ARM or Thumb instruction */ + addne r2, r2, #2 /* Is Manual Breakpoint, Skip to next Thumb instruction */ + addeq r2, r2, #4 /* Is Manual Breakpoint, Skip to next ARM instruction */ + _dbg_setabortedinstr_addr r2 /* Update aborted instruction address */ + b 1b /* To protect against a sequence of Manual Breakpoint Instructions */ + +/* Here, r0 contains the instruction which will be reexecuted when program resumes. We need to dissect it to see if + * it is a branch instruction. + */ +2: +@@@@@@@@@ + bx lr + +/* __dbg__resume_execution + * cleanup, resume execution of program. + * Restore User Mode Regsiters from Debugger Stack, and resume execution from aborted instruction + */ +__dbg__resume_execution: +@@@@@@ + bl _dbg__flush_icache + b __dbg__resume_execution + + + +/**************************************************************************** + * + * Breakpoint Manipulation Routines + * + ****************************************************************************/ + +/* _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} + +/* _dbg__install_singlestep + * Install the Single Step Breakpoint + * On entry: + * R1: Instruction Address (31 bits, b0 = THUMB flag) + */ +_dbg__install_singlestep: + mov r0, #0 +/* b _dbg__install_one_breakpoint */ + +/* _dbg__install_one_breakpoint + * Install breakpoint entry into Breakpoint State Table + * On entry: + * R0: Breakpoint index (assumed valid) + * R1: Instruction Address (31 bits, b0 = THUMB flag) + * + * On exit: + * R2: Breakpoint Instruction + * R3: Breakpoint Entry address + */ +_dbg__install_one_breakpoint: +/* Check for Thumb bit */ + tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ +/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ + ldreq r2, [r1] /* if 0: load ARM instruction from address location */ + ldrneh r2, [r1] /* else load Thumb instruction */ + _index2bkptindex_addr r0, r3 /* Calculate Breakpoint Entry Address */ + stm r3, {r1, r2} + bx lr + + +/* _dbg__restore_singlestep + * Restores the contents of the single step breakpoint to memory + */ +_dbg__restore_singlestep: + mov r0, #0 /* single step breakpoint index */ + _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */ + ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 + bxeq lr /* Exit if not active */ +/* b _dbg__restore_one_breakpoint */ + +/* _dbg__restore_one_breakpoint + * Restores the contents to memory for one breakpoint + * On entry: + * R0: Breakpoint index (assumed valid) [not used -- can be used for validating BKPT] + * R1: Breakpoint Address (assumed valid) + * R2: Breakpoint Instruction (assumed valid) + */ +_dbg__restore_one_breakpoint: +/* Check for Thumb bit */ + tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ +/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ + streq r2, [r1] /* if 0: restore ARM instruction to address location */ + bicne r1, #BKPT_STATE_THUMB_FLAG /* else, clear Thumb Flag */ + strneh r2, [r1] /* store Thumb instruction */ + bx lr + +/* _dbg__restore_breakpoints + * Routine iterates through the array of breakpoints (incl single step breakpoint) and restores the contents to memory + * Only Active breakpoints (i.e., Non-zero Address) are processed. + */ +_dbg__restore_breakpoints: + stmfd sp!, {lr} + ldr r5, =_dbg__restore_one_breakpoint + b __dbg__iterate_breakpoint_array + +/* _dbg__activate_singlestep + * Activate the single step breakpoint to memory + */ +_dbg__activate_singlestep: + mov r0, #0 /* single step breakpoint index */ + _index2bkptindex_addr r0, r1 /* Calculate Single Step Breakpoint Entry Address */ + ldm r1, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 + bxeq lr /* Exit if not active */ +/* b _dbg__activate_one_breakpoint */ + +/* _dbg__activate_one_breakpoint + * Activate one breakpoint to memory + * On entry: + * R0: Breakpoint index (assumed valid) + * R1: Breakpoint Address (assumed valid) + * R2: Breakpoint Instruction (assumed valid) + */ +_dbg__activate_one_breakpoint: +/* Check for Thumb bit */ + tst r1, #BKPT_STATE_THUMB_FLAG /* 1: Thumb instruction */ + bne _nx_is_thumb_bp +_nx_is_arm_bp: +/* Assume that the address entry is valid, otherwise we should sanitize it (mask out b1) */ + ldr r3, [r1] /* if 0: load ARM instruction from address location */ + teq r2, r3 /* check that the two instructions are identical */ + bne _dbg__breakpoint_invalid_arm + ldr r2, =BKPT32_INSTR /* ARM BKPT instruction */ + and 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 */ + and r2, r2, r0 /* Merge Breakpoint index */ + strh r2, [r1] /* Store it into memory location */ +_dbg__breakpoint_invalid_thumb: + bx lr + +/* _dbg__activate_breakpoints + * Routine iterates through the array of breakpoints (incl single step breakpoint) and activates them + * Only Active breakpoints (i.e., Non-zero Address) are processed. + */ +_dbg__activate_breakpoints: + stmfd sp!, {lr} + ldr r5, =_dbg__activate_one_breakpoint + b __dbg__iterate_breakpoint_array + + +/* __dbg__iterate_breakpoint_array + * Common routine iterates through the array of breakpoints (incl single step breakpoint) + * and executes routine given in R5, passing: + * R0: Breakpoint index + * R1: Breakpoint Address + * R2: Breakpoint Instruction + * + * On Entry: + * Assumes that lr has been push to stack (routine can't be called directly) + * + * Only Active breakpoints (i.e., Non-zero Address entries) are processed. + */ +__dbg__iterate_breakpoint_array: + ldr r4, =__breakpoints_end__ /* start from top of the table (Assume __breakpoints_end__ > __breakpoints_start__) */ + ldr r3, =__breakpoints_start__ /* end address check */ + ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */ +4: sub r0, r0, #1 /* Decrement breakpoint index in r0 */ + ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + teq r1, #0 /* Is it active? */ + movne lr, pc + bxne r5 /* active entry */ + cmp r4, r3 + bhi 4b /* if (pointer > start of Breakpoint Table address), get next slot */ + ldmfd sp!, {pc} + +/* _dbg__activate_autobreakpoint + * Activate all other breakpoints except current breakpoint, activate auto breakpoint in next instr slot + * On entry: + * R0: Current Breakpoint index (assumed valid) + * R1: Next Instruction address (for AUTO Breakpoint) [Not used, assume Single Step Breakpoint already has correct info] + */ +_dbg__activate_autobreakpoint: + stmfd sp!, {lr} + mov r5, r0 /* Keep Current Breakpoint Index in r5 */ + ldr r4, =__breakpoints_end__ /* start from top of the table */ + ldr r0, =__breakpoints_num__ /* Number of Breakpoints (incl Single Step) (Assume Non-Zero) */ +4: subs r0, r0, #1 /* Decrement breakpoint index in r0 */ + ldmea r4!, {r1, r2} /* r1: Breakpoint Address, r2: Breakpoint Instruction */ + bls 5f /* Flag set by subs instruction previously. Reached Single Step, go activate AUTO Breakpoint */ + teq r0, r5 /* Is it the Current Breakpoint? */ + beq 4b /* Yes, so skip */ + teq r1, #0 /* Is it active? */ + blne _dbg__activate_one_breakpoint /* active entry */ + b 4b /* Next iteration */ +5: +/* Here, r1: Breakpoint Address, r2: Breakpoint Instruction */ + tst r1, #BKPT_STATE_THUMB_FLAG /* Check for Thumb bit -- 1: Thumb instruction */ + orreq r0, r5, #BKPT32_AUTO_BKPT /* Is ARM Instruction, merge AUTO flag with Current Breakpoint Index */ + orrne r0, r5, #BKPT16_AUTO_BKPT /* Is Thumb Instruction, merge AUTO flag with Current Breakpoint Index */ + bl _dbg__activate_one_breakpoint /* Activate AUTO Breakpoint */ + ldmfd sp!, {pc} + diff --git a/Debugger/debug_stub.h b/Debugger/debug_stub.h new file mode 100644 index 0000000..7849d56 --- /dev/null +++ b/Debugger/debug_stub.h @@ -0,0 +1,183 @@ +/** @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. + * + * Redistribution of this file is permitted under + * the terms of the GNU Public License (GPL) version 2. + */ + +#ifndef __DEBUG_STUB_H__ +#define __DEBUG_STUB_H__ + +#include "_c_arm_macros.h" + +#ifndef __ASSEMBLY__ +#include "types.h" +#endif + +/** @addtogroup debugger */ +/*@{*/ + + +/* Declarations go here. */ +/** @name Debug Message Constants. + * + * Debug Message Values + */ +/*@{*/ +#define MSGBUF_SIZE 256 /* Debug Message Buffer Size */ +#define MSGBUF_STARTCHAR '$' +#define MSGBUF_ACKCHAR '+' +#define MSGBUF_NAKCHAR '-' +#define MSGBUF_ERRCHAR 'E' +#define MSGBUF_SIGCHAR 'S' +#define MSGBUF_CPSRREG '!' +#define MSGBUF_SETCHAR '=' +#define MSGBUF_CMDINDEX_OUTOFRANGE_VAL -1 + +/*@}*/ +/** @name Debug Stack Constants. + * + * Debug Stack Manipulation Values + */ +/*@{*/ +#define DBGSTACK_USERCPSR_OFFSET (DBGSTACK_USERCPSR_INDEX-DBGSTACK_USERREG_INDEX) /* = -1, offset for calculating Debug Stack index */ +#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 */ +/*@}*/ + +/** @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 + +/*@}*/ + +/** @name BKPT suppport constants + * + * ARM and Thumb Breakpoint Instructions. + */ +/*@{*/ +#define BKPT32_INSTR 0xE1200070 /* ARM BKPT instruction */ +#define BKPT32_ENUM_MASK 0x000FFF0F /* ARM BKPT Enum Mask */ +#define BKPT32_AUTO_BKPT 0x00080000 /* ARM BKPT Auto-Step Flag (for CONT support) */ +#define BKPT32_MANUAL_BKPT 0x0007FF0F /* Manually inserted ARM Breakpoint */ + +#define BKPT16_INSTR 0xBE00 /* Thumb BKPT instruction (not supported currently) */ +#define BKPT16_ENUM_MASK 0x00FF /* Thumb BKPT Enum Mask */ +#define BKPT16_AUTO_BKPT 0x0080 /* Thumb BKPT Auto-Step Flag (for CONT support) */ +#define BKPT16_MANUAL_BKPT 0x007F /* Manually inserted Thumb Breakpoint */ +/*@}*/ + +/** 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_MANUAL_BKPT_ARM) /**< Manual ARM Breakpoint. */ +ENUM_VAL(DBG_NORMAL_BKPT_ARM) /**< Normal ARM Breakpoint (Single Step, Normal). */ +ENUM_VAL(DBG_MANUAL_BKPT_THUMB) /**< Manual Thumb Breakpoint. */ +ENUM_VAL(DBG_NORMAL_BKPT_THUMB) /**< Normal Thumb Breakpoint (Single Step, Normal). */ +ENUM_END(dbg_state_t) + +/** Debugger Message Error Enums + * + * Debugger Error Message Enums. + * The enums must be consecutive, starting from 1 + */ +ENUM_BEGIN +ENUM_VALASSIGN(MSG_ERRIMPL, 0) /**< Stub (not implemented) Error. */ +ENUM_VAL(MSG_ERRCHKSUM) /**< Checksum Error. */ +ENUM_VAL(MSG_ERRFORMAT) /**< Message Format Error. */ +ENUM_VAL(MSG_UNKNOWNCMD) /**< Unrecognized Command Error. */ +ENUM_VAL(MSG_UNKNOWNPARAM) /**< Unrecognized Parameter Error. */ +ENUM_END(dbg_msg_errno) + + +#ifndef __ASSEMBLY__ + +/* Define C stuff */ +/** @defgroup debug_public */ +/*@{*/ + + +/** Initialize Debugger. + * Equivalent to GDB set_debug_traps() routine + */ +FUNCDEF void dbg__bkpt_init(void); + +/** 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 inline void dbg_breakpoint_arm(void) { asm volatile (".word BKPT32_INSTR | BKPT32_MANUAL_BKPT") } + +/** dbg_breakpoint_thumb. + * Equivalent to GDB breakpoint() routine for Thumb code + */ +FUNCDEF inline void dbg_breakpoint_thumb(void) { asm volatile (".hword BKPT16_INSTR | BKPT16_MANUAL_BKPT") } + +/*@}*/ + +#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_arm + * GDB breakpoint() for Thumb mode + */ + .macro dbg__bkpt_thumb + .hword (BKPT16_INSTR | BKPT16_MANUAL_BKPT) + .endm + +#endif + /*@}*/ + +#endif /* __DEBUG_STUB_H__ */ diff --git a/Debugger/types.h b/Debugger/types.h new file mode 100644 index 0000000..3a1d4cb --- /dev/null +++ b/Debugger/types.h @@ -0,0 +1,46 @@ +/** @file types.h + * @brief Basic type definitions for the Arm7 platform. + */ + +/* Copyright (c) 2007,2008 the NxOS developers + * + * 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. + */ + +#ifndef __NXOS_BASE_TYPES_H__ +#define __NXOS_BASE_TYPES_H__ + +/** @addtogroup typesAndUtils */ +/*@{*/ + +typedef unsigned char U8; /**< Unsigned 8-bit integer. */ +typedef signed char S8; /**< Signed 8-bit integer. */ +typedef unsigned short U16; /**< Unsigned 16-bit integer. */ +typedef signed short S16; /**< Signed 16-bit integer. */ +typedef unsigned long U32; /**< Unsigned 32-bit integer. */ +typedef signed long S32; /**< Signed 32-bit integer. */ + +#ifndef __SIZE_TYPE__ +#define __SIZE_TYPE__ U32 /**< Used to go conform with gcc, otherwise we are + risking an error because of conflicting types for size_t */ +#endif +typedef __SIZE_TYPE__ size_t; /**< Abstract size type, needed by the memory allocator. */ + +typedef U8 bool; /**< Boolean data type. */ +#define FALSE (0) /**< False boolean value. */ +#define TRUE (!FALSE) /**< True boolean value. */ + +#ifndef NULL +/** Definition of the NULL pointer. */ +#define NULL ((void*)0) +#endif + +/** A function that takes no arguments and returns nothing. */ +typedef void (*nx_closure_t)(void); + +/*@}*/ + +#endif diff --git a/Debugger/undef_handler.S b/Debugger/undef_handler.S new file mode 100644 index 0000000..c160179 --- /dev/null +++ b/Debugger/undef_handler.S @@ -0,0 +1,71 @@ + +/* 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" + +#define MODE_SVC 0x13 /* Supervisor mode. */ + +.text +.code 32 +.align 0 + + .extern dbg__thumb_bkpt_handler + .extern dbg__arm_bkpt_handler + + .global undef_handler + +undef_handler: +/* Remote GDB Debugger relies on BKPT instruction being trapped here + In ARMv4t, it is an Illegal (Undefined) Instruction. + On triggering, lr (R14) contains the previous mode's pc (R15). + Based on example in Hohl, "ARM Assembly Language: Fundamentals and Techniques" + Chapter 11, Example 11.1. + Note: The handler is not AAPCS compliant (8 byte-alignment and stack, etc.) + */ + /* We assume that the UNDEF stack has been setup previously + On entry, LR_undef points to one instruction past the UNDEF instruction + */ + ldr sp, =__debugger_stack__ + stmfd sp, {r0-r15}^ /* Save workspace, user mode's pc via 'S' flag */ + sub sp, sp, #(4*16) /* Need to manually update SP(undef) */ + mrs r1, spsr /* Copy SPSR to r0 */ + sub r0, lr, #-4 /* LR points to instruction after UNDEF instruction */ + stmfd sp!, {r0,r1} /* Save UNDEF instruction addr and previous mode's CPSR to stack */ + 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 */ + and r0, r1, r0 /* Keep index value */ + msr cpsr_c, #(MODE_SVC) /* Configure Supervisor Mode */ + ldr lr, =dbg__thumb_bkpt_handler /* handle BKPT, BKPT index in r0 */ + mov pc, lr /* Invoke Debugger State (Supervisor Mode) */ +_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 */ + and r0, r1, r0 /* Keep index value */ + msr cpsr_c, #(MODE_SVC) /* Configure Supervisor Mode */ + ldr lr, =dbg__arm_bkpt_handler /* handle BKPT, BKPT index in r0 */ + mov pc, lr /* Invoke Debugger State (Supervisor Mode) */ + + +default_undef_handler: + b default_undef_handler /* Infinite loop */ -- cgit v1.2.3 From 97cc8322cef8027db22a24b7e011e5386171d97f Mon Sep 17 00:00:00 2001 From: TC Wan Date: Wed, 1 Dec 2010 17:54:07 +0800 Subject: fix undef_handler, initial design for next instruction decode Fixed error in handling Thumb instructions in undef_handler. Initial Design for Next Instruction Decoding --- .project | 11 +++++++++++ Debugger/debug_stub.S | 29 +++++++++++++++++++++++++++++ Debugger/debug_stub.h | 2 +- Debugger/undef_handler.S | 6 ++++-- 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 .project diff --git a/.project b/.project new file mode 100644 index 0000000..15b12fc --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + armdebug + + + + + + + + diff --git a/Debugger/debug_stub.S b/Debugger/debug_stub.S index 98bc968..030ce40 100644 --- a/Debugger/debug_stub.S +++ b/Debugger/debug_stub.S @@ -155,6 +155,25 @@ debug_cmdJumpTable: .word _dbg__nop /* '?' */ .word 0 +/* + * 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 */ + +/* Thumb Instruction Decode Table */ + .code 32 .text @@ -1245,8 +1264,18 @@ _dbg_next_instruction_addr: /* Here, r0 contains the instruction which will be reexecuted 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 next instruction is the instruction following the current instruction. */ 2: + /* Use R5 to store candidate next instruction address */ + teq r4, #0 /* Check if it is ARM or Thumb instruction */ + beq _next_instr_is_arm +_next_instr_is_thumb: + add r5, r2, #2 /* set next Thumb instruction address */ + _is_thumb_branch_instr r0 /* check if the current instruction is a branch instruction */ +_next_instr_is_arm: + add r5, r2, #4 /* Is ARM, set next ARM instruction address */ @@@@@@@@@ bx lr diff --git a/Debugger/debug_stub.h b/Debugger/debug_stub.h index 7849d56..311fa93 100644 --- a/Debugger/debug_stub.h +++ b/Debugger/debug_stub.h @@ -97,7 +97,7 @@ #define BKPT32_AUTO_BKPT 0x00080000 /* ARM BKPT Auto-Step Flag (for CONT support) */ #define BKPT32_MANUAL_BKPT 0x0007FF0F /* Manually inserted ARM Breakpoint */ -#define BKPT16_INSTR 0xBE00 /* Thumb BKPT instruction (not supported currently) */ +#define BKPT16_INSTR 0xBE00 /* Thumb BKPT instruction */ #define BKPT16_ENUM_MASK 0x00FF /* Thumb BKPT Enum Mask */ #define BKPT16_AUTO_BKPT 0x0080 /* Thumb BKPT Auto-Step Flag (for CONT support) */ #define BKPT16_MANUAL_BKPT 0x007F /* Manually inserted Thumb Breakpoint */ diff --git a/Debugger/undef_handler.S b/Debugger/undef_handler.S index c160179..34bca92 100644 --- a/Debugger/undef_handler.S +++ b/Debugger/undef_handler.S @@ -37,11 +37,11 @@ undef_handler: stmfd sp, {r0-r15}^ /* Save workspace, user mode's pc via 'S' flag */ sub sp, sp, #(4*16) /* Need to manually update SP(undef) */ mrs r1, spsr /* Copy SPSR to r0 */ - sub r0, lr, #-4 /* LR points to instruction after UNDEF instruction */ - stmfd sp!, {r0,r1} /* Save UNDEF instruction addr and previous mode's CPSR to stack */ tst r1, #CPSR_THUMB /* Check for Thumb Mode */ beq _is_arm /* Clear, so it's ARM mode */ _is_thumb: + sub r0, lr, #-2 /* LR points to instruction after UNDEF instruction */ + stmfd sp!, {r0,r1} /* Save UNDEF instruction addr and previous mode's CPSR to stack */ ldrh r0, [r0] /* load UNDEF instruction into r0 */ ldr r1, =BKPT16_ENUM_MASK /* Thumb BKPT enum mask */ bic r2, r0, r1 /* leave only opcode */ @@ -54,6 +54,8 @@ _is_thumb: ldr lr, =dbg__thumb_bkpt_handler /* handle BKPT, BKPT index in r0 */ mov pc, lr /* Invoke Debugger State (Supervisor Mode) */ _is_arm: + sub r0, lr, #-4 /* LR points to instruction after UNDEF instruction */ + stmfd sp!, {r0,r1} /* Save UNDEF instruction addr and previous mode's CPSR to stack */ ldr r0, [r0] /* load UNDEF instruction into r0 */ ldr r1, =BKPT32_ENUM_MASK /* ARM BKPT enum mask */ bic r2, r0, r1 /* leave only opcode */ -- cgit v1.2.3