嵌入式linux-----ARM裸机(2)-----ARM体系结构与汇编指令

1.从源代码到CPU执行过程
.c等高级语言经过编译器编译后转换为.s汇编源代码经过汇编器(也是编译器中的一种)转化为elf格式二进制可执行程序通过Objcopy工具转化成Bin格式烧录文件通过总线传送到CPU中进行解码在CPU内部进行控制指令使CPU开始运作。
2.汇编语言与C等高级语言的差异
(1)汇编难写,C好写
(2)可移植性,汇编 (3)效率,汇编>C>Java
(4)汇编不适合完成大型复杂的项目,更高级的语言适合。
3.汇编语言的本质
是机器指令的助记符(如MOV),是一款CPU的本质特征,是一种低级语言。ARM和Intel的编译器不同,因为它们是不同种类的CPU,它们汇编语言的指令集是不一样的,但都是对C语言进行编译。
4.编程语言的发展过程
纯机器码编程→汇编语言编程→C语言编程→C++语言编程→Java、C#等语言编程→脚本语言编程
5.CISC复杂指令集CPU
设计理念是用最少的指令来完成任务(如完成乘法只需要一条指令MUL)。因此CISC的CPU本身设计复杂、工艺复杂,但好处是编译器好设计。CISC出现较早,至今Intel还一直采用CISC设计。(51是Intel的)
6.RISC精简指令集CPU
设计理念是让软件来完成具体的任务,CPU本身仅提供基本功能指令集。因此RISC CPU的指令集中只有很少的指令,这种设计相对于CISC,CPU的设计和工艺简单了,但是编译器的设计变难了。(如ARM)
7.内存的访问方式和IO的访问方式
(1)内存通过CPU的地址总线来寻址定位,然后通过数据总线来读取。地址总线是CPU设计时确定的(32/64位CPU),因此一款CPU的寻址范围是一定的,而内存是需要占用CPU寻址空间的,两者不一定相等。内存与CPU的总线连接方式是直连,优点是效率高访问快,缺点是资源有限,扩展性差。
(2)IO指的是与CPU连接的各种外设。CPU访问外设有两种方式:一是类似于访问内存的方式,把外设的寄存器当作一个内存地址来读写,从而以访问内存相同的方式来操作外设,叫IO与内存统一编址方式;另一种是使用专用的CPU指令来访问某种特定外设,叫IO与内存独立编址,优点是不占用CPU地址空间,缺点是CPU设计变复杂。
8.冯诺依曼结构和哈佛结构
(1)冯诺依曼结构:程序和数据不彼此分离地放在内存中,如电脑,因此缺点是安全和稳定性低,程序易被更改如中毒,优点是处理起来简单。
(2)哈佛结构:程序和数据分开独立放在不同的内存块中,如大部分单片机,程序放在ROM中,数据放在RAM中,因此优点是安全和稳定性高,缺点是软件处理复杂(需要统一规划链接地址)。
9.寄存器
寄存器属于CPU外设的硬件组成部分。CPU可以像访问内存一样访问寄存器。寄存器是CPU的硬件设计者制定的,目的是留作外设被编程控制的“活动开关”。寄存器是外设硬件的软件编程接口API,使用软件编程控制某一硬件,就是编程读写该硬件的寄存器。
SoC中有两类寄存器:通用寄存器和SFR(special function register)特殊功能寄存器。
(1)通用寄存器(ARM中有37个):是CPU的组成部分,CPU的很多活动都需要通用寄存器的支持和参加。
(2)SFR特殊功能寄存器不在CPU中,而存在于CPU的外设中,我们通过访问外设的SFR来编程操控这个外设,这就是硬件编程控制的方法。
10.关于ARM的总结
(1)ARM是RISC架构
①常用ARM汇编指令只有二三十条。
②ARM是低功耗CPU。
③ARM架构非常适合单片机、嵌入式,尤其是物联网领域;而服务器等高性能领域目前主导还是Intel。
(2)ARM是统一编址的
①大部分ARM都是32位架构
②32位ARM的CPU支持的内存小于4G,通过CPU地址总线来访问
③SoC中的各种内部外设通过各自的SFR编程访问,这些SFR的访问方式类似于普通内存,这叫IO与内存统一编址。
(3)ARM是哈佛结构的
①哈佛结构保证了安全和稳定性,因此ARM适用于嵌入式领域
②哈佛结构也决定了ARM裸机程序(使用实地址即物理地址)的链接比较麻烦,必须使用复杂的链接脚本告知链接器如何组织程序;对于OS之上的应用(工作在虚拟地址中)则不需考虑这么多。
11.什么是地址映射(内存映射)?
S5PV210属于ARM的cortex-A8架构,32位CPU,CPU设计时就有32根地址线和32根数据线。32根地址线决定了地址空间为4G,4G空间如何分配使用就是地址映射问题。
嵌入式linux-----ARM裸机(2)-----ARM体系结构与汇编指令_第1张图片
嵌入式linux-----ARM裸机(2)-----ARM体系结构与汇编指令_第2张图片
12.外存ROM和内存RAM
RAM(DRAM、SRAM);ROM(硬盘、Flash、光盘)。
CPU连接内存和外存的连接方式不同。内存是通过地址总线&数据总线的总线访问方式连接的(好处是直接访问,随机访问;坏处是占用CPU的地址空间,大小受限);外存是通过CPU的外存接口来连接的(好处是不占用CPU的地址空间,坏处是访问速度没有总线式快,访问时序较复杂)。
13.SoC常用外存ROM
Flash{NorFlash、NandFlash [NandFlash、eMMC(美国iNand/三星moviNand)、oneNAND、SD卡/TF卡/MMC卡、eSSD]}、SATA硬盘(SATA是接口),主要用来存储程序(可执行代码),存储器原理、大小等各不相同。
①flash通过电子方式访问,硬盘通过机械方式访问。
②NorFlash与其他不同,是总线式访问,可以接到SROMC_Bank,优点是可以直接总线访问,一般用来启动。
③NandFlash分为SLC和MLC工艺。MLC容量更大成本更低但是容易有坏块所以编程较麻烦。
④eMMC(embeded嵌入式 MMC)。由Nand flash和Nand flash控制器组成,可以进行坏块处理等。
⑤oneNand是三星出的一种Nand,结合了NorFlash和NandFlash的优点。
14.S5PV210为原型的X210开发板支持的外部存储器
使用的是iNand版本(eMMC),板载4GBiNand。S5PV210共支持4个SD/MMC通道,X210的通道0和2依次用作启动。SD/MMC0通道已经连接了内置的eMMC,因此外部启动时只能使用SD/MMC2通道(注意通道3不能启动)
15.内存和外存和外存的选择
(1)内存。SRAM缺点是容量小、价格高,优点是不需要软件初始化直接上电就能用;DRAM优点是容量大、价格低,缺点是需要软件初始化后才可以使用。
①单片机中:内存需求量小,希望开发尽量简单,适合全部用SRAM;
②PC机中:内存需求量大,而且软件复杂不在乎DRAM的初始化开销,适合全部用DRAM;③嵌入式系统:内存需求量大,而且没有NorFlash等可启动介质,居中。
(2)外存。NorFlash:特点是容量小价格高,优点是可以和CPU直接总线式相连,CPU上电后可以直接读取,所以一般用作启动介质。NandFlash(跟硬盘一样):特点是容量大、价格低,缺点是不能总线式访问,CPU上电后可以不可以直接读取,需要CPU先运行一些初始化软件,然后通过时序接口读写(用这个启动就相当于死锁了)。
①PC机:很小容量的BIOS(NorFlash)+很大容量的硬盘(类似于NandFlash);
②单片机中:很小容量的NorFlash。
综上:PC机:很小容量的BIOS(NorFlash)+很大容量的硬盘(类似于NandFlash)+大容量的DRAM。BIOS初始化硬盘和内存,再把要运行的大程序从硬盘中读出来放到内存中运行。 单片机:很小容量的NorFlash+很小容量的SRAM
嵌入式系统:因为NorFlash很贵,所以很多倾向于不用NorFlash,用外接的大容量Nand+外接大容量DRAM+SoC内置SRAM(IRAM)。
16.210的启动过程
注:210更复杂一些,内置了一块96KB大小的IRAM(SRAM)和一块内置的64KB大小的IROM。
(1)CPU上电后先从内部IROM中读取预先设置的代码(BL0),执行,这里首先做了一些基本的初始化(CPU时钟,关看门狗……),这一段IROM代码是三星出厂前设置的,三星也不知道我们板子上将来接的是什么样的DRAM,因此这一段IROM是不能负责初始化外接的DRAM的,因此这一段代码只能初始化SoC内部的东西。然后这一段代码会判断我们选择的启动模式(我们通过硬件跳线可以更改板子的启动模式),然后从相应的外部存储器去读取第一部分启动代码(BL1,大小为16KB)到内部IRAM(SRAM)。
(2)从IRAM(SRAM)去运行读取来的BL1(16KB),执行。BL1负责初始化NandFlash,然后将BL2读取到IRAM(剩余的80KB)。
(3)从IRAM运行BL2,BL2初始化DRAM,然后将OS读取到DRAM中,然后启动OS。
嵌入式linux-----ARM裸机(2)-----ARM体系结构与汇编指令_第3张图片
嵌入式linux-----ARM裸机(2)-----ARM体系结构与汇编指令_第4张图片
17.为什么要设计IROM和IRAM?
为了支持多种外部设备启动。
18.second boot support
当第一启动模式失败时,SD/MMC卡启动模式下回从SD/MMC2通道尝试再次启动。这种二级启动是一种冗余设计。SoC中第一启动介质故障而导致不能启动时,可以从备用启动介质启动。我们做裸机实验时从SD2启动就是利用了这一设计特性。
19.使用IROM启动的好处
(1)降低BOM成本,因为IROM可以使SoC从各种外设启动,因此可以省下一块boot ROM(专门用来启动的ROM,一般是NorFlash)
(2)支持各种校验类型的Nand
(3)可以在不使用编程器的情况下使用一种外部存储器运行程序来给另一种外部存储器编程烧录。这样生产时就不用额外购买专用编程器了,降低了量产成本。
20.BL0做了什么?
关看门狗;初始化指令cache;初始化栈;初始化堆;初始化块设备复制函数(device copy function)(Nand);蛇者SoC时钟系统;复制BL1到内部的IRAM(16KB);检查BL1的校验和;(安全启动);跳转到BL1去执行。
21.S5PV210的所有启动
先1st启动,通过OMpin选择启动介质;再2nd启动,从SD2;再Uart启动;再USB启动。
22.ARM的基本设定
(1)ARM采用的是32位架构。
(2)ARM约定,Byte:8bits;Halfword:16bits;Word:32bits
(3)大部分ARM core提供:ARM指令集(32-bit);Thumb指令集(16-bit);Thumb2指令集(16&32bit)
(4)Jazelle cores支持Java bytecode
23.ARM处理器的工作模式
(1)User:大部分任务执行在这种模式。
(2)FIQ:当一个高优先级(fast)中断产生时将会进入这种模式。
(3)IRQ:当一个低优先级(normal)中断产生时将会进入这种模式。
(4)Supervisor:管理模式。当复位或软中断指令执行时将会进入这种模式。
(5)Abort:当存取异常时将会进入这种模式。
(6)Undef:当执行未定义指令时将会进入这种模式。
(7)System:使用和User模式相同寄存器集的特权模式。
(特权(privilege)模式2-7;普通(normal)模式1;系统模式7;异常模式2-6)
各种模式的切换,可以程序员通过代码主动切换(通过写CPSR寄存器);也可以是CPU在某些情况下自动切换。不同模式下权限和可以访问的寄存器不同。
24.CPU为什么设计这些模式?
CPU是硬件,OS是软件,软件的设计要依赖硬件的特性,硬件的设计要考虑软件需要,便于实现软件特性。操作系统有安全级别要求,因此CPU设计多种模式是为了方便操作系统的多种角色安全等级需要。
25.ARM的37个通用寄存器
在每种模式下最多只能看到18个寄存器,System模式使用User模式寄存器。37个寄存器都是32位长度,有30个为“通用”型,1个固定用作PC,1个固定用作CPSR,5个固定用作5种异常模式下的SPSR。
嵌入式linux-----ARM裸机(2)-----ARM体系结构与汇编指令_第5张图片
(1)CPSR程序状态寄存器
在这里插入图片描述
①CPSR中各个bit位表明了CPU的某些状态信息,这些信息和后面学到的汇编指令息息相关(如BLE指令中的E就和CPSR中的Z标志位有关)。N=negative result from ALU;Z=zero result from ALU;C=ALU operation carried out;V=ALU operation oVerflowed。T(仅ARM×T架构支持):T=0,处理器为ARM状态;T=1,处理器为Thumb状态。
②I、F位和开中断、关中断有关。
③mode位决定了CPU的工作模式,在uboot代码中会使用汇编进行设置。
(2)PC(r15)程序控制寄存器
PC(program control register)为程序指针,PC指向哪里,CPU就会执行哪条指令(所以程序跳转时就是把目标代码放到PC中)
26.ARM的异常处理机制
正常工作之外的流程都叫异常,中断是异常的一种。所有CPU都有异常向量表,异常向量表是硬件向软件提供的处理异常的支持。当异常发生时,CPU会自动动作(PC跳转到异常向量处处理异常,有时会伴有一些辅助动作)。
(1)异常产生时,ARM core:
①拷贝CPSR到SPSR_
②设置当前的CPSR位:改变处理器状态进入ARM态;改变处理器模式进入相应的异常模式;设置中断禁止位禁止相应中断。
③保存返回地址到LR_
④设置PC为相应的异常向量
(2)返回时,异常处理需要:
①从SPSR_恢复CPSR
②从LR_恢复PC
(这些操作只能在ARM态执行)
嵌入式linux-----ARM裸机(2)-----ARM体系结构与汇编指令_第6张图片
27.指令和伪指令的区别
指令是CPU机器指令的助记符,经过编译后会得到一串1、0组成的机器码,可以由CPU读取执行。伪指令本质上不是指令(只是和指令一起写在代码中),它是编译器环境提供的(我们使用gnu工具链),目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。
28.ARM汇编特点
(1)LDR/STR架构
①ARM采用RISC架构,CPU本身不能直接读取内存,需要先将内存中的数据加载到CPU的通用寄存器中才能被处理。
②ldr(load register)指令将内存内容加载到通用寄存器。
③str(store register)指令将寄存器内容存入内存中。
④ldr、str组合用来实现ARM的CPU和内存数据的交换。
(2)8种寻址方式
寄存器寻址 mov r1,r2 立即寻址 mov r0,#0xFF00 寄存器移位寻址 mov r0,r1,lsl #3
寄存器间接寻址 ldr r1,[r2] 基址变址寻址 ldr r1,[r2,#4]
多寄存器寻址 ldmia r1!,{r2-r7,r12} 堆栈寻址 stmfd sp!,{r2-r7,lr}
相对寻址 beg flag(有flag:)
(3)指令后缀
同一指令附带不同的后缀变成不同的指令。B(byte),让操作长度变成8位;H(half word),长度变为16位;S(signed),操作变为对有符号的操作;S(S标志),影响CPSR标志位,如movs r0,#0,CPSR的Z位变为1
(4)条件执行后缀
嵌入式linux-----ARM裸机(2)-----ARM体系结构与汇编指令_第7张图片
moveq r0, r1(如果后缀eq成立,则直接执行mov r0, r1;如果不成立则不执行。条件后缀是否成立取决于这句代码前的代码运行结果,此处为标志位Z是否为1)
(5)多级指令流水线
为增加处理器指令流的速度,ARM使用多级流水线,下图为3级流水线工作示意图。允许多个操作同时处理,而非顺序执行。PC指向的是正被取指的指令。
嵌入式linux-----ARM裸机(2)-----ARM体系结构与汇编指令_第8张图片
29.ARM常用汇编指令
(1)数据处理指令
mov和mvn用法一样,区别是mvn是按位取反后传递。and,orr,eor与、或、异或。bic位清除。bic r0,r1,#0x1f(将r1中的bit0-4清零后赋值给r0)。比较指令cmp、cmn、tst、teq(比较指令后不用加s后缀就可以影响CPSR中的标志位)
(2)CPSR访问指令
CPSR寄存器比较特殊,需要专门的指令访问,就是mrs读和msr写。
(3)跳转指令
b直接跳转(没打算返回);bl(branch and link)跳转前把返回地址放入lr中,以便返回,一般用于函数调用;bx。
(4)访问内存指令
ldr/str&ldm/stm&swp。单个字/半字/字节访问ldr读/str取;多字批量访问ldm/stm;swp。
(5)软中断指令
swi(software interrupt)软中断指令用来实现操作系统中系统调用。
30.合法、非法立即数
ARM指令是32位的,除了指令标记和操作标记外,本身只能附带很少位数的立即数,因此有合法和非法之分。合法立即数:经过任意位数的移位后非零部分可以用8位表示。
31.ARM协处理器CP15操作指令
mrc用于读取CP15中的寄存器;mcr用于写入CP15中的寄存器。
32.什么是协处理器CP(coprocessor)?
SoC内部另一处理核心,协助主CPU实现某些功能,被主CPU调用执行一定任务。ARM支持多达16个,一般只实现其中的CP15。协处理器和MMU、cache、TLB等处理有关,功能上和操作系统的虚拟地址映射、cache管理等有关。
·mcr p15, , , , , {}
opcode_1:对于cp15永远是0;Rd:ARM的普通寄存器;Crn:cp15的寄存器(c0-c15);Crm:cp15的寄存器,一般为c0;opcode_2:一般省略或为0。
例:mrc p15, 0, r0, c1, c0, 0
……
mcr p15, 0, r0, c1, c0, 0
即把c1读到r0进行处理再写回c1
33.为什么需要多寄存器访问指令
ldr/str每周期只能访问4字节内存,如果需要批量读取、写入内存时太慢,解决方案是stm/ldm(store register mutiple/load register mutiple)。
例:stmia sp,{r0 - r12}。将r0存入sp指向的内存处;然后地址+4(32CPU里是4字节对齐的),将r2存入该地址……直到r12内容放完。这里一个访问周期同时完成了13个寄存器的读写。
·ia(increase after)先传输,再地址+4
·ib(increase before)先地址+4,后传输
·da(decrease after)先传输,再地址-4
·db(decrease before)先地址-4,再传输
上面四个和下面四个等价。
·fd(full decrease)满递减堆栈
·ed(empty decrease)空递减堆栈
·fa(full add)满递增堆栈
·ea(empty add)空递增堆栈
常用stmia和stmfd,进栈和出栈时用相同的后缀就不会出错。
34.四种栈
空栈:栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出。
满栈:栈指针指向栈中最后一格数据,每次存入时先将指针移动一格再存入;取出时可以直接取出,然后再移动栈指针。
增栈:栈指针移动时向地址增加的方向移动的栈。
减栈:栈指针移动时向地址减小的方向移动的栈。
35.!、^的作用
(!)r0的值在ldm过程中发生的增减最后会写回到r0去,也就是ldm会改变r0的值。
ldmia r0, {r2 - r3}
ldmia r0!, {r2 - r3}
(^)在目标寄存器中有pc时,会同时将spsr写入到cpsr,一般用于从异常模式返回。
ldmfd sp!, {r0 - r6,pc}
ldmfd sp!, {r0 - r6,pc}
36.gnu汇编中的一些符号
@做注释,放在行首或代码后。
#做注释,放在行首。也可以用来代表立即数。
:以冒号结尾的是标号。
.点号在gnu汇编中代表当前指令的地址。
37.常见gnu伪指令
(1)常用
.global _start @给_start外部链接属性
.section .text @指定当前段为代码段
.ascii .byte .short .long .word .quad .float .string @用来定义变量
/******
IRQ_STACK_START:
.word 0x0badc0de
等价于unsigned int IRQ_STACK_START = 0x0badc0de
******/
.align 4 @以16(2^4)字节对齐
.balignl 16, 0xdeadbeef @对齐+填充,b表示位填充;align表示要对齐;l表示long,以@4字节为单位填充;16表示16字节对齐;0xdeadbeef是用来填充的原料。
.equ @类似于C中宏定义
(2)偶尔使用
.end @标志文件结束
.include @头文件包含
.arm/.code32 @声明以下为arm指令
.thumb/.code16 @声明以下为thumb指令
(3)最重要的几个伪指令
ldr @大范围的地址加载指令(ldr指令ldr r0, #0xff和伪指令ldr r0, =0xfff的区别是立即数前是#和=,且伪指令不需要考虑合法/非法立即数,伪指令时是数字要加=,是符号则不需要加=,一般都用伪指令不用指令)
adr @小范围的地址加载指令
adrl @中等范围的地址加载指令
nop @空操作
(adr总是以PC为基准来表示地址,因此指令本身和运行地址有关,可以用来检测程序当前运行地址在哪里;ldr加载的地址和链接时给定的地址有关,由链接脚本决定。可以通过两者加载的地址比较来判断当前程序是否在链接时指定的地址运行。)


朱有鹏老师linux核心课程学习笔记

你可能感兴趣的:(嵌入式_裸机,嵌入式,arm,操作系统)