Replace polling with irq handling for ML core processing
Bug:284028282
Change-Id: I8b826aa17bac5d16edd799a8c0888a59813632fe
diff --git a/sw/device/examples/demo_hps_from_test_images/BUILD b/sw/device/examples/demo_hps_from_test_images/BUILD
index 454138a..04715b6 100644
--- a/sw/device/examples/demo_hps_from_test_images/BUILD
+++ b/sw/device/examples/demo_hps_from_test_images/BUILD
@@ -132,6 +132,8 @@
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",
"@lowrisc_opentitan//sw/device/silicon_creator/lib:manifest_def",
],
@@ -155,6 +157,7 @@
"//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",
"@lowrisc_opentitan//sw/device/silicon_creator/lib:manifest_def",
],
diff --git a/sw/device/examples/demo_hps_from_test_images/kelvin_checksum_smc.c b/sw/device/examples/demo_hps_from_test_images/kelvin_checksum_smc.c
index aac3b8e..2b34a47 100644
--- a/sw/device/examples/demo_hps_from_test_images/kelvin_checksum_smc.c
+++ b/sw/device/examples/demo_hps_from_test_images/kelvin_checksum_smc.c
@@ -18,7 +18,10 @@
#include "hw/top_matcha/sw/autogen/top_matcha.h"
#include "sw/device/examples/testdata/hps_images/hps_images.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"
@@ -31,13 +34,97 @@
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
+ mmio_region_t base_addr =
+ mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR);
+ CHECK_DIF_OK(dif_ml_top_init(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));
+
// 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,
@@ -78,9 +165,7 @@
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);
- mmio_region_t ml_core =
- mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR);
- mmio_region_write32(ml_core, ML_TOP_CTRL_REG_OFFSET, ML_TOP_CTRL_REG_RESVAL);
+ CHECK_DIF_OK(dif_ml_top_reset_ctrl_en(&ml_top));
// Run ML models and verify HPS images.
for (int frame_idx = 0; frame_idx < num_of_frames; ++frame_idx) {
@@ -98,16 +183,11 @@
}
// Start up Kelvin.
- mmio_region_write32(ml_core, ML_TOP_CTRL_REG_OFFSET, 0x0);
- uint32_t intr_state =
- mmio_region_read32(ml_core, ML_TOP_INTR_STATE_REG_OFFSET);
- while (intr_state == 0x0) {
- intr_state = mmio_region_read32(ml_core, ML_TOP_INTR_STATE_REG_OFFSET);
- busy_spin_micros(10); // Wait for 10ms.
+ ml_top_finish_done = false;
+ CHECK_DIF_OK(dif_ml_top_release_ctrl_en(&ml_top));
+ while (!ml_top_finish_done) {
+ asm volatile("wfi");
}
- mmio_region_write32(ml_core, ML_TOP_CTRL_REG_OFFSET,
- ML_TOP_CTRL_REG_RESVAL);
- mmio_region_write32(ml_core, ML_TOP_INTR_STATE_REG_OFFSET, intr_state);
// Verify checksum
mmio_region_t ml_checksum_base =
diff --git a/sw/device/examples/demo_hps_from_test_images/kelvin_model_smc.c b/sw/device/examples/demo_hps_from_test_images/kelvin_model_smc.c
index 901ff68..3aa087b 100644
--- a/sw/device/examples/demo_hps_from_test_images/kelvin_model_smc.c
+++ b/sw/device/examples/demo_hps_from_test_images/kelvin_model_smc.c
@@ -21,7 +21,9 @@
#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"
@@ -34,15 +36,95 @@
OTTF_DEFINE_TEST_CONFIG();
-static dif_uart_t smc_uart;
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
@@ -85,8 +167,7 @@
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);
- mmio_region_t ml_core =
- mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_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);
@@ -101,16 +182,11 @@
}
// Start up Kelvin.
- mmio_region_write32(ml_core, ML_TOP_CTRL_REG_OFFSET, 0x0);
- uint32_t intr_state =
- mmio_region_read32(ml_core, ML_TOP_INTR_STATE_REG_OFFSET);
- while (intr_state == 0x0) {
- intr_state = mmio_region_read32(ml_core, ML_TOP_INTR_STATE_REG_OFFSET);
- busy_spin_micros(10); // Wait for 10ms.
+ ml_top_finish_done = false;
+ CHECK_DIF_OK(dif_ml_top_release_ctrl_en(&ml_top));
+ while (!ml_top_finish_done) {
+ asm volatile("wfi");
}
- mmio_region_write32(ml_core, ML_TOP_CTRL_REG_OFFSET,
- ML_TOP_CTRL_REG_RESVAL);
- mmio_region_write32(ml_core, ML_TOP_INTR_STATE_REG_OFFSET, intr_state);
// Verify model output
mmio_region_t ml_model_out_base =
diff --git a/sw/device/examples/demo_hps_live/hps_demo_smc.c b/sw/device/examples/demo_hps_live/hps_demo_smc.c
index c397097..5cd11cf 100644
--- a/sw/device/examples/demo_hps_live/hps_demo_smc.c
+++ b/sw/device/examples/demo_hps_live/hps_demo_smc.c
@@ -61,6 +61,8 @@
static volatile bool isp_frame_done = false;
static uint32_t img_offset = TOP_MATCHA_RAM_ML_DMEM_IMG0_OFFSET_ADDR;
+static volatile bool ml_top_finish_done = false;
+
static void handle_isp_wrapper_isp_irq() {
sFONT *font = &Font16;
// Set address of image buffer.
@@ -69,9 +71,8 @@
mmio_region_write32(ml_dmem, TOP_MATCHA_RAM_ML_DMEM_CMD_OFFSET_ADDR,
img_offset);
// Start up Kelvin core running the model
- mmio_region_t ml_core =
- mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR);
- mmio_region_write32(ml_core, ML_TOP_CTRL_REG_OFFSET, 0x0);
+ ml_top_finish_done = false;
+ CHECK_DIF_OK(dif_ml_top_release_ctrl_en(&ml_top));
LOG_INFO("[SMC] Kelvin starts running model.");
// Inform the host that a new frame is available.
@@ -93,14 +94,9 @@
font->Height, LCD_WIDTH, LCD_HEIGHT);
// Wait until Kelvin finishes. Reset Kelvin core.
- uint32_t intr_state =
- mmio_region_read32(ml_core, ML_TOP_INTR_STATE_REG_OFFSET);
- while (intr_state == 0x0) {
- intr_state = mmio_region_read32(ml_core, ML_TOP_INTR_STATE_REG_OFFSET);
- busy_spin_micros(delay_time_micros);
+ while (!ml_top_finish_done) {
+ asm volatile("wfi");
}
- mmio_region_write32(ml_core, ML_TOP_CTRL_REG_OFFSET, ML_TOP_CTRL_REG_RESVAL);
- mmio_region_write32(ml_core, ML_TOP_INTR_STATE_REG_OFFSET, intr_state);
LOG_INFO("[SMC] Kelvin finished running model.");
// Log model score
@@ -143,6 +139,22 @@
}
}
+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;
@@ -156,7 +168,8 @@
CHECK(peripheral_id == kTopMatchaPlicPeripheralIspWrapper ||
peripheral_id == kTopMatchaPlicPeripheralCamI2c ||
peripheral_id == kTopMatchaPlicPeripheralSpiHost2 ||
- peripheral_id == kTopMatchaPlicPeripheralTlulMailboxSmc,
+ peripheral_id == kTopMatchaPlicPeripheralTlulMailboxSmc ||
+ peripheral_id == kTopMatchaPlicPeripheralMlTop,
"Unexpected peripheral in ISR: %d", peripheral_id);
switch (peripheral_id) {
case kTopMatchaPlicPeripheralCamI2c: {
@@ -174,6 +187,10 @@
CHECK_DIF_OK(spi_display_spi_irq_handler(&spi_display));
break;
}
+ case kTopMatchaPlicPeripheralMlTop: {
+ handle_ml_top_isr(interrupt_id);
+ break;
+ }
default:
LOG_FATAL("Peripheral is not implemented!");
}
@@ -185,7 +202,7 @@
}
/*
- * Configures all the relevant interrupts in PLIC_SEC.
+ * Configures all the relevant interrupts in PLIC_SMC.
*/
static void plic_smc_configure_irqs(dif_rv_plic_t *plic) {
CHECK_DIF_OK(camera_hm01b0_irq_init(plic, kTopMatchaPlicTargetIbex0Smc));
@@ -194,24 +211,36 @@
plic, kTopMatchaPlicIrqIdIspWrapperIsp, kDifRvPlicMaxPriority));
CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
plic, kTopMatchaPlicIrqIdIspWrapperMi, kDifRvPlicMaxPriority));
+ 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 IRQs in PLIC
+ // Enable ISP IRQs
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
plic, kTopMatchaPlicIrqIdIspWrapperIsp, kTopMatchaPlicTargetIbex0Smc,
kDifToggleEnabled));
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
plic, kTopMatchaPlicIrqIdIspWrapperMi, kTopMatchaPlicTargetIbex0Smc,
kDifToggleEnabled));
-
+ // Enable Mailbox IRQs
CHECK_DIF_OK(dif_rv_plic_irq_set_enabled(
- &plic_smc, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq,
+ plic, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq,
kTopMatchaPlicTargetIbex0Smc, kDifToggleEnabled));
CHECK_DIF_OK(dif_rv_plic_irq_set_priority(
- &plic_smc, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq, 1));
+ plic, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq, 1));
+ // 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) {
@@ -250,6 +279,10 @@
// 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);
LOG_INFO("[SMC] ML_TOP INIT.");
diff --git a/sw/device/examples/hello_world_multicore/BUILD b/sw/device/examples/hello_world_multicore/BUILD
index fe9bb58..1267682 100644
--- a/sw/device/examples/hello_world_multicore/BUILD
+++ b/sw/device/examples/hello_world_multicore/BUILD
@@ -16,7 +16,6 @@
],
target_compatible_with = [OPENTITAN_CPU],
deps = [
- "//hw/top_matcha/ip/ml_top/data:ml_top_regs",
"//hw/top_matcha/sw/autogen:top_matcha",
"//sw/device/lib/dif:smc_ctrl",
"//sw/device/lib/testing/test_framework:ottf_start",
@@ -81,9 +80,12 @@
},
var_name = "hello_world_multicore_smc_fpga_nexus_bin",
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/testing/test_framework:ottf_start_smc",
"//sw/device/lib/testing/test_framework:test_util",
+ "@lowrisc_opentitan//sw/device/lib/runtime:irq",
"@lowrisc_opentitan//sw/device/lib/testing/test_framework:ottf_test_config",
],
)
diff --git a/sw/device/examples/hello_world_multicore/hello_world_multicore_sc.c b/sw/device/examples/hello_world_multicore/hello_world_multicore_sc.c
index 8a1248d..dc75cf9 100644
--- a/sw/device/examples/hello_world_multicore/hello_world_multicore_sc.c
+++ b/sw/device/examples/hello_world_multicore/hello_world_multicore_sc.c
@@ -14,8 +14,6 @@
* 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/hello_world_multicore/hello_world_multicore_sc_loaders.h"
#include "sw/device/lib/arch/device.h"
@@ -49,9 +47,6 @@
// Copy binary to SMC RAM.
load_smc();
- // Load Kelvin's memory space.
- const uint32_t kKelvinDataOffset = 0x100000; // 1MB
- const uint32_t kKelvinDataSize = 0x1000; // 1024 32-bit words
mmio_region_t ml_dmem =
mmio_region_from_addr(TOP_MATCHA_ML_TOP_DMEM_BASE_ADDR);
@@ -64,43 +59,10 @@
// Copy binary to ML_DMEM.
load_kelvin();
- // Fill Kelvin's working region with known values.
- for (uint32_t i = kKelvinDataOffset; i < kKelvinDataOffset + kKelvinDataSize;
- i += sizeof(uint32_t)) {
- mmio_region_write32(ml_dmem, i, i);
- }
-
// 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);
- 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);
-
- for (uint32_t i = kKelvinDataOffset; i < kKelvinDataOffset + kKelvinDataSize;
- i += sizeof(uint32_t)) {
- uint32_t val = mmio_region_read32(ml_dmem, i);
- CHECK(val == i + 1,
- "Mismatch data at offset 0x%h - Expected: 0x%h | Actual: 0x%h", i,
- i + 1, val);
- }
- test_status_set(kTestStatusPassed);
asm volatile("wfi");
}
diff --git a/sw/device/examples/hello_world_multicore/hello_world_multicore_smc.c b/sw/device/examples/hello_world_multicore/hello_world_multicore_smc.c
index 24d382b..4f0fe88 100644
--- a/sw/device/examples/hello_world_multicore/hello_world_multicore_smc.c
+++ b/sw/device/examples/hello_world_multicore/hello_world_multicore_smc.c
@@ -14,9 +14,13 @@
* 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/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"
@@ -24,10 +28,115 @@
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 void handle_ml_top_isr(const dif_rv_plic_irq_id_t interrupt_id) {
+ switch (interrupt_id) {
+ case kTopMatchaPlicIrqIdMlTopFinish:
+ 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) {
init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart);
LOG_INFO("hello_world_multicore_smc");
- asm volatile("wfi");
+
+ // 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));
+ CHECK_DIF_OK(dif_ml_top_reset_ctrl_en(&ml_top));
+
+ // Load Kelvin's memory space.
+ const uint32_t kKelvinDataOffset = 0x100000; // 1MB
+ const uint32_t kKelvinDataSize = 0x1000; // 1024 32-bit words
+ mmio_region_t ml_dmem =
+ mmio_region_from_addr(TOP_MATCHA_ML_TOP_DMEM_BASE_ADDR);
+
+ // Fill Kelvin's working region with known values.
+ for (uint32_t i = kKelvinDataOffset; i < kKelvinDataOffset + kKelvinDataSize;
+ i += sizeof(uint32_t)) {
+ mmio_region_write32(ml_dmem, i, i);
+ }
+
+ CHECK_DIF_OK(dif_ml_top_release_ctrl_en(&ml_top));
+
+ LOG_INFO("Kelvin finished executing.");
+ for (uint32_t i = kKelvinDataOffset; i < kKelvinDataOffset + kKelvinDataSize;
+ i += sizeof(uint32_t)) {
+ uint32_t val = mmio_region_read32(ml_dmem, i);
+ CHECK(val == i + 1,
+ "Mismatch data at offset 0x%h - Expected: 0x%h | Actual: 0x%h", i,
+ i + 1, val);
+ }
+ test_status_set(kTestStatusPassed);
}
diff --git a/sw/device/lib/dif/dif_ml_top.c b/sw/device/lib/dif/dif_ml_top.c
index 8be195e..f2ca845 100644
--- a/sw/device/lib/dif/dif_ml_top.c
+++ b/sw/device/lib/dif/dif_ml_top.c
@@ -36,6 +36,15 @@
return kDifOk;
}
+dif_result_t dif_ml_top_release_ctrl_en(const dif_ml_top_t *ml_top) {
+ if (ml_top == NULL) {
+ return kDifBadArg;
+ }
+
+ mmio_region_write32(ml_top->base_addr, ML_TOP_CTRL_REG_OFFSET, 0x0);
+ return kDifOk;
+}
+
dif_result_t dif_ml_top_read_ctrl_en(const dif_ml_top_t *ml_top, uint32_t *result) {
if (ml_top == NULL) {
return kDifBadArg;
diff --git a/sw/device/lib/dif/dif_ml_top.h b/sw/device/lib/dif/dif_ml_top.h
index af29c7a..81f079c 100644
--- a/sw/device/lib/dif/dif_ml_top.h
+++ b/sw/device/lib/dif/dif_ml_top.h
@@ -15,9 +15,8 @@
* limitations under the License.
*/
-
-#ifndef MATCHA_SW_DEVICE_LIB_DIF_DIF_ML_TOP_H_
-#define MATCHA_SW_DEVICE_LIB_DIF_DIF_ML_TOP_H_
+#ifndef SW_DEVICE_LIB_DIF_DIF_ML_TOP_H_
+#define SW_DEVICE_LIB_DIF_DIF_ML_TOP_H_
/**
* @file
@@ -34,11 +33,14 @@
// ML_Top Control Register
dif_result_t dif_ml_top_reset_ctrl_en(const dif_ml_top_t *ml_top);
-dif_result_t dif_ml_top_read_ctrl_en(const dif_ml_top_t *ml_top, uint32_t *result);
+dif_result_t dif_ml_top_release_ctrl_en(const dif_ml_top_t *ml_top);
+dif_result_t dif_ml_top_read_ctrl_en(const dif_ml_top_t *ml_top,
+ uint32_t *result);
// ML_Top Interrupt Enable Register
dif_result_t dif_ml_top_reset_intr_en(const dif_ml_top_t *ml_top);
-dif_result_t dif_ml_top_read_intr_en(const dif_ml_top_t *ml_top, uint32_t *result);
+dif_result_t dif_ml_top_read_intr_en(const dif_ml_top_t *ml_top,
+ uint32_t *result);
/**
* Below functions are auto-generated. Keep them here for now for reference.
@@ -140,4 +142,4 @@
} // extern "C"
#endif // __cplusplus
-#endif // MATCHA_SW_DEVICE_LIB_DIF_DIF_ML_TOP_H_
+#endif // SW_DEVICE_LIB_DIF_DIF_ML_TOP_H_
diff --git a/sw/device/tests/smc/BUILD b/sw/device/tests/smc/BUILD
index deee857..a86fe8d 100644
--- a/sw/device/tests/smc/BUILD
+++ b/sw/device/tests/smc/BUILD
@@ -278,6 +278,8 @@
},
deps = [
"//hw/top_matcha/ip/ml_top/data:ml_top_regs",
+ "//sw/device/lib/dif:ml_top",
+ "//sw/device/lib/dif:rv_plic_smc",
"//sw/device/tests:test_lib_smc",
],
)
@@ -298,6 +300,8 @@
},
deps = [
"//hw/top_matcha/ip/ml_top/data:ml_top_regs",
+ "//sw/device/lib/dif:ml_top",
+ "//sw/device/lib/dif:rv_plic_smc",
"//sw/device/tests:test_lib_smc",
],
)
diff --git a/sw/device/tests/smc/smc_kelvin_checksum_test.c b/sw/device/tests/smc/smc_kelvin_checksum_test.c
index 85a4e48..5a81c20 100644
--- a/sw/device/tests/smc/smc_kelvin_checksum_test.c
+++ b/sw/device/tests/smc/smc_kelvin_checksum_test.c
@@ -20,8 +20,11 @@
#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_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/hart.h"
+#include "sw/device/lib/runtime/irq.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/runtime/print.h"
#include "sw/device/lib/testing/test_framework/check.h"
@@ -35,18 +38,99 @@
OTTF_DEFINE_TEST_CONFIG();
+static dif_ml_top_t ml_top;
+static dif_rv_plic_t plic_smc;
static dif_uart_t smc_uart;
-void _ottf_main(void) {
- uint32_t mem_val;
- uint32_t intr_state;
+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);
// Initialize the SMC UART to enable logging for non-DV simulation platforms.
if (kDeviceType != kDeviceSimDV) {
init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart);
}
+ // 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));
+
// Write DMEM with initial values
const uint32_t *input = (const uint32_t *)hps_0;
mmio_region_t ml_dmem_base = mmio_region_from_addr(
@@ -61,32 +145,21 @@
mmio_region_t base_addr =
mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR);
// Un-freeze clock and Reset of ML_TOP
- mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET,
- ML_TOP_CTRL_REG_RESVAL);
- mem_val = mmio_region_read32(base_addr, ML_TOP_CTRL_REG_OFFSET);
+ CHECK_DIF_OK(dif_ml_top_reset_ctrl_en(&ml_top));
+ uint32_t mem_val = mmio_region_read32(base_addr, ML_TOP_CTRL_REG_OFFSET);
CHECK(mem_val == ML_TOP_CTRL_REG_RESVAL,
"ML_TOP_CTRL read out: expected : 0x%x | actual: 0x%x",
ML_TOP_CTRL_REG_RESVAL, mem_val);
// Release the Reset of ML_TOP
- mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET, 0x0);
+ ml_top_finish_done = false;
+ CHECK_DIF_OK(dif_ml_top_release_ctrl_en(&ml_top));
- // Wait for a interrupt
- intr_state = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET);
- CHECK(intr_state == 0,
- "ML_TOP_Core offset 0 INTR_STATE - Expected: 0x0 | Actual: 0x%x",
- intr_state);
-
- while (intr_state == 0x0) {
- intr_state = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET);
- busy_spin_micros(200);
+ // Wait until Kelvin finishes.
+ while (!ml_top_finish_done) {
+ asm volatile("wfi");
}
- // 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);
-
// Check kelvin result. The program sums to the data stored in the test
// range 0x5A300000 to 0x5A312c00, and stored at 0x5A380000
ml_dmem_base = mmio_region_from_addr(TOP_MATCHA_RAM_ML_DMEM_BASE_ADDR);
diff --git a/sw/device/tests/smc/smc_kelvin_hello_test.c b/sw/device/tests/smc/smc_kelvin_hello_test.c
index fab6c61..8a6babf 100644
--- a/sw/device/tests/smc/smc_kelvin_hello_test.c
+++ b/sw/device/tests/smc/smc_kelvin_hello_test.c
@@ -19,8 +19,11 @@
#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_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/hart.h"
+#include "sw/device/lib/runtime/irq.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/runtime/print.h"
#include "sw/device/lib/testing/test_framework/check.h"
@@ -30,8 +33,77 @@
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) {
uint32_t mem_val;
uint32_t intr_state;
@@ -44,12 +116,26 @@
init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart);
}
+ // 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
+ mmio_region_t base_addr =
+ mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR);
+ CHECK_DIF_OK(dif_ml_top_init(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));
+
LOG_INFO("Hello Shodan! let's do a Kelvin core simple test!");
// Start testing ML_TOP_Core
test_status_set(kTestStatusInTest);
- mmio_region_t base_addr =
- mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR);
intr_state = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET);
CHECK(intr_state == 0,
@@ -64,7 +150,8 @@
intr_state);
mem_val = mmio_region_read32(base_addr, ML_TOP_INTR_ENABLE_REG_OFFSET);
- CHECK(mem_val == 0,
+ CHECK(mem_val == (1 << ML_TOP_INTR_COMMON_FINISH_BIT |
+ 1 << ML_TOP_INTR_COMMON_FAULT_BIT),
"ML_TOP_TOP offset 4 INTR_ENABLE - Expected: 0 | Actual: 0x%x",
mem_val);
mem_val = mmio_region_read32(base_addr, ML_TOP_INTR_TEST_REG_OFFSET);
@@ -85,35 +172,24 @@
}
// Un-freeze clock and Reset of ML_TOP
- mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET,
- ML_TOP_CTRL_REG_RESVAL);
+ CHECK_DIF_OK(dif_ml_top_reset_ctrl_en(&ml_top));
mem_val = mmio_region_read32(base_addr, ML_TOP_CTRL_REG_OFFSET);
CHECK(mem_val == ML_TOP_CTRL_REG_RESVAL,
"ML_TOP_CTRL read out: expected : 0x%x | actual: 0x%x",
ML_TOP_CTRL_REG_RESVAL, mem_val);
// Release the Reset of ML_TOP
- mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET, 0x0);
+ ml_top_finish_done = false;
+ CHECK_DIF_OK(dif_ml_top_release_ctrl_en(&ml_top));
mem_val = mmio_region_read32(base_addr, ML_TOP_CTRL_REG_OFFSET);
CHECK(mem_val == 0x0, "ML_TOP_CTRL read out: expected : 0x0 | actual: 0x%x",
mem_val);
- // Wait for a interrupt
- intr_state = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET);
- CHECK(intr_state == 0,
- "ML_TOP_Core offset 0 INTR_STATE - Expected: 0x0 | Actual: 0x%x",
- intr_state);
-
- while (intr_state == 0x0) {
- intr_state = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET);
- busy_spin_micros(200);
+ // Wait until Kelvin finishes.
+ while (!ml_top_finish_done) {
+ asm volatile("wfi");
}
- // 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);
-
// Check Kelvin result. The program adds 1 to the data stored in the test
// range 0x5A100000 to 0x5A101000.
for (uint32_t i = kKelvinDataOffset; i < kKelvinDataOffset + kKelvinDataSize;