FC2カウンター FPGAの部屋 IP

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

FPGAの部屋

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

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム2(SDK)

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム1(プロジェクト作成)”の続き。

前回は、今まで作ってきた AXI4-Stream版ビットマップ・ディスプレイ・コントローラ IPと AXI4-Stream版カメラ・コントローラ IP、Vivado HLS で作成したAXI4 Master DMA Write IP、Vivado HLS で作成したAXI4 Master DMA Read IP を使って、カメラ表示システムのVivado プロジェクトを作り、ビットストリームの生成まで終了した。今回は、ハードウェアをエクスポートしてSDK を立ち上げてアプリケーションを作り、実機で動作させようと思う。

まずは、Vivado でハードウェアをエクスポートした。

次に、SDK を立ち上げた。
cam_disp_axis_7_160821.png

cam_disp_hls アプリケーション・プロジェクトを作成し、cam_disp_hls.c を新規作成した。
cam_disp_axis_8_160821.png

cam_disp_hls.c を完成させた。
cam_disp_axis_9_160823.png

これで、FPGA をプログラムして、出来上がったアプリケーション・ソフトウェアを起動させてみたが、ディスプレイ画面にカメラ画像は表示されなかった。ブルー・スクリーンだったので、画像出力がされていないようだ。
どこがおかしいのか?検討してみる必要がある。

最後に、cam_disp_hls.c を貼っておく。

/* * cam_disp_hls.c * *  Created on: 2016/08/21 *      Author: Masaaki */


#include <stdio.h>
#include <stdlib.h>
#include "xil_io.h"
#include "xdma_read_addr.h"
#include "xdma_write.h"
#include "sleep.h"

#define NUMBER_OF_WRITE_FRAMES    3 // Note: If not at least 3 or more, the image is not displayed in succession.

#define HORIZONTAL_PIXELS    800
#define VERTICAL_LINES        600
#define PIXEL_NUM_OF_BYTES    4

#define FRAME_BUFFER_ADDRESS 0x10000000

void cam_i2c_init(volatile unsigned *mt9d111_i2c_axi_lites) {
    mt9d111_i2c_axi_lites[64] = 0x2// reset tx fifo ,address is 0x100, i2c_control_reg
    mt9d111_i2c_axi_lites[64] = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(volatile unsigned *mt9d111_i2c_axi_lites, unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    mt9d111_i2c_axi_lites[66] = 0x100 | (device_addr & 0xfe);   // Slave IIC Write Address, address is 0x108, i2c_tx_fifo
    mt9d111_i2c_axi_lites[66] = write_addr;
    mt9d111_i2c_axi_lites[66] = (write_data >> 8)|0xff;         // first data
    mt9d111_i2c_axi_lites[66] = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main(){
    XDma_read_addr  dmar, *dmarp;
    XDma_write      dmaw, *dmawp;

    dmarp = &dmar;
    dmawp = &dmaw;

    // Initialization of DMA Read
    if (XDma_read_addr_Initialize(dmarp, 0) != XST_SUCCESS){
        fprintf(stderr,"DMA Read open error\n");
        exit(-1);
    }

    // Initialization of DMA Write
    if (XDma_write_Initialize(dmawp, 0) != XST_SUCCESS){
        fprintf(stderr,"DMA Write open error\n");
        exit(-1);
    }

    // frame buffer settings
    XDma_read_addr_Set_frame_buffer0(&dmar, FRAME_BUFFER_ADDRESS);
    XDma_read_addr_Set_frame_buffer1(&dmar, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);
    XDma_read_addr_Set_frame_buffer2(&dmar, FRAME_BUFFER_ADDRESS+2*HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);

    XDma_write_Set_frame_buffer0(&dmaw, FRAME_BUFFER_ADDRESS);
    XDma_write_Set_frame_buffer1(&dmaw, FRAME_BUFFER_ADDRESS+HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);
    XDma_write_Set_frame_buffer2(&dmaw, FRAME_BUFFER_ADDRESS+2*HORIZONTAL_PIXELS*VERTICAL_LINES*PIXEL_NUM_OF_BYTES);

    // mt9d111_inf_axis_0, axi_iic_0, bitmap_disp_cont_axis_0
    volatile unsigned int *mt9d111_axiL;
    volatile unsigned int *cam_iic_axiL;
    volatile unsigned int *bmdc_axiL;

    mt9d111_axiL = (volatile unsigned int *)XPAR_MT9D111_INF_AXIS_0_BASEADDR;
    cam_iic_axiL = (volatile unsigned int *)XPAR_AXI_IIC_0_BASEADDR;
    bmdc_axiL = (volatile unsigned int *)XPAR_BITMAP_DISP_CONT_AXIS_0_BASEADDR;

    // DMA Start
    XDma_read_addr_Set_mode_V(&dmar, 0);
    while(!XDma_read_addr_IsIdle(&dmar)) ;
    XDma_read_addr_Start(&dmar);
    XDma_read_addr_EnableAutoRestart(&dmar);

    while(!XDma_write_IsIdle(&dmaw)) ;
    XDma_write_Start(&dmaw);
    XDma_write_EnableAutoRestart(&dmaw);

    // mt9d111_inf_axis_0 and bitmap_disp_cont_axis_0 is started
    mt9d111_axiL[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)
    bmdc_axiL[0] = (volatile unsigned int)FRAME_BUFFER_ADDRESS; // Camera Interface start (Address is dummy)

    // CMOS Camera initialize, MT9D111
    cam_i2c_init(cam_iic_axiL);

    cam_i2c_write(cam_iic_axiL, 0xba, 0xf00x1);      // Changed regster map to IFP page 1
    cam_i2c_write(cam_iic_axiL, 0xba, 0x970x20);     // RGB Mode, RGB565

    mt9d111_axiL[1] = 0// One_shot_mode is disabled

    return(0);
}

  1. 2016年08月24日 03:59 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS で生成した AXI4 Master DMA IP を使用したカメラ画像表示システム1(プロジェクト作成)

今まで作ってきた AXI4-Stream版ビットマップ・ディスプレイ・コントローラ IP AXI4-Stream版カメラ・コントローラ IPVivado HLS で作成したAXI4 Master DMA Write IPVivado HLS で作成したAXI4 Master DMA Read IP を使って、カメラ表示システムを作ってみることにした。

Vivado 2016.2 で cam_disp_axis_162 プロジェクトを作成した。(下図ではビットストリームの生成まで終了した状態だ。)
cam_disp_axis_3_160821.png

AXI4-Stream版ビットマップ・ディスプレイ・コントローラ IP AXI4-Stream版カメラ・コントローラ IPVivado HLS で作成したAXI4 Master DMA Write IPVivado HLS で作成したAXI4 Master DMA Read IP をフォルダを作って cam_disp_axis_162 プロジェクトのフォルダに入れた。
cam_disp_axis_1_160821.png

4つのIP をIP Catalog に追加した。
cam_disp_axis_2_160821.png

cam_disp_axis ブロックデザインを作成した。
cam_disp_axis_4_160821.png

Address Editor を示す。
cam_disp_axis_5_160821.png

制約ファイル cam_disp_axis.xdc を作成した。

set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[0]}]
set_property PACKAGE_PIN J18 [get_ports {vga_blue[3]}]
set_property PACKAGE_PIN K19 [get_ports {vga_blue[2]}]
set_property PACKAGE_PIN M20 [get_ports {vga_blue[1]}]
set_property PACKAGE_PIN P20 [get_ports {vga_blue[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports {vga_blue[4]}]
set_property PACKAGE_PIN G19 [get_ports {vga_blue[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_green[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_red[0]}]
set_property PACKAGE_PIN F20 [get_ports {vga_green[5]}]
set_property PACKAGE_PIN H20 [get_ports {vga_green[4]}]
set_property PACKAGE_PIN J19 [get_ports {vga_green[3]}]
set_property PACKAGE_PIN L19 [get_ports {vga_green[2]}]
set_property PACKAGE_PIN N20 [get_ports {vga_green[1]}]
set_property PACKAGE_PIN H18 [get_ports {vga_green[0]}]
set_property PACKAGE_PIN F19 [get_ports {vga_red[4]}]
set_property PACKAGE_PIN G20 [get_ports {vga_red[3]}]
set_property PACKAGE_PIN J20 [get_ports {vga_red[2]}]
set_property PACKAGE_PIN L20 [get_ports {vga_red[1]}]
set_property PACKAGE_PIN M19 [get_ports {vga_red[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports vga_hsync]
set_property IOSTANDARD LVCMOS33 [get_ports vga_vsync]
set_property PACKAGE_PIN P19 [get_ports vga_hsync]
set_property PACKAGE_PIN R19 [get_ports vga_vsync]

set_property PACKAGE_PIN T14 [get_ports {cam_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {cam_data[0]}]
set_property PACKAGE_PIN U14 [get_ports {cam_data[6]}]
set_property PACKAGE_PIN T15 [get_ports {cam_data[5]}]
set_property PACKAGE_PIN U15 [get_ports {cam_data[4]}]
set_property PACKAGE_PIN P14 [get_ports {cam_data[3]}]
set_property PACKAGE_PIN V17 [get_ports {cam_data[2]}]
set_property PACKAGE_PIN R14 [get_ports {cam_data[1]}]
set_property PACKAGE_PIN V18 [get_ports {cam_data[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports mt9d111_iic_scl_io]
set_property IOSTANDARD LVCMOS33 [get_ports mt9d111_iic_sda_io]
set_property IOSTANDARD LVCMOS33 [get_ports href]
set_property IOSTANDARD LVCMOS33 [get_ports pclk]
set_property IOSTANDARD LVCMOS33 [get_ports standby]
set_property IOSTANDARD LVCMOS33 [get_ports vsync]
set_property IOSTANDARD LVCMOS33 [get_ports xck]
set_property PACKAGE_PIN V15 [get_ports mt9d111_iic_scl_io]
set_property PACKAGE_PIN W14 [get_ports mt9d111_iic_sda_io]
set_property PACKAGE_PIN W15 [get_ports vsync]
set_property PACKAGE_PIN Y14 [get_ports href]
set_property PACKAGE_PIN T11 [get_ports standby]
set_property PACKAGE_PIN T10 [get_ports pclk]
set_property PACKAGE_PIN U12 [get_ports xck]
set_property IOSTANDARD LVCMOS33 [get_ports {hdmi_out_en[0]}]
set_property PACKAGE_PIN F17 [get_ports {hdmi_out_en[0]}]

set_property CLOCK_DEDICATED_ROUTE FALSE [get_nets pclk_IBUF]


論理合成、インプリメント、ビットストリームの生成を行って、成功した。
cam_disp_axis_6_160821.png
  1. 2016年08月22日 22:17 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする5(IP作成)

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする4(ソースコードの公開)”の続き。

前回は、シミュレーションを行ってから、Verilog HDLのソースコードを公開した。今回は出来上がりAXI4-Stream版ビットマップ・ディスプレイ・コントローラをIPにする。

Vivado 2016.2 のTools メニューから Create and Package IP... を選択する。

Create and Package New IP ダイアログが表示された。
AXI4-Stream_bitmap_disp_cont_17_160818.png

Package your current project のラジオボタンが設定されていることを確認して、Next > ボタンをクリックした。
AXI4-Stream_bitmap_disp_cont_18_160818.png

ここもデフォルトのまま
AXI4-Stream_bitmap_disp_cont_19_160818.png

Summary
AXI4-Stream_bitmap_disp_cont_20_160818.png

Package IP タブが表示された。Vender を marsee101 に変更した。(Identification)
AXI4-Stream_bitmap_disp_cont_21_160818.png

Compatibility
AXI4-Stream_bitmap_disp_cont_22_160818.png

File Groups
AXI4-Stream_bitmap_disp_cont_23_160818.png

Customization Parameters。C_DISPLAY_START_ADDRESS は要らなかった。削除を忘れたので、このままとする。
AXI4-Stream_bitmap_disp_cont_24_160818.png

Ports and Interfaces 。 vid... 信号をRGB インターフェースにまとめる必要がある。
AXI4-Stream_bitmap_disp_cont_25_160818.png

vid... 信号をすべて選択して、右クリックメニューから Add Bus Interface... を選択した。
AXI4-Stream_bitmap_disp_cont_26_160818.png

RGB インターフェース設定方法については、”ZYBO_0 を変更1(ブロックデザインの修正)”を参照のこと。

RGB インターフェースを設定することができた。
AXI4-Stream_bitmap_disp_cont_27_160818.png

Addressing and Memory
AXI4-Stream_bitmap_disp_cont_28_160818.png

Customization GUI
AXI4-Stream_bitmap_disp_cont_29_160818.png

Review and Package で Package IP ボタンをクリックしてIP を生成した。
AXI4-Stream_bitmap_disp_cont_30_160818.png

IP 生成が成功したというダイアログが表示された。
AXI4-Stream_bitmap_disp_cont_31_160818.png

久しぶりにIP を生成したので、やり方を忘れているのだが、IP をまとめたZIP ファイルができていない。
IP をまとめたZIP ファイルを生成する。
Package IP タブのReview and Package で edit packaging settings をクリックした。
AXI4-Stream_bitmap_disp_cont_32_160818.png

Project Settings ダイアログで、IP のPackager のAutomatic Behavior -> After Packaging のCreate archive of IPにチェックを入れた。
AXI4-Stream_bitmap_disp_cont_33_160818.png

もう一度、Re-Package IP ボタンをクリックして、再度IP を作成した。
AXI4-Stream_bitmap_disp_cont_34_160818.png

もう一度、IP 生成が成功したというダイアログが表示された。

bm_dispc_axis フォルダの下にmarsee101_user_bitmap_disp_cont_axis_1.0.zip が生成された。
AXI4-Stream_bitmap_disp_cont_35_160818.png
  1. 2016年08月18日 06:34 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする4(ソースコードの公開)

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする3(シミュレーション)”の続き。

前回は、シミュレーションを行って、テストベンチのVerilog HDLのソースコードを貼った。今回は、それ以外のVerilog HDLのソースコードを貼っておく。

最初に、bitmap_disp_cont_axis.v から貼っておく。

// bitmap_disp_cont_axis.v
//
// by marsee
//
// Read Only IP, 64 bit bus
//
// 2012/06/28
// 2012/11/22 : HDMI出力を追加
// 2014/07/23 : ZYBO 用に変更
// 2014/09/18 : Frame Buffer のスタートアドレスを設定するためにAXI4 Lite Slave インターフェースを追加
// 2016/08/08 : AXI4 Master から AXI4-Stream インターフェースに変更、AXI4 Lite Slave インターフェースはダミーライトに変更
//                ダミーライトするとディスプレイ・コントローラがスタートする
//

`default_nettype none

module bitmap_disp_cont_axis #
  (
        // AXI4 Lite Slave Interface
        parameter integer C_S_AXI_LITE_ADDR_WIDTH        = 9,
        parameter integer C_S_AXI_LITE_DATA_WIDTH        = 32,

        // AXI4-Stream Interface
        parameter integer C_M_AXIS_DATA_WIDTH            = 32,

        parameter [31:0]    C_DISPLAY_START_ADDRESS        = 32'h17800000,    // フレームバッファのスタートアドレス

        // video resolution : "VGA", "SVGA", "XGA", "SXGA", "HD"
        parameter [80*8:1] RESOLUTION                    ="SVGA"  // SVGA
    )
    (
        // Clocks and Reset
        input wire          s_axi_lite_aclk,
        input wire           AXIS_ACLK,
        input wire           ARESETN,

        ///////////////////////////////
        // AXI4 Lite Slave Interface //
        ///////////////////////////////
        // 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    wire    [C_S_AXI_LITE_DATA_WIDTH-1:0] s_axi_lite_rdata,
        output    wire    [1:0]    s_axi_lite_rresp,

        /////////////////////////////////
        // AXI4-Stream Slave Interface //
        /////////////////////////////////
        input  wire [C_M_AXIS_DATA_WIDTH-1:0]        s_axis_tdata,
        input  wire [(C_M_AXIS_DATA_WIDTH/8)-1:0]   s_axis_tstrb,
        input  wire                                     s_axis_tvalid,
        output wire                                   s_axis_tready,
        input  wire                                   s_axis_tlast,
        input  wire                                    s_axis_tuser,

        // User Ports
        input    wire    pixclk,

        (* IOB = "FORCE" *) output    reg     [4:0]    vga_red,
        (* IOB = "FORCE" *) output    reg     [5:0]    vga_green,
        (* IOB = "FORCE" *) output    reg     [4:0]    vga_blue,
        (* IOB = "FORCE" *) output    reg        vga_hsync,
        (* IOB = "FORCE" *) output    reg        vga_vsync,

        output  wire [23:0] vid_pData,
        output  wire        vid_pVDE,
        output  wire        vid_pHSync,
        output  wire        vid_pVSync
    );

     wire    [7:0]    red, green, blue;
    wire    hsyncx, vsyncx;
    wire    display_enable;
    reg        reset_disp_2b = 1'b1, reset_disp_1b = 1'b1;
    wire    reset_disp;
    wire    afifo_overflow, afifo_underflow;
    wire    reset_out;
    wire    init_done;

    bm_disp_cntrler_axi_lite_slave #(
        .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(C_DISPLAY_START_ADDRESS)
    ) bm_disp_cntrler_axi_lite_slave_i
    (
        .s_axi_lite_aclk(s_axi_lite_aclk),
        .axi_resetn(ARESETN),
        .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(),
        .init_done(init_done)
    );

    bitmap_disp_engine #(
        .RESOLUTION(RESOLUTION)
    ) bitmap_disp_eng_inst (
        .clk_disp(pixclk),
        .clk_axi(AXIS_ACLK),
        .reset_disp(reset_disp),
        .reset_axi(~ARESETN),
        .s_axis_tdata(s_axis_tdata),
        .s_axis_tstrb(s_axis_tstrb),
        .s_axis_tvalid(s_axis_tvalid),
        .s_axis_tready(s_axis_tready),
        .s_axis_tlast(s_axis_tlast),
        .s_axis_tuser(s_axis_tuser),
        .red_out(red),
        .green_out(green),
        .blue_out(blue),
        .hsyncx(hsyncx),
        .vsyncx(vsyncx),
        .display_enable(display_enable),
        .ddr_cont_init_done(init_done),
        .afifo_overflow(afifo_overflow),
        .afifo_underflow(afifo_underflow)
    );

    always @(posedge pixclk) begin
        if (reset_disp) begin
            vga_red <= 5'd0;
            vga_green <= 6'd0;
            vga_blue <= 5'd0;
            vga_hsync <= 1'b1;
            vga_vsync <= 1'b1;
        end else begin
            vga_red <= red[7:3];
            vga_green <= green[7:2];
            vga_blue <= blue[7:3];
            vga_hsync <= hsyncx;
            vga_vsync <= vsyncx;
        end
    end

    always @(posedge pixclk) begin
        reset_disp_2b <= ~ARESETN;
        reset_disp_1b <= reset_disp_2b;
    end
    assign reset_disp = reset_disp_1b;

    assign vid_pData = {red, blue, green};
    assign vid_pVDE = display_enable;
    assign vid_pHSync = hsyncx;
    assign vid_pVSync = vsyncx;

endmodule

`default_nettype wire


次に、bitmap_disp_engine.v を示す。

// BitMap Display Controller
// bitmap_disp_engine.v
// AXI4バス用 by marsee
//
// 2014/07/26 : video_timing_param.vh を使用
// 2014/09/18 : フレームバッファのスタートアドレス入力を追加
// 2016/03/04 : display_enable の出力期間のバグをフィックスした
// 2016/08/08 : AXI4 Master から AXI4-Stream インターフェースに変更
//

`default_nettype none

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

module bitmap_disp_engine #(
        // AXI4-Stream Interface
        parameter integer C_M_AXIS_DATA_WIDTH            = 32,
        // video resolution : "VGA", "SVGA", "XGA", "SXGA", "HD"
        parameter [80*8:1] RESOLUTION                    ="SVGA"  // SVGA
) (
    input    wire    clk_disp,            // ディスプレイ表示用クロック
    input    wire    clk_axi,            // AXI4バスクロック
    input    wire    reset_disp,            // clk_disp 用リセット
    input    wire    reset_axi,            // clk_axi 用リセット

    input    wire [C_M_AXIS_DATA_WIDTH-1:0]        s_axis_tdata,
    input    wire [(C_M_AXIS_DATA_WIDTH/8)-1:0]    s_axis_tstrb,
    input    wire                                s_axis_tvalid,
    output    wire                                   s_axis_tready,
    input     wire                                   s_axis_tlast,
    input    wire                                s_axis_tuser,

    output    reg        [7:0]    red_out,
    output    reg        [7:0]    green_out,
    output    reg      [7:0]    blue_out,
    (*S="TRUE"*) output    reg     hsyncx,
    (*S="TRUE"*) output    reg     vsyncx,
    output    wire    display_enable,
    input    wire    ddr_cont_init_done,    // DDR2 SDRAMコントローラの初期化終了
    output    wire    afifo_overflow, // 非同期FIFO のオーバーフロー・エラー
    output    wire    afifo_underflow    // 非同期FIFO のアンダーフロー・エラー
);
    `include "./video_timing_param.vh"

    parameter [2:0]    idle_rdg=            3'b001,
                    wait_half_full=        3'b010,
                    display_mode=        3'b100;
    reg    [2:0] cs_rdg;

    reg afifo_rd_en;
    wire afifo_wr_en;
    wire [31:0] afifo_dout;
    wire afifo_full;
    wire afifo_empty;
    wire [9:0] wr_data_count;
    reg [15:0] h_count;
    reg [15:0] v_count;
    reg [7:0] red_node, green_node, blue_node;
    reg hsyncx_node, vsyncx_node;
    reg vsync_axi, vsync_axi_b1;
    reg vsync_axi_1d;
    reg vsyncx_rise_pulse;
    reg de, de_b1, de_b2;
    wire disp_mode_ena;
    reg disp_mode_ena_d0, disp_mode_ena_d1;
    reg init_done_d0 = 1'b0;
    reg init_done_d1 = 1'b0;

    // synthesis translate_off
    // wire [`OVL_FIRE_WIDTH-1:0] fire_overflow, fire_underflow;
    // synthesis translate_on

    // RGB保存用非同期FIFO, FWFT Wirte側64ビット幅512深度、Read側32ビット512深度とする
    bitmap_afifo bitmap_afifo_inst (
        .wr_rst(reset_axi),
        .wr_clk(clk_axi),
        .rd_clk(clk_disp),
        .rd_rst(reset_disp),
        //.din(data_in), // Bus [63 : 0]
        .din(s_axis_tdata), // Bus [31 : 0]
        .wr_en(afifo_wr_en),
        .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)  // [9 : 0] wr_data_count
    );
    assign afifo_wr_en = s_axis_tvalid & ~afifo_full;
    // afifo_wr_en が 1 になるときは、tuserが1の時か、cs_rdgがidle_rdgでなく、tvalidが1で、FIFOがFULLでない時
    assign s_axis_tready = ~afifo_full; 

    // ddr_cont_init_done を clk_axi で同期化する
    always @(posedge clk_axi) begin
        init_done_d0 <= ddr_cont_init_done;
        init_done_d1 <= init_done_d0;
    end

    // Readデータ処理モジュール用ステートマシン
    always @(posedge clk_axi) begin
        if (reset_axi | ~init_done_d1)
            cs_rdg <= idle_rdg;
        else begin
            case (cs_rdg)
                idle_rdg :
                    if (s_axis_tuser & afifo_wr_en)
                        cs_rdg <= wait_half_full;
                wait_half_full : // 最初にFIFO が half_full になるのを待ってスタートする
                    if (wr_data_count[8])
                        cs_rdg <= display_mode;
                display_mode : // 画面表示モード
                    ;
            endcase
        end
    end
    assign disp_mode_ena = (cs_rdg==display_mode) ? 1'b1 : 1'b0;

    // ビットマップVGAコントローラのclk_disp 動作部

    // h_count、v_count用にclk_axi 動作のcs_rdg の値を使用するので2回clk_disp 動作のFFでラッチする
    always @(posedge clk_disp) begin
        if (reset_disp) begin
            disp_mode_ena_d0 <= 0;
        end else begin
            disp_mode_ena_d0 <= disp_mode_ena;
            disp_mode_ena_d1 <= disp_mode_ena_d0;
        end
    end

    // h_countの実装(水平カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp==1'b1 || disp_mode_ena_d1==1'b0)
            h_count <= 0;
        else if (h_count>=(H_SUM-1)) // h_count がH_SUM-1よりも大きければ0に戻す(mod H_SUM)
            h_count <= 0;
        else
            h_count <= h_count + 1;
    end

    // v_countの実装(垂直カウンタ)
    always @(posedge clk_disp) begin
        if (reset_disp==1'b1 || disp_mode_ena_d1==1'b0)
            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
                v_count <= v_count + 1;
        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 (disp_mode_ena_d1==1'b0) 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 | ~disp_mode_ena_d1)
            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 | ~disp_mode_ena_d1)
            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 | ~disp_mode_ena_d1)
            de <= 1'b0;
        else begin
            if (h_count<H_ACTIVE_VIDEO && v_count<V_ACTIVE_VIDEO)
                de <= 1'b1;
            else
                de <= 1'b0;
        end
    end
    always @(posedge clk_disp) begin
        if(reset_disp | ~disp_mode_ena_d1) begin
            de_b1 <= 1'b0;
            de_b2 <= 1'b0;
        end else begin
            de_b1 <= de;
            de_b2 <= de_b1;
        end
    end
    assign display_enable = de_b2;

    // afifo_rd_en の処理
    always @(posedge clk_disp) begin
        if (reset_disp)
            afifo_rd_en <= 1'b0;
        else begin
            if (~disp_mode_ena_d1) // 初期化中
                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
endmodule

`default_nettype wire



最後に、bm_disp_cntrler_axi_lite_slave.v を示す。

// bm_disp_cntrler_axi_lite_slave.v
// bitmap_disp_cntrler_axi_master のAXI Lite Slave モジュール。Frame Buffer のスタートアドレス・レジスタを持つ。
//
// Addr 0x0 - frame buffer start address
//

`default_nettype none

module bm_disp_cntrler_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
)(
    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    wire    [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            // PS部の初期化終了
);

    // RESP の値の定義
    parameter    RESP_OKAY =        2'b00;
    parameter    RESP_EXOKAY =    2'b01;
    parameter    RESP_SLVERR =     2'b10;
    parameter    RESP_DECERR =    2'b11;

    parameter    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;

    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)
            fb_start_addr_reg <= C_DISPLAY_START_ADDRESS;
        else
            if (s_axi_lite_wvalid)
                fb_start_addr_reg <= s_axi_lite_wdata;
    end
    assign fb_start_address = fb_start_addr_reg;
    assign s_axi_lite_rdata = fb_start_addr_reg;

    // generated init_done
    always @(posedge aclk) begin
        if(reset) begin
            init_done <= 1'b0;
        end else if(wrt_cs==BREADY_ASSERT) begin
            init_done <= 1'b1;
        end
    end
endmodule

`default_nettype wire

  1. 2016年08月17日 05:14 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする3(シミュレーション)

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする2(bitmap_afifo)”の続き。

前回は、bitmap_afifo を生成した。今回は、”Vivado HLS でAXI4-Stream Master Model IP を作る”で作った AXI4-Stream Master Model IP を使って、AXI4-Stream版ビットマップ・ディスプレイ・コントローラをシミュレーションしてみた。なお、AXI4-Stream版ビットマップ・ディスプレイ・コントローラは、Verilog HDL で実装できている。

下図にシミュレーション画面を示す。なおここには、波形ウインドウは表示されていない。
AXI4-Stream_bitmap_disp_cont_13_160816.png

出力される画像データをアサーションでテストしている。アサーション・エラーが出ていないので、問題ないようだ。最初は、アサーション・エラーが出ていたので、HDL を修正した。

40 us シミュレーションした時の波形ウインドウを示す。
AXI4-Stream_bitmap_disp_cont_14_160816.png

画像データの出力開始部分を示す。
AXI4-Stream_bitmap_disp_cont_15_160816.png

17 ms シミュレーションを行った。
AXI4-Stream_bitmap_disp_cont_16_160818.png 

テストベンチの bitmap_disp_cont_axis_tb.v を貼っておく。

`default_nettype none

`timescale 100ps / 1ps

// bitmap_disp_cont_axis_tb.v
// 2012/07/03
// 2014/09/19 : for ZYBO
// 2016/08/14 : for AXI4-Stream

module bitmap_disp_cntrler_axi_master_tb;
    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 integer C_M_AXIS_DATA_WIDTH= 32; // AXI4-Stream Interface

    parameter DELAY = 1;

    wire ACLK;
    wire ARESETN;

    wire [C_M_AXIS_DATA_WIDTH-1:0]        s_axis_tdata;
    wire [(C_M_AXIS_DATA_WIDTH/8)-1:0]    s_axis_tstrb;
    wire                                s_axis_tvalid;
    wire                                   s_axis_tready;
    wire                                   s_axis_tlast;
    wire                                s_axis_tuser;
    reg        ap_start;
    wire    ap_done;
    wire    ap_idle;
    wire    ap_ready;

    wire pixclk;
    wire [4:0]    vga_red;
    wire [5:0]    vga_green;
    wire [4:0]    vga_blue;
    wire    vga_hsync;
    wire    vga_vsync;

    wire [23:0] vid_pData;
    wire    vid_pVDE;
    wire    vid_pHSync;
    wire    vid_pVSync;

    reg    [7:0]    red;
    reg    [7:0]    blue;
    reg    [7:0]    green;
    wire [32:0]    rbg_data;

    // AXI Lite Write Address Channel
    reg                                        s_axi_lite_awvalid = 1'b0;
    wire                                    s_axi_lite_awready;
    reg        [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_awaddr = 0;
    //reg        [3-1:0]                            s_axi_lite_awport = 1'b0;

    // AXI Lite Write Data Channel
    reg                                        s_axi_lite_wvalid =1'b0;
    wire                                    s_axi_lite_wready;
    reg        [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_wdata = 0;

    // AXI Lite Write Response Channel
    wire    [1:0]                            s_axi_lite_bresp;
    wire                                    s_axi_lite_bvalid;
    reg                                        s_axi_lite_bready = 1'b0;

    // AXI Lite Read Address Channel
    reg                                        s_axi_lite_arvalid = 1'b0;
    wire                                    s_axi_lite_arready;
    reg        [C_S_AXI_LITE_ADDR_WIDTH-1: 0]    s_axi_lite_araddr = 1'b0;
    //reg        [3-1:0]                            s_axi_lite_arport = 0;

    // AXI Lite Read Data Channel
    wire                                    s_axi_lite_rvalid;
    reg                                        s_axi_lite_rready = 1'b0;
    wire    [C_S_AXI_LITE_DATA_WIDTH-1: 0]    s_axi_lite_rdata;
    wire    [1:0]                            s_axi_lite_rresp;

    integer i;

    // Instantiate the Unit Under Test (uut_bdc_axis)
    bitmap_disp_cont_axis #(
        .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_M_AXIS_DATA_WIDTH(C_M_AXIS_DATA_WIDTH),
        .RESOLUTION("SVGA")
    ) uut_bdc_axis (
        .s_axi_lite_aclk(ACLK),
        .AXIS_ACLK(ACLK),
        .ARESETN(ARESETN),

        .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),

        .s_axis_tdata(s_axis_tdata),
        .s_axis_tstrb(s_axis_tstrb),
        .s_axis_tvalid(s_axis_tvalid),
        .s_axis_tready(s_axis_tready),
        .s_axis_tlast(s_axis_tlast),
        .s_axis_tuser(s_axis_tuser),

        .pixclk(pixclk),
        .vga_red(vga_red),
        .vga_green(vga_green),
        .vga_blue(vga_blue),
        .vga_hsync(vga_hsync),
        .vga_vsync(vga_vsync),
        .vid_pData(vid_pData),
        .vid_pVDE(vid_pVDE),
        .vid_pHSync(vid_pHSync),
        .vid_pVSync(vid_pVSync)
    );
    //defparam uut_master.bitmap_disp_eng_inst.INIT_COUNT_VAL = 20; // 初期化時のWaitタイマー

    // clk_gen のインスタンス(ACLK)
    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 のインスタンス(pixclk)
    clk_gen #(
        //.CLK_PERIOD(154),    // 15.4 nsec, 64.9 MHz
        .CLK_PERIOD(250),    // 25 nsec, 40 MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) pixclk_i (
        .clk_out(pixclk)
    );

    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESET_ARESETN (
        .reset_out(ARESETN),
        .init_done()
    );

    // Instantiate the AXI4-Stream Master Model (uut_axi4sm)
    axi4_stream_master uut_axi4sm (
        .ap_clk(ACLK),
        .ap_rst_n(ARESETN),

        .ap_start(ap_start),
        .ap_done(ap_done),
        .ap_idle(ap_idle),
        .ap_ready(ap_ready),
        .outs_TDATA(s_axis_tdata),
        .outs_TVALID(s_axis_tvalid),
        .outs_TREADY(s_axis_tready),
        .outs_TKEEP(),
        .outs_TSTRB(s_axis_tstrb),
        .outs_TUSER(s_axis_tuser),
        .outs_TLAST(s_axis_tlast),
        .outs_TID(),
        .outs_TDEST()
    );

    initial begin
        // Initialize Inputs
        ap_start = 1'b0;
        s_axi_lite_awaddr = 0;
        //s_axi_lite_awport = 0;
        s_axi_lite_wvalid = 0;
        s_axi_lite_wdata = 0;
        s_axi_lite_wvalid = 0;
        s_axi_lite_bready = 0;
        s_axi_lite_araddr = 0;
        //s_axi_lite_arport = 0;
        s_axi_lite_arvalid = 0;
        s_axi_lite_rready = 0;

        // Wait Reset rising edge
        @(posedge ARESETN);

        #10000;    // 1us wait

        for (i=0; i<10; i=i+1) begin
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
        end

        // Add stimulus here
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC1(32'h0000_0100, 32'h55AA_55AA);
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_RADC1(32'h0000_0100);
        #DELAY;

        ap_start = 1'b1;

        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_WADC2(32'h0000_0100, 32'h17800000);
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        AXI_MASTER_RADC2(32'h0000_0600);
    end

    // Write Transcation 1
    task AXI_MASTER_WADC1;
        input    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    awaddr;
        input    [C_S_AXI_LITE_DATA_WIDTH-1:0]    wdata;
        begin
            s_axi_lite_awaddr    = awaddr;
            s_axi_lite_awvalid    = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_awvalid = 1'b0;
            s_axi_lite_wdata = wdata;
            s_axi_lite_wvalid = 1'b1;
            @(posedge ACLK);    // 次のクロックへ, s_axi_lite_wready は常に 1

            #DELAY;
            s_axi_lite_wvalid = 1'b0;
            s_axi_lite_bready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_bready = 1'b0;
        end
    endtask

    // Write Transcation 2
    task AXI_MASTER_WADC2;
        input    [C_S_AXI_LITE_ADDR_WIDTH-1:0]    awaddr;
        input    [C_S_AXI_LITE_DATA_WIDTH-1:0]    wdata;
        begin
            s_axi_lite_awaddr    = awaddr;
            s_axi_lite_awvalid    = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_awvalid = 1'b0;
            s_axi_lite_wdata = wdata;
            s_axi_lite_wvalid = 1'b1;
            @(posedge ACLK);    // 次のクロックへ, s_axi_lite_wready は常に 1

            #DELAY;
            s_axi_lite_wvalid = 1'b0;
            @(posedge ACLK);    // 次のクロックへ

            #DELAY;
            s_axi_lite_bready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_bready = 1'b0;
        end
    endtask

    // Read Transcation 1
    task AXI_MASTER_RADC1;
        input    [31:0]    araddr;
        begin
            s_axi_lite_araddr    = araddr;
            s_axi_lite_arvalid     = 1'b1;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_araddr    = 0;
            s_axi_lite_arvalid     = 1'b0;
            s_axi_lite_rready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_rready = 1'b0;
        end
    endtask

    // Read Transcation 2
    task AXI_MASTER_RADC2;
        input    [31:0]    araddr;
        begin
            s_axi_lite_araddr    = araddr;
            s_axi_lite_arvalid     = 1'b1;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_araddr    = 0;
            s_axi_lite_arvalid     = 1'b0;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_rready = 1'b1;

            @(posedge ACLK);    // 次のクロックへ
            #DELAY;

            s_axi_lite_rready = 1'b0;
        end
    endtask

    // assertion
    always @(posedge pixclk or negedge ARESETN) begin
        if (~ARESETN) begin
            red <= 8'd0;
        end else if (vid_pVDE) begin
            red <= red + 8'd1;
        end
    end
    always @(posedge pixclk or negedge ARESETN) begin
        if (~ARESETN) begin
            green <= 8'd0;
        end else if (vid_pVDE) begin
            green <= green + 8'd2;
        end
    end
    always @(posedge pixclk or negedge ARESETN) begin
        if (~ARESETN) begin
            blue <= 8'd0;
        end else if (vid_pVDE) begin
            blue <= blue + 8'd3;
        end
    end
    assign rbg_data = {8'd0, red, blue, green};

    always @(posedge pixclk or negedge ARESETN) begin
        if (~ARESETN) begin
            ;
        end else if (vid_pVDE==1'b1 && {8'd0, vid_pData} != rbg_data) begin
            $display("%t Data Error : rbg_data = %h, vid_pData = %h", $realtime, rbg_data, vid_pData);
        end
    end
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,
    output    reg        init_done
);
    begin
        initial begin
            reset_out = RESET_STATE;
            init_done = 1'b0;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
            init_done = 1'b1;
        end
    end

endmodule

`default_nettype wire

  1. 2016年08月17日 04:13 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS でAXI4-Stream Master Model IP を作る

久しぶり Verilog HDL を使って、AXI4-Stream版ビットマップ・ディスプレイ・コントローラを作っている。ビットマップ・ディスプレイ・コントローラはAXI4-Stream Slave なので、シミュレーションするには AXI4-Stream Master が必要となる。始めは、HDL で AXI4-Stream Master IP を作ろうとしたのだが、考えてみれば、Vivado HLS で、C++ で AXI4-Stream Master IP を作ってもよいのじゃないか?ということで、Vivado HLS 2016.2 を使用して作ってみた。

Vivado HLS 2016.2 の axi4-stream_master プロジェクトを示す。
AXI4-Stream_bitmap_disp_cont_8_160815.png

最初に axi4_stream_master.h を示す。

// axi4_stream_master.h
// 2016/08/15 by marsee
//

#ifndef __AXI4_STREAM_MASTER_H__
#define __AXI4_STREAM_MASTER_H__

#define HORIZONTAL_PIXELS 800
#define VERTICAL_LINES 600

#endif


ソースファイルの axi4_stream_master.cpp を示す。

// axi4_stream_master.cpp
// 2016/08/15 by marsee
//
// AXI4-Stream Master Model
//

#include <ap_int.h>
#include <hls_stream.h>
#include <ap_axi_sdata.h>

#include "axi4_stream_master.h"

void axi4_stream_master(hls::stream<ap_axis<32,1,1,1> >& outs){
#pragma HLS INTERFACE axis port=outs
#pragma HLS INTERFACE ap_ctrl_hs port=return
    ap_uint<8> red = 0;
    ap_uint<8> blue = 0;
    ap_uint<8> green = 0;
    ap_axis<32,1,1,1> pix;

    for (int y=0; y<VERTICAL_LINES; y++){
        for (int x=0; x<HORIZONTAL_PIXELS; x++){
#pragma HLS PIPELINE II=1
            pix.data = red*65536 + green*256 + blue;
            red++;
            green += 2;
            blue += 3;
            if (x==0 && y==0) // 最初のデータでは、TUSERをアサートする
                pix.user = 1;
            else
                pix.user = 0;

            if (x==(HORIZONTAL_PIXELS-1)) // 行の最後で TLAST をアサートする
                pix.last = 1;
            else
                pix.last = 0;

            outs << pix;
        }
    }
}


テストベンチの axi4_stream_master.tb.cpp を示す。

// axi4_stream_master.tb.cpp
// 2016/08/15 by marsee
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ap_int.h>
#include <hls_stream.h>
#include <iostream>
#include <fstream>
#include <ap_axi_sdata.h>

#include "axi4_stream_master.h"

void axi4_stream_master(hls::stream<ap_axis<32,1,1,1> >& outs);

int main(){
    using namespace std;

    hls::stream<ap_axis<32,1,1,1> > outs;
    ap_axis<32,1,1,1> pix;
    ap_uint<8> red = 0;
    ap_uint<8> blue = 0;
    ap_uint<8> green = 0;
    ap_int<32> pix_data;

    axi4_stream_master(outs);

    for (int y=0; y<VERTICAL_LINES; y++){
        for (int x=0; x<HORIZONTAL_PIXELS; x++){
            outs >> pix;
            pix_data = red*65536 + green*256 + blue;
            //printf("red=%x, green=%x, blue=%x, pix_data=%x\n", (int)red, (int)green, (int)blue, (int)pix_data);
            if (pix.data != pix_data){
                printf("ERROR HW and SW results mismatch x = %d, y = %d, HW = %x, SW = %x\n", x, y, (int)pix.data, (int)pix_data);
                return(1);
            }
            red++;
            green += 2;
            blue += 3;
        }
    }
    cout << "Success HW and SW results match" << endl;
    cout << endl;

    return(0);
}


合成はしないけれども、C コードの合成結果を示す。
AXI4-Stream_bitmap_disp_cont_9_160815.png

C/RTL 協調シミュレーション波形を示す。
AXI4-Stream_bitmap_disp_cont_10_160815.png

outs_TVALID と outs_TREADY がずっと1のままなので、大丈夫そうだ。

AXI4-Stream_bitmap_disp_cont_11_160815.png

最初のデータで outs_TUSER が 1 になっているのがわかる。

AXI4-Stream_bitmap_disp_cont_12_160815.png

さいしょのデータが始まってから、outs_TLAST が 1 にアサートされて、0 になるまでの間は 8 us だった。これは、10 ns のクロックが 800 個分なので、合っている。

最後にIP 化は行ったが、HDLを直接使用すると思う。
  1. 2016年08月16日 03:47 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする2(bitmap_afifo)

ビットマップ・ディスプレイ・コントローラをAXI4-Stream対応にする1(構想編)”の続き。

前回は構想編だったので、今回は、Vivado 2016.2 のプロジェクトを作って、bitmap_afifo (ビットマップのピクセル用の非同期FIFO)を作った。

最初に、Vivado 2016.2 で作成した bm_dispc_axis プロジェクトを示す。
AXI4-Stream_bitmap_disp_cont_2_160811.png

bitmap_afifo のパラメータを示す。
Basic タブでは、Independent Clocks の Block RAM を選択した。
AXI4-Stream_bitmap_disp_cont_3_160811.png

Native Pors タブでは、Read Mode で First Word Fall Through を選択し、Write Depth は512 を選択した。
AXI4-Stream_bitmap_disp_cont_4_160811.png

Status Flags タブでは、Overflow と Underflow フラグを追加した。
AXI4-Stream_bitmap_disp_cont_5_160811.png

Data Counts タブでは、Read Date Count をイネーブルした。
AXI4-Stream_bitmap_disp_cont_6_160811.png

Summary タブを示す。
AXI4-Stream_bitmap_disp_cont_7_160811.png

bitmap_afifo.vhd の entity を貼っておく。

ENTITY bitmap_afifo IS
  PORT (
    wr_clk : IN STD_LOGIC;
    wr_rst : IN STD_LOGIC;
    rd_clk : IN STD_LOGIC;
    rd_rst : IN STD_LOGIC;
    din : IN STD_LOGIC_VECTOR(31 DOWNTO 0);
    wr_en : IN STD_LOGIC;
    rd_en : IN STD_LOGIC;
    dout : OUT STD_LOGIC_VECTOR(31 DOWNTO 0);
    full : OUT STD_LOGIC;
    overflow : OUT STD_LOGIC;
    empty : OUT STD_LOGIC;
    underflow : OUT STD_LOGIC;
    wr_data_count : OUT STD_LOGIC_VECTOR(9 DOWNTO 0)
  );
END bitmap_afifo;

  1. 2016年08月11日 04:49 |
  2. IP
  3. | トラックバック:0
  4. | コメント:0
»