注意:當使用多級非門的時候綜合器往往會將其優(yōu)化掉,因為綜合器會認為一個信號非兩次還是它自己。
需要說明的是在FPGA/CPLD內(nèi)部結(jié)構(gòu)是一種標準的宏單元,下圖是Xilinx公司的Spartans II系列器件的一個標準宏單元。雖然不同的廠家的芯片宏單元的結(jié)構(gòu)不同,但概括而言都是由一些組合邏輯外加一或二個觸發(fā)器而構(gòu)成。在實際應(yīng)用中,當一個模塊內(nèi)的組合邏輯被使用了那么與其對應(yīng)的觸發(fā)器也就不能用了;同樣如果觸發(fā)器單元被用了那么組合邏輯單元也就廢了。這就是有時候(特別是使用CPLD)雖然設(shè)計使用的資源并不多但布局布線器卻報告資源不夠使用的原因。
現(xiàn)面的一個例子是前一段時間我在公司遇到的一個設(shè)計。設(shè)計使用Altera公司的EPM7256型號的CPLD。該設(shè)計實際使用的寄存器資源只有109個,占整個器件資源的42%。可是該設(shè)計使用了如下圖所示的延時方法來做處理器接口的時序:
現(xiàn)面的一個例子是前一段時間我在公司遇到的一個設(shè)計。設(shè)計使用Altera公司的EPM7256型號的CPLD。該設(shè)計實際使用的寄存器資源只有109個,占整個器件資源的42%??墒窃撛O(shè)計使用了如下圖所示的延時方法來做處理器接口的時序:
在該電路的設(shè)計中使用了大量的LCELL來產(chǎn)生100多納秒的延時,這樣做的后果是雖然整個電路的觸發(fā)器資源只使用了42%,可是用MaxplusII進行布局布線已經(jīng)不能夠通過了。而且我懷疑經(jīng)過這么多邏輯的延時后所產(chǎn)生的信號還能保持原來的性能不。
當需要對某一信號作一段延時時,初學(xué)者往往在此信號后串接一些非門或其它門電路,此方法在分離電路中是可行的。但在FPGA中,開發(fā)軟件在綜合設(shè)計時會將這些門當作冗余邏輯去掉,達不到延時的效果。用ALTERA公司的MaxplusII開發(fā)FPGA?xí)r,可以通過插入一些LCELL原語來產(chǎn)生一定的延時,但這樣形成的延時在FPGA芯片中并不穩(wěn)定,會隨溫度等外部環(huán)境的改變而改變,因此并不提倡這樣做。在此,可以用高頻時鐘來驅(qū)動一移位寄存器,待延時信號作數(shù)據(jù)輸入,按所需延時正確設(shè)置移位寄存器的級數(shù),移位寄存器的輸出即為延時后的信號。此方法產(chǎn)生的延時信號與原信號比有誤差,誤差大小由高頻時鐘的周期來決定。對于數(shù)據(jù)信號的延時,在輸出端用數(shù)據(jù)時鐘對延時后信號重新采樣,就可以消除誤差。
對于這樣大的延時我建議的實現(xiàn)方法是采用時鐘鎖存來產(chǎn)生延時的方法,我們知道當一個信號用時鐘鎖存一次,將會占用一個觸發(fā)器資源,信號會向后推移一個時鐘周期;該同事的設(shè)計里CPLD芯片正好連接有32MHz的時鐘,那么每用時鐘鎖存一次ssp信號就會推移31ns,這樣只需多使用3個觸發(fā)器資源就可以達到目的了。電路圖和仿真波形如下圖所示:當然這樣做對原來信號高低電平的寬度會稍有改變,但只要是在與其接口的芯片的容許范圍之內(nèi)就不會影響到功能的實現(xiàn)。
用于延時的電路圖
?
?
上圖仿真波形
2.3 如何提高系統(tǒng)的運行速度
同步電路的速度是指同步時鐘的速度。同步時鐘愈快,電路處理數(shù)據(jù)的時間間隔越短,電路在單位時間處理的數(shù)據(jù)量就愈大.
我們先來看一看同步電路中數(shù)據(jù)傳遞的一個基本模型,如下圖:
(Tco是觸發(fā)器時鐘到數(shù)據(jù)輸出的延時;Tdelay是組合邏輯的延時;Tsetup是觸發(fā)器的建立時間)
假設(shè)數(shù)據(jù)已經(jīng)被時鐘的上升沿打入D觸發(fā)器,那么數(shù)據(jù)到達第一個觸發(fā)器的Q端需要Tco,再經(jīng)過組合邏輯的延時Tdelay到達的第二個觸發(fā)器的D端,要想時鐘能在第二個觸發(fā)器再次被穩(wěn)定的鎖入觸發(fā)器,則時鐘的延遲不能晚于Tco+Tdelay+Tsetup,(我們可以回顧一下前面講過的建立和保持時間的概念,就可以理解為什么公式最后要加上一個Tdelay) 由以上分析可知:最小時鐘周期:T=Tco+Tdelay+Tsetup 最快時鐘頻率 F= 1/T PLD開發(fā)軟件也正是通過這個公式來計算系統(tǒng)運行速度Fmax。
注:在這個邏輯圖中有個參數(shù):Tpd ,即時鐘的延時參數(shù),我們在剛才做時間分析的時候,沒有提這個參數(shù),(如果使用PLD的全局時鐘型號,Tpd可以為0,如果是普通時鐘,則不為0)。所以如果考慮到時鐘的延時,精確的公式應(yīng)該是T=Tco+Tdelay+Tsetup-Tpd。當然以上全部分析的都是器件內(nèi)部的運行速度,如果考慮芯片I/O管腳延時對系統(tǒng)速度的影響,那么還需要加一些修正。
由于Tco、Tsetup是由具體的器件和工藝決定的,我們設(shè)計電路時只可以改變Tdelay。所以縮短觸發(fā)器間組合邏輯的延時是提高同步電路速度的關(guān)鍵。由于一般同步電路都不止一級鎖存(如圖3),而要使電路穩(wěn)定工作,時鐘周期必須滿足最大延時要求,縮短最長延時路徑,才可提高電路的工作頻率。
如圖2所示:我們可以將較大的組合邏輯分解為較小的幾塊,中間插入觸發(fā)器,這樣可以提高電路的工作頻率。這也是所謂“流水線”(pipelining)技術(shù)的基本原理。
對于圖3的上半部分,它時鐘頻率受制于第二個較大的組合邏輯的延時,通過適當?shù)姆椒ㄆ骄峙浣M合邏輯,可以避免在兩個觸發(fā)器之間出現(xiàn)過大的延時,消除速度瓶頸。
FPGA/CPLD開發(fā)軟件中也有一些參數(shù)設(shè)置,通過修改這些設(shè)置,可以提高編譯/布局布線后系統(tǒng)速度,但是根據(jù)經(jīng)驗這種速度的提高是很有限的,假如按照要求我們需要設(shè)計一個可以工作到50MHz的系統(tǒng),實際布局布線器報告出來的Fmax只有40MHz,此時如果我們使用布局布線器的設(shè)置選項最多可以提高到45MHz,這還是運氣比較好的情況。而且你必須了解這些選項的含義、使用背景等。
其實在一個設(shè)計里影響速度的瓶頸經(jīng)常只會有幾條,我們將延時最大的路徑稱作關(guān)鍵路徑。當設(shè)計的運行速度不符合系統(tǒng)設(shè)計要求的時候我們可以首先找到不能滿足要求的關(guān)鍵路徑,按照上述的方法將關(guān)鍵路徑上的組合邏輯拆分成多個中間用觸發(fā)器隔開,這樣很容易就可以從根本上提升系統(tǒng)的運行速度了。
有的設(shè)計在設(shè)計開始就知道那部分電路會產(chǎn)生比較大的組合邏輯,導(dǎo)致速度瓶頸的產(chǎn)生,那么就應(yīng)該在開始就想好解決辦法。比如現(xiàn)在設(shè)計需要產(chǎn)生一個32位的加法器,并且要求能夠工作在50MHz。根據(jù)經(jīng)驗直接用32位加法器肯定是達不到50MHz的要求的,這時我們可以將其分成3個12位計數(shù)器來操作,后面的計數(shù)器只要將前面計數(shù)器結(jié)果的高位(進位位)相加就可以了。
下面是原來在寬帶接入服務(wù)器設(shè)計中的流量統(tǒng)計單元中的32位加法器的描述:
----------------------------------------------------------
---- flow count element
----------------------------------------------------------
-----temporary computing 12 bits adder
process(Count_0_en,count_buffer,Len,Carry_0_0,Carry_0_1)
begin
case Count_0_en is
---1st Step addition (10 downto 0) + (10 downto 0)
when "001" => add_12_a_0 <= ('0' & count_buffer(0)(10 downto 0));
add_12_b_0 <= ('0' & Len(10 downto 0));
---2nd Step addition (21 downto 11) + Carry_0_0
when "010" => add_12_a_0 <= ('0' & count_buffer(0)(21 downto 11));
add_12_b_0 <= ("00000000000" & Carry_0_0);
---3rd Step addition (31 downto 22) + Carry_0_1
when "100" => add_12_a_0 <= ("00" & count_buffer(0)(31 downto 22));
add_12_b_0 <= ("00000000000" & Carry_0_1);
when others => add_12_a_0 <=(others=>’X’);
add_12_b_0 <=(others=>’X’);
end case;
end process;
------12 bits adder
add_12_result_0 <= add_12_a_0 + add_12_b_0;
------Bytes Count
process(RST,CLK_25MHz,IO,OE_bar,data_sel,Count_0_en)
begin
if(RST = '1')then -----system Reset
count_buffer(0) <= (others => '0');
Carry_0_0 <= '0';
Carry_0_1 <= '0';
Carry_0_2 <= '0';
elsif(CLK_25MHz'event and CLK_25MHz = '0')then
if(OE_bar = '0' and data_sel = '0')then
count_buffer(0) <= IO;
Carry_0_2 <= '0';
else
case Count_0_en is
---1st Step addition (10 downto 0) + (10 downto 0)
when "001" => count_buffer(0)(10 downto 0) <= add_12_result_0(10 downto 0);
Carry_0_0 <= add_12_result_0(11);--first step carry
---2nd Step addition (21 downto 11) + Carry_0_0
when "010" => count_buffer(0)(21 downto 11) <= add_12_result_0(10 downto 0);
Carry_0_1 <= add_12_result_0(11);--Second step carry
---3rd Step addition (31 downto 22) + Carry_0_1
when "100" => count_buffer(0)(31 downto 22) <= add_12_result_0(9 downto 0);
Carry_0_2 <= add_12_result_0(10);--Third step carry
when others => Carry_0_2 <= '0';
end case;
end if;
end if;
end process;
評論
查看更多