FC2カウンター FPGAの部屋 カメラ-AXI4-Stream出力IPの作製3(論理合成用HDLソースの公開)

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

FPGAの部屋

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

カメラ-AXI4-Stream出力IPの作製3(論理合成用HDLソースの公開)

カメラ-AXI4-Stream出力IPの作製2(論理シミュレーション)”の続き。

今回は、前回の論理シミュレーションで問題なかった論理合成用のHDLソースコードを貼っておく。

まずは、トップの mt9d111_inf_axims.vhd から貼っておく。

-------------------------------------------------------------------------------
--
-- AXI Stream
--
-- VHDL-Standard:   VHDL'93
----------------------------------------------------------------------------
--
-- Structure:
--   mt9d111_inf_axims
--
----------------------------------------------------------------------------
--
-- 2014/11/07 : AXI4 Lite Slave を追加
-- 2014/11/08 : one_shot_reg を実装。
-- オフセット0番地: フレーム・バッファの先頭アドレス(fb_start_address)
-- オフセット4番地: 0 ビット目が 0 の時動画、0 ビット目に 1 の時に、ワンショットで取得した1フレームのカメラ画像を表示(one_shot_reg)
--            1 ビット目に 1 を Write した時に、ワンショットで1フレームの画像をフレーム・バッファに保存
-- 2015/05/09 : AXI4 Master から AXI4 Master Stream にインターフェースを変更、generic map, port map は ar37425\axi_stream_v1_00_a\hdl\vhdl の axi_stream.vhd から引用した
--                 AXI4 Stream なので、fb_start_address は使用しない。そこに書き込まれたというスタート信号だけを使用する


library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;

--library unisim;
--use unisim.vcomponents.all;

entity mt9d111_inf_axis is
  generic(
    -- AXI4 Lite Slave Interface
    C_S_AXI_LITE_ADDR_WIDTH         : integer       := 9; -- Address width of the AXI Lite Interface
    C_S_AXI_LITE_DATA_WIDTH         : integer       := 32; -- Data width of the AXI Lite Interface

    -- AXI4 Stream Master Interface
    C_M_AXIS_DATA_WIDTH : integer range 32 to 256 := 32  -- Master AXI Stream Data Width  
  );
  port (
    -- Global Ports
    s_axi_lite_aclk                : in   std_logic;
    m_axis_aclk                    : in std_logic;
    axi_resetn                     : in std_logic;

    -- Master Stream Ports
    -- m_axis_aresetn : out std_logic;
    m_axis_tdata   : out std_logic_vector(C_M_AXIS_DATA_WIDTH-1 downto 0);
    m_axis_tstrb   : out std_logic_vector((C_M_AXIS_DATA_WIDTH/8)-1 downto 0);
    m_axis_tvalid  : out std_logic;
    m_axis_tready  : in  std_logic;
    m_axis_tlast   : out std_logic;
    m_axis_tuser   : out std_logic_vector(0 downto 0);

    -- AXI Lite Slave Ports
    s_axi_lite_awvalid          : in  std_logic;
    s_axi_lite_awready          : out std_logic;
    s_axi_lite_awaddr           : in  std_logic_vector(C_S_AXI_LITE_ADDR_WIDTH-1 downto 0);

    -- AXI Lite Write Data Channel --
    s_axi_lite_wvalid           : in  std_logic;
    s_axi_lite_wready           : out std_logic;
    s_axi_lite_wdata            : in  std_logic_vector(C_S_AXI_LITE_DATA_WIDTH-1 downto 0);

    -- AXI Lite Write Response Channel --
    s_axi_lite_bresp            : out std_logic_vector(1 downto 0);
    s_axi_lite_bvalid           : out std_logic;
    s_axi_lite_bready           : in  std_logic;

    -- AXI Lite Read Address Channel --
    s_axi_lite_arvalid          : in  std_logic;
    s_axi_lite_arready          : out std_logic;
    s_axi_lite_araddr           : in  std_logic_vector(C_S_AXI_LITE_ADDR_WIDTH-1 downto 0);
    
    -- AXI Lite Read Data Channel --
    s_axi_lite_rvalid           : out std_logic;
    s_axi_lite_rready           : in  std_logic;
    s_axi_lite_rdata            : out std_logic_vector(C_S_AXI_LITE_DATA_WIDTH-1 downto 0);
    s_axi_lite_rresp            : out std_logic_vector(1 downto 0);
    
    -- MT9D111 Camera Interface
    pclk_from_pll    : in    std_logic;    -- PLLからMT9D111のxck に出力するクロック
    pclk            : in     std_logic;    -- MT9D111からのピクセルクロック入力
    xck                : out    std_logic;    -- MT9D111へのピクセルクロック出力
    href            : in     std_logic;
    vsync            : in    std_logic;
    cam_data        : in    std_logic_vector(7 downto 0);
    standby            : out    std_logic;    -- STANDBY出力(ディスエーブル、0固定)
    pfifo_overflow    : out    std_logic;    -- pfifo overflow
    pfifo_underflow    : out    std_logic    -- pfifo underflow
);

end mt9d111_inf_axis;

-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of mt9d111_inf_axis is

constant    ONE_SHOT_PULSE_LENGTH : integer := 20;    -- 1ショットパルスの長さのAXI Lite Slave ACLKのクロック数をセット

signal reset_1d, reset_2d, reset : std_logic;
signal preset_1d, preset_2d, preset : std_logic;
signal pfifo_empty        : std_logic;
signal pfifo_almost_empty    : std_logic;
signal pfifo_rd_data_count    : std_logic_vector(9 downto 0);
signal pfifo_rd_dcount_dec : unsigned(9 downto 0);
signal pfifo_rd_en : std_logic;
signal ACLK : std_logic := '0';
signal one_shot_state : std_logic;
signal one_shot_trigger : std_logic;
signal init_done : std_logic;
signal pfifo_dout : std_logic_vector(33 downto 0);

component mt9d111_cam_cont 
    port(
        aclk            : in std_logic;
        areset            : in std_logic;
        pclk            : in std_logic;
        preset            : in std_logic;
        pclk_from_pll    : in std_logic;
        xclk            : out std_logic;
        line_valid        : in std_logic;
        frame_valid        : in std_logic;
        cam_data        : in std_logic_vector(7 downto 0);
        standby            : out std_logic;
        pfifo_rd_en        : in std_logic;
        pfifo_dout        : out std_logic_vector(33 downto 0); -- frame data start signal + data[31:0]
        pfifo_empty        : out std_logic;
        pfifo_almost_empty        : out std_logic;
        pfifo_rd_data_count    : out std_logic_vector(9 downto 0);
        pfifo_overflow        : out std_logic;
        pfifo_underflow        : out std_logic;
        one_shot_state            : in std_logic;    -- 1フレーム分取り込んだカメラ画像を保持する
        one_shot_trigger        : in std_logic        -- 1フレーム分のカメラ画像取り込みのトリガー、1クロックパルス
    ); 
end component;

component mt9d111_axi_lite_slave generic (
        C_S_AXI_LITE_ADDR_WIDTH         : integer range 9 to 9        := 9; -- Address width of the AXI Lite Interface
        C_S_AXI_LITE_DATA_WIDTH         : integer range 32 to 32        := 32; -- Data width of the AXI Lite Interface
        
        C_DISPLAY_START_ADDRESS            : std_logic_vector(31 downto 0) := x"1A000000";
        ONE_SHOT_PULSE_LENGTH            : integer                     := 20    -- 1ショットパルスの長さのAXI Lite Slave ACLKのクロック数をセット
    );
    port(
        -- Clock and Reset
        s_axi_lite_aclk                : in   std_logic;
        axi_resetn                    : in   std_logic;
        
        -------------------------------
        -- AXI4 Lite Slave Interface --
        -------------------------------
        -- AXI Lite Write Address Channel --
        s_axi_lite_awvalid          : in  std_logic;
        s_axi_lite_awready          : out std_logic;
        s_axi_lite_awaddr           : in  std_logic_vector(C_S_AXI_LITE_ADDR_WIDTH-1 downto 0);
        
        -- AXI Lite Write Data Channel --
        s_axi_lite_wvalid           : in  std_logic;
        s_axi_lite_wready           : out std_logic;
        s_axi_lite_wdata            : in  std_logic_vector(C_S_AXI_LITE_DATA_WIDTH-1 downto 0);

        -- AXI Lite Write Response Channel  --
        s_axi_lite_bresp            : out std_logic_vector(1 downto 0);
        s_axi_lite_bvalid           : out std_logic;
        s_axi_lite_bready           : in  std_logic;

        -- AXI Lite Read Address Channel --
        s_axi_lite_arvalid          : in  std_logic;
        s_axi_lite_arready          : out std_logic;
        s_axi_lite_araddr           : in  std_logic_vector(C_S_AXI_LITE_ADDR_WIDTH-1 downto 0);
    
        -- AXI Lite Read Data Channel
        s_axi_lite_rvalid           : out std_logic;
        s_axi_lite_rready           : in  std_logic;
        s_axi_lite_rdata            : out std_logic_vector(C_S_AXI_LITE_DATA_WIDTH-1 downto 0);
        s_axi_lite_rresp            : out std_logic_vector(1 downto 0);
        
        fb_start_address            : out std_logic_vector(31 downto 0);    -- Frame Buffer のスタートアドレス
        init_done                   : out std_logic;  -- fb_start_address に書き込まれた
        one_shot_state                : out std_logic;    -- 1フレーム分取り込んだカメラ画像を保持する
        one_shot_trigger            : out std_logic        -- 1フレーム分のカメラ画像取り込みのトリガー、1クロックパルス
    );
end component;

begin
    ACLK <= m_axis_aclk;
    
    -- mt9d111_axi_lite_slave のインスタンス
    mt9d111_axi_lite_slave_i : mt9d111_axi_lite_slave generic map(
        C_S_AXI_LITE_ADDR_WIDTH    => C_S_AXI_LITE_ADDR_WIDTH,
        C_S_AXI_LITE_DATA_WIDTH    => C_S_AXI_LITE_DATA_WIDTH,
        
        C_DISPLAY_START_ADDRESS    => (others => '0'),
        ONE_SHOT_PULSE_LENGTH    => ONE_SHOT_PULSE_LENGTH
    ) port map (
        s_axi_lite_aclk        => s_axi_lite_aclk,
        axi_resetn            => axi_resetn,
        s_axi_lite_awvalid    => s_axi_lite_awvalid,
        s_axi_lite_awready    => s_axi_lite_awready,
        s_axi_lite_awaddr    => s_axi_lite_awaddr,
        s_axi_lite_wvalid    => s_axi_lite_wvalid,
        s_axi_lite_wready    => s_axi_lite_wready,
        s_axi_lite_wdata    => s_axi_lite_wdata,
        s_axi_lite_bresp    => s_axi_lite_bresp,
        s_axi_lite_bvalid    => s_axi_lite_bvalid,
        s_axi_lite_bready    => s_axi_lite_bready,
        s_axi_lite_arvalid    => s_axi_lite_arvalid,
        s_axi_lite_arready    => s_axi_lite_arready,
        s_axi_lite_araddr    => s_axi_lite_araddr,
        s_axi_lite_rvalid    => s_axi_lite_rvalid,
        s_axi_lite_rready    => s_axi_lite_rready,
        s_axi_lite_rdata    => s_axi_lite_rdata,
        s_axi_lite_rresp    => s_axi_lite_rresp,
        fb_start_address    => open,
        init_done            => init_done,
        one_shot_state        => one_shot_state,
        one_shot_trigger    => one_shot_trigger
    );
        
    -- axi_resetn をACLK で同期化
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            reset_1d <= not axi_resetn or not init_done;
            reset_2d <= reset_1d;
        end if;
    end process;
    reset <= reset_2d;
    
    -- axi_resetn をpclk で同期化
    process(pclk) begin
        if pclk'event and pclk='1' then
            preset_1d <= not axi_resetn or not init_done;
            preset_2d <= preset_1d;
        end if;
    end process;
    preset <= preset_2d;
        
    pfifo_rd_en <= not pfifo_empty and m_axis_tready;
    mt9d111_cam_cont_i : mt9d111_cam_cont port map(
        aclk                => ACLK,
        areset                => reset,
        pclk                => pclk,
        preset                => preset,
        pclk_from_pll        => pclk_from_pll,
        xclk                => xck,
        line_valid            => href,
        frame_valid            => vsync,
        cam_data            => cam_data,
        standby                => standby,
        pfifo_rd_en            => pfifo_rd_en,
        pfifo_dout            => pfifo_dout, -- frame start data signal + tlast + data[31:0]
        pfifo_empty            => pfifo_empty,
        pfifo_almost_empty    => pfifo_almost_empty,
        pfifo_rd_data_count    => pfifo_rd_data_count,
        pfifo_overflow        => pfifo_overflow,
        pfifo_underflow        => pfifo_underflow,
        one_shot_state        => one_shot_state,
        one_shot_trigger    => one_shot_trigger
    );
    m_axis_tdata <= pfifo_dout(31 downto 0);
    m_axis_tuser(0) <= pfifo_dout(32);
    m_axis_tlast <= pfifo_dout(33);
    m_axis_tvalid <= not pfifo_empty;
    pfifo_rd_en <= not pfifo_empty and m_axis_tready;
    m_axis_tstrb <= (others => '1');

end implementation;


次に、mt9d111_axi_lite_slave.v を貼っておく。

// mt9d111_axi_lite_slave.v 
// mt9d111_inf_axi_master のAXI Lite Slave モジュール。Frame Buffer のスタートアドレス・レジスタを持つ。
//
// 2014/11/08 : one_shot_reg を実装。
// オフセット0番地: フレーム・バッファの先頭アドレス(fb_start_address)
// オフセット4番地: 0 ビット目が 0 の時動画、0 ビット目に 1 の時に、ワンショットで取得した1フレームのカメラ画像を表示(one_shot_reg)
//            1 ビット目に 1 を Write した時に、ワンショットで1フレームの画像をフレーム・バッファに保存
// 2014/11/11 : init_done を追加
//

`default_nettype none

module mt9d111_axi_lite_slave # (
    parameter integer C_S_AXI_LITE_ADDR_WIDTH = 9, // Address width of the AXI Lite Interface
    parameter integer C_S_AXI_LITE_DATA_WIDTH = 32, // Data width of the AXI Lite Interface
    
    parameter [31:0] C_DISPLAY_START_ADDRESS = 32'h1A00_0000,
    parameter integer ONE_SHOT_PULSE_LENGTH = 20   // 1ショットパルスの長さのAXI Lite Slave ACLKのクロック数をセット
)(
    input    wire                                    s_axi_lite_aclk,
    input    wire                                    axi_resetn,
    
    // AXI Lite Write Address Channel
    input    wire                                    s_axi_lite_awvalid,
    output    wire                                    s_axi_lite_awready,
    input    wire    [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_awaddr,

    // AXI Lite Write Data Channel
    input    wire                                    s_axi_lite_wvalid,
    output    wire                                    s_axi_lite_wready,
    input    wire    [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_wdata,
    
    // AXI Lite Write Response Channel
    output    wire    [1:0]                            s_axi_lite_bresp,
    output    wire                                    s_axi_lite_bvalid,
    input    wire                                    s_axi_lite_bready,

    // AXI Lite Read Address Channel
    input    wire                                    s_axi_lite_arvalid,
    output    wire                                    s_axi_lite_arready,
    input    wire    [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_araddr,
    
    // AXI Lite Read Data Channel
    output    wire                                    s_axi_lite_rvalid,
    input    wire                                    s_axi_lite_rready,
    output    reg        [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_rdata,
    output    wire    [1:0]                            s_axi_lite_rresp,
    
    output    wire    [31:0]                            fb_start_address,    // Frame Buffer のスタートアドレス
    output    reg                                        init_done,            // fb_start_address に書き込まれた
    output    wire                                    one_shot_state,        // 1フレーム分取り込んだカメラ画像を保持する
    output    reg                                        one_shot_trigger    // 1フレーム分のカメラ画像取り込みのトリガー、1クロックパルス
);

    // RESP の値の定義
    parameter    RESP_OKAY =        2'b00;
    parameter    RESP_EXOKAY =    2'b01;
    parameter    RESP_SLVERR =     2'b10;
    parameter    RESP_DECERR =    2'b11;
    
    parameter    [1:0]    IDLE_WR =            2'b00,    // for wrt_cs
                        DATA_WRITE_HOLD =    2'b01,
                        BREADY_ASSERT =        2'b11;
                
    parameter    IDLE_RD    =        1'b0,            //  for rdt_cs
                AR_DATA_WAIT =    1'b1;

    reg        [1:0]    wrt_cs = IDLE_WR;
    
    reg        [31:0]    fb_start_addr_reg = C_DISPLAY_START_ADDRESS;
    
    reg        rdt_cs = IDLE_RD;
    
    reg        reset_1d = 1'b0;
    reg        reset = 1'b0;
    reg        awready = 1'b1;
    reg        bvalid = 1'b0;
    reg        arready = 1'b1;
    reg        rvalid = 1'b0;
    wire        aclk;
    reg        [31:0]    one_shot_reg;

    parameter    [1:0]    IDLE_TSM =            2'b00,    // for one_shot_tsm
                        WAIT_ONE_SHOT =        2'b01,
                        ONE_SHOT_TRIG =        2'b11;
    reg        [1:0]    one_shot_tsm;
    integer    one_shot_counter;

    assign aclk = s_axi_lite_aclk;
    // Synchronization of axi_resetn
    always @(posedge aclk) begin
        reset_1d <= ~axi_resetn;
        reset <= reset_1d;
    end
    
    // AXI4 Lite Slave Write Transaction State Machine
    always @(posedge aclk) begin
        if (reset) begin
            wrt_cs <= IDLE_WR;
            awready <= 1'b1;
            bvalid <= 1'b0;
        end else begin
            case (wrt_cs)
                IDLE_WR :
                    if (s_axi_lite_awvalid & ~s_axi_lite_wvalid) begin    // Write Transaction Start
                        wrt_cs <= DATA_WRITE_HOLD;
                        awready <= 1'b0;
                    end else if (s_axi_lite_awvalid & s_axi_lite_wvalid) begin    // Write Transaction Start with data
                        wrt_cs <= BREADY_ASSERT;
                        awready <= 1'b0;
                        bvalid <= 1'b1;
                    end
                DATA_WRITE_HOLD :
                    if (s_axi_lite_wvalid) begin    // Write data just valid
                        wrt_cs <= BREADY_ASSERT;
                        bvalid <= 1'b1;
                    end
                BREADY_ASSERT :
                    if (s_axi_lite_bready) begin    // The write transaction was terminated.
                        wrt_cs <= IDLE_WR;
                        bvalid <= 1'b0;
                        awready <= 1'b1;
                    end
            endcase
        end
    end
    assign s_axi_lite_awready = awready;
    assign s_axi_lite_bvalid = bvalid;
    assign s_axi_lite_wready = 1'b1;
    assign s_axi_lite_bresp = RESP_OKAY;
    
    // AXI4 Lite Slave Read Transaction State Machine
    always @(posedge aclk) begin
        if (reset) begin
            rdt_cs <= IDLE_RD;
            arready <= 1'b1;
            rvalid <= 1'b0;
        end else begin
            case (rdt_cs)
                IDLE_RD :
                    if (s_axi_lite_arvalid) begin
                        rdt_cs <= AR_DATA_WAIT;
                        arready <= 1'b0;
                        rvalid <= 1'b1;
                    end
                AR_DATA_WAIT :
                    if (s_axi_lite_rready) begin
                        rdt_cs <= IDLE_RD;
                        arready <= 1'b1;
                        rvalid <= 1'b0;
                    end
            endcase
        end
    end
    assign s_axi_lite_arready = arready;
    assign s_axi_lite_rvalid = rvalid;
    assign s_axi_lite_rresp = RESP_OKAY;
                    
    // fb_start_addr_reg
    always @(posedge aclk) begin
        if (reset) begin
            init_done <= 1'b0;
            fb_start_addr_reg <= C_DISPLAY_START_ADDRESS;
        end else begin
            if (s_axi_lite_wvalid==1'b1 && s_axi_lite_awaddr[2]==1'b0) begin
                init_done <= 1'b1;
                fb_start_addr_reg <= s_axi_lite_wdata;
            end
        end
    end
    assign fb_start_address = fb_start_addr_reg;

    // one_shot_reg
    always @(posedge aclk) begin
        if (reset)
            one_shot_reg <= 32'd0;    // default is continuous display mode
        else
            if (s_axi_lite_wvalid==1'b1 && s_axi_lite_awaddr[2]==1'b1)
                one_shot_reg <= s_axi_lite_wdata;
    end
    assign one_shot_state = one_shot_reg[0];

    // one_shot_tsm(State Machine for one_shot_trgger)
    always @(posedge aclk) begin
        if (reset) begin
            one_shot_tsm <= IDLE_TSM;
            one_shot_trigger <= 1'b0;
        end else begin
            case (one_shot_tsm)
                IDLE_TSM :
                    if (s_axi_lite_awvalid & awready & s_axi_lite_awaddr[2]) begin // one_shot_reg address
                        if (s_axi_lite_wvalid) begin // s_axi_wready is always 1
                            if (s_axi_lite_wdata[1]) begin // one_shot was triggered
                                one_shot_tsm <= ONE_SHOT_TRIG;
                                one_shot_trigger <= 1'b1;
                            end else begin // is not trigger
                                one_shot_tsm <= IDLE_TSM;
                                one_shot_trigger <= 1'b0;
                            end
                        end else begin // s_axi_lite_wvalid is not asserted
                            one_shot_tsm <= WAIT_ONE_SHOT;
                            one_shot_trigger <= 1'b0;
                        end
                    end
                WAIT_ONE_SHOT :
                    if (s_axi_lite_wvalid) begin // s_axi_wready is always 1
                        if (s_axi_lite_wdata[1]) begin // one_shot was triggered
                            one_shot_tsm <= ONE_SHOT_TRIG;
                            one_shot_trigger <= 1'b1;
                        end else begin // is not trigger
                            one_shot_tsm <= IDLE_TSM;
                            one_shot_trigger <= 1'b0;
                        end
                    end
                ONE_SHOT_TRIG : begin
                    if (one_shot_counter == 0) begin
                        one_shot_tsm <= IDLE_TSM;
                        one_shot_trigger <= 1'b0;
                    end
                end
            endcase
        end
    end

    // one shot pulse length counter
    always @(posedge aclk) begin
        if (reset) begin
            one_shot_counter <= ONE_SHOT_PULSE_LENGTH;
        end else if (one_shot_tsm == ONE_SHOT_TRIG) begin
            one_shot_counter <= one_shot_counter - 1;
        end else begin
            one_shot_counter <= ONE_SHOT_PULSE_LENGTH;
        end
    end
    // s_axi_lite_rdata
    always @(posedge aclk) begin
        if (reset) begin
            s_axi_lite_rdata <= 0;
        end else if (s_axi_lite_arvalid) begin
            case (s_axi_lite_araddr[2])
                1'b0 :     s_axi_lite_rdata <= fb_start_addr_reg;
                1'b1 :    s_axi_lite_rdata <= one_shot_reg;
            endcase
        end
    end
endmodule
    
`default_nettype wire        


最後に、mt9d111_cam_cont.v を貼っておく。

// MT9D111カメラコントローラ
// mt9d111_cam_cont.v
// 2012/12/26
//
// 2014/11/07 : fb_start_address を追加。レジスタに設定された値をスタートアドレスとして参照。
// 2014/11/08 : one_shot_state, one_shot_trigger の入力ポートを追加
// 2015/05/09 : UPSIDE_DOWN を削除、pifo_dout を 64ビット長から 32 ビット長へ変更、paddr を削除
// 2015/05/11 : last_pixel_4_line を出力するために、データを1つ遅らせることで、line_valid の falling edge を検出し、last_pixel_4_line とする。fb_start_addresを削除

`default_nettype none

module mt9d111_cam_cont (
    input    wire    aclk,
    input    wire    areset,
    input    wire    pclk,
    input    wire    preset,
    input    wire    pclk_from_pll,
    output    wire    xclk,
    input    wire    line_valid,
    input    wire    frame_valid,
    input    wire    [7:0]    cam_data,
    output    wire    standby,
    input    wire    pfifo_rd_en,
    output    wire    [33:0]    pfifo_dout,
    output    wire    pfifo_empty,
    output    wire    pfifo_almost_empty,
    output    wire    [9:0]    pfifo_rd_data_count,
    output    wire    pfifo_overflow,
    output    wire    pfifo_underflow,
    input    wire    one_shot_state,        // 1フレーム分取り込んだカメラ画像を保持する
    input    wire    one_shot_trigger    // 1フレーム分のカメラ画像取り込みのトリガー、1クロックパルス
);
    `include "./disp_timing_parameters.vh"

    // Frame Buffer End Address
    reg        line_valid_1d, line_valid_2d;
    reg        frame_valid_1d, frame_valid_2d;
    reg        [7:0]    cam_data_1d;
    reg        line_valid_1d_odd;
    reg        line_v_1d_odd_1d, line_v_1d_odd_2d;
    reg        [31:0]    rgb565, rgb565_1d;
    wire    pfifo_full, pfifo_almost_full;
    parameter    [1:0]    IDLE_ADDR_RST =    2'b00,
                        ADDR_RST =        2'b01,
                        ADDR_RST_HOLD =    2'b11;

    parameter    [2:0]    IDLE_OS =                3'b000,
                        WAIT_FRAME_VALID_END =    3'b001,
                        HOLD_PICTURE =            3'b011,
                        WAIT_FRAME_VALID_LOW =    3'b010,
                        WAIT_FRAME_VALID_HIGH =    3'b110;
    reg        [2:0]    one_shot_sm;
    reg        frame_valid_1d_oh;
    reg        ost_1d, ost_2d, ost_3d, ost_4d;
    reg        one_shot_tig_pclk;
    reg        first_pixel;
    reg        last_pixel_4_line;
    reg        one_shot_state_1d, one_shot_state_2d;

    assign standby = 1'b0;

    // MT9D111 へのクロックを出力 (xclk)
    ODDR #(
        .DDR_CLK_EDGE("SAME_EDGE"), // "OPPOSITE_EDGE" or "SAME_EDGE"
        .INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
        .SRTYPE("SYNC") // Set/Reset type: "SYNC" or "ASYNC"
    ) ODDR_inst (
        .Q(xclk), // 1-bit DDR output
        .C(pclk_from_pll), // 1-bit clock input
        .CE(1'b1), // 1-bit clock enable input
        .D1(1'b1), // 1-bit data input (positive edge)
        .D2(1'b0), // 1-bit data input (negative edge)
        .R(1'b0), // 1-bit reset
        .S(1'b0) // 1-bit set
    );

    // 入力信号を一旦ラッチする
    always @(posedge pclk) begin
        if (preset) begin
            line_valid_1d <=    1'b0;
            line_valid_2d <=    1'b0;
            frame_valid_1d <=    1'b0;
            frame_valid_2d <=    1'b0;
            cam_data_1d <=        8'd0;
        end else begin
            line_valid_1d <=    line_valid;
            line_valid_2d <=     line_valid_1d;
            frame_valid_1d <=    frame_valid;
            frame_valid_2d <=     frame_valid_1d;
            cam_data_1d <=        cam_data;
        end
    end

    // one_shot_state を pclk で同期化する
    always @(posedge pclk) begin
        if (preset) begin
            one_shot_state_1d <= 1'b0;
            one_shot_state_2d <= 1'b0;
        end else begin
            one_shot_state_1d <= one_shot_state;
            one_shot_state_2d <= one_shot_state_1d;
        end
    end

    // one_shot_trigger はAXIバスのaclkで生成されているので、pclkで動作するステートマシンでは、本当にone shotでは取れない
    // よって、one shotと言ってもある程度の幅を用意してある。pclk の幅のone shot pulse を作る必要がある
    always @(posedge pclk) begin // one_shot_trigger を pclk で同期化
        if (preset) begin
            ost_1d <= 1'b0;
            ost_2d <= 1'b0;
            ost_3d <= 1'b0;
            ost_4d <= 1'b0;
        end else begin
            ost_1d <= one_shot_trigger;
            ost_2d <= ost_1d;
            ost_3d <= ost_2d;
            ost_4d <= ost_3d;
        end
    end

    // pclk 幅の one shot pulse を生成
    always @(posedge pclk) begin
        if (preset) begin
            one_shot_tig_pclk <= 1'b0;
        end else if (ost_3d==1'b1 && ost_4d==1'b0) begin // rising edge
            one_shot_tig_pclk <= 1'b1;
        end else begin
            one_shot_tig_pclk <= 1'b0;
        end
    end
    
    // one shot state machine
    // frame_valid_1d_oh を生成する
    always @(posedge pclk) begin
        if (preset) begin
            one_shot_sm <= IDLE_OS;
            frame_valid_1d_oh <= frame_valid_1d;
        end else begin
            case (one_shot_sm)
                IDLE_OS : begin
                    frame_valid_1d_oh <= frame_valid_1d;
                    if (one_shot_state_2d) begin
                        one_shot_sm <= WAIT_FRAME_VALID_END;
                    end
                end
                WAIT_FRAME_VALID_END : begin
                    frame_valid_1d_oh <= frame_valid_1d;
                    if (!frame_valid_1d) begin
                        one_shot_sm <= HOLD_PICTURE;
                    end
                end
                HOLD_PICTURE : begin
                    frame_valid_1d_oh <= 1'b0;
                    if (one_shot_tig_pclk) begin
                        one_shot_sm <= WAIT_FRAME_VALID_LOW;
                    end else if (~one_shot_state_2d & ~frame_valid_1d) begin
                        one_shot_sm <= IDLE_OS;
                    end
                end
                WAIT_FRAME_VALID_LOW : begin
                    frame_valid_1d_oh <= 1'b0;
                    if (!frame_valid_1d) begin
                        one_shot_sm <= WAIT_FRAME_VALID_HIGH;
                    end
                end
                WAIT_FRAME_VALID_HIGH : begin
                    frame_valid_1d_oh <= frame_valid_1d;
                    if (frame_valid_1d) begin
                        one_shot_sm <= WAIT_FRAME_VALID_END;
                    end
                end
            endcase
        end
    end

    // line_valid_1d が偶数か奇数かをカウント
    always @(posedge pclk) begin
        if (preset)
            line_valid_1d_odd <= 1'b0;
        else begin
            if (!frame_valid_1d_oh)
                line_valid_1d_odd <= 1'b0;
            else if (line_valid_1d)
                line_valid_1d_odd <= ~line_valid_1d_odd;
            else
                line_valid_1d_odd <= 1'b0;
        end
    end

    // rgb565でラッチしているので、line_valid_1d_odd を1クロック遅延する
    always @(posedge pclk) begin
        if (preset) begin
            line_v_1d_odd_1d <= 1'b0;
            line_v_1d_odd_2d <= 1'b0;
        end else begin
            line_v_1d_odd_1d <= line_valid_1d_odd;
            line_v_1d_odd_2d <= line_v_1d_odd_1d;
        end
    end

    // RGB565 のデータを保存する。正常と上下反転ではバイト配列が異なる
    always @(posedge pclk) begin
        if (preset)
            rgb565 <= 32'd0;
        else begin
            case (line_valid_1d_odd)
                1'b0 : // 1番目
                    rgb565[31:13] <= {8'd0, cam_data_1d[7:3], 3'b000, cam_data_1d[2:0]};    // cam_data_1d = R7 R6 R5 R4 R3 G7 G6 G5
                1'b1 : // 2番目
                    rgb565[12:0] <= {cam_data_1d[7:5], 2'b00, cam_data_1d[4:0], 3'b000};    // cam_data_1d = G4 G3 G2 B7 B6 B5 B4 B3
            endcase
        end
    end

    // rgb565 を 1 クロック遅延する
    always @(posedge pclk) begin
        if (preset) begin
            rgb565_1d <= 32'd0;
        end begin
            rgb565_1d <= rgb565;    
        end
    end

    // line_valid の falling edge の検出
    always @(posedge pclk) begin
        if (preset) begin
            last_pixel_4_line <= 1'b0;
        end else if (line_valid_1d==1'b0 && line_valid_2d==1'b1) begin // line_valid_1d の falling edge
            last_pixel_4_line <= 1'b1;
        end else if (line_v_1d_odd_2d) begin
            last_pixel_4_line <= 1'b0;
        end
    end

    // frame_valid が 1 になってから初めてのピクセルを示す
    always @(posedge pclk) begin
        if (preset) begin
            first_pixel <= 1'b0;
        end else if (frame_valid_1d==1'b1 && frame_valid_2d==1'b0) begin // frame_valid_1d rising edge
            first_pixel <= 1'b1;
        end else if (line_v_1d_odd_2d) begin // first pixel
            first_pixel <= 1'b0;
        end
    end

    // pixel FIFO をインスタンスする
    pixel_fifo pfifo (
        .rst(areset), // input rst
        .wr_clk(pclk), // input wr_clk
        .rd_clk(aclk), // input rd_clk
        .din({last_pixel_4_line, first_pixel, rgb565_1d}), // input [33 : 0] din
        .wr_en(line_v_1d_odd_2d), // input wr_en
        .rd_en(pfifo_rd_en), // input rd_en
        .dout(pfifo_dout), // output [33 : 0] dout
        .full(pfifo_full), // output full
        .almost_full(pfifo_almost_full), // output almost_full
        .overflow(pfifo_overflow), // output overflow
        .empty(pfifo_empty), // output empty
        .almost_empty(pfifo_almost_empty), // output almost_empty
        .underflow(pfifo_underflow), // output underflow
        .rd_data_count(pfifo_rd_data_count) // output [9 : 0] rd_data_count
    );
endmodule

`default_nettype wire

  1. 2015年05月13日 03:48 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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