FC2カウンター FPGAの部屋 AXI4 Master アクセスのラプラシアン・フィルタ IP6(line_read_and_y.v と Dual_Port_Memory.v)
FC2ブログ

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

FPGAの部屋

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

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

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

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

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/2658-e2a23840
この記事にトラックバックする(FC2ブログユーザー)