cotex单片机寄存器(cm3为例)

 ARM单片机寄存器列表:

 

堆栈指针 R13
  R13 是堆栈指针。在 CM3 处理器内核中共有两个堆栈指针,于是也就支持两个堆栈。
当引用 R13(或写作 SP)时,你引用到的是当前正在使用的那一个,另一个必须用特殊的指
令来访问(MRS,MSR 指令)。这两个堆栈指针分别是:
     主堆栈指针(MSP),或写作 SP_main。这是缺省的堆栈指针,它由 OS 内核、异常服务
例程以及所有需要特权访问的应用程序代码来使用。
     进程堆栈指针(PSP),或写作 SP_process。用于常规的应用程序代码(不处于异常服
用例程中时)。

MSP和PSP 的含义是Main_Stack_Pointer 和Process_Stack_Pointer

堆栈的 PUSH 与 POP
  堆栈是一种存储器的使用模型。它由一块连续的内存,以及一个栈顶指针组成,用
 于实现“先进后出”的缓冲区。其最典型的应用,就是在数据处理前先保存寄存器的值,
再在处理任务完成后从中恢复先前保护的这些值。 

因此,在 PUSH 新数据时,堆栈指针先减一个单元。通常在进入一个子程序后,第一件事就是把寄存器的值先
PUSH 入堆栈中,在子程序退出前再 POP 曾经 PUSH 的那些寄存器。另外,PUSH 和 POP 还
能一次操作多个寄存器。

可以使用 SP 表示 R13。在程序代码中,both MSP 和 PSP 都被称为 R13/SP

不过,我们可以通过 MRS/MSR 指令来指名道姓地访问具体的堆栈指针。
 MSP,亦写作 SP_main,这是复位后缺省使用堆栈指针,服务于操作系统内核和异常服
务例程
而 PSP,亦写作 SP_process,典型地用于普通的用户线程中

寄存器的 PUSH 和 POP 操作永远都是 4 字节对齐的——也就是说他们的地址必须是
0x4,0x8,0xc,……。这样一来,R13的最低两位被硬线连接到0,并且总是读出0 (Read As Zero)。

连接寄存器 R14
  R14 是连接寄存器(LR)。在一个汇编程序中,你可以把它写作 both LR 和 R14。LR 用于
在调用子程序时存储返回地址。例如,当你在使用 BL(分支并连接,Branch and Link)指令时,
就自动填充 LR 的值。

main ;主程序

BL     function1 ; 使用“分支并连接”指令呼叫 function1
; PC= function1,并且 LR=main 的下一条指令地址

                Function1
… ; function1 的代码
BX LR ; 函数返回(如果 function1 要使用 LR,必须在使用前 PUSH,
                           ; 否则返回时程序就可能跑飞了——译注)

程序计数器 R15
  R15 是程序计数器,在汇编代码中你也可以使用名字“PC”来访问它。因为 CM3 内部
使用了指令流水线,读 PC 时返回的值是当前指令的地址+4。
比如说:
0x1000: MOV R0, PC ; R0 = 0x1004 
  如果向 PC 中写数据,就会引起一次程序的分支(但是不更新 LR 寄存器) )。CM3 中的指
令至少是半字对齐的,所以 PC 的 LSB 总是读回 0。然而,在分支时,无论是直接写 PC 的值
还是使用分支指令,都必须保证加载到 PC 的数值是奇数(即 LSB=1),用以表明这是在
Thumb 状态(半字对齐)下执行。
若写了 0,则视为企图转入 ARM 模式,CM3 将产生一个 fault 异
常。

特殊功能寄存器组
Cortex‐M3 中的特殊功能寄存器包括:

  1.              程序状态寄存器组(PSRs 或曰 xPSR)
  2.              中断屏蔽寄存器组(PRIMASK, FAULTMASK,以及 BASEPRI)
  3.              控制寄存器(CONTROL)

它们只能被专用的 MSR 和 MRS 指令访问,而且它们也没有存储器地址。

  1. MRS <gp_reg>, <special_reg> ;读特殊功能寄存器的值到通用寄存器
  2. MSR <special_reg>, <gp_reg> ;写通用寄存器的值到特殊功能寄存器

程序状态寄存器(PSRs 或曰 PSR)
程序状态寄存器在其内部又被分为三个子状态寄存器:

  1.            应用程序 PSR(APSR)
  2.            中断号 PSR(IPSR)
  3.            执行 PSR(EPSR)

通过 MRS/MSR 指令,这 3 个 PSRs 即可以单独访问,也可以组合访问(2 个组合,3 个组合都可以)。当使用三合一的方式访问时,应使用名字“xPSR”或者“PSR”。

 

 

stmdb    sp!, {fp, ip, lr, pc} //sp=sp-4,sp=pc;先压PC ,把内容压入下一个内存地址即原地址-4.   
                               //sp=sp-4,sp=lr;再压lr
                               //sp=sp-4,sp=ip;再压ip
                               //sp=sp-4,sp=fp;再压fp
ldmia    sp, {fp, sp, pc}       //和stmdb成对使用,  
                               //fp=sp,sp=sp+4;先弹fp    //出栈还原+4
                               //sp=sp,sp=sp+4;先弹sp,此处的弹出不会  影响sp,因为ldmia是一个机器周期执行完的。
                               //pc=sp,sp=sp+4;先弹pc
LDRH           R0, [R13, #0xC] //加载无符号半字数据,即低16位
LDRB           R0, [R13, #0x4] //加载一字节数据,即低8位

 

在特权级下,可以指定具体的堆栈指针,而不受当前使用堆栈的限制

MRS R0, MSP ; 读取主堆栈指针到 R0
MSR MSP, R0 ; 写入 R0 的值到主堆栈中
MRS R0, PSP ; 读取进程堆栈指针到 R0
MSR PSP, R0 ; 写入 R0 的值到进程堆栈中 
         通过读取 PSP 的值,OS 就能够获取用户应用程序使用的堆栈,进一步地就知道了在发
生异常时,被压入寄存器的内容,而且还可以把其它寄存器进一步压栈(使用STMDB和LDMIA
的书写形式)。OS 还可以修改 PSP,用于实现多任务中的任务上下文切换。

堆栈指针 SP 指向最后一个被压入堆栈的 32
位数值。在下一次压栈时,SP 先自减 4,再存入新的数值。

POP 操作刚好相反:先从 SP 指针处读出上一次被压入的值,再把 SP 指针自增 4。

常用加载指令

  1. MRS 加载特殊功能寄存器的值到通用寄存器
  2. MSR 存储通用寄存器的值到特殊功能寄存器
  3. NOP 无操作
  4. SEV 发送事件
  5. WFE 休眠并且在发生事件时被唤醒
  6. WFI 休眠并且在发生中断时被唤醒
  7. ISB 指令同步隔离(与流水线和 MPU 等有关——译注)              //隔离指令
  8. DSB 数据同步隔离(与流水线、MPU 和 cache 等有关——译注)   //隔离指令
  9. DMB 数据存储隔离(与流水线、MPU 和 cache 等有关——译注)   //隔离指令

常用的多重存储器访问方式

LDMIA Rd!, {寄存器列表} 从 Rd 处读取多个字。     每读一个字后 Rd 自增一次,16
位宽度
STMIA Rd!, {寄存器列表} 存储多个字到 Rd 处。      每存一个字后 Rd 自增一次,16
位宽度
LDMIA.W Rd!, {寄存器列表} 从 Rd 处读取多个字。   每读一个字后 Rd 自增一次,32
位宽度
LDMDB.W Rd!, {寄存器列表} 从 Rd 处读取多个字。   每读一个字前 Rd 自减一次,32
位宽度
STMIA.W Rd!, {寄存器列表} 存储多个字到 Rd 处。     每存一个字后 Rd 自增一次,32
位宽度
STMDB.W Rd!, {寄存器列表} 存储多个字到 Rd 处。     每存一个字前 Rd 自减一次,32
位宽度

常用的存储器访问指令

示例                                                                功能描述
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 位)中。
STRB Rd, [Rn, #offset]                       把 Rd 中的低字节存储到地址 Rn+offset 处
STRH Rd, [Rn, #offset]                       把 Rd 中的低半字存储到地址 Rn+offset 处
STR Rd, [Rn, #offset]                          把 Rd 中的低字存储到地址 Rn+offset 处
LDRD Rd1, Rd2, [Rn, #offset]             把 Rd1(低 32 位)和 Rd2(高 32 位)表达的双字存储到地址 Rn+offset 处

 
 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章