转载:http://www.tektalk.cn/2008/10/08/arm-emulator的世界/
1. qemu
http://bellard.org/qemu/
首先当然是大名鼎鼎的qemu了。Qemu目前能支持的指令集包括ARM/MIPS/PPC/X86等等。最新的版本是发布于2008年1月6日的0.9.1。对于ARM来说,目前的SVN的版本中(2008-10-07)支持的SOC/machine包括:
(1) integratorcp: ARM Integrator/CP (ARM926EJ-S)
(2) versatilepb: ARM Versatile/PB (ARM926EJ-S)
(3) versatileab: ARM Versatile/AB (ARM926EJ-S)
(4) realview: ARM RealView Emulation Baseboard (ARM926EJ-S)
(5) akita: Akita PDA (PXA270)
(6) spitz: Spitz PDA (PXA270)
(7) borzoi: Borzoi PDA (PXA270)
(8) terrier: Terrier PDA (PXA270)
(9) cheetah: Palm Tungsten|E aka. Cheetah PDA (OMAP310)
(10) n800: Nokia N800 tablet aka. RX-34 (OMAP2420)
(11) n810: Nokia N810 tablet aka. RX-44 (OMAP2420)
(12) lm3s811evb: Stellaris LM3S811EVB
(13) lm3s6965evb: Stellaris LM3S6965EVB
(14) connex: Gumstix Connex (PXA255)
(15) verdex: Gumstix Verdex (PXA270)
(16) mainstone: Mainstone II (PXA27x)
(17) musicpal: Marvell 88w8618 / MusicPal (ARM926EJ-S)
(18) tosa: Tosa PDA (PXA255)
从上面可以看出,qemu支持了非常多的ARM board。在执行效率方面,qemu采用了JIT的技术,因此,执行的速度比较快。曾经有报道说,在Athlon 64 3800+上,qemu上模拟Linksys NSLU2的效率比真正的硬件快20%[1]。
在目前已经release的版本中,qemu的动态翻译技术实际上是巧妙的利用了gcc来完成中间语言到host代码的翻译工作,也就是说其代码生成器是借助于gcc的。因此,qemu有对gcc版本的依赖。目前来说,推荐使用gcc3来编译运行qemu。对于gcc4的编译器,是不能成功用来编译运行qemu的。Qemu的动态翻译框架可以参考 [2][3]。
为了解决qemu依赖于编译器这个问题,必须要将原本gcc所做的代码生成器工作交由新的代码生成器来进行(看来投机取巧还是要付出代价的)。因此在目前SVN版本的qemu中引进了TCG(Tiny code generator)。这是一个将中间代码翻译成host指令的工具。比如ARM->中间语言->X86。后一步正是由TCG完成的。对于每一个不同的host,都必须有相应的翻译代码。也就是说TCG必须被移植到每一种支持的host。不过采用了TCG以后,可以对生成的basic block进行一定的优化,这是比原来的dyngen方式改进的地方[4]。
图片来自 http://www.aurel32.net/info/debian_arm_qemu.php
2. skyeye
http://skyeye.sourceforge.net/index.shtml
Skyeye是由国内的开发者所开发的一款ARM的emulator。不过对于MIPS的支持也正在进行中。目前,最新的版本是2008年06月10日放出的1.2.5。
Skyeye最初是基于gdb自带的armulator进行开发的,最初的版本运行的时候,过程很类似于gdb,只不过是指定gdb的target是sim。后来开发人员对程序的框架进行了修改,使得运行skyeye 更加方便和直观。
Skyeye支持比较多的ARM CORE和开发板。其支持的硬件包括:
Skeyeye采用了一种称为动态翻译模拟(DBCT)的技术来加速模拟[5]。实际上,该技术和qemu所使用的dyngen很类似。不同之处在于qemu是target->中间代码->host。而DBCT没有中间代码的生成这一个过程。由于DBCT也是采用了gcc来作为代码生成器,因此,其同样有对gcc编译器版本的要求。笔者曾经和DBCT的开发者teawater有过交流,由于teawater已经不参与skyeye的开发,因此对于DBCT的升级和维护目前是skyeye的一个需要解决的问题。
图片来自http://www.ibm.com/developerworks/cn/linux/l-skyeye/part3/s5/index.html
3. Device Emulator
Device Emulator是微软依据Shared Source Academic License发布一款ARM Emulator。实际上这个emulator也被集成到了微软的一系列开发工具中,比如Windows Mobile SDK,VS2005。使用Device Emulator ,可以模拟运行WinCE操作系统,进行WinCE的开发。Devices emulator 2.0的代码可以从这里[6]下载。
同qemu和skyeye一样,device emulator也采用了JIT的技术来加速模拟。下载的源代码包中有简单的JIT的文档说明。从文档中我们得知道,device emulator的JIT过程如下:ARM->IR->IR优化->X86。
虽然说,从IR->X86的过程类似于编译器的代码生成器。但是同编译器不同,对于emulator来说,这个翻译的过程必须要快,翻译的cache可能会被频繁的flush(比如当flush掉I-cache的时候),异步的中断会频繁发生。因此,这就决定了对于emulator来说,其优化必须是简单而快速的,这和编译器追求优化的代码生成不同。
在device emulator中,对于IR的优化主要有:
而对于其代码生成器来说,没有寄存器分配,也就是说,所有的寄存器内容直接保存在host的memory中而不是对应到host的register中。IR结构没有采用树结构,而是采用列表。没有其他诸如窥孔(peephole)等复杂的优化算法。
Device Emulator还有一个蛮有意思的功能。有过emulator开发经验的同学都知道如何调试emulator是蛮头疼的事情。对于解释型的emulator,可以写testcase来去验证对于每一个指令的模拟。而对于具有JIT功能的emulator,又如何调试呢?笔者曾经连续几天追踪一个emulator 的JIT中的bug,加了无数的log语句。虽然最后找出了bug,但各个滋味确实不是很好受。
Device Emulator提供了一个emulator比对的功能。假设你对emulator进行了一些修改,最后却发现修改后的emulator不能工作了。而修改之前的emulator是能够正常工作的。我们称能工作的emulator为GOOD Emulator,不能工作的emulator为BAD emulator。然后在同一台机器上step by step运行GOOD和BAD两个emulator。而在每一个指令模拟完以后,BAD Emulator会去检查BAD Emulator的寄存器值和GOOD Emulator寄存器值。任何一个不相等都会触发ASSERT。从而知道引起错误的是哪一条指令。
但是这种方式有一个前提条件:GOOD Emulator和BAD Emulator的指令执行的顺序必须是相同的。这在emulator中有中断发生的情况下,是不能保证的。比如GOOD Emulator在某一个时刻需要触发时钟中断,而这个时候并不能保证BAD Emulator也会触发时钟中断。因此上面所说的调试方式只适用于emulator中timer中断没有打开之前。对于Linux来说,也就是计算BOGOMIPS之前。
图片来自http://www.cnblogs.com/walzer/archive/2008/05/23/744729.html
4. ARMware
http://code.google.com/p/armware/
ARMware是一个模拟ARM平台的emulator。它模拟了Intel StrongARM SA-1110 CORE,模拟的开发环境类似于HP iPaq H3600。
根据作者的网站介绍,在ARMware中同样采用了动态编译技术来加速模拟。所采用的优化的方法有[7]:
不过目前,并没有audio和network的模拟。
ARMware 目前支援的平台有:
图片来自http://code.google.com/p/armware/
5. GXemul
http://gavare.se/gxemul/
同qemu一样,GXemul可以模拟多种指令集,包括ARM/MIPS/PPC/Super H。最新的版本为0.4.6.5。
对于ARM平台可以模拟的机器为[8]:
GXemul采用动态编译的技术来加速模拟。不过,其翻译的过程为ARM->IR,并没有IR到host的过程,业就是没有native的代码生成器。其IR实际上是指向模拟函数的指针。如下图:
相比于单纯解释型emulator,这种方式避免了重复的取指令/decode的过程。相比于QEMU,由于其没有代码生成器,因此可以说是不依赖于编译器版本,也不需要对于每一个host都写一个代码生成器。提高了可移植性。当然,性能应该是差于qemu的。不过作者认为这是可移植性和性能之间的折中。
图片来自http://gavare.se/gxemul/
6. 结束语
本文只是对常见的ARM Emulator进行了介绍。如果您有其他的ARM Emulator的信息或者对本文有任何的意见,欢迎和我联系( yajin ### vm-kernel.org )
[1] http://www.linuxdevices.com/news/NS9983843412.html
[2] http://cmchao.pixnet.net/blog/post/16035915
[3] http://cmchao.pixnet.net/blog/post/16037053
[4] http://cvs.savannah.gnu.org/viewvc/*checkout*/qemu/tcg/README?root=qemu&revision=1.1
[5] http://www.linuxforum.net/forum/showthreaded.php?Board=program&Number=615579
[6] http://www.microsoft.com/downloads/details.aspx?FamilyID=dd567053-f231-4a64-a648-fea5e7061303&displaylang=zh-cn
[7] http://code.google.com/p/armware/wiki/Chinese_Introduction
[8] http://gavare.se/gxemul/gxemul-stable/doc/intro.html#emulmodes