[flash_ctrl]: ADD FUNCTIONAL COVERAGE

Add covergroups for functional coverage defined in Testplan.

Signed-off-by: Nikola Miladinovic <nikola.miladinovic@ensilica.com>
diff --git a/hw/ip/flash_ctrl/data/flash_ctrl_testplan.hjson b/hw/ip/flash_ctrl/data/flash_ctrl_testplan.hjson
index 9783eab..b293fad 100644
--- a/hw/ip/flash_ctrl/data/flash_ctrl_testplan.hjson
+++ b/hw/ip/flash_ctrl/data/flash_ctrl_testplan.hjson
@@ -292,30 +292,14 @@
       desc: '''
             Covers that all operations READ/PROGRAM/ERASE/UNKNOWN have been tested.
             Covers that ERASE operation is performed on a page and on entire bank.
-            Covers data and info partition selection.
-            Covers types of informational partitions.
-            Covers if request of erase suspension occured.
-            Covers High Endurance feature.
-            Covers scramble feature.
-            Covers ECC feature.
+            Covers data and info partitions selection.
             All valid combinations of the above will also be crossed.
             '''
     }
     {
-      name: flash_words_len_cg
+      name: erase_susp_cg
       desc: '''
-            Covers number of flash words for operations READ/PROGRAM.
-            The minimum tested number of words is 0 and the maximum length is 2^12-1.
-            Cover an acceptable distribution of lengths has been seen including corner cases
-            (length 0 and length 2^12-1).
-            '''
-    }
-    {
-      name: region_range_cg
-      desc: '''
-            Covers all possible numbers of region base pages abd region size pages which are given
-            in pages. Cover an acceptable distribution of lengths has been seen including corner
-            cases (value 0 and maximum value for which it makes sense to test it).
+            Covers if request of erase suspension occured.
             '''
     }
     {
diff --git a/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov.core b/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov.core
new file mode 100644
index 0000000..d04d5e1
--- /dev/null
+++ b/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov.core
@@ -0,0 +1,21 @@
+CAPI=2:
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+name: "lowrisc:dv:flash_ctrl_cov"
+description: "FLASH_CTRL functional coverage interface & bind."
+
+filesets:
+  files_dv:
+    depend:
+      - lowrisc:dv:dv_utils
+      - lowrisc:ip:flash_ctrl
+    files:
+      - flash_ctrl_cov_if.sv
+      - flash_ctrl_cov_bind.sv
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - files_dv
diff --git a/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov_bind.sv b/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov_bind.sv
new file mode 100644
index 0000000..21b8f34
--- /dev/null
+++ b/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov_bind.sv
@@ -0,0 +1,8 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Binds FLASH_CTRL functional coverage interface to the top level FLASH_CTRL module.
+module flash_ctrl_cov_bind;
+  bind flash_ctrl flash_ctrl_cov_if u_flash_ctrl_cov_if (.*);
+endmodule
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
new file mode 100644
index 0000000..33da7ee
--- /dev/null
+++ b/hw/ip/flash_ctrl/dv/cov/flash_ctrl_cov_if.sv
@@ -0,0 +1,23 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Implements functional coverage for FLASH_CTRL
+
+interface flash_ctrl_cov_if (
+  input logic clk_i,
+  input logic rst_ni
+);
+
+  import uvm_pkg::*;
+  import flash_ctrl_pkg::*;
+  import dv_utils_pkg::*;
+  `include "dv_fcov_macros.svh"
+
+  ///////////////////////////////////
+  // Control register cover points //
+  ///////////////////////////////////
+
+  // TODO add covergroups and coverpoints
+
+endinterface
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 c9505ef..eee66ae 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
@@ -15,18 +15,28 @@
   // flash_ctrl_env_cfg: cfg
 
   // covergroups
-  // [add covergroups here]
+
+  covergroup control_cg with function sample (flash_op_t flash_cfg_opts);
+    part_cp : coverpoint flash_cfg_opts.partition;
+    erase_cp : coverpoint flash_cfg_opts.erase_type;
+    op_cp : coverpoint flash_cfg_opts.op;
+    op_part_cross : cross part_cp, op_cp;
+  endgroup // control_cg
+
+  covergroup erase_susp_cg with function sample (bit erase_req = 0);
+    erase_susp_cp : coverpoint erase_req {
+      bins erase_susp_true = {1};
+    }
+  endgroup // erase_susp_cg
 
   function new(string name, uvm_component parent);
     super.new(name, parent);
-    // [instantiate covergroups here]
+    control_cg = new();
+    erase_susp_cg = new();
   endfunction : new
 
   virtual function void build_phase(uvm_phase phase);
     super.build_phase(phase);
-    // [or instantiate covergroups here]
-    // Please instantiate sticky_intr_cov array of objects for all interrupts that are sticky
-    // See cip_base_env_cov for details
   endfunction
 
 endclass
diff --git a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_pkg.sv b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_pkg.sv
index 7dd99fc..4dec2bc 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_pkg.sv
+++ b/hw/ip/flash_ctrl/dv/env/flash_ctrl_env_pkg.sv
@@ -75,12 +75,12 @@
   parameter uint FlashFullDataWidth = flash_ctrl_pkg::DataWidth + 4;
 
   // params for words
-  parameter uint NUM_PAGE_WORDS    = FlashNumBusWordsPerPage;
+  parameter uint NUM_PAGE_WORDS = FlashNumBusWordsPerPage;
   parameter uint NUM_BK_DATA_WORDS = FlashNumBusWordsPerBank;  // 256 pages
-  parameter uint NUM_BK_INFO_WORDS = InfoTypeBusWords[0];      // 10 pages
+  parameter uint NUM_BK_INFO_WORDS = InfoTypeBusWords[0];  // 10 pages
 
   // params for num of pages
-  parameter uint NUM_PAGE_PART_DATA  = flash_ctrl_pkg::PagesPerBank;
+  parameter uint NUM_PAGE_PART_DATA = flash_ctrl_pkg::PagesPerBank;
   parameter uint NUM_PAGE_PART_INFO0 = flash_ctrl_pkg::InfoTypeSize[0];
   parameter uint NUM_PAGE_PART_INFO1 = flash_ctrl_pkg::InfoTypeSize[1];
   parameter uint NUM_PAGE_PART_INFO2 = flash_ctrl_pkg::InfoTypeSize[2];
@@ -155,21 +155,21 @@
   } flash_sec_part_e;
 
   typedef enum {
-    AllOnes,       // All 1s
-    AllZeros,      // All 0s
-    CustomVal      // Custom Value
+    AllOnes,   // All 1s
+    AllZeros,  // All 0s
+    CustomVal  // Custom Value
   } flash_scb_wr_e;
 
   typedef struct packed {
-    mubi4_t  en;           // enable this region
-    mubi4_t  read_en;      // enable reads
-    mubi4_t  program_en;   // enable write
-    mubi4_t  erase_en;     // enable erase
-    mubi4_t  scramble_en;  // enable scramble
-    mubi4_t  ecc_en;       // enable ecc
-    mubi4_t  he_en;        // enable high endurance
-    uint num_pages;        // 0:NumPages % start_page
-    uint start_page;       // 0:NumPages-1
+    mubi4_t en;           // enable this region
+    mubi4_t read_en;      // enable reads
+    mubi4_t program_en;   // enable write
+    mubi4_t erase_en;     // enable erase
+    mubi4_t scramble_en;  // enable scramble
+    mubi4_t ecc_en;       // enable ecc
+    mubi4_t he_en;        // enable high endurance
+    uint    num_pages;    // 0:NumPages % start_page
+    uint    start_page;   // 0:NumPages-1
   } flash_mp_region_cfg_t;
 
   typedef struct packed {
@@ -197,7 +197,7 @@
   typedef bit [TL_AW-1:0] addr_t;
 
   parameter uint ALL_ZEROS = 32'h0000_0000;
-  parameter uint ALL_ONES  = 32'hffff_ffff;
+  parameter uint ALL_ONES = 32'hffff_ffff;
 
   // Parameter for Probing into the DUT RMA FSM
   parameter string PRB_RMA_FSM = "tb.dut.u_flash_hw_if.state_q";
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 127615c..b87ca21 100644
--- a/hw/ip/flash_ctrl/dv/env/flash_ctrl_scoreboard.sv
+++ b/hw/ip/flash_ctrl/dv/env/flash_ctrl_scoreboard.sv
@@ -133,6 +133,7 @@
 
   virtual task process_tl_access(tl_seq_item item, tl_channels_e channel, string ral_name);
     uvm_reg        csr;
+    string         csr_wr_name = "";
     bit            do_read_check = 1'b1;
     bit            write = item.is_write();
     uvm_reg_addr_t csr_addr = cfg.ral_models[ral_name].get_word_aligned_addr(item.a_addr);
@@ -141,6 +142,8 @@
     bit            addr_phase_write = (write && channel == AddrChannel);
     bit            data_phase_read = (!write && channel == DataChannel);
     bit            data_phase_write = (write && channel == DataChannel);
+    flash_op_t     flash_op_cov;
+    bit            erase_req;
 
     // if access was to a valid csr, get the csr handle
     if ((is_mem_addr(
@@ -179,9 +182,10 @@
         end else if (csr_addr inside {cfg.ral_models[ral_name].csr_addrs}) begin
           csr = cfg.ral_models[ral_name].default_map.get_reg_by_offset(csr_addr);
           `DV_CHECK_NE_FATAL(csr, null)
+          csr_wr_name = csr.get_name();
           void'(csr.predict(.value(item.a_data), .kind(UVM_PREDICT_WRITE), .be(item.a_mask)));
           `uvm_info(`gfn, $sformatf("SCB EXP FLASH REG: 0x%0h", csr_addr), UVM_HIGH)
-          if ((csr.get_name() == "control") && cfg.scb_check) begin
+          if ((csr_wr_name == "control") && cfg.scb_check) begin
             csr_rd(.ptr(ral.control), .value(data), .backdoor(1'b1));
             curr_op = get_field_val(ral.control.op, data);
             if (curr_op == 2) begin  //erase op
@@ -214,6 +218,34 @@
               end
             end
           end
+          // coverage collection
+          case (csr_wr_name)
+            "control": begin
+               csr_rd(.ptr(ral.control), .value(data), .backdoor(1'b1));
+               curr_op = get_field_val(ral.control.op, data);
+               erase_sel = get_field_val(ral.control.erase_sel, data);
+               part_sel = get_field_val(ral.control.partition_sel, data);
+               info_sel = get_field_val(ral.control.info_sel, data);
+               part = calc_part(part_sel, info_sel);
+               flash_op_cov.partition  = part;
+               flash_op_cov.erase_type = erase_sel;
+               flash_op_cov.op = curr_op;
+               if (cfg.en_cov) begin
+                 cov.control_cg.sample(flash_op_cov);
+               end
+            end
+            "erase_suspend": begin
+               csr_rd(.ptr(ral.erase_suspend), .value(data), .backdoor(1'b1));
+               erase_req = get_field_val(ral.erase_suspend.req, data);
+               if (cfg.en_cov) begin
+                 cov.erase_susp_cg.sample(erase_req);
+               end
+            end
+            default: begin
+            // TODO: Uncomment once func cover is implemented
+            // `uvm_info(`gfn, $sformatf("Not for func coverage: %0s", csr.get_full_name()))
+            end
+          endcase
         end
       end
 
diff --git a/hw/ip/flash_ctrl/dv/flash_ctrl_sim.core b/hw/ip/flash_ctrl/dv/flash_ctrl_sim.core
index 6ad0b24..b76c17f 100644
--- a/hw/ip/flash_ctrl/dv/flash_ctrl_sim.core
+++ b/hw/ip/flash_ctrl/dv/flash_ctrl_sim.core
@@ -18,6 +18,7 @@
       - lowrisc:dv:mem_bkdr_util
       - lowrisc:dv:flash_ctrl_test
       - lowrisc:dv:flash_ctrl_sva
+      - lowrisc:dv:flash_ctrl_cov
     files:
       - tb/tb.sv
     file_type: systemVerilogSource
diff --git a/hw/ip/flash_ctrl/dv/flash_ctrl_sim_cfg.hjson b/hw/ip/flash_ctrl/dv/flash_ctrl_sim_cfg.hjson
index 4ad3b5b..a5ad86e 100644
--- a/hw/ip/flash_ctrl/dv/flash_ctrl_sim_cfg.hjson
+++ b/hw/ip/flash_ctrl/dv/flash_ctrl_sim_cfg.hjson
@@ -57,7 +57,7 @@
   ]
 
   // Add additional tops for simulation.
-  sim_tops: ["flash_ctrl_bind"]
+  sim_tops: ["flash_ctrl_bind","flash_ctrl_cov_bind"]
 
   // Default iterations for all tests - each test entry can override this.
   reseed: 50