Miscellaneous updates
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
// AXI Manager Driver
|
// AXI Manager Driver
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
class axi_manager_driver extends axi_driver;
|
class axi_manager_driver extends axi_driver;
|
||||||
|
axi_transaction txn_trk[axi_transaction_id_t];
|
||||||
|
|
||||||
|
semaphore write_request_sem;
|
||||||
|
semaphore read_request_sem;
|
||||||
|
|
||||||
`uvm_component_utils(axi_manager_driver)
|
`uvm_component_utils(axi_manager_driver)
|
||||||
|
|
||||||
@@ -9,6 +13,9 @@ class axi_manager_driver extends axi_driver;
|
|||||||
// Constructor
|
// Constructor
|
||||||
function new(string name = "axi_manager_driver", uvm_component parent = null);
|
function new(string name = "axi_manager_driver", uvm_component parent = null);
|
||||||
super.new(name, parent);
|
super.new(name, parent);
|
||||||
|
|
||||||
|
write_request_sem = new(1);
|
||||||
|
read_request_sem = new(1);
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
@@ -45,7 +52,14 @@ class axi_manager_driver extends axi_driver;
|
|||||||
if (!$cast(req, txn)) begin
|
if (!$cast(req, txn)) begin
|
||||||
`uvm_fatal("drive_txn", "Invalid transaction type")
|
`uvm_fatal("drive_txn", "Invalid transaction type")
|
||||||
end
|
end
|
||||||
|
while (txn_trk.size() > (3-1)) begin
|
||||||
|
`uvm_info("run_phase", $sformatf("Waiting for next transaction Txn-trk size=%0d to be under 3", txn_trk.size()), UVM_LOW)
|
||||||
|
@(txn_trk.size());
|
||||||
|
`uvm_info("run_phase", $sformatf("Txn-trk size changed to %0d to be under 3", txn_trk.size()), UVM_LOW)
|
||||||
|
end
|
||||||
|
fork
|
||||||
drive_txn(req);
|
drive_txn(req);
|
||||||
|
join_none
|
||||||
seq_item_port.item_done();
|
seq_item_port.item_done();
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -54,7 +68,12 @@ class axi_manager_driver extends axi_driver;
|
|||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
task drive_txn(axi_transaction req);
|
task drive_txn(axi_transaction req);
|
||||||
int dly = cfg.get_pre_transaction_delay();
|
int dly = cfg.get_pre_transaction_delay();
|
||||||
`uvm_info("drive_txn", $sformatf("Driving AXI transaction:\n%s", req.sprint()), UVM_LOW)
|
axi_transaction_id_t tid = req.get_tid();
|
||||||
|
|
||||||
|
`uvm_info("drive_txn", $sformatf("Driving AXI transaction ID=%s:\n%s",
|
||||||
|
req.show_tid(), req.sprint()), UVM_LOW)
|
||||||
|
|
||||||
|
txn_trk[tid] = req;
|
||||||
|
|
||||||
// Pre transaction delay
|
// Pre transaction delay
|
||||||
`uvm_info("drive_txn", $sformatf("Waiting pre_transaction_delay = %0d cycles",
|
`uvm_info("drive_txn", $sformatf("Waiting pre_transaction_delay = %0d cycles",
|
||||||
@@ -69,39 +88,120 @@ class axi_manager_driver extends axi_driver;
|
|||||||
`uvm_error("drive_txn", $sformatf("Unknown transaction type: %s", req.txn_type.name()))
|
`uvm_error("drive_txn", $sformatf("Unknown transaction type: %s", req.txn_type.name()))
|
||||||
end
|
end
|
||||||
`uvm_info("drive_txn", $sformatf("Driving AXI transaction done."), UVM_LOW)
|
`uvm_info("drive_txn", $sformatf("Driving AXI transaction done."), UVM_LOW)
|
||||||
|
|
||||||
|
finish_tr(req);
|
||||||
|
|
||||||
|
txn_trk.delete(tid);
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// Drive a write transaction
|
// Drive a write transaction
|
||||||
task drive_write_txn(axi_transaction req);
|
task drive_write_txn(axi_transaction req);
|
||||||
|
bit done = 0;
|
||||||
|
bit a_done = 0;
|
||||||
|
bit w_done = 0;
|
||||||
|
bit b_done = 0;
|
||||||
|
|
||||||
|
`uvm_info("drive_write_txn", $sformatf("[%s] Waiting for semaphore to drive",
|
||||||
|
req.show_tag()), UVM_LOW)
|
||||||
|
write_request_sem.get();
|
||||||
|
|
||||||
|
// Drive address channel information
|
||||||
|
// TODO: Sometimes drive after delay
|
||||||
|
// TODO: Sometimes drive after waiting for AWREADY
|
||||||
@(posedge m_if.ACLK);
|
@(posedge m_if.ACLK);
|
||||||
m_if.AWVALID = 1;
|
m_if.AWVALID = 1;
|
||||||
m_if.AWADDR = req.addr;
|
m_if.AWADDR = req.addr;
|
||||||
@(posedge m_if.ACLK);
|
m_if.AWID = 0;
|
||||||
|
|
||||||
|
// Drive data channel information
|
||||||
|
// TODO: Sometimes drive after delay
|
||||||
|
// TODO: Sometimes drive after waiting for WREADY
|
||||||
|
m_if.WVALID = 1;
|
||||||
m_if.WDATA = req.data;
|
m_if.WDATA = req.data;
|
||||||
m_if.WSTRB = req.strb;
|
m_if.WSTRB = req.strb;
|
||||||
|
|
||||||
while (m_if.AWREADY != 1) begin
|
// Wait for write response
|
||||||
@(posedge m_if.ACLK);
|
@(posedge m_if.ACLK);
|
||||||
end
|
m_if.BREADY = 1;
|
||||||
`uvm_info("drive_write_txn", $sformatf("Address phase accepted (AWREADY=1)"), UVM_LOW)
|
while (!done) begin
|
||||||
|
@(posedge m_if.ACLK);
|
||||||
|
|
||||||
|
if (m_if.AWREADY == 1) begin
|
||||||
|
a_done = 1;
|
||||||
m_if.AWVALID = 0;
|
m_if.AWVALID = 0;
|
||||||
`uvm_info("drive_write_txn", $sformatf("Done."), UVM_LOW)
|
end
|
||||||
|
if (m_if.WREADY == 1) begin
|
||||||
|
w_done = 1;
|
||||||
|
m_if.WVALID = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (m_if.BVALID == 1) begin
|
||||||
|
b_done = 1;
|
||||||
|
m_if.BREADY = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Write is done when Address, Data and Response phases are done
|
||||||
|
done = (a_done && w_done && b_done);
|
||||||
|
`uvm_info("drive_write_txn", $sformatf("[%s] Waiting for transaction to be done (%b - a%b w%b b%b)",
|
||||||
|
req.show_tag(), done, a_done, w_done, b_done), UVM_LOW)
|
||||||
|
end
|
||||||
|
|
||||||
|
write_request_sem.put();
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
// Drive a read transaction
|
// Drive a read transaction
|
||||||
task drive_read_txn(axi_transaction req);
|
task drive_read_txn(axi_transaction req);
|
||||||
|
bit done = 0;
|
||||||
|
bit a_done = 0;
|
||||||
|
bit r_done = 0;
|
||||||
|
|
||||||
|
`uvm_info("drive_read_txn", $sformatf("[%s] Waiting for semaphore to drive",
|
||||||
|
req.show_tag()), UVM_LOW)
|
||||||
|
read_request_sem.get();
|
||||||
|
|
||||||
|
// Drive address channel information
|
||||||
|
// TODO: Sometimes drive after delay
|
||||||
|
// TODO: Sometimes drive after waiting for AWREADY
|
||||||
@(posedge m_if.ACLK);
|
@(posedge m_if.ACLK);
|
||||||
m_if.ARVALID = 1;
|
m_if.ARVALID = 1;
|
||||||
m_if.ARADDR = req.addr;
|
m_if.ARADDR = req.addr;
|
||||||
|
m_if.ARID = 0;
|
||||||
|
|
||||||
|
// Wait for write response
|
||||||
|
@(posedge m_if.ACLK);
|
||||||
|
m_if.RREADY = 1;
|
||||||
|
while (!done) begin
|
||||||
@(posedge m_if.ACLK);
|
@(posedge m_if.ACLK);
|
||||||
|
|
||||||
while (m_if.ARREADY != 1) begin
|
if (m_if.ARREADY == 1) begin
|
||||||
@(posedge m_if.ACLK);
|
a_done = 1;
|
||||||
end
|
|
||||||
`uvm_info("drive_read_txn", $sformatf("Address phase accepted (ARREADY=1)"), UVM_LOW)
|
|
||||||
m_if.ARVALID = 0;
|
m_if.ARVALID = 0;
|
||||||
`uvm_info("drive_read_txn", $sformatf("Done."), UVM_LOW)
|
end
|
||||||
|
|
||||||
|
if (m_if.RVALID == 1) begin
|
||||||
|
r_done = 1;
|
||||||
|
m_if.RREADY = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
// Write is done when Address, Data and Response phases are done
|
||||||
|
done = (a_done && r_done);
|
||||||
|
`uvm_info("drive_read_txn", $sformatf("[%s] Waiting for transaction to be done (Data=0x%h) (%b - a%b r%b)",
|
||||||
|
req.show_tag(), m_if.RDATA, done, a_done, r_done), UVM_LOW)
|
||||||
|
end
|
||||||
|
|
||||||
|
read_request_sem.put();
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
|
// ------------------------------------------------------------
|
||||||
|
// Mark transaction done
|
||||||
|
function void finish_tr(axi_transaction txn);
|
||||||
|
uvm_event finished_event;
|
||||||
|
|
||||||
|
finished_event = txn.get_event_pool().get("finished");
|
||||||
|
finished_event.trigger();
|
||||||
|
`uvm_info("finish_tr", $sformatf("[%s] Marked transaction done",
|
||||||
|
txn.show_tag()), UVM_LOW)
|
||||||
|
endfunction
|
||||||
endclass : axi_manager_driver
|
endclass : axi_manager_driver
|
||||||
|
@@ -71,13 +71,13 @@ class axi_monitor extends uvm_monitor; // #(axi_transaction);
|
|||||||
forever begin
|
forever begin
|
||||||
@(posedge mon_if.ACLK);
|
@(posedge mon_if.ACLK);
|
||||||
if (mon_if.ARESETn != 0) begin
|
if (mon_if.ARESETn != 0) begin
|
||||||
if (mon_if.AWVALID == 1) begin
|
if ((mon_if.AWVALID == 1) && (mon_if.AWREADY == 1)) begin
|
||||||
$fwrite(trk_file, "AXI WRITE - ADDR=0x%h DATA=0x%h STRB=%h\n",
|
$fwrite(trk_file, "%10t: AXI WRITE - ADDR=0x%h DATA=0x%h STRB=%h\n",
|
||||||
mon_if.AWADDR, mon_if.WDATA, mon_if.WSTRB);
|
$time, mon_if.AWADDR, mon_if.WDATA, mon_if.WSTRB);
|
||||||
end
|
end
|
||||||
if (mon_if.ARVALID == 1) begin
|
if ((mon_if.ARVALID == 1) && (mon_if.ARREADY == 1)) begin
|
||||||
$fwrite(trk_file, "AXI READ - ADDR=0x%h\n",
|
$fwrite(trk_file, "%10t: AXI READ - ADDR=0x%h\n",
|
||||||
mon_if.ARADDR);
|
$time, mon_if.ARADDR);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
class axi_subordinate_driver extends axi_driver;
|
class axi_subordinate_driver extends axi_driver;
|
||||||
|
int rd_txn_id = 0;
|
||||||
|
int wr_txn_id = 0;
|
||||||
|
|
||||||
|
semaphore write_request_sem;
|
||||||
|
semaphore read_request_sem;
|
||||||
|
|
||||||
`uvm_component_utils(axi_subordinate_driver)
|
`uvm_component_utils(axi_subordinate_driver)
|
||||||
|
|
||||||
@@ -7,6 +12,9 @@ class axi_subordinate_driver extends axi_driver;
|
|||||||
// Constructor
|
// Constructor
|
||||||
function new(string name = "axi_subordinate_driver", uvm_component parent = null);
|
function new(string name = "axi_subordinate_driver", uvm_component parent = null);
|
||||||
super.new(name, parent);
|
super.new(name, parent);
|
||||||
|
|
||||||
|
write_request_sem = new(1);
|
||||||
|
read_request_sem = new(1);
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
@@ -19,21 +27,22 @@ class axi_subordinate_driver extends axi_driver;
|
|||||||
end
|
end
|
||||||
|
|
||||||
forever begin
|
forever begin
|
||||||
@(posedge s_if.ARESETn);
|
@(s_if.ARESETn or s_if.ACLK);
|
||||||
|
|
||||||
while (s_if.ARESETn != 0) begin
|
if (s_if.ARESETn == 0) continue;
|
||||||
@(posedge s_if.ACLK);
|
|
||||||
|
|
||||||
// Following could happen on the same cycle
|
if (s_if.ACLK == 1) begin
|
||||||
if (s_if.AWVALID == 1'b1) begin
|
if (s_if.AWVALID == 1'b1) begin
|
||||||
|
fork
|
||||||
respond_to_write_txn();
|
respond_to_write_txn();
|
||||||
|
join_none
|
||||||
end
|
end
|
||||||
|
|
||||||
if (s_if.ARVALID == 1'b1) begin
|
if (s_if.ARVALID == 1'b1) begin
|
||||||
|
fork
|
||||||
respond_to_read_txn();
|
respond_to_read_txn();
|
||||||
|
join_none
|
||||||
end
|
end
|
||||||
|
|
||||||
@(negedge s_if.ACLK);
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
endtask
|
endtask
|
||||||
@@ -43,22 +52,73 @@ class axi_subordinate_driver extends axi_driver;
|
|||||||
axi_transaction req;
|
axi_transaction req;
|
||||||
int dly = cfg.get_pre_response_delay();
|
int dly = cfg.get_pre_response_delay();
|
||||||
|
|
||||||
|
while (s_if.AWVALID != 1) begin
|
||||||
|
`uvm_info("respond_to_write_txn", $sformatf("Waiting for AWVALID to set (%0b)",
|
||||||
|
s_if.AWVALID), UVM_LOW)
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (!write_request_sem.try_get()) begin
|
||||||
|
`uvm_info("respond_to_write_txn", $sformatf("Already taken write semaphore"), UVM_LOW)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
// `uvm_info("respond_to_write_txn", $sformatf("Waiting for write semaphore"), UVM_LOW)
|
||||||
|
// write_request_sem.get();
|
||||||
|
`uvm_info("respond_to_write_txn", $sformatf("Got write semaphore"), UVM_LOW)
|
||||||
|
|
||||||
req = axi_transaction::type_id::create("req");
|
req = axi_transaction::type_id::create("req");
|
||||||
|
req.set_sequence_id(1);
|
||||||
|
req.set_transaction_id(wr_txn_id);
|
||||||
|
wr_txn_id += 1;
|
||||||
req.txn_type = AXI_WRITE;
|
req.txn_type = AXI_WRITE;
|
||||||
req.addr = s_if.AWADDR;
|
|
||||||
req.data = s_if.WDATA;
|
|
||||||
req.strb = s_if.WSTRB;
|
|
||||||
|
|
||||||
// Pre response delay
|
// Pre response delay
|
||||||
`uvm_info("drive_txn", $sformatf("Waiting pre_response_delay = %0d cycles",
|
`uvm_info("respond_to_write_txn", $sformatf("[%s] Waiting pre_response_delay = %0d cycles",
|
||||||
dly), UVM_LOW)
|
req.show_tag(), dly), UVM_LOW)
|
||||||
repeat(dly) @(posedge s_if.ACLK);
|
repeat(dly) @(posedge s_if.ACLK);
|
||||||
|
|
||||||
`uvm_info("respond_to_write_txn", $sformatf("Responding to AXI write transaction:\n%s", req.sprint()), UVM_LOW)
|
`uvm_info("respond_to_write_txn", $sformatf("[%s] Responding to AXI write transaction:\n%s",
|
||||||
|
req.show_tag(), req.sprint()), UVM_LOW)
|
||||||
|
|
||||||
s_if.AWREADY = 1'b1;
|
s_if.AWREADY = 1'b1;
|
||||||
|
req.addr = s_if.AWADDR;
|
||||||
@(posedge s_if.ACLK);
|
@(posedge s_if.ACLK);
|
||||||
|
while (s_if.AWVALID != 0) begin
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
end
|
||||||
s_if.AWREADY = 1'b0;
|
s_if.AWREADY = 1'b0;
|
||||||
|
|
||||||
|
`uvm_info("respond_to_write_txn", $sformatf("[%s] Request phase done. Waiting data phase",
|
||||||
|
req.show_tag()), UVM_LOW)
|
||||||
|
while (s_if.WVALID != 1) begin
|
||||||
|
`uvm_info("respond_to_write_txn", $sformatf("[%s] Waiting for WVALID to set (%0b)",
|
||||||
|
req.show_tag(), s_if.WVALID), UVM_LOW)
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
end
|
||||||
|
s_if.WREADY = 1'b1;
|
||||||
|
req.data = s_if.WDATA;
|
||||||
|
req.strb = s_if.WSTRB;
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
while (s_if.WVALID != 0) begin
|
||||||
|
`uvm_info("respond_to_write_txn", $sformatf("[%s] Waiting for WVALID to clear (%0b)",
|
||||||
|
req.show_tag(), s_if.WVALID), UVM_LOW)
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
end
|
||||||
|
s_if.WREADY = 1'b0;
|
||||||
|
|
||||||
|
`uvm_info("respond_to_write_txn", $sformatf("[%s] Data phase done. Waiting response phase",
|
||||||
|
req.show_tag()), UVM_LOW)
|
||||||
|
s_if.BVALID = 1;
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
while (s_if.BREADY != 1) begin
|
||||||
|
`uvm_info("respond_to_write_txn", $sformatf("[%s] Waiting for BREADY to set (%0b)",
|
||||||
|
req.show_tag(), s_if.BREADY), UVM_LOW)
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
end
|
||||||
|
s_if.BVALID = 0;
|
||||||
|
`uvm_info("respond_to_write_txn", $sformatf("[%s] Response phase done",
|
||||||
|
req.show_tag()), UVM_LOW)
|
||||||
|
write_request_sem.put();
|
||||||
endtask
|
endtask
|
||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
@@ -66,19 +126,57 @@ class axi_subordinate_driver extends axi_driver;
|
|||||||
axi_transaction req;
|
axi_transaction req;
|
||||||
int dly = cfg.get_pre_response_delay();
|
int dly = cfg.get_pre_response_delay();
|
||||||
|
|
||||||
|
while (s_if.ARVALID != 1) begin
|
||||||
|
`uvm_info("respond_to_read_txn", $sformatf("Waiting for ARVALID to be set (%0b)",
|
||||||
|
s_if.ARVALID), UVM_LOW)
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
end
|
||||||
|
|
||||||
|
if (!read_request_sem.try_get()) begin
|
||||||
|
`uvm_info("respond_to_read_txn", $sformatf("Already taken read semaphore"), UVM_LOW)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
// `uvm_info("respond_to_read_txn", $sformatf("Waiting for read semaphore"), UVM_LOW)
|
||||||
|
// read_request_sem.get();
|
||||||
|
`uvm_info("respond_to_read_txn", $sformatf("Got read semaphore"), UVM_LOW)
|
||||||
|
|
||||||
req = axi_transaction::type_id::create("req");
|
req = axi_transaction::type_id::create("req");
|
||||||
|
req.set_sequence_id(0);
|
||||||
|
req.set_transaction_id(rd_txn_id);
|
||||||
|
rd_txn_id += 1;
|
||||||
req.txn_type = AXI_READ;
|
req.txn_type = AXI_READ;
|
||||||
req.addr = s_if.ARADDR;
|
req.addr = s_if.ARADDR;
|
||||||
|
|
||||||
// Pre response delay
|
// Pre response delay
|
||||||
`uvm_info("respond_to_write_txn", $sformatf("Waiting pre_response_delay = %0d cycles",
|
`uvm_info("respond_to_read_txn", $sformatf("Waiting pre_response_delay = %0d cycles",
|
||||||
dly), UVM_LOW)
|
dly), UVM_LOW)
|
||||||
repeat(dly) @(posedge s_if.ACLK);
|
repeat(dly) @(posedge s_if.ACLK);
|
||||||
|
|
||||||
`uvm_info("respond_to_write_txn", $sformatf("Responding to AXI write transaction:\n%s", req.sprint()), UVM_LOW)
|
`uvm_info("respond_to_read_txn", $sformatf("Responding to AXI read transaction:\n%s",
|
||||||
|
req.sprint()), UVM_LOW)
|
||||||
|
|
||||||
s_if.ARREADY = 1'b1;
|
s_if.ARREADY = 1'b1;
|
||||||
@(posedge s_if.ACLK);
|
@(posedge s_if.ACLK);
|
||||||
|
while (s_if.ARVALID != 0) begin
|
||||||
|
`uvm_info("respond_to_read_txn", $sformatf("[%s] Waiting for ARVALID to clear (%0b)",
|
||||||
|
req.show_tag(), s_if.ARVALID), UVM_LOW)
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
end
|
||||||
s_if.ARREADY = 1'b0;
|
s_if.ARREADY = 1'b0;
|
||||||
|
|
||||||
|
`uvm_info("respond_to_read_txn", $sformatf("[%s] Data phase done. Waiting response phase",
|
||||||
|
req.show_tag()), UVM_LOW)
|
||||||
|
s_if.RVALID = 1;
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
while (s_if.RREADY != 1) begin
|
||||||
|
`uvm_info("respond_to_read_txn", $sformatf("[%s] Waiting for RREADY to set (%0b)",
|
||||||
|
req.show_tag(), s_if.RREADY), UVM_LOW)
|
||||||
|
@(posedge s_if.ACLK);
|
||||||
|
end
|
||||||
|
s_if.RVALID = 0;
|
||||||
|
`uvm_info("respond_to_read_txn", $sformatf("[%s] Response phase done",
|
||||||
|
req.show_tag()), UVM_LOW)
|
||||||
|
|
||||||
|
read_request_sem.put();
|
||||||
endtask
|
endtask
|
||||||
endclass : axi_subordinate_driver
|
endclass : axi_subordinate_driver
|
||||||
|
@@ -5,12 +5,16 @@ class axi_transaction extends uvm_sequence_item;
|
|||||||
rand bit [`ADDR_WIDTH-1:0] addr; // Address
|
rand bit [`ADDR_WIDTH-1:0] addr; // Address
|
||||||
rand bit [`DATA_WIDTH-1:0] data; // Data
|
rand bit [`DATA_WIDTH-1:0] data; // Data
|
||||||
rand bit [`DATA_WIDTH_DIV_8-1:0] strb; // Byte enable
|
rand bit [`DATA_WIDTH_DIV_8-1:0] strb; // Byte enable
|
||||||
|
rand bit [2:0] size; // Size
|
||||||
|
rand bit [7:0] length; // Length
|
||||||
|
|
||||||
`uvm_object_utils_begin(axi_transaction)
|
`uvm_object_utils_begin(axi_transaction)
|
||||||
`uvm_field_enum(axi_transaction_type_t, txn_type, UVM_DEFAULT)
|
`uvm_field_enum(axi_transaction_type_t, txn_type, UVM_DEFAULT)
|
||||||
`uvm_field_int(addr, UVM_DEFAULT)
|
`uvm_field_int(addr, UVM_DEFAULT)
|
||||||
`uvm_field_int(data, UVM_DEFAULT)
|
`uvm_field_int(data, UVM_DEFAULT)
|
||||||
`uvm_field_int(strb, UVM_DEFAULT)
|
`uvm_field_int(strb, UVM_DEFAULT)
|
||||||
|
`uvm_field_int(size, UVM_DEFAULT)
|
||||||
|
`uvm_field_int(length, UVM_DEFAULT)
|
||||||
`uvm_object_utils_end
|
`uvm_object_utils_end
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
@@ -18,6 +22,34 @@ class axi_transaction extends uvm_sequence_item;
|
|||||||
super.new(name);
|
super.new(name);
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
|
// Get transaction id - made up of sequence ID and trasacton ID
|
||||||
|
function axi_transaction_id_t get_tid();
|
||||||
|
axi_transaction_id_t tid;
|
||||||
|
|
||||||
|
tid.seq_id = this.get_sequence_id();
|
||||||
|
tid.txn_id = this.get_transaction_id();
|
||||||
|
|
||||||
|
return tid;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Show transaction id - sequence ID:trasacton ID
|
||||||
|
function string show_tid();
|
||||||
|
return $sformatf("%0h:%0h", this.get_sequence_id(), this.get_transaction_id());
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Show transaction tag - Transaction type:sequence ID:trasacton ID
|
||||||
|
function string show_tag();
|
||||||
|
return $sformatf("%s:%0h:%0h", this.txn_type.name(), this.get_sequence_id(), this.get_transaction_id());
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
// Wait for transaction to be done
|
||||||
|
task wait_for_done();
|
||||||
|
uvm_event finished_event;
|
||||||
|
|
||||||
|
finished_event = get_event_pool().get("finished");
|
||||||
|
finished_event.wait_on();
|
||||||
|
endtask
|
||||||
|
|
||||||
// Copy method for cloning
|
// Copy method for cloning
|
||||||
virtual function uvm_object clone();
|
virtual function uvm_object clone();
|
||||||
axi_transaction copy;
|
axi_transaction copy;
|
||||||
@@ -26,6 +58,8 @@ class axi_transaction extends uvm_sequence_item;
|
|||||||
copy.addr = this.addr;
|
copy.addr = this.addr;
|
||||||
copy.data = this.data;
|
copy.data = this.data;
|
||||||
copy.strb = this.strb;
|
copy.strb = this.strb;
|
||||||
|
copy.size = this.size;
|
||||||
|
copy.length = this.length;
|
||||||
return copy;
|
return copy;
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
@@ -36,7 +70,9 @@ class axi_transaction extends uvm_sequence_item;
|
|||||||
return (this.txn_type == other.txn_type) &&
|
return (this.txn_type == other.txn_type) &&
|
||||||
(this.addr == other.addr) &&
|
(this.addr == other.addr) &&
|
||||||
(this.data == other.data) &&
|
(this.data == other.data) &&
|
||||||
(this.strb == other.strb);
|
(this.strb == other.strb) &&
|
||||||
|
(this.size == other.size) &&
|
||||||
|
(this.length == other.length);
|
||||||
endfunction
|
endfunction
|
||||||
|
|
||||||
endclass : axi_transaction
|
endclass : axi_transaction
|
||||||
|
@@ -1,13 +1,18 @@
|
|||||||
// AXI Types
|
// AXI Types
|
||||||
package axi_types;
|
package axi_types;
|
||||||
|
typedef struct {
|
||||||
|
int seq_id;
|
||||||
|
int txn_id;
|
||||||
|
} axi_transaction_id_t;
|
||||||
|
|
||||||
// Agent type
|
// Agent type
|
||||||
typedef enum {
|
typedef enum bit {
|
||||||
MANAGER,
|
MANAGER = 1'b0,
|
||||||
SUBORDINATE
|
SUBORDINATE = 1'b1
|
||||||
} axi_agent_type_t;
|
} axi_agent_type_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum bit {
|
||||||
AXI_READ,
|
AXI_READ = 1'b0,
|
||||||
AXI_WRITE
|
AXI_WRITE = 1'b1
|
||||||
} axi_transaction_type_t;
|
} axi_transaction_type_t;
|
||||||
endpackage
|
endpackage
|
||||||
|
@@ -36,6 +36,7 @@ class axi_simple_seq extends axi_m_seq_base;
|
|||||||
|
|
||||||
// Task to start the sequence
|
// Task to start the sequence
|
||||||
virtual task body();
|
virtual task body();
|
||||||
|
axi_transaction txns[$];
|
||||||
axi_transaction txn;
|
axi_transaction txn;
|
||||||
|
|
||||||
super.body();
|
super.body();
|
||||||
@@ -48,6 +49,16 @@ class axi_simple_seq extends axi_m_seq_base;
|
|||||||
data != {`DATA_WIDTH{1'b0}};
|
data != {`DATA_WIDTH{1'b0}};
|
||||||
strb == 'hf; // Example byte enable
|
strb == 'hf; // Example byte enable
|
||||||
});
|
});
|
||||||
|
`uvm_info("axi_simple_seq", $sformatf("Starting %s transaction [%0s]",
|
||||||
|
txn.txn_type.name(), txn.show_tag()), UVM_LOW)
|
||||||
|
txns.push_back(txn);
|
||||||
|
end
|
||||||
|
|
||||||
|
`uvm_info("axi_simple_seq", $sformatf("Waiting for %0d txns", txns.size()), UVM_LOW)
|
||||||
|
foreach (txns[i]) begin
|
||||||
|
`uvm_info("axi_simple_seq", $sformatf("Waiting for txn %s", txns[i].show_tag()), UVM_LOW)
|
||||||
|
txns[i].wait_for_done();
|
||||||
|
`uvm_info("axi_simple_seq", $sformatf("Done waiting for txn %s", txns[i].show_tag()), UVM_LOW)
|
||||||
end
|
end
|
||||||
endtask
|
endtask
|
||||||
endclass : axi_simple_seq
|
endclass : axi_simple_seq
|
||||||
|
@@ -12,8 +12,12 @@ class test_base extends uvm_test;
|
|||||||
|
|
||||||
// ------------------------------------------------------------
|
// ------------------------------------------------------------
|
||||||
function void build_phase(uvm_phase phase);
|
function void build_phase(uvm_phase phase);
|
||||||
|
uvm_root ur;
|
||||||
super.build_phase(phase);
|
super.build_phase(phase);
|
||||||
|
|
||||||
|
ur = uvm_root::get();
|
||||||
|
ur.set_timeout(10us);
|
||||||
|
|
||||||
env = tb_env::type_id::create("env", this);
|
env = tb_env::type_id::create("env", this);
|
||||||
tb_printer = new("tb_printer");
|
tb_printer = new("tb_printer");
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user