?1 概述
HDL(VHSIC Hardware Description Language)是一種硬件描述語言,主要用于描述數(shù)字電路和系統(tǒng)的結(jié)構(gòu)、行為和功能。它是一種用于硬件設(shè)計的標準化語言,能夠幫助工程師們更好地描述和設(shè)計數(shù)字電路,并且廣泛應用于FPGA和ASIC設(shè)計中。
在VHDL中,一個設(shè)計被描述為一個實體(entity),它包含了輸入輸出端口的描述。實體也包含了該設(shè)計的行為(behavior)的描述。 此外,VHDL還包括了標準庫(standard library)和數(shù)學運算庫(numeric package)等。
VHDL的基本語法包括關(guān)鍵字、標識符、注釋、數(shù)據(jù)類型(如std_logic、integer等)、變量聲明、信號聲明、過程語句、并行操作符等。
以下是VHDL的一些基本特性和語法:
實體聲明(Entity Declaration):實體(entity)是一個設(shè)計的接口和規(guī)范,描述了設(shè)計的輸入和輸出信號。在實體聲明中,可以指定設(shè)計的接口和端口類型。
架構(gòu)(Architecture):架構(gòu)是實體的行為和功能描述。它包括了組件實例化、信號聲明、過程語句等。在架構(gòu)中,可以描述設(shè)計的邏輯和數(shù)據(jù)流動。
信號(Signal)和變量(Variable):在VHDL中,信號用于描述設(shè)計中的數(shù)據(jù)傳輸,而變量通常用于描述局部的數(shù)據(jù)存儲。信號和變量的作用在于描述設(shè)計中的數(shù)據(jù)流動和數(shù)據(jù)處理。
過程(Process):過程描述了設(shè)計中的行為和邏輯。過程可以包括對信號和變量的操作、時序邏輯的描述等。
循環(huán)(Loop):VHDL中也包括了循環(huán)語句,用于描述設(shè)計中的重復操作。
總的來說,VHDL是一門強大的硬件描述語言,能夠幫助工程師們進行數(shù)字電路的設(shè)計和描述。通過VHDL,工程師們可以更好地理解和描述設(shè)計的結(jié)構(gòu)和行為,從而實現(xiàn)復雜的數(shù)字系統(tǒng)設(shè)計。雖然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 樣例
按鍵消抖
設(shè)計文件:
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 中,時序邏輯指的是描述在特定時鐘信號的邊沿或狀態(tài)變化下發(fā)生的操作。時序邏輯可以包括使用 rising_edge 或 falling_edge 函數(shù)來檢測時鐘信號的上升沿或下降沿,以及使用 wait for 語句來控制時序行為。下面是一個簡單的示例,說明了時序邏輯的基本用法:
architecture Behavioral of ExampleModule is
begin
process (clk)
begin
if rising_edge(clk) then
-- 在時鐘上升沿執(zhí)行的操作
-- 例如,更新寄存器、執(zhí)行狀態(tài)轉(zhuǎn)移等
end if;
end process;
end architecture Behavioral;
在這個例子中,我們定義了一個處理時鐘信號 clk 的過程。使用 if rising_edge(clk) then 表示當檢測到時鐘信號的上升沿時執(zhí)行操作。在這個邏輯塊中,你可以更新寄存器、執(zhí)行狀態(tài)轉(zhuǎn)移等與時鐘相關(guān)的操作。這種時序邏輯的描述允許你根據(jù)特定時鐘信號的變化來控制設(shè)計的行為。
時序邏輯在數(shù)字電路設(shè)計中非常重要,因為它能夠確保設(shè)計在特定時鐘信號的控制和同步下正確運行。通過使用時序邏輯,可以將設(shè)計的行為明確地與時鐘信號進行關(guān)聯(lián),從而實現(xiàn)可靠的同步邏輯。
VHDL組合邏輯:
在 VHDL 中,組合邏輯是指在不涉及時鐘信號的條件下,根據(jù)輸入直接計算輸出的邏輯部分。通常,組合邏輯描述了在給定輸入條件下的輸出行為,而且輸出立即對輸入進行響應,不依賴于時鐘的邊沿。以下是一個簡單的示例,說明了組合邏輯的基本用法:
-- 一個簡單的 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;
在這個例子中,我們創(chuàng)建了一個名為 Mux2x1 的實體,該實體具有三個輸入端口 sel、a 和 b 以及一個輸出端口 y。在 Behavioral 架構(gòu)中的處理過程中,我們使用 if 語句來根據(jù)輸入信號 sel 的值選擇輸出的值。這是一個典型的組合邏輯,因為輸出 y 的值是僅僅依賴于當前輸入信號的狀態(tài)而計算出來的,不涉及時鐘或者時序控制。
組合邏輯在數(shù)字電路設(shè)計中很常見,它描述了電路在給定輸入下的輸出行為,沒有涉及時鐘控制或時序邏輯。
case語句:
當需要根據(jù)輸入的不同值采取不同的操作時,可以使用VHDL中的case語句。下面是一個簡單的VHDL case語句的示例:
process (input)
begin
case input is
when "00" =>
-- 對輸入為 "00" 執(zhí)行的操作
output <= "0000";
when "01" =>
-- 對輸入為 "01" 執(zhí)行的操作
output <= "0011";
when "10" =>
-- 對輸入為 "10" 執(zhí)行的操作
output <= "1100";
when others =>
-- 對其他輸入情況下執(zhí)行的操作
output <= "1111";
end case;
end process;
在這個例子中,我們在一個process中使用了case語句來根據(jù)輸入的不同情況執(zhí)行相應的操作。當輸入信號input的值滿足某個條件時,對應的輸出output會被賦予相應的值。 “when others” 表示當輸入值不滿足前面列舉的情況時執(zhí)行的操作。
這個例子展示了VHDL中使用case語句進行條件判斷和執(zhí)行不同操作的方法。
在 VHDL 中實現(xiàn)狀態(tài)機(state machine)通常是通過組合邏輯和時序邏輯相結(jié)合的方式來完成的。狀態(tài)機描述了一個系統(tǒng)在不同狀態(tài)下的行為,通常會隨著輸入信號的變化而轉(zhuǎn)換狀態(tài)。下面是一個簡單的示例,說明了一個基本的有限狀態(tài)機在 VHDL 中的實現(xiàn):
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; -- 在復位時將狀態(tài)設(shè)置為初始狀態(tài)
elsif rising_edge(clk) then
state <= next_state; -- 在時鐘的上升沿根據(jù)下一個狀態(tài)進行狀態(tài)更新
end if;
end process;
process (state, input)
begin
case state is
when s0 =>
if input = '1' then
next_state <= s1; -- 根據(jù)輸入信號轉(zhuǎn)移至下一個狀態(tài)
else
next_state <= s0; -- 如果輸入信號不滿足條件,保持在當前狀態(tài)
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;
在這個例子中,我們創(chuàng)建了一個名為 SimpleFSM 的實體,該實體包括了時鐘信號 clk、復位信號 reset、輸入信號 input 和輸出信號 output。狀態(tài)機的行為由 state 和 next_state 信號來描述。在第一個 process 中,我們根據(jù)時鐘信號和復位信號來更新 state 的值,以此來控制狀態(tài)的轉(zhuǎn)移。在第二個 process 中,我們根據(jù)當前的狀態(tài)和輸入信號來計算下一個狀態(tài) next_state。這個狀態(tài)機描述了一個簡單的輸入序列檢測過程,根據(jù)輸入序列的不同,狀態(tài)機將在不同的狀態(tài)間轉(zhuǎn)移。這是一個基本的有限狀態(tài)機的例子,通過狀態(tài)的轉(zhuǎn)移來實現(xiàn)不同的行為。
時鐘信號編寫:
a)占空比為50%
constant PERIOD : time := <value>; --定義時鐘周期
--使用after語句
CLK <= not CLK after PERIOD/2;
--使用wait語句
constant PERIOD : time := <value>;
CLK <= '0';
wait for PERIOD/2;
CLK <= '1';
wait for PERIOD/2;
b)非50%占空比
constant DUTY_CYCLE : real := <value_0.01_to_0.99>; --定義占空比系數(shù)
constant PERIOD : time := <value>; --定義時鐘周期
--使用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 := <value>; --設(shè)置時鐘周期
--使用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; --設(shè)置仿真時間SIM_TIME, 時間為10ms
<signal_name> <= <signal_value> after SIM_TIME; --信號在SIM_TIME后進行賦值
wait on <signal_name>; --延時到信號有變化
wait until falling_edge(<signal_name>); --延時到信號的下降沿到來
wait until rising_edge(<signal_name>); --延時到信號的上升沿到來
wait until <signal_name> = <value>; --延時到信號變化到指定值
循環(huán):
a) loop語句
loop
CLK <= not CLK;
wait for PERIOD/2;
if <signal_name = <value> then
exit;
end if;
end loop;
b) for語句
for <variable_name> in <lower_limit> to <upper_limit> loop
<statement>;
<statement>;
end loop;
c)while語句
while <condition> loop
<statement>;
<statement>;
end loop;