引自 EDN博客 博主jiangyi_love 的同名博文
最近在用VHDL設(shè)計簡易CPU,想用總線式的,這就要求端口模式必須是INOUT,之前沒接觸過。在網(wǎng)上搜到了博主jiangyi_love的一篇文章,轉(zhuǎn)載過來,我們大家共同學(xué)習(xí)。
在工程應(yīng)用中,雙向電路是設(shè)計者不得不面對的問題.在實際應(yīng)用中,數(shù)據(jù)總線往往是雙向的.如何正確處理數(shù)據(jù)總線是進(jìn)行時序邏輯電路設(shè)計的基礎(chǔ).在程序設(shè)計過程中,關(guān)鍵技術(shù)在于:實體部分必須對端口屬性進(jìn)行申明,端口屬性必須為inout類型,在構(gòu)造體需要對輸出信號進(jìn)行有條件的高阻控制.在雙向電路的處理問題上,常用的處理方式有兩種,在介紹雙向電路的處理方式之前,先看看雙向電路的基本格式:
ENTITY bidir_pin IS
(
bidir : INOUT std_logic;
oe, clk, from_core : IN std_logic;
to_core : OUT std_logic;
……
END bidir_pin;
ARCHITECTURE behavior OF bidir_pin IS
BEGIN
bidir <= from_core WHEN oe=‘1’ ELSE “ZZZZ”;
to_core <= bidir;
END behavior;
該程序揭示了雙向電路的處理技巧,首先在實體部分bidir屬于雙向信號,在端口定義時,端口屬性為inout類型,即把bidir信號作為輸入三態(tài)輸出. 語句“bidir <= from_core WHEN oe=‘1’ ELSE “ZZZZ”;”表示bidir信號三態(tài)輸出,語句”to_core <= bidir;”把bidir信號作為輸入信號.
由此可見,雙向電路在程序設(shè)計中,didir輸入當(dāng)著普通的in類型,而在輸出時,需要加一定的控制條件,三態(tài)輸出.問題的關(guān)鍵在于:如何確定這個條件?
1)雙向信號作一個信號的輸入,作另一信號的輸出
ENTITY bidir IS
PORT(
bidir : INOUT STD_LOGIC_VECTOR (7 DOWNTO 0);
oe, clk : IN STD_LOGIC;
from_core : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
to_core : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
);
END bidir;
ARCHITECTURE logic OF bidir IS
SIGNAL a : STD_LOGIC_VECTOR (7 DOWNTO 0);
SIGNAL b : STD_LOGIC_VECTOR (7 DOWNTO 0);
BEGIN
PROCESS (clk)
BEGIN
IF clk = '1' AND clk'EVENT THEN
a <= from_core;
to_core <= b;
END IF;
END PROCESS;
PROCESS (oe, bidir)
BEGIN
IF( oe = '0') THEN
bidir <= "ZZZZZZZZ";
b <= bidir;
ELSE
bidir <= a;
b <= bidir;
END IF;
END PROCESS;
END logic;
這種設(shè)計方式叫做寄存雙向信號的方法.本設(shè)計中bidir為雙向信號,from_core為數(shù)據(jù)輸入端,to_core為數(shù)據(jù)輸出端,oe為三態(tài)輸出使能,clk為讀寫數(shù)據(jù)的時鐘.在程序設(shè)計中,需要定義兩個signal a和b信號.a信號用于輸入數(shù)據(jù)from_core的寄存器,b用于輸出數(shù)據(jù)to_core的寄存器.采用寄存器的方法需要設(shè)計兩個進(jìn)程,一個進(jìn)程把a(bǔ),b信號在時鐘的控制下負(fù)責(zé)端口的輸入信號from_core和端口輸出信號to_core的連接,這一步實現(xiàn)了寄存雙向的功能.另外一個進(jìn)程則負(fù)責(zé)信號a,b和雙向口之間的賦值關(guān)系.本設(shè)計只揭示了簡單的雙向信號操作方式,即bidir既可以作為from_core的輸出,又可以作為to_core的輸入
2)雙向信號既做輸出又做輸出
上例是最簡單的雙向信號應(yīng)用的特例.在實際的工程中,雙向信號既做信號的輸入,又做信號的輸出,常見的數(shù)據(jù)總線就是這種操作模式.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
entity dir_data is
port(
clk : in STD_LOGIC;
rst : in STD_LOGIC;
rw : in STD_LOGIC;
address : in STD_LOGIC_VECTOR(1 downto 0);
data : inout STD_LOGIC_VECTOR(7 downto 0)
);
end dir_data;
architecture arc_dir of dir_data is
signal data_in : STD_LOGIC_VECTOR(7 downto 0);
signal data_out: STD_LOGIC_VECTOR(7 downto 0);
signal reg_a: STD_LOGIC_VECTOR(7 downto 0);
signal reg_b: STD_LOGIC_VECTOR(7 downto 0);
begin
data_in<=data;
d1:process(clk,rst,rw)
begin
if rst='1' then
reg_a<= (others=>'0');
reg_b<= (others=>'0');
elsif clk'event and clk='1' then
if rw='1' then
if address="00" then
reg_a<=data_in;
elsif address="01" then
reg_b<=data_in;
else null;
end if;
else null;
end if;
else null;
end if;
end process d1;
d2:process(clk,rw,reg_a,reg_b)
begin
if clk'event and clk='1' then
if rw='0' then
if address="00" then
data_out<=reg_a;
elsif address="01" then
data_out<=reg_b;
else null;
end if;
else null;
end if;
else null;
end if;
end process d2;
data<=data_out when (rw='0' and address(1)='0') else
(others=>'Z');
end arc_dir;
針對這個程序,我編了一個仿真波形,僅供參考!

在程序設(shè)計中,首先需要定義data_in, data_out, reg_a, reg_b四個signal,我們把data_in叫做輸入寄存器,它是從雙向信號data接收數(shù)據(jù)的寄存器,data_out叫做輸出寄存器,它是向雙向信號data發(fā)送信號的寄存器,reg_a和reg_b叫做操作寄存器,它們是在一定的時序控制下把data_in數(shù)據(jù)送給reg_a,reg_b,在一定的時序控制下從reg_a和reg_b讀出數(shù)據(jù)的.
這樣的處理方式必須有兩個進(jìn)程,因為在architecture arc_dir of dir_data is和begin之間定義了data_in, data_out, reg_a, reg_b四個signal,它在同一進(jìn)程內(nèi)不支持既賦值,又調(diào)用,也就是說它不支持在d1進(jìn)程中對信號reg_a, reg_b賦值,又在d1進(jìn)程中又調(diào)用reg_a, reg_b.首先有語句”data_in<=data;”它表示輸入寄存器無條件的接收雙先信號的數(shù)據(jù).在d1進(jìn)程中,首先在rst信號有效時,對操作寄存器reg_a,和reg_b進(jìn)行清零操作,然后在時鐘(clk)的控制下,在寫(rw)信號有效的情況下,對reg_a, reg_b寄存器在不同的地址控制下寫入不同的data_in值.在d2進(jìn)程中,在時鐘(clk)的控制下,在讀(rw)信號有效的時候,把不同地址的reg_a, reg_b的值送進(jìn)data_out中.最關(guān)鍵的是最后一句:“data<=data_out when (rw='0' and address(1)='0') else (others=>'Z');”它表示雙向信號的三態(tài)輸出,而最最關(guān)鍵的是when后面的條件,如果條件限制太寬,就會錯誤占用雙向信號總線,引起總線的誤操作,如果條件限制太窄,輸出寄存器的數(shù)據(jù)就不能夠正確的送到數(shù)據(jù)總線上去,會引起數(shù)據(jù)的丟失.也就是說,只有正確的限制了when語句后面的條件,才能夠把輸出寄存器的數(shù)據(jù)正確地送到數(shù)據(jù)總線上去.仔細(xì)查看此條件,有如下的規(guī)律:when語句后的條件是操作寄存器寫入輸出寄存器的條件的公共條件.如:rw=’0’是操作寄存器的數(shù)據(jù)寫入輸出寄存器的讀使能信號,address(1)是地址線的公共部分.
在實際工程應(yīng)用中,需要設(shè)計者在分配地址總線的時候掌握一定的技巧,盡量從地址的低位到到高位,保證地址總線有更多位的公共部分,比如只對四個寄存器操作時,地址線分配為”100”,”010”,”110”,”001”是不科學(xué)的,而”000”,”001”,”010”和”011”則是理想的.兩者不同的是前者地址線沒有公共部分,這樣的設(shè)計無法用when語句對條件進(jìn)行直接的控制,如果置之不理,由于列舉不全,在邏輯綜合時,電路會利用器件的乘積項和查找表的資源形成一個Latch, Latch不僅會把電路的時序變得復(fù)雜,而且電路存在潛在的危險性.雖然when語句后的條件不能夠?qū)l件進(jìn)行直接的控制,但是可以使用枚舉法一一把用到的地址線羅列出來,表示只有在這樣的地址線的情況下才會用到數(shù)據(jù)總線,否則其他狀態(tài)對數(shù)據(jù)總線送高阻,表示不占用數(shù)據(jù)總線.
總而言之,雙向信號是程序設(shè)計中尤其重要的基礎(chǔ),設(shè)計者在設(shè)計程序的時候,要尤其注意,何時會占用數(shù)據(jù)總線,何時不占用數(shù)據(jù)總線。