• 基础汇编语言编程


    目录

    什么是汇编语言?

    工程搭建

    新建工程

    环境设置

     测试是否成功

     正式学习汇编语言

    数据处理指令

    填充,加,减,乘

     思考:我们可以看到R0寄存器可以存放8位十六进制数,那么0x12345678能不能用mov存入?

    与,或,异或,左移,右移

    思考:UART通信过程中为什么数据位规定8-9位?

    思考:如果规定12或者更多可以吗?有什么影响?

    CPSR寄存器的(NZCV位)

     N位(负标记位)检测

     思考:为什么N位为什么没有置为1?

     Z位(0标记位)和C(进位和借位标记)

     存储位数过多数据存储原理(ADC)

     对内存的读写(STR,LDR)

    回到最初的问题:如何赋值0x12345678?

    对内存读写基础操作

    前索引

    后索引

    自动索引(前后索引)

     批量寄存器操作


    注:本文章记录自己现阶段学到的基础汇编语言编程

    什么是汇编语言?

    汇编语言是一种低级程序设计语言,用于编写计算机程序。它是与特定计算机体系结构相关的,通过使用符号代表机器指令数据,以便于人们理解和编写程序。

    由于汇编语言是与特定体系结构相关的,所以每种计算机体系结构都有自己的汇编语言。常见的汇编语言包括x86(用于大多数个人电脑)、ARM(用于移动设备和嵌入式系统)等。本文主要记录基础ARM汇编语言。

    编写汇编语言程序需要对计算机体系结构和指令集有深入的了解,并且编写的程序可以直接在相应的计算机上运行。汇编语言程序通常用于对性能要求非常高或需要直接访问硬件的应用,如操作系统、驱动程序、嵌入式系统等。

    工程搭建

    新建工程

     

    环境设置

     

     测试是否成功

    输入下方汇编代码测试

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. MOV R1,#1
    4. END

     正式学习汇编语言

    数据处理指令对数据进行逻辑、算数运算

    在汇编语言中;是注释的意思

    1. AREA RESET,CODE,READONLY
    2. ;AREA 指定代码属性
    3. ;RESET 代码片段名称
    4. ;CODE 存放代码
    5. ;READONLY 只读
    6. ENTER ;顶头写的我们称为标号 ENTER是程序入口
    7. MOV R1,#1 ;前面有空格的我们称为指令
    8. END ;END是结尾

    数据处理指令

    填充,加,减,乘

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. MOV R0,#1 ;将1值填充到R0寄存器
    4. MOV R1,#2 ;将2值填充到R1寄存器
    5. ADD R2,R1,R0 ;R2寄存器值=R1+R0
    6. SUB R3,R1,R0 ;R3=R1-R0
    7. MUL R4,R1,R0 ;R4=R1*R0
    8. END

     

     上面演示了基础操作,主要说下第二个界面

     我们看看上面指令最终结果,对应寄存器存储了对应的运算结果

     思考:我们可以看到R0寄存器可以存放8位十六进制数,那么0x12345678能不能用mov存入?

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. MOV R0,#0x12345678 ;将0x12345678值填充到R0寄存器
    4. 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?后面会讲解。

    与,或,异或,左移,右移

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. MOV R1,#1 ;将1值填充到R0寄存器
    4. AND R2,R1,#0 ;R2=R1&0
    5. ORR R3,R2,#1 ;R3=R2|1
    6. EOR R3,R1,#1 ;R3=R1^1 异或
    7. LSR R3,R2,R1 ;R3=R2<
    8. LSL R3,R2,R1 ;R3=R2>>R1
    9. END

    思考:UART通信过程中为什么数据位规定8-9位?

    • 8位可以表示256个不同的数值,足够用于表示大部分常见的字符、数字和符号
    • UART通信的具体配置(包括数据位、停止位、波特率等)应该根据通信双方的协商和需求进行设置,以确保正确的数据传输和解析,8位常用。

    思考:如果规定12或者更多可以吗?有什么影响?

    12位是可行的,但会存在一些影响和限制

    • 兼容性问题:UART通信是由双方协商决定的,两个设备必须都支持12位才行
    • 增加传输开销:增加数据位数量会导致数据字节传输开销增加
    • 设备复杂性增加:位数越多,硬件设计和软件设计实现复杂
    • 干扰和误差率增加:较长的数据位序列更容易受到噪声和干扰的影响

    CPSR寄存器的(NZCV位)

     N位(负标记位)检测

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. ;N位负标记位
    4. MOV R0,#1 ;将1值填充到R0寄存器
    5. MOV R1,#2 ;将2值填充到R1寄存器
    6. SUB R2,R0,R1 ;R2=R0-R1
    7. END

     思考:为什么N位为什么没有置为1?

    默认情况下数据运算不会对条件位(NZCV)产生影响,我们可以在指令后添加后缀 'S'
    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. ;N位负标记位
    4. MOV R0,#1 ;将1值填充到R0寄存器
    5. MOV R1,#2 ;将2值填充到R1寄存器
    6. SUBS R2,R0,R1 ;R2=R0-R1
    7. END

     Z位(0标记位)和C(进位和借位标记)

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. ;N位负标记位
    4. MOV R0,#1 ;将1值填充到R0寄存器
    5. MOV R1,#1 ;将2值填充到R1寄存器
    6. SUBS R2,R0,R1 ;R2=R0-R1
    7. END

     

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. ;N位负标记位
    4. MOV R0,#0xFFFFFFFF ;将0xFFFFFFFF值填充到R0寄存器
    5. MOV R1,#3 ;将3值填充到R1寄存器
    6. ADDS R2,R0,R1 ;R2=R0+R1
    7. END

     存储位数过多数据存储原理(ADC)

    假设有两个数据,怎么进行存储? 

    第一个数        0x00000001 FFFFFFFF

    第二个数        0x00000005 00000002

    我们可以:
    第一个数的低32位放到R1,高32bit放R2

    第二个数的低32位放R3,高32bit放R4

    低加低高加高 运算结构的低32bit放R5,高32bit放R6

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. ;N位负标记位
    4. MOV R1,#0xFFFFFFFF ;NUM1低32位放R1
    5. MOV R2,#0x00000001 ;NUM1高32位放R2
    6. MOV R3,#0x00000002 ;NUM2低32位放R3
    7. MOV R4,#0x00000005 ;NUM2高32位放R4
    8. ADDS R5,R1,R3 ;R5=R1+R3 存放低位
    9. ADDS R6,R2,R4 ;R6=R2+R4 存放高位
    10. END

     上面的代码能达到我们想要的效果吗?

     正确操作是添加C特殊的标志位,使用ADC进行运算

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. ;N位负标记位
    4. MOV R1,#0xFFFFFFFF ;NUM1低32位放R1
    5. MOV R2,#0x00000001 ;NUM1高32位放R2
    6. MOV R3,#0x00000002 ;NUM2低32位放R3
    7. MOV R4,#0x00000005 ;NUM2高32位放R4
    8. ADDS R5,R1,R3 ;R5=R1+R3 存放低位
    9. ADC R6,R2,R4 ;R6=R2+R4+'C' 存放高位
    10. END

     对内存的读写(STR,LDR)

    回到最初的问题:如何赋值0x12345678?

    使用LDR命令就能完成赋值操作

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. LDR R1,=0x12345678
    4. END

     但是R5此时却变为了0x07800000

    R5 变为了 0x07800000,而不是 R1。这可能是因为汇编器在分配常量池地址时,将立即数 0x12345678 分配到了常量池的偏移量为 0x07800000 的位置,并将该地址加载到了 R5 寄存器中。

    对内存读写基础操作

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. MOV R0,#0x40000000 ;设置R0值为0x40000000
    4. MOV R1,#0xFF
    5. STR R1,[R0] ;将R1值存放到地址0x40000000
    6. LDR R2,[R0] ;将地址0x40000000的值取出放到R2
    7. END

    前索引

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. MOV R0,#0x40000000 ;设置R0值为0x40000000
    4. MOV R1,#0xFF ;设置R1值为0xFF
    5. STR R1,[R0,#4] ;将R1值存放到地址0x40000004
    6. END

     

    后索引

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. MOV R0,#0x40000000 ;设置R0值为0x40000000
    4. MOV R1,#0xFF ;设置R1值为0xFF
    5. STR R1,[R0],#4
    6. ;将R1值存放到地址0x40000000
    7. ;RO地址变为Ox40000004
    8. END

    自动索引(前后索引)

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. MOV R0,#0x40000000 ;设置R0值为0x40000000
    4. MOV R1,#0xFF ;设置R1值为0xFF
    5. STR R1,[R0,#4]!
    6. ;将R1值存放到地址0x40000004
    7. ;RO地址变为Ox40000004
    8. END

     批量寄存器操作

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. MOV R0,#0x40000000
    4. MOV R1,#1
    5. MOV R2,#2
    6. MOV R3,#3
    7. MOV R4,#4
    8. MOV R5,#5
    9. STM R0,{R1-R5}
    10. LDM R0,{R6-R10}
    11. END

    1. AREA RESET,CODE,READONLY
    2. ENTER
    3. ;空增
    4. MOV R0,#0x40000000
    5. MOV R1,#1
    6. MOV R2,#2
    7. MOV R3,#3
    8. MOV R4,#4
    9. MOV R5,#5
    10. STMIA R0!,{R1-R5}
    11. ;满增
    12. MOV R0,#0x40000000
    13. MOV R1,#1
    14. MOV R2,#2
    15. MOV R3,#3
    16. MOV R4,#4
    17. MOV R5,#5
    18. STMIB R0!,{R1-R5}
    19. ;空减
    20. MOV R0,#0x4000000C
    21. MOV R1,#1
    22. MOV R2,#2
    23. MOV R3,#3
    24. MOV R4,#4
    25. MOV R5,#5
    26. STMDA R0!,{R1-R5}
    27. ;满减
    28. MOV R0,#0x4000000C
    29. MOV R1,#1
    30. MOV R2,#2
    31. MOV R3,#3
    32. MOV R4,#4
    33. MOV R5,#5
    34. STMDB R0!,{R1-R5}
    35. END

     上述四段代码分开测试能得到结果

     

  • 相关阅读:
    【数据结构】二叉树(C语言实现)
    网络安全(黑客)自学
    DDD 实战 (2):看看代码结构长啥样(值得收藏)
    振弦式测缝(位移)计表面裂缝监测
    Databend 开源周报 #69
    OSPF协议:优点、初始化流程和管理
    golang设计模式——结构模式
    Android 自定义View(一):View是什么?如何创建自定义view,自定义属性等
    云视频协作平台有哪些 云视频在线审片解决方法
    【分析思路】测试数据分析思路
  • 原文地址:https://blog.csdn.net/weixin_42352787/article/details/131135778