[flash_ctrl,dv]Add covergroups for newly added features

This PR added covergroups for follwoing features as part of
addression issue #14527

- Flash instruction execution enable
- RMA entry without flash initialization
- Adjust rd_err sampling point

Other features can be checked by code coverage.

Also moved flash_ctrl_dv_if to flash_ctrl_cov_if
as part of covarege code clean up.

Signed-off-by: Jaedon Kim <jdonjdon@google.com>
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl_testplan.hjson b/hw/ip/flash_ctrl/data/flash_ctrl_testplan.hjson
index 7021cc1..25a9405 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl_testplan.hjson
+++ b/hw/ip/flash_ctrl/data/flash_ctrl_testplan.hjson
@@ -419,5 +419,36 @@
             - update_err: A shadow register encountered an update error.
             '''
     }
+    {
+      name: eviction_cg
+      desc: '''
+            Covers eviction with mp_region_cfgs for data and info regions.
+            Sample all 4 rd_buf status.
+            When each buffer hazard is set, capture the address stored in the buffer.
+            Then search from tb data base to see which region the address belong to.
+            After that record the config value (scrambe_en and ecc_en) of the region.
+            Use cross over buffer index, the operation to cause the eviction and
+            the region config values.
+            '''
+    }
+    {
+      name: fetch_code_cg
+      desc: '''
+            Covers whether dut received valid or invalid key value from ral.exec register.
+            Cross with tlul.instr_types.
+            '''
+    }
+    {
+      name: rma_init_cg
+      desc: '''
+            Cover rma operation is executed regardless of when flash_init started.
+            flash_ctrl_hw_rma runs rma operation and flash init in parallel thread.
+            In this test, sample rma state when flash init starts.
+            If rma state is StRmaIdle, which means rma is not started. So it confirms
+            rma start after flash init start.
+            If rma state is [StRmaPageSel:StRmaInvalid], which mean rma is on going.
+            So it confirms rma start before flash init start.
+            '''
+    }
   ]
 }
diff --git a/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov_if.sv b/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov_if.sv
index 33da7ee..c9eb5bc 100644
--- a/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov_if.sv
+++ b/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov_if.sv
@@ -11,13 +11,15 @@
 
   import uvm_pkg::*;
   import flash_ctrl_pkg::*;
+  import lc_ctrl_pkg::*;
   import dv_utils_pkg::*;
   `include "dv_fcov_macros.svh"
 
-  ///////////////////////////////////
-  // Control register cover points //
-  ///////////////////////////////////
-
-  // TODO add covergroups and coverpoints
-
+  logic       rd_buf_en;
+  lc_tx_t rma_req;
+  rma_state_e rma_state;
+  logic [10:0] prog_state0;
+  logic [10:0] prog_state1;
+  logic [10:0] lcmgr_state;
+  logic        init;
 endinterface
diff --git a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env.core b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env.core
index 1ebc9ec..0d46919 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env.core
+++ b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env.core
@@ -19,7 +19,6 @@
       - flash_ctrl_eflash_ral_pkg.sv
       - flash_ctrl_env_pkg.sv
       - flash_ctrl_if.sv
-      - flash_ctrl_dv_if.sv
       - flash_ctrl_mem_if.sv
       - flash_mem_bkdr_util.sv: {is_include_file: true}
       - flash_mem_addr_attrs.sv: {is_include_file: true}
diff --git a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env.sv b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env.sv
index 6b2843d..a729498 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env.sv
+++ b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env.sv
@@ -30,9 +30,9 @@
         )) begin
       `uvm_fatal(`gfn, "failed to get flash_ctrl_vif from uvm_config_db")
     end
-    if (!uvm_config_db#(virtual flash_ctrl_dv_if)::get(
-            this, "", "flash_ctrl_dv_vif", cfg.flash_ctrl_dv_vif)) begin
-      `uvm_fatal(`gfn, "failed to get flash_ctrl_dv_vif from uvm_config_db")
+    if (!uvm_config_db#(virtual flash_ctrl_cov_if)::get(
+            this, "", "flash_ctrl_cov_vif", cfg.flash_ctrl_cov_vif)) begin
+      `uvm_fatal(`gfn, "failed to get flash_ctrl_cov_vif from uvm_config_db")
     end
     for (int i = 0; i < NumBanks; i++) begin
       if (!uvm_config_db#(virtual flash_ctrl_mem_if)::get(
diff --git a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cfg.sv b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cfg.sv
index d0f951b..9b300a5 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cfg.sv
+++ b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cfg.sv
@@ -22,7 +22,7 @@
   flash_phy_prim_agent_cfg m_fpp_agent_cfg;
   // interface
   virtual flash_ctrl_if flash_ctrl_vif;
-  virtual flash_ctrl_dv_if flash_ctrl_dv_vif;
+  virtual flash_ctrl_cov_if flash_ctrl_cov_vif;
   virtual clk_rst_if clk_rst_vif_flash_ctrl_eflash_reg_block;
   virtual clk_rst_if clk_rst_vif_flash_ctrl_prim_reg_block;
   virtual flash_ctrl_mem_if flash_ctrl_mem_vif[NumBanks];
@@ -871,141 +871,150 @@
     // Use per bank address.
     aligned_addr[31:OTFBankId] = 'h0;
     for (int i = 0; i < size; i++) begin
-      rd_entry.addr = addr_cp;
-      if (ecc_mode == FlashSerrTestMode) begin
-        err_idx = get_serr_idx();
-        if (err_idx >= 0) begin
-          // Make sure only assert error only once per address
-          if (!serr_addr_tbl[addr_cp].exists(partition)) begin
-            serr_addr_tbl[addr_cp][partition] = 1;
-            `uvm_info(name,
-                      $sformatf({"single bit error is inserted at line:%0d(0x%x) %sz",
-                                " the databit[%0d]"},
-                                i, addr_cp, partition.name, err_idx), UVM_MEDIUM)
-            flash_bit_flip(mem_bkdr_util_h[partition][bank], aligned_addr, err_idx);
-          end
-        end
-      end else if (ecc_mode == FlashIerrTestMode) begin
-        randcase
-          ierr_pct: begin
-            if (derr_otd.exists(rd_entry)) continue;
-            if (ierr_addr_tbl[addr_cp].exists(partition)) begin
-              ierr_created[caller] = 1;
-            end else if (!otf_read_entry.hash.exists(rd_entry)) begin
-              ierr_addr_tbl[addr_cp][partition] = 1;
-              ierr_created[caller] = 1;
+      // For controller initiated read, in the worst case, each word (8byte) can belong to
+      // different memory protection region.
+      // So before inject bit error, we have to check per word ecc_en
+      // to make sure bit error injection become valid.
+      // If ecc is not enabled, bit error cannot be detected.
+      if (caller == ReadTaskHost || (item.ctrl_rd_region_q[i].ecc_en == MuBi4True)) begin
+        rd_entry.addr = addr_cp;
+        if (ecc_mode == FlashSerrTestMode) begin
+          err_idx = get_serr_idx();
+          if (err_idx >= 0) begin
+            // Make sure only assert error only once per address
+            if (!serr_addr_tbl[addr_cp].exists(partition)) begin
+              serr_addr_tbl[addr_cp][partition] = 1;
               `uvm_info(name,
-                        $sformatf("icv error [%s][%0d] is inserted at line:%0d rd_entry:%p",
-                                  partition.name, bank, i, rd_entry), UVM_MEDIUM)
-              flash_icv_flip(mem_bkdr_util_h[partition][bank], aligned_addr, item);
+                        $sformatf({"single bit error is inserted at line:%0d(0x%x) %sz",
+                                   " the databit[%0d]"},
+                                  i, addr_cp, partition.name, err_idx), UVM_MEDIUM)
+              flash_bit_flip(mem_bkdr_util_h[partition][bank], aligned_addr, err_idx);
             end
           end
-          10-ierr_pct: begin
-          end
-        endcase // randcase
-      end else begin // if (ecc_mode == FlashIerrTestMode)
-        derr_idx.shuffle();
-        err_idx = 0;
-        if (derr_otd.exists(rd_entry)) continue;
-        if (derr_once == 0 || (derr_created[0] | derr_created[1]) == 0 ) begin
-          repeat (2) begin
-            randcase
-              derr_pct: begin
+        end else if (ecc_mode == FlashIerrTestMode) begin
+          randcase
+            ierr_pct: begin
+              if (derr_otd.exists(rd_entry)) continue;
+              if (ierr_addr_tbl[addr_cp].exists(partition)) begin
+                ierr_created[caller] = 1;
+              end else if (!otf_read_entry.hash.exists(rd_entry)) begin
+                ierr_addr_tbl[addr_cp][partition] = 1;
+                ierr_created[caller] = 1;
                 `uvm_info(name,
-                          $sformatf({"addr:0x%x %x bit error is inserted at line:%0d",
-                                     " the databit[%0d] err_idx:%0d"},
-                                    aligned_addr, addr_cp, i, derr_idx[err_idx], err_idx),
-                          UVM_MEDIUM)
+                          $sformatf("icv error [%s][%0d] is inserted at line:%0d rd_entry:%p",
+                                    partition.name, bank, i, rd_entry), UVM_MEDIUM)
+                flash_icv_flip(mem_bkdr_util_h[partition][bank], aligned_addr, item);
+              end
+            end
+            10-ierr_pct: begin
+            end
+          endcase // randcase
+        end else begin // if (ecc_mode == FlashIerrTestMode)
+          derr_idx.shuffle();
+          err_idx = 0;
+          if (derr_otd.exists(rd_entry)) continue;
+          if (derr_once == 0 || (derr_created[0] | derr_created[1]) == 0 ) begin
+            repeat (2) begin
+              randcase
+                derr_pct: begin
+                  `uvm_info(name,
+                            $sformatf({"addr:0x%x %x bit error is inserted at line:%0d",
+                                       " the databit[%0d] err_idx:%0d"},
+                                      aligned_addr, addr_cp, i, derr_idx[err_idx], err_idx),
+                            UVM_MEDIUM)
 
-                // If address already had a single bit error, just skip this line.
-                // We could add another bit error instead of modeling read cache behavior.
-                if (err_idx != 0 || serr_addr_tbl[addr_cp].exists(partition) == 0) begin
-                  if (!otf_read_entry.hash.exists(rd_entry)) begin
-                    flash_bit_flip(mem_bkdr_util_h[partition][bank], aligned_addr,
-                                   derr_idx[err_idx++]);
-                    serr_addr_tbl[addr_cp][partition] = 1;
+                  // If address already had a single bit error, just skip this line.
+                  // We could add another bit error instead of modeling read cache behavior.
+                  if (err_idx != 0 || serr_addr_tbl[addr_cp].exists(partition) == 0) begin
+                    if (!otf_read_entry.hash.exists(rd_entry)) begin
+                      flash_bit_flip(mem_bkdr_util_h[partition][bank], aligned_addr,
+                                     derr_idx[err_idx++]);
+                      serr_addr_tbl[addr_cp][partition] = 1;
+                    end
+                  end
+                  if (err_idx == 2) begin
+                    `uvm_info(name, $sformatf(" addr:0x%x is added to derr_addr_tbl", addr_cp),
+                              UVM_MEDIUM)
+                    derr_addr_tbl[addr_cp][partition] = 1;
+                    derr_created[caller] = 1;
                   end
                 end
-                if (err_idx == 2) begin
-                  `uvm_info(name, $sformatf(" addr:0x%x is added to derr_addr_tbl", addr_cp),
-                            UVM_MEDIUM)
-                  derr_addr_tbl[addr_cp][partition] = 1;
-                  derr_created[caller] = 1;
+                10-derr_pct: begin
                 end
-              end
-              10-derr_pct: begin
-              end
-            endcase // randcase
-          end // repeat (2)
-        end // if (derr_once == 0 || (|derr_created) == 0)
-      end // else: !if(ecc_mode == FlashIerrTestMode)
-      aligned_addr += 8;
-      addr_cp[OTFBankId-1:0] = aligned_addr[OTFBankId-1:0];
+              endcase // randcase
+            end // repeat (2)
+          end // if (derr_once == 0 || (|derr_created) == 0)
+        end // else: !if(ecc_mode == FlashIerrTestMode)
+        aligned_addr += 8;
+        addr_cp[OTFBankId-1:0] = aligned_addr[OTFBankId-1:0];
+      end
     end // for (int i = 0; i < size; i++)
 
     if (tail) begin
-      rd_entry.addr = addr_cp;
-      if (ecc_mode == FlashSerrTestMode) begin
-        err_idx = get_serr_idx();
-        if (err_idx >= 0) begin
-          if (!serr_addr_tbl[addr_cp].exists(partition)) begin
-            serr_addr_tbl[addr_cp][partition] = 1;
-            `uvm_info(name,
-                      $sformatf({"last:single bit error is inserted at line:%0d(0x%x) %s",
-                                " the databit[%0d]"},
-                                size, addr_cp, partition.name, err_idx), UVM_MEDIUM)
-            flash_bit_flip(mem_bkdr_util_h[partition][bank], aligned_addr, err_idx);
-          end
-        end
-      end else if (ecc_mode == FlashIerrTestMode) begin
-        randcase
-          ierr_pct: begin
-            if (derr_otd.exists(rd_entry)) return;
-            if (ierr_addr_tbl[addr_cp].exists(partition)) begin
-              ierr_created[caller] = 1;
-            end else if (!otf_read_entry.hash.exists(rd_entry)) begin
-              ierr_addr_tbl[addr_cp][partition] = 1;
-              ierr_created[caller] = 1;
+      if (caller == ReadTaskHost || (item.ctrl_rd_region_q[size].ecc_en == MuBi4True)) begin
+        rd_entry.addr = addr_cp;
+        if (ecc_mode == FlashSerrTestMode) begin
+          err_idx = get_serr_idx();
+          if (err_idx >= 0) begin
+            if (!serr_addr_tbl[addr_cp].exists(partition)) begin
+              serr_addr_tbl[addr_cp][partition] = 1;
               `uvm_info(name,
-                        $sformatf("last:icv error[%s][%0d] is inserted at line:%0d rd_entry:%p",
-                                  partition.name, bank, size, rd_entry), UVM_MEDIUM)
-              flash_icv_flip(mem_bkdr_util_h[partition][bank], aligned_addr, item);
+                        $sformatf({"last:single bit error is inserted at line:%0d(0x%x) %s",
+                                   " the databit[%0d]"},
+                                  size, addr_cp, partition.name, err_idx), UVM_MEDIUM)
+              flash_bit_flip(mem_bkdr_util_h[partition][bank], aligned_addr, err_idx);
             end
           end
-          10-ierr_pct: begin
-          end
-        endcase // randcase
-      end else begin // if (ecc_mode == FlashIerrTestMode)
-        derr_idx.shuffle();
-        err_idx = 0;
-        if (derr_otd.exists(rd_entry)) return;
-        if (derr_once == 0 || (derr_created[0] | derr_created[1]) == 0) begin
-          repeat (2) begin
-            randcase
-              derr_pct: begin
+        end else if (ecc_mode == FlashIerrTestMode) begin
+          randcase
+            ierr_pct: begin
+              if (derr_otd.exists(rd_entry)) return;
+              if (ierr_addr_tbl[addr_cp].exists(partition)) begin
+                ierr_created[caller] = 1;
+              end else if (!otf_read_entry.hash.exists(rd_entry)) begin
+                ierr_addr_tbl[addr_cp][partition] = 1;
+                ierr_created[caller] = 1;
                 `uvm_info(name,
-                          $sformatf({"last:addr:0x%x %x bit error is inserted at line:%0d",
-                                     " the databit[%0d] err_idx:%0d"},
-                                    aligned_addr, addr_cp, size, derr_idx[err_idx], err_idx),
-                          UVM_MEDIUM)
-                if (err_idx != 0 || serr_addr_tbl[addr_cp].exists(partition) == 0) begin
-                  if (!otf_read_entry.hash.exists(rd_entry)) begin
-                    flash_bit_flip(mem_bkdr_util_h[partition][bank], aligned_addr,
-                                   derr_idx[err_idx++]);
-                    serr_addr_tbl[addr_cp][partition] = 1;
+                          $sformatf("last:icv error[%s][%0d] is inserted at line:%0d rd_entry:%p",
+                                    partition.name, bank, size, rd_entry), UVM_MEDIUM)
+                flash_icv_flip(mem_bkdr_util_h[partition][bank], aligned_addr, item);
+              end
+            end
+            10-ierr_pct: begin
+            end
+          endcase // randcase
+        end else begin // if (ecc_mode == FlashIerrTestMode)
+          derr_idx.shuffle();
+          err_idx = 0;
+          if (derr_otd.exists(rd_entry)) return;
+          if (derr_once == 0 || (derr_created[0] | derr_created[1]) == 0) begin
+            repeat (2) begin
+              randcase
+                derr_pct: begin
+                  `uvm_info(name,
+                            $sformatf({"last:addr:0x%x %x bit error is inserted at line:%0d",
+                                       " the databit[%0d] err_idx:%0d"},
+                                      aligned_addr, addr_cp, size, derr_idx[err_idx], err_idx),
+                            UVM_MEDIUM)
+                  if (err_idx != 0 || serr_addr_tbl[addr_cp].exists(partition) == 0) begin
+                    if (!otf_read_entry.hash.exists(rd_entry)) begin
+                      flash_bit_flip(mem_bkdr_util_h[partition][bank], aligned_addr,
+                                     derr_idx[err_idx++]);
+                      serr_addr_tbl[addr_cp][partition] = 1;
+                    end
+                  end
+                  if (err_idx == 2) begin
+                    derr_addr_tbl[addr_cp][partition] = 1;
+                    derr_created[caller] = 1;
                   end
                 end
-                if (err_idx == 2) begin
-                  derr_addr_tbl[addr_cp][partition] = 1;
-                  derr_created[caller] = 1;
+                10-derr_pct: begin
                 end
-              end
-              10-derr_pct: begin
-              end
-            endcase // randcase
-          end
-        end // if (derr_once == 0 || (|derr_created) == 0)
-      end // else: !if(ecc_mode == FlashIerrTestMode)
+              endcase // randcase
+            end
+          end // if (derr_once == 0 || (|derr_created) == 0)
+        end // else: !if(ecc_mode == FlashIerrTestMode)
+      end
     end // if (tail)
   endfunction // add_bit_err
 
diff --git a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cov.sv b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cov.sv
index 78f8d2d..28bacb6 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cov.sv
+++ b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_cov.sv
@@ -73,6 +73,21 @@
     evic_all_cross : cross evic_idx_cp, evic_op_cp, evic_cfg_cp;
   endgroup // eviction_cg
 
+  covergroup fetch_code_cg with function sample(bit is_exec_key, logic [MuBi4Width-1:0] instr);
+    key_cp: coverpoint is_exec_key;
+    instr_type_cp: coverpoint instr {
+      bins instr_types[2] = {MuBi4True, MuBi4False};
+      bins others = {[0:15]} with (!(item inside {MuBi4True, MuBi4False}));
+    }
+    key_instr_cross : cross key_cp, instr_type_cp;
+  endgroup // fetch_code_cg
+
+  covergroup rma_init_cg with function sample(flash_ctrl_pkg::rma_state_e st);
+    rma_start_cp: coverpoint st {
+      bins rma_st[2] = {StRmaIdle, [StRmaPageSel:StRmaInvalid]};
+    }
+  endgroup // rma_init_cg
+
   function new(string name, uvm_component parent);
     super.new(name, parent);
     control_cg = new();
@@ -80,6 +95,8 @@
     error_cg = new();
     fifo_lvl_cg = new();
     eviction_cg = new();
+    fetch_code_cg = new();
+    rma_init_cg = new();
   endfunction : new
 
   virtual function void build_phase(uvm_phase phase);
diff --git a/hw/ip/flash_ctrl/dv/env/flash_ctrl_scoreboard.sv b/hw/ip/flash_ctrl/dv/env/flash_ctrl_scoreboard.sv
index 4944a74..4c77195 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_ctrl_scoreboard.sv
+++ b/hw/ip/flash_ctrl/dv/env/flash_ctrl_scoreboard.sv
@@ -74,9 +74,21 @@
       process_eflash_tl_a_chan_fifo();
       process_eflash_tl_d_chan_fifo();
       mon_eviction();
+      mon_rma();
     join_none
   endtask
 
+  task mon_rma;
+    bit init_set = 0;
+    forever begin
+      @(negedge cfg.clk_rst_vif.clk);
+      if (init_set == 0 && cfg.flash_ctrl_cov_vif.init == 1) begin
+        init_set = 1;
+        if (cfg.en_cov) cov.rma_init_cg.sample(cfg.flash_ctrl_cov_vif.rma_state);
+      end
+    end
+  endtask // mon_rma
+
   task mon_eviction;
     flash_mp_region_cfg_t my_region;
     bit ecc_en, scr_en;
@@ -299,6 +311,13 @@
                   end
                end
             end
+            "exec": begin
+              bit is_exec_key = `gmv(ral.exec) == CODE_EXEC_KEY;
+              tlul_pkg::tl_a_user_t a_user = item.a_user;
+              if (cfg.en_cov) begin
+                cov.fetch_code_cg.sample(is_exec_key, a_user.instr_type);
+              end
+            end
             default: begin
             // TODO: Uncomment once func cover is implemented
             // `uvm_info(`gfn, $sformatf("Not for func coverage: %0s", csr.get_full_name()))
@@ -314,6 +333,11 @@
           // process the csr req
           // for write, update local variable and fifo at address phase
           // for read, update predication at address phase and compare at data phase
+          if(!uvm_re_match("err_code*",csr.get_name())) begin
+            if (cfg.en_cov) begin
+              cov.error_cg.sample(item.d_data);
+            end
+          end
           case (csr.get_name())
             // add individual case item for each csr
             "intr_state": begin
@@ -337,9 +361,6 @@
               do_read_check = 1'b0;
             end
             "err_code": begin
-              if (cfg.en_cov) begin
-                cov.error_cg.sample(item.d_data);
-              end
               do_read_check = 1'b0;
             end
             default: begin
diff --git a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_fetch_code_vseq.sv b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_fetch_code_vseq.sv
index cf977e7..177bfb3 100644
--- a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_fetch_code_vseq.sv
+++ b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_fetch_code_vseq.sv
@@ -258,7 +258,6 @@
       end
 
     end
-
   endtask : body
 
   // Task to initialize the Flash Access (Enable All Regions)
diff --git a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_hw_rma_reset_vseq.sv b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_hw_rma_reset_vseq.sv
index c0145cd..d2b3ff8 100644
--- a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_hw_rma_reset_vseq.sv
+++ b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_hw_rma_reset_vseq.sv
@@ -56,7 +56,7 @@
           reset_state_index_e reset_state_index = $urandom_range(DVStRmaPageSel, DVStRmaRdVerify);
           // Assert reset during RMA state transition
           `uvm_info("Test", $sformatf("Reset index: %s", reset_state_index.name), UVM_LOW)
-          `DV_SPINWAIT(wait(cfg.flash_ctrl_dv_vif.rma_state == dv2rma_st(reset_state_index));,
+          `DV_SPINWAIT(wait(cfg.flash_ctrl_cov_vif.rma_state == dv2rma_st(reset_state_index));,
                        $sformatf("Timed out waiting for rma_state: %s", reset_state_index.name),
                        state_wait_timeout_ns)
           // Give more cycles for long stages
diff --git a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_otf_base_vseq.sv b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_otf_base_vseq.sv
index a6f1ab5..ca65863 100644
--- a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_otf_base_vseq.sv
+++ b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_otf_base_vseq.sv
@@ -540,9 +540,8 @@
       // Address has to be 8byte aligned
       rd_entry.addr[2:0] = 'h0;
       rd_entry.part = flash_op.partition;
-
       if (cfg.ecc_mode > FlashEccEnabled) begin
-        if (exp_item.region.ecc_en == MuBi4True && drop == 0) begin
+        if (drop == 0) begin
           if (cfg.ecc_mode == FlashSerrTestMode || flash_op.addr[2] == 0) begin
             cfg.add_bit_err(flash_op, ReadTaskCtrl, exp_item);
           end
@@ -580,8 +579,6 @@
         wait_flash_op_done();
       end
       if (derr_is_set | cfg.ierr_created[0]) begin
-        uvm_reg_data_t ldata;
-        csr_rd(.ptr(ral.err_code), .value(ldata), .backdoor(1));
         `uvm_info("read_flash", $sformatf({"bank:%0d addr: %x(otf:%x) derr_is_set:%0d",
                                           " ierr_created[0]:%0d"}, bank, flash_op.addr,
                                           flash_op.otf_addr, derr_is_set, cfg.ierr_created[0])
@@ -737,6 +734,12 @@
       cfg.inc_otd_tbl(bank, tl_addr, FlashPartData);
       do_direct_read(.addr(tl_addr), .mask('1), .blocking(1), .rdata(rdata),
                      .completed(completed), .exp_err_rsp(derr));
+
+      // issue csr rd to capture coverpoint at sb.
+      if (derr) begin
+        uvm_reg_data_t ldata;
+        csr_rd(.ptr(ral.err_code), .value(ldata));
+      end
       if (completed) begin
         exp_item.dq.push_back(rdata);
         p_sequencer.eg_exp_host_port[bank].write(exp_item);
diff --git a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_otp_reset_vseq.sv b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_otp_reset_vseq.sv
index b5931f3..d0f8f9a 100644
--- a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_otp_reset_vseq.sv
+++ b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_otp_reset_vseq.sv
@@ -46,7 +46,7 @@
             csr_wr(.ptr(ral.init), .value(1));
             `uvm_info("Test","OTP",UVM_LOW)
             otp_model();
-            `DV_SPINWAIT(wait(cfg.flash_ctrl_dv_vif.rd_buf_en == 1);,
+            `DV_SPINWAIT(wait(cfg.flash_ctrl_cov_vif.rd_buf_en == 1);,
                          "Timed out waiting for rd_buf_en",
                          state_wait_timeout_ns)
             `uvm_info("Test", "RMA REQUEST START", UVM_LOW)
@@ -70,7 +70,7 @@
             if (reset_index == DVWaitRmaRsp) wait_time = long_wait_timeout_ns;
             else wait_time = state_wait_timeout_ns;
 
-            `DV_SPINWAIT(wait(cfg.flash_ctrl_dv_vif.lcmgr_state == dv2rtl_st(reset_index));,
+            `DV_SPINWAIT(wait(cfg.flash_ctrl_cov_vif.lcmgr_state == dv2rtl_st(reset_index));,
                          $sformatf("Timed out waiting for %s", reset_index.name),
                          wait_time)
             // Since these are single cycle state,
@@ -138,7 +138,7 @@
       cfg.clk_rst_vif.wait_clks(2);
       `uvm_info("Test","OTP after loop",UVM_LOW)
       otp_model();
-      `DV_SPINWAIT(wait(cfg.flash_ctrl_dv_vif.rd_buf_en == 1);,
+      `DV_SPINWAIT(wait(cfg.flash_ctrl_cov_vif.rd_buf_en == 1);,
                    "Timed out waiting for rd_buf_en",
                    state_wait_timeout_ns)
 
diff --git a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_prog_reset_vseq.sv b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_prog_reset_vseq.sv
index a4ce41c..9787cdb 100644
--- a/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_prog_reset_vseq.sv
+++ b/hw/ip/flash_ctrl/dv/env/seq_lib/flash_ctrl_prog_reset_vseq.sv
@@ -69,8 +69,8 @@
           string path1, path2;
           reset_index_e reset_index = $urandom_range(DVStPrePack, DVStCalcEcc);
           `uvm_info("Test", $sformatf("reset_idx: %s", reset_index.name), UVM_MEDIUM)
-          `DV_SPINWAIT(wait(cfg.flash_ctrl_dv_vif.prog_state0 == dv2rtl_st(reset_index) ||
-                            cfg.flash_ctrl_dv_vif.prog_state1 == dv2rtl_st(reset_index));,
+          `DV_SPINWAIT(wait(cfg.flash_ctrl_cov_vif.prog_state0 == dv2rtl_st(reset_index) ||
+                            cfg.flash_ctrl_cov_vif.prog_state1 == dv2rtl_st(reset_index));,
                        $sformatf("Timed out waiting for %s", reset_index.name),
                        // Use long time out.
                        // Some unique state does not always guarantee to reach.
@@ -87,7 +87,7 @@
     csr_wr(.ptr(ral.init), .value(1));
     `uvm_info("Test","OTP",UVM_LOW)
     otp_model();
-    `DV_SPINWAIT(wait(cfg.flash_ctrl_dv_vif.rd_buf_en == 1);,
+    `DV_SPINWAIT(wait(cfg.flash_ctrl_cov_vif.rd_buf_en == 1);,
                  "Timed out waiting for rd_buf_en",
                  state_timeout_ns)
 
diff --git a/hw/ip/flash_ctrl/dv/tb/tb.sv b/hw/ip/flash_ctrl/dv/tb/tb.sv
index ac89784..ee0224d 100644
--- a/hw/ip/flash_ctrl/dv/tb/tb.sv
+++ b/hw/ip/flash_ctrl/dv/tb/tb.sv
@@ -65,10 +65,6 @@
     .rst_n(rst_n)
   );
   flash_ctrl_if flash_ctrl_if ();
-  flash_ctrl_dv_if flash_ctrl_dv_if (
-    .clk_i  (clk),
-    .rst_ni (rst_n)
-  );
   flash_phy_prim_if fpp_if (
     .clk  (clk),
     .rst_n(rst_n)
@@ -111,14 +107,15 @@
   assign otp_rsp.rand_key   = flash_ctrl_if.otp_rsp.rand_key;
   assign otp_rsp.seed_valid = flash_ctrl_if.otp_rsp.seed_valid;
 
-  assign flash_ctrl_dv_if.rd_buf_en   = tb.dut.u_flash_hw_if.rd_buf_en_o;
-  assign flash_ctrl_dv_if.rma_req     = tb.dut.u_flash_hw_if.rma_req_i;
-  assign flash_ctrl_dv_if.rma_state   = tb.dut.u_flash_hw_if.rma_state_q;
-  assign flash_ctrl_dv_if.prog_state0 =
+  assign dut.u_flash_ctrl_cov_if.rd_buf_en   = tb.dut.u_flash_hw_if.rd_buf_en_o;
+  assign dut.u_flash_ctrl_cov_if.rma_req     = tb.dut.u_flash_hw_if.rma_req_i;
+  assign dut.u_flash_ctrl_cov_if.rma_state   = tb.dut.u_flash_hw_if.rma_state_q;
+  assign dut.u_flash_ctrl_cov_if.prog_state0 =
                tb.dut.u_eflash.gen_flash_cores[0].u_core.gen_prog_data.u_prog.state_q;
-  assign flash_ctrl_dv_if.prog_state1 =
+  assign dut.u_flash_ctrl_cov_if.prog_state1 =
                tb.dut.u_eflash.gen_flash_cores[1].u_core.gen_prog_data.u_prog.state_q;
-  assign flash_ctrl_dv_if.lcmgr_state = tb.dut.u_flash_hw_if.state_q;
+  assign dut.u_flash_ctrl_cov_if.lcmgr_state = tb.dut.u_flash_hw_if.state_q;
+  assign dut.u_flash_ctrl_cov_if.init = tb.dut.u_flash_hw_if.init_i;
 
   wire flash_test_v;
   assign (pull1, pull0) flash_test_v = 1'b1;
@@ -339,8 +336,15 @@
                                        prim_tl_if);
     uvm_config_db#(virtual flash_ctrl_if)::set(null, "*.env", "flash_ctrl_vif", flash_ctrl_if);
     uvm_config_db#(virtual flash_phy_prim_if)::set(null, "*.env.m_fpp_agent*", "vif", fpp_if);
-    uvm_config_db#(virtual flash_ctrl_dv_if)::set(null, "*.env", "flash_ctrl_dv_vif",
-                                                  flash_ctrl_dv_if);
+    uvm_config_db#(virtual flash_ctrl_cov_if)::set(null, "*.env", "flash_ctrl_cov_vif",
+                                                  dut.u_flash_ctrl_cov_if);
+    uvm_config_db#(virtual flash_ctrl_mem_if)::set(null, "*.env", "flash_ctrl_mem_vif[0]",
+        dut.u_eflash.u_flash.gen_generic.u_impl_generic.gen_prim_flash_banks[0].
+                                                   u_prim_flash_bank.flash_ctrl_mem_if);
+    uvm_config_db#(virtual flash_ctrl_mem_if)::set(null, "*.env", "flash_ctrl_mem_vif[1]",
+        dut.u_eflash.u_flash.gen_generic.u_impl_generic.gen_prim_flash_banks[1].
+                                                   u_prim_flash_bank.flash_ctrl_mem_if);
+
     $timeformat(-9, 1, " ns", 9);
     run_test();
   end