#include "c13_common.h" #define TASK04_GPIO_INPUT (UINT32_C(1) << 4) #define TASK04_GPIO_EFFECT (UINT32_C(1) << 0) #define TASK04_UART_EFFECT (UINT32_C(1) << 1) #define TASK04_TIMER_EFFECT (UINT32_C(1) << 2) #define TASK04_TIMER_PERIOD UINT64_C(10000) volatile uint32_t g_task04_timer_irq_count; volatile uint32_t g_task04_timer_flag; volatile uint32_t g_task04_timer_mcause; volatile uint64_t g_task04_timer_deadline; volatile uint64_t g_task04_timer_observed; volatile uint32_t g_task04_uart_irq_count; volatile uint32_t g_task04_uart_irq_number; volatile uint32_t g_task04_uart_byte; volatile uint32_t g_task04_uart_flag; volatile uint32_t g_task04_gpio_irq_count; volatile uint32_t g_task04_gpio_irq_number; volatile uint32_t g_task04_gpio_level; volatile uint32_t g_task04_gpio_flag; volatile uint32_t g_task04_main_timer_actions; volatile uint32_t g_task04_main_uart_actions; volatile uint32_t g_task04_main_gpio_actions; volatile uint32_t g_task04_final_out; volatile uint32_t g_task04_final_in; volatile uint32_t g_task04_pass; void __attribute__((interrupt("machine"))) isr_machine_timer(void) { const uint64_t observed = c13_timer_read64(); g_task04_timer_mcause = read_csr(mcause); g_task04_timer_observed = observed; g_task04_timer_deadline += TASK04_TIMER_PERIOD; c13_timer_set_compare(g_task04_timer_deadline); g_task04_timer_flag = 1u; g_task04_timer_irq_count = g_task04_timer_irq_count + 1u; } void task04_uart_handler(void) { g_task04_uart_irq_number = (uint32_t)h3irq_get_current_irq(); g_task04_uart_byte = *tb_uart_reg(C13_UART_INDEX, TB_UART_DATA) & 0xffu; g_task04_uart_flag = 1u; g_task04_uart_irq_count = g_task04_uart_irq_count + 1u; } void task04_gpio_handler(void) { const uint32_t pending = tb_gpio_read(TB_GPIO_PENDING); g_task04_gpio_irq_number = (uint32_t)h3irq_get_current_irq(); g_task04_gpio_level = (tb_gpio_read(TB_GPIO_IN) & TASK04_GPIO_INPUT) != 0u; tb_gpio_write(TB_GPIO_PENDING, pending); g_task04_gpio_flag = 1u; g_task04_gpio_irq_count = g_task04_gpio_irq_count + 1u; } static uint32_t take_flag(volatile uint32_t *flag) { uint32_t value; global_irq_enable(false); value = *flag; *flag = 0u; global_irq_enable(true); return value; } int main(void) { const uint32_t output_mask = TASK04_GPIO_EFFECT | TASK04_UART_EFFECT | TASK04_TIMER_EFFECT; global_irq_enable(false); timer_irq_enable(false); external_irq_enable(false); tb_uart_rx_irq_enable(C13_UART_INDEX, false); h3irq_enable(C13_UART_IRQ, false); h3irq_enable(C13_GPIO_IRQ, false); c13_timer_set_compare(UINT64_MAX); tb_gpio_write(TB_GPIO_DIR, output_mask); tb_gpio_write(TB_GPIO_OUT_CLR, output_mask); tb_gpio_write(TB_GPIO_RISE_EN, 0u); tb_gpio_write(TB_GPIO_FALL_EN, 0u); tb_gpio_write(TB_GPIO_PENDING, UINT32_MAX); tb_gpio_test_set_input(0u); h3irq_set_handler(C13_UART_IRQ, task04_uart_handler); h3irq_set_handler(C13_GPIO_IRQ, task04_gpio_handler); h3irq_set_priority(C13_UART_IRQ, 1u); h3irq_set_priority(C13_GPIO_IRQ, 2u); h3irq_enable(C13_UART_IRQ, true); h3irq_enable(C13_GPIO_IRQ, true); external_irq_enable(true); tb_uart_rx_irq_enable(C13_UART_INDEX, true); tb_gpio_write(TB_GPIO_RISE_EN, TASK04_GPIO_INPUT); g_task04_timer_deadline = c13_timer_read64() + TASK04_TIMER_PERIOD; c13_timer_set_compare(g_task04_timer_deadline); timer_irq_enable(true); global_irq_enable(true); /* Both writes are testbench stimuli, not production peripheral registers. */ tb_uart_test_inject_rx(C13_UART_INDEX, (uint8_t)'U'); tb_gpio_test_set_input(TASK04_GPIO_INPUT); while (g_task04_main_timer_actions == 0u || g_task04_main_uart_actions == 0u || g_task04_main_gpio_actions == 0u) { if (take_flag(&g_task04_uart_flag) != 0u) { if (g_task04_uart_byte == (uint32_t)'U') { tb_gpio_write(TB_GPIO_OUT_SET, TASK04_UART_EFFECT); } g_task04_main_uart_actions++; } if (take_flag(&g_task04_gpio_flag) != 0u) { if (g_task04_gpio_level != 0u) { tb_gpio_write(TB_GPIO_OUT_SET, TASK04_GPIO_EFFECT); } g_task04_main_gpio_actions++; } if (take_flag(&g_task04_timer_flag) != 0u) { tb_gpio_write(TB_GPIO_OUT_SET, TASK04_TIMER_EFFECT); g_task04_main_timer_actions++; } if (g_task04_main_timer_actions == 0u || g_task04_main_uart_actions == 0u || g_task04_main_gpio_actions == 0u) { __asm__ volatile("wfi" ::: "memory"); } } global_irq_enable(false); timer_irq_enable(false); c13_timer_set_compare(UINT64_MAX); c13_external_disable(); tb_gpio_write(TB_GPIO_RISE_EN, 0u); g_task04_final_out = tb_gpio_read(TB_GPIO_OUT) & output_mask; g_task04_final_in = tb_gpio_read(TB_GPIO_IN) & (output_mask | TASK04_GPIO_INPUT); g_task04_pass = g_task04_timer_irq_count == 1u && g_task04_timer_mcause == C13_MACHINE_TIMER_CAUSE && g_task04_timer_observed >= g_task04_timer_deadline - TASK04_TIMER_PERIOD && g_task04_uart_irq_count == 1u && g_task04_uart_irq_number == C13_UART_IRQ && g_task04_uart_byte == (uint32_t)'U' && g_task04_gpio_irq_count == 1u && g_task04_gpio_irq_number == C13_GPIO_IRQ && g_task04_gpio_level == 1u && g_task04_main_timer_actions == 1u && g_task04_main_uart_actions == 1u && g_task04_main_gpio_actions == 1u && g_task04_final_out == output_mask && g_task04_final_in == (output_mask | TASK04_GPIO_INPUT); c13_report_u32("T04 timer_irq=", g_task04_timer_irq_count); c13_report_u32("T04 timer_mcause=", g_task04_timer_mcause); c13_report_u32("T04 uart_irq=", g_task04_uart_irq_count); c13_report_u32("T04 uart_number=", g_task04_uart_irq_number); c13_report_u32("T04 uart_byte=", g_task04_uart_byte); c13_report_u32("T04 gpio_irq=", g_task04_gpio_irq_count); c13_report_u32("T04 gpio_number=", g_task04_gpio_irq_number); c13_report_u32("T04 gpio_level=", g_task04_gpio_level); c13_report_u32("T04 main_timer=", g_task04_main_timer_actions); c13_report_u32("T04 main_uart=", g_task04_main_uart_actions); c13_report_u32("T04 main_gpio=", g_task04_main_gpio_actions); c13_report_u32("T04 final_out=", g_task04_final_out); c13_report_u32("T04 final_in=", g_task04_final_in); c13_report_u32("T04 pass=", g_task04_pass); return g_task04_pass ? 0 : 1; }