一. ARM 汇编概述
1. 汇编使用位置
汇编位置 :
-- 启动代码 : Bootloader 初始化时对 CPU 和 协处理器 等进行初始化, 此时没有建立起 C 语言运行环境, 这个时候使用汇编语言执行初始化操作;
-- 效率要求 : 汇编效率高, Linux 内核中, 对效率有特殊要求的地方需要汇编;
2. 汇编分类
(1) ARM 标准汇编
ARM 标准汇编简介 :
-- 使用场景 : 适用于ARM公司的汇编器, 适合在 Windows 平台使用, 如ADS;
(2) GNU汇编
GNU 汇编简介 :
-- 使用场景 : 适用于 Linux 平台交叉编译工具链的汇编器;
3. ARM 汇编程序框架
ARM 汇编框架 :
-- ARM 汇编框架示例 :
.section .data < 初始化的数据> .section .bss < 未初始化的数据> .section .text .global _start _start: <汇编代码>
-- 程序入口 : '_start:' 是汇编程序的入口, 相当于 main();
-- 标注入口 : 使用 '.global _start' 标注程序入口, 外部才可以识别这是程序入口;
-- 标明代码段 : '.section .text' 标明这是一个代码段;
-- 标明 bss 段 : 使用 '.section .bss' 标明bss段, 如果没有 bss 段 和 数据段, 直接从 .text 开始;
4. 搭建汇编开发调试环境
(1) 汇编程序准备
程序代码 :
-- 定义代码段 : .text ;
-- 定义程序入口 : .globl _start;
-- 代码示例 :
.text .globl _start _start: mov r1,#1 mov r2,#2 mov r3,#3
Makefile 代码 :
-- 链接 elf 格式文件 : 设置程序起始位置 6410板子是 0x50008000 地址;
-- 在 arm-linux-ld 指定程序起始地址 : 在 -Ttext 50008000 即可;
-- 如果使用链接器脚本指定地址 : 注意第三行指定程序起始地址;
SECTIONS { . = 0x50008000; . = ALIGN(4); .text : { led.o (.text) *(.text) } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); .bss (NOLOAD) : { *(.bss) . = ALIGN(4); } }
-- 代码示例 :
all:start.o arm-linux-ld -Ttext 0x50008000 -o start.elf $^ %.o:%.S arm-linux-gcc -g -o $@ $^ -c clean: rm -rf *.o *.elf
(2) 启动 JLink 调试
JLink 调试启动 :
-- 确保驱动安装 : 注意 要安装 Windows 驱动;
-- 连接 JLink : 虚拟机右下角连接 JLink;
-- 启动 JLinkGDBServer :
[root@localhost JLink_Linux_V434a]# ./JLinkGDBServer SEGGER J-Link GDB Server V4.34a JLinkARM.dll V4.34a (DLL compiled Aug 31 2011 11:51:40) Listening on TCP/IP port 2331 J-Link connected Firmware: J-Link ARM V8 compiled Aug 24 2011 17:23:32 Hardware: V8.00 S/N: 17935099 Feature(s): RDI,FlashDL,FlashBP,JFlash J-Link found 2 JTAG devices, Total IRLen = 5 JTAG ID: 0x07B76F0F (ARM11)
(2) eclipse 调试环境
搭建 eclipse 调试环境 :
-- 导入工程 : 选择 Makefile Project With Existing Code;
-- 选择导入的代码位置 :
-- clean 代码 : 选择 'Project' --> 'Clean';
-- build 工程 : 选择 '菜单' --> Project --> Build All 选项即可;
-- 配置 Debug 调试参数 :
-- 执行调试 : F6 单步调试走两步, 可以再 Register 视图中查看寄存器的值, 可以看到 r1 和 r2 被赋值为 1 和 2 了;
二. ARM 指令分类
ARM 汇编手册 :
GNU 汇编 与 ARM 标准汇编区别 : 上面的手册是 ARM 标准汇编手册, 我们写的是 GNU 汇编手册, 有一定区别;
-- 大小写区别 : ARM 标准汇编 都是大写的, GNU 汇编可以是小写字母;
1. 算术和逻辑指令
(1) MOV 指令
MOV 指令简介 : 赋值操作;
-- 语法格式 : MOV -- 语法解析 : dest 是目的寄存器, op1 可以是立即数, 也可以是寄存器, 地址等, 等价于 dest = op1; 汇编程序注释 : 汇编中使用 '@' 符号添加注释; 示例代码 : (2) MVN 指令 MVN 指令简介 : 取反赋值操作; -- 语法格式 : MVN -- 语法解析 : 将操作数 op1 取反后 赋值给 dest; 指令示例 : -- 代码 : (3) SUB 指令 SUB 指令简介 : 减法操作; -- 语法格式 : SUB -- 语法解析 : dest 存放减法结果, op1 是减数, op2 是被减数, dest = op1 - op2; -- 注意 : dest op1 都不能使用立即数, op2 可以使用立即数; 代码示例 : (4) ADD 指令 ADD 指令简介 : 加法操作; -- 语法格式 : ADD -- 语法解析 : dest 存放加法结果, op1 和 op2 是相加的两个数, dest = op1 + op2; -- 注意 : dest op1 都不能使用立即数, op2 可以使用立即数; 代码示例 : AND 指令简介 : 逻辑与操作; -- 语法格式 : AND -- 语法解析 : dest 存放逻辑与结果, op1 和 op2 是相与的两个数, dest = op1 & op2; -- 注意 : dest op1 都不能使用立即数, 必须使用寄存器, op2 可以使用立即数; 代码示例 : BIC 指令简介 : 位清除指令操作; -- 语法格式 : AND -- 语法解析 : dest 存放位清除结果, op1 是被清除的对象, op2 是掩码; -- 示例 : 'bic r0, r0, #0b1011', 清除 r0 中的 第0, 1, 3 位, 其余位保持不变, 结果放入 r0 中; -- 注意 : dest op1 都不能使用立即数, 必须使用寄存器, op2 可以使用立即数; -- 二进制表示 : 掩码中 % 在标准汇编中表示二进制, 但是在 GNU 汇编中无法使用, GNU 汇编中使用 0b 代表二进制; 代码示例 : 2. 比较指令 (1) CMP 指令 CMP 指令简介 : 比较指令; -- 语法格式 : CMP -- 语法解析 : 比较结果有三种 op1 > op2 (CPSR N = 0), op1 = op2 (CPSR Z = 1), op1 < op2 (CPSR N = 1), 结果放入 CPSR 寄存器; 代码示例 : (2) TST 指令 TST 指令简介 : 比较指令; -- 语法格式 : TST -- 语法解析 : op1 和 op2 按位与操作, 结果影响 CPSR 寄存器, 如果结果 不为 0, CPSR 的 Z = 0, 如果结果为0, Z = 1; 代码示例 : 3. 分支指令 (1) B 指令 B 指令简介 : 分支指令; -- 语法格式 : B{条件} 地址; -- 语法解析 : 如果满足条件, 就跳转到 地址 位置, 如果不满足条件, 就执行下面的语句, 如果没有条件, 就是 100% 执行;; 代码示例 : -- 条件分析 : gt 是大于条件, 如果 r1 > r2 就走条件分支, 否则就继续执行下一条; .text .global _start _start: @b 分支指令范例 mov r1, #6 mov r2, #5 cmp r1, r2 @比较 r1 和 r2 中的值 @b 后可以跟一个条件, {条件} 在 {} 中就是可加可不加, 如果没有条件就是无条件100%执行 @gt 是大于条件指令, 如果条件满足会跳转到 branch1, 如果不满足就执行下面的指令 bgt branch1 add r3, r1, r2 b end @这里为了不执行 branch1 操作, 直接跳转到 end 执行 branch1: sub r3, r1, r2 end: nop BL 指令简介 : 带连接的分支指令; -- 语法格式 : BL{条件} 地址; -- 语法解析 : 如果满足条件, 就跳转到 地址 位置, 如果不满足条件, 就执行下面的语句, 如果没有条件, 就是 100% 执行;; 代码示例 : .text .global _start _start: @bl 带连接的分支指令范例 mov r1, #2 cmp r1, #1 @此时跳转到 func1, func1 执行完程序无法返回, 如果 使用 bl 跳转, 程序会返回 @b func1 @此时使用 bl 跳转到 func1 执行, func1 执行完毕后会返回执行下面的语句 bl func1 mov r1, #2 cmp r1, #3 func1: mov r1, #2 cmp r1, #2 mov r1, #4 cmp r1, #6 4. 移位指令 (1) LSL 指令 LSL 指令简介 : 逻辑左移指令; -- 语法格式 : Rx, LSL#2; -- 语法解析 : 将 Rx 寄存器中的值, 左移2 位; 代码示例 : (2) ROR 指令 ROR 指令简介 : 循环右移指令; -- 语法格式 : Rx, ROR#2; -- 语法解析 : 将 Rx 寄存器中的值 循环右移 2 位; 代码示例 : 程序状态字 : CPSR 和 SPSR; -- 注意 : 程序状态字 不能使用 通用寄存器的语句 如 MOV 等访问, 必须使用 程序状态寄存器的 专用指令 读写; 代码示例 : 6. 存储器访问指令 (1) STR 指令 STR 指令简介 : 将 寄存器中的值 保存到 内存中; -- 语法格式 : str r0, 地址; -- 语法解析 : 将 R0 寄存器中的值 保存到 内存地址中;; 代码示例 : -- 调试 : 添加地址监控, 在 Memory 视图中进行监控; (2) LDR 指令 LDR 指令简介 : 将 寄存器中的值 保存到 内存中; -- 语法格式 : ldr r0, 地址; -- 语法解析 : 将 内存地址中 存放的值 加载入 r0 中; 代码示例 : 7. 以上所有代码示例 以上所有代码示例 : 便于调试学习; .text .global _start _start: @ldr 指令范例 mov r0, #0xff @将 r1 值改为 50000000 (OK-6410) str r0, [r1] ldr r0, [r1] @str 指令范例 mov r0, #0xff @将 r1 值改为 50000000 (OK-6410) str r0, [r1] @mrs msr 指令范例 @rs 是 将 s -> r, sr 是 r -> s mrs r0, cpsr @将 cpsr 中的数据搬移到 r0 中 orr r0, #0b100 程序入口, 用法 '.globol _start', 注意前面加上点;@将 cpsr 中的第三位置为1 msr cprs, r0 @ror 循环右移指令范例 mov r1, #0b11 @结果是 ob1000...0001 mov r1, r1, ror#1 @lsl 左移指令范例 mov r1, #0b1 @将 r1 中的值, 左移 2 位, 放入 r1 寄存器中 mov r1, r1, lsl#2 @bl 带连接的分支指令范例 mov r1, #2 cmp r1, #1 @此时跳转到 func1, func1 执行完程序无法返回, 如果 使用 bl 跳转, 程序会返回 @b func1 @此时使用 bl 跳转到 func1 执行, func1 执行完毕后会返回执行下面的语句 bl func1 mov r1, #2 cmp r1, #3 func1: mov r1, #2 cmp r1, #2 mov r1, #4 cmp r1, #6 @b 分支指令范例 mov r1, #6 mov r2, #5 cmp r1, r2 @比较 r1 和 r2 中的值 @b 后可以跟一个条件, {条件} 在 {} 中就是可加可不加, 如果没有条件就是无条件100%执行 @gt 是大于条件指令, 如果条件满足会跳转到 branch1, 如果不满足就执行下面的指令 bgt branch1 add r3, r1, r2 b end @这里为了不执行 branch1 操作, 直接跳转到 end 执行 branch1: sub r3, r1, r2 end: nop @cmp 指令范例 .text
.global _start
_start:
@mov 指令范例
mov r1, #8 @将 8 赋值给 r1
mov r2, r1 @将 r1 中的值赋值给 r2
mov r3, #10 @将 10 赋值给 r3 寄存器
.text
.global _start
_start:
@mvn 指令范例
mvn r1, #0b10 @0b10 二进制数取反, 赋值给 r1
mvn r2, #5 @5 十进制数取反, 赋值给 r2
mvn r3, r1 @将 r1 寄存器的值, 赋值给 r3
.text
.global _start
_start:
@sub 指令范例
@sub r1, #4, #2 错误示例, 减数不能是立即数, 必须是寄存器
mov r2, #4
sub r1, r2, #4
mov r0, #1
sub r3, r1, r0
@add 指令范例
mov r2, #1
add r1, r2, #3
(5) AND 指令.text
.global _start
_start:
@and 指令范例
mov r1, #5
and r2, r1, #0
mov r1, #5
mov r2, r1, #1
(6) BIC 指令.text
.global _start
_start:
@bic 指令范例
mov r1, #0b101011
bic r2, r1, #0b101 @将r1 的 0, 2 位清除
.text
.global _start
_start:
@cmp 指令范例
mov r1, #2
cmp r1, #1
mov r1, #2
cmp r1, #3
mov r1, #2
cmp r1, #2
.text
.global _start
_start:
@cmp 指令范例
mov r1, #0b101
tst r1, #0b001 @按位与结果是 0b1, 结果不为0, CPSR Z = 0
mov r1, #0b101
tst r1, #0b10 @按位与结果是 0, 结果不为
(2) BL 指令.text
.global _start
_start:
@lsl 左移指令范例
mov r1, #0b1
@将 r1 中的值, 左移 2 位, 放入 r1 寄存器中
mov r1, r1, lsl#2
.text
.global _start
_start:
@ror 循环右移指令范例
mov r1, #0b11
@结果是 ob1000...0001
mov r1, r1, ror#1
5. 程序状态字访问指令.text
.global _start
_start:
@mrs 指令范例
@rs 是 将 s -> r, sr 是 r -> s
mrs r0, cpsr @将 cpsr 中的数据搬移到 r0 中
orr r0, #0b100 @将 cpsr 中的第三位置为1
msr cprs, r0
.text
.global _start
_start:
@str 指令范例
mov r0, #0xff
@将 r1 值改为 50000000 (OK-6410)
str r0, [r1]
@ldr 指令范例
mov r0, #0xff
@将 r1 值改为 50000000 (OK-6410)
str r0, [r1]
ldr r0, [r1]
上一篇:基于WINCE6.0+S3C2443的camera驱动
下一篇:【嵌入式开发】ARM 芯片简介 (ARM芯片类型 | ARM处理器工作模式 | ARM 寄存器 | ARM 寻址)
推荐阅读最新更新时间:2024-11-10 19:48
设计资源 培训 开发板 精华推荐
- 【广西师大校赛】任意波形发生器 基于STM32
- TWR-SMPS-LVFB: Low-Voltage, Full-Bridge DC-DC Switch Mode Power Supply Tower System Module
- LTC2633A-LX12 双路 12 位数模转换器的典型应用
- 锂电池低电量指示模块
- 5V MIL-STD-1553 收发器电路设计应用笔记
- 使用 Silicon Labs 的 CP2112 的参考设计
- NCP300LSN20T1 2V 窗口电压检测器的典型应用
- 使用 TC7106 ADC 提供单 +5V 电源的典型应用
- 使用 NXP Semiconductors 的 TDA1521Q 的参考设计
- SY58610U,用于 GB 以太网交换机的时钟多路复用器的评估板