Page 119 - 《软件学报》2020年第10期
P. 119
刘焰强 等:FPGA 加速系统开发工具设计:综述与实践 3095
Scala 代码则会被执行并发挥类似于编译指令的功能.这样的方式使得我们可以很方便地利用类型系统,将 RTL
抽象在 Scala 中进行映射.具体来说,硬件定义实体的类型可以为模块、语句块、语句和值,其中语句块包括同步
语句块和异步语句块.
SimulationSuite 与 SimulationSchedule 相结合实现了软件模拟功能.由于我们在硬件类型实现中包含了不
同类型在模拟时的行为,因此可以通过事件接口直接驱动硬件定义类实例的运行来实现功能模拟,这极大地简
化了软件模拟器的实现.通过与实现好的基础通信驱动进行对接,测试平台也可以针对真实硬件进行测试.
2.3 底层数据传输与集成方法
要提供简便的软硬件集成支持,基本思路是通过抽象和包装将繁琐的底层数据传输细节隐藏起来.在
Verilog 中我们通过用 Scala 实现的基础通信驱动和根据用户模块定义自动生成的硬件数据接口层来完成软硬
件的对接和传输细节的隐藏.图 5 展示了 VeriScala 框架中的运行时系统.在软件方面,Scala 实现的基础通信驱
动包装内核中的 PCIe DMA 驱动,将上层 Scala 定义的数据结构序列化后传给内核模块,并通过相应的接口控制
PCIe 通道的负载.应用可以在基础通信驱动的基础上开发特定应用的数据传输后端来实现类似函数调用语义
的硬件调用,也可以直接使用基础驱动来进行数据传输.在硬件方面,我们设计了通用的接口层实现库来处理底
层传输协议握手和数据缓存.通过用户顶层设计的接口定义,ScalaHDL 的翻译器可以在生成硬件设计时自动识
别接口信号并进行相关的适配.同时在调试时,用户可以指定需要监视的信号,让翻译器额外生成调试服务硬
件,通过与软件驱动配合来实现类似于 GDB(GNU debugger)风格的硬件调试工具.
Fig.5 The runtime system
图 5 运行时系统
2.4 示例与实验结果
基于之前两节的阐述,VeriScala 框架中形成了如图 6 所示的代码流程.图 6 中以简单的加法器定义为例,在
文件 Adder.scala 中首先定义模块的容器类 Adder 及其构造接口,然后在类中定义模块 add,add 的逻辑由一个同
步块来描述,由于加法器的功能简单,该同步块中仅包含一个条件分支语句.事实上,在 Scala 中,我们可以将运算
函数作为参数来传递,如文件 Arithmetic.scala 中定义的 Arithmetic 类可以在实例时接受一个函数 f 作为参数来
生成不同的算术模块,这给硬件定义代码的复用提供了方便.对于定义好的硬件,开发者可以利用 VeriScala 中的
软件模拟器,通过编写测试平台和测试代码,进行软件模拟,也可以通过生成的一系列 Verilog 代码,利用对应厂
商的工具链和 VeriScala 的运行时框架进行硬件测试并加速系统构建.
为了评估 ScalaHDL 的生成代码质量,我们针对不同复杂度的常用电路分别使用 ScalaHDL 和 Verilog 进行
定义,并根据 Xilinx Vivado 软件编译自动生成代码和手动编写代码的资源消耗报告,得到的统计结果见表 2.