本章首先介绍了Cortex-M0+处理器指令集,包括寄存器传输指令、存储器加载和保存指令、多数据加载和保存指令、堆栈访问指令、算术运算指令、逻辑操作指令、移位操作指令、反序操作指令、扩展操作指令、程序流控制指令、存储器屏障指令、异常相关指令、休眠相关指令和其他指令。在此基础上,本章介绍了STM32G0的向量表格式及堆和堆栈的配置方法。最后,本章通过使用汇编助记符指令实现了三个设计实例,包括冒泡排序算法实现、GPIO的驱动和控制,以及中断的控制和实现。
读者通过学习本章内容,不仅能够掌握Cortex-M0+处理器的指令集和使用方法,而且能够通过编写简单的汇编语言程序实现对处理器核、中断控制器和简单外设的读/写访问操作。
早期的Arm处理器使用32位指令集,称为Arm指令。这个指令集具有较高的运行性能,与8位和16位处理器相比,具有更大的程序存储空间。但是,这也带来了较大的功耗。
在1995年,16位的Thumb-1指令集首先应用于Arm7TDMI处理器,它是Arm指令集的子集。与32位的RISC结构相比,它提供了更好的代码密度,将代码长度减少了30%,但性能也降低了20%。通过使用多路复用器,它能够与Arm指令集一起使用。Thumb指令选择如图4.1所示。
图4.1 Thumb指令选择
Thumb指令流是一系列采用半字对齐的半字。每条Thumb指令要么是该流中的单个16位半字,要么是包含该流中两个连续半字的32位指令。
如果要解码的半字的位域[15:11]取0b11101、0b11110、0b11111中的任何值,则该半字是32位指令的第一个半字;否则,半字为16位指令。
Thumb-2指令集由32位的Thumb指令和最初的16位Thumb指令组成,与32位的Arm指令集相比,其代码长度减少了26%,但保持相似的运行性能。
Cortex-M0+采用了Armv6-M的结构,将电路规模降低到最小,它采用了16位Thumb-1的超集,以及32位Thumb-2的最小子集。
Cortex-M0+支持的16位Thumb指令如图4.2所示。
图4.2 Cortex-M0+支持的16位Thumb指令
Cortex-M0+支持的32位Thumb指令如图4.3所示。
图4.3 Cortex-M0+支持的32位Thumb指令
思考与练习4.1:请说明Thumb指令集的主要特点。
思考与练习4.2:请说明Thumb-1指令集和Thumb-2指令集的区别。
本节将介绍在KeilμVision中编写汇编语言程序的一些基本知识,帮助读者学习汇编语言助记符指令的书写规则。
汇编语言源代码可以包含数字、字符串、布尔值和单个字符文字。文字可以表示如下。
(1)十进制数,如123。
(2)十六进制数,如0x7B。
(3)二至九任何进制的数字。比如,5_204表示五进制数204,即
2×5 2 +0×5 1 +4×5 0 =54
等效于十进制数54。很明显,在采用五进制的数值表示中,有效的数字范围为0~4,这个规则适用于采用其他进制的数值表示,即在采用 n 进制的数值表示中,有效的数字范围为0~ n -1。
(4)浮点数,如123.4。
(5)布尔值{TRUE}或{FALSE}。
(6)单引号引起来的单个字符值,如'W'。
(7)双引号引起来的字符串,如"This is a string"。
注: 在大多数情况下,将包含单个字符的字符串看作单个字符值。例如,接受ADD r0,r1,#"a",但不接受ADD r0,r1,#"ab"。
此外,还可以使用变量和名字来表示文字。
汇编器对汇编语言进行解析并对汇编语言进行汇编以生成目标代码。Keil MDK汇编语言源代码行的格式如图4.4所示。Keil MDK汇编语言源文件中的每行代码都遵循下面的通用格式:
图4.4 Keil MDK汇编语言源代码行的格式
其中:
(1){}表示可选部分,也就是说,每行代码的三个用符号{}括起来的部分都是可选的。
(2)symbol通常是一个标号。在指令和伪指令中,它总是一个标号。在一些命令中,它是变量或常量的符号。
符号必须从第一列开始。除非用竖线(|)括起来,否则它不能包含空格或制表符之类的任何空格字符。
标号是地址的符号表示。可以使用标号来标记要从代码其他部分引用的特定地址。数字局部标签是标签的子类,标签的子类以0~99范围内的数字开头。与其他标号不同,数字局部标号可以多次定义。这使得它们在使用宏生成标号时非常有用。
(3)instruction(指令)|directive(命令)|pseudo-instruction(伪指令)
①命令用于指导汇编器和链接器对汇编语言程序的理解和处理,会影响汇编的过程或影响最终输出的镜像。命令并不能转换为机器指令(机器码)。
②指令是指机器指令(机器码),在汇编语言程序设计中使用汇编语言助记符指令来描述机器指令。本质上,汇编语言程序代码主要是由汇编语言助记符指令构成的。通过使用汇编器和链接器对汇编语言助记符指令进行汇编和连接,转换为可以在Cortex-M0+处理器上执行的机器指令,以实现和完成特定的任务。使用汇编器对图4.4给出的汇编源代码进行汇编后生成的机器指令序列如图4.5所示。
图4.5 使用汇编器对图4.4给出的汇编源代码进行汇编后的生成的机器指令序列
从图4.4和图4.5可知,一条汇编语言助记符指令由操作码和操作数构成。操作码说明指令要执行的操作类型,而操作数说明执行指令时,所需要操作对象的来源。操作数(操作对象)的来源可能是立即数、寄存器或存储器,这与每条指令的寻址方式有关。
(4)comment。注释是源代码行的最后一部分。每行的第一个分号标记注释的开头,除非分号出现在字符串文字内。该行的结尾是注释的结尾。在代码行中,允许仅存在注释。在对汇编源代码进行汇编时,汇编器将忽略所有注释。
注: (1)在KeilμVision软件开发工具中,输入指令助记符、伪指令、命令和符号寄存器名字时,要么全部使用大写字母,要么全部使用小写字母,不允许使用大小写混合的形式。标号和注释可以大写、小写或大小写混合。
(2)为了使汇编源代码更容易阅读,可以通过在每行默认放置反斜杠字符(\),将一行中很长的源代码分成几行。反斜杠后不能跟任何其他字符,包括空格和制表符。汇编器将反斜杠和后面跟随的行结束序列看作空白。此外,还可以使用空行使代码更具有可读性。
对于Cortex-M0+的一些汇编助记符指令,需要在其后面添加后缀,后缀及含义如表4.1所示。
表4.1 后缀及含义