使用 fork-join 在 Systemverilog 中需要多线程

Need for multi-threading in Systemverilog using fork-join

在大多数提倡分层testbench设计的教科书中,建议不同的layers/block 运行并行。我目前无法弄清楚为什么会这样。为什么我们不能按照下面的顺序。

repeat for 1000 tests
    generate a transaction
    drive the transaction on the DUT
    monitor the transaction on the DUT
    compare output with a reference

相反,建议的是生成器、驱动器、监视器和 scoreboard/checker 四个模块应 运行 并行。我的困惑是,为什么我们要避免上述顺序行为,在这种行为中我们一次测试一个测试用例,并且更喜欢并行地 运行ning 不同的块。

有些文章说这是因为这是硬件中的工作方式,即所有事情 运行 都是并行的。但是,不需要分层测试台来模拟任何可综合的硬件。那么,为什么我们必须限制我们的验证 enivornment/testbench 以遵循这些类似硬件的行为。

下面给出了我所指的示例框图:

您正在混合两个不同的概念。分层方法是一种软件概念,可帮助管理从软件事务(数据框架)到各个引脚摆动的不同抽象级别。这些层与 OSI Network Model 非常相似。分层还通过定义清晰的接口来帮助维护和可重用性,使您能够构建更大的系统。在小型组合块的测试台上很难看到这样做的好处。

并行性因其他原因而发挥作用。相对较少的完整设计可以作为单一输入流进行测试,然后将输出与参考模型进行比较。您可能可以通过这种方式测试设计的一小块,但不能测试完整的芯片,因为它通常有许多需要并行驱动的接口。

但让我们以您使用上述方法单独测试的两个简单块为例。现在您想将它们连接在一起,第一个 DUT 的输出成为第二个 DUT 的驱动器

Driver1 -> DUT1 -> DUT2 -> Monitor2

如果我最初将驱动程序和监视器作为单独的对象 运行 并行编写,则效果最佳。

假设您有一个要测试的 fifo。您的 driver 将数据推入其中,监视器检查另一端。数据可用时被推送,直到 fifo 已满,另一端的消费者会尽可能读取数据。所以,管道有时满,有时空。

当fifo满时,driver必须停止。监视器始终工作,但其值不会以与刺激相同的频率变化,并且由于 fifo 深度而延迟。

在您的示例中,当 fifo 已满时,停止的 driver 将阻塞整个循环,因此监视器也不会工作。当然,你可以想出一些条件语句来绕过stopped driver。但是您每次都需要 运行 监视器和记分牌,即使数据没有变化。

随着具有多个 fifos、流水线、延迟、时钟频率等的更复杂的设计,您的循环将变得如此复杂,以至于即使不是不可能,也很难管理。

问题在于,在简单的编程中,不可能在不阻塞整个循环的情况下表达 block/wait 语句的条件。使用并行线程要容易得多。

一般的做法是 运行 driver 和监控在不同的模拟线程中。本例中的 Monitor 等待数据出现并且不阻塞 driver。 driver 在数据可用时推送数据,如果 fifo 已满或没有可驱动的数据,则可以阻止数据。它不会阻止监视器。

对于单个监视器,您可能可以将记分板与监视器打​​包在同一个线程中,但是对于多个监视器,这将是有问题的,特别是当所有监视器 运行 在单独的线程中时。因此,计分板也应该 运行 作为一个单独的线程。