/** 代码演示 - memcpy.s **/.text.global _start.global memcpy.code 32_start:@ 将0x00008e00开始的16个字初始化成1-16mov r0, #0x00008e00mov r1, #1mov r2, #16set_loop:str r1, [r0], #4add r1, r1, #1subs r2, r2, #1bne set_loop@开始复制数据memcpy:mov r0, #0x00008e00mov r1, #0x00008f00mov r2, #16cpy_loop:ldr r3, [r0], #4str r3, [r1], #4subs r2, r2, #1bne cpy_loopmemcpy_ok:b .@在数据段分配1K的空间.data .space 1024 .end/*-----------------------代码演示结束------------------------*/【注意】如果要仿真调试程序 1).data .space 1024 2)指定数据段的地址 arm-...-as memcpy.s -o memcpy.o arm-...-ld -T.data=0x8e00 memcpy.o -o memcpy 3)仿真调试 qemu-arm -g 1234 memcpy 另开窗口 arm-...-gdb memcpy (gdb) target remote localhostip:1234 (gdb) b 10 (gdb) c (gdb) x/16uw 0x8e00 (gdb) b 30 4)查看内存的方式 x/nfu address n,查看内存单元个数 f,format显示内存单元的格式,x-16进制,d-10进制 u,unit单元大小,b-字节,h-半字,w-字3.2 多寄存器加载存储指令 【加载】 'LDM{cond} <address_mode> <Rb>{!}, <Reglist>{^} !,更新地址 reglist,r0,r1,r2,r3,r4,r5(r0-r5) address_mode, ia:inc after // i增大,r0/r1/r5/r6地址分别为0x...0/4/8/C ib:inc before // i增大,r0/r1/r5/r6地址分别为0x...4/8/C/0 da:dec after // d减小,r6/r5/r1/r0地址分别为0x...0/C/8/4 db:dec before // d减小,r6/r5/r1/r0地址分别为0x...C/8/4/0 Rb,基址寄存器 ^,两种作用,特权模式下使用用户模式下的寄存器。 // 编号小的基地址存在低地址上。 mov r10, #0x40000000 ldmxx r10, {r0, r1, r5, r6} @// xx 为地址模式 【存储】 'STM{cond} <address_mode> <Rb>{!}, <Reglist>{^} (同上)练习二: 使用多寄存器加载存储指令,实现memcpy,把0x8e00开始的16个字初始化。mov r0, #0x8e00 mov r1, #0x8f00 mov r2, #4 loop: ldmia r0!, {r3, r4, r5, r6} stmia r1!, {r3, r4, r5, r6} sub r2, r2, #1 cmp r2, #0 bne loop memcpy_ok: b .3.3 栈操作指令 【加载】 'LDMxx sp!, {reglist r5-r9} 【存储】 'STMxx sp!, {reglist r5-r9} xx,取值: FD==ia,full descend<下降> FA==ib,full ascend<上升> ED==da,empty descend EA==db,empty ascend push {fp} <==> stmfd sp!, {r11} // fp是r11的别名 pop {fp, pc} <==> ldm sp!, {fp, pc} 栈 - C语言中的作用: 1)存储局部变量 2)缓存LR4、状态寄存器访问指令 'MRS(mov reg cpsr) msr r0, cpsr @//r0=cpsr 'MSR(mov cpsr reg) msr cpsr_c, r0 @//cpsr[ 7 : 0 ]=r0[ 7 : 0 ] msr cpsr_fsxc, r0 @//cpsr=r05、协处理器指令 在ARM中最多可以有16个协处理器,命名为p0 p1 p2...p15 // p15协处理器比较有名,其中也有寄存器c0 c1 c2 // p15实现大小端的设置; // DDI0500D_cortex_a53_r0p2_trm.pdf P113. 搜索big-endian [25] 'MCR(mov cooperation reg) 'MRC(mov reg cooperation)6、软中断指令 'SWI/SVC n(n为立即数) 该指令会导致软中断异常产生,该异常的产生硬件会做4件事,ARM核会切换为SVC模式。7、乘法指令 'MUL8、交换指令 'SWP
----------------------------------------------------------------------------------------------------
一、ARM指令格式【ARM采用的是32位架构】 Byte:字节,8bits HalfWord:半字,16bits Word:字,32bits // 大部分ARM core提供:ARM-32bit指令集,Thumb-16bit指令集。【ARM指令的特点】 1)没每条指令的多功能; 2)指令都带有条件; 3)灵活的第2操作数。【ARM指令的基本格式】 "<opcode>{<cond>} {s} <Rd> , <Rn>{, <operand2>} cond:条件码。 如果不指定cond,则指令无条件执行。 <>:必须项。 { }:可选项。 opcode:指令助记符。 cond:执行条件。 S:是否影响CPSR状态寄存器的值。 Rd:目标寄存器。 Rn:第1个操作数的寄存器。 // 例如: SUBNES R2, R1, #0x20 @减法运算,条件NE,结果影响CPSR operand2:第2操作数,能够提高代码效率。 有如下形式: #immed_8r 常数表达式(立即数) Rm 寄存器的数值 Rm,shift 寄存器移位后的数值 /* 常数表达式 - 立即数:合法性 */ 一个8位的常数通过循环右移偶数位得到,即为合法常量。 // 例如:合法常数:0xFF, 0x104, 0xFF0, 0xFF000, 0xFF000000, 0xF000000F // 例如:非法常数:0x101, 0x102, 0xFF1, 0xFF04, 0xFF003, 0xFFFFFFFF Rm:寄存器的数值 Rm,shift:寄存器移位后的值 LSL #n:逻辑左移n位 LSR #n:逻辑右移n位 ASL #n:算术左移n位 ASR #n:算术右移n位 ROR #n:循环右移n位 RRX:带扩展的循环右移1位 // n位为2的n次方。二、ARM数据操作指令【数据处理指令】 1)数据传送指令 2)算术运算指令 3)逻辑运算指令 4)比较指令 5)测试指令 6)乘法指令《opcode操作码功能表》AND/EOR/SUB/RSB/ADD/ADC/SBC/RSC/TST/TEQ/CMP/CMN/ORR/MOV/BIC/MVN【数据传送指令】 mov/mvn ' mov{cond}{s} Rd, operand2 将8位立即数或寄存器传送到目标寄存器Rd中。 // 用于移位运算等操作。 ' mvn{cond}{s} Rd, operand2 将8位立即数或寄存器按位取反后传送到目标寄存器Rd中。 // 取反功能,可使寄存器装载范围更广的立即数。【算术运算指令】add/sub/rsb/adc/sbc/rsc add:加法 sub:减法 rsb:逆向减法 adc:带进位加法 sbc:带进位减法 rsc:带进位逆向减法 ' add{cond}{s} Rd, Rn, operand2 将operand2的值与Rn的值相加,结果保存到Rd寄存器。 // 其他算术运算指令等同于add。【逻辑运算指令】and/orr/eor/bic and:逻辑与 orr:逻辑或 eor:逻辑异或 bic:位清除(按位清0,其他位不变) ' and{cond}{s} Rd, Rn, operand2 将operand2的值与寄存器Rn的值按位作逻辑"与&"操作,结果保存到Rd中。 // 其他逻辑运算指令等同于and。---> 嵌入式控制寄存器的移位操作常用。【比较指令】cmp/cmn/tst/teq - 用的比较多! cmp:比较(本质:相减,影响cpsr标志位) cmn:负数比较(本质:相加,影响cpsr标志位) tst:位测试(本质:逻辑与,影响cpsr标志位) teq:相等测试(本质:逻辑异或,影响cpsr标志位) ' cmp{cond} Rn, operand2 将寄存器Rn的值减去operand2的值,根据操作结果更新CPSR中的响应条件标志位,以便后面的指令根据相应的条件标志来判断是否执行。 // 【注意】比较指令的本质是做算术运算,但唯一区别是并不保存运算结果。 // 【错例】cmp r2, r15, asr r0 @r15不允许与被控制移位的寄存器一起出现,在有移位操作的情况下,不能将r15用于任何操作数。【乘法指令】mul/mla/umull/umlal/smull/smlal mul:32bit乘法 mla:32bit乘加 ' mul{cond}{s} Rd, Rm, Rs 将Rm和Rs中的值相乘,结果的低32位保存到Rd中。 ' mla{cond}{s} Rd, Rm, Rs, Rn 将Rm和Rs中的值相乘,再将结果加上第3个操作数Rn,结果的低32位保存到Rd中。 // 【注意】r15不能用作rd, rm, rs, rn,且rd不能与rm相同。 umull/umlal/smull/smlal 均为64位指令。 umull:64bit无符号乘法 umlal:64bit无符号乘加 smull:64bit有符号乘法 smlal:64bit有符号乘加【分支指令】b/bl/bx b:分支指令branch bl:带链接的分支指令branch with link bx:带状态切换的分支指令branch and exchange(bx{cond} Rm) ' b{cond} label 跳转范围限制±32M字节地址内(ARM为字对齐,最低2位地址固定为0) // 【注意】bl指令需要与 mov pc, lr 一起使用,实现返回指定地址。【软中断指令】swi swi:软中断 ' swi{cond} immed_24 实现从用户模式变换到管理模式。三、ARM指令的寻址方式 ARM处理器具有 7 种基本的寻址方式: 1)立即寻址; // 立即寻址就是立即数寻址,操作数直接通过指令给出。 2)寄存器寻址; // 指令中的地址码是寄存器编号,执行时直接取寄存器的值来操作。 3)寄存器间接寻址; // 通过load/store完成对数据的传送操作。利用一个寄存器的值作为存储器地址,在指定的寄存器中存放有效地址,而操作数则放在存储单元中。 4)基址寻址; // 将基址寄存器的内容与指令中给出的偏移量相加,形成操作数的有效地址。 5)相对寻址; // 由程序计数器PC提供基准地址,指令中的地址码字段作为偏移量,两者相加后得到的地址为操作数的有效地址。 6)堆栈寻址; // 后进先出。使用一个专门的寄存器(堆栈指针)指向一块存储区域(堆栈),指针所指向的存储单元即是堆栈的栈顶。向上-递增堆栈,向下-递减堆栈。 7)块拷贝寻址; // 将寄存器内容复制到寄存器的地址所指示的存储器中,需要注意的是在存储第一个值之后存储器地址是增加还是减少。 ia - 传送后,地址+4 ib - 传送钱,地址=4 da - 传送后,地址-4 db - 传送后,地址-4四、存储器访问指令 ARM处理器是load/store型的,即它对数据的操作是通过将数据从存储器加载到片内寄存器中进行处理,处理完成后的结果经过寄存器存回到存储器中,以加快对片外存储器进行数据处理的执行速度。【单寄存器加载】ldr ldr:加载字数据 ldrb:加载无符号字节数据 ldrt:以用户模式加载字数据 ldrbt:以用户模式加载无符号字节数据 ldrh:加载无符号半字数据 ldrsb:加载有符号字节数据 ldrsh:加载有符号半字数据【单寄存器存储】str str:存储字数据 strb:存储字节数据 strt:以用户模式存储字数据 strbt:以用户模式存储字节数据 strh:存储半字数据【字和无符号字节的加载/存储指令】 ' ldr{cond}{t} Rd, <地址> 将制定地址上的字数据读入Rd。 ' str{cond}{t} Rd, <地址> 将Rd中的字数据存入制定地址。 ' ldr{cond}b{t} Rd, <地址> 将制定地址上的字节数据读入Rd。 ' str{cond}b{t} Rd, <地址> 将Rd中的字节数据存入制定地址。 // t 代表处理器是在特权模式下,存储系统也将访问看成是在用户模式下进行的。
新闻热点
疑难解答
图片精选