目录
什么是汇编语言?
工程搭建
新建工程
环境设置
测试是否成功
正式学习汇编语言
数据处理指令
填充,加,减,乘
思考:我们可以看到R0寄存器可以存放8位十六进制数,那么0x12345678能不能用mov存入?
与,或,异或,左移,右移
思考:UART通信过程中为什么数据位规定8-9位?
思考:如果规定12或者更多可以吗?有什么影响?
CPSR寄存器的(NZCV位)
N位(负标记位)检测
思考:为什么N位为什么没有置为1?
Z位(0标记位)和C(进位和借位标记)
存储位数过多数据存储原理(ADC)
对内存的读写(STR,LDR)
回到最初的问题:如何赋值0x12345678?
对内存读写基础操作
前索引
后索引
自动索引(前后索引)
批量寄存器操作
注:本文章记录自己现阶段学到的基础汇编语言编程
什么是汇编语言?
汇编语言是一种低级程序设计语言,用于编写计算机程序。它是与特定计算机体系结构相关的,通过使用符号代表机器指令和数据,以便于人们理解和编写程序。
由于汇编语言是与特定体系结构相关的,所以每种计算机体系结构都有自己的汇编语言。常见的汇编语言包括x86(用于大多数个人电脑)、ARM(用于移动设备和嵌入式系统)等。本文主要记录基础ARM汇编语言。
编写汇编语言程序需要对计算机体系结构和指令集有深入的了解,并且编写的程序可以直接在相应的计算机上运行。汇编语言程序通常用于对性能要求非常高或需要直接访问硬件的应用,如操作系统、驱动程序、嵌入式系统等。
工程搭建
新建工程
环境设置
测试是否成功
输入下方汇编代码测试
AREA RESET,CODE,READONLY
ENTER
MOV R1,#1
END
正式学习汇编语言
数据处理指令对数据进行逻辑、算数运算
在汇编语言中;是注释的意思
AREA RESET,CODE,READONLY
;AREA 指定代码属性
;RESET 代码片段名称
;CODE 存放代码
;READONLY 只读
ENTER ;顶头写的我们称为标号 ENTER是程序入口
MOV R1,#1 ;前面有空格的我们称为指令
END ;END是结尾
数据处理指令
填充,加,减,乘
AREA RESET,CODE,READONLY
ENTER
MOV R0,#1 ;将1值填充到R0寄存器
MOV R1,#2 ;将2值填充到R1寄存器
ADD R2,R1,R0 ;R2寄存器值=R1+R0
SUB R3,R1,R0 ;R3=R1-R0
MUL R4,R1,R0 ;R4=R1*R0
END
上面演示了基础操作,主要说下第二个界面
我们看看上面指令最终结果,对应寄存器存储了对应的运算结果
思考:我们可以看到R0寄存器可以存放8位十六进制数,那么0x12345678能不能用mov存入?
AREA RESET,CODE,READONLY
ENTER
MOV R0,#0x12345678 ;将0x12345678值填充到R0寄存器
END
程序报错了
ARM.S(3): error: A1510E: Immediate 0x12345678 cannot be represented by 0-255 and a rotation
ARM.S(3): error: A1510E: Immediate 0x12345678不能用0-255
这里引入了立即数概念:
立即数(Immediate value)是在汇编语言中表示常数或立即数据的一种方式。它是直接包含在指令中的固定数值,而不是通过寄存器或内存引用获取。
通过测试我们得到当前操作立即数范围是0-255,255后面都是离散的。
那么如何赋值0x12345678?后面会讲解。
与,或,异或,左移,右移
AREA RESET,CODE,READONLY
ENTER
MOV R1,#1 ;将1值填充到R0寄存器
AND R2,R1,#0 ;R2=R1&0 与
ORR R3,R2,#1 ;R3=R2|1 或
EOR R3,R1,#1 ;R3=R1^1 异或
LSR R3,R2,R1 ;R3=R2<<R1
LSL R3,R2,R1 ;R3=R2>>R1
END
思考:UART通信过程中为什么数据位规定8-9位?
- 8位可以表示256个不同的数值,足够用于表示大部分常见的字符、数字和符号
- UART通信的具体配置(包括数据位、停止位、波特率等)应该根据通信双方的协商和需求进行设置,以确保正确的数据传输和解析,8位常用。
思考:如果规定12或者更多可以吗?有什么影响?
12位是可行的,但会存在一些影响和限制
- 兼容性问题:UART通信是由双方协商决定的,两个设备必须都支持12位才行
- 增加传输开销:增加数据位数量会导致数据字节传输开销增加
- 设备复杂性增加:位数越多,硬件设计和软件设计实现复杂
- 干扰和误差率增加:较长的数据位序列更容易受到噪声和干扰的影响
CPSR寄存器的(NZCV位)
N位(负标记位)检测
AREA RESET,CODE,READONLY
ENTER
;N位负标记位
MOV R0,#1 ;将1值填充到R0寄存器
MOV R1,#2 ;将2值填充到R1寄存器
SUB R2,R0,R1 ;R2=R0-R1
END
思考:为什么N位为什么没有置为1?
AREA RESET,CODE,READONLY
ENTER
;N位负标记位
MOV R0,#1 ;将1值填充到R0寄存器
MOV R1,#2 ;将2值填充到R1寄存器
SUBS R2,R0,R1 ;R2=R0-R1
END
Z位(0标记位)和C(进位和借位标记)
AREA RESET,CODE,READONLY
ENTER
;N位负标记位
MOV R0,#1 ;将1值填充到R0寄存器
MOV R1,#1 ;将2值填充到R1寄存器
SUBS R2,R0,R1 ;R2=R0-R1
END
AREA RESET,CODE,READONLY
ENTER
;N位负标记位
MOV R0,#0xFFFFFFFF ;将0xFFFFFFFF值填充到R0寄存器
MOV R1,#3 ;将3值填充到R1寄存器
ADDS R2,R0,R1 ;R2=R0+R1
END
存储位数过多数据存储原理(ADC)
假设有两个数据,怎么进行存储?
第一个数 0x00000001 FFFFFFFF
第二个数 0x00000005 00000002
第一个数的低32位放到R1,高32bit放R2第二个数的低32位放R3,高32bit放R4
低加低高加高 运算结构的低32bit放R5,高32bit放R6
AREA RESET,CODE,READONLY
ENTER
;N位负标记位
MOV R1,#0xFFFFFFFF ;NUM1低32位放R1
MOV R2,#0x00000001 ;NUM1高32位放R2
MOV R3,#0x00000002 ;NUM2低32位放R3
MOV R4,#0x00000005 ;NUM2高32位放R4
ADDS R5,R1,R3 ;R5=R1+R3 存放低位
ADDS R6,R2,R4 ;R6=R2+R4 存放高位
END
上面的代码能达到我们想要的效果吗?
正确操作是添加C特殊的标志位,使用ADC进行运算
AREA RESET,CODE,READONLY
ENTER
;N位负标记位
MOV R1,#0xFFFFFFFF ;NUM1低32位放R1
MOV R2,#0x00000001 ;NUM1高32位放R2
MOV R3,#0x00000002 ;NUM2低32位放R3
MOV R4,#0x00000005 ;NUM2高32位放R4
ADDS R5,R1,R3 ;R5=R1+R3 存放低位
ADC R6,R2,R4 ;R6=R2+R4+'C' 存放高位
END
对内存的读写(STR,LDR)
回到最初的问题:如何赋值0x12345678?
使用LDR命令就能完成赋值操作
AREA RESET,CODE,READONLY
ENTER
LDR R1,=0x12345678
END
但是R5此时却变为了0x07800000
R5 变为了 0x07800000,而不是 R1。这可能是因为汇编器在分配常量池地址时,将立即数 0x12345678
分配到了常量池的偏移量为 0x07800000 的位置,并将该地址加载到了 R5 寄存器中。
对内存读写基础操作
AREA RESET,CODE,READONLY
ENTER
MOV R0,#0x40000000 ;设置R0值为0x40000000
MOV R1,#0xFF
STR R1,[R0] ;将R1值存放到地址0x40000000
LDR R2,[R0] ;将地址0x40000000的值取出放到R2
END
前索引
AREA RESET,CODE,READONLY
ENTER
MOV R0,#0x40000000 ;设置R0值为0x40000000
MOV R1,#0xFF ;设置R1值为0xFF
STR R1,[R0,#4] ;将R1值存放到地址0x40000004
END
后索引
AREA RESET,CODE,READONLY
ENTER
MOV R0,#0x40000000 ;设置R0值为0x40000000
MOV R1,#0xFF ;设置R1值为0xFF
STR R1,[R0],#4
;将R1值存放到地址0x40000000
;RO地址变为Ox40000004
END
自动索引(前后索引)
AREA RESET,CODE,READONLY
ENTER
MOV R0,#0x40000000 ;设置R0值为0x40000000
MOV R1,#0xFF ;设置R1值为0xFF
STR R1,[R0,#4]!
;将R1值存放到地址0x40000004
;RO地址变为Ox40000004
END
批量寄存器操作
AREA RESET,CODE,READONLY
ENTER
MOV R0,#0x40000000
MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R5,#5
STM R0,{R1-R5}
LDM R0,{R6-R10}
END
AREA RESET,CODE,READONLY
ENTER
;空增
MOV R0,#0x40000000
MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R5,#5
STMIA R0!,{R1-R5}
;满增
MOV R0,#0x40000000
MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R5,#5
STMIB R0!,{R1-R5}
;空减
MOV R0,#0x4000000C
MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R5,#5
STMDA R0!,{R1-R5}
;满减
MOV R0,#0x4000000C
MOV R1,#1
MOV R2,#2
MOV R3,#3
MOV R4,#4
MOV R5,#5
STMDB R0!,{R1-R5}
END
上述四段代码分开测试能得到结果