Merge "Update bazel airgap prep script with removed chisel dependency"
diff --git a/hw/top_matcha/dv/chip_sim_cfg.hjson b/hw/top_matcha/dv/chip_sim_cfg.hjson
index 5f2770c..740c38d 100644
--- a/hw/top_matcha/dv/chip_sim_cfg.hjson
+++ b/hw/top_matcha/dv/chip_sim_cfg.hjson
@@ -586,6 +586,14 @@
run_opts:["+sw_test_timeout_ns=40_000_000"]
}
{
+ name: chip_sw_smc_kelvin_model_test
+ uvm_test_seq: chip_sw_base_vseq
+ sw_images: ["//sw/device/tests/smc:smc_kelvin_model_test:6:matcha",
+ "//sw/device/examples/testdata:kelvin_model_ml:7:matcha"]
+ en_run_modes: ["sw_test_mode_test_simple_sec"]
+ run_opts:["+sw_test_timeout_ns=160_000_000"]
+ }
+ {
name: chip_sw_smc_isp_wrapper_test
uvm_test_seq: chip_sw_base_vseq
sw_images: ["//sw/device/tests/smc:smc_isp_wrapper_test:6:matcha"]
@@ -2218,6 +2226,7 @@
"chip_sw_smc_isp_wrapper_tpg_128_64_test",
"chip_sw_smc_kelvin_checksum_test",
"chip_sw_smc_kelvin_hello_test",
+ "chip_sw_smc_kelvin_model_test",
"chip_sw_smc_lsu_interrupt_boundary_test",
"chip_sw_smc_lsu_page_boundary_test",
"chip_sw_smc_ml_sram_smoketest",
@@ -2367,6 +2376,7 @@
"chip_sw_smc_isp_wrapper_tpg_128_64_test",
"chip_sw_smc_kelvin_checksum_test",
"chip_sw_smc_kelvin_hello_test",
+ "chip_sw_smc_kelvin_model_test",
"chip_sw_smc_lsu_interrupt_boundary_test",
"chip_sw_smc_lsu_page_boundary_test",
"chip_sw_smc_ml_sram_smoketest",
diff --git a/sw/device/examples/testdata/BUILD b/sw/device/examples/testdata/BUILD
index 8bd7acf..45d2ca1 100644
--- a/sw/device/examples/testdata/BUILD
+++ b/sw/device/examples/testdata/BUILD
@@ -1,12 +1,49 @@
# Copyright 2023 Google LLC
+load("@lowrisc_opentitan//rules:opentitan.bzl", "bin_to_vmem")
load("//rules:matcha.bzl", "bin_to_c_file")
package(default_visibility = ["//visibility:public"])
+name = "kelvin_model_ml"
+
+bin_name = "{}_bin".format(name)
+
# Binary is built from //sw/device/tests/kelvin/hps-c-port
bin_to_c_file(
- name = "kelvin_model_ml_bin",
+ name = bin_name,
srcs = ["//sw/device/tests/kelvin/hps-c-port:kelvin_hps_model.bin"],
var_name = "kelvin_bin",
)
+
+vmem_32_name = "{}.32.vmem".format(name)
+
+vmem_256_name = "{}.256.vmem".format(name)
+
+vmem_name = "{}_vmem".format(name)
+
+bin_to_vmem(
+ name = vmem_32_name,
+ bin = "//sw/device/tests/kelvin/hps-c-port:kelvin_hps_model.bin",
+ word_size = 32,
+)
+
+genrule(
+ name = vmem_name,
+ srcs = [vmem_32_name],
+ outs = [vmem_256_name],
+ cmd = """
+ $(location //util:gen_vmem_256) \
+ --input=$< \
+ --output=$@
+ """,
+ tools = ["@matcha//util:gen_vmem_256"],
+)
+
+filegroup(
+ name = name,
+ srcs = [
+ ":{}".format(bin_name),
+ ":{}".format(vmem_name),
+ ],
+)
diff --git a/sw/device/tests/kelvin/hps-c-port/main_fpga.cc b/sw/device/tests/kelvin/hps-c-port/main_fpga.cc
index a42fe33..5a91d3b 100644
--- a/sw/device/tests/kelvin/hps-c-port/main_fpga.cc
+++ b/sw/device/tests/kelvin/hps-c-port/main_fpga.cc
@@ -10,7 +10,7 @@
uint32_t padding[1024 - 2];
};
-static int8_t input_[kImageLen] __aligned__ __noinit__;
+static int8_t input_[kImageLen] __aligned__ = {0};
// .model_header is at the DMEM - 4KB
command_t command __attribute__((section(".model_header")));
diff --git a/sw/device/tests/kelvin/hps-c-port/model/src/model.cc b/sw/device/tests/kelvin/hps-c-port/model/src/model.cc
index 84cb798..8ba69ae 100644
--- a/sw/device/tests/kelvin/hps-c-port/model/src/model.cc
+++ b/sw/device/tests/kelvin/hps-c-port/model/src/model.cc
@@ -21,38 +21,21 @@
int8_t buffer_016[2] __aligned__ __noinit__;
void model(const int8_t *input, int8_t *output) {
- printf("Layer(000)\n");
layer_000_conv_2d(input, buffer_000);
- printf("Layer(001)\n");
layer_001_conv_2d(buffer_000, buffer_001);
- printf("Layer(002)\n");
layer_002_conv_2d(buffer_001, buffer_002);
- printf("Layer(003)\n");
layer_003_max_pool_2d(buffer_002, buffer_003);
- printf("Layer(004)\n");
layer_004_conv_2d(buffer_003, buffer_004);
- printf("Layer(005)\n");
layer_005_conv_2d(buffer_004, buffer_005);
- printf("Layer(006)\n");
layer_006_max_pool_2d(buffer_005, buffer_006);
- printf("Layer(007)\n");
layer_007_conv_2d(buffer_006, buffer_007);
- printf("Layer(008)\n");
layer_008_max_pool_2d(buffer_007, buffer_008);
- printf("Layer(009)\n");
layer_009_conv_2d(buffer_008, buffer_009);
- printf("Layer(010)\n");
layer_010_max_pool_2d(buffer_009, buffer_010);
- printf("Layer(011)\n");
layer_011_conv_2d(buffer_010, buffer_011);
- printf("Layer(012)\n");
layer_012_reshape(buffer_011, buffer_012);
- printf("Layer(013)\n");
layer_013_fullyconnected(buffer_012, buffer_013);
- printf("Layer(014)\n");
layer_014_fullyconnected(buffer_013, buffer_014);
- printf("Layer(015)\n");
layer_015_fullyconnected(buffer_014, buffer_015);
- printf("Layer(016)\n");
layer_016_logistic(buffer_015, output);
}
diff --git a/sw/device/tests/smc/BUILD b/sw/device/tests/smc/BUILD
index ec158be..02e0949 100644
--- a/sw/device/tests/smc/BUILD
+++ b/sw/device/tests/smc/BUILD
@@ -307,6 +307,30 @@
)
smc_flash_binary(
+ name = "smc_kelvin_model_test",
+ srcs = [
+ "smc_kelvin_model_test.c",
+ "//sw/device/examples/testdata:kelvin_model_ml_bin.h",
+ "//sw/device/tests/testdata:test_image.h",
+ ],
+ copts = [
+ "-nostdlib",
+ "-ffreestanding",
+ ],
+ per_device_deps = {
+ "sim_verilator": [VERILATOR_CORE_TARGETS.get("smc")],
+ "sim_dv": ["//sw/device/lib/arch:smc_sim_dv"],
+ },
+ deps = [
+ "//hw/top_matcha/ip/ml_top/data:ml_top_regs",
+ "//hw/top_matcha/sw/autogen:top_matcha",
+ "//sw/device/lib/dif:ml_top",
+ "//sw/device/lib/dif:rv_plic_smc",
+ "//sw/device/tests:test_lib_smc",
+ ],
+)
+
+smc_flash_binary(
name = "smc_isp_wrapper_irq_test",
srcs = [
"smc_isp_wrapper_irq_test.c",
diff --git a/sw/device/tests/smc/smc_kelvin_model_test.c b/sw/device/tests/smc/smc_kelvin_model_test.c
new file mode 100644
index 0000000..91d4cfb
--- /dev/null
+++ b/sw/device/tests/smc/smc_kelvin_model_test.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2023 Google LLC
+ * Copyright lowRISC contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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/examples/testdata/kelvin_model_ml_bin.h" // Generated.
+#include "sw/device/lib/arch/device.h"
+#include "sw/device/lib/dif/dif_ml_top.h"
+#include "sw/device/lib/dif/dif_rv_plic.h"
+#include "sw/device/lib/dif/dif_uart.h"
+#include "sw/device/lib/runtime/irq.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/testdata/test_image.h" // Generated.
+
+#define TOP_MATCHA_RAM_ML_DMEM_IMG_OFFSET_ADDR 0x00300000
+#define TOP_MATCHA_RAM_ML_DMEM_OUT_OFFSET_ADDR 0x00380000
+#define TOP_MATCHA_RAM_ML_DMEM_CMD_OFFSET_ADDR 0x003FF000
+
+OTTF_DEFINE_TEST_CONFIG();
+
+static dif_ml_top_t ml_top;
+static dif_rv_plic_t plic_smc;
+static dif_uart_t smc_uart;
+
+static volatile bool ml_top_finish_done = false;
+
+static void handle_ml_top_isr(const dif_rv_plic_irq_id_t interrupt_id) {
+ switch (interrupt_id) {
+ case kTopMatchaPlicIrqIdMlTopFinish:
+ ml_top_finish_done = true;
+ break;
+ case kTopMatchaPlicIrqIdMlTopFinish | kTopMatchaPlicIrqIdMlTopFault:
+ LOG_ERROR("ML core raised fault interrupt.");
+ test_status_set(kTestStatusFailed);
+ default:
+ LOG_FATAL("ISR is not implemented!");
+ test_status_set(kTestStatusFailed);
+ }
+ CHECK_DIF_OK(dif_ml_top_reset_ctrl_en(&ml_top));
+ CHECK_DIF_OK(dif_ml_top_irq_acknowledge_all(&ml_top));
+}
+
+void ottf_external_isr(void) {
+ // Claim the IRQ by reading the Ibex specific CC register.
+ dif_rv_plic_irq_id_t interrupt_id;
+
+ CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic_smc, kTopMatchaPlicTargetIbex0Smc,
+ &interrupt_id));
+
+ // Check if the interrupted peripheral is ISP WRAPPER.
+ top_matcha_plic_peripheral_smc_t peripheral_id =
+ top_matcha_plic_interrupt_for_peripheral_smc[interrupt_id];
+ CHECK(peripheral_id == kTopMatchaPlicPeripheralMlTop,
+ "Unexpected peripheral in ISR: %d", peripheral_id);
+ switch (peripheral_id) {
+ case kTopMatchaPlicPeripheralMlTop: {
+ handle_ml_top_isr(interrupt_id);
+ break;
+ }
+ default:
+ LOG_FATAL("Peripheral is not implemented!");
+ }
+
+ // Complete the IRQ by writing the IRQ source to the Ibex specific CC
+ // register.
+ CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic_smc, kTopMatchaPlicTargetIbex0Smc,
+ interrupt_id));
+}
+
+// Configures all relevant interrupts in PLIC_SMC.
+static void plic_smc_configure_irqs(dif_rv_plic_t *plic) {
+ // Set IRQ priorities to MAX
+ CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
+ plic, kTopMatchaPlicIrqIdMlTopFinish, kDifRvPlicMaxPriority));
+ CHECK_DIF_OK(dif_rv_plic_irq_set_priority(plic, kTopMatchaPlicIrqIdMlTopFault,
+ kDifRvPlicMaxPriority));
+
+ // Set Ibex IRQ priority threshold level
+ CHECK_DIF_OK(dif_rv_plic_target_set_threshold(
+ plic, kTopMatchaPlicTargetIbex0Smc, kDifRvPlicMinPriority));
+
+ // Enable ML core IRQs
+ CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(plic, kTopMatchaPlicIrqIdMlTopFinish,
+ kTopMatchaPlicTargetIbex0Smc,
+ kDifToggleEnabled));
+ CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(plic, kTopMatchaPlicIrqIdMlTopFault,
+ kTopMatchaPlicTargetIbex0Smc,
+ kDifToggleEnabled));
+}
+
+void _ottf_main(void) {
+ test_status_set(kTestStatusInTest);
+ init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart);
+ LOG_INFO("[SMC] Start from SMC!");
+
+ // Init IRQs
+ CHECK_DIF_OK(dif_rv_plic_init(
+ mmio_region_from_addr(TOP_MATCHA_RV_PLIC_SMC_BASE_ADDR), &plic_smc));
+ plic_smc_configure_irqs(&plic_smc);
+ irq_global_ctrl(true);
+ irq_external_ctrl(true);
+
+ // Init ML_TOP
+ CHECK_DIF_OK(dif_ml_top_init(
+ mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR), &ml_top));
+ CHECK_DIF_OK(dif_ml_top_irq_set_enabled(&ml_top, kDifMlTopIrqFinish,
+ kDifToggleEnabled));
+ CHECK_DIF_OK(dif_ml_top_irq_set_enabled(&ml_top, kDifMlTopIrqFault,
+ kDifToggleEnabled));
+ dif_ml_top_reset_ctrl_en(&ml_top);
+
+ // Create an array with the pointers to the image frame
+ // Cast the type from unsigned char into uint32_t
+ const uint32_t *const hps_image_frame[] = {(const uint32_t *)hps_0};
+ const unsigned int hps_image_frame_byte_len[] = {hps_0_len};
+ const int kNumOfFrames = 1;
+
+ const int expected_output[][2] = {{-118, -128}};
+
+ mmio_region_t ml_dmem =
+ mmio_region_from_addr(TOP_MATCHA_ML_TOP_DMEM_BASE_ADDR);
+ mmio_region_write32(ml_dmem, TOP_MATCHA_RAM_ML_DMEM_CMD_OFFSET_ADDR,
+ TOP_MATCHA_RAM_ML_DMEM_IMG_OFFSET_ADDR);
+ mmio_region_write32(ml_dmem,
+ TOP_MATCHA_RAM_ML_DMEM_CMD_OFFSET_ADDR + sizeof(uint32_t),
+ TOP_MATCHA_RAM_ML_DMEM_OUT_OFFSET_ADDR);
+
+ mmio_region_t ml_hps_base =
+ mmio_region_from_addr(TOP_MATCHA_RAM_ML_DMEM_BASE_ADDR +
+ TOP_MATCHA_RAM_ML_DMEM_IMG_OFFSET_ADDR);
+ CHECK_DIF_OK(dif_ml_top_reset_ctrl_en(&ml_top));
+ for (int frame_idx = 0; frame_idx < kNumOfFrames; ++frame_idx) {
+ // Load HPS images 0-6 into ML DMEM.
+ LOG_INFO("[SMC] Start frame [%d]", frame_idx);
+ CHECK(hps_image_frame_byte_len[frame_idx] % sizeof(uint32_t) == 0,
+ "The frame is not word align");
+ for (uintptr_t word_idx = 0;
+ word_idx < hps_image_frame_byte_len[frame_idx] / sizeof(uint32_t);
+ ++word_idx) {
+ uintptr_t offset = word_idx * sizeof(uint32_t);
+ mmio_region_write32(ml_hps_base, offset,
+ hps_image_frame[frame_idx][word_idx]);
+ }
+
+ // Start up Kelvin.
+ ml_top_finish_done = false;
+ CHECK_DIF_OK(dif_ml_top_release_ctrl_en(&ml_top));
+ while (!ml_top_finish_done) {
+ asm volatile("wfi");
+ }
+
+ // Verify model output
+ mmio_region_t ml_model_out_base =
+ mmio_region_from_addr(TOP_MATCHA_RAM_ML_DMEM_BASE_ADDR +
+ TOP_MATCHA_RAM_ML_DMEM_OUT_OFFSET_ADDR);
+ const int8_t model_out_val0 = mmio_region_read8(ml_model_out_base, 0);
+ const int8_t model_out_val1 = mmio_region_read8(ml_model_out_base, 1);
+ CHECK(model_out_val0 == expected_output[frame_idx][0] &&
+ model_out_val1 == expected_output[frame_idx][1],
+ "Frame %d failed - Expected: {%d, %d} | Actual: {%d, %d}", frame_idx,
+ expected_output[frame_idx][0], expected_output[frame_idx][1],
+ model_out_val0, model_out_val1);
+ }
+
+ test_status_set(kTestStatusPassed);
+ asm volatile("wfi");
+}