Cortex-M3那点事

来源:互联网 发布:gta5破解版需启动网络 编辑:程序博客网 时间:2024/04/29 13:53


一:寄存器组

Cortex-M3处理器拥有R0-R15的寄存器组:

   R0-R12是通用寄存器。

R13作为堆栈指针SP有两个,但在同一时刻只有一个起作用。

MSP: 复位后默认使用的堆栈指针,用于操作系统内核以及异常处理例程,PSP: 由用户的应用程序代码使用)

R14: 连接寄存器。

R15:程序寄数器,指向当前的程序地址。

特殊功能寄存器:

 程序状态寄存器组(PSR)

 中断屏蔽寄存器组(PRIMASK,FAULTMASK,BASEPRI)

 控制寄存器(CONTROL)

Cortex-M3中有专门的指令复责堆栈操作——PUSH和POP,其汇编语法如下:

PUSH {R0} ; *(--R13) = R0

POP {R0} ; R0 = *R13++

   注意注释:何谓“向下增长的满栈”?在PUSH新数据时,堆栈指针先减一个单元,通常在进入一个子程序后,第一件事就是把寄存器的值先PUSH入堆放栈中,在子程序退出前再POP曾经PUSH的那些寄存器。在程序中可以直接把R13写作SP。

R15又叫作“PC”,读PC时返回的值是当前指令的地址+4。

特殊功能寄存器组专用的访问指令:

MRS    R0 , PC ;读特殊功能寄存器的值到通用寄存器

MSR    PC ,R0 ;写通用寄存器的值到特殊功能寄存器

二:操作模式和特权级别

两种特权操作模式:handler mode 和 thread mode

特权的分级:特权级和用户级

Thread mode可以使用特权级也可以用用户级,但异常服务例程必须使用特权级。

复位后,处理器默认进入thread mode,特权级访问。

从用户级到特权级的唯一途径就是异常,特权级可以通过修改CONTROL寄存切换到用户级。

三:总线接口

Cortex-M3内部有若干条总线接口,使CM3能同时取址和访问内存,它们是:

 指令存储区总线(若干条)

 系统总线

 私有外设总线

两条代码存储区总线负责对代码存储区的访问,分别是I-Code 总线和我D-Code,前者用于取指,后者用于查表等操作,它们按最佳执行速度进行优化。

系统总线用于访问内存和外设,覆盖的区域包括SRAM,片上外设,片外RAM,片外扩展设备,以及系统级存储区的部分空间。

私有外设总线负责一部分私有外设的访问,主要是访问调试组件。它们是系统级存储区。

四:中断和异常

ARMv7-M开创了一个全新的异常模型,这种异常模型跟传统的ARM处理器使用完全是两码事。新的异常模型“使能”了非常高效的异常处理,它支持16-4-1=11种系统异常,外加240个外部中断输入,在CM3中取消了FIQ的概念,这是因为有了更新的更好的机制——中断优先级管理以及嵌套中断支持,它们被纳入CM3的中断管理逻辑中,因此,支持嵌套中断的系统就更容易实现FIQ。

CM3的所有中断机制都由NVIC实现。

 五:向量表

CM3响应一个发生的异常后,对应的异常服务例程就会执行,为了决定异常服务程序入口地址,CM3使用“向量表查询机制”。向量表其实是一个WORD数组。

六:常见部分汇编指令(移植操作系统时用)

1.后缀的使用:

 S    更新APSR的相关标志

 EQ,NE,LT,GT等:EQ = Euqal, NE = Not Equal, LT = Less Than ,GT = Greater Than.

2.APSR的5个标志:N: 负数标志(Negative);

    Z: 零结果标志(Zero);

  C: 进位/借位标志(Carry);

  V:溢出标志(oVerflow);

                  S: 饱和标志;

3.ADC: 带进位的加法

4.ASR:  算术右移

5.BIC:  按位清0

6.CMP:  比较(更新标志)

7.EOR:  近位异或

8.LSL:  算术左移  

9.ORR:  按位异或

10.ROR: 圈圈左移

11.SBC: 带借位的减法

12.SUB: 减法

13.TST: 测试

14.BL: 转移并链接

15.CBZ: 比较,如果结果为0就转移

16.LDR: 从存储器中加载一个字到一个寄存器中

17.LDRH  加载半字

18.LDRB: 加载一个字节

19.STR:

20.STRH:

21.STRB:

22.TST:  测试(执行按位与操作,并且根据结果更新Z)

         (其本质就是AND指令,只是不写`回运算结果,只更新标志位)

23.TEQ:  测试是否相等(对两个数妨行异或,更新标志但不存储结果)

24.IF THEN 指令

例:CMP  RO,R1

ITTEE EQ :如果R0 == R1,Then-then-Else-Else

ADDEQ

ADDEQ

ADDNE

ADDNE

七:异常

    Cortex-M3在内核水平上搭载了一个异常响应系统,支持为数众多的系统异常和外部中断。其中编号1-15的对的应系统异常,大地等于16的则全是外部中断。

(细分中断和异常:240个外部中断对CM3核来说都是是“意外的突发事件”——也就是说,该诸求信号来自CM3内核的外面,来自各种外部片上外设和外扩的外设,对CM3来说是“异步”的,而异常则是因CM3内核的活动产生的——在执行指令或访问存储器时产生,因此对CM3来说是“同步”的)

当发生了异常并且要响应它时,CM3需要定位其服务例程的入口地址,这些入口地址存储在所谓的“异常向量表”中。

八:SVC和PendSV

SVC(系统服务调用)和PendSV(可挂起系统调用)多用在操作系统的软件开发中。SVC用于产生系统函数的调用请求,例如:操作系统通常不让用户程序直接访问硬件,而是通过提供一些系统服务函数,让用户程序使用SVC发出对系统服务函数的调用请求,以这种方式调用它们来直接访问硬件。因此,当用户程序想要控制特定硬件时,就要产生一个SVC异常,然后操作系统提供的SVC异常服务例程得到执行,它再调用相关的操作系统函数,后者完成用户程序请求的服务。

这种“提出要求——得到满足”的方式,很好,很强大,很方便,很灵活,很能可持续发展。首先,它使用户程序从控制硬件的繁文缛节中解脱出来,由OS负责控制具体的硬件。第二,OS的代码可以经过充分的测试,从而使系统更加健壮和可靠。第三,它使用户程序无需在特权级下执行,用户程序无需承担因误操作而瘫痪整个系统的风险。第四,通过SVC的机制,用户程序变得与硬件无关,因此在开发应用程序时无需了解硬件的操作细节,从而简化了开发的难度和繁琐度,并且使应用程序跨平台移植成为可能。

SVC异常通过执行SVC指令来产生。该指令需要一个立即数充当系统调用代号。SVC异常服务例程序稍后会提取出此代号,从而获知本次调用的具体要求,再调用相应的服务函数。

另一个相关的异常是PendSV,它和SVC协同使用。一方面,SVC异常是必须执行SVC指令后立即得到响应的,应用程序执行SVC时都是希望所需的请求立即得到响应是。另一方面,PendSV则不同,它可以像普通的中断一样被挂起,OS可以利用它“缓期执行”一个异常——直到其它重要的任务完成后才执行动作,挂起PendSV的方法是:手工往NVIC的PendSV挂起寄存器中写1,挂起后,如果优先级不够高,则将缓期执行。

(参见<CORTEX-M3权威指南>130页)

PendSV典型使用场合是在上下文切换时(在不同任务间切换)。例如:一个系统中有两个就绪任务,上下文切换被触发的场合可以是:

 执行一个系统调用

 系统滴答定时器中断(轮转调度中需要)

PendSV异常会自动延尺上下文切换的请求,直到其他的ISR都完成了处理后才放行。为了实现这个机制,需要把PendSV编程为最低优先级的异常。如果OS检测到某IRQ正在活动并且被SysTick抢占,它将挂起一个PendSV异常,以便缓期执行上下文切换。

(《Cortex-M3权威指南》第130-131页)

九:中断的具体行为

 当CM3开始响应一个中断时,在它小小的体内干了三件大事:

   入栈:把8个寄存器的值压入栈。

   取向量: 从向量表中找出对应的中断服务程序入口地址。

   选择堆栈指针MSP/PSP,更新堆栈指针SP,更新连接寄存器LR,更新程序计数器PC。

1.入栈

响应异常的第1个动作,就是自动保存现场的必要部分:依次把x PSR,PC,LR,R12以及R0-R3由硬件自动压入适当的栈中,如果响应异常时,当前的代码正在使用PSP,则压入PSP,也就是使用进程堆栈否则就压入MSP,使用主堆栈,一量进入服务例程,就将一直使用主堆栈。

CM3在看不见的内部打乱了入栈的顺序,这是有深层次的原因的。先把PC与XPSR的值保存,就可以更早地启动服务例程指令的预取——因为这需要修改PC;同时也做到了在早期就可以更新XPSR中IPSR位段的值。

为啥袒护R0-R3和R12呢? R4-R11就是下等公民?

在ARM上,有一套C函数调用标准约定(AAPCS),原因就在它上面,它使得中断服务例程序能用C语言来编写,编绎器首先使用了栈寄存器来保存中间结果(当然,如果程序过大也可能使用到R4-R11,此时编绎器负责生成代码来PUSH它们,但是ISR应短小精悍,不要让系统如此操心)。

2.取向量

   当数据总线(系统总线)正在为入栈操作而忙得风风火火时,指令总线(I-Code)可不是凉快地坐着看热闹——它正在为响应中断紧张有序地执行另一项重要的任务:从向量表中找出正确的异常向量,然后在服务程序的入口处预取指。由此看到各自都有专用总线的好处:入栈与取指这两个工作是同时进行的。

3.更新寄存器

  入栈和取向量操作完成后,在执行服务例程之前,还需要更新一系列的寄存器。

  需要更新的有:SP,PSR,PC,LR以及NVIC相关寄存器。

(详细参见《权威指南》147页)

4.异常返回

  异常返回包括以下两个动作:

 出栈:原先压入栈的数据出栈。

 更新NVIC寄存器:伴随着异常的返回,它的活动位也被硬件清除。

 

Cortex-M3真是好啊,越来越觉得它功能强大,使用灵活,理解其体系结构有助于在各场家芯片间应对自如,还有就是移植UCOS 时必须知道这些东西。


====

http://blog.csdn.net/fanwenjieok/article/details/6316058