本帖最后由 friend0720 于 2016-2-9 12:50 编辑
STM32F1XX核心寄存器 继续上一节内容,针对Contex-M3内核寄存器做一些简单实验。 2 Contex-M3内核寄存器实验 2.1汇编语言工程 新建一个名为 TestASM 的工程。新建一个名为 main.s 的汇编语言文件,并将其加入到工程中。 打开 main.s 文件 输入如下内容:
- ;----------------------------------------------------------
- ;定义一个只读代码段
- ;----------------------------------------------------------
- AREA |.text|, CODE, READONLY
- ;----------------------------------------------------------
- ;SystemInit 函数
- ;----------------------------------------------------------
- SystemInit PROC
- EXPORT SystemInit
-
- BX LR
- ENDP
- ;----------------------------------------------------------
- ;__main 函数
- ;----------------------------------------------------------
- __main PROC
- EXPORT __main
-
- ;------------------------
- ;通用寄存器实验
- ;------------------------
-
- ;寄存器赋值
- MOV R0,#0X100
- MOV R1,#0X101
- MOV R2,#0X102
- MOV R11,#0X111
- MOV R12,#0X112
-
- ;------------------------
- ;堆栈实验
- ;------------------------
-
- ;当前堆栈指针MSP赋值
- LDR SP,=0X20005000
- ;R1 入栈(MSP)
- PUSH {R1}
-
- ;切换堆栈指针到PSP
- MRS R0,CONTROL
- ORR R0,R0,#2
- MSR CONTROL,R0
- ;当前堆栈指针PSP赋值
- LDR SP,=0X20004000
- ;R2值入PSP栈
- PUSH {R2}
- ;PSP栈 出栈
- POP {R1}
- ;切换堆栈指针到MSP
- MRS R0,CONTROL
- AND R0,R0,#1
- MSR CONTROL,R0
- ;MSP栈 出栈
- POP {R1}
- ;------------------------
- ;连接寄存器LR实验
- ;------------------------
-
- ;LR入栈,保护当前LR
- PUSH {LR}
- LDR R0,=SystemInit
- BLX R0
- POP {LR}
- ;------------------------
- ;程序状态寄存器实验
- ;------------------------
-
- ;负数标志
- LDR R0,=0X8FFFFFFF
- LDR R1,=0X01
- ADDS R2,R1,R0
- ;零结果标志
- LDR R0,=0XFFFFFFFF
- LDR R1,=0X01
- ADDS R2,R1,R0
- ;进位借位标志
- LDR R0,=0XFFFFFFFF
- LDR R1,=0XFFFFFFFF
- ADDS R2,R1,R0
- ;溢出标志
- LDR R0,=0X7FFFFFFF
- LDR R1,=0X00000001
- ADDS R2,R1,R0
- ;饱和标志
- LDR R1,=0X7FFFFFFF
- SSAT.W R0,#12,R1
-
- ;------------------------
- ;程序计数器PC实验
- ;------------------------
- LDR PC,=__main
- ;本NOP指令旨在代码对齐
- ;NOP
-
- ENDP
-
- ;----------------------------------------------------------
- ;程序结束
- ;----------------------------------------------------------
- END
-
复制代码
打开工程默认建立的startup_stm32f10x_md.s 文件,将第290行代码注释掉: 点击工具栏中的魔术棒按钮,弹出对话框中做如下修改: 打开工程下的 TestASM.sct文件,删除其中第8行代码: 按F7编译工程: 2.2 实验代码说明 点击工具栏中的魔术棒图标,弹出对话框中做如下修改: 点击工具栏中的调试图标,工程进入软件模拟调试状态。打开 main.s 汇编文件,按F9在 __main 函数第一行设一个断点,按F5程序运行到我们的实验代码开始部分: 2.2.1 通用寄存器实验 ;寄存器赋值 MOV R0,#0X100 MOV R1,#0X101 MOV R2,#0X102 MOV R11,#0X111 MOV R12,#0X112 这部分代码很简单,就是通过MOV 指令对目标寄存器进行赋值操作。按 F10 单步执行代码,通过寄存器窗口可以看到目标寄存器的值发生了改变:
2.2.2 堆栈实验代码说明 ;当前堆栈指针(MSP)赋值 LDR SP,=0X20005000 系统复位后,默认使用主堆栈指针(MSP)。通过寄存器窗口可以看到,本行代码执行前堆栈指针是 MSP =0X20000600 ,这个地址是启动代码设置的。本行代码执行后,MSP =0X20005000 ,我们让堆栈指针指向了 STM32F103C8T6 20K RAM 的最高地址。 从上图也可以看出 R13 和 MSP 内容同时发生了改变,而且改变内容是相同的。 ;R1 入栈(MSP) PUSH {R1} 这条指令将寄存器 R1的值入栈。从寄存器窗口可以看出, R13(SP)及MSP 的值由 0X20005000 变为 0X20004FFC,共减少了4字节,这是因为堆栈是向下增长的。 ;切换堆栈指针到PSP MRS R0,CONTROL ORR R0,R0,#2 MSR CONTROL,R0 这三行代码将当前堆栈指针由MSP 切换到 PSP。上一节讲过 ,CONTROL[1] (控制寄存器第一位)可以用来选择当前使用的堆栈指针。当该位置1时,选择进程堆栈指针 PSP。另外对控制寄存器的操作需要使用 MRS 和 MSR 指令。ORR 是按位或指令。 ;当前堆栈指针PSP赋值 LDR SP,=0X20004000 这条指令将当前堆栈指针赋值为0X20004000。当这条指令执行时,我们看到 R13 和 PSP 的 值都变成了0X20004000,这说明当前堆栈指针已经由 MSP 成功切换到 PSP 。 ;R2值入PSP栈 PUSH {R2} ;PSP栈出栈 POP {R1} 第一条先将 R2 内容推入(PSP)堆栈,第二条指令将(PSP)堆栈内容弹出到 R1 寄存器中。实际上就是通过(PSP)堆栈将 R2 的内容赋值给 R1。 ;切换堆栈指针到MSP MRS R0,CONTROL AND R0,R0,#1 MSR CONTROL,R0 ;MSP栈出栈 POP {R1} 我们将堆栈指针由 PSP 切换回 MSP,并且将 MSP 堆栈中先前保存的 R1 寄存器内容重新弹出到 R1 寄存器。 2.2.3 连接寄存器LR (R14) 实验代码说明 ;LR入栈,保护当前LR PUSH {LR} LDR R0,=SystemInit BLX R0 POP {LR} 连接寄存器 LR (R14),用来保存函数返回地址。代码一开使使用 PUSH 指令,将当前 LR 寄存器内容推入到堆栈中,这样做的目的是对当前 LR 寄存器内容进行保护。接着使用 LDR 伪指令将 SystemInit 函数地址加载到 R0 寄存器中,然后使用 BLX 指令将代码跳转到 SystemInit 函数中执行。最后 SystemInit 函数返回后,通过 POP 指令恢复 LR 寄存器的值。 单步执行这段代码,同时观察寄存器窗口。当代码执行到 BLX R0 语句,此时 LR=0X080000F1,PC=0X800016E (当前准备运行的代码地址)。 我们通过反汇编窗口可以知道,下一条代码 POP {LR} 的地址=0X08000170。此时按下 F11 建,程序跟踪执行到SystemInit 函数中。这时 LR=0X08000171,这个地址就是 SystemInit 函数返回后的地址,也就是 POP {LR} 这行代码的地址。 因此当我们在SystemInit 函数中执行最后一条语句 BX LR 时,程序会跳转到POP {LR} 这行语句继续执行。有人可能会问了:POP {LR} 的地址不是 0X08000170 吗?怎么变成0X08000171了?这是ARM处理器的特点,多出来的 “1”表示当前执行的是 Thumb 指令。 2.2.4 程序状态寄存器实验代码说明 ;负数标志 LDR R0,=0X8FFFFFFF LDR R1,=0X01 ADDS R2,R1,R0 以上代码等效于R2=R0+R1; 如果32位运算结果的最高位为1,那么程序状态寄存器的N位将被置 1 ,但这并不表示结果一定是负数,因为无符号数的最高位也可以为1,在汇编语言中,一个数是否有符号由程序员决定。 ;零结果标志 LDR R0,=0XFFFFFFFF LDR R1,=0X01 ADDS R2,R1,R0 当运算结果为0时,程序状态寄存器的Z位将被置1。 ;进位借位标志 LDR R0,=0XFFFFFFFF LDR R1,=0XFFFFFFFF ADDS R2,R1,R0 当运算结果超出32位范围向前产生进位时,程序状态寄存器的C位置1。 ;溢出标志 LDR R0,=0X7FFFFFFF LDR R1,=0X00000001 ADDS R2,R1,R0 当32位运算结果最高位由0变为1时,程序状态寄存器的V位置1,N位同时置1。 ;饱和标志 LDR R1,=0X7FFFFFFF SSAT.W R0,#12,R1 当 R1 数值超出指定位数(这里指定12位),程序状态寄存器的Q位置1。 2.2.5程序计数器PC实验 LDR PC,=__main 我们知道程序计数器 PC 中装载下一条准备执行的代码地址,这里将 __main 函数地址装载到PC中,程序将跳转到 __main 函数入口重新开始执行。 遥远的海
|
|
2015-9-11 10:28:43
评论
举报
|
|
|