FC2カウンター FPGAの部屋 2012年04月02日
FC2ブログ

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

FPGAの部屋

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

AXI4マスタIPの作製2(単体シミュレーション)

キャラクタ・ディスプレイ・コントローラAXI4スレーブIPを駆動するAXI4マスタIPが一応できたので、シミュレーションしてみた。
仕様は、”AXI4マスタIPの作製(仕様の策定)"を参照のこと。

2012/10/22:(注)この記事は全面的に書き換えた。理由はAXIの書き込みトランザクションにやるハンドシェークの依存関係を誤解していた。書き込みトランザクションにおいて、WVALIDをアサートする前に、AWREADYがアサートされるのを待っていてはダメだそうだ。デッドロック状態を引き起こす可能性があるそうだ。


まずは、AXI4マスタIPを下に示す。まだ、インプリメントして実際に確かめていないので、ミスっているかも知れない。その場合は後で修正する。長いです。(cdctest_axi_master.vhd) (2012/04/04:cdctest_axi_master.vhd を修正)

-------------------------------------------------------------------------------
--
-- AXI Master
--
-- VHDL-Standard:   VHDL'93
----------------------------------------------------------------------------
--
-- Structure:
--   cdctest_axi_master
--
----------------------------------------------------------------------------

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

package m_seq_pack is
    function M_SEQ16_F(mseq16in : std_logic_vector
        )return std_logic_vector;
end package m_seq_pack;
package body m_seq_pack is
    function M_SEQ16_F(mseq16in : std_logic_vector
        )return std_logic_vector is
            variable mseq16 : std_logic_vector(15 downto 0);
            variable xor_result : std_logic;
    begin
        xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
        mseq16 := mseq16in(14 downto 0) & xor_result;
        return mseq16;
    end M_SEQ16_F;
end m_seq_pack;


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

library work;
use work.m_seq_pack.all;

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

entity cdctest_axi_master is
  generic(
    C_M_AXI_THREAD_ID_WIDTH : integer := 1;
    C_M_AXI_ADDR_WIDTH      : integer := 32;
    C_M_AXI_DATA_WIDTH      : integer := 32;
    C_M_AXI_AWUSER_WIDTH    : integer := 1;
    C_M_AXI_ARUSER_WIDTH    : integer := 1;
    C_M_AXI_WUSER_WIDTH     : integer := 1;
    C_M_AXI_RUSER_WIDTH     : integer := 1;
    C_M_AXI_BUSER_WIDTH     : integer := 1
    );
  port(
    -- System Signals
    ACLK    : in std_logic;
    ARESETN : in std_logic;

    -- Master Interface Write Address
    M_AXI_AWID    : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_AWADDR  : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_AWLEN   : out std_logic_vector(8-1 downto 0);
    M_AXI_AWSIZE  : out std_logic_vector(3-1 downto 0);
    M_AXI_AWBURST : out std_logic_vector(2-1 downto 0);
    M_AXI_AWLOCK  : out std_logic;
    M_AXI_AWCACHE : out std_logic_vector(4-1 downto 0);
    M_AXI_AWPROT  : out std_logic_vector(3-1 downto 0);
    -- AXI3    M_AXI_AWREGION:out std_logic_vector(4-1 downto 0);
    M_AXI_AWQOS   : out std_logic_vector(4-1 downto 0);
    M_AXI_AWUSER  : out std_logic_vector(C_M_AXI_AWUSER_WIDTH-1 downto 0);
    M_AXI_AWVALID : out std_logic;
    M_AXI_AWREADY : in  std_logic;

    -- Master Interface Write Data
    -- AXI3   M_AXI_WID(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_WDATA  : out std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_WSTRB  : out std_logic_vector(C_M_AXI_DATA_WIDTH/8-1 downto 0);
    M_AXI_WLAST  : out std_logic;
    M_AXI_WUSER  : out std_logic_vector(C_M_AXI_WUSER_WIDTH-1 downto 0);
    M_AXI_WVALID : out std_logic;
    M_AXI_WREADY : in  std_logic;

    -- Master Interface Write Response
    M_AXI_BID    : in  std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_BRESP  : in  std_logic_vector(2-1 downto 0);
    M_AXI_BUSER  : in  std_logic_vector(C_M_AXI_BUSER_WIDTH-1 downto 0);
    M_AXI_BVALID : in  std_logic;
    M_AXI_BREADY : out std_logic;

    -- Master Interface Read Address
    M_AXI_ARID    : out std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_ARADDR  : out std_logic_vector(C_M_AXI_ADDR_WIDTH-1 downto 0);
    M_AXI_ARLEN   : out std_logic_vector(8-1 downto 0);
    M_AXI_ARSIZE  : out std_logic_vector(3-1 downto 0);
    M_AXI_ARBURST : out std_logic_vector(2-1 downto 0);
    M_AXI_ARLOCK  : out std_logic_vector(2-1 downto 0);
    M_AXI_ARCACHE : out std_logic_vector(4-1 downto 0);
    M_AXI_ARPROT  : out std_logic_vector(3-1 downto 0);
    -- AXI3   M_AXI_ARREGION:out std_logic_vector(4-1 downto 0);
    M_AXI_ARQOS   : out std_logic_vector(4-1 downto 0);
    M_AXI_ARUSER  : out std_logic_vector(C_M_AXI_ARUSER_WIDTH-1 downto 0);
    M_AXI_ARVALID : out std_logic;
    M_AXI_ARREADY : in  std_logic;

    -- Master Interface Read Data 
    M_AXI_RID    : in  std_logic_vector(C_M_AXI_THREAD_ID_WIDTH-1 downto 0);
    M_AXI_RDATA  : in  std_logic_vector(C_M_AXI_DATA_WIDTH-1 downto 0);
    M_AXI_RRESP  : in  std_logic_vector(2-1 downto 0);
    M_AXI_RLAST  : in  std_logic;
    M_AXI_RUSER  : in  std_logic_vector(C_M_AXI_RUSER_WIDTH-1 downto 0);
    M_AXI_RVALID : in  std_logic;
    M_AXI_RREADY : out std_logic;

    -- Example Design only
    wr_error : out std_logic;
    rd_error : out std_logic
);

end cdctest_axi_master;

-------------------------------------------------------------------------------
-- Architecture
-------------------------------------------------------------------------------
architecture implementation of cdctest_axi_master is
constant    RESP_OKAY        : std_logic_vector := "00";
constant    RESP_EXOKAY        : std_logic_vector := "01";
constant    RESP_SLVERR        : std_logic_vector := "10";
constant    RESP_DECERR        : std_logic_vector := "11";

constant    SVGA_ADDR_LIMIT : integer := 800/8*600/8*4; -- SVGAのアドレスリミット(横ドット数/1文字の横ドット数 * 縦ドット数/1文字の縦のドット数 * 1文字を表すバイト数)

constant    DISP_INTERVAL_DIV : integer := 20000000; -- インプリメント 0.2sec
-- constant    DISP_INTERVAL_DIV : integer := 3; -- シミュレーション

signal reset_1d, reset_2d, reset : std_logic;
type wr_rd_transaction_state is (write_state, read_state, wait_state);
signal wr_rd_cs : wr_rd_transaction_state;
type write_transaction_state is (idle_wr, awvalid_assert, data_write_hold, bready_assert, wr_tran_end);
signal wrt_cs : write_transaction_state;
type write_wvalid_state is (idle_wvalid, wvalid_assert, wvalid_hold);
signal wrt_wv_cs : write_wvalid_state;

signal awvalid, wvalid, bready : std_logic;
signal w_r_addr : std_logic_vector(31 downto 0);
signal write_data : std_logic_vector(15 downto 0);
signal awlen16 : std_logic_vector(15 downto 0);
signal awlen, write_count : std_logic_vector(7 downto 0);
signal wlast : std_logic;
type read_transaction_state is (idle_rd, arvalid_assert, data_read, rd_tran_end);
signal rdt_cs : read_transaction_state;
signal arvalid : std_logic;
signal arlen, read_count : std_logic_vector(7 downto 0);
signal read_data : std_logic_vector(15 downto 0);
signal rready : std_logic;
signal disp_count : integer;
signal disp_ena : std_logic;

begin
    -- ARESETN をACLK で同期化
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            reset_1d <= not ARESETN;
            reset_2d <= reset_1d;
        end if;
    end process;
    reset <= reset_2d;
    
    -- インプリメントでは0.2秒に1回表示する
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                disp_count <= 0;
                disp_ena <= '0';
            else
                if disp_count = DISP_INTERVAL_DIV then
                    disp_count <= 0;
                    disp_ena <= '1';
                else
                    disp_count <= disp_count + 1;
                    disp_ena <= '0';
                end if;
            end if;
        end if;
    end process;
    
    -- Write, Read Transaction State Machine
    -- Writeが終了したらReadを行う。シーケンシャルにWrite, Readを繰り返す。
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_rd_cs <= write_state;
            else
                case (wr_rd_cs) is
                    when write_state =>
                        if wrt_cs = wr_tran_end then
                            wr_rd_cs <= read_state;
                        end if;
                    when read_state =>
                        if rdt_cs = rd_tran_end then
                            wr_rd_cs <= wait_state;
                        end if;
                    when wait_state =>
                        if disp_ena='1' then
                            wr_rd_cs <= write_state;
                        end if;
                end case;
            end if;
        end if;
    end process;

    -- Write
    M_AXI_AWID        <= "0";
    M_AXI_AWSIZE     <= "010";    -- 4bytes fixed
    M_AXI_AWBURST    <= "01";    -- INCR
    M_AXI_AWLOCK    <= '0';    -- Normal Access
    M_AXI_AWCACHE    <= "0010";    -- Normal Non-cacheable Non-bufferable
    M_AXI_AWPROT    <= "000";    -- Data access, Secure access, Unprivileged access
    M_AXI_AWQOS        <= "0000";    -- default
    M_AXI_AWUSER    <= "0";
    M_AXI_WSTRB        <= "1111";
    M_AXI_WUSER        <= "0";
    
    -- AXI4バス Write Transaction State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wrt_cs <= idle_wr;
                awvalid <= '0';
                bready <= '0';
            else 
                case(wrt_cs) is
                    when idle_wr =>
                        if wr_rd_cs = write_state then
                            wrt_cs <= awvalid_assert;
                            awvalid <= '1';
                        end if;
                    when awvalid_assert =>
                        if M_AXI_AWREADY='1' then
                            if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1') then
                                wrt_cs <= bready_assert;
                                bready <= '1';
                            else
                                wrt_cs <= data_write_hold;
                            end if;
                            awvalid <= '0';
                        end if;
                    when data_write_hold =>
                        if wrt_wv_cs=wvalid_hold or (wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1') then
                            wrt_cs <= bready_assert;
                            bready <= '1';
                        end if;
                    when bready_assert =>
                        if M_AXI_BVALID='1' then
                            wrt_cs <= wr_tran_end;
                            bready <= '0';
                        end if;
                    when wr_tran_end =>
                        wrt_cs <= idle_wr;
                end case;
            end if;
        end if;
    end process;
    -- AXI4 バス Write Transaction WVALID State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wrt_wv_cs <= idle_wvalid;
                wvalid <= '0';
            else 
                case(wrt_wv_cs) is
                    when idle_wvalid =>
                        if wrt_cs=awvalid_assert then
                            wrt_wv_cs <= wvalid_assert;
                            wvalid <= '1';
                        end if;
                    when wvalid_assert =>
                        if write_count=0 and M_AXI_WREADY='1' then -- 終了
                            wrt_wv_cs <= wvalid_hold;
                            wvalid <= '0';
                        end if;
                    when wvalid_hold =>
                        if wrt_cs=bready_assert then
                            wrt_wv_cs <= idle_wvalid;
                        end if;
                end case;
            end if;
        end if;
    end process;

    M_AXI_AWVALID    <= awvalid;
    M_AXI_WVALID    <= wvalid;
    M_AXI_BREADY    <= bready;
    
    -- w_r_addr の処理、Write Transaction が終了するたびにawlen+1を加える。加える途中でSVGA_ADDR_LIMITを超える時はどうするかだが、そこは無視する
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                w_r_addr <= (others => '0');
            else
                if wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
                    w_r_addr <= w_r_addr + 4;
                elsif wrt_cs=bready_assert and w_r_addr >= SVGA_ADDR_LIMIT then
                    w_r_addr <= (others => '0');
                end if;
            end if;
        end if;
    end process;
    M_AXI_AWADDR <= w_r_addr;
    
    -- M_AXI_AWLEN の値を決定する。M系列を使用してランダムな値とする
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                awlen16 <= CONV_STD_LOGIC_VECTOR(1, 16); -- 0 はダメ
            else
                if wr_rd_cs=write_state and  wrt_cs=idle_wr then
                    awlen16 <= M_SEQ16_F(awlen16);
                end if;
            end if;
        end if;
    end process;
    awlen <= awlen16(7 downto 0);
    M_AXI_AWLEN <= awlen;
    
    -- write_data の処理、0から0xffffまで
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                write_data <= (others => '0');
            else
                if wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
                    if write_data = x"FFFF" then -- 終了なのでクリア
                        write_data <= (others => '0'); -- これをしなくても0に戻るが将来他の値でリミットするためにコードを入れておく
                    else -- data write
                        write_data <= write_data + 1;
                    end if;
                end if;
            end if;
        end if;
    end process;
    M_AXI_WDATA(31 downto 16) <= (others => '0');
    M_AXI_WDATA(15 downto 0) <= write_data;
    
    -- write_count の処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                write_count <= (others => '0');
            else
                if wrt_cs=awvalid_assert then
                    write_count <= awlen;
                elsif wrt_wv_cs=wvalid_assert and M_AXI_WREADY='1' then
                    write_count <= write_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- wlastの処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wlast <= '0';
            else
                if wrt_cs=awvalid_assert and awlen=0 and M_AXI_AWREADY='1' then -- awlen が0の時はデータ転送の最初からwlast をアサートする
                    wlast <= '1';
                elsif wrt_wv_cs=wvalid_assert and write_count=1 and M_AXI_WREADY='1' then -- awlen が0で無い時はwrite_count が1でM_AXI_WREADY='1'の時、つまりwrite_count が0の時にwlastをアサートする
                    wlast <= '1';
                elsif wrt_wv_cs=wvalid_assert and write_count=0 and M_AXI_WREADY='1' then -- データ転送が終了なのでwlast を0にする
                    wlast <= '0';
                end if;
            end if;
        end if;
    end process;
    M_AXI_WLAST <= wlast;
    
    -- wr_error の処理、M_AXI_BRESPがRESP_OKAY以外の時にwr_errorを点灯する
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                wr_error <= '0';
            else
                if wrt_cs=bready_assert and M_AXI_BVALID='1' and M_AXI_BRESP/=RESP_OKAY then
                    wr_error <= '1';
                end if;
            end if;
        end if;
    end process;
    
    -- Read
    M_AXI_ARID        <= "0";
    M_AXI_ARLEN        <= awlen;
    M_AXI_ARSIZE    <= "010";    -- 4bytes
    M_AXI_ARBURST    <= "01";    -- INCR
    M_AXI_ARLOCK    <= "00";    -- Normal Access
    M_AXI_ARCACHE    <= "0010";    -- Normal Non-cacheable Non-bufferable
    M_AXI_ARPROT    <= "000";    -- Data access, Secure access, Unprivileged access
    M_AXI_ARQOS        <= "0000";    -- default
    M_AXI_ARUSER    <= "0";
    
    -- M_AXI_ARADDR の処理、M_AXI_AWVALIDが1の時のw_r_addr を保存しておく
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                M_AXI_ARADDR <= (others => '0');
            else
                if awvalid='1' then
                    M_AXI_ARADDR <= w_r_addr;
                end if;
            end if;
        end if;
    end process;
    
    -- AXI4バス Read Transaction State Machine
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                rdt_cs <= idle_rd;
                arvalid <= '0';
                rready <= '0';
            else
                case rdt_cs is
                    when idle_rd =>
                        if wr_rd_cs=read_state then
                            rdt_cs <= arvalid_assert;
                            arvalid <= '1';
                        end if;
                    when arvalid_assert =>
                        if M_AXI_ARREADY='1' then
                            rdt_cs <= data_read;
                            arvalid <= '0';
                            rready <= '1';
                        end if;
                    when data_read =>
                        if read_count=0 and M_AXI_RVALID='1' then -- 終了
                            rdt_cs <= rd_tran_end;
                            rready <= '0';
                        end if;
                    when rd_tran_end =>
                        rdt_cs <= idle_rd;
                end case;
            end if;
        end if;
    end process;
    M_AXI_ARVALID <= arvalid;
    M_AXI_RREADY <= rready;
    
    -- read_data の処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                read_data <= (others => '0');
            else
                if rdt_cs=data_read and M_AXI_RVALID='1' then
                    if read_data=x"FFFF" then -- 終了なのでクリア
                        read_data <= (others => '0');
                    else -- data read
                        read_data <= read_data + 1;
                    end if;
                end if;
            end if;
        end if;
    end process;
    
    -- read_count の処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                read_count <= (others => '0');
            else
                if rdt_cs=arvalid_assert then
                    read_count <= awlen;
                elsif rdt_cs=data_read and M_AXI_RVALID='1' then
                    read_count <= read_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- rd_error の処理
    process(ACLK) begin
        if ACLK'event and ACLK='1' then
            if reset='1' then
                rd_error <= '0';
            else
                if rdt_cs=data_read and M_AXI_RVALID='1' then -- Read Transaction
                    if M_AXI_RDATA(15 downto 0) /= read_data then
                        rd_error <= '1';
                    elsif M_AXI_RRESP /= RESP_OKAY then
                        rd_error <= '1';
                    end if;
                end if;
            end if;
        end if;
    end process;

end implementation;


インプリメントでは、キャラクタをランダム・バースト長で書く間隔を0.2秒に設定している。だが、シミュレーションでは、そんなに長くインターバルを設定してしまうと、2回のトランザクションを見るには、膨大なシミュレーション時間を必要とする。そのため、シミュレーション時には分周比を小さくした。それを下に示す。

constant DISP_INTERVAL_DIV : integer := 20000000; -- インプリメント 0.2sec
-- constant DISP_INTERVAL_DIV : integer := 3; -- シミュレーション


上の記述は、インプリメントとシミュレーションでコメントにする方を切り替えて使って欲しい。(現在はインプリメント用)

次に、テストベンチファイル (cdctest_axi_master_tb.v) を下に示す。テストベンチはVerilog ファイルにした。テストベンチでは、cdctest_axi_master.vhd とcdc_axi_slave.vhd をインスタンスして、その間を接続している。後で汎用的なAXI4スレーブBFMを作っても良いかな?と思っている。

`default_nettype none

`timescale 100ps / 1ps

module cdctest_axi_master_tb;

    // Inputs
    wire ACLK;
    wire ARESETN;
    wire M_AXI_AWREADY;
    wire M_AXI_WREADY;
    wire [0:0] M_AXI_BID;
    wire [1:0] M_AXI_BRESP;
    wire [0:0] M_AXI_BUSER;
    wire M_AXI_BVALID;
    wire M_AXI_ARREADY;
    wire [0:0] M_AXI_RID;
    wire [31:0] M_AXI_RDATA;
    wire [1:0] M_AXI_RRESP;
    wire M_AXI_RLAST;
    wire [0:0] M_AXI_RUSER;
    wire M_AXI_RVALID;

    // Outputs
    wire [0:0] M_AXI_AWID;
    wire [31:0] M_AXI_AWADDR;
    wire [7:0] M_AXI_AWLEN;
    wire [2:0] M_AXI_AWSIZE;
    wire [1:0] M_AXI_AWBURST;
    wire M_AXI_AWLOCK;
    wire [3:0] M_AXI_AWCACHE;
    wire [2:0] M_AXI_AWPROT;
    wire [3:0] M_AXI_AWQOS;
    wire [0:0] M_AXI_AWUSER;
    wire M_AXI_AWVALID;
    wire [31:0] M_AXI_WDATA;
    wire [3:0] M_AXI_WSTRB;
    wire M_AXI_WLAST;
    wire [0:0] M_AXI_WUSER;
    wire M_AXI_WVALID;
    wire M_AXI_BREADY;
    wire [0:0] M_AXI_ARID;
    wire [31:0] M_AXI_ARADDR;
    wire [7:0] M_AXI_ARLEN;
    wire [2:0] M_AXI_ARSIZE;
    wire [1:0] M_AXI_ARBURST;
    wire [1:0] M_AXI_ARLOCK;
    wire [3:0] M_AXI_ARCACHE;
    wire [2:0] M_AXI_ARPROT;
    wire [3:0] M_AXI_ARQOS;
    wire [0:0] M_AXI_ARUSER;
    wire M_AXI_ARVALID;
    wire M_AXI_RREADY;
    wire wr_error;
    wire rd_error;

    wire pixclk;
    wire TMDS_tx_clk_p;
    wire TMDS_tx_clk_n;
    wire TMDS_tx_2_G_p;
    wire TMDS_tx_2_G_n;
    wire TMDS_tx_1_R_p;
    wire TMDS_tx_1_R_n;
    wire TMDS_tx_0_B_p;
    wire TMDS_tx_0_B_n;
    
    wire [3:0]    S_AXI_AWREGION = 0;
    wire [0:0]    S_AXI_WID = 0;
    wire [3:0]    S_AXI_ARREGION = 0;

    // Instantiate the Unit Under Test (UUT_MASTER)
    cdctest_axi_master uut_master (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .M_AXI_AWID(M_AXI_AWID), 
        .M_AXI_AWADDR(M_AXI_AWADDR), 
        .M_AXI_AWLEN(M_AXI_AWLEN), 
        .M_AXI_AWSIZE(M_AXI_AWSIZE), 
        .M_AXI_AWBURST(M_AXI_AWBURST), 
        .M_AXI_AWLOCK(M_AXI_AWLOCK), 
        .M_AXI_AWCACHE(M_AXI_AWCACHE), 
        .M_AXI_AWPROT(M_AXI_AWPROT), 
        .M_AXI_AWQOS(M_AXI_AWQOS), 
        .M_AXI_AWUSER(M_AXI_AWUSER), 
        .M_AXI_AWVALID(M_AXI_AWVALID), 
        .M_AXI_AWREADY(M_AXI_AWREADY), 
        .M_AXI_WDATA(M_AXI_WDATA), 
        .M_AXI_WSTRB(M_AXI_WSTRB), 
        .M_AXI_WLAST(M_AXI_WLAST), 
        .M_AXI_WUSER(M_AXI_WUSER), 
        .M_AXI_WVALID(M_AXI_WVALID), 
        .M_AXI_WREADY(M_AXI_WREADY), 
        .M_AXI_BID(M_AXI_BID), 
        .M_AXI_BRESP(M_AXI_BRESP), 
        .M_AXI_BUSER(M_AXI_BUSER), 
        .M_AXI_BVALID(M_AXI_BVALID), 
        .M_AXI_BREADY(M_AXI_BREADY), 
        .M_AXI_ARID(M_AXI_ARID), 
        .M_AXI_ARADDR(M_AXI_ARADDR), 
        .M_AXI_ARLEN(M_AXI_ARLEN), 
        .M_AXI_ARSIZE(M_AXI_ARSIZE), 
        .M_AXI_ARBURST(M_AXI_ARBURST), 
        .M_AXI_ARLOCK(M_AXI_ARLOCK), 
        .M_AXI_ARCACHE(M_AXI_ARCACHE), 
        .M_AXI_ARPROT(M_AXI_ARPROT), 
        .M_AXI_ARQOS(M_AXI_ARQOS), 
        .M_AXI_ARUSER(M_AXI_ARUSER), 
        .M_AXI_ARVALID(M_AXI_ARVALID), 
        .M_AXI_ARREADY(M_AXI_ARREADY), 
        .M_AXI_RID(M_AXI_RID), 
        .M_AXI_RDATA(M_AXI_RDATA), 
        .M_AXI_RRESP(M_AXI_RRESP), 
        .M_AXI_RLAST(M_AXI_RLAST), 
        .M_AXI_RUSER(M_AXI_RUSER), 
        .M_AXI_RVALID(M_AXI_RVALID), 
        .M_AXI_RREADY(M_AXI_RREADY), 
        .wr_error(wr_error), 
        .rd_error(rd_error)
    );

    // clk_gen のインスタンス
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ACLK)
    );
    
    clk_gen #(
        .CLK_PERIOD(250),    // 25nsec, 40MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) PIXCLKi (
        .clk_out(pixclk)
    );
    
    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESETi (
        .reset_out(ARESETN)
    );

    // Instantiate the Unit Under Test (UUT_slave)
    CDC_axi_slave uut_slave (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .S_AXI_AWID(M_AXI_AWID), 
        .S_AXI_AWADDR(M_AXI_AWADDR), 
        .S_AXI_AWLEN(M_AXI_AWLEN), 
        .S_AXI_AWSIZE(M_AXI_AWSIZE), 
        .S_AXI_AWBURST(M_AXI_AWBURST), 
        .S_AXI_AWLOCK(2'b00), 
        .S_AXI_AWCACHE(M_AXI_AWCACHE), 
        .S_AXI_AWPROT(M_AXI_AWPROT), 
        .S_AXI_AWREGION(S_AXI_AWREGION), 
        .S_AXI_AWQOS(M_AXI_AWQOS), 
        .S_AXI_AWUSER(M_AXI_AWUSER), 
        .S_AXI_AWVALID(M_AXI_AWVALID), 
        .S_AXI_AWREADY(M_AXI_AWREADY), 
        .S_AXI_WID(S_AXI_WID), 
        .S_AXI_WDATA(M_AXI_WDATA), 
        .S_AXI_WSTRB(M_AXI_WSTRB), 
        .S_AXI_WLAST(M_AXI_WLAST), 
        .S_AXI_WUSER(M_AXI_WUSER), 
        .S_AXI_WVALID(M_AXI_WVALID), 
        .S_AXI_WREADY(M_AXI_WREADY), 
        .S_AXI_BID(M_AXI_BID), 
        .S_AXI_BRESP(M_AXI_BRESP), 
        .S_AXI_BUSER(M_AXI_BUSER), 
        .S_AXI_BVALID(M_AXI_BVALID), 
        .S_AXI_BREADY(M_AXI_BREADY), 
        .S_AXI_ARID(M_AXI_ARID), 
        .S_AXI_ARADDR(M_AXI_ARADDR), 
        .S_AXI_ARLEN(M_AXI_ARLEN), 
        .S_AXI_ARSIZE(M_AXI_ARSIZE), 
        .S_AXI_ARBURST(M_AXI_ARBURST), 
        .S_AXI_ARLOCK(M_AXI_ARLOCK), 
        .S_AXI_ARCACHE(M_AXI_ARCACHE), 
        .S_AXI_ARPROT(M_AXI_ARPROT), 
        .S_AXI_ARREGION(S_AXI_ARREGION), 
        .S_AXI_ARQOS(M_AXI_ARQOS), 
        .S_AXI_ARUSER(M_AXI_ARUSER), 
        .S_AXI_ARVALID(M_AXI_ARVALID), 
        .S_AXI_ARREADY(M_AXI_ARREADY), 
        .S_AXI_RID(M_AXI_RID), 
        .S_AXI_RDATA(M_AXI_RDATA), 
        .S_AXI_RRESP(M_AXI_RRESP), 
        .S_AXI_RLAST(M_AXI_RLAST), 
        .S_AXI_RUSER(M_AXI_RUSER), 
        .S_AXI_RVALID(M_AXI_RVALID), 
        .S_AXI_RREADY(M_AXI_RREADY), 
        .pixclk(pixclk), 
        .TMDS_tx_clk_p(TMDS_tx_clk_p), 
        .TMDS_tx_clk_n(TMDS_tx_clk_n), 
        .TMDS_tx_2_G_p(TMDS_tx_2_G_p), 
        .TMDS_tx_2_G_n(TMDS_tx_2_G_n), 
        .TMDS_tx_1_R_p(TMDS_tx_1_R_p), 
        .TMDS_tx_1_R_n(TMDS_tx_1_R_n), 
        .TMDS_tx_0_B_p(TMDS_tx_0_B_p), 
        .TMDS_tx_0_B_n(TMDS_tx_0_B_n)
    );
      
endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out
);
    begin
        initial begin
            reset_out = RESET_STATE;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
        end
    end
endmodule

`default_nettype wire


ISEのプロジェクトを作成した。下に階層図を示す。
cdctest_axi_master_1_120401.png

ISimでシミュレーションを行った。シミュレーション時間は51usec。Writeデータ転送の全体図を下に示す。
cdctest_axi_master_2_120401.png

M_AXI_WVALID の長さがデータ転送長を表している。いろいろな長さがあるのがわかると思う。M系列を使用した擬似乱数を使用している。間が開いているのは、Writeデータ転送の次に、同じ量のReadデータ転送を行なっているからだ。(WriteとReadはシーケンシャルにアクセスを行なっている)

次に、Readデータ転送の全体図を示す。
cdctest_axi_master_3_120401.png

こちらは、M_AXI_RVALID でReadデータ転送長がわかる。

Writeデータ転送の拡大図を下に示す。
cdctest_axi_master_4_120402.png

上のWriteデータ転送の拡大図に続くReadデータ転送を下に示す。Writeデータ転送の直後に同じアドレスで同じ転送長でReadすることによって直前に書き込んだWriteデータをReadすることができるかどうか?をテストする。テストして値が違っている場合はrd_error 出力を1にする。
cdctest_axi_master_5_120402.png

これで単体シミュレーションは終了したので、XPSでAXI4マスタIPを組み込んで実機で確認する。
  1. 2012年04月02日 04:38 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0