blob: 9e9a2e61d0f9f08f1604cb1a283b6d4c8abbcf9e [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
// ---------------------------------------------
// TileLink agent sequence library
// ---------------------------------------------
// Host sequence, support multiple outstanding request
// generates 'req_cnt' number of completely random requests
class tl_host_seq extends uvm_sequence#(.REQ(tl_seq_item));
`uvm_declare_p_sequencer(tl_sequencer)
rand int unsigned req_cnt;
tl_seq_item pending_req[$];
int min_req_delay = 0;
int max_req_delay = 10;
`uvm_object_utils(tl_host_seq)
`uvm_object_new
virtual task body();
fork
begin : wait_response_thread
for (int i = 0; i < req_cnt; i++) begin
get_response(rsp);
`uvm_info(`gfn, $sformatf("Received rsp[%0d] : %0s",
i, req.convert2string()), UVM_HIGH)
process_response(pending_req.pop_front(), rsp);
end
end
begin : request_thread
`uvm_info(`gfn, $sformatf("Start sending %0d host requests", req_cnt), UVM_HIGH)
for (int i = 0; i < req_cnt; i++) begin
req = tl_seq_item::type_id::create("req");
start_item(req);
randomize_req(req, i);
finish_item(req);
`uvm_info(`gfn, $sformatf("Sent req[%0d] : %0s",
i, req.convert2string()), UVM_HIGH)
pending_req.push_back(req);
end
end
join
`uvm_info(`gfn, $sformatf("Finished sending %0d host requests", req_cnt), UVM_HIGH)
endtask
// Request randomization, override this functiont to do custom request generation
virtual function void randomize_req(tl_seq_item req, int idx);
if (!(req.randomize() with {
a_valid_delay inside {[min_req_delay:max_req_delay]};})) begin
`uvm_fatal(`gfn, "Cannot randomize req")
end
endfunction
// A reserved function that can be extended to process response packet
virtual function void process_response(tl_seq_item req, tl_seq_item rsp);
endfunction
endclass : tl_host_seq
// extend host seq to send single specific item constructed by the caller
class tl_host_single_seq extends tl_host_seq;
rand bit [top_pkg::TL_AW-1:0] addr;
rand tlul_pkg::tl_a_op_e opcode;
rand bit [top_pkg::TL_SZW-1:0] size;
rand bit [top_pkg::TL_AIW-1:0] source;
rand bit [top_pkg::TL_DBW-1:0] mask;
rand bit [top_pkg::TL_DW-1:0] data;
`uvm_object_utils(tl_host_single_seq)
`uvm_object_new
constraint req_cnt_eq_1_c { req_cnt == 1; }
virtual function void randomize_req(tl_seq_item req, int idx);
if (!(req.randomize() with {
a_valid_delay inside {[min_req_delay:max_req_delay]};
a_addr == addr;
a_opcode == opcode;
a_size == size;
a_source == source;
a_mask == mask;
a_data == data;})) begin
`uvm_fatal(`gfn, "Cannot randomize req")
end
endfunction
endclass
// Device sequence, currently support in-order response
class tl_device_seq extends uvm_sequence#(.REQ(tl_seq_item));
int unsigned rsp_cnt;
int min_rsp_delay = 0;
int max_rsp_delay = 10;
mem_model_pkg::mem_model mem;
`uvm_object_utils(tl_device_seq)
`uvm_declare_p_sequencer(tl_sequencer)
function new (string name = "");
super.new(name);
endfunction : new
virtual task body();
tl_seq_item req;
tl_seq_item rsp;
forever begin
p_sequencer.a_chan_req_fifo.get(req);
rsp = randomize_rsp(req);
`uvm_info(`gfn, $sformatf("Sent rsp[%0d] : %0s, req: %0s",
rsp_cnt, rsp.convert2string(), req.convert2string()), UVM_HIGH)
start_item(rsp);
finish_item(rsp);
`uvm_info(`gfn, $sformatf("Sent rsp[%0d] : %0s",
rsp_cnt, rsp.convert2string()), UVM_HIGH)
rsp_cnt++;
end
endtask
virtual function tl_seq_item randomize_rsp(tl_seq_item req);
tl_seq_item rsp;
$cast(rsp, req.clone());
rsp.disable_a_chan_randomization();
if (!(rsp.randomize() with
{rsp.d_valid_delay inside {[min_rsp_delay : max_rsp_delay]};
if (rsp.a_opcode inside {PutFullData, PutPartialData}) {
rsp.d_opcode == tlul_pkg::AccessAck;
} else {
rsp.d_opcode == tlul_pkg::AccessAckData;
}
rsp.d_size == rsp.a_size;
rsp.d_user == '0; // TODO: Not defined yet, tie it to zero
rsp.d_source == rsp.a_source;})) begin
`uvm_fatal(`gfn, "Cannot randomize rsp")
end
if (mem != null) begin
if (req.a_opcode inside {PutFullData, PutPartialData}) begin
bit [tl_agent_pkg::DataWidth-1:0] data;
data = req.a_data;
for (int i = 0; i < $bits(req.a_mask); i++) begin
if (req.a_mask[i]) begin
mem.write_byte(req.a_addr + i, data[7:0]);
end
data = data >> 8;
end
end else begin
for (int i = 2**req.a_size - 1; i >= 0; i--) begin
rsp.d_data = rsp.d_data << 8;
rsp.d_data[7:0] = mem.read_byte(req.a_addr+i);
end
end
end
return rsp;
endfunction
endclass : tl_device_seq