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)語句也會被執行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章