ARM是一个指令集,前面讲的几个汇编指令这些都算做指令。
ARM公司有意思的地方是,他们不做ARM设备,他们只设计指令集架构,然后授权(知识产权核,IP核)给其他半导体厂商做。
A:application,主打高性能,手机电脑有许多就是ARM架构的。
R:realtime,主打实时,比如车联网对实时性要求很高。
M:microcontroller,应用于小型嵌入式系统,我们使用的板子。
m系列有m0到m7(简单说就是性能逐渐增加?),而且向下兼容即m7兼容m0~m6.
我们的板子上有一个黑色的小芯片,上面写着stm32blabla一串字符。这个就是整个板子的核心,相当于囊括了上文提到的计算机架构的芯片结构,system on chips。
设计soc规则:首先选用IP核,设计ARM处理器,外加一系列存储、IO外设结构,全部集成在黑芯片上。
ARM处理器 processor 是 architecture 的具体涵盖,多了很多新内容比如定时器。
我们主要学习m4架构。
只看非optional大概了解即可,处理器核访问代码,数据接口。
前面我们已经简单介绍了register。事实上如果想对内存中数据做处理,也要先拿到处理器核中的寄存器里做运算,然后返回回去。
arm register 如下:
通用寄存器:临时变量,可以存储计算数据之类的。
SP:栈顶指针寄存器,指向栈顶。
LR:函数返回用,保存返回地址。比如要调用函数了,把PC的值存入LR,然后PC跳转到函数起始位置;函数返回的时候LR的值还给PC。
PC:指向程序当前执行到的位置(下一个要执行的指令的地址)程序计数器。每条指令取了之后PC自动加一条指令,比如32位指令集PC+=4B。
PSR系列是状态寄存器,指明当前程序状态。比如当前是用户模式还是内核模式?IPSR指明当前是否允许中断?等。
xPSR包括:
m4有4g的内存空间默认映射到一片空间中,用户也可以根据自己喜好修改。有存储代码的code region,存储数据的sram region,存储外设的peripheral region,external ram region,external device region,Internal Private Peripheral Bus (PPB)。
位带操作。
如果我们要读写32位数据中的某一位,比如第三位(从左往右是31:0,第三位是右边第4个),有的寄存器允许我们直接获取r[3],但是大多数是不允许直接获取的。
如何处理?如果写入1,那么r|0000 0000 0000 0000 0000 0000 0000 1000.
如果写入0,那么 r & 1111 1111 1111 1111 1111 1111 1111 0111.
读取:看 r & 0000 0000 0000 0000 0000 0000 0000 1000 结果是否为0.
这样很麻烦,比如我们要给0x2000 0000处的数据第3位写1,详细汇编代码:
LDR是把后面的数据加载到前面的寄存器中,[R1]是把R1的值当做一个地址,取得其中存储的数据。
这样挺麻烦的,但是因为有内存映射我们可以直接写入和获取“位带别名地址”中的数据。
0x2000 0000处的第0位到第31位分别是:
0x2200 0000
0x2200 0004
0x2200 0008
0x2200 000c……
0x2200 007c
所以直接获取,修改0x2200 000c的数据即可。
0x2000 0000映射到0x2200 0000是 sram 区域映射,0x4000 0000映射到0x4200 0000是外设 peripheral 区域映射。
操作更快,指令更少,而且只访问一位更安全,比如刚取出0x2000 0000的32位数据,这时候中断修改了0x2000 0000的数据,这时我们取得的数据就是旧的错误数据了,修改完第3位再写回去,相当于中断白改了。
vector:向量表,存储比如main堆栈的地址(MSP),异常的地址等信息。
start-up:板子上电或rst时的启动代码。
program code:我们烧进去的程序代码。
c lib code:库函数代码。
复位时,先读取 msp 地址找到 main 在哪。然后读取 reset vector 执行 BIOS 初始化代码,再开始读取第一条,第二条指令……
两种存储规范。
比如十进制数字,1234,一千二百三十四。然后我们记录到数据库中,地址从低到高存储为4321,权值大的位1存在地址最高处,这就是大端存储 Big endian。否则,权值大的位存在地址低处,1234地址从低到高,就是小端存储 Little endian。m4两种方法都支持。
术语“little endian(小端)”和“big endian(大端)”出自Jonathan Swift的《格列佛游记》(Gulliver’s Trabels)一书,其中交战的两个派别无法就应该从哪一端(小端还是大端)打开一个半熟的鸡蛋达成一致。
一下是Jonathan Swift在1726年关于大小端之争历史的描述:
“…下面要告诉你的是,Lilliput和Blefuscu这两大强国在过去36个月里一直在苦战。战争开始是由于以下的原因:我们大家都认为,吃鸡蛋前,原始的方法是打破鸡蛋较大的一端,可是当今皇帝的祖父小时候吃鸡蛋,一次按古法打鸡蛋是碰巧将一个手指弄破了,因此他的父亲,当时的皇帝,就下了一道敕令,命令全体臣民吃鸡蛋时打破鸡蛋较小的一端,违令者重罚。老百姓们对这项命令极为反感。历史告诉我们,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。这些叛乱大多都是由Blefuscu的国王大臣们煽动起来的。叛乱平息后,流亡的人总是逃到那个帝国去寻救避难。据估计,先后几次有11000人情愿受死也不肯去打破鸡蛋较小的一端。关于这一争端,曾出版过几百本大部著作,不过大端派的书一直是受禁的,法律也规定该派的任何人不得做官。”(此段译文摘自网上蒋剑锋译的 《格列佛游记》第一卷第4章。)
在他那个时代,Swift是在讽刺英国(Lilliput)和法国(Blefuscu)之间的持续的冲突。Danny Cohen,一位网络协议的早期开创者,第一次使用这两个术语来指代字节顺序,后来这个术语被广泛接纳了.
大端、小端基础知识 - 知乎 (zhihu.com)
指令集。早期arm指令集32位,性能好能实现的功能强大。但是太长了处理效率低。
thumb-1 指令集16位,处理效率高了,性能也降了。早期arm架构如果是支持两种指令集的,就要频繁切换模式,效率低。
后来thumb-2指令集包含早期16位和新的32位,和arm指令集的混合指令集性能没减太多,代码量和处理效率还高了。