⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 singlestep.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
//==========================================================================
//
//      singlestep.c
//
//      ARM(R) specific single-step support.
//
//==========================================================================
//####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):    
// Contributors: gthomas
// Date:         1999-10-20
// Purpose:      ARM(R) specific single-step support. 
// Description:  ARM is a Registered Trademark of Advanced RISC Machines Limited.
//               Other Brands and Trademarks are the property of their
//               respective owners.
//
//####DESCRIPTIONEND####
//
//=========================================================================


#include <stdlib.h>
#include <bsp/bsp.h>
#include <bsp/cpu.h>
#include "insn.h"

#define DEBUG_SINGLESTEP         0
#define DEBUG_SINGLESTEP_VERBOSE 0

/*
 * Structure to hold opcodes hoisted when breakpoints are
 * set for single-stepping or async interruption.
 */
struct _bp_save {
    unsigned long *addr;
    unsigned long opcode;
};

#define NUM_BREAKS_SAVED 2
static struct _bp_save _breaks[NUM_BREAKS_SAVED];

/*
 *  Insert a breakpoint at 'pc' using first available
 *  _bp_save struct.
 */
static void
insert_ss_break(unsigned long *pc)
{
    struct _bp_save *p = _breaks;
    union arm_insn inst;

    if (p->addr && (++p)->addr)
	return;

    /*
     * We can't set a breakpoint at 0
     */
    if (pc == 0)
    {
#if DEBUG_SINGLESTEP
        bsp_printf("Setting BP at <0x%08lx>: Error\n", pc);
#endif /* DEBUG_SINGLESTEP */
        return;
    }

    /*
     * Make sure we are on a long word boundary.
     */
    if (((unsigned long)pc & 0x3) != 0)
    {
        /*
         * All ARM(R) instructions are on a word boundary.
         * This would be invalid.  Don't set a bkpt here.
         */
#if DEBUG_SINGLESTEP
        bsp_printf("Setting BP at <0x%08lx>: Error\n", pc);
#endif /* DEBUG_SINGLESTEP */
        return;
    }


    /*
     * What is the current instruction
     */
    if (bsp_memory_read(pc, 0, ARM_INST_SIZE * 8, 1, &(inst.word)) == 0)
    {
        /*
         * Unable to read this address, probably an invalid address.
         * Don't set a breakpoint here, as it will likely cause a bus error
         */
#if DEBUG_SINGLESTEP
        bsp_printf("Setting BP at <0x%08lx>: Error\n", pc);
#endif /* DEBUG_SINGLESTEP */
        return;
    }

    if (inst.word != BREAKPOINT_INSN)
    {
        /*
         * Only insert a breakpoint if we haven't done so already
         *
         * We may try to insert 2 breakpoints if we to a branch to
         * the immediately following instruction.
         */
#if DEBUG_SINGLESTEP
        bsp_printf("Setting BP at <0x%08lx>: inst <0x%08lx>\n", pc, inst.word);
#endif /* DEBUG_SINGLESTEP */

        p->addr = pc;
        p->opcode = inst.word;
        inst.word = BREAKPOINT_INSN;
        if (bsp_memory_write(pc, 0, ARM_INST_SIZE * 8, 1, &(inst.word)) == 0)
        {
            /*
             * Unable to write this address, probably an invalid address.
             * Don't set a breakpoint here, as it will likely cause a bus error
             */
#if DEBUG_SINGLESTEP
            bsp_printf("Setting BP at <0x%08lx>: Error\n", pc);
#endif /* DEBUG_SINGLESTEP */
            return;
        }

        /* flush icache and dcache, now */
        bsp_flush_dcache((void *)pc, ARM_INST_SIZE);
        bsp_flush_icache((void *)pc, ARM_INST_SIZE);

#if DEBUG_SINGLESTEP_VERBOSE
        bsp_printf("Done setting BP at <0x%08lx>: inst <0x%08lx>\n", pc, *pc);
#endif /* DEBUG_SINGLESTEP_VERBOSE */
    }
}

/*
 *  Cleanup after a singlestep.
 */
void
bsp_singlestep_cleanup(void *registers)
{
    struct _bp_save *p = _breaks;
    int i;
    
    for (i = 0; i < NUM_BREAKS_SAVED; i++, p++)
    {
        if (p->addr)
        {
            unsigned long *old_addr = p->addr;

#if DEBUG_SINGLESTEP_VERBOSE
            bsp_printf("Remove BP at <0x%08lx>: inst <0x%08lx>\n", old_addr, *old_addr);
#endif /* DEBUG_SINGLESTEP */
            *(p->addr) = p->opcode;
            p->addr = NULL;

            /* flush icache and dcache, now */
            bsp_flush_dcache((void *)old_addr, ARM_INST_SIZE);
            bsp_flush_icache((void *)old_addr, ARM_INST_SIZE);

#if DEBUG_SINGLESTEP_VERBOSE
            bsp_printf("Done removing BP at <0x%08lx>: inst <0x%08lx>\n", old_addr, *old_addr);
#endif /* DEBUG_SINGLESTEP_VERBOSE */
        }
    }
}

/*
 * Rotate right a value by count
 */
static unsigned long ror(unsigned long value, unsigned count)
{
    while (count-- > 0)
    {
        if (value & 0x1)
            value = (value >> 1) | 0x80000000;
        else
            value = (value >> 1);
    }

    return(value);
}

/*
 * Rotate right a value by 1 with extend
 */
static unsigned long rrx(union arm_psr sr, unsigned long value)
{
    if (sr.psr.c_bit)
        value = (value >> 1) | 0x80000000;
    else
        value = (value >> 1);

    return(value);
}

/*
 * Logical shift left by count
 */
static unsigned long lsl(unsigned long value, unsigned count)
{
    value <<= count;

    return(value);
}

/*
 * Logical shift right by count
 */
static unsigned long lsr(unsigned long value, unsigned count)
{
    value >>= count;

    return(value); 
}

/*
 * Arithmetic shift right by count
 */
static unsigned long asr(unsigned long value, unsigned count)
{
    unsigned long sign_ext_mask = 0;

    if (value & 0x80000000)
    {
        if (count >= sizeof(value)*8)
            sign_ext_mask = ~0;
        else
            sign_ext_mask = (~0 << (sizeof(value)*8 - count));
    }
    value = (value >> count) | sign_ext_mask;

    return(value); 
}

/*
 * Calculate an immediate shift operand based on input shift operand, 
 * shift value and register address.
 */
static unsigned long immediate_shift_operand(ex_regs_t *regs, unsigned shift_immediate, 
                                             unsigned shift, unsigned Rm)
{
    unsigned char *regs_array = (unsigned char *)regs;
    unsigned char *reg_ptr = &regs_array[bsp_regbyte(Rm)];
    unsigned long reg_value = *((unsigned long *)(reg_ptr));
    unsigned long rc = 0;

    BSP_ASSERT((shift_immediate >= 0) && (shift_immediate <= 0x1f));
    BSP_ASSERT((shift >= 0) && (shift <= 0x3));
    BSP_ASSERT((Rm >= 0) && (Rm <= 0xf));
    BSP_ASSERT(bsp_regsize(Rm) == sizeof(unsigned long));

    /*
     * According to the ARM(R) Manual, if Rm is PC then,
     * the value used is the address of the current instruction
     * plus 8
     */
    if (Rm == REG_PC)
        reg_value += 8;

    switch (shift)
    {
    case SHIFT_LSL:
        rc = lsl(reg_value, shift_immediate);
        break;

    case SHIFT_LSR:
        if (shift_immediate == 0)
        {
            /*
             * Special Case: LSR IMM(0) == 0
             */
            rc = 0;
        } else {
            rc = lsr(reg_value, shift_immediate);
        }
        break;

    case SHIFT_ASR:
        if (shift_immediate == 0)
        {
            /*
             * Special Case: ASR IMM(0)
             */
            if (reg_value & 0x80000000)
            {
                rc = 0xFFFFFFFF;
            } else {
                rc = 0;
            }
        } else {
            rc = asr(reg_value, shift_immediate);
        }
        break;

    case SHIFT_ROR:
        if (shift_immediate == 0)
        {
            /*
             * SHIFT_RRX
             * Special case: ROR(0) implies RRX
             */
            rc = rrx((union arm_psr)(unsigned long)regs->_cpsr, reg_value);
        } else {
            rc = ror(reg_value, shift_immediate);
        }
        break;

    default:
        BSP_ASSERT(0);
        break;
    }

    return (rc);
}

/*
 * Calculate a register shift operand based on input shift operand, 
 * and target registers.
 */
static unsigned long register_shift_operand(ex_regs_t *regs, unsigned Rs,
                                            unsigned shift, unsigned Rm)
{
    unsigned char *regs_array = (unsigned char *)regs;
    unsigned char *Rs_ptr = &regs_array[bsp_regbyte(Rs)];
    unsigned char *Rm_ptr = &regs_array[bsp_regbyte(Rm)];
    unsigned long Rs_val = *((unsigned long *)(Rs_ptr));
    unsigned long Rm_val = *((unsigned long *)(Rm_ptr));
    unsigned long rc = 0;

    /*
     * Use only the least significant byte of Rs
     */
    Rs_val &= 0xFF;

    BSP_ASSERT((Rs >= 0) && (Rs <= 0xf));
    BSP_ASSERT((shift >= 0) && (shift <= 0x3));
    BSP_ASSERT((Rm >= 0) && (Rm <= 0xf));
    BSP_ASSERT(bsp_regsize(Rs) == sizeof(unsigned long));
    BSP_ASSERT(bsp_regsize(Rm) == sizeof(unsigned long));
    BSP_ASSERT((Rs_val >=0) && (Rs_val <= 0xff));

    /*
     * According to the ARM(R) Manual, if Rm is PC then,
     * the value used is the address of the current instruction
     * plus 8
     */
    if (Rm == REG_PC)
        Rm_val += 8;

    switch (shift)
    {
    case SHIFT_LSL: rc = lsl(Rm_val, Rs_val); break;
    case SHIFT_LSR: rc = lsr(Rm_val, Rs_val); break;
    case SHIFT_ASR: rc = asr(Rm_val, Rs_val); break;
    case SHIFT_ROR: rc = ror(Rm_val, Rs_val); break;
    default:        BSP_ASSERT(0);            break;
    }

    return (rc);
}

/*
 * Calculate a branch exchange operand based on input destination register
 */
static unsigned long branch_exchange_operand(ex_regs_t *regs, unsigned Rm)
{
    unsigned char *regs_array = (unsigned char *)regs;
    unsigned char *reg_ptr = &regs_array[bsp_regbyte(Rm)];
    unsigned long reg_value = *((unsigned long *)(reg_ptr));

    BSP_ASSERT((Rm >= 0) && (Rm <= 0xf));
    BSP_ASSERT(bsp_regsize(Rm) == sizeof(unsigned long));

    /*
     * Clear the low-order bit
     */
    return (reg_value & ~0x1);
}

/*
 * Handle a load to the PC
 */
static void handle_pc_load(unsigned size, unsigned long operand)
{
    unsigned long mem_value = 0;

    if (size == LS_SIZE_WORD)
    {
        if (bsp_memory_read((void*)(operand & ~0x3), 0, 32, 1, &mem_value) == 0)
        {
            /*
             * Unable to read the memory address.
             * Don't try any further.
             */
#if DEBUG_SINGLESTEP
            bsp_printf("Setting BP at *(0x%08lx): Error\n", operand & ~0x3);
#endif /* DEBUG_SINGLESTEP */
            return;
        } else {
#if DEBUG_SINGLESTEP
            bsp_printf("Setting BP at *(0x%08lx): data <0x%08lx>\n", operand & ~0x3, mem_value);
#endif /* DEBUG_SINGLESTEP */
        }

        /*
         * Handle rotations if required
         */
        switch (operand & 0x3)

⌨️ 快捷键说明

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