Files
gps/soc/software/pmod_irq_test/main.c
T

137 lines
3.6 KiB
C

#include <stdint.h>
#include <stdio.h>
#include "bsp/irq.h"
#include "bsp/mmio.h"
#include "bsp/plic.h"
#include "bsp/pmod_spi.h"
#include "bsp/soc.h"
#include "bsp/uart.h"
#ifdef PMOD_IRQ_TEST_QUIET
#define TEST_PRINTF(...) ((void)0)
#define TEST_UART_FLUSH() ((void)0)
#else
#define TEST_PRINTF(...) printf(__VA_ARGS__)
#define TEST_UART_FLUSH() bsp_uart_wait_tx_idle()
#endif
static volatile uint64_t irq_count;
static volatile uint64_t first_irq_timestamp;
static volatile uint64_t unexpected_mcause;
static volatile uint32_t unexpected_irq_id;
void pmod_irq_handler(void)
__attribute__((interrupt("machine"), aligned(4)));
void pmod_irq_handler(void)
{
asm volatile(
".option push\n"
".option norelax\n"
"la gp, __global_pointer$\n"
".option pop\n"
:
:
: "memory");
const uint64_t timestamp = bsp_read64(BSP_CLINT_MTIME);
const uint64_t mcause = bsp_read_mcause();
if(((mcause >> 63) == 0u) ||
((mcause & 0xfffu) != BSP_MCAUSE_MACHINE_EXTERNAL))
{
unexpected_mcause = mcause;
return;
}
const uint32_t irq_id = bsp_plic_claim();
if(irq_id == BSP_PMOD_IRQ)
{
/* PLIC gateway is level-sensitive. Mask on the first assertion so a
* hand-held HIGH wire cannot create an interrupt storm. */
bsp_plic_disable(BSP_PMOD_IRQ);
if(irq_count == 0u)
{
first_irq_timestamp = timestamp;
}
irq_count++;
}
else if(irq_id != 0u)
{
unexpected_irq_id = irq_id;
}
if(irq_id != 0u)
{
bsp_plic_complete(irq_id);
}
}
int main(void)
{
TEST_PRINTF("\nGenesys2 JB1 direct PLIC interrupt test\n");
TEST_PRINTF("PATH,JB1/V29,Rocket_interrupt_bus,PLIC%lu\n",
(unsigned long)BSP_PMOD_IRQ);
TEST_PRINTF("EXPECTED_RTL,wrapper_3FF,internal_pulldown; verify after synthesis\n");
TEST_PRINTF("INPUT,LVCMOS33,active_high,level_sensitive\n");
irq_count = 0u;
first_irq_timestamp = 0u;
unexpected_mcause = 0u;
unexpected_irq_id = 0u;
bsp_plic_disable_all();
bsp_plic_set_threshold(0u);
bsp_plic_set_priority(BSP_PMOD_IRQ, 1u);
bsp_pmod_spi_init();
bsp_pmod_spi_set_mode(BSP_PMOD_SPI_MODE_SINGLE);
bsp_pmod_spi_set_clock_mode(BSP_PMOD_SPI_CLOCK_MODE0);
bsp_set_mtvec(pmod_irq_handler);
bsp_plic_enable(BSP_PMOD_IRQ);
bsp_enable_machine_external_interrupts();
TEST_PRINTF("PMOD_IRQ_READY,disconnect_JB1_then_touch_JB1_to_3V3_once\n");
TEST_PRINTF("LOOPBACK_READY,wire_JC4_SCK_to_JB1_then_send_t\n");
TEST_UART_FLUSH();
while((irq_count == 0u) && (unexpected_mcause == 0u) &&
(unexpected_irq_id == 0u))
{
const int command = bsp_uart_getc_nonblocking();
if((command == 't') || (command == 'T'))
{
TEST_PRINTF("LOOPBACK_TRIGGER,source=JC4,destination=JB1\n");
TEST_UART_FLUSH();
for(unsigned int transfer = 0u; transfer < 16u; transfer++)
{
(void)bsp_pmod_spi_xfer8((uint8_t)(0xa5u ^ transfer));
}
if(irq_count == 0u)
{
TEST_PRINTF("LOOPBACK_NO_IRQ,check_JC4_to_JB1_jumper\n");
TEST_UART_FLUSH();
}
}
asm volatile("nop");
}
if(irq_count != 0u)
{
TEST_PRINTF("PMOD_IRQ_PASS,id=%lu,count=%lu,tick=%lu,tick_hz=%lu\n",
(unsigned long)BSP_PMOD_IRQ,
(unsigned long)irq_count,
(unsigned long)first_irq_timestamp,
(unsigned long)BSP_CLINT_TIMEBASE_HZ);
}
else
{
TEST_PRINTF("PMOD_IRQ_FAIL,mcause=%lu,unexpected_id=%lu\n",
(unsigned long)unexpected_mcause,
(unsigned long)unexpected_irq_id);
}
TEST_PRINTF("PMOD_IRQ_MASKED,remove_3V3_before_reset_or_reload\n");
TEST_UART_FLUSH();
/* The ASIC testbench observes this through mscratch. Returning success is
* therefore reserved for the expected PLIC device-11 ISR path. */
return (irq_count != 0u) ? 0 : 1;
}