|
@@ -0,0 +1,126 @@ |
|
|
|
|
|
class axi_drv extends uvm_driver#(axi_tx); |
|
|
|
|
|
virtual axi_intf vif; |
|
|
|
|
|
`uvm_component_utils(axi_drv) |
|
|
|
|
|
`NEW_COMP |
|
|
|
|
|
|
|
|
|
|
|
function void build_phase(uvm_phase phase); |
|
|
|
|
|
super.build_phase(phase); |
|
|
|
|
|
if(!uvm_config_db#(virtual axi_intf)::get(this, "", "vif", vif)) begin |
|
|
|
|
|
`uvm_error("CONFG_DB", "Not able to get axi intf handle") |
|
|
|
|
|
end |
|
|
|
|
|
endfunction |
|
|
|
|
|
|
|
|
|
|
|
task run_phase(uvm_phase phase); |
|
|
|
|
|
@(negedge vif.arst);//waiting for release the reset |
|
|
|
|
|
forever begin |
|
|
|
|
|
seq_item_port.get_next_item(req); |
|
|
|
|
|
req.print(); |
|
|
|
|
|
drive_tx(req); |
|
|
|
|
|
seq_item_port.item_done(); |
|
|
|
|
|
end |
|
|
|
|
|
endtask |
|
|
|
|
|
|
|
|
|
|
|
task drive_tx(axi_tx tx); |
|
|
|
|
|
if (tx.wr_rd == 1) begin |
|
|
|
|
|
write_addr(tx); |
|
|
|
|
|
write_data(tx); |
|
|
|
|
|
write_resp(tx); |
|
|
|
|
|
end |
|
|
|
|
|
if (tx.wr_rd == 0) begin |
|
|
|
|
|
read_addr(tx); |
|
|
|
|
|
read_data(tx); |
|
|
|
|
|
end |
|
|
|
|
|
endtask |
|
|
|
|
|
|
|
|
|
|
|
task write_addr(axi_tx tx); |
|
|
|
|
|
`uvm_info("AXI_TX", "write_addr", UVM_MEDIUM); |
|
|
|
|
|
//Master drives all write address channel signals (aw), it will drive at the posedge of clock |
|
|
|
|
|
@(vif.mst_cb); |
|
|
|
|
|
vif.mst_cb.awaddr <= tx.addr; |
|
|
|
|
|
vif.mst_cb.awlen <= tx.burst_len; |
|
|
|
|
|
vif.mst_cb.awsize <= tx.burst_size; |
|
|
|
|
|
vif.mst_cb.awburst <= tx.burst_type; |
|
|
|
|
|
vif.mst_cb.awid <= tx.txid; |
|
|
|
|
|
vif.mst_cb.awvalid <= 1'b1; |
|
|
|
|
|
wait (vif.mst_cb.awready == 1'b1); |
|
|
|
|
|
@(vif.mst_cb); |
|
|
|
|
|
vif.mst_cb.awaddr <= 0; |
|
|
|
|
|
vif.mst_cb.awlen <= 0; |
|
|
|
|
|
vif.mst_cb.awsize <= 0; |
|
|
|
|
|
vif.mst_cb.awburst <= 0; |
|
|
|
|
|
vif.mst_cb.awid <= 0; |
|
|
|
|
|
vif.mst_cb.awvalid <= 0; |
|
|
|
|
|
endtask |
|
|
|
|
|
|
|
|
|
|
|
task write_data(axi_tx tx); |
|
|
|
|
|
`uvm_info("AXI_TX", "write_data", UVM_MEDIUM); |
|
|
|
|
|
for (int i = 0; i <= tx.burst_len; i++) begin |
|
|
|
|
|
@(vif.mst_cb) |
|
|
|
|
|
vif.mst_cb.wdata <= tx.dataQ.pop_front(); |
|
|
|
|
|
vif.mst_cb.wstrb <= 4'b1111; //need to be updated as per the burst size |
|
|
|
|
|
vif.mst_cb.wvalid <= 1'b1; |
|
|
|
|
|
vif.mst_cb.wid <= tx.txid; |
|
|
|
|
|
//wlast=1 will be in last beat |
|
|
|
|
|
if(i == tx.burst_len) vif.mst_cb.wlast <= 1'b1; |
|
|
|
|
|
else vif.mst_cb.wlast <= 0; |
|
|
|
|
|
wait(vif.mst_cb.wready == 1'b1); |
|
|
|
|
|
end |
|
|
|
|
|
//once data beats are done, then reset all signals to 0 |
|
|
|
|
|
@(vif.mst_cb); |
|
|
|
|
|
vif.mst_cb.wvalid <= 0; |
|
|
|
|
|
vif.mst_cb.wlast <= 0; |
|
|
|
|
|
vif.mst_cb.wdata <= 0; |
|
|
|
|
|
vif.mst_cb.wstrb <= 0; |
|
|
|
|
|
vif.mst_cb.wid <= 0; |
|
|
|
|
|
endtask |
|
|
|
|
|
|
|
|
|
|
|
task write_resp(axi_tx tx); |
|
|
|
|
|
bit bvalid_f = 0; |
|
|
|
|
|
//`uvm_info("AXI_TX", "write_resp", UVM_MEDIUM); |
|
|
|
|
|
//write response is initiated by slave |
|
|
|
|
|
while (bvalid_f == 0) begin |
|
|
|
|
|
@(vif.mst_cb); |
|
|
|
|
|
bvalid_f = vif.mst_cb.bvalid; |
|
|
|
|
|
end |
|
|
|
|
|
vif.mst_cb.bready <= 1'b1; |
|
|
|
|
|
@(vif.mst_cb); |
|
|
|
|
|
vif.mst_cb.bready <= 1'b0; |
|
|
|
|
|
endtask |
|
|
|
|
|
|
|
|
|
|
|
task read_addr(axi_tx tx); |
|
|
|
|
|
`uvm_info("AXI_TX", "read_addr", UVM_MEDIUM); |
|
|
|
|
|
@(vif.mst_cb); |
|
|
|
|
|
vif.mst_cb.araddr <= tx.addr; |
|
|
|
|
|
vif.mst_cb.arlen <= tx.burst_len; |
|
|
|
|
|
vif.mst_cb.arsize <= tx.burst_size; |
|
|
|
|
|
vif.mst_cb.arburst <= tx.burst_type; |
|
|
|
|
|
vif.mst_cb.arid <= tx.txid; |
|
|
|
|
|
vif.mst_cb.arvalid <= 1'b1; |
|
|
|
|
|
wait (vif.mst_cb.arready == 1'b1); |
|
|
|
|
|
@(vif.mst_cb); |
|
|
|
|
|
vif.mst_cb.araddr <= 0; |
|
|
|
|
|
vif.mst_cb.arlen <= 0; |
|
|
|
|
|
vif.mst_cb.arsize <= 0; |
|
|
|
|
|
vif.mst_cb.arburst <= 0; |
|
|
|
|
|
vif.mst_cb.arid <= 0; |
|
|
|
|
|
vif.mst_cb.arvalid <= 0; |
|
|
|
|
|
endtask |
|
|
|
|
|
|
|
|
|
|
|
task read_data(axi_tx tx); |
|
|
|
|
|
bit rvalid_f = 0; |
|
|
|
|
|
`uvm_info("AXI_TX", "read_data", UVM_MEDIUM); |
|
|
|
|
|
//since read data is happening multiple times, then handshaking should do multiple times |
|
|
|
|
|
for (int i = 0; i <= tx.burst_len; i++) begin |
|
|
|
|
|
rvalid_f = 0; |
|
|
|
|
|
while (rvalid_f == 0) begin |
|
|
|
|
|
@(vif.mst_cb); |
|
|
|
|
|
rvalid_f = vif.mst_cb.rvalid; |
|
|
|
|
|
vif.mst_cb.rready <= 1'b1; |
|
|
|
|
|
end |
|
|
|
|
|
end |
|
|
|
|
|
@(vif.mst_cb); |
|
|
|
|
|
vif.mst_cb.rready <= 1'b0; |
|
|
|
|
|
endtask |
|
|
|
|
|
|
|
|
|
|
|
endclass |
|
|
|
|
|
|