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

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

FPGAの部屋

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

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

Spartan-3A Starter KitでEDKを使ってカメラ表示8(HDLを書く)”の続き。

今回は、やっとVHDLを書き終えたので、シミュレーションをしてみた。

user_logic.vhdの下位モジュールとして、IPICとインターフェースするためのCam_Controller_Top.vhd を作成した。これは、CMOSカメラのコントロール用の回路(Camera_Cntrler.v) とIPIC (IP Interconnect) をインターフェースする回路だ。IPICはPLB4.6に変換されて、XPSのバスに接続される。カメラ回路ではマスタとしては、WriteのみでReadはない。よって、マスタWriteのみ実装している。
下に、Cam_Controller_Top.vhd を示す。VHDLなんでちょっと長いのだけれど、雰囲気を感じてもらえば良いと思う。
(2011/09/01 20:25 : VHDLコードを修正しました。ip2bus_mstwr_reqが1の間、ip2bus_mst_addrの値を固定しました, addr_cntを追加)

-- Cam_Controller_Top.vhd
-- Camera_Cntrler.v とsynchronizer.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 Cam_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(
        cam_href    : in std_logic;    -- CMOSカメラからのHREF
        cam_vsync     : in std_logic;    -- CMOSカメラからのVSYNC
        cam_pclk    : in std_logic;    -- CMOSカメラからのpclk
        cam_data    : in std_logic_vector(7 downto 0);    -- CMOSカメラからのデータ
        cam_clk        : 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;
        
        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;
        Bus2IP_MstWr_dst_rdy_n         : in  std_logic;
        Bus2IP_MstWr_dst_dsc_n         : in  std_logic;

        IP2Bus_MstRd_dst_rdy_n         : out std_logic;
        IP2Bus_MstRd_dst_dsc_n         : out std_logic;
        
        afifo_overflow                    : out std_logic;
        afifo_underflow                    : out std_logic
    );
end Cam_Controller_Top;

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

component Camera_Cntrler
    port(
        clk_cam        : in std_logic;
        clk_ddr2    : in std_logic;
        reset_cam    : in std_logic;
        reset_ddr2    : in std_logic;
        cam_href_2d    : in std_logic;
        cam_vsync_2d    : in std_logic;
        master_sync    : in std_logic;
        cam_data_2d    : in std_logic_vector(7 downto 0);
        address        : out std_logic_vector(18 downto 0);
        data_out    : out std_logic_vector(31 downto 0);
        addr_enable    : in std_logic;
        data_enable    : in std_logic;
        capture_ena    : in std_logic;
        afifo_empty    : out std_logic;
        afifo_rd_data_count    : out std_logic_vector(7 downto 0);
        afifo_overflow    : out std_logic;
        afifo_underflow    : out std_logic
    );
end component;
component synchronizer
    port(
        clk            : in std_logic;
        reset        : in std_logic;
        cam_vsync_1d    : in std_logic;
        cam_href_1d        : in std_logic;
        master_sync        : out std_logic
    );
end component;
component dcm_CAM_clk
    port(
        sysclk        : in std_logic;
        reset        : in std_logic;
        clk_cam        : out std_logic;
        dcm_locked_out    : out std_logic
    );
end component;

signal cam_href_1d, cam_href_2d : std_logic;
signal cam_vsync_1d, cam_vsync_2d : std_logic;
signal cam_data_1d, cam_data_2d : std_logic_vector(7 downto 0);
signal addr_ena, data_ena : std_logic;
signal master_sync : std_logic;
signal dcm_locked : std_logic;
signal clk_cam : std_logic;
signal reset_cam_node, reset_cam : std_logic;
signal reset_cam_srl : std_logic;
signal reset_cam_srl_1d, reset_cam_srl_2d : std_logic;
signal camc_addr : std_logic_vector(18 downto 0);
signal camc_data : std_logic_vector(31 downto 0);
signal afifo_empty : std_logic;
signal afifo_rd_data_count : std_logic_vector(7 downto 0);
type MST_TRANS_STATE is (IDLE_WR, COUNTER_SET, MPMC_WRITE_ST);
signal cs_wr : MST_TRANS_STATE;
type MST_CMD_STATE is (IDLE_CMD, CMD_ASSORT, WAIT_TRANSACTION);
signal cs_cmd : MST_CMD_STATE;
signal trans_count, trans_val : std_logic_vector(4 downto 0);
type MST_SOF_STATE is (IDLE_SOF, SOF_ASSORT, SOF_HOLD);
signal cs_wr_sof : MST_SOF_STATE;
signal wr_sof : std_logic;
signal wr_eof : std_logic;
signal wr_src_rdy : std_logic;
signal mst_addr, addr_cnt : std_logic_vector(31 downto 0);

begin
    IP2Bus_MstRd_Req <= '0';
    IP2Bus_Mst_Lock <= '0';
    IP2Bus_Mst_Reset <= '0';
    IP2Bus_MstRd_dst_rdy_n <= '1';
    IP2Bus_MstRd_dst_dsc_n <= '1';
    
    dcm_CAM_clk_inst : dcm_CAM_clk port map(
        sysclk => Bus2IP_Clk,
        reset => Bus2IP_Reset,
        clk_cam => clk_cam,
        dcm_locked_out => dcm_locked
    );
    reset_cam_node <= not dcm_locked;
    
    -- reset_cam を16クロック遅延される。クロックが出始めてすぐ、dcm_lockedが1になるため同期リセットFFがリセットされない。
    SRL16E_SDA_ena : SRL16E generic map(
        INIT => X"0000")
    port map(
        Q => reset_cam_srl,
        A0 => '1',
        A1 => '1',
        A2 => '1',
        A3 => '1',
        CE => '1',
        CLK => Bus2IP_Clk,
        D => reset_cam_node
    ); 
    
    -- clk_cam で同期化
    process(clk_cam) begin
        if clk_cam'event and clk_cam='1' then
            reset_cam_srl_1d <= reset_cam_srl;
            reset_cam_srl_2d <= reset_cam_srl_1d;
        end if;
    end process;
    reset_cam <= reset_cam_srl_2d;
    
    cam_clk <= clk_cam;
    
    process(clk_cam) begin
        if clk_cam'event and clk_cam='1' then
            if (reset_cam='1') then
                cam_vsync_1d <= '0';
                cam_vsync_2d <= '0';
                cam_href_1d <= '0';
                cam_href_2d <= '0';
                cam_data_1d <= (others => '0');
                cam_data_2d <= (others => '0');
            else
                cam_vsync_1d <= cam_vsync;
                cam_vsync_2d <= cam_vsync_1d;
                cam_href_1d <= cam_href;
                cam_href_2d <= cam_href_1d;
                cam_data_1d <= cam_data;
                cam_data_2d <= cam_data_1d;
            end if;
        end if;
    end process;
    
    Camera_Cntrler_inst : Camera_Cntrler port map(
        clk_cam => clk_cam,
        clk_ddr2 => Bus2IP_Clk,
        reset_cam => reset_cam,
        reset_ddr2 => Bus2IP_Reset,
        cam_href_2d => cam_href_2d,
        cam_vsync_2d => cam_vsync_2d,
        master_sync => master_sync,
        cam_data_2d => cam_data_2d,
        address => camc_addr,
        data_out => camc_data,
        addr_enable => addr_ena,
        data_enable => data_ena,
        capture_ena => '1',
        afifo_empty => afifo_empty,
        afifo_rd_data_count => afifo_rd_data_count,
        afifo_overflow => afifo_overflow,
        afifo_underflow => afifo_underflow
    );
    addr_ena <= '0';
    
    synchronizer_inst : synchronizer port map(
        clk => clk_cam,
        reset => reset_cam,
        cam_vsync_1d => cam_vsync_1d,
        cam_href_1d => cam_href_1d,
        master_sync => master_sync
    );
    
    -- afifo_rd_data_count が16以上になったらMPMCへWrite
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_wr <= IDLE_WR;
            else
                case cs_wr is
                    when IDLE_WR =>
                        if afifo_rd_data_count(7 downto 4)/=0 then -- 16以上
                            cs_wr <= COUNTER_SET;
                        end if;
                    when COUNTER_SET =>
                        cs_wr <= MPMC_WRITE_ST;
                    when MPMC_WRITE_ST =>
                        if trans_count=0 then
                            cs_wr <= IDLE_WR;
                        end if;
                end case;
            end if;
        end if;
    end process;
    
    IP2Bus_Mst_BE <= (others => '1');
    IP2Bus_Mst_Length <= CONV_STD_LOGIC_VECTOR(64, 12); -- 128バイト、32ビット幅、16バースト
    IP2Bus_MstWr_src_dsc_n <= '1';
    IP2Bus_MstWr_rem <= (others => '0');
    
    -- コマンド用ステートマシン
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_cmd <= IDLE_CMD;
                IP2Bus_MstWr_Req <= '0';
                IP2Bus_Mst_Type <= '0';
            else
                case cs_cmd is
                    when IDLE_CMD =>
                        if cs_wr=COUNTER_SET then
                            cs_cmd <= CMD_ASSORT;
                            IP2Bus_MstWr_Req <= '1';
                            IP2Bus_Mst_Type <= '1';
                        end if;
                    when CMD_ASSORT =>
                        if Bus2IP_Mst_CmdAck='1' then
                            cs_cmd <= WAIT_TRANSACTION;
                            IP2Bus_MstWr_Req <= '0';
                            IP2Bus_Mst_Type <= '0';
                        end if;
                    when WAIT_TRANSACTION =>
                        if Bus2IP_Mst_Cmplt='1' then
                            cs_cmd <= IDLE_CMD;
                            IP2Bus_MstWr_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');
                trans_val <= (others => '0');
            else 
                if cs_wr=COUNTER_SET then
                    trans_count <= "10000";
                    trans_val <= "10000";
                elsif cs_wr=MPMC_WRITE_ST and trans_count/=0 and Bus2IP_MstWr_dst_rdy_n='0' then
                    trans_count <= trans_count - 1;
                elsif cs_wr=IDLE_WR then
                    trans_val <= (others => '0');
                end if;
            end if;
        end if;
    end process;
    
    -- IP2Bus_MstWr_sof_n のアサート
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_wr_sof <= IDLE_SOF;
                wr_sof <= '0';
            else
                case cs_wr_sof is
                    when IDLE_SOF =>
                        if cs_wr=COUNTER_SET then
                            cs_wr_sof <= SOF_ASSORT;
                            wr_sof <= '1';
                        end if;
                    when SOF_ASSORT =>
                        if cs_wr=MPMC_WRITE_ST and trans_val=trans_count and Bus2IP_MstWr_dst_rdy_n='0' then
                            cs_wr_sof <= SOF_HOLD;
                            wr_sof <= '0';
                        end if;
                    when SOF_HOLD =>
                        if cs_wr=MPMC_WRITE_ST and trans_count=0 then
                            cs_wr_sof <= IDLE_SOF;
                            wr_sof <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    IP2Bus_MstWr_sof_n <= not wr_sof;
    
    -- IP2Bus_MstWr_eof_n のアサート
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                wr_eof <= '0';
            elsif trans_count=2 and Bus2IP_MstWr_dst_rdy_n='0' then
                wr_eof <= '1';
            elsif trans_count=1 and Bus2IP_MstWr_dst_rdy_n='0' then
                wr_eof <= '0';
            end if;
        end if;
    end process;
    IP2Bus_MstWr_eof_n <= not wr_eof;
    
    -- IP2Bus_MstWr_src_rdy_n のアサート
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                wr_src_rdy <= '0';
            elsif cs_wr=COUNTER_SET then
                wr_src_rdy <= '1';
            elsif trans_count=1 and Bus2IP_MstWr_dst_rdy_n='0' then
                wr_src_rdy <= '0';
            end if;
        end if;
    end process;
    IP2Bus_MstWr_src_rdy_n <= not wr_src_rdy;
    
    IP2Bus_MstWr_d <= camc_data;
    
    -- 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 cam_vsync_1d='1' then
                    addr_cnt <= DDR2_SDRAM_ADDR_START;
                elsif wr_src_rdy='1' and Bus2IP_MstWr_dst_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_wr=COUNTER_SET then
                    mst_addr <= addr_cnt;
                end if;
            end if;
        end if;
    end process;
    
    IP2Bus_Mst_Addr <= mst_addr;
    
    data_ena <= '1' when wr_src_rdy='1' and Bus2IP_MstWr_dst_rdy_n='0' else '0';

end RTL;


これのテストベンチとして、Cam_Controller_Top_tb.vhd を作った。ここには、IPICのインターフェースを組み込んであって、Cam_Controller_Top.vhd の相手をするようになっている。更に、CMOSカメラのモデル(OV7670_Model.v)をつないでいる。Cam_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 Cam_Controller_Top_tb IS
END Cam_Controller_Top_tb;
 
ARCHITECTURE behavior OF Cam_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 Cam_Controller_Top
    generic(
        C_SLV_DWIDTH                   : integer              := 32;
        C_MST_AWIDTH                   : integer              := 32;
        C_MST_DWIDTH                   : integer              := 32;
        C_NUM_REG                      : integer              := 3
    );
    PORT(
         cam_href : IN  std_logic;
         cam_vsync : IN  std_logic;
         cam_pclk : IN  std_logic;
         cam_data : IN  std_logic_vector(7 downto 0);
         cam_clk : 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 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;
         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;
         Bus2IP_MstWr_dst_rdy_n : IN  std_logic;
         Bus2IP_MstWr_dst_dsc_n : IN  std_logic;
         IP2Bus_MstRd_dst_rdy_n : OUT  std_logic;
         IP2Bus_MstRd_dst_dsc_n : OUT  std_logic;
         afifo_overflow : OUT  std_logic;
         afifo_underflow : OUT  std_logic
        );
    END COMPONENT;
    
    component OV7670_Model
        port(
            clk : in std_logic;
            resetx : in std_logic;
            vsync : out std_logic;
            href : out std_logic;
            pclk : out std_logic;
            ydata : out std_logic_vector(7 downto 0)
        );
    end component;
    
   --Inputs
   signal cam_href : std_logic := '0';
   signal cam_vsync : std_logic := '0';
   signal cam_pclk : std_logic := '0';
   signal cam_data : std_logic_vector(7 downto 0) := (others => '0');
   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_MstWr_dst_rdy_n : std_logic := '1';
   signal Bus2IP_MstWr_dst_dsc_n : std_logic := '1';

     --Outputs
   signal cam_clk : 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_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 IP2Bus_MstRd_dst_rdy_n : std_logic;
   signal IP2Bus_MstRd_dst_dsc_n : std_logic;
   signal afifo_overflow : std_logic;
   signal afifo_underflow : 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 MST_WR_TRANS_STATE is (IDLE_MST_D, LOAD_COUNT_MST_D, MST_WR_TRANS_ST, COMPLETE_MST_D);
   signal cs_mst_d : MST_WR_TRANS_STATE;
   signal mst_wr_cnt, mst_length : std_logic_vector(11 downto 0);
    signal cam_resetx : std_logic;

   -- Clock period definitions
   constant Bus2IP_Clk_period : time := 16 ns; -- 62.5MHz
 
BEGIN
 
    -- Instantiate the Unit Under Test (UUT)
   uut: Cam_Controller_Top 
        generic map(
            C_MST_AWIDTH => 32,
            C_MST_DWIDTH => C_MST_DWIDTH
        ) PORT MAP (
          cam_href => cam_href,
          cam_vsync => cam_vsync,
          cam_pclk => cam_pclk,
          cam_data => cam_data,
          cam_clk => cam_clk,
          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,
          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,
          Bus2IP_MstWr_dst_rdy_n => Bus2IP_MstWr_dst_rdy_n,
          Bus2IP_MstWr_dst_dsc_n => Bus2IP_MstWr_dst_dsc_n,
          IP2Bus_MstRd_dst_rdy_n => IP2Bus_MstRd_dst_rdy_n,
          IP2Bus_MstRd_dst_dsc_n => IP2Bus_MstRd_dst_dsc_n,
          afifo_overflow => afifo_overflow,
          afifo_underflow => afifo_underflow
        );

   -- 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;
    
    -- バーストWriteを受ける
    -- IP2Bus_Mst_Lengthはバイト単位なので、C_MST_DWIDTH/8 で割ってバースト長を計算する
    -- データ転送の状態を表すステートマシン
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                cs_mst_d <= IDLE_MST_D;
                Bus2IP_Mst_Cmplt <= '0';
            else
                case cs_mst_d is
                    when IDLE_MST_D =>
                        Bus2IP_Mst_Cmplt <= '0';
                        if IP2Bus_MstWr_Req='1' then
                            cs_mst_d <= LOAD_COUNT_MST_D;
                        end if;
                    when LOAD_COUNT_MST_D =>
                        cs_mst_d <= MST_WR_TRANS_ST;
                    when MST_WR_TRANS_ST =>
                        if mst_wr_cnt=(C_MST_DWIDTH/8) and IP2Bus_MstWr_src_rdy_n='0' and Bus2IP_MstWr_dst_rdy_n='0' then
                            cs_mst_d <= COMPLETE_MST_D;
                            Bus2IP_Mst_Cmplt <= '1';
                        end if;
                    when COMPLETE_MST_D =>
                        cs_mst_d <= IDLE_MST_D;
                        Bus2IP_Mst_Cmplt <= '0';
                end case;
            end if;
        end if;
    end process;
    
    -- mst_wr_cnt の処理
    process(Bus2IP_Clk) begin
        if Bus2IP_Clk'event and Bus2IP_Clk='1' then
            if Bus2IP_Reset='1' then
                mst_wr_cnt <= (others => '0');
                mst_length <= (others => '0');
                Bus2IP_MstWr_dst_rdy_n <= '1';
            else
                if cs_mst_d=LOAD_COUNT_MST_D then
                    mst_wr_cnt <= IP2Bus_Mst_Length;
                    mst_length <= IP2Bus_Mst_Length;
                    Bus2IP_MstWr_dst_rdy_n <= '0';
                elsif cs_mst_d=MST_WR_TRANS_ST then
                    if Bus2IP_MstWr_dst_rdy_n='0' then
                        mst_wr_cnt <= mst_wr_cnt - (C_MST_DWIDTH/8);
                    end if;

                    if mst_wr_cnt=((RDY_WAIT_VAL1+1)*(C_MST_DWIDTH/8)) and Bus2IP_MstWr_dst_rdy_n='0' then -- 1度wait
                        Bus2IP_MstWr_dst_rdy_n <= '1';
                    elsif mst_wr_cnt=((RDY_WAIT_VAL2+1)*(C_MST_DWIDTH/8)) and Bus2IP_MstWr_dst_rdy_n='0' then -- 1度wait
                        Bus2IP_MstWr_dst_rdy_n <= '1';
                    elsif mst_wr_cnt=(C_MST_DWIDTH/8) and IP2Bus_MstWr_src_rdy_n='0' and Bus2IP_MstWr_dst_rdy_n='0' then -- 最後なので、レディを1にする
                        Bus2IP_MstWr_dst_rdy_n <= '1';
                    else
                        Bus2IP_MstWr_dst_rdy_n <= '0';
                    end if;
                else
                    Bus2IP_MstWr_dst_rdy_n <= '1';
                end if;
            end if;
        end if;
    end process;
    
    Bus2IP_MstWr_dst_dsc_n <= '1';
    Bus2IP_Mst_Error <= '0';
    Bus2IP_Mst_Rearbitrate <= '0';
    Bus2IP_Mst_Cmd_Timeout <= '0';
    
    
    -- OV7670_Model のインスタンス
    cam_resetx <= not Bus2IP_Reset;
    OV7670_Model_inst : OV7670_Model port map(
        clk => cam_clk,
        resetx => cam_resetx,
        vsync => cam_vsync,
        href => cam_href,
        pclk => cam_pclk,
        ydata => cam_data
    );
        
    
  -- 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;


すべてのファイルは貼れないので、この辺でProject Navigatorでプロジェクトを作って、VHDLファイルのデバックをするためにシミュレーションを行った。
Spa3A_SKit_OV7670_61_110901.png

dcm_CAM_clk.v はBus2IP_Clkの62.5MHzをピクセル・クロックの25MHzに変換するDCMモジュールだ。synchronizer.v はカメラのピクセル・データのはじめにmaster_sync信号を出力する回路となっている。
さて、これでSimulate Behavioral Model をダブルクリックしてISimでシミュレーションを行った結果を下に示す。
Spa3A_SKit_OV7670_59_110831.png

(ip2bus_mst_addrがip2bus_mstwr_reqが1の間に変化しています。これではまずいので、後で修正します)
(2011/09/01 20:25 : 画像を修正しました。ip2bus_mstwr_reqが1の間、ip2bus_mst_addrの値を固定しました)

これは、マスタWrite(カメラ回路なので)を行っているところだ。ここでは、テストベンチで7番目と12番目にわざとBus2IP_MstWr_dst_rdy_n を非アクティブにして、処理を遅延させている。Bus2IP_MstWr_dst_rdy_n を非アクティブにする位置はconstant値で設定することができる。
カメラ回路から入力されたデータは、1データ16ビットで、非同期FIFO(cam_cont_afifo)に入力されて、32個(32ビット幅で16個)たまったら32ビット幅で16個バーストで出力される。もう少し時間を縮めると、その様子がよくわかる。その図を下に示す。
Spa3A_SKit_OV7670_60_110831.png

(2011/09/01 20:25 : 画像を修正しました。ip2bus_mstwr_reqが1の間、ip2bus_mst_addrの値を固定しました)

その時間間隔は2.56usec となった。
64バイトを2.56usecごとに転送しているので、スループットは64Bytes / 2.54usec = 25MBytes/secとなる。
最大スループットは、4Bytes x 62.5MHz = 250MBytes/sec で、ちょうど最大スループットの1/10となっている。

ちなみに、Spartan-3A Starter Kit の EDK 使用時のDDR2 SDRAMの最大スループットは、125MHz x 2(DDR) x 2Bytes(16ビット幅) = 496MBytes/sec だ。

  1. 2011年09月01日 05:16 |
  2. EDK
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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