1. 程式人生 > >2.VHDL的基本結構和語法(一)

2.VHDL的基本結構和語法(一)

目錄

類屬說明

程序與時鐘

程序的啟動

1.VHDL基本結構

  •  實體(Entity) :描述所設計的系統的外部介面訊號 ,定義電路設計中所有的輸入和輸出埠;
  •  結構體 (Architecture) :描述系統內部的結構和行為;
  • 包集合 (Package): 存放各設模組能共享的資料型別 、常數和子程式等 ;
  • 配置 (Configuration):  指定實體所對應的結構體;
  • 庫 (Library):  存放已經編譯的實體 、結構體 、包集合和配置。

VHDL的基本設計的基本設計單元結構:程式包說明 、實體說明和結構體說明三部分:

 

 1.1.實體(Entity)

實體描述了設計單元的輸入輸出介面訊號或引腳 ,是設計實體經封裝後對外的一個通訊介面。

定義方式:

ENTITY    實體名   IS [ GENERIC( 常數名 :資料型別 :設定值) ]PORT (  埠名1:  埠方向  埠型別;    埠名2:  埠方向  埠型別;  .   .   埠名n:  埠方向  埠類 型 ); END [實體名]; 

注意:實體名由設計者自由命名 ,用來表示被設計電路晶片的名稱 , 但是必須與VHDL程式的程式的檔名稱相同。 要與文 件 名一 致 。

  •   類屬說明

類屬為設計實體與外界通訊的靜態資訊提供通道 ,用來規定埠的大小、實體中子元件的數目和實體的定時特性等。

格 式 :GENERIC(  常數名 :資料型別 :設定值;                      ∶                      常數名  :資料型別 :設定值 );

例 如:

GENERIC (wide :integer:=32); -- 說明寬度為32 GENERIC (tmp :integer:=1ns); -- 說明延時1 ns

  • 埠方向:IN, OUT ,INOUT ,BUFFER

OUT” 和“BUFFER”都可定義輸出埠;

注意:若實體內部需要反饋輸出訊號 ,則輸出埠必須被設定為為“BUFFER”,  而不能為能為“OUT”。

  •   同方向 、同類型的埠可放在同一個說明語句中。

1.2.結構體 (Architecture)

結構 體定義了設計單元具體的功能,描述了該基本設計單元的行為、 元件和內部的連線關係 .

定義方式:

ARCHITECTURE  結構體名 OF 實體名 IS [宣告語句]BEGIN 功能描述語句END [ 結構體名];

提示:

1.宣告語句的作用:用於宣告該結構體將用到的訊號 、資料型別 、常數、子程式和元件等 。 宣告的內容是區域性的。

2.功能描述語句:具體描述結構體的功能和行為。

  • 一 個實體可對應多個結構體 , 每個結構體代表該實體功能的不同實現方案或不同實現方式 。同一時刻只有一個結構體起作用,通過CONFIGURATION決定用哪個結構體進行模擬或綜合。
  • 在結構體描述中, 具體給出了輸入 、 輸出訊號之間的邏輯關係 。

1.3.庫、程式包的呼叫

方法:

LIBRARY 庫名; USE 庫名. 程式包名.專案名;

例子:

LIBRARY IEEE; USE IEEE.Std_Logic_1164.ALL;--呼叫此程式包的所有資源

其他例子:

LIBRARY IEEE; USE IEEE.Std_Logic_1164.ALL ; USE IEEE.Std_Logic_Arith.ALL ; USE IEEE.Std_Logic_Unsigned.ALL 

1.4.VHDL語句

1.4.1.並行語句

在結構體中的執行是同時進行, 執行順序與書寫順序無關。如下圖所示

  •  並行訊號賦值

  • 簡單賦值語句

目標訊號名 <=  表示式

注意:目標訊號的資料型別與右邊表示式一 致。

  • 選擇訊號賦值語句

WITH  選擇表示式 SELECT 賦值目標訊號  <=  表示式1 WHEN 選擇值 1,                                表示式2 WHEN 選擇值 1,                                表示式n WHEN OTHERS;

注意:

1.選擇值要覆蓋所有可能情況 , 若不能一一指定,用OTHERS為其他情況找個出口。

2.選擇值必須互斥 ,不能出現條件重複或重疊的情況。

例子:

實現一個4X1多路選擇器,當選擇訊號為00則輸出訊號為Data0的資料,選擇為01輸出Data1的訊號,依次類推:

程式如下:

library ieee;
use ieee.std_logic_1164.all;
entity mux is
port
(Data0,Data1,Data2,Data3:IN std_logic_Vector(7 downto 0);
 Sel : IN std_logic_vector(1 downto 0);
 Dout: out std_logic_vector(7 downto 0)
);
end;
architecture DataFolw of mux is
begin
	with Sel select
		Dout<= Data0 WHEN "00",
			   Data1 WHEN "01",
			   Data2 WHEN "10",
			   Data3 WHEN "11",
	"00000000" WHEN OTHERS;
end;

進行模擬測試:

  •  條件訊號賦值語句

賦值目標訊號  <=  表示式1 WHEN 賦值條件1 ELSE                               表示式2 WHEN 賦值條件2 ELSE                               表示式n WHEN 賦值條件n ELSE                               表示式;

注意:

1.各賦值語句有優先順序的差別 , 按書寫順序從高到低排列;

2.各賦值條件可以重疊。

例子:

實現8輸入優先編碼器:

程式如下:

library ieee;
use ieee.std_logic_1164.all;
entity Priority_Encoder is
port
(I : in std_logic_vector(7 downto 0);
 A : out std_logic_vector(2 downto 0)
);
end;
architecture DataFlow of priority_Encoder is
begin
	A<="111" WHEN I(7)='1' ElSE
	   "110" WHEN I(6)='1' ElSE
	   "101" WHEN I(5)='1' ElSE
	   "100" WHEN I(4)='1' ElSE
	   "011" WHEN I(3)='1' ElSE
	   "010" WHEN I(2)='1' ElSE
	   "001" WHEN I(1)='1' ElSE
	   "000" WHEN I(0)='1' ElSE
	   "111";
end;

進行模擬測試: 

1.4.2.程序語句

程序語句定義順序語句模組 ,用於將從外部獲得的訊號值 ,或內部的運算資料向其他的訊號進行賦值

  •  程序本身是並行語句, 但內部是順序語句 ;
  • 程序只有在特定的時刻 ( 敏感訊號發生變化) 才會被啟用。

語法:

[ 程序標號 :] ] PROCESS ( 敏感訊號引數表 ) [宣告區 ] ;       BEGIN             順序語句       END PROCESS [程序標號] ;

注意:

1.一 個程序可以有多個敏感訊號 , 任一 敏感訊號發生變化都會啟用程序。

2.宣告區的作用:在程序中起作用的區域性變數。

  • 程序的工作原理:

注意事項:

1.程序掛起:則執行過程終止。

2.當某個敏感訊號的值發生變化時,每個程序語句立即完成程序內順序語句所定義的功能行為。

3.順序語句所定義的功能行為的結果可以賦值給訊號,並通過訊號被其他簡稱讀取或賦值。

  • 程序與時鐘

在每個上升沿啟動一次程序( 執行程序內所有的語句 ) 。

描述方法:

上升沿描述: Clock’ EVENT AND Clock=‘1’ 下降沿描述: Clock’ EVENT AND Clock=‘0’ 上升沿描述: rising_edge (Clock) 下降沿描述: falling_edge (Clock)

例子1:

把clock設為敏感訊號,當clock上升沿時,輸出時鐘就進行取反一次。

程式如下:

library ieee;
use ieee.std_logic_1164.all;
entity FreDevider is
port
(Clock: in std_logic;
 Clkout:out std_logic
);
end;
architecture Behavior of FreDevider is
Signal Clk:std_logic;
begin
	process(Clock)
begin
		if rising_edge(Clock) THEN
			Clk<=NOT Clk;
		end if;
	end process;
Clkout<=Clk;
end;
	

模擬波形如下:

例子2:

本例子做一個自加器,沒遇到一個clock的上升沿,num就自加1,加到3就自動清零,重新開始,迴圈進行,還有一個復位按鈕,只要檢測是reset的值為1,num的數值就清零,重新開始計數。

程式碼如下:

library ieee;
use ieee.std_logic_1164.all;
entity Counter is
port
(reset: in std_logic;  --非同步時鐘復位訊號
 clock: in std_logic;  --時鐘訊號
 num  :buffer integer range 0 to 3); --設定一個整形變數,範圍從0到3
end;
architecture Behavior of Counter is
begin
	process(reset,clock)             --將復位,和時鐘作為程序的敏感訊號
		begin
		 if reset='1' THEN
			num<=0;                  --當檢測到reset=1時,num清零
		 elsif rising_edge(clock) THEN
			if num=3 THEN
				num<=0;              --如果num=3就,清零
			else 
				num<=num+1;          --否則自加1
			end if; 
		 end if;
	end process;
end;

模擬結果如下:

  • 程序的啟動

  • 當process的敏感訊號引數表中沒有列出任何敏感訊號時 ,程序通過wait 語句啟動 

例子:

ARCHITECTURE Behavior OF state IS BEGIN            PROCESS -- 敏感訊號列表為 空            BEGIN            wait until Clock; -- 等待clock啟用程序                  IF ( drive=‘1’) THEN                      CASE output IS                      WHEN s1 => output <= s2;                      WHEN s2 => output <= s3;                      WHEN s3 => output <= s4;                      WHEN s4 => output <= s1;                      END CASE;                  END IF;              END PROCESS; END;

  • 程序的注意事項

  1. 程序本身是並行語句, 但內部為順序語句 ;
  2. 程序在敏感訊號發生變化時被啟用 ,在使用了敏感表的程序中不能含wait 語句 ;
  3. 在同一程序中對同一訊號多次賦值 , 只有最後一次生 效 ;
  4. 在不同程序中,不可對同一訊號進行賦值;
  5. 一個程序不可同時對時鐘上 、下沿敏感 。
  6. 程序中的訊號賦值是在程序掛起時生效的,而變數賦值是即時生 效。
  7. 相對於結構體而言, 訊號具有全域性性 ,是程序間進行並行聯絡的重要途徑 。
  8. 程序為綜合器支援 ,且其建模方式直接影響模擬和綜合結果 ,綜合後對應於程序的硬體結構對程序中所有可讀入訊號都是敏感的。

1.5.元件例化語句

  • 元件例化引入一種連線關係 , 將預先設計好的實體定義為元件 , 並將此元件與當前設計實體中的埠相連線 , 從而為當前設計實體引入一個新的低一級的設計層次 。

舉例:把元件比喻成要插在電路系統板上的晶片,埠比喻成準備接受晶片的插座。

元件例化的方式:

元件定義語句: 

Component    元件名 port ( 埠名錶); End component   元件名;

元件例化語句:例化名 : 元件名 port map ( [元件埠名=>]連線埠名 , …);

注意:

1.port當中列出對外通訊的各埠名。

2.埠的關聯方式有兩種,第一:名字關聯法,port map的語句中位置可以隨意,第二:位置關聯法,埠名和關聯連線符號可以省去,連線埠名的排列方式與所需例化的元件埠定義的埠名順序相對應。

3.連線埠名:當前系統與準備接入的元件對應埠相連的通訊埠。

例子:

設計一個四輸入的與非門,如下圖所示:

此時我們需要設計一個2輸入的與非門,然後通過元件例化這個二輸入的與非門,實現四輸入與非門的功能。

  • 實現元件例化的詳細步驟

1.在電腦本地新建兩個資料夾,分別用於存放二輸入與非門的檔案,另一個是實現這個與非門例化實現功能的元件。

在我們電腦本地目錄下:D:\QuartusII_Test,新建兩個資料夾如下所示:

2.然後再QuartusII新建一個VHDL檔案,實現二輸入與非門的功能,具體程式碼如下:

library ieee;
use ieee.std_logic_1164.all;
entity nd2 is
port
(a,b :in std_logic;
 c   :out std_logic
);
end;
architecture nd2bhv of nd2 is
begin
	c<=a nand b;
end;

 3.然後儲存到D:\QuartusII_Test\nd2中,工程也要命名為:nd2

4.編輯成功後,新建一個模擬波形圖,如下功能模擬正確

5.新建一個工程,工程儲存到D:\QuartusII_Test\ord41 ,然後命名為ord41

6.新建一個VHDL檔案,使用二輸入與非門的元件例化,程式碼編輯如下:

library ieee;
use ieee.std_logic_1164.all;
entity ord41 is
port
(a1,b1,c1,d1 :in std_logic;
 z1   :out std_logic);
end ord41;
architecture ord41bhv of ord41 is
	component nd2
	port(a,b:in std_logic;
	     c  :out std_logic);
	end component;
	signal x,y:std_logic;
	begin
	u1:nd2 port map(a1,b1,x);
	u2:nd2 port map(a=>c1,c=>y,b=>d1);
	u3:nd2 port map(x,y,c=>z1);
end ord41bhv;

附錄:對上面例子的說明

7.儲存,檔名為ord41

8.這一步很重要,如果沒有這一步編譯將會報錯!!!

新增庫剛剛nd2的庫到這個工程。

點選assignment下拉選單中的settings選項,並選中user libraries選項,則下圖所示:

點選library name 後面的“” 按鈕,找到nd2資料夾,點選Add, 如下圖所示:

9.點選編譯按鈕,對ord41工程進行編譯,如果設定好第8步,而且語法沒有錯的話不會報錯。

10.編譯成功後,然後新建模擬圖進行模擬,模擬結果如下: