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

📄 ppc_stub.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 2 页
字号:
  memcpy (value, (char *)_registers + offset, REGSIZE(which));
  return 1;
}

// Alter the contents of saved register WHICH to contain VALUE. This
// is only used for registers larger than sizeof(target_register_t).
// Return non-zero if it is a valid register.
int
put_register_as_bytes (regnames_t which, char *value)
{
  int offset = reg_offset(which);

  memcpy ((char *)_registers + offset, value, REGSIZE(which));
  return 1;
}
#endif

/*----------------------------------------------------------------------
 * 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. */

#ifdef USE_BREAKPOINTS_FOR_SINGLE_STEP

#if (HAL_BREAKINST_SIZE == 1)
typedef cyg_uint8 t_inst;
#elif (HAL_BREAKINST_SIZE == 2)
typedef cyg_uint16 t_inst;
#elif (HAL_BREAKINST_SIZE == 4)
typedef cyg_uint32 t_inst;
#else
#error "Don't know how to handle that size"
#endif

typedef struct
{
  t_inst *targetAddr;
  t_inst savedInstr;
} instrBuffer;

static instrBuffer sstep_instr[2];
static target_register_t irq_state = 0;

static void 
__insert_break(int indx, target_register_t pc)
{
    sstep_instr[indx].targetAddr = (t_inst *)pc;
    sstep_instr[indx].savedInstr = *(t_inst *)pc;
    *(t_inst*)pc = (t_inst)HAL_BREAKINST;
    __data_cache(CACHE_FLUSH);
    __instruction_cache(CACHE_FLUSH);
}

static void 
__remove_break(int indx)
{
    if (sstep_instr[indx].targetAddr != 0) {
        *(sstep_instr[indx].targetAddr) = sstep_instr[indx].savedInstr;
        sstep_instr[indx].targetAddr = 0;
        __data_cache(CACHE_FLUSH);
        __instruction_cache(CACHE_FLUSH);
    }
}

int
__is_single_step(target_register_t pc)
{
    return (sstep_instr[0].targetAddr == (t_inst *)pc) ||
        (sstep_instr[1].targetAddr == (t_inst *)pc);
}


// Compute the target address for this instruction, if the instruction
// is some sort of branch/flow change.

struct xl_form {
    unsigned int op : 6;
    unsigned int bo : 5;
    unsigned int bi : 5;
    unsigned int reserved : 5;
    unsigned int xo : 10;
    unsigned int lk : 1;
};

struct i_form {
    unsigned int op : 6;
    signed   int li : 24;
    unsigned int aa : 1;
    unsigned int lk : 1;
};

struct b_form {
    unsigned int op : 6;
    unsigned int bo : 5;
    unsigned int bi : 5;
    signed   int bd : 14;
    unsigned int aa : 1;
    unsigned int lk : 1;
};

union ppc_insn {
    unsigned int   word;
    struct i_form  i;
    struct b_form  b;
    struct xl_form xl;
};

static target_register_t
__branch_pc(target_register_t pc)
{
    union ppc_insn insn;

    insn.word = *(t_inst *)pc;

    // Decode the instruction to determine the instruction which will follow
    // Note: there are holes in this process, but the important ones work
    switch (insn.i.op) {
    case 16:
	/* bcx */
	if (insn.b.aa) {
	    return (target_register_t)(insn.b.bd << 2);
        } else {
	    return (target_register_t)((insn.b.bd << 2) + (long)pc);
        }
    case 18:
	/* bx */
	if (insn.i.aa) {
	    return (target_register_t)(insn.i.li << 2);
        } else {
	    return (target_register_t)((insn.i.li << 2) + (long)pc);
        }
    case 19:
	if (insn.xl.reserved == 0) {
	    if (insn.xl.xo == 528) {
		/* bcctrx */
                return (target_register_t)(get_register(CNT) & ~3);
	    } else if (insn.xl.xo == 16) {
		/* bclrx */
                return (target_register_t)(get_register(LR) & ~3);
	    }
	}
	break;
    default:
	break;
    }
    return (pc+4);
}

void __single_step(void)
{
    target_register_t msr = get_register(PS);
    target_register_t pc = get_register(PC);
    target_register_t next_pc = __branch_pc(pc);

    // Disable interrupts.
    irq_state = msr & MSR_EE;
    msr &= ~MSR_EE;
    put_register (PS, msr);

    // Set a breakpoint at the next instruction
    __insert_break(0, pc+4);
    if (next_pc != (pc+4)) {
        __insert_break(1, next_pc);
    }
}

/* Clear the single-step state. */

void __clear_single_step(void)
{
    target_register_t msr = get_register (PS);

    // Restore interrupt state.
    // FIXME: Should check whether the executed instruction changed the
    // interrupt state - or single-stepping a MSR changing instruction
    // may result in a wrong EE. Not a very likely scenario though.
    msr |= irq_state;

    // This function is called much more than its counterpart
    // __single_step.  Only re-enable interrupts if they where
    // disabled during the previous cal to __single_step. Otherwise,
    // this function only makes "extra sure" that no trace or branch
    // exception will happen.
    irq_state = 0;

    put_register (PS, msr);

    // Remove breakpoints
    __remove_break(0);
    __remove_break(1);
}

#else

static target_register_t irq_state = 0;

void __single_step (void)
{
    target_register_t msr = get_register (PS);

    // Set single-step flag in the exception context.
    msr |= (MSR_SE | MSR_BE);
    // Disable interrupts.
    irq_state = msr & MSR_EE;
    msr &= ~MSR_EE;

    put_register (PS, msr);
}

/* Clear the single-step state. */

void __clear_single_step (void)
{
    target_register_t msr = get_register (PS);

    // Clear single-step flag in the exception context.
    msr &= ~(MSR_SE | MSR_BE);
    // Restore interrupt state.
    // FIXME: Should check whether the executed instruction changed the
    // interrupt state - or single-stepping a MSR changing instruction
    // may result in a wrong EE. Not a very likely scenario though.
    msr |= irq_state;

    // This function is called much more than its counterpart
    // __single_step.  Only re-enable interrupts if they where
    // disabled during the previous cal to __single_step. Otherwise,
    // this function only makes "extra sure" that no trace or branch
    // exception will happen.
    irq_state = 0;

    put_register (PS, msr);
}
#endif

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)&_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)
{
    put_register (PC, get_register (PC) + 4);
}

#endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS

⌨️ 快捷键说明

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