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