原文鏈接:
FPGA開發全攻略連載之十二:FPGA實戰開發技巧(6)(原文缺失,轉自:FPGA開發全攻略—工程師創新設計寶典)
5.3.3 和FPGA接口相關的設置以及時序分析
5.3.3.1 使用約束文件添加時序約束
一般來講,添加約束的原則為先附加全局約束,再補充局部約束,而且局部約束比較寬松。其目的是在可能的地方盡量放松約束,提高布線成功概率,減少ISE 布局布線時間。典型的全局約束包括周期約束和偏移約束。在添加全局時序約束時,需要根據時鍾頻率划分不同的時鍾域,添加各自的周期約束;然后對輸入輸出端口信號添加偏移約束,對片內邏輯添加附加約束。
1.周期約束
周期約束是附加在時鍾網路上的基本時序約束,以保證時鍾區域內所有同步組件的時序滿足要求。在分析時序時,周期約束能自動處理寄存器時鍾端的反相問題,如果相鄰的同步元件時鍾相位相反,則其延遲會被自動限制為周期約束值的一半,這其實相當於降低了時鍾周期約束的數值,所以在實際中一般不要同時使用時鍾信號的上升沿和下降沿。
硬件設計電路所能工作的最高頻率取決於芯片內部元件本身固有的建立保持時間,以及同步元件之間的邏輯和布線延遲。所以電路最高頻率由代碼和芯片兩部分共同決定,相同的程序,在速度等級高的芯片上能達到更高的最高工作頻率;同樣,在同一芯片內,經過速度優化的代碼具有更高的工作頻率,在實際中往往取二者的平衡。
在添加時鍾周期之前,需要對電路的期望時鍾周期有一個合理的估計,這樣才不會附加過松或過緊的周期約束,過松的約束不能達到性能要求,過緊的約束會增加布局布線的難度,實現的結果也不一定理想。常用的工程策略是:附加的時鍾周期約束的時長為期望值的90%,即約束的最高頻率是實際工作頻率的110% 左右。
附加時鍾周期約束的方法有兩個:一是簡易方法,二是推薦方法。簡易方式是直接將周期約束附加到寄存器時鍾網線上,其語法如下所示:
[ 約束信號] PERIOD = { 周期長度} {HIGH | LOW} [ 脈沖持續時間];其中,[] 內的內容為可選項,{} 中的內容為必選項,“|”表示選擇項。[ 約束信號] 可為“Net net_name”或“TIMEGRP group_name”,前者表示周期約束作用到線網所驅動的同步元件上,后者表示約束到TIMEGRP所定義的信號分組上( 如觸發器、鎖存器以及RAM 等)。{ 周期長度} 為要求的時鍾周期,可選用ms、s、ns以及ps 等單位,默認值為ns,對單位不區分大小寫。{HIGH | LOW} 用於指定周期內第一個脈沖是高電平還是低電平。[ 脈沖持續時間] 用於指定第一個脈沖的持續時間,可選用ms、s、ns 以及ps 等單位,默認值為ns,如果缺省該項,則默認為50% 的占空比。如語句:
Net“ clk_100MHz” period = 10ns High 5ns;
指定了信號clk_100MHz 的周期為10ns,高電平持續的時間為5ns,該約束將被添加到信號clk_100MHz所驅動的元件上。
推薦方法常用於約束具有復雜派生關系的時鍾網絡,其基本語法為:
TIMESPEC“ TS_identifier” = PERIOD“ TNM_reference” {周期長度}
{HIGH | LOW} [ 脈沖持續時間];
其中,TIMESPEC 是一個基本時序相關約束,用於標志時序規范。“TS_identifier”由關鍵字TS 和用戶定義的identifier 表示,二者共同構成一種時序規范,稱為TS 屬性定義,可在約束文件中任意引用,大大地豐富了派生時鍾的定義。在使用時,首先要定義時鍾分組,然后再添加相應的約束,如:
NET“ clk_50MHz” =“ syn_clk”;
TIMESPECT“ TS_syn_clk” = PERIOD“ syn_clk” 20 HIGN 10;
TIMESPEC 利用識別符定義派生時鍾的語法為:
TIMESPEC“ TS_identifier2” = PERIOD“ timegroup_name” “ TS_identifier1”
[* | /] 倍數因子 [+| -] phasevalue [ 單位]
其中,TS_identifier2 是要派生定義的時鍾,TS_identifier1 為已定義的時鍾,“倍數因子”用於給出二者周期的倍數關系,phasevalue 給出二者之間的相位關系。如:
定義系統時鍾clk_syn :
TIMESPEC“ clk_syn” = PERIOD“ clk” 5ns;
下面給出其反相時鍾clk_syn_180 以及2 分頻時鍾clk_syn_half :
TIMESPEC“ clk_syn_180” = PERIOD“ clk_180” clk_syn PHASE + 2.5ns;
TIMESPEC“ clk_syn_180” = PERIOD“ clk_half” clk_syn / 2;
2.偏移約束
偏移約束也是一類基本時序約束,規定了外部時鍾和數據輸入輸出引腳之間的相對時序關系,只能用於端口信號,不能應用於內部信號,包括OFFSET_IN_BEFORE,OFFSET_IN_AFTER,OFFSET_OUT_BEFORE,OFFSET_OUT_ AFTER 等4 類基本約束。偏移約束的基本語法為:
OFFSET = [IN | OUT]“ offset_time” [units] {BEFORE | AFTER}“ clk_name”
[TIMEGRP“ group_name”];
其中[IN | OUT] 說明約束的是輸入還是輸出。“offset_time”為數據和有效時鍾沿之間的時間差,{BEFORE| AFTER} 表明該時間差是在有效時鍾之前還是之后,“clk_name”為有效時鍾的名字,[TIMEGRP “group_name”] 是用戶添加的分組信號,在缺省時,默認為時鍾clk_name 所驅動的所有觸發器。偏移約束通知布局布線器輸入數據的到達時刻,從而可准確調整布局布線的過程,使約束信號建立時間滿足要求。
1)“OFFSET IN”偏移約束
“OFFSET IN ”偏移約束是輸入偏移約束,有OFFSET_IN_AFTER 和OFFSET_IN_BEFORE 兩種,前者定義了輸入數據在有效時鍾到達多長時間后可以到達芯片的輸入管腳,這樣可以得到芯片內部的延遲上限,從而對那些與輸入引腳相連的組合邏輯進行約束;后者定義數據比相應的有效時鍾沿提前多少時間到來,是與其相連的組合邏輯的最大延時,否則在時鍾沿到來時,數據不穩定,會發生采樣錯誤。輸入偏移的時序關系如圖5-10所示。
圖5-10 輸入偏移的時序關系
例如:
NET“ DATA_IN” OFFSET = IN 10.0 BEFORE“ CLK_50MHz”;
表明在時鍾信號CLK_50MHz 上升沿到達前的10ns 內,輸入信號DATA_IN 必須到達數據輸入管腳。
NET“ DATA_IN” OFFSET = IN 10.0 AFTER“ CLK_50MHz”;
表明在時鍾信號CLK_50MHz 上升沿到達后的10ns 內,輸入信號DATA_IN 必須到達數據輸入管腳。
2)“OFFSET OUT”偏移約束
“OFFSET OUT”偏移約束是輸出偏移約束,有OFFSET_OUT_AFTER 和OFFSET_OUT_BEFORE 兩種,前者定義了輸出數據在有效時鍾沿之后多長時間穩定下來,是芯片內部輸出延時的上限;后者定義了在下一個時鍾信號到來之前多長時間必須輸出數據,是下一級邏輯建立時間的上限。輸出偏移的時序關系如圖5.3.11 所示。
圖5-11 輸出偏移的時序關系
例如:
NET“ DATA_OUT” OFFSET = OUT 10.0 BEFORE“ CLK_50MHz”;
表明在時鍾信號CLK_50MHz 上升沿到達前的10ns 內,輸出信號DATA_OUT 信號必須離開數據輸出管腳。
NET“ DATA_OUT” OFFSET = OUT 10.0 AFTER“ CLK_50MHz”;
表明在時鍾信號CLK_50MHz 上升沿到達后的10ns 內,輸出信號DATA_OUT 信號必須一直保持在數據輸出管腳上。
3.分組約束
分組約束可有效管理大量的觸發器、寄存器和存儲器單元,將其分為不同的組,每組附加各自的約束,在大型設計中有着廣泛的應用。
1)TNM/TNM_NET 約束
TNM/TNM_NET 約束用於選出可構成一個分組的元件,並對其重新命名,然后整體添加約束。除了IBUFG和BUFG 外,所有的FPGA 內部元件都可以用TNM 來命名,其語法規則為:
{NET|INST|PIN}“ ob_name” TNM =“ New_name”;
其中“ob_name”為NET、INST 以及PIN 的名稱,New_name 為分組的名稱。例如:
INST ff1 TNM = MY_FF1;
NIST ff2 TNM = MY_FF1;
將實例ff1 與ff2 添加到新分組MY_FF1 中。
此外,TNM 語法也支持通配符“?”和“*”,提高了在大規模設計中添加分組約束的效率。
當TNM 約束附加在線網上時,則該路徑上所有的同步元件都會被添加到分組中,但不會穿過IBUFG 組件;
當TNM 約束附加到宏或原語的管腳上,則被該引腳驅動的所有同步元件會被添加到新分組中;當TNM 約束附加到原語或宏上,則將原語或宏添加到新的分組中。
TNM_NET 約束專門用來完成網線的分組,與TNM 不同的是,TNM 可以穿越IBUFG/BUFG。因此,如果把TNM 約束添加到端口上,則只能定義該端口;而要是把TNM_NET 添加到端口上,則可穿越BUFG,受該端口驅動的所有組件都將被添加到分組中。
2)TIMEGRP 約束
TIMEGRP 用於分組合並和拆分,將多個分組形成一個新的分組。其合並分組的語法為:
TIMEGRP“ New_group” =“ Old_group1” “ Old_group2” … ;
其中,New_group 為新建的分組,而Old_group1 和Old_group2 以及…為要合並的已有分組。
拆分分組的語法為:
TIMEGRP“ New_group” =“ Old_group1” EXCEPT“ Old_group2”;
其中Old_group2 是Old_group1 的子集,New_group 為Old_group1 中除去Old_group2 之外所有的部分。
3)TPSYNC 約束
TPSYNC 用於將那些不是管腳和同步元件的組件定義成同步元件,以便可以利用任意點來作為時序規范的終點和起點。其相應的語法為:
{NET|INST|PIN}“ ob_name” TPSYNC=“ New_part”;
將TPSYNC 約束附加在網線上,則該網線的驅動源為同步點;附加在同步元件的輸出管腳上,則同步元件中驅動該管腳的源為同步點;附加在同步元件上,則輸出管腳為同步點;附加在同步元件的輸入管腳上,則該引腳被定義成同步點。
4)TPTHRU 約束
TPTHRU 用於定義一個或一組路徑上的關鍵點,可使用戶定義出任意期望的路徑。其相應的語法為:
{NET|INST|PIN}“ ob_name” TPTHRU =“ New_name”;
例如,在圖5-12 所示場景中,從A1 到A2 有兩條路徑,其中邏輯1 的延遲很大,需要提取出來完成特定的約束:
圖5-12 TPTHRU約束示例場景
INST“ A1” TNM =“ S”;
INST“ A2” TNM =“ E”;
NET“ A1toA2_1” TPTHRU =“ M”;
TIMESPEC“ SME” = FROM“ S” THRU“ M” TO“ B” 10;
其中第三句指令利用TPTHRU 定義了中間點“M”,然后第4 句在此基礎上定義了通過M 點的整條路徑,從兩條平行的路徑中挑出了期望路徑。
4.局部約束
局部約束包括FROM_TO 約束、最大延時約束、最大偏移約束、虛假路徑、系統時鍾抖動約束、多周期路徑和多時鍾域約束等。在實際開發中,正如本章前沿所述,時序是設計出來,而不是靠約束自動得到的,因此這里不再對局部約束作過多討論。
5.3.3.2 提高時序性能的手段
時序性能是 FPGA 設計最重要的指標之一。造成時序性能差的根本原因有很多,但其直接原因可分為三類:
布局較差、邏輯級數過多以及信號扇出過高。下面通過時序分析實例來定位原因並給出相應的解決方案。
1.布局太差及解決方案
圖 5-13 所示時序報告,其中附加的周圍約束為 3ns,實際周期為 3.027ns,邏輯時間只有 0.869ns,而布線延遲竟達到 2.203ns,很明顯失敗的原因就是布局太差。
圖5-13 布局太差的時序報告示意圖
相應的解決方案有 :
1) 在 ISE 布局工具中調整布局的努力程度 (effort level) ;
2) 利用布局布線工具的特別努力程度 (extra effort) 或 MPPR 選項 ;
3) 如果用戶熟悉區域約束,則利用 Floorplanner 相對區域約束 (RLOC),重新對設計進行布局規划。
2.邏輯級數過多及解決方案
在 FPGA 設計中,邏輯級數越高,意味着資源的利用率就越高,但對設計工作頻率的影響也越大。在圖 5-5所示的例子中,附加的周圍約束為 3ns,實際周期為 3.205ns,邏輯時間為 1.307ns,已經對設計的實際性能造成了一定的影響。對於這種情況,ISE 實現工具是沒有任何改善的,必須通過修改代碼來提高性能,相應的解決方案有 :
1) 使用流水線技術,在組合邏輯中插入寄存器,簡化原有的邏輯結構 ;
2) 檢查該路徑是否是多周期路徑,如果是,添加相應的多周期約束 ;
3) 具備良好的編碼習慣,不要嵌套 if 語句或 if、case 語句,並且盡量用 case 語句代替 if 語句。
圖5-14 邏輯級數太多的時序報告示意圖
3.信號扇出過高及解決方案
高扇出會造成信號傳輸路徑過長,從而降低時序性能。如圖 5-15 所示,附加的周期約束為 3ns,而實際周期為 3.927ns,其中網線的扇出已經高達 187,從而導致布線時延達到 3.003ns,占實際時延的 77.64%。這種情況是任何設計所不能容忍的。
圖5-15 扇出太高的時序報告示意圖
相應的解決方案有 :
1) 通過邏輯復制的方法來降低信號的高扇出,可在 HDL 代碼中手動復制或通過在綜合工具中設置達到目的;
2) 可利用區域約束,將相關邏輯放置在一起,當然本方法僅限於高級用戶。