写在前面
本文参考xilinx的UG998的第七章,主要介绍了关于仿真测试平台的相关内容,以及在HLS中无法进行验证的相关情况的说明。
Testbench
类似在FPGA开发平台的testbench,这里只需要进行编写main函数进行测试hls综合的目标函数,在HLS可以进行C仿真还有C和RTL联合仿真。
软件测试平台
任何HLS生成模块的验证都需要软件测试台。软件测试台具有以下重要功能:
- 证明针对FPGA实现的软件运行且不产生分段故障
- 证明算法的功能正确性
分段错误在HLS中是一个问题,就像在任何其他编译器中一样。但是,在如何检测导致问题的编码错误方面存在差异。在基于处理器的执行中,分段错误是由程序试图访问处理器未知的内存位置引起的。此错误最常见的原因是,在分配内存并将其连接到指针之前,用户程序试图访问内存中与指针地址关联的位置。基于以下事件序列,在运行时检测此错误相对简单:
- 处理器检测到内存访问冲突并通知操作系统(OS)。
- 操作系统向导致错误的程序或进程发送信号。
- 在接收到来自操作系统的错误信号后,程序终止并生成一个内核转储文件以供分析。
在HLS生成的实现中,很难检测分段故障,因为没有处理器,也没有操作系统监视程序执行。分段故障的唯一指示器是电路产生的不正确结果值的出现。 仅此一项不足以确定分段故障的根本原因,因为存在多个问题可能会触发错误的结果计算。
软件测试台的另一个目的是验证针对FPGA执行的算法的功能正确性。对于生成的硬件实现,HLS编译器仅保证与原始C/C++代码的功能等价性。因此,需要有一个良好的软件测试平台,以尽量减少硬件验证和确认的工作量。
一个好的软件测试平台的特点是在一个算法的软件实现上执行数千或数百万个数据集测试。这使得设计者能够高度自信地断言算法被正确捕获。然而,即使有许多测试向量,在FPGA设计的硬件验证期间,有时仍可能检测HLS生成输出中的错误。在硬件验证期间检测功能错误意味着软件测试台不完整。将有问题的测试向量应用于C/C++执行会揭示算法中的错误语句。
Co-Simulation
用于C/C++程序分析和功能测试的工具捕获了影响HLS实现的大多数问题。但是,这些工具无法验证顺序C/C++程序在并行化后是否保持功能正确性。该问题在HLS编译器中通过协同仿真过程得到解决。
协同仿真是由软件仿真过程中使用的相同C/C++测试平台执行生成的FPGA实现的过程。HLS以对用户透明的方式处理C/C++测试台和生成的RTL之间的通信。作为该过程的一部分,HLS调用硬件模拟器,如Vivado模拟器,以模拟RTL在设备上的工作方式。此模拟的主要目的是检查用户提供的并行化指导没有破坏算法的功能正确性。
代码覆盖率
代码覆盖率表示测试台代码执行设计中语句的百分比。该度量可以由gcov等工具生成,它给出了用于执行该算法的测试向量的质量。
至少,测试台必须获得90%的代码覆盖率分数才能被视为算法的适当测试。这意味着测试向量触发case语句、条件if-else语句和for循环中的所有分支。除了总体覆盖率指标外,代码覆盖率工具生成的报告还提供了对函数的哪些部分已执行和哪些部分未执行的深入了解。
越界内存访问问题
在HLS中,内存访问可以表示为对数组的操作,也可以表示为通过指针对外部内存的操作。在越界内存访问的情况下,重点是由HLS转换为内存块的阵列。 下图显示了具有越界内存访问的代码示例。
这段代码试图将数据写入超出分配内存范围的数组中。在处理器编译器中,这种类型的地址溢出会触发地址计数器重置为0。这意味着在处理器执行图中的代码时,位置a[0]的内容是15而不是5。尽管结果在功能上不正确,但这种错误通常不会导致程序崩溃。
当无法进行C/C++验证时
HLS的大多数用例都在算法中,这些算法可以通过C/C++仿真充分验证功能的正确性。然而,仍有一些情况下,在HLS编译之前无法完全验证算法的C/C++表示。下图显示了此类代码的示例。
这段代码显示了C中描述的UDP数据包处理引擎的一个片段。在本例中,所有指针都使用volatile关键字声明。volatile关键字的使用在设备驱动程序开发中很常见,它提醒编译器指针连接到可能在函数执行期间更改的存储元素。每次在源代码中指定此类指针时,都必须读取或写入此类指针。合并指针访问的传统编译器优化也被volatile关键字关闭。
易失性数据的问题在于,在C/C++模拟中无法完全验证代码的行为。C/C++模拟不具备在测试函数执行过程中改变指针值的能力。因此,只有在HLS编译之后,才能在RTL模拟中完全验证这种类型的代码。用户必须为C/C++源代码中的每个易失性指针编写一个RTL测试台,以便在所有可能的情况下测试生成的电路。在这种情况下,联合仿真的使用不适用,因为它受到可用于C/C++仿真的测试向量的限制。
reference
- UG998