Входом IPIC являются 16 линий прерываний(IRQ lines). С помощью регистра IPIC_ICSR
каждая из линий может быть выключена, также можно выбрать уровень активного сигнала линии.
Линия может быть настроена как:
-
level-triggered
- при активном уровне линии, соответсвующее ей прерывание переходит в состояниеPending
. Отмена активного уровня переводит обратно вIdle
. -
edge-triggered
- прерывание переходит в состояниеPending
по активному фронту линии. Дальнейшего поддержания уровня линии не требуется.
Поддерживаются вложенные прерывания. Больший приоритет у прерывания с меньшим номером. Все 16 IPIC прерываний мультиплексируются на один вектор прерывания в scr1 - Machine external interrupt
. Номер конкретного прерывания становится известен из регистра IPIC_CISV
.
stateDiagram-v2
direction LR
state Serviced {
Running: In Service
Running--> Preempted : by higher priority IRQ
Preempted --> Running : end of higher priority IRQ
}
Idle --> Pending: Triggered
Pending --> Idle: Pending clear or line inactive level
Pending --> Serviced: No IRQs in service or IRQ has higher priority
Serviced --> [*] : Idle
Pending
- состояние, в которое переходит прерывание из состояния Idle и пребывает в нем до момента запуска. В этом соcтоянии могут находиться несколько прерываний. Перечислены в регистре IPIC_IPR
. Состояние может быть отменено путем записи в соответсвующее поле IPIC_IPR
. В случае level-triggered
линии, происходит отмна состояния при переводе линии на неактивный уровень.
In Service
- cостояние, в которое переходит прерывание из состояния Pending
. В нём может находиться только одно прерывание, обработчик которого в данный момент исполняется(или будет исполняться первым в случае наличия прерываний от, например, таймера). Регистр IPIC_CISV
содержит номер прерывания в этом состоянии.
Preempted
- состояние, в которое переходит прерывание при вытеснении его другим с более высоким приоритетом. По завершении последнего, переходит обратно в In Service
. В этом соcтоянии могут находиться несколько прерываний.
Serviced
- здесь находятся уже запущенные прерывания, т.е для которых верно In Service
|| Preempted
. Перечислены в регистре IPIC_ISVR
.
В scr1 возможность прерывания(смена контекста) зависит от регистров mstatus.MIE
и mie.MEIE
. В IPIC включение каждой из IRQ линий контролируется регистром IPIC_ICSR
.
Прерывания от IPIC должны быть включены, иначе переход в In Service
будет задержан до их включения.
После перехода нового прерывания в состояние Pending
происходит следующее:
- При отсутствии прерывания в состоянии
In Service
:
flowchart LR
Init["`**Pending**`"] --> E
E[У нас наивысший приоритет среди IRQ в состоянии Pending?]
E -->|Нет| Init
E -->|Да| F
F["`Переход нового IRQ в **In Service**`"]
- При наличии прерывания в состоянии
In Service
:
flowchart LR
Init["`**Pending**`"] --> C
C[Приоритет у нового IRQ более высокий?]
C -->|Да| D
C -->|Нет| Init
D["`Переход нового IRQ в
**In Service**, а
старого в **Preempted**`"]
- CSR
MIP.MEIP
выставляется в1
. Этого регистр не зависит от состояния регистровmstatus.MIE
иmie.MEIE
, а определяется только в IPIC. Фактически он сигнализирует он наличии хотя бы одного IRQ в состоянииPending
. - При выполнении условия
MIP.MEIP == 1 && mstatus.MIE == 1 && mie.MEIE == 1
, в ядре scr1 происходит непосредственно прерывание со сменой контекста и установкойPC
на векторMachine external interrupt
.
Сразу после начала прерывания(смены контекста) scr1 выставляет регистр mstatus.MIE
в 0
и возвращает его в 1
после mret
. То есть, происходит запрет любых прерываний в scr1(при этом IPIC продолжает работать в штатном режиме). В документации к scr1 в п. 7.5 допущена неточность: на временной диаграмме mstatus.MIE
после смены контекста там остается в 1
.
- Обработчик прерывания должен осуществить запись любого значения в регистр
IPIC_SOI
. Именно после этой записи прерывание переходит в состояниеIn Service
. Интересно то, что до момента записи уже работающее прерывание может быть ассоциировано с другим IPIC IRQ более высокого приоритета, успевшего придти после смены контекста. - Прерывание удаляется из регистра
IPIC_IPR
и попадает в регистрыIPIC_CISV
иIPIC_ISVR
. - CSR
MIP.MEIP
выставляется в0
. Он может остаться в1
, если одновременно с записью вIPIC_SOI
придет новое прерывание с более высоким приоритетом. - Вытесненное прерывание(если есть) удаляется из регистра
IPIC_CISV
. Его состояние остается на стеке, а выше него расположится стек новой ISR(Interrupt Service Routine).
В конце своей работы ISR должна осуществить запись любого значения в регистр IPIC_EOI
. Тогда прерывание стирается из регистров IPIC_CISV
и IPIC_ISVR
.
При этом из состояния Preempted
в In Service
будет переведено прерывание с наивысшим приоритетом. Восстановленное прерывание попадает в IPIC_CISV
.
irq_lines
- входы IPIC. Здесь они edge-triggered
и новое прерывание в 39-м такте.
idx
и vd
- индекс наиболее приоритетного прерывания в состоянии Pending
и его валидность, т.е vd == 0
означает отсутсвие прерывываний в состоянии Pending
.
csr_mip_meip
- регистр MIP.MEIP
.
ipic_cisv_ff
- регистр IPIC_CISV
. Значение 16 означает отсутствие прерываний в состоянии In Service
.
ipic_ipr_ff
- регистр IPIC_IPR
. Видно, как поле с индексом 5 сбрасывается после записи в IPIC_SOI
.
ipic_soi_req
- сигнал о выполнении записи в IPIC_SOI
.
ipic_eoi_req
- сигнал о выполнении записи в IPIC_EOI
.
csr2exu_irq_o
- сигнал о смене контекста ядром на обработчик прерывания.
csr_mstatus_mie_ff
- регистр mstatus.MIE
. Виден его переход в 0
после смены контекста.
e_mret
- сигнал о выполении инструкции mret
.
Видно как в регистре IPIC_IPR
меняются поля, соответсвующие прерываниям 4 и 6.
Второе прерывание с индексом 6 произошло на 59-м такте, а соответсвующая ему смена контекса в 74-м. Так происходит из-за глобального запрета прерываний(смены контекста) регистром mstatus.MIE
.
Пример обработчика, который поддерживает вложенные прерывания. В нем необходимо сохранить регистр mepc
, снять глобальный запрет на прерывания и перед mret
восстановить mepc
.
vec_machine_ext_handler:
csrr a1, mcause
li a5, MCAUSE_EXT_IRQ
li a0, -1
bne a1, a5, check_fail
csrr t1, mip
li t0, MIP_MEIP
and t0, t1, t0
beqz t0, check_fail
csrw IPIC_SOI, zero
addi sp, sp, -4
csrr a1, mepc
sw a1, (sp)
csrs mstatus, MSTATUS_MIE
nop
nop
nop
nop
csrw IPIC_EOI, zero
lw a1, (sp)
csrw mepc, a1
addi sp, sp, 4
mret