[dv] Support Multiple EDN Interfaces in OpenTitan

This commit includes changes in CIP to support multiple EDN IFs with
setting NUM_EDN parameter in *env_pkg.sv and num_edn in *env_cfg.sv
Also includes changes in:
- OTBN testbench to allow connecting two EDN interfaces
- In order to support EDN IF changes, DV enviroments of:
  - AES, Key Manager, KMAC, OTP Controller, Alert Handler

Signed-off-by: Canberk Topal <ctopal@lowrisc.org>
diff --git a/hw/dv/sv/cip_lib/cip_base_env.sv b/hw/dv/sv/cip_lib/cip_base_env.sv
index 5c245aa..6d75161 100644
--- a/hw/dv/sv/cip_lib/cip_base_env.sv
+++ b/hw/dv/sv/cip_lib/cip_base_env.sv
@@ -13,7 +13,7 @@
   tl_agent                                           m_tl_agents[string];
   tl_reg_adapter #(tl_seq_item)                      m_tl_reg_adapters[string];
   alert_esc_agent                                    m_alert_agent[string];
-  push_pull_agent#(.DeviceDataWidth(EDN_DATA_WIDTH)) m_edn_pull_agent;
+  push_pull_agent#(.DeviceDataWidth(EDN_DATA_WIDTH)) m_edn_pull_agent[];
 
   `uvm_component_new
 
@@ -63,13 +63,16 @@
     end
 
     // Create and configure the EDN agent if available.
-    if (cfg.has_edn) begin
-      m_edn_pull_agent = push_pull_agent#(.DeviceDataWidth(EDN_DATA_WIDTH))::type_id::create(
-                         "m_edn_pull_agent", this);
-      uvm_config_db#(push_pull_agent_cfg#(.DeviceDataWidth(EDN_DATA_WIDTH)))::set(
-                     this, "m_edn_pull_agent", "cfg", cfg.m_edn_pull_agent_cfg);
-      cfg.m_edn_pull_agent_cfg.en_cov = cfg.en_cov;
-
+    if (cfg.num_edn) begin
+      m_edn_pull_agent = new[cfg.num_edn];
+      foreach (m_edn_pull_agent[i]) begin
+        string agent_name = $sformatf("m_edn_pull_agent[%0d]", i);
+        m_edn_pull_agent[i] = push_pull_agent#(.DeviceDataWidth(EDN_DATA_WIDTH))::
+                              type_id::create(agent_name, this);
+        uvm_config_db#(push_pull_agent_cfg#(.DeviceDataWidth(EDN_DATA_WIDTH)))::
+                      set(this, agent_name, "cfg", cfg.m_edn_pull_agent_cfg[i]);
+        cfg.m_edn_pull_agent_cfg[i].en_cov = cfg.en_cov;
+      end
       if (!uvm_config_db#(virtual clk_rst_if)::get(this, "", "edn_clk_rst_vif",
           cfg.edn_clk_rst_vif)) begin
         `uvm_fatal(get_full_name(), "failed to get edn_clk_rst_vif from uvm_config_db")
@@ -94,7 +97,9 @@
         cfg.m_alert_agent_cfg[i].alert_delay_min = 0;
         cfg.m_alert_agent_cfg[i].alert_delay_max = 0;
       end
-      if (cfg.has_edn) cfg.m_edn_pull_agent_cfg.zero_delays = 1;
+      foreach (cfg.m_edn_pull_agent_cfg[i]) begin
+        cfg.m_edn_pull_agent_cfg[i].zero_delays = 1;
+      end
     end
 
     // Set the synchronise_ports flag on each of the TL agents configs
@@ -131,9 +136,8 @@
       end
     end
 
-    if (cfg.has_edn) begin
-      virtual_sequencer.edn_pull_sequencer_h = m_edn_pull_agent.sequencer;
-      m_edn_pull_agent.monitor.analysis_port.connect(scoreboard.edn_fifo.analysis_export);
+    foreach (m_edn_pull_agent[i]) begin
+      m_edn_pull_agent[i].monitor.analysis_port.connect(scoreboard.edn_fifos[i].analysis_export);
     end
   endfunction
 
diff --git a/hw/dv/sv/cip_lib/cip_base_env_cfg.sv b/hw/dv/sv/cip_lib/cip_base_env_cfg.sv
index dc9778a..4bd7254 100644
--- a/hw/dv/sv/cip_lib/cip_base_env_cfg.sv
+++ b/hw/dv/sv/cip_lib/cip_base_env_cfg.sv
@@ -30,7 +30,7 @@
   bit                 en_tl_intg_gen = 1;
 
   alert_esc_agent_cfg m_alert_agent_cfg[string];
-  push_pull_agent_cfg#(.DeviceDataWidth(EDN_DATA_WIDTH)) m_edn_pull_agent_cfg;
+  push_pull_agent_cfg#(.DeviceDataWidth(EDN_DATA_WIDTH)) m_edn_pull_agent_cfg[];
 
   // EDN clk freq setting, if EDN is present.
   rand uint edn_clk_freq_mhz;
@@ -46,11 +46,10 @@
   // TODO: enable random drive devmode once design supports
   bit  has_devmode = 1;
   bit  en_devmode = 1;
-  bit  has_edn = 0;
   bit  has_shadowed_regs = 0;
 
   uint num_interrupts;
-
+  uint num_edn;
   // if module has alerts, this list_of_alerts needs to override in cfg before super.initialize()
   // function is called
   string list_of_alerts[] = {};
@@ -119,13 +118,14 @@
       end
     end
 
-    if (has_edn) begin
-      m_edn_pull_agent_cfg = push_pull_agent_cfg#(.DeviceDataWidth(EDN_DATA_WIDTH))::type_id::
-                             create("m_edn_pull_agent_cfg");
-      `DV_CHECK_RANDOMIZE_FATAL(m_edn_pull_agent_cfg)
-      m_edn_pull_agent_cfg.agent_type = PullAgent;
-      m_edn_pull_agent_cfg.if_mode    = Device;
-      m_edn_pull_agent_cfg.hold_d_data_until_next_req = 1;
+    m_edn_pull_agent_cfg = new[num_edn];
+    foreach (m_edn_pull_agent_cfg[i]) begin
+      m_edn_pull_agent_cfg[i] = push_pull_agent_cfg#(.DeviceDataWidth(EDN_DATA_WIDTH))::type_id::
+                                 create("m_edn_pull_agent_cfg");
+      `DV_CHECK_RANDOMIZE_FATAL(m_edn_pull_agent_cfg[i])
+      m_edn_pull_agent_cfg[i].agent_type = PullAgent;
+      m_edn_pull_agent_cfg[i].if_mode    = Device;
+      m_edn_pull_agent_cfg[i].hold_d_data_until_next_req = 1;
     end
   endfunction
 
diff --git a/hw/dv/sv/cip_lib/cip_base_env_cov.sv b/hw/dv/sv/cip_lib/cip_base_env_cov.sv
index 6b92c81..b49bec7 100644
--- a/hw/dv/sv/cip_lib/cip_base_env_cov.sv
+++ b/hw/dv/sv/cip_lib/cip_base_env_cov.sv
@@ -210,7 +210,7 @@
       intr_test_cg = new(cfg.num_interrupts);
       intr_pins_cg = new(cfg.num_interrupts);
     end
-    if (cfg.has_edn) resets_cg = new("dut_and_edn_rsts");
+    if (cfg.num_edn) resets_cg = new("dut_and_edn_rsts");
   endfunction
 
 endclass
diff --git a/hw/dv/sv/cip_lib/cip_base_scoreboard.sv b/hw/dv/sv/cip_lib/cip_base_scoreboard.sv
index dd6cb2a..1c3341e 100644
--- a/hw/dv/sv/cip_lib/cip_base_scoreboard.sv
+++ b/hw/dv/sv/cip_lib/cip_base_scoreboard.sv
@@ -17,7 +17,7 @@
   uvm_tlm_analysis_fifo #(alert_esc_seq_item) alert_fifos[string];
 
   // EDN fifo
-  uvm_tlm_analysis_fifo #(push_pull_item#(.DeviceDataWidth(EDN_DATA_WIDTH))) edn_fifo;
+  uvm_tlm_analysis_fifo #(push_pull_item#(.DeviceDataWidth(EDN_DATA_WIDTH))) edn_fifos[];
 
   mem_model#() exp_mem[string];
 
@@ -46,7 +46,8 @@
       string alert_name = cfg.list_of_alerts[i];
       alert_fifos[alert_name] = new($sformatf("alert_fifo[%s]", alert_name), this);
     end
-    if (cfg.has_edn) edn_fifo = new("edn_fifo", this);
+    edn_fifos = new[cfg.num_edn];
+    foreach (cfg.m_edn_pull_agent_cfg[i]) edn_fifos[i] = new($sformatf("edn_fifos[%0d]", i), this);
     foreach (cfg.m_tl_agent_cfgs[i]) begin
       exp_mem[i] = mem_model#()::type_id::create({"exp_mem_", i}, this);
     end
@@ -462,7 +463,7 @@
     super.reset(kind);
     foreach (tl_a_chan_fifos[i]) tl_a_chan_fifos[i].flush();
     foreach (tl_d_chan_fifos[i]) tl_d_chan_fifos[i].flush();
-    if (cfg.has_edn) edn_fifo.flush();
+    foreach (edn_fifos[i]) edn_fifos[i].flush();
     foreach(cfg.list_of_alerts[i]) begin
       alert_fifos[cfg.list_of_alerts[i]].flush();
       exp_alert[cfg.list_of_alerts[i]]             = 0;
@@ -473,7 +474,7 @@
   endfunction
 
   virtual task sample_resets();
-    if (cfg.has_edn && cfg.en_cov) begin
+    if (cfg.num_edn && cfg.en_cov) begin
       // Discard the first resets
       wait(cfg.clk_rst_vif.rst_n && cfg.edn_clk_rst_vif.rst_n);
       forever begin
diff --git a/hw/dv/sv/cip_lib/cip_macros.svh b/hw/dv/sv/cip_lib/cip_macros.svh
index f9918b7..d603469 100644
--- a/hw/dv/sv/cip_lib/cip_macros.svh
+++ b/hw/dv/sv/cip_lib/cip_macros.svh
@@ -32,13 +32,18 @@
   wire edn_rst_n; \
   wire edn_clk; \
   clk_rst_if edn_clk_rst_if(.clk(edn_clk), .rst_n(edn_rst_n)); \
-  push_pull_if #(.DeviceDataWidth(cip_base_pkg::EDN_DATA_WIDTH)) edn_if(.clk(edn_clk), \
-                                                                        .rst_n(edn_rst_n)); \
+  push_pull_if #(.DeviceDataWidth(cip_base_pkg::EDN_DATA_WIDTH)) edn_if[NUM_EDN]( \
+  .clk(edn_clk), \
+  .rst_n(edn_rst_n)); \
   initial begin \
     edn_clk_rst_if.set_active(); \
     uvm_config_db#(virtual clk_rst_if)::set(null, "*.env", "edn_clk_rst_vif", edn_clk_rst_if); \
-    uvm_config_db#(virtual push_pull_if#(.DeviceDataWidth(cip_base_pkg::EDN_DATA_WIDTH)))::set \
-                   (null, "*env.m_edn_pull_agent*", "vif", edn_if); \
+  end \
+  for (genvar i = 0; i < NUM_EDN; i++) begin : connect_edn_pins \
+    initial begin \
+    uvm_config_db#(virtual push_pull_if#(.DeviceDataWidth(cip_base_pkg::EDN_DATA_WIDTH))):: \
+                           set(null, $sformatf("*env.m_edn_pull_agent[%0d]", i), "vif", edn_if[i]); \
+    end \
   end
 `endif
 
diff --git a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
index 4420962..34275ca 100644
--- a/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
+++ b/hw/dv/sv/cip_lib/seq_lib/cip_base_vseq.sv
@@ -138,23 +138,23 @@
   virtual task apply_reset(string kind = "HARD");
     if (kind == "HARD") begin
       fork
-        if (cfg.has_edn) apply_edn_reset(kind);
+        if (cfg.num_edn) apply_edn_reset(kind);
         super.apply_reset(kind);
       join
     end
   endtask
 
   virtual task apply_edn_reset(string kind = "HARD");
-    if (cfg.has_edn && kind == "HARD") cfg.edn_clk_rst_vif.apply_reset();
+    if (cfg.num_edn && kind == "HARD") cfg.edn_clk_rst_vif.apply_reset();
   endtask
 
   virtual task apply_resets_concurrently(int reset_duration_ps = 0);
-    if (cfg.has_edn) begin
+    if (cfg.num_edn) begin
       cfg.edn_clk_rst_vif.drive_rst_pin(0);
       reset_duration_ps = max2(reset_duration_ps, cfg.edn_clk_rst_vif.clk_period_ps);
     end
     super.apply_resets_concurrently(reset_duration_ps);
-    if (cfg.has_edn) cfg.edn_clk_rst_vif.drive_rst_pin(1);
+    if (cfg.num_edn) cfg.edn_clk_rst_vif.drive_rst_pin(1);
   endtask
 
   // tl_access task: does a single BUS_DW-bit write or read transaction to the specified address
diff --git a/hw/ip/aes/dv/env/aes_env_cfg.sv b/hw/ip/aes/dv/env/aes_env_cfg.sv
index 1e19825..9bae1cd 100644
--- a/hw/ip/aes/dv/env/aes_env_cfg.sv
+++ b/hw/ip/aes/dv/env/aes_env_cfg.sv
@@ -179,7 +179,7 @@
 
   virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1);
     list_of_alerts = aes_env_pkg::LIST_OF_ALERTS;
-    has_edn = 1;
+    num_edn = 1;
     has_shadowed_regs = 1;
     super.initialize(csr_base_addr);
     tl_intg_alert_fields[ral.status.alert_fatal_fault] = 1;
diff --git a/hw/ip/aes/dv/env/aes_env_pkg.sv b/hw/ip/aes/dv/env/aes_env_pkg.sv
index 90d300d..8051f53 100644
--- a/hw/ip/aes/dv/env/aes_env_pkg.sv
+++ b/hw/ip/aes/dv/env/aes_env_pkg.sv
@@ -25,6 +25,7 @@
   // parameters
   parameter string LIST_OF_ALERTS[] = {"recov_ctrl_update_err", "fatal_fault"};
   parameter uint NUM_ALERTS = 2;
+  parameter uint NUM_EDN = 1;
 
   typedef enum int { AES_CFG=0, AES_DATA=1, AES_ERR_INJ=2 } aes_item_type_e;
   typedef enum bit { Flip_bits = 0, Pull_reset = 1 } flip_rst_e;
diff --git a/hw/ip/aes/dv/tb/tb.sv b/hw/ip/aes/dv/tb/tb.sv
index 82d44e4..e6be31f 100644
--- a/hw/ip/aes/dv/tb/tb.sv
+++ b/hw/ip/aes/dv/tb/tb.sv
@@ -40,23 +40,23 @@
     .Masking  ( 0                    ),
     .SBoxImpl ( aes_pkg::SBoxImplLut )
   ) dut (
-    .clk_i            ( clk                           ),
-    .rst_ni           ( rst_n                         ),
-    .rst_shadowed_ni  ( rst_shadowed_n                ),
+    .clk_i            ( clk                               ),
+    .rst_ni           ( rst_n                             ),
+    .rst_shadowed_ni  ( rst_shadowed_n                    ),
 
-    .idle_o           (                               ),
-    .lc_escalate_en_i ( lc_ctrl_pkg::Off              ),
-    .clk_edn_i        ( edn_clk                       ),
-    .rst_edn_ni       ( edn_rst_n                     ),
-    .edn_o            ( edn_if.req                    ),
-    .edn_i            ( {edn_if.ack, edn_if.d_data}   ),
-    .keymgr_key_i     ( keymgr_key                    ),
+    .idle_o           (                                   ),
+    .lc_escalate_en_i ( lc_ctrl_pkg::Off                  ),
+    .clk_edn_i        ( edn_clk                           ),
+    .rst_edn_ni       ( edn_rst_n                         ),
+    .edn_o            ( edn_if[0].req                     ),
+    .edn_i            ( {edn_if[0].ack, edn_if[0].d_data} ),
+    .keymgr_key_i     ( keymgr_key                        ),
 
-    .tl_i             ( tl_if.h2d                     ),
-    .tl_o             ( tl_if.d2h                     ),
+    .tl_i             ( tl_if.h2d                         ),
+    .tl_o             ( tl_if.d2h                         ),
 
-    .alert_rx_i       ( alert_rx                      ),
-    .alert_tx_o       ( alert_tx                      )
+    .alert_rx_i       ( alert_rx                          ),
+    .alert_tx_o       ( alert_tx                          )
   );
 
   initial begin
diff --git a/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv b/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv
index e66587b..2c42fa7 100644
--- a/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv
+++ b/hw/ip/keymgr/dv/env/keymgr_env_cfg.sv
@@ -17,7 +17,7 @@
   virtual function void initialize(bit [31:0] csr_base_addr = '1);
     list_of_alerts = keymgr_env_pkg::LIST_OF_ALERTS;
     tl_intg_alert_name = "fatal_fault_err";
-    has_edn = 1;
+    num_edn = 1;
     has_shadowed_regs = 1;
     super.initialize(csr_base_addr);
     tl_intg_alert_fields[ral.fault_status.regfile_intg] = 1;
@@ -29,7 +29,7 @@
 
     // keymgr requests entropy periodically, if seq is done, don't need to add any delay due to
     // activity from EDN interface
-    m_edn_pull_agent_cfg.ok_to_end_delay_ns = 0;
+    m_edn_pull_agent_cfg[0].ok_to_end_delay_ns = 0;
 
     // set num_interrupts & num_alerts
     begin
diff --git a/hw/ip/keymgr/dv/env/keymgr_env_pkg.sv b/hw/ip/keymgr/dv/env/keymgr_env_pkg.sv
index cdbf8cc..2e9963e 100644
--- a/hw/ip/keymgr/dv/env/keymgr_env_pkg.sv
+++ b/hw/ip/keymgr/dv/env/keymgr_env_pkg.sv
@@ -23,6 +23,7 @@
   // parameters and types
   parameter string LIST_OF_ALERTS[] = {"fatal_fault_err", "recov_operation_err"};
   parameter uint NUM_ALERTS = 2;
+  parameter uint NUM_EDN = 1;
   parameter uint DIGEST_SHARE_WORD_NUM = keymgr_pkg::KeyWidth / TL_DW;
 
   typedef virtual keymgr_if keymgr_vif;
diff --git a/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv b/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv
index 6048680..4335311 100644
--- a/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv
+++ b/hw/ip/keymgr/dv/env/keymgr_scoreboard.sv
@@ -567,7 +567,7 @@
                                                     current_cdi);
 
                   // expect no EDN request is issued. After this advance is done, will have 2 reqs
-                  `DV_CHECK_EQ(edn_fifo.is_empty(), 1)
+                  `DV_CHECK_EQ(edn_fifos[0].is_empty(), 1)
                 end else begin // !OpAdvance
                   current_op_status = keymgr_pkg::OpDoneFail;
                   // No KDF issued, done interrupt/alert is triggered in next cycle
@@ -667,7 +667,7 @@
 
               // keymgr should request 2 EDN data during advancing from StReset
               // function `used` returns the number of entries put into the FIFO
-              `DV_CHECK_EQ(edn_fifo.used(), 2)
+              `DV_CHECK_EQ(edn_fifos[0].used(), 2)
             end
           end else begin
             `DV_CHECK_EQ(item.d_data, addr_phase_op_status)
diff --git a/hw/ip/keymgr/dv/tb.sv b/hw/ip/keymgr/dv/tb.sv
index c74282b..63c068c 100644
--- a/hw/ip/keymgr/dv/tb.sv
+++ b/hw/ip/keymgr/dv/tb.sv
@@ -35,10 +35,10 @@
   // edn_clk, edn_rst_n and edn_if are defined and driven in below macro
   `DV_EDN_IF_CONNECT
 
-  assign keymgr_if.edn_clk   = edn_if.clk;
-  assign keymgr_if.edn_rst_n = edn_if.rst_n;
-  assign keymgr_if.edn_req   = edn_if.req;
-  assign keymgr_if.edn_ack   = edn_if.ack;
+  assign keymgr_if.edn_clk   = edn_if[0].clk;
+  assign keymgr_if.edn_rst_n = edn_if[0].rst_n;
+  assign keymgr_if.edn_req   = edn_if[0].req;
+  assign keymgr_if.edn_ack   = edn_if[0].ack;
 
   // dut
   keymgr dut (
@@ -58,8 +58,8 @@
     .otp_key_i            (keymgr_if.otp_key),
     .otp_device_id_i      (keymgr_if.otp_device_id),
     .rom_digest_i         (keymgr_if.rom_digest),
-    .edn_o                (edn_if.req),
-    .edn_i                ({edn_if.ack, edn_if.d_data}),
+    .edn_o                (edn_if[0].req),
+    .edn_i                ({edn_if[0].ack, edn_if[0].d_data}),
     .flash_i              (keymgr_if.flash),
     .intr_op_done_o       (interrupts[0]),
     .alert_rx_i           (alert_rx   ),
diff --git a/hw/ip/kmac/dv/env/kmac_env_cfg.sv b/hw/ip/kmac/dv/env/kmac_env_cfg.sv
index 26aadf4..fdbfcd5 100644
--- a/hw/ip/kmac/dv/env/kmac_env_cfg.sv
+++ b/hw/ip/kmac/dv/env/kmac_env_cfg.sv
@@ -24,7 +24,7 @@
   `uvm_object_new
 
   virtual function void initialize(bit [31:0] csr_base_addr = '1);
-    has_edn = 1;
+    num_edn = 1;
     list_of_alerts = kmac_env_pkg::LIST_OF_ALERTS;
     super.initialize(csr_base_addr);
 
diff --git a/hw/ip/kmac/dv/env/kmac_env_pkg.sv b/hw/ip/kmac/dv/env/kmac_env_pkg.sv
index 2e940cd..cdc68aa 100644
--- a/hw/ip/kmac/dv/env/kmac_env_pkg.sv
+++ b/hw/ip/kmac/dv/env/kmac_env_pkg.sv
@@ -66,6 +66,8 @@
   parameter uint NUM_ALERTS = 1;
   parameter string LIST_OF_ALERTS[] = {"fatal_fault"};
 
+  parameter uint NUM_EDN = 1;
+
   /////////////////////////////
   // Timing Model Parameters //
   /////////////////////////////
diff --git a/hw/ip/kmac/dv/env/kmac_scoreboard.sv b/hw/ip/kmac/dv/env/kmac_scoreboard.sv
index af20c21..436824e 100644
--- a/hw/ip/kmac/dv/env/kmac_scoreboard.sv
+++ b/hw/ip/kmac/dv/env/kmac_scoreboard.sv
@@ -268,7 +268,7 @@
             // of the "host", in this case KMAC needs 64 bits of entropy so prim_edn_req
             // performs 2 fetches from the EDN network.
             repeat (kmac_pkg::MsgWidth / cip_base_pkg::EDN_BUS_WIDTH) begin
-              edn_fifo.get(edn_item);
+              edn_fifos[0].get(edn_item);
             end
             `uvm_info(`gfn, "got all edn transactions", UVM_HIGH)
             // Receiving the last EDN sequence item is synchronized on the EDN clock,
diff --git a/hw/ip/kmac/dv/env/seq_lib/kmac_base_vseq.sv b/hw/ip/kmac/dv/env/seq_lib/kmac_base_vseq.sv
index a5e23dd..33ba2dd 100644
--- a/hw/ip/kmac/dv/env/seq_lib/kmac_base_vseq.sv
+++ b/hw/ip/kmac/dv/env/seq_lib/kmac_base_vseq.sv
@@ -723,7 +723,7 @@
       if (cfg.enable_masking) begin
         // If masked, wait for some time past the max latency of the EDN agent in case
         // an EDN request is sent right as CmdProcess is seen by the KMAC.
-        cfg.edn_clk_rst_vif.wait_clks(2 * cfg.m_edn_pull_agent_cfg.device_delay_max);
+        cfg.edn_clk_rst_vif.wait_clks(2 * cfg.m_edn_pull_agent_cfg[0].device_delay_max);
         cfg.clk_rst_vif.wait_clks(1000);
       end else begin
         cfg.clk_rst_vif.wait_clks(150);
diff --git a/hw/ip/kmac/dv/tb.sv b/hw/ip/kmac/dv/tb.sv
index aa51b22..80397ce 100644
--- a/hw/ip/kmac/dv/tb.sv
+++ b/hw/ip/kmac/dv/tb.sv
@@ -45,19 +45,19 @@
   // dut
 
   kmac #(.EnMasking(`EN_MASKING), .ReuseShare(`REUSE_SHARE)) dut (
-    .clk_i              (clk                          ),
-    .rst_ni             (rst_n                        ),
+    .clk_i              (clk   ),
+    .rst_ni             (rst_n ),
 
     // TLUL interface
-    .tl_i               (tl_if.h2d                    ),
-    .tl_o               (tl_if.d2h                    ),
+    .tl_i               (tl_if.h2d ),
+    .tl_o               (tl_if.d2h ),
 
     // Alerts
-    .alert_rx_i         (alert_rx                     ),
-    .alert_tx_o         (alert_tx                     ),
+    .alert_rx_i         (alert_rx ),
+    .alert_tx_o         (alert_tx ),
 
     // KeyMgr sideload key interface
-    .keymgr_key_i       (sideload_if.sideload_key     ),
+    .keymgr_key_i       (sideload_if.sideload_key ),
 
     // KeyMgr KDF datapath
     //
@@ -67,18 +67,18 @@
     .app_o       (app_rsp ),
 
     // Interrupts
-    .intr_kmac_done_o   (interrupts[KmacDone]         ),
-    .intr_fifo_empty_o  (interrupts[KmacFifoEmpty]    ),
-    .intr_kmac_err_o    (interrupts[KmacErr]          ),
+    .intr_kmac_done_o   (interrupts[KmacDone]      ),
+    .intr_fifo_empty_o  (interrupts[KmacFifoEmpty] ),
+    .intr_kmac_err_o    (interrupts[KmacErr]       ),
 
     // Idle interface
-    .idle_o             (idle                         ),
+    .idle_o             (idle),
 
     // EDN interface
-    .clk_edn_i          (edn_clk                      ),
-    .rst_edn_ni         (edn_rst_n                    ),
-    .entropy_o          (edn_if.req                   ),
-    .entropy_i          ({edn_if.ack, edn_if.d_data}  )
+    .clk_edn_i          (edn_clk                           ),
+    .rst_edn_ni         (edn_rst_n                         ),
+    .entropy_o          (edn_if[0].req                     ),
+    .entropy_i          ({edn_if[0].ack, edn_if[0].d_data} )
   );
 
   for (genvar i = 0; i < kmac_pkg::NumAppIntf; i++) begin : gen_kmac_app_intf
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_env_cfg.sv b/hw/ip/otbn/dv/uvm/env/otbn_env_cfg.sv
index bd10acb..9fa8457 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_env_cfg.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_env_cfg.sv
@@ -55,7 +55,7 @@
   int ok_to_end_delay_ns = 1000;
 
   function void initialize(bit [31:0] csr_base_addr = '1);
-    has_edn = 1;
+    num_edn = 2;
     // Tell the CIP base code not to look for a "devmode" interface. OTBN doesn't have one.
     has_devmode = 0;
 
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_env_pkg.sv b/hw/ip/otbn/dv/uvm/env/otbn_env_pkg.sv
index b1b6972..ba4ab31 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_env_pkg.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_env_pkg.sv
@@ -39,6 +39,7 @@
   // parameters
   parameter string LIST_OF_ALERTS[] = {"fatal", "recov"};
   parameter uint NUM_ALERTS = otbn_reg_pkg::NumAlerts;
+  parameter uint NUM_EDN = 2;
 
   // typedefs
   typedef virtual pins_if #(1) idle_vif;
diff --git a/hw/ip/otbn/dv/uvm/tb.sv b/hw/ip/otbn/dv/uvm/tb.sv
index 3ef561a..718bdd3 100644
--- a/hw/ip/otbn/dv/uvm/tb.sv
+++ b/hw/ip/otbn/dv/uvm/tb.sv
@@ -51,26 +51,23 @@
   // design, change the assertion, or change the DV code so this doesn't happen.
 `define RND_REQ_PATH \
     dut.u_prim_edn_rnd_req.u_prim_sync_reqack_data.gen_assert_data_dst2src
+
+`define URND_REQ_PATH \
+    dut.u_prim_edn_urnd_req.u_prim_sync_reqack_data.gen_assert_data_dst2src
   always @(negedge edn_rst_n or posedge edn_rst_n) begin
     if (!edn_rst_n) begin
       $assertoff(0, `RND_REQ_PATH.SyncReqAckDataHoldDst2SrcA);
+      $assertoff(0, `URND_REQ_PATH.SyncReqAckDataHoldDst2SrcA);
       $assertoff(0, `RND_REQ_PATH.SyncReqAckDataHoldDst2SrcB);
+      $assertoff(0, `URND_REQ_PATH.SyncReqAckDataHoldDst2SrcB);
     end else begin
       $asserton(0, `RND_REQ_PATH.SyncReqAckDataHoldDst2SrcA);
+      $asserton(0, `URND_REQ_PATH.SyncReqAckDataHoldDst2SrcA);
       $asserton(0, `RND_REQ_PATH.SyncReqAckDataHoldDst2SrcB);
+      $asserton(0, `URND_REQ_PATH.SyncReqAckDataHoldDst2SrcB);
     end
   end
 
-  // Mock up EDN & OTP that just instantly return fixed data when requested
-  // TODO: Provide proper EDN and OTP agents
-
-  edn_req_t edn_urnd_req;
-  edn_rsp_t edn_urnd_rsp;
-
-  assign edn_urnd_rsp.edn_ack  = edn_urnd_req.edn_req;
-  assign edn_urnd_rsp.edn_fips = 1'b0;
-  assign edn_urnd_rsp.edn_bus  = 32'h99999999;
-
   otbn_otp_key_req_t otp_key_req;
   otbn_otp_key_rsp_t otp_key_rsp;
 
@@ -118,11 +115,11 @@
 
     .clk_edn_i (edn_clk),
     .rst_edn_ni(edn_rst_n),
-    .edn_rnd_o (edn_if.req),
-    .edn_rnd_i ({edn_if.ack, edn_if.d_data}),
+    .edn_rnd_o (edn_if[0].req),
+    .edn_rnd_i ({edn_if[0].ack, edn_if[0].d_data}),
 
-    .edn_urnd_o(edn_urnd_req),
-    .edn_urnd_i(edn_urnd_rsp),
+    .edn_urnd_o(edn_if[1].req),
+    .edn_urnd_i({edn_if[1].ack, edn_if[1].d_data}),
 
     .clk_otp_i     (clk),
     .rst_otp_ni    (rst_n),
@@ -205,7 +202,7 @@
 
     .err_bits_o   (),
 
-    .edn_rnd_i             ({edn_if.ack, edn_if.d_data}),
+    .edn_rnd_i             ({edn_if[0].ack, edn_if[0].d_data}),
     .edn_rnd_cdc_done_i    (edn_rnd_cdc_done),
 
     .edn_urnd_data_valid_i (edn_urnd_data_valid),
diff --git a/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_cfg.sv b/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_cfg.sv
index cd71e01..df601a7 100644
--- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_cfg.sv
+++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_cfg.sv
@@ -55,7 +55,7 @@
 
   virtual function void initialize(bit [31:0] csr_base_addr = '1);
     list_of_alerts = otp_ctrl_env_pkg::LIST_OF_ALERTS;
-    has_edn = 1;
+    num_edn = 1;
     tl_intg_alert_name = "fatal_bus_integ_error";
     super.initialize(csr_base_addr);
 
diff --git a/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_pkg.sv b/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_pkg.sv
index 688912e..aab8f3e 100644
--- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_pkg.sv
+++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_env_pkg.sv
@@ -32,6 +32,7 @@
                                             "fatal_check_error",
                                             "fatal_bus_integ_error"};
   parameter uint NUM_ALERTS              = 3;
+  parameter uint NUM_EDN                 = 1;
 
   parameter uint DIGEST_SIZE             = 8;
   parameter uint SW_WINDOW_BASE_ADDR     = 'h1000;
diff --git a/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv b/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
index 3bcc619..052dab6 100644
--- a/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
+++ b/hw/ip/otp_ctrl/dv/env/otp_ctrl_scoreboard.sv
@@ -316,7 +316,7 @@
   virtual task process_edn_req();
     forever begin
       push_pull_item#(.DeviceDataWidth(EDN_DATA_WIDTH)) edn_item;
-      edn_fifo.get(edn_item);
+      edn_fifos[0].get(edn_item);
       edn_data_q.push_back(edn_item.d_data[EDN_BUS_WIDTH-1:0]);
     end
   endtask
diff --git a/hw/ip/otp_ctrl/dv/tb.sv b/hw/ip/otp_ctrl/dv/tb.sv
index 6e91a8e..c50bb4c 100644
--- a/hw/ip/otp_ctrl/dv/tb.sv
+++ b/hw/ip/otp_ctrl/dv/tb.sv
@@ -86,8 +86,8 @@
     // edn
     .clk_edn_i                  (edn_clk    ),
     .rst_edn_ni                 (edn_rst_n  ),
-    .edn_o                      (edn_if.req ),
-    .edn_i                      ({edn_if.ack, edn_if.d_data}),
+    .edn_o                      (edn_if[0].req ),
+    .edn_i                      ({edn_if[0].ack, edn_if[0].d_data}),
     // bus interfaces
     .core_tl_i                  (tl_if.h2d  ),
     .core_tl_o                  (tl_if.d2h  ),
diff --git a/hw/ip_templates/alert_handler/dv/env/alert_handler_env_cfg.sv b/hw/ip_templates/alert_handler/dv/env/alert_handler_env_cfg.sv
index c7be872..bd0ff78 100644
--- a/hw/ip_templates/alert_handler/dv/env/alert_handler_env_cfg.sv
+++ b/hw/ip_templates/alert_handler/dv/env/alert_handler_env_cfg.sv
@@ -19,7 +19,7 @@
   `uvm_object_new
 
   virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1);
-    has_edn = 1;
+    num_edn = 1;
     has_shadowed_regs = 1;
     super.initialize(csr_base_addr);
     shadow_update_err_status_fields[ral.loc_alert_cause[LocalShadowRegUpdateErr].la] = 1;
diff --git a/hw/ip_templates/alert_handler/dv/env/alert_handler_env_pkg.sv b/hw/ip_templates/alert_handler/dv/env/alert_handler_env_pkg.sv
index cdc88a7..6acd01f 100644
--- a/hw/ip_templates/alert_handler/dv/env/alert_handler_env_pkg.sv
+++ b/hw/ip_templates/alert_handler/dv/env/alert_handler_env_pkg.sv
@@ -20,6 +20,7 @@
 
   // parameters
   parameter uint NUM_ALERTS                = alert_handler_reg_pkg::NAlerts;
+  parameter uint NUM_EDN                   = 1;
   parameter uint NUM_ESCS                  = 4;
   parameter uint NUM_MAX_ESC_SEV           = 8;
   parameter uint NUM_ESC_SIGNALS           = 4;
diff --git a/hw/ip_templates/alert_handler/dv/tb/tb.sv b/hw/ip_templates/alert_handler/dv/tb/tb.sv
index d33f62f..207f468 100644
--- a/hw/ip_templates/alert_handler/dv/tb/tb.sv
+++ b/hw/ip_templates/alert_handler/dv/tb/tb.sv
@@ -85,8 +85,8 @@
     .lpg_cg_en_i          ( alert_handler_if.lpg_cg_en  ),
     .lpg_rst_en_i         ( alert_handler_if.lpg_rst_en ),
     .crashdump_o          ( crashdump     ),
-    .edn_o                ( edn_if.req    ),
-    .edn_i                ( {edn_if.ack, edn_if.d_data} ),
+    .edn_o                ( edn_if[0].req    ),
+    .edn_i                ( {edn_if[0].ack, edn_if[0].d_data} ),
     .alert_rx_o           ( alert_rx      ),
     .alert_tx_i           ( alert_tx      ),
     .esc_rx_i             ( esc_rx        ),
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env_cfg.sv b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env_cfg.sv
index c7be872..bd0ff78 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env_cfg.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env_cfg.sv
@@ -19,7 +19,7 @@
   `uvm_object_new
 
   virtual function void initialize(bit [TL_AW-1:0] csr_base_addr = '1);
-    has_edn = 1;
+    num_edn = 1;
     has_shadowed_regs = 1;
     super.initialize(csr_base_addr);
     shadow_update_err_status_fields[ral.loc_alert_cause[LocalShadowRegUpdateErr].la] = 1;
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env_pkg.sv b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env_pkg.sv
index cdc88a7..6acd01f 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env_pkg.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/env/alert_handler_env_pkg.sv
@@ -20,6 +20,7 @@
 
   // parameters
   parameter uint NUM_ALERTS                = alert_handler_reg_pkg::NAlerts;
+  parameter uint NUM_EDN                   = 1;
   parameter uint NUM_ESCS                  = 4;
   parameter uint NUM_MAX_ESC_SEV           = 8;
   parameter uint NUM_ESC_SIGNALS           = 4;
diff --git a/hw/top_earlgrey/ip_autogen/alert_handler/dv/tb/tb.sv b/hw/top_earlgrey/ip_autogen/alert_handler/dv/tb/tb.sv
index d33f62f..207f468 100644
--- a/hw/top_earlgrey/ip_autogen/alert_handler/dv/tb/tb.sv
+++ b/hw/top_earlgrey/ip_autogen/alert_handler/dv/tb/tb.sv
@@ -85,8 +85,8 @@
     .lpg_cg_en_i          ( alert_handler_if.lpg_cg_en  ),
     .lpg_rst_en_i         ( alert_handler_if.lpg_rst_en ),
     .crashdump_o          ( crashdump     ),
-    .edn_o                ( edn_if.req    ),
-    .edn_i                ( {edn_if.ack, edn_if.d_data} ),
+    .edn_o                ( edn_if[0].req    ),
+    .edn_i                ( {edn_if[0].ack, edn_if[0].d_data} ),
     .alert_rx_o           ( alert_rx      ),
     .alert_tx_i           ( alert_tx      ),
     .esc_rx_i             ( esc_rx        ),
diff --git a/util/uvmdvgen/base_test.sv.tpl b/util/uvmdvgen/base_test.sv.tpl
index ae0dac5..177ee02 100644
--- a/util/uvmdvgen/base_test.sv.tpl
+++ b/util/uvmdvgen/base_test.sv.tpl
@@ -23,7 +23,9 @@
     super.build_phase(phase);
     cfg.has_ral = 1'b0;
   endfunction
-
+% if num_edn:
+    cfg.num_edn = ${num_edn};
+% endif
 % endif
   // the base class also looks up UVM_TEST_SEQ plusarg to create and run that seq in
   // the run_phase; as such, nothing more needs to be done
diff --git a/util/uvmdvgen/env_cfg.sv.tpl b/util/uvmdvgen/env_cfg.sv.tpl
index d38c510..879dc51 100644
--- a/util/uvmdvgen/env_cfg.sv.tpl
+++ b/util/uvmdvgen/env_cfg.sv.tpl
@@ -27,9 +27,6 @@
 % if has_alerts:
     list_of_alerts = ${name}_env_pkg::LIST_OF_ALERTS;
 % endif
-% if has_edn:
-    cfg.has_edn = 1;
-% endif
 % if has_ral:
     super.initialize(csr_base_addr);
 % endif
diff --git a/util/uvmdvgen/gen_env.py b/util/uvmdvgen/gen_env.py
index b07ee70..98b5943 100644
--- a/util/uvmdvgen/gen_env.py
+++ b/util/uvmdvgen/gen_env.py
@@ -12,7 +12,7 @@
 from uvmdvgen import VENDOR_DEFAULT
 
 
-def gen_env(name, is_cip, has_ral, has_interrupts, has_alerts, has_edn,
+def gen_env(name, is_cip, has_ral, has_interrupts, has_alerts, num_edn,
             env_agents, root_dir, vendor):
     # yapf: disable
     # flake8: noqa
@@ -80,7 +80,7 @@
                                has_ral=has_ral,
                                has_interrupts=has_interrupts,
                                has_alerts=has_alerts,
-                               has_edn=has_edn,
+                               num_edn=num_edn,
                                env_agents=env_agents,
                                vendor=vendor))
             except Exception as e:
diff --git a/util/uvmdvgen/tb.sv.tpl b/util/uvmdvgen/tb.sv.tpl
index 7eab5ea..c6540fe 100644
--- a/util/uvmdvgen/tb.sv.tpl
+++ b/util/uvmdvgen/tb.sv.tpl
@@ -37,7 +37,7 @@
 % if has_alerts:
   `DV_ALERT_IF_CONNECT
 % endif
-% if has_edn:
+% if num_edn:
   // edn_clk, edn_rst_n and edn_if are defined and driven in below macro
   `DV_EDN_IF_CONNECT
 % endif
@@ -49,12 +49,12 @@
     .rst_ni               (rst_n    )${"," if is_cip else ""}
 
     .tl_i                 (tl_if.h2d),
-    .tl_o                 (tl_if.d2h)${"," if has_alerts or has_edn else ""}
+    .tl_o                 (tl_if.d2h)${"," if has_alerts or num_edn else ""}
   % if has_alerts:
     .alert_rx_i           (alert_rx ),
-    .alert_tx_o           (alert_tx )${"," if has_edn else ""}
+    .alert_tx_o           (alert_tx )${"," if num_edn else ""}
   % endif
-  % if has_edn:
+  % if num_edn:
     .clk_edn_i            (edn_clk    ),
     .rst_edn_ni           (edn_rst_n  ),
     .edn_o                (edn_if.req),
diff --git a/util/uvmdvgen/uvmdvgen.py b/util/uvmdvgen/uvmdvgen.py
index 64f67e5..21258a5 100755
--- a/util/uvmdvgen/uvmdvgen.py
+++ b/util/uvmdvgen/uvmdvgen.py
@@ -151,7 +151,7 @@
         if not args.env_agents:
             args.env_agents = []
         gen_env.gen_env(args.name, args.is_cip, args.has_ral,
-                        args.has_interrupts, args.has_alerts, args.has_edn,
+                        args.has_interrupts, args.has_alerts, args.num_edn,
                         args.env_agents, args.env_outdir, args.vendor)