FPGAの部屋

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

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。ご利用ください。 http://marsee101.web.fc2.com/index.html

2013年11月

AXI4 Master アクセスのラプラシアン・フィルタ IP7(インプリメント1)”の続き。

・XPSプロジェクトで、Generate Netlistが終了した。今度は、system_lap_filter_axim_0_wapper のLUT使用率が586になっていて良い感じだ。
baedb460.png


・Poject Navigator に戻って、論理合成、インプリメント、ビットストリームの生成を行った。成功した。
7b05c544.png


・FPGA Editor を立ちあげて、lap_filter_axim_0 を見ると、lap_filter_axim_LiteS_if_Uがあった。これで一安心。
ee3af924.png


・SDKを立ちあげ、SDカードに入れるブートイメージを作製した。

・BOOT.bin をSDカードに入れて、Linuxをブート。

・lap_filte_axim のデバック・コンフィギュレーションを作って、デバック。(手順はかなり省略しています。詳しい手順は、”Vivado HLSで作ったラプラシアン・フィルタAXI4 Master IPを使う2”をどうぞ)

・まずは、ソフトコアで作ったラプラシアン・フィルタ・ソフトウェアを起動して実行した。(詳しくは、”ソフトウエアのプロファイリング4(ハードウェアと同じ方式)”をどうぞ)
f1b736e0.jpg


・lap_filte_axim を実行するソフトウェアを実行すると、下の写真のようになった。
945f6bcb.jpg


・画面の1/4しか、書き込んでいないみたいだ。ショック。。。

・ChipScope Pro を仕掛けておいたので、起動した。下に、WVAILD の立ち上がりでトリガを掛けた時の波形を示す。
d64410cf.png


・Write Address Channel を拡大してみた。なにかおかしい?
168e9825.png


・Read Address Channel を拡大すると理由がわかった。Write Address Channel のアドレス増加ステップがデータバス幅 32/8 = 4 ではなくて、1 だ。
ded24f0c.png


HDLコードの Writeアドレスの増加ステップがおかしかったので、修正を行った。

AXI4 Master アクセスのラプラシアン・フィルタ IP6(line_read_and_y.v と Dual_Port_Memory.v)”の続き。

今回は、MPDファイルやPAOファイルを作って、カスタムIPとしてXPSプロジェクトにADD IPして、ISEから論理合成、インプリメントを行った。

・まずは、XPSプロジェクトに lap_filter_axim IP をADD IPした。
5abfa6cc.png


・Portsタブでクロックを接続。
6ea8ea20.png


・Addressesタブで、アドレスを 0x4A000000 に設定
47f91b16.png


・Project Navigator に戻って、論理合成、インプリメント、ビットストリームの生成を行った。成功した。
829fea85.png


・試しに、FPGA Editor で見てみると、lap_filter_axim_0 のロジックが大幅に少ない。lap_filter_axim_LiteS_if.v は消去されていた。
7b16f97a.png


・試しにVivado HLS で生成した lap_filter_axim_top_0 を Delete して、XPSプロジェクトで Hardware メニューから Generate Netlistをやってみた。
b69e8a65.png


・Summary を見ると、system_lap_filter_axim_0_wapper に使用リソースが少ない。
fea60e5f.png


・system_lap_filter_axim_0_wapper をクリックすると、XSTのログが出る。そこで、s_axi_lite_wstrb が接続されていないという WARNING が出ていた。
df1840db.png

WARNING:Xst:2898 - Port 's_axi_lite_wstrb', unconnected in block instance 'lap_filter_axim_0', is tied to GND.


・Portsタブで確認すると確かに、s_axi_lite_wstrb が接続されていない。
9cfc6969.png


・lap_filter_axim_v2_1_0.mpd ファイルを見ると、s_axi_lite_wstrb の定義が書いていない。これは、ビットマップ・ディスプレイ・コントローラから持ってきたのだが、そこでは、s_axi_lite_wstrb は使っていなかった。

## AXI4 Lite Slave Ports
PORT s_axi_lite_awvalid = AWVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_awready = AWREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_awaddr = AWADDR, DIR = I, VEC = [C_S_AXI_LITE_ADDR_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_wvalid = WVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_wready = WREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_wdata = WDATA, DIR = I, VEC = [C_S_AXI_LITE_DATA_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_bresp = BRESP, DIR = O, VEC = [1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_bvalid = BVALID, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_bready = BREADY, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_arvalid = ARVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_arready = ARREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_araddr = ARADDR, DIR = I, VEC = [C_S_AXI_LITE_ADDR_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_rvalid = RVALID, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_rready = RREADY, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_rdata = RDATA, DIR = O, VEC = [C_S_AXI_LITE_DATA_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_rresp = RRESP, DIR = O, VEC = [1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE


・s_axi_lite_wstrb の定義をMPDファイルに追加した。

## AXI4 Lite Slave Ports
PORT s_axi_lite_awvalid = AWVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_awready = AWREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_awaddr = AWADDR, DIR = I, VEC = [C_S_AXI_LITE_ADDR_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_wvalid = WVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_wready = WREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_wdata = WDATA, DIR = I, VEC = [C_S_AXI_LITE_DATA_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_wstrb = WSTRB, DIR = I, VEC = [((C_S_AXI_LITE_DATA_WIDTH/8)-1):0], ENDIAN = LITTLE, BUS = S_AXI_LITE
PORT s_axi_lite_bresp = BRESP, DIR = O, VEC = [1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_bvalid = BVALID, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_bready = BREADY, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_arvalid = ARVALID, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_arready = ARREADY, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_araddr = ARADDR, DIR = I, VEC = [C_S_AXI_LITE_ADDR_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_rvalid = RVALID, DIR = O, BUS = S_AXI_LITE
PORT s_axi_lite_rready = RREADY, DIR = I, BUS = S_AXI_LITE
PORT s_axi_lite_rdata = RDATA, DIR = O, VEC = [C_S_AXI_LITE_DATA_WIDTH-1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE
PORT s_axi_lite_rresp = RRESP, DIR = O, VEC = [1:0], BUS = S_AXI_LITE, ENDIAN = LITTLE


・Project メニューから Rescan User Repositories を行うと、s_axi_lite_wstrb が見えた。
8dbe269e.png


・これで、もう一度、 Hardware メニューから Generate Netlistを行った。

今、 Generate Netlistを行っている最中です。結果は次回のブログでお知らせします。

AXI4 Master アクセスのラプラシアン・フィルタ IP6(lap_filter_axim_LiteS_if.v のHDLソース)”の続き。

今回は、下位モジュールの line_read_and_y.v と Dual_Port_Memory.v を貼っておく。

line_read_and_y.v は、HORIZONTAL_PIXELS 分のピクセルデータを start_addr から AXI4 Master Readして、RGB - Y変換を行い、y_data へ出力する下位モジュールだ。
line_read_and_y.v を下に貼る。

`default_nettype none

//
// line_read_and_y.v
// HORIZONTAL_PIXELS 分のピクセルデータを start_addr から AXI4 Master Read する
// RGB - Y変換を行い、y_data へ出力する
// 2013/11/17
//

module line_read_and_y #(
    parameter    integer    C_M_AXI_ADDR_WIDTH        = 32,
    parameter    integer    C_M_AXI_DATA_WIDTH        = 32,
    parameter     integer    HORIZONTAL_PIXELS        = 800
)
(
    input    wire                                clk,
    input    wire                                reset,
    input    wire    [C_M_AXI_ADDR_WIDTH-1:0]    start_addr,
    input    wire                                start,
    output    reg                                    done,
    output    reg        [7:0]                        y_data,
    output    reg                                    y_data_valid,

    output    wire                                read_adfifo_wr_ena,
    output    reg        [C_M_AXI_ADDR_WIDTH-1:0]    read_adfifo_addr,
    output    reg        [8-1:0]                        read_adfifo_arlen,
    input    wire                                read_adfifo_full,

    output    wire                                 read_fifo_rd_ena,
    input    wire    [C_M_AXI_DATA_WIDTH-1:0]    read_fifo_read_data,
    input    wire                                read_fifo_empty_n,
    input    wire                                read_fifo_almost_empty_n
);

    // 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

    reg        [log2(HORIZONTAL_PIXELS)-1:0]    h_addr_cnt;

    parameter     IDLE_READ_ADDR =    1'b0,
                READ_ADDR_ACTIVE =     1'b1;
    reg        read_addr_req_cs;
    wire    [log2(HORIZONTAL_PIXELS)-1:0]    BURST_LIMIT_VAL = 256;
    wire    [log2(HORIZONTAL_PIXELS)-1:0]    ONE = 1;
    reg        op_state;
    reg        [log2(HORIZONTAL_PIXELS)-1:0]    y_data_cnt;


    // start が来たら op_state を1にする。全部のReadデータを受け取った時に0にする
    always @(posedge clk) begin : proc_op_state
       if(reset) begin
            op_state <= 1'b0;
       end else begin
               if (start)
                   op_state <= 1'b1;
               else if (y_data_cnt==ONE && y_data_valid==1'b1)
                   op_state <= 1'b0;
       end
    end

    // Read Address Transaction State Machine
    always @(posedge clk) begin : proc_Read_Addr_Tran_SM
       if(reset) begin
            read_addr_req_cs <= IDLE_READ_ADDR;
       end else begin
               case (read_addr_req_cs)
                   IDLE_READ_ADDR :
                       if (read_adfifo_full==1'b0 && h_addr_cnt!=0 && op_state==1'b1)
                           read_addr_req_cs <= READ_ADDR_ACTIVE;
                   READ_ADDR_ACTIVE :
                       read_addr_req_cs <= IDLE_READ_ADDR;

                  default : /* default */;
               endcase
       end
    end
    assign read_adfifo_wr_ena = (read_addr_req_cs==READ_ADDR_ACTIVE) ? 1'b1 : 1'b0;

    // h_addr_cnt の処理
    always @(posedge clk) begin : proc_h_addr_cnt
       if(reset) begin
            h_addr_cnt <= HORIZONTAL_PIXELS;
            read_adfifo_arlen <= 8'd0;
       end else begin
               if (start) begin
                   h_addr_cnt <= HORIZONTAL_PIXELS;
            end else if (h_addr_cnt!=0 && read_addr_req_cs==IDLE_READ_ADDR && read_adfifo_full==1'b0 && op_state==1'b1) begin
                if (h_addr_cnt>=BURST_LIMIT_VAL) begin
                    h_addr_cnt <= h_addr_cnt - BURST_LIMIT_VAL;
                    read_adfifo_arlen <= 8'd255;
                end else begin
                    h_addr_cnt <= 0;
                    read_adfifo_arlen <= h_addr_cnt[7:0] - 8'd1;
                end
            end
       end
    end

    // read_adfifo_addr の処理
    always @(posedge clk) begin : proc_read_adfifo_addr
       if(reset) begin
            read_adfifo_addr <= 0;
       end else begin
               if (start)
                   read_adfifo_addr <= start_addr;
            else if (read_addr_req_cs == READ_ADDR_ACTIVE)
                read_adfifo_addr <= read_adfifo_addr + (read_adfifo_arlen+8'd1)*(C_M_AXI_DATA_WIDTH/8);
       end
    end

    // 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
    always @(posedge clk) begin : proc_RGB2Y
        reg [15:0]    y_f;
        reg [7:0]    b, g, r;

       if(reset) begin
            y_data <= 8'd0;
       end else begin
               r = read_fifo_read_data[23:16];
               g = read_fifo_read_data[15:0];
               b = read_fifo_read_data[7:0];

               y_f = 77*r + 150*g + 29*b; //y_f = 0.299*r + 0.587*g + 0.114*b;の係数に256倍した
               y_data <= y_f[15:8];    // 256で割る
       end
    end

    // y_data_valid の処理
    always @(posedge clk) begin : proc_y_data_valid
       if(reset) begin
            y_data_valid <= 1'b0;
       end else begin
            if (read_fifo_empty_n)
                y_data_valid <= 1'b1;
            else
                y_data_valid <= 1'b0;
       end
    end

    assign read_fifo_rd_ena = 1'b1;

    // y_data のカウント
    always @(posedge clk) begin : proc_y_data_cnt
       if(reset) begin
            y_data_cnt <= HORIZONTAL_PIXELS;
       end else begin
               if (op_state==1'b1 && y_data_valid==1'b1 && y_data_cnt!=0)
                   y_data_cnt <= y_data_cnt - ONE;
               else if (start)
                   y_data_cnt <= HORIZONTAL_PIXELS;
       end
    end

    // done の処理
    always @(posedge clk) begin : proc_done
       if(reset) begin
            done <= 1'b0;
       end else begin
               if (y_data_cnt==ONE && y_data_valid==1'b1)
                   done <= 1'b1;
               else
                   done <= 1'b0;
       end
    end
endmodule

`default_nettype wire


次は、 Dual_Port_Memory.v だが、これは、”XST に Dual Port Memory を推論させる (Verilog HDL)”の Dual_Port_Memory_test.v と同じだが、モジュール名を変更したので、もう一度、貼っておく。

`default_nettype none

module Dual_Port_Memory #(
  parameter integer C_MEMORY_SIZE =   1024, // Word Memory Size (not byte)
  parameter integer DATA_BUS_WIDTH =  32    // RAM Data Width
)
(
    input  wire clk,
    input  wire we,
    input  wire [log2(C_MEMORY_SIZE)-1:0]   waddr,
    input  wire [log2(C_MEMORY_SIZE)-1:0]   raddr,
    input  wire [DATA_BUS_WIDTH-1:0]  din,
    output reg  [DATA_BUS_WIDTH-1:0]  dout
);

    // 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

    reg  [DATA_BUS_WIDTH-1:0]  ram  [0:C_MEMORY_SIZE-1];

    initial begin : memory_initialize
        integer i;
        for (i=0; i<C_MEMORY_SIZE; i=i+1)
            ram[i] = 0;
    end

    always  @(posedge  clk) begin
        if  (we)
            ram[waddr]  <=  din;

        dout  <=  ram[raddr];
    end

endmodule

`default_nettype wire


AXI4 Master アクセスのラプラシアン・フィルタ IP5(lap_filter_axim.v のHDLソース)”の続き。

今回は、Vivado HLSでラプラシアン・フィルタ AXI Master IP を作った際のAXI4 Lite Slave モジュール lap_filter_axim_LiteS_if.v を貼っておく。

// ==============================================================
// File generated by Vivado(TM) HLS - High-Level Synthesis from C, C++ and SystemC
// Version: 2013.3
// Copyright (C) 2013 Xilinx Inc. All rights reserved.
// 
// ==============================================================

`timescale 1ns/1ps
module lap_filter_axim_LiteS_if
#(parameter
    C_ADDR_WIDTH = 6,
    C_DATA_WIDTH = 32
)(
    // axi4 lite slave signals
    input  wire                      ACLK,
    input  wire                      ARESETN,
    input  wire [C_ADDR_WIDTH-1:0]   AWADDR,
    input  wire                      AWVALID,
    output wire                      AWREADY,
    input  wire [C_DATA_WIDTH-1:0]   WDATA,
    input  wire [C_DATA_WIDTH/8-1:0] WSTRB,
    input  wire                      WVALID,
    output wire                      WREADY,
    output wire [1:0]                BRESP,
    output wire                      BVALID,
    input  wire                      BREADY,
    input  wire [C_ADDR_WIDTH-1:0]   ARADDR,
    input  wire                      ARVALID,
    output wire                      ARREADY,
    output wire [C_DATA_WIDTH-1:0]   RDATA,
    output wire [1:0]                RRESP,
    output wire                      RVALID,
    input  wire                      RREADY,
    output wire                      interrupt,
    // user signals
    output wire [31:0]               I_cam_addr,
    output wire                      I_cam_addr_ap_vld,
    input  wire                      I_cam_addr_ap_ack,
    output wire [31:0]               I_lap_addr,
    output wire                      I_lap_addr_ap_vld,
    output wire                      I_ap_start,
    input  wire                      O_ap_ready,
    input  wire                      O_ap_done,
    input  wire                      O_ap_idle,
    input  wire [31:0]               O_ap_return
);
//------------------------Address Info-------------------
// 0x00 : Control signals
//        bit 0  - ap_start (Read/Write/COH)
//        bit 1  - ap_done (Read/COR)
//        bit 2  - ap_idle (Read)
//        bit 3  - ap_ready (Read)
//        bit 7  - auto_restart (Read/Write)
//        others - reserved
// 0x04 : Global Interrupt Enable Register
//        bit 0  - Global Interrupt Enable (Read/Write)
//        others - reserved
// 0x08 : IP Interrupt Enable Register (Read/Write)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x0c : IP Interrupt Status Register (Read/TOW)
//        bit 0  - Channel 0 (ap_done)
//        bit 1  - Channel 1 (ap_ready)
//        others - reserved
// 0x10 : Control signal of cam_addr
//        bit 0  - cam_addr_ap_vld (Read/Write/COH)
//        bit 1  - cam_addr_ap_ack (Read)
//        others - reserved
// 0x14 : Data signal of cam_addr
//        bit 31~0 - cam_addr[31:0] (Read/Write)
// 0x18 : Control signal of lap_addr
//        bit 0  - lap_addr_ap_vld (Read/Write/SC)
//        others - reserved
// 0x1c : Data signal of lap_addr
//        bit 31~0 - lap_addr[31:0] (Read/Write)
// 0x20 : Data signal of ap_return
//        bit 31~0 - ap_return[31:0] (Read)
// (SC = Self Clear, COR = Clear on Read, TOW = Toggle on Write, COH = Clear on Handshake)

//------------------------Parameter----------------------
// address bits
localparam
    ADDR_BITS = 6;

// address
localparam
    ADDR_AP_CTRL         = 6'h00,
    ADDR_GIE             = 6'h04,
    ADDR_IER             = 6'h08,
    ADDR_ISR             = 6'h0c,
    ADDR_CAM_ADDR_CTRL   = 6'h10,
    ADDR_CAM_ADDR_DATA_0 = 6'h14,
    ADDR_LAP_ADDR_CTRL   = 6'h18,
    ADDR_LAP_ADDR_DATA_0 = 6'h1c,
    ADDR_AP_RETURN_0     = 6'h20;

// axi write fsm
localparam
    WRIDLE = 2'd0,
    WRDATA = 2'd1,
    WRRESP = 2'd2;

// axi read fsm
localparam
    RDIDLE = 2'd0,
    RDDATA = 2'd1;

//------------------------Local signal-------------------
// axi write
reg  [1:0]           wstate;
reg  [1:0]           wnext;
reg  [ADDR_BITS-1:0] waddr;
wire [31:0]          wmask;
wire                 aw_hs;
wire                 w_hs;
// axi read
reg  [1:0]           rstate;
reg  [1:0]           rnext;
reg  [31:0]          rdata;
wire                 ar_hs;
wire [ADDR_BITS-1:0] raddr;
// internal registers
wire                 ap_idle;
reg                  ap_done;
wire                 ap_ready;
reg                  ap_start;
reg                  auto_restart;
reg                  gie;
reg  [1:0]           ier;
reg  [1:0]           isr;
reg  [31:0]          _cam_addr;
reg                  _cam_addr_ap_vld;
wire                 _cam_addr_ap_ack;
reg  [31:0]          _lap_addr;
reg                  _lap_addr_ap_vld;
wire [31:0]          ap_return;

//------------------------Body---------------------------
//++++++++++++++++++++++++axi write++++++++++++++++++++++
assign AWREADY = (wstate == WRIDLE);
assign WREADY  = (wstate == WRDATA);
assign BRESP   = 2'b00;  // OKAY
assign BVALID  = (wstate == WRRESP);
assign wmask   = { {8{WSTRB[3]}}, {8{WSTRB[2]}}, {8{WSTRB[1]}}, {8{WSTRB[0]}} };
assign aw_hs   = AWVALID & AWREADY;
assign w_hs    = WVALID & WREADY;

// wstate
always @(posedge ACLK) begin
    if (~ARESETN)
        wstate <= WRIDLE;
    else
        wstate <= wnext;
end

// wnext
always @(*) begin
    case (wstate)
        WRIDLE:
            if (AWVALID)
                wnext = WRDATA;
            else
                wnext = WRIDLE;
        WRDATA:
            if (WVALID)
                wnext = WRRESP;
            else
                wnext = WRDATA;
        WRRESP:
            if (BREADY)
                wnext = WRIDLE;
            else
                wnext = WRRESP;
        default:
            wnext = WRIDLE;
    endcase
end

// waddr
always @(posedge ACLK) begin
    if (aw_hs)
        waddr <= AWADDR[ADDR_BITS-1:0];
end
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++

//++++++++++++++++++++++++axi read+++++++++++++++++++++++
assign ARREADY = (rstate == RDIDLE);
assign RDATA   = rdata;
assign RRESP   = 2'b00;  // OKAY
assign RVALID  = (rstate == RDDATA);
assign ar_hs   = ARVALID & ARREADY;
assign raddr   = ARADDR[ADDR_BITS-1:0];

// rstate
always @(posedge ACLK) begin
    if (~ARESETN)
        rstate <= RDIDLE;
    else
        rstate <= rnext;
end

// rnext
always @(*) begin
    case (rstate)
        RDIDLE:
            if (ARVALID)
                rnext = RDDATA;
            else
                rnext = RDIDLE;
        RDDATA:
            if (RREADY)
                rnext = RDIDLE;
            else
                rnext = RDDATA;
        default:
            rnext = RDIDLE;
    endcase
end

// rdata
always @(posedge ACLK) begin
    if (ar_hs) begin
        rdata <= 1'b0;
        case (raddr)
            ADDR_AP_CTRL: begin
                rdata[0] <= ap_start;
                rdata[1] <= ap_done;
                rdata[2] <= ap_idle;
                rdata[3] <= ap_ready;
                rdata[7] <= auto_restart;
            end
            ADDR_GIE: begin
                rdata <= gie;
            end
            ADDR_IER: begin
                rdata <= ier;
            end
            ADDR_ISR: begin
                rdata <= isr;
            end
            ADDR_CAM_ADDR_CTRL: begin
                rdata[0] <= _cam_addr_ap_vld;
                rdata[1] <= _cam_addr_ap_ack;
            end
            ADDR_CAM_ADDR_DATA_0: begin
                rdata <= _cam_addr[31:0];
            end
            ADDR_LAP_ADDR_CTRL: begin
                rdata[0] <= _lap_addr_ap_vld;
            end
            ADDR_LAP_ADDR_DATA_0: begin
                rdata <= _lap_addr[31:0];
            end
            ADDR_AP_RETURN_0: begin
                rdata <= ap_return[31:0];
            end
        endcase
    end
end
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++

//++++++++++++++++++++++++internal registers+++++++++++++
assign interrupt         = gie & (|isr);
assign I_ap_start        = ap_start;
assign ap_idle           = O_ap_idle;
assign ap_ready          = O_ap_ready;
assign I_cam_addr_ap_vld = _cam_addr_ap_vld;
assign _cam_addr_ap_ack  = I_cam_addr_ap_ack;
assign I_cam_addr        = _cam_addr;
assign I_lap_addr_ap_vld = _lap_addr_ap_vld;
assign I_lap_addr        = _lap_addr;
assign ap_return         = O_ap_return;

// ap_start
always @(posedge ACLK) begin
    if (~ARESETN)
        ap_start <= 1'b0;
    else if (w_hs && waddr == ADDR_AP_CTRL && WSTRB[0] && WDATA[0])
        ap_start <= 1'b1;
    else if (O_ap_ready)
        ap_start <= auto_restart; // clear on handshake/auto restart
end

// ap_done
always @(posedge ACLK) begin
    if (~ARESETN)
        ap_done <= 1'b0;
    else if (O_ap_done)
        ap_done <= 1'b1;
    else if (ar_hs && raddr == ADDR_AP_CTRL)
        ap_done <= 1'b0; // clear on read
end

// auto_restart
always @(posedge ACLK) begin
    if (~ARESETN)
        auto_restart <= 1'b0;
    else if (w_hs && waddr == ADDR_AP_CTRL && WSTRB[0])
        auto_restart <=  WDATA[7];
end

// gie
always @(posedge ACLK) begin
    if (~ARESETN)
        gie <= 1'b0;
    else if (w_hs && waddr == ADDR_GIE && WSTRB[0])
        gie <= WDATA[0];
end

// ier
always @(posedge ACLK) begin
    if (~ARESETN)
        ier <= 1'b0;
    else if (w_hs && waddr == ADDR_IER && WSTRB[0])
        ier <= WDATA[1:0];
end

// isr[0]
always @(posedge ACLK) begin
    if (~ARESETN)
        isr[0] <= 1'b0;
    else if (ier[0] & O_ap_done)
        isr[0] <= 1'b1;
    else if (w_hs && waddr == ADDR_ISR && WSTRB[0])
        isr[0] <= isr[0] ^ WDATA[0]; // toggle on write
end

// isr[1]
always @(posedge ACLK) begin
    if (~ARESETN)
        isr[1] <= 1'b0;
    else if (ier[1] & O_ap_ready)
        isr[1] <= 1'b1;
    else if (w_hs && waddr == ADDR_ISR && WSTRB[0])
        isr[1] <= isr[1] ^ WDATA[1]; // toggle on write
end

// _cam_addr_ap_vld
always @(posedge ACLK) begin
    if (~ARESETN)
        _cam_addr_ap_vld <= 1'b0;
    else if (w_hs && waddr == ADDR_CAM_ADDR_CTRL && WSTRB[0] && WDATA[0])
        _cam_addr_ap_vld <= 1'b1;
    else if (I_cam_addr_ap_ack)
        _cam_addr_ap_vld <= 1'b0; // clear on handshake
end

// _cam_addr[31:0]
always @(posedge ACLK) begin
    if (w_hs && waddr == ADDR_CAM_ADDR_DATA_0)
        _cam_addr[31:0] <= (WDATA[31:0] & wmask) | (_cam_addr[31:0] & ~wmask);
end

// _lap_addr_ap_vld
always @(posedge ACLK) begin
    if (~ARESETN)
        _lap_addr_ap_vld <= 1'b0;
    else if (w_hs && waddr == ADDR_LAP_ADDR_CTRL && WSTRB[0] && WDATA[0])
        _lap_addr_ap_vld <= 1'b1;
    else
        _lap_addr_ap_vld <= 1'b0; // self clear
end

// _lap_addr[31:0]
always @(posedge ACLK) begin
    if (w_hs && waddr == ADDR_LAP_ADDR_DATA_0)
        _lap_addr[31:0] <= (WDATA[31:0] & wmask) | (_lap_addr[31:0] & ~wmask);
end

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++

endmodule


AXI4 Master アクセスのラプラシアン・フィルタ IP4(シミュレーション2)”の続き。

現在のところの lap_filter_axim.v を貼っておく。この回路の動作を下に示す。

1.画像データのDDR3メモリのアドレスと、ラプラシアン・フィルタ後の画像データのDDR3メモリのアドレスを内部レジスタに AXI4 Lite Slave アクセスでARMプロセッサからレジスタにWriteしてもらう。この行為に依って、ラプラシアン・フィルタ回路が動作する。
2.DDR3 メモリから画像データを1ライン分、AXI4 Master Read Transaction でRead する。
3.ラプラシアン・フィルタを掛けた後に、異なるDDR3 メモリのアドレスに、AXI4 Master Write Transaction でフィルタ後の1ライン分の画像データをWriteする。
3.2.から3.を1フレーム分行う。
4.レジスタのap_done ビットをセットする。


下に、lap_filter_axim.v を示す。(2013/12/02:修正)

`default_nettype none

//
// lap_filter_axim.v
// 2013/11/13 by marsee
//


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

    // AXI Master Interface
    parameter integer C_INTERCONNECT_M_AXI_WRITE_ISSUING = 8,
    parameter integer C_M_AXI_THREAD_ID_WIDTH       = 1,
    parameter integer C_M_AXI_ADDR_WIDTH            = 32,
    parameter integer C_M_AXI_DATA_WIDTH            = 32,
    parameter integer C_M_AXI_AWUSER_WIDTH          = 1,
    parameter integer C_M_AXI_ARUSER_WIDTH          = 1,
    parameter integer C_M_AXI_WUSER_WIDTH           = 1,
    parameter integer C_M_AXI_RUSER_WIDTH           = 1,
    parameter integer C_M_AXI_BUSER_WIDTH           = 1,
    parameter [31:0]  C_M_AXI_TARGET                = 32'h00000000,
    parameter integer C_M_AXI_BURST_LEN             = 256,
    parameter integer C_OFFSET_WIDTH                = 32,

    /* Disabling these parameters will remove any throttling.
    The resulting ERROR flag will not be useful */
    parameter integer C_M_AXI_SUPPORTS_WRITE         = 1,
    parameter integer C_M_AXI_SUPPORTS_READ          = 1,

    parameter integer HORIZONTAL_PIXELS             = 800,
    parameter integer VERTICAL_LINES                = 600
)
(
    // Clocks and Reset
    input wire                                      s_axi_lite_aclk,
    input wire                                      M_AXI_ACLK,
    input wire                                      ARESETN,

    ///////////////////////////////
    // AXI4 Lite Slave Interface //
    ///////////////////////////////
    // AXI Lite Write Address Channel
    input   wire                                    s_axi_lite_awvalid,
    output  wire                                    s_axi_lite_awready,
    input   wire    [C_S_AXI_LITE_ADDR_WIDTH-1:0]   s_axi_lite_awaddr,

    // AXI Lite Write Data Channel
    input   wire                                    s_axi_lite_wvalid,
    output  wire                                    s_axi_lite_wready,
    input   wire    [C_S_AXI_LITE_DATA_WIDTH-1:0]   s_axi_lite_wdata,
    input   wire    [C_S_AXI_LITE_DATA_WIDTH/8-1:0] s_axi_lite_wstrb,

    // AXI Lite Write Response Channel
    output  wire    [1:0]                           s_axi_lite_bresp,
    output  wire                                    s_axi_lite_bvalid,
    input   wire                                    s_axi_lite_bready,

    // AXI Lite Read Address Channel
    input   wire                                    s_axi_lite_arvalid,
    output  wire                                    s_axi_lite_arready,
    input   wire    [C_S_AXI_LITE_ADDR_WIDTH-1:0]   s_axi_lite_araddr,

    // AXI Lite Read Data Channel
    output  wire                                    s_axi_lite_rvalid,
    input   wire                                    s_axi_lite_rready,
    output  wire    [C_S_AXI_LITE_DATA_WIDTH-1:0]   s_axi_lite_rdata,
    output  wire    [1:0]                           s_axi_lite_rresp,

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

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

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

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

    // Master Interface Read Data
    input  wire [C_M_AXI_THREAD_ID_WIDTH-1:0]       M_AXI_RID,
    input  wire [C_M_AXI_DATA_WIDTH-1:0]            M_AXI_RDATA,
    input  wire [2-1:0]                             M_AXI_RRESP,
    input  wire                                     M_AXI_RLAST,
    input  wire [C_M_AXI_RUSER_WIDTH-1:0]           M_AXI_RUSER,
    input  wire                                     M_AXI_RVALID,
    output wire                                     M_AXI_RREADY,

    // User Signals
    output  wire                                    interrupt,

    // Error Signal
    output  reg                                     write_fifo_overflow
);

    // 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

    wire [31:0]               I_cam_addr;
    wire                      I_cam_addr_ap_vld;
    reg                       I_cam_addr_ap_ack;
    wire [31:0]               I_lap_addr;
    wire                      I_lap_addr_ap_vld;
    wire                      I_ap_start;
    wire                      O_ap_ready;
    wire                      O_ap_done;
    wire                      O_ap_idle;
    wire [31:0]               O_ap_return;
    reg     lap_addr_ap_vld_hold;

    reg write_adfifo_wr_ena;
    reg [C_M_AXI_ADDR_WIDTH-1:0] write_adfifo_addr;
    reg [7:0] write_adfifo_awlen;
    reg write_fifo_wr_ena;
    wire [31:0] write_fifo_write_data;
    wire [3:0] write_fifo_wstrb;
    wire read_adfifo_wr_ena;
    wire [31:0] read_adfifo_addr;
    wire [7:0] read_adfifo_arlen;
    wire read_fifo_rd_ena;
    reg init_done;
    wire write_adfifo_full;
    wire write_fifo_full;
    wire write_fifo_almost_full;
    wire read_adfifo_full;
    wire [31:0] read_fifo_read_data;
    wire read_fifo_empty_n;
    wire read_fifo_almost_empty_n;
    wire wr_resp_err;

    parameter [2:0] IDLE_MAIN =                     3'b000,
                    LINE_READ_AND_Y_1ST =           3'b001,
                    LINE_READ_AND_Y_2ND =           3'b011,
                    LINE_READ_AND_Y =               3'b010,
                    LAP_FILTER_AND_WRITE =          3'b110,
                    WAIT_AXI_WRITE_TRANSACTION =    3'b111,
                    AP_DONE_ACTIVE =                3'b101;
    reg     [2:0]   main_cs;

    parameter [1:0] IDLE_LINE_READ_AND_Y =      2'b00,
                    LINE_READ_AND_Y_START =     2'b01,
                    LINE_READ_AND_Y_ACTIVE =    2'b11;
    reg     [1:0]   line_read_y_cs;
    reg             line_read_y_start;
    reg     [C_M_AXI_ADDR_WIDTH-1:0]  start_addr;
    wire    line_read_y_done;
    wire    [7:0]   y_data;
    wire            y_data_valid;
    reg     [1:0]   line_buffer_wcount, line_buffer_rcount;
    wire            line_buf0_we, line_buf1_we, line_buf2_we;
    wire    [7:0]   line_buf_dout0, line_buf_dout1, line_buf_dout2;
    reg     [9:0]  line_buf_waddr, line_buf_raddr;
    reg     [7:0]   Xp1Ym1, Xp1Yn, Xp1Yp1;
    reg     [7:0]   XnYm1, XnYn, XnYp1, Xm1Ym1, Xm1Yn, Xm1Yp1;
    reg     [7:0]   lap_filter_out;
    reg     [log2(HORIZONTAL_PIXELS)-1:0]   lap_pixel_count;
    reg     [log2(VERTICAL_LINES)-1:0]      lap_line_count;

    parameter       IDLE_WRITE_ADDR =   1'b0,
                    WRITE_ADDR_ISSUE =  1'b1;
    reg             write_addr_cs;
    reg     [log2(HORIZONTAL_PIXELS)-1:0]   write_addr_count;
    wire            ACLK;
    wire            lap_line_end;
    wire            lap_frame_end;
    wire            write_fifo_empty;


    assign ACLK = M_AXI_ACLK;

    // AXI4 Lite Slave Module
    lap_filter_axim_LiteS_if #(
        .C_ADDR_WIDTH(C_S_AXI_LITE_ADDR_WIDTH),
        .C_DATA_WIDTH(C_S_AXI_LITE_DATA_WIDTH)
    ) lap_filter_axim_LiteS_if_U(
        .ACLK(s_axi_lite_aclk),
        .ARESETN(ARESETN),
        .AWADDR(s_axi_lite_awaddr),
        .AWVALID(s_axi_lite_awvalid),
        .AWREADY(s_axi_lite_awready),
        .WDATA(s_axi_lite_wdata),
        .WSTRB(s_axi_lite_wstrb),
        .WVALID(s_axi_lite_wvalid),
        .WREADY(s_axi_lite_wready),
        .BRESP(s_axi_lite_bresp),
        .BVALID(s_axi_lite_bvalid),
        .BREADY(s_axi_lite_bready),
        .ARADDR(s_axi_lite_araddr),
        .ARVALID(s_axi_lite_arvalid),
        .ARREADY(s_axi_lite_arready),
        .RDATA(s_axi_lite_rdata),
        .RRESP(s_axi_lite_rresp),
        .RVALID(s_axi_lite_rvalid),
        .RREADY(s_axi_lite_rready),
        .interrupt(interrupt),
        .I_cam_addr(I_cam_addr),
        .I_cam_addr_ap_vld(I_cam_addr_ap_vld),
        .I_cam_addr_ap_ack(I_cam_addr_ap_ack),
        .I_lap_addr(I_lap_addr),
        .I_lap_addr_ap_vld(I_lap_addr_ap_vld),
        .I_ap_start(I_ap_start),
        .O_ap_ready(O_ap_ready),
        .O_ap_done(O_ap_done),
        .O_ap_idle(O_ap_idle),
        .O_ap_return(O_ap_return)
    );

    // I_lap_addr_ap_vld
    always @(posedge ACLK) begin : proc_lap_addr_ap_valid_hold
       if(~ARESETN) begin
            lap_addr_ap_vld_hold <= 1'b0;
       end else begin
            if (I_lap_addr_ap_vld)
                lap_addr_ap_vld_hold <= 1'b1;
       end
    end

    // cam_addr_ap_vld, lap_addr_ap_vld  init_done
    always @(posedge s_axi_lite_aclk) begin : proc_init_done
       if(~ARESETN) begin
            init_done <= 1'b0;
            I_cam_addr_ap_ack <= 1'b0;
       end else begin
            if (lap_addr_ap_vld_hold & I_cam_addr_ap_vld) begin
                init_done <= 1'b1;
                I_cam_addr_ap_ack <= 1'b1;
            end
       end
    end

    assign O_ap_return = 32'd1;

    // axi4_master_inf instance
    axi4_master_inf #(
        .C_M_AXI_DATA_WIDTH(32)
    ) axi4_master_inf_U (
        .ACLK(ACLK),
        .ARESETN(ARESETN),
        .M_AXI_AWID(M_AXI_AWID),
        .M_AXI_AWADDR(M_AXI_AWADDR),
        .M_AXI_AWLEN(M_AXI_AWLEN),
        .M_AXI_AWSIZE(M_AXI_AWSIZE),
        .M_AXI_AWBURST(M_AXI_AWBURST),
        .M_AXI_AWLOCK(M_AXI_AWLOCK),
        .M_AXI_AWCACHE(M_AXI_AWCACHE),
        .M_AXI_AWPROT(M_AXI_AWPROT),
        .M_AXI_AWQOS(M_AXI_AWQOS),
        .M_AXI_AWUSER(M_AXI_AWUSER),
        .M_AXI_AWVALID(M_AXI_AWVALID),
        .M_AXI_AWREADY(M_AXI_AWREADY),
        .M_AXI_WDATA(M_AXI_WDATA),
        .M_AXI_WSTRB(M_AXI_WSTRB),
        .M_AXI_WLAST(M_AXI_WLAST),
        .M_AXI_WUSER(M_AXI_WUSER),
        .M_AXI_WVALID(M_AXI_WVALID),
        .M_AXI_WREADY(M_AXI_WREADY),
        .M_AXI_BID(M_AXI_BID),
        .M_AXI_BRESP(M_AXI_BRESP),
        .M_AXI_BUSER(M_AXI_BUSER),
        .M_AXI_BVALID(M_AXI_BVALID),
        .M_AXI_BREADY(M_AXI_BREADY),
        .M_AXI_ARID(M_AXI_ARID),
        .M_AXI_ARADDR(M_AXI_ARADDR),
        .M_AXI_ARLEN(M_AXI_ARLEN),
        .M_AXI_ARSIZE(M_AXI_ARSIZE),
        .M_AXI_ARBURST(M_AXI_ARBURST),
        .M_AXI_ARLOCK(M_AXI_ARLOCK),
        .M_AXI_ARCACHE(M_AXI_ARCACHE),
        .M_AXI_ARPROT(M_AXI_ARPROT),
        .M_AXI_ARQOS(M_AXI_ARQOS),
        .M_AXI_ARUSER(M_AXI_ARUSER),
        .M_AXI_ARVALID(M_AXI_ARVALID),
        .M_AXI_ARREADY(M_AXI_ARREADY),
        .M_AXI_RID(M_AXI_RID),
        .M_AXI_RDATA(M_AXI_RDATA),
        .M_AXI_RRESP(M_AXI_RRESP),
        .M_AXI_RLAST(M_AXI_RLAST),
        .M_AXI_RUSER(M_AXI_RUSER),
        .M_AXI_RVALID(M_AXI_RVALID),
        .M_AXI_RREADY(M_AXI_RREADY),
        .write_clk(ACLK),
        .write_rst(~ARESETN),
        .write_adfifo_wr_ena(write_adfifo_wr_ena),
        .write_adfifo_addr(write_adfifo_addr),
        .write_adfifo_awlen(write_adfifo_awlen),
        .write_adfifo_full(write_adfifo_full),
        .write_fifo_wr_ena(write_fifo_wr_ena),
        .write_fifo_write_data(write_fifo_write_data),
        .write_fifo_wstrb(write_fifo_wstrb),
        .write_fifo_full(write_fifo_full),
        .write_fifo_almost_full(write_fifo_almost_full),
        .write_fifo_empty(write_fifo_empty),
        .read_clk(ACLK),
        .read_rst(~ARESETN),
        .read_adfifo_wr_ena(read_adfifo_wr_ena),
        .read_adfifo_addr(read_adfifo_addr),
        .read_adfifo_arlen(read_adfifo_arlen),
        .read_adfifo_full(read_adfifo_full),
        .read_fifo_rd_ena(read_fifo_rd_ena),
        .read_fifo_read_data(read_fifo_read_data),
        .read_fifo_empty_n(read_fifo_empty_n),
        .read_fifo_almost_empty_n(read_fifo_almost_empty_n),
        .wr_resp_err(wr_resp_err),
        .init_done(init_done)
    );

    // write_fifo_overflow
    always @(posedge ACLK) begin : proc_write_fifo_overflow
       if(~ARESETN) begin
            write_fifo_overflow <= 1'b0;
       end else begin
            if (write_fifo_full & write_adfifo_wr_ena)
                write_fifo_overflow <= 1'b1;
       end
    end

    // Main State Machine
    always @(posedge ACLK) begin : proc_main_sm
       if(~ARESETN) begin
            main_cs <= IDLE_MAIN;
       end else begin
            case (main_cs)
                IDLE_MAIN :
                    if (init_done & I_ap_start) begin
                        main_cs <= LINE_READ_AND_Y_1ST;
                    end
                LINE_READ_AND_Y_1ST :
                    if (line_read_y_done) begin
                        main_cs <= LINE_READ_AND_Y;
                    end
                LINE_READ_AND_Y :
                    if (line_read_y_done) begin
                        main_cs <= LAP_FILTER_AND_WRITE;
                    end
                LAP_FILTER_AND_WRITE :
                    if (lap_frame_end) begin
                        main_cs <= AP_DONE_ACTIVE;
                    end else if (lap_line_end) begin
                        main_cs <= WAIT_AXI_WRITE_TRANSACTION;
                    end
                WAIT_AXI_WRITE_TRANSACTION :    // Write Transaction が完了するまでWait
                    if (write_fifo_empty)
                         main_cs <= LINE_READ_AND_Y;
                AP_DONE_ACTIVE : begin
                    main_cs <= IDLE_MAIN;
                end

               default : /* default */;
            endcase
       end
    end

    assign O_ap_done = (main_cs==AP_DONE_ACTIVE) ? 1'b1 : 1'b0;
    assign O_ap_ready = (main_cs==AP_DONE_ACTIVE) ? 1'b1 : 1'b0;
    assign O_ap_idle = (main_cs==IDLE_MAIN) ? 1'b1 : 1'b0;

    // 1 line Read State Machine
    always @(posedge ACLK) begin : proc_line_read_and_y_SM
       if(~ARESETN) begin
            line_read_y_cs <= IDLE_LINE_READ_AND_Y;
            line_read_y_start <= 1'b0;
       end else begin
            case (line_read_y_cs)
                IDLE_LINE_READ_AND_Y :
                    if (main_cs==LINE_READ_AND_Y_1ST || main_cs==LINE_READ_AND_Y_2ND || main_cs==LINE_READ_AND_Y) begin
                        line_read_y_cs <= LINE_READ_AND_Y_START;
                        line_read_y_start <= 1'b1;
                    end
                LINE_READ_AND_Y_START : begin
                    line_read_y_cs <= LINE_READ_AND_Y_ACTIVE;
                    line_read_y_start <= 1'b0;
                end
                LINE_READ_AND_Y_ACTIVE :
                    if (line_read_y_done)
                        line_read_y_cs <= IDLE_LINE_READ_AND_Y;
               default : /* default */;
            endcase
       end
    end

    line_read_and_y #(
        .C_M_AXI_ADDR_WIDTH(32),
        .C_M_AXI_DATA_WIDTH(32),
        .HORIZONTAL_PIXELS(800)
    ) line_read_and_y_U (/*autoinst*/
        .clk(ACLK),
        .reset(~ARESETN),
        .start_addr(start_addr[C_M_AXI_ADDR_WIDTH-1:0]),
        .start(line_read_y_start),
        .done(line_read_y_done),
        .y_data(y_data[7:0]),
        .y_data_valid(y_data_valid),
        .read_adfifo_wr_ena(read_adfifo_wr_ena),
        .read_adfifo_addr(read_adfifo_addr[C_M_AXI_ADDR_WIDTH-1:0]),
        .read_adfifo_arlen(read_adfifo_arlen[8-1:0]),
        .read_fifo_rd_ena(read_fifo_rd_ena),
        .read_adfifo_full(read_adfifo_full),
        .read_fifo_read_data(read_fifo_read_data[C_M_AXI_DATA_WIDTH-1:0]),
        .read_fifo_empty_n(read_fifo_empty_n),
        .read_fifo_almost_empty_n(read_fifo_almost_empty_n)
    );

    // line_read_and_y の start_addr の処理
    always @(posedge ACLK) begin : proc_start_addr
       if(~ARESETN) begin
            start_addr <= 0;
       end else begin
            if (I_cam_addr_ap_vld)
                start_addr <= I_cam_addr;
            else if (line_read_y_start) begin
                start_addr <= start_addr + HORIZONTAL_PIXELS*(C_M_AXI_DATA_WIDTH/8);
            end
       end
    end

    // line buffer として使用するDual Port Memory を決定する
    always @(posedge ACLK) begin : proc_line_buffer_wcount
       if(~ARESETN) begin
            line_buffer_wcount <= 2'd0;
       end else begin
            if (line_read_y_done) begin
                if (line_buffer_wcount == 2'd2)
                    line_buffer_wcount <= 2'd0;
                else
                    line_buffer_wcount <= line_buffer_wcount + 2'd1;
            end
       end
    end

    assign line_buf0_we = (line_buffer_wcount==2'd0 && y_data_valid==1'b1) ? 1'b1 : 1'b0;
    assign line_buf1_we = (line_buffer_wcount==2'd1 && y_data_valid==1'b1) ? 1'b1 : 1'b0;
    assign line_buf2_we = (line_buffer_wcount==2'd2 && y_data_valid==1'b1) ? 1'b1 : 1'b0;

    // line buffer 0
    Dual_Port_Memory #(
        .C_MEMORY_SIZE(1024),
        .DATA_BUS_WIDTH(8)
    ) line_buffer_0 (/*autoinst*/
            .dout(line_buf_dout0),
            .clk(ACLK),
            .we(line_buf0_we),
            .waddr(line_buf_waddr),
            .raddr(line_buf_raddr),
            .din(y_data)
     );
        // line buffer 1
    Dual_Port_Memory #(
        .C_MEMORY_SIZE(1024),
        .DATA_BUS_WIDTH(8)
    ) line_buffer_1 (/*autoinst*/
            .dout(line_buf_dout1),
            .clk(ACLK),
            .we(line_buf1_we),
            .waddr(line_buf_waddr),
            .raddr(line_buf_raddr),
            .din(y_data)
     );
        // line buffer 2
    Dual_Port_Memory #(
        .C_MEMORY_SIZE(1024),
        .DATA_BUS_WIDTH(8)
    ) line_buffer_2 (/*autoinst*/
            .dout(line_buf_dout2),
            .clk(ACLK),
            .we(line_buf2_we),
            .waddr(line_buf_waddr),
            .raddr(line_buf_raddr),
            .din(y_data)
     );

    // line_buf_waddr
    always @(posedge ACLK) begin : proc_line_buf_waddr
       if(~ARESETN) begin
            line_buf_waddr <= 10'd0;
       end else begin
            if (line_read_y_start)
                line_buf_waddr <= 10'd0;
            else if (y_data_valid)
                line_buf_waddr <= line_buf_waddr + 10'd1;
       end
    end

    // line_buf_raddr
    always @(posedge ACLK) begin : proc_line_buf_raddr
       if(~ARESETN) begin
            line_buf_raddr <= 10'd0;
       end else begin
            if (main_cs == LAP_FILTER_AND_WRITE)
                line_buf_raddr <= line_buf_raddr + 10'd1;
            else
                line_buf_raddr <= 10'd0;
       end
    end

    // line_buffer_rcount
    always @(posedge ACLK) begin : proc_line_buffer_rcount
       if(~ARESETN) begin
            line_buffer_rcount <= 2'd0;
       end else begin
            if (lap_line_end) begin
                if (line_buffer_rcount==2'd2)
                    line_buffer_rcount <= 2'd0;
                else
                    line_buffer_rcount <= line_buffer_rcount + 2'd1;
            end
       end
    end

    // Xp1Ym1, Xp1Yn, Xp1Yp1
    // 最初のラインは3ライン揃っていない状態でオール0の値を出力するので、3ライン揃うのはline_buffer_rcount==1の時からなので、1つずれている
    always @(posedge ACLK) begin : proc_XY_first_input
       if(~ARESETN) begin
            Xp1Ym1  <=  8'd0;
            Xp1Yn   <=  8'd0;
            Xp1Yp1  <=  8'd0;
       end else begin
            if (main_cs == LAP_FILTER_AND_WRITE) begin
                case (line_buffer_rcount)
                    2'd0 : begin
                        Xp1Ym1  <=  line_buf_dout2;
                        Xp1Yn   <=  line_buf_dout0;
                        Xp1Yp1  <=  line_buf_dout1;
                    end
                    2'd1 : begin
                        Xp1Ym1  <=  line_buf_dout0;
                        Xp1Yn   <=  line_buf_dout1;
                        Xp1Yp1  <=  line_buf_dout2;
                    end
                    2'd2 : begin
                        Xp1Ym1  <=  line_buf_dout1;
                        Xp1Yn   <=  line_buf_dout2;
                        Xp1Yp1  <=  line_buf_dout0;
                    end
                    default : /* default */;
                endcase
            end
       end
    end

    // XnYm1, XnYn, XnYp1, Xm1Ym1, Xm1Yn, Xm1Yp1
    always @(posedge ACLK) begin : proc_XY_2_3_stage
       if(~ARESETN) begin
            XnYm1   <=  8'd0;
            XnYn    <=  8'd0;
            XnYp1   <=  8'd0;
            Xm1Ym1  <=  8'd0;
            Xm1Yn   <=  8'd0;
            Xm1Yp1  <=  8'd0;
       end else begin
            XnYm1   <=  Xp1Ym1;
            XnYn    <=  Xp1Yn;
            XnYp1   <=  Xp1Yp1;
            Xm1Ym1  <=  XnYm1;
            Xm1Yn   <=  XnYn;
            Xm1Yp1  <=  XnYp1;
       end
    end

    // laplacian filter
    // DPMで1クロック、ラプラシアン・フィルタ用FFで3クロック遅延している
    always @(posedge ACLK) begin : proc_laplacian_filter
        reg    [12:0]  laplacian_filter;

       if(~ARESETN) begin
            lap_filter_out <= 8'd0;
       end else begin
            laplacian_filter = {1'b0, XnYn, 3'b000} - {4'b0000, Xp1Ym1} - {4'b0000, Xp1Yn} - {4'b0000, Xp1Yp1} - {4'b0000, XnYm1} - {4'b0000, XnYm1} - {4'b0000, Xm1Ym1} - {4'b0000, Xm1Yn} - {4'b0000, Xm1Yp1};

            // 1line のうちの最初と最後は0
            // DPMで1クロック、ラプラシアン・フィルタ用FFで3クロック遅延している。つまりデータが出てくるのは、lap_pixel_count=4 の時
            if (main_cs==LAP_FILTER_AND_WRITE && lap_pixel_count>=4 && lap_pixel_count<HORIZONTAL_PIXELS+2 && lap_line_count>=1 && lap_line_count<VERTICAL_LINES-1) begin
                if (laplacian_filter[11])   // minus
                    lap_filter_out <= 8'd0;
                else if (laplacian_filter[10]==1'b1 || laplacian_filter[9]==1'b1 || laplacian_filter[8]==1'b1)
                    lap_filter_out <= 8'd255;
                else
                    lap_filter_out <= laplacian_filter[7:0];
            end else
                lap_filter_out <= 8'd0;
       end
    end
    assign write_fifo_write_data = {8'b0000_0000, lap_filter_out, lap_filter_out, lap_filter_out};  // 8'd0, R, G, B
    assign write_fifo_wstrb = 4'b1111;

    // lap_pixel_count
    // ラプラシアン/フィルタの1 line = lap_pixel_count>=3 && lap_pixel_count<HORIZONTAL_PIXELS+3
    always @(posedge ACLK) begin : proc_lap_pixel_count
       if(~ARESETN) begin
            lap_pixel_count <= 0;
       end else begin
            if (main_cs==LAP_FILTER_AND_WRITE) begin
                if (lap_pixel_count == HORIZONTAL_PIXELS+2)
                    lap_pixel_count <= 0;
                else
                    lap_pixel_count <= lap_pixel_count + 1;
            end else
                lap_pixel_count <= 0;
       end
    end
    assign lap_line_end = (lap_pixel_count==HORIZONTAL_PIXELS+2) ? 1'b1 : 1'b0;

    // lap_line_count
    always @(posedge ACLK) begin : proc_lap_line_count
       if(~ARESETN) begin
            lap_line_count <= 0;
       end else begin
            if (main_cs==LAP_FILTER_AND_WRITE) begin
                if (lap_pixel_count==HORIZONTAL_PIXELS+2) begin
                    if (lap_line_count==VERTICAL_LINES-1)
                                lap_line_count <= 0;
                    else
                        lap_line_count <= lap_line_count + 1;
                end
            end
       end
    end
    assign lap_frame_end = (lap_pixel_count==HORIZONTAL_PIXELS+2 && lap_line_count==VERTICAL_LINES-1) ? 1'b1 : 1'b0;

    // wirte_fifo_wr_ena
    // ラプラシアン/フィルタの1 line = lap_pixel_count>=3 && lap_pixel_count<HORIZONTAL_PIXELS+3
    // write_adfifo_wr_ena の enable は、1クロック早く、ap_pixel_count==2 でenableし、ap_pixel_count==HORIZONTAL_PIXELS+2でディスエーブル
    always @(posedge ACLK) begin : proc_wirte_fifo_wr_ena
       if(~ARESETN) begin
            write_fifo_wr_ena <= 1'b0;
       end else begin
            if (write_fifo_almost_full)
                write_fifo_wr_ena <= 1'b0;
            else if (lap_pixel_count==2)
                write_fifo_wr_ena <= 1'b1;
            else if (lap_pixel_count==HORIZONTAL_PIXELS+2)
                write_fifo_wr_ena <= 1'b0;
       end
    end

    // write_adfifo_wr_ena, write_adfifo_wr_ena State Machine
    always @(posedge ACLK) begin : proc_write_addr_SM
       if(~ARESETN) begin
            write_addr_cs <= IDLE_WRITE_ADDR;
            write_adfifo_wr_ena <= 1'b0;
       end else begin
            case (write_addr_cs)
                IDLE_WRITE_ADDR :
                    if (main_cs==LAP_FILTER_AND_WRITE && write_addr_count!=0) begin
                        write_addr_cs <= WRITE_ADDR_ISSUE;
                        write_adfifo_wr_ena <= 1'b1;
                    end
                WRITE_ADDR_ISSUE :
                    begin
                        write_addr_cs <= IDLE_WRITE_ADDR;
                        write_adfifo_wr_ena <= 1'b0;
                    end
               default : /* default */;
            endcase
       end
    end

    // write_addr_count, write_adfifo_awlen
    always @(posedge ACLK) begin : proc_write_addr_count
       if(~ARESETN) begin
            write_addr_count <= HORIZONTAL_PIXELS;
            write_adfifo_awlen <= 8'd255;
       end else begin
            if (write_addr_cs==IDLE_WRITE_ADDR && main_cs==LAP_FILTER_AND_WRITE && write_addr_count!=0) begin
                if (write_addr_count >= 256) begin
                    write_addr_count <= write_addr_count - 10'd256;
                    write_adfifo_awlen <= 8'd255;
                end else begin // less than 256
                    write_addr_count <= 10'd0;
                    write_adfifo_awlen <= write_addr_count[7:0]-8'd1;
                end
            end else if (main_cs == LINE_READ_AND_Y)
                write_addr_count <= HORIZONTAL_PIXELS;
       end
    end

    // write_adfifo_addr
    always @(posedge ACLK) begin : proc_write_addr
       if(~ARESETN) begin
            write_adfifo_addr <= I_lap_addr;
       end else begin
            if (I_lap_addr_ap_vld)
                write_adfifo_addr <= I_lap_addr;
            else if (write_adfifo_wr_ena)
                write_adfifo_addr <= write_adfifo_addr + (write_adfifo_awlen + 8'd1)*(C_M_AXI_DATA_WIDTH/8);
       end
    end

endmodule

`default_nettype wire


↑このページのトップヘ