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