弄清FPGA基礎 -- 復位設計
目錄
一開始接觸到FPGA,肯定都知道”復位“,即簡單又複雜。簡單是因為初學時,只需要按照固定的套路——按鍵開關復位,見暫存器就先低電平復位一次,這樣一般情況可以解決99%的問題,甚至簡單的設計,就不可能有問題。複雜是因為復位本身是對大規模的硬體單元進行一種操作,必須要結核底層的設計來考慮問題。
1. 常見問題
自己在學習實踐過程中,以及看到網友詢問的,有關FPGA復位設計大概有以下幾類問題:
- 我板子上沒有設計按鍵復位怎麼辦?
- 怎麼設計上電覆位?不可能上電都要去按鍵吧
- 同步復位還是非同步復位?各自優勢是啥?
- 高電平復位還是低電平復位?
……
歸根結底,就是 怎樣設計復位 ,我可能給不出完美的答案,但查閱了一些資料,總結了一些設計中考慮的因素,在加上參考文獻,應該能解決99.9%的疑惑。
2. 常見的復位方式
我們習慣上通常使用的復位有三種方式:
-
硬體開關:復位訊號接一個撥碼開關或按鍵,或者RC電路
-
電源晶片:上電時候電源晶片產生,可以長時間維持,直到穩定。
-
控制晶片:控制晶片產生復位脈衝。
沒有專門的電源或控制晶片,甚至連按鍵都忘記設計的情況下,有人提出可不可以拿內部計數器做一個所謂的上電“軟”復位,如下程式碼所示,當cnt計數到一定的值時,產生一個復位脈衝訊號。
always@(posedge clk or negedge rst_n) begin if(!rst_n) cnt <= 0; else begin if(cnt < 23'd50_00000) //100ms cnt <= cnt+1'b1; else cnt <= cnt; end end always@(posedge clk or negedge rst_n) begin if(!rst_n) begin rst_nr0 <= 0; rst_nr1 <= 0; end else if(cnt == 23'd50_00000) begin rst_nr0 <= 1; rst_nr1 <= rst_nr0; end else begin rst_nr0 <= 0; rst_nr1 <= 0; end end
沒有設計外部硬體復位的同學又會反駁,我rst_n都沒有!去掉復位,預設上電cnt = 0,可不可以?既然預設cnt = 0了,那其他所有的暫存器不都預設為0了嗎?接著往下分析。
3. 合理的復位設計
從參考文獻中得出有關復位設計的幾條重要結論,有助於我們明確復位設計的方向,如下:
- 低電平復位並不是最合理的處理方式;
- 建議採用非同步復位同步化(非同步復位同步釋放處理) ;
- 全域性復位並不是最佳方式;
- 並不是所有時序電路都要加復位;
對上述結論分析,見後續總結。
3.1 復位電平
有關復位電平,實際上是跟FPGA晶片內部的觸發器結構有關,在之前的博文有提到過。作為xilinx 7系列觸發器,其 R 埠既可用作同步置位/復位埠,也可用作非同步預設/清除埠,但無論哪種方式,都是 高電平有效 。Altera的是低電平有效。
當在7系列晶片上採用低電平復位,會有什麼問題呢?如下:
如果RTL程式碼採用了低電平有效的復位模式,綜合器將在復位訊號驅動暫存器SR控制端之前的 插入一個反相器 (interver)。你必須使用一個查詢表(look up table)來實現反向器,以利用LUT的輸入埠。低電平有效的控制訊號帶來的額外的邏輯可能拉長了執行時間(runtime), 將導致更低的FPGA資源利用率,也將影響時序和功耗。
到底我想說點什麼呢?儘可能的在 HDL 程式碼或者例項化的模組中使用高電平有效的控制訊號。如果在設計中,你不能夠改變這些控制訊號的極性, 你需要在程式碼的頂層檔案反轉這些控制訊號 。採用這種方式描述電路的話,這些反向器將被吸收到 I/O 邏輯中,而不需要使用額外的 FPGA 邏輯、路徑。
所以再次強調: 復位電平的選擇跟晶片結構有關!
3.2 非同步復位同步化
非同步復位同步化簡單的說就是將非同步復位訊號在相關的時鐘域模組中進行同步化處理。單純的同步復位、非同步復位以及其他的一些復位方式,都存在一些缺陷,比如抗噪聲、存在亞穩態等問題,深入學習可以查閱相關文獻。
非同步復位同步化處理的結構程式碼及schematic(xilinx 7系列)如下:
module rst_signal( inputclk, inputrst, outputsys_rst ); regr1_rst,r2_rst; always@(posedge clk or negedge rst) begin if(rst) begin r1_rst <= 1'b1; r2_rst <= 1'b1; end else begin r1_rst <= 1'b0; r2_rst <= r1_rst; end end assign sys_rst = r2_rst; endmodule
可以看到,模組將系統輸入的非同步復位訊號進行同步,產生了一個後續邏輯使用的同步化了的非同步復位,隨後即可將該復位訊號sys_rst用於其他模組的復位。為了減少亞穩態對上述同步器中的兩個暫存器的影響,這兩個暫存器應該在FPGA中被放置的越靠近越好( 相應的約束:set_property ASYNC_REG TRUE [get_cells [list r1_rst_reg r2_rst_reg]] ),儘量減少佈線延遲。
以上只是一個基本原理示意,在實際使用過程中還應注意以下兩點:
- 外部輸入非同步復位訊號應該增加濾波和去抖處理;
- 在復位之前,確保由 MMCM 或PLL 生成的時鐘是穩定且被鎖定的;
- 將非同步復位訊號分別引入不同的時鐘域進行同步化
綜上,復位處理的原理圖如下所示:
3.3 恰到好處的復位
看似簡單的復位,實際上不簡單,來係數復位的N宗罪:
- 復位網路需要佔用佈線資源;
- 導致其餘訊號的佈線訊號受到影響,降低了它們佈線的自由度;
- 增加的佈線網路往往需要使用更高速率的晶片;
- 復位網路佔用大量佈線資源,使得Place&Route的時間大大增加;
- 復位訊號需要佔用大量的邏輯資源;
- 復位訊號需要使用觸發器的專用復位管腳;
- 可操作的復位訊號往往導致D觸發器的輸入前增加額外的門操作或專用的復位訊號輸入;
- 增大整個設計 的尺寸;
- 額外的邏輯消耗降低了系統的效能;
- 阻止了使用高效特徵,如Xilinx FPGA特有的SRL16E 移位暫存器。
簡單的說,復位的存在會對FPGA的綜合面積產生影響,主要體現在兩個方面:第一、在編寫代買的時候,習慣給所有時序電路都加上覆位訊號,這樣往往會導致資源無形的浪費;第二,沒有合理的設計復位電路會產生額外的資源消耗。
什麼時候可以叫復位呢?一般判斷原則是:
類似於移位暫存器這類直通型電路,只起到一個傳輸訊號的作用,本身不會對訊號產生任何影響。其傳輸訊號正確與否,在於其輸入端的訊號是否正確。因此,此類電路自身無需加復位訊號,而只需再起輸入埠加復位訊號(也就是資料來源處的電路),以控制輸入資料。
4. 補充
4.1 所謂的上電初始化
當一個Xilinx的FPGA晶片被重新配置時, 每一個單元都將被初始化 。在某種意義上講,這是一個上電之後的“終極的”全域性復位操作,因為它不僅僅是對所有的觸發器進行了復位操作,還初始化了所有的RAM單元。隨著Xilinx FPGA晶片內部的嵌入式RAM資源越來越多,這種“終極的”全域性復位操作越來越有意義。對所有的RAM單元進行預定義,在軟體模擬和實際操作中都是非常有幫助的,因為這樣避免了在上電時採用複雜的啟動順序來清除儲存單元內容的操作。
所以在xilinx平臺,開篇的“軟”復位,實際上是沒有多大意義的。
綜上,採用以上總結的復位處理方法,應該能解決99.9%的問題了。
參考文獻
- 《wp272: Get Smart About Reset: Think Local, Not Global》;
- 《FPGA實戰演練. 高階技巧篇》——王敏志編著;
- DC綜合之CDC篇
- How do I reset my FPGA?
- Xilinx FPGA復位邏輯處理小結
- FPGA的復位方法幾種方法
- 在FPGA開發中儘量避免全域性復位的使用?