华清远见嵌入式学习day25——ARM指令集

本文深入讲解ARM汇编语言的基础知识,包括汇编的基本语法、指令格式、数据操作指令、跳转指令、load/store指令等。同时,文章还详细介绍了如何使用伪指令、条件码、特殊功能寄存器操作指令以及软中断指令。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 .s文件中的符号
     伪操作:指导编译器对代码进行编译的
         不占用内存空间
     指令:编译器将其编译成机器码,
         存放到内存空间
     伪指令:本身不是一条指令,
         编译器在编译的时候,
         将其编译成多条指令,
         完成一条伪指令的功能
    
 汇编的基本语法
     “@” : 单行注释
     “/* */” : 多行注释
     一条指令占用一行
     汇编中不区分大小写

 汇编指令的基本格式
/*
    <opcode><code>{s}  Rd, Rn, {oprand2}
    opcode:指令的名字
    code:条件码  
        如果什么都不写代表无条件执行
    s:状态位
        指令的结果会影响cpsr的NZCV位
    Rd:目标寄存器
    Rn:第一个操作寄存器,只能是一个寄存器
        如果目标寄存器和第一个操作寄存器的编号相同
        可以合并成只写1个,类似于C语言中的双目运算符
    oprand2:第二个操作数  */
         可以是普通的寄存器
         可以是立即数或者有效数
         经过移位操作的寄存器
        
     1. 数据操作指令
     2. 跳转指令
     3. load/store指令
     4. 特殊功能寄存器操作指令
     5. 软中断
    
    
    .text    以下为代码段
    .global _start   生命一个全局的函数
_start:   函数的入口
     代码段
     1. 数据操作指令    
     搬移指令  mov  mvn
     mov/mvn<code>  Rd,  oprand2        
     mov r0, #0xFF   r0 = 0xFF  
     #号后边跟的是立即数或者有效数
     mov r1, r0    r1 = r0    
     mvn r2, r0    r2 = ~r0    
     mov r3, #0xFFFFFF
     伪指令  ldr 
     ldr r4, =0x12345678
    
     移位操作指令  lsl  lsr asr  ror 
     lsl/lsr/asr/ror<code>{s} Rd, Rn, <oprand2>
     lsl 无符号数的左移
     lsr 无符号数的右移
     asr 有符号数的右移
     ror 循环右移
     mov r0, #0xFF
     lsl r0, #0x4
     将r0中的值左移4位,赋值给R1
     高位移除,低位补0
     lsl  r1, r0, #4 
     将r0中的值右移4位,赋值给R2
     低位移除,高位补0
     lsr r2, r0, #4
     将r0中的值循环右移4位,赋值给R3
     低位移除,补到高位
     ror r3, r0, #4
    
     将r0中的值右移4位,赋值给R4
     低位移出,高位补符号位
     asr r4, r0, #4
     将r0中的值右移4位,赋值给R5
     低位移出,高位补符号位
     ldr r0, =0x800000FF
     asr r5, r0, #4
    
     mov r0, #0xFF
     mov  r1, r0, lsl #4
     mov r2, #(0xFF << 4)
    
     算数运算指令  add  adc sub sbc  mul(乘法) 
     add/adc/sub/sbc<code>{s} Rd, Rn, <oprand2>    
     假设2个64位的数相加
     第一个64位的数,
     R0存放低32位,R1存放高32位
     第二个64位的数,
     R2存放低32位,R3存放高32位
     结果R4存放低32位,R5存放高32位
.if 0        汇编中使用条件语句进行注释
     mov r0, #0xFFFFFFFF
     mov r1, #3
     mov r2, #4
     mov r3, #5    
     adds  r4, r0, r2   r4 = 0x3
     adc  r5, r1, r3   r5 = r1 + r3 + C = 0x9
.endif    
     减法指令 sub   sbc 
     两个64位数相减
     第一个64位的数,
     R0存放低32位,R1存放高32位
     第二个64位的数,
     R3存放低32位,R4存放高32位
     R4存放低[31:0]位,R5存放高[63:32]位
.if 0
    mov r0, #3
    mov r1, #9
    mov r2, #4
    mov r3, #5    
    
    subs r4, r0, r2
    sbc  r5, r1, r3    r5 = r1 - r3 - !C = 0x3
    
.endif    
     mul<code>{s} Rd, Rn, Rm
    
     mul r0, r1, r2   r0 = r1 * r2
    
     逻辑运算指令 and  orr  eor  bic
     and/orr/eor/bic<code>{s} Rd, Rn, <oprand2>
     mov r0, #0xFF
     R0[7:4]清零  --》 R1
     and r1, r0, #0xFFFFFF0F    r1 = 0xF
     and r1, r0, #(~(0xF << 4))
     R0[11:8]置一  --》 R2
     orr r2, r0, #(0xF << 8)   r2 = 0xFFF
     orr r2, r0, #0xF00
    
     R0[11:4]取反  --》 R3    r3 = 0xF0F
     eor r3, r0, #(0xFF << 4)
     eor r3, r0, #0xFF0
    
     bic 位清除指令,想把哪位清零,就给哪位写1
     R0[7:4]清零 --》r4
     bic r4, r0, #0xF0
    
     位操作指令   teq   tst  cmp 
     teq/tst/cmp<code>  Rn, oprand2
     最终影响的是cpsr的NZCV位,不需要加s
     teq 测试两个数是否相等
     mov r1, #5
     teq r1, #5
     teq r1, #6   本质:进行了异或运算
    
     tst  测试某一位是否为1
     mov r0, #0xF    0b1111
     tst r0, #0x4    0b0100
     tst r0, #0x10   0b0001 0000 本质:进行了与运算 
     tst r0, #0x18   0b0001 1000
     cmp 比较指令 
     mov r0, #4
     cmp r0, #5   本质:做减法运算
     条件码
    
     mov r0, #3
     mov r1, #4
     cmp r0, r1
     subhi r0, r0, r1
     subcc  r1, r1, r0
    
 跳转指令     b   bl  
     b/bl<code>   lable   跳转到标签下的第一条指令开始执行
     通过标签可以找到函数入口的首地址
     标签相当于C语言中函数的函数名
.if 0    
     mov r0, #3
    mov r1, #4
    b func1 
     b跳转指令,不会保存跳转指令的下一条指令的地址到lr
fo:
    add r2, r0, r1
    b loop
    
func1:
    mov r0, #5
    mov r1, #6
    add r3, r0, r1
    mov pc, #0xF     0b1100
     b fo
.endif
    
     bl 当执行bl跳转指令时,会将跳转指令的下一条指令的地址,
      保存到lr寄存器中,保存返回地址是cpu自动完成
.if 0    
    mov r0, #3
    mov r1, #4
    bl func2
    add r2, r0, r1
    b loop
func2:
    mov r3, #4
    mov r4, #5
    add r5, r3, r4
    mov pc, lr
    
    总结:跳转指令的本质:修改PC值
    子函数的调用使用bl
.endif    

.if 0
    mov r0, #9
    mov r1, #15
    
loop:
    cmp r0, r1
    beq  stop
    subhi  r0, r0, r1
    subcc  r1, r1, r0
    b loop
.endif

     特殊功能寄存器传送指令  cpsr   
     msr  cpsr, Rn    将Rn中的值赋值给cpsr
     mrs  Rn, cpsr    将cpsr中的值赋值个Rn
     如何从svc模式切换到用户模式
     M = 0x13(svc)   M= 0x10(user)
     0xD3   0b1101 0011
               IFTM MMMM
     mov r0, #0xD0
     msr cpsr, r0
     msr cpsr, #0xD0
    
    mrs r0, cpsr
    bic r0, r0, #0x1F
     and r0, r0, #(~0x1F)
    orr r0, r0, #0x10
    msr cpsr, r0

stop:    死循环相当于while(1);
    b stop
    .end 结束
    

load/sotre指令   内存读写的操作指令
单寄存器操作指令      ldr    str
r:寄存器
语法格式:ldr/str   Rn,[Rm]
对一个字进行操作的指令
int * p; p-->Rm
*p -->[Rm]
ldr r0, =0x20008000
ldr r1, =0x12345678
str r1, [r0]   将r1中的值存储到r0指向的地址空间中
ldr r2 ,[r0]   将r0指向的地址空间的值写道r2寄存器中
如果过直接执行会报错,地址没有读写权限
解决办法:在工程文件中创建 map.ini文件 在文件中添加以下内容
map 0x20000000,0x2000ffff read write
在工程中的projiect--target 1右键选择
options for target --debug--initialization file添加map.ini文件
ldrh strh ldrb strb
h:half半字 b:byte一个字节
用法和ldr str完全一样
str r1,[r0, #4]
将r1中的值,存储到r0+4指向的地址空间中
r0保持不变
str r1, [r0], #4
将r1中的值,存储到r0指向的地址空间中
r0 = r0+4
str r1, [r0, #4]!
将r1中的地址存储到r0+4中
r0 = r0+4
要求是4字节对齐
多寄存器操作指令 ldm stm
m:mutil  
语法格式:
ldm/stm Rn, {寄存器列表}
Rn :内存的地址
{寄存器列表}:要操作的寄存器列表
stm r0,{r1-r5}
如果寄存器编号连续
如果寄存器列表中既有连续又有不连续
连续的中间使用-隔开,不连续的使用,隔开
将r1-r5寄存器中的值存储到r0指向的地址空间的连续的20个字节空间中
寄存器列表中的寄存器的顺序,不管如何排列,永远都是低地址存储编号小的
读取的时候,低地址放到小编号寄存器中
如果stm和ldm什么后缀都不加,默认为后缀为IA
IA:increment after
增加:指向高地址方向存储数据
after:当前指向的地址中,没有数据
可以先存储,再向地址增加的方向依次存储
IB:before:当前指向的地址中,有数据
地址先增加4,再向地址增加的方向依次存储
DA:Dcrement after
Dcrement : 向低地址方向存储数据
after:当前指向的地址中,没有数据
可以先存储,再向地址递减的方向依次存储
DB:before:当前指向的地址中,有数据
地址先减4,再向地址递减的方向依次存储

!:更新r0的地址
stmia r0!,{r1-r5}

栈操作指令 sp
站的种类:
增栈:栈指针想高地址方向移动
减栈:向低地址方向移动
空栈:栈指针指向的当前位置为空,如果要存储数据需要先存数据,然后栈指针在移动到一个空的位置
满栈:栈指针指向的当前位置不为空,如果要存储数据,需要先移动栈指针到一个空的位置,在存储数据

栈的操作方式
满增栈   full ascending         stmfa   ldmfa
满减栈   full descending
空增栈    empy ascending
空减栈    empty descending
arm默认采用的是满减栈
语法格式:
stmfd/ldmfd sp!, {寄存器列表}
软中断指令 swi

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值