UART 高レベル通信モジュール(IP)

プロジェクトファイル: UART_HL.tar.gz (60MB程度)


前回までのUARTモジュールは1バイト毎のデータ通信しかできないため,高度な通信には使いづらい.
そこで,今回は,前回のモジュールの上位モジュールを作り,高度なデータ通信ができるように改良する.
動作のイメージ図は下のようになる.


データを送受信する場合には,はじめにヘッダーを送信する.
ヘッダーには,コマンド(書き込み/読み出し),フラグ(現状は未使用),転送データ数(32ビットデータの数,つまりバイト数はこの4倍),データ読み書きの開始アドレス(FPGA内のアドレス空間)を送信する.

書き込みの場合には,ヘッダーに続いて転送データ数分だけデータを送信する.



読みこみの場合には,ヘッダーを送信した後は,データ数分だけデータを受信する.



【参考】通信のハンドシェーク


AXI等では,データとready, validを使って確実にデータを転送する.(さらに細かい制御には他の信号線も使うが.)
データの送信側は,データの準備ができたら,データと共にvalidをアサートする.
データの受信側は,受信準備ができていればreadyをアサートする.
valid と ready が共にアサートされている時にのみ(クロックの立ち上がりで)データ通信が成立する.
もし,連続してデータを送る場合は,validをアサートしたままで直ちに次のデータを信号線にのせる.(そうじゃないと,古いデータが連続して何個も送信されてしまう.)
もし,次に送るべきデータがないなら,有効なデータ転送が行われた後ただちにvalidをネゲートする.
ちなみに,ready信号は,valid信号が有効になるのを待ってからアサートしてもよいが,その逆は絶対にだめ.(valid信号は,ready信号にかかわらず,データが有効になったらアサートする)



IPの読み込み

まずは,新規プロジェクトを開き,前回までに使用していたUARTモジュールをIPとして読み込む.
UARTの速度は,FPGA内の通信に比べると極めて遅い.
そこで,データ通信速度の差を埋めるために,UARTのデータをFIFOにある程度ためておき,FIFOがいっぱいになりそうになったら,FPGA内部へ高速データ転送させる.
そのための,FIFOを2つ(入力・出力用)読み込む.
IP Catalogから,“FIFO Generator"を選択する.
FIFOの設定は,以下のようにする.


受信用(UARTからFPGA内部へのデータ転送)FIFO









送信用(FPGA内部からUART(PC)へのデータ転送)FIFO







TOPレベル HDL

TOPレベルのHDLは以下のように記述する.
UART_HL.vhd


 
--Header
-- 2byte: keycode(command)
-- 2byte: flag
-- 4byte: length;
-- 4byte: addr


library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;


entity UART_HL is
  Port ( 
    CLK : in std_logic;
    TxClk : in std_logic;
    RxClk : in std_logic;
    RSTn : in std_logic;
    
--UART
    TX : out std_logic;
    RX : in std_logic;    
        
    ADDR_o : out std_Logic_vector( 31 downto 0);
    DATLEN_o : out std_logic_vector(31 downto 0);
    FLAG_o : out std_logic_vector(15 downto 0);
    
    bulkout_data_o : out std_logic_vector( 31 downto 0);
    bulkout_dvalid_o : out std_logic;
    bulkout_ready_i : in std_logic;
    bulkout_start_o : out std_logic;
    bulkout_end_o : out std_logic;
    bulkout_busy_o :out std_logic;
  
    bulkin_data_i : in std_logic_vector( 31 downto 0);
    bulkin_dvalid_i : in std_logic;
    bulkin_ready_o : out std_logic;
    bulkin_start_o : out std_logic;
    bulkin_end_o : out std_logic;
    bulkin_busy_o :out std_logic
  
  );
end UART_HL;



architecture Behavioral of UART_HL is

    constant COMMAND_BULKOUT  : std_logic_vector(15 downto 0) := X"aa55";		 FPGAへのデータ書き込みを示すコマンド
    constant COMMAND_BULKIN : std_logic_vector(15 downto 0) := X"aa56";			FPGAからのデータ読み込みを示すコマンド

    component UARTtop_T2_0 IS					UART低レベルモジュール(前回まで使っていたIP)の読み込み
      PORT (
        CLK : IN STD_LOGIC;
        TxClk : in std_logic;
        RxClk : in std_logic;        
        RSTn : IN STD_LOGIC;
        TXD : OUT STD_LOGIC;
        RXD : IN STD_LOGIC;
        DIN : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
        DOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
        TxEn : IN STD_LOGIC;
        RxEn : IN STD_LOGIC;
        TxRdy : OUT STD_LOGIC;
        RxRdy : OUT STD_LOGIC;
        DoutValid : OUT STD_LOGIC
      );
    END component UARTtop_T2_0;

    component fifo_generator_0 IS			FIFO(BulkOut用)の読み込み
      PORT (
        clk : IN STD_LOGIC;
        srst : IN STD_LOGIC;
        din : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
        wr_en : IN STD_LOGIC;
        rd_en : IN STD_LOGIC;
        dout : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
        full : OUT STD_LOGIC;
        empty : OUT STD_LOGIC;
        prog_full : OUT STD_LOGIC
      );
    END component fifo_generator_0;


    component fifo_bulkin IS					FIFO(BulkIn用)の読み込み
      PORT (
        clk : IN STD_LOGIC;
        srst : IN STD_LOGIC;
        din : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
        wr_en : IN STD_LOGIC;
        rd_en : IN STD_LOGIC;
        dout : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
        full : OUT STD_LOGIC;
        empty : OUT STD_LOGIC
      );
    END component fifo_bulkin;



    type state_t is (COM_RD, ADDR_RD, LEN_RD, DAT_RD, DAT_WR, WAIT_DOUT_FINISH, DAT_WR_END);		内部stateを表すデータ型の定義
    signal state : state_t := COM_RD;

    signal RX_Update_pulse : std_logic;					内部で使用する信号の宣言
    signal RX_Valid : std_logic;
    signal RX_Valid_ff : std_logic;
    signal RX_Valid_ff2 : std_logic;
    signal RXEn : std_Logic;
    signal RxData : std_logic_vector(7 downto 0);
    signal RxRdy : std_logic;

    signal TxEn : std_Logic;
    signal TxData : std_logic_vector(7 downto 0);
    signal TxRdy : std_logic;

    signal start_addr : std_logic_vector( 31 downto 0);
    signal length : std_logic_vector( 31 downto 0);
    signal com_and_flag : std_logic_vector(31 downto 0);

    signal dat32 : std_logic_vector(31 downto 0);
    signal dat32_wr : std_logic;
    signal dat32_wr_pulse : std_logic;
    signal dat32_wr_ff : std_logic;
    signal dat32_wr_ff2 : std_logic;


    signal bulkout_dvalid :std_logic;
    
    signal bulkout_running : std_logic;
    signal bulkout_start : std_logic;
    signal bulkout_data_last :std_logic;

    signal bulkin_running : std_logic;
    signal bulkin_start : std_logic;
    signal bulkin_ready : std_logic;
    signal bulkin_data_last :std_logic;

    signal rst : std_logic;
    
    signal DOUT_FIFO_EMPTY :std_logic;
    signal DOUT_FIFO_FULL :std_logic;
    signal DOUT_FIFO_DATA :std_logic_vector(31 downto 0);
    signal DOUT_FIFO_RD : std_logic;
    signal DOUT_FIFO_PROG_FULL : std_logic;
    
    signal DIN_FIFO_EMPTY :std_logic;
    signal DIN_FIFO_FULL :std_logic;
    signal DIN_FIFO_DOUT :std_logic_vector(31 downto 0);
    signal DIN_FIFO_RD : std_logic;
    signal DIN_FIFO_WR : std_logic;

    
    signal byte_count : integer range 0 to 3;
    signal data_count_Rx : integer;
    signal data_count_BulkOut : integer;

    signal data_count_Tx : integer;
    signal data_count_BulkIn : integer;

    signal last_data_readed : std_logic;


begin

    UART_LL : UARTtop_T2_0			    UART低レベルモジュールの組み込み,配線
    port map(
        CLK => CLK,
        TxClk => TxClk,
        RxClk => RxClk,
        RSTn => RSTn,
        TXD => TX,
        RXD => RX,
        DIN => TxData,
        DOUT => RxData,
        TxEn => TxEn,
        RxEn => RXEn,
        TxRdy => TxRdy,
        RxRdy => RxRdy,
        DoutValid => Rx_Valid
    );

    ADDR_o <= start_addr;
    DATLEN_o <= length;
    FLAG_o <= com_and_flag(31 downto 16);

    process(CLK)						Rx_Valid信号が0から1に変化した際に,1クロックだけパルス(RX_Update_pulse)を生成する 
    begin
        if(CLK'event and CLK='1') then
            RX_Valid_ff <= RX_Valid;    

        end if;
    end process;
    RX_Update_pulse <= RX_Valid and (not RX_Valid_ff);


    process(CLK)					state machineの動作定義 
    begin
        if(CLK'event and CLK='1') then
            if(RSTn = '0') then    リセット処理 
                state <= COM_RD;
                byte_count <= 0;
                RXEn <= '1';    --Enable recieving
                TXEn <= '0';
                bulkin_start <= '0';
                  DIN_FIFO_RD <= '0';
                last_data_readed <= '0';

            else
                case(state) is
                
--=========================== read command and flag ======================                                
                when COM_RD =>      --Receive keycode(command)(2byte)  and flag(2byte) -> into com_and_flag (4byte)
                							最初のデータの到着を待つstate 
                    if(RX_Update_pulse = '1') then				最初のデータが到着した(最初のデータはコマンド16bitとフラグ16bitの32ビットデータ) 
                        com_and_flag( byte_count*8 + 7 downto byte_count*8) <= RxData;		UARTからのデータは8ビットなので,これを32ビットにする 

                        if(byte_count = 3) then			4バイト(32ビット)分のデータを入力し終わった 
                            byte_count <= 0;
                            state <= LEN_RD;    --proceed to next state		 次のステートへ移動する 
                        else
                            byte_count <= byte_count + 1;    1バイト分データをずらし,次のデータの到着を待つ 
                            state <= state;
                        end if;
                    else
                        state <= state;
                    end if;

--=========================== read Data length ======================                                                
                when LEN_RD =>				 次の4バイト分のデータはデータ長 
                    if(RX_Update_pulse = '1') then
                        length( byte_count*8 + 7 downto byte_count*8 ) <= RxData;
                                                   
                       if(byte_count = 3) then
                            byte_count <= 0;
                            state <= ADDR_RD;    4バイト分のデータを受信し終わったら,次のstateへ 
                        else
                            byte_count <= byte_count + 1;
                            state <= state;
                        end if;
                    else
                            state <= state;
                    end if;
                    
--=========================== read Start Addr ======================                                                
                when ADDR_RD => 				 次の4バイト分のデータは開始アドレス 
                    if(RX_Update_pulse = '1') then
                        start_addr( byte_count*8 + 7 downto byte_count*8 ) <= RxData;
                                                   
                       if(byte_count = 3) then		 4バイト分のデータを受信し終わった 
                            byte_count <= 0;
                            
                            if(com_and_flag(15 downto 0) = COMMAND_BULKOUT)then				 もしコマンドがBULKOUT(PCからFPGAへのデータ転送)なら,,  
                                state <= DAT_RD;    --Read data from UART, then output to BULKOUT port 		  データ受信のstateへ移動する 
                                data_count_Rx <= to_integer( unsigned(length ));   		 受信データカウンタの値をlengthに設定 
                                if( to_integer( unsigned(length )) = 1) then    --only 1 byte data -> first data becomes last data
                                    last_data_readed <= '1';
                                else
                                    last_data_readed <= '0';
                                end if;


                            elsif(com_and_flag(15 downto 0) = COMMAND_BULKIN)then		 もしコマンドがBULKIN(FPGAからPCへのデータ転送)なら,,  
                                state <= DAT_WR;    --Write data to UART from BULKIN port			  データ送信のstateへ移動する 
                                data_count_Tx <= to_integer( unsigned(length ));
                                bulkin_start <= '1';			 BulkIN動作を開始させる(FPGA内部からFIFOへデータ転送が始まる) 
	
                            else
                                state <= COM_RD;

                            end if;
                            
                        else
                            byte_count <= byte_count + 1;
                            state <= state;
                        end if;                    
                    else
                            state <= state;
                    end if; --RX?update_Pulse
                
--=========================== read UART -> BULKOUT ======================                
                when DAT_RD =>
                    if(RX_Update_pulse = '1') then

                        dat32( byte_count*8 + 7 downto byte_count*8 ) <= RxData;    4バイト分のデータをdat32に格納する 
                       
                       if(byte_count = 3) then  --4 byte data is received    4バイト分のデータを受信し終わった 
                            byte_count <= 0;
                            dat32_wr <= '1';   -- write to FIFO			 受信した4バイトデータをFIFOへ書き込む 
                            
                            if(data_count_Rx = 1 )then  -- no data left to be read from UART		 もう送るべきデータが無いなら,終了待ちstateへ 
                                state <= WAIT_DOUT_FINISH;
                                
                            elsif(data_count_Rx = 0 )then  -- Something wrong
                                state <= COM_RD;
                                
                            else	
                                if(data_count_Rx = 2) then		 次が最後のデータになる場合にのみ,last_data_readed信号をアサートする 
                                    last_data_readed <= '1';
                                else
                                    last_data_readed <= '0';
                                end if;
                                
                                data_count_Rx <= data_count_Rx -1;     4バイトデータを受信するたびに,受信データカウンタを1つづつ減らす 
                                state <= state;
                            end if;
                            
                        else
                            dat32_wr <= '0'; 
                            byte_count <= byte_count + 1;		 次のバイトの受信へ 
                            state <= state;
                        end if;
                    else
                            state <= state;
                    end if;


                when WAIT_DOUT_FINISH =>   -- wait until all data transferes to BULKOU     UARTからの受信は全て終わり,FIFOのデータがすべてFPGA内部に転送されるのを待つstate 
                
                    if( bulkout_data_last='1' and bulkout_dvalid='1' and bulkout_ready_i='1')then    FIFOの最後のデータが転送されたなら,COM_RDへ戻る 
                        state <= COM_RD;

                    else
                        state <= state;
                    end if;
                
                
--=========================== BULKIN -> write to UART ======================                
                when DAT_WR =>			 BULKIN(FPGAからPCへデータを転送)の場合 
                    bulkin_start <= '0';

                    if( DIN_FIFO_EMPTY='0' and TxRdy='1' and TxEn='0')then --data is ready	 FIFOに何らかのデータが入っており,送信開始可能(TxRdy=1)なら,, 
                        TxEn <= '1';																			 データ送信をトリガーする 
                        TxData <= DIN_FIFO_DOUT(byte_count*8 + 7 downto byte_count*8 ) ;		 FIFOの出力4バイトを1バイトづつUARTモジュールに送っていく 
                        
                        if(byte_count = 3)then				 4バイト分のデータを送信し終わった 
                            byte_count <= 0;
                            
                            if(data_count_Tx = 1)then   --Last data		 最後のデータを送信した 
                                DIN_FIFO_RD <= '1';                            
                                 state <= DAT_WR_END;
                                          
                             else
                                DIN_FIFO_RD <= '1';
                                data_count_Tx <= data_count_TX - 1;     FIFOから1バイトデータを読み込み,カウンタを1つ減らす                     
                                state <= state;
                             end if;
                         else
                            byte_count <= byte_count + 1;			 次のバイトの送信へ 
                            DIN_FIFO_RD <= '0';
                            state <= state;
                         end if;

                    else
                        DIN_FIFO_RD <= '0';
                        TxEn <= '0';     
                        state <= state;
                    end if;    
                
                when DAT_WR_END => 
                    DIN_FIFO_RD <= '0';                            
                    state <= COM_RD;
                    TxEn <= '0';

                
                when others =>
                    state <= COM_RD;
                    
                end case;
            
            end if;
        end if;
    
    end process;


 BulkOut用FIFOの制御信号生成 
-- ================== FIFO (BulkOut) Control ====================

--Start sinal generation (all data received or FIFO full)
    process(clk)
    begin
        if(clk'event and clk='1')then
            if(rstn = '0')then
                bulkout_start <= '0';
                bulkout_running <= '0';
            else
                if(      (DOUT_FIFO_PROG_FULL='1' or (state = WAIT_DOUT_FINISH) )		 FIFOがほぼ満杯(Prog_FULL)か,UARTからすべてのデータを受信おわったら(WAIT_DOUT_FINISH),,
                          and (bulkout_running='0' ) )then
                   bulkout_start <= '1';			 BulkOut転送を開始する 
                   bulkout_running <= '1';		 BulkOut転送中 
                else
                    bulkout_start <= '0';
                       if( bulkout_data_last='1' and DOUT_FIFO_RD='1' )then		 最後のデータを転送した 
                        bulkout_running <= '0';         	 BulkOut転送中信号をクリア 
                    end if;
                end if;
                
            end if;
        end if;
    end process;


    bulkout_start_o <= bulkout_start;
   
   process(clk)    生成される書き込み信号(dat32_wr)から,書き込み用パルス(dat32_wr_pulse)を生成する 
    begin
        if(clk'event and clk='1')then
            dat32_wr_ff <= dat32_wr;
        end if;
    end process;
    dat32_wr_pulse <= dat32_wr and (not dat32_wr_ff);


-- data counter
    process(clk) 	 データ転送数をカウントする(終了判定に使う) 
    begin
        if( (clk'event and clk='1') )then
            if(RSTn = '0')then
                data_count_BulkOut <= 0;
            end if;
            
            if(      (DOUT_FIFO_PROG_FULL='1' or (state = WAIT_DOUT_FINISH) )   BulkOut転送が開始するときに,, 
                    and (bulkout_running='0' ) )then
                data_count_BulkOut <= to_integer( unsigned( length));    データカウント値を設定する 
              end if;
  
              if (DOUT_FIFO_RD = '1')  then		 FIFOからデータを1つ読み込むたびに,,, 
                
                data_count_BulkOut <= data_count_BulkOut - 1;	   カウント値を−1する 
            end if;
        end if;
    end process;

    bulkout_data_last <= '1' when data_count_BulkOut=1 else     最後のデータを送信するタイミングで,last信号をアサートする 
                         '0';


    bulkout_end_o <= bulkout_data_last and bulkout_dvalid; -- -> TODO: it shoud be pulse???
    bulkout_dvalid_o <= bulkout_dvalid;
    bulkout_dvalid <= not DOUT_FIFO_empty;   FIFOに何らかのデータが入っていれば,データを読みだし可能 (TODO:running中のみアサートした方が良い???) 

    bulkout_busy_o <= bulkout_running;
    
    DOUT_FIFO_RD <= bulkout_dvalid and bulkout_ready_i and bulkout_running;    BulkOut転送中であり,ready と valid が共にアサートされている(=データ転送が起こる)時のみ,FIFOの読み出し信号をアサートする 

    rst <= not RSTn;
    bulkout_data_o <= DOUT_FIFO_DATA;

    DOUT_FIFO : fifo_generator_0			 BulkOut用FIFOへの配線 
    port map(
        clk => CLK,
        srst => rst,
        din => dat32,
        wr_en => dat32_wr_pulse,
         rd_en => DOUT_FIFO_RD,
         dout => DOUT_FIFO_DATA,
         full => DOUT_FIFO_full,
         empty => DOUT_FIFO_empty,
         prog_full => DOUT_FIFO_PROG_FULL
    );


-- ======================== FIFO (BulkIn) Control =====================
    DIN_FIFO : fifo_bulkin 		 BulkIN用FIFOの配線 
    port map(
        clk => CLK,
        srst => rst,
        din  => bulkin_data_i,
        wr_en => DIN_FIFO_WR,
        rd_en => DIN_FIFO_RD,
        dout => DIN_FIFO_DOUT,
        full => DIN_FIFO_FULL,
        empty => DIN_FIFO_EMPTY
      );


    DIN_FIFO_WR <= bulkin_dvalid_i and bulkin_ready and bulkin_running;		 BulkIN FIFOへの書き込みは,BulkIN動作中で,かつreadyとvalidが共に有効な時のみ 


--start signal generation (bulkin)
    process(clk)
    begin
        if(clk'event and clk='1')then
            if(rstn = '0')then

                bulkin_running <= '0';
            else
                if(  bulkin_start = '1' ) then    Bulkin_startが発行されたら,running信号をセットする 
                   bulkin_running <= '1';
                else
                    if( bulkin_data_last='1' and bulkin_dvalid_i='1' and bulkin_ready='1')then    最後のデータを転送しおわったら,running信号をクリアする 
                        bulkin_running <= '0';         
                    end if;
                end if;
                
            end if;
        end if;

    end process;

    bulkin_ready <= (not DIN_FIFO_FULL) and bulkin_running;		 FIFOに空きがあり,かつBulkIN動作中のみ,データ受信を許可する 
    
    bulkin_start_o <= bulkin_start;
    bulkin_ready_o <= bulkin_ready;
    bulkin_end_o <= bulkin_data_last;
    bulkin_busy_o <= bulkin_running;

-- data counter
    process(clk)
    begin
        if( (clk'event and clk='1') )then
            if(RSTn = '0')then
                data_count_BulkIn <= 0;
            end if;
            
            if( bulkin_start = '1' and bulkin_running='0')then
                data_count_BulkIn <= to_integer( unsigned( length));   BulkIn転送が開始するタイミングで,カウンタ値をセットする 
            end if;
        
            if (DIN_FIFO_WR = '1')  then
               
                data_count_BulkIn <= data_count_BulkIn - 1;   カウンタ値を−1する 
            end if;
        end if;
    end process;

    bulkin_data_last <= '1' when data_count_BulkIn=1 else    	 次が最後のデータの受信になる時には,last信号をアサートする. 
                        '0';


end Behavioral;



FIFOとUARTモジュール,外部ポートへの接続と,制御信号の配線のイメージ図.
これらの動作は,下のVHDLコード内に書かれている.






動作シミュレーション



テストベンチを以下のように作成し,動作を検証する.

TB.vhd
 

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

use IEEE.NUMERIC_STD.ALL;


entity TB is
end TB;

architecture Behavioral of TB is

    component UART_HL is		 動作を検証するためのモジュール 
      Port ( 
      CLK : in std_logic;
      TxClk : in std_logic;
      RxClk : in std_logic;
      RSTn : in std_logic;
      
  --UART
      TX : out std_logic;
      RX : in std_logic;    
          
      ADDR_o : out std_Logic_vector( 31 downto 0);
      DATLEN_o : out std_logic_vector(31 downto 0);
      FLAG_o : out std_logic_vector(15 downto 0);
      
      bulkout_data_o : out std_logic_vector( 31 downto 0);
      bulkout_dvalid_o : out std_logic;
      bulkout_ready_i : in std_logic;
      bulkout_start_o : out std_logic;
      bulkout_end_o : out std_logic;
      bulkout_busy_o :out std_logic;
      
      bulkin_data_i : in std_logic_vector( 31 downto 0);
      bulkin_dvalid_i : in std_logic;
      bulkin_ready_o : out std_logic;
      bulkin_start_o : out std_logic;
      bulkin_end_o : out std_logic;
      bulkin_busy_o :out std_logic      

    );
    end component UART_HL;

    signal StartAddr : std_Logic_vector(31 downto 0);
    signal DataLength : std_logic_vector(31 downto 0);


    signal clk : std_logic := '0';
    signal Txclk : std_logic := '0';
    signal Rxclk : std_logic := '0';
    signal rstn : std_logic;

    signal Tx : std_logic;
    signal Rx : std_logic;

    signal bulkout_start : std_logic;
    signal bulkout_data : std_logic_vector( 31 downto 0);
    signal bulkout_dvalid : std_logic;
    signal bulkout_ready : std_Logic;
    signal bulkout_end : std_logic;
    signal bulkout_busy : std_logic;

    signal bulkin_start : std_logic;
    signal bulkin_data : std_logic_vector( 31 downto 0);
    signal bulkin_dvalid : std_logic;
    signal bulkin_ready : std_Logic;
    signal bulkin_end : std_logic;
    signal bulkin_busy : std_logic;

    constant TxPeriod : time :=  1000 ns; --1/1000000;			 UARTの転送速度から時間を計算する 
    constant RxPeriod : time :=  1000 ns / 16; --1/1000000;
    constant DatPeriod : time :=  1000 ns; --1/1000000;
    
begin


    DUT : UART_HL				 動作を検証するためのモジュールを読み込む 
    port map(
        CLK => clk,
        TxClk => TxClk,
        RxClk => RxClk,
        RSTn => rstn,
        TX => Tx,
        RX => Rx,
        ADDR_o => StartAddr,
        DATLEN_o => DataLength,
        FLAG_o => open,
        bulkout_data_o => bulkout_data,
        bulkout_dvalid_o => bulkout_dvalid,
        bulkout_ready_i => bulkout_ready,
        bulkout_start_o => bulkout_start,
        bulkout_end_o => bulkout_end,
        bulkout_busy_o => bulkout_busy,
        
        bulkin_data_i => bulkin_data,
        bulkin_dvalid_i => bulkin_dvalid,
        bulkin_ready_o => bulkin_ready,
        bulkin_start_o => bulkin_start,
        bulkin_end_o => bulkin_end,
        bulkin_busy_o => bulkin_busy
        
             
    );


    clk <= not clk after 5ns;				 クロック等の定義 
    TxClk <= not TxClk after TxPeriod/2;  
    RxClk <= not RxClk after RxPeriod/2;
    
    process		 リセット信号の生成 
    begin
        rstn <= '0';
        wait for 1 us;
        rstn <= '1';
        
        wait;
    end process;
    

--UART への入力をシミュレート
    process
        variable dat : std_logic_vector( 7 downto 0);
        variable dat32 :std_logic_vector( 31 downto 0);
        variable command : std_logic_vector(15 downto 0);
        variable flag : std_logic_vector(15 downto 0);
        
    begin
        RX <= '1';
        bulkin_data <= (others => '0');
        wait until clk'event and clk='1' and rstn = '1';

        
        wait for 2us;
        
        
--  note: ******* Little endien ******

-- 1st double word (4 byte dat), UART Rx , command(2byte,LSB) and flag(2byte,MSB)		 最初の4バイトデータをRx信号に与える(PCからのデータ入力を模擬) 
        command := X"aa55";			 送るべきデータ(コマンド16ビット分) 
        flag := X"1357";				 送るべきデータ(フラグ16ビット分) 
        dat32 := flag & command;			 これらを,32ビットデータとしてマージ 
        
        for ii in 0 to 31 loop			 32ビット分データを送信させる 
            if( (ii mod 8) = 0) then					 UARTは8ビットづつデータを送るので, 8ビット毎にスタートビットを送信 
                RX <= '0'; wait for DatPeriod;      --start bit
             end if;
             
             RX <= dat32(ii); wait for DatPeriod;    --data bits			 実際のデータを1ビット分送信 
             
             if( (ii mod 8) = 7) then
                Rx <= '1'; wait for DatPeriod;      --stop bit			 8ビット毎にストップビットを送信 
                
                wait for 5us;
             end if;
         end loop;



-- 2nd double word (4 byte dat), UART Rx, data length
        dat32 := X"00000003";				 2つ目の4バイトデータ(転送データ数) 
        for ii in 0 to 31 loop
            if( (ii mod 8) = 0) then
                RX <= '0'; wait for DatPeriod;      --start bit
             end if;
             
             RX <= dat32(ii); wait for DatPeriod;    --data bits
             
             if( (ii mod 8) = 7) then
                Rx <= '1'; wait for DatPeriod;      --stop bit
                
                wait for 4.5us;
             end if;
         end loop;

-- 3rd double word (4 byte dat), UART Rx, start addr
        dat32 := X"40000002";		 3つ目の4バイトデータ(転送開始アドレス,今回は特に使用していない.モジュールのAddrにこの値が出力される) 
        for ii in 0 to 31 loop
            if( (ii mod 8) = 0) then
                RX <= '0'; wait for DatPeriod;      --start bit
             end if;
             
             RX <= dat32(ii); wait for DatPeriod;    --data bits
             
             if( (ii mod 8) = 7) then
                Rx <= '1'; wait for DatPeriod;      --stop bit
                
                wait for 5.6us;
             end if;
         end loop;


        wait for 20 us;
        
        
-- 1th 32bit data 
                dat32 := X"12345678";		 転送データ1個目 
                for ii in 0 to 31 loop
                    if( (ii mod 8) = 0) then
                        RX <= '0'; wait for DatPeriod;      --start bit
                     end if;
                     
                     RX <= dat32(ii); wait for DatPeriod;    --data bits
                     
                     if( (ii mod 8) = 7) then
                        Rx <= '1'; wait for DatPeriod;      --stop bit
                        
                        wait for 3.9us;
                     end if;
                 end loop;
        
-- 2nd 32bit data 
                 dat32 := X"ffddeeaa";		 転送データ2個目 
                 for ii in 0 to 31 loop
                     if( (ii mod 8) = 0) then
                         RX <= '0'; wait for DatPeriod;      --start bit
                      end if;
                      
                      RX <= dat32(ii); wait for DatPeriod;    --data bits
                      
                      if( (ii mod 8) = 7) then
                         Rx <= '1'; wait for DatPeriod;      --stop bit
                         
                         wait for 5.7us;
                      end if;
                  end loop;        

-- 3rd 32bit data 
                 dat32 := X"11335577";		 転送データ3個目 
                 for ii in 0 to 31 loop
                     if( (ii mod 8) = 0) then
                         RX <= '0'; wait for DatPeriod;      --start bit
                      end if;
                      
                      RX <= dat32(ii); wait for DatPeriod;    --data bits
                      
                      if( (ii mod 8) = 7) then
                         Rx <= '1'; wait for DatPeriod;      --stop bit
                         
                         wait for 4.6us;
                      end if;
                  end loop;        



        wait for 20 us;


--========== Test BULKIN		 次に,データ入力(FPGAからPCへのデータ転送)をシミュレート 
        bulkin_dvalid <= '0';

-- 1st double word (4 byte dat), UART Rx , command(2byte,LSB) and flag(2byte,MSB)
        command := X"aa56"; --read
        flag := X"1357";
        dat32 := flag & command;
        for ii in 0 to 31 loop
            if( (ii mod 8) = 0) then
                RX <= '0'; wait for DatPeriod;      --start bit
             end if;
             
             RX <= dat32(ii); wait for DatPeriod;    --data bits
             
             if( (ii mod 8) = 7) then
                Rx <= '1'; wait for DatPeriod;      --stop bit
                
                wait for 5.9us;
             end if;
         end loop;


-- 2nd double word (4 byte dat), UART Rx, data length
        dat32 := X"00000003";
        for ii in 0 to 31 loop
            if( (ii mod 8) = 0) then
                RX <= '0'; wait for DatPeriod;      --start bit
             end if;
             
             RX <= dat32(ii); wait for DatPeriod;    --data bits
             
             if( (ii mod 8) = 7) then
                Rx <= '1'; wait for DatPeriod;      --stop bit
                
                wait for 7.7us;
             end if;
         end loop;

-- 3rd double word (4 byte dat), UART Rx, start addr
        dat32 := X"40003000";
        for ii in 0 to 31 loop
            if( (ii mod 8) = 0) then
                RX <= '0'; wait for DatPeriod;      --start bit
             end if;
             
             RX <= dat32(ii); wait for DatPeriod;    --data bits
             
             if( (ii mod 8) = 7) then
                Rx <= '1'; wait for DatPeriod;      --stop bit
                
                wait for 8.7us;
             end if;
         end loop;


        wait for 5 us;


--BULKIN
        for jj in 1 to 3 loop		 BulkInにデータを入力させる(FPGAからPCからへ送るデータ) 
            wait for 10 us;
            bulkin_data <= std_logic_vector( to_unsigned( jj, 32 ));		 データをセットして,validをアサートする 
            bulkin_dvalid <= '1';
            
            wait until clk'event and clk='1' and bulkin_ready='1';		 readyが1になる(つまりデータ転送が完了する)のを待つ, 
            bulkin_dvalid <= '0';		 validを一旦0にする 

        end loop;
            
        wait;
    end process;

    


-- bulkout からの読み出しをシミュレート
    process			 UARTから送られてきたデータをFPGA内部に転送する 
    begin	
        bulkout_ready <= '0';

        wait until clk'event and clk='1' and bulkout_start='1';		 バルクout転送が開始するのを待つ 
        wait for 15 us;								 さらに15us待ってみる 

        for jj in 1 to 3 loop					 3個分データを受信する 
            wait until clk'event and clk='1' and bulkout_dvalid='1';			 データがvalidになったら,readyをアサートする.(ちなみに,逆(readyを待ってvalidをアサート)は絶対やっちゃダメ.そういう仕様) 
            wait for 10us;
            bulkout_ready <= '1';        
            
        end loop;        

    end process;


end Behavioral;





シミュレーション結果(受信)





受信したデータをFPGA内部へ転送(BUlkOut)しているところ.
うえのUART受信に比べて極めて短時間で終わっているのがわかる.
FIFOでデータをためておいてから,まとめて送信した恩恵