VHDL編程設計技巧

簡    介:介紹了在VHDL編程設計中,描述方法對電路結構的影響,不同的狀態機描述方法,層次化設計的基本思想和原則,Block RAM的結構、VHDL程序、寬度和深度組合形式,基於IP Core的Block RAM設計,數字延遲鎖相環(DLL,Delay Locked Loop)、全局時鐘網絡(Global Clock Networks)、DCM(數字時鐘管理器,Digital Clock Manager)的結構特點與應用。重點是掌握在VHDL編程設計中,鎖存避免、寄存器使用、括號使用、並行結構、資源共享、數值比較等描述方法對電路結構的影響,單進程狀態機、多進程狀態機的基本結構模型,層次化設計的基本結構與方法,Block RAM的結構、編程、寬度和深度組合,基於IP Core的Block RAM設計,使用DLL、全局時鐘網絡、DCM消除時鐘時延、頻率合成和時鐘相位調整等方法。

VHDL設計是行爲級的設計,所帶來的問題是設計者的設計思考與實際電路結構是相脫節的。設計者主要是根據VHDL的語法規則,對系統目標的邏輯行爲進行描述,然後通過綜合工具進行電路結構的綜合、編譯、優化,通過仿真工具進行邏輯功能仿真和系統時延的仿真。實際設計過程中,由於每個設計工程師對語言規則、對電路行爲的理解程度不同,每個人的編程風格不同,往往同樣的系統功能,描述的方式是不一樣的,綜合出來的電路結構更是大相徑庭。因此,即使最後綜合出的電路都能實現相同的邏輯功能,其電路的複雜程度和時延特性都會有很大的差別,甚至某些臃腫的電路還會產生難以預料的問題。從這些問題出發,很有必要深入討論在VHDL設計中如何簡化電路結構,優化電路設計的問題。用VHDL進行設計,最終綜合出的電路的複雜程度,除取決於設計要求實現的功能的難度外,還受設計工程師對電路的描述方法和對設計的規劃水平的影響。最常見的使電路複雜化的原因之一是在設計中存在許多本不必要的類似LATCH的結構。而且由於這些結構通常都由大量的觸發器組成,不僅使電路更復雜,工作速度降低,而且由於時序配合的原因會導致不可預料的結果。

以下有2段設計,如果單從語法上來看是沒有任何錯誤的,而且編譯時都可以通過,但是如果從電路結構上考慮,它們都存在問題。
Exam1: Process(A,B)
Begin
If A=’1’ then
Q <= B ; 暗指鎖存
End if;
End process;
Exam2: process(C)
Begin
Case C is
When ‘0’=> Q <= ‘1’;
Z <= ‘0’;
When ‘1’=> Q <= ‘0’; 缺少Z的值
End case;
End process;
仔細觀察,在Exam1和Exam2進程中的語句都有同一個毛病。Exam1進程中的if語句僅僅指明瞭A在高電平(1)的時候將B的值傳到Q端,並沒有指明A在低電平(0)的時候Q端應該是什麼值。綜合工具在綜合時,發現這種不完全的狀態描述,會將其綜合爲鎖存(latch)。鎖存的結構如圖7.1.1所示。在ISE中,綜合工具XST會發出一個警告: Found 1-bit latch for signal <q>。鎖存是由與或非邏輯組成的,而這種結構在系統中多半會埋下不穩定的種子。
再看看Exam2進程,有兩個輸出信號,信號的值在Case語句中被決定,但是Z的值只在C爲‘0’時有明確的說明,當C爲高‘1’時設計者並沒有明確指出。所以同樣會使綜合工具理解爲鎖存。


2.描述寄存器代替鎖存
既然鎖存存在不穩定,那麼有必要找到一個好的替代,那就是寄存器。寄存器由時鐘觸發,很大程度上抑制了毛刺。所以,儘可能的使用寄存器而避免鎖存。
下面是不同的D觸發器的VHDL描述:
DFF:process(clk) --D觸發器
Begin
If rising_edge(clk) then
Q <= A;
End if;
End process;


DFF_AR:process(clk,reset)--帶異步復位的D觸發器
Begin
If reset=’1’ then
Q <=’0’;
Elsif rising_edge(clk) then
Q <= A;
End if;
End process;

DFF_AS:process(clk,reset)--帶異步置位的D觸發器
Begin
If reset=’1’ then
Q <=’1’;
Elsif rising_edge(clk) then
Q <= A;
End if;
End process;

DFF_SS:process(clk,reset)-- 帶同步置位的D觸發器
Begin
if rising_edge(clk) then
if reset=’1’ then
Q <=’1’;
else
Q <= A;
End if;
End if;
End process;

從上面的例子可以瞭解到不同的描述對電路結構的影響,在下面的一個例子中,有兩種不同的加法描述,其電路結構也是不同的。


3.使用括號描述想要的結構
(1)Out1<=I1+I2+I3+I4;
(2)Out2<=(I1+I2)+(I3+I4);
從結構上看,第一種描述中沒有使用括號,電路結構爲三層,加法一級一級的進行。它的特點是,四個輸入I1,I2,I3,I4到達加法器的路徑不相等。第二種描述中的使用了括號,電路結構分爲兩層,顯然它的特點是四個輸入信號到達加法器的路徑是相等的。這裏並不能簡單的評論兩種結構的優劣,必須根據實際應用情況分析。

4.並行結構
在VHDL語言描述中,進程中的語句是順序執行的。如果要設計一個並行的電路,不要使用順序語句,而要使用並行語句。
方法1. Process(A,B,C)
begin
if C=’0’then
Y<=A;
Else
Y<=B;
End if;
End process;
方法2. Y<=A when C=’0’else B;
如果電路結構是並行的,那麼使用方法2描述要比方法1好。


5.資源共享
如果有可能的話,儘量使資源共享。一塊FPGA芯片中的資源是有限的。如果不有效利用僅有的資源,將會導致資源不夠,系統冗餘過多,穩定性也變會差。
加法器的資源共享
加法器的輸出Z是A加上C或者B,A與C、B哪個輸入相加由選擇信號S決定,由於在設計中採用了多路選擇器(Mux),在結構上可以得到兩種形式。一種方法是採用了兩個16位的加法器,兩個加法器的結果通過MUX由S選擇輸出。而只採用了一個加法器,它將C、B信號通過MUX後的輸出送到加法器的一端,另一端連接A。兩種結構都能達到設計的要求,顯然,後者的設計設計佔用的資源要小些。

在使用VHDL描述時,在process中比較容易做到資源共享,源程序如下:
process(A,B,C,S)
begin
if S=’1’ then
Z <= A+B;
Else
Z <= A+C;
End if;
End process;


6.integer和std_logic_vector
在VHDL中,信號使用限制了位數的std在VHDL中,信號使用限制了位數的std_logic_vector(標準邏輯向量)型,不使用integer(整型)。如果使用integer,最好在後面加上約束條件,例如:a:integer range 0 to 7;。如果使用了integer而沒有對其進行位數的約束,那麼在32位的PC機中,綜合後將是一個32bit的信號,會造成大量的浪費。 _logic_vector(標準邏輯向量)型,不使用integer(整型)。如果使用integer,最好在後面加上約束條件,例如:a:integer range 0 to 7;。如果使用了integer而沒有對其進行位數的約束,那麼在32位的PC機中,綜合後將是一個32bit的信號,會造成大量的浪費。


7.1.2 不同的狀態機描述
1. 狀態機的選型
按狀態機的輸出方式分類,有限狀態機可分爲Mealy型和Moore型。從輸出時序上看,狀態機的輸出是當前狀態和所有輸入信號的函數,它的輸出是在輸入變化後立即發生的,不依賴時鐘的同步。Moore型狀態機輸出則僅爲當前狀態的函數,狀態機的輸入發生變化還必須與狀態機的時鐘同步。
由於Mealy狀態機的輸出不與時鐘同步,所以當在狀態譯碼比較複雜的時候,很容易在輸出端產生大量的毛刺,這種情況是無法避免的。在一些特定的系統中,這些毛刺可能造成不可預料的結果。但是,由於輸入變化可能出現在時鐘週期內的任何時刻,這就使得Mealy狀態機對輸入的響應可以比Moore狀態機對輸入的響應要早一個時鐘週期。Moore狀態機的輸出與時鐘同步,可以在一定程度上剔除抖動。從穩定性的角度來講,建議使用Moore狀態機以提高系統的穩定性。
在實際工程中,具體電路有具體的設計要求,可能適應於Moore或Mealy狀態機,也可能兩種都可以實現設計,所以設計者必須根據實際情況和經驗綜合決定採用哪種狀態機。

2. 狀態編碼
狀態編碼,是指定義狀態機現態和次態,一般 有3種方式:
(1)方式1
signal curren_state:std_logic_vector(1 downto 0)
signal next_state:std_logic_vector(1 downto 0)
方式1定義的狀態有比較多的毛病。首先,這種方式定義的狀態爲邏輯向量,缺乏具體的狀態含義,程序的可讀性較差,更重要的是,設計後期調試修改比較麻煩。
2)方式2
Type mystate is (st0,st1,st2,st3);
Signal curren_state,next_state:mystate;
採用方式2定義的狀態有具體的狀態含義,可讀 性好,易於調試和修改。使用attribute可以對狀態進行手動編碼,通過設置用戶型編碼方式,綜合工具很容易根據手動狀態編碼進行高效的綜合。
(3)方式3
Signal curren_state,next_state:std_logic_vector(1downto 0);
Constant st0:std_logic_vector(1 downto 0):=”00”;
Constant st1:sta_logic_vector(1 donwot 0):=”01”;
Constant st2:sta_logic_vector(1 donwot 0):=”10”;
Constant st3:sta_logic_vector(1 donwot 0):=”11”;
方式3比方式1要好,因爲方式3的可讀性比方式 1要好。但是方式3的修改沒有方式2方便。

狀態機的編碼在ISE中有6種,其中常用的是順序編碼和一位熱碼。在ISE中可以通過修改綜合約束來指定狀態機的編碼。方法如下:
①綜合前,在Process for current sources窗口中選中Synthesize,單擊鼠標右鍵,彈出下拉菜單,選中Properties(屬性)。
②在彈出的菜單中有3個選項欄,選中HDL options選項欄,如圖7.1.6所示。在Properties name(屬性名)下的第一項便是FSM Encoding Algorithm(有限狀態機編碼算法),在Value中打開下拉菜單,可以看到幾種編碼方式。其中Auto(自動)爲ISE的缺省值,在一般情況下,如果目標芯片是FPGA,那麼XST會將狀態機編碼爲One-Hot(一位熱碼)。使用One-Hot(一位熱碼)的好處是,狀態轉換快,狀態譯碼簡單。

採用Sequential(順序編碼)的好處是,所需要的寄存器少,冗餘狀態相對要少,系統進入其他狀態的機會就更少。
還有一個比較常用的編碼方式,User(用戶)編碼方式。在前面講過,設計者是可以手動編碼的,只要加上Attribute語句便可,這裏給出一個例子:
需要提醒大家注意的是,HDL Options中的設置的優先級要高於用戶的attribute屬性。也就是說,如果使用了attribute語句進行了手動編碼,但是在FSM Encoding Algorithm中選擇的是Gray(格雷)碼,那麼實際綜合的效果是Gray(格雷)編碼。
例子:
type STATE_TYPE is (S1, S2, S3, S4);
attribute ENUM_ENCODING: STRING;
attribute ENUM_ENCODING of STATE_TYPE: type is "1110 1101 1011 0111";
上面的四個狀態S1,S2,S3,S4其實也是一位熱碼,是用‘0’作爲熱碼。選擇User編碼,那麼綜合後的實際狀態機編碼就是設計者在attribute中描述的狀態碼字。


3. 多進程狀態機
在狀態機的描述中,經典的應該屬於3進程狀態機,基本結構可以由下面的模型描述:
SYNC_PROC: process (CLOCK, RESET) --同步進程
begin
if (RESET='1') then --現態 <= 初始狀態;
elsif (CLOCK'event and CLOCK = '1') then
--現態 <= 次態;
end if;
end process;

COMB_PROC1: process (--現態, 輸入信號) –狀態轉化進程
begin
case 現態 is
when初始狀態=>
if (--轉換條件) then
--次態賦值
end if;
--其他所有狀態轉換的描述
end case;
end process;

COMB_PROC2:process(現態, 輸入端) --輸出描述進程
Begin
Case 現態
When初始狀態=>
if (輸入端的變化) then
--輸出賦值
--其他所有狀態下輸出的描述
end case
end process;

或者:
COMB_PROC2:process(現態, 輸入端) --輸出描述進程
Begin
Case 現態
When初始狀態=> --輸出賦值
--其他所有狀態下輸出的描述
end case
end process;

以上模型描述的3進程狀態機中的各個進程分工相當明確。SYNC_PROC進程完成狀態的同步描述和狀態機的初始化,COMB_PROC1進程完成對狀態轉換的描述,COMB_PROC2完成對輸出的描述。3個進程各負責一個工作互不擾,第一個進程的電路是時序邏輯,第二,三進程的電路是組合邏輯。COMB_PROC2進程中可能出現兩種描述。第一種描述,輸出端是現態和輸入的函數,是Mealy狀態機。第二種描述,輸出端是僅爲現態的函數,是Moore狀態機。
當然,COMB_PROC1 ,COMB_PROC2兩個進程完全可以寫到一個進程中。那麼狀態機的進程就分爲時序進程和組合進程。


4. 單進程狀態機
在實際的設計中,在輸入端引入噪聲是難免。如果使用的是Mealy狀態機,噪聲很容易傳到輸出端口,在輸出端口出現毛刺,如果這個狀態機的輸出要被用於作爲其他模塊的同步信號的話,系統設計很有可能會失敗。那麼在這種情況下,最好採用Moore狀態機。但是,在3進程狀態機中,輸出信號是由狀態譯碼得來的,輸出進程描述的電路是組合邏輯,組合邏輯沒有抑制毛刺的能力。所以3進程的Moore狀態機只是相對3進程的Mealy狀態機有一定的抗干擾能力。
爲了使系統更加穩定,可以在輸出組合邏輯後面在加一級寄存器,採用時鐘邊沿觸發,這樣,可以在很大程度上剔除毛刺,抑制噪聲的干擾。這樣採用單進程的狀態機也可以達到設計目的。
(1)單進程狀態機的基本結構模型
單進程狀態機的基本結構可以由下面的模型描述:
SYNC_PROC: process (CLOCK, RESET) --同步進程
begin
if (RESET='1') then
--現態 <= 初始狀態;
elsif (CLOCK'event and CLOCK = '1') then
--現態 <=現態;
case 現態 is
when初始狀態=> if (--轉換條件) then
--現態賦值
end if;
if (--轉換條件) then
--輸出賦值
end if;
--其他所有狀態轉換的描述
--其他所有狀態下輸出的描述
end if;
end process;
可以看出,由於狀態機的所有工作都是在時鐘上升沿觸發下完成的,所以,輸出組合邏輯的後面必定產生了一組寄存器,從而抑制了毛刺的產生。

(2)狀態機的比較
下面以一個簡單的狀態機爲例,驗證上面的分析。其中EXAM1是2個進程的狀態機,分爲時序進程和組合進程;EXAM2是單進程狀態機。這裏不對狀態機的工作做介紹,僅僅表現是兩種方法描述同一個功能的狀態機的差異。通過ISE5.2的RTL視圖工具可以方便的看到綜合後的實際結果,在RTL視圖前對兩種描述綜合出的電路圖做比較可以輕易地看出它們的不同。圖7.1.7和圖7.1.8分別爲EXAM1和EXAM2的綜合結果。
①2個進程的狀態機設計例
EXAM1:-- EXAM1是2個進程的狀態機,分爲時序進程和組合進程。
entity statemachine2 is
Port ( in1 : in std_logic;
in2 : in std_logic;
reset : in std_logic;
clk : in std_logic;
out1 : out std_logic;
out2 : out std_logic);
end statemachine2;
architecture Behavioral of statemachine2 is
Type mystate is (st0,st1,st2,st3);
Signal current_state,next_state:mystate;
begin
process (clk, RESET)
begin
if (RESET='1') then
current_state <= st0;
elsif rising_edge(clk) then
current_state <= next_state;
end if;
end process;
process(in1,in2,current_state)
begin
case current_state is
when st0=> if in1='1' then
next_state <= st1;
end if;
out1<='0';
out2<='0';
when st3=> if in1='0'and in2='0' then
next_state <= st0;
end if;
out1<='1';
out2<='1';
when others => next_state <= st0;
end case;
end process;
end Behavioral;


②單進程狀態機設計例
EXAM2;-- EXAM2是單進程狀態機
entity statemachine is
Port ( in1 : in std_logic;
in2 : in std_logic;
reset : in std_logic;
clk : in std_logic;
out1 : out std_logic;
out2 : out std_logic);
end statemachine;
architecture Behavioral of statemachine is
Type mystate is (st0,st1,st2,st3);
Signal current_state:mystate;
begin
process (clk, RESET,in1,in2)
begin
if (RESET='1') then
current_state <= st0;
elsif rising_edge(clk) then
current_state <= current_state;
case current_state is
when st0=> if in1='1' then
current_state <= st1;
end if;
out1<='0';
out2<='0';
when st1=> if in2='1' then
current_state <= st2;
end if;
out1<='1';
out2<='0';
when st2=> if in1='0'and in2='1' then
current_state <= st3;
end if;
out1<='0';
out2<='1';
when st3=> if in1='0'and in2='0' then
current_state <= st0;
end if;
out1<='1';
out2<='1';

when others => current_state <= st0;
end case;
end if;
end process;
end Behavioral;

③比較
2個進程的狀態機和單進程狀態機的電路不同,單進程狀態機的輸出端的後面採用了一組FDE(帶使能的DFF)。採用單進程的狀態機使用的資源要比2進程的狀態機的要多。這也可以從綜合報告中得到驗證。
a. 單進程狀態機:
Device utilization summary:
---------------------------
Selected Device : 2s100epq208-6
Number of Slices: 4 out of 1200 0%
Number of Slice Flip Flops: 6 out of 2400 0%
Number of 4 input LUTs: 7 out of 2400 0%
Number of bonded IOBs: 5 out of 146 3%
Number of GCLKs: 1 out of 4 25%
b. 2進程狀態機:
Device utilization summary:
---------------------------
Selected Device : 2s100epq208-6
Number of Slices: 3 out of 1200 0%
Number of Slice Flip Flops: 4 out of 2400 0%
Number of 4 input LUTs: 6 out of 2400 0%
Number of bonded IOBs: 5 out of 146 3%
Number of GCLKs: 1 out of 4 25%

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章