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

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

FPGAの部屋

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

AXI4 Slave インターフェースのメモリ・シミュレーション用 IP の作製3(テストベンチ)

AXI4 Slave インターフェースのメモリ・シミュレーション用 IP の作製2(シミュレーション)”の続き。

前回、ブログに貼れなかったテストベンチとOVLチェッカーを貼っておく。

最初に、テストベンチ (mem_sim_axi_slave_tb.v ) を下に貼る。

`default_nettype none

`timescale 100ps / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:
//
// Create Date:   04:01:46 06/27/2013
// Design Name:   mem_sim_axi_slave
// Module Name:   D:/HDL/FndtnISEWork/Zynq-7000/ZedBoard/test/mem_sim_axi_slave/mem_sim_axi_slave_tb.v
// Project Name:  mem_sim_axi_slave
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: mem_sim_axi_slave
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
////////////////////////////////////////////////////////////////////////////////

module mem_sim_axi_slave_tb;
    
    parameter DELAY    = 10;
    parameter NUMBER_OF_TEST = 100;    // テストする数
    
    parameter    ASIZE_BT_4    = 3'd2;    // 32 bit width
    parameter    ASIZE_BT_2 = 3'd1;    // 16 bit width
    parameter    ASIZE_BT_1 = 3'd0;    // 8 bit width
    
    parameter    ABURST_FIXED    = 2'd0;
    parameter    ABURST_INCR    = 2'd1;
    parameter    ABURST_WRAP    = 2'd2;
    
    parameter    BRESP_OKAY        = 2'b00;
    parameter    BRESP_EXOKAY    = 2'b01;
    parameter    BRESP_SLVERR    = 2'b10;
    parameter    BRESP_DECERR    = 2'b11;

    // Inputs
    wire ACLK;
    wire ARESETN;
    wire [0:0] S_AXI_AWID;
    wire [31:0] S_AXI_AWADDR;
    wire [7:0] S_AXI_AWLEN;
    wire [2:0] S_AXI_AWSIZE;
    wire [1:0] S_AXI_AWBURST;
    wire [1:0] S_AXI_AWLOCK;
    wire [3:0] S_AXI_AWCACHE;
    wire [2:0] S_AXI_AWPROT;
    wire [3:0] S_AXI_AWREGION;
    wire [3:0] S_AXI_AWQOS;
    wire [0:0] S_AXI_AWUSER;
    wire S_AXI_AWVALID;
    wire [0:0] S_AXI_WID;
    wire [31:0] S_AXI_WDATA;
    wire [3:0] S_AXI_WSTRB;
    wire S_AXI_WLAST;
    wire [0:0] S_AXI_WUSER;
    wire S_AXI_WVALID;
    wire S_AXI_BREADY;
    wire [0:0] S_AXI_ARID;
    wire [31:0] S_AXI_ARADDR;
    wire [7:0] S_AXI_ARLEN;
    wire [2:0] S_AXI_ARSIZE;
    wire [1:0] S_AXI_ARBURST;
    wire [1:0] S_AXI_ARLOCK;
    wire [3:0] S_AXI_ARCACHE;
    wire [2:0] S_AXI_ARPROT;
    wire [3:0] S_AXI_ARREGION;
    wire [3:0] S_AXI_ARQOS;
    wire [0:0] S_AXI_ARUSER;
    wire S_AXI_ARVALID;
    wire S_AXI_RREADY;

    // Outputs
    reg S_AXI_AWREADY;
    reg S_AXI_WREADY;
    reg [0:0] S_AXI_BID;
    reg [1:0] S_AXI_BRESP;
    wire [0:0] S_AXI_BUSER = 0;
    reg S_AXI_BVALID;
    reg S_AXI_ARREADY;
    reg [0:0] S_AXI_RID;
    reg [31:0] S_AXI_RDATA;
    reg [1:0] S_AXI_RRESP;
    reg S_AXI_RLAST;
    wire [0:0] S_AXI_RUSER = 0;
    reg S_AXI_RVALID;

    wire S_AXI_AWREADY_d;
    wire S_AXI_WREADY_d;
    wire [0:0]    S_AXI_BID_d;
    wire [1:0]    S_AXI_BRESP_d;
    wire S_AXI_BVALID_d;
    wire S_AXI_ARREADY_d;
    wire [0:0]    S_AXI_RID_d;
    wire [31:0]    S_AXI_RDATA_d;
    wire [1:0]    S_AXI_RRESP_d;
    wire S_AXI_RLAST_d;
    wire S_AXI_RVALID_d;
    
    // Instantiate the Unit Under Test (UUT)
    mem_sim_axi_slave #(
        .C_MEMORY_SIZE(1024)
    ) UUT (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .S_AXI_AWID(S_AXI_AWID), 
        .S_AXI_AWADDR(S_AXI_AWADDR), 
        .S_AXI_AWLEN(S_AXI_AWLEN), 
        .S_AXI_AWSIZE(S_AXI_AWSIZE), 
        .S_AXI_AWBURST(S_AXI_AWBURST), 
        .S_AXI_AWLOCK(S_AXI_AWLOCK), 
        .S_AXI_AWCACHE(S_AXI_AWCACHE), 
        .S_AXI_AWPROT(S_AXI_AWPROT), 
        .S_AXI_AWREGION(S_AXI_AWREGION), 
        .S_AXI_AWQOS(S_AXI_AWQOS), 
        .S_AXI_AWUSER(S_AXI_AWUSER), 
        .S_AXI_AWVALID(S_AXI_AWVALID), 
        .S_AXI_AWREADY(S_AXI_AWREADY_d), 
        .S_AXI_WID(S_AXI_WID), 
        .S_AXI_WDATA(S_AXI_WDATA), 
        .S_AXI_WSTRB(S_AXI_WSTRB), 
        .S_AXI_WLAST(S_AXI_WLAST), 
        .S_AXI_WUSER(S_AXI_WUSER), 
        .S_AXI_WVALID(S_AXI_WVALID), 
        .S_AXI_WREADY(S_AXI_WREADY_d), 
        .S_AXI_BID(S_AXI_BID_d), 
        .S_AXI_BRESP(S_AXI_BRESP_d), 
        .S_AXI_BUSER(S_AXI_BUSER), 
        .S_AXI_BVALID(S_AXI_BVALID_d), 
        .S_AXI_BREADY(S_AXI_BREADY), 
        .S_AXI_ARID(S_AXI_ARID), 
        .S_AXI_ARADDR(S_AXI_ARADDR), 
        .S_AXI_ARLEN(S_AXI_ARLEN), 
        .S_AXI_ARSIZE(S_AXI_ARSIZE), 
        .S_AXI_ARBURST(S_AXI_ARBURST), 
        .S_AXI_ARLOCK(S_AXI_ARLOCK), 
        .S_AXI_ARCACHE(S_AXI_ARCACHE), 
        .S_AXI_ARPROT(S_AXI_ARPROT), 
        .S_AXI_ARREGION(S_AXI_ARREGION), 
        .S_AXI_ARQOS(S_AXI_ARQOS), 
        .S_AXI_ARUSER(S_AXI_ARUSER), 
        .S_AXI_ARVALID(S_AXI_ARVALID), 
        .S_AXI_ARREADY(S_AXI_ARREADY_d), 
        .S_AXI_RID(S_AXI_RID_d), 
        .S_AXI_RDATA(S_AXI_RDATA_d), 
        .S_AXI_RRESP(S_AXI_RRESP_d), 
        .S_AXI_RLAST(S_AXI_RLAST_d), 
        .S_AXI_RUSER(S_AXI_RUSER), 
        .S_AXI_RVALID(S_AXI_RVALID_d), 
        .S_AXI_RREADY(S_AXI_RREADY) 
    );
    always @* S_AXI_AWREADY <= #DELAY S_AXI_AWREADY_d;
    always @* S_AXI_WREADY <= #DELAY S_AXI_WREADY_d;
    always @* S_AXI_BID <= #DELAY S_AXI_BID_d;
    always @* S_AXI_BRESP <= #DELAY S_AXI_BRESP_d;
    always @* S_AXI_BVALID <= #DELAY S_AXI_BVALID_d;
    always @* S_AXI_ARREADY <= #DELAY S_AXI_ARREADY_d;
    always @* S_AXI_RID <= #DELAY S_AXI_RID_d;
    always @* S_AXI_RDATA <= #DELAY S_AXI_RDATA_d;
    always @* S_AXI_RRESP <= #DELAY S_AXI_RRESP_d;
    always @* S_AXI_RLAST <= #DELAY S_AXI_RLAST_d;
    always @* S_AXI_RVALID <= #DELAY S_AXI_RVALID_d;
    
    // clk_gen のインスタンス
    clk_gen #(
        .CLK_PERIOD(100),    // 10nsec, 100MHz
        .CLK_DUTY_CYCLE(0.5),
        .CLK_OFFSET(0),
        .START_STATE(1'b0)
    ) ACLKi (
        .clk_out(ACLK)
    );
    
    // reset_gen のインスタンス
    reset_gen #(
        .RESET_STATE(1'b0),
        .RESET_TIME(1000)    // 100nsec
    ) RESETi (
        .reset_out(ARESETN)
    );
    
    // AXI4_BFM のインスタンス
    AXI4_Master_BFM #(
        .DELAY(DELAY)
    ) MBFMi(
        .ACLK(ACLK), 
        .S_AXI_AWID(S_AXI_AWID), 
        .S_AXI_AWADDR(S_AXI_AWADDR), 
        .S_AXI_AWLEN(S_AXI_AWLEN), 
        .S_AXI_AWSIZE(S_AXI_AWSIZE), 
        .S_AXI_AWBURST(S_AXI_AWBURST), 
        .S_AXI_AWLOCK(S_AXI_AWLOCK), 
        .S_AXI_AWCACHE(S_AXI_AWCACHE), 
        .S_AXI_AWPROT(S_AXI_AWPROT), 
        .S_AXI_AWREGION(S_AXI_AWREGION), 
        .S_AXI_AWQOS(S_AXI_AWQOS), 
        .S_AXI_AWUSER(S_AXI_AWUSER), 
        .S_AXI_AWVALID(S_AXI_AWVALID), 
        .S_AXI_AWREADY(S_AXI_AWREADY), 
        .S_AXI_WID(S_AXI_WID), 
        .S_AXI_WDATA(S_AXI_WDATA), 
        .S_AXI_WSTRB(S_AXI_WSTRB), 
        .S_AXI_WLAST(S_AXI_WLAST), 
        .S_AXI_WUSER(S_AXI_WUSER), 
        .S_AXI_WVALID(S_AXI_WVALID), 
        .S_AXI_WREADY(S_AXI_WREADY), 
        .S_AXI_BID(S_AXI_BID), 
        .S_AXI_BRESP(S_AXI_BRESP), 
        .S_AXI_BUSER(S_AXI_BUSER), 
        .S_AXI_BVALID(S_AXI_BVALID), 
        .S_AXI_BREADY(S_AXI_BREADY), 
        .S_AXI_ARID(S_AXI_ARID), 
        .S_AXI_ARADDR(S_AXI_ARADDR), 
        .S_AXI_ARLEN(S_AXI_ARLEN), 
        .S_AXI_ARSIZE(S_AXI_ARSIZE), 
        .S_AXI_ARBURST(S_AXI_ARBURST), 
        .S_AXI_ARLOCK(S_AXI_ARLOCK), 
        .S_AXI_ARCACHE(S_AXI_ARCACHE), 
        .S_AXI_ARPROT(S_AXI_ARPROT), 
        .S_AXI_ARREGION(S_AXI_ARREGION), 
        .S_AXI_ARQOS(S_AXI_ARQOS), 
        .S_AXI_ARUSER(S_AXI_ARUSER), 
        .S_AXI_ARVALID(S_AXI_ARVALID), 
        .S_AXI_ARREADY(S_AXI_ARREADY), 
        .S_AXI_RID(S_AXI_RID), 
        .S_AXI_RDATA(S_AXI_RDATA), 
        .S_AXI_RRESP(S_AXI_RRESP), 
        .S_AXI_RLAST(S_AXI_RLAST), 
        .S_AXI_RUSER(S_AXI_RUSER), 
        .S_AXI_RVALID(S_AXI_RVALID), 
        .S_AXI_RREADY(S_AXI_RREADY)
    );
    
    // OVL Checker
    OVL_Checker OVLi (
        .ACLK(ACLK), 
        .ARESETN(ARESETN), 
        .S_AXI_AWID(S_AXI_AWID), 
        .S_AXI_AWADDR(S_AXI_AWADDR), 
        .S_AXI_AWLEN(S_AXI_AWLEN), 
        .S_AXI_AWSIZE(S_AXI_AWSIZE), 
        .S_AXI_AWBURST(S_AXI_AWBURST), 
        .S_AXI_AWLOCK(S_AXI_AWLOCK), 
        .S_AXI_AWCACHE(S_AXI_AWCACHE), 
        .S_AXI_AWPROT(S_AXI_AWPROT), 
        .S_AXI_AWREGION(S_AXI_AWREGION), 
        .S_AXI_AWQOS(S_AXI_AWQOS), 
        .S_AXI_AWUSER(S_AXI_AWUSER), 
        .S_AXI_AWVALID(S_AXI_AWVALID), 
        .S_AXI_AWREADY(S_AXI_AWREADY), 
        .S_AXI_WID(S_AXI_WID), 
        .S_AXI_WDATA(S_AXI_WDATA), 
        .S_AXI_WSTRB(S_AXI_WSTRB), 
        .S_AXI_WLAST(S_AXI_WLAST), 
        .S_AXI_WUSER(S_AXI_WUSER), 
        .S_AXI_WVALID(S_AXI_WVALID), 
        .S_AXI_WREADY(S_AXI_WREADY), 
        .S_AXI_BID(S_AXI_BID), 
        .S_AXI_BRESP(S_AXI_BRESP), 
        .S_AXI_BUSER(S_AXI_BUSER), 
        .S_AXI_BVALID(S_AXI_BVALID), 
        .S_AXI_BREADY(S_AXI_BREADY), 
        .S_AXI_ARID(S_AXI_ARID), 
        .S_AXI_ARADDR(S_AXI_ARADDR), 
        .S_AXI_ARLEN(S_AXI_ARLEN), 
        .S_AXI_ARSIZE(S_AXI_ARSIZE), 
        .S_AXI_ARBURST(S_AXI_ARBURST), 
        .S_AXI_ARLOCK(S_AXI_ARLOCK), 
        .S_AXI_ARCACHE(S_AXI_ARCACHE), 
        .S_AXI_ARPROT(S_AXI_ARPROT), 
        .S_AXI_ARREGION(S_AXI_ARREGION), 
        .S_AXI_ARQOS(S_AXI_ARQOS), 
        .S_AXI_ARUSER(S_AXI_ARUSER), 
        .S_AXI_ARVALID(S_AXI_ARVALID), 
        .S_AXI_ARREADY(S_AXI_ARREADY), 
        .S_AXI_RID(S_AXI_RID), 
        .S_AXI_RDATA(S_AXI_RDATA), 
        .S_AXI_RRESP(S_AXI_RRESP), 
        .S_AXI_RLAST(S_AXI_RLAST), 
        .S_AXI_RUSER(S_AXI_RUSER), 
        .S_AXI_RVALID(S_AXI_RVALID), 
        .S_AXI_RREADY(S_AXI_RREADY)
    );        
    
    
    // test
    
    // Write Channel
    
    // wr_data生成、+1する
    reg        [15:0]    wcount;
    wire    [31:0]    wdata;
    
    always @(posedge ACLK) begin
        if (~ARESETN)
            wcount <= 0;
        else begin
            if (S_AXI_WVALID & S_AXI_WREADY)
                wcount <= wcount + 16'd1;
        end
    end
    assign wdata = {{16{1'b0}}, wcount};

    
    reg    WriteTaskBusy = 1'b0;
    integer wt_cnt;
    initial begin
        // Wait 100 ns for global reset to finish
        #1000;
        #5000;    // 500nsec Wait, PLL Locked
        
        @(posedge ACLK);    // 次のクロックへ
        #DELAY;
        
        for (wt_cnt=0; wt_cnt<NUMBER_OF_TEST; wt_cnt=wt_cnt+1) begin
            WriteTaskBusy = 1'b1;
            MBFMi.AXI_Master_1Seq_Write(0, 32'h100, 8'd7, ASIZE_BT_4, ABURST_INCR, wdata, 0, 2);
            MBFMi.AXI_Master_1Seq_Write(0, 32'h200, 8'd3, ASIZE_BT_4, ABURST_INCR, wdata, 1, 3);
            MBFMi.AXI_Master_1Seq_Write(0, 32'h300, 8'd1, ASIZE_BT_4, ABURST_INCR, wdata, 1, 4);
            MBFMi.AXI_Master_1Seq_Write(0, 32'h400, 8'd0, ASIZE_BT_4, ABURST_INCR, wdata, 1, 5);
            
            WriteTaskBusy = 1'b0;
            while (ReadTestBusy) begin // Read 終了待ち
                @(posedge ACLK);    // 次のクロックへ
                #DELAY;
            end
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
        end
    end
    
    // Read Channel
    reg    ReadTestBusy = 1'b0;
    integer rd_cnt;
    initial begin
        // Wait 100 ns for global reset to finish
        #1000;
        #5000;    // 500nsec Wait, PLL Locked
        
        for (rd_cnt=0; rd_cnt<NUMBER_OF_TEST; rd_cnt=rd_cnt+1) begin
            
            ReadTestBusy = 1'b1;
            #1000;
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
            
            MBFMi.AXI_Master_1Seq_Read(0, 32'h100, 8'd7, ASIZE_BT_4, ABURST_INCR, 2);
            MBFMi.AXI_Master_1Seq_Read(0, 32'h200, 8'd3, ASIZE_BT_4, ABURST_INCR, 3);
            MBFMi.AXI_Master_1Seq_Read(0, 32'h300, 8'd1, ASIZE_BT_4, ABURST_INCR, 4);
            MBFMi.AXI_Master_1Seq_Read(0, 32'h400, 8'd0, ASIZE_BT_4, ABURST_INCR, 5);
            
            ReadTestBusy = 1'b0;
            while (WriteTaskBusy) begin // Write の終了待ち
                @(posedge ACLK);    // 次のクロックへ
                #DELAY;
            end
            @(posedge ACLK);    // 次のクロックへ
            #DELAY;
        end
    end
    
endmodule

module clk_gen #(
    parameter         CLK_PERIOD = 100,
    parameter real    CLK_DUTY_CYCLE = 0.5,
    parameter        CLK_OFFSET = 0,
    parameter        START_STATE    = 1'b0 )
(
    output    reg        clk_out
);
    begin
        initial begin
            #CLK_OFFSET;
            forever
            begin
                clk_out = START_STATE;
                #(CLK_PERIOD-(CLK_PERIOD*CLK_DUTY_CYCLE)) clk_out = ~START_STATE;
                #(CLK_PERIOD*CLK_DUTY_CYCLE);
            end
        end
    end
endmodule

module reset_gen #(
    parameter    RESET_STATE = 1'b1,
    parameter    RESET_TIME = 100 )
(
    output    reg        reset_out
);
    begin
        initial begin
            reset_out = RESET_STATE;
            #RESET_TIME;
            reset_out = ~RESET_STATE;
        end
    end
endmodule

`default_nettype wire


次に、OVLチェッカー (OVL_Checker.v) を貼っておく。(2013/07/12:大幅変更)

// OVL_Checker.v
// 2012/10/25:書き込みトランザクションの時に、MasterがAWREADYを待って、WVALIDをアサートしていけないというルールがあったので、修正した。
// 2013/07/12:大幅に書き換えた
//

`default_nettype none

`timescale 100ps / 1ps

`include "std_ovl_defines.h"

module OVL_Checker (
    input    wire    ACLK,
    input    wire    ARESETN,

    input wire [0:0] S_AXI_AWID,
    input wire [31:0] S_AXI_AWADDR,
    input wire [7:0] S_AXI_AWLEN,
    input wire [2:0] S_AXI_AWSIZE,
    input wire [1:0] S_AXI_AWBURST,
    input wire [1:0] S_AXI_AWLOCK,
    input wire [3:0] S_AXI_AWCACHE,    // Normal Non-cacheable Non-bufferable
    input wire [2:0] S_AXI_AWPROT,
    input wire [3:0] S_AXI_AWREGION,
    input wire [3:0] S_AXI_AWQOS,
    input wire [0:0] S_AXI_AWUSER,
    input wire S_AXI_AWVALID,
    input wire [0:0] S_AXI_WID,
    input wire [31:0] S_AXI_WDATA,
    input wire [3:0] S_AXI_WSTRB,
    input wire S_AXI_WLAST,
    input wire [0:0] S_AXI_WUSER,
    input wire S_AXI_WVALID,
    input wire S_AXI_BREADY,
    input wire [0:0] S_AXI_ARID,
    input wire [31:0] S_AXI_ARADDR,
    input wire [7:0] S_AXI_ARLEN,
    input wire [2:0] S_AXI_ARSIZE,
    input wire [1:0] S_AXI_ARBURST,
    input wire [1:0] S_AXI_ARLOCK,
    input wire [3:0] S_AXI_ARCACHE, // Normal Non-cacheable Non-bufferable
    input wire [2:0] S_AXI_ARPROT,
    input wire [3:0] S_AXI_ARREGION,
    input wire [3:0] S_AXI_ARQOS,
    input wire [0:0] S_AXI_ARUSER,
    input wire S_AXI_ARVALID,
    input wire S_AXI_RREADY,

    input wire S_AXI_AWREADY,
    input wire S_AXI_WREADY,
    input wire [0:0] S_AXI_BID,
    input wire [1:0] S_AXI_BRESP,
    input wire [0:0] S_AXI_BUSER,
    input wire S_AXI_BVALID,
    input wire S_AXI_ARREADY,
    input wire [0:0] S_AXI_RID,
    input wire [31:0] S_AXI_RDATA,
    input wire [1:0] S_AXI_RRESP,
    input wire S_AXI_RLAST,
    input wire [0:0] S_AXI_RUSER,
    input wire S_AXI_RVALID
);

    wire [`OVL_FIRE_WIDTH-1:0] fire_wr_data, fire_rd_data;
    wire [`OVL_FIRE_WIDTH-1:0] fire_aw_hcheck, fire_ar_hcheck;
    wire [`OVL_FIRE_WIDTH-1:0] fire_awvalid_cont, fire_wd_sig_assert;
    wire [`OVL_FIRE_WIDTH-1:0] fire_ar_never;
    reg        [7:0]    countw, countr;
    
    parameter    idle_wts =        3'b001,
                wr_data_tran =    3'b010,
                wr_resp_tran =    3'b100;
    reg    [2:0]    wr_tran_cs;
    
    parameter    idle_rts =        1'b0,
                rd_data_tran =    1'b1;
    reg    rd_trans_cs;
    
    reg S_AXI_WDATA_d, S_AXI_RDATA_d;
    
    // Wirte Transaction データが+1されていることをチェックする(BFM Check)
    ovl_increment #(
        `OVL_ERROR,            // severity_level
        32,                        // width
        1,                        // value
        `OVL_ASSERT,            // property_type
        "Error: Write data has not been incremented", // msg
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock_edge
        `OVL_ACTIVE_HIGH,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) wr_data_check (
        ACLK,                    // clock
        ~ARESETN | (S_AXI_AWVALID & S_AXI_AWREADY),    // reset, Write のアドレス転送でリセット
        S_AXI_WVALID & S_AXI_WREADY,                    // enable
        S_AXI_WDATA,            // test_expr
        fire_wr_data            // fire    parameter
    );
    
    // Read Transaction データが+1されていることをチェックする(BFM Check)
    ovl_increment #(
        `OVL_ERROR,            // severity_level
        32,                        // width
        1,                        // value
        `OVL_ASSERT,            // property_type
        "Error: Read data has not been incremented", // msg
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock_edge
        `OVL_ACTIVE_HIGH,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) rd_data_check (
        ACLK,                    // clock
        ~ARESETN | (S_AXI_ARVALID & S_AXI_ARREADY),    // reset, Read のアドレス転送でリセット
        S_AXI_RVALID & S_AXI_RREADY,                    // enable
        S_AXI_RDATA,            // test_expr
        fire_rd_data            // fire    parameter
    );
    
    // S_AXI_AWVALID とS_AXI_AWREADY のハンドシェークのテスト
    ovl_change #(
        `OVL_ERROR,             // severity_level 
        1,                         // width 
        1,                         // num_cks 
        `OVL_IGNORE_NEW_START,     // action_on_new_start
        `OVL_ASSERT,             // property_type
        "INFO: AWREADY invalid synchronization",// msg 
        `OVL_COVER_DEFAULT,        // coverage_level 
        `OVL_POSEDGE,            // clock_edge 
        `OVL_ACTIVE_LOW,        // reset_polarity 
        `OVL_GATE_CLOCK            // gating_type
    ) aw_valid_ready_check (
        ACLK,                      // clock 
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_AWVALID == 1'b1,     // start_event 
        S_AXI_AWREADY,            // test_expr 
        fire_aw_hcheck            // fire    
    );

    // S_AXI_ARVALID とS_AXI_ARREADY のハンドシェークのテスト
    ovl_change #(
        `OVL_ERROR,             // severity_level 
        1,                         // width 
        1,                         // num_cks 
        `OVL_IGNORE_NEW_START,     // action_on_new_start
        `OVL_ASSERT,             // property_type
        "Error: ARREADY invalid synchronization",// msg 
        `OVL_COVER_DEFAULT,        // coverage_level 
        `OVL_POSEDGE,            // clock_edge 
        `OVL_ACTIVE_LOW,        // reset_polarity 
        `OVL_GATE_CLOCK            // gating_type
    ) ar_valid_ready_check (
        ACLK,                      // clock 
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_ARVALID == 1'b1,     // start_event 
        S_AXI_ARREADY,            // test_expr 
        fire_ar_hcheck            // fire    
    );
    
    // Write, S_AXI_AWREADY がアサートされるとき、次のクロックでS_AXI_AWVALIDがディアサートされる(エラーではない)
    ovl_transition #(
        `OVL_INFO,                // severity_level
        1,                        // width
        `OVL_ASSERT,            // property_type
        "Info : S_AXI_AWVALID have been asserted to continue",
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock edge
        `OVL_ACTIVE_LOW,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) awvalid_cont_assert (
        ACLK,                    // clock_edge
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_AWVALID,        // test_expr
        1'b1,                    // start_state
        (S_AXI_AWREADY == 1'b1) ? 1'b0 : 1'b1,    // next_state
        fire_awvalid_cont
    );
    
    // Write, S_AXI_WVALID, S_AXI_WLAST, S_AXI_WREADYがアサートされるとき、次のクロックで、それらの信号がディアサートされる
    ovl_change #(
        `OVL_ERROR,             // severity_level 
        1,                         // width 
        1,                         // num_cks 
        `OVL_IGNORE_NEW_START,     // action_on_new_start
        `OVL_ASSERT,             // property_type
        "Error : After S_AXI_WREADY and S_AXI_WLAST and S_AXI_WVALID is asserted at the same time, S_AXI_WVALID is not de-asserted.",// msg 
        `OVL_COVER_DEFAULT,        // coverage_level 
        `OVL_POSEDGE,            // clock_edge 
        `OVL_ACTIVE_LOW,        // reset_polarity 
        `OVL_GATE_CLOCK            // gating_type
    ) wd_sig_wvalid_assert (
        ACLK,                      // clock 
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_WVALID==1'b1 && S_AXI_WLAST==1'b1 && S_AXI_WREADY==1'b1,     // start_event 
        S_AXI_WVALID,            // test_expr 
        fire_ar_hcheck            // fire    
    );
    
    ovl_change #(
        `OVL_ERROR,             // severity_level 
        1,                         // width 
        1,                         // num_cks 
        `OVL_IGNORE_NEW_START,     // action_on_new_start
        `OVL_ASSERT,             // property_type
        "Error : After S_AXI_WREADY and S_AXI_WLAST and S_AXI_WVALID is asserted at the same time, S_AXI_WLAST is not de-asserted.",// msg 
        `OVL_COVER_DEFAULT,        // coverage_level 
        `OVL_POSEDGE,            // clock_edge 
        `OVL_ACTIVE_LOW,        // reset_polarity 
        `OVL_GATE_CLOCK            // gating_type
    ) wd_sig_wlast_assert (
        ACLK,                      // clock 
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_WVALID==1'b1 && S_AXI_WLAST==1'b1 && S_AXI_WREADY==1'b1,     // start_event 
        S_AXI_WLAST,            // test_expr 
        fire_ar_hcheck            // fire    
    );
    
    ovl_change #(
        `OVL_INFO,                 // severity_level 
        1,                         // width 
        1,                         // num_cks 
        `OVL_IGNORE_NEW_START,     // action_on_new_start
        `OVL_ASSERT,             // property_type
        "INFO : After S_AXI_WREADY and S_AXI_WLAST and S_AXI_WVALID is asserted at the same time, S_AXI_WREADY is not de-asserted.",// msg 
        `OVL_COVER_DEFAULT,        // coverage_level 
        `OVL_POSEDGE,            // clock_edge 
        `OVL_ACTIVE_LOW,        // reset_polarity 
        `OVL_GATE_CLOCK            // gating_type
    ) wd_sig_wready_assert (
        ACLK,                      // clock 
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_WVALID==1'b1 && S_AXI_WLAST==1'b1 && S_AXI_WREADY==1'b1,     // start_event 
        S_AXI_WREADY,            // test_expr 
        fire_ar_hcheck            // fire    
    );
    
    // Read, S_AXI_RREADY がアサートされるときは、 S_AXI_RVALID, S_AXI_RREADY, S_AXI_RLAST はアサートされない
    ovl_never #(
        `OVL_ERROR,                // severity_level
        `OVL_ASSERT,            // property_type
        "Read, Assert Error of S_AXI_RREADY",
        `OVL_COVER_DEFAULT,        // coverage_level
        `OVL_POSEDGE,            // clock edge
        `OVL_ACTIVE_LOW,        // reset_polarity
        `OVL_GATE_CLOCK            // gating_type
    ) ar_never_assert (
        ACLK,                    // clock_edge
        ARESETN,                // reset
        1'b1,                    // enable
        S_AXI_ARREADY & (S_AXI_RVALID | S_AXI_RREADY | S_AXI_RLAST),
        fire_ar_never
    );
    
    // Write の転送数をカウントして、 S_AXI_WLAST の出力を確認するアサーション
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0)
            countw <= 0;
        else begin
            if (S_AXI_AWVALID & S_AXI_AWREADY) begin // countw へロード
                countw <= S_AXI_AWLEN;
            end else if (S_AXI_WVALID & S_AXI_WREADY) begin // データ転送
                if (countw==0) begin // データ転送終了
                    if (~S_AXI_WLAST) begin // countw==0 でS_AXI_WLASTが立たない
                        $display("%m: at time %t Error: countw==0 でS_AXI_WLASTが立たない",$time);
                    end
                end
            end
        end
    end
    
    // Read の転送数をカウントして、 S_AXI_RLAST の出力を確認するアサーション
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0)
            countr <= 0;
        else begin
            if (S_AXI_ARVALID & S_AXI_ARREADY) begin // countw へロード
                countr <= S_AXI_ARLEN;
            end else if (S_AXI_RVALID & S_AXI_RREADY) begin // データ転送
                if (countr==0) begin // データ転送終了
                    if (~S_AXI_RLAST) begin // countw==0 でS_AXI_WLASTが立たない
                        $display("%m: at time %t Error: countr==0 でS_AXI_WLASTが立たない",$time);
                    end
                end
            end
        end
    end
    
    // Write 動作用ステートマシン
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0)
            wr_tran_cs <= idle_wts;
        else begin
            case (wr_tran_cs)
                idle_wts :
                    if (S_AXI_AWREADY & (S_AXI_BREADY)) // エラー
                        $display("%m: at time %t S_AXI_AWREADY がアサートされた時に、BREADY信号がアサートされた",$time);
                    else if (S_AXI_AWVALID & S_AXI_AWREADY) // アドレス転送終了
                        wr_tran_cs <= wr_data_tran;
                wr_data_tran :
                    if (S_AXI_BREADY) // エラー
                        $display("%m: at time %t Write データ転送中に、S_AXI_BREADY がアサートされた",$time);
                    else if (S_AXI_WVALID & S_AXI_WREADY & S_AXI_WLAST) // データ転送終了
                        wr_tran_cs <= wr_resp_tran;
                wr_resp_tran :
                    if (S_AXI_WVALID | S_AXI_WREADY | S_AXI_WLAST) // エラー 2013/06/28: S_AXI_AWREADY を条件から削除した
                        $display("%m: at time %t Write Response Channel 転送時に関連しない信号がアサートされた",$time);
                    else if (S_AXI_BVALID & S_AXI_BREADY) // Write Response Channel 転送終了
                        wr_tran_cs <= idle_wts;
            endcase
        end
    end
    
    // Read 動作用ステートマシン
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0)
            rd_trans_cs <= idle_rts;
        else begin
            case (rd_trans_cs)
                idle_rts :
                    if (S_AXI_ARREADY & (S_AXI_RVALID | S_AXI_RREADY | S_AXI_RLAST)) // エラー
                        $display("%m: at time %t S_AXI_ARREADY がアサートされた時に、その他のVALID, READY信号がアサートされた",$time);
                    else if (S_AXI_ARVALID & S_AXI_ARREADY) // アドレス転送終了
                        rd_trans_cs <= rd_data_tran;
                rd_data_tran :
                    if (S_AXI_ARREADY) // エラー
                        $display("%m: at time %t Read データ転送中に、S_AXI_ARREADY がアサートされた",$time);
                    else if (S_AXI_RVALID & S_AXI_RREADY & S_AXI_RLAST) // データ転送終了
                        rd_trans_cs <= idle_rts;
            endcase
        end
    end
                        
endmodule    

`default_nettype wire

  1. 2013年07月03日 04:24 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:5

お神輿用LED配線基板が来ました

KiCad 2013-05-31 BZR 4019 でFusionPCBに基板を注文”でFusionPCBに発注した基板が昨日届きました。6月15日に注文して、7月1日に着いたので、足掛け18日で届きました。長く感じたのですが、普通の納期ですね。
kiban_130702.jpg

基板の大きさは 5cm x 5cm です。10枚注文したのですが、12枚入っていました。
部品を載せてみましたが(ハンダ付けはしていません)、パッドやホールは大丈夫のようです。

問題は基板の切断ですが、使う分は、なひたふさんに教えて頂いた、オルファ PカッターL型 205B を購入したので、これで切ろうと思います。残りは、FPGA-CAFEの基板切断機を借りて切ろうと思っています。
  1. 2013年07月02日 05:30 |
  2. プリント基板作成
  3. | トラックバック:0
  4. | コメント:0

AXI4 Slave インターフェースのメモリ・シミュレーション用 IP の作製2(シミュレーション)

AXI4 Slave インターフェースのメモリ・シミュレーション用 IP の作製1”の続き。

ISim で OVL Ver. 2.7 のOVLライブラリのコンパイルと登録”と”ISim で OVL Ver. 2.7 のOVLライブラリを使用したシミュレーション”で、OVLライブラリもISim で使用可能になったので、出来上がったAXI4 Slave インターフェースのメモリ・シミュレーション用 IPをシミュレーションしてみた。

Project Navigator のプロジェクトとISimの画面は、”ISim で OVL Ver. 2.7 のOVLライブラリを使用したシミュレーション”に使用している。この時は、OVL_HANDSHAKE の OVL_ERROR が出ていたが、これは、AWREADY や ARREADY を常時1にアサートしていて、AWVALID や ARVALID が来た時だけディアサートする仕様に変更したためだった。この場合は、OVL_HANDSHAKE は使えないようだ。その代わりにOVL_CHANGE を使って、AxVALID == 1 の後に、AxREADY が変化するのを監視することにした。

シミュレーション波形は、概略を貼っただけで、詳しくは見ていなかったので、詳しく見ていこう。
最初は、AXI4 バスのWrite で、0x100番地から順番にに0x0~0x7までをWriteしている。
std_ovl_v2p7_simlib_10_130702.png

次は、Writeに対するRead波形を下に示す。0x100番地から順番に0x0~0x7までをRead できている。
std_ovl_v2p7_simlib_11_130702.png

AXI4_Master_BFM.v に、Write する場合は、AXI_Master_1Seq_Write タスクを用意してあって、それをテストベンチから呼び出すことで、AXI4 Maste Writeアクセスを行うことができる。Read する場合は、AXI_Master_1Seq_Read タスクを呼び出す。AXI4_Master_BFM.v は、”キャラクタ・ディスプレイ・コントローラをAXI4スレーブにする8.3(AXI Master BFMのVerilogコード)”に貼ってあるので、そちらを参照のこと。

肝心のAXI4 Slave IPのシミュレーション用メモリモジュール、mem_sim_axi_slave.v を貼っておく。

//-----------------------------------------------------------------------------
//-- (c) Copyright 2010 Xilinx, Inc. All rights reserved.
//--
//-- This file contains confidential and proprietary information
//-- of Xilinx, Inc. and is protected under U.S. and
//-- international copyright and other intellectual property
//-- laws.
//--
//-- DISCLAIMER
//-- This disclaimer is not a license and does not grant any
//-- rights to the materials distributed herewith. Except as
//-- otherwise provided in a valid license issued to you by
//-- Xilinx, and to the maximum extent permitted by applicable
//-- law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND
//-- WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES
//-- AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
//-- BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-
//-- INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and
//-- (2) Xilinx shall not be liable (whether in contract or tort,
//-- including negligence, or under any other theory of
//-- liability) for any loss or damage of any kind or nature
//-- related to, arising under or in connection with these
//-- materials, including for any direct, or any indirect,
//-- special, incidental, or consequential loss or damage
//-- (including loss of data, profits, goodwill, or any type of
//-- loss or damage suffered as a result of any action brought
//-- by a third party) even if such damage or loss was
//-- reasonably foreseeable or Xilinx had been advised of the
//-- possibility of the same.
//--
//-- CRITICAL APPLICATIONS
//-- Xilinx products are not designed or intended to be fail-
//-- safe, or for use in any application requiring fail-safe
//-- performance, such as life-support or safety devices or
//-- systems, Class III medical devices, nuclear facilities,
//-- applications related to the deployment of airbags, or any
//-- other applications that could lead to death, personal
//-- injury, or severe property or environmental damage
//-- (individually and collectively, "Critical
//-- Applications"). Customer assumes the sole risk and
//-- liability of any use of Xilinx products in Critical
//-- Applications, subject only to applicable laws and
//-- regulations governing limitations on product liability.
//--
//-- THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS
//-- PART OF THIS FILE AT ALL TIMES.
//-----------------------------------------------------------------------------
//
// AXI Slave
//
// Verilog-standard:  Verilog 2001
//--------------------------------------------------------------------------
//
// Structure:
//   mem_sim_axi_slave
//
//--------------------------------------------------------------------------
// 
// アクセスのデータ幅は、定義されたデータ幅だけに対応する

`default_nettype none

module mem_sim_axi_slave # (
    parameter integer C_S_AXI_ID_WIDTH             = 1,
    parameter integer C_S_AXI_ADDR_WIDTH            = 32,
    parameter integer C_S_AXI_DATA_WIDTH            = 32,
    parameter integer C_S_AXI_AWUSER_WIDTH          = 1,
    parameter integer C_S_AXI_ARUSER_WIDTH          = 1,
    parameter integer C_S_AXI_WUSER_WIDTH           = 1,
    parameter integer C_S_AXI_RUSER_WIDTH           = 1,
    parameter integer C_S_AXI_BUSER_WIDTH           = 1,

    parameter integer C_MEMORY_SIZE                    = 512    // Word (not byte)
) (
    // System Signals
    input wire ACLK,
    input wire ARESETN,

    // Slave Interface Write Address Ports
    input  wire [C_S_AXI_ID_WIDTH-1:0]     S_AXI_AWID,
    input  wire [C_S_AXI_ADDR_WIDTH-1:0]   S_AXI_AWADDR,
    input  wire [8-1:0]                  S_AXI_AWLEN,
    input  wire [3-1:0]                  S_AXI_AWSIZE,
    input  wire [2-1:0]                  S_AXI_AWBURST,
    input  wire [2-1:0]                  S_AXI_AWLOCK,
    input  wire [4-1:0]                  S_AXI_AWCACHE,
    input  wire [3-1:0]                  S_AXI_AWPROT,
    input  wire [4-1:0]                  S_AXI_AWREGION,
    input  wire [4-1:0]                  S_AXI_AWQOS,
    input  wire [C_S_AXI_AWUSER_WIDTH-1:0] S_AXI_AWUSER,
    input  wire                          S_AXI_AWVALID,
    output wire                          S_AXI_AWREADY,

    // Slave Interface Write Data Ports
    input wire [C_S_AXI_ID_WIDTH-1:0]      S_AXI_WID,
    input  wire [C_S_AXI_DATA_WIDTH-1:0]   S_AXI_WDATA,
    input  wire [C_S_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
    input  wire                          S_AXI_WLAST,
    input  wire [C_S_AXI_WUSER_WIDTH-1:0]  S_AXI_WUSER,
    input  wire                          S_AXI_WVALID,
    output wire                          S_AXI_WREADY,

    // Slave Interface Write Response Ports
    output wire [C_S_AXI_ID_WIDTH-1:0]    S_AXI_BID,
    output wire [2-1:0]                 S_AXI_BRESP,
    output wire [C_S_AXI_BUSER_WIDTH-1:0] S_AXI_BUSER,
    output wire                         S_AXI_BVALID,
    input  wire                         S_AXI_BREADY,

    // Slave Interface Read Address Ports
    input  wire [C_S_AXI_ID_WIDTH-1:0]     S_AXI_ARID,
    input  wire [C_S_AXI_ADDR_WIDTH-1:0]   S_AXI_ARADDR,
    input  wire [8-1:0]                  S_AXI_ARLEN,
    input  wire [3-1:0]                  S_AXI_ARSIZE,
    input  wire [2-1:0]                  S_AXI_ARBURST,
    input  wire [2-1:0]                  S_AXI_ARLOCK,
    input  wire [4-1:0]                  S_AXI_ARCACHE,
    input  wire [3-1:0]                  S_AXI_ARPROT,
    input  wire [4-1:0]                  S_AXI_ARREGION,
    input  wire [4-1:0]                  S_AXI_ARQOS,
    input  wire [C_S_AXI_ARUSER_WIDTH-1:0] S_AXI_ARUSER,
    input  wire                          S_AXI_ARVALID,
    output wire                          S_AXI_ARREADY,

    // Slave Interface Read Data Ports
    output wire [C_S_AXI_ID_WIDTH-1:0]    S_AXI_RID,
    output wire [C_S_AXI_DATA_WIDTH-1:0]  S_AXI_RDATA,
    output wire [2-1:0]                 S_AXI_RRESP,
    output wire                         S_AXI_RLAST,
    output wire [C_S_AXI_RUSER_WIDTH-1:0] S_AXI_RUSER,
    output wire                         S_AXI_RVALID,
    input  wire                         S_AXI_RREADY
   
);

    // Value of S_AXI_BRESP
    localparam    RESP_OKAY =        2'b00,
                RESP_EXOKAY =    2'b01,
                RESP_SLVERR =    2'b10,
                RESP_DECERR =    2'b11;
    
    // Value of S_AXI_ARBURST
    localparam    AxBURST_FIXED =    2'b00,
                AxBURST_INCR =    2'b01,
                AxBURST_WRAP =    2'b10;

    localparam    IDLE_WADDR =         1'b0,
                AWREADY_HOLD_OFF =    1'b1;
    reg        waddr_sm_cs;
    reg        awready;
    reg        awid;
    reg        [C_S_AXI_ADDR_WIDTH-1:0]    waddr;
    reg        [C_S_AXI_ID_WIDTH-1:0]    wid;
    reg        [2-1:0]    awburst;
    
    localparam    IDLE_WDATA =    1'b0,
                WREADY_ASSERT =    1'b1;
    reg        wdata_sm_cs;
    reg        wready;
    
    localparam    IDLE_WRES =        1'b0,
                BVALID_ASSERT =    1'b1;
    reg        wres_sm_cs;
    reg        [2-1:0]    bresp;
    reg        bvalid;
    
    localparam    IDLE_RADDR =        1'b0,
                ARREADY_HOLD_OFF =    1'b1;
    reg        raddr_sm_cs;
    reg        arready;
    reg        [C_S_AXI_ID_WIDTH-1:0]    arid;
    reg        [C_S_AXI_ADDR_WIDTH-1:0]    raddr;
    
    localparam    IDLE_RDATA =    1'b0,
                RVALID_ASSERT =    1'b1;
    reg        rdata_sm_cs;
    reg        rvalid;
    reg        [C_S_AXI_ID_WIDTH-1:0]    rid;
    reg        [1:0]    rresp;
    reg        [8:0]    rdata_count;
    
    localparam    IDLE_RLAST =     1'b0,
                RLAST_ASSERT =    1'b1;
    reg        rlast_sm_cs;
    reg        rlast;
    
    // instance memory_8bit
    generate
        genvar i;
        
        for (i=(C_S_AXI_DATA_WIDTH/8-1); i>=0; i=i-1) begin : MEMORY_GEN
            memory_8bit #(
                .C_S_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH),
                .C_MEMORY_SIZE(C_MEMORY_SIZE)
            ) memory_8bit_i (
                .clk(ACLK),
                .waddr(waddr),
                .write_data(S_AXI_WDATA[i*8+7:i*8]),
                .write_enable(wready & S_AXI_WVALID),
                .byte_enable(S_AXI_WSTRB[i]),
                .raddr(raddr),
                .read_data(S_AXI_RDATA[i*8+7:i*8])
            );
        end
    endgenerate
    
    // Write Transaction
    assign S_AXI_BUSER = 1'd0;
    
    // waddr State Machine
    // awready is normally 1. if S_AXI_AWVALID is 1 then awready is 0.
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            waddr_sm_cs <= IDLE_WADDR;
            awready <= 1'b1;
            awid <= {C_S_AXI_ID_WIDTH{1'b0}};
            awburst <= 2'd0;
        end else begin
            case (waddr_sm_cs)
                IDLE_WADDR : 
                    if (S_AXI_AWVALID) begin
                        waddr_sm_cs <= AWREADY_HOLD_OFF;
                        awready <= 1'b0;
                        awid <= S_AXI_AWID;
                        awburst <= S_AXI_AWBURST;
                    end
                AWREADY_HOLD_OFF :
                    if (bvalid) begin
                        waddr_sm_cs <= IDLE_WADDR;
                        awready <= 1'b1;
                    end
            endcase
        end
    end
    assign S_AXI_AWREADY = awready;
    
    // waddr
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            waddr <= {C_S_AXI_ADDR_WIDTH{1'b0}};
        end else begin
            if (waddr_sm_cs == IDLE_WADDR & S_AXI_AWVALID)
                waddr <= S_AXI_AWADDR;
            else if (wready & S_AXI_WVALID)
                waddr <= waddr + C_S_AXI_DATA_WIDTH/8;
        end
    end
    
    // wdata State Machine
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            wdata_sm_cs <= IDLE_WDATA;
            wready <= 1'b0;
        end else begin
            case (wdata_sm_cs)
                IDLE_WDATA :
                    if (waddr_sm_cs == IDLE_WADDR && S_AXI_AWVALID) begin // Write transaction start
                        wdata_sm_cs <= WREADY_ASSERT;
                        wready <= 1'b1;
                    end
                WREADY_ASSERT :
                    if (S_AXI_WLAST & S_AXI_WVALID) begin    // Write transaction end
                        wdata_sm_cs <= IDLE_WDATA;
                        wready <= 1'b0;
                    end
            endcase
        end
    end
    assign S_AXI_WREADY = wready;
    
    assign S_AXI_BID = awid;
    // Write Response State Machine
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            wres_sm_cs <= IDLE_WRES;
            bvalid <= 1'b0;
        end else begin
            case (wres_sm_cs)
                IDLE_WRES :
                    if (wdata_sm_cs == WREADY_ASSERT & S_AXI_WLAST & S_AXI_WVALID) begin    // Write transaction end
                        wres_sm_cs <= BVALID_ASSERT;
                        bvalid <= 1'b1;
                    end
                BVALID_ASSERT :
                    if (S_AXI_BREADY) begin
                        wres_sm_cs <= IDLE_WRES;
                        bvalid <= 1'b0;
                    end
            endcase
        end
    end
    assign S_AXI_BVALID = bvalid;
    
    // bresp
    // if S_AXI_AWBURST is INCR then return OKAY else return SLVERR
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0)
            bresp <= 2'b0;
        else begin
            if (waddr_sm_cs == AWREADY_HOLD_OFF) begin
                if (awburst == AxBURST_INCR) // The burst type is Addres Increment Type
                    bresp <= RESP_OKAY; // The Write Transaction is success
                else
                    bresp <= RESP_SLVERR; // Error
            end
        end
    end
    assign S_AXI_BRESP = bresp;

    // Read Transaction
    assign S_AXI_RUSER = 0;
    
    // raddr State Machine
    // arready is normally 1. if S_AXI_ARVALID is 1 then arready is 0.
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            raddr_sm_cs <= IDLE_RADDR;
            arready <= 1'b1;
            arid <= {C_S_AXI_ID_WIDTH{1'b0}};
        end else begin
            case (raddr_sm_cs)
                IDLE_RADDR :
                    if (S_AXI_ARVALID) begin
                        raddr_sm_cs <= ARREADY_HOLD_OFF;
                        arready <= 1'b0;
                        arid <= S_AXI_ARID;
                    end
                ARREADY_HOLD_OFF :
                    if (rvalid & S_AXI_RREADY & S_AXI_RLAST) begin // Read Transaction End
                        raddr_sm_cs <= IDLE_RADDR;
                        arready <= 1'b1;
                    end
            endcase
        end
    end
    assign S_AXI_ARREADY = arready;
    
    // raddr
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            raddr <= {C_S_AXI_ADDR_WIDTH{1'b0}};
        end else begin
            if (raddr_sm_cs == IDLE_RADDR & S_AXI_ARVALID)
                raddr <= S_AXI_ARADDR;
            else if (rvalid & S_AXI_RREADY)
                raddr <= raddr + C_S_AXI_ADDR_WIDTH/8;
        end
    end
    
    // rdata State Machine
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            rdata_sm_cs <= IDLE_RDATA;
            rvalid <= 1'b0;
            rid <= {C_S_AXI_ID_WIDTH{1'b0}};
        end else begin
            case (rdata_sm_cs)
                IDLE_RDATA :
                    if (raddr_sm_cs == IDLE_RADDR & S_AXI_ARVALID) begin 
                        rdata_sm_cs <= RVALID_ASSERT;
                        rvalid <= 1'b1;
                    end
                RVALID_ASSERT :
                    if (rlast & S_AXI_RREADY) begin
                        rdata_sm_cs <= IDLE_RDATA;
                        rvalid <= 1'b0;
                    end
            endcase
        end
    end
    assign S_AXI_RVALID = rvalid;
    assign S_AXI_RID = arid;
    
    //     assign S_AXI_RRESP = RESP_OKAY;
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            rresp <= RESP_OKAY;
        end else if (rdata_sm_cs == RVALID_ASSERT && rid != arid) begin
            rresp <= RESP_SLVERR;
        end
    end
    assign S_AXI_RRESP = rresp;
    
    // rdata_count
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            rdata_count <= 9'd0;
        end else begin
            if (raddr_sm_cs == IDLE_RADDR & S_AXI_ARVALID)
                rdata_count <= {1'b0, S_AXI_ARLEN} + 9'd1;
            else if (rvalid & S_AXI_RREADY)
                rdata_count <= rdata_count - 9'd1;
        end
    end
    
    // rlast
    always @(posedge ACLK) begin
        if (ARESETN == 1'b0) begin
            rlast_sm_cs <= IDLE_RLAST;
            rlast <= 1'b0;
        end else begin
            case (rlast_sm_cs)
                IDLE_RLAST :
                    if (rdata_count == 9'd2 && (rvalid & S_AXI_RREADY)) begin
                        rlast_sm_cs <= RLAST_ASSERT;
                        rlast <= 1'b1;
                    end else if (raddr_sm_cs==IDLE_RADDR && S_AXI_ARVALID==1'b1 && S_AXI_ARLEN==8'd0) begin
                    // 転送数が1の時はデータ転送の最初からrlast を1にする
                        rlast_sm_cs <= RLAST_ASSERT;
                        rlast <= 1'b1;
                    end
                RLAST_ASSERT :
                    if (rvalid & S_AXI_RREADY) begin
                        rlast_sm_cs <= IDLE_RLAST;
                        rlast <= 1'b0;
                    end
            endcase
        end
    end
    assign S_AXI_RLAST = rlast;
    
endmodule


mem_sim_axi_slave.v の下位モジュールの memory_8bit.v を下に貼っておく。これは、バイト・イネーブルを使用するためにメモリを8ビットごとに分けたからだ。このメモリは、残念ながらBlock RAMに割り当てることは出来ない。シミュレーション用となる。インプリするとSLICEMが使われると思う。(2013/07/03:バグ修正)(2013/07/16:修正)

// 8bit Memory Module

`default_nettype none

module memory_8bit #(
    parameter integer C_S_AXI_ADDR_WIDTH            = 32,
    parameter integer C_MEMORY_SIZE                    = 512    // Word (not byte)
)(
    input    wire    clk,
    input    wire    [C_S_AXI_ADDR_WIDTH-1:0]    waddr,
    input    wire    [7:0]    write_data,
    input    wire    write_enable,
    input    wire    byte_enable,
    input    wire    [C_S_AXI_ADDR_WIDTH-1:0]    raddr,
    output    wire    [7:0]    read_data
);

    // 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        [7:0]    mem    [0:C_MEMORY_SIZE-1];
    wire    [log2(C_MEMORY_SIZE)-1:0]    mem_waddr;
    wire    [log2(C_MEMORY_SIZE)-1:0]    mem_raddr;
    integer i;

    // initialization
    initial begin
        for (i=0; i < C_MEMORY_SIZE; i=i+1) begin
            mem[i] = 8'd0;
        end
    end
   
    // The Address is byte address
    assign mem_waddr = waddr[(log2(C_MEMORY_SIZE)+log2((C_S_AXI_ADDR_WIDTH/8)))-1:log2((C_S_AXI_ADDR_WIDTH/8))];
    assign mem_raddr = raddr[(log2(C_MEMORY_SIZE)+log2((C_S_AXI_ADDR_WIDTH/8)))-1:log2((C_S_AXI_ADDR_WIDTH/8))];
    
    // Write
    always @(posedge clk) begin
        if (write_enable & byte_enable)
            mem[mem_waddr] <= write_data;
    end
    
    // Read
    // always @(posedge clk) begin
    assign read_data = mem[mem_raddr];
    // end
endmodule

`default_nettype wire


Block RAM対応にしなかったのは、この方がバーストするのに便利だからだ。どのみち、シミュレーションしかしないので、これで良しということにした。
  1. 2013年07月02日 04:50 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

FabLab SENDAI - FLAT に行ってきた

土曜日にさくらんぼ狩りに行って、仙台の娘のところに行った時に、FabLab SENDAI - FLAT にお邪魔して来ました。

場所は、仙台のダイエーのある中央通りを南方向に少し歩いた場所IKIビルの4階にありました。少しわかりにくかったです。FPGA-CAFE/FabLab Tsukuba も知らないとわかりにくいと思いますが。。。

IKIビルの中に入ってみると、ありました。4階にあるそうです。
FabLab_Sendai_1_120630.jpg

4階までエレベーターで行くと、どこに行ったら良いのか迷っていると、エレベーターから降りて右側に、FabLab SENDAI - FLATの看板が出ていました。鉄の扉なので、中がどうなっているかわからずに、ちょっと入りづらかったです。ガラスとかで中が見えると入りやすいですね。

中に入ると、FPGA-CAFE/FabLab Tsukubaに比べるとかなり広いです。FPGA-CAFE/FabLab Tsukuba は秘密基地感が半端ないですが、ここは至ってまともなスペース的に余裕のある空間でした。全景を写真に取れなかったのが残念ですが、”FLATとは?”のページが空間の状況をよく表していると思いました。
スタッフの方とユーザーの方がいらっしゃいました。”FabLab Tsukuba のユーザーですが、FabLab SENDAI - FLATを見せて頂けますか?”と尋ねると、丁寧に説明して頂きました。(スタッフの皆さん、ありがとうございました)

FabLab SENDAI - FLATは、”FLATは仙台市「クリエイターのためのものづくり支援事業」として株式会社anno lab( http://annolab.com )が運営しています。”とWebページの下にも書いてありますが、仙台市が支援しているそうです。そのため、定休日が週に2日で、それ以外は営業しているそうです。また、オープンしてから2ヶ月しか経っていないそうです。

さて、設備はと言いますと、2台の3Dプリンタが特徴的ですね。FPGA-CAFE/FabLab Tsukubaには3Dプリンタはありません。入って左側です。(FabLab SENDAI - FLAT の FACILITIES のページです)
FabLab_Sendai_2_120630.jpg

写真がわかりにくくてすみませんが、Makerbot Replicator 2 Solidoodle の3Dプリンタが2台ありました。ABSとPLAのフィラメントが使えるそうです。

その奥にレーザー加工機がありました。UNIVERSAL VLS3.50だそうです。50Wのレーザー出力だそです。レーザー加工機の排気はそのままでは、とっても臭いのですが、しっかりフィルタで処理して排気しているそうです。
FabLab_Sendai_8_120701.jpg

MDFが主な加工素材だそうです。(MDFのパラメータサンプルがありました)アクリルも加工できるそうです。ハニカムカッティングテーブルの代わりに自作ハニカムを使用されているそうです。
FabLab_Sendai_4_120630.jpg

紙は厚紙は当然OKだそうですが、薄い紙は捨て板や捨て厚紙の上に貼ってレーザー加工されているそうです。

写真は取っていないですが、電子ミシンもありましたよ。。。

一番奥には、カラフルな椅子がスタッキングしてありました。かなりの人数が入っても座れそうですね。
FabLab_Sendai_7_120701.jpg

入って右奥にあったパソコンです。
FabLab_Sendai_3_120630.jpg

MDFをレーザー加工機で加工したとっても素敵なPCケースに入っていました。
FabLab_Sendai_5_120701.jpg

MDFで自作した棚など、いろいろ自作されているようでした。棚の右の一番下にハンダゴテも2本用意されているようです。Arduinoの講習会も企画されているそうです。(Arduinoの講習会をやったことがあるでしたか?もう歳なので、記憶が定かではありません)
FabLab_Sendai_6_120701.jpg

ダイエーにお買い物に行った奥さんを待たせていたので、少しの時間でしたが、FabLab SENDAI - FLATを見学して来ました。出来て2ヶ月ですが、ユーザー同士のディスカッションやアドバイスも行われているそうです。私もなにかレーザー加工や3Dプリントしてみたいと思いました。スタッフの皆さん、いろいろお話していただいて、ありがとうございました。またよろしくお願いします。

最後に、7/13に、”レーザーカッターで作る小さなアクセサリー”というイベントをされるそうです。人気があるそうです。自分で素敵なアクセサリーを作れるのは良いですね。
FabLab_Sendai_9_120701.jpg

とにかく、おしゃれなスペースのイメージです。秘密基地は、FPGA-CAFE/FabLab Tsukuba だけなんでしょうか?他のFabLabにも行ってみたくなりました。とりえずは渋谷と鎌倉に行ってみようと思います。
  1. 2013年07月01日 04:57 |
  2. FPGA-CAFE
  3. | トラックバック:0
  4. | コメント:0