From 728d2a0f6d8a1c6df1c8bfd3c2c009c5d05e4cd2 Mon Sep 17 00:00:00 2001 From: Mahesh Asolkar Date: Sun, 24 Aug 2025 22:59:43 -0700 Subject: [PATCH] Added agent config and random transaction delays --- src/axi/axi_agent.sv | 20 +++++++-- src/axi/axi_agent_config.sv | 67 +++++++++++++++++++++++++++++++ src/axi/axi_driver.sv | 14 ++++++- src/axi/axi_manager_driver.sv | 8 +++- src/axi/axi_pkg.sv | 1 + src/axi/axi_subordinate_driver.sv | 16 +++++++- 6 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 src/axi/axi_agent_config.sv diff --git a/src/axi/axi_agent.sv b/src/axi/axi_agent.sv index 541b66c..d122c60 100644 --- a/src/axi/axi_agent.sv +++ b/src/axi/axi_agent.sv @@ -10,10 +10,12 @@ class axi_agent extends uvm_agent; virtual `AXI_INTF.SUBORDINATE s_if; virtual `AXI_INTF mon_if; + // Configuration object + rand axi_agent_config cfg; // Declare the sequencer and driver - axi_sequencer sequencer; - axi_driver driver; - axi_monitor monitor; + axi_sequencer sequencer; + axi_driver driver; + axi_monitor monitor; `uvm_component_utils_begin(axi_agent) `uvm_field_enum(axi_agent_type_t, agent_type, UVM_DEFAULT) @@ -32,9 +34,21 @@ class axi_agent extends uvm_agent; `uvm_info("set_agent_type", $sformatf("Agent type set to %s", agent_type.name()), UVM_LOW) endfunction + // -------------------------------------------------- + function axi_agent_config get_cfg(); + return cfg; + endfunction + // -------------------------------------------------- // Build phase virtual function void build_phase(uvm_phase phase); + cfg = axi_agent_config::type_id::create("cfg"); + if (!cfg.randomize()) begin + `uvm_fatal("build_phase", "Randomization of cfg failed") + end else begin + `uvm_info("build_phase", $sformatf("%s randomized:\n%s", cfg.get_full_name(), cfg.sprint()), UVM_LOW) + end + sequencer = axi_sequencer::type_id::create("sequencer", this); if (agent_type == MANAGER) begin // TODO: Additional variable md should not be needed. We should diff --git a/src/axi/axi_agent_config.sv b/src/axi/axi_agent_config.sv new file mode 100644 index 0000000..47fc1e6 --- /dev/null +++ b/src/axi/axi_agent_config.sv @@ -0,0 +1,67 @@ +// Configuration class to hold options used in the agent. This contains +// options for anything in side the agent +class axi_agent_config extends uvm_object; + + /// Minimum value of pre_transaction_delay + int pre_transaction_delay_min = 0; + /// Maximum value of pre_transaction_delay + int pre_transaction_delay_max = 20; + + /// Minimum value of pre_response_delay + int pre_response_delay_min = 1; + /// Maximum value of pre_response_delay + int pre_response_delay_max = 20; + + `uvm_object_utils_begin(axi_agent_config) + `uvm_field_int(pre_transaction_delay_min, UVM_DEFAULT) + `uvm_field_int(pre_transaction_delay_max, UVM_DEFAULT) + `uvm_field_int(pre_response_delay_min, UVM_DEFAULT) + `uvm_field_int(pre_response_delay_max, UVM_DEFAULT) + `uvm_object_utils_end + + // -------------------------------------------------- + function new(string name = "axi_agent_config"); + super.new(name); + endfunction + + // -------------------------------------------------- + function post_randomize(); + `uvm_info("post_randomzie", $sformatf("AXI Agent Config:\n%s", this.sprint()), UVM_LOW) + endfunction + + // TODO: Using $urandom_range() since Verilator does not have support for + // std::randomize() with {} + // -------------------------------------------------- + function int get_pre_transaction_delay(); + int dly = 0; + // if (!std::randomzie(dly) with { + // dly dist { + // pre_transaction_delay_min :/ 4, + // pre_transaction_delay_max :/ 4, + // [pre_transaction_delay_min + // :pre_transaction_delay_max] :/ 2 + // }; + // }) begin + // `uvm_error("get_pre_transaction_delay", "Randomization failed") + // end + dly = $urandom_range(pre_transaction_delay_max, pre_transaction_delay_min); + return dly; + endfunction + + // -------------------------------------------------- + function int get_pre_response_delay(); + int dly = 0; + // if (!std::randomzie(dly) with { + // dly dist { + // pre_response_delay_min :/ 4, + // pre_response_delay_max :/ 4, + // [pre_response_delay_min + // :pre_response_delay_max] :/ 2 + // }; + // }) begin + // `uvm_error("get_pre_response_delay", "Randomization failed") + // end + dly = $urandom_range(pre_response_delay_max, pre_response_delay_min); + return dly; + endfunction +endclass diff --git a/src/axi/axi_driver.sv b/src/axi/axi_driver.sv index 3e7cc18..ed37835 100644 --- a/src/axi/axi_driver.sv +++ b/src/axi/axi_driver.sv @@ -1,10 +1,13 @@ // ---------------------------------------------------------------------- // Driver for AXI transactions // ---------------------------------------------------------------------- +typedef axi_agent; + class axi_driver extends uvm_driver; // #(axi_transaction); virtual `AXI_INTF.MANAGER m_if; virtual `AXI_INTF.SUBORDINATE s_if; axi_agent_type_t agent_type; + axi_agent_config cfg; `uvm_component_utils(axi_driver) @@ -24,9 +27,18 @@ class axi_driver extends uvm_driver; // #(axi_transaction); // -------------------------------------------------- // Set virtual interfaces function void set_virtual_interfaces(virtual `AXI_INTF.MANAGER m_if_p, - virtual `AXI_INTF.SUBORDINATE s_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 + + // -------------------------------------------------- + virtual function void end_of_elaboration_phase(uvm_phase phase); + axi_agent agt; + + if ($cast(agt, get_parent())) begin + cfg = agt.get_cfg(); + end + endfunction endclass : axi_driver diff --git a/src/axi/axi_manager_driver.sv b/src/axi/axi_manager_driver.sv index 0c1335d..6ff7dff 100644 --- a/src/axi/axi_manager_driver.sv +++ b/src/axi/axi_manager_driver.sv @@ -53,8 +53,14 @@ 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) + + // Pre transaction delay + `uvm_info("drive_txn", $sformatf("Waiting pre_transaction_delay = %0d cycles", + dly), UVM_LOW) + repeat(dly) @(posedge m_if.ACLK); + if (req.txn_type == AXI_WRITE) begin drive_write_txn(req); end else if (req.txn_type == AXI_READ) begin diff --git a/src/axi/axi_pkg.sv b/src/axi/axi_pkg.sv index d25a2cf..563f8b1 100644 --- a/src/axi/axi_pkg.sv +++ b/src/axi/axi_pkg.sv @@ -5,6 +5,7 @@ package axi_pkg; `include "uvm_macros.svh" // UVM data items + `include "axi_agent_config.sv" `include "axi_transaction.sv" // UVM components diff --git a/src/axi/axi_subordinate_driver.sv b/src/axi/axi_subordinate_driver.sv index 0a82125..66c63a9 100644 --- a/src/axi/axi_subordinate_driver.sv +++ b/src/axi/axi_subordinate_driver.sv @@ -41,6 +41,7 @@ class axi_subordinate_driver extends axi_driver; // ------------------------------------------------------------ task respond_to_write_txn(); axi_transaction req; + int dly = cfg.get_pre_response_delay(); req = axi_transaction::type_id::create("req"); req.txn_type = AXI_WRITE; @@ -48,25 +49,36 @@ class axi_subordinate_driver extends axi_driver; req.data = s_if.WDATA; req.strb = s_if.WSTRB; - @(posedge s_if.ACLK); + // Pre response delay + `uvm_info("drive_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) s_if.AWREADY = 1'b1; + @(posedge s_if.ACLK); + s_if.AWREADY = 1'b0; endtask // ------------------------------------------------------------ task respond_to_read_txn(); axi_transaction req; + int dly = cfg.get_pre_response_delay(); req = axi_transaction::type_id::create("req"); req.txn_type = AXI_READ; req.addr = s_if.ARADDR; - @(posedge s_if.ACLK); + // Pre response delay + `uvm_info("respond_to_write_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) s_if.ARREADY = 1'b1; + @(posedge s_if.ACLK); + s_if.ARREADY = 1'b0; endtask endclass : axi_subordinate_driver