这种转变/跳跃能否比转换...案例声明更快?

时间:2015-06-03 11:00:20

标签: assembly x86 switch-statement emulation opcodes

我试图在其最大值处优化分支(交换机......类似情况)以模拟x86 CPU上的X CPU。我想到了这一点:在内存中,我将加载x86 opCodes的块,其长度固定为0x100字节,如下所示:

first block 
0
...[my code, jump at 0x10000, nop nop nop until 0x9F...]
0x9F
second block 
0x100
...
019F
third block
0x200
...
0x29F
...
etc, etc
...
0x10000

这将是有限的,从内存$ 0开始(+可能是一些偏移量)并以$ 0xFFFF结束(如#0x; rom"大小为0x10000)。现在,每次获取和模拟X CPU opCode时,我都会这样做:将其向左移8位并跳转到该位置。执行此操作,并正常继续我的程序流程。我的问题是:1)这些opCode块是否可能如此紧凑? 2)这是过去常见的做法吗?

1 个答案:

答案 0 :(得分:1)

如果你通过一个开关模块分支256个操作码,你将会进行间接跳转,这是CPU无法预测的,这会让你在每个操作码上都有一个管道中断。

如果模拟操作码的工作是合理的,那么这个管道中断可能并不重要。我怀疑它确实如此; a"加载寄存器"操作码基本上只是通过内存读取进行模拟,这不是很多工作。

您可以通过在切换块之前添加特殊测试来购买一些可见的改进,检查两个或三个最频繁的操作码(可能是LOAD,CMP,JMP条件)[如果opcode = JMP则...]这些测试CPU 可以通常预测良好。如果您这样做,请进行测量,测量和测量。

如果可以的话,一个更好的技巧是分摊多个指令的管道中断成本。如果机器有很多单字节操作码,您可以考虑在接下来的两个操作码字节中执行65536路分支。 (现在你必须编写很多开关案例,但很多都是 基本上是一样的。想知道你的编译器是否可以处理它?)在摘要中,这会将管道中断成本降低两倍。对于具有非常规则指令集的特定机器,这可能不会给你带来很多。

但是,您可能没有很多单字节操作码,但您可能需要为每条指令解码一个或多个字节。 x86就像这样(前缀,操作码,MODRM,SIB,偏移......)。大开关盒应该可以很好地工作。

将每个开关盒对齐在缓存行边界上可能是件好事。如果指令仿真很简单,则代码可能适合高速缓存行,因此内存只能看到该高速缓存行的一次提取。如果你不这样做,你的指令仿真将有更高的机会跨越缓存行边界,将内存获取成本提高到两倍。 这对于频繁执行的指令可能无关紧要,但是很少执行的指令的代码可能会从缓存中掉出来。当你真正遇到其中一个时,这将有所帮助。

最后一点建议:衡量,衡量,衡量。