FC2カウンター FPGAの部屋 2014年06月

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

FPGAの部屋

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

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ13(Verilog HDLソース3)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ12(Verilog HDLソース2)”の続き。

最後に、disp_timing.v と frame_buffer.v を貼っておく。まずは、disp_timing.v から下に貼っておく。

// 水平同期(h_sync)、垂直同期(v_sync)、表示期間(display_on)

`default_nettype none
`timescale 1ns / 1ps

module disp_timing # (
        parameter integer RESOLUTION    = 1    // SVGA
    )
    (clk, reset, page_start, display_on, h_addr, v_addr, h_sync, h_sync_pulse, v_sync);
    `include "video_timing_param.vh"
    `include "convenient_functions.vh"

    input clk; // 25MHz
    input reset;
    output page_start; // 1ページのスタート信号、ページの最初の表示ビットのときにだけ1(同期用信号)
    output display_on; // 表示期間を示す(Active High)
    output [log2(H_SUM)-1:0] h_addr; // 水平のドットアドレス
    output [log2(V_SUM)-1:0] v_addr; // 垂直のドットアドレス
    output h_sync; // 水平同期、Active High
    output h_sync_pulse; // 水平同期パルス
    output v_sync; // 垂直同期、Active High

    wire clk;
    wire reset;
    wire page_start;
    wire display_on;
    wire [log2(H_SUM)-1:0] h_addr; // 水平のドットアドレス
    wire [log2(V_SUM)-1:0] v_addr; // 垂直のドットアドレス
    wire h_sync;
    wire h_sync_pulse;
    wire v_sync;

    reg [log2(H_SUM)-1:0] h_point, h_addr_node;
    reg [log2(V_SUM)-1:0] v_point, v_addr_node;
    reg page_start_node;
    reg display_on_node;
    reg h_sync_node;
    reg v_sync_node;
    reg h_sync_pulse_node;

    always @(posedge reset, posedge clk) begin // 水平信号
        if (reset) begin
            h_point <= 0;
            h_addr_node <= 0;
        end else begin
            h_addr_node <= h_point;
            if (h_point == H_SUM-1) // H_SUM-1だったらクリア
                h_point <= 0;
            else // H_SUM-1になるまでインクリメント
                h_point <= h_point + 1;
        end
    end
    assign h_addr = h_addr_node[9:0];

    always @(posedge reset, posedge clk) begin // 垂直信号
        if (reset) begin
            v_point <= 0;
            v_addr_node <= 0;
        end else begin
            v_addr_node <= v_point;
            if (v_point == V_SUM-1) // H_SUM-1だったらクリア
                v_point <= 0;
            else if (h_point == H_SUM-1) // 水平信号のエンドでインクリメント
                v_point <= v_point + 1;
        end
    end
    assign v_addr = v_addr_node[9:0];

    always @(posedge reset, posedge clk) begin // 表示期間
        if (reset)
            display_on_node <= 0;
        else begin
            if (h_point<H_ACTIVE_VIDEO && v_point<V_ACTIVE_VIDEO) // 表示期間
                display_on_node <= 1'b1;
            else
                display_on_node <= 1'b0; // 非表示期間
        end
    end
    assign display_on = display_on_node;

    always @(posedge reset, posedge clk) begin // 表示スタート
        if (reset)
            page_start_node <= 1'b0;
        else begin
            if (h_point==0) // 表示スタート
                page_start_node <= 1'b1;
            else
                page_start_node <= 1'b0;
        end
    end
    assign page_start = page_start_node;

    always @(posedge reset, posedge clk) begin // 水平同期
        if (reset)
            h_sync_node <= 1'b0;
        else begin
            if ((h_point>=(H_ACTIVE_VIDEO + H_FRONT_PORCH)) && (h_point < (H_SUM-H_BACK_PORCH))) // 水平同期期間
                h_sync_node <= 1'b1;
            else
                h_sync_node <= 1'b0;
        end
    end
    assign h_sync = h_sync_node;

    always @(posedge reset, posedge clk) begin // 水平同期位置のパルス
        if (reset)
            h_sync_pulse_node <= 1'b0;
        else begin
            if (h_point==(H_ACTIVE_VIDEO+H_FRONT_PORCH))
                h_sync_pulse_node <= 1'b1;
            else
                h_sync_pulse_node <= 1'b0;
        end
    end
    assign h_sync_pulse = h_sync_pulse_node;

    always @(posedge reset, posedge clk) begin // 垂直同期
        if (reset)
            v_sync_node <= 1'b0;
        else begin
            if ((v_point>=(V_ACTIVE_VIDEO + V_FRONT_PORCH)) && (v_point<(V_SUM-V_BACK_PORCH))) // 垂直同期期間
                v_sync_node <= 1'b1;
            else
                v_sync_node <= 1'b0;
        end
    end
    assign v_sync = v_sync_node;
endmodule


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

// フレームバッファ用メモリ
// AポートはプロセッサからのRead/Write用ポート、BポートはVGA用データ出力ポート
// display_on信号を受け取って、フレームバッファ用のアドレスを生成。このアドレスは8クロックごとにカウントアップ。
// データはキャラクタコード7ビットにR,G,Bの3ビットを追加
//
// 2012/02/24 : R 3bit, G 3bit, B 3bit, キャラクタ 7bitの16ビットに変更した。
// 2012/02/25 : Write側とRead側のクロックを分離して、非同期RAMに変更した。
// 2013/03/05 : reset を reset_a, reset_b に変更
// 2014/03/16 : 全面変更

`default_nettype none

module frame_buffer # (
        parameter integer RESOLUTION    = 1    // SVGA
    )
    (clka, clkb, reset_a, reset_b, processor_addr, processor_din, processor_dout, processor_we, display_addr, display_dout);
    `include "video_timing_param.vh"
    `include "convenient_functions.vh"

    input clka;
    input clkb;
    input reset_a;
    input reset_b;
    input [log2(ALL_CHAR_SIZE)-1:0] processor_addr;
    input [15:0] processor_din;
    output [15:0] processor_dout;
    input processor_we;
    input [log2(ALL_CHAR_SIZE)-1:0] display_addr;
    output [15:0] display_dout;

    parameter integer    FB_MEM_SIZE    = near_power2(ALL_CHAR_SIZE);

    reg        [15:0]    mem    [0:near_power2(ALL_CHAR_SIZE)-1];
    wire clka;
    wire clkb;
    wire reset_a;
    wire reset_b;
    wire [log2(ALL_CHAR_SIZE)-1:0] processor_addr;
    wire [15:0] processor_din;
    reg  [15:0] processor_dout;
    wire processor_we;
    wire [log2(ALL_CHAR_SIZE)-1:0] display_addr;
    reg  [15:0] display_dout;
    integer i;

    // initialization
    // Simulation では通るが、Synthesize だと、どうしてもエラーになるので Simulation のみとした
    // pragma translate off
    initial begin
        for (i=0; i<FB_MEM_SIZE; i=i+1) begin
            mem[i] = 16'd0;
        end
    end
    // pragma translate on
    
    // Write
    always @(posedge clka) begin
        if (processor_we)
            mem[processor_addr] <= processor_din;
        processor_dout <= mem[processor_addr];
    end

    // Read
    always @(posedge clkb) begin
        display_dout <= mem[display_addr];
    end

endmodule

`default_nettype none

  1. 2014年06月30日 04:36 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ12(Verilog HDLソース2)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ11(Verilog HDLソース1)”の続き。

Verilog HDLのソースコードの第2弾。CharDispCtrler.v から貼っておく。

// CharDispCtrler.v
// キャラクタ ディスレイ コントローラ
// processor_dout, display_doutのビット構成 bit9 - RED, bit8 - GREEN, bit7 - BLUE, bit6〜0 : キャラクタデータ
//
// 2010/06/21 : Ver.1.1 : display_enableを追加
// 2012/02/24 : R 3bit, G 3bit, B 3bit, キャラクタ 7bitの16ビットに変更した。
// 2012/02/25 : プロセッサ側のクロックと画像表示用クロックを分けた。

`default_nettype none
`timescale 1ns / 1ps

module CharDispCtrler # (
        parameter integer RESOLUTION    = 1    // SVGA
    )
    (axi4clk, pixclk, reset_axi, reset_pix, processor_addr, processor_din, processor_dout, processor_we, VGA_RED, VGA_GREEN, VGA_BLUE, VGA_HSYNC, VGA_VSYNC, display_enable);
    `include "video_timing_param.vh"
    `include "convenient_functions.vh"

    input wire axi4clk;
    input wire pixclk;
    input wire reset_axi;
    input wire reset_pix;
    input wire [log2(ALL_CHAR_SIZE)-1:0] processor_addr;
    input wire [15:0] processor_din;
    output wire [15:0] processor_dout;
    input wire processor_we;

    output [COLOR_ATTRIB_WIDHT-1 : 0]    VGA_RED;
    output [COLOR_ATTRIB_WIDHT-1 : 0]    VGA_GREEN;
    output [COLOR_ATTRIB_WIDHT-1 : 0]    VGA_BLUE;
    output VGA_HSYNC;
    output VGA_VSYNC;
    output wire display_enable;

    wire [COLOR_ATTRIB_WIDHT-1 : 0]    VGA_RED;
    wire [COLOR_ATTRIB_WIDHT-1 : 0]    VGA_GREEN;
    wire [COLOR_ATTRIB_WIDHT-1 : 0]    VGA_BLUE;
    wire VGA_HSYNC;
    wire VGA_VSYNC;

    wire [log2(H_SUM)-1:0] h_addr; // 水平のドットアドレス
    wire [log2(V_SUM)-1:0] v_addr; // 垂直のドットアドレス
    wire h_sync_pulse;
    reg [COLOR_ATTRIB_WIDHT-1 : 0]    red_node, green_node, blue_node;
    reg [6:0] char_data_node;
    reg [log2(ALL_CHAR_SIZE)-1:0] temp_pointer;
    wire page_start, display_on;
    wire h_sync_0, v_sync_0;
    reg h_sync_1, v_sync_1;
    reg h_sync_2, v_sync_2;
    reg h_sync_3, v_sync_3;
    reg [log2(ALL_CHAR_SIZE)-1:0] display_addr;
    wire [15:0] display_dout;
    wire [7:0] char_data;
    reg [RED_DOT_POS:BLUE_DOT_POS-COLOR_ATTRIB_WIDHT+1] temp_color;
    reg display_on_d1, display_on_d2;

    frame_buffer #(
        .RESOLUTION(RESOLUTION)
    ) frame_buffer_inst (
        .clka(axi4clk),
        .clkb(pixclk),
        .reset_a(reset_axi),
        .reset_b(reset_pix),
        .processor_addr(processor_addr),
        .processor_din(processor_din),
        .processor_dout(processor_dout),
        .processor_we(processor_we),
        .display_addr(display_addr),
        .display_dout(display_dout)
    );

    char_gen_rom char_gen_rom_inst (
        .clk(pixclk),
        .reset(reset_pix),
        .char_addr(display_dout[6:0]),
        .row_addr(v_addr[2:0]),
        .dout(char_data)
    );

    disp_timing #(
        .RESOLUTION(RESOLUTION)
    ) disp_timing_inst (
        .clk(pixclk),
        .reset(reset_pix),
        .page_start(page_start),
        .display_on(display_on),
        .h_addr(h_addr),
        .v_addr(v_addr),
        .h_sync(h_sync_0),
        .h_sync_pulse(h_sync_pulse),
        .v_sync(v_sync_0)
    );

    always @(posedge pixclk) begin // display_onを2クロック遅延する。下の表示部分はframe_buffer, キャラジェネROMで2クロックデータが遅延している。それを吸収するためにdisplay_onを2クロック遅延した信号を作る
        if (reset_pix) begin
            display_on_d1 <= 1'b0;
            display_on_d2 <= 1'b0;
        end else begin
            display_on_d1 <= display_on;
            display_on_d2 <= display_on_d1;
        end
    end
    assign display_enable = display_on_d2;

    always @(posedge pixclk) begin // キャラジェネROM、赤、緑、青のビット
        if (reset_pix) begin
            red_node <= 3'b111;
            green_node <= 3'b111;
            blue_node <= 3'b111;
            char_data_node <= 0;
            temp_color <= 0;
        end else begin
            if (h_addr[2:0] == 3'd2) begin // 最初の時、なぜ2かと言うと0でframe_bufferのアドレスが変化して、データが出るのが1クロック後、さらにそのデータからキャラクタROMのデータが出るのが更に1クロック後だから
                char_data_node <= char_data[7:1];
                temp_color <= display_dout[RED_DOT_POS : BLUE_DOT_POS-COLOR_ATTRIB_WIDHT+1]; // 最後に色データがなくなってしまうのでとりあえず保存しておく
                if (char_data[0]==1'b1 && display_on_d2==1'b1) begin // 最初はシフトレジスタにロードするのと同時なので直接0ビット目を判定する。表示領域のときだけ映像信号を出力
                    red_node <= display_dout[RED_DOT_POS : RED_DOT_POS-COLOR_ATTRIB_WIDHT+1];
                    green_node <= display_dout[GREEN_DOT_POS : GREEN_DOT_POS-COLOR_ATTRIB_WIDHT+1];
                    blue_node <= display_dout[BLUE_DOT_POS : BLUE_DOT_POS-COLOR_ATTRIB_WIDHT+1];
                end else begin
                    red_node <= 3'b000;
                    green_node <= 3'b000;
                    blue_node <= 3'b000;
                end
            end else begin
                char_data_node <= {1'b0, char_data_node[6:1]}; // 1ビット右シフト
                if (char_data_node[0]==1'b1 && display_on_d2==1'b1) begin // シフトデータを判定
                    red_node <= temp_color[RED_DOT_POS : RED_DOT_POS-COLOR_ATTRIB_WIDHT+1]; // 以降は保存した色データから判断
                    green_node <= temp_color[GREEN_DOT_POS : GREEN_DOT_POS-COLOR_ATTRIB_WIDHT+1];
                    blue_node <= temp_color[BLUE_DOT_POS : BLUE_DOT_POS-COLOR_ATTRIB_WIDHT+1];
                end else begin
                    red_node <= 3'b000;
                    green_node <= 3'b000;
                    blue_node <= 3'b000;
                end
            end
        end
    end
    assign VGA_RED = red_node;
    assign VGA_GREEN = green_node;
    assign VGA_BLUE = blue_node;

    always @(posedge pixclk) begin // 表示するフレームバッファのアドレスを生成
        if (reset_pix) begin
            display_addr <= 0;
            temp_pointer <= 0;
        end else begin
            if (display_on == 1'b1)  begin // 1キャラクタのラスタが終了のときにアドレスを+1
                if (h_addr[2:0] == 3'd7) // 1キャラクタのラスタが終了のときにアドレスを+1
                    display_addr <= display_addr + 1;
            end else begin // 非表示領域
                if (v_sync_0 == 1'b1) begin // 垂直同期のときはdisplay_addrを0クリア
                    display_addr <= 0;
                    temp_pointer <= 0;
                end else if (h_sync_pulse == 1'b1) begin // 水平同期のとき
                    if (v_addr[2:0] == 3'd7) // 最後のラスタ
                        temp_pointer <= display_addr; // 現在のアドレス値+1になっているので、そのままtemp_pointerに入れる
                    else // それ以外のラスタのとき
                        display_addr <= temp_pointer;
                end
            end
        end
    end

    always @(posedge pixclk) begin // 同期信号の位相を合わせる
        if (reset_pix) begin
            h_sync_1 <= 1'b0;
            v_sync_1 <= 1'b0;
            h_sync_2 <= 1'b0;
            v_sync_2 <= 1'b0;
            h_sync_3 <= 1'b0;
            v_sync_3 <= 1'b0;
        end else begin
            h_sync_1 <= h_sync_0;
            v_sync_1 <= v_sync_0;
            h_sync_2 <= h_sync_1;
            v_sync_2 <= v_sync_1;
            h_sync_3 <= h_sync_2;
            v_sync_3 <= v_sync_2;
        end
    end
    assign VGA_HSYNC = !h_sync_3;
    assign VGA_VSYNC = !v_sync_3;
endmodule

`default_nettype wire


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

// キャラクタジェネレータ用ROM

`default_nettype none
`timescale 1ns / 1ps

module char_gen_rom(clk, reset, char_addr, row_addr, dout);
    input clk;
    input reset;
    input [6:0] char_addr;
    input [2:0] row_addr;
    output [7:0] dout;
    
    wire clk;
    wire reset;
    wire [6:0] char_addr;
    wire [2:0] row_addr;
    wire [7:0] dout;
    
    wire [10:0] addr;
    
    assign addr = {1'b0, char_addr, row_addr};
    
    RAMB16_S9 #(
        .INIT_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_07(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_08(256'h0014147F147F1414000000000012243600080008080808080000000000000000), // #,",!, 
        .INIT_09(256'h0000000000081018004C322254081408002152240812254200083E483E093E08), // ',&,%,$
        .INIT_0A(256'h000808087F08080800492A1C7F1C2A4900040810101008040020100808081020), // +,*,),(
        .INIT_0B(256'h00010204081020400006060000000000000000007F0000000002040600000000), // /,.,-,,
        .INIT_0C(256'h001C22201820221C003E02041820221C001C080808080C080018244242422418), // 3,2,1,0
        .INIT_0D(256'h001010202040407E003C42423E02423C001E20201E02023E0020207E22242830), // 7,6,5,4
        .INIT_0E(256'h0004080C00000C000000000C00000C00003C42407C42423C003C42423C42423C), // ;,:,9,8
        .INIT_0F(256'h000800081020221C00040810201008040000003E003E00000020100804081020), // ?,>,=,<
        .INIT_10(256'h001C22010101221C003F41413F41413F0041417F2236141C005C2A155549221E), // C,B,A,@
        .INIT_11(256'h001C22710101221C000101013F01017F007F01013F01017F001F21414141211F), // G,F,E,D
        .INIT_12(256'h0022120A060A1222000E11101010103E001C08080808081C004141417F414141), // K,J,I,H
        .INIT_13(256'h001C22414141221C00416151494543410041414149556341003E020202020202),// O,N,M,L
        .INIT_14(256'h003C42403C02423C002111093F41413F005C26594141221C000101013F41413F), // S,R,Q,P
        .INIT_15(256'h00225555554949490008141422224141001C224141414141000808080808087F), // W,V,U,T
        .INIT_16(256'h0038080808080838003F02040810203F00080808081422410041221408142241), // [,Z,Y,X
        .INIT_17(256'h007F0000000000000000000000221408001C10101010101C0008083E083E1422), // _,^,],\
        .INIT_18(256'h0038040438000000001E22221E020200003C223C201C00000000000000180810), // c,b,a,`
        .INIT_19(256'h001C221C0C122C00000808081C081000001C021E221C0000003C22223C202000), // g,f,e,d
        .INIT_1A(256'h0024140C14240400000C1210100010000008080800080000002424241C040400), // k,j,i,h
        .INIT_1B(256'h0018242424180000002828282814000000545454542A00000018080808080800), // o,n,m,l
        .INIT_1C(256'h0018201804180000000404040C34000000202038243800000004041C241C0000), // s,r,q,p
        .INIT_1D(256'h00142A2A2A2200000008141422220000001824242424000000180808081C0800), // w,v,u,t
        .INIT_1E(256'h001008080C080810003E0408103E000000020408142200000022140814220000), // {,z,y,x
        .INIT_1F(256'h0000000000000000000000000000142800040808180808040008080808080808), //  ,~,},|
        .INIT_20(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_21(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_22(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_23(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_24(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_25(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_26(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_27(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_28(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_29(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2A(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2B(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2C(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2D(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2E(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_2F(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_31(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_32(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_33(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_34(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_35(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_36(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_37(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_38(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_39(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3A(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3B(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3C(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3D(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3E(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INIT_3F(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_00(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_01(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_02(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_03(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_04(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_05(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_06(256'h0000000000000000000000000000000000000000000000000000000000000000),
        .INITP_07(256'h0000000000000000000000000000000000000000000000000000000000000000)
    ) CHAR_GEN_ROM_INST (
        .DO(dout),
        .DOP(),
        .ADDR(addr),
        .CLK(clk),
        .DI(8'd0),
        .DIP(1'b0),
        .EN(1'b1),
        .SSR(reset),
        .WE(1'b0)
    );
endmodule


VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ13(Verilog HDLソース3)”に続く。
  1. 2014年06月29日 06:48 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ11(Verilog HDLソース1)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ10(VHDLソース)”の続き。

今回は、Verilog HDLのソースコードを貼っておく。video_timing_param.vh から貼っておく。

// video_timing_param.vh
//

parameter integer H_ACTIVE_VIDEO = (RESOLUTION==0) ? 640 :  // VGA    25MHz
                    (RESOLUTION==1) ?    800 :              // SVGA   40MHz
                    (RESOLUTION==2) ?    1024 :             // XGA    65MHz
                    (RESOLUTION==3) ?    1280 :             // SXGA   108MHz
                    (RESOLUTION==4) ?    1920 : 1920;       // HD     148.5MHz

parameter integer H_FRONT_PORCH = (RESOLUTION==0) ? 16 :    // VGA
                    (RESOLUTION==1) ?    40 :               // SVGA
                    (RESOLUTION==2) ?    24 :               // XGA
                    (RESOLUTION==3) ?    48 :               // SXGA
                    (RESOLUTION==4) ?    88 : 88;           // HD

parameter integer H_SYNC_PULSE = (RESOLUTION==0) ? 96 :     // VGA
                    (RESOLUTION==1) ?    128 :              // SVGA
                    (RESOLUTION==2) ?    136 :              // XGA
                    (RESOLUTION==3) ?    112 :              // SXGA
                    (RESOLUTION==4) ?    44 : 44;           // HD

parameter integer H_BACK_PORCH = (RESOLUTION==0) ? 48 :     // VGA
                    (RESOLUTION==1) ?    88 :               // SVGA
                    (RESOLUTION==2) ?    160 :              // XGA
                    (RESOLUTION==3) ?    248 :              // SXGA
                    (RESOLUTION==4) ?    148 : 148;         // HD

parameter integer V_ACTIVE_VIDEO = (RESOLUTION==0) ? 480 :  // VGA
                    (RESOLUTION==1) ?    600 :              // SVGA
                    (RESOLUTION==2) ?    768 :              // XGA
                    (RESOLUTION==3) ?    1024 :             // SXGA
                    (RESOLUTION==4) ?    1080 : 1080;       // HD

parameter integer V_FRONT_PORCH = (RESOLUTION==0) ? 11 :    // VGA
                    (RESOLUTION==1) ?    1 :                // SVGA
                    (RESOLUTION==2) ?    2 :                // XGA
                    (RESOLUTION==3) ?    1 :                // SXGA
                    (RESOLUTION==4) ?    4 : 4;             // HD

parameter integer V_SYNC_PULSE = (RESOLUTION==0) ? 2 :      // VGA
                    (RESOLUTION==1) ?    4 :                // SVGA
                    (RESOLUTION==2) ?    6 :                // XGA
                    (RESOLUTION==3) ?    3 :                // SXGA
                    (RESOLUTION==4) ?    5 : 5;             // HD

parameter integer V_BACK_PORCH = (RESOLUTION==0) ? 31 :     // VGA
                    (RESOLUTION==1) ?    23 :               // SVGA
                    (RESOLUTION==2) ?    29 :               // XGA
                    (RESOLUTION==3) ?    38 :               // SXGA
                    (RESOLUTION==4) ?    36 : 36;           // HD

    parameter H_SUM = H_ACTIVE_VIDEO + H_FRONT_PORCH + H_SYNC_PULSE + H_BACK_PORCH;
    parameter V_SUM = V_ACTIVE_VIDEO + V_FRONT_PORCH + V_SYNC_PULSE + V_BACK_PORCH;

    parameter H_DISPLAY_SIZE = H_ACTIVE_VIDEO/8; // 横?桁
    parameter V_DISPLAY_SIZE = V_ACTIVE_VIDEO/8; // 縦?行
    parameter ALL_CHAR_SIZE = H_DISPLAY_SIZE*V_DISPLAY_SIZE;

    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;    // 色情報のビット幅


次に、convenient_functions.vh を貼っておく。

// function (log2, near_power2)
// convenient_functions.vh
//

// Beyond Circuts, Constant Function in Verilog 2001を参照しました
// http://www.beyond-circuits.com/wordpress/2008/11/constant-functions/
function integer log2;
    input integer addr;
    begin
        addr = addr - 1;
        for (log2=0; addr>0; log2=log2+1)
            addr = addr >> 1;
    end
endfunction

// 一番近く、より大きい2のn乗の値を返す
function integer near_power2;
    input integer num;
    begin
        for (near_power2=2; near_power2<=num; )
          near_power2=near_power2*2;
    end
endfunction


VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ12(Verilog HDLソース2)”に続く。
  1. 2014年06月29日 05:04 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ10(VHDLソース)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ9(SDK、実機テスト)”の続き。

VHDLソースコードを貼っておく。video_timing_pkg.vhdを下に示す。

package video_timing_pkg is
    subtype RESLUTION_TYPE is integer range 0 to 4;
    type VIDEO_RECORD is record
        H_ACTIVE_VIDEO  : integer range 640 to 1920;
        H_FRONT_PORCH   : integer;
        H_SYNC_PULSE    : integer;
        H_BACK_PORCH    : integer;
        V_ACTIVE_VIDEO  : integer range 480 to 1080;
        V_FRONT_PORCH   : integer;
        V_SYNC_PULSE    : integer;
        V_BACK_PORCH    : integer;
    end record VIDEO_RECORD;
    type VIDEO_RECORD_A is array (RESLUTION_TYPE) of VIDEO_RECORD;
    constant CONST_VIDEO_R : VIDEO_RECORD_A := (
        0 => (  H_ACTIVE_VIDEO  =>  640,
                H_FRONT_PORCH   =>  16,
                H_SYNC_PULSE    =>  96,
                H_BACK_PORCH    =>  48,
                V_ACTIVE_VIDEO  =>  480,
                V_FRONT_PORCH   =>  11,
                V_SYNC_PULSE    =>  2,
                V_BACK_PORCH    =>  31
            ), -- VGA, 25MHz
        1 => (  H_ACTIVE_VIDEO  =>  800,
                H_FRONT_PORCH   =>  40,
                H_SYNC_PULSE    =>  128,
                H_BACK_PORCH    =>  88,
                V_ACTIVE_VIDEO  =>  600,
                V_FRONT_PORCH   =>  1,
                V_SYNC_PULSE    =>  4,
                V_BACK_PORCH    =>  23
            ), -- SVGA, 40MHz
        2 => (  H_ACTIVE_VIDEO  =>  1024,
                H_FRONT_PORCH   =>  24,
                H_SYNC_PULSE    =>  136,
                H_BACK_PORCH    =>  160,
                V_ACTIVE_VIDEO  =>  768,
                V_FRONT_PORCH   =>  2,
                V_SYNC_PULSE    =>  6,
                V_BACK_PORCH    =>  29
            ), -- XGA, 65MHz
        3 => (  H_ACTIVE_VIDEO  =>  1280,
                H_FRONT_PORCH   =>  48,
                H_SYNC_PULSE    =>  112,
                H_BACK_PORCH    =>  248,
                V_ACTIVE_VIDEO  =>  1024,
                V_FRONT_PORCH   =>  1,
                V_SYNC_PULSE    =>  3,
                V_BACK_PORCH    =>  38
            ), -- SXGA, 108MHz
        4 => (  H_ACTIVE_VIDEO  =>  1920,
                H_FRONT_PORCH   =>  88,
                H_SYNC_PULSE    =>  44,
                H_BACK_PORCH    =>  148,
                V_ACTIVE_VIDEO  =>  1080,
                V_FRONT_PORCH   =>  4,
                V_SYNC_PULSE    =>  5,
                V_BACK_PORCH    =>  36
            )  -- HD, 148.5MHz
    );
end package video_timing_pkg;


cdc_vga_axi_slave.vhd を下に示す。

-----------------------------------------------------------------------------
--
-- AXI Slave
--
-----------------------------------------------------------------------------
-- 2012/02/25 : S_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。

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

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

use work.video_timing_pkg.all;

entity cdc_vga_axi_slave is
  generic (
    C_S_AXI_ID_WIDTH     : integer := 1;
    C_S_AXI_ADDR_WIDTH   : integer := 32;
    C_S_AXI_DATA_WIDTH   : integer := 32;
    C_S_AXI_AWUSER_WIDTH : integer := 1;
    C_S_AXI_ARUSER_WIDTH : integer := 1;
    C_S_AXI_WUSER_WIDTH  : integer := 1;
    C_S_AXI_RUSER_WIDTH  : integer := 1;
    C_S_AXI_BUSER_WIDTH  : integer := 1;

    RESOLUTION : integer := 1    -- SVGA
  );
  port(
    -- System Signals
    ACLK    : in std_logic;
    ARESETN : in std_logic;

    -- Slave Interface Write Address Ports
    S_AXI_AWID     : in  std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
    S_AXI_AWADDR   : in  std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
    S_AXI_AWLEN    : in  std_logic_vector(8-1 downto 0);
    S_AXI_AWSIZE   : in  std_logic_vector(3-1 downto 0);
    S_AXI_AWBURST  : in  std_logic_vector(2-1 downto 0);
    S_AXI_AWLOCK   : in  std_logic_vector(2-1 downto 0);
    S_AXI_AWCACHE  : in  std_logic_vector(4-1 downto 0);
    S_AXI_AWPROT   : in  std_logic_vector(3-1 downto 0);
    S_AXI_AWREGION : in  std_logic_vector(4-1 downto 0);
    S_AXI_AWQOS    : in  std_logic_vector(4-1 downto 0);
    S_AXI_AWUSER   : in  std_logic_vector(C_S_AXI_AWUSER_WIDTH-1 downto 0);
    S_AXI_AWVALID  : in  std_logic;
    S_AXI_AWREADY  : out std_logic;

    -- Slave Interface Write Data Ports
    S_AXI_WID    : in  std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
    S_AXI_WDATA  : in  std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
    S_AXI_WSTRB  : in  std_logic_vector(C_S_AXI_DATA_WIDTH/8-1 downto 0);
    S_AXI_WLAST  : in  std_logic;
    S_AXI_WUSER  : in  std_logic_vector(C_S_AXI_WUSER_WIDTH-1 downto 0);
    S_AXI_WVALID : in  std_logic;
    S_AXI_WREADY : out std_logic;

    -- Slave Interface Write Response Ports
    S_AXI_BID    : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
    S_AXI_BRESP  : out std_logic_vector(2-1 downto 0);
    S_AXI_BUSER  : out std_logic_vector(C_S_AXI_BUSER_WIDTH-1 downto 0);
    S_AXI_BVALID : out std_logic;
    S_AXI_BREADY : in  std_logic;

    -- Slave Interface Read Address Ports
    S_AXI_ARID     : in  std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
    S_AXI_ARADDR   : in  std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
    S_AXI_ARLEN    : in  std_logic_vector(8-1 downto 0);
    S_AXI_ARSIZE   : in  std_logic_vector(3-1 downto 0);
    S_AXI_ARBURST  : in  std_logic_vector(2-1 downto 0);
    S_AXI_ARLOCK   : in  std_logic_vector(2-1 downto 0);
    S_AXI_ARCACHE  : in  std_logic_vector(4-1 downto 0);
    S_AXI_ARPROT   : in  std_logic_vector(3-1 downto 0);
    S_AXI_ARREGION : in  std_logic_vector(4-1 downto 0);
    S_AXI_ARQOS    : in  std_logic_vector(4-1 downto 0);
    S_AXI_ARUSER   : in  std_logic_vector(C_S_AXI_ARUSER_WIDTH-1 downto 0);
    S_AXI_ARVALID  : in  std_logic;
    S_AXI_ARREADY  : out std_logic;

    -- Slave Interface Read Data Ports
    S_AXI_RID    : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
    S_AXI_RDATA  : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
    S_AXI_RRESP  : out std_logic_vector(2-1 downto 0);
    S_AXI_RLAST  : out std_logic;
    S_AXI_RUSER  : out std_logic_vector(C_S_AXI_RUSER_WIDTH-1 downto 0);
    S_AXI_RVALID : out std_logic;
    S_AXI_RREADY : in  std_logic;
    
    -- VGA Signals
    pixclk        : in    std_logic;
    reset_pixclk    : in     std_logic;
    red_out        : out std_logic_vector(4 downto 0);
    green_out    : out std_logic_vector(5 downto 0);
    blue_out    : out std_logic_vector(4 downto 0);
    hsync_n        : out std_logic;
    vsync_n        : out std_logic
    );

end cdc_vga_axi_slave;

architecture implementation of cdc_vga_axi_slave is
constant    VIDEO_PARAM        : VIDEO_RECORD    := CONST_VIDEO_R(RESOLUTION);
constant    H_ACTIVE_VIDEO    : integer         := VIDEO_PARAM.H_ACTIVE_VIDEO;
constant    V_ACTIVE_VIDEO    : integer         := VIDEO_PARAM.V_ACTIVE_VIDEO;
constant    ALL_CHAR_SIZE    : integer        := (H_ACTIVE_VIDEO/8)*(V_ACTIVE_VIDEO/8);
constant    CDC_ADDR_WIDTH    : integer        := natural(ceil(log(real(ALL_CHAR_SIZE), 2.0)));

component CharDispCtrler
    generic(
        RESOLUTION : integer := 4    -- HD
    );
    port(
        axi4clk : in std_logic;
        pixclk : in std_logic;
        reset_axi : in std_logic;
        reset_pix : in std_logic;
        
        processor_addr : in std_logic_vector(CDC_ADDR_WIDTH-1 downto 0);
        processor_din : in std_logic_vector(15 downto 0);
        processor_dout : out std_logic_vector(15 downto 0);
        processor_we : in std_logic;
        
        VGA_RED : out std_logic_vector(2 downto 0);
        VGA_GREEN : out std_logic_vector(2 downto 0);
        VGA_BLUE : out std_logic_vector(2 downto 0);
        VGA_HSYNC : out std_logic;
        VGA_VSYNC : out std_logic;
        display_enable : out std_logic
    );
end component;
COMPONENT afifo_sm
  PORT (
    clk : IN STD_LOGIC;
    rst : IN STD_LOGIC;
    din : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
    wr_en : IN STD_LOGIC;
    rd_en : IN STD_LOGIC;
    dout : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
    full : OUT STD_LOGIC;
    almost_full : OUT STD_LOGIC;
    overflow : OUT STD_LOGIC;
    empty : OUT STD_LOGIC;
    almost_empty : OUT STD_LOGIC;
    underflow : OUT STD_LOGIC
  );
END COMPONENT;

constant    AxBURST_FIXED    : std_logic_vector := "00";
constant    AxBURST_INCR    : std_logic_vector := "01";
constant    AxBURST_WRAP    : std_logic_vector := "10";

constant    RESP_OKAY        : std_logic_vector := "00";
constant    RESP_EXOKAY        : std_logic_vector := "01";
constant    RESP_SLVERR        : std_logic_vector := "10";
constant    RESP_DECERR        : std_logic_vector := "11";

-- for write transaction
type write_transaction_state is (idle_wr, awr_wait, awr_accept, wr_burst);
type write_response_state is (idle_wres, bvalid_assert);
type write_wready_state is (idle_wrdy, wready_assert);
signal wrt_cs : write_transaction_state;
signal wrres : write_response_state;
signal wrwr : write_wready_state;

-- for read transaction
type read_transaction_state is (idle_rd, arr_wait, arr_accept, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdt_cs : read_transaction_state;
signal rdlast : read_last_state;

signal reset_1d, reset_2d, reset_axi : std_logic := '1';

signal awready         : std_logic;
signal wr_addr         : std_logic_vector(CDC_ADDR_WIDTH-1 downto 0);
signal wr_bid         : std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
signal wr_bresp     : std_logic_vector(1 downto 0);
signal wr_bvalid     : std_logic;

signal arready         : std_logic;
signal rd_addr         : std_logic_vector(CDC_ADDR_WIDTH-1 downto 0);
signal rd_axi_count    : std_logic_vector(7 downto 0);
signal rd_cdc_count    : std_logic_vector(8 downto 0);
signal rdfifo_din    : std_logic_vector(15 downto 0);
signal rdfifo_wr_en    : std_logic;
signal rdfifo_rd_en    : std_logic;
signal rdfifo_full, rdfifo_empty    : std_logic;
signal rdfifo_almost_full, rdfifo_almost_empty : std_logic;
signal rdfifo_overflow, rdfifo_underflow : std_logic;
signal rvalid        : std_logic;
signal rlast        : std_logic;
signal cdc_addr        : std_logic_vector(CDC_ADDR_WIDTH-1 downto 0);
signal vga_red, vga_green, vga_blue : std_logic_vector(2 downto 0);
signal vga_red8, vga_green8, vga_blue8 : std_logic_vector(7 downto 0);
signal vga_hsync, vga_vsync : std_logic;
signal display_enable : std_logic;
signal cdc_we : std_logic;
signal rdfifo_wr_en_node : std_logic;
signal reset_p1d, reset_p2d, reset_pix : std_logic;

begin
    -- ARESETN をACLK で同期化
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            reset_1d <= not ARESETN;
            reset_2d <= reset_1d;
        end if;
    end process;
    reset_axi <= reset_2d;
    
    -- reset_pix を pixclk で同期化
    process (pixclk) begin
        if pixclk'event and pixclk='1' then 
            reset_p1d <= reset_pixclk;
            reset_p2d <= reset_p1d;
        end if;
    end process;
    reset_pix <= reset_p2d;
    
    -- AXI4バス Write Transaction State Machine
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                wrt_cs <= idle_wr;
                awready <= '0';
            else
                case (wrt_cs) is
                    when idle_wr =>
                        if S_AXI_AWVALID='1' then -- S_AXI_AWVALID が1にアサートされた
                            if rdt_cs=idle_rd then -- Read Transaction が終了している(Writeの方が優先順位が高い)
                                wrt_cs <= awr_accept;
                                awready <= '1';
                            else -- Read Transaction が終了していないのでWait
                                wrt_cs <= awr_wait;
                            end if;
                        end if;
                    when awr_wait => -- Read Transaction の終了待ち
                        if rdt_cs=idle_rd or rdt_cs=arr_wait then -- Read Transaction が終了
                            wrt_cs <= awr_accept;
                            awready <= '1';
                        end if;
                    when awr_accept => -- S_AXI_AWREADY をアサート
                        wrt_cs <= wr_burst;
                        awready <= '0';
                    when wr_burst => -- Writeデータの転送
                        if S_AXI_WLAST='1' and S_AXI_WVALID='1' then -- Write Transaction 終了
                            wrt_cs <= idle_wr;
                        end if;
                end case;
            end if;
        end if;
    end process;
    S_AXI_AWREADY <= awready;
    S_AXI_WREADY <= '1' when wrt_cs=wr_burst else '0';
    cdc_we <= '1' when wrt_cs=wr_burst and S_AXI_WVALID='1' else '0';
    
    -- wr_addr の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                wr_addr <= (others => '0');
            else
                if wrt_cs=awr_accept then
                    wr_addr <= S_AXI_AWADDR(CDC_ADDR_WIDTH+1 downto 2); -- 32ビット幅データのため
                elsif wrt_cs=wr_burst and S_AXI_WVALID='1' then -- アドレスを1つ進める
                    wr_addr <= wr_addr + 1;
                end if;
            end if;
        end if;
    end process;
    
    -- wr_bid の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                wr_bid <= (others => '0');
            else
                if wrt_cs=awr_accept then
                    wr_bid <= S_AXI_AWID;
                end if;
            end if;
        end if;
    end process;
    S_AXI_BID <= wr_bid;
    
    -- wr_bresp の処理
    -- S_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                wr_bresp <= (others => '0');
            else
                if wrt_cs=awr_accept then
                    if S_AXI_AWBURST=AxBURST_INCR then -- バーストタイプがアドレス・インクリメントタイプ
                        wr_bresp <= RESP_OKAY; -- Write Transaction は成功
                    else
                        wr_bresp <= RESP_SLVERR; -- エラー
                    end if;
                end if;
            end if;
        end if;
    end process;
    S_AXI_BRESP <= wr_bresp;
    
    -- wr_bvalid の処理
    -- Write Transaction State Machineには含まない。axi_master のシミュレーションを見ると1クロックで終了しているので、長い間、Master側の都合でWaitしていることは考えない。
    -- 次のWrite転送まで遅延しているようであれば、Write Transaction State Machine に入れてブロックすることも考える必要がある。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                wr_bvalid <= '0';
            else
                if S_AXI_WLAST='1' and S_AXI_WVALID='1' then -- Write Transaction 終了
                    wr_bvalid <= '1';
                elsif wr_bvalid='1' and S_AXI_BREADY='1' then -- wr_bvalid が1でMaster側のReadyも1ならばWrite resonse channel の転送も終了
                    wr_bvalid <= '0';
                end if;
            end if;
        end if;
    end process;
    S_AXI_BVALID <= wr_bvalid;
    S_AXI_BUSER <= (others => '0');
    
    
    -- AXI4バス Read Transaction State Machine
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                rdt_cs <= idle_rd;
                arready <= '0';
            else
                case (rdt_cs) is
                    when idle_rd =>
                        if S_AXI_ARVALID='1' then -- Read Transaction 要求
                            if wrt_cs=idle_wr and S_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
                                rdt_cs <= arr_accept;
                                arready <= '1';
                            else -- Write Transaction が終了していないのでWait
                                rdt_cs <= arr_wait;
                            end if;
                        end if;
                    when arr_wait => -- Write Transaction の終了待ち
                        if wrt_cs=idle_wr and S_AXI_AWVALID='0' then -- Write Transaction State Machine がidle でWrite要求もない
                            rdt_cs <= arr_accept;
                            arready <= '1';
                        end if;
                    when arr_accept => -- S_AXI_ARREADY をアサート
                        rdt_cs <= rd_burst;
                        arready <= '0';
                    when rd_burst => -- Readデータの転送
                        if rd_axi_count=0 and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了
                            rdt_cs <= idle_rd;
                        end if;
                end case;
            end if;
        end if;
    end process;
    S_AXI_ARREADY <= arready;
    
    -- rd_addr の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                rd_addr <= (others => '0');
            else
                if rdt_cs=arr_accept then
                    rd_addr <= S_AXI_ARADDR(CDC_ADDR_WIDTH+1 downto 2); -- 32ビット幅データのため
                elsif rdt_cs=rd_burst and rdfifo_almost_full='0' and rd_cdc_count/=0 then -- rdfifoに余裕があるときにはアドレスを1つ進める
                    rd_addr <= rd_addr + 1;
                end if;
            end if;
        end if;
    end process;
    
    -- Read用FIFOのインスタンス
    rdfifo : afifo_sm PORT MAP (
        clk => ACLK,
        rst => reset_axi,
        din => rdfifo_din,
        wr_en => rdfifo_wr_en,
        rd_en => rdfifo_rd_en,
        dout => S_AXI_RDATA(15 downto 0),
        full => rdfifo_full,
        almost_full => rdfifo_almost_full,
        overflow => rdfifo_overflow,
        empty => rdfifo_empty,
        almost_empty => rdfifo_almost_empty,
        underflow => rdfifo_underflow
    );
    S_AXI_RDATA(31 downto 16) <= (others => '0');
    rvalid <= not rdfifo_empty;
    S_AXI_RVALID <= rvalid;
    
    rdfifo_wr_en_node <= '1' when rdt_cs=rd_burst and rdfifo_almost_full='0' and rd_cdc_count/=0 else '0';
    -- BlockRAMのReadは1クロック遅延するため、1クロック遅延させる。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                rdfifo_wr_en <= '0';
            else
                rdfifo_wr_en <= rdfifo_wr_en_node;
            end if;
        end if;
    end process;
        
    rdfifo_rd_en <= '1' when rdt_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' else '0';
    
    -- rd_cdc_count の処理(CDC側のデータカウント)
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                rd_cdc_count <= (others => '0');
            else
                if rdt_cs=arr_accept then -- ロード
                    rd_cdc_count <= ('0'& S_AXI_ARLEN) + 1;
                elsif rdt_cs=rd_burst and rdfifo_almost_full='0' and rd_cdc_count/=0 then -- FIFOに余裕がある
                    rd_cdc_count <= rd_cdc_count - 1;
                end if;
            end if;
        end if;
    end process;
                    
    -- rd_axi_count の処理(AXIバス側のデータカウント)
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                rd_axi_count <= (others => '0');
            else
                if rdt_cs=arr_accept then -- rd_axi_count のロード
                    rd_axi_count <= S_AXI_ARLEN;
                elsif rdt_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction が1つ終了
                    rd_axi_count <= rd_axi_count - 1;
                end if;
            end if;
        end if;
    end process;
    
    -- rdlast State Machine
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                rdlast <= idle_rlast;
                rlast <= '0';
            else
                case (rdlast) is
                    when idle_rlast =>
                        if rd_axi_count=1 and rvalid='1' and S_AXI_RREADY='1' then -- バーストする場合
                            rdlast <= rlast_assert;
                            rlast <= '1';
                        elsif rdt_cs=arr_accept and S_AXI_ARLEN=0 then -- 転送数が1の場合
                            rdlast <= rlast_assert;
                            rlast <= '1';
                        end if;
                    when rlast_assert => 
                        if rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了(rd_axi_count=0は決定)
                            rdlast <= idle_rlast;
                            rlast <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    S_AXI_RLAST <= rlast;
    
    -- S_AXI_RID, S_AXI_RUSER の処理
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                S_AXI_RID <= (others => '0');
            else
                if rdt_cs=arr_accept then
                    S_AXI_RID <= S_AXI_ARID;
                end if;
            end if;
        end if;
    end process;
    S_AXI_RUSER <= (others => '0');
    
    -- S_AXI_RRESP は、S_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
    process (ACLK) begin
        if ACLK'event and ACLK='1' then 
            if reset_axi='1' then
                S_AXI_RRESP <= (others => '0');
            else
                if rdt_cs=arr_accept then
                    if S_AXI_ARBURST=AxBURST_INCR then
                        S_AXI_RRESP <= RESP_OKAY;
                    else
                        S_AXI_RRESP <= RESP_SLVERR;
                    end if;
                end if;
            end if;
        end if;
    end process;
    
    
    -- CharDispCtrler
    cdc_addr <= wr_addr when rdt_cs=idle_rd or rdt_cs=arr_wait else rd_addr;
    
    CDC_inst : CharDispCtrler generic map(
        RESOLUTION        => RESOLUTION
    ) port map (
        axi4clk         => ACLK,
        pixclk            => pixclk,
        reset_axi        => reset_axi,
        reset_pix        => reset_pix,
        processor_addr    => cdc_addr,
        processor_din    => S_AXI_WDATA(15 downto 0),
        processor_dout    => rdfifo_din,
        processor_we    => cdc_we,
        VGA_RED            => vga_red,
        VGA_GREEN        => vga_green,
        VGA_BLUE        => vga_blue,
        VGA_HSYNC        => vga_hsync,
        VGA_VSYNC        => vga_vsync,
        display_enable    => display_enable
    );
    
    vga_red8    <= vga_red & "00000";
    vga_green8    <= vga_green & "00000";
    vga_blue8     <= vga_blue & "00000";

    -- VGA Signals
    process( pixclk ) begin
        if pixclk'event and pixclk='1' then
            if reset_pix = '1' then
                red_out        <= (others => '0');
                green_out    <= (others => '0');
                blue_out        <= (others => '0');
                hsync_n        <= '1';
                vsync_n        <= '1';
            else
                red_out        <= vga_red8(7 downto 3);
                green_out    <= vga_green8(7 downto 2);
                blue_out        <= vga_blue8(7 downto 3);
                hsync_n        <= vga_hsync;
                vsync_n        <= vga_vsync;
            end if;
        end if;
    end process ;

end implementation;


VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ11(Verilog HDLソース1)”に続く。
  1. 2014年06月29日 04:53 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado 2014.2 で IP の更新のやり方を試してみた

Vivado 2014.2 を使用して、Vivado プロジェクトで、IP Integrator(ブロック・デザイン)を使用している時に、IPを修正する方法を試してみた。

IPのパラメータ、たぶん外部ポートもだが、を修正する時は、ブロック・デザイン上でIPを削除し、IPのプロジェクトで、IP-XACT のcomponent.xml を削除してから、再度IPをパッケージ化する必要があるのは、”VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ6(ブロック・デザインのデバック)”に書いた。更に、IPをパッケージ化する時のIP のアドレスも、たぶん、IP-XACT のcomponent.xml を削除する必要があった。
さて、IPのHDLを変更する場合は、IPを右クリックして、右クリックメニューから Edit in IP Packager を選択して、IP Packager を立ちあげて、HDLを変更して再パケージすれば、HDLの変更がブロック・デザインのプロジェクトに反映されるのかをテストした。

テスト用プロジェクトとしては、”VivadoでZYBO用LEDテストプロジェクト3(SDK、実機テスト)”で書いた Vivado 2013.4 の ZYBO用LEDテストプロジェクトを、Vivado 2014.2 にアップグレードして使用する。このプロジェクトは、GitHubの”marsee101/Vivado_ZYBO_LED_test2”に上げてある。
このプロジェクトを Vivado 2014.2 に変換して、IPをアップグレードするときは、AXIインターコネクトがロックされしまった。結局何をやってもダメなので、一旦削除して新たにインスタンスした。更に、注意点としては、Windows の260文字パス制限にすぐ引っかかってしまうので、とにかく浅いパスのフォルダに置くことだ。
下に、Vivado 2014.2 に変換したZYBO用LEDテストプロジェクトを下に示す。
Vivado_2014_2_1_140628.png

・led4_axi_lite_slave_0 を右クリックして、右クリックメニューから、Edit in IP Packager を選択する。
Vivado_2014_2_2_140628.png

・Edit in IP Packager ダイアログが表示された。デフォルト値のまま、OKボタンをクリックした。
Vivado_2014_2_3_140628.png

・led4_axi_lite_slave_v1_0_project が開いて、Package IP 画面が表示された。
Vivado_2014_2_4_140628.png

・IP File Groups をクリックして、led4_axi_lite_slave.v を表示させた。
Vivado_2014_2_5_140628.png

・led4_axi_lite_slave.v を右クリックして、右クリックメニューから Open Files を選択して、表示させた。
Vivado_2014_2_6_140628.png

ここで、上の図で選択されている部分を


LED_Display_Counter <= LED_Display_Counter + 4'd1;

から、


LED_Display_Counter <= LED_Display_Counter - 4'd1;

に変更した。
なお、リセットの部分を


LED_Display_Counter <= 4'd0;


LED_Display_Counter <= 4'd3;

に変更したが、LEDの表示は3 にはならなかった。ARESETNが 0 になることはないのか?ハードウェアをコンフィギュレーションしたあとで。。。

・Review and Package 画面で、Re-Package IP ボタンをクリックした。
Vivado_2014_2_7_140628.png

・IP Status 画面を見ると、/led4_axi_lite_slave_0 に更新マーク?が付いている。Rerun をクリックする。
Vivado_2014_2_8_140628.png

・Address Editor タブで、led4_axi_lite_slave_0 のアドレスのRange を 4G から 64K に設定を変更しておく。

・Flow Navigator の Program and Debug -> Generate Bitstream をクリックして、インプリメントとビットストリームの生成を行う。

・Synthesis is Out-of-date ダイアログが表示された。Yesボタンをクリックした。

・ビットストリームの生成まで正常に終了した。Open Implemented Design ラジオボタンをクリックして、OKボタンをクリックした。

・ビットストリームの生成まで終了した。
Vivado_2014_2_9_140628.png

ここからが Vivado 2014.1 とちょっと違っている。Launch SDK が別にあった。

・File メニューから Export -> Export Hardware を選択した。
Vivado_2014_2_10_140628.png

・Export Hardware ダイアログが表示された。OKボタンをクリックした。
Vivado_2014_2_11_140628.png

・File メニューから Launch SDK を選択した。
Vivado_2014_2_12_140628.png

・Launch SDK が表示された。OKボタンをクリックした。
Vivado_2014_2_13_140628.png

・SDKが開いた。
Vivado_2014_2_14_140628.png

後の手順は、”VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ9(SDK、実機テスト)”と同様だ。(省略)

ソフトウェアを起動して、動作させたところ、LEDは加算ではなく、減算を行った。うまく行った。これで、この手順で、IPのHDLを変更できることがわかった。
  1. 2014年06月28日 06:44 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:2

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ9(SDK、実機テスト)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ8(インプリメント)”の続き。

前回はインプリメント、ビットストリームの生成を行って成功した。今回はハードウェア情報をSDKにエクスポートして、ソフトウェアを作製し、ZYBOでキャラクタが表示されるか?テストを行う。

・Implemented Design を開いたまま、File メニューから Export -> Export Hardware for SDK... を選択する。
Vivado_ZYBO_CDC_axi_slave_175_140624.png

・ Export Hardware for SDKダイアログが表示された。Include bitstream のところがHideされていないが、これはISE同様に、Implemented Designを開いているからかもしれない? 

・Launch SDK にチェックを入れて、SDKを起動するように設定する。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_176_140624.png

・SDKが起動した。hw_platform_0 ができていた。system.xml には、自分IPの cdc_vga_axi_slave_0 が入っているのがわかる。
Vivado_ZYBO_CDC_axi_slave_177_140624.png

・Cプロジェクトを作製する。

・File メニューから New -> Application Project を選択する。
Vivado_ZYBO_CDC_axi_slave_178_140626.png

・New Project ダイアログが表示された。Project Name に cdc_test と入力して、Next > ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_179_140626.png

・Template では、Empty Application を選択する。Finish ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_180_140626.png

・Project Explorer 上に、cdc_test, cd_test_bsp プロジェクトができている。
Vivado_ZYBO_CDC_axi_slave_181_140626.png

・Cソース・ファイルを生成する。cdc_test -> src フォルダを右クリックして、右クリックメニューから New -> Source File を選択する。
Vivado_ZYBO_CDC_axi_slave_182_140626.png

・New Source File ダイアログが表示された。Source file に cdc_test.c と入力して、Finish ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_183_140626.png

・cdc_test.c が表示された。ファイルの内容は、ISEの時のファイルをそのままコピペしてある。
Vivado_ZYBO_CDC_axi_slave_184_140626.png

・cdc_test_bsp がビルド・エラーなので、ProjectメニューからClean... を選択した。
Vivado_ZYBO_CDC_axi_slave_185_140626.png

・Clean all projects のラジオボタンがクリックされているのを確認して、OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_186_140626.png

・cdc_test.c もエラーが発生していた。XPAR_CDC_VGA_AXI_SLAVE_0_S_AXI_RNG00_BASEADDR が無いというエラーだった。
Vivado_ZYBO_CDC_axi_slave_187_140626.png

・xparameters.h を見ると、XPAR_CDC_VGA_AXI_SLAVE_0_S_BASEADDR に変更になっていた。
Vivado_ZYBO_CDC_axi_slave_188_140626.png

・cdc_test.c の XPAR_CDC_VGA_AXI_SLAVE_0_S_AXI_RNG00_BASEADDR を XPAR_CDC_VGA_AXI_SLAVE_0_S_BASEADDR に変更した。
Vivado_ZYBO_CDC_axi_slave_189_140626.png

・ZYBOをJTAG モードにして、電源をONする。

・SDKのXilinx Tools メニューから Program FPGA を選択し、Zynqをコンフィギュレーションする。
Vivado_ZYBO_CDC_axi_slave_190_140626.png

・ Program FPGA ダイアログが表示された。Program ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_191_140626.png

・Zynqのコンフィギュレーションが開始され、終了した。
Vivado_ZYBO_CDC_axi_slave_192_140626.png

・Zynqのコンフィギュレーション後のSDK
Vivado_ZYBO_CDC_axi_slave_193_140626.png

・ソフトウェアを起動する前に Run Configuration を作製する。

・cdc_test プロジェクトを右クリックして、右クリックメニューから、Run As -> Run Configurations... を選択する。
Vivado_ZYBO_CDC_axi_slave_194_140626.png

・Run Configurations ダイアログが表示された。Xilinx C/C++ application (GDB) を右クリックして、右クリックメニューからNew を選択する。
Vivado_ZYBO_CDC_axi_slave_195_140626.png

・cdc_teste Debug ができた。デフォルトのまま、Run ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_196_140626.png

・ソフトウェアが起動して、キャラクタがVGAポートに表示された。その時のSDKを示す。
Vivado_ZYBO_CDC_axi_slave_197_140626.png

・表示されたキャラクタを下に示す。解像度はHD (1920 x 1080ピクセル、148.5MHz)だ。
Vivado_ZYBO_CDC_axi_slave_198_140627.jpg

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ10(VHDLソース)”に続く。
  1. 2014年06月27日 05:06 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ8(インプリメント)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ7(配置制約の生成)”の続き。

前回は配置制約を生成した。次は、いよいよインプリメントを行う。

・Flow Navigator の Program and Debug -> Generate Bitstream をクリックして、インプリメントとビットストリームの生成を行う。
Vivado_ZYBO_CDC_axi_slave_169_140624.png

・Synthesis is Out-of-date ダイアログが表示された。Yesボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_170_140624.png

・ビットストリームの生成まで正常に終了した。Open Implemented Design ラジオボタンをクリックして、OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_171_140624.png

・Implemented Design が表示された。
Vivado_ZYBO_CDC_axi_slave_172_140624.png

結構、ロジックセルが分散しないで、まとまって配置されている。

比較するために、ISEで作ったZYBO用キャラクタ・ディスプレイ・コントローラのPlanAhead のデザインを下に示す。
Vivado_ZYBO_CDC_axi_slave_173_140624.png

こちらはロジックセルが、Vivado で生成したものに比べて散らばっているのがわかる。

・FF や LUT の使用率は 1% だった。
Vivado_ZYBO_CDC_axi_slave_174_140624.png

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ9(SDK、実機テスト)”の続く。
  1. 2014年06月26日 04:30 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ7(配置制約の生成)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ6(ブロック・デザインのデバック)”の続き。

前回、ブロック・デザインが終了して、ラッパー Verilog HDLファイルを作製した。今回は、論理合成し、出力端子の出力レベルと配置を制約して、インプリメント、ビットストリームの生成までを行う。

・Flow Navigaotr の Synthesis -> Run Synthesis をクリックして、論理合成を行う。
Vivado_ZYBO_CDC_axi_slave_159_140624.png

・論理合成が問題なく終了し、Synthesis Completed ダイアログが表示された。Open Synthesized Design のラジオボタンをクリックして、OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_160_140624.png

・Synthesized Design が開いた。ここで、出力端子の出力レベルと配置の制約を行う。
Vivado_ZYBO_CDC_axi_slave_161_140624.png

・Layout メニューから I/O Planning を選択した。
Vivado_ZYBO_CDC_axi_slave_162_140624.png

・I/Oの制約画面が開いた。ここで、blue_out, green_out, red_out, 同期信号の制約を行う。
Vivado_ZYBO_CDC_axi_slave_163_140624.png

・I/O Std に LVCOMS33 を設定して、Site にピン配置を指定した。
Vivado_ZYBO_CDC_axi_slave_164_140624.png

・全部の配置制約を入れたので、Save Constraionts アイコンをクリックして、セーブした。
Vivado_ZYBO_CDC_axi_slave_165_140624.png

・論理合成が古くなったという表示が出た。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_166_140624.png

・Save Constraints ダイアログが表示された。File type にXDCが指定されていた。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_167_140624.png

・cdc_vga141.xdc が生成された。
Vivado_ZYBO_CDC_axi_slave_168_140624.png

下に生成された cdc_vga141.xdc を示す。

set_property IOSTANDARD LVCMOS33 [get_ports {blue_out[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {blue_out[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {blue_out[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {blue_out[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {blue_out[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {green_out[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {green_out[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {green_out[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {green_out[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {green_out[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {green_out[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {red_out[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {red_out[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {red_out[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {red_out[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {red_out[0]}]
set_property PACKAGE_PIN G19 [get_ports {blue_out[4]}]
set_property PACKAGE_PIN J18 [get_ports {blue_out[3]}]
set_property PACKAGE_PIN K19 [get_ports {blue_out[2]}]
set_property PACKAGE_PIN M20 [get_ports {blue_out[1]}]
set_property PACKAGE_PIN P20 [get_ports {blue_out[0]}]
set_property PACKAGE_PIN F20 [get_ports {green_out[5]}]
set_property PACKAGE_PIN H20 [get_ports {green_out[4]}]
set_property PACKAGE_PIN J19 [get_ports {green_out[3]}]
set_property PACKAGE_PIN L19 [get_ports {green_out[2]}]
set_property PACKAGE_PIN N20 [get_ports {green_out[1]}]
set_property PACKAGE_PIN H18 [get_ports {green_out[0]}]
set_property PACKAGE_PIN F19 [get_ports {red_out[4]}]
set_property PACKAGE_PIN G20 [get_ports {red_out[3]}]
set_property PACKAGE_PIN J20 [get_ports {red_out[2]}]
set_property PACKAGE_PIN L20 [get_ports {red_out[1]}]
set_property PACKAGE_PIN M19 [get_ports {red_out[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports hsync_n]
set_property IOSTANDARD LVCMOS33 [get_ports vsync_n]
set_property PACKAGE_PIN P19 [get_ports hsync_n]
set_property PACKAGE_PIN R19 [get_ports vsync_n]


VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ8(インプリメント)”に続く。
  1. 2014年06月25日 04:49 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ6(ブロック・デザインのデバック)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ5(ブロック・デザインの生成)”の続き。

ブロック・デザインの生成でエラーがでているので、デバックをしていた。日曜日の1日中いろいろなことを試したが、やっとわかってきたと思うので、ブログに書いておく。
因みに、プロジェクト名を短くしないとWinodwsのパス名260文字問題に引っかかってしまうので、プロジェクトを作りなおした。

まずは、cdc_vga_axi_slave IP の構成だが、トップファイルは、cdc_vga_axi_slave.vhd だ。ポート宣言部分の一部分を示す。

library ieee;
use ieee.std_logic_1164.all;

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

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

use work.video_timing_pkg.all;

entity cdc_vga_axi_slave is
  generic (
    C_S_AXI_ID_WIDTH     : integer := 1;
    C_S_AXI_ADDR_WIDTH   : integer := 32;
    C_S_AXI_DATA_WIDTH   : integer := 32;
    C_S_AXI_AWUSER_WIDTH : integer := 1;
    C_S_AXI_ARUSER_WIDTH : integer := 1;
    C_S_AXI_WUSER_WIDTH  : integer := 1;
    C_S_AXI_RUSER_WIDTH  : integer := 1;
    C_S_AXI_BUSER_WIDTH  : integer := 1;

    RESOLUTION : RESLUTION_TYPE := 1    -- SVGA
  );
  port(
    -- System Signals
    ACLK    : in std_logic;
    ARESETN : in std_logic;

    -- Slave Interface Write Address Ports
    S_AXI_AWID     : in  std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
    S_AXI_AWADDR   : in  std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);


generic で宣言された RESLUTION の型は、RESLUTION_TYPE だが、これは、video_timing_pkg.vhd の最初で宣言されている。


subtype RESLUTION_TYPE is integer range 0 to 4;


これで、単体シミュレーションもXPSでのIP化もOKだった。

Vivado のIP Integrator でのIP化は自動的に行われて、IP Packager の IP Customization Parameters 画面では、RESOLUTION は、long 型になっている。
Vivado_ZYBO_CDC_axi_slave_55_140610.png

しかし、IP-XACT の component.xml 上では、subtype で定義された RESLUTION_TYPE 型になっていて、これでエラーが出ていたようだ。

      <spirit:modelParameter spirit:dataType="RESLUTION_TYPE">
        <spirit:name>RESOLUTION</spirit:name>
        <spirit:displayName>Resolution</spirit:displayName>
        <spirit:value spirit:format="long" spirit:resolve="generated" spirit:id="MODELPARAM_VALUE.RESOLUTION">1</spirit:value>
      </spirit:modelParameter>


つまり、Vivado でIP化する場合は、トップのHDLファイルに subtype で宣言した型を使うとまずいということのようだ。

対策としては、cdc_vga_axi_slave.vhd の generic における RESOLUTION の宣言の型を RESLUTION_TYPE から integer に変更した。

cdc_vga_axi_slave IP の修正手順を下に書いておく。

・まずは、ブロック・デザインで、cdc_vga_axi_slave IPを削除する。

・IP Catalog で右クリックして、右クリックメニューから IP settings... を選択する。
Vivado_ZYBO_CDC_axi_slave_88_140614.png

・IP ダイアログで、IP Repositories の所で、cdc_vga_axi_slave IPを選択された状態で、 X ボタンをクリックして削除する。
Vivado_ZYBO_CDC_axi_slave_91_140614.png

・cdc_vga_axi_slave IP のプロジェクトを立上て、cdc_vga_axi_slave.vhd の generic における RESOLUTION の宣言の型を RESLUTION_TYPE から integer に変更した。
Vivado_ZYBO_CDC_axi_slave_145_140624.png

・Sourcesウインドウで、IP-XACT の下の component.xml を削除した。
Vivado_ZYBO_CDC_axi_slave_146_140624.png

・Tools メニューから、Create and Package IP を選択して、もう一度、IP化を行う。

・Re-Package IP を行う。
Vivado_ZYBO_CDC_axi_slave_147_140624.png

・Re-Package IP 後の component.xml は、RESOLUTION の dateType が integer に変更されていた。

      <spirit:modelParameter spirit:dataType="integer">
        <spirit:name>RESOLUTION</spirit:name>
        <spirit:displayName>Resolution</spirit:displayName>
        <spirit:value spirit:format="long" spirit:resolve="generated" spirit:id="MODELPARAM_VALUE.RESOLUTION">1</spirit:value>
      </spirit:modelParameter>

これでOK。

・これでもう一度、ブロック・デザインのVivado プロジェクトに行って、IP Repositories に cdc_vga_axi_slave IPを追加して、プロック・デザインに cdc_vga_axi_slave IPを再度インスタンスした。

・Generate Block Design を実行したら、エラー無しで終了した。
Vivado_ZYBO_CDC_axi_slave_148_140624.png

アドレス範囲の critical warning があるので修正を試みる。

・最初に、Tools メニューから、Report -> Report IP Status を選択して、IP Status ウインドウを下に出しておく。
Vivado_ZYBO_CDC_axi_slave_153_140624.png

・下にIP Status 画面は出るはずだが、順番を間違ってしまったので出ていない。cdc_vga_axi_slave_0 を右クリックして、右クリックメニューから、Edit in IP Packager を選択する。
Vivado_ZYBO_CDC_axi_slave_149_140624.png

・Edit in IP Packager ダイアログが表示された。デフォルト値のまま、OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_150_140624.png

・cdc_vga_axi_slave_v1_0_project が開いて、Package IP 画面が表示された。

・IP Addressing and Memory 画面で、reg0 のRange Dependency を pow(2,17)に変更した。前はRange は4G だったが、131072 に変更された。
Vivado_ZYBO_CDC_axi_slave_151_140624.png

・Review and Package 画面で、Re-Package IP ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_152_140624.png

・すると、cdc_vga_axi_slave_v1_0_project は自動的にクローズされて、元のプロジェクトに戻る。

・IP Status 画面を見ると、/cdc_vga_axi_slave_0 に更新マーク?が付いている。Rerun をクリックする。
Vivado_ZYBO_CDC_axi_slave_154_140624.png

・Address Editor タブで、cdc_vga_axi_slave_0 のアドレスのRange を 4G から 128K に設定を変更しておく。
Vivado_ZYBO_CDC_axi_slave_155_140624.png

・これで、もう一度、Generate Block Design をしてみたが、やはり、Range が 4G とう critical warning が出ている。
Vivado_ZYBO_CDC_axi_slave_156_140624.png

・やはり、Package IPでパッケージ化された情報は、component.xml に書かれて編集が出来ないのかもしれない(未確認)。もう一度、IPを作り直すのが面倒なので、とりあえず、これで論理合成などをやってみることにした。

・ブロック・デザインの CDC_VGA を右クリックして、右クリックメニューから Create HDL Wapper... を選択する。
Vivado_ZYBO_CDC_axi_slave_157_140624.png

・Create HDL Wapper ダイアログが表示された。そのまま、OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_158_140624.png

・CDC_VGA_wapper.v が生成された。

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ7(配置制約の生成)”に続く。
  1. 2014年06月24日 04:54 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ5(ブロック・デザインの生成)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ4(PS以外のブロックデザイン)”の続き。

前回は、PS以外のIPをインスタンスして、ブロック・デザインを完成させた。今回は、ブロック・デザインのバリデーションから行う。

・Validate Design アイコンをクリックして、デザインのバリデーションを行った。
Vivado_ZYBO_CDC_axi_slave_140_140621.png

・エラー発生。ID_WIDTHが合わないそうだ。
Vivado_ZYBO_CDC_axi_slave_131_140617.png

・Messages ウインドウの /processing_system7_0_axi_periph/s00_couplers/auto_pc/M_AXI(12) をクリックした。
Vivado_ZYBO_CDC_axi_slave_132_140617.png

・エラーの部分が表示された。AXIインターコネクトの3つ下のモジュールのID_WIDTHが12だったが、その上のAXIインターコネクトのモジュールと、一番上のAXIインターコネクトのID_WIDTHは1だった。これでなぜエラーが出るのかな?
AXIインターコネクトの外に出ているID_WIDTHは1 なんだけど。。。
Vivado_ZYBO_CDC_axi_slave_133_140617.png

・なんか矛盾している気がするが、仕方が無いので、cdc_vga_axi_slave_v1_0 をダブルクリックして、C S Axi ID Width を 12 に変更した。
Vivado_ZYBO_CDC_axi_slave_134_140617.png

・これでもう一度、Validate Design アイコンをクリックして、デザインのバリデーションを行ったら、通りました。
Vivado_ZYBO_CDC_axi_slave_135_140617.png

・Save Block Design アイコンをクリックして、ブロック・デザインをセーブします。
Vivado_ZYBO_CDC_axi_slave_136_140617.png

・Generate Block Design をクリックして、ブロック・デザインを生成する。
Vivado_ZYBO_CDC_axi_slave_137_140621.png

・Generate Output Products ダイアログが表示された。Generate ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_138_140621.png

・エラーが出てしまった。VHDL関連のエラーだ。
Vivado_ZYBO_CDC_axi_slave_139_140621.png

・Messages ウインドウで、エラーを右クリックして、右クリックメニューから、Search for Answer Record を選択した。
Vivado_ZYBO_CDC_axi_slave_141_140621.png

・アンサー・レコードが表示された。1つしかエントリーが無かったので、クリックすると、”AR# 58038 Vivado IP パッケージャー - REAL タイプのジェネリック SIGNED タイプに変換され「ERROR: [IP_Flow 19-3285] Failed to convert float value 'x.xx' to HDL value.」というエラー メッセージが表示される”が表示された。

そうか、Vivado では、math_real パッケージが使えないのか? これはショックだ。あまり VHDL は使われることを想定していないのだろうか? Verilog で書いたほうが良いのだろうか? System Verilog は、Vivado Simulatorがサポートしていない。。。

仕方がないので、
VHDLコードを修正することにする。

(追記)よく見たら、RESLUTIONがおかしいように書いてありますね。最初にエラーが出た時は、real がエラーと書いてあったので、勘違いしました。階層も深すぎるようです。

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ6(ブロック・デザインのデバック)”に続く。
  1. 2014年06月21日 05:44 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ4(PS以外のブロックデザイン)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ3(PSのインポートと設定)”の続き。

・Diagram ウインドウのの空いている所で、右クリックし、右クリックメニューから Add IP... を選択する。
Vivado_ZYBO_CDC_axi_slave_108_140617.png

・Search テキストボックスに cdc と入れると、cdc_vga_axi_slave_v1_0 のIPが検索できた。ENTERキーを押した。
Vivado_ZYBO_CDC_axi_slave_109_140617.png

・cdc_vga_axi_slave_0 がインスタンスされた。
Vivado_ZYBO_CDC_axi_slave_110_140617.png

・cdc_vga_axi_slave_0 をダブルクリックして設定を行う。Resolution を HD 解像度の 4 に設定する。SVGA - 1, XGA - 2, SXGA - 3, HD - 4
Vivado_ZYBO_CDC_axi_slave_111_1_140621.png

・Run Connection Automation をクリックした。

・/cdc_vga_axi_slave_0/S_AXI の選択肢が出てくるので、選択した。
Vivado_ZYBO_CDC_axi_slave_111_140617.png

・Run Connection Automation ダイアログが表示された。Clock Connection で /processing_system7_0/FCLK_CLK0 (100MHz) を選択した。
Vivado_ZYBO_CDC_axi_slave_112_140617.png

・この状態で、OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_113_140617.png

・AXIインターコネクト(processing_system7_0_axi_periph) と Processor System Reset (rst_processing_system7_0_100M) がインスタンスされて、自動配線された。
Vivado_ZYBO_CDC_axi_slave_114_140617.png

・Diagram ウインドウのの空いている所で、右クリックし、右クリックメニューから Add IP... を選択する。

・Clocking Wizard を選択肢て、ENTER キーを押した。
Vivado_ZYBO_CDC_axi_slave_115_140617.png

・Clocking Wizard (clk_wiz_0) がインスタンスされた。

・Run Connection Automation をクリックし、/clk_wiz_0/clk_in1 を選択した。
Vivado_ZYBO_CDC_axi_slave_116_140617.png

・Run Connection Automation ダイアログが表示された。しかし、External につながるようなので、Cancel ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_117_140617.png

・clk_wiz_0 をダブルクリックした。設定を行う。

・Clocking Options タブは Primitive が MMCM になっている。ここはそのまま。
Vivado_ZYBO_CDC_axi_slave_118_1_140617.png

・Output CLocks タブで、clk_out1 にチェックを入れて、Output Freq (MHz)を 148.5 に設定した。
Vivado_ZYBO_CDC_axi_slave_118_2_140617.png

・MMCM Settings タブはこのまま。
Vivado_ZYBO_CDC_axi_slave_118_3_140617.png

・Port Renaming タブもこのまま。
Vivado_ZYBO_CDC_axi_slave_118_4_140617.png

・Summary タブが表示された。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_118_5_140617.png
これで、clk_wiz_0 の設定は終了した。

・clk_wiz_0 の clk_in1 を processing_system7_0/FCLK_CLK0 に接続する。
Vivado_ZYBO_CDC_axi_slave_118_140617.png

・clk_wiz_0 の clk_in1 が processing_system7_0/FCLK_CLK0 に接続された。
Vivado_ZYBO_CDC_axi_slave_119_140617.png

・clk_wiz_0 の reset を rst_pcocessing_system7_0_100M の peripheral_reset に接続する。
Vivado_ZYBO_CDC_axi_slave_120_140617.png

・clk_wiz_0 の reset が rst_pcocessing_system7_0_100M の peripheral_reset に接続された。
Vivado_ZYBO_CDC_axi_slave_121_140617.png

・clk_wiz_0 の clk_out1 から、cdc_vga_axi_slave_0 の pixclk に接続した。
Vivado_ZYBO_CDC_axi_slave_122_140617.png

clk_wiz_0 の locked から、cdc_vga_axi_slave_0 の reset_pixclk に接続したいが、論理が反対なので、インバータを挿入する。

・右クリックメニューから Add IP... を選択肢て、Utility Vector Logic を選択した。
Vivado_ZYBO_CDC_axi_slave_123_140617.png

・util_vector_logic_0 がインスタンスされた。ダブルクリックして設定を行う。
Vivado_ZYBO_CDC_axi_slave_124_140617.png

・ダイアログで、C Size を 1 に設定し、C Operation のラジオボタンを not にした。
Vivado_ZYBO_CDC_axi_slave_125_140617.png

・clk_wiz_0/locked から util_vector_logic_0/Op1 に配線した。
・util_vector_logic_0/Res から cdc_vga_axi_slave_0/reset_pixclk に配線した。つまり、クロック・ジェネレーターのLocked信号を反転して、 cdc_vga_axi_slave_0のpixclkのリセットにした。
Vivado_ZYBO_CDC_axi_slave_126_140617.png

cdc_vga_axi_slave_0 の外部出力端子を配線する。

・read_out[4:0] を選択して、右クリックし、右クリックメニューから Make External を選択する。
Vivado_ZYBO_CDC_axi_slave_127_140617.png

・read_out[4:0] が外部出力端子として出力された。
Vivado_ZYBO_CDC_axi_slave_128_140617.png

・同様に、cdc_vga_axi_slave_0 の外部出力端子をすべて設定した。
Vivado_ZYBO_CDC_axi_slave_129_140617.png

・Regenerate layout アイコンをクリックして、レイアウトを再生成した。
Vivado_ZYBO_CDC_axi_slave_130_1_140617.png

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ5(ブロック・デザインの生成)”へ続く。
  1. 2014年06月20日 04:25 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Parallella-16でUbuntuを動作させる

Parallella-16ボードでUbuntuを動作させてみました。

まずは、”Parallella Quick Start Guide”を見て接続をチェックします。

次に、”Creating a Parallella SD card”を見て、”Ubuntu 14.04 for Parallella (June 11th release, 2.2GB)”と”Parallella Linux kernel with HDMI support”と Parallella FPGA “flavours” の”Zynq 7010 version with HDMI display”をダウンロードしました。
Parallella_6_140618.png

gunzip -d ubuntu-14.04-140611.img.gz
コマンドを実行して、Ubuntuのイメージを解凍したら、my_backup.img が解凍できました。
Parallella_7_140618.png

sudo fdisk -l | grep Disk
コマンドでSDカードがどのデバイスに割あたっているかを確認しました。下に実行結果を示します。SDカードは /dev/sdc に割り当てられていました。

masaaki@masaaki-VirtualBox:~/Parallella$ sudo fdisk -l | grep Disk
Disk /dev/sda: 214.7 GB, 214748364800 bytes
Disk /dev/sdc: 15.9 GB, 15931539456 bytes


sudo dd bs=64k if=my_backup.img of=/dev/sdc
コマンドで、Ubuntu14.04のイメージをSDカードに書きました。書き終わると、FAT32フォーマットのBOOT ドライブとEXT4フォーマットの rootfs ドライブが出来ます。下に rootfs ドライブを示します。
Parallella_5_140618.png

tar -zxvf kernel-hdmi-default.tgz -C /media/masaaki/BOOT
コマンドで、カーネルイメージ (uImage) とデバイス・ツリー (devicetree.dtb) を BOOT ドライブに書きます。

cp parallella_e16_hdmi_gpiose_7010.bit.bin /media/masaaki/BOOT/parallella.bit.bin
コマンドで、PL部のビットストリームを BOOT ドライブに書き込みます。
これでSDカードの作製は終了です。BOOTドライブを下に示します。
Parallella_4_140618.png

Parallella-16 にケーブルを接続します。
Parallella_8_140618.jpg

Ubuntuが起動しました。Unity じゃなくて LXDE かな?
Parallella_9_140618.jpg

top コマンドを実行してみましたが、本当に SDRAM が 1GB あるんですね。それに、メモリの占有率が Unity の ZYBO や ZedBoard と比べると小さいです。LXDE にしたいですね。。。
Parallella_10_140618.jpg

しかし、Parallella-16 ボードは電源を入れると基板ごと、あっちっちです。これは基板全体をFANで風を当ててクーリングしないとチップが死にますね。。。簡易放射温度計で測ると Zynq の基板の裏側で 65度、Epiphanyの基板の裏側で 62度でした。危ないですね。。。
Parallellalfan さんに教えて頂いたんですが、皆さん、FANをつけているそうです。”Show your Parallella!!”参照。

私も、共立エレショップで5V の3cmファンをガード込みで購入しました。ケースを作る必要がありそうですね。
  1. 2014年06月19日 04:46 |
  2. Parallella-16
  3. | トラックバック:0
  4. | コメント:2

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ3(PSのインポートと設定)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ2(IPリポジトリへの追加)”の続き。

・左の Flow Navigator -> Project Manager -> Create Block Design をクリックする。
Vivado_ZYBO_CDC_axi_slave_93_140614.png

・Create Block Design ダイアログが出る。Vivado_ZYBO_CDC_VGA と入力して、OKボタンをクリックする。
Vivado_ZYBO_CDC_axi_slave_94_140614.png

・Diagramウインドウが開く。

・Add IPをクリックして、IPコアをインポートする。
Vivado_ZYBO_CDC_axi_slave_95_140614.png

・IPのカタログが出てくるので、ZYNQ 7 Processing System をダブルクリックする。
Vivado_ZYBO_CDC_axi_slave_96_140614.png

・ZYNQがインポートされた。
Vivado_ZYBO_CDC_axi_slave_97_140614.png

・Run Block Automation をクリックすると、processing_system_0 の選択肢が出てくるので選択した。
Vivado_ZYBO_CDC_axi_slave_98_140614.png

・Run Block Automation ダイアログが開いた。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_99_140614.png

・ポートが増えて、DDRとFIXED_IOの外部ポートが追加された。
Vivado_ZYBO_CDC_axi_slave_100_140614.png

・ZYNQ 7 Processing System を右クリックし、右クリックメニューから Customize Block... を選択し、ZYBOのMIOなどの設定を行う。
Vivado_ZYBO_CDC_axi_slave_101_140614.png

・ZYNQ7 Processing System (5.4) のRe-customize IP ダイアログが表示された。
ここでZYBOのWebサイトからダウンロードしたZYBOの設定ファイル (ZYBO_zynq_def.xml)を読み込む。Digilent社のZYBOサイトの”ZYBO Board Definition File for configuring the Zynq Processing System core in Xilinx Platform Studio and Vivado IP Integrator”のZIPの中に入っている。

・Import XPS Settingsをクリックする。
Vivado_ZYBO_CDC_axi_slave_102_140614.png

・ZYBO_zynq_def.xmlを指定して、OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_103_140614.png

・ZYBOのMIOの情報などが設定された。
Vivado_ZYBO_CDC_axi_slave_104_140614.png

・Page Navigatgor から、Clock Configuration をクリックし、PL Fabric Clocks を展開し、FCLK_CLK0を100MHzに設定する。
Vivado_ZYBO_CDC_axi_slave_107_140616.png

・これで、ZYNQ7 Processing System (5.4) の設定は終了した。OKボタンをクリックしてダイアログを閉じた。
Vivado_ZYBO_CDC_axi_slave_107_140616.png

・processing_system7_0 のポートが増えた。
Vivado_ZYBO_CDC_axi_slave_106_140614.png

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ4(PS以外のブロックデザイン)”に続く。
  1. 2014年06月16日 04:34 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Parallella-16 ボードが届きました

Parallella-16 ボードを購入”を 2013/07/24 に書いてから、約11ヶ月後にParallella-16 ボードが届きました。
嬉しいです。

大きさがとっても小さいですね。。。ZYBOと並べてみました。
Parallella_1_140615.jpg

遅れたお詫びにと送ってくれたTシャツです。因みに、ケースと選べたのですが、ケースはレーザー加工機で作れば良いや。。。ということでTシャツにしました。
Parallella_2_140615.jpg

他の同梱物です。ケーブルなどです。上に反対ですが、Parallella-16 ボードが入ってきた箱があります。
Parallella_3_140615.jpg

Parallella-16 ボードは、PLのコンフィギュレーション用ポートがパッドにしか出ていないので(パッドにコネクタが付いているモデルも有ります)、PLをデバックするのが面倒そうです。ChipScopeやVivado Analyzer などの標準デバック機能が使えません。パッドから線を出してJTAG用のコネクタを出せばできますね。但し、PLのコンフィギュレーションはBOOT.binにビットファイルを入れれば、SDカード経由で問題なく出来るはずです。
ソフトウェアもSDKでリモート・デバック出来ると思いますので、心配は無いですね。
ロジック・アナライザ機能を実装しようと思ったら、トリガの掛け方を決めて、トリガが掛かったら、AXIバス経由でデータをDDR3 SDRAMにDMAできるので、そのようなモジュールを作れそうですね。ロジック・アナライザのデータは、Ubuntu上ででもGUIで表示できると良いですね。。。
  1. 2014年06月15日 19:58 |
  2. Parallella-16
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ2(IPリポジトリへの追加)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ1(新規プロジェクトの作製)”の続き。

・cdc_vga_axi_slave_141 (”VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP4(IP化)”のIP)をフォルダごとコピーした。
Vivado_ZYBO_CDC_axi_slave_86_140614.png

・左の Flow Navigator -> Project Manager -> IP Catalog をクリックする。
Vivado_ZYBO_CDC_axi_slave_87_140614.png

・右に IP Catalog のウインドウが出る。そこで右クリックして、右クリックメニューから IP Setting... を選択する。
Vivado_ZYBO_CDC_axi_slave_88_140614.png

・Project Setting のダイアログが出る。Add Repository... ボタンをクリックする。
Vivado_ZYBO_CDC_axi_slave_89_140614.png

・プロジェクトのフォルダの下のcdc_vga_axi_slave_141 フォルダを選択し、Select ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_90_140614.png

・cdc_vga_axi_slave_v1_0 がリポジトリに追加された。
Vivado_ZYBO_CDC_axi_slave_91_140614.png

・IP Catalog のBase IP に追加されているのがわかる。
Vivado_ZYBO_CDC_axi_slave_92_140614.png

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ3(PSのインポートと設定)”に続く。
  1. 2014年06月15日 18:20 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ1(新規プロジェクトの作製)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP4(IP化)”で、ZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラの IP化が終了したので、今回はZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラの回路全体を作製する。
Vivado 2014.1を使用して、IPにした ZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラをインスタンスして、動作する様に、他のIPもインスタンスし、回路全体を構成する。
なお、Vivado 2014.1のチュートリアルとしても使用できるように、1つ1つの手順を図入りで紹介する。

・Vivado 2014.1を起動して、Create New Project をクリックした。
Vivado_ZYBO_CDC_axi_slave_76_140614.png

・Create a New Vivado Project ダイアログが表示された。Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_77_140614.png

・Project Name ダイアログで、Project name と Project location を指定した。Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_78_140614.png

・Project Type は、RTL Project のディフォルトのままとした。Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_79_140614.png

・Add Sources は、そのまま Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_80_140614.png

・Add Existing IP でも、そのまま Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_81_140614.png

・Add Constraints でも、そのまま Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_82_140614.png

・Default Part は xc7Z010clg400-1 を選択した。Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_83_140614.png

・New Project Summary が表示された。Finish ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_84_140614.png

・空のVivado 2014.1プロジェクトが生成された。
Vivado_ZYBO_CDC_axi_slave_85_140614.png

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ2(IPリポジトリへの追加)”へ続く。
  1. 2014年06月15日 04:14 |
  2. ZYBO
  3. | トラックバック:0
  4. | コメント:0

Vivado 2014.2 で論理シミュレーション2(Vivado 2014.1とVivado 2014.2を比較)

Vivado 2014.2 で論理シミュレーション1(エラー発生)”の続き。

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IPをVivado 2014.1で作っていたが、Vivado 2014.2が出たので、今まで Vivado 2014.1で作ってきたプロジェクトをVivado 2014.2に変更した。そうしたら、論理シミュレーションがエラーになってしまった。今回は、プロジェクト変換を行ったので、エラーが出たのかを検証するためにVivado 2014.2で新規プロジェクトを作製して確かめてみる。

早速だが、Vivado 2014.2で新規プロジェクトを作製して、論理シミュレーションを行ったところ、前回同様にエラーとなった。
Vivado_ZYBO_CDC_axi_slave_74_140612.png

同様に、Vivado 2014.1で新規プロジェクトを作製して、論理シミュレーションを行ってみたが、問題なく論理シミュレーションを行うことができた。
Vivado_ZYBO_CDC_axi_slave_75_140613.png

新規プロジェクトの作成方法、FIFO IP の作成方法、論理シミュレーションの実行方法については、下に示す3つの記事を参照のこと。

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP1(新規プロジェクトの生成)
VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP2(FIFOの生成)
VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP3(単体シミュレーション)


ソースコードは、ISEプロジェクトだが、GitHubに上げてある ZYBO_CDC_VGA のソースコードをそのまま使用している。

Vivado 2014.2 は、おかしいのか? それとも、このような仕様になったのか?
Vivado 2014.2 は登場する間隔も短いので、そんなに変わっていないと思っていたが、シミュレーション・エンジンにも変更があるようだ?
正常に論理シミュレーションを行うことができないので、Vivado 2014.1 を使うことにする。

Vivado 2014.2のバグ情報等があったら、コメント欄でお知らせください。よろしくお願いします。

(2014/06/14:追記)
Vivado 2014.2 の論理シミュレーションの時に、OVLのライブラリをコンパイルして、xsim.ini にライブラリを登録するのを忘れていました。それを実行して、再度、Vivado 2014.2でプロジェクトを作り直して、論理シミュレーションしてみましたが、同様にエラーでした。
  1. 2014年06月13日 04:28 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

Vivado 2014.2 で論理シミュレーション1(エラー発生)

Vivado 2014.2 が出ました”で、”VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP4(IP化)”のプロジェクトを早速、Vivado 2014.2に移行した。
今回は、Vivado 2014.2にプロジェクトを変換しても”VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP3(単体シミュレーション)”と同様にシミュレーション出来るかどうかを確かめてみることにした。

2014/06/29:追記 エラーの原因が分かりました。詳しくは下の記事の該当部分に書きます。)

・初めに、Project Manager の Simulation Settings をクリックした。
Vivado_ZYBO_CDC_axi_slave_71_140612.png
問題無さそうだ。

・Project Manager から Run Simulation をクリックして、右に出た表示の中の Run Behavioral Simulation を選択した。

・コンパイルが始まるが途中でエラーが出てしまった。
Vivado_ZYBO_CDC_axi_slave_72_140612.png

・次のダイアログ。
Vivado_ZYBO_CDC_axi_slave_73_140612.png
xelab.log を見ろとの事だった。

・xelab.log のエラー部分を下に示す。


ERROR: [VRFC 10-1540] value for parameter FB_MEM_SIZE is not constant [C:/Users/Masaaki/Documents/Vivado/Zynq/ZYBO/IP_test/cdc_vga_axi_slave/cdc_vga_axi_slave.srcs/sources_1/imports/hdl/verilog/frame_buffer.v:31]
ERROR: [XSIM 43-3322] Static elaboration of top level Verilog design unit(s) in library work failed.K/pre>


FB_MEM_SIZE が定数じゃないと言われている。
frame_buffer.v の FB_MEM_SIZE 定義部分を下に示す。

module frame_buffer # (
        parameter integer RESOLUTION    = 1    // SVGA
    )
    (clka, clkb, reset_a, reset_b, processor_addr, processor_din, processor_dout, processor_we, display_addr, display_dout);
    `include "video_timing_param.vh"
    `include "convenient_functions.vh"

    input clka;
    input clkb;
    input reset_a;
    input reset_b;
    input [log2(ALL_CHAR_SIZE)-1:0] processor_addr;
    input [15:0] processor_din;
    output [15:0] processor_dout;
    input processor_we;
    input [log2(ALL_CHAR_SIZE)-1:0] display_addr;
    output [15:0] display_dout;

    parameter integer    FB_MEM_SIZE    = near_power2(ALL_CHAR_SIZE);


near_power2() は、convenient_functions.vh で定義されている。定義部分を下に示す。

// 一番近く、より大きい2のn乗の値を返す
function integer near_power2;
    input integer num;
    begin
        for (near_power2=2; near_power2<=num; near_power2=near_power2*2);
    end
endfunction


ALL_CHAR_SIZE は、video_timing_param.vh で定義されている。定義部分を下に示す。

parameter ALL_CHAR_SIZE = H_DISPLAY_SIZE*V_DISPLAY_SIZE;


H_DISPLAY_SIZE と V_DISPLAY_SIZE は、RESOLUTION が決まれば一意に決定される。”video_timing_param.vh”については、”ZYBO用キャラクタ・ディスプレイ・コントローラ IPの単体テスト(VGAポート専用)”にVerilog HDLコードの全コードが載せてあるので参照のこと。

2014/06/29:追記 near_power2() の for ループの中で実行する行が無いのが原因でした。これは、Vivado 2014.1 でも論理合成時にエラーが表示されました。near_power2() を以下の様に修正したらエラー無しでシミュレーションを行うことが出来ました。でも、エラーの解説が不親切ですね。原因を指摘して欲しいです。

function integer near_power2;
    input integer num;
    begin
        for (near_power2=2; near_power2<=num; )
          near_power2=near_power2*2;
    end
endfunction


シミュレーション画面を下に示します。
Vivado_2014_2_15_140628.png

これで、Vivado 2014.2 が問題なく使えることがわかったので、積極的に使っていこうと思う。

Vivado 2014.1をVivado 2014.2に変換したプロジェクトの論理シミュレーションでエラーが出てしまった。Vivado 2014.1では問題なくシミュレーションができていたのだが、HDLソースも間違っていないようだし、どうしようか考え中だ。
  1. 2014年06月12日 05:21 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

Vivado 2014.2 が出ました

昨日、Vivado 2014.2が出ているのに気づいて、と言うか、ツイッターで hiyuh さんがつぶやいていたので、慌ててダウンロードしようとしたのですが、ダウンロードできませんでした。家でダウンロードしたら素直にダウンロードできたので、機能インストールしました。
VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP4(IP化)”のプロジェクトを早速、Vivado 2014.2に移行しました。
Vivado 2014.2 で、cdc_vga_axi_slave プロジェクトを開くと、upgrade するか聞かれて、OKすると、(残念ながら画面をキャプチャするのを忘れました) Vivado 2014.2 が立ち上がりました。

afifo_sm があるので、IPを Upgrade するのかを聞かれたので、Upgrade を選びました。afifo_sm を選択しています。Upgrade Selected ボタンをクリックします。
Vivado_ZYBO_CDC_axi_slave_63_140611.png

Upgrade 成功のダイアログが出ました。
Vivado_ZYBO_CDC_axi_slave_64_140611.png

afifo_sm IP を生成するというダイアログが出たので、Generate ボタンをクリックして、IPを生成してもらいます。
Vivado_ZYBO_CDC_axi_slave_65_140611.png

IPが生成できました。Design Runs のウインドウが出ましたが、いろいろなステータスを表示できるようになっていますね。Vivado 2014.1とは明らかに違った表示になっています。
Vivado_ZYBO_CDC_axi_slave_66_140611.png

すいません。途中から文体を変えます。

Sources ウインドウの IP-XACT の下の component.xml をダブルクリックして開いたら、IP Addressing and Memory で warnning が出ていたレンジが 4GB あるので、もっと小さくしろということだった。
Vivado_ZYBO_CDC_axi_slave_67_140611.png

どのくらいのメモリが必要か計算してみた。
最大はHD解像度なので、1920 x 1080 ピクセルなので、これはビットマップでは無くキャラクタ・ディスプレイなので、使用メモリの計算式は、(1920/8)*(1080/8)*4バイト = 129,600 これに一番近くて、かつ大きい2のn乗は17乗だった。
Vivado_ZYBO_CDC_axi_slave_68_140611.png

これを入力しても warning が止まらない。
Vivado_ZYBO_CDC_axi_slave_69_140611.png

IPを再生成しても warning が止まらないが、これで良いだろうということにした。
Vivado_ZYBO_CDC_axi_slave_70_140611.png

というわけで、これからは、Vivado 2014.2を使ってやっていこうと思う。
Vivado 2014.2 は、ウインドウの項目や、IPの取り扱い方が Vivado 2014.1 とは違っているところがあるのがわかった。
  1. 2014年06月11日 05:31 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP4(IP化)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP3(単体シミュレーション)”の続き。

単体シミュレーションが終了したZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラをIPする。

・Toolsメニューから Create and Package IP... を選択した。
Vivado_ZYBO_CDC_axi_slave_46_140610.png

・Create And Package New IPダイアログが立ち上がった。Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_47_140610.png

・Package your projectのラジオボタンが選択されていたので、そのまま、Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_48_140610.png

・Package your project の Packaging IP in the Project の Include .xci files が選択されていた。これは、最初にIPコアを生成する場合に選択するそうだ。そのまま、Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_49_140610.png

・New IP Creation が表示された。Finish ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_50_140610.png

・Finish Packaging successfully ダイアログが表示された。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_51_140610.png

・Package IP ウインドウが表示された。IP Identification が表示されている。
Vivado_ZYBO_CDC_axi_slave_52_140610.png

・IP Compatibility 画面だ。
Vivado_ZYBO_CDC_axi_slave_53_140610.png

・IP File Groups 画面。
Vivado_ZYBO_CDC_axi_slave_54_140610.png

・IP Customization Parameters 画面。
Vivado_ZYBO_CDC_axi_slave_55_140610.png

・IP Ports and Interface 画面。入出力ポートがリストされてた。ACLK と ARESETN も認識されていた。
Vivado_ZYBO_CDC_axi_slave_56_140610.png

・同じ IP Ports and Interface 画面だが、S_AXI を展開してみた。AXIバスが認識されていた。
Vivado_ZYBO_CDC_axi_slave_57_140610.png

・IP Addressing and Memory 画面では、Slave のMemory Mapが表示されていた。これでは4GBの領域全部なので設定を行う。 (2014/06/21 追記:領域の設定部分は後で書き換えました)
Vivado_ZYBO_CDC_axi_slave_58_140610.png

必要なメモリは1920/8 * 1080/8 * 4 Bytes = 129,600 Bytes だ。それよりも大きい2のn乗の値は、2 ^ 17 = 131,072 なので、この値を設定する。

・Range Dependency に pow(2,17) を書いたら、Range が 131072 となった。
Vivado_ZYBO_CDC_axi_slave_59_1_140621.png

・IP GUI Customization 画面では、IP Integrator でインスタンスする際のシンボルが表示された。
Vivado_ZYBO_CDC_axi_slave_59_140610.png

・Review and Package 画面で、Package IP ボタンをクリックして、IPを作製した。(2014/06/11 : 追記、IP root directory が間違っています。正しくは、C:\Users\Masaaki\Documents\Vivado\Zynq\ZYBO\IP_test\cdc_vga_axi_slave です)
Vivado_ZYBO_CDC_axi_slave_60_140610.png

・Finished packaging successfully. ダイアログが出た。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_61_140610.png

・Sources のところに IP-XACT フォルダができて、その下にcomponent.xml ができた。
Vivado_ZYBO_CDC_axi_slave_62_140610.png
  1. 2014年06月10日 05:31 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする9(単体シミュレーション)

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする8(パイプライン化ソースを実機テスト3)”の続き。

今回は、単体シミュレーションを行った。

まずは、tu1978 さんに教えて頂いたラプラシアンフィルタ処理をパイプライン化したCソースをVivado HLS 2014.1 でIPにしたものを単体シミュレーションする。単体シミュレーションは、AXI4 Slaveメモリか、もしくはAXI4 Slave として動作するBFM(Bus Functional Model)を使用している。BFMは自作でこのブログにVHDLソースが載っている。(単体シミュレーションについては、”Vivado HLS 2013.4でラプラシアン・フィルタ関数をaxi masterモジュールにする5(単体シミュレーション)”を参照のこと)

・ラプラシアンフィルタ処理をパイプライン化したVivado HLS 2014.1 のIP用のProject Navigator のプロジェクトを下に示す。
Vivado_HLS_2014_1_48_140609.png

・Project Navigator プロジェクトの中のXPSプロジェクトを下に示す。
Vivado_HLS_2014_1_49_140609.png

・次に、HDLで自作したIPの単体シミュレーション用のProject Navigator プロジェクトを下に示す。
Vivado_HLS_2014_1_50_140609.png

・ラプラシアンフィルタ処理をパイプライン化したVivado HLS 2014.1 のIPの単体シミュレーション結果を下に示す。20 ms 程度の所でラプラシアンフィルタ処理が終了して、AXI4 Lite Slave モジュールの ap_done が 1 になっている。
Vivado_HLS_2014_1_51_140609.png

但し、この単体シミュレーションのクロックは100MHz を使用している。今回のラプラシアンフィルタ処理をパイプライン化したVivado HLS 2014.1 のIPの動作クロックは90MHzなので、処理終了時間は、20 ms /9 * 10 ≒ 22 ms となる。

・この単体シミュレーションの1ラインごとの処理を見ていこう。カーソル間を拡大する。
Vivado_HLS_2014_1_52_140609.png

m_axi_cam_fb_RVALID と m_axi_lap_fg_WVALID に注目して欲しい。m_axi_cam_fb_RVALID はAXIバスのReadのValid信号だ。これは、画面の横の800ピクセルの画像の値を4つのバーストに分けてReadしている。その後、ラプラシアンフィルタ処理を行う。最後に、ラプラシアンフィルタ処理の結果を AXI4 バスを使ってメモリにWriteしている。そのWriteしている時にアサートするのが m_axi_lap_fg_WVALID だ。なお、この単体シミュレーションではAXIバスのデータ・チャネルの転送にWait を入れていない。
m_axi_cam_fb_RVALID のアサートの最初と次のアサートの最初の間は、33.8 us となった。これが画像1ライン分のラプラシアンフィルタの処理時間だ。しかし、この単体シミュレーションは100MHzで行っていることを忘れてはならない。実機での動作クロックは 90MHz なので、10/9 する必要がある。
よって、33.8 us * 10 / 9 ≒ 37.6 ms となった。
全体の処理時間を計算すると、画面は、800 x 600 のSVGAなので、37.6 us x 600 ライン = 22.6 ms となった。
実機で、ラプラシアンフィルタ処理IPの動作時間のみを測定してみると 21.9 ms となって、大体合っていることがわかった。

ラプラシアンフィルタのパイプライン化する前のVivado HLS 2014.1 によるIPの性能を単体シミュレーションで見ると、1ラインの処理時間は約141us となった。単純に 600ラインとすると、141us x 600ライン = 84.6ms となった。(”Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする3(単体シミュレーション)”参照)
Vivado_HLS_2014_1_15_140424.png

次に、HDLで自作したIPの単体シミュレーション波形を見ていこう。
・まずは、14 ms シミュレーションした結果を示す。約 10 ms でラプラシアンフィルタ処理が終了している。
Vivado_HLS_2014_1_53_140609.png

・単体シミュレーションの1ラインごとの処理を見ていこう。カーソル間を拡大する。
Vivado_HLS_2014_1_54_140609.png

M_AXI_RVALID と M_AXI_WVALID に注目して欲しい。先ほどの m_axi_cam_fb_RVALID と m_axi_lap_fg_WVALID と同様の信号なので、説明は省略する。
1ラインの処理時間は、約16.5 us だった。
全画面での処理時間は、16.5 us x 600 ライン = 9.90 ms となった。

こちらのM_AXI_RVALID と M_AXI_WVALID を見ると、M_AXI_RVALID のアサート終了から M_AXI_WVALID のアサート開始までの間隔がないのに気が付くと思う。これは、Readするのと同時に、つまり1クロックでラプラシアンフィルタ処理が終了しているからだ。ハードウェアなので、1クロックでラプラシアンフィルタ処理することが出来る、というかこれが普通だ。
もっとチューニングするとしたら、Readバーストで画像のピクセル値を読んでいる途中に、Writeバーストでラプラシアンフィルタ処理結果を書き込むことも可能だ。その場合は、DDR3 SDRAMのコントローラで、アービトレーションを行い、Read, Writeのうちのどちらをやるのかを決定することになる。DDR3 SRAMのバス帯域が十分に大きくて、DDR3 SDRAMのコントローラが十分に賢い場合は、更に2倍程度の性能向上をすることが可能かもしれない?
  1. 2014年06月09日 05:20 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする8(パイプライン化ソースを実機テスト3)

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする7(パイプライン化ソースを実機テスト2)”の続き。

(2014/06/08:時間計測にバグがあったので、大幅に結果を書き換えました)
前回、インプリメント時のタイミング制約のエラーが消えなかった。そこで、Vivado HLS 2014.1 のラプラシアンフィルタのIPの動作クロックを 100MHz か 90MHz にすることにした。計算上の限界は 94MHz だったが、XPSのClock Generator IP に 94MHz に動作クロックを設定したら、エラーになってしまったので、90MHz とすることにした。

・XPSの clock_generator_0 をダブルクリックして、ダイアログを立ちあげて、CLKOUT2 の Required Frequency (Hz) に 90000000 (90MHz) を設定した。
Vivado_HLS_2014_1_37_140606.png

・XPS上での clock_generator_0 の様子を下図に示す。CLKOUT2 が追加されている。
Vivado_HLS_2014_1_38_140606.png

・、Vivado HLS 2014.1 のラプラシアンフィルタのIP (lap_filter_axim_top_0) の動作クロックは、PSの FCLK_CLK0 が供給されている。これは、100MHz のクロックだ。
Vivado_HLS_2014_1_39_140606.png

・それらのクロックを、clock_generator_0::CLKOUT2 に変更した。
Vivado_HLS_2014_1_40_140606.png

・これでインプリメントを行ったところ、-0.026 ns だが、タイミング制約エラーが出てしまった。
Vivado_HLS_2014_1_41_140606.png

・この程度だったら、Map Properties のコストテーブルの値を変えてインプリメントしてみることで、解消できるだろう。Project Navigator のMap Properties の Starting Placer Cost Table (1-100) を 2 に変更した。
Vivado_HLS_2014_1_42_140607.png

・これで、Project Navigator でインプリメント、ビットストリームの生成を行ったが、タイミング制約エラーが無くなった。
Vivado_HLS_2014_1_43_140607.png

・ハードウェアをエクスポートして、SDKを立ちあげた。
Vivado_HLS_2014_1_44_140607.png

・Create Boot Image でSDカードのブートイメージを作製して、SDカードにコピーした。

・ZedBoardにSDカードを挿入して電源ONした。

・Tera Termを立ちあげて、./lap_fil_hls_axim.elf を起動して、Vivado HLS 2014.1 で作製したラプラシアンフィルタIPを起動すると、実行時間は 36 ms 程度だった。./laplacian_filter.elf コマンドは、ソフトウェアでラプラシアンフィルタを実行した時の実行時間を示す。実行時間は 400ms 程度だった。./lap_filter_axim.elf コマンドは自作HDLによるラプラシアンフィルタIPの実行時間を示す。実行時間は 17ms 程度だった。(但し、この時間計測はソフトウェアの開始時にタイマーセットして、ソフトウェアの最後に時間計測を停止して、時間を表示している)
Vivado_HLS_2014_1_45_140607.png

・下に、ラプラシアンフィルタ処理を行う前の原画像を示す。
Vivado_HLS_2014_1_46_140608.jpg

・Vivado HLS 2014.1 で作製したラプラシアンフィルタIPを起動した時のラプラシアンフィルタ処理後の画像を示す。
Vivado_HLS_2014_1_47_140608.jpg

tu1978 さんに教えて頂いたラプラシアンフィルタ処理をパイプライン化するCソースをVivado HLS 2014.1 でIPすると、ISEでインプリメントするときに、100MHzでは動作せず(10 ns に制約をVivado HLS 2014.1 でかけていたのだが)、90MHzでの動作になった。そのラプラシアンフィルタ処理時間は、約 36 ms だった。
自分で作ったラプラシアンフィルタ処理のCソースを使用したラプラシアンフィルタIPの処理時間は、約 98 ms だったので、2.7倍程度、ラプラシアンフィルタ処理をパイプライン化したほうが速くなった。(”Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする2(実機でテスト)”参照)
しかし、HDLで自作したラプラシアンフィルタIPの実行時間 17 ms からは2倍程度遅い。(”AXI4 Master アクセスのラプラシアン・フィルタ IP9(できた。完成)”参照)
(追加:ソフトウェアとHLS IPとの比較は、400 ms / 36 ms ≒11倍程度早くなっているので、有効だといえる)

今のところは、意図した回路になるように、Cソースを書き換える必要があるようだ。これでもAXIバス・インターフェースを自動生成してくれたりするので、便利なのだが、どうのような形にCソースを変更すれば、所望の回路になるのかがよくわからない。できれば、Vivado HLSでソースの修正を行わずに性能が向上できれば良いと思った。
  1. 2014年06月08日 05:19 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

「ポンペイ」(映画)を見てきました

以前、2回ほどポンペイ展を仙台で見たことがあります。一回目は2011年の地震の前、娘の大学受験に行った時でした。その後は、地震のあと奥さんと仙台でポンペイ展を見ました。地震の前と後で展示内容が違っていました。それは、火山灰が固まったところに人が埋まっていると、人は朽ち果てて空間が残ります。その空間に石膏などを流し込んで石膏像を作ったものがありますが、それが地震の後では撤去されていました。地震で犠牲になった方が大勢いらっしゃるので、撤去したようでした。
ポンペイ展も2度見ているので、「ポンペイ」の映画(音注意)は見ようと思っていました。話は陳腐だと思いましたが、噴火の様子はなかなか良かったです。楽しめたというか自然の脅威を痛感しました。
  1. 2014年06月07日 21:13 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする7(パイプライン化ソースを実機テスト2)

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする6(パイプライン化ソースを実機テスト1)”の続き。

前回、ISEでタイミング・エラーが発生したので、Vivado HLS 2014.1 に戻って、タイミング制約を変更することにした。

・Vivado HLS 2014.1 を立ちあげて、Solutionメニューから Solution Settings... を選択した。

・左のペインからSynthesis を選択して、Clock Period を 9 に変更した。
Vivado_HLS_2014_1_32_140606.png

・これで、合成したところ、Summary の Estimated は 10.92 に悪化してしまった。
Vivado_HLS_2014_1_33_140606.png

これではダメだ。C++ソースを修正する必要があるのだろうか?
いろいろと Clock Period を変更して試してみたが、以前の 9.63 より小さくはならなかった。
Vivado HLSでは手詰まりなので、ISEの方で頑張ってみることにした。

・Project Navigator のMap Properties の Placer Extra Effort を Continue on Impossible , Register Duplication を On , これは直接は関係ないと思うが、Enable Muti-Threading を 2 に変更した。
Vivado_HLS_2014_1_34_140606.png

・Project Navigator のMap Properties の Place & Route Properties の Extra Effort を Continue on Impossible , これも直接は関係ないと思うが、Enable Muti-Threading を 2 に変更した。
Vivado_HLS_2014_1_35_140606.png

・Place & Route 終了後に、・Processes ウインドウのImplement Desgin -> Place & Route -> Generate Post-Place & Route Static Timing -> Analyze Post-Place & Route Static Timing をダブルクリックして、静的タイミング解析結果を表示した。
Vivado_HLS_2014_1_36_140606.png

結果は最大、-1.273 ns になってしまって、悪化した。
前回の結果だと、-0.631 ns だったので、クロック周期が 10.631 ns だったら、問題ない事になる。10.631 ns ≒ 94 MHz だ。94 MHz で動作させて間に合うのだったらタイミング制約はクリアすることになる。
  1. 2014年06月07日 05:11 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする6(パイプライン化ソースを実機テスト1)

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする5(Cソースのフィルタ処理をパイプライン化)”の続き。

前回は、twitter で tu1978 さんに頂いたフィルタ処理をパイプライン化したラプラシアンフィルタのCソースを合成した。今日は、XPS用のIPを生成して実機テストしてみる。

・最初に、Vivado HLS 2014.1 で、合成後のたフィルタ処理をパイプライン化したラプラシアンフィルタのCソースをXPS用にIPを行った。

・XPSのIP、lap_filter_axim_top_v1_00_a を、以前から使用している Zed_OOB_Desin2_HLS_147 という名前のProject Navigator プロジェクトの中のXPSプロジェクト(system) の pcores フォルダにコピーした。
Vivado_HLS_2014_1_27_140606.png

・XPSを立ちあげて、Project メニュー -> Clean All Generate Files を行った。
Vivado_HLS_2014_1_28_140606.png

・Project Navigator で、左下のProcesses ウインドウの Generate Programming File をダブルクリックして、論理合成、インプリメント、ビットストリームの生成を行った。
Vivado_HLS_2014_1_29_140606.png

・ビットストリームの生成まで終了したが、Timing Constrains のエラーが出ていた。
Vivado_HLS_2014_1_30_140606.png

・Processes ウインドウのImplement Desgin -> Place & Route -> Generate Post-Place & Route Static Timing -> Analyze Post-Place & Route Static Timing をダブルクリックして、静的タイミング解析結果を表示した。
Vivado_HLS_2014_1_31_140606.png

lap_filter_axim_top_0 つまり、Vivado HLS 2014.1 で作ったIPのFF間でタイミング・エラーが発生している。
最初のタイミング・エラーの情報を下に引用する。

 ================================================================================ 
Timing constraint: TS_clk_fpga_0 = PERIOD TIMEGRP "clk_fpga_0" 100 MHz HIGH 50%;
For more information, see Period Analysis in the Timing Closure User Guide (UG612).
3814414 paths analyzed, 74771 endpoints analyzed, 43 failing endpoints
43 timing errors detected. (43 setup errors, 0 hold errors, 0 component switching limit errors)
Minimum period is 10.631ns.
--------------------------------------------------------------------------------

Paths for end point system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/tmp_i_37_reg_859_9 (SLICE_X82Y21.CIN), 244131 paths
--------------------------------------------------------------------------------
Slack (setup path): -0.631ns (requirement - (data path - clock path skew + uncertainty))
Source: system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ap_reg_ppstg_exitcond_reg_804_pp0_it3_0 (FF)
Destination: system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/tmp_i_37_reg_859_9 (FF)
Requirement: 10.000ns
Data Path Delay: 10.564ns (Levels of Logic = 13)
Clock Path Skew: -0.032ns (0.158 - 0.190)
Source Clock: system_i/processing_system7_0_FCLK_CLK0 rising at 0.000ns
Destination Clock: system_i/processing_system7_0_FCLK_CLK0 rising at 10.000ns
Clock Uncertainty: 0.035ns

Clock Uncertainty: 0.035ns ((TSJ^2 + TIJ^2)^1/2 + DJ) / 2 + PE
Total System Jitter (TSJ): 0.070ns
Total Input Jitter (TIJ): 0.000ns
Discrete Jitter (DJ): 0.000ns
Phase Error (PE): 0.000ns

Maximum Data Path at Slow Process Corner: system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ap_reg_ppstg_exitcond_reg_804_pp0_it3_0 to system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/tmp_i_37_reg_859_9
Location Delay type Delay(ns) Physical Resource
Logical Resource(s)
------------------------------------------------- -------------------
SLICE_X83Y14.CQ Tcko 0.456 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ap_reg_ppstg_exitcond_reg_804_pp0_it3_0
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ap_reg_ppstg_exitcond_reg_804_pp0_it3_0
SLICE_X81Y14.C3 net (fanout=4) 0.673 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ap_reg_ppstg_exitcond_reg_804_pp0_it3_0
SLICE_X81Y14.C Tilo 0.124 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/current_2_V_1_fu_84<7>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/Mmux_current_2_V_phi_fu_247_p41101_1
SLICE_X81Y14.D4 net (fanout=6) 0.458 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/Mmux_current_2_V_phi_fu_247_p41101
SLICE_X81Y14.D Tilo 0.124 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/current_2_V_1_fu_84<7>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd1_lut<0>
SLICE_X80Y15.A5 net (fanout=1) 0.465 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd1_lut<0>
SLICE_X80Y15.COUT Topcya 0.656 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd1_cy<3>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd1_lut<0>_rt
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd1_cy<3>
SLICE_X80Y16.CIN net (fanout=1) 0.000 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd1_cy<3>
SLICE_X80Y16.CMUX Tcinc 0.417 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd_71
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd1_cy<7>
SLICE_X81Y18.C4 net (fanout=1) 0.900 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd_61
SLICE_X81Y18.CMUX Tilo 0.356 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/y_reg_869<7>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd26
SLICE_X81Y18.D5 net (fanout=2) 0.422 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd26
SLICE_X81Y18.COUT Topcyd 0.525 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/y_reg_869<7>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd2_lut<0>7
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd2_cy<0>_6
SLICE_X81Y19.CIN net (fanout=1) 0.000 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd2_cy<0>7
SLICE_X81Y19.DMUX Tcind 0.495 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd_102
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd2_xor<0>_10
SLICE_X83Y18.C6 net (fanout=33) 0.446 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd_112
SLICE_X83Y18.C Tilo 0.124 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/current_0_V_1_fu_76<3>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/Mmux_current_0_V_phi_fu_238_p431
SLICE_X83Y19.C4 net (fanout=1) 0.571 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/current_0_V_phi_fu_238_p4<2>
SLICE_X83Y19.CMUX Tilo 0.356 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd_36
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd62
SLICE_X83Y19.DX net (fanout=2) 0.617 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd62
SLICE_X83Y19.COUT Tdxcy 0.385 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd_36
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd6_cy<0>_2
SLICE_X83Y20.CIN net (fanout=1) 0.000 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd6_cy<0>3
SLICE_X83Y20.BQ Tito_logic 0.674 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd_76
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd6_cy<0>_6
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd_56_rt
SLICE_X82Y20.B4 net (fanout=1) 0.449 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd_56
SLICE_X82Y20.COUT Topcyb 0.657 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/tmp_i_37_reg_859<7>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd7_lut<5>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd7_cy<7>
SLICE_X82Y21.CIN net (fanout=1) 0.000 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd7_cy<7>
SLICE_X82Y21.CLK Tcinck 0.214 system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/tmp_i_37_reg_859<11>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/ADDERTREE_INTERNAL_Madd7_xor<11>
system_i/lap_filter_axim_top_0/lap_filter_axim_top_0/lap_filter_axim_U/grp_filter_line_fu_397/tmp_i_37_reg_859_9
------------------------------------------------- ---------------------------
Total 10.564ns (5.563ns logic, 5.001ns route)
(52.7% logic, 47.3% route)


結構、タイミング・エラーが発生しているので、Vivado HLS 2014.1 に戻って、タイミング制約を変更してみようと思う。
  1. 2014年06月06日 04:20 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする5(Cソースのフィルタ処理をパイプライン化)

Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする4(ChipScope Proでデバック)”の続き。

twitter で tu1978 さんに、私のラプラシアンフィルタのCソースのフィルタ処理をパイプライン化して頂いたので、そのVivado HLS 2014.1合成結果と以前の合成結果を比べてみようと思う。

フィルタ処理をパイプライン化したC++のソースを、Vivado HLS 2014.1 のプロジェクトにして、合成を書けてみた結果を下に示す。
Vivado_HLS_2014_1_23_140605.png

Latency を見ると、min で 1943516 クロック、max で 3884624 クロックだった。1クロックは、100MHz, 10 ns なので、約 19.44 ms から、約 38.85 ms だった。

以前の合成結果を下に示す。
Vivado_HLS_2014_1_24_140605.png

Latency を見ると、min で 1450201 クロック、max で 6930730201 クロックだった。1クロックは、100MHz, 10 ns なので、約 14.50 ms から、約 69.31 s だった。実際にこのラプラシアンフィルタのAXI Master IPを使ってみると、実行時間は、984 ms だった。(”Vivado HLS 2014.1でラプラシアン・フィルタ関数をaxi masterモジュールにする2(実機でテスト)”参照)

下に、フィルタ処理をパイプライン化したC++ソースのAnalysis 結果の一部を示す。
Vivado_HLS_2014_1_25_140605.png

以前のラプラシアンフィルタのCソースのAnalysis 結果の一部を示す。
Vivado_HLS_2014_1_26_140605.png

フィルタ処理をパイプライン化したC++ソースを下に示す。(tu1978 さん、ありがとうございました。公開させていただきます)

// laplacian_filter.cpp
// lap_filter_axim()

#include <stdio.h>
#include <string.h>
#include <ap_int.h>

#define HORIZONTAL_PIXEL_WIDTH    800
#define VERTICAL_PIXEL_WIDTH    600
#define ALL_PIXEL_VALUE    (HORIZONTAL_PIXEL_WIDTH*VERTICAL_PIXEL_WIDTH)

int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2);
int conv_rgb2y(int rgb);

void conv_line(unsigned int* buf){
    for (int b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){
#pragma HLS pipeline
        buf[b] = conv_rgb2y(buf[b]);    // カラーから白黒へ
    }
}

void filter_line(unsigned int* lap_buf, unsigned int* fl, unsigned int* sl, unsigned int* tl){
    int lap_fil_val;
    ap_uint<8> prev[3],current[3],next[3];    // 0->1ライン目, 1->2ライン目, 2->3ライン目, prev->1pixel前, current->現在, next->次pixel
#pragma HLS array_partition variable=prev complete dim=0
#pragma HLS array_partition variable=current complete dim=0
#pragma HLS array_partition variable=next complete dim=0

    next[0] = fl[0] & 0xFF;
    next[1] = sl[0] & 0xFF;
    next[2] = sl[0] & 0xFF;

    for (int x = 0; x < HORIZONTAL_PIXEL_WIDTH; x++){
#pragma HLS pipeline
        if (x == 0 || x == HORIZONTAL_PIXEL_WIDTH-1){
            lap_fil_val = 0;

            current[0] = next[0];
            next[0] = fl[1];

            current[1] = next[1];
            next[1] = sl[1];

            current[2] = next[2];
            next[2] = tl[1];
        }else{
            prev[0] = current[0];
            current[0] = next[0];
            next[0] = fl[x+1];

            prev[1] = current[1];
            current[1] = next[1];
            next[1] = sl[x+1];

            prev[2] = current[2];
            current[2] = next[2];
            next[2] = tl[x+1];
            lap_fil_val = laplacian_fil(prev[0], current[0], next[0],
                                        prev[1], current[1], next[1],
                                        prev[2], current[2], next[2]);
        }
        lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
    }
}

int lap_filter_axim(int cam_addr, int lap_addr, volatile int *cam_fb, volatile int *lap_fb)
{
    #pragma HLS RESOURCE variable=cam_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
    #pragma HLS RESOURCE variable=lap_addr core=AXI4LiteS metadata="-bus_bundle LiteS"
    #pragma HLS RESOURCE variable=return core=AXI4LiteS metadata="-bus_bundle LiteS"

    #pragma HLS INTERFACE ap_bus port=cam_fb depth=480000
    #pragma HLS INTERFACE ap_bus port=lap_fb depth=480000
    #pragma HLS RESOURCE variable=cam_fb core=AXI4M
    #pragma HLS RESOURCE variable=lap_fb core=AXI4M

    unsigned int line_buf[3][HORIZONTAL_PIXEL_WIDTH];
#pragma HLS array_partition variable line_buf block factor=3 dim=1
#pragma HLS resource variable=line_buf core=RAM_2P

    unsigned int lap_buf[HORIZONTAL_PIXEL_WIDTH];
    int x, y;
    int lap_fil_val;
    int a, b;
    int fl, sl, tl;
    unsigned int offset_cam_addr, offset_lap_addr;
    int *cam_fb_addr, *lap_fb_addr;

    offset_cam_addr = cam_addr/sizeof(int);
    offset_lap_addr = lap_addr/sizeof(int);

    // RGB値をY(輝度成分)のみに変換し、ラプラシアンフィルタを掛けた。
    for (y=1; y<VERTICAL_PIXEL_WIDTH-1; y++){
        fl = (y-1)%3;    // 最初のライン, y=1 012, y=2 120, y=3 201, y=4 012
        sl = y%3;        // 2番めのライン
        tl = (y+1)%3;    // 3番目のライン

        if (y == 1){
#ifndef __SYNTHESIS__
            printf("copy 3 lines\n");
#endif
            for (a=0; a<3; a++){ // 3ライン分
                cam_fb_addr = (int*)(cam_fb+offset_cam_addr+(a*(HORIZONTAL_PIXEL_WIDTH)));
                memcpy(line_buf[a], (unsigned int*)cam_fb_addr, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
                conv_line(line_buf[a]);
            }
        }else// 最初のラインではないので、1ラインだけ読み込む。すでに他の2ラインは読み込まれている
            cam_fb_addr = (int*)(cam_fb+offset_cam_addr+((y+1)*(HORIZONTAL_PIXEL_WIDTH)));
            memcpy(line_buf[tl], (unsigned int*)cam_fb_addr, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
            conv_line(line_buf[tl]);
        }
        filter_line(lap_buf, line_buf[fl], line_buf[sl], line_buf[tl]);
        lap_fb_addr = (int *)(lap_fb+offset_lap_addr+(y*(HORIZONTAL_PIXEL_WIDTH)));
#ifndef __SYNTHESIS__
        printf("write back:%d\n", y);
#endif
        memcpy((unsigned int*)lap_fb_addr, (unsigned int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
    }

    // 最初と最後のラインは0にする
    for (x = 0; x < HORIZONTAL_PIXEL_WIDTH; x++)
        lap_buf[x] = 0;
    lap_fb_addr = (int *)(lap_fb+offset_lap_addr+(0*(HORIZONTAL_PIXEL_WIDTH)));
    memcpy((unsigned int*)lap_fb_addr, (unsigned int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
    lap_fb_addr = (int *)(lap_fb+offset_lap_addr+(VERTICAL_PIXEL_WIDTH-1)*HORIZONTAL_PIXEL_WIDTH);
    memcpy((unsigned int*)lap_fb_addr, (unsigned int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));

#if 0
        for (x=0; x<HORIZONTAL_PIXEL_WIDTH; x++){
            if (y==0 || y==VERTICAL_PIXEL_WIDTH-1){ // 縦の境界の時の値は0とする
                lap_fil_val = 0;
            }else if (x==0 || x==HORIZONTAL_PIXEL_WIDTH-1){ // 横の境界の時も値は0とする
                lap_fil_val = 0;
            }else{
                 if (x == 1){ // ラインの最初でラインの画素を読み出す
                    if (y == 1){ // 最初のラインでは3ライン分の画素を読み出す
                        for (a=0; a<3; a++){ // 3ライン分
                            cam_fb_addr = (int*)(cam_fb+offset_cam_addr+(a*(HORIZONTAL_PIXEL_WIDTH)));
                            memcpy(&line_buf[a][0], (const int*)cam_fb_addr, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
                            for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
#pragma HLS pipeline
                                line_buf[a][b] = conv_rgb2y(line_buf[a][b]);    // カラーから白黒へ
                            }
                        }
                    } else {
                        cam_fb_addr = (int*)(cam_fb+offset_cam_addr+((y+1)*(HORIZONTAL_PIXEL_WIDTH)));
                        memcpy(line_buf[(y+1)%3], (const int*)cam_fb_addr, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
                        for (b=0; b<HORIZONTAL_PIXEL_WIDTH; b++){ // ライン
#pragma HLS pipeline
                            line_buf[(y+1)%3][b] = conv_rgb2y(line_buf[(y+1)%3][b]);    // カラーから白黒へ
                        }
                    }
                }
                lap_fil_val = laplacian_fil(line_buf[fl][x-1], line_buf[fl][x], line_buf[fl][x+1], line_buf[sl][x-1], line_buf[sl][x], line_buf[sl][x+1], line_buf[tl][x-1], line_buf[tl][x], line_buf[tl][x+1]);
            }
            lap_buf[x] = (lap_fil_val<<16)+(lap_fil_val<<8)+lap_fil_val; // RGB同じ値を入れる
        }
        lap_fb_addr = (int *)(lap_fb+offset_lap_addr+(y*(HORIZONTAL_PIXEL_WIDTH)));
        memcpy(lap_fb_addr, (const int*)lap_buf, HORIZONTAL_PIXEL_WIDTH*sizeof(int));
    }
#endif
    return(7);
}

// RGBからYへの変換
// RGBのフォーマットは、{8'd0, R(8bits), G(8bits), B(8bits)}, 1pixel = 32bits
// 輝度信号Yのみに変換する。変換式は、Y =  0.299R + 0.587G + 0.114B
// "YUVフォーマット及び YUV<->RGB変換"を参考にした。http://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
// 2013/09/27 : float を止めて、すべてint にした
int conv_rgb2y(int rgb){
    int r, g, b, y_f;
    int y;

    b = rgb & 0xff;
    g = (rgb>>8) & 0xff;
    r = (rgb>>16) & 0xff;

    y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
    y = y_f >> 8// 256で割る

    return(y);
}

// ラプラシアンフィルタ
// x0y0 x1y0 x2y0 -1 -1 -1
// x0y1 x1y1 x2y1 -1  8 -1
// x0y2 x1y2 x2y2 -1 -1 -1
int laplacian_fil(int x0y0, int x1y0, int x2y0, int x0y1, int x1y1, int x2y1, int x0y2, int x1y2, int x2y2)
{
    int y;

    y = -x0y0 -x1y0 -x2y0 -x0y1 +8*x1y1 -x2y1 -x0y2 -x1y2 -x2y2;
    if (y<0)
        y = 0;
    else if (y>255)
        y = 255;
    return(y);
}


やはり、ラプラシアンフィルタに値を入力するためにラインバッファの該当領域を参照するのではなく、明示的にFFを作るように書く必要がある様だ。これを余りやってしまうと、HDLを書くのと変わらなくなってしまう気がする。。。
  1. 2014年06月05日 05:37 |
  2. Vivado HLS
  3. | トラックバック:0
  4. | コメント:0

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP3(単体シミュレーション)

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP2(FIFOの生成)”の続き。

前回は、IP Catalog からFIFO IPを生成した。今回は、OVL(Open Verification Library)を使用した単体シミュレーションを行う。OVLのVivado Simulator 用の設定は、”Vivado Simulator用のOVL2.8.1のOVLライブラリをコンパイルして登録した”でやったので問題ないはずだ。

まずは、シミュレーション用HDLファイルを登録する。

・Project Manager のAdd Source をクリックした。
Vivado_ZYBO_CDC_axi_slave_19_140602.png

・Add Source ダイアログが表示された。Add or Create Simulation Sources のラジオボタンをクリックして、Next >ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_20_140602.png

・Add or Create Simulation Sources ダイアログで、Add Files... ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_21_140602.png

・Add Sources Files ダイアログで以前ISEで単体シミュレーションを行った時のテストベンチやAXI4 Master BFM、OVL_Checker を選択してOKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_22_140602.png

・Add or Create Simulation Sources ダイアログに戻った。3つのファイルが選択されたのがわかる。もう一度、Add Files... ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_23_140602.png

・Add Sources Files ダイアログで、std_ovl_v281フォルダに行って、std_ovl_defines.h を選択して、OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_24_140602.png

・Add or Create Simulation Sources ダイアログに戻った。4つのファイルが選択されたのがわかる。Copy source into project にチェックを入れて、Finish ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_25_140602.png

これで、シミュレーション用HDLソースを追加できた。次は、シミュレーション用設定を行う。

・Project Manager の Simulation Settings をクリックした。
Vivado_ZYBO_CDC_axi_slave_26_140602.png

・Simulation 用のProject Settings ダイアログが開いた。Compilation タブが選択されていた。最初に、Verilog options を設定する。これはOVLを使用するための設定を行う。右脇の・・・ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_27_140602.png

・Verilog Options ダイアログ開いた。Verilog Include Files Search Paths のAdd Directories... ボタンをクリックして、std_ovl_v281 フォルダを指定した。

・Defines のAdd ボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_28_140602.png

・Add Value ダイアログ開いた。OVL_VERILOG を設定した。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_29_140602.png

・Verilog Options ダイアログのDefines に、OVL_VERILOG が表示された。
Vivado_ZYBO_CDC_axi_slave_30_140602.png

・同様に、OVL_ASSERT_ONと、OVL_FINISH_OFF を設定した。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_31_140602.png

・Project Settings ダイアログに戻った。Verilog Options が設定できたのがわかる。More Compilation Options に -L accellera_ovl_vlog を指定した。OVLのVerilog ライブラリを指定した。
Vivado_ZYBO_CDC_axi_slave_32_140602.png

・Simulation タブに切り替えて、Simulation Run Time に 2000ns を指定した。OKボタンをクリックした。
Vivado_ZYBO_CDC_axi_slave_33_140602.png

・Project Manager から Run Simulation をクリックすると、右に表示が出て選択できるが、今は、Run Behavioral Simulation のみが選択できるので、それを選択した。
Vivado_ZYBO_CDC_axi_slave_34_140602.png

・シミュレーション用のコンパイルが開始された。
Vivado_ZYBO_CDC_axi_slave_35_140602.png

・シミュレーション結果が表示された。Flow Navigator が邪魔なので、<< ボタンをクリックして隠した。
Vivado_ZYBO_CDC_axi_slave_36_140602.png

・このような表示になった。シミュレーションのみの表示になった。
Vivado_ZYBO_CDC_axi_slave_37_140602.png

・シミュレーション時間全体を表示してみた。
Vivado_ZYBO_CDC_axi_slave_38_140602.png

・Vivao Simulator の機能としては、Analog 表示があるので、試してみた。
Vivado_ZYBO_CDC_axi_slave_39_140602.png

・Analog 表示になった。
Vivado_ZYBO_CDC_axi_slave_40_140602.png

・Analog 表示を元に戻して、Divider を挿入する。右クリックメニューから New Divider を選択した。
Vivado_ZYBO_CDC_axi_slave_41_140602.png

・Dividerの名前をダイアログに入力した。Write Channel と入力した。AXI4バスのWrite Channel を表示する。
Vivado_ZYBO_CDC_axi_slave_42_140602.png

・Write Channel のDivider が表示された。
Vivado_ZYBO_CDC_axi_slave_43_140602.png

・Read Channel のDivider も作成した。
Vivado_ZYBO_CDC_axi_slave_45_140602.png

・信号をAXI4バスが見やすい順番に並べ替えた。まずはWrite Channel を表示する。
Vivado_ZYBO_CDC_axi_slave_44_140602.png

・Write Channel は問題ないようだ。次にRead Channel を表示する。
Vivado_ZYBO_CDC_axi_slave_45_140602.png

Read Channel も問題ないようだ。OVLチェッカーもエラーが出ていない。単体シミュレーションは問題ないようだ。

VivadoでZYBOのAXI4 Slave キャラクタ・ディスプレイ・コントローラ IP4(IP化)”に続く。
  1. 2014年06月03日 04:42 |
  2. Vivado
  3. | トラックバック:0
  4. | コメント:0

Xillinuxに新しいユーザー zybo を追加

ZYBOにOpenCV 2.4.6.1をインストール”でZybo のXillinux にOpenCV 2.4.6.1 をインストールしたのですが、これは、root でやっていました。どうも root でコマンドを実行しているとあまり気持ちよく無いので、zybo というユーザーを作ることにしました。パスワードは同じく zybo です。

・”ubuntu コマンドでユーザーの追加と削除 ”を参照して、adduser zybo コマンドで、zybo という新しいユーザーを追加しました。

・”ユーザーアカウントの権限を管理者権限に変更してみる”を参考にして、root で gpasswd -a zybo sudo コマンドで、zybo を sudo グループの参加させました。これで、sudo が使えるようになりました。

・このままだと、Tera TermでZybvo のIPアドレスを指定して、リモート・ログインはできますが、startx するとX Windowが起動できません。GUI画面でも zybo でログインできずに、すぐにログイン画面に戻ってしまいます。

startx コマンドを起動すると、/tmp ディレクトリに何らかのファイルを書きに行くようでした。/tmp ディレクトリを見ると、ディレクトリのオーナーが root で Writeパーミッションが入っていなかったので、sudo chmod a+w /tmp で、/tmp ディレクトリにWriteパーミッションを入れました。下に GUI画面上で、zybo でログインしている状態の /tmp ディレクトリの内容を示します。
Xillinux_16_140601.png

・これでも、startx ではエラーが出ます。エラーは、

X: user not authorized to run the X server, aborting.

というものです。”How to fix “X: user not authorized to run the X server, aborting.”? ”にそのバグ・フィックスの方法が書いてありました。

sudo vi /etc/X11/Xwrapper.config コマンドを実行して、Xwrapper.config ファイルを編集し、allowed_users=anybody を追加しました。
Xillinux_17_140601.png

sudo dpkg-reconfigure x11-common コマンドで、Configuring x11-common を表示して、Anybody になっていることを確認して、returnキーを押しました。
Xillinux_18_140601.png

・これで、startx コマンドも成功して、GUI画面でも、zybo ユーザーでログイン出来るようになりました。
Xillinux_19_140601.jpg

・次に、root でビルドした OpenCV 2.4.6.1 を /home/zybo に移します。その際に、オーナーとグループを変更しました。これからは root で作業しました。

・まずは、chown -R zybo opencv コマンドで、再帰的に opencv ディレクトリ内のファイルをすべて、zybo オーナーに変更しました。

・次に、chgrp -R zybo opencv コマンドで、再帰的に opencv ディレクトリ内のファイルをすべて、zybo グループに変更しました。

mv opencv /home/zybo コマンドで、opencv を /home/zybo の下に移動しました。

・GUI画面で、レナ像の顔認識も問題なく実行できました。
  1. 2014年06月01日 04:13 |
  2. Linux
  3. | トラックバック:0
  4. | コメント:0