FC2カウンター FPGAの部屋 2013年11月28日
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

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

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


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