event触发的竞争条件(Event trigger race conditions)

问题:在进程等待event触发的同一时间步长内,若该event触发,则不一定能等到该event

E文原文:http://www.deepchip.com/items/0466-07.html

(转载请注明出处,谢谢! seabeam

verilog通过event数据类型提供一种基本的进程同步机制,使用这种机制会遇到两个问题。第一个问题也许一开始不会被当做问题,但是过了几年你会意识到这真是个问题:许多工程师甚至不知道sv中还有event,根本没想到去用它。有个工程师使用了N年的verilog后最近才打算和他的team参加verilog培训班。当上到event这节,他问这是不是sv里的新玩意,答案是它早就在Verilog里。他惊呆了:“以前咋没人告诉我呢?”


第二点,说点有现实意义的,event事件触发在仿真时很容易产生竞争条件,看看下面这个例子:


 module event_example1;


     event get_data, send_data;   // handshaking flags


     initial -> get_data;         // trigger get_data event at time zero


     always @(get_data) begin     // wait for a get_data event
       ... // do code to get data
       ... // when done, trigger send_data
       -> send_data;              // sync with send_data process
     end


     always @(send_data) begin    // wait for a send_data event
       ... // do code to send data
       ... // when done, trigger get_data
       -> get_data;               // sync with get_data process
     end


   endmodule

 这个简单的例子里有两个always块,使用event同步做了一个简单的握手模型,当一个块结束时另一块开始工作。问题在于仿真开始的0时刻,两个always块都处于活动状态,如果initial比get_data的always块先激活,那这个module就别想开工了。怎么办呢?verilog里只有一条路:延迟initial里的event触发时间,至少到get_data的always块被激活之后: 
   initial #0 -> get_data;  // start handshaking at time 0, but after all
                            // procedural blocks have been activated

使用#0延迟触发get_data,保证在0时刻get_data的always块先跑起来。但是#0本身就是个问题,在verilog里是个容易被滥用且不能保证在一个给定的时间步长里,加了#0就真的会在所有语句执行完毕


后执行(译者注:例如工程是个庞然大物,在不同的结构里都存在#0语句,那么他们之间也会互相竞争)。所以许多老师教导我们不要用#0,要用非阻塞赋值,或者预先确定顺序的event.除了event数据


类型,不使用#0是个好的guideline.但是在verilog里,没法将event触发做成非阻塞event队列。
这时候sv带了两种解决方案来救世了,现在可以和#0道别了。


方案1:操作符->>,它可以让event触发排成非阻塞队列。在本节的例子里,避免0时刻竞争条件的同时彻底抛弃了#0.将get_data event放入非阻塞队列使其触发前保证过程块处于激活状态(译者注:->>操作符不能出现在class里,只能存在于module中)。

   initial ->> get_data;  // start handshaking at time 0 nonblocking
                          // queue, after all procedural blocks have
                          // been activated

方案2:sv提供另一种方法以满足更多情况的需求。这种方法利用event内建的trigger属性使触发在整个时间步长内可见,而不是触发的那一瞬间。


   module event_example2 ( ... );


     event get_data, send_data;   // handshaking flags


     initial -> get_data;         // trigger get_data event at time zero


     always begin
       wait(get_data.triggered)   // wait for a get_data event
       ... // do code to get data
       ... // when done, trigger send_data
       -> send_data;              // sync with send_data process
     end


     always @(send_data) begin    // wait for a send_data event
       // could have used wait(send_data.triggered) here also, but it is
       // not needed since there is no race condition between the two
       // always blocks
       ... // do code to send data
       ... // when done, trigger get_data
       -> get_data;               // sync with get_data process
     end
   endmodule

当get_data触发时,wait(get_data.triggered)返回为真。event触发行为发生在wait语句激活前后都无关紧要。在上面的例子中,如果initial块先于第一个always块激活,那么激活行为在第一个always block激活时仍然可见,而且wait(get_data.triggered)语句也会被执行。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值