汇编语言基础知识
- 多重存储器访问
- MRS 和 MSR
- isb 和 dsb
- ldr 和 str
- mov
- bl 和 bx
- cps
多重存储器访问
感叹号!表示要自增(Increment)或自减(Decrement)基址寄存器 Rd 的值,时机是在每次访问前(Before)或访问后(After)。增/减,单位:字(4字节)。
Ldr R1,=0x10000000 //传送数据的起始地址0x10000000 LDMIA R1!,{R0,R4-R6} //从左到右加载,相当于 LDR R0,10000000 LDR R4,10000004... .../*传送后地址加+4,所以R0=0X10000000地址里的内容,地址加4,R4=0X10000004地址里的内容,地址加4,R5=0X10000008地址里的内容,地址加4,R6=0X1000000C 地址里的内容,地址加4,由于!,最后的地址写回到R1中,所以R1=0X10000010 */
MRS 和 MSR
这两条指令是访问特殊功能寄存器的“绿色通道”—当然必须在特权级下。
MRS <Rn>, <SReg> ;加载特殊功能寄存器的值到 Rn
MSR <Sreg>,<Rn> ;存储 Rn 的值到特殊功能寄存器
指定 PSP 进行更新的例子:
LDR R0, =0x20008000
MSR PSP, R0
BX LR ;如果是从异常返回到线程状态,则使用新的 PSP 的值作为栈顶指针
isb 和 dsb
isb:如果某个程序从下一条要执行的指令处更新了自己,但是先前的旧指令已经被预取到流水线中去了,此时就必须清洗流水线,把旧版本的指令洗出去,再预取新版本的指令。因此,必须在被更新代码段的前面使用 ISB,以保证旧的代码从流水线中被清洗出去,不再有机会执行。
DSB:如果把向量表重定位到了RAM中,且这块RAM所在的存储器区域是写缓冲的,向量更新就可能被延迟。为了以防万一,必须在建立完所有向量后追加一条“数据同步隔离(DSB)” 指令,以等待缓冲写入后再继续,从而确保所有数据都已落实。
DSB:如果存储器的映射关系,或者内存保护区的设置可以在运行时更改,就必须在更改之后立即补上一条 DSB 指令(数据同步指令)。因为对 MMU/MPU 的写操作很可能会被放到一个写缓冲中。写缓冲是为了提高存储器的总体访问效率而设的,但它也有副作用,其中之一,就是会导致写内存的指令被延迟几个周期执行,因此对存储器的设置不能即刻生效,这会导致紧临着的下一条指令仍然使用旧的存储器设置。
ldr 和 str
用于访问存储器的基础指令是“加载(Load)”和“存储(Store)”。
ldr命令:把数据从内存加载到寄存器。
ldr r0, =addr ;r0 = addr
ldr r1, [r0] ; r1 = *r0 r0指向的内容给r1
ldr r1, [r0, #4] ; r1 = *(r0+4)
ldr r1, [r0, #4] ! ; r1 = *(r0+4);r0=r0+4;
ldr r1, [r0], #4 ; r1 = *(r0);r0=r0+4;
str命令:把数据从寄存器保存到内存。
str r1, [r0] ; *r0 = r1 r1的值作为r0的内容
str r1, [r0, #4] ; *(r0+4) = r1
str r1, [r0, #4] ! ; *(r0+4) = r1;r0=r0+4;
str r1, [r0], #4 ; *r0 = r1;r0=r0+4;
LDR R3, =MY_NUMBER ; R3= MY_NUMBER
LDR R4, [R3] ; R4= *R3,也就是把R3指向的内容给R4
汇编器通常都支持”LDR Rd, = imm32”伪指令。(LDR内涵挺多)
LDR r0, =0x12345678
mov
MOV 寄存器加载数据,既能用于寄存器间的传输,也能用于加载立即数。
MOV R8, R3 ;把 R3 的数据传送给 R8
MOV R0, #0x12 ;16位指令 MOV 支持 8 位立即数加载
bl 和 bx
BL 转移并连接。用于呼叫一个子程序,返回地址被存储在 LR 中。
子程呼叫与无条件转移指令:
BL Label ;转移到 Label 处对应的地址,并且把转移前的下条指令地址保存到 LR
BX reg ;转移到由寄存器 reg 给出的地址
在BX中,reg的最低位指示出在转移后,将进入的状态是ARM(LSB=0)还是Thumb(LSB=1)。 既然 CM3 只在 Thumb 中运行,就必须保证 reg 的 LSB=1。关于bx这个指令,前面中断部分也有讲到。
cps
为了快速地开关中断,CM3 专门设置了 CPS 指令,有 4 种用法:
CPSID I ;PRIMASK=1, ;关中断
CPSIE I ;PRIMASK=0, ;开中断
CPSID F ;FAULTMASK=1, ;关异常
CPSIE F ;FAULTMASK=0 ;开异常