mov r13,#3
mov r0,r1
mov r0,r1,LSL#2 @LSL#2表示逻辑左移两位,将r1左移两位之后的数值赋给寄存器r0
mov r0,r1,LSR#2 @LSR#2表示逻辑右移两位,将r1右移两位之后的数值赋给寄存器r0
mrs r0,cpsr @读取cpsr寄存器的值,赋给r0。注意特殊寄存器的读取使用mrs指令
msr cpsr,r0 @将r0的值赋给cpsr。注意特殊寄存器的写入使用msr指令
if (a==0) x=0;
if (a>0) x=x+3;
cmp r0,#0 @比较r0与0是否相等
moveq r1,#0 @mov是上面讲过的搬移指令,eq判断上一条指令执行的结果是否相等,如果相等,则将0赋值给r1
addgt r1,r1,#3 @add是加法运算,gt判断cmp指令r0是否大于0,如果大于零,则将r1+3的值赋给r1
写c代码--------------------------------->生成汇编代码------------------------->FLASH中最终存储机器指令(二进制)
当赋给寄存器的值过大时(一般大于255),就要使用伪指令对其赋值:ldr r0,=0x123456
and r0,r1,#0xFF // r0 = r1&0xFF(与运算)
orr r3,r0,#0x0F // r3 = r0|0x0F (或运算)
bic r0,r0,#0x03 // 清除r0中的0号位和1号位
tst r0,#0x20 //测试第6位是否为0 ,为0则Z标志置1
cmp r1,r0 //将R1与R0相减做比较,并根据结果设置CPSR的标志位
例:
• 使能中断和快速中断?
mrs r0,cpsr
bic r0,r0,#0xc0 (清零F位和I位)
msr cpsr,r0
• 判断当前工作状态是否是ARM状态,是则切换到user 工作模式?
mrs r0,cpsr
tst r0,#0x20
andeq r0,r0,#0xFFFFFFE0 (低5位清零)
orreq r0,r0,#0x10
msreq cpsr,r0
add r0,r1,r2 //r0=r1+r2
sub r0,r1,#3 //r0= r1 - 3
sub r0,r1,r2,LSL#1 //r0=r1-(r2<<1)
mul r1,r2,r3 //r1=r2*r3
b main //跳转到标号为main地代码处
bl func //保存下一条要执行的指令的位置到 LR寄存器,跳转函数func
//当跳转代码结束后,用MOV PC,LR指令跳回来
beq addr //当CPSR寄存器中的Z条件码置位时,跳转到该地址处
bne addr //当不等时,跳转到地址addr
例:
用汇编实现下面功能:
void main(void)
{
int ret=0;
func1(2);
while(1) {};
}
func1(int a)
{
if(a==2)
return func2(a);
else
return func3(a);
}
func2(int a)
{
return a+3;
}
func3(int a)
{
return a-1;
}
实现 延时1秒函数:
@delay fos 1 second
delay1s:
ldr r4,=0x3FFFF
loop_delay1s:
sub r4,r4,#1
cmp r4,#0
bne loop_delay1s
delay1s_end:
mov pc,lr
测验:
用汇编实现求最大公约数?(如9 15 值是3)
int GCD(int a,int b)
{
while(1)
{
if(a==b)
break;
if(a>b){
a=a-b;
}else{
b=b-a;
}
}
return a;
}
注:load/store架构规定,存储器之间不能直接拷贝,需通过寄存器做中转 (比如讲FLASH中的指令传入到内存中就必须使用CPU寄存器做中转)
ldr r0,[r1] (load) //r0=*r1 r1里存放的是地址,把该地址里存放的内容读入到r0中
//LDRB(byte) LDRH(half word)
ldr r0,[r1,#8] //r0=*(r1+8) 存储器地址为r1+8的字数据读入寄存器0。
ldr pc,_irq // pc = *(_irq) 将标号中的内容放入pc中
str r0,[r1] (store) // *r1 = r0 将寄存器r0中值写入到存储器地址为r1的空间中
str r0,[r1],#4 // r0=*r1, r1=r1+4 将r0 中的字数据写入以r1为地址的内存中,并将新地址r1+4 写入r1
str r0,[r1,#4] //*(r1+4)=r0 将r0 中的字数据写入以r1+4 为地址的内存中
Pre-indexed: STR r0,[r1,#12]
例:
拷贝srcBuf里内容 到destBuf中:
.text
ldr r0,=srcBuf
ldrb r1,[r0]
ldr r0,=destBuf
strb r1,[r0]
srcBuf:
.byte 0x01,02,0x03,0x04
.data
destBuf:
.space 8
.end
用汇编实现下面功能 :
main()
{
int i=0;
const char buf[]={1,2,3};
char destBuf[8];
for(i=0,i<3,i++)
{
destBuf[i] = buf[i];
}
}
.text 将定义符开始的代码编译到代码段
.data 将定义符开始的代码编译到数据段
.end 文件结束
.equ GPG3CON, 0XE03001C0 定义宏(即用GPG3CON代替 0XE03001C0)
.byte 定义变量 1字节
.byte 0x11,'a',0 定义字节数组
.word 定义word变量 (4字节 32位机)
.word 0x12344578,0x33445566
.string 定义字符串 .string "abcd\0"
ldr r0,=0xE0028008 载入大常数0xE0028008 到r0中
.global _start 声明_start 为全局符号
例 拷贝ROM中字符串到RAM中:
.text
start:
ldr r5,=srcBuf
ldr r6,=destBuf
loop:
ldrb r4,[r5]
cmp r4,#0
beq main_end
ldrb r0,[r5],#1
strb r0,[r6],#1
b loop
main_end:
b main_end
srcBuf:
.string "abcdefg\0"
.data
destBuf:
.space 8
.end
• 批量操作指令 (ia-Increment After ib-Increment Before da-Dec After db-Dec Before)
ldmia r0!, {r3 - r10} //r0里地址指向的内容批量,load 到r3~r10寄存器中, r0里地址会自动加4
stmia r0!, {r3 - r10} //把r3~r10寄存器中内容,store 到r0里地址执行空间中,r0里地址会自动加4
• 例:实现块数据批量拷贝
r12指向源数据起始地址
r14指向源数据尾地址
r13指向目的数据起始地址
例 批量拷贝数据:
.text
ldr r12,=srcBuf
ldr r13,=dstBuf
ldmia r12!,{r0 - r11}
stmia r13!,{r0 - r11}
.data
srcBuf:
.string "abdfasdf13535dfksjdlfkjlksldkjflkl\0"
srcBuf_end:
dstBuf:
.space 12*4
.end
stmfd sp!,{r0-r12,lr} 将寄存器r0~r12 lr中的值存入栈中
常用于中断保护现场,! 表示会自动偏移
ldmfd sp!,{r0-r12,pc}^ 将栈中值逐个弹出到寄存器r0~r12 pc中
常用于中恢复断现场,^表示会恢复spsr到cpsr
• 软中断指令
swi 0x02 产生软中断, 软中断号为2