【百问网智能家居】ARM架构的一些知识点

从入门单片机以来,我所用来学习的板子都是ST公司的。他们公司有写好的标准库,HAL库,LL库供学习者使用。但是我觉得这不利于理解单片机工作原理,因为在以后的学习或是工作里,总有遇到其他公司芯片的时候。这就涉及到了寄存器操作等知识。因为ARM架构在嵌入式领域使用较为广泛,所以我在韦东山老师的课程下学习了相关知识。以下内容大部分源于韦老师的课件。

官网就有很多免费的课程,很适合新手入门,韦老师在B站也有课程,我就是B站搜索发现的。下面是韦东山老师团队的官网及B站地址:
新版官网:http://100ask.org/
旧版官网:https://www.100ask.net/
B站链接:https://space.bilibili.com/275908810/channel/detail?cid=135681

一、ARM与x86的区别

首先是操作地址空间的区别,ARM根据cpu发出的不同地址选择不同的设备,包括内存,串口等设备,不区分IO和内存,直接把IO空间映射到内存空间,访问方法都是用内存空间的方式操作。x86是根据cpu发出的不同指令选择不同设备,并且在cpu眼里内存和IO是隔离开的,IO空间使用完全不同的指令来访问。

其次就是指令集,ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing)。它所用的指令比较简单,有如下特点: 对内存只有读、写指令;对于数据的运算是在CPU内部(即寄存器)实现,所以RISC设定多组寄存器来加速程序的运算;使用RISC指令的CPU复杂度小一点,易于设计。

x86属于复杂指令集计算机(CISC:Complex Instruction Set Computing),它所用的指令比较复杂,比如某些复杂的指令,它是通过“微程序”来实现的。比如执行乘法指令时,实际上会去执行一个“微程序”。CISC架构的很多复杂指令都通过CPU内的微码来完成,会影响效率。但是CISC的指令集丰富,编译器设计可以更简单。CISC允许数据处理指令对内存进行直接操作,需要的寄存器数量减少。

二、ARM内部寄存器及汇编知识

ARM架构中CPU内部都有R0-R15寄存器,分别用来暂存不同的数据。
CM3寄存器功能示意图
ARM体系结构提供了十六个32位通用寄存器(R0-R15)供软件使用。其中的15个(R0-R14)可用于通用数据存储,而R15是程序计数器,其值随处理器执行指令而改变。显式地写入R15可以更改程序流程。软件还可以访问CPSR和SPSR。SPSR中保存的上一个运行模式的CPSR的副本。
同一个寄存器可能在不同模式下对应物理上不同的位置。只有特定模式下才能访问到这些位置的寄存器。
有些寄存器,不同的工作模式下有自己的副本,当切换到另一个工作模式时,那个工作模式的寄存器副本将被使用,这些寄存器被称为备份寄存器。备份寄存器在物理上使用不同的存储,通常仅在特定模式下才可以访问它们。下图中带阴影标记的寄存器都是备份寄存器。

在所有模式下,“低位寄存器”和R15共享相同的物理存储位置。图3-5显示了某些模式下的某些“高位寄存器”被备份。例如,FIQ模式下使用R8-R12备份寄存器,也就是说,FIQ模式下对其的访问将转到另一个物理存储位置。对于除用户和系统模式以外的所有模式,R13和SPSR都是备份寄存器。
对于备份寄存器,软件通常不会指定要访问哪个模式下的寄存器,这是由当前运行的模式隐含的。例如,在用户模式下使用R13时实际上将访问R13_usr,而在SVC模式下将访问R13_svc。
R13(在所有模式下)是堆栈指针,但是当堆栈操作不需要时,它可以用作通用寄存器。
R14(链接寄存器)保存BL分支指令的下一条指令的地址。当它不支持子程序的返回时,它也可以用作通用寄存器。R14_svc,R14_irq,R14_fiq,R14_abt和R14_und同样用于在发生中断和异常时,或者执行转移和链接指令时,备份R15的返回值。
R15是程序计数器并保存当前程序地址(实际上,在ARM状态下,它始终指向当前指令之后的八个字节,而在Thumb状态下,它始终指向当前指令之后的四个字节,这是原始ARM1的三级流水线的遗留特性)。在ARM状态下读取R15时,位[1:0]为零,位[31:2]包含PC值。在Thumb状态下,位[0]始终读为零。
R0-R14的复位值是不定的。在使用堆栈之前,必须通过引导代码初始化SP(堆栈指针)。因为每种模式下的R13即SP寄存器都有自己的实体,所以你用到哪种模式,就需要单独为该模式设置SP。ARM体系结构过程调用标准(AAPCS)或ARM嵌入式ABI(AEABI)指定了软件应如何使用通用寄存器,以便在不同的工具链或编程语言之间进行互操作。

M系和A系稍有不同。M系的程序状态保存在xPSR里,A系保存在CPSR里。
M3\M4\A7_CPU内部寄存器
xPSR在其内部又被分为三个子状态寄存器:
应用程序 PSR(APSR);中断号 PSR(IPSR);执行 PSR(EPSR)
通过 MRS/MSR 指令,这 3 个 PSRs 即可以单独访问,也可以组合访问(2 个组合,3 个组合都可以)。当使用三合一的方式访问时,应使用名字“xPSR”或者“PSR”。
xPSR
汇编指令可以分为几大类:数据处理、内存访问、跳转、饱和运算、其他指令
数据处理指令的UAL汇编格式为:
数据处理
Operation表示各类汇编指令,比如ADD、MOV;
cond表示conditon,即该指令执行的条件;
S表示该指令执行后,会去修改程序状态寄存器;
Rd为目的寄存器,用来存储运算的结果;
Rn、Operand2是两个源操作数
数据操作指令
内存访问指令:读内存指令LDR/LDM,写内存指令STR/STM,
LDM:Load Multiple Register;
STM:Store Multiple Register。
内存操作指令一般格式

LDR使用伪指令将任意数值赋给寄存器,LDR作为“伪指令”时,指令中有一个“=”,否则它就是真实的LDR(load regisgter)指令了。由编译器将伪指令替换成真实指令。

ADR的意思是:address,用来读某个标号的地址,它是伪指令,ADR伪指令会被编译器替换成一条合适的指令,通常,编译器会用一条ADD指令或SUB指令来实现该ADR伪指令的功能,如果不能用一条指令来实现ADR伪指令的功能,编译器将会报错。

LDR 和 ADR 都有能力产生一个地址,但是语法和行为不同。对于 LDR,如果汇编器发现要产生立即数是一个程序地址,它会自动地把 LSB 置位,ADR则不会修改LSB。LDR 通常是把要加载的数值预先定义,再使用一条 PC 相对加载指令来取出。而 ADR 则尝试对 PC 作算术加法或减法来取得立即数。因此 ADR 未必总能求出需要的立即数。其实顾名思义,ADR 是为了取出附近某条指令或者变量的地址,而 LDR 则是取出一个通用的 32 位整数。因为 ADR 更专一,所以得到了优化,故而它的代码效率常常比 LDR的要高。

常用的”满减“:入栈(STMFD/STMDB)出栈(LDMFD/LDMIA)
sp的顺序原则是低标号的寄存器对应低地址,高标号的寄存器对应高地址。
根据栈指针指向,可分为满(Full)/空(Empty):
满SP指向最后一个入栈的数据,需要先修改SP再入栈
空SP指向下一个空位置,先入栈再修改SP
内存访问指令
跳转指令的核心指令是
B:Branch,跳转
BL:Branch with Link,跳转前先把返回地址保持在LR寄存器中
BX:Branch and eXchange,根据跳转地址的BIT0切换为ARM或Thumb状态(0:ARM状态,1:Thumb状态)
BLX:Branch with Link and eXchange 根据跳转地址的BIT0切换为ARM或Thumb状态(0:ARM状态,1:Thumb状态)
跳转指令
了解完这些之后,还是要自己手撸一遍点灯的汇编过程,才会记得更加深刻。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pupuhetu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值