ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Воскресенье
24 ноября
1077023 Топик полностью
evgeniy1294 (14.02.2021 04:12, просмотров: 400) ответил Evgeny_CD на Асм листинг надо курить. Чем там ядро занимается.
Понятно чем. Там два (в какой-то степени три) способа обработки прерываний: отдельный обработчик на прерывание, общий обработчик на прерывания, третьим вариантом можно считать возможность цепочечной обработки прерываний через 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; }



Основной прикол в том, что каждое прерывание конфигурируется отдельно. Критические можно обрабатывать собственными обработчиками, остальные через общий.