Понятно чем. Там два (в какой-то степени три) способа обработки
прерываний: отдельный обработчик на прерывание, общий обработчик на
прерывания, третьим вариантом можно считать возможность цепочечной
обработки прерываний через CSR_JALMNXTI. Дополнительно необходимо
сохранить текущий контекст. В примерах от gigadevice используется
3-й вариант, вполне может быть за 50 тактов. Первый вариант может быть немного быстрее, дополнительно можно разместить таблицу в RAM. Ниже решение от GD
// IRQ entry point
//
.section .text.irq
.align 2
.global irq_entry
.weak irq_entry
irq_entry: // -------------> This label will be set to MTVT2 register
// Allocate the stack space
SAVE_CONTEXT// Save 16 regs
//------This special CSR read operation, which is actually use mcause as operand to directly store it to memory
csrrwi x0, CSR_PUSHMCAUSE, 17
//------This special CSR read operation, which is actually use mepc as operand to directly store it to memory
csrrwi x0, CSR_PUSHMEPC, 18
//------This special CSR read operation, which is actually use Msubm as operand to directly store it to memory
csrrwi x0, CSR_PUSHMSUBM, 19
service_loop:
//------This special CSR read/write operation, which is actually Claim the CLIC to find its pending highest
// ID, if the ID is not 0, then automatically enable the mstatus.MIE, and jump to its vector-entry-label, and
// update the link register
csrrw ra, CSR_JALMNXTI, ra
//RESTORE_CONTEXT_EXCPT_X5
#---- Critical section with interrupts disabled -----------------------
DISABLE_MIE # Disable interrupts
LOAD x5, 19*REGBYTES(sp)
csrw CSR_MSUBM, x5
LOAD x5, 18*REGBYTES(sp)
csrw CSR_MEPC, x5
LOAD x5, 17*REGBYTES(sp)
csrw CSR_MCAUSE, x5
RESTORE_CONTEXT
// Return to regular code
mret
Мой вариант в лоб
[[gnu::interrupt]] void InterruptEntry() {
volatile const auto mcause = mpp::core::MCAUSE::Read();
volatile const auto mepc = mpp::core::MEPC ::Read();
volatile const auto msubm = mpp::core::MSUBM ::Read();
const auto exceptionCode = mcause & 0xFFF ;
if (exceptionCode < InterruptVectorTable.size())
{
tInterruptFunction fp = InterruptVectorTable[exceptionCode];
if (fp != nullptr)
{
fp(); // вызываем обработчик
}
}
else {
while(1)
asm("nop");
}
mpp::core::MSTATUS::Clear(MSTATUS_MIE);
mpp::core::MCAUSE::Write(mcause);
mpp::core::MEPC ::Write(mepc);
mpp::core::MSUBM ::Write(msubm);
return;
}
Основной прикол в том, что каждое прерывание конфигурируется отдельно. Критические можно обрабатывать собственными обработчиками, остальные через общий.