FC2カウンター FPGAの部屋 2014年06月29日
FC2ブログ

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

FPGAの部屋

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

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