|
.用戶自定義數據類型
使用關鍵字TYPE,例如:
TYPE my_integer IS RANGE -32 TO 32;
–用戶自定義的整數類型的子集
TYPE student_grade IS RANGE 0 TO 100;
–用戶自定義的自然數類型的子集
TYPE state IS (idle, forward, backward, stop);
–枚舉數據類型,常用于有限狀態機的狀態定義
一般來說,枚舉類型的數據自動按順序依次編碼。
2.子類型
在原有已定義數據類型上加一些約束條件,可以定義該數據類型的子類型。VHDL不允許不同類型的數據直接進行操作運算,而某個數據類型的子類型則可以和原有類型數據直接進行操作運算。
子類型定義使用SUBTYPE關鍵字。
3.數組(ARRAY)
ARRAY是將相同數據類型的數據集合在一起形成的一種新的數據類型。
TYPE type_name IS ARRAY (specification) OF data_type;
–定義新的數組類型語法結構
SIGNAL signal_name: type_name [:= initial_value];
–使用新的數組類型對SIGNAL,CONSTANT, VARIABLE進行聲明
例如:
TYPE delay_lines IS ARRAY (L-2 DOWNTO 0) OF SIGNED (W_IN-1 DOWNTO 0);
–濾波器輸入延遲鏈類型定義
TYPE coeffs IS ARRAY (L-1 DOWNTO 0) OF SIGNED (W_COEF-1 DOWNTO 0);
–濾波器系數類型定義
SIGNAL delay_regs: delay_lines; – 信號延遲寄存器聲明
CONSTANT coef: coeffs := ( ); –常量系數聲明并賦初值
4.端口數組
在定義電路的輸入/輸出端口時,有時需把端口定義為矢量陣列,而在ENTITY中不允許使用TYPE進行類型定義,所以必須在包集(PACKAGE)中根據端口的具體信號特征建立用戶自定義的數據類型,該數據類型可以供包括ENTITY在內的整個設計使用。
—————————————PACKAGE———————————-
library ieee;
use ieee.std_logic_1164.all;
——————————————
PACKAGE my_data_types IS
TYPE vector_array IS ARRAY (natural range <>) OF STD_LOGIC_VECTOR(7 DOWNTO 0); –聲明8位的數組
END my_data_types;
———————————–Main Code—————————————
library ieee;
use ieee.std_logic_1164.all;
use work.my_data_types.all; –用戶自定義包集
——————————————————————
ENTITY mux IS
PORT (inp: IN vector_array(0 to 3);
END mux;
——————————————————————————-
5.有符號數和無符號數
要使用SIGNED和UNSIGNED類型數據,必須在代碼開始部分聲明ieee庫中的包集std_logic_arith。它們支持算術運算但不支持邏輯運算。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
……
SIGNAL a: IN SIGNED (7 DOWNTO 0);
SIGNAL b: IN SIGNED (7 DOWNTO 0);
SIGNAL x: IN SIGNED (7 DOWNTO 0);
……
v <= a + b;
w <= a AND b; –非法(不支持邏輯運算)
——————————————————————————-
STD_LOGIC_VECTOR類型的數據不能直接進行算術運算,只有聲明了std_logic_signed和std_logic_unsigned兩個包集后才可以像SIGNED和UNSIGNED類型的數據一樣進行算術運算。
6.數據類型轉換
在ieee庫的std_logic_arith包集中提供了許多數據類型轉換函數:
1. conv_integer(p): 將數據類型為INTEGER,UNSIGNED,SIGNED,STD_ULOGIC或STD_LOGIC的操作數p轉換成INTEGER類型。不包含STD_LOGIC_VECTOR。
2. conv_unsigned(p,b):將數據類型為INTEGER,UNSIGNED,SIGNED或STD_ULOGIC的操作數p轉換成位寬為b的UNSIGNED類型數據。
3. conv_signed(p,b):將數據類型為INTEGER, UNSIGNED, SIGNED或STD_ULOGIC的操作數p轉換成位寬為b的SIGNED類型的數據。
4. conv_std_logic_vector(p, b):將數據類型為INTEGER, UNSIGNED, SIGNED或STD_LOGIC的操作數p轉換成位寬為b的STD_LOGIC_VECTOR類型的數據。
二、 運算操作符和屬性
1. 運算操作符
l 賦值運算符
賦值運算符用來給信號、變量和常數賦值。
<= 用于對SIGNAL類型賦值;
:= 用于對VARIABLE,CONSTANT和GENERIC賦值,也可用于賦初始值;
=> 用于對矢量中的某些位賦值,或對某些位之外的其他位賦值(常用OTHERS表示)。
例:
SIGNAL x: STD_LOGIC;
VARIABLE y: STD_LOGIC_VECTOR(3 DOWNTO 0); –最左邊的位是MSB
SIGNAL w: STD_LOGIC_VECTOR(0 TO 7); –最右邊的位是MSB
x <= ‘1’;
y := “0000”;
w <= “1000_0000”; – LSB位為1,其余位為0
w <= (0 => ‘1’, OTHERS => ‘0’); – LSB位是1, 其他位是0
l 邏輯運算符
操作數必須是BIT, STD_LOGIC或STD_ULOGIC類型的數據或者是這些數據類型的擴展,即BIT_VECTOR, STD_LOGIC_VECTOR,STD_ULOGIC_VECTOR。
VHDL的邏輯運算符有以下幾種:(優先級遞減)
Ÿ NOT —— 取反
Ÿ AND —— 與
Ÿ OR —— 或
Ÿ NAND —— 與非
Ÿ NOR —— 或非
Ÿ XOR —— 異或
l 算術運算符
操作數可以是INTEGER, SIGNED, UNSIGNED, 如果聲明了std_logic_signed或std_logic_unsigned,可對STD_LOGIC_VECTOR類型的數據進行加法或減法運算。
+ —— 加
- —— 減
* —— 乘
/ —— 除
** —— 指數運算
MOD —— 取模
REM —— 取余
ABS —— 取絕對值
加,減,乘是可以綜合成邏輯電路的;除法運算只在除數為2的n次冪時才能綜合,此時相當于對被除數右移n位;對于指數運算,只有當底數和指數都是靜態數值(常量或GENERIC參數)時才是可綜合的;對于MOD運算,結果的符號同第二個參數的符號相同,對于REM運算,結果的符號同第一個參數符號相同。
l 關系運算符
=, /=, <, >, <=, >=
左右兩邊操作數的類型必須相同。
l 移位操作符
<左操作數> <移位操作符> <右操作數>
其中左操作數必須是BIT_VECTOR類型的,右操作數必須是INTEGER類型的(可以為正數或負數)。
VHDL中移位操作符有以下幾種:
u sll 邏輯左移 – 數據左移,右端補0;
u srl 邏輯右移 – 數據右移,左端補0;
u sla 算術左移 – 數據左移,同時復制最右端的位,填充在右端空出的位置;
u sra 算術右移 – 數據右移,同時復制最左端的位,填充在左端空出的位置;
u rol 循環邏輯左移 — 數據左移,從左端移出的位填充到右端空出的位置上;
u ror 循環邏輯右移 – 數據右移,從右端移出的位填充到左端空出的位置上。
例:x <= “01001”,那么:
y <= x sll 2; – 邏輯左移2位,y<=”00100”
y <= x sla 2; – 算術左移2位,y<=”00111”
y <= x srl 3; – 邏輯右移3位,y<=”00001”
y <= x sra 3; – 算術右移3位,y<=”00001”
y <= x rol 2; – 循環左移2位,y<=”00101”
y <= x srl -2; –相當于邏輯左移2位
l 并置運算符
用于位的拼接,操作數可以是支持邏輯運算的任何數據類型。有以下兩種:
2 &
2 (, , , )
與Verilog中{}的功能一樣。
2. 屬性(ATTRIBUTE)
l 數值類屬性
數值類屬性用來得到數組、塊或一般數據的相關信息,例如可用來獲取數組的長度和數值范圍等。
以下是VHDL中預定義的可綜合的數值類屬性:
d’LOW –返回數組索引的下限值
d’HIGH –返回數組索引的上限值
d’LEFT –返回數組索引的左邊界值
d’RIGHT –返回數組索引的右邊界值
d’LENGTH –返回矢量的長度值
d’RANGE –返回矢量的位寬范圍
d’REVERSE_RANGE –按相反的次序返回矢量的位寬范圍
例:定義信號 SIGNAL d: STD_LOGIC_VECTOR(7 DOWNTO 0);
則有:d’LOW = 0, d’HIGH = 7, d’LEFT = 7, d’RIGHT = 0, d’LENGTH = 8, d’RANGE = (7 DOWNTO 0), d’REVERSE_RANGE = (0 TO 7).
l 信號類屬性
對于信號s,有以下預定義的屬性(可綜合的):
s’EVENT 若s的值發生變化,則返回布爾量TRUE,否則返回FALSE
s’STABLE 若s保持穩定,則返回TRUE,否則返回FALSE
例:clk的上升沿判斷
IF (clk’EVENT AND clk = ‘1’)
IF (NOT clk’STABLE AND clk = ‘1’)
WAIT UNTIL (clk’EVENT AND clk = ‘1’)
3. 通用屬性語句
GENERIC語句提供了一種指定常規參數的方法,所指定的參數是靜態的,增加了代碼的可重用性,類似于Verilog中的parameter與defparam。GENERIC語句必須在ENTITY中進行聲明,由GENERIC語句指定的參數是全局的,不僅可在ENTITY內部使用,也可在后面的整個設計中使用。語法結構如下:
GENERIC (parameter_name: parameter_type := parameter_value);
用GENERIC語句指定多個參數:
GENERIC (n: INTEGER := 8; vector: BIT_VECTOR := “0000_1111”);
三、 并發代碼
VHDL中并發描述語句有WHEN和GENERATE。除此之外,僅包含AND, NOT, +, *和sll等邏輯、算術運算操作符的賦值語句也是并發執行的。在BLOCK中的代碼也是并發執行的。
從本質上講,VHDL代碼是并行執行的。只有PROCESS, FUNCTION, PROCEDURE內部的代碼才是順序執行的。但是當它們作為一個整體時,與其他模塊之間又是并行執行的。并發代碼稱為“數據流”代碼。
通常我們只能用并發描述語句來實現組合邏輯電路,為了實現時序邏輯電路,必須使用順序描述語句。事實上,使用順序描述語句可以同時實現組合邏輯電路和時序邏輯電路。
在并發代碼中可以使用以下各項:
Ø 運算操作符
Ø WHEN語句(WHEN/ELSE或WITH/SELECT/WHEN)
Ø GENERATE語句
Ø BLOCK語句
使用運算操作符
運算類型
運算操作符
操作數類型
邏輯運算
NOT, AND, NAND,OR
NOR, XOR, XNOR
BIT, BIT_VECTOR, STD_LOGIC, STD_LOGIC_VECTOR
STD_ULOGIC, STD_ULOGIC_VECTOR
算術運算符
+, —, *, /, **
INTEGER, SIGNED, UNSIGNED
比較運算符
=, /=, <, >, <=, >=
任意數據類型
移位運算符
sll, srl, sla, sra, rol, ror
BIT_VECTOR
并置運算符
&,(, , ,)
STD_LOGIC, STD_LOGIC_VECTOR, STD_ULOGIC
STD_ULOGIC_VECTOR, SIGNED, UNSIGNED
WHEN語句
WHEN語句是一種基本的并發描述語句,有兩種形式:WHEN/ELSE和WITH/SELECT/WHEN。
WHEN/ELSE語法結構:
assignment WHEN condition ELSE
assignment WHEN condition ELSE
…;
WITH/SELECT/WHEN語法結構
WITH identifier SELECT
assignment WHEN value,
assignemnt WHEN value,
…;
當使用WITH/SELECT/WHEN時,必須對所有可能出現的條件給予考慮,使用關鍵字OTHERS,如果在某些條件出現時不需要進行任何操作,那應該使用UNAFFECTED。
例:
————————————-with WHEN/ELSE——————————————-
Output <= “000” WHEN (inp = ‘0’ OR reset = ‘1’) ELSE
“001” WHEN ctl = ‘1’ ELSE
“010”;
———————————–with WITH/SELECT/WHEN——————————–
WITH control SELECT
Output <= “000” WHEN reset,
“111” WHEN set,
UNAFFECTED WHEN OTHERS;
對于WHEN語句,WHEN value的描述方式有以下幾種:
WHEN value –針對單個值進行判斷
WHEN value1 to value2 –針對取值范圍進行判斷
WHEN value1 | value2 | … –針對多個值進行判斷
GENERATE語句
GENERATE語句和順序描述語句中的LOOP語句一樣用于循環執行某項操作,通常與FOR一起使用。語法結構如下:
label: FOR identifier IN range GENERATE
(concurrent assignments)
END GENERATE
GENERATE語句還有另一種形式:IF/GENERATE,此處不允許使用ELSE。IF/GENERATE可以嵌套在FOR/GENERATE內部使用。反之亦然。
Label1: FOR identifier IN range GENERATE
……
Label2: IF condition GENERATE
(concurrent assignments)
END GENERATE;
……
END GENERATE;
例:
SIGNAL x: BIT_VECTOR(7 DOWNTO 0);
SIGNAL y: BIT_VECTOR(15 DOWNTO 0);
SIGNAL z: BIT_VECTOR(7 DOWNTO 0);
……
G1: FOR i IN x’RANGE GENERATE
z(i) <= x(i) AND y(i+8);
END GENERATE;
GENERATE中循環操作的上界和下界必須是靜態的,在使用過程中還要注意多值驅動問題。
例:
OK: FOR i IN 0 TO 7 GENERATE
Output(i) <= ‘1’ WHEN (a(i) AND b(i)) = ‘1’ ELSE ‘0’;
END GENERATE;
—————————————————————————
NotOK: FOR i IN 0 TO 7 GENERATE
accum <= “1111_1111” WHEN (a(i) AND b(i)) = ‘1’ ELSE “0000_0000”;
END GENERATE;
—————————————————————-
NotOK: FOR i IN 0 TO 7 GENERATE
Accum <= accum + 1 WHEN x(i) = ‘1’;
END GENERATE;
—————————————————————-
塊語句(BLOCK)
VHDL中有兩種BLOCK:simple BLOCK和guarded BLOCK。
n Simple BLOCK
Simple BLOCK僅僅是對原有代碼進行區域分割,增強整個代碼的可讀性和可維護性。語法結構如下:
label:BLOCK
[ declarative part]
BEGIN
(concurrent statement)
END BLOCK label;
—————————————————————————————————-
ARCHITETURE example…
BEGIN
…
block1: BLOCK
BEGIN
…
END BLOCK block1;
…
block2: BLOCK
BEGIN
…
END BLOCK block2;
…
END example;
—————————————————————————————–
例:
b1: BLOCK
SIGNAL a: STD_LOGIC;
BEGIN
a <= input_sig WHEN ena = ‘1’ ELSE ‘z’;
END BLOCK b1;
———————————————————————————————————————-
無論是simple BLOCK還是guarded BLOCK,其內部都可以嵌套其他的BLOCK語句,相應的語法結構如下:
label1: BLOCK
[頂層BLOCK聲明部分]
BEGIN
[頂層BLOCK并發描述部分]
label2: BLOCK
[嵌套BLOCK聲明部分]
BEGIN
[嵌套BLOCK并發描述部分]
END BLOCK label2;
[頂層BLOCK其他并發描述語句]
END BLOCK label1;
———————————————————————————————————
n Guarded BLOCK
多了一個衛式表達式,只有當衛式表達式為真時才能執行。語法結構如下:
Label: BLOCK(衛式表達式)
[聲明部分]
BEGIN
(衛式語句和其他并發描述語句)
END BLOCK label;
四、 順序代碼
在PROCESS, FUNCTION, PROCEDURE內部的代碼都是順序執行的,這樣的語句包括IF,WAIT,CASE和LOOP。變量只能在順序代碼中使用,相對于信號而言,變量是局部的,所以它的值不能傳遞到PROCESS,FUNCTION和PROCEDURE的外部。
1. 進程(PROCESS)
進程內部經常使用IF,WAIT,CASE或LOOP語句。PROCESS具有敏感信號列表(sensitivity list),或者使用WAIT語句進行執行條件的判斷。PROCESS必須包含在主代碼段中,當敏感信號列表中的某個信號發生變化時(或者當WAIT語句的條件得到滿足時),PROCESS內部的代碼就順序執行一次。語法結構如下:
[label: ] PROCESS (sensitivity list)
[VARIABLE name type [range] [ := initial_value; ]]
BEGIN
(順序執行的代碼)
END PROCESS [label];
如果要在PROCESS內部使用變量,則必須在關鍵字BEGIN之前的變量聲明部分對其進行定義。變量的初始值是不可綜合的,只用于仿真。在設計同步電路時,要對某些信號邊沿的跳變進行監視(時鐘的上升沿或下降沿)。通常使用EVENT屬性來監視一個信號是否發生了變化。
2. 信號和變量
信號可在PACKAGE,ENTITY和ARCHITECTURE中聲明,而變量只能在一段順序描述代碼的內部聲明。因此,信號通常是全局的,變量通常是局部的。賦予變量的值是立刻生效的,在后續的代碼中,此變量將使用新的變量值,而信號的值通常只有在整個PROCESS執行完畢后才開始生效。
3. IF語句
IF/ELSE語句在綜合時可能會產生不必要的優先級解碼電路。IF語句語法結構如下:
IF conditions THEN assignments;
ELSIF conditions THEN assignments;
ELSE assignments;
END IF;
————————————————————————————————
例:
IF (x < y) temp := “1111_1111”;
ELSIF (x = y AND w = ‘0’) THEN temp := “1111_0000”;
ELSE temp := (OTHERS => ‘0’);
4. WAIT語句
如果在process中使用了WAIT語句,就不能使用敏感信號列表了。WAIT語句使用以下3種形式的語法結構:
WAIT UNTIL signal_condition;
WAIT ON signal1 [, signal2, ...];
WAIT FOR time;
WAIT UNTIL 后面只有一個信號條件表達式,更適合于實現同步電路(將時鐘的上升沿或下降沿作為條件),由于沒有敏感信號列表,所以它必須是process的第一條語句。當WAIT UNTIL語句的條件滿足是,process內部的代碼就執行一遍。
–帶有同步復位的8bit寄存器
process –沒有敏感信號列表
begin
wait until (clk’event and clk = ‘1′);
if (rst = ‘1′) then
output <= (others => ‘0′);
elsif (clk’event and clk = ‘1′) then
output <= input;
end if;
end process;
WAIT ON 語句中可以出現多個信號,只要信號列表中的任何一個發生變化,process內的代碼就開始執行。
–帶異步復位的8bit寄存器
process
begin
wait on clk, rst;
if (rst = ‘1′) then
output <= (others => ‘0′);
elsif (clk’event and clk = ‘1′) then
output <= input;
end if;
end process;
WAIT FOR 語句只能用于仿真。
5. CASE 語句
CASE語句的語法結構如下:
CASE 表達式 IS
WHEN 條件表達式 => 順序執行語句;
WHEN 條件表達式 => 順序執行語句;
……
END CASE
例:
case control is
when “00″ => x <= a; y <= b;
when “01″ => x <= b; y <= c;
when others => x <= “0000″; y <= “zzzz”;
end case;
關鍵詞OTHERS代表了所有未列出的可能情況,與Verilog中default相當。關鍵詞NULL表示沒有操作發生,如WHEN OTHERS => NULL.
CASE語句允許在每個測試條件下執行多個賦值操作,WHEN語句只允許執行一個賦值操作。
6. LOOP語句
LOOP語句用在需要多次重復執行時。語法結構有以下幾種:
FOR/LOOP: 循環固定次數
[label: ] FOR 循環變量 IN 范圍 LOOP
(順序描述語句)
END LOOP [label];
WHILE/LOOP: 循環執行直到某個條件不再滿足
[label: ] WHILE condition LOOP
(順序描述語句)
END LOOP [label];
EXIT: 結束整個循環操作
[label: ] EXIT [label] [WHEN condition];
NEXT: 跳出本次循環
[label: ] NEXT [loop_label] [WHEN condition];
Example: FOR/LOOP
for i in 0 to 5 loop
x(i) <= enable and w(i+2);
y(0, i) <= w(i);
end loop
Example: WHILE/LOOP
while (i < 10) loop — 0~9
wait until clk’event and clk = ‘1′;
(其他語句)
end loop;
for i in 0 to data’range loop
case data(i) is
when ‘0′ => count := count + 1;
when others => null;
end case;
end loop;
7. CASE語句和IF語句的比較
IF語句和CASE語句編寫的代碼在綜合、優化后最終生成的電路結構是一樣的。
例:下面兩段代碼綜合后可以得到結構相同的多路復用器
————with IF————–
if (sel = “00″) then x <= a;
elsif (sel = “01″) then x <= b;
elsif (sel = “10″) then x <= c;
else x <= d;
end if;
————-with case———–
case sel is
when “00″ => x <= a;
when “01″ => x <= b;
when “10″ => x <= c;
when others => x <= d;
end case;
8. CASE語句和WHEN語句的比較
case語句和when語句的不同之處在于,when語句是并發執行的,case語句是順序實行的。
–下面兩段代碼的功能等效
——-with when——————
with sel select
x <= a when “000″,
b when “001″,
c when “101″,
unaffected when others;
——-with case——————
case sel is
when “000″ => x <= a;
when “001″ => x <= b;
when “101″ => x <= c;
when others => null;
end case;
9. 使用順序代碼設計組合邏輯電路
原則1:確保在process中用到的所有輸入信號都出現在敏感信號列表中;
原則2:電路的真值表必須在代碼中完整的反映出來。(否則會生成鎖存器)
五、 信號和變量
常量和信號是全局的,既可以用在順序執行的代碼中,也可用在并發執行的代碼中。變量是局部的,只能用在順序代碼中,并且它們的值是不能直接向外傳遞的。
1. 常量
CONSTANT name: type := value;
2. 信號-signal
VHDL中的signal代表的是邏輯電路中的“硬”連線,既可用于電路的輸入/輸出端口,也可用于電路內部各單元之間的連接。Entity的所有端口默認為signal。格式如下:
SIGNAL name: type [range] [:= initial value];
當信號用在順序描述語句中時,其值不是立刻更新的,信號值是在相應的進程、函數或過程完成之后才進行更新的。對信號賦初值的操作時不可綜合的。
3. 變量
變量僅用于局部電路的描述,只能在順序執行的代碼中使用,而且對它的賦值是立即生效的,所以新的值可在下一行代碼中立即使用。格式:
VARIABLE name: type [range] [:= initial value];
對變量的賦初值操作也是不可綜合的。
4. 寄存器的數量
當一個信號的賦值是以另一個信號的跳變為條件時,或者說當發生同步賦值時,該信號經過編譯后就會生成寄存器。如果一個變量是在一個信號跳變時被賦值的,并且該值最終又被賦給了另外的信號,則綜合后就會生成寄存器。如果一個信號在還沒有進行賦值操作時已被使用,那么也會在綜合時生成寄存器。
process (clk)
begin
if (clk’event and clk = ‘1′) then
output1 <= temp; – output1被寄存
output2 <= a; – output2被寄存
end if;
end process;
process (clk)
begin
if (clk’event and clk = ‘1′) then
output1 <= temp; – output1被寄存
end if;
output2 <= a; – output2未被寄存
end process;
process (clk)
variable temp: bit;
begin
if (clk’event and clk = ‘1′) then
temp <= a;
end if;
x <= temp; – temp促使x被寄存
end process;
六、 包集元件
1. 包集
經常使用的代碼通常以component,function或procedure的形式編寫。這些代碼被添加到package中,并在最后編譯到目標library中。Package中還可以包含TYPE和CONSTANT的定義。語法格式如下:
package package_name is
(declaration)
end package_name;
package body package_name is
(function and procedure description)
end package_name;]
Example6.1 簡單的程序包
library ieee;
use ieee.std_logic_1164.all;
———————————————————————-
package my_package is
type state is (st1, st2, st3, st4);
type color is (red, green, blue);
constant vec: std_logic_vector(7 downto0) := “1111_1111″;
end my_package;
Example6.2 內部包含函數的package
library ieee;
use ieee.std_logic_1164.all;
———————————————————————-
package my_package is
type state is (st1, st2, st3, st4);
type color is (red, green, blue);
contant vec: std_logic_vector(7 downto 0) := “1111_1111″;
function positive_edge(signal s: std_logic) return boolean;
end my_package;
———————————————————————-
package body my_package is
function positive_edge(signal s: std_logic) return boolean is
begin
return(s’event and s = ‘1′);
end positive_edge;
end my_package;
為了在QUARTUS II中使用這些package,要在當前project目錄下新建一個文件夾,不妨起名為user_lib,把要編譯的package放進此文件夾中,然后在AssignmentsàSettingàLibrary中設置相應的目錄即可。在VHDL代碼中要使用這些package,要在主程序中加入如下代碼:
use work.package_name.all;
2. 元件component
一個元件是一段結構完整的常用代碼,包括聲明,實體和結構體,使用component可以使代碼具有層次化的結構。
元件聲明:
component comp_name is
port (
port_name1: signal_mode signal_type;
port_name2: signal_mode signal_type;
…
);
end component;
元件實例化:
label: comp_name port map (port_list);
元件的聲明可以放在主代碼中,即調用該元件的代碼;或者將元件的聲明放到package中,使用時在主代碼中增加一條USE語句即可,這樣避免了主代碼中每實例化一個元件就要聲明一次的麻煩。
3. 端口映射
在元件實例化過程中,有兩種方法實現元件端口的映射:位置映射和名稱映射。
component inverter is
port ( a: in std_logic;
b: out std_logic
);
end component;
…
U1: inverter port map(x, y);
此處采用的是位置映射法,x對應a,y對應b。
U1: inverter port map(a => x, b=> y);
此處采用的是名稱映射法。對于不需要使用的端口可以斷開,只需使用關鍵字open即可,但是輸入端口不能指定為空連接。比如:
U2: my_circuit port map(x => a, y => b, w => open, z => b);
4. GENERIC參數映射
元件實例化時如果要通過GENERIC傳遞參數,則需進行GENERIC參數的映射。元件實例化的格式如下:
label: comp_name generic map(param_list) port map(port_list);
七、 函數和過程
Function和procedure統稱為子程序,內部包含的都是順序描述的VHDL語言.
八、 有限狀態機
狀態機的設計包含兩個主要過程:狀態機建模和狀態的編碼。
1.有限狀態機的建模
有限狀態機通常使用CASE語句來建模,一般的模型由兩個進程組成,一個進程用來實現時序邏輯電路,另一個進程用來實現組合邏輯電路。
模型的構建:
(1) 分析設計目標,確定有限狀態機所需的狀態,并繪制狀態圖;
(2) 建立VHDL實體,定義枚舉類型的數據類型;
(3) 定義狀態變量,其數據類型為前面所定義的枚舉數據類型;例:
TYPE STATE IS (STATE0, STATE1, STATE2, …);
SIGNAL CR_STATE, NEXT_STATE: STATE;
(4) 建立時序邏輯電路的實現進程;例:
PROCESS (CLK,RESET)
BEGIN
IF RESET=’1’ THEN
CR_STATE <= STATE0;
ELSIF CLK’EVENT AND CLK=’1’ THEN
CR_STATE <= NEXT_STATE;
END IF;
END PROCESS;
(5) 使用CASE語句建立組合邏輯電路的實現進程。例:
PROCESS(CR_STATE,INPUT)
BEGIN
CASE CR_STATE IS
WHEN STATE0 =>
IF INPUT = … THEN
NEXT_STATE <= STATE1;
END IF;
WHEN STATE1 =>
…
WHEN OHTERS => NEXT_STATE <= STATE0;
END CASE;
END PROCESS;
2.狀態編碼
狀態編碼包括二進制編碼、枚舉類型的編碼和一位有效編碼。利用一位有效編碼(One-hot encoding)可以創建更有效地在FPGA結構中實現的有限狀態機。每個狀態可以使用一個觸發器來創建狀態機,并且可以降低組合邏輯的寬度。
有限狀態機的可能狀態由枚舉類型所定義,即:
TYPE type_name IS(枚舉元素1, 枚舉元素2, …., 枚舉元素n);
這個定義是通用的格式,時必須的。在該枚舉類型定義語句之后,就可以聲明信號為所定義的枚舉類型:
TYPE STATE_TYPE IS(S1, S2, S3, S4, S5, S6, S7);
SIGNAL CS,NS: STATE_TYPE;
為了選擇有限狀態機的狀態編碼方式,需要指定狀態矢量。也可以通過綜合工具指定編碼方式。當在程序中指定編碼方式時,可以在枚舉類型定義語句后指定狀態矢量,例如,
定義二進制編碼的狀態矢量的語句是:
ATTRIBUTE ENUM_ENCODING: STRING;
ATTRIBUTE ENUM_ENCODING OF STATE_TYPE:TYPE IS “001 010 011 100 101 110 111”;
定義一位有效編碼的狀態矢量的語句為:
ATTRIBUTE ENUM_ENCODING:STRING;
ATTRIBUTE ENUM_ENCODING OF STATE_TYPE:TYPE IS ”0000001 0000010 0000100 0001000 0010000 0100000 1000000”; |
|