diff --git a/common/common_macros.svh b/common/common_macros.svh index 20bc9c7..444ce61 100644 --- a/common/common_macros.svh +++ b/common/common_macros.svh @@ -4,5 +4,7 @@ .CEIL_DATA_WIDTH_DIV_128_TMS_4(`CEIL_DATA_WIDTH_DIV_128_TMS_4), \ .CEIL_DATA_WIDTH_DIV_64(`CEIL_DATA_WIDTH_DIV_64), \ .DATA_WIDTH(`DATA_WIDTH), \ - .DATA_WIDTH_DIV_8(`DATA_WIDTH_DIV_8)) + .DATA_WIDTH_DIV_8(`DATA_WIDTH_DIV_8), \ + .BRESP_WIDTH(`BRESP_WIDTH) \ + ) diff --git a/common/common_params.svh b/common/common_params.svh index 5fc4bf5..249011c 100644 --- a/common/common_params.svh +++ b/common/common_params.svh @@ -6,7 +6,7 @@ // `define ARSNOOP_WIDTH 1 // `define AWCMO_WIDTH 1 // `define AWSNOOP_WIDTH 1 -// `define BRESP_WIDTH 1 +`define BRESP_WIDTH 1 `define CEIL_DATA_WIDTH_DIV_128 1 `define CEIL_DATA_WIDTH_DIV_128_TMS_4 4 `define CEIL_DATA_WIDTH_DIV_64 1 diff --git a/src/axi/axi_driver.sv b/src/axi/axi_driver.sv index ed37835..9d6868e 100644 --- a/src/axi/axi_driver.sv +++ b/src/axi/axi_driver.sv @@ -9,6 +9,9 @@ class axi_driver extends uvm_driver; // #(axi_transaction); axi_agent_type_t agent_type; axi_agent_config cfg; + // Filehandle for transaction tracker file + int trk_file; + `uvm_component_utils(axi_driver) // -------------------------------------------------- @@ -41,4 +44,32 @@ class axi_driver extends uvm_driver; // #(axi_transaction); cfg = agt.get_cfg(); end endfunction + + // -------------------------------------------------- + // Run phase + virtual function void run_phase(uvm_phase phase); + // Open transaction log file + trk_file = $fopen($sformatf("axi_driver.%s.log", agent_type.name()), "w"); + if (trk_file == 0) begin + `uvm_error("run_phase", "Failed to open transaction log file") + end else begin + `uvm_info("run_phase", "Transaction log file opened successfully", UVM_LOW) + end + + // Start driver + drive_axi(phase); + endfunction + + // -------------------------------------------------- + virtual task drive_axi(uvm_phase phase); + $fwrite(trk_file, "AXI driver (%0s Mode)\n", agent_type.name()); + $fwrite(trk_file, "--------------------------------------------------\n"); + $fwrite(trk_file, "%s\n", axi_transaction::tracker_line_hdr()); + endtask + + // -------------------------------------------------- + // Function to write captured transaction into a file + function void write_transaction_to_file(axi_transaction txn); + $fwrite(trk_file, "%s\n", txn.tracker_line()); + endfunction endclass : axi_driver diff --git a/src/axi/axi_manager_driver.sv b/src/axi/axi_manager_driver.sv index 713780a..ebc8cda 100644 --- a/src/axi/axi_manager_driver.sv +++ b/src/axi/axi_manager_driver.sv @@ -19,25 +19,27 @@ class axi_manager_driver extends axi_driver; endfunction // -------------------------------------------------- - virtual task run_phase(uvm_phase phase); - `uvm_info("run_phase", $sformatf("Running AXI manager driver: %s", + virtual task drive_axi(uvm_phase phase); + super.drive_axi(phase); + + `uvm_info("drive_axi", $sformatf("Running AXI manager driver: %s", get_full_name()), UVM_LOW) if (m_if == null) begin - `uvm_error("run_phase", "MANAGER interface is null, cannot drive transactions") + `uvm_error("drive_axi", "MANAGER interface is null, cannot drive transactions") end forever begin - `uvm_info("run_phase", $sformatf("Starting to drive transactions for %s (rst_n = %0b)", + `uvm_info("drive_axi", $sformatf("Starting to drive transactions for %s (rst_n = %0b)", get_full_name(), m_if.ARESETn), UVM_LOW) // Wait for reset to be de-asserted if (m_if.ARESETn == 0) begin - `uvm_info("run_phase", $sformatf("Waiting for reset to be released (rst_n = %0b)", + `uvm_info("drive_axi", $sformatf("Waiting for reset to be released (rst_n = %0b)", m_if.ARESETn), UVM_LOW) @(posedge m_if.ARESETn); end - `uvm_info("run_phase", $sformatf("Starting to drive transactions for %s (rst_n = %0b)", + `uvm_info("drive_axi", $sformatf("Starting to drive transactions for %s (rst_n = %0b)", get_full_name(), m_if.ARESETn), UVM_LOW) // Drive transactions until reset is asserted @@ -45,7 +47,7 @@ class axi_manager_driver extends axi_driver; uvm_sequence_item txn; axi_transaction req; - `uvm_info("run_phase", $sformatf("Waiting for next transaction"), UVM_LOW) + `uvm_info("drive_axi", $sformatf("Waiting for next transaction"), UVM_LOW) seq_item_port.get_next_item(txn); @@ -53,9 +55,9 @@ class axi_manager_driver extends axi_driver; `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) + `uvm_info("drive_axi", $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) + `uvm_info("drive_axi", $sformatf("Txn-trk size changed to %0d to be under 3", txn_trk.size()), UVM_LOW) end fork drive_txn(req); @@ -73,6 +75,8 @@ class axi_manager_driver extends axi_driver; `uvm_info("drive_txn", $sformatf("Driving AXI transaction ID=%s:\n%s", req.show_tid(), req.sprint()), UVM_LOW) + write_transaction_to_file(req); + txn_trk[tid] = req; // Pre transaction delay diff --git a/src/axi/axi_monitor.sv b/src/axi/axi_monitor.sv index c004adb..89d9e26 100644 --- a/src/axi/axi_monitor.sv +++ b/src/axi/axi_monitor.sv @@ -2,13 +2,11 @@ // Monitor for AXI transactions // ---------------------------------------------------------------------- class axi_monitor extends uvm_monitor; // #(axi_transaction); - virtual `AXI_INTF.MANAGER m_if; - virtual `AXI_INTF.SUBORDINATE s_if; virtual `AXI_INTF mon_if; axi_agent_type_t agent_type; // Declare the analysis export - uvm_analysis_port ap; + uvm_analysis_port#(axi_transaction) ap; // Filehandle for transaction tracker file int trk_file; @@ -34,9 +32,6 @@ class axi_monitor extends uvm_monitor; // #(axi_transaction); function void set_virtual_interfaces(virtual `AXI_INTF.MANAGER m_if_p, virtual `AXI_INTF.SUBORDINATE s_if_p); `uvm_info("set_virtual_interfaces", $sformatf("Setting virtual interfaces"), UVM_LOW) - - m_if = m_if_p; - s_if = s_if_p; endfunction // -------------------------------------------------- @@ -68,62 +63,135 @@ class axi_monitor extends uvm_monitor; // #(axi_transaction); $fwrite(trk_file, "AXI monitor (%0s Mode)\n", agent_type.name()); $fwrite(trk_file, "--------------------------------------------------\n"); + fork + monitor_write(); + monitor_read(); + join + endtask + + // -------------------------------------------------- + // Monitor logic for Write transactions + virtual task monitor_write(); + bit prev_awready, prev_awvalid; + bit prev_wready, prev_wvalid; + bit prev_bready, prev_bvalid; + axi_transaction txn; + int txn_ph = 0; // IDLE + forever begin @(posedge mon_if.ACLK); - if (mon_if.ARESETn != 0) begin - 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) && (mon_if.ARREADY == 1)) begin - $fwrite(trk_file, "%10t: AXI READ - ADDR=0x%h\n", - $time, mon_if.ARADDR); + + // Address phase + if (txn_ph == 0) begin + if (((mon_if.AWREADY != prev_awready) || (mon_if.AWVALID != prev_awvalid)) + && ((mon_if.AWREADY === 1'b1) && (mon_if.AWVALID === 1'b1))) begin + txn_ph = 1; // ADDR + + txn = axi_transaction::type_id::create("txn"); + + // Capture transaction details here + txn.txn_type = AXI_WRITE; + txn.addr = mon_if.AWADDR; + txn.length = mon_if.AWLEN; end end - end - // if (agent_type == MANAGER) begin - // do_manager_monitor(); - // end else if (agent_type == SUBORDINATE) begin - // do_subordinate_monitor(); - // end else begin - // `uvm_fatal("AXI_MONITOR", "Unknown agent type") - // end - endtask + // Data phase - may overlap with address phase + if (txn_ph inside {0, 1}) begin + if (((mon_if.WREADY != prev_wready) || (mon_if.WVALID != prev_wvalid)) + && ((mon_if.WREADY === 1'b1) && (mon_if.WVALID === 1'b1))) begin + txn_ph = 2; // DATA - // -------------------------------------------------- - // Monitor logic for MANAGER agent - virtual task do_manager_monitor(); - // Placeholder for actual monitoring logic - // This would typically involve sampling signals and creating transactions - forever begin - axi_transaction txn; - @(posedge m_if.ACLK); + // Capture transaction details here + txn.data = mon_if.WDATA; + txn.strb = mon_if.WSTRB; + end + end - txn = axi_transaction::type_id::create("txn"); + // Response phase - must come after address and data phases + if (txn_ph == 2) begin + if (((mon_if.BREADY != prev_bready) || (mon_if.BVALID != prev_bvalid)) + && ((mon_if.BREADY === 1'b1) && (mon_if.BVALID === 1'b1))) begin + txn_ph = 2; // DATA - // Capture transaction details here + // Capture transaction details here + txn.resp = mon_if.WSTRB; - ap.write(txn); - write_transaction_to_file(txn); + ap.write(txn); + write_transaction_to_file(txn); + end + end + + // Update previous values + prev_awready = mon_if.AWREADY; + prev_awvalid = mon_if.AWVALID; + prev_wready = mon_if.WREADY; + prev_wvalid = mon_if.WVALID; + prev_bready = mon_if.BREADY; + prev_bvalid = mon_if.BVALID; end endtask // -------------------------------------------------- - // Monitor logic for SUBORDINATE agent - virtual task do_subordinate_monitor(); - // Placeholder for actual monitoring logic - // This would typically involve sampling signals and creating transactions + // Monitor logic for Read transactions + virtual task monitor_read(); + bit prev_arready, prev_arvalid; + bit prev_rready, prev_rvalid; + axi_transaction txn; + int txn_ph = 0; + forever begin - axi_transaction txn; - @(posedge s_if.ACLK); + @(posedge mon_if.ACLK); - txn = axi_transaction::type_id::create("txn"); + // Address phase + if (txn_ph == 0) begin + if (((mon_if.ARREADY != prev_arready) || (mon_if.ARVALID != prev_arvalid)) + && ((mon_if.ARREADY === 1'b1) && (mon_if.ARVALID === 1'b1))) begin + txn_ph = 1; - // Capture transaction details here + txn = axi_transaction::type_id::create("txn"); - ap.write(txn); - write_transaction_to_file(txn); + // Capture transaction details here + txn.txn_type = AXI_READ; + txn.addr = mon_if.ARADDR; + txn.length = mon_if.ARLEN; + end + end + + // Data/response phase - must come after address phase + if (txn_ph == 1) begin + if (((mon_if.RREADY != prev_rready) || (mon_if.RVALID != prev_rvalid)) + && ((mon_if.RREADY === 1'b1) && (mon_if.RVALID === 1'b1))) begin + txn_ph = 0; + + // Capture transaction details here + txn.data = mon_if.RDATA; + + ap.write(txn); + write_transaction_to_file(txn); + end + end + + if (((mon_if.ARREADY != prev_arready) || (mon_if.ARVALID != prev_arvalid)) + && ((mon_if.ARREADY === 1'b1) && (mon_if.ARVALID === 1'b1))) begin + axi_transaction txn; + + txn = axi_transaction::type_id::create("txn"); + + // Capture transaction details here + txn.txn_type = AXI_READ; + txn.addr = mon_if.ARADDR; + txn.length = mon_if.ARLEN; + + ap.write(txn); + write_transaction_to_file(txn); + end + + // Update previous values + prev_arready = mon_if.ARREADY; + prev_arvalid = mon_if.ARVALID; + prev_rready = mon_if.RREADY; + prev_rvalid = mon_if.RVALID; end endtask diff --git a/src/axi/axi_subordinate_driver.sv b/src/axi/axi_subordinate_driver.sv index 166fec4..cacac1d 100644 --- a/src/axi/axi_subordinate_driver.sv +++ b/src/axi/axi_subordinate_driver.sv @@ -18,12 +18,14 @@ class axi_subordinate_driver extends axi_driver; endfunction // -------------------------------------------------- - virtual task run_phase(uvm_phase phase); - `uvm_info("run_phase", $sformatf("Running AXI subordinate driver: %s", + virtual task drive_axi(uvm_phase phase); + super.drive_axi(phase); + + `uvm_info("drive_axi", $sformatf("Running AXI subordinate driver: %s", get_full_name()), UVM_LOW) if (s_if == null) begin - `uvm_error("run_phase", "subordinate interface is null, cannot respond to transactions") + `uvm_error("drive_axi", "subordinate interface is null, cannot respond to transactions") end forever begin @@ -118,6 +120,9 @@ class axi_subordinate_driver extends axi_driver; s_if.BVALID = 0; `uvm_info("respond_to_write_txn", $sformatf("[%s] Response phase done", req.show_tag()), UVM_LOW) + + write_transaction_to_file(req); + write_request_sem.put(); endtask @@ -177,6 +182,8 @@ class axi_subordinate_driver extends axi_driver; `uvm_info("respond_to_read_txn", $sformatf("[%s] Response phase done", req.show_tag()), UVM_LOW) + write_transaction_to_file(req); + read_request_sem.put(); endtask endclass : axi_subordinate_driver diff --git a/src/axi/axi_transaction.sv b/src/axi/axi_transaction.sv index 60058ec..0253500 100644 --- a/src/axi/axi_transaction.sv +++ b/src/axi/axi_transaction.sv @@ -5,6 +5,7 @@ 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 [`BRESP_WIDTH-1:0] resp; // Response code rand bit [2:0] size; // Size rand bit [7:0] length; // Length @@ -13,6 +14,7 @@ class axi_transaction extends uvm_sequence_item; `uvm_field_int(addr, UVM_DEFAULT) `uvm_field_int(data, UVM_DEFAULT) `uvm_field_int(strb, UVM_DEFAULT) + `uvm_field_int(resp, UVM_DEFAULT) `uvm_field_int(size, UVM_DEFAULT) `uvm_field_int(length, UVM_DEFAULT) `uvm_object_utils_end @@ -58,6 +60,7 @@ class axi_transaction extends uvm_sequence_item; copy.addr = this.addr; copy.data = this.data; copy.strb = this.strb; + copy.resp = this.resp; copy.size = this.size; copy.length = this.length; return copy; @@ -75,5 +78,17 @@ class axi_transaction extends uvm_sequence_item; (this.length == other.length); endfunction + // Tracker print line + static function string tracker_line_hdr(); + return $sformatf("%7s %10s %16s %16s %4s %3s %3s", + "TIME", "TYPE", "ADDR", "DATA", "STRB", "SZ", "LEN"); + endfunction + + function string tracker_line(); + return $sformatf("%7t %10s %16h %16h %4h %3d %3d", + $time, this.txn_type.name(), this.addr, + this.data, this.strb, this.size, this.length); + endfunction + endclass : axi_transaction diff --git a/tb/tb_env.sv b/tb/tb_env.sv index 54882a2..5465ac2 100644 --- a/tb/tb_env.sv +++ b/tb/tb_env.sv @@ -20,6 +20,8 @@ class tb_env extends uvm_env; // Set agent types in AXI agents axi_m.set_agent_type(MANAGER); axi_s.set_agent_type(SUBORDINATE); + + set_up_reporting(); endfunction // ------------------------------------------------------------ @@ -33,6 +35,14 @@ class tb_env extends uvm_env; // Add any specific report phase tasks here endfunction + // ------------------------------------------------------------ + function void set_up_reporting(); + uvm_coreservice_t cs = uvm_coreservice_t::get(); + uvm_tree_printer tree_printer = new(); + + cs.set_default_printer(tree_printer); + endfunction + // ------------------------------------------------------------ function uvm_sequencer_base get_axi_m_sequencer(); return axi_m.sequencer;