双方向バスは通常、トライステート バッファを使用して実装されます。inout
トライステート バッファ出力が "Z" の場合、ポートから読み取ることができます。バッファがラインを駆動している場合、出力として機能します。VHDL では、プリミティブ (IOBUF
ザイリンクス デバイスなど) を直接インスタンス化するか、上記のロジックを記述して合成ツールにトライステート バッファーを推論させることで、これを実装できます。
ここで扱っている信号は 3 つあります。
T
これはあなたのトライステートコントロールです。この信号は、ULPI のプロトコルを知っている同期ロジックから派生します。これは、バスが共有されているため、データを受信するタイミングとデータを送信するタイミングを知る方法が必要です。
I
これは、適切なクロックによって登録された後、バスを介して送信したい入力データです。
O
これは、登録/同期の前に、バスを介して受信している出力データです。
キー: トライステート バッファは同期ではありません。信号を適切に同期させるのは、トライステート バッファーの前後で行うことです。この場合、クロックの立ち上がりエッジでトライステート バッファー (送信される) への入力を同期し、クロックの立ち下がりエッジでトライステート バッファー/IOBUF から受信したレジスタ データを同期する必要があります。
サンプル デザイン。
library ieee;
use ieee.std_logic_1164.all;
library unisim; -- for xilinx IOBUF
use unisim.vcomponents.all;
entity iobuffer_example is
port (
I_CLK : in std_logic; -- synchronized with bidir bus
IO_DATA : inout std_logic; -- data to/from external pin on bidir bus
I_DIR_CTRL : in std_logic; -- from other VHDL logic, controlling bidir bus direction
O_DATA_FROM_EXTERNAL : out std_logic; -- data received over bidir bus
I_DATA_TO_EXTERNAL : in std_logic); -- data to send over bidir bus
end entity iobuffer_example;
architecture io_buffer_arch of iobuffer_example is
signal data_in : std_logic;
signal data_out : std_logic;
begin
IOBUF_Inst : IOBUF
port map (
O => data_in, -- data from bidir bus
IO => IO_DATA, -- data on bidir bus
I => data_out, -- data to bidir bus
T => I_DIR_CTRL); -- 3-state enable input, high=input, low=output
Register_Input : process (I_CLK) is
begin
if (falling_edge(I_CLK)) then
O_DATA_FROM_EXTERNAL <= data_in;
end if;
end process Register_Input;
Register_Output : process (I_CLK) is
begin
if (rising_edge(I_CLK)) then
data_out <= I_DATA_TO_EXTERNAL;
end if;
end process Register_Output;
end architecture io_buffer_arch;
ノート。
クロス クロック ドメインの交差に注意してください。ここでは、特に内部ロジックがバス クロックとは異なるクロックで駆動されている場合に、バスから出入りするデータが交差する可能性が多数あります。詳細が分からないと何とも言えません。
トライステート バッファーの動作表現を合成ツールで推論したい場合は、unisim ライブラリと を使用する代わりに、次のようなことを行うことができますIOBUF
。
PROCESS (I_DIR_CTRL, IO_DATA)
BEGIN
IF( I_DIR_CTRL = '1') THEN
IO_DATA <= 'Z';
ELSE
IO_DATA <= data_out;
END IF;
data_in <= IO_DATA;
END PROCESS;