FC2カウンター FPGAの部屋 Altium Designer

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

FPGAの部屋

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

AXI4 Write Transaction のステートマシン

今まで、AXI4 Write Transaction のステートマシンは、Address ChannelとResponse Channelを一緒にしたステートマシンと Data Channel 用のステートマシンに分けていた。(”ZedBoard用CMOSカメラ回路の作製2(HDLソースの公開1)”参照)

しかし、なひたふさんの”ZYNQのPLからPSへ大規模DMA”の記事のタイミングチャートを見ると、Write Response Channel は別ステートマシンにしているか、無視していることがひと目で分かった。Write Response Channel をステートマシンにしておく必要も無く、BREADY をいつも 1 にしておいて、BVALID が来た時にエラーだったらエラー表示をすれば良いと思った。

この方式は特に、XilinxのAXI Interconnect をデフォルトで使用して、DDRメモリに書き込んでいる時に有効だと思う。と言うのは、かなり Write Response が帰ってくるまでが長いからだ。下に、ラプラシアン・フィルタ AXI4 Master IPでのAXI4 Write Transaction を示す。WLASTがアサートされてから、BVALIDがアサートされるまでに結構時間がかかっているのがわかる。その場合に、Write Response Channel を無視すれば、(つまり、BREADY をいつも 1 にしておくということ)次の、Write Address Channelのアサートが速くなって、全体のスループットの向上が図れる。
axi4m_lap_filter_40_131202.png

但し、AXI4 Master Interfaceモジュールを使用すれば、すべてのWrite のChannel を重ねあわせることができるように設計しているので、最小のレイテンシでAXI4 Master IPが作れるはずである。上のChipScope 波形は、AXI4 Master Interfaceモジュールを使用しているタイミングチャートである。Write Transaction のそれぞれのチャネルが重なり合っているのがわかるだろうか?
AXI4 Master Interfaceモジュールの作製1(仕様の検討)
AXI4 Master Interfaceモジュールの作製2(シミュレーション)
AXI4 Master Interfaceモジュールの作製3(シミュレーション2)
AXI4 Master Interfaceモジュールの作製4(axi4_master_inf.v のHDLソース)
AXI4 Master Interfaceモジュールの作製5(Write用FIFOのXCO)
AXI4 Master Interfaceモジュールの作製6(Read用FIFOのXCO)


なひたふさん、ありがとうございました。タイミングチャートを見せて頂いたので、勉強になりました。
  1. 2013年12月05日 20:44 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラの作製21(PlanAheadプロジェクトで画面にキャラクタを描画)

ビットマップ・ディスプレイ・コントローラの作製21(画面にキャラクタを描画)”でISEプロジェクト中にXPSプロジェクトを作って、MCBでDDR2を制御した。また、ビットマップ・ディスプレイ・コントローラ IPとキャラクタROM IPを追加し、MicroBlazeでキャラクタROMのラスタデータをReadして、DDR2 SDRAMフレームバッファに書くこむことによってキャラクタを表示することができた。だが、PlanAheadプロジェクトを使用して、MCBの設定を自分で行ったXPSプロジェクトでは、動作していない。ISEプロジェクトのXPSプロジェクトは、”AtlysボードでXPSプロジェクトを試す1(XPSのプロジェクト作成、インプリメント)”で使用したDigilent社のBSBサポート・パッケージを使用している。つまりMIGの設定はおまかせでXPSプロジェクトを作成した時点で設定されていた。(注:現在は、Atlys_BSB_Support_v_3_4でAXIバスのHDMI IPが入っていた。まだ動作は未確認)
そこで、ISEプロジェクトでうまく行ったXPSプロジェクトをPlanAheadプロジェクトで使用したら、うまくいくかどうか確かめてみた。
最初にPlanAheadプロジェクトを生成する場合にISEプロジェクトをインポートしたところ、XPSプロジェクトが無いと言われてエラーになってしまった。そこで、新規のPlanAheadプロジェクトを作成して、XPSプロジェクトをコピーしてみたところ、うまく論理合成、インプリメントが終了してビットストリームを出力することができた。
BitMapDispCont_135_120828.png

SDKにエクスポートして、drawn_disp.cをコンパイルして実行してみたところ、前回同様にキャラクタが並んだ画面が表示された。
BitMapDispCont_136_120828.png

BitMapDispCont_134_120826.png

となると、XPSプロジェクトにMCB (axi_s6_ddrx) をAdd IPする時のMIGの設定が悪いのか?自分でMCBを構築して動作できないと良くないので、設定値を比べてみたい。

(2012/08/29:追加)
axi_s6_ddrx の設定値は一緒にしましたが、自分でIPを追加した方はまだ動作しません。データバスを32ビットにしてMicroBlazeにつないでみることにします。
  1. 2012年08月28日 08:17 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラの作製21(画面にキャラクタを描画)

ビットマップ・ディスプレイ・コントローラの作製20(DDR2をMicroBlazeと接続)”の続き。

XPSプロジェクトには、キャラクタROMのAXI4 Lite IPが入っている。実は今回のビットマップ・ディスプレイ・コントローラをMircoBlazeからテストするためにキャラクタROMのAXI4 Lite IPを作った。(”AXI4 Lite Slave IPの作製”を参照のこと)
これをMicroBlazeから読みだして、MicroBlazeでDDR2 SDRAMのビデオ・フレームバッファに書き込めば、キャラクタを表示することが出来る。
SDKでソフトウェアを書いてやってみたらディスプレイにキャラクタを書くことに成功した。下にCのソフトウェアを示す。なお、xparameters.hのアドレス定義を使うとなぜか?うまくいかないので、アドレスは直書きしている。

/* * drawn_disp.c * *  Created on: 2012/08/23 *      Author: Masaaki */

// char_draw: アドレスとキャラクタコードを受け取ってそのキャラクタを描画する
// addr : 描画するキャラクタのスタートアドレス
// char_code : 描画するキャラクタのコード
// char_color : 描画するキャラクタのカラー、32ビットで表される、0RGBと8ビットずつで表す
// 戻り値:次のキャラクタの描画先頭アドレスを示す。
unsigned int *char_draw(unsigned int *addr, unsigned char char_code, unsigned int char_color){
    int i,j;
    unsigned int char_pattern;
    unsigned int char_code_int;
    unsigned int *cal_char_addr;
    unsigned int *return_addr;

    char_code_int = (unsigned int)(char_code);
    return_addr = addr + 8;
    cal_char_addr = 0x7f800000+((char_code_int<<3)<<2); // キャラジェネROMのデータは32ビット幅で下の8ビットだけ有効
    for(i=0; i<8; i++){
        char_pattern = *(volatile unsigned int *)(cal_char_addr); // キャラクタのパターンを読み出し
        for(j=0; j<8; j++){
            if(char_pattern & 0x1// 7ビット目が1の時はドットを描画
                *(volatile unsigned int *)((unsigned int)addr ^ 4) = char_color;
            else
                *(volatile unsigned int *)((unsigned int)addr ^ 4) = 0// 黒を描画
            addr++;
            char_pattern >>= 1// キャラクタのパターンを1ビット右シフト
        }
        addr -= 8// 行の最初のアドレスに戻す
        addr += 640// アドレスを1行下にする
        cal_char_addr++;
    }

    return return_addr;
}

int main()
{
    unsigned char char_code;
    unsigned int * ddr2_addr;
    unsigned int coler_code;
    unsigned int char_cnt;
    int i, j;

    for (ddr2_addr=0x20000000; ddr2_addr<0x2012C000; ddr2_addr++){
        *(volatile unsigned int *)((unsigned int)ddr2_addr ^ 4) = 0;
    }
    
    ddr2_addr = 0x20000000;
    char_cnt = 0;
    for(j=0; j<8; j++){
        for(i=1; i<8; i++){
            switch(i){
                case 1 :
                    coler_code = 0xff;
                    break;
                case 2 :
                    coler_code = 0xff00;
                    break;
                case 3 :
                    coler_code = 0xffff;
                    break;
                case 4 :
                    coler_code = 0xff0000;
                    break;
                case 5 :
                    coler_code = 0xff00ff;
                    break;
                case 6 :
                    coler_code = 0xffff00;
                    break;
                case 7 :
                    coler_code = 0xffffff;
            }
            
            for(char_code=0x21; char_code<0x80; char_code++){
                if(char_code >= 0x80// キャラクタコードが上限に達したら、一番下に戻す
                    char_code = 0x21;
                if (char_cnt!=0 && char_cnt%80==0)
                    ddr2_addr = (unsigned int)ddr2_addr + 640*4*7// 1行書き終わったので、下の行に、アドレスは640ドットx1ピクセル4バイトx7行
                ddr2_addr = char_draw(ddr2_addr, char_code, coler_code); // キャラクタを描画
                char_cnt++;
            }
        }
    }

    return 0;
}


このソフトウェアを実行した後のディスプレイの写真を下に示す。
BitMapDispCont_134_120826.png

(2012/08/28:追記)
なぜ、DDR2 SDRAMにデータを書く時に、4とXORを取っているかだが( *(volatile unsigned int *)((unsigned int)addr ^ 4) )、それは、AXI4バスはリトル・エンディアンだが、WriteとReadのデータバス幅が異なるFIFOのデータの出てくる順番はビック・エンディアンだからだ。(”Write側とRead側のデータ幅の異なるFIFOのシミュレーション2”を参照のこと)
MicroBlazeのデータバス幅は32ビット、ビットマップ・ディスプレイ・コントローラとMCBの接続されているAXI4バスのデータバス幅は64ビットで、その間をaxi2axi_connector で接続している。32ビット・データバスのMicroBlazeからDDR2 SDRAMにWriteする時に、Writeデータは64ビットの半分の32ビットで、リトル・エンディアンであるため、低いアドレスのデータはMSBの方の32ビットにWriteされる。ビットマップ・ディスプレイ・コントローラは64ビット・データバスでそのデータをReadして、ビック・エンディアンのWriteとReadのデータバス幅が異なるFIFOのデータでとり出すので、4バイト境界でアドレスが反対になる(MicroBlazeのデータWriteは4バイト長のみとする)。そこで、4とXORを取って4バイト境界のアドレスを反転して、MicroBlazeからデータをWriteしている。こうしないとキャラクタがうまく描画できないのだ。
  1. 2012年08月26日 06:10 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラの作製20(DDR2をMicroBlazeと接続)

ビットマップ・ディスプレイ・コントローラの作製19(HDLソースの公開)”の続き。

今回はXPSのaxi2axi_connector IPを使って、MicroBlazeとaxi_s6_ddrx_0(MCB)を接続して、MicroBlazeからDDR2 SDRAMのデータをRead/Writeしてみた。

axi2axi_connector の追加の仕方については、”AXI4バスに接続するビットマップ・ディスプレイ・コントローラの作製7(MCBインプリメント4)”を参照のこと。
今までのXPSのプロジェクトにaxi2axi_connector を追加した。
BitMapDispCont_131_120823.png

アドレスはaxi2axi_connector_0 が0x20000000 ~ 0x2FFFFFFF で、MCB_DDR2が0x20000000 ~ 0x27FFFFFF でアドレスがかぶっている。つまり、MicroBlaze のアクセスをaxi2axi_connector_0が中継することで、MicroBlazeがMCB_DDR2 にアクセスできるようになる。
BitMapDispCont_132_120823.png

・ISEでExport Hardware Design To SDK with Bitstream を選んで、SDKを立ち上げた。

・SDKでデバックモードにして、XMDで0x20000000にRead/Writeしてみたところ問題なくRead/Writeすることが出来た。
BitMapDispCont_130_120823.png

・SDKでプログラムを作って動作させてみたところ、HDMIの表示画面を書き換えることが出来た。
下図にSDKの画面を示す。
BitMapDispCont_133_120823.png

下にプログラムを示す。

/* * drawn_disp.c * *  Created on: 2012/08/23 *      Author: Masaaki */

int main()
{
    unsigned int * ddr2_addr;
    unsigned int pixel_data;

    pixel_data=0x0;
    for (ddr2_addr=0x20000000; ddr2_addr<0x20010000; ddr2_addr++){
        *(volatile unsigned int *)(ddr2_addr) = pixel_data++;
    }
    return 0;
}



HDMIの画面を下に示す。
BitMapDispCont_134_120823.jpg

以前の画面と比べると上の方が青くなっているのが見えるはずだ。以前の画面を下に示す。
BitMapDispCont_121_120821.jpg

これで、HDMI画面のフレームバッファとして使用しているDDR2 SDRAMにMicroBlazeからデータを書くことが出来た。とっても嬉しい。。。
32ビット幅のAXI4Liteバスと64ビット幅のAXI4バスがaxi2axi_connectorで接続できたことになる。まだChipScopeでプロトコルを確認してはいないが、XMDでアドレスを+4するとデータが+1されているのは確認した。
  1. 2012年08月23日 06:03 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラの作製19(HDLソースの公開)

ビットマップ・ディスプレイ・コントローラの作製18(動作した?)”の続き。

一応動作したと思われるので、HDLソースを公開します。無保証ですので、ご了承ください。後でバグがあった場合は修正します。また、バグを見つけた方はコメント欄でお知らせください。長いです。
まずは、画像の表示タイミングを定義する disp_timing_parameters.vh から。
(2012/12/13:修正、(誤)disp_timing_parameter.vh (正)disp_timing_parameters.vh)

//  表示タイミングの定義
    
    // VGA 解像度 pixel clock = 25MHz
    parameter H_ACTIVE_VIDEO= 640;
    parameter H_FRONT_PORCH = 16;
    parameter H_SYNC_PULSE = 96;
    parameter H_BACK_PORCH = 48;
    parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

    parameter V_ACTIVE_VIDEO = 480;
    parameter V_FRONT_PORCH = 11;
    parameter V_SYNC_PULSE = 2;
    parameter V_BACK_PORCH = 31;
    parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

    // SVGA 解像度 pixel clock = 40MHz
    // parameter H_ACTIVE_VIDEO= 800;
    // parameter H_FRONT_PORCH = 40;
    // parameter H_SYNC_PULSE = 128;
    // parameter H_BACK_PORCH = 88;
    // parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

    // parameter V_ACTIVE_VIDEO = 600;
    // parameter V_FRONT_PORCH = 1;
    // parameter V_SYNC_PULSE = 4;
    // parameter V_BACK_PORCH = 23;
    // parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

    // XGA 解像度 pixel clock = 65MHz
    // parameter H_ACTIVE_VIDEO= 1024;
    // parameter H_FRONT_PORCH = 24;
    // parameter H_SYNC_PULSE = 136;
    // parameter H_BACK_PORCH = 160;
    // parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

    // parameter V_ACTIVE_VIDEO = 768;
    // parameter V_FRONT_PORCH = 2;
    // parameter V_SYNC_PULSE = 6;
    // parameter V_BACK_PORCH = 29;
    // parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

    // SXGA 解像度 pixel clock = 108MHz
    // parameter H_ACTIVE_VIDEO= 1280;
    // parameter H_FRONT_PORCH = 48;
    // parameter H_SYNC_PULSE = 112;
    // parameter H_BACK_PORCH = 248;
    // parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;

    // parameter V_ACTIVE_VIDEO = 1024;
    // parameter V_FRONT_PORCH = 1;
    // parameter V_SYNC_PULSE = 3;
    // parameter V_BACK_PORCH = 38;
    // parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

    
    parameter H_DISPLAY_SIZE = H_ACTIVE_VIDEO/8; // 横80桁
    parameter V_DISPLAY_SIZE = V_ACTIVE_VIDEO/8; // 縦60行
    
    parameter RED_DOT_POS = 15; // 15~13ビット目がRED
    parameter GREEN_DOT_POS = 12; // 12~10ビット目がGREEN
    parameter BLUE_DOT_POS = 9; // 9~7ビット目がBLUE
    parameter COLOR_ATTRIB_WIDHT = 3;    // 色情報のビット幅


次に、XPSのpcore のトップの bitmap_disp_cntrler_axi_master.v

// bitmap_disp_cntrler_axi_master.v 
//
// Read Only IP, 64 bit bus
//
// 2012/06/28

`default_nettype none

module bitmap_disp_cntrler_axi_master #
  (
        parameter integer C_INTERCONNECT_M_AXI_WRITE_ISSUING = 8,
        parameter integer C_M_AXI_THREAD_ID_WIDTH       = 1,
        parameter integer C_M_AXI_ADDR_WIDTH            = 32,
        parameter integer C_M_AXI_DATA_WIDTH            = 64,
        parameter integer C_M_AXI_AWUSER_WIDTH          = 1,
        parameter integer C_M_AXI_ARUSER_WIDTH          = 1,
        parameter integer C_M_AXI_WUSER_WIDTH           = 1,
        parameter integer C_M_AXI_RUSER_WIDTH           = 1,
        parameter integer C_M_AXI_BUSER_WIDTH           = 1,
        parameter [31:0]  C_M_AXI_TARGET                 = 32'h00000000,
        parameter integer C_M_AXI_BURST_LEN                = 256,
        parameter integer C_OFFSET_WIDTH                = 32,
        
        /* Disabling these parameters will remove any throttling.
        The resulting ERROR flag will not be useful */ 
        parameter integer C_M_AXI_SUPPORTS_WRITE         = 0,
        parameter integer C_M_AXI_SUPPORTS_READ         = 1
    )
    (
        // System Signals
        input wire           ACLK,
        input wire           ARESETN,

        // Master Interface Write Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0] M_AXI_AWID,
        output wire [C_M_AXI_ADDR_WIDTH-1:0]      M_AXI_AWADDR,
        output wire [8-1:0]              M_AXI_AWLEN,
        output wire [3-1:0]              M_AXI_AWSIZE,
        output wire [2-1:0]              M_AXI_AWBURST,
        output wire                  M_AXI_AWLOCK,
        output wire [4-1:0]              M_AXI_AWCACHE,
        output wire [3-1:0]              M_AXI_AWPROT,
        // AXI3 output wire [4-1:0]                  M_AXI_AWREGION,
        output wire [4-1:0]              M_AXI_AWQOS,
        output wire [C_M_AXI_AWUSER_WIDTH-1:0]      M_AXI_AWUSER,
        output wire                  M_AXI_AWVALID,
        input  wire                  M_AXI_AWREADY,

        // Master Interface Write Data
        // AXI3 output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]     M_AXI_WID,
        output wire [C_M_AXI_DATA_WIDTH-1:0]      M_AXI_WDATA,
        output wire [C_M_AXI_DATA_WIDTH/8-1:0]      M_AXI_WSTRB,
        output wire                  M_AXI_WLAST,
        output wire [C_M_AXI_WUSER_WIDTH-1:0]      M_AXI_WUSER,
        output wire                  M_AXI_WVALID,
        input  wire                  M_AXI_WREADY,

        // Master Interface Write Response
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_BID,
        input  wire [2-1:0]              M_AXI_BRESP,
        input  wire [C_M_AXI_BUSER_WIDTH-1:0]      M_AXI_BUSER,
        input  wire                  M_AXI_BVALID,
        output wire                  M_AXI_BREADY,

        // Master Interface Read Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_ARID,
        output wire [C_M_AXI_ADDR_WIDTH-1:0]      M_AXI_ARADDR,
        output wire [8-1:0]              M_AXI_ARLEN,
        output wire [3-1:0]              M_AXI_ARSIZE,
        output wire [2-1:0]              M_AXI_ARBURST,
        output wire [2-1:0]              M_AXI_ARLOCK,
        output wire [4-1:0]              M_AXI_ARCACHE,
        output wire [3-1:0]              M_AXI_ARPROT,
        // AXI3 output wire [4-1:0]          M_AXI_ARREGION,
        output wire [4-1:0]              M_AXI_ARQOS,
        output wire [C_M_AXI_ARUSER_WIDTH-1:0]      M_AXI_ARUSER,
        output wire                  M_AXI_ARVALID,
        input  wire                  M_AXI_ARREADY,

        // Master Interface Read Data 
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_RID,
        input  wire [C_M_AXI_DATA_WIDTH-1:0]      M_AXI_RDATA,
        input  wire [2-1:0]              M_AXI_RRESP,
        input  wire                  M_AXI_RLAST,
        input  wire [C_M_AXI_RUSER_WIDTH-1:0]      M_AXI_RUSER,
        input  wire                  M_AXI_RVALID,
        output wire                  M_AXI_RREADY,
        
        // User Ports
        input    wire    pixclk,
        
        output    wire    TMDS_tx_clk_p,
        output    wire    TMDS_tx_clk_n,
        output    wire    TMDS_tx_2_G_p,
        output    wire    TMDS_tx_2_G_n,
        output    wire    TMDS_tx_1_R_p,
        output    wire    TMDS_tx_1_R_n,
        output    wire    TMDS_tx_0_B_p,
        output    wire    TMDS_tx_0_B_n,
        
        input    wire    ddr_cont_init_done
    );
    
    wire    [7:0]    red, green, blue;
    wire    hsyncx, vsyncx;
    wire    display_enable;
    wire    bde_req, bde_ack;
    wire    [7:0]    bde_arlen;
    wire    [31:0]    bde_address;
    wire    [63:0]    bde_data;
    wire    bde_data_valid;
    reg        reset_disp_2b, reset_disp_1b;
    wire    reset_disp;
    wire    afifo_overflow, afifo_underflow;
    wire    addr_is_zero, h_v_is_zero;
    
    axi_master_interface #(
        .C_M_AXI_THREAD_ID_WIDTH(C_M_AXI_THREAD_ID_WIDTH),
        .C_M_AXI_ADDR_WIDTH(C_M_AXI_ADDR_WIDTH),
        .C_M_AXI_DATA_WIDTH(C_M_AXI_DATA_WIDTH),
        .C_M_AXI_AWUSER_WIDTH(C_M_AXI_AWUSER_WIDTH),
        .C_M_AXI_ARUSER_WIDTH(C_M_AXI_ARUSER_WIDTH),
        .C_M_AXI_WUSER_WIDTH(C_M_AXI_WUSER_WIDTH),
        .C_M_AXI_RUSER_WIDTH(C_M_AXI_RUSER_WIDTH),
        .C_M_AXI_BUSER_WIDTH(C_M_AXI_BUSER_WIDTH),
        .C_M_AXI_SUPPORTS_WRITE(C_M_AXI_SUPPORTS_WRITE),
        .C_M_AXI_SUPPORTS_READ(C_M_AXI_SUPPORTS_READ)
    ) axi_master_inf_inst
    (
        .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), 
        
        .bde_req(bde_req),
        .bde_ack(bde_ack),
        .bde_arlen(bde_arlen),
        .bde_address(bde_address),
        .bde_data_out(bde_data),
        .bde_data_valid(bde_data_valid)
    );
    
    bitmap_disp_engine bitmap_disp_eng_inst (
        .clk_disp(pixclk),
        .clk_axi(ACLK),
        .reset_disp(reset_disp),
        .reset_axi(~ARESETN),
        .req(bde_req),
        .ack(bde_ack),
        .ARLEN(bde_arlen),
        .address(bde_address),
        .data_in(bde_data),
        .data_valid(bde_data_valid),
        .red_out(red),
        .green_out(green),
        .blue_out(blue),
        .hsyncx(hsyncx),
        .vsyncx(vsyncx),
        .display_enable(display_enable),
        .ddr_cont_init_done(ddr_cont_init_done),
        .afifo_overflow(afifo_overflow),
        .afifo_underflow(afifo_underflow),
        .addr_is_zero(addr_is_zero),
        .h_v_is_zero(h_v_is_zero)
    );
    
    dvi_disp #(
        .PLL_CLKFBOUT_MULT(20),        // クロック倍率 PLL VCO Freq 400MHz ~ 1000MHz
        .PLL_CLKIN_PERIOD(40.0),    // 40 ns, VGA, 640x480
        .PLL_CLKOUT0_DIVIDE(2),        // ピクセルクロックX10
        .PLL_CLKOUT1_DIVIDE(20),    // ピクセルクロック
        .PLL_CLKOUT2_DIVIDE(10)        // ピクセルクロックX2
    ) dvi_disp_inst
    (
        .pixclk(pixclk),
        .reset_in(reset_disp),
        .red_in(red),
        .green_in(green),
        .blue_in(blue),
        .hsync(hsyncx),
        .vsync(vsyncx),
        .display_enable(display_enable),
        .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)
    );
    
    always @(posedge pixclk) begin
        reset_disp_2b <= ~ARESETN;
        reset_disp_1b <= reset_disp_2b;
    end
    assign reset_disp = reset_disp_1b;
endmodule

`default_nettype wire


次に、AXI4バスとのインターフェースの axi_master_interface.v です。ビットマップ・ディスプレイ・コントローラはDDR2 SDRAMからReadするだけなので、Write側は実装していません。

// axi_master_interface.v
//
// Read Only IP, 64 bit bus
//
// 2012/06/28

`default_nettype none

module axi_master_interface #
  (
        parameter integer C_M_AXI_THREAD_ID_WIDTH       = 1,
        parameter integer C_M_AXI_ADDR_WIDTH            = 32,
        parameter integer C_M_AXI_DATA_WIDTH            = 64,
        parameter integer C_M_AXI_AWUSER_WIDTH          = 1,
        parameter integer C_M_AXI_ARUSER_WIDTH          = 1,
        parameter integer C_M_AXI_WUSER_WIDTH           = 1,
        parameter integer C_M_AXI_RUSER_WIDTH           = 1,
        parameter integer C_M_AXI_BUSER_WIDTH           = 1,

        /* Disabling these parameters will remove any throttling.
        The resulting ERROR flag will not be useful */ 
        parameter integer C_M_AXI_SUPPORTS_WRITE         = 0,
        parameter integer C_M_AXI_SUPPORTS_READ         = 1
    )
    (
        // System Signals
        input wire           ACLK,
        input wire           ARESETN,

        // Master Interface Write Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0] M_AXI_AWID,
        output wire [C_M_AXI_ADDR_WIDTH-1:0]      M_AXI_AWADDR,
        output wire [8-1:0]              M_AXI_AWLEN,
        output wire [3-1:0]              M_AXI_AWSIZE,
        output wire [2-1:0]              M_AXI_AWBURST,
        output wire                  M_AXI_AWLOCK,
        output wire [4-1:0]              M_AXI_AWCACHE,
        output wire [3-1:0]              M_AXI_AWPROT,
        // AXI3 output wire [4-1:0]                  M_AXI_AWREGION,
        output wire [4-1:0]              M_AXI_AWQOS,
        output wire [C_M_AXI_AWUSER_WIDTH-1:0]      M_AXI_AWUSER,
        output wire                  M_AXI_AWVALID,
        input  wire                  M_AXI_AWREADY,

        // Master Interface Write Data
        // AXI3 output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]     M_AXI_WID,
        output wire [C_M_AXI_DATA_WIDTH-1:0]      M_AXI_WDATA,
        output wire [C_M_AXI_DATA_WIDTH/8-1:0]      M_AXI_WSTRB,
        output wire                  M_AXI_WLAST,
        output wire [C_M_AXI_WUSER_WIDTH-1:0]      M_AXI_WUSER,
        output wire                  M_AXI_WVALID,
        input  wire                  M_AXI_WREADY,

        // Master Interface Write Response
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_BID,
        input  wire [2-1:0]              M_AXI_BRESP,
        input  wire [C_M_AXI_BUSER_WIDTH-1:0]      M_AXI_BUSER,
        input  wire                  M_AXI_BVALID,
        output wire                  M_AXI_BREADY,

        // Master Interface Read Address
        output wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_ARID,
        output reg  [C_M_AXI_ADDR_WIDTH-1:0]      M_AXI_ARADDR,
        output reg  [8-1:0]              M_AXI_ARLEN,
        output wire [3-1:0]              M_AXI_ARSIZE,
        output wire [2-1:0]              M_AXI_ARBURST,
        output wire [2-1:0]              M_AXI_ARLOCK,
        output wire [4-1:0]              M_AXI_ARCACHE,
        output wire [3-1:0]              M_AXI_ARPROT,
        // AXI3 output wire [4-1:0]          M_AXI_ARREGION,
        output wire [4-1:0]              M_AXI_ARQOS,
        output wire [C_M_AXI_ARUSER_WIDTH-1:0]      M_AXI_ARUSER,
        output wire                  M_AXI_ARVALID,
        input  wire                  M_AXI_ARREADY,

        // Master Interface Read Data 
        input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]      M_AXI_RID,
        input  wire [C_M_AXI_DATA_WIDTH-1:0]      M_AXI_RDATA,
        input  wire [2-1:0]              M_AXI_RRESP,
        input  wire                  M_AXI_RLAST,
        input  wire [C_M_AXI_RUSER_WIDTH-1:0]      M_AXI_RUSER,
        input  wire                  M_AXI_RVALID,
        output wire                  M_AXI_RREADY,
        
        // bitmap_disp_engine Interface
        input    wire    bde_req,
        output    reg    bde_ack,
        input    wire    [7:0]    bde_arlen,
        input    wire    [31:0]    bde_address,
        output    reg        [63:0]    bde_data_out,
        output    reg        bde_data_valid
    );
    
    parameter    RESP_OKAY =        2'b00,
                RESP_EXOKAY =    2'b01,
                RESP_SLVERR =    2'b10,
                RESP_DECERR =    2'b11;
    
    reg        reset_1d, reset;
    
    parameter    idle_rd =            4'b0001,
                arvalid_assert =    4'b0010,
                data_read =            4'b0100,
                rd_tran_end =        4'b1000;
    reg        [3:0]    rdt_cs;
    
    reg        arvalid;
    reg        [63:0]    read_data;
    reg        rready;
    
    // ARESETN をACLK で同期化
    always @(posedge ACLK) begin
        reset_1d <= ~ARESETN;
        reset <= reset_1d;
    end
    
    // Write は無し
    assign    M_AXI_AWID = 0;
    assign    M_AXI_AWADDR = 0;
    assign    M_AXI_AWLEN = 0;
    assign    M_AXI_AWSIZE = 0;
    assign    M_AXI_AWBURST = 0;
    assign    M_AXI_AWLOCK = 0;
    assign    M_AXI_AWCACHE = 0;
    assign    M_AXI_AWPROT = 0;
    assign    M_AXI_AWQOS = 0;
    assign    M_AXI_AWUSER = 0;
    assign    M_AXI_AWVALID = 0;
    assign    M_AXI_WDATA = 0;
    assign    M_AXI_WSTRB = 0;
    assign    M_AXI_WLAST = 0;
    assign    M_AXI_WUSER = 0;
    assign    M_AXI_WVALID = 0;
    assign    M_AXI_BREADY = 0;

    // Read
    
    // AXI4バス Read Transaction State Machine
    always @(posedge ACLK) begin
        if (reset) begin
            rdt_cs <= idle_rd;
            arvalid <= 1'b0;
            rready <= 1'b0;
        end else begin
            case (rdt_cs)
                idle_rd :
                    if (bde_req) begin
                        rdt_cs <= arvalid_assert;
                        arvalid <= 1'b1;
                    end
                arvalid_assert :
                    if (M_AXI_ARREADY) begin
                        rdt_cs <= data_read;
                        arvalid <= 1'b0;
                        rready <= 1'b1;
                    end
                data_read :
                    if (M_AXI_RLAST && M_AXI_RVALID) begin // 終了
                        rdt_cs <= rd_tran_end;
                        rready <= 1'b0;
                    end
                rd_tran_end :
                    rdt_cs <= idle_rd;
            endcase
        end
    end
    assign M_AXI_ARVALID = arvalid;
    assign M_AXI_RREADY = rready;
    
    assign M_AXI_ARID = 0;
    
    // M_AXI_ARADDR の処理
    always @(posedge ACLK) begin
        if (reset)
            M_AXI_ARADDR <= 0;
        else begin
            if (bde_req)
                M_AXI_ARADDR <= bde_address;
        end
    end
    
    // M_AXI_ARLEN の処理
    always @(posedge ACLK) begin
        M_AXI_ARLEN <= bde_arlen;
    end
    
    assign M_AXI_ARSIZE = 3'b011;        // 8 Bytes in Transfer
    assign M_AXI_ARBURST = 2'b01;        // INCR
    assign M_AXI_ARLOCK = 2'b00;        // Normal Access
    assign M_AXI_ARCACHE = 4'b0010;    // Normal Non-cacheable Non-bufferable
    assign M_AXI_ARPROT = 3'b000;        // Data access, Secure access, Unprivileged access
    assign M_AXI_ARQOS = 4'b0000;        // default
    assign M_AXI_ARUSER = 1'b0;
    
    // bde_ack の処理
    always @(posedge ACLK) begin
        if (arvalid && M_AXI_ARREADY)
            bde_ack <= 1'b1;
        else
            bde_ack <= 1'b0;
    end
    
    // bde_data_out の処理
    always @(posedge ACLK) begin
        bde_data_out <= M_AXI_RDATA;
    end
    
    // bde_data_valid の処理
    always @(posedge ACLK) begin
        if (rready && M_AXI_RVALID)
            bde_data_valid <= 1'b1;
        else
            bde_data_valid <= 1'b0;
    end
    
endmodule


ビットマップ・ディスプレイ・コントローラの中核部で、水平同期、垂直同期を作ったり、DDR2 SDRAMからピクセルデータを読んでくるように指示する bitmap_disp_engine.v です。

// BitMap Display Controller
// bitmap_disp_engine.v
// AXI4バス用

`default_nettype none

// synthesis translate_off
// `include "std_ovl_defines.h"
// synthesis translate_on

module bitmap_disp_engine (    
    input    wire    clk_disp,            // ディスプレイ表示用クロック
    input    wire    clk_axi,            // AXI4バスクロック
    input    wire    reset_disp,            // clk_disp 用リセット
    input    wire    reset_axi,            // clk_axi 用リセット
    output    reg        req,                // Read Address転送のrequest
    input    wire    ack,                // Read Address転送のacknowlege 
    output    reg        [7:0]    ARLEN,        // Read Address転送のバースト長-1
    output    wire    [31:0]    address,    // AXI4 Busのアドレス
    input    wire    [63:0]    data_in,    // DDR2 SDRAMの画像データ(2つのRGB)
    input    wire    data_valid,
    output    reg        [7:0]    red_out,
    output    reg        [7:0]    green_out,
    output    reg      [7:0]    blue_out,
    output    reg     hsyncx,
    output    reg     vsyncx,
    output    reg        display_enable,
    input    wire    ddr_cont_init_done,    // DDR2 SDRAMコントローラの初期化終了
    output    wire    afifo_overflow, // 非同期FIFO のオーバーフロー・エラー
    output    wire    afifo_underflow,    // 非同期FIFO のアンダーフロー・エラー
    output    reg        addr_is_zero,    // for test
    output    reg        h_v_is_zero        // for test
);
    `include "./disp_timing_parameters.vh"
    
    parameter DDR2_SDRAM_START_ADDRESS = 32'h2000_0000;    // DDR2 SDRAMのスタートアドレス
    
    parameter AFIFO_FULL_VAL = 8'b1000_0000; // Write側の値。Write側は32ビットなので、128でRead側は256となる
    parameter AFIFO_HALF_FULL_VAL = 8'b0100_0000; // Write側の値。Write側は32ビットなので、64でRead側は128となる
    
    parameter [5:0]    idle_rdg=            6'b000001,
                    init_full_mode=        6'b000010,
                    wait_half_full=        6'b000100,
                    req_burst=            6'b001000,
                    frame_wait_state=    6'b010000,
                    frame_start_full=    6'b100000;
    reg    [5:0] cs_rdg;
    
    parameter [2:0]    IDLE_REQ =        3'b001,
                    REQ_ASSERT =    3'b010,
                    REQ_HOLD =        3'b100;
    reg [2:0]    cs_req;
    
    reg afifo_rd_en;
    wire [31:0] afifo_dout;
    wire afifo_full;
    wire afifo_empty;
    wire [7:0] wr_data_count;
    reg [31:0] addr_count;
    (* KEEP="TURE" *) wire hv_count_enable;
    reg [7:0] read_count;
    (* KEEP="TURE" *) reg hv_cnt_ena_d1;
    (* KEEP="TURE" *) reg hv_cnt_ena_d2;
    reg [11:0] h_count;
    reg [11:0] v_count;
    reg [7:0] red_node, green_node, blue_node;
    reg hsyncx_node, vsyncx_node;
    reg addr_is_zero_node, h_v_is_zero_node;
    reg vsync_axi, vsync_axi_b1;
    reg vsync_axi_1d;
    reg vsyncx_rise_pulse;

    // synthesis translate_off
    // wire [`OVL_FIRE_WIDTH-1:0] fire_overflow, fire_underflow;
    // synthesis translate_on
    
    // RGB保存用非同期FIFO, FWFT Wirte側64ビット幅128深度、Read側32ビット256深度とする
    bitmap_afifo bitmap_afifo_inst (
        .wr_rst(reset_axi | vsync_axi),
        .wr_clk(clk_axi),
        .rd_clk(clk_disp),
        .rd_rst(reset_disp | ~vsyncx_node),
        .din(data_in), // Bus [63 : 0] 
        .wr_en(data_valid),
        .rd_en(afifo_rd_en),
        .dout(afifo_dout), // Bus [31 : 0] 
        .full(afifo_full),
        .overflow(afifo_overflow),
        .empty(afifo_empty),
        .underflow(afifo_underflow),
        .wr_data_count(wr_data_count) // Bus [7 : 0] 
    );
    
    // AXI4 Busのアドレスカウンタ(AXI4クロックドメイン)カウンタの単位は1バイト
    always @(posedge clk_axi) begin
        if (reset_axi)
            addr_count <= DDR2_SDRAM_START_ADDRESS;
        else begin
            // if (addr_count>=(DDR2_SDRAM_START_ADDRESS + (H_ACTIVE_VIDEO * V_ACTIVE_VIDEO *4))) // 1フレーム分描画終了したのでクリアする(1ピクセルに3バイト使用する。つまり32ビット(4bytes)使用するので*4する)
            if (vsync_axi)
                addr_count <= DDR2_SDRAM_START_ADDRESS;
            else if (data_valid) // データが来たらカウントアップ
                addr_count <= addr_count + 32'd8; // 1回のデータは64ビット長(8バイト)
        end
    end
    assign address = addr_count;
    
    // Readデータ処理モジュール用ステートマシン
    always @(posedge clk_axi) begin
        if (reset_axi)
            cs_rdg <= idle_rdg;
        else begin
            case (cs_rdg)
                idle_rdg :
                    if (ddr_cont_init_done)
                        cs_rdg <= init_full_mode;
                init_full_mode : // 最初にcam_data_afifo をFULLにするステート、このステートではVGA信号は出力しないで、ひたすらcam_data_afifo がFULLになるのを待つ。
                    if (read_count==0)
                        cs_rdg <= wait_half_full;
                wait_half_full : // cam_data_afifo がHALF_FULLになるまでこのステートで待機
                    if (vsync_axi)
                        cs_rdg <= frame_wait_state;
                    else if (wr_data_count<=AFIFO_HALF_FULL_VAL)
                        cs_rdg <= req_burst;
                req_burst :
                    if (vsync_axi)
                        cs_rdg <= frame_wait_state;
                    else if (read_count==0) // データが全部来たら
                        cs_rdg <= wait_half_full;
                frame_wait_state : // 1フレーム終了後vsync の時にWaitする
                    if (vsyncx_rise_pulse) // vsyncx の立ち上がり
                        cs_rdg <= frame_start_full;
                frame_start_full : // 1フレームのスタートの時にFIFOをフルにする
                    if (read_count==0)
                        cs_rdg <= wait_half_full;
            endcase
        end
    end
    assign hv_count_enable = (cs_rdg==wait_half_full || cs_rdg==req_burst || cs_rdg==frame_wait_state || cs_rdg==frame_start_full) ? 1'b1 : 1'b0;
    
    // req の実装。VRAMのデータをReadしたいときにアクティベート。ackが帰ってきたら落とす
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            cs_req <= IDLE_REQ;
            req <= 1'b0;
        end else begin
            case (cs_req)
                IDLE_REQ : 
                    if (cs_rdg==req_burst || cs_rdg==init_full_mode || cs_rdg==frame_start_full) begin
                        cs_req <= REQ_ASSERT;
                        req <= 1'b1;
                    end
                REQ_ASSERT :
                    if (ack) begin
                        cs_req <= REQ_HOLD;
                        req <= 1'b0;
                    end
                REQ_HOLD :
                    if (~(cs_rdg==req_burst || cs_rdg==init_full_mode || cs_rdg==frame_start_full))
                        cs_req <= IDLE_REQ;
            endcase
        end
    end
    
    // ARLEN, read_count の決定。 init_full_mode,frame_start_full  の時はAFIFO_FULL_VAL-1、それ以外はAFIFO_HALF_FULL_VAL-1
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            ARLEN <= AFIFO_FULL_VAL-1;
            read_count <= AFIFO_FULL_VAL;
        end else begin
            if (cs_rdg==idle_rdg || cs_rdg==frame_wait_state) begin
                ARLEN <= AFIFO_FULL_VAL-1;
                read_count <= AFIFO_FULL_VAL;
            end else if (cs_rdg==wait_half_full) begin
                ARLEN <= AFIFO_HALF_FULL_VAL-1;
                read_count <= AFIFO_HALF_FULL_VAL;
            end else if (cs_rdg==req_burst || cs_rdg==init_full_mode || cs_rdg==frame_start_full) begin
                if (read_count!=0 && data_valid) // 0になるまで、データが来たらデクリメント
                    read_count <= read_count - 1;
            end
        end
    end
    
    // read_count の実装、AXI4 Bus Interface へのRead要求のカウントをする。
    // always @(posedge clk_axi) begin
        // if (reset_axi)
            // read_count <= ARLEN+1;
        // else begin
            // if (cs_rdg==wait_half_full || cs_rdg==idle_rdg)
                // read_count <= ARLEN+1;
            // else if (cs_rdg==req_burst || cs_rdg==init_full_mode) begin
                // if (read_count!=0 && data_valid) // 0になるまで、データが来たらデクリメント
                    // read_count <= read_count - 1;
            // end
        // end
    // end
    
    // ビットマップVGAコントローラのclk_disp 動作部
    
    // h_count、v_count用にclk_axi 動作のcs_rdg の値を使用するので2回clk_disp 動作のFFでラッチする
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            hv_cnt_ena_d1 <= 1'b0;
            hv_cnt_ena_d2 <= 1'b0;
        end else begin
            hv_cnt_ena_d1 <= hv_count_enable;
            hv_cnt_ena_d2 <= hv_cnt_ena_d1;
        end
    end
    
    // h_countの実装(水平カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp)
            h_count <= 0;
        else if (h_count>=(H_SUM-1)) // h_count がH_SUM-1よりも大きければ0に戻す(mod H_SUM)
            h_count <= 0;
        else if (hv_cnt_ena_d2) // 最初に非同期FIFOをフルにするまではカウントしない
            h_count <= h_count + 11'd1;
    end
    
    // v_countの実装(垂直カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp)
            v_count <= 0;
        else if (h_count>=(H_SUM-1)) begin // 水平カウンタがクリアされるとき
            if (v_count>=(V_SUM-1)) // v_count がV_SUM-1よりも大きければ0に戻す(mode V_SUM)
                v_count <= 0;
            else if (hv_cnt_ena_d2) // 最初に非同期FIFOをフルにするまではカウントしない
                v_count <= v_count + 10'd1;
        end
    end
    
    // Red, Green, Blue出力
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            red_node <= 0;
            green_node <= 0;
            blue_node <= 0;
        end else begin
            if (~hv_cnt_ena_d2) begin // 最初にpixel_async_fifo がフルになるまで画像データを出力しない。
                red_node <= 0;
                green_node <= 0;
                blue_node <= 0;
            end else if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO) begin
                red_node <= afifo_dout[23:16];
                green_node <= afifo_dout[15:8];
                blue_node <= afifo_dout[7:0];
            end else begin
                red_node <= 0;
                green_node <= 0;
                blue_node <= 0;
            end 
                
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            red_out <= 0;
            green_out <= 0;
            blue_out <= 0;
        end else begin
            red_out <= red_node;
            green_out <= green_node;
            blue_out <= blue_node;
        end
    end
    
    // hsyncx 出力(水平同期信号)
    always @(posedge clk_disp) begin
        if (reset_disp)
            hsyncx_node <= 1'b1;
        else
            if (h_count>(H_ACTIVE_VIDEO + H_FRONT_PORCH-1) && h_count<=(H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE-1)) // 水平同期期間
                hsyncx_node <= 1'b0;
            else
                hsyncx_node <= 1'b1;
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            hsyncx <= 1'b1;
        else
            hsyncx <= hsyncx_node;
    end
    
    // vsyncx 出力(水平同期信号)
    always @(posedge clk_disp) begin
        if (reset_disp)
            vsyncx_node <= 1'b1;
        else
            if (v_count>(V_ACTIVE_VIDEO + V_FRONT_PORCH-1) && v_count<=(V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE-1)) // 垂直同期期間
                vsyncx_node <= 1'b0;
            else
                vsyncx_node <= 1'b1;
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            vsyncx <= 1'b1;
        else
            vsyncx <= vsyncx_node;
    end

    // vsync をclk_axi で同期化
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            vsync_axi        <= 1'b0;
            vsync_axi_b1    <= 1'b0;
            vsync_axi_1d    <= 1'b0;
        end else begin
            vsync_axi_b1     <= ~vsyncx_node;
            vsync_axi         <= vsync_axi_b1;
            vsync_axi_1d    <= vsync_axi;
        end
    end
    
    // vsyncx_rise_pulse の処理。vsyncx の立ち上がり時に1パルス出力する
    always @(posedge clk_axi) begin
        if (reset_axi)
            vsyncx_rise_pulse <= 1'b0;
        else begin
            if (vsync_axi==1'b0 && vsync_axi_1d==1'b1)
                vsyncx_rise_pulse <= 1'b1;
            else
                vsyncx_rise_pulse <= 1'b0;
        end
    end
    
    // display_enable 出力
    always @(posedge clk_disp) begin
        if (reset_disp)
            display_enable <= 1'b1;
        else begin
            if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO)
                display_enable <= 1'b1;
            else
                display_enable <= 1'b0;
        end
    end
    
    // afifo_rd_en の処理
    always @(posedge clk_disp) begin
        if (reset_disp)
            afifo_rd_en <= 1'b0;
        else begin
            if (~hv_cnt_ena_d2) // 初期化中
                afifo_rd_en <= 1'b0;
            else if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO) // 表示期間
                afifo_rd_en <= 1'b1;
            else
                afifo_rd_en <= 1'b0;
        end
    end

    
    // アサーション
    // synthesis translate_off
    always @ (posedge clk_axi) begin
        if (reset_axi)
            ;
        else begin
            if (afifo_overflow) begin 
                $display("%m: at time %t ERROR : FIFOがフルなのにライトした",$time);
                $stop;
            end
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp)
            ;
        else begin
            if (afifo_underflow) begin
                $display("%m: at time %t ERROR : FIFOが空なのにリードした",$time);
                $stop;
            end
        end
    end
    
    // ovl_never #(
        // `OVL_ERROR,            // severity_level
        // `OVL_ASSERT,        // property_type
        // "ERROR : FIFOがフルなのにライトした", // msg
        // `OVL_COVER_DEFAULT,    // coverage_level
        // `OVL_POSEDGE,        // clock_edge
        // `OVL_ACTIVE_HIGH,    // reset_polarity
        // `OVL_GATE_CLOCK    // gating_type
    // ) afifo_overflow_assertion (
        // clk_axi,
        // reset_axi,
        // 1'b1,
        // afifo_overflow,
        // fire_overflow
    // );
        
    // ovl_never #(
        // `OVL_ERROR,            // severity_level
        // `OVL_ASSERT,        // property_type
        // "ERROR : FIFOが空なのにリードした", // msg
        // `OVL_COVER_DEFAULT,    // coverage_level
        // `OVL_POSEDGE,        // clock_edge
        // `OVL_ACTIVE_HIGH,    // reset_polarity
        // `OVL_GATE_CLOCK    // gating_type
    // ) afifo_underflow_assertion (
        // clk_disp,
        // reset_disp,
        // 1'b1,
        // afifo_underflow,
        // fire_underflow
    // );
    // synthesis translate_on
    
    //  for test
    always @(posedge clk_axi) begin
        if (reset_axi) begin
            addr_is_zero_node <= 1'b0;
            addr_is_zero <= 1'b0;
        end else begin
            if (addr_count == 0)
                addr_is_zero_node <= 1'b1;
            else
                addr_is_zero_node <= 1'b0;
            addr_is_zero <= addr_is_zero_node;
        end
    end
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            h_v_is_zero_node <= 1'b0;
            h_v_is_zero <= 1'b0;
        end else begin
            if (h_count==0 && v_count==0)
                h_v_is_zero_node <= 1'b1;
            else
                h_v_is_zero_node <= 1'b0;
            h_v_is_zero <= h_v_is_zero_node;
        end
    end
            
endmodule

`default_nettype wire


次に、bitmap_afifo.v だが、これは、IPとしてCoreGenで生成したので、ここには載せないことにします。代わりに、Fifo Generator の設定画面を載せておきます。
BitMapDispCont_122_120822.png

BitMapDispCont_123_120822.png

BitMapDispCont_124_120822.png

BitMapDispCont_125_120822.png

BitMapDispCont_126_120822.png

BitMapDispCont_127_120822.png

BitMapDispCont_128_120822.png

dvi_disp.vhd については、”DVI、HDMIの勉強6(キャラクタ・ディスプレイ・コントローラをDVI出力にする VHDL編1)”にVHDLソースコードを貼ってあります。

XPSにpcoreフォルダ関連のファイルやそのやり方については、以下のブログ記事を参考にしてください。
ビットマップ・ディスプレイ・コントローラの作製9(BitMapDCの接続1)
ビットマップ・ディスプレイ・コントローラの作製10(BitMapDCの接続2)
ビットマップ・ディスプレイ・コントローラの作製11(BitMapDCの接続3)
ビットマップ・ディスプレイ・コントローラの作製12(BitMapDCのインプリメント1)

最後にXPSの構成画面を下に貼っておきます。
BitMapDispCont_129_120822.png
  1. 2012年08月22日 04:51 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラの作製18(動作した?)

ビットマップ・ディスプレイ・コントローラの作製17(動き出した)”の続き。タイトルの”動作した?”は、まだ画像が止まって見えるだけで、DDR2 SDRAMの電源ON時のデータを読みだして表示しているだけだからです。こっちの意図した画像を表示しているわけではないという理由で?を付けてあります。

前回は画面が流れていたので、回路がおかしかった。bitmap_disp_engine.v を修正して画面が流れないようになった。(VGAです)
BitMapDispCont_121_120821.jpg

ChipScopeでAXI4バス等の波形を観察してみた。data_valid が1になる間隔を観察してみた。これは、DDR2 SDRAMからデータをReadバーストする間隔だ。
BitMapDispCont_119_120821.png

間隔は514クロックだった。クロック周波数は100MHzなので、周期は10nsec なので、514クロックだと5.14usec となる。

data_valid が1になっている間隔は下の図から64クロックだった。
BitMapDispCont_120_120821.png

64クロックは640nsec となる。
AXI4バス帯域の占有率は 64/512x100≒12.5% となった。
AXI4バス帯域の占有率を計算で出してみて比べてみる。100MHzのAXI4バスでDDR2 SDRAMのデータをReadして、VGAのピクセルクロック25MHzでピクセルデータを読み出している。AXI4バスは64ビット幅で、ピクセルデータは32ビット幅なので、AXI4バスのデータ幅のほうがVGAのピクセルデータよりも2倍のデータを1クロックでReadすることが出来る。以上のことから式を立てると下のようになる。
AXI4バス帯域の占有率は (25/100x100)/2 = 12.5% となる。
よって、実際のAXI4バス帯域の占有率と計算値は、ほぼ等しい。

SVGAではピクセルクロックは40MHzなので、AXI4バス帯域の占有率の計算値は 20%
XGAではピクセルクロックは65MHzなので、AXI4バス帯域の占有率の計算値は 32.5%
SXGAではピクセルクロックは108MHzなので、AXI4バス帯域の占有率の計算値は 54%
HDではピクセルクロックは148.5MHzなので、AXI4バス帯域の占有率の計算値は 74.25% (注:AtlysボードではHDは出力できない)
になる予定だ。HDはバス帯域の占有率から言っても厳しいかもしれないが、Altysボードでは、PLLの最高周波数が対応していないので出力できない。
  1. 2012年08月21日 20:14 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラの作製17(動き出した)

ビットマップ・ディスプレイ・コントローラの作製16(全体シミュレーション)”の続き。

MCBにキャリブレーションが終了せずに(cal_doneが0) だいぶ苦労してしまった。今までの自分でaxi_s6_ddrx IP (DDR2 SDRAM Controller) を入れて作ったXPSプロジェクト入りのPlanAheadプロジェクトを使ってきたが、どうもaxi_s6_ddrx IP が動かない。そこで違うプロジェクトで確かめてみることにした。それは、”AtlysボードでXPSプロジェクトを試す1(XPSのプロジェクト作成、インプリメント)”で作成してあったXPSプロジェクト入りのISEプロジェクトをISE14.2に変換し、ビットマップ・ディスプレイ・コントローラを入れて使用することにした。下にそのプロジェクトを示す。
BitMapDispCont_117_120818.png

これだと初めからaxi_s6_ddrxのキャリブレーションが終了して、MCBが動作した。ピクセルクロックをつなぎ忘れもしたが、それは修正した。ChipScopeで確認すると、ビットマップ・ディスプレイ・コントローラは動作しているようだった。
BitMapDispCont_118_120818.png

ディスプレイに表示してみたが、まだ表示がおかしいようだ。
BitMapDispCont_119_120818.jpg

ちらついている。DDR2のReadデータとビットマップ・ディスプレイ・コントローラの同期がおかしいのかもしれない。
次回は、現在動作したXPSプロジェクトをPlanAhead にインポートして動くかどうか?を調べてみる。なぜ、自分でAdd IPしたaxi_s6_ddrxが動作しないのか?を調べてみようと思う。
  1. 2012年08月18日 04:47 |
  2. AXI4 Master IPの作製
  3. | トラックバック:0
  4. | コメント:0
»