Skip to content

模拟器之我见

从事芯片模拟器开发的工作也有一段时间了,随着工作的深入,有一个问题一直在我脑海中不时的浮现:当我们需要使用模拟器的时候,我们怎么来确定实现方案

这个问题可以拆分为两步:

  • 确定需求
  • 根据需要确定实现方案

要完成这两步,最关键的是需要对目前在模拟器领域大家普遍采用的方案做一个总结,这也是这篇文章的主题之一。在这之前,我觉得还有一个问题很关键,也非常需要说明白。如果说如何选择模拟器是方法论,那么这个问题就是世界观:我们为什么需要模拟器

我们为什么需要模拟器

  • 在芯片开发前期,RTL刚开始开发,没有FPGA环境,更没有验证板, 这时候软件也需要开发和验证,需要有一个和芯片行为一致的环境来做软件开发,这时候就需要行为级模拟器,simulator
  • 在架构设计过程中,希望能够快速的验证微架构的设计,时钟级模拟器,emulator
  • 希望有一个能够产生golden的环境,需要验证框架,模拟器,RTL进行一个三方验证
  • 在软件优化方面,如果能有一个时钟级模拟器,能够提供一些关键信息,那么会对软件和工具链优化有很大帮助。毕竟FPGA和帕拉丁环境都是有限的
  • 一些IP厂商往往会提供配套的IP模拟器,比如systemC的一个IP模拟

总结起来,模拟器具有如下优势

  • 开发速度较快,开发周期短,方便进行修改,迭代
  • 发布,部署简单,PC就能运行,运行环境成本低,不容易受硬件资源的限制
  • 能够添加的辅助手段多,能够提供丰富的调试信息

那模拟器的缺点呢?我觉得主要是下面几个方面:

  • 运行速度慢,特别是细力度的时钟级模拟器,行为级普遍还能接受
  • 开发成本不低,时钟级模拟器如果要模拟精细,工作量也不亚于写RTL

总体来看,模拟器的优点非常明显,它解决的都是芯片设计开发过程中的痛点,能够帮助尽早的发现问题,确认问题,至于运行速度慢,可以有很多解决办法和优化手段,比如只对关注模块做细力度,比如采用多线程和分布式,至于工作量的问题,我想还是成本更重要。

未来很长一段时间,模拟器在芯片开发领域仍然是不可或缺的,而且随着国内芯片的发力,这方面的需求逐渐旺盛,至少未来三年是一个供小于求的局面

模拟器的分类

很多文章或者论文中可能会对模拟器种类分的很细,有兴趣的也可以自行搜索。我认为宏观上模拟器就分两类,行为级和时钟级。 有些文章中将时钟级模拟称为emulation行为级模拟称为simulation。这两个明显的区别在于涉不涉及微架构的抽象。行为级是功能模型,不需要对微架构进行抽象,不需要有精确的时钟; 时钟级一定会有精确的时钟,也一定会涉及微架构。

是不是此时特别想要一个表格,里面汇总了目前市面上的各种各样的模拟器?别说,还真让我找到了一个

[http://pages.cs.wisc.edu/~arch/www/tools.html]

行为级模拟器

一般来讲,行为级模拟器实现起来要简单的多,代码量不会太大。当然,很多行为级模拟器肩负了虚拟化的使命,也会比较庞大。 有些为了执行起来更快,也引入了一些比较复杂的实现。但总体来讲,行为级模拟器要相对简单,开发周期短,容易稳定。

行为级模拟器适合用来做软件运行平台,为软件开发提供调试环境。也很适合做三方验证,出一些测试golden。

时钟级模拟器

时钟级模拟器的代码逻辑要更复杂,它的重点在于微架构的模拟,要给出微架构在每一个时钟周期的行为。要看明白一个模块,往往需要看多个模块,比如分析流水线,就不能只分析执行阶段,要分析寄存器重命名,还需要结合流水线,ROB等模块。总之,它需要同盘分析,需要更多的逻辑性。

时钟级模拟是有粒度的。粒度越细,运行速度越慢,哪里粗哪里细,要看需求,一味的细会带来巨大的工作量

时钟级模拟是可以偷懒的。毕竟是模拟器,在满足需求的情况下,完全可以从软件实现方便、高效的角度来进行实现。比如一个计算指令的实现,假如无法在一个周期中执行完,那么RTL就需要分多次进行计算,但模拟器完全可以一次计算完成,只需要多次store即可。这样,软件计算起来就方便,而且容易进行加速。

常见行为级模拟器分析

QEMU

QEMU很经典,应用广泛,好多软件都在使用QEMU。它不单单是一款行为级模拟器,更是一款虚拟机。

作为模拟器框架来看,优点可以总结如下:

  • 采用动态转换机制,以Translate Block为单位,运行速度快,效率高。跑个linux内核完全没有问题,同时还可以KVM加速
  • 支持的指令集架构丰富,常见的都支持,包括现在火热的RISCV
  • 支持丰富的外设模拟,组建SOC完全够用

缺点总结如下:

  • 无法单条指令debug,对于分析指令流来讲不太好用,也不容易看到
  • gdb调试麻烦,内部采用多线程实现,调试起来不太容易
  • 机制比较多,学习成本相对高

总结一下,QEMU适用于为系统软件提供调试、运行环境,为测试产生golden的场景。特别是在进行SOC开发时,验证整套软件运行环境,从uboot到opensbi,到linux kernel,以及一些常用软件。它丰富的外设,高效的运行速度,是选择它的首要指标。

关于QEMU的详细分析,参见qemu章节

spike

RISCV社区官方行为级模拟器,这个不能算做是模拟器框架,毕竟它只支持RISCV

总结优点如下:

  • 代码简单,上手迅速
  • 调试功能完善,可以直接对目标代码单步执行,加断点,查看寄存器状态方便
  • 代码本身调试方便,很容易进行gdb跟踪

当然它也有缺点

  • 外设支持很少,基本只关注于CPU和内存系统
  • 运行不快,多个CPU要交替运行
  • 扩展性不强

总结起来,spike适合调试目标代码,适合作为小型软件的运行环境,比如测试case,也就是说对于产生golden,调试测试case来讲非常方便

遗留问题:

  • 是否能运行linux内核

Bochs

很有名,但似乎只能模拟x86, 放过它吧

常见时钟级模拟器分析

gem5

很经典,学院风,适合做架构探索

罗列一下优点:

  • 模块化,易于扩展,基础模块比较多
  • 配置方便,使用python可以很方便的定制
  • debug信息丰富,gdb调试方便
  • 支持多种架构
  • 开发周期短,能快速验证想法

至于缺点嘛,还真是不好想,慢肯定是慢了。学习成本是有的,不至于太过分,好在有一些官方文档可以参考。作为架构探索很合适。听说还有一个分布式的分支?

systemC

似乎是工程化的正统,作为芯片公司,似乎必须要有一个systemC的模拟器!? 市面上有没有一些基于systemC的开发框架?

FireSim

[https://fires.im/]

开源的时钟精确的通过亚马逊云FPGA加速的全系统硬件模拟平台,又是博克利大学(不得不佩服这个大学的科研能力呀,他们怎么能这么厉害)的一个产物。

抄一段官网的描述如下:

FireSim can simulate arbitrary hardware designs written in Chisel or designs that can be transformed into FIRRTL (including early work on supporting Verilog designs via Yosys’s Verilog to FIRRTL flow). With FireSim, you can write your own RTL (processors, accelerators, etc.) and run it at near-FPGA-prototype speeds on cloud FPGAs, while obtaining cycle-accurate performance results (i.e. matching what you would find if you taped-out a chip)

它可以仿真(simulate)任意的硬件设计,不过这个设计要求是用Chisel写的,或者是FIRRTL(看来是它自己的一套RTL语法,当然也可以通过Yosys的 verlog转FIRRTL工具将RTL转换成FIRRTL)。这样看来它并不是一个模拟器框架,更像是一个仿真工具,用Chisel写好设计,然后通过这个在亚马逊云FPGA上快速运行,得到性能数据,这是不是类似与palladium?

典型应用场景包括:

  • 评估自己实现的IC设计。比如写一个加速器,在上面实际的跑一下
  • 快速的定制或者评估riscv核。firesim 实现了Rocket Chip and BOOM,可以直接跑这俩CPU
  • 以FPGA的速度调试Chisel代码,这对于Chisel调试来讲应该是有用的
  • 模拟大型数据中心系统,因为它云端资源丰富
  • 高性能带外分析,比如想在实现的SOC上跑一个linux系统,用这个能比较快

这样来看,不还是云端Palladium吗?粗略看了一下使用方法,类似于FPGA IDE,它会将Chisel代码编译成FPGA代码,然后在云端执行。因此不能把这个称为模拟器框架,而应该称为亚马逊云FPGA编译器。它实际上降低了FPGA的使用成本。

当要把时钟级模拟器做的很细的话,工作量不亚于写Chisel代码,那么这个时候直接写Chisel,然后用FireSim来加速仿真,似乎也是一个不错的选择,运行起来肯定比Gem5要快,而且适合大规模。这就回归到了前面的世界观问题,当FPGA或者Palladium成本变得非常低的时候,当需要模拟的很精细的时候,Gem5这种纯软件的模拟器是不是还有它的价值?我目前仍认为Gem5这种纯软件的模拟器还是有它的优势

  • 类似gem5这种模拟器,模块化普遍做的较好,基于某一个类似的实现去改,可能会大大缩短开发周期
  • 毕竟是软件,可添加的功能和手段都更多更丰富

当然,我现在的水平也无法看得清楚,只是一些碎碎念而已

另外,这种利用FPGA加速的就是不知道它调试手段是不是足够丰富,是不是会导致代码泄漏。而且Chisel是不是真的有前途? 后续有机会可以按照它的文档自己搭建一下环境,尝试运行一下,看看效果。目前不在这里展开。

socrocket

Transaction-Level Modeling Framework for Space Applications

直译为用于空间探索的事物级建模框架,那为什么说用于空间探索,一个以卫星为图标的框架,似乎是与航天有什么关系。 所谓Transaction-Level,我想是因为这个框架用的TLM是事物级的。TLM可以抽象层次很高,并且既可以用来写始终精确的也可以用来写功能型的。也就是说两种模型的要求都能满足,可盐可甜,真不戳。

To archive these goals, we designed the SoCRocket Framework. Written in SystemC/TLM, it is fitted to serve the space industry'sspecial needs and builds the foundation of space-domain ESL design.

这个真是晕了,怎么真的扯到航天工业去了,到底啥意思,怎么就适合航天工业特殊需求了,怎么就为空间域ESL设计奠定基础了。SOC火箭到底是个啥?我觉得这部分描述应该是有一些理解上的歧义,或许是我还不了解IC开发的一些东西。

TLM解析 ESL是IC设计的未来?

RISC-V-TLM

这是一个用TLM写的riscv的模拟器。目前仅支持rv32imac。显然,这是学习TLM和SystemC的一个很好的参考,对基于TLM搭建自己的模拟器也具有指导意义,或许我应该尝试去跟他一起扩展这个实现

[https://github.com/mariusmm/RISC-V-TLM]

Simics

风河的产品,要花钱的还是算了吧

完全自己实现模拟器

这里暂时不展开,知乎文章[https://zhuanlan.zhihu.com/p/53476489]中提到的一些点和我的观点一致。 比如离散事件模型,比如模块化,但自己造轮子的意义是什么呢?

总结

Qemu, Gem5, SystemC/TLM是值得重点关注的

对于时钟精确的模拟器开发,它的问题在于尽管时钟可以很精确,但仍然是模拟器。比如用gem5来开发,那它注定无法转换成RTL实现,他需要开发人员主动保证和RTL实现的同步,这在现实中往往很难做到,并且可能用它的人也没指望能够做到。但无论如何,我们总是觉得模拟器的开发和RTL开发这两者之间存在很多重复性工作。假如能有一个全面的工具,它既能满足架构探索的需求,又能转化为可用的RTL实现,岂不美哉。但一旦涉及到转换,那就必然会引入一个类似编译器的东西,经过编译器编译出来的东西是很难维护的,也就是说生成的RTL是很难人工加入到现有RTL中的,那只能是完全使用全新的更高抽象层次的语言来开发,这样既解决了架构探索和验证的问题,也不用再手写RTL。这似乎是未来,但目前上不成熟,等到那个时候,在产品层面可能就不再需要gem5这种框架进行架构探索了,所以长远来看,模拟器开发人员掌握足够的RTL开发能力是必须的,当然还应该积极拥抱Chisel, TLM等更高层次的抽象。但就目前来看,更高抽象层的语言还有很长的路要走,手写RTL还是目前最佳方案。模拟器开发方案的选择仍然需要先聚焦到基本需求上。

更新 2023/10/23

Q1:跑benchmark gem5到底应该使用fs模式还是se模式

尽可能的使用fs模式。

使用fs模式的优点:

  • 不需要担心se模式下的系统调用支持不完善的问题
  • fs模式下的checkpoint更加简单
  • fs模式只有kernel启动的时候需要额外的花费较长时间,真正运行的时候额外的时间开销比较少,不对总体模拟时间造成太多影响。

Q2:模拟器对齐可以有哪几种形式

  • gem5很难实现在微结构输入输出层面的对齐,而且这种对齐真的有意义吗?可以从原理和时序上做微结构的对齐,但不必保证在输入输出层面的完全一致。
  • 可以做延时和throughput层面的对齐
  • 可以利用benchmark切片在IPC,cache miss, branch miss等层面进行对齐