[sw,tests] SRAM execution test DV integration

Checks whether code can be executed from the SRAM depending on the values
of LC_STATE, OTP HW_CFG[IFETCH] and SRAM_CTRL EXEC CSR.

Signed-off-by: Dave Williams <dave.williams@ensilica.com>
diff --git a/hw/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv b/hw/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv
index 1ac0c98..d26b8b6 100644
--- a/hw/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv
+++ b/hw/dv/sv/mem_bkdr_util/mem_bkdr_util__otp.sv
@@ -6,13 +6,13 @@
 // This file is included in `mem_bkdr_util.sv` as a continuation of `mem_bkdr_util` class.
 
 virtual function void otp_write_lc_partition_state(lc_ctrl_state_pkg::lc_state_e lc_state);
-  for (int i = 0; i < LcStateSize; i+=4) begin
+  for (int i = 0; i < LcStateSize; i += 4) begin
     write32(i + LcStateOffset, lc_state[i*8+:32]);
   end
 endfunction
 
 virtual function void otp_write_lc_partition_cnt(lc_ctrl_state_pkg::lc_cnt_e lc_cnt);
-  for (int i = 0; i < LcTransitionCntSize; i+=4) begin
+  for (int i = 0; i < LcTransitionCntSize; i += 4) begin
     write32(i + LcTransitionCntOffset, lc_cnt[i*8+:32]);
   end
 endfunction : otp_write_lc_partition_cnt
@@ -22,32 +22,59 @@
 
   otp_write_lc_partition_cnt(lc_cnt);
   otp_write_lc_partition_state(lc_state);
-endfunction: otp_write_lc_partition
+endfunction : otp_write_lc_partition
 
 // The following steps are needed to backdoor write a secret partition:
 // 1). Scramble the RAW input data.
 // 2). Backdoor write the scrambled input data to OTP memory.
 // 3). Calculate the correct digest for the secret partition.
 // 4). Backdoor write digest data to OTP memory.
-virtual function void otp_write_secret0_partition(bit [TestUnlockTokenSize*8-1:0] unlock_token,
-                                                  bit [TestExitTokenSize*8-1:0]   exit_token);
+virtual function void otp_write_secret0_partition(
+    bit [TestUnlockTokenSize*8-1:0] unlock_token,
+    bit [TestExitTokenSize*8-1:0] exit_token);
   bit [Secret0DigestSize*8-1:0] digest;
 
   bit [TestUnlockTokenSize*8-1:0] scrambled_unlock_token;
   bit [TestExitTokenSize*8-1:0] scrambled_exit_token;
   bit [bus_params_pkg::BUS_DW-1:0] secret_data[$];
 
-  for (int i = 0; i < TestUnlockTokenSize; i+=8) begin
+  for (int i = 0; i < TestUnlockTokenSize; i += 8) begin
     scrambled_unlock_token[i*8+:64] = scramble_data(unlock_token[i*8+:64], Secret0Idx);
     write64(i + TestUnlockTokenOffset, scrambled_unlock_token[i*8+:64]);
   end
-  for (int i = 0; i < TestExitTokenSize; i+=8) begin
+  for (int i = 0; i < TestExitTokenSize; i += 8) begin
     scrambled_exit_token[i*8+:64] = scramble_data(exit_token[i*8+:64], Secret0Idx);
     write64(i + TestExitTokenOffset, scrambled_exit_token[i*8+:64]);
   end
 
-  secret_data = {<<32 {scrambled_exit_token, scrambled_unlock_token}};
+  secret_data = {<<32{scrambled_exit_token, scrambled_unlock_token}};
   digest = cal_digest(Secret0Idx, secret_data);
 
   write64(Secret0DigestOffset, digest);
 endfunction
+
+virtual function void otp_write_hw_cfg_partition(
+    bit [DeviceIdSize*8-1:0] device_id, bit [ManufStateSize*8-1:0] manuf_state,
+    bit [EnSramIfetchSize*8-1:0] en_sram_ifetch,
+    bit [EnCsrngSwAppReadSize*8-1:0] en_csrng_sw_app_read,
+    bit [EnEntropySrcFwReadSize*8-1:0] en_entropy_src_fw_read,
+    bit [EnEntropySrcFwOverSize*8-1:0] en_entropy_src_fw_over);
+  bit [HwCfgDigestSize*8-1:0] digest;
+
+  bit [bus_params_pkg::BUS_DW-1:0] hw_cfg_data[$];
+
+  for (int i = 0; i < DeviceIdSize; i += 4) begin
+    write32(i + DeviceIdOffset, device_id[i*8+:32]);
+  end
+  for (int i = 0; i < ManufStateSize; i += 4) begin
+    write32(i + ManufStateOffset, manuf_state[i*8+:32]);
+  end
+  write32(EnSramIfetchOffset,
+          {en_entropy_src_fw_over, en_entropy_src_fw_read, en_csrng_sw_app_read, en_sram_ifetch});
+
+  hw_cfg_data = {<<32 {32'h0, en_entropy_src_fw_over, en_entropy_src_fw_read,
+                       en_csrng_sw_app_read, en_sram_ifetch, manuf_state, device_id}};
+  digest = cal_digest(HwCfgIdx, hw_cfg_data);
+
+  write64(HwCfgDigestOffset, digest);
+endfunction
diff --git a/hw/top_earlgrey/data/chip_testplan.hjson b/hw/top_earlgrey/data/chip_testplan.hjson
index f5e6faa..595bf58 100644
--- a/hw/top_earlgrey/data/chip_testplan.hjson
+++ b/hw/top_earlgrey/data/chip_testplan.hjson
@@ -2090,7 +2090,7 @@
             For the retention SRAM, instruction fetch is completely disabled via design parameter.
             '''
       milestone: V2
-      tests: []
+      tests: ["chip_sw_sram_ctrl_execution_main"]
     }
     {
       name: chip_sw_sram_lc_escalation
diff --git a/hw/top_earlgrey/dv/chip_sim_cfg.hjson b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
index a36e98c..e0e62f9 100644
--- a/hw/top_earlgrey/dv/chip_sim_cfg.hjson
+++ b/hw/top_earlgrey/dv/chip_sim_cfg.hjson
@@ -353,6 +353,12 @@
       uvm_test_seq: chip_sw_rom_ctrl_integrity_check_vseq
       sw_images: ["sw/device/tests/rom_ctrl_integrity_check_test:1"]
       en_run_modes: ["sw_test_mode"]
+    }    
+    {
+      name: chip_sw_sram_ctrl_execution_main
+      uvm_test_seq: chip_sw_sram_ctrl_execution_main_vseq
+      sw_images: ["sw/device/tests/sram_ctrl_execution_test_main:1"]
+      en_run_modes: ["sw_test_mode"]
     }
     {
       name: chip_sw_coremark
diff --git a/hw/top_earlgrey/dv/env/chip_env.core b/hw/top_earlgrey/dv/env/chip_env.core
index c531224..cfc2232 100644
--- a/hw/top_earlgrey/dv/env/chip_env.core
+++ b/hw/top_earlgrey/dv/env/chip_env.core
@@ -45,6 +45,7 @@
       - seq_lib/chip_sw_lc_ctrl_transition_vseq.sv: {is_include_file: true}
       - seq_lib/chip_sw_spi_tx_rx_vseq.sv: {is_include_file: true}
       - seq_lib/chip_sw_rom_ctrl_integrity_check_vseq.sv: {is_include_file: true}
+      - seq_lib/chip_sw_sram_ctrl_execution_main_vseq.sv: {is_include_file: true}
       - autogen/chip_env_pkg__params.sv: {is_include_file: true}
       - ast_supply_if.sv
     file_type: systemVerilogSource
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_sw_sram_ctrl_execution_main_vseq.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_sram_ctrl_execution_main_vseq.sv
new file mode 100644
index 0000000..8d89b4d
--- /dev/null
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_sw_sram_ctrl_execution_main_vseq.sv
@@ -0,0 +1,55 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+class chip_sw_sram_ctrl_execution_main_vseq extends chip_sw_base_vseq;
+  `uvm_object_utils(chip_sw_sram_ctrl_execution_main_vseq)
+
+  `uvm_object_new
+
+  localparam logic [255:0] DEVICE_ID =
+      256'hFA53B8058E157CB69F1F413E87242971B6B52A656A1CAB7FEBF21E5BF1F45EDD;
+  localparam logic [255:0] MANUF_STATE =
+      256'h41389646B3968A3B128F4AF0AFFC1AAC77ADEFF42376E09D523D5C06786AAC34;
+  localparam logic [7:0] EN_CSRNG_SW_APP_READ = 8'hA5;
+  localparam logic [7:0] EN_ENTROPY_SRC_FW_READ = 8'hA5;
+  localparam logic [7:0] EN_ENTROPY_SRC_FW_OVER = 8'hA5;
+  localparam logic [7:0] MUBI8TRUE = 8'h5A;
+  localparam logic [7:0] MUBI8FALSE = 8'hA5;
+
+  virtual task do_test(logic [7:0] en_sram_ifetch, bit set_prod_lc);
+
+    apply_reset();
+
+    if (set_prod_lc) begin
+      cfg.mem_bkdr_util_h[Otp].otp_write_lc_partition_state(LcStProd);
+    end
+    cfg.mem_bkdr_util_h[Otp].otp_write_hw_cfg_partition(
+        .device_id(DEVICE_ID), .manuf_state(MANUF_STATE), .en_sram_ifetch(en_sram_ifetch),
+        .en_csrng_sw_app_read(EN_CSRNG_SW_APP_READ),
+        .en_entropy_src_fw_read(EN_ENTROPY_SRC_FW_READ),
+        .en_entropy_src_fw_over(EN_ENTROPY_SRC_FW_OVER));
+
+    wait(cfg.sw_test_status_vif.sw_test_status == SwTestStatusInTest);
+    wait(cfg.sw_test_status_vif.sw_test_status == SwTestStatusInWfi);
+  endtask
+
+  virtual task body();
+
+    super.body();
+
+    // State 0 - SRAM_IFETCH = False, LC_STATE = LcStRma (default).
+    do_test(MUBI8FALSE, 0);
+    // State 1 - SRAM_IFETCH = True, LC_STATE = LcStRma (default).
+    do_test(MUBI8TRUE, 0);
+    // State 2 - SRAM_IFETCH = False, LC_STATE = LcStProd.
+    do_test(MUBI8FALSE, 1);
+    // State 3 - SRAM_IFETCH = True, LC_STATE = LcStProd.
+    do_test(MUBI8TRUE, 1);
+
+    cfg.sw_test_status_vif.sw_test_status = SwTestStatusPassed;
+    cfg.sw_test_status_vif.sw_test_done   = 1'b1;
+
+  endtask
+
+endclass
diff --git a/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv b/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv
index 0e9402d..2aa310f 100644
--- a/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv
+++ b/hw/top_earlgrey/dv/env/seq_lib/chip_vseq_list.sv
@@ -17,3 +17,4 @@
 `include "chip_sw_lc_ctrl_transition_vseq.sv"
 `include "chip_sw_spi_tx_rx_vseq.sv"
 `include "chip_sw_rom_ctrl_integrity_check_vseq.sv"
+`include "chip_sw_sram_ctrl_execution_main_vseq.sv"
diff --git a/sw/device/tests/meson.build b/sw/device/tests/meson.build
index fe68d7e..ba4c545 100644
--- a/sw/device/tests/meson.build
+++ b/sw/device/tests/meson.build
@@ -705,29 +705,6 @@
   }
 }
 
-# SRAM Controller execution from Main SRAM test.
-sram_ctrl_execution_test_main_lib = declare_dependency(
-  link_with: static_library(
-    'sram_ctrl_execution_test_main_lib',
-    sources: ['sram_ctrl_execution_test_main.c'],
-    dependencies: [
-      sw_lib_bitfield,
-      sw_lib_dif_sram_ctrl,
-      sw_lib_runtime_ibex,
-      sw_lib_runtime_log,
-      sw_lib_testing_lc_ctrl_testutils,
-      sw_lib_testing_otp_ctrl_testutils,
-      sw_lib_testing_sram_ctrl_testutils,
-      top_earlgrey,
-    ],
-  ),
-)
-sw_tests += {
-  'sram_ctrl_execution_test_main': {
-    'library': sram_ctrl_execution_test_main_lib,
-  }
-}
-
 # SRAM Controller execution from Ret SRAM test.
 sram_ctrl_execution_test_ret_lib = declare_dependency(
   link_with: static_library(
diff --git a/sw/device/tests/sim_dv/meson.build b/sw/device/tests/sim_dv/meson.build
index 3c40442..463d762 100644
--- a/sw/device/tests/sim_dv/meson.build
+++ b/sw/device/tests/sim_dv/meson.build
@@ -161,3 +161,29 @@
     'library': rom_ctrl_integrity_check_test_lib,
   }
 }
+
+# SRAM Controller execution from Main SRAM test.
+sram_ctrl_execution_test_main_lib = declare_dependency(
+  link_with: static_library(
+    'sram_ctrl_execution_test_main_lib',
+    sources: [
+      hw_ip_otp_ctrl_reg_h,
+      'sram_ctrl_execution_test_main.c',
+    ],
+    dependencies: [
+      sw_lib_bitfield,
+      sw_lib_dif_sram_ctrl,
+      sw_lib_runtime_ibex,
+      sw_lib_runtime_log,
+      sw_lib_testing_lc_ctrl_testutils,
+      sw_lib_testing_otp_ctrl_testutils,
+      sw_lib_testing_sram_ctrl_testutils,
+      top_earlgrey,
+    ],
+  ),
+)
+sw_tests += {
+  'sram_ctrl_execution_test_main': {
+    'library': sram_ctrl_execution_test_main_lib,
+  }
+}
diff --git a/sw/device/tests/sram_ctrl_execution_test_main.c b/sw/device/tests/sim_dv/sram_ctrl_execution_test_main.c
similarity index 71%
rename from sw/device/tests/sram_ctrl_execution_test_main.c
rename to sw/device/tests/sim_dv/sram_ctrl_execution_test_main.c
index f334679..d73b9c4 100644
--- a/sw/device/tests/sram_ctrl_execution_test_main.c
+++ b/sw/device/tests/sim_dv/sram_ctrl_execution_test_main.c
@@ -7,6 +7,7 @@
 
 #include "sw/device/lib/base/bitfield.h"
 #include "sw/device/lib/base/macros.h"
+#include "sw/device/lib/base/multibits.h"
 #include "sw/device/lib/dif/dif_sram_ctrl.h"
 #include "sw/device/lib/runtime/ibex.h"
 #include "sw/device/lib/runtime/log.h"
@@ -20,6 +21,7 @@
 #include "sw/device/lib/testing/test_framework/test_status.h"
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
+#include "otp_ctrl_regs.h"  // Generated
 
 const test_config_t kTestConfig;
 
@@ -45,9 +47,10 @@
  *
  * x = OTP_CTRL_PARAM_EN_SRAM_IFETCH_OFFSET (1728)
  * y = OTP_CTRL_PARAM_HW_CFG_OFFSET (1664)
- * IFETCH_OFFSET = (x - y) / 8 = 8
+ * IFETCH_OFFSET = (x - y) = 64
  */
-static const uint32_t kOtpIfetchHwRelativeOffset = 8;
+static const uint32_t kOtpIfetchHwRelativeOffset =
+    OTP_CTRL_PARAM_EN_SRAM_IFETCH_OFFSET - OTP_CTRL_PARAM_HW_CFG_OFFSET;
 
 /**
  * Executes the return instruction from MAIN SRAM.
@@ -79,8 +82,9 @@
   uint32_t value;
   CHECK_DIF_OK(dif_otp_ctrl_dai_read32_end(&otp, &value));
 
-  // OTP stores IFETCH state in a single bit (enabled/disabled).
-  return bitfield_bit32_read(value, 0);
+  return bitfield_field32_read(
+             value, (bitfield_field32_t){.mask = 0xff, .index = 0}) ==
+         kMultiBitBool8True;
 }
 
 /**
@@ -103,7 +107,7 @@
  * stack by the OTTF exception handler entry subroutine, which means that the
  * return address can be loaded from there. See comments below for more details.
  */
-void ottf_exeception_handler(void) {
+void ottf_exception_handler(void) {
   // The frame address is the address of the stack location that holds the
   // `mepc`, since the OTTF exception handler entry code saves the `mepc` to
   // the top of the stack before transferring control flow to the exception
@@ -144,6 +148,42 @@
 }
 
 /**
+ * Sets the sram_ctrl exec CSR to both states and attempts to execute
+ * the code in SRAM. Checks whether an exception was observed for each
+ * case in line with the expected result based on LC_STATE and
+ * OTP IFETCH.
+ */
+void do_execute_test(bool debug_func, bool ifetch_en) {
+  bool csr_enabled_exception_expected;
+  bool csr_disabled_exception_expected;
+
+  if (debug_func && !ifetch_en) {
+    csr_enabled_exception_expected = false;
+    csr_disabled_exception_expected = false;
+  } else if (debug_func && ifetch_en) {
+    csr_enabled_exception_expected = false;
+    csr_disabled_exception_expected = true;
+  } else if (!debug_func && !ifetch_en) {
+    csr_enabled_exception_expected = true;
+    csr_disabled_exception_expected = true;
+  } else {
+    csr_enabled_exception_expected = false;
+    csr_disabled_exception_expected = true;
+  }
+
+  CHECK_DIF_OK(dif_sram_ctrl_exec_set_enabled(&sram_ctrl, kDifToggleEnabled));
+  exception_observed = false;
+  execute_code_in_sram();
+  CHECK(exception_observed == csr_enabled_exception_expected,
+        "Expected exception not observed whilst executing from SRAM!");
+  CHECK_DIF_OK(dif_sram_ctrl_exec_set_enabled(&sram_ctrl, kDifToggleDisabled));
+  exception_observed = false;
+  execute_code_in_sram();
+  CHECK(exception_observed == csr_disabled_exception_expected,
+        "Expected exception not observed whilst executing from SRAM!");
+}
+
+/**
  * Performs the tests.
  *
  * When chip is in one of the lifecycle states where debug functions are
@@ -161,35 +201,25 @@
       mmio_region_from_addr(TOP_EARLGREY_SRAM_CTRL_MAIN_REGS_BASE_ADDR),
       &sram_ctrl));
 
+  bool locked;
+  CHECK_DIF_OK(
+      dif_sram_ctrl_is_locked(&sram_ctrl, kDifSramCtrlLockExec, &locked));
+  CHECK(!locked, "Execution is disabled and locked, cannot perform the test");
+
   dif_lc_ctrl_t lc;
   CHECK_DIF_OK(dif_lc_ctrl_init(
       mmio_region_from_addr(TOP_EARLGREY_LC_CTRL_BASE_ADDR), &lc));
 
-  if (otp_ifetch_enabled()) {
-    dif_toggle_t state;
-    CHECK_DIF_OK(dif_sram_ctrl_exec_get_enabled(&sram_ctrl, &state));
-    if (state == kDifToggleDisabled) {
-      bool locked;
-      CHECK_DIF_OK(
-          dif_sram_ctrl_is_locked(&sram_ctrl, kDifSramCtrlLockExec, &locked));
-      CHECK(!locked,
-            "Execution is disabled and locked, cannot perform the test");
-      CHECK_DIF_OK(
-          dif_sram_ctrl_exec_set_enabled(&sram_ctrl, kDifToggleEnabled));
+  // For the current configuration (set by the testbench)
+  // check that execution exceptions are as expected.
+  do_execute_test(lc_ctrl_testutils_debug_func_enabled(&lc),
+                  otp_ifetch_enabled());
 
-      exception_observed = false;
-      execute_code_in_sram();
-      CHECK(!exception_observed,
-            "Exception observed whilst executing from SRAM!");
-    }
-  } else if (lc_ctrl_testutils_debug_func_enabled(&lc)) {
-    exception_observed = false;
-    execute_code_in_sram();
-    CHECK(!exception_observed,
-          "Exception observed whilst executing from SRAM!");
-  } else {
-    LOG_FATAL("Execution from SRAM cannot be enabled, cannot run the test");
-  }
+  // When the test is complete flag WFI status so
+  // the testbench can reset and progress to the next
+  // combination of LC_STATE and OTP IFETCH.
+  test_status_set(kTestStatusInWfi);
+  wait_for_interrupt();
 
   return true;
 }