嵌入式Arm立即数判定


基础知识

在ARM中,机器指令的格式大致有以下几种:

ARM指令格式

立即寻址的方式

立即寻址

立即寻址

  • 在立即寻址,操作数本身直接在指令中给出,取出指令也就获得了操作数,这个操作数也称为立即数。例子如下
ADD R0, R1, #0xF      ;R0=R1+15
MOV R0, #0x55       ;R0=0x55 

在这两个例子中0xF和0x55就是立即数。(立即数要以#开头)

抛出问题

  • 我们知道因为ARM指令长度是32-bit的,所以立即数不可能还有32-bit。
  • ARM在指令格式中设定,只能用指令机器码32位中的低12位来表示要操作的常数。
  • 但是简单的用这12位来表示,显然范围太小了,为了扩展到32-bit,因此使用了构造的方法,在12位中用8位来表示基本数据值,用4位表示移位值,通过用8位基本数据值往右循环移动4位位移值×2次,来表示要操作的常数。
  • 这里要强调终的循环次数是4位位移值乘以2得到的,所以得到的终循环次数肯定是一个偶数,为什么要乘以2呢,实质还是因为范围不够,4位表示位移次数,大才15次,加上8位数据还是不够32位,这样只能通过ALU的内部结构设计将4位位移次数乘以2,这样就能用12位表示32位常数了。

具体点的定义:

立即数 = immed_8 循环右移 (2 * Rotate_imm)
如果存在一个 Rotate_imm 能够让该立即数由 immed_8 循环右移 2×Rotate_imm 位( 偶数位 )表示,那么这个立即数就是合法的。

那么什么样的立即数才是合法的?

合法立即数的判断

  1. 把数据转化二进制形式,4位一组,不够的补0
  2. 数1的个数,大于8个肯定不是立即数
  3. 如果小于8个,如果数据是两端为1,中间有连续的大于等于24个0,循环左移4的倍数,使高位全为0
    • 比如 1111 0000 0000 0000 0000 0000 0000 1111
  4. 找到最高位的1,尽可能多的去掉前面的0(去掉的0必须是偶数个)
    • 比如 0001 0010 0010 ,最高位的1前面有3个0,所以去掉2个0,即 ××01 0010 0010
  5. 找到最低位的1,尽可能多的去掉后面的0(去掉的0必须是偶数个)
    • 比如 0001 0010 0010 ,最低位的1后面有1个0,所以出掉0个0,即 ××01 0010 0010
  6. 数剩下的位数,如果小于等于8位,那么这个数就是立即数,反之就不是立即数

举几个例子

(1)0x4FF
  1. 0100 1111 1111
  2. 有9个1,大于8,所以不是立即数
(2)0x122
  1. 0001 0010 0010
  2. 3个1,小于8
  3. 不满足中间有24个0
  4. 最高位的1前面有3个0,所以去掉2个0,即××01 0010 0010
  5. 最低位的1后面又1个0,所以去掉0个0,即××01 0010 0010
  6. 剩下××01 0010 0010共10位,大于8,所以不是立即数
(3)0x234
  1. 0010 0011 0100
  2. 4个1,小于8
  3. 不满足中间有24个0
  4. 最高位的1前面有2个0,所以去掉2个0,即××10 0011 0100
  5. 最低为的1后面又2个0,所以去掉2个0,即××10 0011 01××
  6. 剩下的共8位,等于8,是立即数
(4)0xF000000F
  1. 1111 0000 0000 0000 0000 0000 0000 1111
  2. 8个1,不大于8
  3. 满足中间有24个0,循环左移4位,使高位全为0,即0000 0000 0000 0000 0000 0000 1111 1111
  4. 最高位的1前面有24个0,所以去掉24个0,即×××× ×××× ×××× ×××× ×××× ×××× 1111 1111
  5. 最低为的1后面没有0
  6. 剩下的共8位,是立即数
(5)0x8000007F
  1. 1000 0000 0000 0000 0000 0000 0111 1111
  2. 8个1,不大于8
  3. 满足中间有24个0,循环左移4位,是高位全为0,即0000 0000 0000 0000 0000 0000 0111 1111 1000
  4. 最高位的1前面有24个0,所以去掉24个0,即xxxx xxxx xxxx xxxx xxxx xxxx 0111 1111 1000
  5. 最低为的1后面有3个0,所以去掉2个0,即xxxx xxxx xxxx xxxx xxxx xxxx 0111 1111 10xx
  6. 剩下的共10位,大于8,不是立即数

如何规避立即数

  • 可以通过使用 LDR 伪指令代替
    • 例如直接把MOV指令变为, LDR R1,=0x12345678这样编译器就不会报错。

总结

适合自己的方法才是最好了,真正理解了才能叫懂了!

才疏学浅,望雅正!


文章作者: incipe
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 incipe !
评论
 上一篇
嵌入式学习笔记(3) 嵌入式学习笔记(3)
ARM指令集精简指令集设计理念(The RISC design philosophy) 设计原则(Design rules) 指令”短小精悍” 应用流水线技术设计 大量采用寄存器 Load/Store存储结构 ARM指令集特点 所有
2020-05-13
下一篇 
Makefile简单使用 Makefile简单使用
一. 题外话1.1 c/cc编译流程以 main.cpp 为例: 1.2 gcc编译参数( 部分)除了前面的 -E -S -c 以外 -o 指定输出的文件名; -Wall 启用所有警告; -w 不产生任何警告; -g 生成调试信息; -
2020-05-13
  目录