目次

Hand shaking

 CPLD/FPGA内の回路は、それぞれ独立に動作することが
 可能です。2、3の回路を同期させて動かす場合には
 同期回路をはさみますが、回路に主従関係がある場合
 や一方から他方へのデータ転送でよい場合に、同期の
 ための回路を挟み込むのは、大掛かりすぎます。

 同期回路を使わないで、2ブロック間でデータ転送する
 ために、Hand shakingを利用します。

 2ブロック間で同期をとるためには、データバスに加えて
 request、acknowlegeの2信号を用意して対応します。



 2信号request、acknowlegeを利用して、Hand shakingを
 実現します。タイミングチャートでみると、次のように
 なります。



 シーケンスは、次のように遷移します。

 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" ;


目次

inserted by FC2 system