ARM的常数表达式

 

如果说Intel指令中的立即数,相信大家都很熟悉。类似的,Arm指令中的“立即数”就是常数表达式。之所以称为常数表达式,而不称为立即数是有原因的。

Intel指令属于CISC指令集,指令是不定长的,因此可以将任意32位立即数编码到指令内。

Arm指令属于RISC指令集,指令是定长的32字节。众所周知,指令中操作码是必须的字段,如果把32位立即数直接编码到指令内部,操作码就无“容身之地”了……

因此,Arm指令中“立即数”的位数必小于32位。那么如何在Arm指令中正常表示立即数呢?我们看看Arm的通用指令格式。

Arm指令中,操作码(opcode)、目的操作数(Rd)、源操作数1(Rn)是必须的字段。条件码(cond)、符号位标记(s)源操作数2(oprand2)是可选的。其中Rd和Rn必须是寄存器,因此Arm的“立即数”只能存储在oprand2。

在Arm的指令编码内,使用“立即数”的指令为“立即数”提供了12bit的存储空间,也就是说Arm的“立即数”只能表示212=4096个数字。这显然无法表示所有的32位立即数,如果使用这12bit表示0~4095的数字,那么从4096~(232-1)的数组都不能表示了。考虑到这种“后果”,Arm指令集的设计者们使用了一个技巧,即使用常数表达式代替立即数的概念。

常数表达式表示一个常数,且该常数对应8位的位图,即可以由一个8位的常数通过循环移位偶数位得到。

比如0x3fc可以由8位常数0xff循环左移2位或循环右移30位得到,是常数表达式。再比如0x1fe,虽然可以有0xff循环左移1位或循环右移31位得到,但是移动的位数不是偶数,因此不是常数表达式。

根据常数表达式的定义,常数表达式只需要12bit的存储空间。

12bit空间中,低8字节存储8位位图,高4字节存储循环右移的次数。4字节只能表示24=16种移动次数,但是由于常数表达式定义中,移位限定为偶数次,因此这4个字节刚好能表示0、2、4、6、8…32位16个数字!

比如0x3fc的二进制表示为0xfff,即使用8位数字0xff循环右移0xf*2=30次得到。

明确了常数表达式的含义后,可以通过简单的编程识别一个数字是否是常数表达式。

/*

循环左移两位

*/

void roundLeftShiftTwoBit(unsigned int& num)

{

unsigned int overFlow=num & 0xc0000000;//取左移即将溢出的两位

num=(num<<2) | (overFlow>>30);//将溢出部分追加到尾部

}

/*

判断num是否是常数表达式,8位数字循环右移偶数位得到

*/

bool constExpr(unsigned int num)

{

for(int i=0;i<16;i++){

if(num<=0xff)

return true;//有效位图

else

roundLeftShiftTwoBit(num);//循环左移2位

}

}

roundLeftShiftTwoBit函数将一个无符号32位整数循环左移2位,constExpr反复将一个无符号32位整数循环左移2位,直到发现该数字在0到0xff之间为止,否则表示该数字不是常数表达式。

通过常数表达式,Arm指令便避免了“立即数”仅仅局限于0~4095的数字范围的问题了。但是常数表达式仍不能表示全部的32位整数,比如0x1fe。对于非常数表达式的数字,只能通过拆分来解决。

比如Arm指令mov r0,#0x1fe不是合法的指令,因为0x1fe不是常数表达式。那么只能将0x1fe拆分,表示为两条指令,比如:

mov r0,#0xfe

add r0,r0,#0x100

除了拆分数字的方法,Arm的LDR宏使用临时变量的方式实现非常数表达式的数据传送,即:

LDR r0,=0x1fe

ldr宏指令不是Arm的真正指令,它由如下两条指令实现:

.tmp .word 0x1fe

ldr r0,.tmp

ldr r0,[r0]

Arm的ldr指令用于将内存的数据加载到寄存器。这里数字0x1fe被存储在ldr指令附近的位置.tmp处,ldr r0,.tmp被编译为ldr r0,[pc+offset]的形式,其中offset为符号.tmp相对ldr指令的偏移。这样ldr r0,.tmp获取了符号.tmp的地址,然后再次使用ldr r0,[r0]将.tmp地址处的数据取出,即0x1fe。

通过以上的描述,我们明确了Arm指令中常数表达式的真正含义,并基于此编写了一个验证常数表达式的函数。最后,我们解析了如何在Arm中实现非常数表达式数据的传送,并讨论了它的实现。希望对你理解Arm的常数表达式有所帮助。

ARM的常数表达式的更多相关文章

  1. ARM指令集(上)

    ADuC702x可以用两套指令集:ARM指令集和Thumb指令集.本小节介绍ARM指令集.在介绍ARM指令集之前,先介绍指令的格式. A.2.1  指令格式         (1)基本格式       ...

  2. ARM嵌入式整理

    填空 1指令含义 列出文件列表的ls命令 切换目录的cd命令 创建目录的mkdir命令 删除目录的rmdir命令 复制文件的cp命令 删除文件或目录的rm命令 让显示画面暂停的more命令 连接文件的 ...

  3. 常用 ARM 指令集及汇编

    ARM7TDMI(-S)指令集及汇编 ARM 处理器是基于精简指令集计算机(RISC)原理设计的,指令集和相关译码机制 较为简单,ARM7TDMI(-S)具有 32 位 ARM 指令集和 16 位 T ...

  4. ARM指令集详解--汇编

    1.       汇编 1.1.    通用寄存器 通用寄存器 37个寄存器,31个通用寄存器,6个状态寄存器,R13堆栈指针sp,R14返回指针,R15为PC指针, cpsr_c代表的是这32位中的 ...

  5. 开源纯C#工控网关+组态软件(八)表达式编译器

    一.   引子 监控画面的主要功能之一就是跟踪下位机变量变化,并将这些变化展现为动画.大部分时候,界面上一个图元组件的某个状态,与单一变量Tag绑定,比如电机的运行态,绑定一个MotorRunning ...

  6. C#复习笔记(4)--C#3:革新写代码的方式(Lambda表达式和表达式树)

    Lambda表达式和表达式树 先放一张委托转换的进化图 看一看到lambda简化了委托的使用. lambda可以隐式的转换成委托或者表达式树.转换成委托的话如下面的代码: Func<string ...

  7. 基于语法分析器GOLD Parser开发的数学表达式计算器

    最近发现一款文法分析神器,看完官网(http://goldparser.org/)的介绍后感觉很犀利的样子,于是就拿来测试了一番,写了一个数学表达式分析的小程序,支持的数学运算符如下所示:常规运算:+ ...

  8. Expression表达式树(C#)

    Lambda表达式: 1.下面举例通过Lambda表达式创建了一个用于验证Name的Func委托. //通过Lambda表达式创建一个对象的Name属性验证委托 Func<SearchInfo, ...

  9. C#3.0新增功能10 表达式树 02 说明

    连载目录    [已更新最新开发文章,点击查看详细] 表达式树是定义代码的数据结构. 它们基于编译器用于分析代码和生成已编译输出的相同结构.表达式树和 Roslyn API 中用于生成分析器和 Cod ...

随机推荐

  1. css雪碧图生成工具4.3更新

    v3.0更新介绍地址:http://www.cnblogs.com/wang4517/p/4476758.html v4.0更新介绍地址:http://www.cnblogs.com/wang4517 ...

  2. CSS3 波浪简单模拟--我是波浪,我有起伏,有大波与小波(坏笑中...)

    我是波浪,我有起伏,我有大波与小波(坏笑中...) 最近改版网站,一般也不会去写动画,但是有些网站还是需要的,故拿出一个较简单的动画出来分享,很简单很简单. 原理简单阐述 其实很简单,使用一张美工做好 ...

  3. nodejs复习03

    文件系统fs 重命名 fs.rename() fs.renameSync 优先选择异步,可以进行异常判断 打开关闭文件 fd = fs.openSync(file, flags) fs.closeSy ...

  4. LINUX 查看当前系统的内存使用情况

    # free 显示结果如下: Mem:表示物理内存统计 total 内存总数 8057964KB used 已使用的内存 7852484KB free 空闲的内存数 205480KB shared 当 ...

  5. hypermesh 之 interface操作

  6. The innocence is brilliant.

    [11.20~12.20] 2016年的最后一个月在听Avril的歌,感觉她发音状态好好(对此建议去听<Wish You Were Here>!!!) 到此12月份的活都干完了吧~还剩最后 ...

  7. From cls答辩

    我没有想过有一天会因为wjmzbmr而开一篇. 因为看到了cls答辩的链接而震撼或是感动. 可能也跟最近身心比较疲惫有关...容易产生这样那样的感触... cls可能已不是我们这代OIER所能膜到的了 ...

  8. C++-Qt【2】-实现一个简单的记事本

    用Qt实现一个简单的记事本: #include "helloqt.h" #include <qfiledialog.h> #include <qfile.h> ...

  9. js实现阶乘

    //while循环实现function calNum(n) { var product = 1; while(n > 1){//1*5*4*3*2,1*n*(n-1)*(n-2)*...*2 p ...

  10. 【填坑】bzoj3224 splay裸题

    人生第一道splay不出所料是一道裸题,一道水题,一道2k代码都不到的题 #include <cstdio> ,n,p,q; ],c[][],size[],sp[]; void rot(i ...