初稿第2章Cortex-M3权威指南异常返回特权级handler模式复位触发异常触发异常特权级线程模式异常返回修改用户级线程模式CONTROL寄存器图2.5合法的操作模式转换图通过引入特权级和用户级,就能够在硬件水平上限制某些不受信任的或者还没有调试好的程序不让它们随便地配置涉及要害的寄存器,因而系统的可靠性得到了提高。进一步地,如果配了MPU,它还可以作为特权机制的补充一一保护关键的存储区域不被破坏,这些区域通常是操作系统的区域。举例来说,操作系统的内核通常都在特权级下执行,所有没有被MPU禁掉的存储器都可以访问。在操作系统开启了一个用户程序后,通常都会让它在用户级下执行,从而使系统不会因某个程序的崩溃或恶意破坏而受损。内建的嵌套向量中断控制器Cortex-M3在内核水平上搭载了一颗中断控制器一一嵌套向量中断控制器NVIC(NestedVectoredInterruptController)。它与内核有很深的“私交”一一与内核是紧耦合的。NVIC提供如下的功能:·可嵌套中断支持向量中断支持?动态优先级调整支持.中断延迟大大缩短.中断可屏蔽可嵌套中断支持可嵌套中断支持的作用范围很广,覆盖了所有的外部中断和绝大多数系统异常。外在表现是这些异常都可以被赋予不同的优先级。当前优先级被存储在xPSR的专用字段中。当一个异常发生时,硬件会自动比较该异常的优先级是否比当前的异常优先级更高。如果发现来了更高优先级的异常,处理器就会中断当前的中断服务例程(或者是普通程序),而服务新来的异常一一即立即抢占。向量中断支持当开始响应一个中断后,CM3会自动定位一张向量表,并且根据中断号从表中找出ISR的入口地址,然后跳转过去执行。不需要像以前的ARM那样,由软件来分辨到底是哪个中断发生了,也无需半导体厂商提供私有的中断控制器来完成这种工作。这么一来,中断延迟时间大为缩短。动态优先级调整支持29
Cortex‐M3 权威指南 初稿 第 2 章 图 2.5 合法的操作模式转换图 通过引入特权级和用户级,就能够在硬件水平上限制某些不受信任的或者还没有调试好的程序, 不让它们随便地配置涉及要害的寄存器,因而系统的可靠性得到了提高。进一步地,如果配了 MPU, 它还可以作为特权机制的补充——保护关键的存储区域不被破坏,这些区域通常是操作系统的区域。 举例来说,操作系统的内核通常都在特权级下执行,所有没有被 MPU 禁掉的存储器都可以访 问。在操作系统开启了一个用户程序后,通常都会让它在用户级下执行,从而使系统不会因某个程 序的崩溃或恶意破坏而受损。 内建的嵌套向量中断控制器 Cortex‐M3 在内核水平上搭载了一颗中断控制器——嵌套向量中断控制器 NVIC(Nested Vectored Interrupt Controller)。它与内核有很深的“私交”——与内核是紧耦合的。NVIC 提供如下的功能: z 可嵌套中断支持 z 向量中断支持 z 动态优先级调整支持 z 中断延迟大大缩短 z 中断可屏蔽 可嵌套中断支持 可嵌套中断支持的作用范围很广,覆盖了所有的外部中断和绝大多数系统异常。外在表现是, 这些异常都可以被赋予不同的优先级。当前优先级被存储在 xPSR 的专用字段中。当一个异常发生 时,硬件会自动比较该异常的优先级是否比当前的异常优先级更高。如果发现来了更高优先级的异 常,处理器就会中断当前的中断服务例程(或者是普通程序),而服务新来的异常——即立即抢占。 向量中断支持 当开始响应一个中断后,CM3 会自动定位一张向量表,并且根据中断号从表中找出 ISR 的入口 地址,然后跳转过去执行。不需要像以前的 ARM 那样,由软件来分辨到底是哪个中断发生了,也无 需半导体厂商提供私有的中断控制器来完成这种工作。这么一来,中断延迟时间大为缩短。 动态优先级调整支持 29
初稿第2章Cortex-M3权威指南软件可以在运行时期更改中断的优先级。如果在某ISR中修改了自己所对应中断的优先级,而且这个中断又有新的实例处于悬起中(pending),也不会自己打断自己,从而没有重入(reentry)【译71风险。【译注7]:所谓的重入,就是指某段子程序还没有执行完,就因为中断或者是多任务操作系统的调度原因,导致该子程序在一个新的寄存器上下文中被执行(请不要把重入与递归混淆,它们有本质的区别)。这种情况常常会闹出乱子,因此有“可重入性”的研究。中断延迟大大缩短Cortex-M3为了缩短中断延迟,引入了好几个新特性。包括自动的现场保护和恢复,以及其它的措施,用于缩短中断嵌套时的ISR间延退。详情请见后面关于“咬尾中断”和“晚到中断”的讲述。中断可屏蔽既可以屏蔽优先级低于某个阈值的中断/异常[译注81(设置BASEPRI寄存器),也可以全体封杀设置PRIMASK和FAULTMASK寄存器)。这是为了让时间关键(time-critical)的任务能在死线(deadline,或日最后期限)到来前完成,而不被干扰。【译注8]:鉴于(外部)中断的常见性,以后译文中如果没有特殊说明,凡是提到“异常”,均指除了外部中断之外的异常,而使用“中断”来表示所有外部中断一一也就是对于处理器来说是异步的中断。存储器映射总体来说,Cortex-M3支持4GB存储空间,如图2.6所示地被划分成若干区域。30
Cortex‐M3 权威指南 初稿 第 2 章 软件可以在运行时期更改中断的优先级。如果在某 ISR 中修改了自己所对应中断的优先级,而 且这个中断又有新的实例处于悬起中(pending),也不会自己打断自己,从而没有重入(reentry)[译注 7] 风险。 [译注 7]:所谓的重入,就是指某段子程序还没有执行完,就因为中断或者是多任务操作系统的调度原因,导致该 子程序在一个新的寄存器上下文中被执行(请不要把重入与递归混淆,它们有本质的区别)。这种情况常常会闹出乱 子,因此有“可重入性”的研究。 中断延迟大大缩短 Cortex‐M3 为了缩短中断延迟,引入了好几个新特性。包括自动的现场保护和恢复,以及其它 的措施,用于缩短中断嵌套时的 ISR 间延迟。详情请见后面关于“咬尾中断”和“晚到中断”的讲 述。 中断可屏蔽 既可以屏蔽优先级低于某个阈值的中断/异常[译注 8](设置 BASEPRI 寄存器),也可以全体封杀(设 置 PRIMASK 和 FAULTMASK 寄存器)。这是为了让时间关键(time‐critical)的任务能在死线(deadline, 或曰最后期限)到来前完成,而不被干扰。 [译注 8]:鉴于(外部)中断的常见性,以后译文中如果没有特殊说明,凡是提到“异常”,均指除了外部中断之 外的异常,而使用“中断”来表示所有外部中断——也就是对于处理器来说是异步的中断。 存储器映射 总体来说,Cortex‐M3 支持 4GB 存储空间,如图 2.6 所示地被划分成若干区域。 30
初稿第2章Cortex-M3权威指南OXFFFFFFFF服务于CM3的私房外设包括NVIC寄存器,MPU寄512SystemLevel存器以及片上调试组件MBOxE0000000OXDFFFFFFF主要用于扩展片外的外设1GBExternalDevice(像8051配8255似的)0xA0000000Ox9FFFFFFF用于扩展外部存储器1GBExternalRAM0x60000000Ox5FFFFFFF512MBPeripherals用于片上外设0x40000000Ox3FFFFFFF512MBSRAM用于片上静态RAM0x20000000代码区。也可用于存储启动Ox1FFFFFFF512MBCode后缺省的中断向量表0x00000000从图中可见,不像其它的ARM架构,它们的存储器映射由半导体厂家说了算,Cortex-M3预先定义好了“粗线条的”存储器映射。通过把片上外设的寄存器映射到外设区,就可以简单地以访问内存的方式来访问这些外设的寄存器,从而控制外设的工作。结果,片上外设可以使用C语言来操作。这种预定义的映射关系,也使得对访问速度可以做高度的优化,而且对于片上系统的设计而言更易集成(还有一个重要的,不用每学一种不同的单片机就要熟悉一种新的存储器映射一一译注)。Cortex-M3的内部拥有一个总线基础设施,专用于优化对这种存储器结构的使用。在此之上,CM3甚至还允许这些区域之间“越权使用”。比如说,数据存储器也可以被放到代码区,而且代码也能够在外部RAM区中执行(但是会变慢不少一一译注)。处于最高地址的系统级存储区,是CM3用于藏“私房钱”的一一包括中断控制器、MPU以及各种调试组件。所有这些设备均使用固定的地址(本书第5章讨论存储器系统)。通过把基础设施的地址定死,就至少在内核水平上,为应用程序的移植扫清了障碍。总线接口Cortex-M3内部有若干个总线接口,以使CM3能同时取址和访内(访问内存),它们是:指令存储区总线(两条)·系统总线·私有外设总线有两条代码存储区总线负责对代码存储区的访问,分别是I-Code总线和D-Code总线。前者用于取指,后者用于查表等操作,它们按最佳执行速度进行优化。系统总线用于访问内存和外设,覆盖的区域包括SRAM,片上外设,片外RAM,片外扩展设备,以及系统级存储区的部分空间。31
Cortex‐M3 权威指南 初稿 第 2 章 从图中可见,不像其它的 ARM 架构,它们的存储器映射由半导体厂家说了算,Cortex‐M3 预先 定义好了“粗线条的”存储器映射。通过把片上外设的寄存器映射到外设区,就可以简单地以访问 内存的方式来访问这些外设的寄存器,从而控制外设的工作。结果,片上外设可以使用 C 语言来操 作。这种预定义的映射关系,也使得对访问速度可以做高度的优化,而且对于片上系统的设计而言 更易集成(还有一个重要的,不用每学一种不同的单片机就要熟悉一种新的存储器映射——译注)。 Cortex‐M3 的内部拥有一个总线基础设施,专用于优化对这种存储器结构的使用。在此之上, CM3 甚至还允许这些区域之间“越权使用”。比如说,数据存储器也可以被放到代码区,而且代码 也能够在外部 RAM 区中执行(但是会变慢不少——译注)。 处于最高地址的系统级存储区,是 CM3 用于藏“私房钱”的——包括中断控制器、MPU 以及 各种调试组件。所有这些设备均使用固定的地址(本书第 5 章讨论存储器系统)。通过把基础设施 的地址定死,就至少在内核水平上,为应用程序的移植扫清了障碍。 总线接口 Cortex‐M3 内部有若干个总线接口,以使 CM3 能同时取址和访内(访问内存),它们是: z 指令存储区总线(两条) z 系统总线 z 私有外设总线 有两条代码存储区总线负责对代码存储区的访问,分别是 I‐Code 总线和 D‐Code 总线。前者用 于取指,后者用于查表等操作,它们按最佳执行速度进行优化。 系统总线用于访问内存和外设,覆盖的区域包括 SRAM,片上外设,片外 RAM,片外扩展设备, 以及系统级存储区的部分空间。 31
初稿第2章Cortex-M3权威指南私有外设总线负责一部分私有外设的访问,主要就是访问调试组件。它们也在系统级存储区。存储器保护单元(MPU)Cortex-M3有一个可选的存储器保护单元。配上它之后,就可以对特权级访问和用户级访问分别施加不同的访问限制。当检测到犯规(violated)时,MPU就会产生一个fault异常,可以由fault异常的服务例程来分析该错误,并且在可能时改正它。MPU有很多玩法。最常见的就是由操作系统使用MPU,以使特权级代码的数据,包括操作系统本身的数据不被其它用户程序弄坏。MPU在保护内存时是按区管理的(“区”的原文是region,以后不再中译此名词一一译注)。它可以把某些内存region设置成只读,从而避免了那里的内容意外被更改;还可以在多任务系统中把不同任务之间的数据区隔离。一句话,它会使嵌入式系统变得更加健壮,更加可靠(很多行业标准,尤其是航空的,就规定了必须使用MPU来行使保护职能一一译注)。指令集Cortex-M3只使用Thumb-2指令集。这是个了不起的突破,因为它允许32位指令和16位指令水乳交融,代码密度与处理性能两手抓,两手都硬。而且虽然它很强大,却依然易于使用。在过去,做ARM开发必须处理好两个状态。这两个状态是井水不犯河水的,它们是:32位的ARM状态和16位的Thumb状态。当处理器在ARM状态下时,所有的指令均是32位的(哪怕只是个"NOp"指令),此时性能相当高。而在Thumb状态下,所有的指令均是16位的,代码密度提高了一倍。不过,thumb状态下的指令功能只是ARM下的一个子集,结果可能需要更多条的指令去完成相同的工作,导致处理性能下降。为了取长补短,很多应用程序都混合使用ARM和Thumb代码段。然而,这种混合使用是有额外开销(overhead)的,时间上的和空间上的都有,主要发生在状态切换之时。另一方面,ARM代码和Thumb代码需要以不同的方式编译,这也增加了软件开发管理的复杂度。时间上的额外开销返回ARM状态(e.g.,BX LR)(32位代码)情急之际的代码在ARM态下执行Thumb状态连接跳转井主程序代码主程序代码(16位代码)一切换状态的指令在Thumb下执行在Thumb下执行如BLXTime图2.7在诸如ARM7处理器上的状态切换模式图伴随着Thumb-2指令集的横空出世,终于可以在单一的操作模式下搞定所有处理了,再也没有来回切换的事来烦你了。事实上,Cortex-M3内核干脆都不支持ARM指令,中断也在Thumb态下处理(以前的ARM总是在ARM状态下处理所有的中断和异常)。这可不是小便宜,它使CM3在好几个方面都比传统的ARM处理器更先进:消灭了状态切换的额外开销,节省了both执行时间和指令空间。?不再需要把源代码文件分成按ARM编译的和按Thumb编译的,软件开发的管理大大减负。?无需再反复地求证和测试:究竞该在何时何地切换到何种状态下,我的程序才最有效率。开发32
Cortex‐M3 权威指南 初稿 第 2 章 私有外设总线负责一部分私有外设的访问,主要就是访问调试组件。它们也在系统级存储区。 存储器保护单元(MPU) Cortex‐M3 有一个可选的存储器保护单元。配上它之后,就可以对特权级访问和用户级访问分 别施加不同的访问限制。当检测到犯规(violated)时,MPU 就会产生一个 fault 异常,可以由 fault 异常的服务例程来分析该错误,并且在可能时改正它。 MPU 有很多玩法。最常见的就是由操作系统使用 MPU,以使特权级代码的数据,包括操作系 统本身的数据不被其它用户程序弄坏。MPU 在保护内存时是按区管理的(“区”的原文是 region,以 后不再中译此名词——译注)。它可以把某些内存 region 设置成只读,从而避免了那里的内容意外被 更改;还可以在多任务系统中把不同任务之间的数据区隔离。一句话,它会使嵌入式系统变得更加 健壮,更加可靠(很多行业标准,尤其是航空的,就规定了必须使用 MPU 来行使保护职能——译 注)。 指令集 Cortex‐M3 只使用 Thumb‐2 指令集。这是个了不起的突破,因为它允许 32 位指令和 16 位指令 水乳交融,代码密度与处理性能两手抓,两手都硬。而且虽然它很强大,却依然易于使用。 在过去,做 ARM 开发必须处理好两个状态。这两个状态是井水不犯河水的,它们是:32 位的 ARM 状态和 16 位的 Thumb 状态。当处理器在 ARM 状态下时,所有的指令均是 32 位的(哪怕只是 个”NOP”指令),此时性能相当高。而在 Thumb 状态下,所有的指令均是 16 位的,代码密度提高了 一倍。不过,thumb 状态下的指令功能只是 ARM 下的一个子集,结果可能需要更多条的指令去完成 相同的工作,导致处理性能下降。 为了取长补短,很多应用程序都混合使用 ARM 和 Thumb 代码段。然而,这种混合使用是有额 外开销(overhead)的,时间上的和空间上的都有,主要发生在状态切换之时。另一方面,ARM 代 码和 Thumb 代码需要以不同的方式编译,这也增加了软件开发管理的复杂度。 图 2.7 在诸如 ARM7 处理器上的状态切换模式图 伴随着 Thumb‐2 指令集的横空出世,终于可以在单一的操作模式下搞定所有处理了,再也没有 来回切换的事来烦你了。事实上,Cortex‐M3 内核干脆都不支持 ARM 指令,中断也在 Thumb 态下处 理(以前的 ARM 总是在 ARM 状态下处理所有的中断和异常)。这可不是小便宜,它使 CM3 在好几 个方面都比传统的 ARM 处理器更先进: z 消灭了状态切换的额外开销,节省了 both 执行时间和指令空间。 z 不再需要把源代码文件分成按 ARM 编译的和按 Thumb 编译的,软件开发的管理大大减负。 z 无需再反复地求证和测试:究竟该在何时何地切换到何种状态下,我的程序才最有效率。开发 32
初稿第2章Cortex-M3权威指南软件容易多了。不少有趣和强大的指令为Cortex-M3注入了新鲜的青春血液,下面给出几个例子:位段提取,位段插入,位段清零。支持C位段,也简化了外设寄存器操作。UBFX,BFI,BFC:CLZ, RBIT:计算前导零指令和位反转指令。二者组合使用能实现一些特技0.UDIV,SDIV:无符号除法和带符号除法指令。SEV,WFE,WFI:发送事件,等待事件以及等待中断指令。用于实现多处理器之间的任务同步,?还可以进入不同的休眠模式。MSR,MRS:通向禁地一一访问特殊功能寄存器。因为CM3专情于最新的Thumb-2,旧的应用程序需要移植和重建。对于大多数C源程序,只需简单地重新编译就能重建,汇编代码则可能需要大面积地修改和重写,才能使用CM3的新功能,并且融入cM3新引入的统一汇编器框架(unifiedassemblerframework)中。请注意:CM3并不支持所有的Thumb-2指令,ARMv7-M的规格书只要求实现Thumb-2的一个子集。举例来说,协处理器指令就被裁掉了(可以使用外部的数据处理引擎来替代)。CM3也没有实现SIMD指令集。旧世代的一些Thumb指令不再需要,因此也被排除。不支持指令还包括v6中引入的SETEND指令。如欲查出一个完整的指令列表,可以去看附录A。中断和异常ARMv7-M开创了一个全新的异常模型,CM3采用了它。请你一定要划清界线:这种异常模型跟传统ARM处理器使用的完全是两码事。新的异常模型“使能”了非常高效的异常处理。它支持16-4-1=11种系统异常(保留了4+1个档位),外加240个外部中断输入。在CM3中取消了FIQ的概念(v7前的ARM都有这个FIQ,快中断请求),这是因为有了更新更好的机制一一中断优先级管理以及嵌套中断支持,它们被纳入CM3的中断管理逻辑中。因此,支持嵌套中断的系统就更容易实现FIQ。CM3的所有中断机制都由NVIC实现。除了支持240条中断之外,NVIC还支持16-4-1=11个内部异常源,可以实现fault管理机制。结果,CM3就有了256个预定义的异常类型,如表2.2所示。表 2.2 Cortex-M3异常类型编号类型优先级简介0N/AN/A没有异常在运行1复位-3(最高)复位2-2NMI不可屏蔽中断(来自外部NMI输入脚)3-1硬(hard)fault所有被除能的fault,都将“上访”成硬fault4MemManage可编程存储器管理fault,MPU访问犯规以及访问非法位置fault5可编程总线fault总线错误(预取流产(Abort)或数据流产)6可编程用法(usage)由于程序错误导致的异常Fault7-10N/AN/A保留11SVCall可编程系统服务调用12可编程调试监视器调试监视器(断点,数据观察点,或者是外部调试请求13N/A保留N/A14Pendsv可编程为系统设备而设的“可悬挂请求”(pendablerequest)15SysTick可编程系统滴答定时器(也就是周期性溢出的时基定时器一译注)33
Cortex‐M3 权威指南 初稿 第 2 章 软件容易多了。 不少有趣和强大的指令为 Cortex‐M3 注入了新鲜的青春血液,下面给出几个例子: z UBFX,BFI,BFC:位段提取,位段插入,位段清零。支持 C 位段,也简化了外设寄存器操作。 z CLZ,RBIT: 计算前导零指令和位反转指令。二者组合使用能实现一些特技 z UDIV,SDIV: 无符号除法和带符号除法指令。 z SEV,WFE,WFI:发送事件,等待事件以及等待中断指令。用于实现多处理器之间的任务同步, 还可以进入不同的休眠模式。 z MSR,MRS: 通向禁地——访问特殊功能寄存器。 因为 CM3 专情于最新的 Thumb‐2,旧的应用程序需要移植和重建。对于大多数 C 源程序,只需 简单地重新编译就能重建,汇编代码则可能需要大面积地修改和重写,才能使用 CM3 的新功能,并 且融入 CM3 新引入的统一汇编器框架(unified assembler framework)中。 请注意:CM3 并不支持所有的 Thumb‐2 指令,ARMv7‐M 的规格书只要求实现 Thumb‐2 的一个 子集。举例来说,协处理器指令就被裁掉了(可以使用外部的数据处理引擎来替代)。CM3 也没有 实现 SIMD 指令集。旧世代的一些 Thumb 指令不再需要,因此也被排除。不支持指令还包括 v6 中 引入的 SETEND 指令。如欲查出一个完整的指令列表,可以去看附录 A。 中断和异常 ARMv7‐M 开创了一个全新的异常模型,CM3 采用了它。请你一定要划清界线:这种异常模型 跟传统 ARM 处理器使用的完全是两码事。新的异常模型“使能”了非常高效的异常处理。它支持 16‐4‐1=11 种系统异常(保留了 4+1 个档位),外加 240 个外部中断输入。在 CM3 中取消了 FIQ 的概 念(v7 前的 ARM 都有这个 FIQ,快中断请求),这是因为有了更新更好的机制——中断优先级管理 以及嵌套中断支持,它们被纳入 CM3 的中断管理逻辑中。因此,支持嵌套中断的系统就更容易实现 FIQ。 CM3 的所有中断机制都由 NVIC 实现。除了支持 240 条中断之外,NVIC 还支持 16‐4‐1=11 个内 部异常源,可以实现 fault 管理机制。结果,CM3 就有了 256 个预定义的异常类型,如表 2.2 所示。 表 2.2 Cortex‐M3 异常类型 编号 类型 优先级 简介 0 N/A N/A 没有异常在运行 1 复位 -3(最高) 复位 2 NMI -2 不可屏蔽中断(来自外部 NMI 输入脚) 3 硬(hard) fault -1 所有被除能的 fault,都将“上访”成硬 fault 4 MemManage fault 可编程 存储器管理 fault,MPU 访问犯规以及访问非法位置 5 总线 fault 可编程 总线错误(预取流产(Abort)或数据流产) 6 用法(usage) Fault 可编程 由于程序错误导致的异常 7-10 保留 N/A N/A 11 SVCall 可编程 系统服务调用 12 调试监视器 可编程 调试监视器(断点,数据观察点,或者是外部调试请求 13 保留 N/A N/A 14 PendSV 可编程 为系统设备而设的“可悬挂请求”(pendable request) 15 SysTick 可编程 系统滴答定时器(也就是周期性溢出的时基定时器——译注) 33