您好,欢迎访问三七文档
当前位置:首页 > 机械/制造/汽车 > 综合/其它 > Cortex M3基础
CortexM3基础•寄存器组•特殊功能寄存器组•操作模式•异常和中断•向量表•存储器保护单元•堆栈区的操作•复位序列提纲一.寄存器组CM3拥有通用寄存器R0‐R15以及一些特殊功能寄存器。R0‐R12是最“通用目的”的,但是绝大多数的16位指令只能使用R0‐R7(低组寄存器),而32位的Thumb‐2指令则可以访问所有通用寄存器。特殊功能寄存器有预定义的功能,而且必须通过专用的指令来访问。1.通用目的寄存器R0-R7R0‐R7也被称为低组寄存器。所有指令都能访问它们。它们的字长全是32位,复位后的初始值是不可预料的。2.通用目的寄存器R8-R12R8‐R12也被称为高组寄存器。这是因为只有很少的16位Thumb指令能访问它们,32位的指令则不受限制。它们也是32位字长,且复位后的初始值是不可预料的。3.堆栈指针R13R13是堆栈指针。在CM3处理器内核中共有两个堆栈指针,于是也就支持两个堆栈。当引用R13(或写作SP)时,你引用到的是当前正在使用的那一个,另一个必须用特殊的指令来访问(MRS,MSR指令)。这两个堆栈指针分别是:•主堆栈指针(MSP),或写作SP_main。这是缺省的堆栈指针,它由OS内核、异常服务例程以及所有需要特权访问的应用程序代码来使用。•进程堆栈指针(PSP),或写作SP_process。用于常规的应用程序代码(不处于异常服用例程中时)。要注意的是,并不是每个应用都必须用齐两个堆栈指针。简单的应用程序只使用MSP就够了。堆栈指针用于访问堆栈,并且PUSH指令和POP指令默认使用SP。在Cortex‐M3中,有专门的指令负责堆栈操作——PUSH和POP。它俩的汇编语言语法如下例所演示PUSH{R0};*(--R13)=R0。R13是long*的指针POP{R0};R0=*R13++请注意后面C程序风格的注释,ortex‐M3中的堆栈以这种方式来使用的,这就是所谓的“向下生长的满栈”(本章后面在讲到堆栈内存操作时还要展开论述)。因此,在PUSH新数据时,堆栈指针先减一个单元。通常在进入一个子程序后,第一件事就是把寄存器的值先PUSH入堆栈中,在子程序退出前再POP曾经PUSH的那些寄存器。另外,PUSH和POP还能一次操作多个寄存器,如下所示:subroutine_1PUSH{R0-R7,R12,R14};保存寄存器列表…;执行处理POP{R0-R7,R12,R14};恢复寄存器列表BXR14;返回到主调函数在程序中为了突出重点,你可以使用SP表示R13。在程序代码中,bothMSP和PSP都被称为R13/SP。不过,我们可以通过MRS/MSR指令来指名道姓地访问具体的堆栈指针。MSP,亦写作SP_main,这是复位后缺省使用堆栈指针,服务于操作系统内核和异常服务例程;而PSP,亦写作SP_process,典型地用于普通的用户线程中。寄存器的PUSH和POP操作永远都是4字节对齐的——也就是说他们的地址必须是0x4,0x8,0xc,……。这样一来,R13的最低两位被硬线连接到0,并且总是读出0(ReadAsZero)。4.连接寄存器R14R14是连接寄存器(LR)。在一个汇编程序中,你可以把它写作bothLR和R14。LR用于在调用子程序时存储返回地址。例如,当你在使用BL(分支并连接,BranchandLink)指令时,就自动填充LR的值。main;主程序…BLfunction1;使用“分支并连接”指令呼叫function1;PC=function1,并且LR=main的下一条指令地址…Function1…;function1的代码BXLR;函数返回(如果function1要使用LR,必须在使用前PUSH,否则返回时程序就可能跑飞了——译注)尽管PC的LSB总是0(因为代码至少是字对齐的),LR的LSB却是可读可写的。这是历史遗留的产物。在以前,由位0来指示ARM/Thumb状态。因为其它有些ARM处理器支持ARM和Thumb状态并存,为了方便汇编程序移植,CM3需要允许LSB可读可写。5.程序计数器R15R15是程序计数器,在汇编代码中你也可以使用名字“PC”来访问它。因为CM3内部使用了指令流水线,读PC时返回的值是当前指令的地址+4。比如说:0x1000:MOVR0,PC;R0=0x1004如果向PC中写数据,就会引起一次程序的分支(但是不更新LR寄存器)。CM3中的指令至少是半字对齐的,所以PC的LSB总是读回0。然而,在分支时,无论是直接写PC的值还是使用分支指令,都必须保证加载到PC的数值是奇数(即LSB=1),用以表明这是在Thumb状态下执行。倘若写了0,则视为企图转入ARM模式,CM3将产生一个fault异常。二、特殊功能寄存器组Cortex‐M3中的特殊功能寄存器包括:程序状态寄存器组(PSRs或曰xPSR)中断屏蔽寄存器组(PRIMASK,FAULTMASK,以及BASEPRI)控制寄存器(CONTROL)它们只能被专用的MSR和MRS指令访问,而且它们也没有存储器地址。MRSgp_reg,special_reg;读特殊功能寄存器的值到通用寄存器MSRspecial_reg,gp_reg;写通用寄存器的值到特殊功能寄存器1.程序状态寄存器(PSRs或PSR)程序状态寄存器在其内部又被分为三个子状态寄存器:•应用程序PSR(APSR)•中断号PSR(IPSR)•执行PSR(EPSR)通过MRS/MSR指令,这3个PSRs即可以单独访问,也可以组合访问(2个组合,3个组合都可以)。当使用三合一的方式访问时,应使用名字“xPSR”或者“PSR”。2.PRIMASK,FAULTMASK和BASEPRI这三个寄存器用于控制异常的使能和除能。名字功能描述PRIMASK这是个只有1个位的寄存器。当它置1时,就关掉所有可屏蔽的异常,只剩下NMI和硬fault可以响应。它的缺省值是0,表示没有关中断。FAULTMASK这是个只有1个位的寄存器。当它置1时,只有NMI才能响应,所有其它的异常,包括中断和fault,通通闭嘴。它的缺省值也是0,表示没有关异常。BASEPRI这个寄存器最多有9位(由表达优先级的位数决定)。它定义了被屏蔽优先级的阈值。当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设成0,则不关闭任何中断,0也是缺省值。对于时间‐关键任务而言,PRIMASK和BASEPRI对于暂时关闭中断是非常重要的。而FAULTMASK则可以被OS用于暂时关闭fault处理机能,这种处理在某个任务崩溃时可能需要。因为在任务崩溃时,常常伴随着一大堆faults。在系统料理“后事”时,通常不再需要响应这些fault——人死帐清。总之FAULTMASK就是专门留给OS用的。要访问PRIMASK,FAULTMASK以及BASEPRI,同样要使用MRS/MSR指令,如:MRSR0,BASEPRI;读取BASEPRI到R0中MRSR0,FAULTMASK;似上MRSR0,PRIMASK;似上MSRBASEPRI,R0;写入R0到BASEPRI中MSRFAULTMASK,R0;似上MSRPRIMASK,R0;似上只有在特权级下,才允许访问这3个寄存器。其实,为了快速地开关中断,CM3还专门设置了一条CPS指令,有4种用法CPSIDI;PRIMASK=1,;关中断CPSIEI;PRIMASK=0,;开中断CPSIDF;FAULTMASK=1,;关异常CPSIEF;FAULTMASK=0;开异常3.控制寄存器(CONTROL)控制寄存器用于定义特权级别,还用于选择当前使用哪个堆栈指针。位功能CONTROL[1]堆栈指针选择0=选择主堆栈指针MSP(复位后缺省值)1=选择进程堆栈指针PSP在线程或基础级(没有在响应异常——译注),可以使用PSP。在handler模式下,只允许使用MSP,所以此时不得往该位写1。CONTROL[0]0=特权级的线程模式1=用户级的线程模式Handler模式永远都是特权级的。CONTROL[1]在Cortex‐M3的handler模式中,CONTROL[1]总是0。在线程模式中则可以为0或1。仅当处于特权级的线程模式下,此位才可写,其它场合下禁止写此位。改变处理器的模式也有其它的方式:在异常返回时,通过修改LR的位2,也能实现模式切换。这将在第5章中展开论述。CONTROL[0]仅当在特权级下操作时才允许写该位。一旦进入了用户级,唯一返回特权级的途径,就是触发一个(软)中断,再由服务例程改写该位。CONTROL寄存器也是通过MRS和MSR指令来操作的:MRSR0,CONTROLMSRCONTROL,R0三、操作模式Cortex‐M3支持2个模式和两个特权等级。当处理器处在线程状态下时,既可以使用特权级,也可以使用用户级;另一方面,handler模式总是特权级的。在复位后,处理器进入线程模式+特权级。在线程模式+用户级下,对系统控制空间(SCS)的访问将被阻止——该空间包含了配置寄存器s以及调试组件的寄存器s。除此之外,还禁止使用MSR访问刚才讲到的特殊功能寄存器——除了APSR有例外。谁若是以身试法,则将fault伺候。在特权级下的代码可以通过置位CONTROL[0]来进入用户级。而不管是任何原因产生了任何异常,处理器都将以特权级来运行其服务例程,异常返回后将回到产生异常之前的特权级。用户级下的代码不能再试图修改CONTROL[0]来回到特权级。它必须通过一个异常handler,由那个异常handler来修改CONTROL[0],才能在返回到线程模式后拿到特权级。把代码按特权级和用户极分开对待,有利于使架构更加安全和健壮。例如,当某个用户代码出问题时,不会让它成为害群之马,因为用户级的代码是禁止写特殊功能寄存器和NVIC中寄存器的。另外,如果还配有MPU,保护力度就更大,甚至可以阻止用户代码访问不属于它的内存区域。为了避免系统堆栈因应用程序的错误使用而毁坏,你可以给应用程序专门配一个堆栈,不让它共享操作系统内核的堆栈。在这个管理制度下,运行在线程模式的用户代码使用PSP,而异常服务例程则使用MSP。这两个堆栈指针的切换是全自动的,就在出入异常服务例程时由硬件处理。第8章将详细讨论此主题。如前所述,特权等级和堆栈指针的选择均由CONTROL负责。当CONTROL[0]=0时,在异常处理的始末,只发生了处理器模式的转换,如下图所示。但若CONTROL[0]=1(线程模式+用户级),则在中断响应的始末,both处理器模式和特权等极都要发生变化,如下图所示。CONTROL[0]只有在特权级下才能访问。用户级的程序如想进入特权级,通常都是使用一条“系统服务呼叫指令(SVC)”来触发“SVC异常”,该异常的服务例程可以选择修改CONTROL[0]。四、异常与中断Cortex‐M3支持大量异常,包括16‐4‐1=11个系统异常,和最多240个外部中断——简称IRQ。具体使用了这240个中断源中的多少个,则由芯片制造商决定。由外设产生的中断信号,除了SysTick的之外,全都连接到NVIC的中断输入信号线。典型情况下,处理器一般支持16到32个中断,当然也有在此之外的。作为中断功能的强化,NVIC还有一条NMI输入信号线。NMI究竟被拿去做什么,还要视处理器的设计而定。在多数情况下,NMI会被连接到一个看门狗定时器,有时也会是电压监视功能块,以便在电压掉至危险级别后警告处理器。NMI可以在任何时间被激活,甚至是在处理器刚刚复位之后。下表列出了Cortex‐M3可以支持的所有异常。有一定数量的系统异常是用于fault处理的,它们可以由多种错误条件引发。NVIC还提供了一些fault状态寄存器,以便于fault服务例程找出导致异常的具体原因。五、向量表当一个发生的异常被CM3内核接受,对应的异常handler就会执行。为了决定handler的入口地址,CM3使用了“向量表查
本文标题:Cortex M3基础
链接地址:https://www.777doc.com/doc-3649119 .html