FC2カウンター FPGAの部屋 2013年11月27日
FC2ブログ

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

FPGAの部屋

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

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

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

  1. 2013年11月27日 05:21 |
  2. Co-design
  3. | トラックバック:0
  4. | コメント:0