這篇文章來整體的聊一下個人理解的例化寄存器型的RTL編碼風格。在脫離實驗室氛圍開始在公司寫芯片設(shè)計代碼的時候,就發(fā)現(xiàn)公司里代碼規(guī)范里明確表明:
1.避免always @*語句;
2.避免always時序語句;
這讓我幼小的心靈備受打擊,不用always怎么怎么寫RTL呢?當然了寫著寫著也就習慣了。避免always @*這個咱們已經(jīng)理解用意了,主要是避免X態(tài)問題被掩蓋。那么避免always時序語句是為什么?又應(yīng)該如何實操呢? 要避免always時序語句其實也很簡單,自然就是例化dff了呀,根據(jù)接口和特性可以劃分歸類一下有哪幾種dff我們可能會用得到:
1.是否需要復(fù)位
2.是否需要使能
3.是否需要校驗
暫時排除第三種校驗情況稍后再聊,根據(jù)前兩個分類我們會得到以下的dff模塊:
1.moon_dffre
2.moon_dffr
3.moon_dffe
4.moon_dff
這個前綴就是做一下標志隨便加就可以。dff例化的風格怎么取代always時序呢,以下面這段代碼為例:
1.能夠規(guī)避不合理的代碼習慣。最典型的就是時序邏輯中的clk_gating問題。想要綜合工具自動插入門控的話,那么always塊中就盡量不要有else分支(或者else分支是非阻塞賦值給自身),如果else中對信號賦常值了那么門控就插不進去,影響整個芯片的功耗。那么如果自己來寫always塊粗心大意了的話就可能出問題,且這個事完全靠個人意識了(當然工具可以查gating比例)。如果采用例化dff的方式,寄存器的實現(xiàn)方式就是統(tǒng)一的,只要dff模塊寫的合理那么無論如何調(diào)用都不會出這個問題。
2.便于X態(tài)檢查。如同之前文章中所述的,if-else會掩蓋X態(tài)問題,而如果我們希望對X態(tài)進行檢查那么就可以統(tǒng)一在dff模塊內(nèi)來完成。
3.便于集中操作。假如某天突然有一個需求,要求所有的寄存器都加入校驗邏輯,那么如果是always塊怎么處理比較快速呢?需要把所有寄存器的值送入一個模塊,然后連出一根error線。dff模塊呢可以在模塊內(nèi)加入邏輯,例化時把error接出來||在一起。還是那句話,這兩種方式難說好壞,dff例化型編碼倒是可以從底層保證所有例化的寄存器都加入了校驗邏輯(引出的工作還是得自己來的)。
4.便于全局替換。還是剛剛那個例子,加入校驗邏輯,只需要全局把moon_dffre替換為moon_dffre_chk就可以了。
5.邏輯和互聯(lián)更加清晰,更接近于底層電路實現(xiàn)對工具友好。同時我的習慣是用xx_d、xx_q、xx_en來命名信號,那么在寫邏輯時,代碼中用到了xx_q我就會非常放心因為這意味著該信號的時序極好,寫習慣了對于時序路徑的把握也有所提升。
6.有利于降低復(fù)位比例,利于功耗控制。dff例化風格編碼時,組合邏輯和時序邏輯是分開寫的,在每一個時序邏輯處都面臨一個模塊選型的問題,這個時候就需要分析這個寄存器是不是需要復(fù)位,如果不需要就選用moon_dffe型好了。而always塊寫法組合邏輯和時序邏輯是在一處寫,精力很容易投在if-else的邏輯上,復(fù)位很多時候就順手寫了,后面還得艱難的降復(fù)位比例。
7.便于腳本工具集中處理,對,說的就是auto_dff哈哈。 最后一點,dff例化風格的代碼天然的會分成信號聲明、組合邏輯、時序邏輯三個部分,因此你可以選擇這樣組織代碼:
//寄存器1 ...聲明... ...邏輯... ...例化... //寄存器2 ...聲明... ...邏輯... ...例化... 也可以很輕易的把三個區(qū)域分開:
...聲明所有信號... ... ...例化所有寄存器... ... ...完成所有邏輯... ... 那么這個收益是什么呢?這樣編碼形式和風格容易寫出美感,畢竟好看才是編碼第一要務(wù)! 好的,dff編碼風格的收益部分就寫完了,接下來進行實操部分,各種dff模塊應(yīng)該怎么寫呢?從最典型的moon_dffre寫起吧。dffre顧名思義就是有復(fù)位有使能,內(nèi)部根據(jù)使能進行賦值:
odulemodule moon_dffre #( parameter WD = 1, parameter VE = {WD{1'b0}}) ( input clk, input rst_n, input [DW -1:0]d, input en, output reg[DW -1:0]q ); always @(posedge clk or negedge rst_n)begin if(!rst_n) q <= VE; else if(en) q <= d; end endmodule 兩個參數(shù)分別是寄存器的位寬和復(fù)位值。那么如果在模塊內(nèi)加入關(guān)于X態(tài)的校驗,可以增加如下的代碼(示意):
`ifdef ASSERT_ON property chk_en_xz(); @(posedge clk) disable iff(~rst_n) ~$isunknown(en); endproperty property chk_d_xz(); @(posedge clk) disable iff(~rst_n) en |-> ~$isunknown(d); endproperty assert_chk_en_xz: assert property(chk_en_xz()) else $assertoff(0, assert_chk_en_xz); assert_chk_d_xz: assert property(chk_d_xz()) else $assertoff(0, assert_chk_d_xz); `endif 這樣一來,X態(tài)檢查的問題就融在底層模塊中了。順著這個思路,另外幾種dff的編碼也很簡單,moon_dffe:
module moon_dffe #( parameter WD = 1) ( input clk, input [DW -1:0]d, input en, output reg[DW -1:0]q ); always @(posedge clk)begin if(en) q <= d; end `ifdef ASSERT_ON property chk_en_xz(); @(posedge clk) disable iff(~rst_n) ~$isunknown(en); endproperty property chk_d_xz(); @(posedge clk) disable iff(~rst_n) en |-> ~$isunknown(d); endproperty assert_chk_en_xz: assert property(chk_en_xz()) else $assertoff(0, assert_chk_en_xz); assert_chk_d_xz: assert property(chk_d_xz()) else $assertoff(0, assert_chk_d_xz); `endif endmodule moon_dffr沒有使能其實就沒有必要檢查什么X態(tài)的事了:
module moon_dffr #( parameter WD = 1, parameter VE = {WD{1'b0}}) ( input clk, input rst_n, input [DW -1:0]d, output reg[DW -1:0]q ); always @(posedge clk or negedge rst_n)begin q <= d; end endmodule 最最古樸的自然還是moon_dff:
module moon_dffr #( parameter WD = 1, parameter VE = {WD{1'b0}}) ( input clk, input rst_n, input [DW -1:0]d, output reg[DW -1:0]q ); always @(posedge clk)begin q <= d; end endmodule 基礎(chǔ)版本的寄存器這四種就完全夠用了。那么如果有需求在寄存器中加入校驗,比如說加入奇偶校驗,又該如何編碼呢?這就需要一個單獨的寄存器,當數(shù)據(jù)寫入時同步寫入校驗位,之后每拍檢查是否發(fā)生數(shù)據(jù)篡改:
編輯:黃飛
-
寄存器
+關(guān)注
關(guān)注
31文章
5317瀏覽量
120008 -
芯片設(shè)計
+關(guān)注
關(guān)注
15文章
1001瀏覽量
54812 -
RTL
+關(guān)注
關(guān)注
1文章
385瀏覽量
59701 -
代碼
+關(guān)注
關(guān)注
30文章
4748瀏覽量
68356 -
時序邏輯
+關(guān)注
關(guān)注
0文章
39瀏覽量
9148
原文標題:IC設(shè)計筆記 | 論RTL中always語法的消失術(shù)
文章出處:【微信號:IC修真院,微信公眾號:IC修真院】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論