FC2カウンター FPGAの部屋 Spartan-3A Starter KitでEDKを使ってカメラ表示12(ディスプレイ回路のシミュレーション)
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Spartan-3A Starter KitでEDKを使ってカメラ表示12(ディスプレイ回路のシミュレーション)

Spartan-3A Starter KitでEDKを使ってカメラ表示11(ディスプレイ回路を作り始める)”の続きです。

Disp_Controller_Top.vhd、Disp_Controller_Top_tb.vhd を作って、シミュレーションしてみました。シミュレーションがうまく行ったら、Disp_Controller_Top.vhdをuser_logic.vhdに接続します。
Disp_Controller_Top.vhdを下に示す。

-- Disp_Controller_Top.vhd
-- VGA_Display_Controller.v のトップ
-- DDR2 SDRAM 64MBの内の真ん中から1MBを使用する。データバス幅は32ビット

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

library unisim;
use unisim.vcomponents.all;

entity Disp_Controller_Top is
    generic(
        C_SLV_DWIDTH                   : integer              := 32;
        C_MST_AWIDTH                   : integer              := 32;
        C_MST_DWIDTH                   : integer              := 32;
        C_NUM_REG                      : integer              := 3
    );
    port(
        red_out        : out std_logic_vector(3 downto 0);
        green_out    : out std_logic_vector(3 downto 0);
        blue_out    : out std_logic_vector(3 downto 0);
        hsyncx        : out std_logic;
        vsyncx        : out std_logic;
        
        Bus2IP_Clk                     : in  std_logic;
        Bus2IP_Reset                   : in  std_logic;
        IP2Bus_MstRd_Req               : out std_logic;
        IP2Bus_MstWr_Req               : out std_logic;
        IP2Bus_Mst_Addr                : out std_logic_vector(0 to C_MST_AWIDTH-1);
        IP2Bus_Mst_BE                  : out std_logic_vector(0 to C_MST_DWIDTH/8-1);
        IP2Bus_Mst_Length              : out std_logic_vector(0 to 11);
        IP2Bus_Mst_Type                : out std_logic;
        IP2Bus_Mst_Lock                : out std_logic;
        IP2Bus_Mst_Reset               : out std_logic;
        Bus2IP_Mst_CmdAck              : in  std_logic;
        Bus2IP_Mst_Cmplt               : in  std_logic;
        Bus2IP_Mst_Error               : in  std_logic;
        Bus2IP_Mst_Rearbitrate         : in  std_logic;
        Bus2IP_Mst_Cmd_Timeout         : in  std_logic;

        Bus2IP_MstRd_d                 : in  std_logic_vector(0 to C_MST_DWIDTH-1);
        Bus2IP_MstRd_rem               : in  std_logic_vector(0 to C_MST_DWIDTH/8-1);
        Bus2IP_MstRd_sof_n             : in  std_logic;
        Bus2IP_MstRd_eof_n             : in  std_logic;
        Bus2IP_MstRd_src_rdy_n         : in  std_logic;
        Bus2IP_MstRd_src_dsc_n         : in  std_logic;
        IP2Bus_MstRd_dst_rdy_n         : out std_logic;
        IP2Bus_MstRd_dst_dsc_n         : out std_logic;
        
        IP2Bus_MstWr_d                 : out std_logic_vector(0 to C_MST_DWIDTH-1);
        IP2Bus_MstWr_rem               : out std_logic_vector(0 to C_MST_DWIDTH/8-1);
        IP2Bus_MstWr_sof_n             : out std_logic;
        IP2Bus_MstWr_eof_n             : out std_logic;
        IP2Bus_MstWr_src_rdy_n         : out std_logic;
        IP2Bus_MstWr_src_dsc_n         : out std_logic;
        
        -- for test output
        afifo_overflow    : out std_logic;
        afifo_underflow    : out std_logic;
        addr_is_zero    : out std_logic;
        h_v_is_zero        : out std_logic
    );
end Disp_Controller_Top;

architecture RTL of Disp_Controller_Top is
constant    DDR2_SDRAM_ADDR_START    : std_logic_vector(31 downto 0) := x"46000000"; -- 32MB目から1MBを使用する。
constant    TRANSFER_LENGTH            : integer := 128;

component VGA_Display_Controller generic (
        AFIFO_FULL_VAL            : integer    := TRANSFER_LENGTH*2;
        AFIFO_HALF_FULL_VAL    : integer    := TRANSFER_LENGTH
    );
    port(
        clk_disp            : in std_logic;
        clk_ddr2        : in std_logic;
        reset_disp        : in std_logic;
        reset_ddr2        : in std_logic;
        request            : out std_logic;
        grant            : in std_logic;
        address            : out std_logic_vector(18 downto 0);
        req_we            : out std_logic;
        addr_fifo_full    : in std_logic;
        data_in            : in std_logic_vector(31 downto 0);
        data_valid        : in std_logic;
        red_out            : out std_logic_vector(7 downto 0);
        green_out         : out std_logic_vector(7 downto 0);
        blue_out        : out std_logic_vector(7 downto 0);
        hsyncx            : out std_logic;
        vsyncx            : out std_logic;
        afifo_overflow    : out std_logic;
        afifo_underflow    : out std_logic;
        addr_is_zero    : out std_logic;
        h_v_is_zero        : out std_logic
    );
end component;

component dcm_DISP_clk
    port(
        sysclk            : in std_logic;
        reset            : in std_logic;
        clk_disp            : out std_logic;
        dcm_locked_out    : out std_logic
    );
end component;

signal clk_disp : std_logic;
signal reset_disp : std_logic;
signal reset_disp_node : std_logic;
signal reset_disp_srl, reset_disp_srl_1d, reset_disp_srl_2d : std_logic;
signal Bus2IP_MstRd_src_rdy : std_logic;
signal hsyncx_node, vsyncx_node : std_logic;
signal dcm_locked : std_logic;
signal request, grant : std_logic;
signal req_we : std_logic;
type DISP_RD_STATE is (IDLE_DISP_RD, DISP_RD_COUNT_SET, MST_RD_CONTINUED);
signal cs_disp_rd : DISP_RD_STATE;
signal disp_rd_count : std_logic_vector(7 downto 0);
type RD_STATE is (IDLE_RD, TRANS_COUNT_SET, MPMC_RD_ST);
signal cs_rd : RD_STATE;
type CMD_STATE is (IDLE_CMD, CMD_ASSORT, WAIT_TRANSACTION);
signal cs_cmd : CMD_STATE;
signal trans_count : std_logic_vector(4 downto 0);
signal addr_cnt, mst_addr : std_logic_vector(C_MST_AWIDTH-1 downto 0);
signal red, green, blue : std_logic_vector(7 downto 0);
signal rd_dst_rdy : std_logic;

begin
    IP2Bus_Mst_Lock        <= '0';
    IP2Bus_Mst_Reset    <= '0';
    -- Master Write 信号の処理
    IP2Bus_MstWr_Req    <= '0';
    IP2Bus_MstWr_d        <= (others => '0');
    IP2Bus_MstWr_rem    <= (others => '0');
    IP2Bus_MstWr_sof_n    <= '1';
    IP2Bus_MstWr_eof_n    <= '1';
    IP2Bus_MstWr_src_rdy_n    <= '1';
    IP2Bus_MstWr_src_dsc_n    <= '1';
    
    dcm_DISP_clk_inst : dcm_DISP_clk port map(
        sysclk            => Bus2IP_Clk,
        reset             => Bus2IP_Reset,
        clk_disp         => clk_disp,
        dcm_locked_out    => dcm_locked
    );
    reset_disp_node <= not dcm_locked;
    
    -- reset_disp を16クロック遅延される。クロックが出始めてすぐ、dcm_lockedが1になるため同期リセットFFがリセットされない。
    SRL16E_SDA_ena : SRL16E generic map(
        INIT => X"0000")
    port map(
        Q => reset_disp_srl,
        A0 => '1',
        A1 => '1',
        A2 => '1',
        A3 => '1',
        CE => '1',
        CLK => Bus2IP_Clk,
        D => reset_disp_node
    ); 
    
    -- clk_disp で同期化
    process(clk_disp) begin
        if clk_disp'event and clk_disp='1' then
            reset_disp_srl_1d <= reset_disp_srl;
            reset_disp_srl_2d <= reset_disp_srl_1d;
        end if;
    end process;
    reset_disp <= reset_disp_srl_2d;
    
    Bus2IP_MstRd_src_rdy <= not Bus2IP_MstRd_src_rdy_n;
    VGA_Disp_Cont_inst : VGA_Display_Controller generic map(
        AFIFO_FULL_VAL        => TRANSFER_LENGTH*2,
        AFIFO_HALF_FULL_VAL    => TRANSFER_LENGTH
    ) port map (
        clk_disp        => clk_disp,
        clk_ddr2        => Bus2IP_Clk,
        reset_disp        => reset_disp,
        reset_ddr2        => Bus2IP_Reset,
        request            => request,
        grant            => grant,
        address            => open,
        req_we            => req_we,
        addr_fifo_full    => '0',
        data_in            => Bus2IP_MstRd_d,
        data_valid        => Bus2IP_MstRd_src_rdy,
        red_out            => red,
        green_out        => green,
        blue_out        => blue,
        hsyncx            => hsyncx_node,
        vsyncx            => vsyncx_node,
        afifo_overflow    => afifo_overflow,
        afifo_underflow    => afifo_underflow,
        addr_is_zero    => addr_is_zero,
        h_v_is_zero        => h_v_is_zero
    );
    red_out        <= red(7 downto 4);
    green_out    <= green(7 downto 4);
    blue_out    <= blue(7 downto 4);
    hsyncx <= hsyncx_node;
    vsyncx <= vsyncx_node;
    
    -- ディスプレイ回路のrequest の処理。128ワード必要なので、16バーストを8回行う
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_disp_rd <= IDLE_DISP_RD;
                grant <= '0';
            else
                case cs_disp_rd is
                    when IDLE_DISP_RD =>
                        if request='1' then
                            cs_disp_rd <= DISP_RD_COUNT_SET;
                        end if;
                    when DISP_RD_COUNT_SET =>
                        cs_disp_rd <= MST_RD_CONTINUED;
                        grant <= '1';
                    when MST_RD_CONTINUED =>
                        if disp_rd_count=1 and Bus2IP_MstRd_src_rdy='1' then
                            cs_disp_rd <= IDLE_DISP_RD;
                            grant <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    -- disp_rd_count の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                disp_rd_count <= (others => '0');
            else
                if cs_disp_rd=DISP_RD_COUNT_SET then
                    disp_rd_count <= CONV_STD_LOGIC_VECTOR(TRANSFER_LENGTH, 8);
                elsif cs_rd=MPMC_RD_ST and Bus2IP_MstRd_src_rdy_n='0' then
                    disp_rd_count <= disp_rd_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- マスタRead用ステートマシン, 16バースト転送
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_rd <= IDLE_RD;
                rd_dst_rdy <= '0';
            else
                case cs_rd is
                    when IDLE_RD =>
                        if cs_disp_rd=MST_RD_CONTINUED and cs_cmd=IDLE_CMD then
                            cs_rd <= TRANS_COUNT_SET;
                            rd_dst_rdy <= '0';
                        end if;
                    when TRANS_COUNT_SET =>
                        cs_rd <= MPMC_RD_ST;
                        rd_dst_rdy <= '1';
                    when MPMC_RD_ST =>
                        if trans_count=1 and Bus2IP_MstRd_src_rdy='1' then
                            cs_rd <= IDLE_RD;
                            rd_dst_rdy <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    IP2Bus_MstRd_dst_rdy_n <= not rd_dst_rdy;
    
    IP2Bus_Mst_BE <= (others => '1');
    IP2Bus_MstRd_dst_dsc_n <= '1';
    
    -- コマンド用ステートマシン
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_cmd <= IDLE_CMD;
                IP2Bus_MstRd_Req <= '0';
                IP2Bus_Mst_Type <= '0';
            else
                case cs_cmd is
                    when IDLE_CMD =>
                        if cs_rd=TRANS_COUNT_SET then
                            cs_cmd <= CMD_ASSORT;
                            IP2Bus_MstRd_Req <= '1';
                            IP2Bus_Mst_Type <= '1';
                        end if;
                    when CMD_ASSORT =>
                        if Bus2IP_Mst_CmdAck='1' then
                            cs_cmd <= WAIT_TRANSACTION;
                            IP2Bus_MstRd_Req <= '0';
                            IP2Bus_Mst_Type <= '0';
                        end if;
                    when WAIT_TRANSACTION =>
                        if Bus2IP_Mst_Cmplt='1' then
                            cs_cmd <= IDLE_CMD;
                            IP2Bus_MstRd_Req <= '0';
                            IP2Bus_Mst_Type <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    -- trans_countの処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                trans_count <= (others => '0');
                IP2Bus_Mst_Length <= CONV_STD_LOGIC_VECTOR(64, 12); -- 128バイト、32ビット幅、16バースト
            else
                if cs_rd=TRANS_COUNT_SET then
                    if disp_rd_count>=16 then
                        trans_count <= CONV_STD_LOGIC_VECTOR(16,5);
                        IP2Bus_Mst_Length <= CONV_STD_LOGIC_VECTOR(64, 12); -- 128バイト、32ビット幅、16バースト
                    else -- 転送の残りが16以下
                        trans_count <= disp_rd_count(4 downto 0);
                        IP2Bus_Mst_Length <= "0000000" & disp_rd_count(4 downto 0);
                    end if;
                elsif cs_rd=MPMC_RD_ST and Bus2IP_MstRd_src_rdy_n='0' then
                    trans_count <= trans_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- addr_cnt の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                addr_cnt <= DDR2_SDRAM_ADDR_START;
            else
                if vsyncx_node='0' then
                    addr_cnt <= DDR2_SDRAM_ADDR_START;
                elsif rd_dst_rdy='1' and Bus2IP_MstRd_src_rdy_n='0' then
                    addr_cnt <= addr_cnt + 4;
                end if;
            end if;
        end if;
    end process;
    
    -- mst_addr の処理、コマンド転送の初めにaddr_cnt をmst_addr にコピーする
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                mst_addr <= DDR2_SDRAM_ADDR_START;
            else
                if cs_rd=TRANS_COUNT_SET then
                    mst_addr <= addr_cnt;
                end if;
            end if;
        end if;
    end process;
    
    IP2Bus_Mst_Addr <= mst_addr;

end RTL;


次に、Disp_Controller_Top_tb.vhdを下に示す。

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
 
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--USE ieee.numeric_std.ALL;
 
ENTITY Disp_Controller_Top_tb IS
END Disp_Controller_Top_tb;
 
ARCHITECTURE behavior OF Disp_Controller_Top_tb IS 
    constant C_MST_DWIDTH : integer := 32;

    -- wait を入れるバースト位置、バーストの最初と最後でwaitすることはできない。0を入れるとwaitはなしになる
    constant    RDY_WAIT_VAL1    : integer := 10;
    constant    RDY_WAIT_VAL2    : integer := 5;
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT Disp_Controller_Top
    generic(
        C_SLV_DWIDTH                   : integer              := 32;
        C_MST_AWIDTH                   : integer              := 32;
        C_MST_DWIDTH                   : integer              := 32;
        C_NUM_REG                      : integer              := 3
    );
    PORT(
         red_out : OUT  std_logic_vector(3 downto 0);
         green_out : OUT  std_logic_vector(3 downto 0);
         blue_out : OUT  std_logic_vector(3 downto 0);
         hsyncx : OUT  std_logic;
         vsyncx : OUT  std_logic;
         Bus2IP_Clk : IN  std_logic;
         Bus2IP_Reset : IN  std_logic;
         IP2Bus_MstRd_Req : OUT  std_logic;
         IP2Bus_MstWr_Req : OUT  std_logic;
         IP2Bus_Mst_Addr : OUT  std_logic_vector(0 to 31);
         IP2Bus_Mst_BE : OUT  std_logic_vector(0 to 3);
         IP2Bus_Mst_Length : OUT  std_logic_vector(0 to 11);
         IP2Bus_Mst_Type : OUT  std_logic;
         IP2Bus_Mst_Lock : OUT  std_logic;
         IP2Bus_Mst_Reset : OUT  std_logic;
         Bus2IP_Mst_CmdAck : IN  std_logic;
         Bus2IP_Mst_Cmplt : IN  std_logic;
         Bus2IP_Mst_Error : IN  std_logic;
         Bus2IP_Mst_Rearbitrate : IN  std_logic;
         Bus2IP_Mst_Cmd_Timeout : IN  std_logic;
         Bus2IP_MstRd_d : IN  std_logic_vector(0 to 31);
         Bus2IP_MstRd_rem : IN  std_logic_vector(0 to 3);
         Bus2IP_MstRd_sof_n : IN  std_logic;
         Bus2IP_MstRd_eof_n : IN  std_logic;
         Bus2IP_MstRd_src_rdy_n : IN  std_logic;
         Bus2IP_MstRd_src_dsc_n : IN  std_logic;
         IP2Bus_MstRd_dst_rdy_n : OUT  std_logic;
         IP2Bus_MstRd_dst_dsc_n : OUT  std_logic;
         IP2Bus_MstWr_d : OUT  std_logic_vector(0 to 31);
         IP2Bus_MstWr_rem : OUT  std_logic_vector(0 to 3);
         IP2Bus_MstWr_sof_n : OUT  std_logic;
         IP2Bus_MstWr_eof_n : OUT  std_logic;
         IP2Bus_MstWr_src_rdy_n : OUT  std_logic;
         IP2Bus_MstWr_src_dsc_n : OUT  std_logic;
         afifo_overflow : OUT  std_logic;
         afifo_underflow : OUT  std_logic;
         addr_is_zero : OUT  std_logic;
         h_v_is_zero : OUT  std_logic
        );
    END COMPONENT;
    

   --Inputs
   signal Bus2IP_Clk : std_logic := '0';
   signal Bus2IP_Reset : std_logic := '0';
   signal Bus2IP_Mst_CmdAck : std_logic := '0';
   signal Bus2IP_Mst_Cmplt : std_logic := '0';
   signal Bus2IP_Mst_Error : std_logic := '0';
   signal Bus2IP_Mst_Rearbitrate : std_logic := '0';
   signal Bus2IP_Mst_Cmd_Timeout : std_logic := '0';
   signal Bus2IP_MstRd_d : std_logic_vector(0 to 31) := (others => '0');
   signal Bus2IP_MstRd_rem : std_logic_vector(0 to 3) := (others => '0');
   signal Bus2IP_MstRd_sof_n : std_logic := '1';
   signal Bus2IP_MstRd_eof_n : std_logic := '1';
   signal Bus2IP_MstRd_src_rdy_n : std_logic := '1';
   signal Bus2IP_MstRd_src_dsc_n : std_logic := '1';

     --Outputs
   signal red_out : std_logic_vector(3 downto 0);
   signal green_out : std_logic_vector(3 downto 0);
   signal blue_out : std_logic_vector(3 downto 0);
   signal hsyncx : std_logic;
   signal vsyncx : std_logic;
   signal IP2Bus_MstRd_Req : std_logic;
   signal IP2Bus_MstWr_Req : std_logic;
   signal IP2Bus_Mst_Addr : std_logic_vector(0 to 31);
   signal IP2Bus_Mst_BE : std_logic_vector(0 to 3);
   signal IP2Bus_Mst_Length : std_logic_vector(0 to 11);
   signal IP2Bus_Mst_Type : std_logic;
   signal IP2Bus_Mst_Lock : std_logic;
   signal IP2Bus_Mst_Reset : std_logic;
   signal IP2Bus_MstRd_dst_rdy_n : std_logic;
   signal IP2Bus_MstRd_dst_dsc_n : std_logic;
   signal IP2Bus_MstWr_d : std_logic_vector(0 to 31);
   signal IP2Bus_MstWr_rem : std_logic_vector(0 to 3);
   signal IP2Bus_MstWr_sof_n : std_logic;
   signal IP2Bus_MstWr_eof_n : std_logic;
   signal IP2Bus_MstWr_src_rdy_n : std_logic;
   signal IP2Bus_MstWr_src_dsc_n : std_logic;
   signal afifo_overflow : std_logic;
   signal afifo_underflow : std_logic;
   signal addr_is_zero : std_logic;
   signal h_v_is_zero : std_logic;

   type CMD_ACK_STATE is (IDLE_CMD_ACK, CMD_TRANS_1, CMD_TRANS_2, CMD_TRANS_3, CMD_TRANS_4, CMD_ACK_ST);
   signal cs_cmd_ack : CMD_ACK_STATE;
   signal cmd_ack : std_logic;
   type DATA_RD_STATE is (IDLE_DATA_RD, SOF_ASSORT, RD_DATA_OUT, EOF_ASSORT, RD_DATA_COMPLT);
   signal cs_data_rd : DATA_RD_STATE;
   signal trans_count : std_logic_vector(4 downto 0);
   signal data : std_logic_vector(31 downto 0);
   signal mst_rd_rdy, mst_rd_rdy_1d : std_logic;
   
   -- Clock period definitions
   constant Bus2IP_Clk_period : time := 16 ns; -- 62.5MHz
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: Disp_Controller_Top
        generic map(
            C_MST_AWIDTH => 32,
            C_MST_DWIDTH => C_MST_DWIDTH
        )PORT MAP (
          red_out => red_out,
          green_out => green_out,
          blue_out => blue_out,
          hsyncx => hsyncx,
          vsyncx => vsyncx,
          Bus2IP_Clk => Bus2IP_Clk,
          Bus2IP_Reset => Bus2IP_Reset,
          IP2Bus_MstRd_Req => IP2Bus_MstRd_Req,
          IP2Bus_MstWr_Req => IP2Bus_MstWr_Req,
          IP2Bus_Mst_Addr => IP2Bus_Mst_Addr,
          IP2Bus_Mst_BE => IP2Bus_Mst_BE,
          IP2Bus_Mst_Length => IP2Bus_Mst_Length,
          IP2Bus_Mst_Type => IP2Bus_Mst_Type,
          IP2Bus_Mst_Lock => IP2Bus_Mst_Lock,
          IP2Bus_Mst_Reset => IP2Bus_Mst_Reset,
          Bus2IP_Mst_CmdAck => Bus2IP_Mst_CmdAck,
          Bus2IP_Mst_Cmplt => Bus2IP_Mst_Cmplt,
          Bus2IP_Mst_Error => Bus2IP_Mst_Error,
          Bus2IP_Mst_Rearbitrate => Bus2IP_Mst_Rearbitrate,
          Bus2IP_Mst_Cmd_Timeout => Bus2IP_Mst_Cmd_Timeout,
          Bus2IP_MstRd_d => Bus2IP_MstRd_d,
          Bus2IP_MstRd_rem => Bus2IP_MstRd_rem,
          Bus2IP_MstRd_sof_n => Bus2IP_MstRd_sof_n,
          Bus2IP_MstRd_eof_n => Bus2IP_MstRd_eof_n,
          Bus2IP_MstRd_src_rdy_n => Bus2IP_MstRd_src_rdy_n,
          Bus2IP_MstRd_src_dsc_n => Bus2IP_MstRd_src_dsc_n,
          IP2Bus_MstRd_dst_rdy_n => IP2Bus_MstRd_dst_rdy_n,
          IP2Bus_MstRd_dst_dsc_n => IP2Bus_MstRd_dst_dsc_n,
          IP2Bus_MstWr_d => IP2Bus_MstWr_d,
          IP2Bus_MstWr_rem => IP2Bus_MstWr_rem,
          IP2Bus_MstWr_sof_n => IP2Bus_MstWr_sof_n,
          IP2Bus_MstWr_eof_n => IP2Bus_MstWr_eof_n,
          IP2Bus_MstWr_src_rdy_n => IP2Bus_MstWr_src_rdy_n,
          IP2Bus_MstWr_src_dsc_n => IP2Bus_MstWr_src_dsc_n,
          afifo_overflow => afifo_overflow,
          afifo_underflow => afifo_underflow,
          addr_is_zero => addr_is_zero,
          h_v_is_zero => h_v_is_zero
        );
    Bus2IP_Mst_Error <= '0';
    Bus2IP_Mst_Rearbitrate <= '0';
    Bus2IP_Mst_Cmd_Timeout <= '0';
    IP2Bus_MstWr_rem <= (others => '0');
    Bus2IP_MstRd_src_dsc_n <= '1';
    
   -- Clock process definitions
   Bus2IP_Clk_process :process
   begin
        Bus2IP_Clk <= '0';
        wait for Bus2IP_Clk_period/2;
        Bus2IP_Clk <= '1';
        wait for Bus2IP_Clk_period/2;
   end process;

   -- IPIC のマスタRead, Writeの対応をするモジュール、バースト対応のみ  
   -- まず、コマンド転送に応答して、Bus2IP_Mst_CmdAck を返す
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_cmd_ack <= IDLE_CMD_ACK;
                cmd_ack <= '0';
            else
                case cs_cmd_ack is
                    when IDLE_CMD_ACK =>
                        if IP2Bus_MstRd_Req='1' or IP2Bus_MstWr_Req='1' then
                            cs_cmd_ack <= CMD_TRANS_1;
                        end if;
                    when CMD_TRANS_1 =>
                        cs_cmd_ack <= CMD_TRANS_2;
                    when CMD_TRANS_2 =>
                        cs_cmd_ack <= CMD_TRANS_3;
                    when CMD_TRANS_3 =>
                        cs_cmd_ack <= CMD_TRANS_4;
                    when CMD_TRANS_4 =>
                        cs_cmd_ack <= CMD_ACK_ST;
                        cmd_ack <= '1';
                    when CMD_ACK_ST =>
                        cs_cmd_ack <= IDLE_CMD_ACK;
                        cmd_ack <= '0';
                end case;
            end if;
        end if;
    end process;
    Bus2IP_Mst_CmdAck <= cmd_ack;

    -- Readデータを出力するステートマシン
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_data_rd <= IDLE_DATA_RD;
                Bus2IP_MstRd_sof_n <= '1';
                Bus2IP_MstRd_eof_n <= '1';
                Bus2IP_Mst_Cmplt <= '0';
            else
                case cs_data_rd is
                    when IDLE_DATA_RD =>
                        if cmd_ack='1' then
                            cs_data_rd <= SOF_ASSORT;
                            Bus2IP_MstRd_sof_n <= '0';
                        end if;
                    when SOF_ASSORT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            cs_data_rd <= RD_DATA_OUT;
                            Bus2IP_MstRd_sof_n <= '1';
                        end if;
                    when RD_DATA_OUT =>
                        if trans_count=2 and mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            cs_data_rd <= EOF_ASSORT;
                            Bus2IP_MstRd_eof_n <= '0';
                        end if;
                    when EOF_ASSORT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            cs_data_rd <= RD_DATA_COMPLT;
                            Bus2IP_MstRd_eof_n <= '1';
                            Bus2IP_Mst_Cmplt <= '1';
                        end if;
                    when RD_DATA_COMPLT =>
                        cs_data_rd <= IDLE_DATA_RD;
                        Bus2IP_Mst_Cmplt <= '0';
                end case;
            end if;
        end if;
    end process;
    
    -- trans_count の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                trans_count <= CONV_STD_LOGIC_VECTOR(16,5);
            else
                case cs_data_rd is
                    when IDLE_DATA_RD =>
                        trans_count <= CONV_STD_LOGIC_VECTOR(16,5);
                    when SOF_ASSORT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            trans_count <= trans_count - 1;
                        end if;
                    when RD_DATA_OUT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            trans_count <= trans_count - 1;
                        end if;
                    when EOF_ASSORT =>
                        if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                            trans_count <= trans_count - 1;
                        end if;
                    when others =>
                end case;
            end if;
        end if;
    end process;
    
    -- data の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                data <= (others => '0');
            else
                if mst_rd_rdy='1' and IP2Bus_MstRd_dst_rdy_n='0' then
                    data <= data + 1;
                end if;
            end if;
        end if;
    end process;
    Bus2IP_MstRd_d <= data;
    
    -- Bus2IP_MstRd_src_rdy_n の処理
    process(Bus2IP_Clk) begin
        case cs_data_rd is
            when IDLE_DATA_RD =>
                mst_rd_rdy <= '0';
            when SOF_ASSORT =>
                mst_rd_rdy <= '1';
            when RD_DATA_OUT =>
                if mst_rd_rdy_1d='1' and trans_count=RDY_WAIT_VAL1 then
                    mst_rd_rdy <= '0';
                elsif mst_rd_rdy_1d='1' and trans_count=RDY_WAIT_VAL2 then
                    mst_rd_rdy <= '0';
                else
                    mst_rd_rdy <= '1';
                end if;
            when EOF_ASSORT =>
                mst_rd_rdy <= '1';
            when others =>
                mst_rd_rdy <= '0';
        end case;
    end process;
    Bus2IP_MstRd_src_rdy_n <= not mst_rd_rdy;
    
    -- mst_rd_rdy_1d の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                mst_rd_rdy_1d <= '0';
            else
                mst_rd_rdy_1d <= mst_rd_rdy;
            end if;
        end if;
    end process;
    
  -- Stimulus process
   stim_proc: process
   begin    
      Bus2IP_Reset <= '1';
      -- hold reset state for 100 ns.
      wait for 100 ns;    

      wait for Bus2IP_Clk_period*10;
      Bus2IP_Reset <= '0';

      -- insert stimulus here 

      wait;
   end process;

END behavior;


これでシミュレーションすると、1つにIPIC転送は以下のようになった。
Spa3A_SKit_OV7670_66_110910.png

これは最大の16バーストしている状態だ。Bus2IP_MstRd_src_rdy_nをデータ転送10回目と5回目にわざとディアサートしている。IP2Bus_MstRd_Reqが1になってから、Readデータが受け終わるまでに400nsec掛かっている。これは、前に述べたように2クロックWaitが入っているので、Waitが無いと、600nsec - 16nsec X 2 = 568nsec となる。

VGA_Display_Controller.v のFIFOの容量が半分を切って、requestを1にアサートする場合は、1度に128ワード(32ビット幅)のデータを要求する。IPICのバーストの単位は最大16バーストのため、バースト転送を8回行う(16X8=128)。それを下のシミュレーションに示す。
Spa3A_SKit_OV7670_67_110910.png

この間が3.424usec なので、この間に16バーストを8回行う。よって、16*8/3.424E-6 ≒ 37.4MW/sec (32bit幅)。
バイトに直すと、37.4 * 4 ≒ 150MBytes/sec となった。62.5MHz、32ビット幅の最大スルーレートは250Bytes/sec なので、約60%の帯域があることになる。案外、帯域が取れるもんだ?
(注:あくまで、現在のところの試算です。MIGのレイテンシやスループットによって変動します)

後は、次のブログで下のモジュールのHDLソースを貼ります。
  1. 2011年09月10日 20:41 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/1901-5b2e057d
この記事にトラックバックする(FC2ブログユーザー)