arm-emulator的世界

本文介绍了常见的ARM模拟器,如QEMU、Skyeye、DeviceEmulator等,对比了它们的技术特点,如动态编译加速、代码优化方法及调试手段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载: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和开发板。其支持的硬件包括:

  • CPU CORE: ARM7TDMI, ARM720T,StrongARM, XScale, Blackfin
  • APPLICATION CPU: Atmel AT91X40/AT91RM9200,Cirrus CIRRUS LOGIC EP7312/EP9312 CS89712,Intel SA1100/SA1110, Intel PXA 25x/27x, Samsung 4510B/44B0/2410/2440 , Sharp LH7xxxx, NS9750, Philips LPC22xx, BF533
  • MEMORY: RAM, ROM, Flash
  • Peripheral: Timer, UART,NIC chip,LCD, TouchScreen, etc.

      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的优化主要有:

  1. ARM PSR标志的计算
  2. 简单的代码合并

      而对于其代码生成器来说,没有寄存器分配,也就是说,所有的寄存器内容直接保存在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]:

  • Redundant condition code calculation elimination
  • Global grouping conditional execuating instruction
  • Redundant jump elimination
  • Dead code elimination
  • Constant folding
  • Global Common Subexpression Elimination
  • Global redundany memory operation elimination
  • Algebraic canonicalization
  • Global SSA form based linear scan register allocation
  • I use MMX and SSE2 instructions to accomplish the rotation of the LCD screen of HP iPaq by an angle of 270 degrees (That is to say, you have to execute ARMware on a CPU with MMX and SSE2 instruction sets, like Pentium M or Pentium 4).
  • I also use x86 assembly codes to accomplish the condition codes calculation in the ARM processor.

      不过目前,并没有audio和network的模拟。
      ARMware 目前支援的平台有:

  • Win32 (using Visual C++ 2005 (express))
  • Linux (using gcc)


图片来自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]:

  • CATS (NetBSD/cats, OpenBSD/cats)
  • IQ80321 (NetBSD/evbarm)
  • NetWinder (NetBSD/netwinder)

      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

### Locale-Emulator 报错解决方案 在使用 Locale-Emulator 时,可能会遇到各种错误情况。以下是常见的错误及其对应的解决方案: #### 1. **无法模拟区域设置** 如果发现 Locale-Emulator 未能成功更改设备的语言或地区设置,可能是由于权限不足或其他配置问题引起的。可以通过以下方式解决: - 确保已授予应用所需的权限,例如 `WRITE_SETTINGS` 或者 `SYSTEM_ALERT_WINDOW` 权限[^1]。 - 如果是在 Android 10 及以上版本运行,可能需要额外启用开发者选项中的“允许调试 APK”功能。 #### 2. **ADB 命令执行失败** 当尝试通过 ADB 控制 Locale-Emulator 的行为时,可能出现命令执行失败的情况。例如,在停止 QQ 应用的过程中出现问题: ```bash [D:\android-sdk-windows\platform-tools\adb.exe -P 5037 -s emulator-5554 shell am force-stop com.tencent.mobileqqi] ``` 这通常是因为目标设备未连接、包名拼写错误或者服务不可用所致[^2]。可以按照以下步骤排查: - 验证设备是否正常连接并处于可调试状态:`adb devices`。 - 检查指定的应用包名是否正确。 - 尝试重启 ADB 服务器:`adb kill-server && adb start-server`。 #### 3. **窗口管理异常** 某些情况下,Locale-Emulator 可能会抛出类似于以下的错误: ```plaintext android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application ``` 这种问题是由于窗口令牌无效造成的。具体原因和修复方法如下: - 错误通常是由于上下文不匹配引起,比如使用了 `getApplicationContext()` 而非 Activity 上下文[^3]。 - 修改代码逻辑,将 `getApplication()` 替换为当前 Activity 实例(即 `this`),从而确保正确的上下文传递。 #### 4. **广播接收器注册问题** 如果 Locale-Emulator 使用了动态广播接收器,则可能存在未注销广播接收器的风险。典型表现为日志中提示类似以下内容: ```plaintext call you are unregister onbrocastRevicer? ``` 这是由于忘记调用 `unregisterReceiver()` 方法导致的资源泄漏问题[^3]。建议在生命周期结束前显式注销广播接收器。 #### 5. **更新冲突** 安装过程中出现以下错误信息: ```plaintext INSTALLATION error: INSTALL_FAILED_UPDATE_INCOMPATIBLE ``` 该问题表明旧版应用尚未完全卸载就试图覆盖安装新版本[^3]。推荐的操作流程包括: - 手动删除现有应用实例后再重新部署。 - 清理缓存数据以及关联文件夹路径下的残留记录。 #### 6. **R.java 文件丢失** 开发阶段偶尔会发生 R.java 自动移除的现象,并伴随重建需求的通知: ```plaintext R.java was removed! Recreating R.java! ``` 此类警告一般不会影响最终产物质量,但仍需注意保持构建环境稳定性和依赖同步准确性[^3]。 --- ### 示例代码片段 下面提供一段简单的脚本用于验证 Locale-Emulator 是否能够切换至特定语言环境: ```java import android.content.Context; import android.os.LocaleList; public class LocaleHelper { public static void setAppLocale(Context context, String languageCode) { LocaleList localeList = new LocaleList(new Locale(languageCode)); LocaleList.setDefault(localeList); Configuration config = context.getResources().getConfiguration(); config.setLocales(localeList); context.createConfigurationContext(config); // Apply changes immediately. } } ``` --- ### 总结 针对 Locale-Emulator 中常见的一些报错现象进行了分析说明,并给出了相应的调整措施。实际操作时还需结合具体情况灵活应对。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值