Verilog代碼設(shè)計(jì)之時(shí)分復(fù)用
時(shí)間:2025-08-21 22:08:15
手機(jī)看文章
掃描二維碼
隨時(shí)隨地手機(jī)看文章
做芯片第一要追求的是功能,在保證功能都滿足的情況下追求性能,在性能滿足的情況下追求成本,也就是面積。當(dāng)然功耗也十分重要。提高速度和降低面積屬于兩個(gè)矛盾的目標(biāo),各自努力的方向基本相反,想要更快的運(yùn)行速度,就得堆更多的資源,在具體的設(shè)計(jì)中往往需要折中(Trade off)。在性能允許條件下采用時(shí)分復(fù)用更多的邏輯來減少芯片的面積,面積及成本。通常情況下面積關(guān)系為加法器 > 比較器 > 選擇器,乘法器可以認(rèn)為是多個(gè)加法器。所以就有先選后比,先選后加,先選后乘。
畫個(gè)圖意思一下。
圖中的加法器可以替換成,比較器,乘法器,一個(gè)運(yùn)算單元,甚至巨大的一個(gè)模塊。乘法器時(shí)分復(fù)用在計(jì)算模塊中乘法器也是非常大的一部分邏輯,一個(gè)設(shè)計(jì)要考慮PPA最優(yōu),一個(gè)必須要考慮乘法器的數(shù)量多少以及復(fù)用能不能最大化,追求最好的設(shè)計(jì)是整個(gè)數(shù)據(jù)通路中乘法器空閑不下來。通常的設(shè)計(jì)是做一個(gè)專門的乘法器模塊,按系統(tǒng)最大的位寬開辟乘法器位寬邏輯,根據(jù)設(shè)計(jì)流程最大程度上復(fù)用乘法器資源。
每一路乘法配備一個(gè)vld,用vld來作為當(dāng)前有效的乘法運(yùn)算,乘法器的結(jié)果隨著vld的下一拍進(jìn)行鎖存。從下圖可以看出乘法器的復(fù)用需要將各個(gè)部分的運(yùn)算時(shí)間區(qū)分開,不可避免系統(tǒng)的時(shí)間會(huì)變長,想要縮短時(shí)間則可以用更多的乘法器來大幅縮短時(shí)間,想要面積更小,則用更少的乘法器資源來時(shí)分復(fù)用。面積與速度互換思想核心。
修改完后的寄存器省了很多,但是乘法器的輸出寄存器負(fù)載會(huì)變大,不過后端綜合時(shí)約束了max_fan_out工具會(huì)自動(dòng)插buffer和復(fù)制寄存器,經(jīng)過實(shí)測還是會(huì)節(jié)省很多面積。不過這是在時(shí)序較好的情況下,如果時(shí)序比較緊,這樣插多余的buffer會(huì)導(dǎo)致時(shí)序過不了。RAM的復(fù)用大于1k的寄存器組使用,考慮用RAM替代,但用RAM讀寫數(shù)據(jù)需要時(shí)序控制邏輯,并行度會(huì)降低。要求并行度高,可使用多個(gè)RAM。
從設(shè)計(jì)的整體來看,RAM也可以復(fù)用,前面處理完空閑下來的ram,后面處理也可以使用。真的要這么多的復(fù)用嗎?復(fù)用可以是各種的,從單個(gè)邏輯運(yùn)算到一個(gè)巨大的IP。那么真的要這么多的復(fù)用嗎?前面說的復(fù)用必然需要分時(shí),所以會(huì)導(dǎo)致系統(tǒng)處理時(shí)間變長,所以必須在保證處理性能的前提下通過復(fù)用來減少面積。在控制通路上,大大小小的計(jì)數(shù)器會(huì)有很多個(gè),理論上一些計(jì)數(shù)器也可以復(fù)用,但是共用一個(gè)計(jì)數(shù)器意味著,這個(gè)計(jì)數(shù)器的開始和結(jié)束邏輯復(fù)雜,而到了調(diào)試(debug)階段,必然會(huì)是調(diào)試變得復(fù)雜繁瑣。一個(gè)加法器如果要復(fù)用的數(shù)據(jù)比較多,除了是debug看起來復(fù)雜之外,增加的選擇器邏輯可能也不一定會(huì)小。兩個(gè)獨(dú)立的模塊中有部分相同的邏輯,是否真的有必要在提高了復(fù)雜度和模塊之間的耦合度的情況下去復(fù)用,這也需要考慮。到了項(xiàng)目后期一個(gè)小改動(dòng)也是需要回歸測試所有的測試用例,為了一小點(diǎn)減少邏輯而付出相對巨大的工作量從而影響進(jìn)度,總的來說獲得的邊際收益是非常小的。所以復(fù)用雖好,但也要適時(shí)、適度。
assign sum[4:0] = enable ? (data_a + data_b) : (data_c + data_d); assign add_a[3:0] = enable ? data_a : data_c;assign add_b[3:0] = enable ? data_b : data_d;assign sum[4:0] = add_a + add_b;




always @(*)beginif(mult0_vld) mult_a[3:0] = mult_a0;else if(mult1_vld) mult_a[3:0] = mult_a1;else // if(mult2_vld) mult_a[3:0] = mult_a2;end第二種選擇器寫法
assign mult_a[3:0] = ({4{mult0_vld}} & mult_a0) | ({4{mult1_vld}} & mult_a1) | ({4{mult2_vld}} & mult_a2)第二種寫法需要保證vld條件不會(huì)同時(shí)有效,看上去只用了一些門實(shí)現(xiàn),而且沒有優(yōu)先級(jí),感覺比第一種寫法邏輯少,但實(shí)際上經(jīng)過工具的優(yōu)化后,可能消耗邏輯差不多。但是第二種寫法在綜合后就會(huì)是你寫的這個(gè)樣子,而第一種則會(huì)綜合成一堆組合邏輯門。對于ECO來說,第二種寫法更友好,第一種復(fù)雜多了。而我更喜歡第一種寫法,因?yàn)榈谝环N在收集覆蓋率時(shí)會(huì)更友好。代碼覆蓋率會(huì)清楚的看到哪一行沒跑到,條件覆蓋率也比較簡單。每個(gè)if里面就一個(gè)條件。乘法器調(diào)用方法,一般是在乘法器的輸入保證寄存器輸入,結(jié)果輸出到各個(gè)復(fù)用模塊時(shí)打一拍再使用??梢宰龀稍谶M(jìn)行完乘法運(yùn)算后再打拍,這樣消耗的寄存器會(huì)少很多。畫個(gè)圖意思一下(單bit)。

