黎明灰烬 博客 +

Transmeta Crusoe 技术揭秘

review on The Technology Behind Crusoe Processors

摘要

Crusoe处理器是Transmeta公司在2000年左右推出的X86兼容系统所依赖的硬件平台。 和传统的纯软件二进制翻译实现的兼容系统不一样,Transmeta通过打造完整的软硬件平台可以高效地模拟X86处理器。 该方案包含两部分:Crusoe处理器和Code Morphing翻译器。 本质上,Crusoe是一个VLIW(超长指令字)处理器,每个时钟周期可以执行多个功能(类似于多发射)。 通过利用VLIW的这种特性,Transmeta重新组织X86翻译后代码,使得多条指令可以“并行”执行,从而提高性能。 Crusoe的主要贡献在于开辟了一种全新的软硬件结合设计方法,使得协同设计真正地能提供一致性平台。(区别于传统的处理器即平台) 基于协同设计的特点,Crusoe方案不光在性能上取得了显著的成果,同时还降低了硬件设计复杂度、硅片面积、功耗等。

技术愿景

传统的处理器设计以ISA(指令集)为界面:处理器需要实现所有ISA的功能,软件以ISA为标准使用处理器功能。 作为软硬件界面的ISA存在一定的弊端:一方面,ISA要保证兼容性,这要求处理器实现所有以往的功能,还不能随意添加新功能; 另一方面,ISA限制了软件的编程能力,要使用新的硬件特性必然需要重写软件。

Crusoe方案从某种程度上实现了ISA的虚拟化。通过将X86翻译为Crusoe的VLIW指令,ISA兼容的问题解决了,因为指令翻译是由软件完成的,修改代价较低。 另一方面,硬件复杂度也降低了,Crusoe不再需要复杂的流水线系统,指令优化、流水线维护工作可以交给Code Morphing做。

Crusoe处理器基本原理

现代高性能处理器大多采用激进的多发射、动态流水线、乱序执行、寄存器重命名设计。 这种方法在提高性能的同时也给硬件设计带来极大的困难。 Transmeta构建的这套软件硬件协同系统使得处理器不需要再考虑乱序执行、动态流水线、寄存器重命名等工作。 这些带来巨大硬件设计(功耗、面积)开销的功能均由Code Morphing建立的运行时环境完成。 Crusoe处理器就是一个简单的VLIW引擎。

Crusoe处理器包含两个定点单元、一个浮点单元、一个访存单元和一个分支单元。 对应地,它的每条指令(称之为“分子”)可以包含4个操作(称之为“原子”):浮点运算、定点运算、访存、分支。 每条指令为128比特,每个操作是32比特。分子的格式如下图所示。 显然地,每个原子在一个分子中由固定位置,一个分子不一定要包含四个有效的原子。 即可能某一条VLIW指令仅仅执行了一个定点运算操作。

Crusoe处理器“分子”图

传统高性能处理器的乱序执行需要存在巨大开销,因为硬件要记录流水线中每一条指令的编号,保证按序提交。 这种功能的简化流程图如下图所示。 而在Transmeta方案中,乱序执行由软件功能提供。 Code Morphing还可以采用激进的编译优化技术,实现编译时无法确定的动态软流水,从而提高系统性能。 这样一来,Crusoe处理器的芯片面积得到了大大减少。

X86乱序执行示意图

同时,对于X86这样带有复杂译码机制的处理器(内部采用微码RSIC结构),重复执行一段代码所带来的译码代价也是很高的。 Code Morphing在翻译X86代码时将翻译后代码存入缓存中,对于同一段代码只需要翻译一次。 这种机制实质上提高了系统性能,还降低了系统功耗。

Code Morphing 系统

Crusoe方案的提出是为了以一种全新的方式实现X86兼容。 Code Morphing的主要功能就是在Crusoe处理器上模拟出一套X86环境,使得上层软件认为自己运行在X86处理器上,如下图所示。 TM3120和TM5400的产品化已经证明这种方案是可行的。

Code Morphing 结构

划分软硬件界面

虽然Crusoe打破了原有的ISA界面,但在本系统中仍然需要一个确定的软硬件界面。 Crusoe划分的标准在于将X86结构中复杂的工作和生成高效VLIW指令的工作交给软件来做。 硬件只负责一个简单高效的VLIW引擎。 值得说明的是,Crusoe的划分是非常灵活的,因为VLIW界面并不会开放给所有用户使用,用户编程的界面仍旧是X86.

译码和调度

作为一个二进制翻译器,Code Morhping只要翻译一次X86代码。 这相当于降低了传统X86处理器在译码阶段的开销。要知道,作为一个CISC处理器,X86的译码开销是显著的。 同时,Code Morphing也消除了处理器的分派开销,使得不再需要动态流水线来实现复杂的代码调度。

缓存

Code Morphing将翻译后代码存在在缓存中,不需要多次翻译。 基于局部性原理,常规程序的执行表现会非常好。甚至随着执行次数越多,平均性能越好。 当然,某些“不友好”的benchmark并不会展示出Crusoe的这种特长。

过滤

Code Morphing可以动态地检测代码的执行次数,剖析程序行为。 这样一来,可以应用启发式算法来翻译代码: 在最开始所有代码都执行简单翻译,随着程序的执行,翻译器针对特点代码作深入的代码调度来优化性能。

预测和路径选择

传统处理器在分支预测失败或跳转是会导致流水线失效。这对于多发射流水线来说简直就是性能灾难。 而对于Crusoe方案来说,由于复杂流水线由软件实现,针对分支和跳转由两种解决办法。 Code Morphing在流水线上同时执行两个分支后的代码,在得知分支结果后选择正确的分支执行结果。 这种方法将执行路径相关转换成数据相关,有效地解决了流水线失效的问题。 对于跳转,Code Morphing可以在翻译阶段使用软件流水调度指令来解决。(文章中并没有这么说)

翻译

Code Morphing可以在运行时动态翻译,发现许多在编译时无法确定的事实,从而采用编译优化技术提高性能。 这意味着:虽然硬件不支持乱序执行,但从X86 ISA角度来说,Crusoe平台就是乱序执行的。

X86代码:

A. addl %eax,(%esp)     // load data from stack, add to %eax
B. addl %ebx,(%esp)     // ditto, for %ebx
C. movl %esi,(%ebp)     // load %esi from memory
D. subl %ecx,5          // subtract 5 from %ecx register

第一趟翻译后代码:

ld %r30,[%esp]          // load from stack, into temporary
add.c %eax,%eax,%r30    // add to %eax, set condition codes.
ld %r31,[%esp]
add.c %ebx,%ebx,%r31
ld %esi,[%ebp]
sub.c %ecx,%ecx,5

第二趟翻译后代码,减少了一次读操作:

ld %r30,[%esp]          // load from stack only once
add %eax,%eax,%r30
add %ebx,%ebx,%r30      // reuse data loaded earlier
ld %esi,[%ebp]
sub.c %ecx,%ecx,5       // only this last condition code needed

VLIW代码:

ld %r30,[%esp]; sub.c %ecx,%ecx,5
ld %esi,[%ebp]; add %eax,%eax,%r30; add %ebx,%ebx,%r30

Crusoe特殊硬件支持

Crusoe包含三个特殊的硬件支持来提高系统模拟X86的性能。

例外和推测

上文中可以看到,Code Morphing的代码调度可以调整访存指令的排列,以提高处理器各部件利用率。 但激进的代码调度可能导致错误:上一节例子中,如果第二条VLIW指令发生页缺失例外,这是sub指令执行完成,会造成逻辑错误。 为了解决这种问题,Crusoe引入了“影子”处理器状态(相对于“工作”处理器状态)。 每执行一次翻译时,Crusoe复杂维护“影子”状态。 如果这段翻译后代码执行没有触发例外,那么在执行完成之后Crusoe会更新影子状态。 否则,Crusoe会从影子状态中恢复出“最后正确”的处理器状态,进入“保守”执行模式以定位出发例外的指令。 在“保守”模式中,每条VLIW只执行一种功能。

对于访存功能,Crusoe维护了一个访存buffer,所有的访存结果都缓存在这里。 当某段翻译后代码执行成功后,buffer中内容会被真正写入存储器; 否则,Crusoe无效掉buffer中所有例外发生后的存储器写操作。

别名硬件

对类似“针对同一个地址‘读-写-读’”重排可能会带来错误,一般的编译器在优化访存相关代码时都非常保守。 Crusoe增加了特殊的硬件功能来记录来检测的访存冲突,使得Code Morphing可以对访存指令作激进的代码调度。 同时,这种特性还可以减少“重复读”指令,因为带标记的访存指令对可以放肆执行,系统能确保它们被正确执行。 下面是一个例子。

传统代码:

ld %r30,[%x]        // first load from location X
...
st %data,[%y]       // might overwrite location X
ld %r31,[%x]        // this accesses location X again
use %r31

Crusoe上的代码:

ldp %r30,[%x]       // load from X and protect it
...
stam %data,[%y]     // this store traps if it writes X
use %r30            // can use data from first load

自修改代码

X86包含很多自修改代码,如果没有特殊机制,自修改代码会导致程序运行逻辑紊乱。 Crusoe增加了特殊的标记位,将翻译后代码区域(如果x86代码地址也被转换了)置为保护态。 这样一来,所有的自修改代码都会导致Code Morphing陷入,从而由特殊的机制来保证翻译后代码也被修改。

一个复杂的翻译实例

下面展示一个摘自Windows NT操作系统的代码翻译实例。 它在某种程度上展示了前面所描述的Crusoe特性:分支、寄存器重命名、指令重排、分支选择、别名……

X86代码:

    movl %ecx,$0x3
    jmp lbl1
    ...
    lbl1: movl %edx,0x2fc(%ebp)
    movl %eax,0x304(%ebp)
    movl %esi,$0x0
    cmpl %edx,%eax
    movl 0x40(%esp,1),$0x0
    jle skip1
    movl %esi,$0x1
    skip1: movl 0x6c(%esp,1),%esi
    cmpl %edx,%eax
    movl %eax,$0x1
    jl skip2
    xorl %eax,%eax
    skip2: movl %esi,0x308(%ebp)
    movl %edi,0x300(%ebp)
    movl 0x7c(%esp,1),%eax
    cmpl %esi,%edi
    movl %eax,$0x0
    jnl exit1
exit2:

翻译后VLIW代码:

    addi %r39,%ebp,0x2fc
    addi %r38,%ebp,0x304
    ld %edx,[%r39]; add %r27,%r38,4; add %r26,%r38,-4
    ld %r31,[%r38]; add %r35,0,1; add %r36,%esp,0x40
    ldp %esi,[%r27]; add %r33,%esp,0x6c; sub.c %null,%edx,%r31
    ldp %edi,[%r26]; sel #le,%r32,0,%r35
    stam 0,[%r36]; sel #l,%r24,%r35,0; add %r25,%esp,0x7c
    stam %r32,[%r33]; add %ecx,0,3; sub.c %null,%esi,%edi
    st %r24,[%r25]; or %eax,0,0; brcc #lt,<exit2>
    br <exit1>

LongRun 功耗管理

为了控制功耗,传统的X86处理器有工作/不工作两种模式。X86通过调整这两种模式切换的频率来控制功耗。 考虑这样一种情况,当处理器被短暂关闭时,恰好出现一个需要大量运算的应用需求,这种控制模式会导致该应用响应速度降低。 比如在播放视频时,不恰当地关闭处理器会造成丢帧,这种影响会极大地降低用户体验。

TM5400控制功耗的方法较为先进,它能通过软件配置,实时地调整处理器运行速度(时钟频率),从而匹配应用需求。 这种动态频率调整方法较为平滑,不会引起巨大的性能波动,对用户透明。 在调整频率的同时,TM5400还可以调整处理器工作电压。 这两种方式结合起来可以以近乎指数级的表现降低功耗。

结论

自1995年起,Transmeta就在处理器市场,主要是移动计算市场,寻求挑战。设计了面向轻量手持终端的处理器Crusoe。 在设计过程中,Transmeta并没有把过于复杂的问题全抛给硬件设计团队。 相反地,Crusoe的诞生凝结了硬件和软件工程师的智慧结晶。 通过将原本由硬件完成的复杂工作交给软件,Transmeta在一个简单高效的VLIW引擎上实现了X86兼容系统。 该系统中软件负责翻译、调度、优化指令,这样一来,原来的X86指令以近乎并行地方式在Crusoe处理器上执行。 由于降低了硬件设计复杂度,Crusoe节省了数百万的晶体管,同事降低了60%-70%的功耗。 TM3120和TM5400是这种思路的首次尝试。结果表明这种软件硬件结合的X86兼容系统是切实可行的。

REVIEW

Transmeta在20世纪90年代末提出的的Crusoe方案确实具有很强的诱惑。 尤其是它能在相同主频下达到甚至超过X86处理器的性能。 该方案将诸如动态流水、乱序执行、寄存器重命名工作交给软件,硬件只负责简单高效的有序流水线确实是一种新颖的思路。 在那个时代,面对潮水般的RSIC高性能结构,Transmeta能提出这种简化硬件结构而不只是简化ISA的思路是极具先锋意识的。 然而,软件维护的系统性能确实有限。 随着处理器工艺的不断提升,复杂硬件设计方案的不断成熟,Crusoe方案的技术优势被渐渐抹平了。 尤其是进入21世纪后,Intel在处理器性能上的突飞猛进,俨然在技术和市场上都罕逢敌手。 在Transmeta所关注的移动设备端,ARM则独树一帜,占领了市场。 Crusoe这种X86兼容方案日趋尴尬,最终没能在市场上掀起腥风血雨。 即便如此,Transmeta提出的这种设计方案也足以在学术史上名垂千古。

黎明灰烬 博客

Creative Commons License 信箱:i(at)jackwish.net

计算机

清 谈