最近在学ARM Cortex-M3,找了本声称很经典的书“An Definitive Guide to The ARM Cortex-M3”在看。这个系列学习笔记其实就是在学习这本书的过程中做的读书笔记。
第四章 指令系统
数据传送类指令
寄存器到寄存器传送:MOV 指令、MVN指令
MOV R8, R3; R8 = R3
MVN R8, R3; R8 = -R3
学过微机原理的都应记住,x86中一条MOV 指令存储器和寄存器间的恣意传送。ARM 中是不可的,这也是CISC和RISC 内核的一个比较显着的差异。
存储器到寄存器传送:LDRx 指令、LDMxy指令
寄存器到存储器:STRx 指令、STMxy指令
LDRx 指令的x可所以B(byte)、H(half word)、D(Double word)或许省掉(word),详细的用法如下:
示例 |
功用描绘 |
LDRB Rd, [Rn, #offset] |
从地址Rn+offset处读取一个字节送到Rd |
LDRH Rd, [Rn, #offset] |
从地址Rn+offset处读取一个半字送到Rd |
LDR Rd, [Rn, #offset] |
从地址Rn+offset处读取一个字送到Rd |
LDRD Rd1, Rd2, [Rn, #offset] |
从地址Rn+offset处读取一个双字(64位整数)送到Rd1(低32位)和Rd2(高32位)中。 |
STRx 指令的x相同可所以B(byte)、H(half word)、D(Double word)或许省掉(word),详细的用法如下:
示例 |
功用描绘 |
STRB Rd, [Rn, #offset] |
把Rd中的低字节存储到地址Rn+offset处 |
STRH Rd, [Rn, #offset] |
把Rd中的低半字存储到地址Rn+offset处 |
STR Rd, [Rn, #offset] |
把Rd中的低字存储到地址Rn+offset处 |
STRD Rd1, Rd2, [Rn, #offset] |
把Rd1(低32位)和Rd2(高32位)表达的双字存储到地址Rn+offset处 |
LDRx和STRx指令还有一种带预索引的格局,下面举个比方(留意查办中的“!”):
LDR.W R0,[R1, #20]! ;预索引
上面查办的意思是先把地址R1+offset处的值加载到R0,然后,R1 ßR1+ 20
还有一种后索引方式,留意与上面的预索引的差异(还要留意查办中没有“!”):
STR.W R0, [R1], #-12 ;把R0的值存储到地址R1处。结束后, R1ßR1+(-12)
LDMxy指令和STMxy指令能够一次传送更多的数据。
X能够为要I或D,I一共自增(Increment),D一共自减(Decrement)。
Y能够为A或B,一共自增或自减的机遇是在每次拜访前(Before)仍是拜访后(After)。
别的,指令带有“.W”后缀一共这条指令是32位的Thumb-2指令,否则是16位的指令。
示例 |
功用描绘 |
LDMIA Rd!, {寄存器列表} |
从Rd处读取多个字,并顺次送到寄存器列表中的寄存器。每读一个字后Rd自增一次,16位指令 |
LDMIA.W Rd!, {寄存器列表} |
从Rd处读取多个字,并顺次送到寄存器列表中的寄存器。每读一个字后Rd自增一次 |
STMIA Rd!, {寄存器列表} |
顺次存储寄存器列表中各寄存器的值到Rd给出的地址。每存一个字后Rd自增一次,16位指令 |
STMIA.W Rd!, {寄存器列表} |
顺次存储寄存器列表中各寄存器的值到Rd给出的地址。每存一个字后Rd自增一次 |
LDMDB.W Rd!, {寄存器列表} |
从Rd处读取多个字,并顺次送到寄存器列表中的寄存器。每读一个字前Rd自减一次 |
STMDB.W Rd!, {寄存器列表} |
存储多个字到Rd处。每存一个字前Rd自减一次 |
这儿需求特别留意!的意义,它一共要自增(Increment)或自减(Decrement)基址寄存器Rd的值,机遇是在每次拜访前(Before)或拜访后(After)。比方:
假定 R8=0x8000,则
STMIA.W R8!, {R0-R3} ; R8值变为0x8010
STMIA.W R8, {R0-R3} ; R8值不变
上面两行代码都是将R0-R3共16个字节的数据存储到从0x8000开端的16个字节空间中,仅有的差异是第一条指令碑文完后R8被更新为0x8010,而第二条指令不更新R8。
当即数的加载
MOV支撑8位当即数加载,比方:
MOV R0, #0x12
32位指令MOVW(加载到寄存器的低16位)和MOVT(加载到寄存器的高16位)能够支撑16位当即数加载。假如要加载32位的当即数,必须先运用MOVW,再运用MOVT,由于MOVW会清零高16位。
LDR 和ADR的差异
LDR和ADR都是伪指令,都能够用来加载一个当即数(也可所以一个地址),假如加载的是程序地址,LDR会自动地把LSB置位,ADR则不会:
LDR R0, =address1 ; R0= 0x4000 | 1
ADR R1, address1 ; R1= 0x4000。留意:没有“=”号
…
address1
0x4000: MOV R0, R1
特别功用寄存器只能用MSR/MRS指令拜访:
MRS
MSR
下面是两个比方:
MRS R0, PRIMASK ; 读取PRIMASK到R0中
MSR BASEPRI, R0 ;写入R0到BASEPRI中
可是需求留意大多数的特别功用寄存器都只能在特权级下拜访,非特权级下只能拜访APSR