可能會造成綜合前后仿真不匹配的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語句等等。這些都有可能是造成仿真和綜合不匹配的原因。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM