frv_stub.c

来自「eCos操作系统源码」· C语言 代码 · 共 383 行

C
383
字号
//========================================================================////      frv_stub.c////      Helper functions for stub, generic to all FUJITSU processors////========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//========================================================================//#####DESCRIPTIONBEGIN####//// Author(s):     Red Hat, gthomas// Contributors:  Red Hat, gthomas, jskov, msalter// Date:          2001-09-16// Purpose:       // Description:   Helper functions for stub, generic to all FUJITSU processors// Usage:         ////####DESCRIPTIONEND####////========================================================================#include <pkgconf/hal.h>#ifdef CYGPKG_REDBOOT#include <pkgconf/redboot.h>#endif#ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS#include <cyg/hal/hal_stub.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/hal_intr.h>#include <cyg/hal/hal_cache.h>#ifndef FALSE#define FALSE 0#define TRUE  1#endif#ifdef CYGDBG_HAL_DEBUG_GDB_THREAD_SUPPORT#include <cyg/hal/dbg-threads-api.h>    // dbg_currthread_id#endif#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)cyg_uint32 __frv_breakinst = HAL_BREAKINST;#endif// Sadly, this doesn't seem to work on the FRV400 either//#define USE_HW_STEP  #ifdef CYGSEM_HAL_FRV_HW_DEBUGstatic inline unsigned __get_dcr(void){    unsigned retval;    asm volatile (        "movsg   dcr,%0\n"        : "=r" (retval)        : /* no inputs */  );    return retval;}static inline void __set_dcr(unsigned val){    asm volatile (        "movgs   %0,dcr\n"        : /* no outputs */        : "r" (val) );}#endif/* Given a trap value TRAP, return the corresponding signal. */int __computeSignal (unsigned int trap_number){    // should also catch CYGNUM_HAL_VECTOR_UNDEF_INSTRUCTION here but we    // can't tell the different between a real one and a breakpoint :-(    switch (trap_number) {      // Interrupts    case CYGNUM_HAL_VECTOR_EXTERNAL_INTERRUPT_LEVEL_1 ... CYGNUM_HAL_VECTOR_EXTERNAL_INTERRUPT_LEVEL_15:        return SIGINT;    case CYGNUM_HAL_VECTOR_INSTR_ACCESS_MMU_MISS:    case CYGNUM_HAL_VECTOR_INSTR_ACCESS_ERROR:    case CYGNUM_HAL_VECTOR_INSTR_ACCESS_EXCEPTION:    case CYGNUM_HAL_VECTOR_MEMORY_ADDRESS_NOT_ALIGNED:    case CYGNUM_HAL_VECTOR_DATA_ACCESS_ERROR:    case CYGNUM_HAL_VECTOR_DATA_ACCESS_MMU_MISS:    case CYGNUM_HAL_VECTOR_DATA_ACCESS_EXCEPTION:    case CYGNUM_HAL_VECTOR_DATA_STORE_ERROR:        return SIGBUS;    case CYGNUM_HAL_VECTOR_PRIVELEDGED_INSTRUCTION:    case CYGNUM_HAL_VECTOR_ILLEGAL_INSTRUCTION:    case CYGNUM_HAL_VECTOR_REGISTER_EXCEPTION:    case CYGNUM_HAL_VECTOR_FP_DISABLED:    case CYGNUM_HAL_VECTOR_MP_DISABLED:    case CYGNUM_HAL_VECTOR_FP_EXCEPTION:    case CYGNUM_HAL_VECTOR_MP_EXCEPTION:    case CYGNUM_HAL_VECTOR_DIVISION_EXCEPTION:    case CYGNUM_HAL_VECTOR_COMMIT_EXCEPTION:    case CYGNUM_HAL_VECTOR_COMPOUND_EXCEPTION:      return SIGILL;    default:        return SIGTRAP;    }}/* 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->vector;}#if defined(CYGSEM_REDBOOT_BSP_SYSCALLS)int __is_bsp_syscall(void) {  // Might want to be more specific here  return (_hal_registers->vector == CYGNUM_HAL_VECTOR_SYSCALL);}#endif // defined(CYGSEM_REDBOOT_BSP_SYSCALLS)/* Set the currently-saved pc register value to PC. */void set_pc (target_register_t pc){    put_register (PC, pc);}/*---------------------------------------------------------------------- * Single-step support *//* 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. */#ifndef CYGSEM_HAL_FRV_HW_DEBUG#if CYGINT_HAL_FRV_ARCH_FR400 == 1#define VLIW_DEPTH 2#endif#if CYGINT_HAL_FRV_ARCH_FR500 == 1#define VLIW_DEPTH 4#endif/* * Structure to hold opcodes hoisted when breakpoints are * set for single-stepping or async interruption. */struct _bp_save {    unsigned long  *addr;    unsigned long   opcode;};/* * We single-step by setting breakpoints. * * This is where we save the original instructions. */static struct _bp_save step_bp[VLIW_DEPTH+1];//**************************************************************//************ CAUTION!! ***************************************//**************************************************************//// Attempt to analyze the current instruction.  This code is not// perfect in the case of VLIW sequences, although it's close.// Consider these sequences:////      ldi.p   @(gr5,0),gr4//      jmpl    @(gr4,gr0)// and ////      ldi.p   @(gr5,0),gr4//      add.p   gr6,gr7,gr8//      jmpl    @(gr4,gr0)//// In these cases, the only way to effectively calculate the // target address (of the jump) would be to simulate the actions// of the pipelined instructions which come beforehand.//// Of course, this only affects single stepping through a VLIW// sequence which contains such pipelined effects and a branch.// Hopefully this is rare.//// Note: testing of the above sequence on the FR400 yielded an// illegal instruction (invalid VLIW sequence), so this may not// turn out to be a problem in practice, just theory.////**************************************************************//**************************************************************static int_analyze_instr(unsigned long pc, unsigned long *targ,                unsigned long *next, int *is_vliw){    unsigned long opcode;    int n, is_branch = 0;    opcode = *(unsigned long *)pc;    switch ((opcode >> 18) & 0x7f) {    case 6:    case 7:        /* bcc, fbcc */        is_branch = 1;        n = (int)(opcode << 16);        n >>= 16;        *targ = pc + n*4;        pc += 4;        break;    case 12:        /* jmpl */        n = (int)(get_register((opcode>>12)&63));        n += (int)(get_register(opcode&63));        pc = n;        break;    case 13:        /* jmpil */        n = (int)(get_register((opcode>>12)&63));        n += (((int)(opcode << 20)) >> 20);        pc = n;        break;    case 15:        /* call */        n = (opcode >> 25) << 18;        n |= (opcode & 0x3ffff);        n <<= 8;        n >>= 8;        pc += n*4;        break;    case 14:        /* ret */        is_branch = 1;        *targ = get_register(LR);        pc += 4;        break;    default:        pc += 4;        break;    }    *next = pc;    *is_vliw = (opcode & 0x80000000) == 0;    return is_branch;}#endifvoid __single_step (void){#ifdef CYGSEM_HAL_FRV_HW_DEBUG    __set_dcr(__get_dcr() | _DCR_SE);    diag_printf("Setting single step - DCR: %x\n", __get_dcr());#else    unsigned long pc, targ, next_pc;    int i, is_branch = 0;    int is_vliw;    for (i = 0;  i < VLIW_DEPTH+1;  i++) {        step_bp[i].addr = NULL;    }    pc = get_register(PC);    i = 1;    while (i < (VLIW_DEPTH+1)) {        is_branch = _analyze_instr(pc, &targ, &next_pc, &is_vliw);        if (is_branch && next_pc != targ) {            step_bp[i].addr = (unsigned long *)targ;            step_bp[i].opcode = *(unsigned long *)targ;            *(unsigned long *)targ = HAL_BREAKINST;            HAL_DCACHE_STORE(targ, 4);            HAL_ICACHE_INVALIDATE(targ, 4);        }        if (is_vliw) {            pc += 4;            i++;        } else {            break;        }    }    step_bp[0].addr = (unsigned long *)next_pc;    step_bp[0].opcode = *(unsigned long *)next_pc;    *(unsigned long *)next_pc = HAL_BREAKINST;    HAL_DCACHE_STORE(next_pc, 4);    HAL_ICACHE_INVALIDATE(next_pc, 4);#endif}/* Clear the single-step state. */void __clear_single_step (void){#ifdef CYGSEM_HAL_FRV_HW_DEBUG    __set_dcr(__get_dcr() & ~_DCR_SE);#else    struct _bp_save *p;    int i;    for (i = 0;  i < VLIW_DEPTH+1;  i++) {        p = &step_bp[i];        if (p->addr) {            *(p->addr) = p->opcode;            HAL_DCACHE_STORE((cyg_uint32)p->addr, 4);            HAL_ICACHE_INVALIDATE((cyg_uint32)p->addr, 4);            p->addr = NULL;        }    }#endif}void __install_breakpoints (void){#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)    /* Install the breakpoints in the breakpoint list */    __install_breakpoint_list();#endif}void __clear_breakpoints (void){#if defined(CYGNUM_HAL_BREAKPOINT_LIST_SIZE) && (CYGNUM_HAL_BREAKPOINT_LIST_SIZE > 0)    __clear_breakpoint_list();#endif}/* 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)&_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 4. */void __skipinst (void){    unsigned long pc = get_register(PC);    pc += 4;    put_register(PC, pc);}#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?