TKEEP : ザイリンクス IP では、 ヌル バイ ト の利用をパケット化されたストリームの末尾にある残りのバイ トのエンコードに限定しています。
ザイリンクスのエンドポイン ト IP では、 ストリーム中の先頭または途中のヌル バイ ト を示す目的で TKEEP を使用しません。
デフォルト: 1
TSTRB : 変更な し
通常、 TSTRB はスパース ストリーム のエンコードに使用 し ます。TSTRB は、 残りのパケットのエンコード だけを目的として使用すべきではありません。
デフォルト: TKEEP と同じ、 それ以外の場合は 1
AXI4 Lite Master BFM の Verilog HDL コードを貼っておく。AXI4 Lite Master BFM は、AXI4 Master BFM のラッパーとして作られている。
Verilog HDL の task で書いてあって、下に示す。7つの task がある。
・AXI_LiteM_1Seq_Write(Write Address, Write Data, Write Response をシーケンシャルにオーバーラップせずに行う)
・AXI_LiteM_WAC(Write Address Channel の Transaction を実行する)
・AXI_LiteM_WDC(Write Data Channel の Transaction を実行する)
・AXI_LiteM_WRC(Write Response Channel の Transaction を実行する)
・AXI_LiteM_1Seq_Read(Read Address, Read Data をシーケンシャルに行う)
・AXI_LiteM_RAC(Read Address Channel の Transaction を実行する)
・AXI_LiteM_RDC(Read Data Channel の Transaction を実行する)
// AXI4 bus Lite Master Bus Fucntion Mode
// AXI4_Lite_Master_BFM.v
// https://marsee101.blog.fc2.com/blog-entry-2673.html
// 2013/12/14
// AXI4_Master_BFM のラッパー
// 2021/04/15 AXI_LiteM_1Seq_Read と AXI_LiteM_RDC に rdata 出力を追加
//
`default_nettype none
`timescale 100ps / 1ps
module AXI4_Lite_Master_BFM #(
parameter DELAY = 10,
parameter integer C_S_AXI_LITE_ADDR_WIDTH = 12, // Address width of the AXI Lite Interface
parameter integer C_S_AXI_LITE_DATA_WIDTH = 32 // Data width of the AXI Lite Interface
)(
input wire ACLK,
output wire [C_S_AXI_LITE_ADDR_WIDTH-1:0] S_AXI_AWADDR,
output wire [2:0] S_AXI_AWPROT,
output wire S_AXI_AWVALID,
output wire [C_S_AXI_LITE_DATA_WIDTH-1:0] S_AXI_WDATA,
output wire [C_S_AXI_LITE_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
output wire S_AXI_WVALID,
output wire S_AXI_BREADY,
output wire [C_S_AXI_LITE_ADDR_WIDTH-1:0] S_AXI_ARADDR,
output wire [2:0] S_AXI_ARPROT,
output wire S_AXI_ARVALID,
output wire S_AXI_RREADY,
input wire S_AXI_AWREADY,
input wire S_AXI_WREADY,
input wire [1:0] S_AXI_BRESP,
input wire S_AXI_BVALID,
input wire S_AXI_ARREADY,
input wire [C_S_AXI_LITE_DATA_WIDTH-1:0] S_AXI_RDATA,
input wire [1:0] S_AXI_RRESP,
input wire S_AXI_RVALID
);
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;
// RESP の値の定義
parameter RESP_OKAY = 2'b00;
parameter RESP_EXOKAY = 2'b01;
parameter RESP_SLVERR = 2'b10;
parameter RESP_DECERR = 2'b11;
reg [7:0] awlen_hold = 0;
reg [0:0] wid_hold = 0;
reg axi_w_transaction_active = 0;
reg axi_r_transaction_active = 0;
reg [7:0] arlen_hold = 0;
// AXI4_BFM のインスタンス
AXI4_Master_BFM #(
.DELAY(DELAY),
.C_S_AXI_ADDR_WIDTH(C_S_AXI_LITE_ADDR_WIDTH),
.C_S_AXI_DATA_WIDTH(C_S_AXI_LITE_DATA_WIDTH)
) MBFMi(
.ACLK(ACLK),
.S_AXI_AWID(),
.S_AXI_AWADDR(S_AXI_AWADDR),
.S_AXI_AWLEN(),
.S_AXI_AWSIZE(),
.S_AXI_AWBURST(),
.S_AXI_AWLOCK(),
.S_AXI_AWCACHE(),
.S_AXI_AWPROT(S_AXI_AWPROT),
.S_AXI_AWREGION(),
.S_AXI_AWQOS(),
.S_AXI_AWUSER(),
.S_AXI_AWVALID(S_AXI_AWVALID),
.S_AXI_AWREADY(S_AXI_AWREADY),
.S_AXI_WID(),
.S_AXI_WDATA(S_AXI_WDATA),
.S_AXI_WSTRB(S_AXI_WSTRB),
.S_AXI_WLAST(),
.S_AXI_WUSER(),
.S_AXI_WVALID(S_AXI_WVALID),
.S_AXI_WREADY(S_AXI_WREADY),
.S_AXI_BID(1'b0),
.S_AXI_BRESP(S_AXI_BRESP),
.S_AXI_BUSER(1'b0),
.S_AXI_BVALID(S_AXI_BVALID),
.S_AXI_BREADY(S_AXI_BREADY),
.S_AXI_ARID(),
.S_AXI_ARADDR(S_AXI_ARADDR),
.S_AXI_ARLEN(),
.S_AXI_ARSIZE(),
.S_AXI_ARBURST(),
.S_AXI_ARLOCK(),
.S_AXI_ARCACHE(),
.S_AXI_ARPROT(S_AXI_ARPROT),
.S_AXI_ARREGION(),
.S_AXI_ARQOS(),
.S_AXI_ARUSER(),
.S_AXI_ARVALID(S_AXI_ARVALID),
.S_AXI_ARREADY(S_AXI_ARREADY),
.S_AXI_RID(1'b0),
.S_AXI_RDATA(S_AXI_RDATA),
.S_AXI_RRESP(S_AXI_RRESP),
.S_AXI_RLAST(1'b1),
.S_AXI_RUSER(1'b0),
.S_AXI_RVALID(S_AXI_RVALID),
.S_AXI_RREADY(S_AXI_RREADY)
);
// Write Channel
// wait_clk_bready : 0 - bready の Wait は無し、0以外 - bready の Wait は wait_clk_bready の値の Wait が入る
// wmax_wait : 0 - wvalid の Wait は無し、0以外 - wmax_wait を最大値とするランダムな値の Wait が wvalid に入る
task AXI_LiteM_1Seq_Write; // Write Address, Write Data, Write Response をシーケンシャルにオーバーラップせずに行う。
input [C_S_AXI_LITE_ADDR_WIDTH-1:0] awaddr;
input [C_S_AXI_LITE_DATA_WIDTH-1:0] wdata;
input [7:0] wait_clk_bready;
input [7:0] wmax_wait;
begin
MBFMi.AXI_Master_1Seq_Write(1'b0, awaddr, 8'd0, ASIZE_BT_4, ABURST_INCR, wdata, wait_clk_bready, wmax_wait);
end
endtask
// Write Address Channel
task AXI_LiteM_WAC;
input [C_S_AXI_LITE_ADDR_WIDTH-1:0] awaddr;
begin
MBFMi.AXI_MASTER_WAC(1'b0, awaddr, 8'd0, ASIZE_BT_4, ABURST_INCR);
end
endtask
// Write Data Channel
// wmax_wait : 0 - wvalid の Wait は無し、0以外 - wmax_wait を最大値とするランダムな値の Wait が wvalid に入る
task AXI_LiteM_WDC; // WDATA は+1する
// とりあえず、WSTRBはオール1にする
input [C_S_AXI_LITE_DATA_WIDTH-1:0] wdata;
input [7:0] wmax_wait; // Write時の最大wait数
begin
MBFMi.AXI_MASTER_WDC(wdata, wmax_wait);
end
endtask
// Write Response Channel
// wait_clk_bready : 0 - bready の Wait は無し、0以外 - bready の Wait は wait_clk_bready の値の Wait が入る
task AXI_LiteM_WRC; // wait_clk_bready
input [7:0] wait_clk_bready;
begin
MBFMi.AXI_MASTER_WRC(wait_clk_bready);
end
endtask
// Read Channel
task AXI_LiteM_1Seq_Read; // Read Address, Read Data をシーケンシャルに行う
input [C_S_AXI_LITE_ADDR_WIDTH-1:0] araddr;
input [7:0] rmax_wait; // Read時の最大wait数
output [C_S_AXI_LITE_DATA_WIDTH-1:0] rdata; // S_AXI_RDATA のラッチ
begin
MBFMi.AXI_Master_1Seq_Read(1'b0, araddr, 8'd0, ASIZE_BT_4, ABURST_INCR, rmax_wait, rdata);
end
endtask
// Read Address Channel
task AXI_LiteM_RAC;
input [C_S_AXI_LITE_ADDR_WIDTH-1:0] araddr;
begin
MBFMi.AXI_MASTER_RAC(1'b0, araddr, 8'd0, ASIZE_BT_4, ABURST_INCR);
end
endtask
// Read Data Channel
task AXI_LiteM_RDC; // S_AXI_RLAST がアサートされるまでS_AXI_RREADY をアサートする
input [7:0] rmax_wait; // Read時の最大wait数
output [C_S_AXI_LITE_DATA_WIDTH-1:0] rdata; // S_AXI_RDATA のラッチ
begin
MBFMi.AXI_MASTER_RDC(rmax_wait, rdata);
end
endtask
endmodule
`default_nettype wire
AXI Master BFMの Write の task がAXI_Master_1Seq_Write だ。このtaskは、(Write Address, Write Data), Write Response をシーケンシャルにオーバーラップせずに行う。今回の修正で、(Write Address, Write Data)はfork ~ join を使用して、オーバーラップするように変更した。AXI_Master_1Seq_Writeは、8個の引数を持つ。wait_clk_bready、wmax_wait 以外の信号はAXIバスの信号なので、説明は省く。wait_clk_bready はWriteのデータ転送が終了して、BREADYをアサートするまでのWaitクロック数を設定する。Writeデータ転送時にランダムな数のWaitが入るが、wmax_wait は、そのWait の最大値を指示する。
AXI Master BFMの Read の task が、AXI_Master_1Seq_Read で、Read Address, Read Data をシーケンシャルに行う。
// AXI4 bus Master Bus Fucntion Mode
// AXI4_Master_BFM.v
// https://marsee101.blog.fc2.com/blog-entry-2288.html
// 2012/10/24 : 修正、S_AXI_AWREADYが1になるのを確認してからS_AXI_WVALIDを1にしていたのでは、AXIバスの非標準となる。
// よって、AXI_MASTER_WAC とAXI_MASTER_WDC をfork ~ join で並列に実行する
// 2013/12/14 : input に DELAYを入れるように変更
// 2021/04/15 : AXI_Master_1Seq_Read, AXI_MASTER_RDC に rdata 出力を追加
//
`default_nettype none
`timescale 100ps / 1ps
module AXI4_Master_BFM #(
parameter DELAY = 10,
parameter integer C_S_AXI_ADDR_WIDTH = 32, // Address width of the AXI Interface
parameter integer C_S_AXI_DATA_WIDTH = 32 // Data width of the AXI Interface
)(
input wire ACLK,
output reg [0:0] S_AXI_AWID = 0,
output reg [C_S_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR = 0,
output reg [7:0] S_AXI_AWLEN = 0,
output reg [2:0] S_AXI_AWSIZE = 0,
output reg [1:0] S_AXI_AWBURST = 0,
output reg [1:0] S_AXI_AWLOCK = 0,
output reg [3:0] S_AXI_AWCACHE = 3, // Normal Non-cacheable bufferable
output reg [2:0] S_AXI_AWPROT = 0,
output reg [3:0] S_AXI_AWREGION = 0,
output reg [3:0] S_AXI_AWQOS = 0,
output reg [0:0] S_AXI_AWUSER = 0,
output reg S_AXI_AWVALID = 0,
output reg [0:0] S_AXI_WID = 0,
output reg [C_S_AXI_DATA_WIDTH-1:0] S_AXI_WDATA = 0,
output reg [C_S_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB = 0,
output reg S_AXI_WLAST = 0,
output reg [0:0] S_AXI_WUSER = 0,
output reg S_AXI_WVALID = 0,
output reg S_AXI_BREADY = 0,
output reg [0:0] S_AXI_ARID = 0,
output reg [C_S_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR = 0,
output reg [7:0] S_AXI_ARLEN = 0,
output reg [2:0] S_AXI_ARSIZE = 0,
output reg [1:0] S_AXI_ARBURST = 0,
output reg [1:0] S_AXI_ARLOCK = 0,
output reg [3:0] S_AXI_ARCACHE = 2, // Normal Non-cacheable bufferable
output reg [2:0] S_AXI_ARPROT = 0,
output reg [3:0] S_AXI_ARREGION = 0,
output reg [3:0] S_AXI_ARQOS = 0,
output reg [0:0] S_AXI_ARUSER = 0,
output reg S_AXI_ARVALID = 0,
output reg S_AXI_RREADY = 0,
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 [C_S_AXI_DATA_WIDTH-1: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
);
reg [7:0] awlen_hold = 0;
reg [0:0] wid_hold = 0;
reg axi_w_transaction_active = 0;
reg axi_r_transaction_active = 0;
reg [7:0] arlen_hold = 0;
reg S_AXI_AWREADY_d;
reg S_AXI_WREADY_d;
reg [0:0] S_AXI_BID_d;
reg [1:0] S_AXI_BRESP_d;
reg [0:0] S_AXI_BUSER_d;
reg S_AXI_BVALID_d;
reg S_AXI_ARREADY_d;
reg [0:0] S_AXI_RID_d;
reg [C_S_AXI_DATA_WIDTH-1:0] S_AXI_RDATA_d;
reg [1:0] S_AXI_RRESP_d;
reg S_AXI_RLAST_d;
reg [0:0] S_AXI_RUSER_d;
reg S_AXI_RVALID_d;
always @* S_AXI_AWREADY_d <= #DELAY S_AXI_AWREADY;
always @* S_AXI_WREADY_d <= #DELAY S_AXI_WREADY;
always @* S_AXI_BID_d <= #DELAY S_AXI_BID;
always @* S_AXI_BRESP_d <= #DELAY S_AXI_BRESP;
always @* S_AXI_BUSER_d <= #DELAY S_AXI_BUSER;
always @* S_AXI_BVALID_d <= #DELAY S_AXI_BVALID;
always @* S_AXI_ARREADY_d <= #DELAY S_AXI_ARREADY;
always @* S_AXI_RID_d <= #DELAY S_AXI_RID;
always @* S_AXI_RDATA_d <= #DELAY S_AXI_RDATA;
always @* S_AXI_RRESP_d <= #DELAY S_AXI_RRESP;
always @* S_AXI_RLAST_d <= #DELAY S_AXI_RLAST;
always @* S_AXI_RUSER_d <= #DELAY S_AXI_RUSER;
always @* S_AXI_RVALID_d <= #DELAY S_AXI_RVALID;
// Write Channel
// wait_clk_bready : 0 - bready の Wait は無し、0以外 - bready の Wait は wait_clk_bready の値の Wait が入る
// wmax_wait : 0 - wvalid の Wait は無し、0以外 - wmax_wait を最大値とするランダムな値の Wait が wvalid に入る
task AXI_Master_1Seq_Write; // Write Address; Write Data, Write Response をシーケンシャルにオーバーラップせずに行う。
input [0:0] awid;
input [C_S_AXI_ADDR_WIDTH-1:0] awaddr;
input [7:0] awlen;
input [2:0] awsize;
input [1:0] awburst;
input [C_S_AXI_DATA_WIDTH-1:0] wdata;
input [7:0] wait_clk_bready;
input [7:0] wmax_wait;
begin
fork
AXI_MASTER_WAC(awid, awaddr, awlen, awsize, awburst);
AXI_MASTER_WDC(wdata, wmax_wait);
join
AXI_MASTER_WRC(wait_clk_bready);
end
endtask
// Write Address Channel
task AXI_MASTER_WAC;
input [0:0] awid;
input [C_S_AXI_ADDR_WIDTH-1:0] awaddr;
input [7:0] awlen;
input [2:0] awsize;
input [1:0] awburst;
begin
S_AXI_AWID = awid;
S_AXI_AWADDR = awaddr;
S_AXI_AWLEN = awlen;
S_AXI_AWSIZE = awsize;
S_AXI_AWBURST = awburst;
S_AXI_AWVALID = 1'b1;
if (axi_w_transaction_active == 1'b0) begin // AXI Write トランザクションが開始されている場合は戻る
axi_w_transaction_active = 1'b1; // AXIトランザクション開始
awlen_hold = awlen; // Write Data Channel のためにバースト数を取っておく
@(posedge ACLK); // 次のクロックへ
while (~S_AXI_AWREADY_d) begin // S_AXI_AWREADY が1になるまで待つ
#DELAY;
@(posedge ACLK); // 次のクロックへ
end
#DELAY;
S_AXI_AWID = 0;
S_AXI_AWADDR = 0;
S_AXI_AWLEN = 0;
S_AXI_AWSIZE = 0;
S_AXI_AWBURST = 0;
S_AXI_AWVALID = 1'b0;
@(posedge ACLK); // 次のクロックへ
#DELAY;
end
end
endtask
// Write Data Channel
// wmax_wait : 0 - wvalid の Wait は無し、0以外 - wmax_wait を最大値とするランダムな値の Wait が wvalid に入る
task AXI_MASTER_WDC; // WDATA は+1する
// とりあえず、WSTRBはオール1にする
input [C_S_AXI_DATA_WIDTH-1:0] wdata;
input [7:0] wmax_wait; // Write時の最大wait数
integer i, j, val;
begin
i = 0; j = 0;
S_AXI_WSTRB = {(C_S_AXI_DATA_WIDTH/8-1){1'b1}};
while (~S_AXI_AWVALID) begin // S_AXI_AWVALID が1になるまで待つ
@(posedge ACLK); // 次のクロックへ
#DELAY;
end
while (i<=awlen_hold) begin
if (wmax_wait == 0) // wmax_wait が0の時は$random を実行しない
val = 0;
else
val = $unsigned($random) % (wmax_wait+1);
if (val == 0) begin // waitなし
S_AXI_WVALID = 1'b1;
end else begin // waitあり
S_AXI_WVALID = 1'b0;
for (j=0; j<val; j=j+1) begin
@(posedge ACLK); // 次のクロックへ
#DELAY;
end
S_AXI_WVALID = 1'b1; // wait終了
end
if (i == awlen_hold)
S_AXI_WLAST = 1'b1;
else
S_AXI_WLAST = 1'b0;
S_AXI_WDATA = wdata;
wdata = wdata + 1;
@(posedge ACLK); // 次のクロックへ
while (~S_AXI_WREADY_d) begin // S_AXI_WREADY が0の時は1になるまで待つ
#DELAY;
@(posedge ACLK); // 次のクロックへ
end
#DELAY;
i = i + 1;
end
S_AXI_WVALID = 1'b0;
S_AXI_WLAST = 1'b0;
S_AXI_WSTRB = {(C_S_AXI_DATA_WIDTH/8-1){1'b0}};
end
endtask
// Write Response Channel
// wait_clk_bready : 0 - bready の Wait は無し、0以外 - bready の Wait は wait_clk_bready の値の Wait が入る
task AXI_MASTER_WRC; // wait_clk_bready
input [7:0] wait_clk_bready;
integer i;
begin
for (i=0; i<wait_clk_bready; i=i+1) begin
@(posedge ACLK); // 次のクロックへ
#DELAY;
end
S_AXI_BREADY = 1'b1;
@(posedge ACLK); // 次のクロックへ
while (~S_AXI_BVALID_d) begin // S_AXI_BVALID が1になるまでWait
#DELAY;
@(posedge ACLK); // 次のクロックへ
end
#DELAY;
S_AXI_BREADY = 1'b0;
axi_w_transaction_active = 1'b0; // AXIトランザクション終了
@(posedge ACLK);
#DELAY;
end
endtask
// Read Channel
task AXI_Master_1Seq_Read; // Read Address, Read Data をシーケンシャルに行う。
input [0:0] arid;
input [C_S_AXI_ADDR_WIDTH-1:0] araddr;
input [7:0] arlen;
input [2:0] arsize;
input [1:0] arburst;
input [7:0] rmax_wait; // Read時の最大wait数
output [C_S_AXI_DATA_WIDTH-1:0] rdata; // S_AXI_RDATA のラッチ
begin
AXI_MASTER_RAC(arid, araddr, arlen, arsize, arburst);
AXI_MASTER_RDC(rmax_wait, rdata);
end
endtask
// Read Address Channel
task AXI_MASTER_RAC;
input [0:0] arid;
input [C_S_AXI_ADDR_WIDTH-1:0] araddr;
input [7:0] arlen;
input [2:0] arsize;
input [1:0] arburst;
begin
S_AXI_ARID = arid;
S_AXI_ARADDR = araddr;
S_AXI_ARLEN = arlen;
S_AXI_ARSIZE = arsize;
S_AXI_ARBURST = arburst;
S_AXI_ARVALID = 1'b1;
if (axi_r_transaction_active == 1'b0) begin // AXI Read トランザクションが開始されている場合は戻る
arlen_hold =arlen; // Read Data Channel のためにバースト数を取っておく
@(posedge ACLK); // 次のクロックへ
while (~S_AXI_ARREADY_d) begin // S_AXI_ARREADY が1になるまで待つ
#DELAY;
@(posedge ACLK); // 次のクロックへ
end
#DELAY;
S_AXI_ARID = 0;
S_AXI_ARADDR = 0;
S_AXI_ARLEN = 0;
S_AXI_ARSIZE = 0;
S_AXI_ARBURST = 0;
S_AXI_ARVALID = 1'b0;
@(posedge ACLK); // 次のクロックへ
#DELAY;
axi_r_transaction_active = 1'b1; // AXIトランザクション開始
end
end
endtask
// Read Data Channel
task AXI_MASTER_RDC; // S_AXI_RLAST がアサートされるまでS_AXI_RREADY をアサートする
input [7:0] rmax_wait; // Read時の最大wait数
output [C_S_AXI_DATA_WIDTH-1:0] rdata; // S_AXI_RDATA のラッチ
integer i, val;
begin
while (~(S_AXI_RLAST_d & S_AXI_RVALID_d & S_AXI_RREADY)) begin // S_AXI_RLAST & S_AXI_RVALID & S_AXI_RREADY で終了
if (rmax_wait == 0) begin // rmax_wait が0の時は$random を実行しない
val = 0;
S_AXI_RREADY = 1'b1;
end else begin
val = $unsigned($random) % (rmax_wait+1);
if (val == 0)
S_AXI_RREADY = 1'b1;
else
S_AXI_RREADY = 1'b0;
end
#DELAY;
for (i=0; i<val; i=i+1) begin // ランダム値でWait、val=0の時はスキップ
@(posedge ACLK); // 次のクロックへ
#DELAY;
end
S_AXI_RREADY = 1'b1;
@(posedge ACLK); // 次のクロックへ
while (~S_AXI_RVALID_d) begin // S_AXI_RVALID が1になるまでWait
#DELAY;
@(posedge ACLK); // 次のクロックへ
end
#DELAY;
rdata = S_AXI_RDATA;
end
#DELAY;
S_AXI_RREADY = 1'b0;
axi_r_transaction_active = 1'b0; // AXIトランザクション終了
@(posedge ACLK);
#DELAY;
end
endtask
endmodule
`default_nettype wire
を実行したときのものだ。XMnist_nn_Set_in_V(&mnits_nn_ap, char_num);
を実行したときのものだ。while(!XMnist_nn_IsDone(&mnits_nn_ap));
/* AXI Master用 Slave Bus Function Mode (BFM)
axi_slave_BFM_intf.v
2012/02/25 : S_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
2012/07/04 : READ_ONLY_TRANSACTION を追加。Read機能のみでも+1したデータを出力することが出来るように変更した。
2014/01/05 : ポート名をM_AXI?からS_AXI?に修正、Verilogに移植(By Koba)
*/
// 2014/07/18 : Write Respose Channel に sync_fifo を使用した by marsee
// 2014/07/19 : RAM を初期化する初期化ファイルを追加(init_ram_data.txt) by marsee
// 2014/07/20 : RAM 初期化ファイル名を parameter に追加 by marsee
// 2014/08/31 : READ_RANDOM_WAIT=1 の時に、S_AXI_RREADY が S_AXI_RVALID に依存するバグをフィック。 by marsee
// WRITE_RANDOM_WAIT=1 の時に、S_AXI_WVALID が S_AXI_WREADY に依存するバグをフィック。 by marsee
// LOAD_RAM_INIT_FILE パラメータを追加 by marsee
//
// 2016/07/03 : AWREADY_IS_USUALLY_HIGH と ARREADY_IS_USUALLY_HIGH の2つのパラメータを追加 by marsee
//
// ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
//
module axi_slave_bfm #(
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_S_AXI_TARGET = 0,
parameter integer C_OFFSET_WIDTH = 10, // 割り当てるRAMのアドレスのビット幅
parameter integer C_S_AXI_BURST_LEN = 256,
parameter integer WRITE_RANDOM_WAIT = 1, // Write Transactionデータ転送時にランダムなWaitを発生させる=1、Waitしない=0
parameter integer READ_RANDOM_WAIT = 0, // Read Transactionデータ転送時にランダムなWaitを発生させる=1、Waitしない=0
parameter integer READ_DATA_IS_INCREMENT = 0, // Read TransactionでRAMのデータを読み出す=0、0はじまりの+1データを使う=1
parameter integer RANDOM_BVALID_WAIT = 0, // Write Transaction後、BVALIDをランダムにWaitする=1、ランダムにWaitしない=0
parameter [80*8:1] RAM_INIT_FILE = "init_ram_data.data",
parameter integer LOAD_RAM_INIT_FILE = 0, // RAM_INIT_FILE をLoadする - 1, Load しない - 0
parameter integer AWREADY_IS_USUALLY_HIGH = 1, // AWRAEDY は通常はLow=0, High=1
parameter integer ARREADY_IS_USUALLY_HIGH = 1 // AWRAEDY は通常はLow=0, High=1
)
(
// System Signals
input ACLK,
input ARESETN,
// Slave Interface Write Address Ports
input [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_AWID,
input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
input [8-1 : 0] S_AXI_AWLEN,
input [3-1 : 0] S_AXI_AWSIZE,
input [2-1 : 0] S_AXI_AWBURST,
// input S_AXI_AWLOCK [2-1 : 0],
input [1 : 0] S_AXI_AWLOCK,
input [4-1 : 0] S_AXI_AWCACHE,
input [3-1 : 0] S_AXI_AWPROT,
input [4-1 : 0] S_AXI_AWQOS,
input [C_S_AXI_AWUSER_WIDTH-1 :0] S_AXI_AWUSER,
input S_AXI_AWVALID,
output S_AXI_AWREADY,
// Slave Interface Write Data Ports
input [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
input [C_S_AXI_DATA_WIDTH/8-1 : 0]S_AXI_WSTRB,
input S_AXI_WLAST,
input [C_S_AXI_WUSER_WIDTH-1 : 0] S_AXI_WUSER,
input S_AXI_WVALID,
output S_AXI_WREADY,
// Slave Interface Write Response Ports
output [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_BID,
output [2-1 : 0] S_AXI_BRESP,
output [C_S_AXI_BUSER_WIDTH-1 : 0] S_AXI_BUSER,
output S_AXI_BVALID,
input S_AXI_BREADY,
// Slave Interface Read Address Ports
input [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_ARID,
input [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
input [8-1 : 0] S_AXI_ARLEN,
input [3-1 : 0] S_AXI_ARSIZE,
input [2-1 : 0] S_AXI_ARBURST,
input [2-1 : 0] S_AXI_ARLOCK,
input [4-1 : 0] S_AXI_ARCACHE,
input [3-1 : 0] S_AXI_ARPROT,
input [4-1 : 0] S_AXI_ARQOS,
input [C_S_AXI_ARUSER_WIDTH-1 : 0]S_AXI_ARUSER,
input S_AXI_ARVALID,
output S_AXI_ARREADY,
// Slave Interface Read Data Ports
output reg [C_S_AXI_ID_WIDTH-1: 0] S_AXI_RID,
output [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
output reg [2-1 : 0] S_AXI_RRESP,
output S_AXI_RLAST,
output [C_S_AXI_RUSER_WIDTH-1 : 0] S_AXI_RUSER,
output S_AXI_RVALID,
input S_AXI_RREADY
);
localparam AXBURST_FIXED = 2'b00;
localparam AXBURST_INCR = 2'b01;
localparam AXBURST_WRAP = 2'b10;
localparam RESP_OKAY = 2'b00;
localparam RESP_EXOKAY = 2'b01;
localparam RESP_SLVERR = 2'b10;
localparam RESP_DECERR = 2'b11;
localparam DATA_BUS_BYTES = (C_S_AXI_DATA_WIDTH / 8);
//localparam ADD_INC_OFFSET = log2(DATA_BUS_BYTES);
localparam ADD_INC_OFFSET = (DATA_BUS_BYTES==1) ? 0:
(DATA_BUS_BYTES==2) ? 1:
(DATA_BUS_BYTES==4) ? 2:
(DATA_BUS_BYTES==8) ? 3:
(DATA_BUS_BYTES==16) ? 4:
(DATA_BUS_BYTES==32) ? 5:
(DATA_BUS_BYTES==64) ? 6:
(DATA_BUS_BYTES==128) ? 7: 32'hxxxxxxxx;
// fifo depth for address
localparam AD_FIFO_DEPTH = 16;
// wad_fifo field
localparam WAD_FIFO_WIDTH = C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1+1;
localparam WAD_FIFO_AWID_HIGH = C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1;
localparam WAD_FIFO_AWID_LOW = C_S_AXI_ADDR_WIDTH+5;
localparam WAD_FIFO_AWBURST_HIGH = C_S_AXI_ADDR_WIDTH+4;
localparam WAD_FIFO_AWBURST_LOW = C_S_AXI_ADDR_WIDTH+3;
localparam WAD_FIFO_AWSIZE_HIGH = C_S_AXI_ADDR_WIDTH+2;
localparam WAD_FIFO_AWSIZE_LOW = C_S_AXI_ADDR_WIDTH;
localparam WAD_FIFO_ADDR_HIGH = C_S_AXI_ADDR_WIDTH-1;
localparam WAD_FIFO_ADDR_LOW = 0;
// wres_fifo field
localparam WRES_FIFO_WIDTH = 2+C_S_AXI_ID_WIDTH-1+1;
localparam WRES_FIFO_AWID_HIGH = 2+C_S_AXI_ID_WIDTH-1;
localparam WRES_FIFO_AWID_LOW = 2;
localparam WRES_FIFO_AWBURST_HIGH = 1;
localparam WRES_FIFO_AWBURST_LOW = 0;
// rad_fifo field
localparam RAD_FIFO_WIDTH = C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1+1;
localparam RAD_FIFO_ARID_HIGH = C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1;
localparam RAD_FIFO_ARID_LOW = C_S_AXI_ADDR_WIDTH+13;
localparam RAD_FIFO_ARBURST_HIGH = C_S_AXI_ADDR_WIDTH+12;
localparam RAD_FIFO_ARBURST_LOW = C_S_AXI_ADDR_WIDTH+11;
localparam RAD_FIFO_ARSIZE_HIGH = C_S_AXI_ADDR_WIDTH+10;
localparam RAD_FIFO_ARSIZE_LOW = C_S_AXI_ADDR_WIDTH+8;
localparam RAD_FIFO_ARLEN_HIGH = C_S_AXI_ADDR_WIDTH+7;
localparam RAD_FIFO_ARLEN_LOW = C_S_AXI_ADDR_WIDTH;
localparam RAD_FIFO_ADDR_HIGH = C_S_AXI_ADDR_WIDTH-1;
localparam RAD_FIFO_ADDR_LOW = 0;
// RAMの生成
localparam SLAVE_ADDR_NUMBER = 2 ** (C_OFFSET_WIDTH - ADD_INC_OFFSET);
reg [(C_S_AXI_DATA_WIDTH - 1):0] ram_array [0:(SLAVE_ADDR_NUMBER - 1)];
// for write transaction
// write_address_state
localparam IDLE_WRAD = 1'd0;
localparam AWR_ACCEPT = 1'd1;
reg wradr_cs;
// write_data_state
localparam IDLE_WRDT = 1'd0;
localparam WR_BURST = 1'd1;
reg wrdat_cs;
// write_response_state
localparam IDLE_WRES = 2'd0;
localparam WAIT_BVALID = 2'd1;
localparam BVALID_ASSERT = 2'd2;
reg [1:0] wrres_cs;
integer addr_inc_step_wr = 1;
reg awready;
reg [(C_OFFSET_WIDTH - 1):0] wr_addr;
reg [(C_S_AXI_ID_WIDTH - 1):0] wr_bid;
reg [1:0] wr_bresp;
reg wr_bvalid;
reg [15:0] m_seq16_wr;
reg wready;
// wready_state
localparam IDLE_WREADY = 2'd0;
localparam ASSERT_WREADY = 2'd1;
localparam DEASSERT_WREADY = 2'd2;
reg [1:0] cs_wready;
wire cdc_we;
wire wad_fifo_full;
wire wad_fifo_empty;
wire wad_fifo_almost_full;
wire wad_fifo_almost_empty;
wire wad_fifo_rd_en;
wire wad_fifo_wr_en;
wire [WAD_FIFO_WIDTH-1:0] wad_fifo_din;
wire [WAD_FIFO_WIDTH-1:0] wad_fifo_dout;
reg [15:0] m_seq16_wr_res;
reg [4:0] wr_resp_cnt;
// wres_fifo
wire wres_fifo_wr_en;
wire wres_fifo_full;
wire wres_fifo_empty;
wire wres_fifo_almost_full;
wire wres_fifo_almost_empty;
wire wres_fifo_rd_en;
wire [WRES_FIFO_WIDTH-1:0] wres_fifo_din;
wire [WRES_FIFO_WIDTH-1:0] wres_fifo_dout;
// for read transaction
// read_address_state
localparam IDLE_RDA = 1'd0;
localparam ARR_ACCEPT = 1'd1;
reg rdadr_cs;
// read_data_state
localparam IDLE_RDD = 1'd0;
localparam RD_BURST = 1'd1;
reg rddat_cs;
// read_last_state
localparam IDLE_RLAST = 1'd0;
localparam RLAST_ASSERT = 1'd1;
reg rdlast;
integer addr_inc_step_rd = 1;
reg arready;
reg [(C_OFFSET_WIDTH - 1):0] rd_addr;
reg [7:0] rd_axi_count;
reg rvalid;
reg rlast;
reg [15:0] m_seq16_rd;
// rvalid_state
localparam IDLE_RVALID = 2'd0;
localparam ASSERT_RVALID = 2'd1;
localparam DEASSERT_RVALID = 2'd2;
reg [1:0] cs_rvalid;
reg [(C_S_AXI_DATA_WIDTH - 1):0] read_data_count;
reg reset_1d;
reg reset_2d;
wire reset;
wire rad_fifo_full;
wire rad_fifo_empty;
wire rad_fifo_almost_full;
wire rad_fifo_almost_empty;
wire rad_fifo_rd_en;
wire rad_fifo_wr_en;
wire [RAD_FIFO_WIDTH-1:0] rad_fifo_din;
wire [RAD_FIFO_WIDTH-1:0] rad_fifo_dout;
// ram_array を初期化
initial begin
if (LOAD_RAM_INIT_FILE==1) begin
$readmemh(RAM_INIT_FILE, ram_array, 0, (SLAVE_ADDR_NUMBER - 1));
end
end
// ARESETN をACLK で同期化
always @ ( posedge ACLK ) begin
reset_1d <= ~ARESETN;
reset_2d <= reset_1d;
end
assign reset = reset_2d;
// AXI4バス Write Address State Machine
always @ ( posedge ACLK ) begin
if ( reset ) begin
wradr_cs <= IDLE_WRAD;
awready <= 1'b0;
end
else
case (wradr_cs)
IDLE_WRAD: if ((S_AXI_AWVALID == 1'b1) && (wad_fifo_full == 1'b0) && (wres_fifo_full == 1'b0)) // S_AXI_AWVALIDが1にアサートされた
begin
wradr_cs <= AWR_ACCEPT;
awready <= 1'b1;
end
AWR_ACCEPT: begin
wradr_cs <= IDLE_WRAD;
awready <= 1'b0;
end
endcase
end
assign S_AXI_AWREADY = (AWREADY_IS_USUALLY_HIGH==1) ? ~wad_fifo_full : awready;
// {S_AXI_AWID, S_AXI_AWBURST, S_AXI_AWSIZE, S_AXI_AWADDR}を保存しておく同期FIFO
assign wad_fifo_din = {S_AXI_AWID, S_AXI_AWBURST, S_AXI_AWSIZE, S_AXI_AWADDR};
assign wad_fifo_wr_en = (AWREADY_IS_USUALLY_HIGH==1) ? (S_AXI_AWVALID & ~wad_fifo_full) : awready;
sync_fifo #(
.C_MEMORY_SIZE (AD_FIFO_DEPTH),
.DATA_BUS_WIDTH (WAD_FIFO_WIDTH)
) wad_fifo (
.clk (ACLK),
.rst (reset),
.wr_en (wad_fifo_wr_en),
.din (wad_fifo_din),
.full (wad_fifo_full),
.almost_full (wad_fifo_almost_full),
.rd_en (wad_fifo_rd_en),
.dout (wad_fifo_dout),
.empty (wad_fifo_empty),
.almost_empty (wad_fifo_almost_empty)
);
assign wad_fifo_rd_en = (wready & S_AXI_WVALID & S_AXI_WLAST);
// AXI4バス Write Data State Machine
always @( posedge ACLK ) begin
if ( reset )
wrdat_cs <= IDLE_WRDT;
else
case (wrdat_cs)
IDLE_WRDT: if ( wad_fifo_empty == 1'b0 ) // AXI Writeアドレス転送の残りが1個以上ある
wrdat_cs <= WR_BURST;
WR_BURST : if ( S_AXI_WLAST & S_AXI_WVALID & wready ) // Write Transaction終了
wrdat_cs <= IDLE_WRDT;
endcase
end
// M系列による16ビット乱数生成関数
function [15:0] M_SEQ16_BFM_F;
input [15:0] mseq16in;
reg xor_result;
begin
xor_result = mseq16in[15] ^ mseq16in[12] ^ mseq16in[10] ^ mseq16in[8] ^
mseq16in[7] ^ mseq16in[6] ^ mseq16in[3] ^ mseq16in[2];
M_SEQ16_BFM_F = {mseq16in[14:0], xor_result};
end
endfunction
// m_seq_wr、16ビットのM系列を計算する
always @( posedge ACLK ) begin
if ( reset )
m_seq16_wr <= 16'b1;
else begin
if ( WRITE_RANDOM_WAIT ) begin // Write Transaction時にランダムなWaitを挿入する
if ( wrdat_cs == WR_BURST )
m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
end
else // Wait無し
m_seq16_wr <= 16'b0;
end
end
// wready の処理、M系列を計算して128以上だったらWaitする。
always @( posedge ACLK ) begin
if ( reset ) begin
cs_wready <= IDLE_WREADY;
wready <= 1'b0;
end
else
case (cs_wready)
IDLE_WREADY: if ( (wrdat_cs == IDLE_WRDT) && (wad_fifo_empty == 1'b0) ) begin
if ( (m_seq16_wr[7] == 1'b0) && (wres_fifo_full==1'b0) ) begin
cs_wready <= ASSERT_WREADY;
wready <= 1'b1;
end
else begin
cs_wready <= DEASSERT_WREADY;
wready <= 1'b0;
end
end
ASSERT_WREADY: if ( (wrdat_cs == WR_BURST) && S_AXI_WLAST && S_AXI_WVALID ) begin
cs_wready <= IDLE_WREADY;
wready <= 1'b0;
end
else if ( (wrdat_cs == WR_BURST) && S_AXI_WVALID ) begin
if ((m_seq16_wr[7] == 1'b1) || (wres_fifo_full==1'b1)) begin
cs_wready <= DEASSERT_WREADY;
wready <= 1'b0;
end
end
DEASSERT_WREADY:if ( (m_seq16_wr[7] == 1'b0) && (wres_fifo_full==1'b0) ) begin
cs_wready <= ASSERT_WREADY;
wready <= 1'b1;
end
endcase
end
assign S_AXI_WREADY = wready;
assign cdc_we = ( (wrdat_cs == WR_BURST) && wready && S_AXI_WVALID );
// addr_inc_step_wrの処理
always @ ( posedge ACLK ) begin
if ( reset )
addr_inc_step_wr <= 1;
else begin
if ( (wrdat_cs == IDLE_WRDT) & (wad_fifo_empty == 1'b0) )
case (wad_fifo_dout[WAD_FIFO_AWSIZE_HIGH:WAD_FIFO_AWSIZE_LOW])
3'b000 : addr_inc_step_wr <= 1; // 8ビット転送
3'b001 : addr_inc_step_wr <= 2; // 16ビット転送
3'b010 : addr_inc_step_wr <= 4; // 32ビット転送
3'b011 : addr_inc_step_wr <= 8; // 64ビット転送
3'b100 : addr_inc_step_wr <= 16; // 128ビット転送
3'b101 : addr_inc_step_wr <= 32; // 256ビット転送
3'b110 : addr_inc_step_wr <= 64; // 512ビット転送
default: addr_inc_step_wr <= 128; // 1024ビット転送
endcase
end
end
// wr_addr の処理
always @ (posedge ACLK ) begin
if ( reset )
wr_addr <= 'b0;
else begin
if ( (wrdat_cs == IDLE_WRDT) && (wad_fifo_empty == 1'b0) )
wr_addr <= wad_fifo_dout[(C_OFFSET_WIDTH - 1):0];
else if ( (wrdat_cs == WR_BURST) && S_AXI_WVALID && wready ) // アドレスを進める
wr_addr <= (wr_addr + addr_inc_step_wr);
end
end
// Wirte Response FIFO (wres_fifo)
sync_fifo #(
.C_MEMORY_SIZE(AD_FIFO_DEPTH),
.DATA_BUS_WIDTH(WRES_FIFO_WIDTH)
) wres_fifo (
.clk(ACLK),
.rst(reset),
.wr_en(wres_fifo_wr_en),
.din(wres_fifo_din),
.full(wres_fifo_full),
.almost_full(wres_fifo_almost_full),
.rd_en(wres_fifo_rd_en),
.dout(wres_fifo_dout),
.empty(wres_fifo_empty),
.almost_empty(wres_fifo_almost_empty)
);
assign wres_fifo_wr_en = (S_AXI_WLAST & S_AXI_WVALID & wready) ? 1'b1 : 1'b0; // Write Transaction 終了
assign wres_fifo_din = {wad_fifo_dout[WAD_FIFO_AWID_HIGH:WAD_FIFO_AWID_LOW], wad_fifo_dout[WAD_FIFO_AWBURST_HIGH:WAD_FIFO_AWBURST_LOW]};
assign wres_fifo_rd_en = (wr_bvalid & S_AXI_BREADY) ? 1'b1 : 1'b0;
// S_AXI_BID の処理
assign S_AXI_BID = wres_fifo_dout[WRES_FIFO_AWID_HIGH:WRES_FIFO_AWID_LOW];
// S_AXI_BRESP の処理
// S_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
assign S_AXI_BRESP = (wres_fifo_dout[WRES_FIFO_AWBURST_HIGH:WRES_FIFO_AWBURST_LOW]==AXBURST_INCR) ? RESP_OKAY : RESP_SLVERR;
// wr_bvalid の処理
// wr_bvalid のアサートは、Write Data Channelの完了より必ず1クロックは遅延する
always @ ( posedge ACLK ) begin
if ( reset ) begin
wrres_cs <= IDLE_WRES;
wr_bvalid <= 1'b0;
end
else
case (wrres_cs)
IDLE_WRES: if ( wres_fifo_empty == 1'b0 ) begin // Write Transaction 終了
if ( (m_seq16_wr_res == 0) || (RANDOM_BVALID_WAIT == 0) ) begin
wrres_cs <= BVALID_ASSERT;
wr_bvalid <= 1'b1;
end
else
wrres_cs <= WAIT_BVALID;
end
WAIT_BVALID:if ( wr_resp_cnt == 0 ) begin
wrres_cs <= BVALID_ASSERT;
wr_bvalid <= 1'b1;
end
BVALID_ASSERT: if ( S_AXI_BREADY ) begin
wrres_cs <= IDLE_WRES;
wr_bvalid <= 1'b0;
end
endcase
end
assign S_AXI_BVALID = wr_bvalid;
assign S_AXI_BUSER = 'b0;
// wr_resp_cnt
always @ ( posedge ACLK ) begin
if ( reset )
wr_resp_cnt <= 'b0;
else begin
if ( (wrres_cs == IDLE_WRES) && (wres_fifo_empty==1'b0) )
wr_resp_cnt <= m_seq16_wr_res[4:0];
else if ( wr_resp_cnt!=0 )
wr_resp_cnt <= wr_resp_cnt - 1;
end
end
// m_seq_wr_res、16ビットのM系列を計算する
always @ ( posedge ACLK ) begin
if ( reset )
m_seq16_wr_res <= 16'b1;
else
m_seq16_wr_res <= M_SEQ16_BFM_F(m_seq16_wr_res);
end
// AXI4バス Read Address Transaction State Machine
always @ ( posedge ACLK ) begin
if ( reset ) begin
rdadr_cs <= IDLE_RDA;
arready <= 1'b0;
end
else
case (rdadr_cs)
IDLE_RDA: if ( (S_AXI_ARVALID == 1'b1) && (rad_fifo_full == 1'b0) ) begin // Read Transaction要求
rdadr_cs <= ARR_ACCEPT;
arready <= 1'b1;
end
ARR_ACCEPT: begin // S_AXI_ARREADYをアサート
rdadr_cs <= IDLE_RDA;
arready <= 1'b0;
end
endcase
end
assign S_AXI_ARREADY = (ARREADY_IS_USUALLY_HIGH==1) ? ~rad_fifo_full : arready;
// S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR を保存しておく同期FIFO
assign rad_fifo_din ={S_AXI_ARID, S_AXI_ARBURST, S_AXI_ARSIZE, S_AXI_ARLEN, S_AXI_ARADDR};
assign rad_fifo_wr_en = (ARREADY_IS_USUALLY_HIGH==1) ? (S_AXI_ARVALID & ~rad_fifo_full) : arready;
sync_fifo #(
.C_MEMORY_SIZE (AD_FIFO_DEPTH),
.DATA_BUS_WIDTH (RAD_FIFO_WIDTH)
) rad_fifo
(
.clk (ACLK),
.rst (reset),
.wr_en (rad_fifo_wr_en),
.din (rad_fifo_din),
.full (rad_fifo_full),
.almost_full (rad_fifo_almost_full),
.rd_en (rad_fifo_rd_en),
.dout (rad_fifo_dout),
.empty (rad_fifo_empty),
.almost_empty (rad_fifo_almost_empty)
);
assign rad_fifo_rd_en = (rvalid & S_AXI_RREADY & rlast);
// AXI4バス Read Data Transaction State Machine
always @( posedge ACLK ) begin
if ( reset )
rddat_cs <= IDLE_RDD;
else
case (rddat_cs)
IDLE_RDD: if ( rad_fifo_empty == 1'b0 ) // AXI Read アドレス転送の残りが1個以上ある
rddat_cs <= RD_BURST;
RD_BURST: if ( (rd_axi_count == 0) && rvalid && S_AXI_RREADY ) // Read Transaction終了
rddat_cs <= IDLE_RDD;
endcase
end
// m_seq_rd、16ビットのM系列を計算する
always @ ( posedge ACLK ) begin
if ( reset )
m_seq16_rd <= 16'hffff;
else begin
if ( READ_RANDOM_WAIT) begin
if ( rddat_cs == RD_BURST )
m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
end else
m_seq16_rd <= 16'b0;
end
end
// rvalidの処理、M系列を計算して128以上だったらWaitする
always @( posedge ACLK ) begin
if ( reset ) begin
cs_rvalid <= IDLE_RVALID;
rvalid <= 1'b0;
end
else
case (cs_rvalid)
IDLE_RVALID: if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) ) begin // 次はrd_burst
if ( m_seq16_rd[7] == 1'b0 ) begin
cs_rvalid <= ASSERT_RVALID;
rvalid <= 1'b1;
end
else begin
cs_rvalid <= DEASSERT_RVALID;
rvalid <= 1'b0;
end
end
ASSERT_RVALID: if ( (rddat_cs == RD_BURST) && rlast && S_AXI_RREADY ) begin // 終了
cs_rvalid <= IDLE_RVALID;
rvalid <= 1'b0;
end
else if ( (rddat_cs == RD_BURST) & S_AXI_RREADY ) begin // 1つのトランザクション終了
if ( m_seq16_rd[7] ) begin
cs_rvalid <= DEASSERT_RVALID;
rvalid <= 1'b0;
end
end
DEASSERT_RVALID:if ( m_seq16_rd[7] == 1'b0 ) begin
cs_rvalid <= ASSERT_RVALID;
rvalid <= 1'b1;
end
endcase
end
assign S_AXI_RVALID = rvalid;
// addr_inc_step_rdの処理
always @( posedge ACLK ) begin
if ( reset )
addr_inc_step_rd <= 1;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) )
case (rad_fifo_dout[RAD_FIFO_ARSIZE_HIGH:RAD_FIFO_ARSIZE_LOW])
3'b000: addr_inc_step_rd <= 1; // 8ビット転送
3'b001: addr_inc_step_rd <= 2; // 16ビット転送
3'b010: addr_inc_step_rd <= 4; // 32ビット転送
3'b011: addr_inc_step_rd <= 8; // 64ビット転送
3'b100: addr_inc_step_rd <= 16; // 128ビット転送
3'b101: addr_inc_step_rd <= 32; // 256ビット転送
3'b110: addr_inc_step_rd <= 64; // 512ビット転送
default:addr_inc_step_rd <= 128; // 1024ビット転送
endcase
end
end
// rd_addr の処理
always @ ( posedge ACLK ) begin
if ( reset )
rd_addr <= 'b0;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) )
rd_addr <= rad_fifo_dout[(C_OFFSET_WIDTH - 1):0];
else if ( (rddat_cs == RD_BURST) && S_AXI_RREADY && rvalid )
rd_addr <= (rd_addr + addr_inc_step_rd);
end
end
// rd_axi_countの処理(AXIバス側のデータカウント)
always @ ( posedge ACLK ) begin
if ( reset )
rd_axi_count <= 'b0;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) ) // rd_axi_countのロード
rd_axi_count <= rad_fifo_dout[RAD_FIFO_ARLEN_HIGH:RAD_FIFO_ARLEN_LOW];
else if ( (rddat_cs == RD_BURST) && rvalid && S_AXI_RREADY ) // Read Transactionが1つ終了
rd_axi_count <= rd_axi_count - 1;
end
end
// rdlast State Machine
always @ ( posedge ACLK ) begin
if ( reset ) begin
rdlast <= IDLE_RLAST;
rlast <= 1'b0;
end
else
case (rdlast)
IDLE_RLAST: if ( (rd_axi_count == 1) && rvalid && S_AXI_RREADY ) begin // バーストする場合
rdlast <= RLAST_ASSERT;
rlast <= 1'b1;
end
else if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) &&
(rad_fifo_dout[RAD_FIFO_ARLEN_HIGH:RAD_FIFO_ARLEN_LOW] == 0) ) begin // 転送数が1の場合
rdlast <= RLAST_ASSERT;
rlast <= 1'b1;
end
RLAST_ASSERT:if ( rvalid && S_AXI_RREADY ) begin // Read Transaction終了(rd_axi_count=0は決定)
rdlast <= IDLE_RLAST;
rlast <= 1'b0;
end
endcase
end
assign S_AXI_RLAST = rlast;
// S_AXI_RID, S_AXI_RUSER の処理
always @ ( posedge ACLK ) begin
if ( reset )
S_AXI_RID <= 'b0;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) )
S_AXI_RID <= rad_fifo_dout[RAD_FIFO_ARID_HIGH:RAD_FIFO_ARID_LOW];
end
end
assign S_AXI_RUSER = 'b0;
// S_AXI_RRESP は、S_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
always @( posedge ACLK ) begin
if ( reset )
S_AXI_RRESP <= 'b0;
else begin
if ( (rddat_cs == IDLE_RDD) && (rad_fifo_empty == 1'b0) ) begin
if ((rad_fifo_dout[RAD_FIFO_ARBURST_HIGH:RAD_FIFO_ARBURST_LOW] == AXBURST_INCR))
S_AXI_RRESP <= RESP_OKAY;
else
S_AXI_RRESP <= RESP_SLVERR;
end
end
end
// RAM
integer i;
always @( posedge ACLK ) begin
if ( cdc_we ) begin :Block_Name_2
for (i=0; i<(C_S_AXI_DATA_WIDTH / 8); i=i+1) begin
if ( S_AXI_WSTRB[i] )
ram_array[wr_addr[(C_OFFSET_WIDTH - 1):ADD_INC_OFFSET]][(i * 8) +: 8]
<= S_AXI_WDATA[(i * 8) +: 8];
end
end
end
// Read Transaciton の時に +1 されたReadデータを使用する(Read 毎に+1)
always @( posedge ACLK ) begin
if ( reset )
read_data_count <= 'b0;
else begin
if ( (rddat_cs == RD_BURST) && rvalid && S_AXI_RREADY )
read_data_count <= read_data_count + 1;
end
end
assign S_AXI_RDATA = (READ_DATA_IS_INCREMENT == 0) ?
ram_array[rd_addr[(C_OFFSET_WIDTH - 1):ADD_INC_OFFSET]] : read_data_count;
endmodule
// Synchronous FIFO for Simulation
//
// 2013/11/08 by marsee
//
// ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
//
`default_nettype none
module sync_fifo #(
parameter integer C_MEMORY_SIZE = 512, // Word (not byte), 2のn乗
parameter integer DATA_BUS_WIDTH = 32 // RAM Data Width
)
(
input wire clk,
input wire rst,
input wire wr_en,
input wire [DATA_BUS_WIDTH-1:0] din,
output wire full,
output wire almost_full,
input wire rd_en,
output wire [DATA_BUS_WIDTH-1:0] dout,
output wire empty,
output wire almost_empty
);
// 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] mem [0:C_MEMORY_SIZE-1];
reg [log2(C_MEMORY_SIZE)-1:0] mem_waddr = 0;
reg [log2(C_MEMORY_SIZE)-1:0] mem_raddr = 0;
reg [log2(C_MEMORY_SIZE)-1:0] rp = 0;
reg [log2(C_MEMORY_SIZE)-1:0] wp = 0;
wire [log2(C_MEMORY_SIZE)-1:0] plus_1 = 1;
wire [log2(C_MEMORY_SIZE)-1:0] plus_2 = 2;
wire almost_full_node;
wire almost_empty_node;
integer i;
// initialize RAM Data
initial begin
for (i=0; i<C_MEMORY_SIZE; i=i+1)
mem[i] = 0;
end
// Write
always @(posedge clk) begin
if (rst) begin
mem_waddr <= 0;
wp <= 0;
end else begin
if (wr_en) begin
mem_waddr <= mem_waddr + 1;
wp <= wp + 1;
end
end
end
always @(posedge clk) begin
if (wr_en) begin
mem[mem_waddr] <= din;
end
end
assign full = (wp+plus_1 == rp) ? 1'b1 : 1'b0;
assign almost_full_node = (wp+plus_2 == rp) ? 1'b1 : 1'b0;
assign almost_full = full | almost_full_node;
// Read
always @(posedge clk) begin
if (rst) begin
mem_raddr <= 0;
rp <= 0;
end else begin
if (rd_en) begin
mem_raddr <= mem_raddr + 1;
rp <= rp + 1;
end
end
end
assign dout = mem[mem_raddr];
assign empty = (wp == rp) ? 1'b1 : 1'b0;
assign almost_empty_node = (wp == rp+plus_1) ? 1'b1 : 1'b0;
assign almost_empty = empty | almost_empty_node;
endmodule
`default_nettype wire
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |