參考書目:英文版:《advanced FPGA design》 中文版:《高級FPGA設計,結構,實現,和優化》
解決數字電路中時序問題的八大忠告
忠告一:如果時序差的不多,在1ns以內,可以通過修改綜合、布局布線選項來搞定,如果差的多,就得動代碼。
忠告二:看時序報告,找到時序最差的路徑,仔細看看是什么原因導致,先看邏輯級數是多少?是哪種電路有問題,乘法器或者RAM接口數據,弄清楚哪兒的問題。
忠告三:搞時序優化的話,插入寄存器是王道,但也要看具體情況,不一定都得插寄存器,插入寄存器效果不明顯的話,先檢查一下寄存器插入的位置,如果寄存器不是在關鍵路徑的中間插入而是在某一端的話,確實不大明顯。
忠告四:把關鍵路徑找出來,看時序報告,看是什么原因導致頻率上不去,如果是組合邏輯復雜,就優化邏輯或者復制邏輯,如果是DSP延遲大,就選多級流水的,只要想搞到150,就一定可以。
忠告五:看時序報告的時候,建議同時對照電路圖一起看,這樣最直觀。
忠告六:對照代碼,自己把關鍵路徑涉及部分的電路圖畫出來,然后根據時序要求,算一下要插多少寄存器,插哪兒合適。
忠告七:32bit的比較器,進位鏈有點長,可以分段比較,分成4個8bit的數據段去比,或者分成兩段,先比高16,插寄存器,再比低16,時序很好,如果想深入些,就自己手寫一個比較器,不要調庫。
忠告八:多bit的邏輯,時序上不去,通常都是進位鏈太長,通常做法就是打斷進位鏈,建議看看計算方法或者數字算法之類的書,應該會有幫助。
進行數字電路中時序優化的五大方法
這里說的優化是讓FPGA設計獲得更高的工作頻率,也就是通常說的性能和吞吐率。
1.插入寄存器(pipeline)
這種方式會增加設計的時滯(clock latency)。插入了幾個寄存器,結果輸出就會延長幾個周期,在不違反設計規格(對clock latency有要求)以及功能沒有影響的時滯情況之下可以這么做。舉例說明,如果下面一個FIR濾波器的設計沒能滿足時序要求。
1 module fir( 2 output [7:0] Y, 3 input [7:0] A,B,C,X, 4 input clk, 5 input validsample); 6 always @(posedge clk) 7 if(validsample) begin 8 X1<=X; 9 X2<=X1; 10 Y<=A*X+B*X1+C*X2; 11 end 12 endmodule
從代碼可以看出,X2這條路徑過長,是整個設計的Critical Path,如果采用流水線設計可以用寄存器暫存自已在執行Y的運算,改進如下:
1 module fir( 2 output [7:0] Y, 3 input [7:0] A,B,C,X, 4 input clk, 5 input validsample); 6 reg [7:0] X1,X2,Y; 7 reg [7:0] prod1,prod2,prod3; 8 always @(posedge clk) begin 9 if(validsample) begin 10 X1<=X; 11 X2<=X1; 12 prod1<=A*X; 13 prod2<=B*X1; 14 prod3<=C*X2; 15 end 16 Y<=prod1+prod2+prod3; 17 end 18 endmodule
2.並行化設計
並行化設計的思想是將一個邏輯函數分解為幾個小一些的邏輯函數並行計算,從而減少關鍵路徑上的延遲 。
例如計算兩個8bits數的乘法,將8bits數分為兩個4bits數,則乘法運算可以被分解為下面幾個部分:
X∗X={A,B}∗{A,B}={(A∗A),(2∗A∗B),(B∗B)};
通過這種方法可以將設計簡化為一系列4bits乘法器的實現。
1 module power3( 2 output [7:0] XPower, 3 input [7:0] X, 4 input clk); 5 reg [7:0] XPower1; 6 //部分結果寄存器 7 reg [3:0] XPower2_ppAA,XPower2_ppAB,XPower2_ppBB; 8 reg [3:0] XPower3_ppAA,XPower3_ppAB,XPower3_ppBB; 9 reg [7:0] X1,X2; 10 wire [7:0] XPower2; 11 wire [3:0] XPower1_A = XPower1[7:4]; 12 wire [3:0] XPower1_B = XPower1[3:0]; 13 wire [3:0] X1_A = X1[7:4]; 14 wire [3:0] X1_B = X1[3:0]; 15 wire [3:0] XPower2_A = XPower2[7:4]; 16 wire [3:0] XPower2_B = XPower2[3:0]; 17 wire [3:0] X2_A = X2[7:4]; 18 wire [3:0] X2_B = X2[3:0]; 19 assign XPower2 = (XPower2_ppAA << 8) + (2*XPower2_ppBB << 4) + XPower2_ppBB; 20 assign XPower = (XPower3_ppAA << 8) + (2*XPower3_ppBB << 4) + XPower3_ppBB; 21 always @(posedge clk) begin 22 //第一級流水線 23 X1 <=X; 24 XPower1 <= X; 25 //第二級流水線 26 X2 <= X1; 27 XPower2_ppAA <= XPower1_A * X1_A; 28 XPower2_ppAB <= XPower1_A * X1_B; 29 XPower2_ppBB <= XPower1_B * X1_B; 30 //第三級流水線 31 XPower3_ppAA <= XPower2_A * X2_A; 32 XPower3_ppAB <= XPower2_A * X2_B; 33 XPower3_ppBB <= XPower2_B * X2_B; 34 end 35 endmodule
3.邏輯展平
通過優化掉設計中的優先級譯碼電路,邏輯結構被展平,路徑延遲得以縮短,優先級譯碼電路常出現在IF/ELSE結構語句中出現。
1 module regwrite( 2 output reg [3:0] rout, 3 input clk,in, 4 input [3:0] ctrl); 5 always @(posedge clk) 6 if(ctrl[0]) rout[0] <= in; 7 else if(ctrl[1]) rout[1] <= in; 8 else if(ctrl[2]) rout[2] <= in; 9 else if(ctrl[3]) rout[3] <= in; 10 endmodule
上面代碼綜合后就會產生優先級譯碼器,通過各項平級的if語句或者case語句可以避免這樣的優先級譯碼設計
1 //改進后 2 module regwrite( 3 output reg [3:0] rout, 4 input clk,in, 5 input [3:0] ctrl); 6 always @(posedge clk) begin 7 if(ctrl[0]) rout[0] <= in; 8 if(ctrl[1]) rout[1] <= in; 9 if(ctrl[2]) rout[2] <= in; 10 if(ctrl[3]) rout[3] <= in; 11 end 12 endmodule
4.均衡設計
均衡設計的思想是把 Critical Path 上的組合邏輯拿出一部分放在 short path 上進行,從而縮短 Critical Path 的延遲。
下面舉例一個8位加法器。
1 module adder( 2 output reg [7:0] Sum, 3 input [7:0] A,B,C, 4 input clk); 5 reg [7:0] rA,rB,rC; 6 always @(posedge clk) begin 7 rA <= A; 8 rB <= B; 9 rC <= C; 10 Sum <= rA+rB+rC; 11 end 12 endmodule
可以看到,在寄存器rA,rB,rC之前的路徑上沒有組合邏輯,所以可以考慮把一部分計算拿到寄存器之前
1 //改進后 2 module adder( 3 output reg [7:0] Sum, 4 input [7:0] A,B,C, 5 input clk); 6 reg [7:0] rABSum,rC; 7 always @(posedge clk) begin 8 rABSum <= A + B; 9 rC <= C 10 Sum <= rABSum + rC; 11 end 12 endmodule
5.優化路徑
最后一種方法也是我認為最難的,通過優化數據流的路徑來縮短 Critical Path ,提升系統性能。重新布局和 Critical Path 在一起的路徑,從而 Critical Path上的邏輯門可以更靠近目標寄存器。舉一個栗子:
1 module randomlogic( 2 output reg [7:0] Out, 3 input [7:0] A,B,C, 4 input clk, 5 input Cond1,Cond2); 6 always @(posedge clk) 7 if(Cond1) 8 Out <= A; 9 else if(Cond2&&(C<8)) 10 Out <= B; 11 else 12 Out <= C; 13 endmodule
可以看到C作為B的輸出條件的路徑最長,經過了一個比較器和兩個邏輯門,是整個設計的 Critical Path ,可以做后續優化。
1 //改進后 2 module randomlogic( 3 output reg [7:0] Out, 4 input [7:0] A,B,C, 5 input clk, 6 input Cond1,Cond2); 7 wire CondB = (Cond2 &!Cond1); 8 always @(posedge clk) 9 if(CondB&& (C<8)) 10 Out <= B; 11 else if(Cond1) 12 Out <= A; 13 else 14 Out <= C; 15 endmodule
后續待補充。。。