本帖最后由 turmary 于 2016-9-14 00:15 编辑
不处于(取指和数据)异常的环境是应用程序环境,因为在不存在的虚拟地址取指,Cortex-M3会产生取指异常,进入异常后的环境是仿真环境。
仿真环境的代码都在有效ROM地址范围,即仿真环境本身不能再触发异常,否则就会死循环了。
发生异常后,Cortex-M3硬件自动保存的堆栈exception_t到PSP指向的RAM,
typedef struct {
unsigned r0;
unsigned r1;
unsigned r2;
unsigned r3;
unsigned r12;
unsigned lr;
unsigned pc;
unsigned psr;
} exception_t;
这时已进入仿真环境,首先需要用汇编处理硬件堆栈,整理出应用程序的寄存器环境exception2_t
typedef struct {
unsigned r0; // 0x00
unsigned r1;
unsigned r2;
unsigned r3;
unsigned r4; // 0x10
unsigned r5;
unsigned r6;
unsigned r7;
unsigned r8; // 0x20
unsigned r9;
unsigned r10;
unsigned r11;
unsigned r12; // 0x30
unsigned sp;
unsigned lr;
unsigned pc;
unsigned psr; // 0x40
unsigned exc_return;
} exception2_t;
所有应用环境寄存器里的地址都是虚拟地址。
后面仿真环境全用C代码处理喽,无非是获取PC处指令的二进制代码,分析后做相应动作,并且不断重复分析、执行这两个动作。
int fault_with_ibus(const m3env_t* env, volatile unsigned virt_pc) {
opcode_t* op = opcode_buf;
unsigned long pc;
#if ACCELERATE_IBUS_INNER_LOOP
next_ibus_fault:
#endif
pc = virt2phy(virt_pc);
// maybe an unaligned access
op->binary = unaligned_long(pc);
opcode_parse(op);
opcode_exec(op, env);
if (op->attr & OPCODE_ATTR_EMUL) {
// if soft emulation then
#if ACCELERATE_IBUS_INNER_LOOP
// remove Thumb state
virt_pc = (env->ep2->pc & ~0x1UL) + INSTRUCTION_SIZE(op);
if (!interrupt_pending() && IN_TEXT_AREA(virt_pc)) {
env->ep2->pc = virt_pc;
goto next_ibus_fault;
} else
#endif
{
return INSTRUCTION_SIZE(op);
}
}
// if hard_exec then
return 0;
}
与地址无关的指令可以直接使用硬件仿真,这里的办法很简单,
把这个指令放进某个RAM单元 --- exec_space[0],下个RAM单元 --- exec_space[1]放一个断点指令。
保存下一个应用程序指令的地址<1>,设置异常返回后的PC指向exec_space[0],并从异常返回。
就时处于应用环境,执行exec_space[0]里的指令,之后执行exec_space[1]里的指令将触发调试异常,
在调试异常中(仿真环境)恢复地址<1>到PC,异常返回后回到应用环境,一个应用程序指令(硬件)仿真周期完成。
#define BKPT_INST 0xBE01UL
#define CSPC_INSTRUCTION 0
#define CSPC_BKPT 1
unsigned exec_space[] = {
(BKPT_INST << 16) | BKPT_INST,
(BKPT_INST << 16) | BKPT_INST,
};
static uint32_t real_pc[] = {0, 0};
int hard_exec_entry(const m3env_t* env, const opcode_t* op) {
unsigned next_pc;
if (IS_INST_32BIT(op)) {
next_pc = env->ep2->pc + 4;
exec_space[0] = op->binary;
} else {
next_pc = env->ep2->pc + 2;
exec_space[0] = (BKPT_INST << 16) | (op->binary & 0xFFFFUL);
}
real_pc[is_app_in_intr()] = next_pc;
env->ep2->pc = (unsigned)&exec_space[0];
/*
printf("exec_space[0] = 0x%.8X\n", exec_space[0]);
printf("exec_space[1] = 0x%.8X\n", exec_space[1]);
*/
return 0;
}
这时应用环境在下一条指令的虚拟地址取指,再次触发取指异常,新的应用指令仿真周期开始。
|