Compare commits

...

5 Commits

Author SHA1 Message Date
36eedfb56d Random seed set to 2 for now 2025-10-01 23:57:54 -07:00
56e107879b Miscellaneous updates 2025-10-01 23:57:25 -07:00
9f14bc7ceb AXI interface regenerated 2025-10-01 23:57:04 -07:00
cce61f687a GTKWave signal file 2025-10-01 23:53:03 -07:00
76472bdffe Added script to launch VSCode 2025-10-01 23:52:37 -07:00
13 changed files with 376 additions and 94 deletions

View File

@@ -45,6 +45,7 @@ BUILD_ARGS=-I$(UVM_HOME)/src -I. \
--error-limit 10 \
--timing $(TIMESCALE) \
--trace \
--x-initial 0 \
--top tb_top \
+define+SVA_ON \
$(TB_DEFINES) \
@@ -112,7 +113,7 @@ run: $(CPP_OUT)
$(info #---------------------)
@if [ ! -d runs/$(TEST_NAME) ]; then mkdir -p runs/$(TEST_NAME); fi
@cd runs/$(TEST_NAME) && \
$(PROJ_BASE)/obj_dir/$(PROJ).sim +UVM_TESTNAME=$(TEST_NAME) +UVM_CONFIG_DB_TRACE |& tee $(SIM_LOG)
$(PROJ_BASE)/obj_dir/$(PROJ).sim +verilator+seed+2 +UVM_TESTNAME=$(TEST_NAME) +UVM_CONFIG_DB_TRACE |& tee $(SIM_LOG)
notify-send "[$(PROJ)] Test run done"
#

View File

@@ -1,20 +1,21 @@
[*]
[*] GTKWave Analyzer v3.3.124 (w)1999-2025 BSI
[*] Sun Aug 24 18:22:14 2025
[*] GTKWave Analyzer v3.3.125 (w)1999-2025 BSI
[*] Sun Sep 28 00:35:45 2025
[*]
[dumpfile] "/home/mahesh/dev/sv/axipg/runs/test_basic/wave.vcd"
[dumpfile_mtime] "Sun Aug 24 18:18:15 2025"
[dumpfile_size] 19493
[dumpfile_mtime] "Sun Sep 28 00:13:17 2025"
[dumpfile_size] 48138
[savefile] "/home/mahesh/dev/sv/axipg/axi.gtkw"
[timestart] 0
[size] 1388 1348
[pos] -1 -1
*-6.502242 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[size] 1900 988
[pos] -7 -4
*-10.447897 1195 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] tb_top.
[treeopen] tb_top.t_if.
[sst_width] 290
[signals_width] 126
[signals_width] 150
[sst_expanded] 1
[sst_vpaned_height] 417
[sst_vpaned_height] 292
@28
tb_top.t_if.ARESETn
tb_top.t_if.ACLK
@@ -26,6 +27,17 @@ tb_top.t_if.ARLEN[7:0]
@200
-
@28
tb_top.t_if.RVALID
@29
tb_top.t_if.RREADY
@22
tb_top.t_if.RDATA[63:0]
@28
tb_top.t_if.RLAST
tb_top.t_if.RRESP[0]
@200
-
@28
tb_top.t_if.AWVALID
tb_top.t_if.AWREADY
@22
@@ -43,5 +55,9 @@ tb_top.t_if.WDATA[63:0]
tb_top.t_if.WLAST
@200
-
@28
tb_top.t_if.BVALID
tb_top.t_if.BREADY
tb_top.t_if.BRESP[0]
[pattern_trace] 1
[pattern_trace] 0

View File

@@ -85,6 +85,7 @@ interface axi_intf #(
// A2.1.1 Write request channel
logic WVALID; // Valid indicator [Manager]
logic WREADY; // Ready indicator [Subordinate]
logic [ID_W_WIDTH-1:0] WID; // Transaction identifier for the write channels [Manager]
logic [DATA_WIDTH-1:0] WDATA; // Write data [Manager]
logic [DATA_WIDTH_DIV_8-1:0] WSTRB; // Write data strobes [Manager]
logic [CEIL_DATA_WIDTH_DIV_128_TMS_4-1:0] WTAG; // Memory Tag [Manager]
@@ -210,6 +211,7 @@ interface axi_intf #(
// A2.1.1 Write request channel
output WVALID,
input WREADY,
output WID,
output WDATA,
output WSTRB,
output WTAG,
@@ -336,6 +338,7 @@ interface axi_intf #(
// A2.1.1 Write request channel
input WVALID,
output WREADY,
input WID,
input WDATA,
input WSTRB,
input WTAG,

View File

@@ -248,44 +248,44 @@ sub get_axi_intf_data {
'name' => 'A2.1.1 Write request channel',
'signals' => [
# n: name, w: width, s: source, d: description
{'n' =>'AWVALID','w' =>'1','s' =>'Manager','d' =>'Valid indicator' },
{'n' =>'AWREADY','w' =>'1','s' =>'Subordinate','d' =>'Ready indicator' },
{'n' =>'AWID','w' =>'ID_W_WIDTH','s' =>'Manager','d' =>'Transaction identifier for the write channels' },
{'n' =>'AWADDR','w' =>'ADDR_WIDTH','s' =>'Manager','d' =>'Transaction address' },
{'n' =>'AWREGION','w' =>'4','s' =>'Manager','d' =>'Region identifier' },
{'n' =>'AWLEN','w' =>'8','s' =>'Manager','d' =>'Transaction length' },
{'n' =>'AWSIZE','w' =>'3','s' =>'Manager','d' =>'Transaction size' },
{'n' =>'AWBURST','w' =>'2','s' =>'Manager','d' =>'Burst attribute' },
{'n' =>'AWLOCK','w' =>'1','s' =>'Manager','d' =>'Exclusive access indicator' },
{'n' =>'AWCACHE','w' =>'4','s' =>'Manager','d' =>'Memory attributes' },
{'n' =>'AWPROT','w' =>'3','s' =>'Manager','d' =>'Access attributes' },
{'n' =>'AWNSE','w' =>'1','s' =>'Manager','d' =>'Non-secure extension bit for RME' },
{'n' =>'AWQOS','w' =>'4','s' =>'Manager','d' =>'QoS identifier' },
{'n' =>'AWUSER','w' =>'USER_REQ_WIDTH','s' =>'Manager','d' =>'User-defined extension to a request' },
{'n' =>'AWDOMAIN','w' =>'2','s' =>'Manager','d' =>'Shareability domain of a request' },
{'n' =>'AWSNOOP','w' =>'AWSNOOP_WIDTH','s' =>'Manager','d' =>'Write request opcode' },
{'n' =>'AWSTASHNID','w' =>'11','s' =>'Manager','d' =>'Stash Node ID' },
{'n' =>'AWSTASHNIDEN','w' =>'1','s' =>'Manager','d' =>'Stash Node ID enable' },
{'n' =>'AWSTASHLPID','w' =>'5','s' =>'Manager','d' =>'Stash Logical Processor ID' },
{'n' =>'AWSTASHLPIDEN','w' =>'1','s' =>'Manager','d' =>'Stash Logical Processor ID enable' },
{'n' =>'AWTRACE','w' =>'1','s' =>'Manager','d' =>'Trace signal' },
{'n' =>'AWLOOP','w' =>'LOOP_W_WIDTH','s' =>'Manager','d' =>'Loopback signals on the write channels' },
{'n' =>'AWMMUVALID','w' =>'1','s' =>'Manager','d' =>'MMU signal qualifier' },
{'n' =>'AWMMUSECSID','w' =>'SECSID_WIDTH','s' =>'Manager','d' =>'Secure Stream ID' },
{'n' =>'AWMMUSID','w' =>'SID_WIDTH','s' =>'Manager','d' =>'StreamID' },
{'n' =>'AWMMUSSIDV','w' =>'1','s' =>'Manager','d' =>'SubstreamID valid' },
{'n' =>'AWMMUSSID','w' =>'SSID_WIDTH','s' =>'Manager','d' =>'SubstreamID' },
{'n' =>'AWMMUATST','w' =>'1','s' =>'Manager','d' =>'Address translated indicator' },
{'n' =>'AWMMUFLOW','w' =>'2','s' =>'Manager','d' =>'SMMU flow type' },
{'n' =>'AWPBHA','w' =>'4','s' =>'Manager','d' =>'Page-based Hardware Attributes' },
{'n' =>'AWNSAID','w' =>'4','s' =>'Manager','d' =>'Non-secure Access ID' },
{'n' =>'AWSUBSYSID','w' =>'SUBSYSID_WIDTH','s' =>'Manager','d' =>'Subsystem ID' },
{'n' =>'AWATOP','w' =>'6','s' =>'Manager','d' =>'Atomic transaction opcode' },
{'n' =>'AWMPAM','w' =>'MPAM_WIDTH','s' =>'Manager','d' =>'MPAM information with a request' },
{'n' =>'AWIDUNQ','w' =>'1','s' =>'Manager','d' =>'Unique ID indicator' },
{'n' =>'AWCMO','w' =>'AWCMO_WIDTH','s' =>'Manager','d' =>'CMO type' },
{'n' =>'AWTAGOP','w' =>'2','s' =>'Manager','d' =>'Memory Tag operation for write requests' },
{'n' =>'AWMECID','w' =>'MECID_WIDTH','s' =>'Manager','d' =>'Memory Encryption Context identifier' },
{ 'n' => 'AWVALID','w' => '1','s' => 'Manager','d' => 'Valid indicator' },
{ 'n' => 'AWREADY','w' => '1','s' => 'Subordinate','d' => 'Ready indicator' },
{ 'n' => 'AWID','w' => 'ID_W_WIDTH','s' => 'Manager','d' => 'Transaction identifier for the write channels' },
{ 'n' => 'AWADDR','w' => 'ADDR_WIDTH','s' => 'Manager','d' => 'Transaction address' },
{ 'n' => 'AWREGION','w' => '4','s' => 'Manager','d' => 'Region identifier' },
{ 'n' => 'AWLEN','w' => '8','s' => 'Manager','d' => 'Transaction length' },
{ 'n' => 'AWSIZE','w' => '3','s' => 'Manager','d' => 'Transaction size' },
{ 'n' => 'AWBURST','w' => '2','s' => 'Manager','d' => 'Burst attribute' },
{ 'n' => 'AWLOCK','w' => '1','s' => 'Manager','d' => 'Exclusive access indicator' },
{ 'n' => 'AWCACHE','w' => '4','s' => 'Manager','d' => 'Memory attributes' },
{ 'n' => 'AWPROT','w' => '3','s' => 'Manager','d' => 'Access attributes' },
{ 'n' => 'AWNSE','w' => '1','s' => 'Manager','d' => 'Non-secure extension bit for RME' },
{ 'n' => 'AWQOS','w' => '4','s' => 'Manager','d' => 'QoS identifier' },
{ 'n' => 'AWUSER','w' => 'USER_REQ_WIDTH','s' => 'Manager','d' => 'User-defined extension to a request' },
{ 'n' => 'AWDOMAIN','w' => '2','s' => 'Manager','d' => 'Shareability domain of a request' },
{ 'n' => 'AWSNOOP','w' => 'AWSNOOP_WIDTH','s' => 'Manager','d' => 'Write request opcode' },
{ 'n' => 'AWSTASHNID','w' => '11','s' => 'Manager','d' => 'Stash Node ID' },
{ 'n' => 'AWSTASHNIDEN','w' => '1','s' => 'Manager','d' => 'Stash Node ID enable' },
{ 'n' => 'AWSTASHLPID','w' => '5','s' => 'Manager','d' => 'Stash Logical Processor ID' },
{ 'n' => 'AWSTASHLPIDEN','w' => '1','s' => 'Manager','d' => 'Stash Logical Processor ID enable' },
{ 'n' => 'AWTRACE','w' => '1','s' => 'Manager','d' => 'Trace signal' },
{ 'n' => 'AWLOOP','w' => 'LOOP_W_WIDTH','s' => 'Manager','d' => 'Loopback signals on the write channels' },
{ 'n' => 'AWMMUVALID','w' => '1','s' => 'Manager','d' => 'MMU signal qualifier' },
{ 'n' => 'AWMMUSECSID','w' => 'SECSID_WIDTH','s' => 'Manager','d' => 'Secure Stream ID' },
{ 'n' => 'AWMMUSID','w' => 'SID_WIDTH','s' => 'Manager','d' => 'StreamID' },
{ 'n' => 'AWMMUSSIDV','w' => '1','s' => 'Manager','d' => 'SubstreamID valid' },
{ 'n' => 'AWMMUSSID','w' => 'SSID_WIDTH','s' => 'Manager','d' => 'SubstreamID' },
{ 'n' => 'AWMMUATST','w' => '1','s' => 'Manager','d' => 'Address translated indicator' },
{ 'n' => 'AWMMUFLOW','w' => '2','s' => 'Manager','d' => 'SMMU flow type' },
{ 'n' => 'AWPBHA','w' => '4','s' => 'Manager','d' => 'Page-based Hardware Attributes' },
{ 'n' => 'AWNSAID','w' => '4','s' => 'Manager','d' => 'Non-secure Access ID' },
{ 'n' => 'AWSUBSYSID','w' => 'SUBSYSID_WIDTH','s' => 'Manager','d' => 'Subsystem ID' },
{ 'n' => 'AWATOP','w' => '6','s' => 'Manager','d' => 'Atomic transaction opcode' },
{ 'n' => 'AWMPAM','w' => 'MPAM_WIDTH','s' => 'Manager','d' => 'MPAM information with a request' },
{ 'n' => 'AWIDUNQ','w' => '1','s' => 'Manager','d' => 'Unique ID indicator' },
{ 'n' => 'AWCMO','w' => 'AWCMO_WIDTH','s' => 'Manager','d' => 'CMO type' },
{ 'n' => 'AWTAGOP','w' => '2','s' => 'Manager','d' => 'Memory Tag operation for write requests' },
{ 'n' => 'AWMECID','w' => 'MECID_WIDTH','s' => 'Manager','d' => 'Memory Encryption Context identifier' },
]
},
{
@@ -293,6 +293,7 @@ sub get_axi_intf_data {
'signals' => [
{ 'n' => 'WVALID', 'w' => '1', 's' => 'Manager', 'd' => 'Valid indicator' },
{ 'n' => 'WREADY', 'w' => '1', 's' => 'Subordinate', 'd' => 'Ready indicator' },
{ 'n' => 'WID','w' => 'ID_W_WIDTH','s' => 'Manager','d' => 'Transaction identifier for the write channels' },
{ 'n' => 'WDATA', 'w' => 'DATA_WIDTH', 's' => 'Manager', 'd' => 'Write data' },
{ 'n' => 'WSTRB', 'w' => 'DATA_WIDTH_DIV_8', 's' => 'Manager', 'd' => 'Write data strobes' },
{ 'n' => 'WTAG', 'w' => 'CEIL_DATA_WIDTH_DIV_128_TMS_4', 's' => 'Manager', 'd' => 'Memory Tag' },

6
scripts/vscode Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
/opt/vscode/VSCode-linux-x64/code \
--enable-features=UseOzonePlatform,WaylandWindowDecorations \
--ozone-platform-hint=auto \
--unity-launch %F . & disown %1

View File

@@ -2,6 +2,10 @@
// AXI Manager 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)
@@ -9,6 +13,9 @@ class axi_manager_driver extends axi_driver;
// Constructor
function new(string name = "axi_manager_driver", uvm_component parent = null);
super.new(name, parent);
write_request_sem = new(1);
read_request_sem = new(1);
endfunction
// --------------------------------------------------
@@ -45,7 +52,14 @@ class axi_manager_driver extends axi_driver;
if (!$cast(req, txn)) begin
`uvm_fatal("drive_txn", "Invalid transaction type")
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);
join_none
seq_item_port.item_done();
end
end
@@ -54,7 +68,12 @@ class axi_manager_driver extends axi_driver;
// ------------------------------------------------------------
task drive_txn(axi_transaction req);
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
`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()))
end
`uvm_info("drive_txn", $sformatf("Driving AXI transaction done."), UVM_LOW)
finish_tr(req);
txn_trk.delete(tid);
endtask
// ------------------------------------------------------------
// Drive a write transaction
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);
m_if.AWVALID = 1;
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.WSTRB = req.strb;
while (m_if.AWREADY != 1) begin
// Wait for write response
@(posedge m_if.ACLK);
end
`uvm_info("drive_write_txn", $sformatf("Address phase accepted (AWREADY=1)"), UVM_LOW)
m_if.BREADY = 1;
while (!done) begin
@(posedge m_if.ACLK);
if (m_if.AWREADY == 1) begin
a_done = 1;
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
// ------------------------------------------------------------
// Drive a read transaction
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);
m_if.ARVALID = 1;
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);
while (m_if.ARREADY != 1) begin
@(posedge m_if.ACLK);
end
`uvm_info("drive_read_txn", $sformatf("Address phase accepted (ARREADY=1)"), UVM_LOW)
if (m_if.ARREADY == 1) begin
a_done = 1;
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
// ------------------------------------------------------------
// 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

View File

@@ -71,13 +71,13 @@ class axi_monitor extends uvm_monitor; // #(axi_transaction);
forever begin
@(posedge mon_if.ACLK);
if (mon_if.ARESETn != 0) begin
if (mon_if.AWVALID == 1) begin
$fwrite(trk_file, "AXI WRITE - ADDR=0x%h DATA=0x%h STRB=%h\n",
mon_if.AWADDR, mon_if.WDATA, mon_if.WSTRB);
if ((mon_if.AWVALID == 1) && (mon_if.AWREADY == 1)) begin
$fwrite(trk_file, "%10t: AXI WRITE - ADDR=0x%h DATA=0x%h STRB=%h\n",
$time, mon_if.AWADDR, mon_if.WDATA, mon_if.WSTRB);
end
if (mon_if.ARVALID == 1) begin
$fwrite(trk_file, "AXI READ - ADDR=0x%h\n",
mon_if.ARADDR);
if ((mon_if.ARVALID == 1) && (mon_if.ARREADY == 1)) begin
$fwrite(trk_file, "%10t: AXI READ - ADDR=0x%h\n",
$time, mon_if.ARADDR);
end
end
end

View File

@@ -1,5 +1,10 @@
// ----------------------------------------------------------------------
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)
@@ -7,6 +12,9 @@ class axi_subordinate_driver extends axi_driver;
// Constructor
function new(string name = "axi_subordinate_driver", uvm_component parent = null);
super.new(name, parent);
write_request_sem = new(1);
read_request_sem = new(1);
endfunction
// --------------------------------------------------
@@ -19,21 +27,22 @@ class axi_subordinate_driver extends axi_driver;
end
forever begin
@(posedge s_if.ARESETn);
@(s_if.ARESETn or s_if.ACLK);
while (s_if.ARESETn != 0) begin
@(posedge s_if.ACLK);
if (s_if.ARESETn == 0) continue;
// Following could happen on the same cycle
if (s_if.ACLK == 1) begin
if (s_if.AWVALID == 1'b1) begin
fork
respond_to_write_txn();
join_none
end
if (s_if.ARVALID == 1'b1) begin
fork
respond_to_read_txn();
join_none
end
@(negedge s_if.ACLK);
end
end
endtask
@@ -43,22 +52,73 @@ class axi_subordinate_driver extends axi_driver;
axi_transaction req;
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.set_sequence_id(1);
req.set_transaction_id(wr_txn_id);
wr_txn_id += 1;
req.txn_type = AXI_WRITE;
req.addr = s_if.AWADDR;
req.data = s_if.WDATA;
req.strb = s_if.WSTRB;
// Pre response delay
`uvm_info("drive_txn", $sformatf("Waiting pre_response_delay = %0d cycles",
dly), UVM_LOW)
`uvm_info("respond_to_write_txn", $sformatf("[%s] Waiting pre_response_delay = %0d cycles",
req.show_tag(), dly), UVM_LOW)
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;
req.addr = s_if.AWADDR;
@(posedge s_if.ACLK);
while (s_if.AWVALID != 0) begin
@(posedge s_if.ACLK);
end
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
// ------------------------------------------------------------
@@ -66,19 +126,57 @@ class axi_subordinate_driver extends axi_driver;
axi_transaction req;
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.set_sequence_id(0);
req.set_transaction_id(rd_txn_id);
rd_txn_id += 1;
req.txn_type = AXI_READ;
req.addr = s_if.ARADDR;
// 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)
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;
@(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;
`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
endclass : axi_subordinate_driver

View File

@@ -5,12 +5,16 @@ class axi_transaction extends uvm_sequence_item;
rand bit [`ADDR_WIDTH-1:0] addr; // Address
rand bit [`DATA_WIDTH-1:0] data; // Data
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_field_enum(axi_transaction_type_t, txn_type, UVM_DEFAULT)
`uvm_field_int(addr, UVM_DEFAULT)
`uvm_field_int(data, UVM_DEFAULT)
`uvm_field_int(strb, UVM_DEFAULT)
`uvm_field_int(size, UVM_DEFAULT)
`uvm_field_int(length, UVM_DEFAULT)
`uvm_object_utils_end
// Constructor
@@ -18,6 +22,34 @@ class axi_transaction extends uvm_sequence_item;
super.new(name);
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
virtual function uvm_object clone();
axi_transaction copy;
@@ -26,6 +58,8 @@ class axi_transaction extends uvm_sequence_item;
copy.addr = this.addr;
copy.data = this.data;
copy.strb = this.strb;
copy.size = this.size;
copy.length = this.length;
return copy;
endfunction
@@ -36,7 +70,9 @@ class axi_transaction extends uvm_sequence_item;
return (this.txn_type == other.txn_type) &&
(this.addr == other.addr) &&
(this.data == other.data) &&
(this.strb == other.strb);
(this.strb == other.strb) &&
(this.size == other.size) &&
(this.length == other.length);
endfunction
endclass : axi_transaction

View File

@@ -1,13 +1,18 @@
// AXI Types
package axi_types;
typedef struct {
int seq_id;
int txn_id;
} axi_transaction_id_t;
// Agent type
typedef enum {
MANAGER,
SUBORDINATE
typedef enum bit {
MANAGER = 1'b0,
SUBORDINATE = 1'b1
} axi_agent_type_t;
typedef enum {
AXI_READ,
AXI_WRITE
typedef enum bit {
AXI_READ = 1'b0,
AXI_WRITE = 1'b1
} axi_transaction_type_t;
endpackage

View File

@@ -36,6 +36,7 @@ class axi_simple_seq extends axi_m_seq_base;
// Task to start the sequence
virtual task body();
axi_transaction txns[$];
axi_transaction txn;
super.body();
@@ -48,6 +49,16 @@ class axi_simple_seq extends axi_m_seq_base;
data != {`DATA_WIDTH{1'b0}};
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
endtask
endclass : axi_simple_seq

View File

@@ -12,8 +12,12 @@ class test_base extends uvm_test;
// ------------------------------------------------------------
function void build_phase(uvm_phase phase);
uvm_root ur;
super.build_phase(phase);
ur = uvm_root::get();
ur.set_timeout(10us);
env = tb_env::type_id::create("env", this);
tb_printer = new("tb_printer");

View File

@@ -49,6 +49,7 @@
// A2.1.1 Write request channel
always @(a_if.WVALID) t_if.WVALID <= a_if.WVALID;
always @(a_if.WREADY) t_if.WREADY <= a_if.WREADY;
always @(a_if.WID) t_if.WID <= a_if.WID;
always @(a_if.WDATA) t_if.WDATA <= a_if.WDATA;
always @(a_if.WSTRB) t_if.WSTRB <= a_if.WSTRB;
always @(a_if.WTAG) t_if.WTAG <= a_if.WTAG;