Mercurial > flash_v2
diff packages/hal/sh/arch/current/src/sh_stub.c @ 76:435cced73e2f ecos-v1_3_1-release
eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
| author | jlarmour |
|---|---|
| date | Tue, 28 Mar 2000 14:10:45 +0000 |
| parents | |
| children | 02ea4320376c |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/hal/sh/arch/current/src/sh_stub.c @@ -0,0 +1,281 @@ +//========================================================================== +// +// sh_stub.c +// +// GDB Stub code for SH +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): jskov +// Contributors: jskov, Ben Lee, Steve Chamberlain +// Date: 1999-05-18 +// Description: GDB Stub support for sh CPU. +// +//####DESCRIPTIONEND#### +// +//=========================================================================== + +#include <stddef.h> + +#include <pkgconf/hal.h> + +#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS + +#include <cyg/hal/sh_regs.h> + +#include <cyg/hal/hal_stub.h> +#include <cyg/hal/hal_arch.h> +#include <cyg/hal/hal_intr.h> + +#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT +#include <cyg/hal/dbg-threads-api.h> // dbg_currthread_id +#endif + +/* Given a trap value TRAP, return the corresponding signal. */ + +int +__computeSignal(unsigned int trap_number) +{ + switch( trap_number ) { + case CYGNUM_HAL_EXCEPTION_TRAP: + case CYGNUM_HAL_EXCEPTION_INSTRUCTION_BP: + return SIGTRAP; + + case CYGNUM_HAL_EXCEPTION_POWERON: + case CYGNUM_HAL_EXCEPTION_RESET: + // Reset - given that the CPU resets if it gets confused we + // want to treat it as an interupt so the developer has a + // chance to find out what happened (as opposed to SIGTERM). + return SIGINT; + + case CYGNUM_HAL_EXCEPTION_TLBMISS_ACCESS: + case CYGNUM_HAL_EXCEPTION_TLBMISS_WRITE: + case CYGNUM_HAL_EXCEPTION_INITIAL_WRITE: + case CYGNUM_HAL_EXCEPTION_TLBERROR_ACCESS: + case CYGNUM_HAL_EXCEPTION_TLBERROR_WRITE: + return SIGSEGV; + + case CYGNUM_HAL_EXCEPTION_DATA_ACCESS: + case CYGNUM_HAL_EXCEPTION_DATA_WRITE: + return SIGBUS; + + case CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION: + case CYGNUM_HAL_EXCEPTION_ILLEGAL_SLOT_INSTRUCTION: + return SIGILL; + + default: + return SIGTERM; + } +} + +/* Return the trap number corresponding to the last-taken trap. */ + +int +__get_trap_number(void) +{ + // The vector is not not part of the GDB register set so get it + // directly from the save context. + return _hal_registers->event; +} + +/* Set the currently-saved pc register value to PC. This also updates NPC + as needed. */ + +void +set_pc(target_register_t pc) +{ + put_register(PC, pc); +} + + +/*---------------------------------------------------------------------- + * Single-step support, copied from gdb/sh-stub.c, written by Ben Lee + * and Steve Chamberlain. Extended to handle braf, bsrf, bt/s and bf/s. + */ + +#define COND_BRx_MASK 0xfb00 +#define UCOND_DBR_MASK 0xe000 +#define UCOND_RBR_MASK 0xf0df +#define TRAPA_MASK 0xff00 + +#define COND_DISP 0x00ff +#define UCOND_DISP 0x0fff +#define UCOND_REG 0x0f00 + +#define BFx_INSTR 0x8b00 +#define BTx_INSTR 0x8900 +#define BRA_INSTR 0xa000 +#define BSR_INSTR 0xb000 +#define JMP_INSTR 0x402b +#define JSR_INSTR 0x400b +#define RTS_INSTR 0x000b +#define RTE_INSTR 0x002b +#define TRAPA_INSTR 0xc300 +#define BxxF_INSTR 0x0003 + +#define SSTEP_INSTR 0xc3ff + +#define T_BIT_MASK 0x0001 + +typedef struct { + short *memAddr; + short oldInstr; +} stepData; + +static stepData instrBuffer; +static char stepped; + +/* Set things up so that the next user resume will execute one instruction. + This may be done by setting breakpoints or setting a single step flag + in the saved user registers, for example. */ + +void __single_step (void) +{ + short *instrMem; + int displacement; + int reg; + unsigned short opcode; + + cyg_uint32 pc = get_register(PC); + cyg_uint32 sr = get_register(SR); + + instrMem = (short *) pc; + + opcode = *instrMem; + stepped = 1; + + if ((opcode & UCOND_RBR_MASK) == BxxF_INSTR) { + reg = (char) ((opcode & UCOND_REG) >> 8); + displacement = get_register(reg); + instrMem = (short *) (pc + displacement + 4); + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + } else if ((opcode & COND_BRx_MASK) == BTx_INSTR) { + if (sr & T_BIT_MASK) { + displacement = (opcode & COND_DISP) << 1; + if (displacement & 0x80) { + displacement |= 0xffffff00; + } + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + instrMem = (short *) (pc + displacement + 4); + } else { + instrMem += 1; + } + } else if ((opcode & COND_BRx_MASK) == BFx_INSTR) { + if (sr & T_BIT_MASK) { + instrMem += 1; + } else { + displacement = (opcode & COND_DISP) << 1; + if (displacement & 0x80) + displacement |= 0xffffff00; + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + instrMem = (short *) (pc + displacement + 4); + } + } else if ((opcode & UCOND_DBR_MASK) == BRA_INSTR) { + displacement = (opcode & UCOND_DISP) << 1; + if (displacement & 0x0800) { + displacement |= 0xfffff000; + } + + /* + * Remember PC points to second instr. + * after PC of branch ... so add 4 + */ + instrMem = (short *) (pc + displacement + 4); + } else if ((opcode & UCOND_RBR_MASK) == JSR_INSTR) { + reg = (char) ((opcode & UCOND_REG) >> 8); + instrMem = (short *) get_register(reg); + } else if (opcode == RTS_INSTR) { + instrMem = (short *) get_register(PR); + } else if (opcode == RTE_INSTR) { + instrMem = (short *) get_register(SP); + } else if ((opcode & TRAPA_MASK) == TRAPA_INSTR) { + instrMem = (short *) ((opcode & ~TRAPA_MASK) << 2); + } else { + instrMem += 1; + } + + instrBuffer.memAddr = instrMem; + instrBuffer.oldInstr = *instrMem; + *instrMem = SSTEP_INSTR; +} + +/* Clear the single-step state. */ + +void __clear_single_step (void) +{ + /* Undo the effect of a previous doSStep. If we single stepped, + restore the old instruction. */ + + if (stepped) { + short *instrMem; + instrMem = instrBuffer.memAddr; + *instrMem = instrBuffer.oldInstr; + } + stepped = 0; +} + + +void __install_breakpoints (void) +{ + /* NOP since single-step HW exceptions are used instead of + breakpoints. */ +} + +void __clear_breakpoints (void) +{ +} + + +/* If the breakpoint we hit is in the breakpoint() instruction, return a + non-zero value. */ + +int +__is_breakpoint_function () +{ + return get_register(PC) == (target_register_t)&CYG_LABEL_NAME(breakinst); +} + + +/* Skip the current instruction. Since this is only called by the + stub when the PC points to a breakpoint or trap instruction, + we can safely just skip 2. */ +void __skipinst (void) +{ + put_register(PC, get_register (PC) + 2); +} + +#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
