指令集的设计是处理器架构中最重要的部分之一,在
A
R
M
ARM
ARM的术语之中,称呼为
I
n
s
t
r
u
c
t
i
o
n
S
e
t
A
r
c
h
i
t
e
c
t
u
r
e
,
I
S
A
Instruction\quad Set\quad Architecture,ISA
InstructionSetArchitecture,ISA,所有的
A
R
M
ARM
ARM的
C
O
R
T
E
X
−
M
CORTEX-M
CORTEX−M处理器都是基于
T
h
u
m
b
−
2
Thumb-2
Thumb−2技术,这种技术允许16位和32位的指令在
o
n
e
o
p
e
r
a
t
i
n
g
s
t
a
t
e
one\quad operating\quad state
oneoperatingstate里面混合使用,这和经典的
A
R
M
ARM
ARM处理器,例如
A
R
M
7
T
D
M
I
ARM7TDMI
ARM7TDMI是不同的。早期的
A
R
M
ARM
ARM处理器,
A
R
M
7
T
D
M
I
ARM7TDMI
ARM7TDMI之前的处理器,支持一个叫做
A
R
M
ARM
ARM指令集的32位指令集,经过一些年的发展,它从
A
R
M
ARM
ARM架构1发展到了
A
R
M
ARM
ARM架构4。这个32位指令集支持大部分指令的条件执行并且性能也不错,但是和8比特和16比特的架构相比,它需要更多的存储空间。
在1995年,
A
R
M
ARM
ARM推出了
A
R
M
7
T
D
M
I
ARM7TDMI
ARM7TDMI处理器,这个处理器支持一种新的操作状态,
o
n
e
o
p
e
r
a
t
i
n
g
s
t
a
t
e
one\quad operating\quad state
oneoperatingstate,运行一种新的16位指令集,这种新的16位指令集叫做
T
h
u
m
b
Thumb
Thumb。
A
R
M
7
T
D
M
I
ARM7TDMI
ARM7TDMI处理器可以操作在
A
R
M
ARM
ARM状态,默认状态,也可以操作在
T
h
u
m
b
Thumb
Thumb状态。在操作期间处理器在软件的控制下,在这两种状态之间进行切换。应用程序的一部分用
A
R
M
ARM
ARM指令来进行编译以求获得更高的性能,剩下的部分用
T
h
u
m
b
Thumb
Thumb指令来进行编译以求获得更高的代码紧凑性。有了这两种状态机制,编译后程序代码大小在降低的情况下同时也保持了较高的性能。
即使是这样
T
h
u
m
b
Thumb
Thumb指令集还是有一定的局限性,因此在2003年
A
R
M
ARM
ARM推出了
T
h
u
m
b
−
2
Thumb-2
Thumb−2技术,这种技术在一种操作状态,
o
n
e
o
p
e
r
a
t
i
n
g
s
t
a
t
e
one\quad operating\quad state
oneoperatingstate,中结合了16位和32位指令集。在
T
h
u
m
b
−
2
Thumb-2
Thumb−2技术中的指令集可以说是
T
h
u
m
b
Thumb
Thumb指令集的一个超集,它们中的很多指令都是32位的,因此可以处理以前仅仅在32位的
A
R
M
ARM
ARM指令集中可以处理的操作,但是这些32位的指令和32位的
A
R
M
ARM
ARM指令集中的指令的编码是不同的。在2006年,
A
R
M
ARM
ARM推出了
C
O
R
T
E
X
−
M
3
CORTEX-M3
CORTEX−M3处理器,它使用了
T
h
u
m
b
−
2
Thumb-2
Thumb−2技术,仅仅支持
T
h
u
m
b
Thumb
Thumb操作状态,不像早期的处理器,它不支持
A
R
M
ARM
ARM指令集。因为
C
O
R
T
E
X
−
M
CORTEX-M
CORTEX−M处理器不支持
A
R
M
ARM
ARM指令集,因此
C
O
R
T
E
X
−
M
CORTEX-M
CORTEX−M处理器不向后兼容经典的
A
R
M
ARM
ARM处理器。
A
R
M
ARM
ARM指令集架构也是在不断发展的。在2011年,
A
R
M
ARM
ARM公司推出了
A
R
M
v
8
ARMv8
ARMv8指令集架构,这个指令集架构里面有一个支持64位操作的指令集,当前支持
A
R
M
v
8
ARMv8
ARMv8指令集架构的是
C
O
R
T
E
X
−
A
CORTEX-A
CORTEX−A和
C
O
R
T
E
X
−
R
CORTEX-R
CORTEX−R系列处理器,
C
O
R
T
E
X
−
M
CORTEX-M
CORTEX−M系列不支持。
A
R
M
ARM
ARM指令集的发展如图1所示。
不同的 C O R T E X − M CORTEX-M CORTEX−M系列处理器之间的区别是它们所支持的指令的不同,为了减小最后设计的芯片的尺寸, C O R T E X − M 0 CORTEX-M0 CORTEX−M0, C O R T E X − M 0 + CORTEX-M0+ CORTEX−M0+以及 C O R T E X − M 1 CORTEX-M1 CORTEX−M1处理器仅仅支持大部分16位的 T h u m b Thumb Thumb指令以及少部分的32位的 T h u m b Thumb Thumb指令, C O R T E X − M 3 CORTEX-M3 CORTEX−M3处理器支持更多的32位的 T h u m b Thumb Thumb指令以及少量增加的16位的 T h u m b Thumb Thumb指令, C O R T E X − M 4 CORTEX-M4 CORTEX−M4处理器支持 D S P DSP DSP增强指令以及浮点指令。 C O R T E X − M 0 CORTEX-M0 CORTEX−M0, C O R T E X − M 0 + CORTEX-M0+ CORTEX−M0+, C O R T E X − M 1 CORTEX-M1 CORTEX−M1, C O R T E X − M 3 CORTEX-M3 CORTEX−M3以及 C O R T E X − M 4 CORTEX-M4 CORTEX−M4处理器所支持的指令的简单视图如图2所示。从图中我们可以知道, C O R T E X − M 0 CORTEX-M0 CORTEX−M0, C O R T E X − M 0 + CORTEX-M0+ CORTEX−M0+, C O R T E X − M 1 CORTEX-M1 CORTEX−M1, C O R T E X − M 3 CORTEX-M3 CORTEX−M3以及 C O R T E X − M 4 CORTEX-M4 CORTEX−M4处理器所支持的指令是向上兼容的。同时我们可以看到对于 C O R T E X − M 0 CORTEX-M0 CORTEX−M0, C O R T E X − M 0 + CORTEX-M0+ CORTEX−M0+, C O R T E X − M 1 CORTEX-M1 CORTEX−M1, C O R T E X − M 3 CORTEX-M3 CORTEX−M3以及 C O R T E X − M 4 CORTEX-M4 CORTEX−M4这些处理器,支持的指令越多,功能也就更强大,这样用户就可以根据自己的需求做出选择。
在 A R M ARM ARM架构汇编下,指令使用格式如下所示:
label
mnemonic operand1, operand2, . ; Comments
l a b e l label label一般是作为一个地址位置的参考,它是可选的。立即数一般有前缀 # \# #,定义常数使用 E Q U EQU EQU。
MOVS R0, #0x12 ; Set R0 = 0x12 (hexadecimal)
MOVS R1, #’A’ ; Set R1 = ASCII character A
NVIC_IRQ_SETEN EQU 0xE 000E100
NVIC_IRQ0_ENABLE EQU 0x1
.
LDR R0,=NVIC_IRQ_SETEN ; Put 0xE000E100 into R0
; LDR here is a pseudo instruction that will be converted
; to a PC relative literal data load by the assembler
MOVS R1, #NVIC_IRQ0_ENABLE ; Put immediate data (0x1) into
; register R1
STR R1, [R0] ; Store 0x1 to 0xE000E100, this enable external
; interrupt IRQ#0
在上面的这一段代码中, N V I C NVIC NVIC模块的寄存器的地址值用 L D R LDR LDR伪指令(即它不是标准的ARM指令,汇编程序在编译过程中,会将伪指令替换成标准的ARM指令,可能对应多条ARM指令)放到寄存器 R 0 R0 R0中。对于代码语句 L D R R 0 , = N V I C _ I R Q _ S E T E N ; LDR\quad R0,=NVIC\_IRQ\_SETEN ; LDRR0,=NVIC_IRQ_SETEN;汇编器将会在代码中放置一个常数并插入一条内存读指令来将这个值放到寄存器 R 0 R0 R0中。伪指令的使用是很有必要的,因为当前的这个常数值太大了,因此不能被编码成单一的移动立即数指令。在使用 L D R LDR LDR指令移动值到寄存器的时候,值得前面需要加一个前缀 = = =。
LDR R3,=MY_NUMBER ; Get the memory location of MY_NUMBER
LDR R4, [R3] ; Read the value 0x12345678 into R4
.
LDR R0,=HELLO_TEXT ; Get the starting address of HELLO_TEXT
BL PrintText ; Call a function called PrintText to
; display string
.
ALIGN 4
MY_NUMBER DCD 0x12345678
HELLO_TEXT DCB “Hello\n”, 0 ; Null terminated string
大部分汇编工具的另一个典型特征是可以在程序中插入数据,在上面的代码中,使用 D C D DCD DCD指令在代码存储空间中放了一个字,这个字的值为 0 x 12345678 0x12345678 0x12345678,存放这个字的地址空间的地址为 M Y _ N U M B E R MY\_NUMBER MY_NUMBER。使用 D C B DCB DCB指令在代码存储空间中放了一个以 A S C I I ASCII ASCII码0值结尾的字符串,“Hello\n”,存放这个字符串的地址空间的地址为 H E L L O _ T E X T HELLO\_TEXT HELLO_TEXT。还有一些类似 D C D DCD DCD和 D C B DCB DCB的指令。我们这里就不一一详细介绍了。在 A R M ARM ARM处理器的汇编器中有些指令可以带一些后缀(可能在较新的指令集架构中才会生效),具体带与不带后缀的含义如图3所示。
C O R T E X − M 3 CORTEX-M3 CORTEX−M3和 C O R T E X − M 4 CORTEX-M4 CORTEX−M4处理器的指令可以根据功能划分为以下分组: