摘要:本文主要通過一個實例具體介紹ISE中通過編輯UCF文件來對FPGA設計進行約束,主要涉及到的約束包括時鍾約束、群組約束、邏輯管腳約束以及物理屬性約束。
Xilinx FPGA設計約束的分類
Xilinx定義了如下幾種約束類型:
• “Attributes and Constraints”
• “CPLD Fitter”
• “Grouping Constraints”
• “Logical Constraints”
• “Physical Constraints”
• “Mapping Directives”
• “Placement Constraints”
• “Routing Directives”
• “Synthesis Constraints”
• “Timing Constraints”
• “Configuration Constraints”
通過編譯UCF(user constraints file)文件可以完成上述的功能。
還是用實例來講UCF的語法是如何的。
圖1 RTL Schematic
圖1 是頂層文件RTL圖,左側一列輸入,右側為輸出,這些端口需要分配相應的FPGA管腳。
1: NET "pin_sysclk_i" LOC = AD12 | TNM_NET = pin_sysclk_i;
2: TIMESPEC TS_pin_sysclk_i = PERIOD "pin_sysclk_i" 15 ns HIGH 50 %;
3: #
4: NET "pin_plx_lreset_n_i" LOC = B18;
5: #
6: NET "pin_plx_lhold_i" LOC = C17;
7: NET "pin_plx_lholda_o" LOC = D17 | SLEW = FAST;
8: #
9: NET "pin_plx_ads_n_i" LOC = E18;
10: NET "pin_plx_ads_n_i" OFFSET = IN 6.3 ns AFTER "pin_sysclk_i" HIGH;
11: #
12: NET "pin_plx_lw_r_n_i" LOC = E9;
13: NET "pin_plx_lw_r_n_i" OFFSET = IN 6.3 ns AFTER "pin_sysclk_i" HIGH;
14: #
15: NET "pin_plx_blast_n_i" LOC = D18;
16: NET "pin_plx_blast_n_i" OFFSET = IN 6.3 ns AFTER "pin_sysclk_i" HIGH;
17: #
18: NET "pin_plx_lad_io<0>" LOC = AD13 | SLEW = FAST | TNM = LAD;
19: NET "pin_plx_lad_io<1>" LOC = AC13 | SLEW = FAST | TNM = LAD;
20: NET "pin_plx_lad_io<2>" LOC = AC15 | SLEW = FAST | TNM = LAD;
21: NET "pin_plx_lad_io<3>" LOC = AC16 | SLEW = FAST | TNM = LAD;
22: NET "pin_plx_lad_io<4>" LOC = AA11 | SLEW = FAST | TNM = LAD;
23: NET "pin_plx_lad_io<5>" LOC = AA12 | SLEW = FAST | TNM = LAD;
24: NET "pin_plx_lad_io<6>" LOC = AD14 | SLEW = FAST | TNM = LAD;
25: NET "pin_plx_lad_io<7>" LOC = AC14 | SLEW = FAST | TNM = LAD;
26: NET "pin_plx_lad_io<8>" LOC = AA13 | SLEW = FAST | TNM = LAD;
27: NET "pin_plx_lad_io<9>" LOC = AB13 | SLEW = FAST | TNM = LAD;
28: NET "pin_plx_lad_io<10>" LOC = AA15 | SLEW = FAST | TNM = LAD;
29: NET "pin_plx_lad_io<11>" LOC = AA16 | SLEW = FAST | TNM = LAD;
30: NET "pin_plx_lad_io<12>" LOC = AC11 | SLEW = FAST | TNM = LAD;
31: NET "pin_plx_lad_io<13>" LOC = AC12 | SLEW = FAST | TNM = LAD;
32: NET "pin_plx_lad_io<14>" LOC = AB14 | SLEW = FAST | TNM = LAD;
33: NET "pin_plx_lad_io<15>" LOC = AA14 | SLEW = FAST | TNM = LAD;
34: NET "pin_plx_lad_io<16>" LOC = D12 | SLEW = FAST | TNM = LAD;
35: NET "pin_plx_lad_io<17>" LOC = E13 | SLEW = FAST | TNM = LAD;
36: NET "pin_plx_lad_io<18>" LOC = C16 | SLEW = FAST | TNM = LAD;
37: NET "pin_plx_lad_io<19>" LOC = D16 | SLEW = FAST | TNM = LAD;
38: NET "pin_plx_lad_io<20>" LOC = D11 | SLEW = FAST | TNM = LAD;
39: NET "pin_plx_lad_io<21>" LOC = C11 | SLEW = FAST | TNM = LAD;
40: NET "pin_plx_lad_io<22>" LOC = E14 | SLEW = FAST | TNM = LAD;
41: NET "pin_plx_lad_io<23>" LOC = D15 | SLEW = FAST | TNM = LAD;
42: NET "pin_plx_lad_io<24>" LOC = D13 | SLEW = FAST | TNM = LAD;
43: NET "pin_plx_lad_io<25>" LOC = D14 | SLEW = FAST | TNM = LAD;
44: NET "pin_plx_lad_io<26>" LOC = F15 | SLEW = FAST | TNM = LAD;
45: NET "pin_plx_lad_io<27>" LOC = F16 | SLEW = FAST | TNM = LAD;
46: NET "pin_plx_lad_io<28>" LOC = F11 | SLEW = FAST | TNM = LAD;
47: NET "pin_plx_lad_io<29>" LOC = F12 | SLEW = FAST | TNM = LAD;
48: NET "pin_plx_lad_io<30>" LOC = F13 | SLEW = FAST | TNM = LAD;
49: NET "pin_plx_lad_io<31>" LOC = F14 | SLEW = FAST | TNM = LAD;
50: TIMEGRP "LAD" OFFSET = IN 6.4 ns AFTER "pin_sysclk_i" HIGH;
51: TIMEGRP "LAD" OFFSET = OUT 3.1 ns BEFORE "pin_sysclk_i" HIGH;
52: #
53: NET "pin_plx_ready_n_o" LOC = F18 | SLEW = FAST;
54: NET "pin_plx_ready_n_o" OFFSET = OUT 4.2 ns BEFORE "pin_sysclk_i" HIGH;
55: #
56: NET "pin_plx_bterm_n_o" LOC = D10 | SLEW = FAST;
57: NET "pin_plx_bterm_n_o" OFFSET = OUT 4.2 ns BEFORE "pin_sysclk_i" HIGH;
58: #
59: NET "pin_led_o<0>" LOC = D22;
60: NET "pin_led_o<1>" LOC = C22;
61: NET "pin_led_o<2>" LOC = E21;
62: NET "pin_led_o<3>" LOC = D21;
63: NET "pin_led_o<4>" LOC = C21;
64: NET "pin_led_o<5>" LOC = B24;
65: NET "pin_led_o<6>" LOC = C20;
66: NET "pin_led_o<7>" LOC = B23;
表1. UCF example
對上面的UCF文件進行一些注釋:
該UCF文件主要是完成了管腳的約束、時鍾的約束,以及組的約束。
第一、二行:主要定義了時鍾以及對應的物理管腳。
第一行,端口pin_sysclk_i 分配到FPGA管腳AD12,並放到了 pin_sysclk_i group中。那如何得知是AD12的管腳呢,請看圖2,FPGA管腳AD12 是一個66MHz的外部時鍾。FPGA的開發板肯定有電路原理圖供你分配外部管腳。
圖2,電路原理圖
第二行:時鍾說明:周期15ns,占空比50%。關鍵詞TIMESPEC(Timing Specifications),即時鍾說明。一般的語法是:
TIMESPEC "TSidentifier"=PERIOD "timegroup_name" value [units];
其中TSidentifier用來指定TS(時鍾說明)的唯一的名稱。
第七行:pin_plx_lholda_o 連接至物理管腳 D17,並配置該管腳電平變化的速率。關鍵詞:SLEW,用來定義電平變化的速率的,一般語法是:
       NET "top_level_port_name" SLEW="value";
       其中value = {FAST|SLOW|QUIETIO}, QUIETIO僅用在Spartan-3A。
第十行:定義pin_plx_ads_n_i 輸入跟時鍾的關系。OFFSET IN和OFFSET OUT的約束。OFFSET IN 定義了數據輸入的時間和接收數據時鍾沿(capture Edge)的關系。
一般的語法是:OFFSET = IN value VALID value BEFORE clock
OFFSET = OUT value VALID value AFTER clock
圖3 時序圖(OFFSET IN)
例子:
NET "SysCLk" TNM_NET = "SysClk";
TIMESPEC "TS_SysClk" = PERIOD "SysClk" 5 ns HIGH 50%;
OFFSET = IN 5 ns VALID 5 ns BEFORE "SysClk";
上面的定義了基於SysClk的全局OFFSET IN的屬性。時序可看圖3.
圖4 時序圖(OFFSET OUT)
例子:
NET "ClkIn" TNM_NET = "ClkIn";
OFFSET = OUT 5 ns AFTER "ClkIn";
上面設置主要是定了了時鍾跟數據的時間關系,時序圖4。可以看到這時一種全局定義,Data1 和Data2輸出時間都受到 OFFSET = OUT 5 ns AFTER "ClkIn" 的約束。如果需要單獨定義輸出端口的OFFSET OUT的,需要制定相應的NET,可參考表1中的第57行。
第18至49行:pin_plx_lad_io<*> 被歸到了名稱為LAD的TMN(Timing name),這個可以說是GROUP的約束。這樣往往給約束帶來方便,不用一個一個的NET 或者INST進行約束。
第50至51行:對TIMEGRP 是LAD進行OFFSET IN和OUT的定義。
在時序約束中,在這里還未提及FROM TO的約束。FROM TO的約束主要是用來兩個同步模塊之間的時間關系的約束。在這里不做深入的討論。
至此,基本上把一般的UCF文件的作用進行了注釋。
注:一般的時間的約束需要通過靜態的時序分析,然后再設定相應PERIOD,OFFSET IN 以及OFFEET OUT等的時間參數。
當然在例子中還沒有涉及到區域的約束。下面會試圖說一下。
ISE進行綜合后會將設計代碼生成相應的邏輯網表,然后經過translate過程,轉換到Xilinx特定的底層結構和硬件原語,MAP過程就是將映射到具體型號的器件上,最后就是就是布線和布局的操作了。
區域的約束相當於將布局過程中指定特定型號的器件的位置,這完全可以通過FloorPlanner的GUI界面進行設置,用圖形界面設置完后,配置信息會放到UCF中,這里只介紹UCF的使用。
例如:
INST "Done" LOC = "SLICE_X32Y163" ;    #Done映射為一個寄存器,映射到SLICE_X32Y163的位置上。(32,163)相當於一個坐標,可以用FloorPlanner進行查看。
INST"BRAM4/BU2/U0/blk_mem_generator/valid.cstr/ramloop[0].ram.r/v4_init.ram/TRUE_DP.SINGLE_PRIM.TDP"LOC = "RAMB16_X2Y22" ; #RAM16的一個映射。
又例如,X,Y,Z是對應的是寄存器。現在想把它們放在一個指定的區域中,我可以這樣寫,
INST “X” AREA_GROUP = reg;
INST “X” AREA_GROUP = reg;
INST “X” AREA_GROUP = reg;
AREA_GROUP reg RANGE = SLICE_X1Y1 :SLICE_X1Y6;
注:如何查看INST中的名稱呢?在ISE中 Timing constraints editor中可以查看。
注:NET,LOC,TNM_NET,TIMESPEC,PERIOD,OFFSET,IN,OUT,SLEW,HIGH等都是關鍵字,UCF文件是大小敏感的,端口名稱必須和源代碼中的名字一致,且端口名字不能和關鍵字一樣。但是關鍵字NET是不區分大小寫的。
其實上述都是約束的入門的內容,如果要想深入的了解的話,請參考Ref1。
筆者也是初學者,如果有什么不對的地方,請批評指正。
ISE 約束文件的基本操作 
1.約束文件的概念 
FPGA設計中的約束文件有3類:用戶設計文件(.UCF文件)、網表約束文件(.NCF文件)以及物理約束文件(.PCF文件),可以完成時序約束、管腳約束以及區域約束。3類約束文件的關系為:用戶在設計輸入階段編寫UCF文件,然后UCF文件和設計綜合后生成NCF文件,最后再經過實現后生成PCF 文件。本節主要介紹UCF文件的使用方法。 
UCF文件是ASC 2碼文件,描述了邏輯設計的約束,可以用文本編輯器和Xilinx約束文件編輯器進行編輯。NCF約束文件的語法和UCF文件相同,二者的區別在於: UCF文件由用戶輸入,NCF文件由綜合工具自動生成,當二者發生沖突時,以UCF文件為准,這是因為UCF的優先級最高。PCF文件可以分為兩個部分:一部分是映射產生的物理約束,另一部分是用戶輸入的約束,同樣用戶約束輸入的優先級最高。一般情況下,用戶約束都應在UCF文件中完成,不建議直接修改 NCF文件和PCF文件。 
2.創建約束文件 
約束文件的后綴是.ucf,所以一般也被稱為UCF文件。創建約束文件有兩種方法,一種是通過新建方式,另一種則是利用過程管理器來完成。 
第一種方法:新建一個源文件,在代碼類型中選取“Implementation Constrains File”,在“File Name”中輸入“one2two_ucf”。單擊“Next”按鍵進入模塊選擇對話框,選擇模塊“one2two”,然后單擊“Next”進入下一頁,再單擊“Finish”按鍵完成約束文件的創建。 
第二種方法:在工程管理區中,將“Source for”設置為“Synthesis/Implementation”。“Constrains Editor”是一個專用的約束文件編輯器,雙擊過程管理區中“User Constrains”下的“Create Timing Constrains”就可以打開“Constrains Editor”,其界面如圖所示: 
圖 啟動Constrains Editor引腳約束編輯
 
在“Ports”選項卡中可以看到,所有的端口都已經羅列出來了,如果要修改端口和FPGA管腳的對應關系,只需要在每個端口的“Location”列中填入管腳的編號即可。例如在UCF文件中描述管腳分配的語法為:
        NET “端口名稱” LOC = 引腳編號; 
需要注意的是,UCF文件是大小敏感的,端口名稱必須和源代碼中的名字一致,且端口名字不能和關鍵字一樣。但是關鍵字NET是不區分大小寫的。 
3.編輯約束文件 
在工程管理區中,將“Source for”設置為“Synthesis/Implementation”,然后雙擊過程管理區中“User Constrains”下的“Edit Constraints (Text)”就可以打開約束文件編輯器,如下圖所示,就會新建當前工程的約束文件。
 
圖 用戶約束管理窗口 
  UCF文件的語法說明 
1.語法 
        UCF文件的語法為: 
{NET|INST|PIN} "signal_name" Attribute; 
其中,“signal_name”是指所約束對象的名字,包含了對象所在層次的描述;“Attribute”為約束的具體描述;語句必須以分號“;”結束。可以用“#”或“/* */”添加注釋。需要注意的是:UCF文件是大小寫敏感的,信號名必須和設計中保持大小寫一致,但約束的關鍵字可以是大寫、小寫甚至大小寫混合。例如: 
NET "CLK" LOC = P30; 
“CLK”就是所約束信號名,LOC = P30;是約束具體的含義,將CLK信號分配到FPGA的P30管腳上。 
對於所有的約束文件,使用與約束關鍵字或設計環境保留字相同的信號名會產生錯誤信息,除非將其用" "括起來,因此在輸入約束文件時,最好用" "將所有的信號名括起來。 
2.通配符 
在UCF文件中,通配符指的是“*”和“?”。“*”可以代表任何字符串以及空,“?”則代表一個字符。在編輯約束文件時,使用通配符可以快速選擇一組信號,當然這些信號都要包含部分共有的字符串。例如: 
NET "*CLK?" FAST; 
將包含“CLK”字符並以一個字符結尾的所有信號,並提高了其速率。 
在位置約束中,可以在行號和列號中使用通配符。例如: 
INST "/CLK_logic/*" LOC = CLB_r*c7; 
把CLK_logic層次中所有的實例放在第7列的CLB中。 
3.定義設計層次 
       在UCF文件中,通過通配符*可以指定信號的設計層次。其語法規則為: 
* 遍歷所有層次 
Level1/* 遍歷level1及以下層次中的模塊 
Level1/*/ 遍歷level1種的模塊,但不遍歷更低層的模塊 
例4-5 根據圖4-75所示的結構,使用通配符遍歷表4-3所要求的各個模塊。
圖 層次模塊示意圖 
表 要求遍歷的符號列表
管腳和區域約束語法 
LOC約束是FPGA設計中最基本的布局約束和綜合約束,能夠定義基本設計單元在FPGA芯片中的位置,可實現絕對定位、范圍定位以及區域定位。此外, LOC還能將一組基本單元約束在特定區域之中。LOC語句既可以書寫在約束文件中,也可以直接添加到設計文件中。換句話說,ISE中的FPGA底層工具編輯器(FPGA Editor)、布局規划器(Floorplanner)和引腳和區域約束編輯器的主要功能都可以通過LOC語句完成。 
- LOC語句語法
 
INST "instance_name " LOC = location; 
其中“location”可以是FPGA芯片中任一或多個合法位置。如果為多個定位,需要用逗號“,”隔開,如下所示: 
LOC = location1,location2,...,locationx; 
目前,還不支持將多個邏輯置於同一位置以及將多個邏輯至於多個位置上。需要說明的是,多位置約束並不是將設計定位到所有的位置上,而是在布局布線過程中,布局器任意挑選其中的一個作為最終的布局位置。 
范圍定位的語法為: 
INST “instance_name” LOC=location:location [SOFT]; 
常用的LOC定位語句如表4-4所列。
表 常用的LOC定位語句
使用LOC完成端口定義時,其語法如下: 
NET "Top_Module_PORT" LOC = "Chip_Port"; 
其中,“Top_Module_PORT”為用戶設計中頂層模塊的信號端口,“Chip_Port”為FPGA芯片的管腳名。 
LOC語句中是存在優先級的,當同時指定LOC端口和其端口連線時,對其連線約束的優先級是最高的。例如,在圖4-76中,LOC=11的優先級高於LOC=38。 
圖 LOC優先級示意圖 
2.LOC屬性說明 
LOC語句通過加載不同的屬性可以約束管腳位置、CLB、Slice、TBUF、塊RAM、硬核乘法器、全局時鍾、數字鎖相環(DLL)以及DCM模塊等資源,基本涵蓋了FPGA芯片中所有類型的資源。由此可見,LOC語句功能十分強大,表4-5列出了LOC的常用屬性。 
表 LOC語句常用屬性列表
