1 概述
HDL(VHSIC Hardware Description Language)是一種硬件描述語言,主要用于描述數字電路和系統的結構、行為和功能。它是一種用于硬件設計的標準化語言,能夠幫助工程師們更好地描述和設計數字電路,并且廣泛應用于FPGA和ASIC設計中。
在VHDL中,一個設計被描述為一個實體(entity),它包含了輸入輸出端口的描述。實體也包含了該設計的行為(behavior)的描述。 此外,VHDL還包括了標準庫(standard library)和數學運算庫(numeric package)等。
VHDL的基本語法包括關鍵字、標識符、注釋、數據類型(如std_logic、integer等)、變量聲明、信號聲明、過程語句、并行操作符等。
以下是VHDL的一些基本特性和語法:
實體聲明(Entity Declaration):實體(entity)是一個設計的接口和規范,描述了設計的輸入和輸出信號。在實體聲明中,可以指定設計的接口和端口類型。
架構(Architecture):架構是實體的行為和功能描述。它包括了組件實例化、信號聲明、過程語句等。在架構中,可以描述設計的邏輯和數據流動。
信號(Signal)和變量(Variable):在VHDL中,信號用于描述設計中的數據傳輸,而變量通常用于描述局部的數據存儲。信號和變量的作用在于描述設計中的數據流動和數據處理。
過程(Process):過程描述了設計中的行為和邏輯。過程可以包括對信號和變量的操作、時序邏輯的描述等。
循環(Loop):VHDL中也包括了循環語句,用于描述設計中的重復操作。
總的來說,VHDL是一門強大的硬件描述語言,能夠幫助工程師們進行數字電路的設計和描述。通過VHDL,工程師們可以更好地理解和描述設計的結構和行為,從而實現復雜的數字系統設計。雖然VHDL的語法可能對初學者來說有一定的復雜性,但一旦熟悉了其基本特性和語法,將會成為非常有用的工具。
library IEEE; use IEEE.std_logic_1164.all; entity ExampleModule is port( clk, reset : in std_logic; input1, input2 : in std_logic_vector(7 downto 0); output1 : out std_logic_vector(7 downto 0) ); end ExampleModule; architecture Behavioral of ExampleModule is component SubModule is port( a, b : in std_logic_vector(7 downto 0); c : out std_logic_vector(7 downto 0) ); end component; signal intermediate : std_logic_vector(7 downto 0); begin SubModule_inst : SubModule port map( a => input1, b => input2, c => intermediate ); process(clk, reset) begin if reset = '1' then output1 <= (others => '0'); elsif rising_edge(clk) then output1 <= intermediate; end if; end process; end Behavioral;
?
?
2 樣例
按鍵消抖
設計文件:
?
?
library ieee; use ieee.std_logic_1164.all; use IEEE.NUMERIC_STD.ALL; entity debouncing is generic(N: integer := 10); port(clk: in std_logic; rst: in std_logic; u: in std_logic; delay : in std_logic_vector(N-1 downto 0); y: out std_logic); end debouncing; architecture arch of debouncing is type state_type is (zero, wait0, wait1, one); signal state, state_n: state_type; signal cnt, cnt_n: unsigned(N-1 downto 0); begin -- state register process(clk,rst) begin if (rst='1') then state <= zero; cnt <= (others => '0'); elsif (rising_edge(clk)) then state <= state_n; cnt <= cnt_n; end if; end process; -- next-state/output logic process(state,u,cnt,delay) begin state_n <= state; cnt_n <= (others => '0'); case state is when zero => y <= '0'; if u= '1' then state_n <= wait0; end if; when wait0 => y <= '0'; -- check next state if u = '0' then state_n <= zero; elsif cnt = unsigned(delay) then state_n <= one; end if; -- increment counter cnt_n <= cnt + 1; when wait1 => y <= '1'; -- check next state if u = '1' then state_n <= one; elsif cnt = unsigned(delay) then state_n <= zero; end if; -- increment counter cnt_n <= cnt + 1; when one => y <= '1'; if u= '0' then state_n <= wait1; end if; end case; end process; end arch;
?
?
按鍵消抖仿真文件:
?
?
ibrary ieee; use ieee.std_logic_1164.all; use IEEE.NUMERIC_STD.ALL; entity debouncing_tb is end debouncing_tb; architecture tb of debouncing_tb is constant N: integer := 8; signal delay: std_logic_vector(N-1 downto 0); signal u, y,z : std_logic; signal clk, rst : std_logic; -- Clock period definitions constant Ts : time := 10 ns; begin db0 : entity work.debouncing generic map(N => N) port map (clk => clk, rst => rst, delay => delay, u => u, y => y); -- Clock process definitions process begin clk <= '0'; wait for Ts/2; clk <= '1'; wait for Ts/2; end process; stimuli : process begin rst <= '1'; u <= '0'; delay <= (others => '0'); wait for 5*Ts; rst <= '0'; delay <= std_logic_vector(to_unsigned(20,N)); u <= '1'; wait for 3*Ts; u <= '0'; wait for 5*Ts; u <= '1'; wait for 10*Ts; u <= '0'; wait for 3*Ts; u <= '1'; wait for 25*Ts; u <= '0'; wait for 2*Ts; u <= '1'; wait for 5*Ts; u <= '0'; wait for 25*Ts; wait; end process; end tb;
?
?
?
3 常用編寫
時序邏輯:
在 VHDL 中,時序邏輯指的是描述在特定時鐘信號的邊沿或狀態變化下發生的操作。時序邏輯可以包括使用 rising_edge 或 falling_edge 函數來檢測時鐘信號的上升沿或下降沿,以及使用 wait for 語句來控制時序行為。下面是一個簡單的示例,說明了時序邏輯的基本用法:
?
?
architecture Behavioral of ExampleModule is begin process (clk) begin if rising_edge(clk) then -- 在時鐘上升沿執行的操作 -- 例如,更新寄存器、執行狀態轉移等 end if; end process; end architecture Behavioral;
?
?
在這個例子中,我們定義了一個處理時鐘信號 clk 的過程。使用 if rising_edge(clk) then 表示當檢測到時鐘信號的上升沿時執行操作。在這個邏輯塊中,你可以更新寄存器、執行狀態轉移等與時鐘相關的操作。這種時序邏輯的描述允許你根據特定時鐘信號的變化來控制設計的行為。
時序邏輯在數字電路設計中非常重要,因為它能夠確保設計在特定時鐘信號的控制和同步下正確運行。通過使用時序邏輯,可以將設計的行為明確地與時鐘信號進行關聯,從而實現可靠的同步邏輯。
VHDL組合邏輯:
在 VHDL 中,組合邏輯是指在不涉及時鐘信號的條件下,根據輸入直接計算輸出的邏輯部分。通常,組合邏輯描述了在給定輸入條件下的輸出行為,而且輸出立即對輸入進行響應,不依賴于時鐘的邊沿。以下是一個簡單的示例,說明了組合邏輯的基本用法:
?
?
-- 一個簡單的 2:1 多路選擇器的組合邏輯 entity Mux2x1 is port ( sel: in std_logic; a, b: in std_logic; y: out std_logic ); end entity Mux2x1; architecture Behavioral of Mux2x1 is begin process (sel, a, b) begin if sel = '0' then y <= a; else y <= b; end if; end process; end architecture Behavioral;
?
?
在這個例子中,我們創建了一個名為 Mux2x1 的實體,該實體具有三個輸入端口 sel、a 和 b 以及一個輸出端口 y。在 Behavioral 架構中的處理過程中,我們使用 if 語句來根據輸入信號 sel 的值選擇輸出的值。這是一個典型的組合邏輯,因為輸出 y 的值是僅僅依賴于當前輸入信號的狀態而計算出來的,不涉及時鐘或者時序控制。
組合邏輯在數字電路設計中很常見,它描述了電路在給定輸入下的輸出行為,沒有涉及時鐘控制或時序邏輯。
case語句:
當需要根據輸入的不同值采取不同的操作時,可以使用VHDL中的case語句。下面是一個簡單的VHDL case語句的示例:
?
?
process (input) begin case input is when "00" => -- 對輸入為 "00" 執行的操作 output <= "0000"; when "01" => -- 對輸入為 "01" 執行的操作 output <= "0011"; when "10" => -- 對輸入為 "10" 執行的操作 output <= "1100"; when others => -- 對其他輸入情況下執行的操作 output <= "1111"; end case; end process;
?
?
在這個例子中,我們在一個process中使用了case語句來根據輸入的不同情況執行相應的操作。當輸入信號input的值滿足某個條件時,對應的輸出output會被賦予相應的值。 “when others” 表示當輸入值不滿足前面列舉的情況時執行的操作。
這個例子展示了VHDL中使用case語句進行條件判斷和執行不同操作的方法。
狀態機:
在 VHDL 中實現狀態機(state machine)通常是通過組合邏輯和時序邏輯相結合的方式來完成的。狀態機描述了一個系統在不同狀態下的行為,通常會隨著輸入信號的變化而轉換狀態。下面是一個簡單的示例,說明了一個基本的有限狀態機在 VHDL 中的實現:
?
?
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity SimpleFSM is Port ( clk : in STD_LOGIC; reset : in STD_LOGIC; input : in STD_LOGIC; output : out STD_LOGIC); end SimpleFSM; architecture Behavioral of SimpleFSM is type state_type is (s0, s1, s2, s3); signal state, next_state : state_type; begin process (clk, reset) begin if reset = '1' then state <= s0; -- 在復位時將狀態設置為初始狀態 elsif rising_edge(clk) then state <= next_state; -- 在時鐘的上升沿根據下一個狀態進行狀態更新 end if; end process; process (state, input) begin case state is when s0 => if input = '1' then next_state <= s1; -- 根據輸入信號轉移至下一個狀態 else next_state <= s0; -- 如果輸入信號不滿足條件,保持在當前狀態 end if; when s1 => if input = '0' then next_state <= s2; else next_state <= s1; end if; when s2 => if input = '1' then next_state <= s3; else next_state <= s2; end if; when s3 => next_state <= s0; when others => next_state <= s0; end case; end process; end Behavioral;
?
?
在這個例子中,我們創建了一個名為 SimpleFSM 的實體,該實體包括了時鐘信號 clk、復位信號 reset、輸入信號 input 和輸出信號 output。狀態機的行為由 state 和 next_state 信號來描述。在第一個 process 中,我們根據時鐘信號和復位信號來更新 state 的值,以此來控制狀態的轉移。在第二個 process 中,我們根據當前的狀態和輸入信號來計算下一個狀態 next_state。這個狀態機描述了一個簡單的輸入序列檢測過程,根據輸入序列的不同,狀態機將在不同的狀態間轉移。這是一個基本的有限狀態機的例子,通過狀態的轉移來實現不同的行為。
時鐘信號編寫:
a)占空比為50%
?
?
constant PERIOD : time :=; --定義時鐘周期 --使用after語句 CLK <= not CLK after PERIOD/2; --使用wait語句 constant PERIOD : time := ; CLK <= '0'; wait for PERIOD/2; CLK <= '1'; wait for PERIOD/2;
?
?
b)非50%占空比
?
?
constant DUTY_CYCLE : real :=; --定義占空比系數 constant PERIOD : time := ; --定義時鐘周期 --使用after語句 CLK <= '1' after (PERIOD - (PERIOD * DUTY_CYCLE)) when CLK = '0' else '0' after (PERIOD * DUTY_CYCLE); --使用wait語句 CLK <= '0'; wait for (PERIOD - (PERIOD * DUTY_CYCLE)); CLK <= '1'; wait for (PERIOD * DUTY_CYCLE);
?
?
c)差分端口占空比為50%
?
?
constant PERIOD : time :=; --設置時鐘周期 --使用after語句 CLK_P <= not CLK_P after PERIOD/2; CLK_N <= not CLK_N after PERIOD/2; --使用wait語句 CLK_P <= '0'; CLK_N <= '1'; wait for PERIOD/2; CLK_P <= '1'; CLK_N <= '0'; wait for PERIOD/2;
?
?
延時:
?
?
constant SIM_TIME : time := 10 ms; --設置仿真時間SIM_TIME, 時間為10ms<= after SIM_TIME; --信號在SIM_TIME后進行賦值 wait on ; --延時到信號有變化 wait until falling_edge( ); --延時到信號的下降沿到來 wait until rising_edge( ); --延時到信號的上升沿到來 wait until = ; --延時到信號變化到指定值
?
?
循環:
a) loop語句
?
?
loop CLK <= not CLK; wait for PERIOD/2; ifthen exit; end if; end loop;
?
?
b) for語句
?
?
forin to loop ; ; end loop;
?
?
c)while語句
?
?
whileloop ; ; end loop;
?
?
審核編輯:黃飛
?
評論
查看更多