圖9.1 局部變量-基礎
局部變量是您可能經常使用的功能。它們可以用于序列和屬性中。它們被稱為本地的,因為它們确實是一個序列本地的,并且不可見或不可用于其他序列或屬性。當然,這個限制是有解決辦法的,我們将在這一章節進一步研究。圖9.1指出了局部變種的關鍵元素。局部變量的最重要和有用的方面是它允許多線程應用程式,并為每個使用它的序列執行個體建立局部變量的新副本。使用者無需擔心在每次調用序列時都要建立局部變量的副本。上面的應用程式說,隻要RdWr在posedge clk處采樣為高,那麼rData将在5個時鐘後與wData進行比較。這個例子展示了如何實作這個規範。在clk posedge局部變量int local_data将存儲rData,然後在5個時鐘後将其與wData進行比較。請注意,RdWr可以在每個posedge時鐘采樣為真。序列data_check将進入每個時鐘;建立一個local_data的新副本,并建立一個新的線程,它将在5個鐘後用wData檢查local_data+'hff。圖9.2顯示了局部變量的其他語義。密切關注局部變量必須附加到表達式,而比較不能附加到表達式的規則!
圖9.2局部變量-Dos和Donts
如圖9.2所示,當存儲一個值時,必須将一個局部變量附加到表達式上。但是,當比較存儲在局部變量中的值時,它不能附加到表達式上。
在最上面的示例中,local_data = rData附加到序列rdC。換句話說,指派“local_data = rData”将僅在序列rdC完成時發生。繼續将這個值存儲到局部變量的故事中,如果在存儲值時沒有任何附加到局部變量的内容,該怎麼辦?使用1'b1(始終為true)作為表達式。這意味着無論何時輸入一個序列,表達式總是為真,并且應該将該值存儲在局部變量中。簡單!
同樣,如果您比較表達式上的值為真,該怎麼辦?如圖9.2所示,您可以通過如圖所示分離表達式來實作此目的。結果序列(圖9.2中的最後一個序列)将被了解為“進入dataCheck,将rData存儲到local_data中,等待5個時鐘,然後如果b(序列rdC)在5個時鐘内為真,則将wData與存儲的 local_data+ h'ff 比較”。
圖9.3局部變量 - 和形式參數
圖9.3指出了其他一些重要特性。首先,在序列或屬性中使用局部變量沒有限制。此外,您不能将局部變量聲明為形式參數,并将其作為另一個序列/屬性中的實際值傳遞。這是有道理的,否則為什麼它會被稱為本地?
圖9.4局部變量 - 可見性
在圖9.4中,我們看到序列中的局部變量對執行個體化它的序列是不可見的。解決方案非常簡單。不要直接使用局部變量,隻需将參數傳遞給包含局部變量的序列即可。當序列L_seq在本地更新參數時,它将對調用序列(H_seq)可見。請注意,Ldata未在序列L_seq聲明為局部變量(否則這将是我們讨論的錯誤)。 L_seq隻是更新一個形式參數并将其傳遞給調用序列,其中實際被聲明為局部變量。這顯示在圖9.4, 9.5的底部。
圖9.6,9.7,9.8,9.9,9.10,9.11,9.12顯示了更精細的規則。當你着手寫複雜的斷言時,将它們作為參考。圖中的注釋解釋了情況。
圖9.5帶有‘OR’的局部變量複合序列
圖9.6局部變量 - 用于OR配置設定本地資料 - 在複合序列之前
圖9.6描述了在兩個序列的‘OR’中使用時控制局部變量的語義。局部變量必須在OR的序列中配置設定。但是,如果你不能這樣做呢?圖9.7中提供了幾個解決方案。
圖9.7局部變量 - 在OR的兩個序列中配置設定局部資料
圖9.9描述了管理一個‘and’兩個序列的語義。與一個或兩個序列相比,一個局部變量不能附加到‘and’中所涉及的兩個序列上。第一種解決方案與‘or’相同。如圖所示,在兩個序列之外配置設定局部變量。或者,隻需在兩個序列中的一個中配置設定局部變量,這是一個明顯的解決方案。除了圖9.8中的解決方案#1之外,圖9.9還顯示了解決方案#2。
圖9.8局部變量 - ‘and’複合序列
圖9.9局部變量 - 更細微的細微差别III
圖9.10局部變量 - 進一步的細微差别IV
圖9.10描述了控制局部變量的更多規則。首先,您可以将多個局部變量配置設定給一個表達式。其次,您也可以按照相同的順序操作指定的本地資料(與ldata2的情況相同)。但是和以前一樣,在配置設定(存儲)局部變量和比較它們的存儲值方面存在差異。您不能在序列中的單個表達式中比較多個局部變量值,就像行(// wData == ldata1,wretryData ==!ldata2)中的情況一樣。這是非法的。當然,總是有一個解決方案,如圖所示。簡單地将兩個子序列中的多個值進行比較,兩者之間沒有延遲。圖中的‘Solution’注釋說明了這一點。
圖9.11局部變量不能在延遲範圍内使用
圖9.11顯示了你不能在範圍運算符中使用局部變量。 但是,這不是局部變量錯。 這是事實,我們不能在#m或#[m:n]延遲運算符中有可變延遲。 從軟體角度來看,延遲範圍操作符需要在elaboration時已知。 是以他們不能是變數? 從硬體角度來看,這是一個無賴!
圖9.12顯示你不能用正式的形參來定義局部變量。 同樣,矢量(總線)聲明的大小隻能是一個常量。 再次,這有一個軟體原因和硬體原因。 我會留給讀者猜測我的想法!
圖9.12局部變量 - 不能使用形參來确定定義變量的大小
9.1 應用程式:局部變量
圖9.13局部變量 - 應用程式
圖9.13中的應用程式分解如下。
($rose(read),localID=readID
在$ rose(read)上,readID存儲在localID中。
not (($rose(read) && readID==localID) [*1:$])
然後,我們檢查是否發生了另一個讀取($ rose(read)),它的readID與我們為先前存儲在localID的readID相同。我們繼續連續檢查,直到出現## 0($ rose(readAck)&& readAckID == localID)。
如果連續檢查确實導緻了比對,那麼這意味着我們獲得了另一個$ rose(read),其中具有與前一次讀取相同的readID。這違反了規範。這就是為什麼我們采用這種表達式取反(not)來看到它在比對中檢查到錯誤并且屬性會結束。
如果在## 0($ rose(readAck)&& readAckID == localID)到達之前連續檢查沒有導緻比對,那麼我們确實得到了一個readAck,它具有與發出原始讀取相同的readAckID。該屬性将通過。
簡而言之,我們已經證明,一旦發起一次'讀',在相同ID的'readAck'傳回之前,來自同一個readID的另一次'讀'不能被重發。