赞
踩
在写一个driver的过程中,遇到了一个奇怪的问题。driver的drv_transfer函数如下:
forever begin
wait(hready);
repeat(4) begin
data <= data_q.pop_front;
@if.driver_cb;
end
end
这样写完之后,会出现一个时钟周期,queue被pop两次的情况,因此data的第一个数据就会被覆盖掉,并且这种现象仅仅发生在第一组数据上。出现这种情况的原因在于,hready是一个和时钟同步的信号,hready和时钟的上升沿是同时到来的。当hready拉高时,循环不会被@if.driver_cb阻塞,会继续运行,直到被下一个@if.driver_cb阻塞,因此,在一个时钟周期,queue会被pop两次,当forever不阻塞在wait(hready)时,已经不是上升沿的时钟周期,因此会pop一个数据,进入下一次循环,阻塞在@if.driver_cb,然后再次pop。对第一组数据而言,wait等待的信号成立,也就是hready初始就是高电平,因此不会被wait(hready)阻塞,也不会在某个上升沿不被wait(hready)阻塞,因此,第一组数据会pop两次,而其它的数据仅仅会pop一次。解决这个问题的方法是在pop后面添加#0语句。添加#0语句会将仿真时间推向当前时间的末尾,因此第一次pop就会被@if.driver_cb阻塞。
systemverilog中的@和wait都是阻塞,但是区别在于一个@是同步阻塞,而wait是异步阻塞。对于被@阻塞的信号,如果触发时没有执行,就会一直阻塞,对于被wait阻塞的信号,只要触发过一次,就不会被阻塞。
对于systemverilog而言,在同一仿真时刻,不同事件出现由先后顺序的。一个被posedge clk驱动的信号,出现的顺序会晚于posedge clk,因此,如果使用wait(signal)来阻塞程序,会等信号出现之后再继续执行,如果后面还有一个@posedge clk, 程序仍然会被阻塞。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。