/********************************************** _ _ Cook Darwin __

_ descript: author : Cook.Darwin Version: VERA.0.0 creaded: 2016/12/27 madified: ***********************************************/ package AxiBfmPkg ;

typedef struct {

logic [32-1:0]   addr;
logic [32-1:0]   data;
string           name = "";

} AddrData;

typedef struct {

int   id;
int   addr;
int   len;

} IdAddrLen_S ;

task automatic sync_clk_wait(const ref bit clock,ref logic condition);

forever begin
    @(posedge clock);
    if(condition)
        break;
end

endtask:sync_clk_wait

class AxiLiteMasterBfm_c #(

parameter ASIZE  = 12,
parameter DSIZE  = 32,
parameter FreqM  = 1

);

AddrData addr_data [$];

virtual axi_lite_inf #(

.ASIZE      (ASIZE  ),
.DSIZE      (DSIZE  ),
.FreqM      (FreqM  )

)axil;

function new (virtual axi_lite_inf #(.ASIZE(ASIZE),.DSIZE(DSIZE),.FreqM(FreqM)) b);

axil = b;

endfunction:new

task master_reset;

begin
    #1 ;
    axil.axi_awvalid   =  0;
    axil.axi_awaddr    =  0;
    axil.axi_wvalid    =  0;
    axil.axi_wdata     =  0;
    axil.axi_bready    =  0;
    axil.axi_arvalid   =  0;
    axil.axi_araddr    =  0;
    axil.axi_rready    =  0;
end

endtask:master_reset

task automatic wr_data(ref AddrData addr_data [$],input logic relex_last=0); int length;

length = addr_data.size;
master_reset;
@(posedge axil.axi_aclk);
axil.axi_awlock = 1;
axil.axi_arlock = 0;
foreach(addr_data[i])begin
    $write("====>>> WRITING AXI LITE: N[%s]  A[%h] D[%d] ...... ",addr_data[i].name,addr_data[i].addr,addr_data[i].data);
    fork:ADDR_DATA_FORK
        fork:CMD_LOOP
            axil.axi_awvalid    = #1    1;
            axil.axi_awaddr     = #1    addr_data[i].addr;
            if(relex_last)begin
                if(i != length - 1)
                        axil.axi_awlock = 1'b1;
                else
                        axil.axi_awlock = 1'b0;
            end

            begin
                forever begin
                    @(posedge axil.axi_aclk);
                    if(axil.axi_awready)begin
                        axil.axi_awvalid    = #1    0;
                        break;
                    end
                end
                $write(" CMD DONE !");
            end
        join
        fork:DATA_LOOP
            axil.axi_wvalid     = #1    1;
            axil.axi_wdata      = #1    addr_data[i].data;
            begin
                forever begin
                    @(posedge axil.axi_aclk);
                    if(axil.axi_wready)begin
                        axil.axi_wvalid     = #1    0;
                        break;
                    end
                end
                $write(" DONE DONE !");
            end
        join
    join
    fork:RESP_LOOP
        axil.axi_bready = #1    1;
        begin
            forever begin
                @(posedge axil.axi_aclk);
                if(axil.axi_bvalid)
                    break;
            end
            $write(" RESP DONE !");
        end
    join
    $write(" DONE!!!\n");
end
axil.axi_awlock = 0;
master_reset;

endtask:wr_data

task automatic rd_data(ref AddrData addr_data [$]);

master_reset;
this.addr_data = {};
@(posedge axil.axi_aclk);
axil.axi_arlock = 1;
axil.axi_awlock = 0;
foreach(addr_data[i])fork
    this.addr_data[i].name = addr_data[i].name;
    $write("====>>> READING AXI LITE: N[%s] A[%h] ...... ",addr_data[i].name,addr_data[i].addr);
    fork:CMD_LOOP
        axil.axi_arvalid    = #1    1;
        axil.axi_araddr     = #1    addr_data[i].addr;
        this.addr_data[i].addr = addr_data[i].addr;
        begin
            forever begin
                @(posedge axil.axi_aclk);
                if(axil.axi_arready)begin
                    axil.axi_arvalid    = #1    0;
                    break;
                end
            end
            $write(" CMD DONE !");
        end
    join
    fork:DATA_LOOP
        axil.axi_rready     = #1    1;
        begin
            forever begin
                @(posedge axil.axi_aclk);
                if(axil.axi_rvalid)begin
                    // addr_data[i]    = #1 axil.axi_rdata;
                    axil.axi_rready        = #1    0;
                    this.addr_data[i].data =  axil.axi_rdata;
                    break;
                end
            end
            $write(" >>>D[%h]  DATA DONE !!!\n",axil.axi_rdata);
        end
    join
join
axil.axi_arlock = 0;
addr_data = this.addr_data;

endtask:rd_data

endclass:AxiLiteMasterBfm_c

class AxiLiteSlaverBfm_c #(

parameter ASIZE  = 12,
parameter DSIZE  = 32,
parameter FreqM  = 1

);

int mem [int];

virtual axi_lite_inf #(

.ASIZE      (ASIZE  ),
.DSIZE      (DSIZE  ),
.FreqM      (FreqM  )

)axil;

function new (virtual axi_lite_inf #(.ASIZE(ASIZE),.DSIZE(DSIZE),.FreqM(FreqM)) b);

axil = b;

endfunction:new

task slaver_wr_reset;

begin
    #1 ;
    axil.axi_awready   =  0;
    axil.axi_wready    =  0;
    axil.axi_bresp     =  0;
    axil.axi_bvalid    =  0;
end

endtask:slaver_wr_reset

task slaver_rd_reset;

begin
    #1 ;
    axil.axi_arready   =  0;
    axil.axi_rdata     =  0;
    axil.axi_rvalid    =  0;
end

endtask:slaver_rd_reset

task automatic wr_data(); AddrData addr_data;

slaver_wr_reset;
@(posedge axil.axi_aclk);
wait(axil.axi_awvalid);
begin
    // $write("====>>> WRITING AXI LITE: N[%s]  A[%h] D[%d] ...... ",addr_data[i].name,addr_data[i].addr,addr_data[i].data);
    fork:ADDR_DATA_FORK
        fork:CMD_LOOP
            axil.axi_awready    = #1    1;
            begin
                forever begin
                    @(posedge axil.axi_aclk);
                    if(axil.axi_awready && axil.axi_awvalid)begin
                        addr_data.addr     = axil.axi_awaddr;
                        axil.axi_awready   = #1    0;
                        break;
                    end
                end
            end
        join
        fork:DATA_LOOP
            axil.axi_wready     = #1    1;
            begin
                forever begin
                    @(posedge axil.axi_aclk);
                    if(axil.axi_wready && axil.axi_wvalid)begin
                        addr_data.data      = axil.axi_wdata;
                        axil.axi_wready     = #1    0;
                        break;
                    end
                end
            end
        join
    join
    fork:RESP_LOOP
        axil.axi_bvalid = #1    1;
        axil.axi_bresp  = 0;
        begin
            forever begin
                @(posedge axil.axi_aclk);
                if(axil.axi_bvalid && axil.axi_bready)begin
                    #1;
                    axil.axi_bvalid = 0;
                    break;
                end
            end
        end
    join
end
mem[addr_data.addr] = addr_data.data;
$write("\n====>>> WRITING AXI LITE: N[%s]  A[%h] D[%d]\n",addr_data.name,addr_data.addr,addr_data.data);
slaver_wr_reset;

endtask:wr_data

task automatic rd_data(); AddrData addr_data; int data_tmp;

slaver_rd_reset;
@(posedge axil.axi_aclk);
wait(axil.axi_arvalid);
begin
    fork:CMD_LOOP
        axil.axi_arready    = #1    1;
        begin
            forever begin
                @(posedge axil.axi_aclk);
                if(axil.axi_arready && axil.axi_arvalid)begin
                    addr_data.addr      = axil.axi_araddr;
                    data_tmp            = mem[addr_data.addr];
                    axil.axi_arready    = #1    0;
                    break;
                end
            end
            $write(" RD Lite CMD DONE !");
        end
    join
    fork:DATA_LOOP
        axil.axi_rvalid     =    1;
        // axil.axi_rdata      = addr_data.data;
        axil.axi_rdata      = data_tmp;
        begin
            forever begin
                @(posedge axil.axi_aclk);
                if(axil.axi_rvalid && axil.axi_rready)begin
                    axil.axi_rvalid        = #1    0;
                    break;
                end
            end
        end
    join
end
$write("\n====>>> READING AXI LITE: N[%s] A[%h]\n",addr_data.name,addr_data.addr);
slaver_rd_reset;

endtask:rd_data

endclass : AxiLiteSlaverBfm_c

class AxiStreamSlaverBfm_c #(

parameter   DSIZE = 8,
parameter   FreqM = 1

);

logic data_squeue [$];

virtual axi_stream_inf #(.DSIZE(DSIZE),.FreqM(FreqM)) axis_inf;

function new (virtual axi_stream_inf #(.DSIZE(DSIZE),.FreqM(FreqM)) b);

axis_inf = b;

endfunction:new

task automatic get_data(int rate = 100,bit info=1); int rm;

wait(axis_inf.aresetn);
data_squeue = {};
forever begin
    rm  = $urandom_range(0,99);
    if(rm < rate)
            axis_inf.axis_tready    = #(1ps) 1;
    else    axis_inf.axis_tready    = #(1ps) 0;

    @(posedge axis_inf.aclk)
    if(axis_inf.axis_tvalid && axis_inf.axis_tready)begin
        data_squeue.push_back(axis_inf.axis_tdata);
        if(axis_inf.axis_tlast)
            break;
    end
end
#(1ps)
axis_inf.axis_tready    = 0;
if(info)
    $display("AXI GET LENGTH [%d] DATA DONE!!!",data_squeue.size());

endtask:get_data

endclass:AxiStreamSlaverBfm_c

class AxiStreamMasterBfm_c #(

parameter DSIZE = 8,
parameter MSG   = "ON",
parameter FreqM = 1

);

virtual axi_stream_inf #(.DSIZE(DSIZE),.FreqM(FreqM)) axis_inf;

function new (virtual axi_stream_inf #(.DSIZE(DSIZE),.FreqM(FreqM)) b);

axis_inf = b;
axis_inf.axis_tvalid    = 0;
axis_inf.axis_tlast     = 0;
axis_inf.axis_tdata     = 0;
axis_inf.axis_tkeep     = 0;

endfunction:new

task automatic resize_queue(

int                 len,
ref logic [DSIZE-1:0]   in_queue [$],
ref logic [DSIZE-1:0]   out_queue[$]

); int real_len; int d_len; int r_len; out_queue = {}; if(len == 0)

out_queue = in_queue;

else if(len <= in_queue.size())

out_queue   = in_queue[0:(len-1)];

else begin

real_len    = in_queue.size();
d_len = len/real_len;
r_len = len%real_len;
for(int i=0;i<d_len;i++)
    out_queue = {out_queue,in_queue};
out_queue = {out_queue,in_queue[0:(r_len-1)]};

end // $display(“—%d–%d–%d”,len,in_queue.size(),out_queue.size()); endtask:resize_queue

task automatic gen_axi_stream (

int                    length,
int                    valid_ramdon_percent,
ref  [DSIZE-1:0] data_s [$]

); int rt; logic [DSIZE-1:0] data_ss;

resize_queue(length,data_s,data_ss);
// $display("ORIGIN LENGTH: %d,REAL LENGTH: %d",data_s.size(),data_ss.size());
@(posedge axis_inf.aclk);
#(1ps);
if(MSG=="ON")begin
    $display("_______________SEND___________________");
    $display("%t,GEN AXI STREAM LEN = %d",$time,data_ss.size());
end
while(1)begin
    rt = $urandom_range(99,0);
    axis_inf.axis_tvalid = (rt < valid_ramdon_percent);
    if(axis_inf.axis_tvalid)begin
        axis_inf.axis_tdata  = data_ss.size() != 0? data_ss.pop_front : axis_inf.axis_tdata;
        axis_inf.axis_tkeep  = '1;
        axis_inf.axis_tlast  = data_ss.size() == 0;

        sync_clk_wait(axis_inf.aclk,axis_inf.axis_tready);

        if(axis_inf.axis_tlast)begin
            // axis_inf.axis_tlast = 0;
            // @(posedge axis_inf.aclk);
            // #(1ps);
            break;
        end
        // @(posedge axis_inf.aclk);
        #(1ps);
    end else begin
        @(posedge axis_inf.aclk);
    end
end
#(1ps);
axis_inf.axis_tvalid    = 0;
axis_inf.axis_tlast     = 0;
axis_inf.axis_tkeep     = '0;
if(MSG=="ON")
    $display("===============SEND===================");

endtask:gen_axi_stream

endclass:AxiStreamMasterBfm_c

//——————————————————————— // AXI 4 Master BFM //__ class Axi4MasterBfm_c #(

parameter IDSIZE    = 1,
parameter ASIZE     = 32,
parameter LSIZE     = 1,
parameter DSIZE     = 32,
parameter MSG       = "ON",
parameter ADDR_STEP = 32'hFFFF_FFFF,
parameter FreqM     = 1

); mailbox wid_box; // typedef struct { // logic [IDSIZE-1:0] id; // logic [ASIZE-1:0] addr; // logic [LSIZE-1:0] len; // } IdAddrLen_S ;

IdAddrLen_S tra_ar_od [$];

virtual axi_inf #(

.IDSIZE    (IDSIZE  ),
.ASIZE     (ASIZE   ),
.LSIZE     (LSIZE   ),
.DSIZE     (DSIZE   ),
.ADDR_STEP (ADDR_STEP),
.FreqM     (FreqM   )

) inf;

function new (virtual axi_inf #(.IDSIZE(IDSIZE),.ASIZE(ASIZE),.LSIZE(LSIZE),.DSIZE(DSIZE),.ADDR_STEP(ADDR_STEP),.FreqM(FreqM)) b);

inf = b;
wid_box = new();

endfunction:new

task wr_reset_status;

inf.axi_awid     = 0;
inf.axi_awaddr   = 0;
inf.axi_awlen    = 0;
inf.axi_awsize   = 0;
inf.axi_awburst  = 0;
inf.axi_awlock   = 0;
inf.axi_awcache  = 0;
inf.axi_awprot   = 0;
inf.axi_awqos    = 0;
inf.axi_awvalid  = 0;

inf.axi_wdata    = 0;
inf.axi_wstrb    = 0;
inf.axi_wlast    = 0;
inf.axi_wvalid   = 0;

inf.axi_bready   = 0;

endtask:wr_reset_status task rd_reset_status;

inf.axi_arid     = 0;
inf.axi_araddr   = 0;
inf.axi_arlen    = 0;
inf.axi_arsize   = 0;
inf.axi_arburst  = 0;
inf.axi_arlock   = 0;
inf.axi_arcache  = 0;
inf.axi_arprot   = 0;
inf.axi_arqos    = 0;
inf.axi_arvalid  = 0;
inf.axi_rready   = 0;

endtask:rd_reset_status

task automatic init ();

fork
    wr_reset_status();
    rd_reset_status();
join

endtask:init

task automatic sync_wait(ref logic condition);

forever begin
    @(posedge inf.axi_aclk);
    if(condition)
        break;
end

endtask:sync_wait

task automatic aw_task(logic [ASIZE-1:0] addr,logic [LSIZE-1:0] len);

wr_reset_status();
if(MSG=="ON")
    $display("AXI4 Write ADDR[%h],LEN[%d]",addr,len);

@(posedge inf.axi_aclk);
inf.axi_awvalid = 1;
inf.axi_awlen   = len-1;
inf.axi_awaddr  = addr;
inf.axi_awid    = $urandom_range(10,0);
sync_wait(inf.axi_awready);
inf.axi_awvalid = 0;
// wid_box.put(inf.axi_awid);

endtask:aw_task

task automatic wdata_task(

int                    length,
int                    valid_ramdon_percent,
ref  [DSIZE-1:0] data_s [$]

);

if(MSG=="ON")
    ;
gen_axi_stream(length,valid_ramdon_percent,data_s);

endtask:wdata_task

task automatic wbrep_task();

inf.axi_bready  = 1;
sync_wait(inf.axi_bvalid);
inf.axi_bready  = 0;
if(MSG=="ON")
    $display("WRITE BURST COMPLETE!!!");

endtask:wbrep_task

task automatic ar_task(logic [ASIZE-1:0] addr,logic [LSIZE-1:0] len);

// @(posedge inf.axi_aclk);
inf.axi_arvalid = 1;
// @(posedge inf.axi_aclk);
// $stop;
inf.axi_arid    = $urandom_range(10,0);
inf.axi_arlen   = len-1;
inf.axi_araddr  = addr;
sync_wait(inf.axi_arready);
// forever begin 
//     @(negedge inf.axi_aclk);
//     if(inf.axi_arready)begin 
//         break;
//     end 
// end
// @(negedge inf.axi_aclk);
#(1ps);
inf.axi_arvalid = 0;
if(MSG=="ON")
    $display("%t,MASTER AXI4 READ ADDR[%h]",$time,addr);

endtask:ar_task

task automatic ar_od_task(int id,int addr,int len); IdAddrLen_S ial;

inf.axi_arvalid = 1;
inf.axi_arlen   = len-1;
inf.axi_araddr  = addr;
inf.axi_arid    = id;
sync_wait(inf.axi_arready);
ial.id  = inf.axi_arid;
ial.addr = inf.axi_araddr;
ial.len = inf.axi_arlen;
#(1ps);
inf.axi_arvalid = 0;
if(MSG=="ON")
    $display("%t,MASTER AXI4 READ ADDR[%h]",$time,addr);
tra_ar_od.push_back(ial);

endtask:ar_od_task

task automatic gen_axi_stream (

int                    length,
int                    valid_ramdon_percent,
ref  [DSIZE-1:0] data_s [$]

); int index; int cc = 0; int data_len; int rt; logic [DSIZE-1:0] data_ss; logic curr_data; int real_len;

data_len = data_s.size();
cc=0;

if(length==0)
        real_len    = data_len;
else    real_len    = length;

repeat(real_len)begin
    index = cc%data_len;
    data_ss[cc] = data_s[index];
    cc++;
end
// $display("ORIGIN LENGTH: %d,REAL LENGTH: %d",data_s.size(),data_ss.size());
if(MSG=="ON")begin
    $display("__________________________________");
    $display("GEN AXI4 write burst STREAM LEN = %d",data_ss.size());
end
while(1)begin
    rt = $urandom_range(99,0);

    if(rt < valid_ramdon_percent)begin
        inf.axi_wvalid  = 1;
        #(1ps);
        inf.axi_wdata  = data_ss.size() != 0? data_ss.pop_front : inf.axi_wdata;
        inf.axi_wlast  = data_ss.size() == 0;
        sync_wait(inf.axi_wready);
        // forever begin 
        //     @(negedge inf.axi_aclk);
        //     if(inf.axi_wready)begin 
        //         break;
        //     end
        // end
        if(inf.axi_wlast)
            break;
    end else begin
        inf.axi_wvalid  = 0;
        inf.axi_wlast   = 0;
        @(posedge inf.axi_aclk);
    end

end

#(1ps)
// @(negedge inf.axi_aclk);
inf.axi_wvalid    = 0;
inf.axi_wlast     = 0;
if(MSG=="ON")
    $display("==================================");

endtask:gen_axi_stream

task automatic get_axi_data(int rate = 100,ref logic [DSIZE-1:0] data [$]); int rm;

data = {};
forever begin
    rm  = $urandom_range(0,99);
    if(rm < rate)
            inf.axi_rready    = 1;
    else    inf.axi_rready    = 0;
    if(inf.axi_rready)begin
        sync_wait(inf.axi_rvalid);
        // forever begin 
        //     @(negedge inf.axi_aclk);
        //     if(inf.axi_rvalid)begin 
        //         // @(posedge inf.axi_aclk);
        //         break;
        //     end
        // end

        data.push_back(inf.axi_rdata);
        if(inf.axi_rlast)begin
            // @(posedge inf.axi_aclk);
                break;
        end
    end else begin
        @(posedge inf.axi_aclk);
    end
end
#(1ps);
inf.axi_rready    = 0;
if(MSG=="ON")
    $display("%t,MASTER AXI4 READ LENGTH [%d] DATA DONE!!!",$time,data.size());

endtask:get_axi_data

//public task automatic write_burst(

logic[ASIZE-1:0]       addr,
int                    length,
int                    valid_ramdon_percent,
ref  [DSIZE-1:0]       data_s [$]

); int len ;

if(length==0)
        len = data_s.size();
else    len = length;

aw_task(addr,len);
wdata_task(len,valid_ramdon_percent,data_s);
wbrep_task();

endtask:write_burst

task automatic read_burst(

logic[ASIZE-1:0]       addr,
int                    length,
int                    ready_ramdon_percent,
ref  [DSIZE-1:0]       data_s [$]

);

ar_task(addr,length);
get_axi_data(ready_ramdon_percent,data_s);

endtask:read_burst

logic [DSIZE-1:0] rd_queue [$];

task automatic out_of_order_read_burst(

ref IdAddrLen_S        ial [$],
int                    ready_ramdon_percent,
ref  [DSIZE-1:0]       data_s [$]

);

fork
    foreach(ial[i])
        ar_od_task(ial[i].id,ial[i].addr,ial[i].len);
    foreach(ial[i])
        get_axi_data(ready_ramdon_percent,data_s);
join
if(MSG=="ON")
    $display("%t,MASTER AXI4 OUT OF ORDER READ BURST DONE!!!",$time);

endtask:out_of_order_read_burst

endclass:Axi4MasterBfm_c //———————————————————————- // AXI 4 Slaver BFM //__ class Axi4SlaverBfm_c #(

parameter IDSIZE    = 1,
parameter ASIZE     = 32,
parameter LSIZE     = 1,
parameter DSIZE     = 32,
parameter MSG       = "ON",
parameter ADDR_STEP = 32'hFFFF_FFFF,
parameter FreqM     = 1

); mailbox wid_box; mailbox rid_box;

virtual axi_inf #(

.IDSIZE    (IDSIZE  ),
.ASIZE     (ASIZE   ),
.LSIZE     (LSIZE   ),
.DSIZE     (DSIZE   ),
.ADDR_STEP (ADDR_STEP),
.FreqM     (FreqM   )

) inf;

IdAddrLen_S rev_ar_OD [$];

function new (virtual axi_inf #(.IDSIZE(IDSIZE),.ASIZE(ASIZE),.LSIZE(LSIZE),.DSIZE(DSIZE),.ADDR_STEP(ADDR_STEP),.FreqM(FreqM)) b);

inf = b;
wid_box = new();
rid_box = new();

inf.axi_rvalid  = 0;
inf.axi_arready = 0;

endfunction:new

task automatic sync_wait(ref logic condition);

forever begin
    @(negedge inf.axi_aclk);
    if(condition)begin 
        @(posedge inf.axi_aclk);
        break;
    end
end

endtask:sync_wait

task automatic create_wr_transaction();

inf.axi_awready = 1;
inf.axi_wready  = 1;
inf.axi_bid     = 0;
inf.axi_bvalid  = 0;
inf.axi_bresp   = 0;

endtask:create_wr_transaction

task automatic create_rd_transaction();

inf.axi_arready = 1;
inf.axi_rvalid  = 0;
inf.axi_rid     = 0;
inf.axi_rdata   = 0;
inf.axi_rlast   = 0;
inf.axi_rresp   = 0;

endtask:create_rd_transaction

task automatic create_transaction();

create_wr_transaction();
create_rd_transaction();

endtask:create_transaction

task automatic aw_task(ref logic addr,ref logic len);

inf.axi_awready = 1;
sync_wait(inf.axi_awvalid);
if(MSG=="ON")begin
    $display("%t,SLAVER AXI4 WRITE BURST REQ ADDR[%h],LEN[%d]",$time,inf.axi_awaddr,inf.axi_awlen);
end
addr = inf.axi_awaddr;
len =  inf.axi_awlen;
wid_box.put(inf.axi_awid);

endtask:aw_task

task automatic ar_task(ref logic addr,ref logic len);

inf.axi_arready = 1;
sync_wait(inf.axi_arvalid);
inf.axi_arready = 0;
if(MSG=="ON")begin
    $display("%t,SLAVER AXI4 READ BURST REQ ADDR[%h],LEN[%d]",$time,inf.axi_araddr,inf.axi_arlen);
end
addr = inf.axi_araddr;
len =  inf.axi_arlen;
rid_box.put(inf.axi_arid);

endtask:ar_task

task automatic ar_od_task(); IdAddrLen_S ial;

inf.axi_arready = 1;
sync_wait(inf.axi_arvalid);
ial.id      = inf.axi_arid;
ial.addr    = inf.axi_araddr;
ial.len     = inf.axi_arlen;
rid_box.put(inf.axi_arid);
if(MSG=="ON")begin
    $display("%t,SLAVER AXI4 READ BURST REQ ID [%d] ADDR[%h],LEN[%d]",$time,ial.id,ial.addr,ial.len);
end
rev_ar_OD.push_back(ial);

endtask:ar_od_task

task automatic wdata_task(

int                   ready_ramdon_percent,
ref logic[DSIZE-1:0]  data [$]);

int rt;

data    = {};
forever begin
    rt = $urandom_range(99,0);
    if(rt < ready_ramdon_percent)begin
        inf.axi_wready  = 1;
        sync_wait(inf.axi_wvalid);
        data    = {data,inf.axi_wdata};
        if(inf.axi_wlast)
            break;
    end else begin
        inf.axi_wready  = 0;
        @(posedge inf.axi_aclk);
    end
end
if(MSG=="ON")
    $display("%t,AXI4 GET DATA LEN [%d]",$time,data.size());

endtask:wdata_task

task automatic rdata_task(

int                   len,
int                   valid_ramdon_percent,
ref logic[DSIZE-1:0]  data [$]

); int rt; logic data_queue;

resize_queue(len+1,data,data_queue);
// $display("AXI4 READ BURST SLAVER DONE !!! LEN [%d]",len);
rid_box.get(inf.axi_rid);
forever begin
    rt = $urandom_range(99,0);
    if(rt < valid_ramdon_percent)begin
        inf.axi_rvalid  = 1;
        inf.axi_rdata  = data_queue.size() != 0? data_queue.pop_front : inf.axi_rdata;
        inf.axi_rlast  = data_queue.size() == 0;
        sync_wait(inf.axi_rready);
        if(inf.axi_rlast)
            break;
    end else begin
        inf.axi_rvalid  = 0;
        inf.axi_rlast   = 0;
        @(posedge   inf.axi_aclk);
    end
end
inf.axi_rvalid  = 0;
inf.axi_rlast   = 0;
inf.axi_arready = 1;
if(MSG=="ON")
    $display("%t,AXI4 READ BURST SLAVER DONE !!! LEN [%0d]",$time,len);

endtask:rdata_task

task automatic rdata_od_task(

int                   id,
int                   len,
int                   valid_ramdon_percent,
ref logic[DSIZE-1:0]  data [$]

); int rt; logic data_queue;

resize_queue(len,data,data_queue);
// $display(">>>>>>AXI4 READ BURST SLAVER DONE !!! LEN [%d][%d]",len,data_queue.size());
rid_box.get(inf.axi_rid);
forever begin
    rt = $urandom_range(99,0);
    // inf.axi_rid     = id;
    if(rt < valid_ramdon_percent)begin
        inf.axi_rvalid  = 1;
        inf.axi_rdata  = data_queue.size() != 0? data_queue.pop_front : inf.axi_rdata;
        inf.axi_rlast  = data_queue.size() == 0;
        sync_wait(inf.axi_rready);
        if(inf.axi_rlast)begin
            @(posedge   inf.axi_aclk);
            break;
        end
    end else begin
        inf.axi_rvalid  = 0;
        inf.axi_rlast   = 0;
        @(posedge   inf.axi_aclk);
    end
end
inf.axi_rvalid  = 0;
inf.axi_rlast   = 0;
if(MSG=="ON")
    $display("%t,AXI4 READ BURST SLAVER DONE !!! LEN [%d]",$time,len);

endtask:rdata_od_task

task automatic wbresp_task();

inf.axi_bresp = '0;
inf.axi_bvalid = 1;
wid_box.get(inf.axi_bid);
sync_wait(inf.axi_bready);
inf.axi_bvalid = 0;
if(MSG=="ON")
    $display("%t,AXI4 WRITE BUSRT BRESP DONE !!!",$time);

endtask:wbresp_task

task automatic resize_queue(

int                 len,
ref logic [DSIZE-1:0]   in_queue [$],
ref logic [DSIZE-1:0]   out_queue[$]

); int real_len; int d_len; int r_len; out_queue = {}; if(len == 0)

out_queue = in_queue;

else if(len <= in_queue.size())

out_queue   = in_queue[0:(len-1)];

else begin

real_len    = in_queue.size();
d_len = len/real_len;
r_len = len%real_len;
for(int i=0;i<d_len;i++)
    out_queue = {out_queue,in_queue};
out_queue = {out_queue,in_queue[0:(r_len-1)]};

end // $display(“—%d–%d–%d”,len,in_queue.size(),out_queue.size()); endtask:resize_queue

task automatic burst_write(

ref logic[ASIZE-1:0]   addr,
ref logic[LSIZE-1:0]   length,
input int              ready_ramdon_percent,
ref  [DSIZE-1:0]       data_s [$]

);

aw_task(addr,length);
wdata_task(ready_ramdon_percent,data_s);
wbresp_task();

endtask:burst_write

task automatic burst_read(

ref logic[ASIZE-1:0]   addr,
ref logic[LSIZE-1:0]   length,
int                    valid_ramdon_percent,
ref  [DSIZE-1:0]       data_s [$]

);

ar_task(addr,length);
rdata_task(int'(length),valid_ramdon_percent,data_s);

endtask:burst_read

logic [ASIZE-1:0] wr_addr,rd_addr; logic [LSIZE-1:0] wr_len,rd_len; logic [DSIZE-1:0] wr_queue [$]; logic [DSIZE-1:0] rd_queue [$];

task automatic run (int valid_ramdon_percent,int ready_ramdon_percent);

create_transaction();
fork
    forever begin
        burst_write(wr_addr,wr_len,ready_ramdon_percent,wr_queue);
    end
    forever begin
        burst_read(rd_addr,rd_len,valid_ramdon_percent,rd_queue);
    end
join_none

endtask:run

task automatic out_fo_order_burst_read(

int                    valid_ramdon_percent

); IdAddrLen_S idl; logic [DSIZE-1:0] rd_queue [$]; rd_queue = {0,1,2,3,4,5,6,7,8,9}; fork

forever begin
    ar_od_task();
end
forever begin
    forever begin
        @(posedge inf.axi_aclk);
        if(rev_ar_OD.size()>0)
            break;
    end
    idl = rev_ar_OD.pop_front();
    rdata_od_task(idl.id,int'(idl.len+1),valid_ramdon_percent,rd_queue);
end

join_none endtask:out_fo_order_burst_read

endclass:Axi4SlaverBfm_c

endpackage:AxiBfmPkg

// package AXI_BFM_PKG; // import AxiBfmPkg::*; // export AxiBfmPkg::*; // endpackage