在用embest ide调试s3c44b0的时候,想在C环境下操作内部寄存器。查了很多资料可是编译始终通不过。照着书上__ASM格式还是错。后来经过一天一夜的努力,终于实现了,现在传上来大家一起研究一下~~
网上说的都是80x86的内嵌汇编,跟据那上面的格式来编译是通不过的。还有 arm-elf-gcc和arm-linux-gcc的语法也是不同的。
刚开始时在网上看到一位仁兄写的调试笔记,他说自己没有钱买仿真器,只可以烧程序。他是用ADS调试的,要想看内部寄存器(R0-R15)级必须读这些寄存器,然后通过串口来观察。但是在C的环境下操作内部寄存器是不可能的,只能在C中内嵌汇编。
我用的是embest ide ,因为给的例子都是GCC环境下的,所以我就用的这个环境在调,刚开始我把上面那位仁兄的程序COPY过来,完全编译不同,后来我一句一句的删 发现两个环境下的语法完全不同,于是我就到晚上找例子,没什么收获。下面是那位仁兄的代码,在ADS下可能适用(没有测试过)
int ReadPC(int argc, char *argv[])
{
U32 i;
U16 j,k;
__asm
{
mov i,R15
}
j=i/0x10000;
k=i%0x10000;
printf("PC Value = 0x%x /n",i);
printf("PC Value = %d - %d /n" ,j,k);
__asm
{
MRS i,CPSR
}
j=i/0x10000;
k=i%0x10000;
printf("CPSR Value = 0x%x /n",i);
printf("CPSR Value = %d - %d /n" ,j,k);
return 0;
}
书上倒是有一个例子,不过只有一句:
__ASM("MOV R0,R0");
我把这一句写上去 结果编译通过了,我还以为解决了。但是接下来又遇到一个问题 怎么把寄存器的值传给C中的变量呢?我也尝试着直接在汇编中使用变量MOV I,R15结果又报错。
再后来在CSDN上看到有人说:定义 int get_R0(void){}
然后调用int I=get_R0;
我想不太可能吧 但是事实是确实得到了R0的值,刚开始想不同,还以为get_R0()是一个库函数,我把R0换成R15,结果奇怪的是得到的也是R0的值。我把get_R0换成mm__R0结果还是可以到R0的值。虽然不懂为什么,但是我把程序改了下达到了我的目的。在int I=get_R0;前面用__ASM("MOV R0,R15");这样就得到了R15也就是PC的值。一看手机都凌晨3.半了,关机睡觉。
第二天早上起了个早,有摸索了几个小时,意外发现用LDR R1 ,=I这句编译居然没有错,呵呵。太好了总算和C链接起来了,这下好办了,直接把R15的值给R0然后STR R0,[R1]这样就把R15的值赋给变量了。
__ASM("LDR R1,=I
MOV R0,R15
STR R0,[R1]
")
编译、链接,运行。串口没有反应。还好我有仿真器,单步调试发现出现了未定义指令异常,程序跳到0X00000004处去了。我打开汇编窗口发现在这几句指令后面多了一条不认识的东西:
0x0c0019a4 stfeqd f3, [r0], -#800
我把所有的语句删了 这条语句还是会出现,也就说是只要用到__ASM就会出现这个东西。
每次运行到这里就发生异常,于是我就把程序改成这样了:运行,结果完全显示了PC的值:
__asm("ldmfd sp,{r0,r1}
ldr r1,=Mr15
mov r0,r15
sub r0,r0,#0x16 //还原当前PC的值
str r0,[r1]
stmfd sp!,{r0,r1}
add pc,pc,#0x01 //为了跳过那条未定义的指令
");
Uart_Printf("/npc=0x%x/n",Mr15);
本来想把这段定义为宏,以后要用就直接展开。可是这个__ASM的格式太苛刻了,没有成功,只能这样了。不过应该可以包装成函数,到时候直接读LC-8就是PC的值了。。。。