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

📄 arm_stub.c

📁 ecos实时嵌入式操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
                    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<<i)) reg_count++;                    }                                        if (ins & 0x00800000) {                        // Add offset                        Rn += reg_count*4;                    } else {                        // Subtract offset                        Rn -= 4;                    }                    return ((unsigned long *)*(unsigned long *)Rn);                }            }        } else {            // Branch            if (ins_will_execute(ins)) {                offset = (ins & 0x00FFFFFF) << 2;                if (ins & 0x00800000) offset |= 0xFC000000;  // sign extend                new_pc = (unsigned long)(pc+2) + offset;		// If its BLX, make new_pc a thumb address.		if ((ins & 0xFE000000) == 0xFA000000) {		    if ((ins & 0x01000000) == 0x01000000)			new_pc |= 2;		    new_pc = MAKE_THUMB_ADDR(new_pc);		}                return ((unsigned long *)new_pc);            } else {                // Falls through                return (pc+1);            }        }    case 0x3:  // Coprocessor & SWI        return (pc+1);    default:        // Never reached - but fixes compiler warning.        return 0;    }}// FIXME: target_ins also needs to check for CPSR/THUMB being set and//        set the thumb bit accordingly.static unsigned longtarget_thumb_ins(unsigned long pc, unsigned short ins){    unsigned long new_pc = MAKE_THUMB_ADDR(pc+2); // default is fall-through                                         // to next thumb instruction    unsigned long offset, arm_ins, sp;    int i;    switch ((ins & 0xf000) >> 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        // Use ARM function to check condition        arm_ins = ((unsigned long)(ins & 0x0f00)) << 20;        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;    }}/* Clear the single-step state. */void __clear_single_step (void){    if (ss_saved_pc != 0) {        // Restore instruction according to type        if (IS_THUMB_ADDR(ss_saved_pc)) {            // Thumb instruction            unsigned long t_pc = UNMAKE_THUMB_ADDR(ss_saved_pc);            *(unsigned short*)t_pc = ss_saved_thumb_instr;        } else {            // ARM instruction            *(unsigned long*)ss_saved_pc = ss_saved_instr;        }        ss_saved_pc = 0;    }}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);    unsigned long cpsr = get_register(PS);    if (cpsr & CPSR_THUMB_ENABLE)        pc += 2;    else        pc += 4;    put_register(PC, pc);}//-----------------------------------------------------------------------// Thumb-aware GDB interrupt handler.// This is a brute-force replacement of the ones in hal_stub.c. Need to// find a better way of handling it... Maybe... Probably only ARM/thumb// that is this weird.typedef struct{    cyg_uint32 targetAddr;    union {        cyg_uint32 arm_instr;        cyg_uint16 thumb_instr;    } savedInstr;} instrBuffer;static instrBuffer break_buffer;volatile int cyg_hal_gdb_running_step = 0;// This function is passed thumb/arm information about the PC address// in bit 0. This information is passed on to the break_buffer.void cyg_hal_gdb_place_break (target_register_t pc){    // Clear flag that we Continued instead of Stepping    cyg_hal_gdb_running_step = 0;    if (0 == break_buffer.targetAddr) {        // Setting a breakpoint in Thumb or ARM code?       if (IS_THUMB_ADDR(pc)) {            break_buffer.targetAddr = (cyg_uint32)pc;            pc = UNMAKE_THUMB_ADDR(pc);            break_buffer.savedInstr.thumb_instr = *(cyg_uint16*)pc;            *(cyg_uint16*)pc = HAL_BREAKINST_THUMB;        } else {            break_buffer.targetAddr = (cyg_uint32)pc;            break_buffer.savedInstr.arm_instr = *(cyg_uint32*)pc;            *(cyg_uint32*)pc = HAL_BREAKINST_ARM;        }                __data_cache(CACHE_FLUSH);        __instruction_cache(CACHE_FLUSH);    }}int cyg_hal_gdb_remove_break (target_register_t pc){    if ( cyg_hal_gdb_running_step )        return 0; // Do not remove the break: we must hit it!    if (pc == UNMAKE_THUMB_ADDR(break_buffer.targetAddr)) {        if (IS_THUMB_ADDR(break_buffer.targetAddr)) {            *(cyg_uint16*)pc = break_buffer.savedInstr.thumb_instr;        } else {            *(cyg_uint32*)pc = break_buffer.savedInstr.arm_instr;        }        break_buffer.targetAddr = 0;        __data_cache(CACHE_FLUSH);        __instruction_cache(CACHE_FLUSH);        return 1;    }    return 0;}void cyg_hal_gdb_interrupt (target_register_t pc){    // Clear flag that we Continued instead of Stepping    cyg_hal_gdb_running_step = 0;    // and override existing break? So that a ^C takes effect...    if (0 != break_buffer.targetAddr)        cyg_hal_gdb_remove_break( break_buffer.targetAddr );    if (0 == break_buffer.targetAddr) {        cyg_uint32 cpsr = get_register(PS);        if (cpsr & CPSR_THUMB_ENABLE) {            break_buffer.targetAddr = MAKE_THUMB_ADDR((cyg_uint32)pc);            break_buffer.savedInstr.thumb_instr = *(cyg_uint16*)pc;            *(cyg_uint16*)pc = HAL_BREAKINST_THUMB;        } else {            break_buffer.targetAddr = (cyg_uint32)pc;            break_buffer.savedInstr.arm_instr = *(cyg_uint32*)pc;            *(cyg_uint32*)pc = HAL_BREAKINST_ARM;        }        __data_cache(CACHE_FLUSH);        __instruction_cache(CACHE_FLUSH);    }}intcyg_hal_gdb_break_is_set (void){    if (0 != break_buffer.targetAddr) {        return 1;    }    return 0;}#ifdef CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT#define ICE_THREAD_KEY0 0xDEAD0001#define ICE_THREAD_KEY1 0xDEAD0002#define ICE_THREAD_INBUFSIZ  2048#define ICE_THREAD_OUTBUFSIZ 2048#define ICE_THREAD_STACKSIZE 4096static cyg_uint8 ice_thread_inbuf[ICE_THREAD_INBUFSIZ];static cyg_uint8 ice_thread_outbuf[ICE_THREAD_OUTBUFSIZ];static cyg_uint8 ice_thread_stack[ICE_THREAD_STACKSIZE];static void ice_thread_proc(void);struct {    cyg_uint32 _key0;  // Must be ICE_KEY0    cyg_uint8  *in_buffer;    cyg_int32  in_buffer_size;    cyg_uint8  *out_buffer;    cyg_int32  out_buffer_size;    cyg_uint8  *stack;    cyg_int32  stack_size;    void       (*fun)(void);    cyg_uint32 _key1;  // Must be ICE_KEY1} hal_arm_ice_thread_handler = {    ICE_THREAD_KEY0,    ice_thread_inbuf,    ICE_THREAD_INBUFSIZ,    ice_thread_outbuf,    ICE_THREAD_OUTBUFSIZ,    ice_thread_stack,    ICE_THREAD_STACKSIZE,    ice_thread_proc,    ICE_THREAD_KEY1,};static intice_thread_query(void){    switch (ice_thread_inbuf[1]) {    case 'L': // get thread list        stub_pkt_getthreadlist(&ice_thread_inbuf[2], ice_thread_outbuf, sizeof(ice_thread_outbuf));        break;    case 'P': // thread or process information        stub_pkt_getthreadinfo(&ice_thread_inbuf[2], ice_thread_outbuf, sizeof(ice_thread_outbuf));        break;    case 'C': // current thread        stub_pkt_currthread(&ice_thread_inbuf[2], ice_thread_outbuf, sizeof(ice_thread_outbuf));        break;    default:        return 0;    }    return 1;}static intice_thread_set(void){    return 0;}static voidice_thread_proc(void){    switch (ice_thread_inbuf[0]) {    case 'g': // Fetch thread registers        stub_format_registers(ice_thread_outbuf);        return;    case 'P': // Update a single register    case 'G': // Update all registers        stub_update_registers(ice_thread_inbuf, ice_thread_outbuf);        return;    case 'H': // Thread set/query        stub_pkt_changethread(&ice_thread_inbuf[1], ice_thread_outbuf, sizeof(ice_thread_outbuf));        return;    case 'q': // Thread queries        if (ice_thread_query()) return;        break;    case 'Q': // Thread set operations        if (ice_thread_set()) return;        break;    case 'T': // Thread alive?        stub_pkt_thread_alive(&ice_thread_inbuf[1], ice_thread_outbuf, sizeof(ice_thread_outbuf));        return;    default:    }    strcpy(ice_thread_outbuf, "ENN");  // Dunno}#endif // CYGHWR_HAL_ARM_ICE_THREAD_SUPPORT#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS

⌨️ 快捷键说明

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