[Synth 8-1766] cannot open include file ./video_timing_param.vh ["z:/V_ZYBO_BMDC142/V_ZYBO_BMDC142.srcs/sources_1/ipshared/xilinx.com/bitmap_disp_cntrler_axi_master_v1_0/510327c8/sources/verilog/bitmap_disp_engine.v":39]
ERROR: [VRFC 10-91] oserdes2 is not declared [C:/Users/Masaaki/Documents/Vivado/Zynq/ZYBO/IP_test/bm_dispc_wh_142/sources/vhdl/Digilent_RTL/SerializerN_1.vhd:134]
ERROR: [VRFC 10-91] oserdes2 is not declared [C:/Users/Masaaki/Documents/Vivado/Zynq/ZYBO/IP_test/bm_dispc_wh_142/sources/vhdl/Digilent_RTL/SerializerN_1.vhd:168]
ERROR: [VRFC 10-1504] unit behavioral ignored due to previous errors [C:/Users/Masaaki/Documents/Vivado/Zynq/ZYBO/IP_test/bm_dispc_wh_142/sources/vhdl/Digilent_RTL/SerializerN_1.vhd:76]
このテキストファイルは、Excel で、最初の列に+1した数を書いて、次の列に、=DEC2HEX(A1, 8) の様に10進数から16進数を変換する関数を書くことによって作っている。なお、RAMを16進数で書かれた外部ファイルから初期化する方法は、”VerilogでXSTにBlock RAMを推論させる”を参照のこと。00000000
00000001
00000002
00000003
00000004
00000005
アドレスの大きい方から初期値が入ってしまうので、reg [(C_S_AXI_DATA_WIDTH - 1):0] ram_array [(SLAVE_ADDR_NUMBER - 1):0];
に変更した。reg [(C_S_AXI_DATA_WIDTH - 1):0] ram_array [0:(SLAVE_ADDR_NUMBER - 1)];
/* 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
//
// ライセンスは二条項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.txt",
parameter integer LOAD_RAM_INIT_FILE = 0 // RAM_INIT_FILE をLoadする - 1, Load しない - 0
)
(
// 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_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_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;
// {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};
sync_fifo #(
.C_MEMORY_SIZE (AD_FIFO_DEPTH),
.DATA_BUS_WIDTH (WAD_FIFO_WIDTH)
) wad_fifo (
.clk (ACLK),
.rst (reset),
.wr_en (awready),
.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;
// 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};
sync_fifo #(
.C_MEMORY_SIZE (AD_FIFO_DEPTH),
.DATA_BUS_WIDTH (RAD_FIFO_WIDTH)
) rad_fifo
(
.clk (ACLK),
.rst (reset),
.wr_en (arready),
.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
このテキストファイルは、Excel で、最初の列に+1した数を書いて、次の列に、=DEC2HEX(A1, 8) の様に10進数から16進数を変換する関数を書くことによって作っている。なお、RAMを16進数で書かれた外部ファイルから初期化する方法は、”VHDLでのブロックRAMや分散RAMの初期化(16進数で書かれた外部データファイル)”を参照のこと。00000000
00000001
00000002
00000003
00000004
00000005
アドレスの大きい方から初期値が入ってしまうので、type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
に変更した。type ram_array_def is array (0 to SLAVE_ADDR_NUMBER-1) of std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
-----------------------------------------------------------------------------
--
-- AXI Master用 Slave Bus Function Mode (BFM) by marsee
-- axi_slave_BFM_initf.vhd
--
-----------------------------------------------------------------------------
-- 2012/02/25 : S_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
-- 2012/07/04 : READ_ONLY_TRANSACTION を追加。Read機能のみでも+1したデータを出力することが出来るように変更した。
-- sync_fifo を使用したオーバーラップ対応版
-- 2014/07/04 : M_AXIをスレーブに対応した名前のS_AXIに変更
-- 2014/07/16 : Write Respose Channel に sync_fifo を使用した
-- 2014/07/19 : RAM を初期化する初期化ファイルを追加(init_ram_data.txt)
-- 2014/07/20 : RAM 初期化ファイル名を generic に追加
-- 2014/08/31 : READ_RANDOM_WAIT=1 の時に、S_AXI_RREADY が S_AXI_RVALID に依存するバグをフィック。
-- WRITE_RANDOM_WAIT=1 の時に、S_AXI_WVALID が S_AXI_WREADY に依存するバグをフィック。
-- LOAD_RAM_INIT_FILE パラメータを追加
--
-- ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
package m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector;
end package m_seq_bfm_pack;
package body m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector is
variable mseq16 : std_logic_vector(15 downto 0);
variable xor_result : std_logic;
begin
xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
mseq16 := mseq16in(14 downto 0) & xor_result;
return mseq16;
end M_SEQ16_BFM_F;
end m_seq_bfm_pack;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
use IEEE.math_real.all;
use STD.textio.all;
use IEEE.std_logic_textio.all;
library work;
use work.m_seq_bfm_pack.all;
--library unisim;
--use unisim.vcomponents.all;
entity axi_slave_bfm is
generic (
C_S_AXI_ID_WIDTH : integer := 1;
C_S_AXI_ADDR_WIDTH : integer := 32;
C_S_AXI_DATA_WIDTH : integer := 32;
C_S_AXI_AWUSER_WIDTH : integer := 1;
C_S_AXI_ARUSER_WIDTH : integer := 1;
C_S_AXI_WUSER_WIDTH : integer := 1;
C_S_AXI_RUSER_WIDTH : integer := 1;
C_S_AXI_BUSER_WIDTH : integer := 1;
C_S_AXI_TARGET : integer := 0;
C_OFFSET_WIDTH : integer := 10; -- 割り当てるRAMのアドレスのビット幅
C_S_AXI_BURST_LEN : integer := 256;
WRITE_RANDOM_WAIT : integer := 1; -- Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_RANDOM_WAIT : integer := 0; -- Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_DATA_IS_INCREMENT : integer := 0; -- ReadトランザクションでRAMの内容をReadする = 0(RAMにWriteしたものをReadする)、Readデータを+1する = 1(データは+1したデータをReadデータとして使用する
RANDOM_BVALID_WAIT : integer := 0; -- Write Data Transaction が終了した後で、BVALID をランダムにWaitする = 1、BVALID をランダムにWaitしない = 0, 31 ~ 0 クロックのWait
RAM_INIT_FILE : string := "init_ram_data.txt"; -- RAM の初期化ファイル名
LOAD_RAM_INIT_FILE : integer := 0 -- RAM_INIT_FILE をLoadする - 1, Load しない - 0
);
port(
-- System Signals
ACLK : in std_logic;
ARESETN : in std_logic;
-- Master Interface Write Address Ports
S_AXI_AWID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_AWADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_AWLEN : in std_logic_vector(8-1 downto 0);
S_AXI_AWSIZE : in std_logic_vector(3-1 downto 0);
S_AXI_AWBURST : in std_logic_vector(2-1 downto 0);
-- S_AXI_AWLOCK : in std_logic_vector(2-1 downto 0);
S_AXI_AWLOCK : in std_logic_vector(1 downto 0);
S_AXI_AWCACHE : in std_logic_vector(4-1 downto 0);
S_AXI_AWPROT : in std_logic_vector(3-1 downto 0);
S_AXI_AWQOS : in std_logic_vector(4-1 downto 0);
S_AXI_AWUSER : in std_logic_vector(C_S_AXI_AWUSER_WIDTH-1 downto 0);
S_AXI_AWVALID : in std_logic;
S_AXI_AWREADY : out std_logic;
-- Master Interface Write Data Ports
S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_WSTRB : in std_logic_vector(C_S_AXI_DATA_WIDTH/8-1 downto 0);
S_AXI_WLAST : in std_logic;
S_AXI_WUSER : in std_logic_vector(C_S_AXI_WUSER_WIDTH-1 downto 0);
S_AXI_WVALID : in std_logic;
S_AXI_WREADY : out std_logic;
-- Master Interface Write Response Ports
S_AXI_BID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_BRESP : out std_logic_vector(2-1 downto 0);
S_AXI_BUSER : out std_logic_vector(C_S_AXI_BUSER_WIDTH-1 downto 0);
S_AXI_BVALID : out std_logic;
S_AXI_BREADY : in std_logic;
-- Master Interface Read Address Ports
S_AXI_ARID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_ARADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_ARLEN : in std_logic_vector(8-1 downto 0);
S_AXI_ARSIZE : in std_logic_vector(3-1 downto 0);
S_AXI_ARBURST : in std_logic_vector(2-1 downto 0);
S_AXI_ARLOCK : in std_logic_vector(2-1 downto 0);
S_AXI_ARCACHE : in std_logic_vector(4-1 downto 0);
S_AXI_ARPROT : in std_logic_vector(3-1 downto 0);
S_AXI_ARQOS : in std_logic_vector(4-1 downto 0);
S_AXI_ARUSER : in std_logic_vector(C_S_AXI_ARUSER_WIDTH-1 downto 0);
S_AXI_ARVALID : in std_logic;
S_AXI_ARREADY : out std_logic;
-- Master Interface Read Data Ports
S_AXI_RID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_RRESP : out std_logic_vector(2-1 downto 0);
S_AXI_RLAST : out std_logic;
S_AXI_RUSER : out std_logic_vector(C_S_AXI_RUSER_WIDTH-1 downto 0);
S_AXI_RVALID : out std_logic;
S_AXI_RREADY : in std_logic
);
end axi_slave_bfm;
architecture implementation of axi_slave_bfm is
constant AxBURST_FIXED : std_logic_vector := "00";
constant AxBURST_INCR : std_logic_vector := "01";
constant AxBURST_WRAP : std_logic_vector := "10";
constant RESP_OKAY : std_logic_vector := "00";
constant RESP_EXOKAY : std_logic_vector := "01";
constant RESP_SLVERR : std_logic_vector := "10";
constant RESP_DECERR : std_logic_vector := "11";
constant DATA_BUS_BYTES : natural := C_S_AXI_DATA_WIDTH/8; -- データバスのビット幅
constant ADD_INC_OFFSET : natural := natural(log(real(DATA_BUS_BYTES), 2.0));
-- fifo depth for address
constant AD_FIFO_DEPTH : natural := 16;
-- wad_fifo field
constant WAD_FIFO_WIDTH : natural := C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1+1;
constant WAD_FIFO_AWID_HIGH : natural := C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1;
constant WAD_FIFO_AWID_LOW : natural := C_S_AXI_ADDR_WIDTH+5;
constant WAD_FIFO_AWBURST_HIGH : natural := C_S_AXI_ADDR_WIDTH+4;
constant WAD_FIFO_AWBURST_LOW : natural := C_S_AXI_ADDR_WIDTH+3;
constant WAD_FIFO_AWSIZE_HIGH : natural := C_S_AXI_ADDR_WIDTH+2;
constant WAD_FIFO_AWSIZE_LOW : natural := C_S_AXI_ADDR_WIDTH;
constant WAD_FIFO_ADDR_HIGH : natural := C_S_AXI_ADDR_WIDTH-1;
constant WAD_FIFO_ADDR_LOW : natural := 0;
-- wres_fifo field
constant WRES_FIFO_WIDTH : natural := 2+C_S_AXI_ID_WIDTH-1+1;
constant WRES_FIFO_AWID_HIGH : natural := 2+C_S_AXI_ID_WIDTH-1;
constant WRES_FIFO_AWID_LOW : natural := 2;
constant WRES_FIFO_AWBURST_HIGH : natural := 1;
constant WRES_FIFO_AWBURST_LOW : natural := 0;
-- rad_fifo field
constant RAD_FIFO_WIDTH : natural := C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1+1;
constant RAD_FIFO_ARID_HIGH : natural := C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1;
constant RAD_FIFO_ARID_LOW : natural := C_S_AXI_ADDR_WIDTH+13;
constant RAD_FIFO_ARBURST_HIGH : natural := C_S_AXI_ADDR_WIDTH+12;
constant RAD_FIFO_ARBURST_LOW : natural := C_S_AXI_ADDR_WIDTH+11;
constant RAD_FIFO_ARSIZE_HIGH : natural := C_S_AXI_ADDR_WIDTH+10;
constant RAD_FIFO_ARSIZE_LOW : natural := C_S_AXI_ADDR_WIDTH+8;
constant RAD_FIFO_ARLEN_HIGH : natural := C_S_AXI_ADDR_WIDTH+7;
constant RAD_FIFO_ARLEN_LOW : natural := C_S_AXI_ADDR_WIDTH;
constant RAD_FIFO_ADDR_HIGH : natural := C_S_AXI_ADDR_WIDTH-1;
constant RAD_FIFO_ADDR_LOW : natural := 0;
-- RAMの生成
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (0 to SLAVE_ADDR_NUMBER-1) of std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
impure function InitRamFromFile (RamFileName : in string) return ram_array_def is
FILE RamFile : text is in RamFileName;
variable RamFileLine : line;
variable RAM : ram_array_def;
begin
for I in ram_array_def'range loop
if (LOAD_RAM_INIT_FILE=1) then
readline (RamFile, RamFileLine);
hread (RamFileLine, RAM(I));
end if;
end loop;
return RAM;
end function;
signal ram_array : ram_array_def := InitRamFromFile(RAM_INIT_FILE);
-- for write transaction
type write_address_state is (idle_wrad, awr_accept);
type write_data_state is (idle_wrdt, wr_burst);
type write_response_state is (idle_wres, wait_bvalid, bvalid_assert);
signal wradr_cs : write_address_state;
signal wrdat_cs : write_data_state;
signal wrres_cs : write_response_state;
signal addr_inc_step_wr : integer := 1;
signal awready : std_logic;
signal wr_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal wr_bvalid : std_logic;
signal m_seq16_wr : std_logic_vector(15 downto 0);
signal wready : std_logic;
type wready_state is (idle_wready, assert_wready, deassert_wready);
signal cs_wready : wready_state;
signal cdc_we : std_logic;
signal wad_fifo_full, wad_fifo_empty : std_logic;
signal wad_fifo_almost_full, wad_fifo_almost_empty : std_logic;
signal wad_fifo_rd_en : std_logic;
signal wad_fifo_din : std_logic_vector(WAD_FIFO_WIDTH-1 downto 0);
signal wad_fifo_dout : std_logic_vector(WAD_FIFO_WIDTH-1 downto 0);
signal m_seq16_wr_res : std_logic_vector(15 downto 0);
signal wr_resp_cnt : std_logic_vector(4 downto 0);
signal wres_fifo_wr_en : std_logic;
signal wres_fifo_full, wres_fifo_empty : std_logic;
signal wres_fifo_almost_full, wres_fifo_almost_empty : std_logic;
signal wres_fifo_rd_en : std_logic;
signal wres_fifo_din : std_logic_vector(WRES_FIFO_WIDTH-1 downto 0);
signal wres_fifo_dout : std_logic_vector(WRES_FIFO_WIDTH-1 downto 0);
-- for read transaction
type read_address_state is (idle_rda, arr_accept);
type read_data_state is (idle_rdd, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdadr_cs : read_address_state;
signal rddat_cs : read_data_state;
signal rdlast : read_last_state;
signal addr_inc_step_rd : integer := 1;
signal arready : std_logic;
signal rd_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal rd_axi_count : std_logic_vector(7 downto 0);
signal rvalid : std_logic;
signal rlast : std_logic;
signal m_seq16_rd : std_logic_vector(15 downto 0);
type rvalid_state is (idle_rvalid, assert_rvalid, deassert_rvalid);
signal cs_rvalid : rvalid_state;
signal read_data_count : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal reset_1d, reset_2d, reset : std_logic := '1';
signal rad_fifo_full, rad_fifo_empty : std_logic;
signal rad_fifo_almost_full, rad_fifo_almost_empty : std_logic;
signal rad_fifo_rd_en : std_logic;
signal rad_fifo_din : std_logic_vector(RAD_FIFO_WIDTH-1 downto 0);
signal rad_fifo_dout : std_logic_vector(RAD_FIFO_WIDTH-1 downto 0);
component sync_fifo generic (
constant C_MEMORY_SIZE : integer := 512; -- Word (not byte), 2のn乗
constant DATA_BUS_WIDTH : integer := 32 -- RAM Data Width
);
port (
clk : in std_logic;
rst : in std_logic;
wr_en : in std_logic;
din : in std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
full : out std_logic;
almost_full : out std_logic;
rd_en : in std_logic;
dout : out std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
empty : out std_logic;
almost_empty : out std_logic
);
end component;
begin
-- ARESETN をACLK で同期化
process (ACLK) begin
if ACLK'event and ACLK='1' then
reset_1d <= not ARESETN;
reset_2d <= reset_1d;
end if;
end process;
reset <= reset_2d;
-- AXI4バス Write Address State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wradr_cs <= idle_wrad;
awready <= '0';
else
case (wradr_cs) is
when idle_wrad =>
if S_AXI_AWVALID='1' and wad_fifo_full='0' and wres_fifo_full='0' then -- S_AXI_AWVALID が1にアサートされた
wradr_cs <= awr_accept;
awready <= '1';
end if;
when awr_accept => -- S_AXI_AWREADY をアサート
wradr_cs <= idle_wrad;
awready <= '0';
end case;
end if;
end if;
end process;
S_AXI_AWREADY <= awready;
-- S_AXI_AWID & S_AXI_AWBURST & S_AXI_AWSIZE & S_AXI_AWADDR を保存しておく同期FIFO
wad_fifo_din <= (S_AXI_AWID & S_AXI_AWBURST & S_AXI_AWSIZE & S_AXI_AWADDR);
wad_fifo : sync_fifo generic map(
C_MEMORY_SIZE => AD_FIFO_DEPTH,
DATA_BUS_WIDTH => WAD_FIFO_WIDTH
) port map (
clk => ACLK,
rst => reset,
wr_en => awready,
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
);
wad_fifo_rd_en <= '1' when wready='1' and S_AXI_WVALID='1' and S_AXI_WLAST='1' else '0';
-- AXI4バス Write Data State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrdat_cs <= idle_wrdt;
else
case( wrdat_cs ) is
when idle_wrdt =>
if wad_fifo_empty='0' then -- AXI Write アドレス転送の残りが1個以上ある
wrdat_cs <= wr_burst;
end if;
when wr_burst => -- Writeデータの転送
if S_AXI_WLAST='1' and S_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wrdat_cs <= idle_wrdt;
end if;
when others =>
end case ;
end if;
end if;
end process;
-- m_seq_wr、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr <= (0 => '1', others => '0');
else
if WRITE_RANDOM_WAIT=1 then -- Write Transaction 時にランダムなWaitを挿入する
if wrdat_cs=wr_burst then
m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
end if;
else -- Wait無し
m_seq16_wr <= (others => '0');
end if;
end if;
end if;
end process;
-- wready の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_wready <= idle_wready;
wready <= '0';
else
case (cs_wready) is
when idle_wready =>
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then -- 次はwr_burst
if m_seq16_wr(7)='0' and wres_fifo_full='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
else -- m_seq16_wr(7)='1' then -- wready='0'
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when assert_wready => -- 一度wreadyがアサートされたら、1つのトランザクションが終了するまでwready='1'
if wrdat_cs=wr_burst and S_AXI_WLAST='1' and S_AXI_WVALID='1' then -- 終了
cs_wready <= idle_wready;
wready <= '0';
elsif wrdat_cs=wr_burst and S_AXI_WVALID='1' then -- 1つのトランザクション終了。
if m_seq16_wr(7)='1' or wres_fifo_full='1' then
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when deassert_wready =>
if m_seq16_wr(7)='0' and wres_fifo_full='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
end if;
end case;
end if;
end if;
end process;
S_AXI_WREADY <= wready;
cdc_we <= '1' when wrdat_cs=wr_burst and wready='1' and S_AXI_WVALID='1' else '0';
-- addr_inc_step_wr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_wr <= 1;
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
case (wad_fifo_dout(WAD_FIFO_AWSIZE_HIGH downto WAD_FIFO_AWSIZE_LOW)) is
when "000" => -- 8ビット転送
addr_inc_step_wr <= 1;
when "001" => -- 16ビット転送
addr_inc_step_wr <= 2;
when "010" => -- 32ビット転送
addr_inc_step_wr <= 4;
when "011" => -- 64ビット転送
addr_inc_step_wr <= 8;
when "100" => -- 128ビット転送
addr_inc_step_wr <= 16;
when "101" => -- 256ビット転送
addr_inc_step_wr <= 32;
when "110" => -- 512ビット転送
addr_inc_step_wr <= 64;
when others => --"111" => -- 1024ビット転送
addr_inc_step_wr <= 128;
end case;
end if;
end if;
end if;
end process;
-- wr_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_addr <= (others => '0');
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
wr_addr <= wad_fifo_dout(C_OFFSET_WIDTH-1 downto 0);
elsif wrdat_cs=wr_burst and S_AXI_WVALID='1' and wready='1' then -- アドレスを進める
wr_addr <= std_logic_vector(unsigned(wr_addr) + addr_inc_step_wr);
end if;
end if;
end if;
end process;
-- Wirte Response FIFO (wres_fifo)
wres_fifo : sync_fifo generic map(
C_MEMORY_SIZE => AD_FIFO_DEPTH,
DATA_BUS_WIDTH => WRES_FIFO_WIDTH
) port map (
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
);
wres_fifo_wr_en <= '1' when S_AXI_WLAST='1' and S_AXI_WVALID='1' and wready='1' else '0'; -- Write Transaction 終了
wres_fifo_din <= (wad_fifo_dout(WAD_FIFO_AWID_HIGH downto WAD_FIFO_AWID_LOW) & wad_fifo_dout(WAD_FIFO_AWBURST_HIGH downto WAD_FIFO_AWBURST_LOW));
wres_fifo_rd_en <= '1' when wr_bvalid='1' and S_AXI_BREADY='1' and wres_fifo_empty='0' else '0';
-- S_AXI_BID の処理
S_AXI_BID <= wres_fifo_dout(WRES_FIFO_AWID_HIGH downto WRES_FIFO_AWID_LOW);
-- S_AXI_BRESP の処理
-- S_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
S_AXI_BRESP <= RESP_OKAY when wres_fifo_dout(WRES_FIFO_AWBURST_HIGH downto WRES_FIFO_AWBURST_LOW)=AxBURST_INCR else RESP_SLVERR;
-- wr_bvalid の処理
-- wr_bvalid のアサートは、Write Data Channelの完了より必ず1クロックは遅延する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrres_cs <= idle_wres;
wr_bvalid <= '0';
else
case( wrres_cs ) is
when idle_wres =>
if wres_fifo_empty='0' then -- Write Transaction 終了
if unsigned(m_seq16_wr_res) = 0 or RANDOM_BVALID_WAIT=0 then
wrres_cs <= bvalid_assert;
wr_bvalid <= '1';
else
wrres_cs <= wait_bvalid;
end if;
end if;
when wait_bvalid =>
if unsigned(wr_resp_cnt) = 0 then
wrres_cs <= bvalid_assert;
wr_bvalid <= '1';
end if;
when bvalid_assert =>
if (S_AXI_BREADY='1') then
wrres_cs <= idle_wres;
wr_bvalid <= '0';
end if;
when others =>
end case ;
end if;
end if;
end process;
S_AXI_BVALID <= wr_bvalid;
S_AXI_BUSER <= (others => '0');
-- wr_resp_cnt
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_resp_cnt <= (others => '0');
else
if wrres_cs=idle_wres and wres_fifo_empty='0' then
wr_resp_cnt <= m_seq16_wr_res(4 downto 0);
elsif unsigned(wr_resp_cnt) /= 0 then
wr_resp_cnt <= std_logic_vector(unsigned(wr_resp_cnt) - 1);
end if;
end if;
end if;
end process;
-- m_seq_wr_res、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr_res <= (0 => '1', others => '0');
else
m_seq16_wr_res <= M_SEQ16_BFM_F(m_seq16_wr_res);
end if;
end if;
end process;
-- AXI4バス Read Address Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdadr_cs <= idle_rda;
arready <= '0';
else
case (rdadr_cs) is
when idle_rda =>
if S_AXI_ARVALID='1' and rad_fifo_full='0' then -- Read Transaction 要求
rdadr_cs <= arr_accept;
arready <= '1';
end if;
when arr_accept => -- S_AXI_ARREADY をアサート
rdadr_cs <= idle_rda;
arready <= '0';
end case;
end if;
end if;
end process;
S_AXI_ARREADY <= arready;
-- S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR を保存しておく同期FIFO
rad_fifo_din <= (S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR);
rad_fifo : sync_fifo generic map (
C_MEMORY_SIZE => AD_FIFO_DEPTH,
DATA_BUS_WIDTH => RAD_FIFO_WIDTH
) port map (
clk => ACLK,
rst => reset,
wr_en => arready,
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
);
rad_fifo_rd_en <= '1' when rvalid='1' and S_AXI_RREADY='1' and rlast='1' else '0';
-- AXI4バス Read Data Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rddat_cs <= idle_rdd;
else
case (rddat_cs) is
when idle_rdd =>
if rad_fifo_empty='0' then -- AXI Read アドレス転送の残りが1個以上ある
rddat_cs <= rd_burst;
end if;
when rd_burst =>
if unsigned(rd_axi_count)=0 and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了
rddat_cs <= idle_rdd;
end if;
end case;
end if;
end if;
end process;
-- m_seq_rd、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_rd <= (others => '1'); -- Writeとシードを変更する
else
if READ_RANDOM_WAIT=1 then -- Read Transaciton のデータ転送でランダムなWaitを挿入する場合
if rddat_cs=rd_burst then
m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
end if;
else -- Wati無し
m_seq16_rd <= (others => '0');
end if;
end if;
end if;
end process;
-- rvalid の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_rvalid <= idle_rvalid;
rvalid <= '0';
else
case (cs_rvalid) is
when idle_rvalid =>
if rddat_cs=idle_rdd and rad_fifo_empty='0' then -- 次はrd_burst
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
else -- m_seq16_rd(7)='1' then -- rvalid='0'
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when assert_rvalid => -- 一度rvalidがアサートされたら、1つのトランザクションが終了するまでrvalid='1'
if rddat_cs=rd_burst and rlast='1' and S_AXI_RREADY='1' then -- 終了
cs_rvalid <= idle_rvalid;
rvalid <= '0';
elsif rddat_cs=rd_burst and S_AXI_RREADY='1' then -- 1つのトランザクション終了。
if m_seq16_rd(7)='1' then
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when deassert_rvalid =>
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
end if;
end case;
end if;
end if;
end process;
S_AXI_RVALID <= rvalid;
-- addr_inc_step_rd の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_rd <= 1;
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
case (rad_fifo_dout(RAD_FIFO_ARSIZE_HIGH downto RAD_FIFO_ARSIZE_LOW)) is
when "000" => -- 8ビット転送
addr_inc_step_rd <= 1;
when "001" => -- 16ビット転送
addr_inc_step_rd <= 2;
when "010" => -- 32ビット転送
addr_inc_step_rd <= 4;
when "011" => -- 64ビット転送
addr_inc_step_rd <= 8;
when "100" => -- 128ビット転送
addr_inc_step_rd <= 16;
when "101" => -- 256ビット転送
addr_inc_step_rd <= 32;
when "110" => -- 512ビット転送
addr_inc_step_rd <= 64;
when others => -- "111" => -- 1024ビット転送
addr_inc_step_rd <= 128;
end case;
end if;
end if;
end if;
end process;
-- rd_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_addr <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
rd_addr <= rad_fifo_dout(C_OFFSET_WIDTH-1 downto 0);
elsif rddat_cs=rd_burst and S_AXI_RREADY='1' and rvalid='1' then
rd_addr <= std_logic_vector(unsigned(rd_addr) + addr_inc_step_rd);
end if;
end if;
end if;
end process;
-- rd_axi_count の処理(AXIバス側のデータカウント)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_axi_count <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then -- rd_axi_count のロード
rd_axi_count <= rad_fifo_dout(RAD_FIFO_ARLEN_HIGH downto RAD_FIFO_ARLEN_LOW);
elsif rddat_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction が1つ終了
rd_axi_count <= std_logic_vector(unsigned(rd_axi_count) - 1);
end if;
end if;
end if;
end process;
-- rdlast State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdlast <= idle_rlast;
rlast <= '0';
else
case (rdlast) is
when idle_rlast =>
if unsigned(rd_axi_count)=1 and rvalid='1' and S_AXI_RREADY='1' then -- バーストする場合
rdlast <= rlast_assert;
rlast <= '1';
elsif rddat_cs=idle_rdd and rad_fifo_empty='0' and unsigned(rad_fifo_dout(RAD_FIFO_ARLEN_HIGH downto RAD_FIFO_ARLEN_LOW))=0 then -- 転送数が1の場合
rdlast <= rlast_assert;
rlast <= '1';
end if;
when rlast_assert =>
if rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了(rd_axi_count=0は決定)
rdlast <= idle_rlast;
rlast <= '0';
end if;
end case;
end if;
end if;
end process;
S_AXI_RLAST <= rlast;
-- S_AXI_RID, S_AXI_RUSER の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
S_AXI_RID <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
S_AXI_RID <= rad_fifo_dout(RAD_FIFO_ARID_HIGH downto RAD_FIFO_ARID_LOW);
end if;
end if;
end if;
end process;
S_AXI_RUSER <= (others => '0');
-- S_AXI_RRESP は、S_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
S_AXI_RRESP <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
if rad_fifo_dout(RAD_FIFO_ARBURST_HIGH downto RAD_FIFO_ARBURST_LOW)=AxBURST_INCR then
S_AXI_RRESP <= RESP_OKAY;
else
S_AXI_RRESP <= RESP_SLVERR;
end if;
end if;
end if;
end if;
end process;
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if cdc_we='1' then
for i in 0 to C_S_AXI_DATA_WIDTH/8-1 loop
if S_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(TO_INTEGER(unsigned(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))))(i*8+7 downto i*8) <= S_AXI_WDATA(i*8+7 downto i*8);
end if;
end loop;
end if;
end if;
end process;
-- Read Transaciton の時に +1 されたReadデータを使用する(Read 毎に+1)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
read_data_count <= (others => '0');
else
if rddat_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction が1つ終了
read_data_count <= std_logic_vector(unsigned(read_data_count) + 1);
end if;
end if;
end if;
end process;
S_AXI_RDATA <= ram_array(TO_INTEGER(unsigned(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))) when READ_DATA_IS_INCREMENT=0 else read_data_count;
end implementation;
/* AXI Master用 Slave Bus Function Mode (BFM)
axi_slave_BFM.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/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
//
// ライセンスは二条項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
)
(
// 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 [(SLAVE_ADDR_NUMBER - 1):0];
// 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_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_WIDTH-1:0] rad_fifo_din;
wire [RAD_FIFO_WIDTH-1:0] rad_fifo_dout;
// 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;
// {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};
sync_fifo #(
.C_MEMORY_SIZE (AD_FIFO_DEPTH),
.DATA_BUS_WIDTH (WAD_FIFO_WIDTH)
) wad_fifo (
.clk (ACLK),
.rst (reset),
.wr_en (awready),
.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;
// 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};
sync_fifo #(
.C_MEMORY_SIZE (AD_FIFO_DEPTH),
.DATA_BUS_WIDTH (RAD_FIFO_WIDTH)
) rad_fifo
(
.clk (ACLK),
.rst (reset),
.wr_en (arready),
.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
-----------------------------------------------------------------------------
--
-- AXI Master用 Slave Bus Function Mode (BFM)
-- axi_slave_BFM.vhd
--
-----------------------------------------------------------------------------
-- 2012/02/25 : S_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
-- 2012/07/04 : READ_ONLY_TRANSACTION を追加。Read機能のみでも+1したデータを出力することが出来るように変更した。
-- sync_fifo を使用したオーバーラップ対応版
-- 2014/07/04 : M_AXIをスレーブに対応した名前のS_AXIに変更
-- 2014/07/16 : Write Respose Channel に sync_fifo を使用した
-- 2014/08/31 : READ_RANDOM_WAIT=1 の時に、S_AXI_RREADY が S_AXI_RVALID に依存するバグをフィック。
-- WRITE_RANDOM_WAIT=1 の時に、S_AXI_WVALID が S_AXI_WREADY に依存するバグをフィック。
--
-- ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
package m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector;
end package m_seq_bfm_pack;
package body m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector is
variable mseq16 : std_logic_vector(15 downto 0);
variable xor_result : std_logic;
begin
xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
mseq16 := mseq16in(14 downto 0) & xor_result;
return mseq16;
end M_SEQ16_BFM_F;
end m_seq_bfm_pack;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
use IEEE.math_real.all;
library work;
use work.m_seq_bfm_pack.all;
--library unisim;
--use unisim.vcomponents.all;
entity axi_slave_bfm is
generic (
C_S_AXI_ID_WIDTH : integer := 1;
C_S_AXI_ADDR_WIDTH : integer := 32;
C_S_AXI_DATA_WIDTH : integer := 32;
C_S_AXI_AWUSER_WIDTH : integer := 1;
C_S_AXI_ARUSER_WIDTH : integer := 1;
C_S_AXI_WUSER_WIDTH : integer := 1;
C_S_AXI_RUSER_WIDTH : integer := 1;
C_S_AXI_BUSER_WIDTH : integer := 1;
C_S_AXI_TARGET : integer := 0;
C_OFFSET_WIDTH : integer := 10; -- 割り当てるRAMのアドレスのビット幅
C_S_AXI_BURST_LEN : integer := 256;
WRITE_RANDOM_WAIT : integer := 1; -- Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_RANDOM_WAIT : integer := 0; -- Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_DATA_IS_INCREMENT : integer := 0; -- ReadトランザクションでRAMの内容をReadする = 0(RAMにWriteしたものをReadする)、Readデータを+1する = 1(データは+1したデータをReadデータとして使用する
RANDOM_BVALID_WAIT : integer := 0 -- Write Data Transaction が終了した後で、BVALID をランダムにWaitする = 1、BVALID をランダムにWaitしない = 0, 31 ~ 0 クロックのWait
);
port(
-- System Signals
ACLK : in std_logic;
ARESETN : in std_logic;
-- Master Interface Write Address Ports
S_AXI_AWID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_AWADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_AWLEN : in std_logic_vector(8-1 downto 0);
S_AXI_AWSIZE : in std_logic_vector(3-1 downto 0);
S_AXI_AWBURST : in std_logic_vector(2-1 downto 0);
-- S_AXI_AWLOCK : in std_logic_vector(2-1 downto 0);
S_AXI_AWLOCK : in std_logic_vector(1 downto 0);
S_AXI_AWCACHE : in std_logic_vector(4-1 downto 0);
S_AXI_AWPROT : in std_logic_vector(3-1 downto 0);
S_AXI_AWQOS : in std_logic_vector(4-1 downto 0);
S_AXI_AWUSER : in std_logic_vector(C_S_AXI_AWUSER_WIDTH-1 downto 0);
S_AXI_AWVALID : in std_logic;
S_AXI_AWREADY : out std_logic;
-- Master Interface Write Data Ports
S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_WSTRB : in std_logic_vector(C_S_AXI_DATA_WIDTH/8-1 downto 0);
S_AXI_WLAST : in std_logic;
S_AXI_WUSER : in std_logic_vector(C_S_AXI_WUSER_WIDTH-1 downto 0);
S_AXI_WVALID : in std_logic;
S_AXI_WREADY : out std_logic;
-- Master Interface Write Response Ports
S_AXI_BID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_BRESP : out std_logic_vector(2-1 downto 0);
S_AXI_BUSER : out std_logic_vector(C_S_AXI_BUSER_WIDTH-1 downto 0);
S_AXI_BVALID : out std_logic;
S_AXI_BREADY : in std_logic;
-- Master Interface Read Address Ports
S_AXI_ARID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_ARADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_ARLEN : in std_logic_vector(8-1 downto 0);
S_AXI_ARSIZE : in std_logic_vector(3-1 downto 0);
S_AXI_ARBURST : in std_logic_vector(2-1 downto 0);
S_AXI_ARLOCK : in std_logic_vector(2-1 downto 0);
S_AXI_ARCACHE : in std_logic_vector(4-1 downto 0);
S_AXI_ARPROT : in std_logic_vector(3-1 downto 0);
S_AXI_ARQOS : in std_logic_vector(4-1 downto 0);
S_AXI_ARUSER : in std_logic_vector(C_S_AXI_ARUSER_WIDTH-1 downto 0);
S_AXI_ARVALID : in std_logic;
S_AXI_ARREADY : out std_logic;
-- Master Interface Read Data Ports
S_AXI_RID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_RRESP : out std_logic_vector(2-1 downto 0);
S_AXI_RLAST : out std_logic;
S_AXI_RUSER : out std_logic_vector(C_S_AXI_RUSER_WIDTH-1 downto 0);
S_AXI_RVALID : out std_logic;
S_AXI_RREADY : in std_logic
);
end axi_slave_bfm;
architecture implementation of axi_slave_bfm is
constant AxBURST_FIXED : std_logic_vector := "00";
constant AxBURST_INCR : std_logic_vector := "01";
constant AxBURST_WRAP : std_logic_vector := "10";
constant RESP_OKAY : std_logic_vector := "00";
constant RESP_EXOKAY : std_logic_vector := "01";
constant RESP_SLVERR : std_logic_vector := "10";
constant RESP_DECERR : std_logic_vector := "11";
constant DATA_BUS_BYTES : natural := C_S_AXI_DATA_WIDTH/8; -- データバスのビット幅
constant ADD_INC_OFFSET : natural := natural(log(real(DATA_BUS_BYTES), 2.0));
-- fifo depth for address
constant AD_FIFO_DEPTH : natural := 16;
-- wad_fifo field
constant WAD_FIFO_WIDTH : natural := C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1+1;
constant WAD_FIFO_AWID_HIGH : natural := C_S_AXI_ADDR_WIDTH+5+C_S_AXI_ID_WIDTH-1;
constant WAD_FIFO_AWID_LOW : natural := C_S_AXI_ADDR_WIDTH+5;
constant WAD_FIFO_AWBURST_HIGH : natural := C_S_AXI_ADDR_WIDTH+4;
constant WAD_FIFO_AWBURST_LOW : natural := C_S_AXI_ADDR_WIDTH+3;
constant WAD_FIFO_AWSIZE_HIGH : natural := C_S_AXI_ADDR_WIDTH+2;
constant WAD_FIFO_AWSIZE_LOW : natural := C_S_AXI_ADDR_WIDTH;
constant WAD_FIFO_ADDR_HIGH : natural := C_S_AXI_ADDR_WIDTH-1;
constant WAD_FIFO_ADDR_LOW : natural := 0;
-- wres_fifo field
constant WRES_FIFO_WIDTH : natural := 2+C_S_AXI_ID_WIDTH-1+1;
constant WRES_FIFO_AWID_HIGH : natural := 2+C_S_AXI_ID_WIDTH-1;
constant WRES_FIFO_AWID_LOW : natural := 2;
constant WRES_FIFO_AWBURST_HIGH : natural := 1;
constant WRES_FIFO_AWBURST_LOW : natural := 0;
-- rad_fifo field
constant RAD_FIFO_WIDTH : natural := C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1+1;
constant RAD_FIFO_ARID_HIGH : natural := C_S_AXI_ADDR_WIDTH+13+C_S_AXI_ID_WIDTH-1;
constant RAD_FIFO_ARID_LOW : natural := C_S_AXI_ADDR_WIDTH+13;
constant RAD_FIFO_ARBURST_HIGH : natural := C_S_AXI_ADDR_WIDTH+12;
constant RAD_FIFO_ARBURST_LOW : natural := C_S_AXI_ADDR_WIDTH+11;
constant RAD_FIFO_ARSIZE_HIGH : natural := C_S_AXI_ADDR_WIDTH+10;
constant RAD_FIFO_ARSIZE_LOW : natural := C_S_AXI_ADDR_WIDTH+8;
constant RAD_FIFO_ARLEN_HIGH : natural := C_S_AXI_ADDR_WIDTH+7;
constant RAD_FIFO_ARLEN_LOW : natural := C_S_AXI_ADDR_WIDTH;
constant RAD_FIFO_ADDR_HIGH : natural := C_S_AXI_ADDR_WIDTH-1;
constant RAD_FIFO_ADDR_LOW : natural := 0;
-- RAMの生成
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));
-- for write transaction
type write_address_state is (idle_wrad, awr_accept);
type write_data_state is (idle_wrdt, wr_burst);
type write_response_state is (idle_wres, wait_bvalid, bvalid_assert);
signal wradr_cs : write_address_state;
signal wrdat_cs : write_data_state;
signal wrres_cs : write_response_state;
signal addr_inc_step_wr : integer := 1;
signal awready : std_logic;
signal wr_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal wr_bvalid : std_logic;
signal m_seq16_wr : std_logic_vector(15 downto 0);
signal wready : std_logic;
type wready_state is (idle_wready, assert_wready, deassert_wready);
signal cs_wready : wready_state;
signal cdc_we : std_logic;
signal wad_fifo_full, wad_fifo_empty : std_logic;
signal wad_fifo_almost_full, wad_fifo_almost_empty : std_logic;
signal wad_fifo_rd_en : std_logic;
signal wad_fifo_din : std_logic_vector(WAD_FIFO_WIDTH-1 downto 0);
signal wad_fifo_dout : std_logic_vector(WAD_FIFO_WIDTH-1 downto 0);
signal m_seq16_wr_res : std_logic_vector(15 downto 0);
signal wr_resp_cnt : std_logic_vector(4 downto 0);
signal wres_fifo_wr_en : std_logic;
signal wres_fifo_full, wres_fifo_empty : std_logic;
signal wres_fifo_almost_full, wres_fifo_almost_empty : std_logic;
signal wres_fifo_rd_en : std_logic;
signal wres_fifo_din : std_logic_vector(WRES_FIFO_WIDTH-1 downto 0);
signal wres_fifo_dout : std_logic_vector(WRES_FIFO_WIDTH-1 downto 0);
-- for read transaction
type read_address_state is (idle_rda, arr_accept);
type read_data_state is (idle_rdd, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdadr_cs : read_address_state;
signal rddat_cs : read_data_state;
signal rdlast : read_last_state;
signal addr_inc_step_rd : integer := 1;
signal arready : std_logic;
signal rd_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal rd_axi_count : std_logic_vector(7 downto 0);
signal rvalid : std_logic;
signal rlast : std_logic;
signal m_seq16_rd : std_logic_vector(15 downto 0);
type rvalid_state is (idle_rvalid, assert_rvalid, deassert_rvalid);
signal cs_rvalid : rvalid_state;
signal read_data_count : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal reset_1d, reset_2d, reset : std_logic := '1';
signal rad_fifo_full, rad_fifo_empty : std_logic;
signal rad_fifo_almost_full, rad_fifo_almost_empty : std_logic;
signal rad_fifo_rd_en : std_logic;
signal rad_fifo_din : std_logic_vector(RAD_FIFO_WIDTH-1 downto 0);
signal rad_fifo_dout : std_logic_vector(RAD_FIFO_WIDTH-1 downto 0);
component sync_fifo generic (
constant C_MEMORY_SIZE : integer := 512; -- Word (not byte), 2のn乗
constant DATA_BUS_WIDTH : integer := 32 -- RAM Data Width
);
port (
clk : in std_logic;
rst : in std_logic;
wr_en : in std_logic;
din : in std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
full : out std_logic;
almost_full : out std_logic;
rd_en : in std_logic;
dout : out std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
empty : out std_logic;
almost_empty : out std_logic
);
end component;
begin
-- ARESETN をACLK で同期化
process (ACLK) begin
if ACLK'event and ACLK='1' then
reset_1d <= not ARESETN;
reset_2d <= reset_1d;
end if;
end process;
reset <= reset_2d;
-- AXI4バス Write Address State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wradr_cs <= idle_wrad;
awready <= '0';
else
case (wradr_cs) is
when idle_wrad =>
if S_AXI_AWVALID='1' and wad_fifo_full='0' and wres_fifo_full='0' then -- S_AXI_AWVALID が1にアサートされた
wradr_cs <= awr_accept;
awready <= '1';
end if;
when awr_accept => -- S_AXI_AWREADY をアサート
wradr_cs <= idle_wrad;
awready <= '0';
end case;
end if;
end if;
end process;
S_AXI_AWREADY <= awready;
-- S_AXI_AWID & S_AXI_AWBURST & S_AXI_AWSIZE & S_AXI_AWADDR を保存しておく同期FIFO
wad_fifo_din <= (S_AXI_AWID & S_AXI_AWBURST & S_AXI_AWSIZE & S_AXI_AWADDR);
wad_fifo : sync_fifo generic map(
C_MEMORY_SIZE => AD_FIFO_DEPTH,
DATA_BUS_WIDTH => WAD_FIFO_WIDTH
) port map (
clk => ACLK,
rst => reset,
wr_en => awready,
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
);
wad_fifo_rd_en <= '1' when wready='1' and S_AXI_WVALID='1' and S_AXI_WLAST='1' else '0';
-- AXI4バス Write Data State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrdat_cs <= idle_wrdt;
else
case( wrdat_cs ) is
when idle_wrdt =>
if wad_fifo_empty='0' then -- AXI Write アドレス転送の残りが1個以上ある
wrdat_cs <= wr_burst;
end if;
when wr_burst => -- Writeデータの転送
if S_AXI_WLAST='1' and S_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wrdat_cs <= idle_wrdt;
end if;
when others =>
end case ;
end if;
end if;
end process;
-- m_seq_wr、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr <= (0 => '1', others => '0');
else
if WRITE_RANDOM_WAIT=1 then -- Write Transaction 時にランダムなWaitを挿入する
if wrdat_cs=wr_burst then
m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
end if;
else -- Wait無し
m_seq16_wr <= (others => '0');
end if;
end if;
end if;
end process;
-- wready の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_wready <= idle_wready;
wready <= '0';
else
case (cs_wready) is
when idle_wready =>
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then -- 次はwr_burst
if m_seq16_wr(7)='0' and wres_fifo_full='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
else -- m_seq16_wr(7)='1' then -- wready='0'
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when assert_wready => -- 一度wreadyがアサートされたら、1つのトランザクションが終了するまでwready='1'
if wrdat_cs=wr_burst and S_AXI_WLAST='1' and S_AXI_WVALID='1' then -- 終了
cs_wready <= idle_wready;
wready <= '0';
elsif wrdat_cs=wr_burst and S_AXI_WVALID='1' then -- 1つのトランザクション終了。
if m_seq16_wr(7)='1' or wres_fifo_full='1' then
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when deassert_wready =>
if m_seq16_wr(7)='0' and wres_fifo_full='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
end if;
end case;
end if;
end if;
end process;
S_AXI_WREADY <= wready;
cdc_we <= '1' when wrdat_cs=wr_burst and wready='1' and S_AXI_WVALID='1' else '0';
-- addr_inc_step_wr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_wr <= 1;
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
case (wad_fifo_dout(WAD_FIFO_AWSIZE_HIGH downto WAD_FIFO_AWSIZE_LOW)) is
when "000" => -- 8ビット転送
addr_inc_step_wr <= 1;
when "001" => -- 16ビット転送
addr_inc_step_wr <= 2;
when "010" => -- 32ビット転送
addr_inc_step_wr <= 4;
when "011" => -- 64ビット転送
addr_inc_step_wr <= 8;
when "100" => -- 128ビット転送
addr_inc_step_wr <= 16;
when "101" => -- 256ビット転送
addr_inc_step_wr <= 32;
when "110" => -- 512ビット転送
addr_inc_step_wr <= 64;
when others => --"111" => -- 1024ビット転送
addr_inc_step_wr <= 128;
end case;
end if;
end if;
end if;
end process;
-- wr_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_addr <= (others => '0');
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
wr_addr <= wad_fifo_dout(C_OFFSET_WIDTH-1 downto 0);
elsif wrdat_cs=wr_burst and S_AXI_WVALID='1' and wready='1' then -- アドレスを進める
wr_addr <= std_logic_vector(unsigned(wr_addr) + addr_inc_step_wr);
end if;
end if;
end if;
end process;
-- Wirte Response FIFO (wres_fifo)
wres_fifo : sync_fifo generic map(
C_MEMORY_SIZE => AD_FIFO_DEPTH,
DATA_BUS_WIDTH => WRES_FIFO_WIDTH
) port map (
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
);
wres_fifo_wr_en <= '1' when S_AXI_WLAST='1' and S_AXI_WVALID='1' and wready='1' else '0'; -- Write Transaction 終了
wres_fifo_din <= (wad_fifo_dout(WAD_FIFO_AWID_HIGH downto WAD_FIFO_AWID_LOW) & wad_fifo_dout(WAD_FIFO_AWBURST_HIGH downto WAD_FIFO_AWBURST_LOW));
wres_fifo_rd_en <= '1' when wr_bvalid='1' and S_AXI_BREADY='1' and wres_fifo_empty='0' else '0';
-- S_AXI_BID の処理
S_AXI_BID <= wres_fifo_dout(WRES_FIFO_AWID_HIGH downto WRES_FIFO_AWID_LOW);
-- S_AXI_BRESP の処理
-- S_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
S_AXI_BRESP <= RESP_OKAY when wres_fifo_dout(WRES_FIFO_AWBURST_HIGH downto WRES_FIFO_AWBURST_LOW)=AxBURST_INCR else RESP_SLVERR;
-- wr_bvalid の処理
-- wr_bvalid のアサートは、Write Data Channelの完了より必ず1クロックは遅延する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrres_cs <= idle_wres;
wr_bvalid <= '0';
else
case( wrres_cs ) is
when idle_wres =>
if wres_fifo_empty='0' then -- Write Transaction 終了
if unsigned(m_seq16_wr_res) = 0 or RANDOM_BVALID_WAIT=0 then
wrres_cs <= bvalid_assert;
wr_bvalid <= '1';
else
wrres_cs <= wait_bvalid;
end if;
end if;
when wait_bvalid =>
if unsigned(wr_resp_cnt) = 0 then
wrres_cs <= bvalid_assert;
wr_bvalid <= '1';
end if;
when bvalid_assert =>
if (S_AXI_BREADY='1') then
wrres_cs <= idle_wres;
wr_bvalid <= '0';
end if;
when others =>
end case ;
end if;
end if;
end process;
S_AXI_BVALID <= wr_bvalid;
S_AXI_BUSER <= (others => '0');
-- wr_resp_cnt
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_resp_cnt <= (others => '0');
else
if wrres_cs=idle_wres and wres_fifo_empty='0' then
wr_resp_cnt <= m_seq16_wr_res(4 downto 0);
elsif unsigned(wr_resp_cnt) /= 0 then
wr_resp_cnt <= std_logic_vector(unsigned(wr_resp_cnt) - 1);
end if;
end if;
end if;
end process;
-- m_seq_wr_res、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr_res <= (0 => '1', others => '0');
else
m_seq16_wr_res <= M_SEQ16_BFM_F(m_seq16_wr_res);
end if;
end if;
end process;
-- AXI4バス Read Address Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdadr_cs <= idle_rda;
arready <= '0';
else
case (rdadr_cs) is
when idle_rda =>
if S_AXI_ARVALID='1' and rad_fifo_full='0' then -- Read Transaction 要求
rdadr_cs <= arr_accept;
arready <= '1';
end if;
when arr_accept => -- S_AXI_ARREADY をアサート
rdadr_cs <= idle_rda;
arready <= '0';
end case;
end if;
end if;
end process;
S_AXI_ARREADY <= arready;
-- S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR を保存しておく同期FIFO
rad_fifo_din <= (S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR);
rad_fifo : sync_fifo generic map (
C_MEMORY_SIZE => AD_FIFO_DEPTH,
DATA_BUS_WIDTH => RAD_FIFO_WIDTH
) port map (
clk => ACLK,
rst => reset,
wr_en => arready,
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
);
rad_fifo_rd_en <= '1' when rvalid='1' and S_AXI_RREADY='1' and rlast='1' else '0';
-- AXI4バス Read Data Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rddat_cs <= idle_rdd;
else
case (rddat_cs) is
when idle_rdd =>
if rad_fifo_empty='0' then -- AXI Read アドレス転送の残りが1個以上ある
rddat_cs <= rd_burst;
end if;
when rd_burst =>
if unsigned(rd_axi_count)=0 and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了
rddat_cs <= idle_rdd;
end if;
end case;
end if;
end if;
end process;
-- m_seq_rd、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_rd <= (others => '1'); -- Writeとシードを変更する
else
if READ_RANDOM_WAIT=1 then -- Read Transaciton のデータ転送でランダムなWaitを挿入する場合
if rddat_cs=rd_burst then
m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
end if;
else -- Wati無し
m_seq16_rd <= (others => '0');
end if;
end if;
end if;
end process;
-- rvalid の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_rvalid <= idle_rvalid;
rvalid <= '0';
else
case (cs_rvalid) is
when idle_rvalid =>
if rddat_cs=idle_rdd and rad_fifo_empty='0' then -- 次はrd_burst
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
else -- m_seq16_rd(7)='1' then -- rvalid='0'
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when assert_rvalid => -- 一度rvalidがアサートされたら、1つのトランザクションが終了するまでrvalid='1'
if rddat_cs=rd_burst and rlast='1' and S_AXI_RREADY='1' then -- 終了
cs_rvalid <= idle_rvalid;
rvalid <= '0';
elsif rddat_cs=rd_burst and S_AXI_RREADY='1' then -- 1つのトランザクション終了。
if m_seq16_rd(7)='1' then
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when deassert_rvalid =>
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
end if;
end case;
end if;
end if;
end process;
S_AXI_RVALID <= rvalid;
-- addr_inc_step_rd の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_rd <= 1;
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
case (rad_fifo_dout(RAD_FIFO_ARSIZE_HIGH downto RAD_FIFO_ARSIZE_LOW)) is
when "000" => -- 8ビット転送
addr_inc_step_rd <= 1;
when "001" => -- 16ビット転送
addr_inc_step_rd <= 2;
when "010" => -- 32ビット転送
addr_inc_step_rd <= 4;
when "011" => -- 64ビット転送
addr_inc_step_rd <= 8;
when "100" => -- 128ビット転送
addr_inc_step_rd <= 16;
when "101" => -- 256ビット転送
addr_inc_step_rd <= 32;
when "110" => -- 512ビット転送
addr_inc_step_rd <= 64;
when others => -- "111" => -- 1024ビット転送
addr_inc_step_rd <= 128;
end case;
end if;
end if;
end if;
end process;
-- rd_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_addr <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
rd_addr <= rad_fifo_dout(C_OFFSET_WIDTH-1 downto 0);
elsif rddat_cs=rd_burst and S_AXI_RREADY='1' and rvalid='1' then
rd_addr <= std_logic_vector(unsigned(rd_addr) + addr_inc_step_rd);
end if;
end if;
end if;
end process;
-- rd_axi_count の処理(AXIバス側のデータカウント)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_axi_count <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then -- rd_axi_count のロード
rd_axi_count <= rad_fifo_dout(RAD_FIFO_ARLEN_HIGH downto RAD_FIFO_ARLEN_LOW);
elsif rddat_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction が1つ終了
rd_axi_count <= std_logic_vector(unsigned(rd_axi_count) - 1);
end if;
end if;
end if;
end process;
-- rdlast State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdlast <= idle_rlast;
rlast <= '0';
else
case (rdlast) is
when idle_rlast =>
if unsigned(rd_axi_count)=1 and rvalid='1' and S_AXI_RREADY='1' then -- バーストする場合
rdlast <= rlast_assert;
rlast <= '1';
elsif rddat_cs=idle_rdd and rad_fifo_empty='0' and unsigned(rad_fifo_dout(RAD_FIFO_ARLEN_HIGH downto RAD_FIFO_ARLEN_LOW))=0 then -- 転送数が1の場合
rdlast <= rlast_assert;
rlast <= '1';
end if;
when rlast_assert =>
if rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了(rd_axi_count=0は決定)
rdlast <= idle_rlast;
rlast <= '0';
end if;
end case;
end if;
end if;
end process;
S_AXI_RLAST <= rlast;
-- S_AXI_RID, S_AXI_RUSER の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
S_AXI_RID <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
S_AXI_RID <= rad_fifo_dout(RAD_FIFO_ARID_HIGH downto RAD_FIFO_ARID_LOW);
end if;
end if;
end if;
end process;
S_AXI_RUSER <= (others => '0');
-- S_AXI_RRESP は、S_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
S_AXI_RRESP <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
if rad_fifo_dout(RAD_FIFO_ARBURST_HIGH downto RAD_FIFO_ARBURST_LOW)=AxBURST_INCR then
S_AXI_RRESP <= RESP_OKAY;
else
S_AXI_RRESP <= RESP_SLVERR;
end if;
end if;
end if;
end if;
end process;
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if cdc_we='1' then
for i in 0 to C_S_AXI_DATA_WIDTH/8-1 loop
if S_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(TO_INTEGER(unsigned(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))))(i*8+7 downto i*8) <= S_AXI_WDATA(i*8+7 downto i*8);
end if;
end loop;
end if;
end if;
end process;
-- Read Transaciton の時に +1 されたReadデータを使用する(Read 毎に+1)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
read_data_count <= (others => '0');
else
if rddat_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction が1つ終了
read_data_count <= std_logic_vector(unsigned(read_data_count) + 1);
end if;
end if;
end if;
end process;
S_AXI_RDATA <= ram_array(TO_INTEGER(unsigned(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))) when READ_DATA_IS_INCREMENT=0 else read_data_count;
end implementation;
./facedetect --cascade="/usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml" lena.jpg
wget http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.4.6.1/opencv-2.4.6.1.tar.gz
tar xvzf opencv-2.4.6.1.tar.gz
cd opencv-2.4.6.1
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig
sudo apt-get -y update
sudo apt-get -y upgrade
sudo reboot
sudo apt-get -y install build-essential
sudo apt-get -y install libboost1.46-all-dev
#
cd /tmp; sudo apt-get source opencv
sudo apt-get -y build-dep opencv
#
sudo apt-get -y install libqt4-dev
sudo apt-get -y install libgtk2.0-dev
sudo apt-get -y install pkg-config
#
sudo apt-get -y install opencl-headers
#
sudo apt-get -y install libjpeg-dev
sudo apt-get -y install libopenjpeg-dev
sudo apt-get -y install jasper
sudo apt-get -y install libjasper-dev libjasper-runtime
sudo apt-get -y install libpng12-dev
sudo apt-get -y install libpng++-dev libpng3
sudo apt-get -y install libpnglite-dev libpngwriter0-dev libpngwriter0c2
sudo apt-get -y install libtiff-dev libtiff-tools pngtools
sudo apt-get -y install zlib1g-dev zlib1g-dbg
sudo apt-get -y install v4l2ucp
#
sudo apt-get -y install python
sudo apt-get -y install autoconf
sudo apt-get -y install libtbb2 libtbb-dev
sudo apt-get -y install libeigen2-dev
sudo apt-get -y install cmake
sudo apt-get -y install openexr
sudo apt-get -y install gstreamer-plugins-*
sudo apt-get -y install freeglut3-dev
sudo apt-get -y install libglui-dev
sudo apt-get -y install libavc1394-dev libdc1394-22-dev libdc1394-utils
#
sudo apt-get -y install libxine-dev
sudo apt-get -y install libxvidcore-dev
sudo apt-get -y install libva-dev
sudo apt-get -y install libssl-dev
sudo apt-get -y install libv4l-dev
sudo apt-get -y install libvo-aacenc-dev
sudo apt-get -y install libvo-amrwbenc-dev
sudo apt-get -y install libvorbis-dev
sudo apt-get -y install libvpx-dev
wget http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.4.6.1/opencv-2.4.6.1.tar.gz
tar xvzf opencv-2.4.6.1.tar.gz
cd opencv-2.4.6.1
mkdir build
cd build
cmake ..
make
-----------------------------------------------------------------------------
--
-- AXI Master用 Slave Bus Function Mode (BFM) by marsee
-- axi_slave_BFM.vhd
-- by marsee
-----------------------------------------------------------------------------
-- 2012/02/25 : S_AXI_AWBURST=1 (INCR) にのみ対応、AWSIZE, ARSIZE = 000 (1byte), 001 (2bytes), 010 (4bytes) のみ対応。
-- 2012/07/04 : READ_ONLY_TRANSACTION を追加。Read機能のみでも+1したデータを出力することが出来るように変更した。
-- sync_fifo を使用したオーバーラップ対応版
-- 2014/07/04 : M_AXIをスレーブに対応した名前のS_AXIに変更
--
-- ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
package m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector;
end package m_seq_bfm_pack;
package body m_seq_bfm_pack is
function M_SEQ16_BFM_F(mseq16in : std_logic_vector
)return std_logic_vector is
variable mseq16 : std_logic_vector(15 downto 0);
variable xor_result : std_logic;
begin
xor_result := mseq16in(15) xor mseq16in(12) xor mseq16in(10) xor mseq16in(8) xor mseq16in(7) xor mseq16in(6) xor mseq16in(3) xor mseq16in(2);
mseq16 := mseq16in(14 downto 0) & xor_result;
return mseq16;
end M_SEQ16_BFM_F;
end m_seq_bfm_pack;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use IEEE.math_real.all;
library work;
use work.m_seq_bfm_pack.all;
--library unisim;
--use unisim.vcomponents.all;
entity axi_slave_bfm is
generic (
C_S_AXI_ID_WIDTH : integer := 1;
C_S_AXI_ADDR_WIDTH : integer := 32;
C_S_AXI_DATA_WIDTH : integer := 32;
C_S_AXI_AWUSER_WIDTH : integer := 1;
C_S_AXI_ARUSER_WIDTH : integer := 1;
C_S_AXI_WUSER_WIDTH : integer := 1;
C_S_AXI_RUSER_WIDTH : integer := 1;
C_S_AXI_BUSER_WIDTH : integer := 1;
C_S_AXI_TARGET : integer := 0;
C_OFFSET_WIDTH : integer := 10; -- 割り当てるRAMのアドレスのビット幅
C_S_AXI_BURST_LEN : integer := 256;
WRITE_RANDOM_WAIT : integer := 1; -- Write Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_RANDOM_WAIT : integer := 0; -- Read Transaction のデータ転送の時にランダムなWaitを発生させる=1, Waitしない=0
READ_DATA_IS_INCREMENT : integer := 0; -- ReadトランザクションでRAMの内容をReadする = 0(RAMにWriteしたものをReadする)、Readデータを+1する = 1(データは+1したデータをReadデータとして使用する
RUNDAM_BVALID_WAIT : integer := 0 -- Write Data Transaction が終了した後で、BVALID をランダムにWaitする = 1、BVALID をランダムにWaitしない = 0, 31 ~ 0 クロックのWait
);
port(
-- System Signals
ACLK : in std_logic;
ARESETN : in std_logic;
-- Master Interface Write Address Ports
S_AXI_AWID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_AWADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_AWLEN : in std_logic_vector(8-1 downto 0);
S_AXI_AWSIZE : in std_logic_vector(3-1 downto 0);
S_AXI_AWBURST : in std_logic_vector(2-1 downto 0);
-- S_AXI_AWLOCK : in std_logic_vector(2-1 downto 0);
S_AXI_AWLOCK : in std_logic_vector(1 downto 0);
S_AXI_AWCACHE : in std_logic_vector(4-1 downto 0);
S_AXI_AWPROT : in std_logic_vector(3-1 downto 0);
S_AXI_AWQOS : in std_logic_vector(4-1 downto 0);
S_AXI_AWUSER : in std_logic_vector(C_S_AXI_AWUSER_WIDTH-1 downto 0);
S_AXI_AWVALID : in std_logic;
S_AXI_AWREADY : out std_logic;
-- Master Interface Write Data Ports
S_AXI_WDATA : in std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_WSTRB : in std_logic_vector(C_S_AXI_DATA_WIDTH/8-1 downto 0);
S_AXI_WLAST : in std_logic;
S_AXI_WUSER : in std_logic_vector(C_S_AXI_WUSER_WIDTH-1 downto 0);
S_AXI_WVALID : in std_logic;
S_AXI_WREADY : out std_logic;
-- Master Interface Write Response Ports
S_AXI_BID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_BRESP : out std_logic_vector(2-1 downto 0);
S_AXI_BUSER : out std_logic_vector(C_S_AXI_BUSER_WIDTH-1 downto 0);
S_AXI_BVALID : out std_logic;
S_AXI_BREADY : in std_logic;
-- Master Interface Read Address Ports
S_AXI_ARID : in std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_ARADDR : in std_logic_vector(C_S_AXI_ADDR_WIDTH-1 downto 0);
S_AXI_ARLEN : in std_logic_vector(8-1 downto 0);
S_AXI_ARSIZE : in std_logic_vector(3-1 downto 0);
S_AXI_ARBURST : in std_logic_vector(2-1 downto 0);
S_AXI_ARLOCK : in std_logic_vector(2-1 downto 0);
S_AXI_ARCACHE : in std_logic_vector(4-1 downto 0);
S_AXI_ARPROT : in std_logic_vector(3-1 downto 0);
S_AXI_ARQOS : in std_logic_vector(4-1 downto 0);
S_AXI_ARUSER : in std_logic_vector(C_S_AXI_ARUSER_WIDTH-1 downto 0);
S_AXI_ARVALID : in std_logic;
S_AXI_ARREADY : out std_logic;
-- Master Interface Read Data Ports
S_AXI_RID : out std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
S_AXI_RDATA : out std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
S_AXI_RRESP : out std_logic_vector(2-1 downto 0);
S_AXI_RLAST : out std_logic;
S_AXI_RUSER : out std_logic_vector(C_S_AXI_RUSER_WIDTH-1 downto 0);
S_AXI_RVALID : out std_logic;
S_AXI_RREADY : in std_logic
);
end axi_slave_bfm;
architecture implementation of axi_slave_bfm is
constant AxBURST_FIXED : std_logic_vector := "00";
constant AxBURST_INCR : std_logic_vector := "01";
constant AxBURST_WRAP : std_logic_vector := "10";
constant RESP_OKAY : std_logic_vector := "00";
constant RESP_EXOKAY : std_logic_vector := "01";
constant RESP_SLVERR : std_logic_vector := "10";
constant RESP_DECERR : std_logic_vector := "11";
constant DATA_BUS_BYTES : natural := C_S_AXI_DATA_WIDTH/8; -- データバスのビット幅
constant ADD_INC_OFFSET : natural := natural(log(real(DATA_BUS_BYTES), 2.0));
-- wad_fifo field
constant WAD_FIFO_AWID_HIGH : natural := 37;
constant WAD_FIFO_AWID_LOW : natural := 37;
constant WAD_FIFO_AWBURST_HIGH : natural := 36;
constant WAD_FIFO_AWBURST_LOW : natural := 35;
constant WAD_FIFO_AWSIZE_HIGH : natural := 34;
constant WAD_FIFO_AWSIZE_LOW : natural := 32;
constant WAD_FIFO_ADDR_HIGH : natural := 31;
constant WAD_FIFO_ADDR_LOW : natural := 0;
-- rad_fifo field
constant RAD_FIFO_ARID_HIGH : natural := 45;
constant RAD_FIFO_ARID_LOW : natural := 45;
constant RAD_FIFO_ARBURST_HIGH : natural := 44;
constant RAD_FIFO_ARBURST_LOW : natural := 43;
constant RAD_FIFO_ARSIZE_HIGH : natural := 42;
constant RAD_FIFO_ARSIZE_LOW : natural := 40;
constant RAD_FIFO_ARLEN_HIGH : natural := 39;
constant RAD_FIFO_ARLEN_LOW : natural := 32;
constant RAD_FIFO_ADDR_HIGH : natural := 31;
constant RAD_FIFO_ADDR_LOW : natural := 0;
-- RAMの生成
constant SLAVE_ADDR_NUMBER : integer := 2**(C_OFFSET_WIDTH - ADD_INC_OFFSET);
type ram_array_def is array (SLAVE_ADDR_NUMBER-1 downto 0) of std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal ram_array : ram_array_def := (others => (others => '0'));
-- for write transaction
type write_address_state is (idle_wrad, awr_accept);
type write_data_state is (idle_wrdt, wr_burst);
type write_response_state is (idle_wres, wait_bvalid, bvalid_assert);
signal wradr_cs : write_address_state;
signal wrdat_cs : write_data_state;
signal wrres_cs : write_response_state;
signal addr_inc_step_wr : integer := 1;
signal awready : std_logic;
signal wr_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal wr_bid : std_logic_vector(C_S_AXI_ID_WIDTH-1 downto 0);
signal wr_bresp : std_logic_vector(1 downto 0);
signal wr_bvalid : std_logic;
signal m_seq16_wr : std_logic_vector(15 downto 0);
signal wready : std_logic;
type wready_state is (idle_wready, assert_wready, deassert_wready);
signal cs_wready : wready_state;
signal cdc_we : std_logic;
signal wad_fifo_full, wad_fifo_empty : std_logic;
signal wad_fifo_almost_full, wad_fifo_almost_empty : std_logic;
signal wad_fifo_rd_en : std_logic;
signal wad_fifo_din : std_logic_vector(37 downto 0);
signal wad_fifo_dout : std_logic_vector(37 downto 0);
signal m_seq16_wr_res : std_logic_vector(15 downto 0);
signal wr_resp_cnt : std_logic_vector(4 downto 0);
-- for read transaction
type read_address_state is (idle_rda, arr_accept);
type read_data_state is (idle_rdd, rd_burst);
type read_last_state is (idle_rlast, rlast_assert);
signal rdadr_cs : read_address_state;
signal rddat_cs : read_data_state;
signal rdlast : read_last_state;
signal addr_inc_step_rd : integer := 1;
signal arready : std_logic;
signal rd_addr : std_logic_vector(C_OFFSET_WIDTH-1 downto 0);
signal rd_axi_count : std_logic_vector(7 downto 0);
signal rvalid : std_logic;
signal rlast : std_logic;
signal m_seq16_rd : std_logic_vector(15 downto 0);
type rvalid_state is (idle_rvalid, assert_rvalid, deassert_rvalid);
signal cs_rvalid : rvalid_state;
signal read_data_count : std_logic_vector(C_S_AXI_DATA_WIDTH-1 downto 0);
signal reset_1d, reset_2d, reset : std_logic := '1';
signal rad_fifo_full, rad_fifo_empty : std_logic;
signal rad_fifo_almost_full, rad_fifo_almost_empty : std_logic;
signal rad_fifo_rd_en : std_logic;
signal rad_fifo_din : std_logic_vector(45 downto 0);
signal rad_fifo_dout : std_logic_vector(45 downto 0);
component sync_fifo generic (
constant C_MEMORY_SIZE : integer := 512; -- Word (not byte), 2のn乗
constant DATA_BUS_WIDTH : integer := 32 -- RAM Data Width
);
port (
clk : in std_logic;
rst : in std_logic;
wr_en : in std_logic;
din : in std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
full : out std_logic;
almost_full : out std_logic;
rd_en : in std_logic;
dout : out std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
empty : out std_logic;
almost_empty : out std_logic
);
end component;
begin
-- ARESETN をACLK で同期化
process (ACLK) begin
if ACLK'event and ACLK='1' then
reset_1d <= not ARESETN;
reset_2d <= reset_1d;
end if;
end process;
reset <= reset_2d;
-- AXI4バス Write Address State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wradr_cs <= idle_wrad;
awready <= '0';
else
case (wradr_cs) is
when idle_wrad =>
if S_AXI_AWVALID='1' and wad_fifo_full='0' then -- S_AXI_AWVALID が1にアサートされた
wradr_cs <= awr_accept;
awready <= '1';
end if;
when awr_accept => -- S_AXI_AWREADY をアサート
wradr_cs <= idle_wrad;
awready <= '0';
end case;
end if;
end if;
end process;
S_AXI_AWREADY <= awready;
-- S_AXI_AWID & S_AXI_AWBURST & S_AXI_AWSIZE & S_AXI_AWADDR を保存しておく同期FIFO
wad_fifo_din <= (S_AXI_AWID & S_AXI_AWBURST & S_AXI_AWSIZE & S_AXI_AWADDR);
wad_fifo : sync_fifo generic map(
C_MEMORY_SIZE => 16,
DATA_BUS_WIDTH => 38
) port map (
clk => ACLK,
rst => reset,
wr_en => awready,
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
);
wad_fifo_rd_en <= '1' when wready='1' and S_AXI_WVALID='1' and S_AXI_WLAST='1' else '0';
-- AXI4バス Write Data State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrdat_cs <= idle_wrdt;
else
case( wrdat_cs ) is
when idle_wrdt =>
if wad_fifo_empty='0' then -- AXI Write アドレス転送の残りが1個以上ある
wrdat_cs <= wr_burst;
end if;
when wr_burst => -- Writeデータの転送
if S_AXI_WLAST='1' and S_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wrdat_cs <= idle_wrdt;
end if;
when others =>
end case ;
end if;
end if;
end process;
-- m_seq_wr、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr <= (0 => '1', others => '0');
else
if WRITE_RANDOM_WAIT=1 then -- Write Transaction 時にランダムなWaitを挿入する
if wrdat_cs=wr_burst and S_AXI_WVALID='1' then
m_seq16_wr <= M_SEQ16_BFM_F(m_seq16_wr);
end if;
else -- Wait無し
m_seq16_wr <= (others => '0');
end if;
end if;
end if;
end process;
-- wready の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_wready <= idle_wready;
wready <= '0';
else
case (cs_wready) is
when idle_wready =>
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then -- 次はwr_burst
if m_seq16_wr(7)='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
else -- m_seq16_wr(7)='1' then -- wready='0'
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when assert_wready => -- 一度wreadyがアサートされたら、1つのトランザクションが終了するまでwready='1'
if wrdat_cs=wr_burst and S_AXI_WLAST='1' and S_AXI_WVALID='1' then -- 終了
cs_wready <= idle_wready;
wready <= '0';
elsif wrdat_cs=wr_burst and S_AXI_WVALID='1' then -- 1つのトランザクション終了。
if m_seq16_wr(7)='1' then
cs_wready <= deassert_wready;
wready <= '0';
end if;
end if;
when deassert_wready =>
if m_seq16_wr(7)='0' then -- wready='1'
cs_wready <= assert_wready;
wready <= '1';
end if;
end case;
end if;
end if;
end process;
S_AXI_WREADY <= wready;
cdc_we <= '1' when wrdat_cs=wr_burst and wready='1' and S_AXI_WVALID='1' else '0';
-- addr_inc_step_wr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_wr <= 1;
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
case (wad_fifo_dout(WAD_FIFO_AWSIZE_HIGH downto WAD_FIFO_AWSIZE_LOW)) is
when "000" => -- 8ビット転送
addr_inc_step_wr <= 1;
when "001" => -- 16ビット転送
addr_inc_step_wr <= 2;
when "010" => -- 32ビット転送
addr_inc_step_wr <= 4;
when "011" => -- 64ビット転送
addr_inc_step_wr <= 8;
when "100" => -- 128ビット転送
addr_inc_step_wr <= 16;
when "101" => -- 256ビット転送
addr_inc_step_wr <= 32;
when "110" => -- 512ビット転送
addr_inc_step_wr <= 64;
when others => --"111" => -- 1024ビット転送
addr_inc_step_wr <= 128;
end case;
end if;
end if;
end if;
end process;
-- wr_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_addr <= (others => '0');
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
wr_addr <= wad_fifo_dout(C_OFFSET_WIDTH-1 downto 0);
elsif wrdat_cs=wr_burst and S_AXI_WVALID='1' and wready='1' then -- アドレスを進める
wr_addr <= wr_addr + addr_inc_step_wr;
end if;
end if;
end if;
end process;
-- wr_bid の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bid <= "0";
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
wr_bid <= wad_fifo_dout(WAD_FIFO_AWID_HIGH downto WAD_FIFO_AWID_LOW);
end if;
end if;
end if;
end process;
S_AXI_BID <= wr_bid;
-- wr_bresp の処理
-- S_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_bresp <= (others => '0');
else
if wrdat_cs=idle_wrdt and wad_fifo_empty='0' then
if wad_fifo_dout(WAD_FIFO_AWBURST_HIGH downto WAD_FIFO_AWBURST_LOW)=AxBURST_INCR then -- バーストタイプがアドレス・インクリメントタイプ
wr_bresp <= RESP_OKAY; -- Write Transaction は成功
else
wr_bresp <= RESP_SLVERR; -- エラー
end if;
end if;
end if;
end if;
end process;
S_AXI_BRESP <= wr_bresp;
-- wr_bvalid の処理
-- Write Transaction State Machineには含まない。axi_master のシミュレーションを見ると1クロックで終了しているので、長い間、Master側の都合でWaitしていることは考えない。
-- 次のWrite転送まで遅延しているようであれば、Write Transaction State Machine に入れてブロックすることも考える必要がある。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wrres_cs <= idle_wres;
wr_bvalid <= '0';
else
case( wrres_cs ) is
when idle_wres =>
if S_AXI_WLAST='1' and S_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
if m_seq16_wr_res = 0 or RUNDAM_BVALID_WAIT=0 then
wrres_cs <= bvalid_assert;
wr_bvalid <= '1';
else
wrres_cs <= wait_bvalid;
end if;
end if;
when wait_bvalid =>
if wr_resp_cnt = 0 then
wrres_cs <= bvalid_assert;
wr_bvalid <= '1';
end if;
when bvalid_assert =>
wrres_cs <= idle_wres;
wr_bvalid <= '0';
when others =>
end case ;
end if;
end if;
end process;
S_AXI_BVALID <= wr_bvalid;
S_AXI_BUSER <= (others => '0');
-- wr_resp_cnt
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
wr_resp_cnt <= (others => '0');
else
if S_AXI_WLAST='1' and S_AXI_WVALID='1' and wready='1' then -- Write Transaction 終了
wr_resp_cnt <= m_seq16_wr_res(4 downto 0);
elsif wr_resp_cnt /= 0 then
wr_resp_cnt <= wr_resp_cnt - 1;
end if;
end if;
end if;
end process;
-- m_seq_wr_res、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_wr_res <= (0 => '1', others => '0');
else
m_seq16_wr_res <= M_SEQ16_BFM_F(m_seq16_wr_res);
end if;
end if;
end process;
-- AXI4バス Read Address Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdadr_cs <= idle_rda;
arready <= '0';
else
case (rdadr_cs) is
when idle_rda =>
if S_AXI_ARVALID='1' and rad_fifo_full='0' then -- Read Transaction 要求
rdadr_cs <= arr_accept;
arready <= '1';
end if;
when arr_accept => -- S_AXI_ARREADY をアサート
rdadr_cs <= idle_rda;
arready <= '0';
end case;
end if;
end if;
end process;
S_AXI_ARREADY <= arready;
-- S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR を保存しておく同期FIFO
rad_fifo_din <= (S_AXI_ARID & S_AXI_ARBURST & S_AXI_ARSIZE & S_AXI_ARLEN & S_AXI_ARADDR);
rad_fifo : sync_fifo generic map (
C_MEMORY_SIZE => 16,
DATA_BUS_WIDTH => 46
) port map (
clk => ACLK,
rst => reset,
wr_en => arready,
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
);
rad_fifo_rd_en <= '1' when rvalid='1' and S_AXI_RREADY='1' and rlast='1' else '0';
-- AXI4バス Read Data Transaction State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rddat_cs <= idle_rdd;
else
case (rddat_cs) is
when idle_rdd =>
if rad_fifo_empty='0' then -- AXI Read アドレス転送の残りが1個以上ある
rddat_cs <= rd_burst;
end if;
when rd_burst =>
if rd_axi_count=0 and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了
rddat_cs <= idle_rdd;
end if;
end case;
end if;
end if;
end process;
-- m_seq_rd、16ビットのM系列を計算する
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
m_seq16_rd <= (others => '1'); -- Writeとシードを変更する
else
if READ_RANDOM_WAIT=1 then -- Read Transaciton のデータ転送でランダムなWaitを挿入する場合
if rddat_cs=rd_burst and S_AXI_RREADY='1' then
m_seq16_rd <= M_SEQ16_BFM_F(m_seq16_rd);
end if;
else -- Wati無し
m_seq16_rd <= (others => '0');
end if;
end if;
end if;
end process;
-- rvalid の処理、M系列を計算して128以上だったらWaitする。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
cs_rvalid <= idle_rvalid;
rvalid <= '0';
else
case (cs_rvalid) is
when idle_rvalid =>
if rddat_cs=idle_rdd and rad_fifo_empty='0' then -- 次はrd_burst
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
else -- m_seq16_rd(7)='1' then -- rvalid='0'
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when assert_rvalid => -- 一度rvalidがアサートされたら、1つのトランザクションが終了するまでrvalid='1'
if rddat_cs=rd_burst and rlast='1' and S_AXI_RREADY='1' then -- 終了
cs_rvalid <= idle_rvalid;
rvalid <= '0';
elsif rddat_cs=rd_burst and S_AXI_RREADY='1' then -- 1つのトランザクション終了。
if m_seq16_rd(7)='1' then
cs_rvalid <= deassert_rvalid;
rvalid <= '0';
end if;
end if;
when deassert_rvalid =>
if m_seq16_rd(7)='0' then -- rvalid='1'
cs_rvalid <= assert_rvalid;
rvalid <= '1';
end if;
end case;
end if;
end if;
end process;
S_AXI_RVALID <= rvalid;
-- addr_inc_step_rd の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
addr_inc_step_rd <= 1;
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
case (rad_fifo_dout(RAD_FIFO_ARSIZE_HIGH downto RAD_FIFO_ARSIZE_LOW)) is
when "000" => -- 8ビット転送
addr_inc_step_rd <= 1;
when "001" => -- 16ビット転送
addr_inc_step_rd <= 2;
when "010" => -- 32ビット転送
addr_inc_step_rd <= 4;
when "011" => -- 64ビット転送
addr_inc_step_rd <= 8;
when "100" => -- 128ビット転送
addr_inc_step_rd <= 16;
when "101" => -- 256ビット転送
addr_inc_step_rd <= 32;
when "110" => -- 512ビット転送
addr_inc_step_rd <= 64;
when others => -- "111" => -- 1024ビット転送
addr_inc_step_rd <= 128;
end case;
end if;
end if;
end if;
end process;
-- rd_addr の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_addr <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
rd_addr <= rad_fifo_dout(C_OFFSET_WIDTH-1 downto 0);
elsif rddat_cs=rd_burst and S_AXI_RREADY='1' and rvalid='1' then
rd_addr <= rd_addr + addr_inc_step_rd;
end if;
end if;
end if;
end process;
-- rd_axi_count の処理(AXIバス側のデータカウント)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rd_axi_count <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then -- rd_axi_count のロード
rd_axi_count <= rad_fifo_dout(RAD_FIFO_ARLEN_HIGH downto RAD_FIFO_ARLEN_LOW);
elsif rddat_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction が1つ終了
rd_axi_count <= rd_axi_count - 1;
end if;
end if;
end if;
end process;
-- rdlast State Machine
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
rdlast <= idle_rlast;
rlast <= '0';
else
case (rdlast) is
when idle_rlast =>
if rd_axi_count=1 and rvalid='1' and S_AXI_RREADY='1' then -- バーストする場合
rdlast <= rlast_assert;
rlast <= '1';
elsif rddat_cs=idle_rdd and rad_fifo_empty='0' and rad_fifo_dout(RAD_FIFO_ARLEN_HIGH downto RAD_FIFO_ARLEN_LOW)=0 then -- 転送数が1の場合
rdlast <= rlast_assert;
rlast <= '1';
end if;
when rlast_assert =>
if rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction 終了(rd_axi_count=0は決定)
rdlast <= idle_rlast;
rlast <= '0';
end if;
end case;
end if;
end if;
end process;
S_AXI_RLAST <= rlast;
-- S_AXI_RID, S_AXI_RUSER の処理
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
S_AXI_RID <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
S_AXI_RID <= rad_fifo_dout(RAD_FIFO_ARID_HIGH downto RAD_FIFO_ARID_LOW);
end if;
end if;
end if;
end process;
S_AXI_RUSER <= (others => '0');
-- S_AXI_RRESP は、S_AXI_ARBURST がINCR の場合はOKAYを返す。それ以外はSLVERRを返す。
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
S_AXI_RRESP <= (others => '0');
else
if rddat_cs=idle_rdd and rad_fifo_empty='0' then
if rad_fifo_dout(RAD_FIFO_ARBURST_HIGH downto RAD_FIFO_ARBURST_LOW)=AxBURST_INCR then
S_AXI_RRESP <= RESP_OKAY;
else
S_AXI_RRESP <= RESP_SLVERR;
end if;
end if;
end if;
end if;
end process;
-- RAM
process (ACLK) begin
if ACLK'event and ACLK='1' then
if cdc_we='1' then
for i in 0 to C_S_AXI_DATA_WIDTH/8-1 loop
if S_AXI_WSTRB(i)='1' then -- Byte Enable
ram_array(CONV_INTEGER(wr_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET)))(i*8+7 downto i*8) <= S_AXI_WDATA(i*8+7 downto i*8);
end if;
end loop;
end if;
end if;
end process;
-- Read Transaciton の時に +1 されたReadデータを使用する(Read 毎に+1)
process (ACLK) begin
if ACLK'event and ACLK='1' then
if reset='1' then
read_data_count <= (others => '0');
else
if rddat_cs=rd_burst and rvalid='1' and S_AXI_RREADY='1' then -- Read Transaction が1つ終了
read_data_count <= read_data_count + 1;
end if;
end if;
end if;
end process;
S_AXI_RDATA <= ram_array(CONV_INTEGER(rd_addr(C_OFFSET_WIDTH-1 downto ADD_INC_OFFSET))) when READ_DATA_IS_INCREMENT=0 else read_data_count;
end implementation;
-- Synchronous FIFO for Simulation
--
-- 2014/07/03 by marsee
--
-- ライセンスは二条項BSDライセンス (2-clause BSD license)とします。
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_misc.all;
use IEEE.math_real.all;
entity sync_fifo is
generic (
C_MEMORY_SIZE : integer := 512; -- Word (not byte), 2のn乗
DATA_BUS_WIDTH : integer := 32 -- RAM Data Width
);
port (
clk : in std_logic;
rst : in std_logic;
wr_en : in std_logic;
din : in std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
full : out std_logic;
almost_full : out std_logic;
rd_en : in std_logic;
dout : out std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
empty : out std_logic;
almost_empty : out std_logic
);
end sync_fifo;
architecture RTL of sync_fifo is
constant C_MEMORY_LENGTH : natural := natural(ceil(log(real(C_MEMORY_SIZE), 2.0))); -- C_MEMORY_SIZEの2進数の桁数
type mem_type is array (0 to C_MEMORY_SIZE-1) of std_logic_vector(DATA_BUS_WIDTH-1 downto 0);
signal mem : mem_type := (OTHERS => (OTHERS => '0'));
signal mem_waddr : std_logic_vector(C_MEMORY_LENGTH-1 downto 0) := (others => '0');
signal mem_raddr : std_logic_vector(C_MEMORY_LENGTH-1 downto 0) := (others => '0');
signal rp : std_logic_vector(C_MEMORY_LENGTH-1 downto 0) := (others => '0');
signal wp : std_logic_vector(C_MEMORY_LENGTH-1 downto 0) := (others => '0');
signal almost_full_node : std_logic;
signal almost_empty_node : std_logic;
signal full_node : std_logic;
signal empty_node : std_logic;
begin
-- Write
process (clk) begin
if clk'event and clk='1' then
if rst='1' then
mem_waddr <= (others => '0');
wp <= (others => '0');
else
if wr_en='1' then
mem_waddr <= std_logic_vector(unsigned(mem_waddr) + 1);
wp <= std_logic_vector(unsigned(wp) + 1);
end if;
end if;
end if;
end process;
process (clk) begin
if clk'event and clk='1' then
if wr_en='1' then
mem(TO_INTEGER(unsigned(mem_waddr))) <= din;
end if;
end if;
end process;
full_node <= '1' when std_logic_vector(unsigned(wp)+1)=rp else '0';
full <= full_node;
almost_full_node <= '1' when std_logic_vector(unsigned(wp)+2)=rp else '0';
almost_full <= full_node or almost_full_node;
-- Read
process (clk) begin
if clk'event and clk='1' then
if rst='1' then
mem_raddr <= (others => '0');
rp <= (others => '0');
else
if rd_en='1' then
mem_raddr <= std_logic_vector(unsigned(mem_raddr) + 1);
rp <= std_logic_vector(unsigned(rp) + 1);
end if;
end if;
end if;
end process;
dout <= mem(TO_INTEGER(unsigned(mem_raddr)));
empty_node <= '1' when wp=rp else '0';
empty <= empty_node;
almost_empty_node <= '1' when wp=std_logic_vector(unsigned(rp)+1) else '0';
almost_empty <= empty_node or almost_empty_node;
end RTL;
/* AXI Master用 Slave Bus Function Mode (BFM)
axi_slave_BFM.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)
*/
// ライセンスは二条項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 RANDAM_BVALID_WAIT = 0 // Write Transaction後、BVALIDをランダムにWaitする=1、ランダムにWaitしない=0
)
(
// 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;
// wad_fifo field
localparam WAD_FIFO_AWID_HIGH = 37;
localparam WAD_FIFO_AWID_LOW = 37;
localparam WAD_FIFO_AWBURST_HIGH = 36;
localparam WAD_FIFO_AWBURST_LOW = 35;
localparam WAD_FIFO_AWSIZE_HIGH = 34;
localparam WAD_FIFO_AWSIZE_LOW = 32;
localparam WAD_FIFO_ADDR_HIGH = 31;
localparam WAD_FIFO_ADDR_LOW = 0;
// rad_fifo field
localparam RAD_FIFO_ARID_HIGH = 45;
localparam RAD_FIFO_ARID_LOW = 45;
localparam RAD_FIFO_ARBURST_HIGH = 44;
localparam RAD_FIFO_ARBURST_LOW = 43;
localparam RAD_FIFO_ARSIZE_HIGH = 42;
localparam RAD_FIFO_ARSIZE_LOW = 40;
localparam RAD_FIFO_ARLEN_HIGH = 39;
localparam RAD_FIFO_ARLEN_LOW = 32;
localparam RAD_FIFO_ADDR_HIGH = 31;
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 [(SLAVE_ADDR_NUMBER - 1):0];
// 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 [37:0] wad_fifo_din;
wire [37:0] wad_fifo_dout;
reg [15:0] m_seq16_wr_res;
reg [4:0] wr_resp_cnt;
// 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 [45:0] rad_fifo_din;
wire [45:0] rad_fifo_dout;
// 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)) // 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;
// {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};
sync_fifo #(
.C_MEMORY_SIZE (16),
.DATA_BUS_WIDTH (38)
) wad_fifo (
.clk (ACLK),
.rst (reset),
.wr_en (awready),
.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) && S_AXI_WVALID )
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 ) 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)) begin
cs_wready <= DEASSERT_WREADY;
wready <= 1'b0;
end
end
DEASSERT_WREADY:if ( m_seq16_wr[7] == 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
// wr_bid の処理
always @ ( posedge ACLK ) begin
if ( reset )
wr_bid <= 1'b0;
else begin
if ( (wrdat_cs == IDLE_WRDT) && (wad_fifo_empty == 1'b0) )
wr_bid <= wad_fifo_dout[WAD_FIFO_AWID_HIGH:WAD_FIFO_AWID_LOW];
end
end
assign S_AXI_BID = wr_bid;
// wr_bresp の処理
// S_AXI_AWBURSTがINCRの時はOKAYを返す。それ以外はSLVERRを返す
always @ ( posedge ACLK ) begin
if ( reset )
wr_bresp <= 'b0;
else begin
if ( (wrdat_cs == IDLE_WRDT) && (wad_fifo_empty == 1'b0) ) begin
if ( wad_fifo_dout[WAD_FIFO_AWBURST_HIGH:WAD_FIFO_AWBURST_LOW] == AXBURST_INCR ) // バーストタイプはインクリメント
wr_bresp <= RESP_OKAY; // Write Transaction は成功
else
wr_bresp <= RESP_SLVERR;// エラー
end
end
end
assign S_AXI_BRESP = wr_bresp;
// wr_bvalid の処理
// Write Transaction State Machineには含まない
// axi_master のシミュレーションを見ると1クロックで終了しているので
// 長い間、Master側の都合でWaitしていることは考えない。
// 次のWrite転送まで遅延しているようであれば、Write Transaction State Machine に入れて
// ブロックすることも考える必要がある。
always @ ( posedge ACLK ) begin
if ( reset ) begin
wrres_cs <= IDLE_WRES;
wr_bvalid <= 1'b0;
end
else
case (wrres_cs)
IDLE_WRES: if ( S_AXI_WLAST && S_AXI_WVALID && wready ) begin
if ( (m_seq16_wr_res == 0) || (RANDAM_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: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 ( S_AXI_WLAST && S_AXI_WVALID && wready ) // Write Transaction終了
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;
// 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};
sync_fifo #(
.C_MEMORY_SIZE (16),
.DATA_BUS_WIDTH (46)
) rad_fifo
(
.clk (ACLK),
.rst (reset),
.wr_en (arready),
.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) && S_AXI_RREADY )
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
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
- | - | 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 | - | - |