[aes/dv] added coverage outline to aes

Signed-off-by: Rasmus Madsen <rasmus.madsen@wdc.com>
diff --git a/hw/ip/aes/dv/aes_sim.core b/hw/ip/aes/dv/aes_sim.core
index 514746f..b2b2023 100644
--- a/hw/ip/aes/dv/aes_sim.core
+++ b/hw/ip/aes/dv/aes_sim.core
@@ -13,6 +13,7 @@
     depend:
       - lowrisc:dv:aes_test
       - lowrisc:dv:aes_sva
+      - lowrisc:dv:aes_cov
     files:
       - tb/tb.sv
     file_type: systemVerilogSource
diff --git a/hw/ip/aes/dv/aes_sim_cfg.hjson b/hw/ip/aes/dv/aes_sim_cfg.hjson
index db595d4..16e84b6 100644
--- a/hw/ip/aes/dv/aes_sim_cfg.hjson
+++ b/hw/ip/aes/dv/aes_sim_cfg.hjson
@@ -37,7 +37,7 @@
                 // "{proj_root}/hw/dv/tools/dvsim/tests/stress_tests.hjson"]
 
   // Add additional tops for simulation.
-  sim_tops: ["aes_bind"]
+  sim_tops: [ "aes_bind", "aes_cov_bind"]
 
   // Default iterations for all tests - each test entry can override this.
   reseed: 50
diff --git a/hw/ip/aes/dv/cov/aes_cov.core b/hw/ip/aes/dv/cov/aes_cov.core
new file mode 100644
index 0000000..8296517
--- /dev/null
+++ b/hw/ip/aes/dv/cov/aes_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:aes_cov"
+description: "AES functional coverage interface & bind."
+
+filesets:
+  files_dv:
+    depend:
+      - lowrisc:dv:dv_utils
+      - lowrisc:ip:aes:0.6
+    files:
+      - aes_cov_if.sv
+      - aes_cov_bind.sv
+    file_type: systemVerilogSource
+
+targets:
+  default:
+    filesets:
+      - files_dv
diff --git a/hw/ip/aes/dv/cov/aes_cov_bind.sv b/hw/ip/aes/dv/cov/aes_cov_bind.sv
new file mode 100644
index 0000000..37f9fdf
--- /dev/null
+++ b/hw/ip/aes/dv/cov/aes_cov_bind.sv
@@ -0,0 +1,12 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// Binds UART functional coverage interaface to the top level AES module.
+module aes_cov_bind;
+
+  bind aes aes_cov_if u_aes_cov_if (
+    .clk_i      (clk_i)
+  );
+
+endmodule
diff --git a/hw/ip/aes/dv/cov/aes_cov_if.sv b/hw/ip/aes/dv/cov/aes_cov_if.sv
new file mode 100644
index 0000000..1d504ec
--- /dev/null
+++ b/hw/ip/aes/dv/cov/aes_cov_if.sv
@@ -0,0 +1,157 @@
+// 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 AES
+
+interface aes_cov_if
+  (
+   input logic clk_i // not sure I will use this yet
+   );
+
+  import uvm_pkg::*;
+  import aes_pkg::*;
+  import dv_utils_pkg::*;
+  `include "dv_fcov_macros.svh"
+
+  bit          en_full_cov = 1'b1;
+  bit          en_intg_cov = 1'b1;
+
+  ///////////////////////////////////
+  // Control register cover points //
+  ///////////////////////////////////
+
+  covergroup aes_ctrl_cg  with function sample(bit                                 aes_op,
+                                               bit [aes_pkg::AES_MODE_WIDTH-1:0]   aes_mode,
+                                               bit [aes_pkg::AES_KEYLEN_WIDTH-1:0] aes_keylen,
+                                               bit                                 aes_man_op,
+                                               bit                                 aes_force_0mask
+                                               );
+    option.per_instance = 1;
+    option.name         = "aes_ctrl_cg";
+
+    cp_operation: coverpoint aes_op
+      {
+       bins enc         = {AES_ENC};
+       bins dec         = {AES_DEC};
+       }
+
+     cp_mode: coverpoint aes_mode
+      {
+       bins ecb     = { AES_ECB};
+       bins cbc     = { AES_CBC };
+       bins cfb     = { AES_CFB };
+       bins ofb     = { AES_OFB };
+       bins ctr     = { AES_CTR };
+       bins none    = { AES_NONE };
+       bins illegal = { [0:$] } with ($countones(item) != 1);
+      }
+
+    cp_key_len: coverpoint aes_keylen
+      {
+       bins aes_128 = {AES_128};
+       bins aes_192 = {AES_192};
+       bins aes_256 = {AES_256};
+       bins illegal = { [0:$] } with ($countones(item) != 1);
+      }
+
+    cp_manual_operation: coverpoint aes_man_op
+      {
+       bins auto_mode   = { 1'b0 };
+       bins manual_mode = { 1'b1 };
+      }
+
+    cp_force_0_masks: coverpoint aes_force_0mask;
+
+    // Cross coverage points
+    // All key_lens are tested in all modes
+    cr_mode_key_len: cross cp_mode, cp_key_len;
+    // all modes are tested in both auto an manual operation
+    cr_mode_man_op:  cross cp_mode, cp_manual_operation;
+    // All modes used in both incryption and decryption
+    cr_mode_op:      cross cp_mode, cp_operation;
+  endgroup // aes_ctrl_cg
+
+
+  ///////////////////////////////////
+  // Status register cover points  //
+  ///////////////////////////////////
+
+  covergroup aes_status_cg with function sample(status_t aes_status);
+    option.per_instance = 1;
+    option.name         = "aes_status_cg";
+  endgroup // aes_status_cg
+
+
+  ///////////////////////////////////
+  // Trigger register cover points //
+  ///////////////////////////////////
+
+  covergroup aes_trigger_cg with function sample(bit aes_start,
+                                                 bit aes_key_iv_datain_clear,
+                                                 bit aes_dataout_clear,
+                                                 bit aes_prng_reseed
+                                                 );
+    option.per_instance = 1;
+    option.name         = "aes_trigger_cg";
+
+    cp_start:                coverpoint aes_start;
+    cp_key_iv_datain_clear:  coverpoint aes_key_iv_datain_clear;
+    cp_dataout_clear:        coverpoint aes_dataout_clear;
+    cp_prng_reseed:          coverpoint aes_prng_reseed;
+
+    cr_clear: cross cp_key_iv_datain_clear, cp_dataout_clear;
+
+  endgroup // aes_trigger_cg
+
+  ///////////////////////////////////
+  // Alert register cover points   //
+  ///////////////////////////////////
+
+  covergroup aes_alert_cg with function sample(alert_test_t alert_test);
+    option.per_instance = 1;
+    option.name         = "aes_test_alert_cg";
+  endgroup // aes_alert_cg
+
+
+  ///////////////////////////////////
+  // Instantiation Macros          //
+  ///////////////////////////////////
+
+ `DV_FCOV_INSTANTIATE_CG(aes_ctrl_cg, en_full_cov)
+ `DV_FCOV_INSTANTIATE_CG(aes_status_cg, en_full_cov)
+ `DV_FCOV_INSTANTIATE_CG(aes_trigger_cg, en_full_cov)
+ `DV_FCOV_INSTANTIATE_CG(aes_alert_cg, en_full_cov)
+
+
+  ///////////////////////////////////
+  // Sample functions              //
+  // needed for xcelium            //
+  ///////////////////////////////////
+
+  function automatic void cg_ctrl_sample(bit                                 aes_op,
+                                         bit [aes_pkg::AES_MODE_WIDTH-1:0]   aes_mode,
+                                         bit [aes_pkg::AES_KEYLEN_WIDTH-1:0] aes_keylen,
+                                         bit                                 aes_man_op,
+                                         bit                                 aes_force_0mask
+                                         );
+    aes_ctrl_cg_inst.sample(aes_op, aes_mode, aes_keylen, aes_man_op, aes_force_0mask);
+  endfunction
+
+  function automatic void cg_status_sample(bit [31:0] val);
+    aes_status_cg_inst.sample(val);
+  endfunction
+
+  function automatic void cg_trigger_sample(bit aes_start,
+                                            bit aes_key_iv_datain_clear,
+                                            bit aes_dataout_clear,
+                                            bit aes_prng_reseed
+                                           );
+    aes_trigger_cg_inst.sample(aes_start, aes_key_iv_datain_clear, aes_dataout_clear, aes_prng_reseed);
+  endfunction
+
+  function automatic void cg_alert_test_sample(bit [31:0] val);
+    aes_alert_cg_inst.sample(val);
+  endfunction
+
+endinterface
diff --git a/hw/ip/aes/dv/env/aes_env.core b/hw/ip/aes/dv/env/aes_env.core
index 636bf8b..9f26142 100644
--- a/hw/ip/aes/dv/env/aes_env.core
+++ b/hw/ip/aes/dv/env/aes_env.core
@@ -14,6 +14,7 @@
       - lowrisc:dv:cip_lib
       - lowrisc:dv:csr_utils
       - lowrisc:dv:aes_model_dpi
+      - lowrisc:dv:aes_cov
     files:
       - aes_env_pkg.sv
       - aes_seq_item.sv: {is_include_file: true}
diff --git a/hw/ip/aes/dv/env/aes_env_pkg.sv b/hw/ip/aes/dv/env/aes_env_pkg.sv
index a3f1294..c90c856 100644
--- a/hw/ip/aes/dv/env/aes_env_pkg.sv
+++ b/hw/ip/aes/dv/env/aes_env_pkg.sv
@@ -43,17 +43,6 @@
     bit          mode;
   } cfg_error_type_t;
 
-  typedef struct packed {
-    logic [31:7] unused;
-    logic        alert_fatal_fault;
-    logic        alert_recov_ctrl_update_err;
-    logic        input_ready;
-    logic        output_valid;
-    logic        output_lost;
-    logic        stall;
-    logic        idle;
-  } status_t;
-
 
   // package sources
  `include "aes_env_cfg.sv"
diff --git a/hw/ip/aes/dv/env/aes_message_item.sv b/hw/ip/aes/dv/env/aes_message_item.sv
index a952de2..a57f4ed 100644
--- a/hw/ip/aes/dv/env/aes_message_item.sv
+++ b/hw/ip/aes/dv/env/aes_message_item.sv
@@ -184,7 +184,7 @@
    constraint c_manual_operation {
                   manual_operation dist { 0:/ (100 - manual_operation_pct),
                                           1:/ manual_operation_pct};
-   };
+   }
 
 
   function void add_data_item(aes_seq_item item);
diff --git a/hw/ip/aes/dv/env/aes_scoreboard.sv b/hw/ip/aes/dv/env/aes_scoreboard.sv
index af66900..ee7d1f9 100644
--- a/hw/ip/aes/dv/env/aes_scoreboard.sv
+++ b/hw/ip/aes/dv/env/aes_scoreboard.sv
@@ -26,6 +26,7 @@
   int          corrupt_cnt        = 0;        // number of aes_mode errors seen
   int          skipped_cnt        = 0;        // number of skipped messages
 
+  virtual      aes_cov_if   cov_if;          // handle to aes coverage interface
   // local queues to hold incoming packets pending comparison //
 
   // Items containing both input and output data, ready to be added to a message
@@ -42,6 +43,10 @@
     item_fifo   = new();
     input_item  = new("input_item");
     output_item = new ();
+
+    if (!uvm_config_db#(virtual aes_cov_if)::get(null, "*.env" , "aes_cov_if", cov_if)) begin
+      `uvm_fatal(`gfn, $sformatf("FAILED TO GET HANDLE TO COVER IF"))
+    end
   endfunction
 
 
@@ -87,13 +92,20 @@
       csr_name = csr.get_name();
       case (1)
         // add individual case item for each csr
+        (!uvm_re_match("alert_test", csr_name)): begin
+          // TODO
+          cov_if.cg_alert_test_sample(item.a_data);
+        end
+
+
         (!uvm_re_match("ctrl_shadowed", csr_name)): begin
           if (write) begin
-            input_item.manual_op = item.a_data[10];
-            input_item.key_len   = item.a_data[9:7];
-            `downcast(input_item.operation, item.a_data[0]);
+//            cov_if.cg_ctrl_sample(item.a_data);
+            input_item.manual_op = get_field_val(ral.ctrl_shadowed.manual_operation, item.a_data);
+            input_item.key_len   = get_field_val(ral.ctrl_shadowed.key_len, item.a_data);
+            `downcast(input_item.operation, get_field_val(ral.ctrl_shadowed.operation ,item.a_data));
             input_item.valid = 1'b1;
-            case (item.a_data[6:1])
+            case (get_field_val(ral.ctrl_shadowed.mode, item.a_data))
               6'b00_0001:  input_item.mode = AES_ECB;
               6'b00_0010:  input_item.mode = AES_CBC;
               6'b00_0100:  input_item.mode = AES_CFB;
@@ -101,7 +113,15 @@
               6'b01_0000:  input_item.mode = AES_CTR;
               6'b10_0000:  input_item.mode = AES_NONE;
               default:     input_item.mode = AES_NONE;
-            endcase // case item.a_data[4:1]
+            endcase
+            // sample coverage on ctrl register
+            cov_if.cg_ctrl_sample(get_field_val(ral.ctrl_shadowed.operation, item.a_data),
+                                  get_field_val(ral.ctrl_shadowed.mode, item.a_data),
+                                  get_field_val(ral.ctrl_shadowed.key_len, item.a_data),
+                                  get_field_val(ral.ctrl_shadowed.manual_operation, item.a_data),
+                                  get_field_val(ral.ctrl_shadowed.force_zero_masks, item.a_data)
+                                  );
+
             input_item.clean();
             input_item.start_item = 1;
           end
@@ -149,6 +169,11 @@
 
       (!uvm_re_match("trigger", csr_name)): begin
         //start triggered
+        cov_if.cg_trigger_sample(get_field_val(ral.trigger.start, item.a_data),
+                                 get_field_val(ral.trigger.key_iv_data_in_clear, item.a_data),
+                                 get_field_val(ral.trigger.data_out_clear, item.a_data),
+                                 get_field_val(ral.trigger.prng_reseed, item.a_data)
+                                );
         `uvm_info(`gfn, $sformatf("\n CLEAR REGISTER SEEN 0x%h", item.a_data), UVM_MEDIUM)
         if (get_field_val(ral.trigger.start, item.a_data)) begin
           ok_to_fwd                = 1;
@@ -188,9 +213,9 @@
         end
        end
 
-      // "status": begin
-      //   //TBD
-      // end
+      // (!uvm_re_match("status", csr_name)): begin
+      //   // not used in scoreboard
+      //  end
 
        default: begin
          // DO nothing- trying to write to a read only register
@@ -359,7 +384,10 @@
           output_item.data_out[3]     = item.d_data;
           output_item.data_out_vld[3] = 1;
         end
+
         "status": begin
+          cov_if.cg_status_sample(item.d_data);
+
           // if dut IDLE and able to accept input
           // and no output is ready
           // there won't be a response for this item
diff --git a/hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv b/hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv
index ebd4a66..8f1d797 100644
--- a/hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv
+++ b/hw/ip/aes/dv/env/seq_lib/aes_base_vseq.sv
@@ -82,26 +82,34 @@
 
 
   virtual task set_operation(bit operation);
-    ral.ctrl_shadowed.operation.set(operation);
-    csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+    if (ral.ctrl_shadowed.operation.get_mirrored_value() != operation) begin
+      ral.ctrl_shadowed.operation.set(operation);
+      csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+    end
   endtask // set_operation
 
 
   virtual task set_mode(bit [5:0] mode);
-    ral.ctrl_shadowed.mode.set(mode);
-    csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+    if (ral.ctrl_shadowed.mode.get_mirrored_value() != mode) begin
+      ral.ctrl_shadowed.mode.set(mode);
+      csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+    end
   endtask
 
 
   virtual task set_key_len(bit [2:0] key_len);
-    ral.ctrl_shadowed.key_len.set(key_len);
-    csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+    if (ral.ctrl_shadowed.key_len.get_mirrored_value() != key_len) begin
+      ral.ctrl_shadowed.key_len.set(key_len);
+      csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+    end
   endtask
 
 
   virtual task set_manual_operation(bit manual_operation);
-    ral.ctrl_shadowed.manual_operation.set(manual_operation);
-    csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+    if (ral.ctrl_shadowed.manual_operation.get_mirrored_value() != manual_operation) begin
+      ral.ctrl_shadowed.manual_operation.set(manual_operation);
+      csr_update(.csr(ral.ctrl_shadowed), .en_shadow_wr(1'b1), .blocking(1));
+    end
   endtask
 
 
diff --git a/hw/ip/aes/dv/tb/tb.sv b/hw/ip/aes/dv/tb/tb.sv
index ba71b2b..783c2bb 100644
--- a/hw/ip/aes/dv/tb/tb.sv
+++ b/hw/ip/aes/dv/tb/tb.sv
@@ -25,6 +25,7 @@
   pins_if #(1) devmode_if(devmode);
   tl_if tl_if(.clk(clk), .rst_n(rst_n));
 
+
   `DV_ALERT_IF_CONNECT
 
   // dut
@@ -53,6 +54,8 @@
     uvm_config_db#(intr_vif)::set(null, "*.env", "intr_vif", intr_if);
     uvm_config_db#(devmode_vif)::set(null, "*.env", "devmode_vif", devmode_if);
     uvm_config_db#(virtual tl_if)::set(null, "*.env.m_tl_agent*", "vif", tl_if);
+    uvm_config_db#(virtual aes_cov_if)::set(null, "*.env", "aes_cov_if", dut.u_aes_cov_if );
+
     $timeformat(-12, 0, " ps", 12);
     run_test();
   end
diff --git a/hw/ip/aes/dv/tests/aes_smoke_test.sv b/hw/ip/aes/dv/tests/aes_smoke_test.sv
index c4baeb9..8290f91 100644
--- a/hw/ip/aes/dv/tests/aes_smoke_test.sv
+++ b/hw/ip/aes/dv/tests/aes_smoke_test.sv
@@ -16,8 +16,8 @@
   function void configure_env();
     super.configure_env();
     cfg.error_types              = 0;     // no errors in smoke test
-    cfg.num_messages_min         = 2;
-    cfg.num_messages_max         = 2;
+    cfg.num_messages_min         = 3;
+    cfg.num_messages_max         = 3;
     // message related knobs
     cfg.ecb_weight               = 10;
     cfg.cbc_weight               = 10;