137 lines
3.6 KiB
C
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;
|
|
}
|