×
单片机 > 单片机程序设计 > 详情

ARM Cortex-M3 学习笔记(4-2)

发布时间:2020-08-26 发布时间:
|
最近在学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



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址