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





