VHDL總結

一個VHDL程序代碼包含實體(entity)結構體(architecture)、配置(configuration)、程序包(package)、庫(library)等。

 

一、        數據類型

1.用戶自定義數據類型

使用關鍵字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.       運算操作符

 賦值運算符

賦值運算符用來給信號、變量和常數賦值。

<=    用於對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

 邏輯運算符

操作數必須是BIT, STD_LOGIC或STD_ULOGIC類型的數據或者是這些數據類型的擴展,即BIT_VECTOR, STD_LOGIC_VECTOR,STD_ULOGIC_VECTOR。

VHDL的邏輯運算符有以下幾種:(優先級遞減

Ÿ   NOT —— 取反

Ÿ   AND —— 與

Ÿ   OR —— 或

Ÿ   NAND —— 與非

Ÿ   NOR —— 或非

Ÿ   XOR —— 異或

 算術運算符

操作數可以是INTEGER, SIGNED, UNSIGNED, 如果聲明瞭std_logic_signed或std_logic_unsigned,可對STD_LOGIC_VECTOR類型的數據進行加法或減法運算。

+ —— 加

         —— 減

* —— 乘

/ —— 除

** —— 指數運算

MOD —— 取模

REM —— 取餘

ABS —— 取絕對值

加,減,乘是可以綜合成邏輯電路的;除法運算只在除數爲2的n次冪時才能綜合,此時相當於對被除數右移n位;對於指數運算,只有當底數和指數都是靜態數值(常量或GENERIC參數)時纔是可綜合的;對於MOD運算,結果的符號同第二個參數的符號相同,對於REM運算,結果的符號同第一個參數符號相同。

 關係運算符

=, /=, <, >, <=, >=

左右兩邊操作數的類型必須相同。

 移位操作符

<左操作數> <移位操作符> <右操作數>

其中左操作數必須是BIT_VECTOR類型的,右操作數必須是INTEGER類型的(可以爲正數或負數)。

VHDL中移位操作符有以下幾種:

 sll  邏輯左移  – 數據左移,右端補0;

 srl  邏輯右移  – 數據右移,左端補0;

 sla  算術左移  – 數據左移,同時複製最右端的位,填充在右端空出的位置;

 sra  算術右移  – 數據右移,同時複製最左端的位,填充在左端空出的位置;

 rol  循環邏輯左移 — 數據左移,從左端移出的位填充到右端空出的位置上;

 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位

 並置運算符

用於位的拼接,操作數可以是支持邏輯運算的任何數據類型。有以下兩種:

²  &

²  (, , , )

與Verilog中{}的功能一樣。

2.       屬性(ATTRIBUTE)

 數值類屬性

數值類屬性用來得到數組、塊或一般數據的相關信息,例如可用來獲取數組的長度和數值範圍等。

以下是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).

 信號類屬性

對於信號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。

 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;

———————————————————————————————————

 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”;

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