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;