本文根据上一篇TQ2440开发板学习纪实(1)—最简单的独立运行汇编程序进化而来。
0 ARM堆栈(Stack)基础知识
ARM支持满减类型的堆栈,满的意思是说堆栈指针SP(即R13)总是指向刚刚入栈的数据单元。与满相对应的就是不满,这种类型的栈指针SP指向栈顶的下一个空白单元。减的意思是说,栈底的内存地址大,栈顶地址小,压入数据时,栈向地址小的方向扩展。
目前我们只有4KB的内存可用,范围为:0x00000000-0x00000FFF,如下图:
为了充分利用这4KB的内存,我们把堆栈
指针SP初始指向0x00001000。这样设置有如下考虑:
- 必须4字节对齐,这是ARM的要求。也就是最后两位二进制位必须为0.
- 虽然最大可用内存地址为0x00000FFF,但是这里仍然可以设置SP=0x00001000。因为ARM堆栈是”满减”,所以后续使用时并不会使用0x00001000这个内存单元。
C语言的函数的实现,严重依赖于堆栈,虽然参数较少时,直接使用寄存器传参,但是调用函数前其返回地址必须存放到堆栈上供被调用函数返回使用。
1 项目源码
从本文开始,项目源码不再在文中完整列出,有需要的朋友,请自行去CSDN的git库中下载。本次源码的tag为v0.1。
设置堆栈代码就一行:
/* set statck, must be aligned by 4 bytes */
ldr sp, =0x00001000
调用C函数也非常简单
b Main
注意这里没有使用bl,也就意味着,永远不会执行后面的代码。
需要说明的是,s3c2440有好几个运行模式,不同的模式下有各自独立的堆栈指针寄存器,需要分别设置。目前我们只工作在默认的SVC模式下,也只是设置了该模式下的堆栈而已。
有了堆栈,C语言的函数就可以顺利执行,有了C语言,谁还会用汇编呢?所以后面是用C语言写的一个LED流水灯程序。
void Main(void)
{
led_init();
while(1){
int i=0;
for(i=1; i<=4; i++) {
led_off( i-1 < 1 ? 4 : i-1);
led_on(i);
delay(10000);
}
}
}
2 编译说明
详见Makefile文件。