1

ARM基本知识

ARM 内核版本号

  • ARM一款微处理器
  • ARMv7(ARM version 7):ARM的第七版本

ARM soc版本号

  • ARMv7对应的soc版本号:Cortex-M、Cortex-A、Cortex-R。
  • M:microcontriller微控制器,就是单片机
  • A:application应用级处理器,就是手机、平板、电脑的CPU
  • R:realtime实时处理器,响应速度快,用于工业等领域

SoC和CPU

  • SoC:System on Chip,系统级芯片,内部包含CPU并且内置了其他外设。
  • CPU:Central Processing Unit,中央处理器,一块超大规模的集成电路。
  • 现在所说的CPU和芯片其实都是SoC。

嵌入式与单片机

  • 单片机平台:51、PIC、STM32、AVR等
  • 嵌入式平台:ARM、PPC、MIPS等
  • 单片机上资源有限、价格低、应用领域多为小家电等。
  • 嵌入式系统片上资源丰富、价格较高、应用领域广泛、例如智能手机/平板/游戏机/摄像机等。

嵌入式系统特点

  • 专用、软硬件可裁剪可配置。
  • 低功耗、高可靠性、高稳定性。
  • 软件代码短小精悍。
  • 代码可固化(代码可以烧录到硬件中,且断电后不丢失)
  • 实时性。
  • 弱交互性。
  • 专用开发工具及开发环境。

嵌入式系统的组成

  • 硬件组成:微处理器、存储器、I/O接口、输入输出设备等
  • 软件组成:

    • 嵌入式操作系统
    • BSP(board support package板级支持包)
    • 应用软件

交叉编译

  • 非嵌入式开发模式:A类操作系统机型编写源代码,编译得到可执行程序,发布给A类操作系统机型运行(机型可能变过,但是操作系统没变)
  • 嵌入式开发:A类机型编写程序,编译得到可执行程序,发布给B类操作系统机型运行(操作系统变了,例如Windows和Linux)
  • 嵌入式开发环境的CPU比较简答,本身无法搭建开发环境,有的甚至操作系统都没有,所以要使用交叉编译。
  • 交叉编译可以用高性能机为低性能机开发软件。
  • 交叉编译特点:

    • 必须使用专用的交叉编译工具链。
    • 由于可执行程序不能本地运行调试,因此必须配合一定手段将可执行程序加载到目标嵌入式设备上运行及调试(JTAG调试器、USB下载等)

地址总线和数据总线

  • CPU通过地址总线寻址,然后通过数据总线与外部设备交互信息。
  • 地址总线位数决定CPU寻址范围。
  • 数据总线位数决定CPU单次通信能交换的信息数量。
  • 总线的速度决定CPU与外设交互信息的速度。
  • CPU地址总线的位数和数据总线的位数是可以不相同的,但一般都相同。
  • CPU的位数是指数据总线的位数。

ARM体系结构与汇编指令

可编程器件的特点

  • CPU在固定频率的时钟控制下有节奏的运行。
  • CPU可以通过总线读取外部存储设备中的二进制指令集,然后解码执行。
  • 这些可以被CPU解码执行的二进制指令集是CPU设计时就确定了的,本质上是一串由1和0组成的数字,这就是CPU的汇编指令集。

汇编语言

  • 汇编语言就是CPU的机器指令集的助记符,是一款CPU的本质特征。
  • 不同CPU的机器指令集设计不同,因此汇编程序不能在不同CPU之间相互移植。
  • 汇编编程效率高响应快,因此在操作系统内核中效率极其重要处都需要用汇编语言编写。

RISC和CISC

  • CISC:complex instruction set computer 复杂指令集CPU。
  • CISC体系的设计理念是用最少的指令来完成任务,因此CISC的CPU本身设计复杂、工艺复杂,但好处是编译器好设计。
  • RISC:reduced instruction set conputer 精简指令集CPU。
  • RISC体系的设计理念是让软件来完成具体任务,CPU本身只提供基本功能指令集。

统一编址/独立编址

  • 内存:内存是程序的运行场所,内存和CPU之间通过总线连接,CPU通过一定的地址来访问具体的内存单元。
  • IO:指输入输出接口,是CPU和其他外部设备之间的通信道路,一般说的IO指的就是CPU的各种内部或外部外设。
  • 内存的访问方式:内存通过CPU的地址总线来寻址定位,然后通过CPU的数据总线传输数据。
  • IO的访问方式:

    * 统一编址:用类似于访问内存的方式,即把外设的寄存器当作一个内存地址来读写,从而以访问内存的方式来操作外设,这叫IO与内存统一编址。
    * 独立编址:使用专用的CPU指令来访问某种特定外设,这叫IO与内存独立编址。
    

哈佛结构/冯诺依曼结构

  • 程序和数据

    • 程序运行时有两大元素:程序+数据。
    • 程序是我们写好的源代码经过编译、汇编之后得到的机器码,这些机器码可以拿给CPU去解码执行,CPU也不会去修改程序,所以程序是只读的。
    • 数据是程序运行过程中定义和产生的变量的值,是可以读写的,程序运行实际就是为了改变数据的值。
  • 哈佛结构:程序和数据分开独立放在不同的内存块中,彼此完全分离的结构

    • 程序一般放在ROM和flash,数据一般放在RAM中。
    • 优势:安全和稳定性高。
    • 劣势:软件处理复杂,需要统一规划链接地址等。
  • 冯诺依曼结构:程序和数据都放在内存中,且彼此不分离的结构

    • 优势:处理起来简单。
    • 劣势:安全和稳定性低

寄存器

  • 寄存器:是软件控制硬件的关键,是外部设备的硬件组成部分。
  • 寄存器就相当于外设硬件的软件接口API,使用软件编程控制某一硬件,实质就是编程读写该硬件的寄存器。
  • 寄存器中每个bit位都有特定含义,因此编程时需要位操作。
  • 编程操作寄存器类似与访问内存。
  • SoC中有两类寄存器

    • 通用寄存器:ARM中有37个,是CPU的组成部分。
    • SFR特殊功能寄存器:不在CPU中,存在于CPU的外设中,通过访问外设的SFR来编程控制这个外设,这就是硬件编程控制的方法。

地址映射

  • 为了保证CPU执行指令时可正确访问存储单元,需将用户程序中的逻辑地址转换为运行时由机器直接寻址的物理地址,这一过程称为地址映射。也就是说我们常说的内存中某个地址0x0fffffff其实是实际内存中某个地址的代名词。

内存与外存

  • 内存:

    • SRAM:静态内存,缺点是容量小、价格高,优点是不需要软件初始化直接上电就能用。
    • DRAM:动态内存,优点是容量大、价格低,缺点是上电后不能直接使用,需要软件初始化。
  • 单片机中:内存需求小,且希望开发更简单,适合全用SRAM。
  • 嵌入式系统中:内存需求大,而且没有NorFlash等启动介质(一般是NandFlash+DRAM+SoC内置的SRAM)
  • PC机中:内存需求大,而且软件复杂,不在乎DRAM的初始化开销,适合全用DRAM。
  • 外存:

    • NorFlash:缺点是容量小、价格高,优点是可以和CPU直接总线式相连,CPU上电后可以直接读取,所以一般常用作启动介质。
    • NandFlash:跟硬盘一样,容量大、价格低,缺点是不能总线式访问,也就是说上电后CPU不能直接读取,需要CPU先运行一些初始化软件,然后通过时序接口读写。

ARM的7种工作模式

  • User:非特权模式,大部分任务执行在这种模式下。
  • FIQ:当一个高优先级中断产生时将会进入这种模式。
  • IRQ:当一个低优先级中断产生时将会进入这种模式。
  • Supervisor:当复位或软件中断指令执行时将会进入这种模式。
  • Abort:当存取异常时将会进入这种模式。
  • Undef:当执行未定义指令时将会进入这种模式。
  • System:使用和User模式相同寄存器集的特权模式。
  • 各种模式下权限和可以访问的寄存器是不同的。
  • 除了User是普通模式外,其他都是特权模式。
  • 操作系统有安全级别要求,因此设计多种模式是为了方便操作系统的多种角色安全等级需要。

ARM的寄存器

  • ARM总共有37个寄存器。
  • 寄存器的使用与ARM的工作模式相关,每种模式下最多只能看到18个寄存器。
  • 例如:对于r14这个寄存器,在ARM中有6个寄存器是同样的名字,但是在每种特定的模式下只能看到其中一个,其它的r14寄存器必须切换模式后才能看到。
    • 切换模式后,以User寄存器为基础(黑色部分),会用备用寄存器替换当前可见寄存器中的同名寄存器。(图中就是切换到Abort模式时,看到的寄存器)
      image.png

ARM的异常处理方式

  • 什么是异常:正常工作之外的流程都叫异常,异常会打断正在执行的任务,并且一般我们希望异常处理完后继续执行之前的任务,中断也是异常的一种。
  • 异常向量表:所以的CPU都有异常向量表,是由硬件决定的。当发生异常时,CPU会自动动作(PC跳转到异常向量处处理异常,有时还伴有一些辅助动作),异常向量表是硬件向软件提供的处理异常的支持。

ARM汇编指令集

指令与伪指令
  • 汇编指令:是指CPU机器指令的助记符,记过编译后可以得到一串由1和0组成的机器码,可以由CPU读取执行。
  • 汇编伪指令:其本质上不是指令,只是和指令一起写在代码中,它是编译环境提供的用来指导编译过程,经过编译后伪指令不会生成机器码。
ARM汇编指令集
  • ARM采用RISC架构,CPU本身不能直接读取内存,需要先将内存中内容加载如CPU的通用寄存器中才能被CPU处理。

    • ldr指令:将内存中内容加载入通用寄存器。
    • str指令:将寄存器内容存入内存空间。
    • ldr/str组合实现ARM的CPU和内存的数据交换。
  • ARM支持8种寻址方式

    • 寄存器寻址:mov r1, r2(把r2的值赋给r1)
    • 立即数寻址:mov r0,#0xFF00(把xff00这个数立即赋给r0)
    • 寄存器移位寻址:mov r0,r1,lsl #3(r1左移3位,再赋给r0,lsl是左移符)
    • 寄存器间接寻址:ldr r1,[r2]
    • 基址变址寻址:ldr r1,[r2,#4]
    • 多寄存器寻址:ldmia r1!,{r2-r7,r12}
    • 堆栈寻址:stmfd sp!,[r2-r7,r12,lr]
    • 相对寻址:flag1 :beq flag2 (在汇编代码中,在flag1中使用相对寻址时,程序会跳转到flag2处去执行)
  • 指令后缀

    • 同一指令经常附带不同的后缀,变成不同的指令。
    • B(byte):功能不变,操作长度变为8位。
    • H(half word):功能不变,操作长度变为16位。
    • S(signed):功能不变,操作数变为有符号数。
    • 例如:ldr、ldrb、ldrh、ldrsh、ldrsb
    • S(S标志):功能不变,影响CPSR标志位。
    • 例如:mov、movs
  • 条件指令后缀

    • 例如:moveq r0,r1 (如果eq后缀条件成立,则执行mov r0,r1;如果不成立则作废)
    • 条件后缀是否成立,不是取决于本句代码,而是取决于之前的代码运行后的结果。

    image.png

数据处理指令
  • 数据传输指令:mov、mvn

    • mov r1,r0 :将r0寄存器中的值原封不动的传递给r1
    • mvn r1,r0 :将r0寄存器中的值按位取反后传递给r1
  • 算数指令:add加、sub减、rsb、adc、sbc、rsc
  • 逻辑指令:and与、orr或、eor异或、bic

    • bic :位清除指令
    • bic r0,r1,#0x1f :将r1中的值的bit0位到bit4清零后赋值给r0,清楚后面那个数中为一的那些位。
  • 比较指令:cmp、cmn、tst、teq

    • 比较指令不用加S后缀就可以影响cpsr中的标志位。
    • cmp :与正数相比较
    • cmn :与负数相比较
    • tst :检测某位是否为零;tst r0,#0x08 ;检测bit3位是否为零。
    • teq :测试等价
  • 乘法指令:mvl、mla、umull、umlal、smull、smlal
  • 前导零计数:clz (计算一个数前面有多少个0)
cpsr访问指令
  • cpsr寄存器较为特殊,不能用mov指令访问,需要专门的指令。
  • cpsr寄存器是程序状态寄存器,整个SoC中只有一个。
  • spsr寄存器在SoC中有5个,分别在5中异常模式下,作用是当从普通模式进入异常模式时,用来保存之前普通模式下的cpsr,以便在返回普通模式时恢复原来的cpsr。
  • mrs指令:用来读psr寄存器。
  • msr指令:用来写psr寄存器。
跳转指令
  • b :直接跳转
  • bl :跳转前把返回地址放入lr中,以便返回,一般用于函数调用。
  • bx :跳转的同时切换到ARM模式,一般用于异常处理的跳转。
访存指令
  • 字节访问:ldr/str
  • 多字节批量访问:ldm/stm
  • swp指令:

    • swp r1,r2,[r0] 将r0地址中内容读到r1中,再将r2中内容读到r0地址中
软中断指令
  • swi (software interrupt):用软件来产生中断,实现操作系统中系统调用。
协处理器CP15操作指令
  • 协处理器:SoC内部另一处理核心,协助主CPU实现某些功能,被主CPU调用执行一定的任务。
  • ARM设计上支持多达16个协处理器,但一般SoC只实现其中的CP15(总共是CP0--CP15)
  • CPU中的寄存器都是以r开头,协处理器中的寄存器都是以c开头。
  • mrc :用于读取CP15中的寄存器。
  • mcr :用于写入CP15中的寄存器。
多字节批量访问
  • ldm :读取存储器内容到寄存器中
  • stm :将寄存器中值写入存储器中
  • 例如 :

    • stmia sp,{r0-r12}
    • 将r0存入sp所指向的内存处,然后地址加4,再将r1存入该地址,然后地址再加4,一直到r12内容放入内存处,指令完成。
  • 感叹号的作用:将内存中运算后的值返回到寄存器中。

    • ldmia sp!,{r0-r12}
    • 读取sp指向的地址到r0-r12中,每读一次,地址会+4,但是sp所指向的地址没有发生改变,加上!号后,会将增加的地址返回到sp中,使sp指向新的地址。
  • ^ 符号的作用:在目标寄存器中有pc时才起作用,将spsr中的内容写入cpsr中

    • 例如:ldmfd sp!,{r0-r6,pc}^
    • 读取sp指向的地址到r0-r6和pc寄存器中,同时将spsr中的内容写入cpsr中。
  • 8中后缀:

    • ia :先传输,后地址+4。
    • ib :先地址+4,后传输。
    • da :先传输,后地址-4。
    • db :先地址-4,后传输。
    • fd :满递减堆栈(ARM中默认使用满减栈)
    • ed :空递减堆栈
    • fa :满递增堆栈
    • ea :空递增堆栈
  • 空栈:栈指针指向空位,每次入栈时都可以直接存入,然后指针移动一格,而出栈时需要先移动一格才能取出。
  • 满栈:栈指针指向栈中最后一格数据,入栈时需要指针先移动一格再存入,出栈时可以直接取出,然后再移动一格。
  • 增栈:栈指针移动时向地址增加的方向移动的栈。
  • 减栈:栈指针移动时向地址减少的方向移动的栈。
  • 操作栈时尽量使用相同后缀,不容易出错。

ARM伪指令

  • @符号:用来做注释,可以在首行也可以在代码后面,和C语言的//注释符类型。
  • 符号:用来做注释,一般放在首行,表示这一行都是注释而不是代码。

  • .符号:在gnu汇编中表示当前指令的地址。
  • /$符号:立即数前面加#号或$号表示这是个立即数。

  • :符号:在gnu汇编中以冒号结尾的,表示这是个标号,不是指令。
  • .global符号:.global _start 声明_start为外部链接属性(在别的文件也可以访问_satrt)
  • .section符号:指定当前段为代码段。
  • 定义数据的符号:

    • .ascii 定义字符长度
    • .byte 定义字节长度
    • .shour 定义两个字节长度
    • .long 定义四个字节长度
    • .word 定义四个字节长度(一个字)
    • 例如 a:
    • .word 0xffffffff @表示a = 0xffffffff
    • .quad 定义双字,8个字节
    • .float 定义浮点型
    • .string 定义字符串
  • .align 4 以16字节对齐
  • .align 2 以4字节对齐
  • .balignl 16,0xabcdefgh @b表示位填充,align表示对齐,l表示long以四字节填充,16表示16字节对齐,0xabcdefgh是用来填充的原料。
  • .equ 类似于C语言的宏定义。
  • ldr 大范围的地址加载指令
  • adr 小范围的地址加载指令
  • adrl 中等范围的地址加载指令
  • nop 空操作

夜枫微凉
24 声望4 粉丝