Workaround for Kelvin ASIC fifo issue at SC startup

Change-Id: I51889f7a7f8742db5f01997d33dc8bef78c45af8
diff --git a/sw/device/lib/testing/test_framework/BUILD b/sw/device/lib/testing/test_framework/BUILD
index 6f9912e..b527390 100644
--- a/sw/device/lib/testing/test_framework/BUILD
+++ b/sw/device/lib/testing/test_framework/BUILD
@@ -35,9 +35,10 @@
 cc_library(
     name = "ottf_start",
     srcs = [
+        ":fix_kelvin.c",
+        "//sw/device/lib/testing/test_framework:ottf_start.S",
         "@lowrisc_opentitan//sw/device/lib/testing/test_framework:ottf_isrs.S",
         "@lowrisc_opentitan//sw/device/lib/testing/test_framework:ottf_isrs.c",
-        "@lowrisc_opentitan//sw/device/lib/testing/test_framework:ottf_start.S",
     ],
     hdrs = [
         "@lowrisc_opentitan//sw/device/lib/testing/test_framework:ottf_isrs.h",
@@ -46,6 +47,9 @@
     target_compatible_with = [OPENTITAN_CPU],
     deps = [
         ":linker_script",
+        "//hw/top_matcha/sw:top_matcha",
+        "//hw/top_matcha/ip/ml_top/data:ml_top_regs",
+        "//sw/device/lib/dif:ml_top",
         "//sw/device/lib/dif:rv_plic_sec",
         "@lowrisc_opentitan//sw/device/lib/base:csr",
         "@lowrisc_opentitan//sw/device/lib/base:macros",
diff --git a/sw/device/lib/testing/test_framework/fix_kelvin.c b/sw/device/lib/testing/test_framework/fix_kelvin.c
new file mode 100644
index 0000000..64f6b63
--- /dev/null
+++ b/sw/device/lib/testing/test_framework/fix_kelvin.c
@@ -0,0 +1,57 @@
+// Copyright 2024 Google LLC
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+#include "hw/top_matcha/ip/ml_top/data/ml_top_regs.h"  // Generated.
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/dif/dif_ml_top.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+
+void fix_kelvin(void) {
+#if defined(MATCHA_SPARROW)
+  dif_ml_top_t ml_top;
+  mmio_region_t ml_dmem =
+      mmio_region_from_addr(TOP_MATCHA_ML_TOP_DMEM_BASE_ADDR);
+
+  int i = 0;
+  for (; i < 8; ++i) {
+    mmio_region_write32(ml_dmem, i * sizeof(uint32_t),
+                        0x4000201fU);  // vdup.v.x
+  }
+  for (; i < 16; ++i) {
+    mmio_region_write32(ml_dmem, i * sizeof(uint32_t),
+                        0x42f02c05U);  // aconv.vxv
+  }
+  for (; i < 24; ++i) {
+    mmio_region_write32(ml_dmem, i * sizeof(uint32_t), 0x50002c1fU);  // vcget
+  }
+  for (; i < 32; ++i) {
+    mmio_region_write32(ml_dmem, i * sizeof(uint32_t), 0x00002000U);  // vadd
+  }
+  for (; i < 40; ++i) {
+    mmio_region_write32(ml_dmem, i * sizeof(uint32_t), 0x48000c06U);  // adwinit
+  }
+  for (; i < 48; ++i) {
+    mmio_region_write32(ml_dmem, i * sizeof(uint32_t), 0x00002083U);  // lw
+  }
+  mmio_region_write32(ml_dmem, i * sizeof(uint32_t), 0x08000073U);  // mpause
+
+  uint32_t ml_result;
+  do {
+    CHECK_DIF_OK(dif_ml_top_init(
+        mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR), &ml_top));
+    dif_ml_top_reset_ctrl_en(&ml_top);
+    mmio_region_t base_addr =
+        mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR);
+    mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET, 0x0);
+    while ((ml_result =
+                mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET)) ==
+           ML_TOP_INTR_STATE_REG_RESVAL) {
+    }
+    mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET,
+                        ML_TOP_CTRL_REG_RESVAL);
+    mmio_region_write32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET, ml_result);
+  } while (ml_result == ((1 << ML_TOP_INTR_ENABLE_FINISH_BIT) |
+                         (1 << ML_TOP_INTR_ENABLE_FAULT_BIT)));
+#endif  // MATCHA_SPARROW
+}
diff --git a/sw/device/lib/testing/test_framework/ottf_start.S b/sw/device/lib/testing/test_framework/ottf_start.S
new file mode 100644
index 0000000..6c04afd
--- /dev/null
+++ b/sw/device/lib/testing/test_framework/ottf_start.S
@@ -0,0 +1,195 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+
+/**
+ * OTTF Interrupt Vector.
+ */
+
+  .section .vectors, "ax"
+  .option push
+
+  // Disable RISC-V instruction compression: we need all instructions to
+  // be exactly word wide in the interrupt vector.
+  .option norvc
+
+  // Disable RISC-V linker relaxation, as it can compress instructions at
+  // link-time, which we also really don't want.
+  .option norelax
+
+  /**
+   * `_ottf_interrupt_vector` is an ibex-compatible interrupt vector.
+   *
+   * Interrupt vectors in Ibex have 32 4-byte entries for 32 possible interrupts.
+   * The vector must be 256-byte aligned, as Ibex's vectoring mechanism requires
+   * that.
+   *
+   * Only the following will be used by Ibex:
+   * - Exception Handler (Entry 0)
+   * - Machine Software Interrupt Handler (Entry 3)
+   * - Machine Timer Interrupt Handler (Entry 7)
+   * - Machine External Interrupt Handler (Entry 11)
+   * - Vendor Interrupt Handlers (Entries 16-31)
+   *
+   * More information about Ibex's interrupts can be found here:
+   *   https://ibex-core.readthedocs.io/en/latest/03_reference/exception_interrupts.html
+   */
+  .balign 256
+  .global _ottf_interrupt_vector
+  .type _ottf_interrupt_vector, @function
+_ottf_interrupt_vector:
+  // RISC-V Standard (Vectored) Interrupt Handlers:
+
+  // Exception and User Software Interrupt Handler.
+  j handler_exception
+  // Supervisor Software Interrupt Handler.
+  unimp
+  // Reserved.
+  unimp
+  // Machine Software Interrupt Handler.
+  j handler_irq_software
+
+  // User Timer Interrupt Handler.
+  unimp
+  // Supervisor Timer Interrupt Handler.
+  unimp
+  // Reserved.
+  unimp
+  // Machine Timer Interrupt Handler.
+  j handler_irq_timer
+
+  // User External Interrupt Handler.
+  unimp
+  // Supervisor External Interrupt Handler.
+  unimp
+  // Reserved.
+  unimp
+  // Machine External Interrupt Handler.
+  j handler_irq_external
+
+  // Reserved.
+  unimp
+  unimp
+  unimp
+  unimp
+
+  // Vendor Interrupt Handlers:
+
+  // On Ibex, interrupt IDs 16-30 are for "fast" interrupts.
+  .rept 15
+  unimp
+  .endr
+
+  // On Ibex, interrupt ID 31 is for non-maskable interrupts
+  j handler_irq_internal
+
+  // Set size so vector can be disassembled.
+  .size _ottf_interrupt_vector, .-_ottf_interrupt_vector
+
+  .option pop
+
+// -----------------------------------------------------------------------------
+
+/**
+ * OTTF runtime initialization code.
+ */
+
+  /**
+   * NOTE: The "ax" flag below is necessary to ensure that this section
+   * is allocated executable space in ROM by the linker.
+   */
+  .section .crt, "ax"
+
+  /**
+   * Entry point.
+   *
+   * This symbol is jumped to from the test ROM or ROM using the
+   * `entry_point` field of the manifest.
+   */
+  .balign 4
+  .global _ottf_start
+  .type _ottf_start, @function
+_ottf_start:
+  /**
+   * Set up the global pointer `gp`.
+   *
+   * Linker relaxations are disabled until the global pointer is setup below,
+   * because otherwise some sequences may be turned into `gp`-relative
+   * sequences, which is incorrect when `gp` is not initialized.
+   */
+  .option push
+  .option norelax
+  la gp, __global_pointer$
+  .option pop
+
+  /**
+   * Set up the stack pointer.
+   *
+   * In RISC-V, the stack grows downwards, so we load the address of the highest
+   * word in the stack into sp. We don't load in `_stack_end`, as that points
+   * beyond the end of RAM, and we always want it to be valid to dereference
+   * `sp`, and we need this to be 128-bit (16-byte) aligned to meet the psABI.
+   *
+   * If an exception fires, the handler is conventionaly only allowed to clobber
+   * memory at addresses below `sp`.
+   */
+  la   sp, (_stack_end - 16)
+
+  /**
+   * Set well-defined interrupt/exception handlers.
+   *
+   * The lowest two bits should be `0b01` to ensure we use vectored interrupts.
+   */
+  la   t0, (_ottf_interrupt_vector + 1)
+  csrw mtvec, t0
+
+  /**
+   * Setup C Runtime
+   */
+
+  /**
+   * Initialize the `.data` section in RAM from Flash.
+   */
+  la   a0, _data_start
+  la   a1, _data_end
+  la   a2, _data_init_start
+  call crt_section_copy
+
+  /**
+   * Initialize the `.bss` section.
+   *
+   * We do this despite zeroing all of SRAM above, so that we still zero `.bss`
+   * once we've enabled SRAM scrambling.
+   */
+  la   a0, _bss_start
+  la   a1, _bss_end
+  call crt_section_clear
+
+ /**
+  * Call the functions in the `.init_array` section.
+  *
+  * This section is typically empty except for executables built with LLVM
+  * coverage enabled. When coverage is enabled, the compiler emits pointers to
+  * the functions that initialize the profile buffer in this section. These
+  * functions must be called before the instrumented functions in the program.
+  *
+  * We use `s0` and `s1` to represent the start and end pointers of
+  * `.init_array`, respectively, and `t0` to store the addresses of the
+  * functions to be called.
+  */
+  la   s0, _init_array_start
+  la   s1, _init_array_end
+  bgeu s0, s1, init_array_loop_end
+init_array_loop:
+  lw   t0, 0(s0)
+  jalr t0
+  addi s0, s0, 0x4
+  bltu s0, s1, init_array_loop
+init_array_loop_end:
+
+ /**
+  * Jump into the OTTF C entry point.
+  */
+  call fix_kelvin
+  tail _ottf_main
+  .size _ottf_start, .-_ottf_start