【ARM】基本汇编指令——Keil

时间:2021-12-03 01:07:18
    area reset, code    ; 定义一个代码段叫reset


;/*汇编文件中的符号*/
;1.指令:编译完成后作为一条指令存储在内存单元当中,CPU执行时能完成一定的操作
;2.伪操作:不会生成代码也不会占用内存,告诉编译器怎样编译
;3.伪指令:本身不是指令,编译器在编译的时候将其替换成CPU能识别的指令

;/*指令*/
;1.数据操作指令:对数据进行逻辑、数学等运算与处理
;2.跳转指令:实现程序的跳转,实质是修改PC
;3.Load/Store:对内存的读写操作
;4.状态寄存器传送指令:对CPSR进行读写操作
;5.异常中断产生指令:触发软中断
;6.协处理器指令:操作协处理器的指令

entry ; 汇编的入口

;/*********************数据处理指令**********************/
; 数据搬移指令
; mov r1, #1
; r1 = 1
; mov r2, r1
; r2 = r1
; mvn r1, #0x000000FF
; r1 = ~(0x000000FF)

; 立即数
; mov r1, #0xFF000000
; 立即数0xFF0000000xFF循环右移(0x4*2)次得到 所以机器码中【7:0】为0xFF11:8】为0x4
; 立即数的本质是包含在指令当中的数
; 在mov指令中给立即数留了12位的存储空间,所以立即数只包含了212次方个
; 一个立即数是由一个八位的数循环右移偶数次得到的
; mov r1, #0xFFFFFFFF
; 编译器将其进行了指令的替换

; 加法指令
; mov r1, #1
; mov r2, #2
; add r3, r1, r2
; r3 = r1 + r2
; add r3, r1, #2
; r3 = r1 + 2

;数据运算指令的基本格式
;《操作码》《目标寄存器》《第一操作寄存器》《第二操作数》

;默认情况下,数据处理指令不影响标志位,可以选择通过添加后缀“S”来影响标志位。
; mov r1, #0xFFFFFFFE
; adds r2, r1, #3

; 带进位的加法指令
; 两个64位数相加,第一个数的低32位放在r0高32位放在r1,第二个数的低32位放在r2高32位放在r3
; 编写代码实现两个64位数的和,结果的低32位放在r4高32位放在r5
; MOV R0, #0xFFFFFFFE
; MOV R1, #1

; MOV R2, #0x5
; MOV R3, #1

; ADDS R4, R0, R2
; ADC R5, R1, R3
; 本质:r5 = r1 + r3 + 'C'

; 减法指令
; mov r1, #5
; mov r2, #3
; subs r3, r1, r2
; r3 = r1 - r2

; 带借位的减法指令
; mov r0, #5
; mov r1, #3

; mov r2, #6
; mov r3, #1

; subs r4, r0, r2
; sbc r5, r1, r3
; 本质:r5 = r1 - r3 - '!C'

; 逆向减法
; mov r1, #5
; rsb r2, r1, #8
; r2 = 8 - r1

; 乘法指令
; mov r1, #3
; mov r2, #5
; mul r3, r1, r2
; 乘法指令不能使用立即数

;逻辑与
;mov r0, #0xf0
;mov r1, #0x0f
;and r2, r0, r1
;r2 = r0 & r1

;逻辑或运算
;mov r0, #0xf0
;mov r1, #0x0f
;orr r2, r0, r1
;r2 = r0 | r1

;逻辑异或运算
;mov r0, #0xff
;mov r1, #0xff
;eor r2, r1, r0
;r2 = r1 eor r0

; 位清零指令
; mov r0, #0xff
; bic r1, r0, #0xf

;比较指令
;mov r1, #1
;mov r2, #1
;cmp r1, r2
;实质:减法指令
;没有目标寄存器
;比较的结果在Z位显示

;移位器
; mov r1, #0xFF
; lsl r1, r1, #4
; 逻辑左移 高位移出 低位补零
; lsr r1,r1, #4
; 逻辑右移 低位移出 高位补零
; mov r1, #0x7FFFFFFF
; asr r1, r1, #16
; 算数右移 低位移出 高位补符号位
; mov r1, 0xff
; ror r2, r1, #4
; 循环右移 低位移出 高位补低位

; mov r2, #0xFF
; mov r1, r2, lsl #4
; r1 = (r2 << 4)

;/*********************跳转指令**********************/

;mov r1, #1
;mov r2, #2
;mov r3, #3
;b loop
;mov r4, #4
;mov r5, #5

;loop
;mov r6, #6
;mov r7, #7
;跳转指令的实质就是将PC修改为跳转标签下的第一条指令的地址

;带返回的跳转
;MAIN
; MOV R1, #1
; MOV R2, #2
; BL FUNC
; MOV R5,#5
; MOV R6,#6

;FUNC
; MOV R3,#3
; MOV R4,#4
; MOV PC,LR

;ARM指令的条件执行
;mov r1, #1
;mov r2, #2
;cmp r1, r2
;beq loop ;if(eq){b loop} => 实质:if(z==1){b loop}
;bne loop ;if(ne){b loop} => 实质:if(z==0){b loop}
;mov r3, #3
;mov r4, #4
;loop
;mov r5, #5
;mov r6, #6

;练习
;mov r0, #9
;mov r1, #15
;loop
;cmp r0, r1
;beq stop
;subgt r0, r0, r1
;sublt r1, r1, r0
;b loop
;stop
;b stop

;/*********************Load/Store指令**********************/

; mov r1, #0xF000000F
; mov r2, #0x40000000
; str r1, [r2]
; 将r1寄存器中的值存储到内存中以0x40000000为起始地址的连续的4字节空间
; strb r1, [r2]
; 将r1的低8位存储到内存0x40000000地址中
; strh r1, [r2]
; 将r1寄存器中的低16位存储到内存中以0x40000000为起始地址的连续的2字节空间
; ldr r3, [r2]
; 将内存中以r2为起始地址的连续的4字节读取到r3寄存器

; 单寄存器操作索引方式
; 前索引
; mov r1, #0xFFFFFFFF
; mov r2, #0x40000000
; str r1, [r2, #4]
; 将r1的值存储到r2+4地址

; 后索引
; str r1, [r2], #4
; 将r1的值存储到r2地址,然后r2=r2+4

; 自动索引
; str r1, [r2, #8]!
; 将r1的值存储到r2+48地址, 然后r2=r2+8

; 三种索引方式同样适用于ldr

; 批量寄存器操作
; mov r1, #1
; mov r2, #2
; mov r3, #3
; mov r4, #4
; mov r5, #5
; mov r11,#0x40000000
; stm r11, {r1-r5}
; 将r1-r5寄存器的值存储到内存以r11为起始地址的20个字节
; stm r11, {r1,r3,r5}
; 如果寄存器列表中的寄存器编号不连续 使用逗号隔开
; stm r11!, {r1-r5}
; 自动索引适用于批量寄存器操作
; stm r11, {r2,r5,r1,r4,r3}
; 不管寄存器列表顺序如何,永远是小编号的寄存器对应低地址
; ldm r11, {r6-r10}
; 将内存中r11为起始地址的20个字节读取到r6-r10寄存器

;批量寄存器操作中地址的增长方式
;mov r1, #1
;mov r2, #2
;mov r3, #3
;mov r4, #4
;mov r5, #5
;mov r11,#0x40000020
; stmia r11!, {r1-r5} ; 先存储数据 后增长地址
; stmib r11!, {r1-r5} ; 先增长地址 后存储数据
; stmda r11!, {r1-r5} ; 先存储数据 后递减地址
; stmdb r11!, {r1-r5} ; 先递减地址 后存储数据

;增栈:每次压栈后栈指针向高地址方向增长
;减栈:每次压栈后栈指针向低地址方向增长
;满栈:栈指针指向的是最后一次压入到栈中的数据 所以再压栈的时候需要先移动栈指针后压栈
;空栈:栈指针指向的是最后一次压入到栈中的数据相邻的内存空间 所以再压栈的时候可以直接先压栈再移动栈指针
;所以栈可以分为满增(FA) 满减(FD) 空增(EA) 空减(ED) 四类
;习惯上我们使用满减栈
;stmfd r11!, {r1-r5}
;ldmfd r11!, {r6-r10}

;模拟子程序调用过程

; 初始化栈
;MOV SP, #0x40000020

;MAIN
;MOV R1, #3
;MOV R2, #5
;BL FUNC
;ADD R3, R1, R2
;B STOP

;FUNC
;压栈保护现场
;STMFD SP!, {R1,R2}
;MOV R1, #10
;MOV R2, #20
;SUB R3, R2, R1
;出栈恢复现场
;LDMFD SP!, {R1,R2}
;MOV PC, LR

;STOP
;B STOP

;优化
;初始化栈
;MOV SP, #0x40000020

;MAIN
;MOV R1, #3
;MOV R2, #5
;BL FUNC
;ADD R3, R1, R2
;B STOP

;FUNC
;压栈保护现场
;STMFD SP!, {R1,R2,LR}
;MOV R1, #10
;MOV R2, #20
;SUB R3, R2, R1
;出栈恢复现场
;LDMFD SP!, {R1,R2,PC}
;STOP
;B STOP
;信号量操作
;MOV R3, #0x40000000
;MOV R2, #0x34
;STR R2, [R3]
;MOV R2, #0x12
;SWP R1, R2, [R3]
;在内存和CPU寄存器之间进行一次数据交换
;数据交换过程不会被其他事件打断 常用于操作信号量

;/*********************状态寄存器传送指令**********************/

;1.读CPSR
; MRS R1, CPSR
; R1 = CPSR
;2.
; BIC R1, R1, #0x3
;3,写CPSR
; MSR CPSR_C, R1
; CPSR = R1 写CPSR的控制域【7:0

;/*********************异常中断产生指令**********************/
;MRS R1, CPSR
;BIC R1, R1, #0xC3
;MSR CPSR_C, R1
;MOV R1, #1
;MOV R2, #2
;MOV R3, #3
;SWI #1
;MOV R4, #4
;MOV R5, #5

;/*********************协处理器指令**********************/
;协处理器指令的种类
;1.协处理器的数据处理指令
;2.协处理器操作存储器的指令
;3.ARM处理器对协处理器内部寄存器的读写
;MRC-从协处理器寄存器移到ARM寄存器
;MCR-从ARM寄存器移到协处理器寄存器

;/*********************伪指令**********************/

ldr r1, =0x12345678
; r1 = 0x12345678
ldr r2, = 0x12
; 编译器将其替换成了CPU认识的指令

end ; 汇编的结束