VUnit 中等待 UART 接收数据时仿真为何长时间不结束?
结论
按给出的参数,发送 8 个 UART 字节通常不至于让仿真运行 45 分钟。115200 baud 下,每个字节包含 1 个起始位、8 个数据位和 1 个停止位,发送 8 个字节约需 0.7 ms 仿真时间。以 20 MHz 接收时钟计算,这段时间约有 14 万个时钟周期。
实际运行速度还取决于设计和仿真设置。先确认是哪种情况:仿真时间推进得很慢,还是主进程一直在等 rx_count 达到目标值。后一种情况看起来像仿真运行了很久,实际上可能是等待条件始终没有满足。
原代码在 wait until rx_count = tx_bytes'length; 处等待,rx_count 则由 capture_rx 进程更新。如果计数器没有正确初始化、接收进程没有产生预期的上升沿,或接收数据数量不足,主进程就不会进入后续的校验循环。仅凭当前代码片段,无法确定具体原因。
先检查计数器是否真的到达目标
可以在等待处设置仿真时间超时,并在超时后报告计数值。时间上限应留出余量,下面以 10 ms 为例:
wait until rx_count = tx_bytes'length for 10 ms;
assert rx_count = tx_bytes'length
report "Timeout waiting for UART bytes; rx_count=" & integer'image(rx_count)
severity failure;
wait until ... for ... 超时后会继续执行,因此还需要用 assert 检查等待条件是否满足。超时信息可以帮助判断是数据没有收全,还是后续比较出错,也能避免测试一直等待。如果 rx_count 不是 integer 类型,错误信息的写法需要按实际类型调整。
确认 rx_count 在测试开始前已初始化或复位为 0。若它是未初始化的 std_logic_vector,初值中的未知态会影响比较和加法;若它是 integer 信号,也应明确设置初值,或在复位流程中赋值。还要确认 uart_tx_fifo_wr 在接收期间确实出现了 8 个上升沿,并检查每次捕获后 rx_count 是否按预期递增。
检查接收进程与数组边界
给出的接收进程只在 uart_tx_fifo_wr 变化时运行,并在上升沿记录数据:
capture_rx: process(uart_tx_fifo_wr)
begin
if rising_edge(uart_tx_fifo_wr) then
rx_log(rx_count) <= uart_rx_fifo_rdata;
rx_count <= rx_count + 1;
report "Received byte: " & to_hstring(uart_rx_fifo_rdata);
end if;
end process;
确认 uart_tx_fifo_wr 是接收数据有效时的写使能信号,并检查 rx_log 的索引范围是否覆盖 rx_count 的所有取值。信号赋值会在当前进程挂起后更新,因此同一个上升沿中,rx_log(rx_count) 使用的是递增前的计数值。这通常适用于从索引 0 开始记录的写法,前提是计数器初值与数组范围匹配。
如果 rx_count 超出 rx_log 的范围,仿真器通常会报告索引越界。可以在记录前加入边界保护,让错误信息更明确:
if rising_edge(uart_tx_fifo_wr) then
if rx_count < rx_log'length then
rx_log(rx_count) <= uart_rx_fifo_rdata;
rx_count <= rx_count + 1;
report "Received byte: " & to_hstring(uart_rx_fifo_rdata);
else
report "Received more bytes than rx_log can store"
severity error;
end if;
end if;
这段保护假设 rx_log 的索引从 0 开始。如果数组使用其他索引范围,应通过 rx_log'range 判断索引是否有效,不能直接把 rx_log'length 当作上界。
定位仿真开销
逐字节输出 8 条 report 通常不足以解释 45 分钟的运行时间,但可以暂时关闭报告,观察运行速度是否变化。也可以查看 QuestaSim 的仿真时间是否持续推进,以及推进期间主要运行哪些进程。如果仿真时间在推进但速度很慢,检查是否启用了大量波形记录、高频时钟进程是否反复打印信息,以及测试平台是否存在不必要的零时间循环。可以先只记录与 UART 收发和计数器有关的信号,再比较运行速度。
如果仿真时间停在某个时刻,测试进程也没有报错,先检查尚未满足的等待条件、未驱动的时钟或握手信号,以及测试平台中是否存在零时间循环。不同原因对应的观察信号不同,建议同时查看 rx_count、uart_tx_fifo_wr、复位信号和仿真时间。
保留自动校验
自动比较可以保留。接收条件满足后,逐字节检查 rx_log 和 tx_bytes 是合理的测试方式。先确保接收计数能够达到目标,并为等待添加超时。如果确认仿真时间推进正常但运行仍然缓慢,再检查波形记录和测试平台中的高频操作。
备注:内容仅供参考。
