乐趣区

关于arm:嵌入式ARM设计编程三-处理器工作模式

文章和代码已归档至【Github 仓库:hardware-tutorial】,须要的敌人们自取。或者关注公众号【AIShareLab】,回复 嵌入式 也可获取。

一、试验目标

(1)通过试验把握学会应用 msr/mrs 指令实现 ARM 处理器工作模式的切换,察看不同模式下的寄存器,加深对 CPU 构造的了解;

(2)通过试验把握 ld 中如何应用命令行指定代码段起始地址。

二、试验环境

硬件:PC 机。

软件:ADS1.2 集成开发环境

三、试验内容

通过 ARM 汇编指令,在各种处理器模式下切换并察看各种模式下寄存器的区别;把握 ARM 不同模式的进入与退出。

四、试验要求

(1) 依照 2.3 节介绍的办法, 在 ADS 下创立一个工程 asmmodelab,实现各个模式下的堆栈初始化工作, 并将 R1-R12 的内容存入以后模式下堆栈。通过 AXD 使用单步执行形式调试程序,验证工作模式的切换,留神察看 CPSR 寄存器中的变动。随着程序调试过程中在模式间的切换,应用寄存器观察器切换到不同的工作模式下察看 SP(R13)的变动状况。

(2) 试验过程中请记录并思考以下内容:

1)程序复位之后零碎处于什么模式?

2)记录每种模式下的初始堆栈指针,以及执行 R1-R12 内容压栈后本模式堆栈相干内存单元的数值。并剖析疾速中断 FIQ 模式与其余模式存入的 R1-R12 有什么不同。

3)切换成用户模式之后还是否从用户模式切换到其余模式(如零碎模式)?

4)用户模式下是否执行堆栈压栈操作?如果能得话,察看用户模式下压栈之前和压栈之后其堆栈区域的变动状况。

5)察看本程序模式切换过程中 SPSR 有无变动,并解释其起因。

五、试验状况

1、试验源代码(含正文):

usr_stack_legth equ 64 ; 定义各个模式的栈空间长度
svc_stack_legth equ 32
fiq_stack_legth equ 16
irq_stack_legth equ 64
abt_stack_legth equ 16
und_stack_legth equ 16               

  area reset,code,readonly ; 定义 code 片段 reset 只读
  entry ; 设置程序入口伪指令
  code32 ; 定义前面的指令为 32 位的 ARM 指令

; 设置各个寄存器中的内容
start    mov r0,#0
    mov r1,#1
    mov r2,#2
    mov r3,#3
    mov r4,#4
    mov r5,#5
    mov r6,#6
    mov r7,#7
    mov r8,#8
    mov r9,#9
    mov r10,#10
    mov r11,#11
    mov r12,#12
             
    bl initstack  ; 跳转至 initstack,并且初始化各模式下的堆栈指针,关上 IRQ 中断 (将 cpsr 寄存器的 i 位清 0)
                              
    mrs r0,cpsr        ;r0<--cpsr
    bic r0,r0,#0x80    ;cpsr 的 I 地位 0,开 IRQ 中断
    msr cpsr_cxsf,r0   ;cpsr<--r0
                                    
    ; 切换到用户模式
    msr cpsr_c,#0xd0  ; 设置 11010000,其中 I,F 地位 1,禁止 IRQ 和 FIQ 中断,T=0,ARM 执行,M[4:0] 为 10000,切换到用户模式
    mrs r0,cpsr          ;r0<--cpsr
    stmfd sp!,{r1-r12}   ; 将 R1-R12 入栈     
; 察看用户模式是否切换到其余模式
    ; 切换到管理模式
    msr cpsr_c,#0xdf    ; 设置 11011111,其中 I,F 地位 1,禁止 IRQ 和 FIQ 中断,T=0,ARM 执行,M[4:0] 为 11111,切换到零碎模式
    mrs r0,cpsr            ;r0<--cpsr
    stmfd sp!,{r1-r12}  ; 将寄存器列表中的 r1-r12 寄存器存入堆栈

halt  b halt ; 从 halt 跳转到 halt 循环

initstack  mov r0,lr   ; r0<--lr, 因为各种模式下 r0 是雷同的而各个模式不同       
                                   
    ; 设置管理模式堆栈
    msr cpsr_c,#0xd3   ; 设置 11010011 切换到管理模式
    ldr sp,stacksvc    ; 设置管理模式堆栈地址
    stmfd sp!,{r1-r12} ;R1-R12 入栈,满递加模式

    ; 设置中断模式堆栈
    msr cpsr_c,#0xd2   ; 设置 11010010  切换到中断模式
    ldr sp,stackirq    ; 设置中断模式堆栈地址
    stmfd sp!,{r1-r12} ;R1-R12 入栈,满递加模式

    ; 设置疾速中断模式堆栈
    msr cpsr_c,#0xd1   ; 设置 11010001  切换到疾速中断模式
    ldr sp,stackfiq    ; 设置疾速中断模式堆栈地址
    stmfd sp!,{r1-r12} ;R1-R12 入栈,满递加模式

    ; 设置停止模式堆栈   
    msr cpsr_c,#0xd7   ; 设置 11010111  切换到停止模式
    ldr sp,stackabt    ; 设置停止模式堆栈地址
    stmfd sp!,{r1-r12} ;R1-R12 入栈,满递加模式

    ; 设置未定义模式堆栈   
    msr cpsr_c,#0xdb   ; 设置 11011011  切换到未定义模式
    ldr sp,stackund    ; 设置未定义模式堆栈地址
    stmfd sp!,{r1-r12} ;R1-R12 入栈,满递加模式

    ; 设置零碎模式堆栈    
    msr cpsr_c,#0xdf   ; 设置 11011111  切换到零碎模式
    ldr sp,stackusr    ; 设置零碎模式堆栈地址
    stmfd sp!,{r1-r12} ;R1-R12 入栈,满递加模式

    mov pc,r0 ; 返回
    
    ; 为各模式堆栈开拓一段间断的字存储空间
stackusr    dcd  usrstackspace+(usr_stack_legth-1)*4
stacksvc    dcd  svcstackspace+(svc_stack_legth-1)*4
stackirq    dcd  irqstackspace+(irq_stack_legth-1)*4
stackfiq    dcd  fiqstackspace+(fiq_stack_legth-1)*4
stackabt    dcd  abtstackspace+(abt_stack_legth-1)*4
stackund    dcd  undstackspace+(und_stack_legth-1)*4
      ; 定义 data 段并命名
      area reset,data,noinit,align=2
; 为各模式堆栈调配存储区域
usrstackspace space usr_stack_legth*4
svcstackspace space svc_stack_legth*4
irqstackspace space irq_stack_legth*4
fiqstackspace space fiq_stack_legth*4
abtstackspace space abt_stack_legth*4
undstackspace space und_stack_legth*4
    end

2、试验过程(含后果截图及相应文字解释):

试验过程中请记录并思考以下内容:

1)程序复位之后零碎处于什么模式?

由上可知,零碎复位后处于管理模式。

2)记录每种模式下的初始堆栈指针,以及执行 R1-R12 内容压栈后本模式堆栈相干内存单元的数值。并剖析疾速中断 FIQ 模式与其余模式存入的 R1-R12 有什么不同。

①管理模式

由上图可知,管理模式初始指针为 0x8244。

执行 R1-R12 内容压栈后本模式堆栈相干内存单元的数值如上图所示,可知压栈后,堆栈指针变为 0x8214,离初始的堆栈指针 0x30 字节,即 12 个字 (32 位零碎),从内存单元的数值能够看到别离与 R1-R12 存储的数值对应。

②中断模式

由上图可知,中断模式初始指针为 0x8344。

执行 R1-R12 内容压栈后本模式堆栈相干内存单元的数值如上图所示,可知压栈后,堆栈指针变为 0x8314,离初始的堆栈指针 0x30 字节,即 12 个字 (32 位零碎),从内存单元的数值能够看到别离与 R1-R12 存储的数值对应。

③疾速中断模式

由上图可知,疾速中断模式初始指针为 0x8384。

执行 R1-R12 内容压栈后本模式堆栈相干内存单元的数值如上图所示,可知压栈后,堆栈指针变为 0x8354,离初始的堆栈指针 0x30 字节,即 12 个字 (32 位零碎),从内存单元的数值能够看到别离与 R1-R7 存储的数值对应,阐明该模式下仅能压入 R1-R7,因为疾速中断模式有本人的 R8-R12。

④停止模式

由上图可知,停止模式初始指针为 0x83C4。

执行 R1-R12 内容压栈后本模式堆栈相干内存单元的数值如上图所示,可知压栈后,堆栈指针变为 0x8394,离初始的堆栈指针 0x30 字节,即 12 个字 (32 位零碎),从内存单元的数值能够看到别离与 R1-R12 存储的数值对应。

⑤未定义模式

由上图可知,未定义模式初始指针为 0x8404。

执行 R1-R12 内容压栈后本模式堆栈相干内存单元的数值如上图所示,可知压栈后,堆栈指针变为 0x83D4,离初始的堆栈指针 0x30 字节,即 12 个字 (32 位零碎),从内存单元的数值能够看到别离与 R1-R12 存储的数值对应。

⑥零碎模式

由上图可知,零碎模式初始指针为 0x81C4。

执行 R1-R12 内容压栈后本模式堆栈相干内存单元的数值如上图所示,可知压栈后,堆栈指针变为 0x8194,离初始的堆栈指针 0x30 字节,即 12 个字 (32 位零碎),从内存单元的数值能够看到别离与 R1-R12 存储的数值对应。

⑦用户模式:

由上图可知,用户模式初始指针为 0x8194。

执行 R1-R12 内容压栈后本模式堆栈相干内存单元的数值如上图所示,可知压栈后,堆栈指针变为 0x8164,离初始的堆栈指针 0x30 字节,即 12 个字 (32 位零碎),从内存单元的数值能够看到别离与 R1-R12 存储的数值对应。

3)切换成用户模式之后还是否从用户模式切换到其余模式(如零碎模式)?

由上图可知,当进行切换管理模式时,模式仍是用户模式,因而可知切换成用户模式之后,不能操作 CPSR 返回到其余模式。

4)用户模式下是否执行堆栈压栈操作?如果能得话,察看用户模式下压栈之前和压栈之后其堆栈区域的变动状况。

压栈前:

压栈后:

压栈后存储单元状况:

答:用户模式下能够执行堆栈压栈操作,且以 4 个字节(1 个字)为单位进行压栈操作,压栈前堆栈区域状况如左图,压栈后如右图所示,对应的存储单元状况如上图。

5)察看本程序模式切换过程中 SPSR 有无变动,并解释其起因。

答:除了用户模式和零碎模式,其余模式下都有一个公有 SPSR 保留状态寄存器. 用来保留切换到该模式之前的执行状态,SPSR 是异样模式的程序状态保留寄存器, 当特定的异常中断产生时,这个寄存器寄存 CPSR 的内容,在异常中断退出时,能够用 SPSR 来复原 CPSR,然而通过观察可知,整个切换过程中没有异样的产生,因而 SPSR 没有变动。

六、总结

ARM 处理器模式别离是 usr(用户模式),fiq(疾速中断模式),irq(通用中断模式),svc(管理模式),abt(终止模式),sys(零碎模式)以及 und(未定义模式)。也通过 ARM 指令,实现了 ARM 不同模式的进入与退出,切换各种处理器模式,并察看各种模式下寄存器的区别。当特定的异样呈现时,进入相应的模式。每种模式都有某些附加的寄存器,以防止异样呈现时用户模式的状态不牢靠。此外也应用状态寄存器到通用寄存器的传送指令(MRS)以及通用寄存器到状态寄存器的传送指令(MSR),批改状态寄存器通过“读取-批改-写回”三个步骤操作来实现。


欢送关注公众号【AIShareLab】,一起交换更多相干常识,前沿算法,Paper 解读,我的项目源码,面经总结。

退出移动版