学习笔记(四)——ARM汇编
在CM3上一般使用C语言或者汇编语言编程,使用C语言开发大型程序,汇编语言则可以实现一些特殊功能,比如操作特殊功能寄存器、用c写效率不够高的程序等,因此学会ARM汇编语言是精通arm编程的前提。
以一个HelloWorld程序作为例子来学习ARM汇编,注释部分详细介绍了程序是怎么运行的,很适合新手,当然,汇编语言的语法就当你已经学过了。
STACK_TOP EQU 0x20002000 ;顶格写常量定义,这里是定义堆 UART0_BASE EQU 0x4000C000 ;栈指针的地址、UART的一些常量 UART0_FLAG EQU UART0_BASE+0x018 ;定义 UART0_DATA EQU UART0_BASE+0x000 AREA | Header Code|, CODE ;AERA定义一个名为HeaderCode的代码段 DCD STACK_TOP ;为栈分配一片连续的字存储单元 DCD Start ENTRY ;程序入口,一个汇编程序至少有一个ENTRY Start ;标号,顶格书写,这里是偏移地址的标记 MOV R0, #0 ;将0写入寄存器 MOV R1, #0 MOV R2, #0 MOV R3, #0 MOV R4, #0 BL Uart0Initialize ;B简单跳转,BL带连接(保存在R14(LR)连接寄存器 ;中)跳转,一般用于子程序,便于从子程序返回 LDR R0, =HELL0_TXT ;把字符串数据装载到寄存器,LDR字LDRH半字LDRB字节 BL Puts ;跳转至Puts子程序 deadend ;一个死循环里不停跳转 B deadend ;-------------------------------------------------------------------------------------- ;各个子程序 ;-------------------------------------------------------------------------------------- Puts ;标号,代表子程序名称,该子程序作用是往UART送一个字符串,入口条件 ;是当前R0=待输出字符串的起始地址,且以0结尾 PUSH {R0, R1, LR} ;将R0,R1,LR入栈 MOV R1, R0 PutLoop LDRB R0, [R1], #1 ;取一个字节至R0,再自增1字节地址 CBZ R0, PutsLoopExit ;若R0为0则跳转 BL Putc ;跳转至Putc子程序 B PutsLoop PutLoopExit POP {R0, R1, PC} ;出栈 ;-------------------------------------------------------------------------------------- Putc ;子程序,作用是使用UART发一个字符串 PUSH {R1, R2, LR} LDR R1, =UART0_FLAG PutcWaitLoop LDR R2, [R1] TST R2, #0x20 ;TST是按位与并将结果更新CPSR标志位的值,这 ;一句是与0x20按位与,检查“发送缓存满”标志 BNE PutWaitLoop ;不为0则跳转,即已满则重试 LDR R1, =UART0_DATA ;有空位时将UART的寄存器地址加载到R1中 STRB R0, [R1] ;将R0中的数据写入以R1数据为地址的寄存器中 POP {R1, R2, PC} ;-------------------------------------------------------------------------------------- Uart0Initialize ;UART初始化程序,与硬件有关,略 BX LR ;-------------------------------------------------------------------------------------- HELLO_TXT ;定义一个以0结尾的"HelloWorld"字符串 DCB "HelloWorld\n",0 END ;本文件结束
此程序流程如下:首先对一些需要使用的资源进行定义和初始化,包括堆栈指针地址、字符串内存空间、4个寄存器、UART等,然后把字符串(以0结尾)从内存装载到R0,转到子程序Puts,把R0、R1、LR入栈,LR的作用是保存连接数据,待子程序运行完毕即可通过LR回到主程序,子程序Pu将ts先R0数据复制到R1,再将R1中的一个字节复制到R0,若不为0(为0代表到了结尾),则跳转至子程序Putc,Putc的作用是使用UART发送字符串数据,检查缓冲未满后,将UART寄存器地址加载到R1中,再将R0保存的字节数据写入R1,即写入到UART寄存器,即可完成输出,返回至子程序Puts,再通过Putc输送下一个字节数据,直至遇到0,输出完毕,退出至主程序,进入死循环。