Move the kelvin control logic to SMC Use SC to control flash image loading, and use SMC to control the kelvin core. The ML results are sent back to SC during binary iteration via the mailbox. Change-Id: I8be6bdced8269156bec76e1cdea324da9e090003
diff --git a/sw/device/tests/kelvin/fpga_tests/BUILD b/sw/device/tests/kelvin/fpga_tests/BUILD index 364d0cf..612828e 100644 --- a/sw/device/tests/kelvin/fpga_tests/BUILD +++ b/sw/device/tests/kelvin/fpga_tests/BUILD
@@ -23,11 +23,10 @@ "//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:rv_plic_sec", "//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", + "//sw/device/lib/dif:tlul_mailbox", + "//sw/device/tests:test_lib", ], ) @@ -43,11 +42,13 @@ per_device_deps = { "fpga_nexus": [NEXUS_CORE_TARGETS.get("smc")], }, - var_name = "kelvin_test_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/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", + "//sw/device/lib/dif:ml_top", + "//sw/device/lib/dif:rv_plic_smc", + "//sw/device/lib/dif:tlul_mailbox", + "//sw/device/tests:test_lib_smc", + "@lowrisc_opentitan//sw/device/lib/dif:rv_timer", ], )
diff --git a/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c index 0031960..4887bd2 100644 --- a/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c +++ b/sw/device/tests/kelvin/fpga_tests/kelvin_test_sc.c
@@ -3,8 +3,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_rv_plic.h" #include "sw/device/lib/dif/dif_smc_ctrl.h" +#include "sw/device/lib/dif/dif_tlul_mailbox.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/spi_flash.h" #include "sw/device/lib/testing/test_framework/check.h" @@ -13,16 +16,31 @@ #include "sw/device/lib/testing/test_framework/test_util.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. + * SC - Initialize SMC, load kelvin program, and print status to UART. + * SMC - Print to UART and orchestrate ML core/programs. */ OTTF_DEFINE_TEST_CONFIG(); static dif_smc_ctrl_t smc_ctrl; static dif_uart_t uart; +static dif_rv_plic_t plic_sec; +static dif_tlul_mailbox_t tlul_mailbox; + +volatile uint32_t message; + +void ottf_external_isr(void) { + dif_rv_plic_irq_id_t plic_irq_id; + uint32_t rx; + CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic_sec, kTopMatchaPlicTargetIbex0, + &plic_irq_id)); + CHECK_DIF_OK( + dif_tlul_mailbox_irq_acknowledge(&tlul_mailbox, kDifTlulMailboxIrqRtirq)); + CHECK_DIF_OK(dif_tlul_mailbox_read_message(&tlul_mailbox, &rx)); + message = rx; + CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic_sec, kTopMatchaPlicTargetIbex0, + plic_irq_id)); +} void _ottf_main(void) { test_status_set(kTestStatusInTest); @@ -44,17 +62,33 @@ mmio_region_write32(ml_dmem, i * sizeof(uint32_t), 0); } + // Setup mailbox. + CHECK_DIF_OK(dif_tlul_mailbox_init( + mmio_region_from_addr(TOP_MATCHA_TLUL_MAILBOX_SEC_BASE_ADDR), + &tlul_mailbox)); + CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled( + &tlul_mailbox, kDifTlulMailboxIrqRtirq, kDifToggleEnabled)); + CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled( + &tlul_mailbox, kDifTlulMailboxIrqWtirq, kDifToggleEnabled)); + CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled( + &tlul_mailbox, kDifTlulMailboxIrqEirq, kDifToggleEnabled)); + + // Set Interrupt. + CHECK_DIF_OK(dif_rv_plic_init( + mmio_region_from_addr(TOP_MATCHA_RV_PLIC_BASE_ADDR), &plic_sec)); + CHECK_DIF_OK(dif_rv_plic_irq_set_enabled( + &plic_sec, kTopMatchaPlicIrqIdTlulMailboxSecRtirq, + kTopMatchaPlicTargetIbex0, kDifToggleEnabled)); + CHECK_DIF_OK(dif_rv_plic_irq_set_priority( + &plic_sec, kTopMatchaPlicIrqIdTlulMailboxSecRtirq, 1)); + irq_global_ctrl(true); + irq_external_ctrl(true); + // 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)); - // Reset and Freeze 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 | (1 << ML_TOP_CTRL_FREEZE_BIT)); - // Copy binary to ML_DMEM. char kelvin_bin_name[256] = {'\0'}; size_t bin_offset = 0; @@ -70,32 +104,15 @@ CHECK_DIF_OK(kelvin_load_result, "Failed to load %s", kelvin_bin_name); test_num++; LOG_INFO("Test %d: Run kelvin binary %s", test_num, kelvin_bin_name); - // Start up Kelvin. - 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) { - busy_spin_micros(10 * 1000); // Wait for 10ms. - intr_state = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET); - } - // Received interrupts from Kelvin core, check if only FINISH asserted - if (intr_state != (1 << ML_TOP_INTR_STATE_FINISH_BIT)) { - LOG_ERROR("INTR_STATE read out: expected : 0x%x | actual: 0x%x", - (1 << ML_TOP_INTR_STATE_FINISH_BIT), intr_state); + uint32_t tx = 0; + // Send to smc to kickoff ML program + CHECK_DIF_OK(dif_tlul_mailbox_send_message(&tlul_mailbox, &tx)); + // Wait for mailbox interrupt + asm volatile("wfi"); + if (message != (1 << ML_TOP_INTR_STATE_FINISH_BIT)) { + LOG_ERROR(" Test finish with fault"); failed_test++; } - // Reset and halt Kelvin - mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET, - ML_TOP_CTRL_REG_RESVAL | (1 << ML_TOP_CTRL_FREEZE_BIT)); - // Write 1 to clear INTR_STATE - mmio_region_write32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET, intr_state); - intr_state = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET); - CHECK( - intr_state == 0, - "ML_TOP_Core offset 0 INTR_STATE read again - Expected: 0 | Actual: " - "0x%x", - intr_state); } LOG_INFO("Total test: %d, failed test: %d", test_num, failed_test); if (failed_test == 0) {
diff --git a/sw/device/tests/kelvin/fpga_tests/kelvin_test_smc.c b/sw/device/tests/kelvin/fpga_tests/kelvin_test_smc.c index ec9f4a8..916b4c8 100644 --- a/sw/device/tests/kelvin/fpga_tests/kelvin_test_smc.c +++ b/sw/device/tests/kelvin/fpga_tests/kelvin_test_smc.c
@@ -1,17 +1,167 @@ +#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_rv_timer.h" +#include "sw/device/lib/dif/dif_tlul_mailbox.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/test_util.h" +/* + * Sample program to run some code on all cores in the system. + * SMC - Print to UART and orchestrate ML core/programs. + * Kelvin - SW program built to run on Kelvin. + */ + OTTF_DEFINE_TEST_CONFIG(); static dif_uart_t smc_uart; +static dif_tlul_mailbox_t tlul_mailbox; +static dif_rv_plic_t plic_smc; +static dif_rv_timer_t rv_timer; +static dif_ml_top_t ml_top; + +static volatile bool ml_top_done = false; +static volatile bool bin_loaded = false; +static volatile uint32_t ml_result = 0; + +void ottf_external_isr(void) { + dif_rv_plic_irq_id_t plic_irq_id; + CHECK_DIF_OK(dif_rv_plic_irq_claim(&plic_smc, kTopMatchaPlicTargetIbex0Smc, + &plic_irq_id)); + top_matcha_plic_peripheral_smc_t peripheral_id = + top_matcha_plic_interrupt_for_peripheral_smc[plic_irq_id]; + CHECK(peripheral_id == kTopMatchaPlicPeripheralTlulMailboxSmc || + peripheral_id == kTopMatchaPlicPeripheralMlTop, + "Unexpected peripheral in ISR: %d", peripheral_id); + switch (peripheral_id) { + case kTopMatchaPlicPeripheralTlulMailboxSmc: { + uint32_t rx; + CHECK_DIF_OK(dif_tlul_mailbox_irq_acknowledge(&tlul_mailbox, + kDifTlulMailboxIrqRtirq)); + CHECK_DIF_OK(dif_tlul_mailbox_read_message(&tlul_mailbox, &rx)); + bin_loaded = true; + break; + } + case kTopMatchaPlicPeripheralMlTop: { + mmio_region_t base_addr = + mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR); + // Reset and halt Kelvin + mmio_region_write32( + base_addr, ML_TOP_CTRL_REG_OFFSET, + ML_TOP_CTRL_REG_RESVAL | (1 << ML_TOP_CTRL_FREEZE_BIT)); + ml_result = mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET); + // Write 1 to clear INTR_STATE + mmio_region_write32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET, ml_result); + uint32_t intr_state = + mmio_region_read32(base_addr, ML_TOP_INTR_STATE_REG_OFFSET); + CHECK(intr_state == 0, + "ML Top interrupt reset failed: expect 0, actual 0x%x", intr_state); + ml_top_done = true; + break; + } + default: + LOG_FATAL("Peripheral is not implemented!"); + } + CHECK_DIF_OK(dif_rv_plic_irq_complete(&plic_smc, kTopMatchaPlicTargetIbex0Smc, + plic_irq_id)); +} + +/* + * Configures all the relevant interrupts in PLIC_SMC. + */ +static void plic_smc_configure_irqs(dif_rv_plic_t *plic) { + // Set ML_TOP 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 Mailbox IRQs + CHECK_DIF_OK(dif_rv_plic_irq_set_enabled( + plic, kTopMatchaPlicIrqIdTlulMailboxSmcRtirq, + kTopMatchaPlicTargetIbex0Smc, kDifToggleEnabled)); + CHECK_DIF_OK(dif_rv_plic_irq_set_priority( + 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) { init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart); LOG_INFO("kelvin_test_smc"); - asm volatile("wfi"); + + // Configure Mailbox. + CHECK_DIF_OK(dif_tlul_mailbox_init( + mmio_region_from_addr(TOP_MATCHA_TLUL_MAILBOX_SMC_BASE_ADDR), + &tlul_mailbox)); + CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled( + &tlul_mailbox, kDifTlulMailboxIrqRtirq, kDifToggleEnabled)); + CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled( + &tlul_mailbox, kDifTlulMailboxIrqWtirq, kDifToggleEnabled)); + CHECK_DIF_OK(dif_tlul_mailbox_irq_set_enabled( + &tlul_mailbox, kDifTlulMailboxIrqEirq, kDifToggleEnabled)); + + // 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); + + // Set interrupt. + 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); + + // Set timer. + dif_rv_timer_tick_params_t tick_params; + CHECK_DIF_OK(dif_rv_timer_init( + mmio_region_from_addr(TOP_MATCHA_RV_TIMER_SMC_BASE_ADDR), &rv_timer)); + CHECK_DIF_OK(dif_rv_timer_approximate_tick_params(kClockFreqPeripheralHz, + 1000, &tick_params)); + CHECK_DIF_OK(dif_rv_timer_set_tick_params(&rv_timer, 0, tick_params)); + CHECK_DIF_OK( + dif_rv_timer_counter_set_enabled(&rv_timer, 0, kDifToggleEnabled)); + + uint32_t bin_index = 0; + while (true) { + uint64_t timer_start, timer_end; + bin_loaded = false; + while (!bin_loaded) { + asm volatile("wfi"); + } + // Start up Kelvin. + ml_top_done = false; + ml_result = 0; + CHECK_DIF_OK(dif_rv_timer_counter_read(&rv_timer, 0, &timer_start)); + mmio_region_t base_addr = + mmio_region_from_addr(TOP_MATCHA_ML_TOP_CORE_BASE_ADDR); + mmio_region_write32(base_addr, ML_TOP_CTRL_REG_OFFSET, 0x0); + while (!ml_top_done) { + asm volatile("wfi"); + } + CHECK_DIF_OK(dif_rv_timer_counter_read(&rv_timer, 0, &timer_end)); + LOG_INFO("Test %d: Finish in %d ms", ++bin_index, + (uint32_t)(timer_end - timer_start)); + uint32_t tx = ml_result; + CHECK_DIF_OK(dif_tlul_mailbox_send_message(&tlul_mailbox, &tx)); + } }