在上一篇文章中(FPGA 的數(shù)字信號處理:Verilog 實現(xiàn)簡單的 FIR 濾波器)演示了在 Verilog 中編寫自定義 FIR 模塊的初始demo。該項目在行為仿真中正常,但在布局和布線時未能滿足時序要求。
所以今天的文章讓我們來看看當(dāng)設(shè)計不能滿足時序要求時如何分析并解決它。
當(dāng)在目標(biāo) FPGA 芯片中布局和布線時,首先在 Vivado 中確定時序要求.
將 FIR 作為RTL 模塊導(dǎo)入到block design中,其中通過AXI DMA 從存儲器傳輸相位增量偏移值的DDS可以輸入可變頻率正弦曲線,這樣就可以演示FIR的行為。
在 Vivado 中綜合布局布線并打開設(shè)計后,會彈出嚴(yán)重警告,告知設(shè)計不符合時序要求。
為了能夠準(zhǔn)確查看設(shè)計時序失敗的原因,在已完成綜合設(shè)計的底部窗口包含一個選項卡,用于 Vivado 在綜合期間對設(shè)計執(zhí)行的時序分析。當(dāng)存在時序失敗的信號路徑時,用戶可以過濾此時序分析以僅使用下圖中顯示的紅色圓圈感嘆號查看這些違規(guī)路徑:
在這個特定的設(shè)計中,有幾個信號路徑未能達(dá)到其分配的時序,這意味著信號的物理距離太遠(yuǎn)而無法穿過芯片和/或在信號出去之前需要通過太多的邏輯級別。保持時間太長的信號意味著當(dāng)將其計時到下一級寄存器中時,不能依賴它的值是否有效,從而使其余下游邏輯的行為不可靠/不可預(yù)測。
s_axis_fir_tdata在這種情況下,進(jìn)入 FIR 模塊的 AXI Stream 輸入接口的數(shù)據(jù)信號需要很長時間才能到達(dá)m_axis_fir_tdata目標(biāo)寄存器處的輸出。要查看比屏幕底部的時序分析窗口中的內(nèi)容更多的詳細(xì)信息,右鍵單擊底部時序分析窗口中的違規(guī)信號路徑,然后選擇“查看路徑報告(View Path Report)”選項。然后,將能夠看到 Vivado 如何計算出該信號的允許建立時間,并與它實際給出的 HDL 設(shè)計編寫方式進(jìn)行比較。這會給一些提示,說明是什么導(dǎo)致建立時間延長。然而,我發(fā)現(xiàn)要真正可視化保持時序違規(guī)比在示意圖中查看信號會更直觀。
要在原理圖中打開特定信號路徑,再次右鍵單擊底部時序分析窗口中的違規(guī)信號路徑,然后選擇“Schematic”選項。將打開一個新選項卡,顯示信號路徑在設(shè)計的物理布局中經(jīng)過的邏輯。
在為axis_fir_tdata的數(shù)據(jù)總線中的一個位打開信號路徑時,它揭示了設(shè)計在芯片中的布線,從圖中可以看出信號必須通過 11 級邏輯串行后才能到達(dá)其目的地。
既然對已實施設(shè)計的分析已經(jīng)揭示了哪些信號路徑是哪個時序違規(guī)的問題,現(xiàn)在的問題是我們?nèi)绾谓鉀Q它?在這種情況下,很明顯需要重新設(shè)計當(dāng)前邏輯,以更并行的方式處理更小的數(shù)據(jù)塊,從而縮短數(shù)據(jù)到其目標(biāo)寄存器的總路徑。
個人更喜歡在嘗試編寫任何實際的 Verilog 代碼之前繪制出邏輯。當(dāng)有這種設(shè)計執(zhí)行的操作的可視化表示時,調(diào)試設(shè)計會容易得多,特別是對于跟蹤此類時序違規(guī)等問題。
檢查當(dāng)前 FIR 模塊的邏輯設(shè)計,其中數(shù)據(jù)總線違反了建立時序,很明顯循環(huán)緩沖區(qū)串行填充然后將所有 15 個數(shù)據(jù)發(fā)送到累加塊時,立即求和會產(chǎn)生大量的處理延遲。
核心的想法是嘗試填充循環(huán)緩沖區(qū),將每個緩沖區(qū)乘以適當(dāng)?shù)南禂?shù),最后一次性對 15 個算子的每一個求和,但是這次我們考慮重新設(shè)計邏輯,讓循環(huán)緩沖區(qū)中僅花費乘法和累加(求和)兩個寄存器一個級聯(lián)的時間。
新 FIR 模塊的 Verilog 代碼:
`timescale1ns/1ps moduleFIR( inputclk, inputreset, inputsigned[15:0]s_axis_fir_tdata, input[3:0]s_axis_fir_tkeep, inputs_axis_fir_tlast, inputs_axis_fir_tvalid, inputm_axis_fir_tready, outputregm_axis_fir_tvalid, outputregs_axis_fir_tready, outputregm_axis_fir_tlast, outputreg[3:0]m_axis_fir_tkeep, outputregsigned[31:0]m_axis_fir_tdata ); /*ThisloopcontrolstkeepsignalonAXIStreaminterface*/ always@(posedgeclk) begin m_axis_fir_tkeep<=?4'hf; ????????end ???????? ????/*?This?loop?controls?tlast?signal?on?AXI?Stream?interface?*/ ????always?@?(posedge?clk) ????????begin ????????????if?(s_axis_fir_tlast?==?1'b1) ????????????????begin ????????????????????m_axis_fir_tlast?<=?1'b1; ????????????????end ????????????else ????????????????begin ????????????????????m_axis_fir_tlast?<=?1'b0; ????????????????end ????????end ???? ????//?15-tap?FIR? ????reg?enable_fir; ????reg?signed?[15:0]?buff0,?buff1,?buff2,?buff3,?buff4,?buff5,?buff6,?buff7,?buff8,?buff9,?buff10,?buff11,?buff12,?buff13,?buff14; ????wire?signed?[15:0]?tap0,?tap1,?tap2,?tap3,?tap4,?tap5,?tap6,?tap7,?tap8,?tap9,?tap10,?tap11,?tap12,?tap13,?tap14;? ????reg?signed?[31:0]?acc0,?acc1,?acc2,?acc3,?acc4,?acc5,?acc6,?acc7,?acc8,?acc9,?acc10,?acc11,?acc12,?acc13,?acc14;? ???? ????/*?Taps?for?LPF?running?@?1MSps?*/ ????assign?tap0?=?16'hFC9C;??//?twos(-0.0265?*?32768)?=?0xFC9C ????assign?tap1?=?16'h0000;??//?0 ????assign?tap2?=?16'h05A5;??//?0.0441?*?32768?=?1445.0688?=?1445?=?0x05A5 ????assign?tap3?=?16'h0000;??//?0 ????assign?tap4?=?16'hF40C;??//?twos(-0.0934?*?32768)?=?0xF40C ????assign?tap5?=?16'h0000;??//?0 ????assign?tap6?=?16'h282D;??//?0.3139?*?32768?=?10285.8752?=?10285?=?0x282D ????assign?tap7?=?16'h4000;??//?0.5000?*?32768?=?16384?=?0x4000 ????assign?tap8?=?16'h282D;??//?0.3139?*?32768?=?10285.8752?=?10285?=?0x282D ????assign?tap9?=?16'h0000;??//?0 ????assign?tap10?=?16'hF40C;?//?twos(-0.0934?*?32768)?=?0xF40C ????assign?tap11?=?16'h0000;?//?0 ????assign?tap12?=?16'h05A5;?//?0.0441?*?32768?=?1445.0688?=?1445?=?0x05A5 ????assign?tap13?=?16'h0000;?//?0 ????assign?tap14?=?16'hFC9C;?//?twos(-0.0265?*?32768)?=?0xFC9C ???? ????/*?This?loop?controls?tready?&?tvalid?signals?on?AXI?Stream?interface?*/ ????always?@?(posedge?clk) ????????begin ????????????if(reset?==?1'b0?||?m_axis_fir_tready?==?1'b0?||?s_axis_fir_tvalid?==?1'b0) ????????????????begin ????????????????????enable_fir?<=?1'b0; ????????????????????s_axis_fir_tready?<=?1'b0; ????????????????????m_axis_fir_tvalid?<=?1'b0; ????????????????end ????????????else ????????????????begin ????????????????????enable_fir?<=?1'b1; ????????????????????s_axis_fir_tready?<=?1'b1; ????????????????????m_axis_fir_tvalid?<=?1'b1; ????????????????end ????????end ???? ????reg?[3:0]?cnt; ????reg?signed?[31:0]?acc01,?acc012,?acc23,?acc34,?acc45,?acc56,?acc67,?acc78,?acc89,?acc910,?acc1011,?acc1112,?acc1213; ???? ????/*?Circular?buffer?w/?Multiply?&?Accumulate?stages?of?FIR?*/ ????always?@?(posedge?clk?or?posedge?reset) ????????begin ????????????if?(reset?==?1'b0) ????????????????begin ????????????????????m_axis_fir_tdata?<=?32'd0; ????????????????end ????????????else?if?(enable_fir?==?1'b1) ????????????????begin ????????????????????buff0?<=?s_axis_fir_tdata; ????????????????????acc0?<=?tap0?*?buff0; ???????????????????? ????????????????????buff1?<=?buff0;? ????????????????????acc1?<=?tap1?*?buff1;?? ????????????????????acc01?<=?acc0?+?acc1; ????????????????????????? ????????????????????buff2?<=?buff1;? ????????????????????acc2?<=?tap2?*?buff2; ????????????????????acc012?<=?acc01?+?acc2; ???????????????????????????? ????????????????????buff3?<=?buff2;? ????????????????????acc3?<=?tap3?*?buff3; ????????????????????acc23?<=?acc012?+?acc3; ????????????????????????? ????????????????????buff4?<=?buff3;? ????????????????????acc4?<=?tap4?*?buff4; ????????????????????acc34?<=?acc23?+?acc4; ????????????????????????? ????????????????????buff5?<=?buff4; ????????????????????acc5?<=?tap5?*?buff5;? ????????????????????acc45?<=?acc34?+?acc5; ?????????????????????????? ????????????????????buff6?<=?buff5;? ????????????????????acc6?<=?tap6?*?buff6; ????????????????????acc56?<=?acc45?+?acc6; ??????????????????????? ????????????????????buff7?<=?buff6;? ????????????????????acc7?<=?tap7?*?buff7; ????????????????????acc67?<=?acc56?+?acc7; ?????????????????????????? ????????????????????buff8?<=?buff7; ????????????????????acc8?<=?tap8?*?buff8; ????????????????????acc78?<=?acc67?+?acc8; ??????????????????????????? ????????????????????buff9?<=?buff8;? ????????????????????acc9?<=?tap9?*?buff9; ????????????????????acc89?<=?acc78?+?acc9; ?????????????????????????? ????????????????????buff10?<=?buff9;? ????????????????????acc10?<=?tap10?*?buff10; ????????????????????acc910?<=?acc89?+?acc10; ??????????????????????????? ????????????????????buff11?<=?buff10;? ????????????????????acc11?<=?tap11?*?buff11; ????????????????????acc1011?<=?acc910?+?acc11; ?????????????????????????? ????????????????????buff12?<=?buff11;? ????????????????????acc12?<=?tap12?*?buff12; ????????????????????acc1112?<=?acc1011?+?acc12; ?????????????????????????? ????????????????????buff13?<=?buff12;? ????????????????????acc13?<=?tap13?*?buff13; ????????????????????acc1213?<=?acc1112?+?acc13; ?????????????????????????? ????????????????????buff14?<=?buff13;? ????????????????????acc14?<=?tap14?*?buff14; ????????????????????m_axis_fir_tdata?<=?acc1213?+?acc14; ???????????????????? ????????????????end ????????end ???? endmodule
使用新 FIR 模塊的 Verilog 代碼重新運行綜合布局布線后就可以產(chǎn)生滿足所有時序要求的設(shè)計。打開之前違反建立時序的相同數(shù)據(jù)信號路徑的原理圖,可以直觀地證明信號路徑是如何整體縮短的。
新原理圖顯示axis_fir_tdata總線中每個位的信號路徑都被并行處理,有效地縮短了它們到達(dá)目標(biāo)寄存器的時間,這就是減少信號建立時間的原因。
當(dāng)新設(shè)計滿足時序要求時,接下來就是驗證重寫后的邏輯是否仍然與舊邏輯一樣。重新運行行為仿真將很快回答這個問題。
由于希望用新代碼替換之前的邏輯,發(fā)現(xiàn)設(shè)置斷點并在更新波形圖時單步執(zhí)行 Verilog 的每一行的功能可以實現(xiàn)我們的目的。
啟動行為仿真后,會注意到 HDL 的每條有效行的行號右側(cè)都有一個紅色圓圈。單擊這些紅色圓圈之一將啟用該行上的斷點。
當(dāng)仿真運行并遇到該斷點時,可以使用頂部工具欄中的“步進(jìn)”按鈕(如下所示)或 F8 來逐步執(zhí)行剩余的代碼行。
最后,我們看到 FIR 濾波器的新邏輯設(shè)計確實按預(yù)期運行!
總結(jié)
上面的兩個例子能證明在目標(biāo) FPGA 芯片上,最終輸出相同結(jié)果的兩種不同的 HDL 編寫方式對時序影響不同的重要性。這就是為什么在編寫代碼腦中“有電路”是很重要的原因。
審核編輯:湯梓紅
-
FPGA
+關(guān)注
關(guān)注
1629文章
21744瀏覽量
603670 -
存儲器
+關(guān)注
關(guān)注
38文章
7493瀏覽量
163879 -
數(shù)字信號處理
+關(guān)注
關(guān)注
15文章
560瀏覽量
45866 -
Verilog
+關(guān)注
關(guān)注
28文章
1351瀏覽量
110124 -
時序
+關(guān)注
關(guān)注
5文章
388瀏覽量
37343
原文標(biāo)題:FPGA 的數(shù)字信號處理:重寫 FIR 邏輯以滿足時序要求
文章出處:【微信號:Open_FPGA,微信公眾號:OpenFPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論