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

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