mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 17:20:10 +00:00
* Корректировки конспектов лекций * Корректировка конспекта лекции 5 * Корректировка конспекта лекции 8 * Корректировка конспекта лекции 9 * Корректировка конспекта лекции 10 * Корректировка конспекта лекции 11 * Корректировка конспекта лекции 12 * Корректировка конспекта лекции 13 * Корректировка конспекта лекции 12 * Корректировка конспекта лекции 14 * Корректировка конспекта лекции 16 * Корректировка конспекта лекции 17 * Корректировка конспекта лекции * Корректировка конспекта лекции 20 * Корректировка конспекта лекции 21 * Корректировка конспекта лекции 22 * Корректировка конспекта лекции 23 * Корректировка конспекта лекции 13 * Корректировка конспекта лекции 12 * Корректировка конспекта лекции 20
275 lines
28 KiB
Markdown
275 lines
28 KiB
Markdown
# Лекция 14. Подсистема прерывания
|
||
|
||
## Содержание
|
||
|
||
- [Лекция 14. Подсистема прерывания](#лекция-14-подсистема-прерывания)
|
||
- [Содержание](#содержание)
|
||
- [Определение](#определение)
|
||
- [Сканирование-входов](#сканирование-входов)
|
||
- [Передача управления при прерывании](#передача-управления-при-прерывании)
|
||
- [Классификация событий прерывания](#классификация-событий-прерывания)
|
||
- [Основные характеристики прерываний](#основные-характеристики-прерываний)
|
||
- [Допустимые моменты прерывания программы](#допустимые-моменты-прерывания-программы)
|
||
- [Маски́рование прерывания](#маски́рование-прерывания)
|
||
- [Способы выявления прерывания](#способы-выявления-прерывания)
|
||
- [Схемы реализации контроллера прерываний](#схемы-реализации-контроллера-прерываний)
|
||
- [Контроллер прерывания](#контроллер-прерывания)
|
||
- [Control and Status Register RISC-V](#control-and-status-register-risc-v)
|
||
- [Подсистема прерываний для RISC-V](#подсистема-прерываний-для-risc-v)
|
||
- [Программа, реализующая прерывания на ассемблере](#программа-реализующая-прерывания-на-ассемблере)
|
||
- [Основные материалы лекции](#основные-материалы-лекции)
|
||
- [Дополнительные материалы к лекции для саморазвития](#дополнительные-материалы-к-лекции-для-саморазвития)
|
||
|
||
## Определение
|
||
|
||
**Прерывание** — событие, на которое реагирует процессор.
|
||
|
||
_Пример_: Перемещение мыши. Если бы не было прерываний, то процессор был бы вынужден постоянно обращаться к мыши с целью узнать: изменилось ли её положение или нет, стоит ли перерисовать курсор. А это очень ресурсоёмко. Такой подход называется [сканирование входов](#сканирование-входов).
|
||
|
||
### Сканирование-входов
|
||
|
||
**Сканирование входов** — последовательный программный опрос входных сигналов. Этот подход используется в суперкомпьютерах, т.к. у них неразвитая периферия. В таком случае подсистема прерываний не нужна.
|
||
|
||
## Передача управления при прерывании
|
||
|
||
В случае, если во время выполнения программы произошло событие прерывания, процессор останавливает выполнение основной программы и начинает выполнять подпрограмму обработки прерывания. Завершив обработку прерывания, процессор возвращается к исполнению основной программы.
|
||
|
||

|
||
|
||
*Рис. 1. Схема передачи управления при прерывании.*
|
||
|
||
## Классификация событий прерывания
|
||
|
||
- **Прерывания** — события, сигнал о которых приходит извне. Это события происходит _асинхронно_ фронту тактового импульса. Пример: перемещение мыши.
|
||
- Маски́руемые — прерывания, которые процессор может игнорировать. _Например_: нажатие клавиши на клавиатуре. [Аппаратная реализация]( #маски́рование-прерывания) будет продемонстрирована чуть позже.
|
||
- Немаски́руемые — прерывания, которые процессор не может игнорировать. _Например_: сигнал от датчика температуры о перегреве процессора.
|
||
- **Исключения** — события, происходящие вследствие выполнения какой-то инструкции. Эти события происходят _синхронно_ фронту тактового импульса.
|
||
- Ошибки. _Например_: обращение в несуществующую область памяти.
|
||
- Ловушки. _Например_: деление на 0.
|
||
- Отказы. _Например_: ситуации, которые никак нельзя устранить. Зачастую приводят к выключению/перезапуску процессора.
|
||
|
||
## Основные характеристики прерываний
|
||
|
||
- **Время реакции прерывания**, T<sub>реакции</sub>
|
||
|
||
Это время, между запросом на прерывание и переходом к прерывающей программе (см. рис. 2)
|
||
|
||
- **Затраты времени на переключение программ**, T<sub>загрузки</sub> и T<sub>востановления</sub>
|
||
|
||
Это время, которое требуется программе выполнить сервисные инструкции (см. рис. 2). Например: узнать причину прерывания, сохранить данные на стек прерывания и др.
|
||
|
||
- **Эффективность прерывания**
|
||
|
||
Это время эффективной работы программы. Т.е. отношение "полезных" (не сервисных) инструкций программы прерывания ко всем инструкциям прерывания.
|
||
|
||

|
||
|
||
*Рис. 2. Характеристики прерывания.*
|
||
|
||
- **Глубина прерывания**
|
||
|
||
Это кол-во прерываний, которые могут произойти во время обработки прерывания (см. рис. 3). Например: если процессор, находясь внутри прерывания, не способен прерваться на другое, то говорят что глубина прерывания n=1. Также программы могут неограниченно прерывать друг друга, в таком случаем, есть ограничение по памяти.
|
||
|
||

|
||
|
||
*Рис. 3. Глубина прерываний.*
|
||
|
||
## Допустимые моменты прерывания программы
|
||
|
||
В зависимости от архитектуры процессора могут быть использованы различные методы, определяющие когда прерывание становится возможным:
|
||
|
||
- **Метод помеченного оператора**
|
||
|
||
Внутри какой-нибудь инструкции добавляется бит, отвечающий за прерывание. Допустим, если этот бит равен 1 и есть сигнал на прерывание, то процессор запустит обработчик прерывания.
|
||
|
||
- **Покомандный метод**
|
||
|
||
Этот метод относится к [многотактным архитектурам](09.%20Multicycle%20processor.md). Процессор начинает реагировать на сигнал прерывания, только после завершения инструкции.
|
||
|
||
- **Метод быстрого реагирования**
|
||
|
||
Этот метод позволяет реагировать на прерывание на любом такте.
|
||
|
||
### Маски́рование прерывания
|
||
|
||
**Маска прерывания** — это регистр, отвечающий за разрешение на прерывание (см. рис. 4). Эта маска побитово перемножается с запросами на прерывание других устройств/модулей. Если в результате перемножения получилась хотя бы одна 1, то формируется сигнал `interrupt`, который подаётся на блок управления процессора.
|
||
|
||

|
||
|
||
*Рис. 4. Аппаратная реализация маски́рования прерывания.*
|
||
|
||
## Способы выявления прерывания
|
||
|
||
- **Обзорная система прерывания**
|
||
|
||
Каждый запрос на прерывание запускает одну и ту же подпрограмму, которая определяет, кто отправил запрос, а затем запускает конкретную программу обработчика прерывания. Работает такая система сравнительно дольше, но реализация её проще.
|
||
|
||
- **Векторная система прерывания**
|
||
|
||
В векторной системе есть участок памяти — _таблица векторов прерывания_. В таблице лежат **вектора прерывания** — адрес начала подпрограммы обработчика прерывания. После обращения к таблице будет запущена нужная подпрограмма. Работает такая система быстрее, но реализовать её сложнее.
|
||
|
||
## Схемы реализации контроллера прерываний
|
||
|
||
[**Контроллер прерывания**](#контроллер-прерывания) — устройство, которое отвечает за передачу сигнала прерывания процессору и формирование кода причины прерывания.
|
||
|
||
- **Цепочечная схема**
|
||
|
||
От процессора идет сигнал подтверждения `ПДТ`, который приходит только тогда, когда процессор готов обработать какое-то прерывание (см. рис. 5.). Этот сигнал приходит на вход первого устройства, которое, в случае необходимости, выдаёт процессору сигнал на прерывание и вектор прерывания. Если же в прерывании от первого устройства нет необходимости, то сигнал подтверждения передаётся на следующее устройство и т.д. Цепочечная схема проста в реализации, но очень медленная. К тому же в этой схеме некоторые устройства имеют приоритет над другими в очерёдности обработки запроса на прерывание. Также существует вероятность, что до последних устройств никогда не дойдёт сигнал подтверждения, и процессор не обработает их запрос на прерывание.
|
||
|
||

|
||
|
||
*Рис. 5. Цепочечная схема.*
|
||
|
||
- **Схема с циклическим опросом**
|
||
|
||
Каждый раз, когда в счётчик `СТ` приходит сигнал `C` (тактирование), он увеличивает своё значение (см. рис. 6). Затем это значение подаётся на вход дешифратору `DC`, который только на одном выходе выдаёт 1. И каждый такт меняется номер выхода от 0 до N. Если во время обхода всех выходов появится сигнал на прерывание, то этот сигнал отправится на RS триггер, который затем отправит `interrupt` сигнал процессору. А на вход `C` счётчика `CT` будет отправлен 0. В таком случае счётчик перестанет суммировать, и он будет иметь значение кода номера прерывания.
|
||
|
||

|
||
|
||
*Рис. 6. Циклическая схема.*
|
||
|
||
- **Дейзи-цепочка**
|
||
|
||
Рассмотрим дейзи-цепочку (см. рисунок 7). Эта схема будет работать только тогда, когда вход `Приоритет` равен 1. Если на первый запрос пришла 1, то на соответствующий выход y<sub>1</sub> будет подана 1, которая будет говорить о том, что именно первое устройство сделало запрос на прерывание. На выход `INT` также будет передана 1, которая отправится процессору для оповещения о прерывании. На остальные же выходы y<sub>2</sub>...y<sub>n</sub> будет передан 0. Т.е. на выходе y<sub>1</sub>...y<sub>n</sub> будет получена только одна 1 от запроса с наивысшим приоритетом. Дейзи-цепочка часто используется в определении наиболее приоритетного запроса.
|
||
|
||

|
||
|
||
*Рис. 7. Дейзи-цепочка.*
|
||
|
||
### Контроллер прерывания
|
||
|
||
Теперь рассмотрим, как выглядит контроллер прерывания. (см. рис. 8) По каналу `ПДТ` поступает сигнал от процессора, разрешающий прерывание. Этот сигнал поступает на регистры запроса прерывания. Затем с помощью [маски прерывания](#маски́рование-прерывания) определяются, каким устройствам разрешён запрос на прерывание. Сигналы на прерывания попадают в `схему определения наиболее приоритетного запроса` (_например_: дейзи-цепочка), где определяется самый приоритетный запрос. С помощью `формирователя номера запроса` формируется некоторое число, отвечающее за степень приоритета запроса. В `схеме сравнения приоритетов` сравнивается это число с приоритетом текущего прерывания (приоритет текущего прерывания записан в регистры `порога прерывания`). Если число, хранимое в регистрах "_порога прерывания_" меньше, то в `порог прерывания` записывается новое число, а на процессор по каналу `ЗП` пойдёт сигнал о новом прерывании.
|
||
|
||

|
||
|
||
*Рис. 8. Схема контроллера прерывания.*
|
||
|
||
## Control and Status Register RISC-V
|
||
|
||
Это набор регистров, связанных с блоками процессора, с помощью которых можно управлять ими или узнавать информацию о них.
|
||
Минимальный набор для поддержания прерывания в RISC-V нужно реализовать следующие регистры:
|
||
|
||
| Номер | Привилегия | Имя | Описание |
|
||
|:------------|:-----------|:----------|:-----------------------------------------------------------|
|
||
| 0x304 | MRW | mie | Регистр маски |
|
||
| 0x305 | MRW | mtvec | Регистр вектора прерывания |
|
||
| 0x340 | MRW | mscratch | Регистр указателя на стек прерывания |
|
||
| 0x341 | MRW | mepc | Регистр адреса инструкции, на котором случилось прерывание |
|
||
| 0x342 | MRW | mcause | Регистр причины (кода) прерывания |
|
||
|
||
Инструкции для работы с CSR:
|
||
|
||
| Opcode | func3 | Тип | Инструкция | Описание | Операция |
|
||
|:----------|:------|:-----|:--------------------|:--------------------------|:------------------------|
|
||
| 1110011 | 000 | I | mret | Возврат и прерывание | PC=mepc |
|
||
| 1110011 | 001 | I | csrrw rd, csr, rs1 | Чтение/запись CSR | rd = csr, csr=rs1 |
|
||
| 1110011 | 010 | I | csrrs rd, csr, rs1 | Чтение/установка бит CSR | rd = csr, csr=csr\|rs1 |
|
||
| 1110011 | 011 | I | csrrc rd, csr, rs1 | Чтение/очистка бит CSR | rd=csr, csr=csr&~rs1 |
|
||
|
||
## Подсистема прерываний для RISC-V
|
||
|
||

|
||
|
||
*Рис. 9. Микроархитектура RISC-V с CSR.*
|
||
|
||
Теперь рассмотрим отдельно блок CSR:
|
||
|
||

|
||
|
||
*Рис. 10. Схема CSR.*
|
||
|
||
Рассмотрим схему CSR (см. рис. 10). На ней красным прямоугольником (номер 1) отмечены регистры CSR. К нему подключены мультиплексор и демультиплексор для считывания и записи данных с регистров (номер 2 и 3). С помощью входа `A`, определяется к какому регистру будет применена запись/чтение. Теперь рассмотрим нижнюю часть схемы (см. рис. 11):
|
||
|
||

|
||
|
||
*Рис. 11. Нижняя часть схемы CSR.*
|
||
|
||
Она нужна для оперативного обновления значений регистров `mepc` и `mcause`. Вход `OP[2]` — это сигнал о возникновении прерывания. Если сигнал на прерывание равен 1, то значения `mepc` и `mcause` изменятся. Осталось рассмотреть верхнюю часть схемы (см. рис. 12):
|
||
|
||

|
||
|
||
*Рис. 12. Верхняя часть схемы CSR.*
|
||
|
||
Она нужна для реализации инструкций для работы с CSR. В зависимости от нужной инструкции у выхода `WD` будет своё значение. На нулевой вход мультиплексора поступают нули, если не требуется запись в регистры.
|
||
Отдельно стоит отметить, что значение регистра причины прерывания `mcause` берётся из контроллера прерывания. А значение регистра маски прерывании `mie`, которое мы устанавливаем в блоке CSR, отправляется в контроллер прерывания. Давайте рассмотрим устройство контроллера прерывания. У него будет [схема с циклическим опросом](#схемы-реализации-контроллера-прерываний) (см. рис. 13):
|
||
|
||

|
||
|
||
*Рис. 13. Контроллер прерывания с циклическим опросом.*
|
||
|
||
На вход в контроллер прерывания подаются регистры маски прерывания `mie[31:0]`, запросы на прерывание `int_req[31:0]`. Если бит маски и бит запроса будут равны 1 и если в этот момент времени счётчик (красный прямоугольник на рисунке 13) будет соответствовать данному запросу на прерывание, то счётчик будет заблокирован, и будет сформирован сигнал `INT`, который сообщит о прерывании. Значение регистра `mcause` будет соответствовать значению остановленного счётчика.
|
||
|
||
Такое состояние будет, пока не придёт сигнал с `INT_RST`. Также после получения сигнала `INT_RST` периферийному устройству, чей сигнал обрабатывался, будет передана 1 через регистр `int_fin`, сигнализирующий о том, что обработка прерывания окончена.
|
||
|
||
В целом схема подключения выглядит так (см. рис. 14):
|
||
|
||

|
||
|
||
*Рис. 14. Схема подключения подсистемы прерывания.*
|
||
|
||
## Программа, реализующая прерывания на ассемблере
|
||
|
||
Программа обрабатывает два прерывания, имеющие коды 5 и 19. При пятом прерывании некоторое число из памяти делится на 2. При девятнадцатом прерывании к некоторому числу из памяти прибавляется 3.
|
||
|
||
```assembly
|
||
# Инициализируем начальные значения регистров
|
||
li sp, 0xFFFFFFFC # устанавливаем указатель на верхушку стека
|
||
li gp, 0x10000000 # устанавливаем указатель на глобальные данные
|
||
|
||
li t0, 0x00080020 # подготавливаем маску прерывания для 5 и 19 входов
|
||
csrw mie, t0 # загружаем маску в регистр маски
|
||
la t0, interrupt # аналогично li загружает число, в данном случае - адрес
|
||
csrw mtvec, t0 # устанавливаем вектор прерывания
|
||
li t0, 0xEFFFFFFC # готовим адрес верхушки стека прерывания
|
||
csrw mscratch, t0 # загружаем в указатель на верхушку стека прерывания
|
||
|
||
li t0, 1 # начальное значение глобальной переменной
|
||
lw t0, 0(gp) # загружаем переменную в память
|
||
|
||
while: # бесконечный цикл, аналогичный while (1);
|
||
beq x0, x0, while # ничего не делаем!
|
||
|
||
interrupt:
|
||
csrrw t0, mscratch, t0 # меняем местами mscratch и t0
|
||
sw t1, 0(t0) # сохраняем t1 на стек mscratch
|
||
sw t2, 4(t0) # сохраняем t2 на стек mscratch
|
||
|
||
# Переключаем адрес возврата на следующую инструкцию
|
||
csrr t2, mepc # t2 = pc в момент прерывания
|
||
addi t2, t2, 4 # увеличиваем pc на 4
|
||
csrw mepc, t2 # mepc = mepc + 4
|
||
|
||
# Проверяем регистр причины и на 5-ое прерывание
|
||
csrr t1, mcause # t1 = mcause
|
||
li t2, 5 # t2 = 5 (код одного из прерываний)
|
||
bne t1, t2, nineteen # если это не 5 прерывание, то проверяем 19
|
||
# Обработчик 5-го прерывания
|
||
lw t2, 0(gp) # загружаем переменную из памяти
|
||
addi t2, t2, 3 # прибавляем к значению 3
|
||
sw t2, 0(gp) # возвращаем переменную в память
|
||
j done # идем возвращать регистры и на выход
|
||
|
||
nineteen: # Проверяем на 19-ое прерывание
|
||
li t2, 19 # t2 = 19 (код другого прерывания)
|
||
bne t1, t2, done # если не 19-ое, то выходим
|
||
# Обработчик 19-го прерывания
|
||
lw t2, 0(gp) # загружаем переменную из памяти
|
||
srli t2, t2, 1 # делим число пополам сдвигом вправо
|
||
sw t2, 0(gp) # возвращаем переменную в память
|
||
j done # идем возвращать регистры и на выход
|
||
|
||
# Возвращаем регистры на места и выходим
|
||
done:
|
||
lw t1, 0(t0) # возвращаем t1 со стека
|
||
lw t2, 4(t0) # возвращаем t2 со стека
|
||
csrrw t0, mscratch, t0 # меняем обратно местами t0 и mscratch
|
||
mret # возвращаем управление программе (pc = mepc)
|
||
|
||
```
|
||
|
||
## Основные материалы лекции
|
||
|
||
1. [Ссылка](https://youtu.be/E21EtIasiU8?si=f_UEatkkQUow9iX5) на видеозапись лекции
|
||
|
||
## Дополнительные материалы к лекции для саморазвития
|