Добавление конспектов лекций

This commit is contained in:
Andrei Solodovnikov
2023-12-11 18:04:56 +03:00
parent 26b0f592f5
commit c3bb1df66b
242 changed files with 3573 additions and 0 deletions

View File

@@ -0,0 +1,274 @@
# Лекция 14. Подсистема прерывания
## Содержание
- [Лекция 14. Подсистема прерывания](#лекция-14-подсистема-прерывания)
- [Содержание](#содержание)
- [Определение](#определение)
- [Сканирование-входов](#сканирование-входов)
- [Передача управления при прерывании](#передача-управления-при-прерывании)
- [Классификация событий прерывания](#классификация-событий-прерывания)
- [Основные характеристики прерываний](#основные-характеристики-прерываний)
- [Допустимые моменты прерывания программы](#допустимые-моменты-прерывания-программы)
- [Маски́рование прерывания](#маски́рование-прерывания)
- [Способы выявления прерывания](#способы-выявления-прерывания)
- [Схемы реализации контроллера прерываний](#схемы-реализации-контроллера-прерываний)
- [Контроллер прерывания](#контроллер-прерывания)
- [Control and Status Register RISC-V](#control-and-status-register-risc-v)
- [Подсистема прерываний для RISC-V](#подсистема-прерываний-для-risc-v)
- [Программа, реализующая прерывания на ассемблере](#программа-реализующая-прерывания-на-ассемблере)
- [Основные материалы лекции](#основные-материалы-лекции)
- [Дополнительные материалы к лекции для саморазвития](#дополнительные-материалы-к-лекции-для-саморазвития)
## Определение
**Прерывание** — событие, на которое реагирует процессор.
ример_: Перемещение мыши. Если бы не было прерываний, то процессор был бы вынужден постоянно обращаться к мыши с целью узнать: изменилось ли её положение или нет, стоит ли перерисовать курсор. А это очень ресурсоёмко. Такой подход называется [сканирование входов](#сканирование-входов).
### Сканирование-входов
**Сканирование входов** — последовательный программный опрос входных сигналов. Этот подход используется в суперкомпьютерах, т.к. у них неразвитая периферия. В таком случае подсистема прерываний не нужна.
## Передача управления при прерывании
В случае, если во время выполнения программы произошло событие прерывания, процессор останавливает выполнение основной программы и начинает выполнять подпрограмму обработки прерывания. Завершив обработку прерывания, процессор возвращается к исполнению основной программы.
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_01.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_01.jpg)
*Рис. 1. Схема передачи управления при прерывании.*
## Классификация событий прерывания
- **Прерывания** — события, сигнал о которых приходит извне. Это события происходит _асинхронно_ фронту тактового импульса. Пример: перемещение мыши.
- Маски́руемые — прерывания, которые процессор может игнорировать. _Например_: нажатие клавиши на клавиатуре. [Аппаратная реализация]( #маски́рование-прерывания) будет продемонстрирована чуть позже.
- Немаски́руемые — прерывания, которые процессор не может игнорировать. _Например_: сигнал от датчика температуры о перегреве процессора.
- **Исключения** — события, происходящие вследствие выполнения какой-то инструкции. Эти события происходят _синхронно_ фронту тактового импульса.
- Ошибки. _Например_: обращение в несуществующую область памяти.
- Ловушки. _Например_: деление на 0.
- Отказы. _Например_: ситуации, которые никак нельзя устранить. Зачастую приводят к выключению/перезапуску процессора.
## Основные характеристики прерываний
- **Время реакции прерывания**, T<sub>реакции</sub>
Это время, между запросом на прерывание и переходом к прерывающей программе (см. рис. 2)
- **Затраты времени на переключение программ**, T<sub>загрузки</sub> и T<sub>востановления</sub>
Это время, которое требуется программе выполнить сервисные инструкции (см. рис. 2). Например: узнать причину прерывания, сохранить данные на стек прерывания и др.
- **Эффективность прерывания**
Это время эффективной работы программы. Т.е. отношение "полезных" (не сервисных) инструкций программы прерывания ко всем инструкциям прерывания.
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_02.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_02jpg)
*Рис. 2. Характеристики прерывания.*
- **Глубина прерывания**
Это кол-во прерываний, которые могут произойти во время обработки прерывания (см. рис. 3). Например: если процессор, находясь внутри прерывания, не способен прерваться на другое, то говорят что глубина прерывания n=1. Также программы могут неограниченно прерывать друг друга, в таком случаем, есть ограничение по памяти.
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_03.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_03.jpg)
*Рис. 3. Глубина прерываний.*
## Допустимые моменты прерывания программы
В зависимости от архитектуры процессора могут быть использованы различные методы, определяющие когда прерывание становится возможным:
- **Метод помеченного оператора**
Внутри какой-нибудь инструкции добавляется бит, отвечающий за прерывание. Допустим, если этот бит равен 1 и есть сигнал на прерывание, то процессор запустит обработчик прерывания.
- **Покомандный метод**
Этот метод относится к [многотактным архитектурам](09.%20Multicycle%20processor.md). Процессор начинает реагировать на сигнал прерывания, только после завершения инструкции.
- **Метод быстрого реагирования**
Этот метод позволяет реагировать на прерывание на любом такте.
### Маски́рование прерывания
**Маска прерывания** — это регистр, отвечающий за разрешение на прерывание (см. рис. 4). Эта маска побитово перемножается с запросами на прерывание других устройств/модулей. Если в результате перемножения получилась хотя бы одна 1, то формируется сигнал `interrupt`, который подаётся на блок управления процессора.
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_04.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_04.jpg)
*Рис. 4. Аппаратная реализация маски́рования прерывания.*
## Способы выявления прерывания
- **Обзорная система прерывания**
Каждый запрос на прерывание запускает одну и ту же подпрограмму, которая определяет, кто отправил запрос, а затем запускает конкретную программу обработчика прерывания. Работает такая система сравнительно дольше, но реализация её проще.
- **Векторная система прерывания**
В векторной системе есть участок памяти — аблица векторов прерывания_. В таблице лежат **вектора прерывания** — адрес начала подпрограммы обработчика прерывания. После обращения к таблице будет запущена нужная подпрограмма. Работает такая система быстрее, но реализовать её сложнее.
## Схемы реализации контроллера прерываний
[**Контроллер прерывания**](#контроллер-прерывания) — устройство, которое отвечает за передачу сигнала прерывания процессору и формирование кода причины прерывания.
- **Цепочечная схема**
От процессора идет сигнал подтверждения `ПДТ`, который приходит только тогда, когда процессор готов обработать какое-то прерывание (см. рис. 5.). Этот сигнал приходит на вход первого устройства, которое, в случае необходимости, выдаёт процессору сигнал на прерывание и вектор прерывания. Если же в прерывании от первого устройства нет необходимости, то сигнал подтверждения передаётся на следующее устройство и т.д. Цепочечная схема проста в реализации, но очень медленная. К тому же в этой схеме некоторые устройства имеют приоритет на другими в очерёдности обработки запроса на прерывание. Также существует вероятность, что до последних устройств никогда не дойдёт сигнал подтверждения, и процессор не обработает их запрос на прерывание.
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_05.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_05.jpg)
*Рис. 5. Цепочечная схема.*
- **Схема с циклическим опросом**
Каждый раз, когда в счётчик `СТ` приходит сигнал `C` (тактирование), он увеличивает своё значение (см рис. 6). Затем это значение подаётся на вход дешифратору `DC`, который только на одном выходе выдаёт 1. И каждый такт меняется номер выхода от 0 до N. Если во время обхода всех выходов появится сигнал на прерывание, то этот сигнал отправится на RS триггер, который затем отправит `interrupt` сигнал процессору. А на вход `C` счётчика `CT` будет отправлен 0. В таком случае счётчик перестанет суммировать, и он будет иметь значение кода номера прерывания.
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_06.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_06.jpg)
*Рис. 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 от запроса с наивысшим приоритетом. Дейзи-цепочка часто используется в определении наиболее приоритетного запроса.
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_07.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_07.jpg)
*Рис. 7. Дейзи-цепочка.*
### Контроллер прерывания
Теперь рассмотрим, как выглядит контроллер прерывания. (см. рис. 8) По каналу `ПДТ` поступает сигнал от процессора, разрешающий прерывание. Этот сигнал поступает на регистры запроса прерывания. Затем с помощью [маски прерывания](#маски́рование-прерывания) определяются, каким устройствам разрешён запрос на прерывание. Сигналы на прерывания попадают в `схему определения наиболее приоритетного запроса` (_например_: дейзи-цепочка), где определяется самый приоритетный запрос. С помощью `формирователя номера запроса` формируется некоторое число, отвечающее за степень приоритета запроса. В `схеме сравнения приоритетов` сравнивается это число с приоритетом текущего прерывания (приоритет текущего прерывания записан в регистры `порога прерывания`). Если число, хранимое в регистрах "_порога прерывания_" меньше, то в `порог прерывания` записывается новое число, а на процессор по каналу `ЗП` пойдёт сигнал о новом прерывании.
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_08.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_08.jpg)
*Рис. 8. Схема контроллера прерывания.*
## Control and Status Register RISC-V
Это набор регистров, связанных с блоками процессора, с помощью которых можно управлять ими или узнавать информацию о них.
Минимальный набор для поддержания прерывания в RISC-V нужно реализовать следующие регистры:
| Номер | Привилегия | Имя | Описание |
|:------------|:-----------|:----------|:-----------------------------------------------------------|
| Ox304 | MRW | mie | Регистр маски |
| Ox305 | MRW | mtvec | Регистр вектора прерывания |
| Ox340 | MRW | mscratch | Регистр указателя на стек прерывания |
| Ox341 | MRW | mepc | Регистр адреса инструкции, на котором случилось прерывание |
| Ox342 | MRW | mcause | Регистр причины (кода) прерывания |
Инструкции для работы с CSR:
| Opcode | func3 | Тип | Инструкция | Описание | Операция |
|:----------|:------|:-----|:--------------------|:--------------------------|:------------------------|
| 1110011 | 000 | I | mret | Возврат и прерывание | PC=merc |
| 1110011 | 001 | I | csrrw rd, csr, rs1 | Чтение/запись CSR | rd = csr, csr=rs1 |
| 1110011 | 010 | I | csrrs rd, csr, rs1 | Чтение/установка бит CSR | rd = csr, csr=rs1\|rs1 |
| 1110011 | 011 | I | csrrc rd, csr, rs1 | Чтение/очистка бит CSR | rd=csr, csr=csr&~rs1 |
## Подсистема прерываний для RISC-V
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_09.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_09.jpg)
*Рис. 9. Микроархитектура RISC-V с CSR.*
Теперь рассмотрим отдельно блок CSR:
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_10.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_10.jpg)
*Рис. 10. Схема CSR.*
Рассмотрим схему CSR (см. рис. 10). На ней красным прямоугольником (номер 1) отмечены регистры CSR. К нему подключены мультиплексор и демультиплексор для считывания и записи данных с регистров (номер 2 и 3). С помощью входа `A`, определяется к какому регистру будет применена запись/чтение. Теперь рассмотрим нижнюю часть схемы (см. рис. 11):
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_11.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_11.jpg)
*Рис. 11. Нижняя часть схемы CSR.*
Она нужна для оперативного обновления значений регистров `mepc` и `mcause`. Вход `OP[2]` — это сигнал о возникновении прерывания. Если сигнал на прерывание равен 1, то значения `mepc` и `mcause` изменятся. Осталось рассмотреть верхнюю часть схемы (см. рис. 12):
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_12.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_12.jpg)
*Рис. 12. Верхняя часть схемы CSR.*
Она нужна для реализации инструкций для работы с CSR. В зависимости от нужной инструкции у выхода `WD` будет своё значение. На нулевой вход мультиплексора поступают нули, если не требуется запись в регистры.
Отдельно стоит отметить, что значение регистра причины прерывания `mcause` берётся из контроллера прерывания. А значение регистра маски прерывании `mie`, которое мы устанавливаем в блоке CSR, отправляется в контроллер прерывания. Давайте рассмотрим устройство контроллера прерывания. У него будет [схема с циклическим опросом](#схемы-реализации-контроллера-прерываний) (см. рис. 13):
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_13.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_13.jpg)
*Рис. 13. Контроллер прерывания с циклическим опросом.*
На вход в контроллер прерывания подаются регистры маски прерывания `mie[31:0]`, запросы на прерывание `int_req[31:0]`. Если бит маски и бит запроса будут равны 1 и если в этот момент времени счётчик (красный прямоугольник на рисунке 13) будет соответствовать данному запросу на прерывание, то счётчик будет заблокирован, и будет сформирован сигнал `INT`, который сообщит о прерывании. Значение регистра `mcause` будет соответствовать значению остановленного счётчика.
Такое состояние будет, пока не придёт сигнал с `INT_RST`. Также после получения сигнала `INT_RST` периферийному устройству, чей сигнал обрабатывался, будет передана 1 через регистр `int_fin`, сигнализирующий о том, что обработка прерывания окончена.
В целом схема подключения выглядит так (см. рис. 14):
![../.pic/Lectures/14.%20Interrupt%20subsystem/fig_14.jpg](../.pic/Lectures/14.%20Interrupt%20subsystem/fig_14.jpg)
*Рис. 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) на видеозапись лекции
## Дополнительные материалы к лекции для саморазвития