目次
前
次
Hand shaking
CPLD/FPGA内の回路は、それぞれ独立に動作することが
可能です。2、3の回路を同期させて動かす場合には
同期回路をはさみますが、回路に主従関係がある場合
や一方から他方へのデータ転送でよい場合に、同期の
ための回路を挟み込むのは、大掛かりすぎます。
同期回路を使わないで、2ブロック間でデータ転送する
ために、Hand shakingを利用します。
2ブロック間で同期をとるためには、データバスに加えて
request、acknowlegeの2信号を用意して対応します。
2信号request、acknowlegeを利用して、Hand shakingを
実現します。タイミングチャートでみると、次のように
なります。
シーケンスは、次のように遷移します。
- a データ要求
- b データ出力
- c データ確定を通知
- d データ確定検出
- e データ入力
- f データ取得通知 データ取得確認
- g データ出力終了
Hand shakingには、双方のブロックにシーケンサ(ステートマシン)を
用意すれば、実現できます。
次の仕様で、Hand shakingを記述してみます。
ブロックAは、4ビットのデータを自分のタイミングで入力
ブロックBは、ブロックAのデータを要求し取得
ブロックAのシーケンサは、次のコードで実現。
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSTATEA <= "00" ;
elsif rising_edge(iCLK) then
case conv_integer(iSTATEA) is
-- wait request
when 0 => if ( iBREQ = '1' ) then
iSTATEA <= "01" ;
else
iSTATEA <= "00" ;
end if ;
-- send data to buffer and send acknowledge
when 1 => iREG <= iREGA ;
iSTATEA <= "11" ;
-- return first state
when 3 => if ( iBACK = '1' ) then
iSTATEA <= "10" ;
else
iSTATEA <= "11" ;
end if ;
-- return first state
when 2 => iSTATEA <= "00" ;
-- default
when others =>
iSTATEA <= "00" ;
end case ;
end if ;
end process ;
iAACK <= iSTATEA(0) ;
ブロックBからのrequestを見て、データを出力し
acknowlegeを返します。
ブロックBのシーケンサは、以下としました。
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSTATEB <= "000" ;
iREGB <= "0000" ;
elsif rising_edge(iCLK) then
case conv_integer(iSTATEB) is
-- wait trigger
when 0 => if ( iBREQX = '1' ) then
iSTATEB <= "001" ;
else
iSTATEB <= "000" ;
end if ;
-- *** send request to target ***
when 1 => iSTATEB <= "011" ;
-- *** wait target acknowledge ***
when 3 => if ( iAACK = '1' ) then
iSTATEB <= "111" ;
else
iSTATEB <= "011" ;
end if ;
-- *** get data ***
when 7 => iSTATEB <= "110" ;
iREGB <= iREG ;
-- send myself acknowledge
when 6 => iSTATEB <= "100" ;
-- return first state
when 4 => if ( iAACK = '0' and iBACKX = '1' ) then
iSTATEB <= "000" ;
else
iSTATEB <= "100" ;
end if ;
-- default
when others =>
iSTATEB <= "000" ;
end case ;
end if ;
end process ;
iBREQ <= '1' when ( iSTATEB = "001" or iSTATEB = "011" ) else '0' ;
iBACK <= '1' when ( iSTATEB = "110" or iSTATEB = "100" ) else '0' ;
ブロックBは外部から制御したいので、そのための信号を
入力し、ブロックAからのデータ取得を実現しています。
ブロックAは、自分のタイミングでデータを取得
すればよいので、単純なデータ格納をさせます。
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iREGA <= "0000" ;
elsif rising_edge(iCLK) then
iREGA <= ADin ;
end if ;
end process ;
ブロックAのシーケンサと内部データバスの状態を
外部で確認できるようにし、VHDLコードにします。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity tstcom is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ; -- 4MHz
-- object A
ADin : in std_logic_vector(3 downto 0) ;
-- object A monitor
AMON : out std_logic_vector(1 downto 0) ;
-- object B
BREQ : in std_logic ;
BACK : in std_logic ;
BREQM : out std_logic ;
BACKM : out std_logic ;
BDout : out std_logic_vector(3 downto 0) ;
-- monitor output
LOUT : out std_logic_vector(3 downto 0) ;
MOUT : out std_logic -- ;
);
end tstcom ;
architecture behavioral of tstcom is
--
CONSTANT CNTMAX : integer := 39_999 ;
CONSTANT CNTHALF : integer := 20_000 ;
-- clock divider
signal iCNT : integer range 0 to CNTMAX ;
signal iCLK : std_logic ;
-- object A
signal iREGA : std_logic_vector(3 downto 0) ;
signal iSTATEA : std_logic_vector(1 downto 0) ;
signal iAACK : std_logic ;
-- internal bus
signal iREG : std_logic_vector(3 downto 0) ;
-- object B
signal iREGB : std_logic_vector(3 downto 0) ;
signal iSTATEB : std_logic_vector(2 downto 0) ;
signal iBREQ : std_logic ;
signal iBACK : std_logic ;
signal iBREQ_SFT : std_logic_vector(2 downto 0) ;
signal iBREQX : std_logic ;
signal iBACK_SFT : std_logic_vector(2 downto 0) ;
signal iBACKX : std_logic ;
begin
-- output
AMON <= not iSTATEA ;
BDout <= not iREGB ;
MOUT <= iCLK ;
LOUT <= not iREG ;
BREQM <= not iBREQ ;
BACKM <= not iBACK ;
-- clock divider
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCNT <= 0 ;
elsif rising_edge(CLOCK) then
if ( iCNT = CNTMAX ) then
iCNT <= 0 ;
else
iCNT <= iCNT + 1 ;
end if ;
end if ;
end process ;
iCLK <= '1' when ( iCNT < CNTHALF ) else '0' ;
-- object A handling (simple latch)
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iREGA <= "0000" ;
elsif rising_edge(iCLK) then
iREGA <= ADin ;
end if ;
end process ;
-- object A handshake
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSTATEA <= "00" ;
elsif rising_edge(iCLK) then
case conv_integer(iSTATEA) is
-- wait request
when 0 => if ( iBREQ = '1' ) then
iSTATEA <= "01" ;
else
iSTATEA <= "00" ;
end if ;
-- send data to buffer and send acknowledge
when 1 => iREG <= iREGA ;
iSTATEA <= "11" ;
-- return first state
when 3 => if ( iBACK = '1' ) then
iSTATEA <= "10" ;
else
iSTATEA <= "11" ;
end if ;
-- return first state
when 2 => iSTATEA <= "00" ;
-- default
when others =>
iSTATEA <= "00" ;
end case ;
end if ;
end process ;
iAACK <= iSTATEA(0) ;
-- object B handling
process (nRESET,iCLK)
begin
if ( nRESET = '0' ) then
iSTATEB <= "000" ;
iREGB <= "0000" ;
elsif rising_edge(iCLK) then
case conv_integer(iSTATEB) is
-- wait trigger
when 0 => if ( iBREQX = '1' ) then
iSTATEB <= "001" ;
else
iSTATEB <= "000" ;
end if ;
-- *** send request to target ***
when 1 => iSTATEB <= "011" ;
-- *** wait target acknowledge ***
when 3 => if ( iAACK = '1' ) then
iSTATEB <= "111" ;
else
iSTATEB <= "011" ;
end if ;
-- *** get data ***
when 7 => iSTATEB <= "110" ;
iREGB <= iREG ;
-- send myself acknowledge
when 6 => iSTATEB <= "100" ;
-- return first state
when 4 => if ( iAACK = '0' and iBACKX = '1' ) then
iSTATEB <= "000" ;
else
iSTATEB <= "100" ;
end if ;
-- default
when others =>
iSTATEB <= "000" ;
end case ;
end if ;
end process ;
iBREQ <= '1' when ( iSTATEB = "001" or iSTATEB = "011" ) else '0' ;
iBACK <= '1' when ( iSTATEB = "110" or iSTATEB = "100" ) else '0' ;
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iBREQ_SFT <= "000" ;
iBACK_SFT <= "000" ;
elsif rising_edge(CLOCK) then
iBREQ_SFT <= iBREQ_SFT(1 downto 0) & BREQ ;
iBACK_SFT <= iBACK_SFT(1 downto 0) & BACK ;
end if ;
end process ;
iBREQX <= '1' when ( iBREQ_SFT = "011" ) else '0' ;
iBACKX <= '1' when ( iBACK_SFT = "011" ) else '0' ;
end behavioral;
XilinxのXC9572を利用してみました。
UCFファイルは、以下。
# system
NET "CLOCK" LOC = "P5" ;
NET "nRESET" LOC = "P39" ;
# object A input
NET "ADin<0>" LOC = "P1" ;
NET "ADin<1>" LOC = "P2" ;
NET "ADin<2>" LOC = "P3" ;
NET "ADin<3>" LOC = "P4" ;
NET "BREQ" LOC = "P6" ;
NET "BACK" LOC = "P7" ;
# input
NET "Lout<0>" LOC = "P11" ;
NET "Lout<1>" LOC = "P12" ;
NET "Lout<2>" LOC = "P13" ;
NET "Lout<3>" LOC = "P14" ;
NET "BDout<0>" LOC = "P18" ;
NET "BDout<1>" LOC = "P19" ;
NET "BDout<2>" LOC = "P20" ;
NET "BDout<3>" LOC = "P22" ;
# monitor
NET "AMON<0>" LOC = "P24" ;
NET "AMON<1>" LOC = "P25" ;
NET "BREQM" LOC = "P26" ;
NET "BACKM" LOC = "P27" ;
NET "MOUT" LOC = "P28" ;
目次
前
次