ARM架构

地址空间_RISC与CISC

ARM中怎么访问寄存器?就像访问内存一样,用指针

c 复制代码
unsigned int *p =  0x40010800; // p等于某个寄存器的地址

*p = val;   // 写这个地址,也就是写这个寄存器
val = *p;  // 读寄存器

在ARM CPU看来,内存,I/O的操作是一样的。根据CPU发出的地址选择不同的设备。

在x86架构中内存和IO是分开的,根据CPU发出的指令选择不同的设备

RISC

ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing),它所使用的指令比较简单,有如下特点:

  1. 对内存只有读、写指令
  2. 对于数据的运算是在CPU内部实现
  3. 使用RISC指令的CPU复杂度小一点易于设计

CISC

X86属于复杂指令集计算机(CISC:Complex Instruction Set Computing),它所用的指令比较复杂,比如某些复杂的指令会通过"微程序"实现。

比如执行乘法指令时,实际上会去执行一个"微程序",

在"微程序"里,

一样是去执行这4不操作:

① 读内存a

② 读内存b

③ 计算a*b

④ 把结果写入内存

但是对于程序员来说,

他看不到"微程序",

他好像用一条指令就搞定了这一切!

RISC与CISC比较

CISC的指令能力强,单多数指令使用率低却增加了CPU的复杂度,指令是可变长格式;

RISC的指令大部分为单周期指令,指令长度固定,操作寄存器,对于内存只有Load/Store操作

CISC支持多种寻址方式;RISC支持的寻址方式

CISC通过微程序控制技术实现;

RISC增加了通用寄存器,硬布线逻辑控制为主,采用流水线

CISC的研制周期长

RISC优化编译,有效支持高级语言

ARM内部寄存器

在CPU内部,用什么来保存a、b、a*b?

无论是Cortex-M3/4或者A7,CPU内部都有R0~R15寄存器,用来暂存数据。

  1. LDR R0,[a] 把地址a上的值赋值给R0
  2. LDR R1,[b] 把地址b上的值赋值给R1
  3. ADD R0,R0,R1 将R0上的值与R1相加,结果保存在R0
  4. STR R0,[a] 把R0的值赋到地址a空间上。

R13:SP,栈指针

R14:LR,用来保存返回地址

R15:PC,程序计数器,预执行指令地址,写入新值即可跳转

对于Cortex-M3/4,汇编指令里使用SP,但是可能对应不同的SP寄存器,一般情况下都是使用SP_main,运行RTOS时,可以让APP使用SP_process。

xPSR保存程序状态,比如上一条指令的执行结果、比较结果,也有一些控制作用,比如屏蔽中断,使能中断。


ARM汇编概述

一开始,ARM公司发布两类指令集:

  1. ARM指令集,32位,高效,但是太占空间。
  2. Thumb指令集,16位,节省空间。

因此,要节省空间时使用Thumb指令,要效率时使用ARM指令。

一个CPU既可以运行Thumb指令,也能运行ARM指令。

怎么区分当前指令是Thumb还是ARM指令呢?
程序状态寄存器中有一位,名为"T",它等于1时表示当前运行的是Thumb指令。

假设函数A是用Thumb指令写的,函数B是用ARM指令写的,怎么调用A/B?

我们可以往PC寄存器里写入函数A或B的地址,就可以调用A或B。

那么如何让CPU在执行A函数时进入Thumb状态,在执行B时进入ARM状态?

调用A时,让PC寄存器的BIT0等于1,即PC=函数A地址+(1<<0)

调用B时,让PC寄存器的BIT0等于0,即PC=函数B地址

很麻烦,因此引入Thumb2指令集,它支持16位指令集、32位指令混合编程。

有ARM、Thumb、Thumb2指令集,但是ARM公司推出了统一汇编语言,不需要去区分这些指令集。

在程序前面用CODE32/CODE16/THUMB表示指令集ARM/Thumb/Thumb2

汇编指令格式

  • Operation表示各类汇编指令,比如ADD、MOV
  • cond表示condition,即该指令执行的条件
  • S表示该指令执行后,会去修改程序状态寄存器
  • Rd为目的寄存器,用来存储运算的结果
  • Rn、Operand2表示两个源操作数

Operation表示各类汇编指令,比如ADD、MOV

cond有多种取指,如

读内存指令:LDR/LDM

写内存指令:STR/STM

LDR:Load Register LDM:Load Multiple Register

STR:Store Register STM:Store Multiple Register

立即数

MOV R0,#VAL

意思是把VAL这个值存入R0寄存器。

VAL可以是任意值吗?

  • 不可以,必须是立即数。
  • 假设VAL可以是任意数,MOV R0,#VAL本身是16位或32位,哪来的空间保存任意数值的VAL?所以,VAL必须符合某些规定。

LDR伪指令

去判断一个VAL是否是立即数,很麻烦!

并且就是想把任意数值赋给R0,怎么办?

可以使用伪指令

c 复制代码
LDR R0, =VAL

伪指令,就是假的、不存在的指令。

LDR作为"伪指令"时,指令中有一个=,否则它就是真实的LDR指令了。

编译器会把伪指令替换成真实的指令,比如:

c 复制代码
LDR R0, =0x12

0x12是立即数,那么替换为:MOV R0,#0x12

c 复制代码
LDR R0, =0x12345678

0x12345678不是立即数,那么替换为:

c 复制代码
LDR R0,[PC,#offset]  //2.使用Load Register读内存指令读出值,offset是链接程序时确定的

Label DCD 0x12345678 //1.编译器在程序某个地方保存这个值

ADR伪指令

ADR的意思是:address,用来读取某个标号的地址

c 复制代码
ADR R0,Loop

Loop
	ADD R0,R0,#1

它是伪指令,会被转换成某条真实的指令,比如:

c 复制代码
ADD R0,PC,#val  ;val在链接时确定

Loop
	ADD R0,R0,#1

ARM编译器与GCC编译器语法差异

使用keil这种工具,所用到的编辑器就是armasm

arm-linux-gnueabihf这种就是GNU Assembler

相关推荐
JosieBook1 分钟前
【架构】主流企业架构Zachman、ToGAF、FEA、DoDAF介绍
架构
.生产的驴1 小时前
SpringCloud OpenFeign用户转发在请求头中添加用户信息 微服务内部调用
spring boot·后端·spring·spring cloud·微服务·架构
丁总学Java1 小时前
ARM 架构(Advanced RISC Machine)精简指令集计算机(Reduced Instruction Set Computer)
arm开发·架构
ZOMI酱3 小时前
【AI系统】GPU 架构与 CUDA 关系
人工智能·架构
天天扭码10 小时前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
余生H10 小时前
transformer.js(三):底层架构及性能优化指南
javascript·深度学习·架构·transformer
凡人的AI工具箱10 小时前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang