[otbn,dv] Add coverpoints for flag writes

Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
diff --git a/hw/ip/otbn/doc/dv/index.md b/hw/ip/otbn/doc/dv/index.md
index 2eaf734..811e2f7 100644
--- a/hw/ip/otbn/doc/dv/index.md
+++ b/hw/ip/otbn/doc/dv/index.md
@@ -134,6 +134,11 @@
 Each flag in each flag group should be set to one from zero by some instruction.
 Similarly, each flag in each flag group should be cleared to zero from one by some instruction.
 
+> These events are tracked in `flag_write_cg`.
+> This is called from `on_insn()` once for each flag group that is being written.
+> The covergroup contains eight coverpoints (for each flag set and cleared).
+> These are then crossed with the flag group.
+
 ### Instruction-based coverage
 
 As a processor, much of OTBN's coverage points are described in terms of instructions being executed.
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_env_cov.sv b/hw/ip/otbn/dv/uvm/env/otbn_env_cov.sv
index 3244139..0abfbaa 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_env_cov.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_env_cov.sv
@@ -306,6 +306,38 @@
 
   endgroup
 
+  covergroup flag_write_cg
+    with function sample(bit     flag_group,
+                         flags_t read_data,
+                         flags_t write_data);
+
+    // The following coverpoints track writes to the different flags in the flag group that set or
+    // clear the flag, respectively. These are then crossed with fg_cp because we want to see each
+    // event with each flag group.
+
+    fg_cp: coverpoint flag_group;
+
+    `DEF_SEEN_CP(set_Z_cp, write_data.Z & ~read_data.Z)
+    `DEF_SEEN_CP(set_L_cp, write_data.L & ~read_data.L)
+    `DEF_SEEN_CP(set_M_cp, write_data.M & ~read_data.M)
+    `DEF_SEEN_CP(set_C_cp, write_data.C & ~read_data.C)
+
+    `DEF_SEEN_CP(clr_Z_cp, read_data.Z & ~write_data.Z)
+    `DEF_SEEN_CP(clr_L_cp, read_data.L & ~write_data.L)
+    `DEF_SEEN_CP(clr_M_cp, read_data.M & ~write_data.M)
+    `DEF_SEEN_CP(clr_C_cp, read_data.C & ~write_data.C)
+
+    set_Z_cross: cross fg_cp, set_Z_cp;
+    set_L_cross: cross fg_cp, set_L_cp;
+    set_M_cross: cross fg_cp, set_M_cp;
+    set_C_cross: cross fg_cp, set_C_cp;
+
+    clr_Z_cross: cross fg_cp, clr_Z_cp;
+    clr_L_cross: cross fg_cp, clr_L_cp;
+    clr_M_cross: cross fg_cp, clr_M_cp;
+    clr_C_cross: cross fg_cp, clr_C_cp;
+  endgroup
+
   // Per-encoding covergroups //////////////////////////////////////////////////
   covergroup enc_bna_cg
     with function sample(mnem_str_t    mnemonic,
@@ -1480,6 +1512,7 @@
     super.new(name, parent);
 
     call_stack_cg = new;
+    flag_write_cg = new;
 
     enc_bna_cg = new;
     enc_bnaf_cg = new;
@@ -1613,6 +1646,13 @@
     // Call stack tracking.
     call_stack_cg.sample(rtl_item.call_stack_flags, rtl_item.call_stack_fullness);
 
+    // Flag set/clear tracking
+    for (int fg = 0; fg < 2; fg++) begin
+      if (rtl_item.flags_write_valid[fg]) begin
+        flag_write_cg.sample(fg[0], rtl_item.flags_read_data[fg], rtl_item.flags_write_data[fg]);
+      end
+    end
+
     // Per-encoding coverage. First, use insn_encodings to find the encoding for the instruction.
     // Every instruction mnemonic should have an associated encoding schema.
     encoding = insn_encodings[mnem];
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_trace_item.sv b/hw/ip/otbn/dv/uvm/env/otbn_trace_item.sv
index d875a7d..aa578b2 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_trace_item.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_trace_item.sv
@@ -15,8 +15,9 @@
   logic [255:0] wdr_operand_a;
   logic [255:0] wdr_operand_b;
 
-  // Flag output data
+  // Flag read/write data
   otbn_pkg::flags_t flags_read_data [2];
+  logic [1:0]       flags_write_valid;
   otbn_pkg::flags_t flags_write_data [2];
 
   // GPR and WDR write data
@@ -52,6 +53,7 @@
     `uvm_field_int        (wdr_operand_a,            UVM_DEFAULT | UVM_HEX)
     `uvm_field_int        (wdr_operand_b,            UVM_DEFAULT | UVM_HEX)
     `uvm_field_sarray_int (flags_read_data,          UVM_DEFAULT | UVM_HEX)
+    `uvm_field_int        (flags_write_valid,        UVM_DEFAULT | UVM_BIN)
     `uvm_field_sarray_int (flags_write_data,         UVM_DEFAULT | UVM_HEX)
     `uvm_field_int        (gpr_write_data,           UVM_DEFAULT | UVM_HEX)
     `uvm_field_int        (wdr_write_data,           UVM_DEFAULT | UVM_HEX)
diff --git a/hw/ip/otbn/dv/uvm/env/otbn_trace_monitor.sv b/hw/ip/otbn/dv/uvm/env/otbn_trace_monitor.sv
index 1bc3027..593d686 100644
--- a/hw/ip/otbn/dv/uvm/env/otbn_trace_monitor.sv
+++ b/hw/ip/otbn/dv/uvm/env/otbn_trace_monitor.sv
@@ -36,6 +36,7 @@
           item.wdr_operand_a = cfg.trace_vif.rf_bignum_rd_data_a;
           item.wdr_operand_b = cfg.trace_vif.rf_bignum_rd_data_b;
           item.flags_read_data = cfg.trace_vif.flags_read_data;
+          item.flags_write_valid = cfg.trace_vif.flags_write;
           item.flags_write_data = cfg.trace_vif.flags_write_data;
           item.gpr_write_data = cfg.trace_vif.rf_base_wr_data;
           item.wdr_write_data = cfg.trace_vif.rf_bignum_wr_data;