ARM-----数据处理、异常处理、模式切换

实列一:

1. 异常向量表

复制代码
area reset, code, readonly
code32
entry
  • area reset, code, readonly:定义一个名为reset的代码区域,只读。

  • code32:指示编译器生成32位ARM指令。

  • entry:标记程序的入口点。

2. 程序入口和算术运算

复制代码
start
    mov r0, #1                 ; r0 = 1
    mov r1, #2                 ; r1 = 2
    add r2, r0, r1             ; r2 = r0 + r1 = 3
    sub r3, r2, r1             ; r3 = r2 - r1 = 1
  • mov r0, #1:将立即数1加载到寄存器r0

  • mov r1, #2:将立即数2加载到寄存器r1

  • add r2, r0, r1:将r0r1相加,结果存入r2r2 = 1 + 2 = 3)。

  • sub r3, r2, r1:将r2减去r1,结果存入r3r3 = 3 - 2 = 1)。

3. 位运算

复制代码
    mov r0, #0xff              ; r0 = 0xff (255)
    mov r1, #0x55              ; r1 = 0x55 (85)
    and r2, r0, r1             ; r2 = r0 & r1 = 0x55 (85)
  • mov r0, #0xff:将立即数0xff(十进制255)加载到r0

  • mov r1, #0x55:将立即数0x55(十进制85)加载到r1

  • and r2, r0, r1:对r0r1进行按位与操作,结果存入r2r2 = 0xff & 0x55 = 0x55)。

4. 更多位运算

复制代码
    mov r3, #0xaa              ; r3 = 0xaa (170)
    orr r4, r1, r3             ; r4 = r1 | r3 = 0xff (255)
    eor r5, r1, r3             ; r5 = r1 ^ r3 = 0xff (255)
    bic r3, r0, #3             ; r3 = r0 & ~3 = 0xfc (252)
  • mov r3, #0xaa:将立即数0xaa(十进制170)加载到r3

  • orr r4, r1, r3:对r1r3进行按位或操作,结果存入r4r4 = 0x55 | 0xaa = 0xff)。

  • eor r5, r1, r3:对r1r3进行按位异或操作,结果存入r5r5 = 0x55 ^ 0xaa = 0xff)。

  • bic r3, r0, #3:对r0进行按位与非操作,清除低3位,结果存入r3r3 = 0xff & ~0x3 = 0xfc)。

5. 条件执行

复制代码
    ; 0x 1 ffff ffff
    ; 0x 2 0000 0003
    ; 0x 4 0000 0002
    mov r0, #0x1               ; r0 = 1
    mov r1, #0xffffffff        ; r1 = 0xffffffff (-1 in two's complement)
    mov r2, #0x2               ; r2 = 2
    mov r3, #0x3               ; r3 = 3

    adds r5, r1, r3            ; r5 = r1 + r3 = 0xffffffff + 3 = 0x2 (with carry)
    adcs r4, r0, r2            ; r4 = r0 + r2 + carry = 1 + 2 + 1 = 4
  • adds r5, r1, r3:将r1r3相加,结果存入r5,并更新条件标志位。由于r1是0xffffffff(-1),加上3后结果为2,进位标志(C)被设置。

  • adcs r4, r0, r2:将r0r2相加,并加上进位标志(C),结果存入r4r4 = 1 + 2 + 1 = 4)。

6. 条件移动

复制代码
    mov r0, #1                 ; r0 = 1
    mov r1, #3                 ; r1 = 3
    cmp r0, r1                 ; 比较r0和r1,设置条件标志位
    movgt r2, r0               ; 如果r0 > r1,将r0的值存入r2,否则r2保持原值
    movle r2, r1               ; 如果r0 <= r1,将r1的值存入r2
  • cmp r0, r1:比较r0r1,设置条件标志位。

  • movgt r2, r0:如果r0 > r1,将r0的值存入r2

  • movle r2, r1:如果r0 <= r1,将r1的值存入r2

7. 循环

复制代码
    mov r0, #0                 ; r0 = 0
    mov r1, #0                 ; r1 = 0

loop
    add r0, r0, #1             ; r0 = r0 + 1
    add r1, r0, r1             ; r1 = r0 + r1
    cmp r0, #100               ; 比较r0和100
    blt loop                   ; 如果r0 < 100,跳转到loop
  • mov r0, #0:将r0初始化为0。

  • mov r1, #0:将r1初始化为0。

  • loop:循环标签。

    • add r0, r0, #1r0递增1。

    • add r1, r0, r1:将r0r1相加,结果存入r1

    • cmp r0, #100:比较r0和100。

    • blt loop:如果r0 < 100,跳转到loop继续循环。

8. 无限循环

复制代码
    nop                        ; 空操作
    b start                    ; 无限循环,返回start

    end
  • nop:空操作。

  • b start:跳转到start,形成无限循环。

实列二:

以下这段代码的主要功能是:

  1. 定义异常向量表,处理复位和软件中断。

  2. 从SVC模式切换到USER模式。

  3. 调用C语言函数main

  4. 实现一个简单的加法函数asm_add

1. 异常向量表

复制代码
preserve8
area reset, code, readonly
code32
entry

b start          ; 复位异常
nop              ; 未定义异常
b deal_swi       ; 软件中断(SWI)
nop              ; 预取中止
nop              ; 数据中止
nop              ; 保留
nop              ; IRQ
nop              ; FIQ
  • preserve8:确保代码对齐到8字节边界。

  • area reset, code, readonly:定义一个名为reset的代码区域,只读。

  • code32:指示编译器生成32位ARM指令。

  • entry:标记程序的入口点。

  • 异常向量表:定义了处理器在发生不同异常时的处理程序入口。

    • b start:复位异常时跳转到start

    • b deal_swi:软件中断(SWI)时跳转到deal_swi

    • 其他异常(如未定义异常、预取中止等)未处理,直接跳过。

2. 软件中断处理

复制代码
deal_swi
    stmfd sp!, {r4-r12, lr}    ; 保存现场
    sub r0, lr, #4             ; 获取SWI号
    ldr r1, [r0]               ; 从内存中加载SWI号
    bic r0, r1, #(0xff << 24)  ; 清除SWI号的高8位
    ldmfd sp!, {r4-r12, pc}^   ; 恢复现场并返回
  • stmfd sp!, {r4-r12, lr}:将寄存器r4r12和链接寄存器lr压入堆栈,保存现场。

  • sub r0, lr, #4:从链接寄存器lr中提取SWI号。

  • ldr r1, [r0]:从内存中加载SWI号。

  • bic r0, r1, #(0xff << 24):清除SWI号的高8位。

  • ldmfd sp!, {r4-r12, pc}^:从堆栈中恢复寄存器r4r12和程序计数器pc,并切换模式。

3. 程序入口

复制代码
start
    ldr sp, =0x40001000        ; 设置SVC模式的堆栈指针
    mrs r0, cpsr               ; 将CPSR寄存器的值加载到r0
    bic r0, r0, #0x1f          ; 清除模式位(低5位)
    orr r0, r0, #0x10          ; 设置模式位为USER模式(0b10000)
    msr cpsr_c, r0             ; 将r0的值写回CPSR,切换到USER模式

    ldr sp, =0x40000c00        ; 设置USER模式的堆栈指针
    mov r0, #1                 ; 设置r0为1
    mov r1, #2                 ; 设置r1为2
    mov r6, #0x1               ; 设置r6为1
    import main                ; 导入C语言函数main
    bl main                    ; 调用main函数
    swi #0x7                   ; 触发软件中断,编号为0x7
    nop                        ; 空操作
    b start                    ; 无限循环,返回start
  • ldr sp, =0x40001000:设置SVC模式的堆栈指针。

  • mrs r0, cpsr:将当前程序状态寄存器(CPSR)的值加载到r0

  • bic r0, r0, #0x1f:清除r0的低5位(模式位)。

  • orr r0, r0, #0x10:设置模式位为USER模式(0b10000)。

  • msr cpsr_c, r0:将r0的值写回CPSR,切换到USER模式。

  • ldr sp, =0x40000c00:设置USER模式的堆栈指针。

  • bl main:调用C语言函数main

  • swi #0x7:触发软件中断,编号为0x7。

  • b start:无限循环,返回start

4. 简单加法函数

复制代码
export asm_add

asm_add
    stmfd sp!, {r4-r12, lr}    ; 保存现场
    add r6, r0, r1             ; 将r0和r1相加,结果存入r6
    mov r0, r6                 ; 将结果存入r0
    ldmfd sp!, {r4-r12, pc}    ; 恢复现场并返回
  • export asm_add:导出asm_add函数,使其可以被其他模块调用。

  • stmfd sp!, {r4-r12, lr}:将寄存器r4r12和链接寄存器lr压入堆栈,保存现场。

  • add r6, r0, r1:将r0r1相加,结果存入r6

  • mov r0, r6:将结果存入r0

  • ldmfd sp!, {r4-r12, pc}:从堆栈中恢复寄存器r4r12和程序计数器pc,返回。

相关推荐
钡铼技术物联网关4 小时前
ARM边缘计算时代:BLIoTLink如何打通设备互联任督二脉
arm开发·人工智能·边缘计算
一道微光7 小时前
mac air m系列arm架构芯片安装虚拟机 UTM+debian 浏览器firefox和chrome
arm开发·macos·架构
小蘑菇二号7 小时前
ARM 架构--通用寄存器/状态寄存器/控制寄存器/特殊用途寄存器
arm开发·架构
最后一个bug1 天前
教你快速理解linux中的NUMA节点探测是干什么用的?
linux·c语言·开发语言·arm开发·嵌入式硬件
磨十三2 天前
初始ARM
arm开发
Xuan-ZY4 天前
【KEIL5.3.7以上版本ARM compiler5 version】
arm开发
一枝小雨5 天前
ARM异常处理流程与中断机制总结,与常见丢中断情况
arm开发·嵌入式硬件·架构·系统架构·arm
钡铼技术物联网关5 天前
模块化革命:树莓派CM5嵌入式工业计算机如何重构嵌入式系统开发边界
linux·arm开发·边缘计算
心随雪冻6 天前
18.PCIe总线入门理解与Linux上PCIe设备配置与使用
linux·arm开发·嵌入式硬件