Merge "Add kelvin SW FPGA tests"
diff --git a/WORKSPACE b/WORKSPACE
index 578cdb7..62bb960 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -22,6 +22,12 @@
     path = "../../cache/toolchain_kelvin",
 )
 
+new_local_repository(
+    name = "kelvin-binary",
+    build_file = "third_party/kelvin-binary/BUILD",
+    path = "../../out/kelvin/sw/bazel_out",
+)
+
 # CRT is the Compiler Repository Toolkit.  It contains the configuration for
 # the windows compiler.
 load("@lowrisc_opentitan//third_party/crt:repos.bzl", "crt_repos")
diff --git a/rules/matcha.bzl b/rules/matcha.bzl
index c8886e6..b3026bc 100644
--- a/rules/matcha.bzl
+++ b/rules/matcha.bzl
@@ -430,7 +430,8 @@
         sc_binary,
         smc_binary = None,
         kelvin_binary = None,
-        data = None):
+        data = None,
+        **kwargs):
     """A rule for creating a tarball containing program code and resources.
 
     Args:
@@ -439,6 +440,7 @@
         smc_binary: The binary for the system management core. This will be named smc.bin, and is optional.
         kelvin_binary: The binary for the Kelvin core. This will be named kelvin.bin, and is optional.
         data: A dictionary of extra files to add to the archive. The key is the input file, and the value is filename in the archive.
+        **kwargs: Arguments forwared to pkg_tar
     """
 
     files = {
@@ -453,6 +455,7 @@
     pkg_tar(
         name = name,
         files = files,
+        **kwargs
     )
 
 def bin_to_c_file(
diff --git a/sw/device/tests/kelvin/fpga_tests/BUILD b/sw/device/tests/kelvin/fpga_tests/BUILD
new file mode 100644
index 0000000..70870f2
--- /dev/null
+++ b/sw/device/tests/kelvin/fpga_tests/BUILD
@@ -0,0 +1,116 @@
+# Copyright Google LLC 2023
+# Copyright lowRISC contributors.
+# Licensed under the Apache License, Version 2.0, see LICENSE for details.
+# SPDX-License-Identifier: Apache-2.0
+
+load("//rules:matcha.bzl", "NEXUS_CORE_TARGETS", "matcha_extflash_tar", "sec_flash_binary", "smc_flash_binary")
+
+sec_flash_binary(
+    name = "kelvin_test_sc_extflash",
+    srcs = [
+        "kelvin_test_sc.c",
+        "kelvin_test_sc_loaders.h",
+        "kelvin_test_sc_loaders_extflash.c",
+    ],
+    copts = [
+        "-nostdlib",
+        "-ffreestanding",
+    ],
+    per_device_deps = {
+        "fpga_nexus": [NEXUS_CORE_TARGETS.get("secure_core")],
+    },
+    deps = [
+        "//hw/top_matcha/ip/ml_top/data:ml_top_regs",
+        "//hw/top_matcha/sw/autogen:top_matcha",
+        "//sw/device/lib:spi_flash",
+        "//sw/device/lib/dif:smc_ctrl",
+        "//sw/device/lib/testing/test_framework:ottf_start",
+        "//sw/device/lib/testing/test_framework:test_util",
+        "@lowrisc_opentitan//sw/device/lib/testing/test_framework:ottf_test_config",
+        "@lowrisc_opentitan//sw/device/silicon_creator/lib:manifest_def",
+    ],
+)
+
+smc_flash_binary(
+    name = "kelvin_test_smc",
+    srcs = [
+        "kelvin_test_smc.c",
+    ],
+    copts = [
+        "-nostdlib",
+        "-ffreestanding",
+    ],
+    per_device_deps = {
+        "fpga_nexus": [NEXUS_CORE_TARGETS.get("smc")],
+    },
+    var_name = "kelvin_test_smc_fpga_nexus_bin",
+    deps = [
+        "//hw/top_matcha/sw/autogen:top_matcha",
+        "//sw/device/lib/testing/test_framework:ottf_start_smc",
+        "//sw/device/lib/testing/test_framework:test_util",
+        "@lowrisc_opentitan//sw/device/lib/testing/test_framework:ottf_test_config",
+    ],
+)
+
+KELVIN_BINS = [
+    "branch_div_test_elf",
+    "branch_modulo_test_elf",
+    "getvl_test_elf",
+    "rv32ui_add_elf",
+    "rv32ui_addi_elf",
+    "rv32ui_and_elf",
+    "rv32ui_andi_elf",
+    "rv32ui_auipc_elf",
+    "rv32ui_beq_elf",
+    "rv32ui_bge_elf",
+    "rv32ui_bgeu_elf",
+    "rv32ui_blt_elf",
+    "rv32ui_bltu_elf",
+    "rv32ui_bne_elf",
+    "rv32ui_fence_i_elf",
+    "rv32ui_jalr_elf",
+    "rv32ui_jal_elf",
+    "rv32ui_lb_elf",
+    "rv32ui_lbu_elf",
+    "rv32ui_lh_elf",
+    "rv32ui_lhu_elf",
+    "rv32ui_lui_elf",
+    "rv32ui_lw_elf",
+    "rv32ui_ori_elf",
+    "rv32ui_or_elf",
+    "rv32ui_sb_elf",
+    "rv32ui_sh_elf",
+    "rv32ui_simple_elf",
+    "rv32ui_slli_elf",
+    "rv32ui_sll_elf",
+    "rv32ui_slti_elf",
+    "rv32ui_sltiu_elf",
+    "rv32ui_slt_elf",
+    "rv32ui_sltu_elf",
+    "rv32ui_srai_elf",
+    "rv32ui_sra_elf",
+    "rv32ui_srli_elf",
+    "rv32ui_srl_elf",
+    "rv32ui_sub_elf",
+    "rv32ui_sw_elf",
+    "rv32ui_xori_elf",
+    "rv32ui_xor_elf",
+    "rv32um_div_elf",
+    "rv32um_divu_elf",
+    "rv32um_mul_elf",
+    "rv32um_mulh_elf",
+    "rv32um_mulhsu_elf",
+    "rv32um_mulhu_elf",
+    "rv32um_rem_elf",
+    "rv32um_remu_elf",
+]
+
+[matcha_extflash_tar(
+    name = "kelvin_fpga_test_{}_extflash".format(test),
+    kelvin_binary = "@kelvin-binary//:{}.bin".format(test),
+    sc_binary = ":kelvin_test_sc_extflash_fpga_nexus_bin",
+    smc_binary = ":kelvin_test_smc_fpga_nexus_bin",
+    tags = [
+        "kelvin_fpga",
+    ],
+) for test in KELVIN_BINS]
diff --git a/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c
new file mode 100644
index 0000000..d27bf6f
--- /dev/null
+++ b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c
@@ -0,0 +1,76 @@
+// Copyright 2023 Google LLC
+
+#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/arch/device.h"
+#include "sw/device/lib/dif/dif_smc_ctrl.h"
+#include "sw/device/lib/dif/dif_uart.h"
+#include "sw/device/lib/runtime/print.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_test_config.h"
+#include "sw/device/lib/testing/test_framework/status.h"
+#include "sw/device/lib/testing/test_framework/test_util.h"
+#include "sw/device/tests/kelvin/fpga_tests/kelvin_test_sc_loaders.h"
+
+/*
+ * Sample program to run some code on all cores in the system.
+ * SC - Orchestrate the other cores, print status to UART.
+ * SMC - Print to UART.
+ * Kelvin - SW program built to run on Kelvin.
+ */
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static dif_smc_ctrl_t smc_ctrl;
+static dif_uart_t uart;
+
+void _ottf_main(void) {
+  test_status_set(kTestStatusInTest);
+  init_uart(TOP_MATCHA_UART0_BASE_ADDR, &uart);
+  LOG_INFO("kelvin_test_sc");
+  // Do any initialization needed before loading SMC and Kelvin.
+  load_init();
+
+  // Copy binary to SMC RAM.
+  load_smc();
+
+  mmio_region_t ml_dmem =
+      mmio_region_from_addr(TOP_MATCHA_ML_TOP_DMEM_BASE_ADDR);
+
+  // Fill the memory with zeroes.
+  for (int i = 0; i < TOP_MATCHA_ML_TOP_DMEM_SIZE_BYTES / sizeof(uint32_t);
+       ++i) {
+    mmio_region_write32(ml_dmem, i * sizeof(uint32_t), 0);
+  }
+
+  // Copy binary to ML_DMEM.
+  load_kelvin();
+
+  // Enable SMC.
+  CHECK_DIF_OK(dif_smc_ctrl_init(
+      mmio_region_from_addr(TOP_MATCHA_SMC_CTRL_BASE_ADDR), &smc_ctrl));
+  CHECK_DIF_OK(dif_smc_ctrl_set_en(&smc_ctrl));
+
+  // Start up Kelvin.
+  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,
+                      ML_TOP_CTRL_REG_RESVAL);
+  mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET, 0x0);
+  uint32_t intr_state =
+      mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET);
+  // TODO(ykwang): Change this to interrupt handler.
+  while (intr_state == 0x0) {
+    intr_state = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET);
+    busy_spin_micros(10 * 1000);  // Wait for 10ms.
+  }
+
+  LOG_INFO("Kelvin finished executing.");
+  // Received interrupts from Kelvin core, check if only FINISH asserted
+  CHECK(intr_state == (1 << ML_TOP_INTR_STATE_FINISH_BIT),
+        "INTR_STATE read out: expected : 0x%x | actual: 0x%x",
+        (1 << ML_TOP_INTR_STATE_FINISH_BIT), intr_state);
+
+  test_status_set(kTestStatusPassed);
+  asm volatile("wfi");
+}
diff --git a/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc_loaders.h b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc_loaders.h
new file mode 100644
index 0000000..fd0161f
--- /dev/null
+++ b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc_loaders.h
@@ -0,0 +1,18 @@
+// Copyright 2023 Google LLC
+
+#ifndef SW_DEVICE_TESTS_KELVIN_FPGA_TESTS_KELVIN_TEST_SC_LOADERS_H_
+#define SW_DEVICE_TESTS_KELVIN_FPGA_TESTS_KELVIN_TEST_SC_LOADERS_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+void load_init(void);
+void load_smc(void);
+void load_kelvin(void);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif  // SW_DEVICE_TESTS_KELVIN_FPGA_TESTS_KELVIN_TEST_SC_LOADERS_H_
diff --git a/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc_loaders_extflash.c b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc_loaders_extflash.c
new file mode 100644
index 0000000..15abee6
--- /dev/null
+++ b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc_loaders_extflash.c
@@ -0,0 +1,18 @@
+// Copyright 2023 Google LLC
+
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/spi_flash.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/tests/kelvin/fpga_tests/kelvin_test_sc_loaders.h"
+
+void load_smc(void) {
+  CHECK_DIF_OK(
+      load_file_from_tar("smc.bin", (void*)TOP_MATCHA_RAM_SMC_BASE_ADDR));
+}
+
+void load_kelvin(void) {
+  CHECK_DIF_OK(load_file_from_tar("kelvin.bin",
+                                  (void*)TOP_MATCHA_ML_TOP_DMEM_BASE_ADDR));
+}
+
+void load_init(void) { spi_flash_init(); }
diff --git a/sw/device/tests/kelvin/fpga_tests/kelvin_test_smc.c b/sw/device/tests/kelvin/fpga_tests/kelvin_test_smc.c
new file mode 100644
index 0000000..ec9f4a8
--- /dev/null
+++ b/sw/device/tests/kelvin/fpga_tests/kelvin_test_smc.c
@@ -0,0 +1,17 @@
+#include "hw/top_matcha/sw/autogen/top_matcha.h"
+#include "sw/device/lib/arch/device.h"
+#include "sw/device/lib/dif/dif_uart.h"
+#include "sw/device/lib/runtime/print.h"
+#include "sw/device/lib/testing/test_framework/check.h"
+#include "sw/device/lib/testing/test_framework/ottf_test_config.h"
+#include "sw/device/lib/testing/test_framework/test_util.h"
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static dif_uart_t smc_uart;
+
+void _ottf_main(void) {
+  init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart);
+  LOG_INFO("kelvin_test_smc");
+  asm volatile("wfi");
+}
diff --git a/third_party/kelvin-binary/BUILD b/third_party/kelvin-binary/BUILD
new file mode 100644
index 0000000..e279b32
--- /dev/null
+++ b/third_party/kelvin-binary/BUILD
@@ -0,0 +1,3 @@
+package(default_visibility = ["//visibility:public"])
+
+exports_files(glob(["*.bin"]))