[flash_ctrl] First step fix for flash ECC

- Should address #9397
- Merge the separate flash data / metadata memories back into one
- Update the backdoor path to use the full 76_68 ECC scheme
- Update flash backdoor load to create the extra 4-bits of integrity
  ECC for the purposes of backdoor load.
- The flash routine is responsible for the 4-bit integrity ECC, while
  the mem_bkdr_util routine is responsible for the 8-bit reliability
  ECC

- In the future, the same routine that creates the 4-bit integrity
  ECC will also be responsible for scramble, the final backdoor load
  will only be aware of the 8-bit reliability ECC.

Signed-off-by: Timothy Chen <timothytim@google.com>
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 ca74199..f4dd4bb 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
@@ -130,7 +130,11 @@
       logic [TL_DW-1:0] loc_data = (scheme == FlashMemInitCustom) ? data[i] :
           (scheme == FlashMemInitRandomize) ? $urandom() : wr_data;
 
-      mem_bkdr_util_h[flash_op.partition][addr_attrs.bank].write32(addr_attrs.bank_addr, loc_data);
+      _flash_full_write(flash_op.partition,
+                        addr_attrs.bank,
+                        addr_attrs.bank_addr,
+                        loc_data);
+
       `uvm_info(`gfn, $sformatf("flash_mem_bkdr_write: partition = %s , {%s} = 0x%0h",
                                 flash_op.partition.name(), addr_attrs.sprint(), loc_data),
                                 UVM_MEDIUM)
@@ -145,6 +149,43 @@
     end
   endfunction : flash_mem_bkdr_write
 
+  // Helper function that takes a 32-bit data and correctly populates the integrity ECC
+  //
+  function void _flash_full_write(flash_dv_part_e partition,
+                                  uint bank,
+                                  // bus word aligned address
+                                  bit [TL_AW-1:0] addr,
+                                  bit [TL_DW-1:0] wr_data);
+
+    // read back the full flash word
+    logic [flash_ctrl_pkg::DataWidth-1:0] data;
+    logic [7:0] intg_data;
+    logic is_upper = addr[flash_ctrl_pkg::DataByteWidth-1];
+    logic [TL_AW-1:0] aligned_addr = addr;
+
+    if (is_upper) begin
+       aligned_addr = {addr[TL_AW-1:FlashDataByteWidth], {FlashDataByteWidth{1'b0}}};
+    end
+
+    // get the full flash word
+    data = mem_bkdr_util_h[partition][bank].read64(aligned_addr);
+
+    // writing the upper portion of the flash word
+    if (is_upper) begin
+      data = {wr_data, data[TL_DW-1:0]};
+    end else begin
+      data = {data[flash_ctrl_pkg::DataWidth -: TL_DW], wr_data};
+    end
+
+    // calculate truncated integrity
+    {intg_data, data} = prim_secded_pkg::prim_secded_hamming_72_64_enc(data);
+
+    // program fully via backdoor
+    mem_bkdr_util_h[partition][bank].write64(aligned_addr, {intg_data[3:0], data});
+
+  endfunction
+
+
   // Helper function that randomizes the half-word at the given address if unknown.
   //
   // When the 'other' flash half-word is being written by the flash_mem_bkdr_write() method, the
@@ -157,7 +198,7 @@
     if ($isunknown(data)) begin
       `DV_CHECK_STD_RANDOMIZE_FATAL(data)
       `uvm_info(`gfn, $sformatf("Data at 0x%0h is Xs, writing random 0x%0h", addr, data), UVM_HIGH)
-      mem_bkdr_util_h[partition][bank].write32(addr, data);
+      _flash_full_write(partition, bank, addr, data);
     end
   endfunction
 
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 a568709..3f00c18 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
@@ -67,6 +67,8 @@
                                             FlashPageWidth - 1;
   parameter uint FlashMemAddrBankMsbBit   = FlashDataByteWidth + FlashWordLineWidth +
                                             FlashPageWidth + FlashBankWidth - 1;
+  // Need to create a design parameter for this
+  parameter uint FlashFullDataWidth       = flash_ctrl_pkg::DataWidth + 4;
 
   // types
   typedef enum int {
diff --git a/hw/ip/flash_ctrl/dv/tb/tb.sv b/hw/ip/flash_ctrl/dv/tb/tb.sv
index 399fa7b..c9b0fdf 100644
--- a/hw/ip/flash_ctrl/dv/tb/tb.sv
+++ b/hw/ip/flash_ctrl/dv/tb/tb.sv
@@ -183,7 +183,7 @@
                               .path  (`FLASH_DATA_MEM_HIER_STR(i)),
                               .depth ($size(`FLASH_DATA_MEM_HIER(i))),
                               .n_bits($bits(`FLASH_DATA_MEM_HIER(i))),
-                              .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_72_64));
+                              .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_76_68));
         uvm_config_db#(mem_bkdr_util)::set(null, "*.env", m_mem_bkdr_util.get_name(),
                                            m_mem_bkdr_util);
         part = part.next();
@@ -196,7 +196,7 @@
                                 .path  (`FLASH_INFO_MEM_HIER_STR(i, j)),
                                 .depth ($size(`FLASH_INFO_MEM_HIER(i, j))),
                                 .n_bits($bits(`FLASH_INFO_MEM_HIER(i, j))),
-                                .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_72_64));
+                                .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_76_68));
           uvm_config_db#(mem_bkdr_util)::set(null, "*.env", m_mem_bkdr_util.get_name(),
                                              m_mem_bkdr_util);
           part = part.next();
diff --git a/hw/top_earlgrey/dv/tb/tb.sv b/hw/top_earlgrey/dv/tb/tb.sv
index 8443db9..3a383b6 100644
--- a/hw/top_earlgrey/dv/tb/tb.sv
+++ b/hw/top_earlgrey/dv/tb/tb.sv
@@ -310,7 +310,7 @@
           .path  (`DV_STRINGIFY(`FLASH0_DATA_MEM_HIER)),
           .depth ($size(`FLASH0_DATA_MEM_HIER)),
           .n_bits($bits(`FLASH0_DATA_MEM_HIER)),
-          .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_72_64));
+          .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_76_68));
       `MEM_BKDR_UTIL_FILE_OP(m_mem_bkdr_util[FlashBank0Data], `FLASH0_DATA_MEM_HIER)
 
       `uvm_info("tb.sv", "Backdoor init flash 0 info", UVM_MEDIUM)
@@ -319,7 +319,7 @@
           .path  (`DV_STRINGIFY(`FLASH0_INFO_MEM_HIER)),
           .depth ($size(`FLASH0_INFO_MEM_HIER)),
           .n_bits($bits(`FLASH0_INFO_MEM_HIER)),
-          .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_72_64));
+          .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_76_68));
       `MEM_BKDR_UTIL_FILE_OP(m_mem_bkdr_util[FlashBank0Info], `FLASH0_INFO_MEM_HIER)
 
       `uvm_info("tb.sv", "Backdoor init flash 1 data", UVM_MEDIUM)
@@ -328,7 +328,7 @@
           .path  (`DV_STRINGIFY(`FLASH1_DATA_MEM_HIER)),
           .depth ($size(`FLASH1_DATA_MEM_HIER)),
           .n_bits($bits(`FLASH1_DATA_MEM_HIER)),
-          .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_72_64));
+          .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_76_68));
       `MEM_BKDR_UTIL_FILE_OP(m_mem_bkdr_util[FlashBank1Data], `FLASH0_DATA_MEM_HIER)
 
       `uvm_info("tb.sv", "Backdoor init flash 0 info", UVM_MEDIUM)
@@ -337,7 +337,7 @@
           .path  (`DV_STRINGIFY(`FLASH1_INFO_MEM_HIER)),
           .depth ($size(`FLASH1_INFO_MEM_HIER)),
           .n_bits($bits(`FLASH1_INFO_MEM_HIER)),
-          .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_72_64));
+          .err_detection_scheme(mem_bkdr_util_pkg::EccHamming_76_68));
       `MEM_BKDR_UTIL_FILE_OP(m_mem_bkdr_util[FlashBank1Info], `FLASH1_INFO_MEM_HIER)
 
       `uvm_info("tb.sv", "Backdoor init OTP", UVM_MEDIUM)