linux嵌入式编程学习笔记(1)


ARM汇编指令:

指令基本格式: {{s} , {,}}

其中<>为必选项, {}为可选项

: 助记符, 如LDR, STR等

cond: 执行条件, 如BEQ, BNE等

助记符后跟S, 影响CPSR的值, 如SUB加S后为SUBS

Rd: 目标寄存器

Rn: 第一个操作数的寄存器

operand2: 第二个操作数

存储器访问指令:

加载/存储体系结构:

ARM是RISC结构, 无法直接对存储数据进行操作, 首先要加载到寄存器才能处理

对寄存器访问使用加载指令LDR和存储指令STR实现

可以实现半字, 字, 无符号/有符号字节操作

基本命令:

LDR R1, [R0]: 将R0值作为内存地址, 取出该地址的值保存到R1

STR R1, [R0]: 将R1的值保存到以R0中的值为地址的存储单元中

LDRB/STRB: 读取一字节

LDM/STM: 数据块传输指令, 实现一组寄存器和连续内存单元之间的数据传输

加载(LDM)或存储(STM)一组寄存器

支持堆栈操作

SWP R1, R1, [R0]: 将R1与R0指向的存储单元内容进行互换

SWP R1, R2, [R0]: 将[R0]读取到R1, 将R2写入到[R0]存储单元中

数据传输指令:

MOV R1, #1: 将立即数1传送到寄存器R1中

MOV R1, R0: 将R0中的值传送到R1寄存器中

MOV PC, LR: 子程序返回

MVN R1, #0xff: 将0xff取反后赋值给R1

算术逻辑运算指令:

加减指令:

ADD R1, R1, #1: R1 = R1 + 1

ADC R1, R1, #1: R1 = R1 + 1 + C(CPSR中的进位/借位标志位), 用于64位数据的相加

SUB R1, R1, R2: R1 = R1 - R2

SBC R1, R1, R2: R1 = R1 - R2 - C, 用于64位数据的相减

与或非指令:

AND R0, R0, #3: 将R0与立即数3(00000011)相与, 即保留R0中的0, 1位, 其余位置零(两数相与, 见零则零, 全一则一)

ORR R0, R0, #3: 置位R0中的0, 1位, 其余位不变(两数相或, 见一则一, 全零则零)

异或指令:

EOR R0, R0, #3: 反转R0中的0, 1位, 其余位不变(两数异或, 同零异一, 与零异或为原数, 与一异或为取反)

清除指令:

BIC R0, R0, #3: R0与取反的立即数3(11111100)相与, 即置零R0中的0, 1位, 其余位不变

乘法指令:

MUL R2, R1, R0: R2 = R1 * R0

带累加的乘法:

MLA R3, R2, R1, R0: R3 = R2 * R1 +R0

比较指令:

影响CPSR状态寄存器的N(31: 负数标志位), Z(30: 零标志位), C(29: 进位标志位), V(28: 溢出标志位)

CMP R1, #10: R1 - 10

CMP R1, R2: R1 - R2

CMN R0, #1: R0 - (-1), 与负数比较

TST R1, #1: R1 & 1, 位测试, 测试0位为0或1

TEQ R1, R0: R1 ^ R0(异或), 测试两数是否相等

条件执行:

几乎所有ARM指令都可以根据CPSR的标志位, 有条件地执行

条件码 ------CPSR标志位-------含义

EQ------------Z = 1-----------------相等

NE------------Z = 0-----------------不相等

CS/HS-------C = 1----------------无符号数大于或等于

CC/LO-------C = 0----------------无符号数小于

MI-------------N置位----------------负数

PL-------------N清零----------------整数或零

VS-------------V置位----------------溢出

VC-------------V清零----------------未溢出

HI -------------C置位, Z清零-------无符号数大于

LS-------------C清零, Z置位-------无符号数小于或等于

GE-------------N = V-----------------有符号数大于或等于

LT--------------N != V ---------------有符号数小于

GT-------------Z清零, N = V-------有符号数大于

LE-------------Z置位, N != V------ 有符号数小于或等于

AL--------------忽略------------------无条件执行

NV-------------忽略-------------------从不执行

跳转指令:

B label: 跳转到label处, 跳转范围为前后32M

BL label:

带链接跳转, 先将下一条指令保存到LR, 然后再跳转

MOV PC, LR: 常用于函数调用, 然后从子程序返回

BX Rm:

带状态切换跳转, Rm保存的是跳转地址, 处理器根据Rm的0位决定切换到ARM或Thumb状态

0位状态: 0: 目标地址为ARM指令, 1: 目标地址为Thumb指令

BLX label: 带链接和状态切换跳转

伪指令:

为了编程方便定义的伪指令, 并不是ARM指令集中的指令

编译时会将这些伪指令等效为一条或多条机器指令

四条伪指令:

ADR R0, label: 将标号地址放入R0

将基于PC的相对偏移地址值存入寄存器中

相对寻址, 与代码位置无关

ADR当前指令地址为PC-8

偏移量为标号地址-(PC-8)

ADRL: 中等范围的地址读取伪指令

LDR: 大范围的地址读取伪指令, 常用来加载外部设备的寄存器地址, 参数带有"="

若等号后立即数小于8bit, 则等价于MOV

若等号后立即数大于8bit:

在内存中定义一个字的存储单元, 将立即数存放在存储单元中, 该存储单元通常叫做文字池(literal pool)

计算出该存储单元到LDR伪指令之间的偏移地址offset, 即可用相对寻址, 将这个立即数存入寄存器

NOP: 空操作伪指令, 常用来延时

LDR, MOV和LDR伪指令的区别:

指令格式:

LDR伪指令的指令格式为:

LDR R0, =0xffffffff: 有等号表示是伪指令, 将立即数0xffffffff存入R0

LDR R0, LOOP: 将标号LOOP所代表的内存地址存入R0

LDR指令通常用于寄存器间接寻址:

LDR R0, [R1]: 将R1的值作为内存地址, 取该地址的内容存入R0

LDR R0, LOOP: 将标号LOOP代表的内存地址处的内容存入R0

MOV指令通常用于寄存器间的数据传输:

MOV R0, R1: 将寄存器R1的值存入R0

MOV R0, #20: 将立即数20存入R0

用途:

ARM是RISC结构, 不能直接操作内存数据, 要通过LDR/STR指令在内存中和寄存器之间存取数据

MOV指令用于在寄存器之间存取数据

LDR伪指令用于加载一个32位立即数或地址到指定寄存器

LDR指令与ADR指令比较:

相同点:

都是ARM伪指令, 加载一个地址到指定寄存器

不同点:

LDR伪指令通常被被翻译为LDR或MOV指令, 而ADR伪指令通常被翻译为ADD所SUB指令

LDR主要用来操作外设寄存器, ADR主要通过相对寻址, 生成与位置无关的代码, 只要各标号相对位置不变, 就可以做到与位置无关

LDR使用绝对地址, ADR使用相对地址

LDR范围为4G, ADR要求标号必须在同一个段中, 偏移地址对齐时为1020, 未对齐时为4096


本文为我原创

-- --
  • 投诉或建议
评论