- Clock Period : 2.4 ns
- Total Latency : 40303 cycles
- RTL Area (03_gate_sim) : 251327.664931 μ𝑚2
- Performance : (Total Cycle x Clock Period)2 x Area = 2.35146 E+15
- Rank : 2 / 173
相較往年是一個非常佛心的 final project,主要就是實現以下四個功能。
- AXI 讀寫 DRAM 。
- 瑣碎但簡單的運算(加減、除法、比大小)。
- 切 pipeline 壓低 Clock Period 。
- 預判圖片內資訊(後面詳述),減少 DRAM 讀寫需求。
- 這是一個看起來非常簡單,實際上也非常簡單的實驗。
- 底子好的人會覺得學不太到東西。
- 強度不足,放在面試中沒辦法看出設計能力是否出色。
- DRAM 存放 16 張 32x32x3 圖片,每張圖由 R , G , B 三張子圖組成。
- 共有三個功能:Auto Focus , Auto Exposure , Average of Min and Max in the Picture
Auto Focus : 算出圖片正中心的 2x2 灰階、4x4 灰階、6x6 灰階,然後計算任兩個元素間的差值絕對值,加總後除上權重,找出答案最大的 idx。聽起來有點艱澀,不過看了題目就知道了。
Auto Exposure : 獲得一個權重(x0.25 / x0.5 / x1 / x2),將所有元素乘上該權重後算出整張圖片的灰階,除上 32*32。
Average of Min and Max in the Picture : 分別找出 R , G , B 中的最大值以及最小值,將 R_max , G_max , B_max 相加除三,將 R_min , G_min , B_min 相加除三,再將結果相加除二。
我大概花了五天時間完成這份實驗,看題目想架構花了兩天,兩天寫 code 、debug ,最後一天優化,pattern 是用管神的加上 max_min avg 功能,所以五天的時程不包含寫 pattern 。
- 資料共用 除非遇上 Auto Exposure 導致圖片內元素改變,否則 Average of Min and Max in the Picture 、 Auto Focus 的答案不會更動。因此只在倍率改變時訪問 DRAM ,並一次計算出三種功能的答案,將其存放於 DFF 中。
備註:每張圖片首次訪問若不是 Auto Exposure 功能,則以 Auto Exposure x1 的方式訪問。
- 預判 0 圖
一張圖片遇上多次 x0.5 / x0.25 後會將所有元素歸零,此時不論如何所有功能的答案都是 0 ,將不再需要訪問 DRAM 。
- 解 critical path Clock Period 決勝負,把所有能切的東西切一遍就完事了。
此部分情況繁瑣,無法點出所有狀況,以下是幾個比較常見的問題點:
always @(posedge clk) begin
if (cnt == 30) begin
// do something
end else begin
// do something
end
end
可以改成這樣
always @(posedge clk) cnt_is_30 <= (cny == 29);
always @(posedge clk) begin
if (cnt_is_30) begin
// do something
end else begin
// do something
end
end
always @(posedge clk) begin
if (in_valid)
in_pic_no_q <= in_pic_no;
end
always @(posedge clk) begin
info[in_pic_no_q] <= info_n;
end
此處的程式很簡潔,但是合成出來的電路卻很大一包," info[in_pic_no_q] <= info_n; " 隱含由比較器構成的索引功能,相當於
always @(posedge clk) begin
for (int i = 0; i < 16; i++) begin
if (in_pic_no_q == i) begin
info[i] <= info_n;
end
end
end
此處的 "in_pic_no_q == i" 也可用同樣的方法擋一顆 DFF。
always @(posedge clk) begin
div_result <= div_in / 3 ;
end
發生在這種地方就非常頭痛了,能用 DW_ip 的話就直接叫一顆 multi-stages 除法器,但偏偏這次不能用,就只能手刻 pipeline 除法器了。
除法、乘法可以切 pipeline ,若是加減法,可以改成較低位元的運算,以多個 cycle 完成。
通常都是切到走火入魔才會遇到這種問題。
always @(posedge clk) begin
if (awready_s_inf)
// do something
end
這邊的 awready_s_inf 是 input 訊號,會有 0.5T input slack,解法就是找其他等價訊號替代掉 awready_s_inf 。
always @(posedge clk) begin
awvalid_q <= awvalid;
awvalid_qq <= awvalid_q;
end
always @(posedge clk) begin
if (awvalid_qq)
// do something
end
不過這種情況應該只有 iclab 會遇到,不太實際。
此處的 data buffer 代表用於保存 input 資訊的 DFF
reg [7:0] in_data_buffer [0:15];
reg [3:0] in_cnt;
always @(posedge clk or negedge rst_n) begin
if (~rst_n)
in_cnt <= 0;
else if (in_valid)
in_cnt <= in_cnt+1;
else
in_cnt <= 0;
end
always @(posedge clk)begin
if (in_valid)
in_data_buffer[in_cnt] <= in_data;
end
可以用 shift reg 來取代,但當資料過多時不適合使用,會造成 power 負擔。
reg [7:0] in_data_buffer [0:15];
int i;
always @(posedge clk)begin
if (in_valid) begin
in_data_buffer[15] <= in_data;
for (i=0;i<15;i=i+1;) begin
in_data_buffer[i] <= in_data_buffer[i+1];
end
end
end
特別感謝
Bonbodii -> GitHub Home Page <-
chance-chhong -> GitHub Home Page <-
Anonymous A -> GitHub Home Page <-
Allen Kuan -> GitHub Home Page <-
- RANK 是我自己換算出來的
- 2.4ns 版本 critical path 長在加法器上,繼續切可以壓到 1.8 ns ,想要進一步優化要調整控制訊號,也就是說會切到本架構的大動脈,我想我該寫論文了。