1. 程式人生 > 其它 >可能會造成綜合前後模擬不匹配的RTL 程式碼

可能會造成綜合前後模擬不匹配的RTL 程式碼

最近開始讀Cummings大神的一系列文章,然後就單純做做讀書筆記,這次的文章全名是RTL Coding Styles That Yield Simulation and Synthesis Mismatches。網上搜Cummings和文章名應該就能找到,這裡就不放連結了。

模擬和綜合不匹配通常會以綜合前的模擬和綜合後的模擬不一致來體現,所以綜合後看看模擬結果也是需要的。那什麼是不好的RTL程式碼習慣呢?Cummings總結下來就是,基本上如果RTL程式碼裡面的設計資訊可以被HDL模擬器提取,卻不能被綜合工具理解的,就是不好的;反過來說,如果可以被綜合工具理解,模擬器卻不支援,那也是不好的。

Cummings提到的情況有這些:

1. 不完整的sensitivity list

使用always 模組來實現組合邏輯電路和鎖存器時,如果給出的sensitivity list不完整的話就會導致模擬和綜合不匹配了。綜合工具可以不依賴於列表,通過分析邏輯方程從而完成綜合,但是綜合前模擬就不行了。

下面三段程式碼,code1a的模擬和綜合是匹配的。Coed1a由於列表裡缺少訊號b,其綜合前模擬的輸出o無法對訊號b的變化作出反應。Code1c則因為沒有列表而導致綜合前模擬陷入死迴圈。此時可以通過使用always @(*) 來避免。

2. 錯誤的語句順序

由於always模組在模擬中會順序執行裡面的賦值語句,所以不同的語句順序也可能導致模擬和綜合不匹配,尤其是當被賦值的訊號會在同一個always 模組用於if, case裡的判斷或是用於賦值其他訊號。

下面程式碼被綜合後實現的都是兩個2輸入的與門和一個2輸入的或門。但是對於code2a的綜合前模擬來說,由於中間量temp在被新的訊號c和d賦值前,就被用於賦值輸出o,也就是說輸出o 用的是temp上一次更新的值從而導致模擬結果不匹配。而code2b的語句順序就沒有這個問題。

3. Function模組的使用

Functions裡的模組總是會被綜合成組合邏輯電路,所以當模擬器理解function裡描述的是鎖存器時,就會造成模擬和綜合的不匹配。Code3a裡的always模組會被綜合成鎖存器,而code3b由於使用了function,裡面的邏輯會被綜合成3輸入的與門。所以在使用function來進行邏輯設計時需格外謹慎。

4. Full case directive

在使用case語句時加入//synopsys full_case可能會導致模擬和綜合不匹配。這個directive會告訴綜合工具這個case語句所需的情況都定義好了,沒有定義的情況就會被當作don’t care。

下面的code4a和code4b的綜合前模擬結果是相同的,但是code4a沒有使用full_case, 整個case語句綜合出來的4個3輸入的與門和2個取反器。而code4b使用full_case後,由於沒定義的case(即en訊號為0是情況)直接被當成don’t care,訊號en就直接被優化掉了,整個case語句跟en沒有關係了,所以綜合得到的電路是4個2輸入的或非門和2個取反器。

5. Parallel case driective

當case語句加入//synopsys parallel_case時,相似的情況也會出現。這個directive會告訴綜合工具並行地描述整個case語句。而一般情況下,如果case中有重疊的情況,優先編碼器很可能會被綜合出來。

下面的code5a和code5b在綜合前模擬會得到相同的結果,但是code5a被綜合成一個優先編碼器,而由於parallel case的使用,code5b被綜合成並行的兩個2輸入與門。

6. casex 的使用

使用casex可能會造成模擬和綜合不匹配。如果一個訊號在casex模組裡是作為判斷條件的,但沒有被初始化或者其他原因處於unknown的時候,模擬器會把這個訊號當成”don’t care”。但是由於實際電路就不存在unknown,這個unknown訊號經過實際電路會解析成訊號0或1,這樣就有可能錯誤地匹配到casex裡面的語句了,而這種錯誤在綜合前模擬就可能注意不到了。

Code6就描述了一個簡單的地址decoder。如果電路中出現錯誤導致en訊號在初始化一段時間內處於unknown的狀態,在出現相應的地址時就有可能導致memce0或者memce1被錯誤地拉高到高電平。

Cummings直接推薦不要在RTL裡使用casex語句,有需要的話就使用casez。雖然casez和casex有相似的問題,就是在訊號在high-z的時候會被模擬器當成”don’t care”。但是相對於unknown,high-z的情況偏少並且較容易被注意到。但是使用casez時還是要多加註意。

(為了和程式碼的順序一致,跳過了7)

8. 把訊號賦值成X

除了上述使用casex的情況外,模擬器都是把程式碼裡的X當成unknown的,但是綜合工具為了更簡單優化的電路會把X當成”don’t care”,這就會導致綜合前後的模擬出現不一致了。當然這種不一致有時候是除錯的技巧。

下面code8a裡的訊號y,在用case語句賦值前就先賦值到X。如果這個訊號S是不應該跑到2’11的,那如果在綜合前模擬中發現訊號y有時候出現unknown了就容易捕抓到這個錯誤(畢竟波形圖裡unknown是紅色的比較顯眼)。當然如果無所謂訊號S是不是會出現2’11的情況,那這個模擬不匹配就有點惱人了(畢竟紅色刺眼:D)。

11. always 模組裡的時間延遲

還有就是時間延遲的使用。當構建一些用於模擬的模型時(例如模擬一個ADC來輸出訊號),可能會用到一些時間的語句。如code11, 當訊號in發生翻轉時,延時25個單位時間後訊號in取反然後賦值給訊號out1,再延時40個單位時間後,給訊號out2賦值。問題在於,如果進入always模組後65個單位時間內,訊號in出現翻轉,就不會再觸發一次進入always模組的情況。這意味著如果訊號in的變換頻率高於65個單位時間,訊號out1和out2的更新速度是跟不上的。模擬和綜合不匹配的情況就可能會出現了。

文章還提到了translate_on和translate_off這些綜合directives的使用也會造成模擬和綜合的不匹配。暫時沒有什麼體驗就不多說了,但是據文章的描述,使用這對directives可以強制輸出正確的訊號水平來彌補一些模擬器模擬不充分的情況。有興趣的朋友可以多搜搜。

除了文章提到的,為了避免綜合前後模擬不一致的情況,還需要注意metastability的設計,例如非同步的訊號有沒有被正確地進行同步和跨時鐘領域處理。綜合後時序也需要檢查,看看有沒有違反時序的情況,時鐘頻率和各種時序約束是否正確。還有testbench中沒有使用blocking語句等等。這些都有可能是造成模擬和綜合不匹配的原因。