如何创建自检测试平台
自检测试台是一个 VHDL 程序,它可以验证被测设备 (DUT) 的正确性,而无需操作员手动检查输出。自检测试台完全独立运行,最后打印“OK”或“Failed”消息。
每个 VHDL 模块都应该有一个相关的自检测试平台。能够随时验证所有模块是否具有预期行为非常重要。例如,当您对 DUT、子模块或接口模块进行更改时。我们都知道东西会坏掉,而解决这些问题的最佳工具就是自检测试台。
被测设备
让我们直接进入并创建一个自检测试平台的示例。首先,我们需要测试的东西,一个 DUT。为此,我在下面的代码中创建了模块。这是一个二进制到格雷码的转换器。
library ieee; use ieee.std_logic_1164.all; entity gray_converter is port ( bin : in std_logic_vector; gray : out std_logic_vector ); end gray_converter; architecture rtl of gray_converter is begin process(bin) is begin gray(gray'high) <= bin(bin'high); for i in bin'high - 1 downto bin'low loop gray(i) <= bin(i + 1) xor bin(i); end loop; end process; end architecture;
格雷码是一种替代数字编码方案,不同于常规的二进制编码。格雷码的主要属性和用途是在相邻数值之间计数时只改变一位。
十进制 | 二进制 | 灰色 |
---|---|---|
0 | 0000 | 0000 |
1 | 0001 | 0001 |
2 | 0010 | 0011 |
3 | 0011 | 0010 | 4 | 0100 | 0110 | 5 | 0101 | 0111 | 6 | 0110 | 0101 | 7 | 0111 | 0100 | 8 | 1000 | 1100 | 9 | 1001 | 1101 | 10 | 1010 | 1111 | 11 | 1011 | 1110 | 12 | 1100 | 1010 | 13 | 1101 | 1011 | 14 | 1110 | 1001 | 15 | 1111 | 1000 |
上表显示了格雷码与二进制码的区别。
测试台
我们将首先创建基本测试平台并在其中实例化 DUT。下面的代码显示了 DUT 实例化和所有必要导入的测试台文件。
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use std.env.finish; entity gray_converter_tb is end gray_converter_tb; architecture sim of gray_converter_tb is signal bin : std_logic_vector(3 downto 0) := (others => '0'); signal gray : std_logic_vector(3 downto 0); begin DUT : entity work.gray_converter(rtl) port map ( bin => bin, gray => gray ); end architecture;
请注意,我们正在导入 std.env.finish
这需要 VHDL-2008。如果您尝试在 ModelSim 中编译测试台而不做任何更改,您将收到以下错误:
# ** Warning: gray_converter_tb.vhd(6): (vcom-1516) Package "STD.ENV" does not exist in this language version.

幸运的是,通过将测试平台文件的 VHDL 版本设置为 VHDL-2008 可以轻松解决此问题。右击testbench.vhd文件,选择Properties→VHDL→Use 1076-2008->OK。
您无需为 DUT 进行任何更改。与 RTL 模块相比,测试平台使用更高版本的 VHDL 是正常的。您总是希望能够在测试台中使用最新的 VHDL 结构,但大多数综合工具不支持它们。
生成输入
我们对测试平台的下一个添加将是为 DUT 生成输入的过程。最好创建一个详尽的测试,一个尝试所有可能的输入值的测试。虽然,如果排列太多,您可能会被限制只做极端情况。
我们 DUT 的输入和输出范围未指定。但是,我会做出一个有根据的猜测,即使用四位向量长度进行测试足以揭示该模块的任何可能问题。
下面的代码包含了生成输入序列的整个过程。
PROC_SEQUENCE : process begin -- Test all possible input values for i in 0 to 2**bin'length - 1 loop bin <= std_logic_vector(to_unsigned(i, bin'length)); wait for 10 ns; end loop; -- Finally, test the wrapped value bin <= (others => '0'); wait for 10 ns; report "Test: OK"; finish; end process;
第一个代码块是一个 For 循环,它生成从最低可能值到最高可能值的计数序列。在这些值之间,我们等待 10 纳秒让 DUT 做出反应。虽然,任何大于 0 的纳秒值都会起作用,因为 DUT 内部的逻辑是纯组合的。
第二段代码用于测试输入计数器回到 0(即初始输入值)的情况。之后,无需进一步测试,因为 DUT 只会一遍又一遍地继续产生相同的结果。

该过程中的最后两行代码用于优雅地结束测试。将文本“Test:OK”打印到控制台,然后使用 VHDL-2008 关键字“finish”停止模拟。
请注意,如果您使用默认的运行按钮运行 ModelSim,则在测试台成功完成后,ModelSim 将通过退出对话框提示您。从脚本或命令行启动 Vsim 时,可能会更改此行为。将“-onfinish stop”开关添加到 Vsim 命令中,如 ModelSim 命令参考中所述。
检查输出
现在我们为 DUT 提供输入,但根本没有检查输出。无论输出是否正确,测试台都会打印出“Test:OK”。让我们做点什么吧。
创建验证算法时,您应该始终尝试以不同于 DUT 的方式实施测试。否则,逻辑中的基本缺陷可能会被忽视,因为它存在于 DUT 以及测试台算法中。
遵循这一原则,我们将测试 DUT 输出,而不是通过检查格雷码是否正确,而是通过检查只有一位从一个数字变为下一个数字。毕竟,这就是首先使用格雷码的全部原因。下面的代码显示了执行这种检查的过程。
PROC_CHECKER : process variable prev : std_logic_vector(gray'range); variable count : integer; begin wait on bin; prev := gray; -- Wait for all delta cycles to propagate wait for 1 ns; -- Count the number of changed bits count := 0; for i in gray'range loop if gray(i) /= prev(i) then count := count + 1; end if; end loop; assert count = 1 report integer'image(count) & " bits changed, should have been 1" severity failure; end process;
进程对bin
敏感 信号,输入到DUT。我们本可以使用具有相同结果的敏感度列表,但我更喜欢在测试台代码中仅使用 Wait 语句。这是一种约定,只需查看代码的编写方式,就可以很容易地知道您是在处理测试平台还是 RTL 模块。
在第二行,我们复制之前的 DUT 输出。请记住,这是 bin
之后的第一个增量循环 信号已经改变,DUT 可能还不能做出反应。因此,假设这是旧值,复制 DUT 输出是安全的。
然后,我们等待 1 纳秒,让 DUT 中的所有组合逻辑完成。现在,DUT 的输出应该是稳定的,我们可以放心地检查它的值了。
在下一段代码中,我们使用 For 循环来计算 DUT 输出上更改的位数。
最后是 Assert 语句,它检查更改的位数是否正好为 1。Assert 语句通过检查条件来工作,在这种情况下是 count = 1
.如果条件评估为 false
,将引发一个断言,并且模拟器将在“Test:OK”消息打印出来之前停止。
在 assert 语句中包含可选的报告语句是明智的。如果断言失败,该文本将被打印出来。在我们的示例中,我简要说明了导致测试台失败的事件。
运行测试台
是时候运行我们的测试平台来验证 DUT 是否正常工作了。在 ModelSim 中启动仿真后,按下“run -all”按钮,我们看到控制台打印出“Test:OK”消息。
VSIM 1> run -all # ** Note: Test: OK # Time: 170 ns Iteration: 0 Instance: /gray_converter_tb
测试测试台
我总是喜欢在 DUT 中创建一个失败条件,只是为了查看测试台是否正常工作。有时这是由于您在开发 DUT 时出现的实际错误而自然产生的。但如果没有,只需简单地创建一个错误来测试测试台即可。
为此,我将编辑 DUT 代码以在第 3 位上创建一个卡在 0 的错误。在此测试之后,我将在知道测试平台能够检测到此类错误的情况下删除该错误。下面的代码显示了带有附加代码行的 DUT 过程。
process(bin) is begin gray(gray'high) <= bin(bin'high); for i in bin'high - 1 downto bin'low loop gray(i) <= bin(i + 1) xor bin(i); end loop; -- Emulate a stuck at zero error gray(3) <= '0'; end process;
当我们现在运行测试平台时,我们可以看到测试平台停止,并且在到达“Test:OK”行之前打印出错误。 ModelSim 控制台的脚本如下所示。
VSIM 2> run -all # ** Failure: 0 bits changed, should have been 1 # Time: 81 ns Iteration: 0 Process: /gray_converter_tb/PROC_CHECKER File: gray_converter_tb.vhd # Break in Process PROC_CHECKER at ray_converter_tb.vhd line 61
开始使用自检测试台
您应该能够使用您在本文中学到的内容创建一个自检测试平台。养成为所有 VHDL 模块创建自检测试台的习惯。从长远来看,它将为您节省时间。
在编写测试平台时有创意是可以的。比编写 RTL 模块更重要,因为并非所有 VHDL 结构都可以综合,但测试平台不需要综合。预计编写测试所花费的时间至少与编写 DUT 所花费的时间一样多。
如果你想认真对待测试,你可能会对我的 * 感兴趣 即将推出的 VHDL 和 FPGA 课程。在课程中,我将引导您完成从构思到实际工作的 FPGA 原型的完整设计过程。我们将创建多个自检测试平台。
2020 年 10 月 12 日更新: 我已经完成了课程。点击下图了解更多。
我将教您以正确方式成功创建 VHDL 和 FPGA 设计的最佳实践。我在学术界和国防工业担任硬件工程师后获得的知识将传授给您。

在此处阅读有关点阵 VHDL 和 FPGA 课程的更多信息!
打开:
待定 .
VHDL