一,计算机组成
1,嵌入式系统
嵌入式系统是以应用为中心,以计算机技术为基础,并且软硬件可裁剪,适用于应用系统对功能、可靠性、成本、体积、功耗等有严格要求的专用计算机系统。
计算机:
通用计算机系统: PC,服务器
专用计算机系统: 软硬件可裁剪 ==> 嵌入式
嵌入式系统:
硬件
软件:
bootloader: 启动引导程序,作用是把操作系统从存储设备拷贝到内存去运行。
OS(操作系统)
应用程序
2,什么是计算机系统? 计算机组成。
冯·诺伊曼结构(存储程序型电脑)
最早的计算机仅含固定用途的程序。例如一个计算机仅有固定的数学计算机程序,它不能拿来当文字处理软件,更不能拿来学习办公、玩游戏。
程序 ==> 存储
冯·诺依曼结构把计算机系统分为如下几个部分:
算术逻辑单元(运算器)
控制器
存储器
输入输出接口
指令和数据以同等低位存放与存储器内,并可按地址寻访;指令按顺序执行。
有人提出:指令和数据虽然在本质都是"数据",但是它们的属性却不一样。
指令 ==> 只读
数据 ==> 可读可写。
有些存储器只读。
有些存储器可读可写。
哈佛架构(Harvad Architecure)
是一种将程序存储和数据存储分开的存储器结构。但是它并未完全突破冯·诺依曼结构。
ROM : Read Only Memory 只读存储器/程序存储器
RAM : Random Access Memory 随机读写存储器
3,各组件如何通信呢?
总线: 多根"电线"
总线的两个特点:
(1)任意时刻只能有一个设备向总线发送信息 ==> 系统瓶颈
(2)多个部件可以同时从总线上接收相同的信息 ==> 广播式
总线按功能分:
数据总线(DB): 双向,CPU在数据总线上发数据或者接收数据
地址总线(AB): 单向,用来发送地址
控制总线(CB): 单向,用来CPU发送命令和状态
总线按位置分:
片内总线: CPU内部连接各个寄存器及运算器逐渐之间的总线。
系统总线: CPU与内存、I/O设备等其它高速功能部件之间的总线。
通信总线(I/O总线): CPU与中低速I/O设备互相连接的总线。
4,CPU工作原理
ALU <- 加法器
Control Unit 控制器
Register(寄存器):
CPU内部寄存器是CPU内部用来存放数据的一些小型的存储区域,用来
暂时存放参与运算的数据和运算的结果。
R0~R15 xPSR
寄存器实现就是一种常见的时序逻辑电路,只不过这种时序逻辑电路只
包含存储电路。 锁存器/触发器
5,几个基本概念
机器字长: 是指CPU一次能处理数据的位数,通常与CPU的寄存器位数有关。
字长越大,数的表示范围就大,精度也越高。
int 与机器字长?
int类型一般为机器中最自然的长度。
unsigned long(32bits==>4字节,64bits==>8字节)
指针类型(32bits==>4字节,64bits==>8字节)
bit: 一个存储元件寄存一位二进制代码
Byte: 一个存储元件,包含8个bit。可访问的基本单元。
芯片(集成电路,IC): CPU + 总线 + 各硬件控制器
组合逻辑电路
时序逻辑电路
二、ARM Cortex M4 体系结构
1,ARM 简介
一个公司的名字(英国)
一种处理器架构(RISC精简指令集,高性能、低功耗)
采用ARM结构的处理器
ARM系列 ARM内核 典型芯片
Cortex-M[MCU] M0/M1/M2/M3/M4 STM32F103/STM32F407
Cortex-A[Application] A7/A8/A9/A53 S5PV210/S5P6818
Cortex-R[RealTime] R4/R5//R7/R8
STM32是ST(意法半导体)公司基于Cortex-M3/M4内核推出的一款微控制器。
主要应用在控制场合,工控场景。凭借其产品线的多样化、极高的性价比、简单易用的
固件库开发方式,STM32在嵌入式领域深受欢迎。
2,Cortex M4 总线接口
ARM Cortex M4 采用哈佛结构,为系统提供了三套总线
(1)Icode总线,用于访问代码空间的指令。32bits
访问空间为:0x0000 0000 ~ 0x1FFF FFFF(512M)。每次取4字节。
注: 指令为只读数据
(2)Dcode总线,用于访问代码空间的数据。32bits
访问空间为:0x0000 0000 ~ 0x1FFF FFFF(512M)。
非对齐的访问会被总线分割为几个对齐的访问。
"4字节对齐",变量的地址必须为4的倍数
(3)System总线,用于访问其它系统空间。如:硬件控制器,
访问空间为 0x2000 0000 ~ 0xDFFF FFFF 和 0xE010 0000 ~ 0xFFFF FFFF
非对齐的访问会被总线分割为几个对齐的访问。
3,Cortex M4 工作状态(处理器状态)
ARM公司设计的CPU,可以支持多种指令集:
ARM指令集 :32bits的,功能比较强大,通用。
Thumb指令集:
thumb 16bits,功能也强大
thumb-2 32bits,功能也强大,增加了不少专用的DSP指令。
注: Cortex M4 只支持Thumb指令
★4,Cortex M4 寄存器 (M3权威指南37页)
通用寄存器
R0~R7 : thumb,thumb-2都可以访问
R8~R12: 只有少量的thumb,thumb-2都可以访问
ADD R0 ,R0 ,R1
专用寄存器: R13 R14 R15 xPSR
R13(SP) : Stack Pointer 保存堆栈的栈顶地址。
"堆栈":(stack)是什么?是用"栈的思想"来管理的一段内存。
"栈的思想":先进后出。
为什么需要"堆栈"?为了支持调用过程(函数)。
"现场保护": 把寄存器里面的内容保存到内存中去。
"现场恢复": 把原先保存的内容还原到相应的寄存器中去。
这个过程,正好是 先进后出。
Cortex M4 有两个堆栈,双堆栈
MSP 主堆栈指针
PSP 进程堆栈指针
为什么需要双堆栈呢?
为了支持操作系统。把操作系统用的堆栈和用户线程用的堆栈分开。
R14(LR): Linked Register 链接寄存器。
在执行调用过程(函数)指令的时候,我们需要保存该指令的下一条指令的地址,
因为这个地址,就是函数结束后,要返回的地址。
有一个专门的寄存器,用来保存函数调用的返回地址。 ==> LR(R14)
BL func ;BL带返回的跳转指令,把这条指令的下一条指令的地址赋值给LR
;跳转: 到指定的地方去取指令执行。
R15(PC) : Program Counter程序计数器。保存下一条要执行的指令的地址。
PC保存的是下一条取值的指令的地址,我们可以通过改变PC的值来实现跳转。
"指令按顺序执行" ==> 地址跟程序指令的条数是正相关。所以叫程序计数器。
指令流水线? Cortex M4 采用的是三级流水线(取指、译码、执行)。
xPSR : Program Status Register 程序状态寄存器
程序状态寄存器: 保存程序运行过程中的一些状态,这些要保存的状态分为三类:
a. 应用状态寄存器 APSR: 计算结果的标志
N Z C V Q
b. 中断状态寄存器 IPSR: 保存中断的编号 Exception Number 8bits
c. 执行状态寄存器 EPSR: 执行状态 (如: Thumb/ARM)
==> 组合成一个32bits的 xPSR,如图(M3权威指南 41页)
我们每一条执行的指令都可以影响这些状态标志位。
N: (Negative)负数标志位。
如果上一个指令操作的结果为负数,则把N置一
Z: (Zero)零标志位
如果上一个指令操作的结构为零,则把Z置一
C: (Carry)进位或借位标志。
进位: 在加法运算时,产生了进位。
借位: 在减法运算时,产生了借位。
ADD :不带进位的加法指令
ADC :带进位的加法指令
SUB : 不带借位的减法指令
SBC : 带借位的减法指令
V: overflow 溢出
反映有符号数做加减法运算时所得结果是否溢出,如果运算结果超过当前运算
位数所能表示的范围,则溢出,V=1,否则V=0。
直观的效果: 正数+正数==>负数
负数+负数==>正数
注意: 在有符号数的运算中,进(借)C和溢出是两个完全不同的概念。
Q: 饱和标志。
饱和计算: 通过将数据强制置为最大值(最小允许值),减少了数据畸变,
当然畸变仍任存在的,不过若数据没有超过最大范围太多,就不会有太大的问题。
8bits无符号的加法
普通计算:
1111 1111
+ 0000 0001
--------------
10000 0000
饱和计算:
1111 1111 + 1 ==> 1111 1111
ADD R0 ,R0 ,R1 普通计算
QADD R0 ,R0 ,R1 饱和计算
T: xPSR[24]
表示处理器当前执行的状态。(工作状态/处理器状态)
ARM状态 xPSR.T == 0
Thumb状态 xPSR.T == 1
IT
xPSR[26:25]
xPSR[15:10]
IF-THEN位。它们是if-then指令的执行状态位。
包含了if-then模块的指令数目和它们的执行条件。
ICI Interruptible-Continuable Instruction 可中断--中断继续指令位。
xPSR[15:12]
如果执行多寄存器寻址指令(LDM/STM)操作时,产生了一次中断,中断的优先级很高,
必须要打断这条指令的执行,那么你的数据就有可能拷贝了一部分。
这种情况下怎么办呢?
ICI位保存该操作中下一个寄存器操作数的编号,在中断响应之后,
处理器返回由该位指向的寄存器,并恢复操作。
中断屏蔽寄存器:
中断
异常
PRIMASK[0] 片上外设的总中断开关
1 屏蔽所有的片上外设中断
0 响应所有外设的中断
FAULTMASK[0] 系统错误异常的中断总开关
1 屏蔽所有异常
0 响应所有异常
BASEPRI 为使中断屏蔽更加灵活,该寄存器根据中断优先级来屏蔽中断或异常。
当被设置为一个非0的数值时,它就会屏蔽所有具有相同或更低优先级的异常
(包括中断),而更高优先级的则还可以响应。(数值越小,优先级越高)
控制寄存器 CONTROL
用来: 控制选择使用哪个堆栈(主堆栈/进程堆栈)
线程模式的访问等级(特权等级/非特权等级)
特权等级可以访问所有的东西;
非特权等级只能有限的访问。
CONTROL[0] : 线程模式的访问等级
1 非特权等级
0 特权等级
CONTROL[1] : 堆栈的选择。 Cortex M4是双堆栈机制
1 进程堆栈 PSP
0 主堆栈 MSP
5.Cortex M4 工作模式
ARM Cortex M4 有两种工作模式
Thread Mode : 线程模式
Handler Mode :处理模式(异常中断模式)
异常是什么? 打断CPU指令执行顺序的事件。
为什么要支持两种模式呢? 而不只有一种模式呢? Thread Mode。
原因: 在线程模式下,一般只有非特权等级,这是防止对敏感资源进行了误操作的一种保护。
而一旦出现异常(中断),就会进入处理模式,在处理模式下一定是特权等级,
可以更加方便的处理异常。
两种模式之间是怎么切换的呢?
(详情请参考M3权威指南44页 图3.8中断前后状态转换)
练习: 现定义了一个int的变量a并进行了初始化, a为32位 ==> [31:0]
(1)将变量a的第3位 置1,其它位保持不变
a |= 1<<3;
(2)将变量a的第3位 清0,其它位保持不变
a &= ~(1<<3);
(3)将变量a的第3位 取反,其它位保持不变
a ^= 1<<3;
(4)将变量a的[6:3]位赋值为12 (B1100),其它位保持不变
a &= ~(0x0F<<3); //把变量a的【6:3】清零
a |= 12<<3;
汇编写法:
LDR R0 ,=_addr_a ;把a的地址存放到R0
LDR R1 ,[R0] ;把变量a的值保存到R1
BIC R1 ,R1 ,#0x78 ;把R1的【6:3】清零
ORR R1 ,R1 ,#0x60 ;把R1的[6:3]位赋值为12
STR R1 ,[R0] ;把R1的值保存到R0指向的空间(变量a)