8.1. Механизм прерываний
8.2. Таблица векторов прерываний
8.3. Маскирование прерываний
8.4. Изменение таблицы векторов прерываний
8.5. Особенности обработки аппаратных прерываний
8.6. Контроллер прерываний 8259
В первой книге первого тома мы уже рассказывали о контроллере
прерываний и о механизме прерываний в персональном компьютере
IBM PC/XT/AT. Для полноты изложения мы приведем этот материал
здесь еще раз, так как контроллер прерываний занимает одно из
центральных мест в архитектуре персонального компьютера. Без умения
работать с контроллером прерываний вы не сможете использовать
режим прямого доступа к памяти, который будет обсуждаться в этой
книге.
Для обработки событий, происходящих асинхронно по отношению к
выполнению программы, лучше всего подходит механизм прерываний.
Прерывание можно рассматривать как некоторое особое событие в
системе, требующее моментальной реакции. Например, хорошо спроектированные
системы повышенной надежности используют прерывание по аварии
в питающей сети для выполнения процедур записи содержимого регистров
и оперативной памяти на магнитный носитель, с тем чтобы после
восстановления питания можно было продолжить работу с того же
места.
Кажется очевидным, что возможны самые разнообразные прерывания
по самым различным причинам. Поэтому прерывание рассматривается
не просто как таковое, с ним связывают число, называемое номером
типа прерывания или просто номером прерывания. С каждым номером
прерывания связывается то или иное событие. Система умеет распознавать,
какое прерывание, с каким номером произошло и запускает соответствующую
этому номеру процедуру.
Программы могут сами вызывать прерывания с заданным номером. Для
этого они используют команду INT. Это так называемые программные
прерывания. Программные прерывания не являются асинхронными, так
как вызываются из программы (а она-то знает, когда она вызывает
прерывание!).
Программные прерывания удобно использовать для организации доступа
к отдельным, общим для всех программ модулям. Например, программные
модули операционной системы доступны прикладным программам именно
через прерывания, и нет необходимости при вызове этих модулей
знать их текущий адрес в памяти. Прикладные программы могут сами
устанавливать свои обработчики прерываний для их последующего
использования другими программами. Для этого встраиваемые обработчики
прерываний должны быть резидентными в памяти. Мы научимся создавать
свои программы обработки прерываний и будем говорить об этом при
обсуждении резидентных программ.
Аппаратные прерывания вызываются физическими устройствами и приходят
асинхронно. Эти прерывания информируют систему о событиях, связанных
с работой устройств, например о том, что наконец-то завершилась
печать символа на принтере и неплохо было бы выдать следующий
символ, или о том, что требуемый сектор диска уже прочитан его
содержимое доступно программе.
Использование прерываний при работе с медленными внешними устройствами
позволяют совместить ввод/вывод с обработкой данных в центральном
процессоре и в результате повышает общую производительность системы.
Некоторые прерывания (первые пять в порядке номеров) зарезервированы
для использования самим центральным процессором на случай каких-либо
особых событий вроде попытки деления на ноль, переполнения и т.п.
Иногда желательно сделать систему нечувствительной ко всем или
отдельным прерываниям. Для этого используют так называемое маскирование
прерываний, о котором мы еще будем подробно говорить. Но некоторые
прерывания замаскировать нельзя, это немаскируемые прерывания.
Заметим еще, что обработчики прерываний могут сами вызывать программные
прерывания, например, для получения доступа к сервису BIOS или
DOS (сервис BIOS также доступен через механизм программных прерываний).
Составление собственных программ обработки прерываний и замена
стандартных обработчиков DOS и BIOS является ответственной и сложной
работой. Необходимо учитывать все тонкости работы аппаратуры и
взаимодействия программного и аппаратного обеспечения. При отладке
возможно разрушение операционной системы с непредсказуемыми последствиями,
поэтому надо очень внимательно следить за тем, что делает Ваша
программа.
Для того чтобы связать адрес обработчика прерывания с номером
прерывания, используется таблица векторов прерываний, занимающая
первый килобайт оперативной памяти - адреса от 0000:0000 до 0000:03FF.
Таблица состоит из 256 элементов - FAR-адресов обработчиков прерываний.
Эти элементы называются векторами прерываний. В первом слове элемента
таблицы записано смещение, а во втором - адрес сегмента обработчика
прерывания.
Прерыванию с номером 0 соответствует адрес 0000:0000, прерыванию
с номером 1 - 0000:0004 и т.д. Для программиста, использующего
язык Си, таблицу можно описать следующим образом:
void (* interrupt_table[256])();
Инициализация таблицы происходит частично BIOS после тестирования
аппаратуры и перед началом загрузки операционной системой, частично
при загрузке DOS. DOS может переключить на себя некоторые прерывания
BIOS.
Займемся теперь содержимым таблицы векторов прерываний. Приведем
назначение некоторых наиболее важных векторов:
Номер | Описание |
0 | Ошибка деления. Вызывается автоматически после выполнения команд DIV или IDIV, если в результате деления происходит переполнение (например, при делении на 0). DOS обычно при обработке этого прерывания выводит сообщение об ошибке и останавливает выполнение программы. Для процессора 8086 при этом адрес возврата указывает на следующую после команды деления команду, а в процессоре 80286 - на первый байт команды, вызвавшей прерывание.
|
1 | Прерывание пошагового режима. Вырабатывается после выполнения каждой машинной команды, если в слове флагов установлен бит пошаговой трассировки TF. Используется для отладки программ. Это прерывание не вырабатывается после выполнения команды MOV в сегментные регистры или после загрузки сегментных регистров командой POP.
|
2 | Аппаратное немаскируемое прерывание. Это прерывание может использоваться по-разному в разных машинах. Обычно вырабатывается при ошибке четности в оперативной памяти и при запросе прерывания от сопроцессора.
|
3 | Прерывание для трассировки. Это прерывание генерируется при выполнении однобайтовой машинной команды с кодом CCh и обычно используется отладчиками для установки точки прерывания.
|
4 | Переполнение. Генерируется машинной командой INTO, если установлен флаг OF. Если флаг не установлен, то команда INTO выполняется как NOP. Это прерывание используется для обработки ошибок при выполнении арифметических операций.
|
5 | Печать копии экрана. Генерируется при нажатии на клавиатуре клавиши PrtScr. Обычно используется для печати образа экрана. Для процессора 80286 генерируется при выполнении машинной команды BOUND, если проверяемое значение вышло за пределы заданного диапазона.
|
6 | Неопределенный код операции или длина команды больше 10 байт (для процессора 80286).
|
7 | Особый случай отсутствия математического сопроцессора (процессор 80286).
|
8 | IRQ0 - прерывание интервального таймера, возникает 18,2 раза в секунду.
|
9 | IRQ1 - прерывание от клавиатуры. Генерируется при нажатии и при отжатии клавиши. Используется для чтения данных от клавиатуры.
|
A | IRQ2 - используется для каскадирования аппаратных прерываний в машинах класса AT.
|
B | IRQ3 - прерывание асинхронного порта COM2.
|
C | IRQ4 - прерывание асинхронного порта COM1.
|
D | IRQ5 - прерывание от контроллера жесткого диска для XT.
|
E | IRQ6 - прерывание генерируется контроллером флоппи-диска после завершения операции.
|
F | IRQ7 - прерывание принтера. Генерируется принтером, когда он готов к выполнению очередной операции. Многие адаптеры принтера не используют это прерывание.
|
10 | Обслуживание видеоадаптера.
|
11 | Определение конфигурации устройств в системе.
|
12 | Определение размера оперативной памяти в системе.
|
13 | Обслуживание дисковой системы.
|
14 | Последовательный ввод/вывод.
|
15 | Расширенный сервис для AT-компьютеров.
|
16 | Обслуживание клавиатуры.
|
17 | Обслуживание принтера.
|
18 | Запуск BASIC в ПЗУ, если он есть.
|
19 | Загрузка операционной системы.
|
1A | Обслуживание часов. |
1B | Обработчик прерывания Ctrl-Break.
|
1C | Прерывание возникает 18.2 раза в секунду, вызывается программно обработчиком прерывания таймера.
|
1D | Адрес видеотаблицы для контроллера видеоадаптера 6845.
|
1E | Указатель на таблицу параметров дискеты.
|
1F | Указатель на графическую таблицу для символов с кодами ASCII 128-255.
|
20-5F | Используется DOS или зарезервировано для DOS.
|
60-67 | Прерывания, зарезервированные для пользователя.
|
68-6F | Не используются. |
70 | IRQ8 - прерывание от часов реального времени.
|
71 | IRQ9 - прерывание от контроллера EGA.
|
72 | IRQ10 - зарезервировано.
|
73 | IRQ11 - зарезервировано.
|
74 | IRQ12 - зарезервировано.
|
75 | IRQ13 - прерывание от математического сопроцессора.
|
76 | IRQ14 - прерывание от контроллера жесткого диска.
|
77 | IRQ15 - зарезервировано.
|
78 - 7F | Не используются. |
80-85 | Зарезервированы для BASIC.
|
86-F0 | Используются интерпретатором BASIC.
|
F1-FF | Не используются. |
IRQ0-IRQ15 - это аппаратные прерывания, о них будет рассказано
позже.
Часто при выполнении критических участков программ для того, чтобы
гарантировать выполнение определенной последовательности команд
целиком приходится запрещать прерывания. Это можно сделать командой
CLI. Ее нужно поместить в начало критической последовательности
команд, а в конце расположить команду STI, разрешающую процессору
воспринимать прерывания. Команда CLI запрещает только маскируемые
прерывания, немаскируемые всегда обрабатываются процессором.
Если вы используете запрет прерываний с помощью команды CLI, следите
за тем, чтобы прерывания не отключались на длительный период времени,
так как это может привести к нежелательным последствиям. Например,
будут отставать часы.
Если вам надо запретить не все прерывания, а только некоторые,
например, от клавиатуры, то для этого надо воспользоваться услугами
контроллера прерываний. Подробно об этом немного ниже, сейчас
отметим только, что выдачей в этот контроллер определенной управляющей
информации можно замаскировать прерывания от отдельных устройств.
Вашей программе может потребоваться организовать обработку некоторых
прерываний. Для этого программа должна переназначить вектор на
свой обработчик. Это можно сделать, изменив содержимое соответствующего
элемента таблицы векторов прерываний.
Очень важно не забыть перед завершением работы восстановить содержимое
измененных векторов в таблице прерываний, т.к. после завершения
работы программы память, которая была ей распределена, считается
свободной и может быть использована для загрузки другой программы.
Если вы забыли восстановить вектор и пришло прерывание, то система
может разрушиться - вектор теперь указывает на область, которая
может содержать что угодно.
Поэтому последовательность действий для нерезидентных программ,
желающих обрабатывать прерывания, должна быть такой:
- прочитать содержимое элемента таблицы векторов прерываний
для вектора с нужным вам номером;
- запомнить это содержимое (адрес старого обработчика прерывания)
в области данных программы;
- установить новый адрес в таблице векторов прерываний так,
чтобы он соответствовал началу Вашей программы обработки прерывания;
- перед завершением работы программы прочитать из области данных
адрес старого обработчика прерывания и записать его в таблицу
векторов прерываний.
Кроме того, операция изменения вектора прерывания должна быть
непрерывной в том смысле, что во время изменения не должно произойти
прерывание с номером, для которого производится замена программы
обработки. Если вы, например, запишете новое значение смещения,
а сегментный адрес обновить не успеете, то по какому адресу будет
передано управление в случае прерывания и что при этом произойдет?
Об этом можно только догадываться.
Для облегчения работы по замене прерывания DOS предоставляет в
ваше распоряжение специальные функции для чтения элемента таблицы
векторов прерывания и для записи в нее нового адреса. Если вы
будете использовать эти функции, DOS гарантирует, что операция
по замене вектора будет выполнена правильно. вам не надо заботиться
о непрерывности процесса замены вектора прерывания.
Для чтения вектора используйте функцию 35h прерывания 21h. Перед
ее вызовом регистр AL должен содержать номер вектора в таблице.
После выполнения функции в регистрах ES:BX будет искомый адрес
обработчика прерывания.
Функция 25h прерывания 21h устанавливает для вектора с номером,
находящимся в AL, обработчик прерывания DS:DX.
Разумеется, вы можете непосредственно обращаться к таблице векторов
прерываний, но тогда при записи необходимо замаскировать прерывания
командой CLI, не забыв разрешить их после записи командой STI.
Для пользователей языка Си библиотека Quick C содержит функции
_dos_getvec(), _dos_setvect(). Первая функция получает адрес из
таблицы векторов прерываний, вторая устанавливает новый адрес.
Если вам надо добавить какие-либо собственные действия к тем,
что выполняет стандартный обработчик прерывания, то можно организовать
цепочку прерываний.
Для организации цепочки прерываний вы записываете в векторную
таблицу адрес своего обработчика, не забыв сохранить прежнее содержимое
таблицы. Ваш обработчик получает управление по прерыванию, выполняет
какие-либо действия, затем передает управление стандартному обработчику.
Можно сделать и по-другому - ваш обработчик вызывает стандартный
как подпрограмму, после возврата из стандартного обработчика выполняет
дополнительные действия. То есть вы можете вставить дополнительную
обработку как до вызова стандартного обработчика, так и после
его вызова.
В библиотеке Quick C имеется функция для организации цепочки
прерываний - _chain_intr().
Рассмотрим более подробно возможности библиотеки интегрированной
среды Quick C, предназначенные для работы с прерываниями.
Модификатор interrupt (_interrupt для Quick C 2.5 и C 6.0)
описывает функцию, которая является обработчиком прерывания. Такая
функция завершается командой возврата из обработки прерывания
IRET, и для нее автоматически генерируются команды сохранения
регистров на входе и их восстановления при выходе из обработчика
прерывания. Пример использования модификатора для описания
функции обработки прерывания:
void interrupt far int_funct(void) {
// Тело обработчика прерывания
}
Функция обработки прерывания должна быть FAR-функцией, т.к. таблица
векторов прерываний содержит полные адреса в виде сегмент:смещение.
Ключевое слово interrupt используется также для описания переменных,
предназначенных для хранения векторов прерываний:
void (_interrupt _far *oldvect)(void);
Модификаторы _interrupt и _far для Quick C 2.5 и C 6.0 являются
синонимами соответственно interrupt и far.
Какие требования предъявляются к программе обработки прерывания?
Если прерывания происходят часто, то их обработка может сильно
замедлить работу прикладной программы. Поэтому обработчик прерывания
должен быть короткой, быстро работающей программой, которая выполняет
только самые необходимые действия. Например, считать очередной
символ из порта принтера и поместить его в буфер, увеличить значение
какого-либо глобального счетчика прерываний и т.п.
Для установки своего обработчика прерываний используйте функцию
_dos_setvec. Эта функция имеет два параметра - номер прерывания
и указатель на новую функцию обработки прерывания. Например:
_dos_setvect(0x16, my_key_intr);
В этом примере для клавиатурного прерывания с номером 16h устанавливается
новый обработчик прерывания my_key_intr.
Если вам надо узнать адрес старого обработчика прерывания по его
номеру, лучше всего воспользоваться функцией _dos_getvect, которая
принимает в качесте параметра номер прерывания и возвращает указатель
на соответствующий этому номеру в таблице векторов прерываний
обработчик. Например:
old_vector = _dos_getvect(0x16);
Для организации цепочки прерываний используйте функцию _chain_intr.
В качестве параметра эта функция принимает адрес старого обработчика
прерываний.
Следующий простой пример иллюстрирует применение всех трех функций,
предназначенных для работы с прерываниями. Эта программа встраивает
собственный обработчик прерывания таймера, который будет вызываться
примерно 18,2 раза в секунду. Встраиваемый обработчик прерывания
считает тики таймера, и если значение счетчика кратно 20, на динамик
компьютера выдается звуковой сигнал. В конце работы новая программа
обработки прерывания таймера вызывает старый обработчик с помощью
функции _chain_intr.
После установки нового обработчика прерывания таймера основная
программа ждет нажатия на клавиатуре любой клавиши, затем она
восстанавливает старое содержимое вектора прерывания.
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
// Выключаем проверку стека и указателей
#pragma check_stack( off )
#pragma check_pointer( off )
// Это макро используется для выдачи
// сигнала на внутренний динамик
// компьютера. Используется вывод
// в формате TTY символа BELL (7)
// через прерывание BIOS 10h
#define BEEP() _asm { \
_asm mov bx,0 \
_asm mov ax, 0E07h \
_asm int 10h \
}
void main(void);
// Объявление программы обработки прерывания
void _interrupt _far timer(void);
// Эта переменная предназначена для хранения
// старого значения вектора прерывания
// таймера. Она должна быть глобальной.
void (_interrupt _far *oldvect)(void);
// Переменная для подсчета тиков таймера
volatile long ticks;
void main(void) {
ticks=0L; // Сбрасываем счетчик тиков таймера
oldvect = _dos_getvect(0x1c); // Запоминаем адрес
// старого обработчика
// прерывания
_dos_setvect(0x1c, timer); // Устанавливаем свой
// обработчик
printf("\nТаймер установлен. Нажмите любую"
"клавишу...\n");
getch(); // Ожидаем нажатия на любую клавишу
_dos_setvect(0x1c,oldvect); // Восстанавливаем старый
// обработчик прерывания
// таймера
exit(0);
}
// Функция обрабатывает прерывания таймера
void _interrupt _far timer(void) {
ticks++; // Увеличиваем счетчик тиков таймера
// Если значение счетчика тиков кратно 20,
// выдаем сигнал на динамик компьютера
if((ticks % 20) == 0) BEEP();
// Вызываем старый обработчик прерывания
_chain_intr(oldvect);
}
Аппаратные прерывания вырабатываются устройствами компьютера,
когда возникает необходимость их обслуживания. Например, по прерыванию
таймера соответствующий обработчик прерывания увеличивает содержимое
ячеек памяти, используемых для хранения времени. В отличие от
программных прерываний, вызываемых запланировано самой прикладной
программой, аппаратные прерывания всегда происходят асинхронно
по отношению к выполняющимся программам. Кроме того, может возникнуть
одновременно сразу несколько прерываний!
Для того, чтобы система "не растерялась", решая какое
прерывание обслуживать в первую очередь, существует специальная
схема приоритетов. Каждому прерыванию назначается свой уникальный
приоритет. Если происходит одновременно несколько прерываний,
то система отдает предпочтение самому высокоприоритетному, откладывая
на время обработку остальных прерываний.
Система приоритетов реализована на двух микросхемах Intel 8259
(для машин класса XT - на одной такой микросхеме). Каждая микросхема
обслуживает до восьми приоритетов. Микросхемы можно объединять
(каскадировать) для увеличения количества уровней приоритетов
в системе.
Уровни приоритетов обозначаются сокращенно IRQ0 - IRQ15 (для машин
класса XT существуют только уровни IRQ0 - IRQ7).
Для машин XT приоритеты линейно зависели от номера уровня прерывания.
IRQ0 соответствовало самому высокому приоритету, за ним шли IRQ1,
IRQ2, IRQ3 и так далее. Уровень IRQ2 в машинах класса XT был зарезервирован
для дальнейшего расширения системы. И начиная с машин класса AT
IRQ2 стал использоваться для каскадирования контроллеров прерывания
8259. Добавленные приоритетные уровни IRQ8 - IRQ15 в этих машинах
располагаются по приоритету между IRQ1 и IRQ3.
Приведем таблицу аппаратных прерываний, расположенных в порядке
приоритета:
Номер | Описание |
8 | IRQ0 прерывание интервального таймера, возникает 18,2 раза в секунду.
|
9 | IRQ1 прерывание от клавиатуры. Генерируется при нажатии и при отжатии клавиши. Используется для чтения данных с клавиатуры.
|
A | IRQ2 используется для каскадирования аппаратных прерываний в машинах класса AT.
|
70 | IRQ8 прерывание от часов реального времени.
|
71 | IRQ9 прерывание от контроллера EGA.
|
72 | IRQ10 зарезервировано.
|
73 | IRQ11 зарезервировано.
|
74 | IRQ12 зарезервировано.
|
75 | IRQ13 прерывание от математического сопроцессора.
|
76 | IRQ14 прерывание от контроллера жесткого диска.
|
77 | IRQ15 зарезервировано.
|
B | IRQ3 прерывание асинхронного порта COM2.
|
C | IRQ4 прерывание асинхронного порта COM1.
|
D | IRQ5 прерывание от контроллера жесткого диска для XT.
|
E | IRQ6 прерывание генерируется контроллером флоппи диска после завершения операции
|
F | IRQ7 прерывание принтера. Генерируется принтером, когда он готов к выполнению очередной операции. Многие адаптеры принтера не используют это прерывание.
|
Из таблицы видно, что самый высокий приоритет у прерываний от
интервального таймера, затем идет прерывание от клавиатуры.
Для управления схемами приоритетов необходимо знать внутреннее
устройство контроллера прерываний 8259. Поступающие прерывания
запоминаются в регистре запроса на прерывание IRR. Каждый бит
из восьми в этом регистре соответствует прерыванию. После проверки
на обработку в настоящий момент другого прерывания запрашивается
информация из регистра обслуживания ISR. Перед выдачей запроса
на прерывание в процессор проверяется содержимое восьмибитового
регистра маски прерываний IMR. Если прерывание данного уровня
не замаскировано, то выдается запрос на прерывание.
Наиболее интересными с точки зрения программирования контроллера
прерываний являются регистры маски прерываний IMR и управляющий
регистр прерываний.
В машинах класса XT регистр маски прерываний имеет адрес 21h,
управляющий регистр прерываний - 20h. Для машин AT первый контроллер
8259 имеет такие же адреса, что и в машинах XT, регистр маски
прерываний второго контроллера имеет адрес A1h, управляющий регистр
прерываний - A0h.
Разряды регистра маски прерываний соответствуют номерам IRQ. Для
того, чтобы замаскировать аппаратное прерывание какого-либо уровня,
надо заслать в регистр маски байт, в котором бит, соответствующий
этому уровню, установлен в 1. Например, для маскирования прерываний
от НГМД в порт 21h надо заслать двоичное число 01000000.
Приведем пример программы, маскирующей прерывание от флоппи-диска:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void main(void);
void main(void) {
outp(0x21,0x40);
printf("\nПрерывания от флоппи-диска запрещены.\n");
exit(0);
}
Эта программа есть на дискете, прилагающейся к книге. Запустите
ее (с жесткого диска) и попробуйте поработать, например, с дисководом
А. У вас ничего не получится!
Чтобы "оживить" флоппи-диски, запустите программу, которая
размаскирует все прерывания (в том числе и от флоппи):
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
void main(void);
void main(void) {
outp(0x21,0);
printf("\nПрерывания от флоппи-диска разрешены.\n");
exit(0);
}
Заметьте, что мы только что замаскировали прерывание именно от
флоппи-диска, все остальные устройства продолжали нормально работать.
Если бы мы выдали машинную команду CLI, то отключились бы все
аппаратные прерывания. Это привело бы, например, к тому, что клавиатура
была бы заблокирована.
Еще одно замечание, касающееся обработки аппаратных прерываний.
Если вы полностью заменяете стандартный обработчик аппаратного
прерывания, не забудьте в конце программы выдать байт 20h в порт
с адресом 20h (A0h для второго контроллера 8259). Эти действия
необходимы для очистки регистра обслуживания прерывания ISR. При
этом разрешается обработка прерываний с более низким приоритетом,
чем то, которое только что обрабатывалось.
Если вы обрабатываете прерывание 1Ch, то добавка в конце программы
не нужна, так как это прерывание является расширением другого
прерывания (прерывания таймера).
Перед тем, как завершить изучение прерываний, зададимся вопросом
- можно ли замаскировать немаскируемое прерывание? Оказывается,
можно!
Конечно, если сигнал прерывания пришел на вход немаскируемого
прерывания процессора, ничего сделать нельзя - прерывание произойдет
неизбежно. Но в компьютерах XT и AT предусмотрены схемы, блокирующие
вход немаскируемого прерывания процессора NMI.
Для XT маскированием немаскируемого прерывания управляет порт
с адресом 0A0h. Если записать в него 0, немаскируемое прерывание
будет запрещено, если 80h - разрешено.
Аналогично для AT маскированием немаскируемого прерывания управляет
бит 7 порта 70h. Запись байта 0ADh в порт 70h запретит немаскируемое
прерывание, а байта 2Dh - разрешит прохождение прерывания.
Заметим, что мы не запрещаем немаскируемое прерывание "внутри"
процессора - это невозможно по определению, мы "не пускаем"
сигнал прерывания на вход NMI.
Программируемый контроллер прерываний 8259 (отечественный аналог
- КР1810ВН59А) предназначен для обработки до восьми приоритетных
уровней прерываний. Возможно каскадирование микросхем, при этом
общее число уровней прерываний будет достигать 64.
Контроллер 8259 имеет несколько режимов работы, которые устанавливаются
программным путем. В персональных компьютерах XT и AT за первоначальную
установку режимов работы микросхем 8259 отвечает BIOS. У программиста
скорее всего не возникнет потребность перепрограммировать контроллер
- это небезопасно, так как неправильное программирование контроллера
приведет к нарушению логики работы всей системы.
Однако часто возникает необходимость изменения текущего режима
работы (запрет или разрешение прерываний определенного или всех
уровней, обработка конца прерывания) или опроса состояния внутренних
регистров контроллера. Для этого необходимо ознакомиться со справочными
данными на микросхему 8259, где детально описано как первоначальное
программирование контроллера, так и управление им во время работы.
Каждому приоритетному уровню прерывания микросхема ставит в соответствие
определенный, задаваемый программно, номер прерывания. В разделе
книги, посвященном особенностям обработки аппаратных прерываний,
приводится такое соответствие для машин типа XT и AT.
Если контроллеры 8259 каскадированы, то ведомой микросхеме присваивается
код (выдачей в микросхему соответствующего командного слова).
Этот код равен номеру входа IRQ ведущей микросхемы, с которым
соединен выход запроса прерывания INT ведомой микросхемы. Внутри
микросхемы приоритет зависит от номера IRQ и задается программно.
Для компьютеров XT и AT самым высоким приоритетом внутри группы,
обслуживаемой каждым контроллером, является вход IRQ0. Однако
возможно программное изменение приоритетов в рамках так называемого
приоритетного кольца. При этом дно приоритетного кольца имеет
самый низкий приоритет.
Приведем возможные варианты задания приоритетов:
Вход Уровни приоритета
IRQ0 7 6 5 4 3 2 1 0
IRQ1 0 7 6 5 4 3 2 1
IRQ2 1 0 7 6 5 4 3 2
IRQ3 2 1 0 7 6 5 4 3
IRQ4 3 2 1 0 7 6 5 4
IRQ5 4 3 2 1 0 7 6 5
IRQ6 5 4 3 2 1 0 7 6
IRQ7 6 5 4 3 2 1 0 7
Наиболее высокий приоритет у входа IRQ с обозначением 0 приоритетного
кольца, наиболее низкий - с обозначением 7.
Для обработки прерываний контроллер имеет несколько внутренних
регистров. Это регистр запросов прерываний IRR, регистр обслуживания
прерываний ISR, регистр маски прерываний IMR. В регистре IRR хранятся
запросы на обслуживание прерываний от аппаратуры. После выработки
сигнала прерывания центральному процессору соответствующий разряд
регистра ISR устанавливается в единичное состояние, что блокирует
обслуживание всех запросов с равным или более низким приоритетом.
Устранить эту блокировку можно либо сбросом соответствующего бита
в ISR, либо командой специального маскирования.
Имеется два типа команд, посылаемых программой в контроллер 8259
- команды инициализации и команды операции. Возможны следующие
операции:
- индивидуальное маскирование запросов прерывания;
- специальное маскирование обслуженных запросов;
- установка статуса уровней приоритета (по установке исходного
состояния, по обслуженному запросу, по указанию);
- операции конца прерывания (обычный конец прерывания, специальный
конец прерывания, автоматический конец прерывания);
- чтение регистров IRR, ISR, IMR.
Мы не будем подробно описывать команды инициализации контроллера
8259, так как программистам они скорее всего не понадобятся. Желающих
разобраться во всех тонкостях задания начального режима работы
контроллера прерываний мы отсылаем к справочной литературе по
микросхеме 8259 или ее отечественному аналогу.
Рассмотрим команды операций. Существуют три типа команд операций:
- Маскирование запросов прерывания.
- Команды обработки конца прерывания.
- Опрос регистров и специальное маскирование.
Байты команды маскирования запросов прерывания выводятся соответственно
в порты 21h и A1h для первого и второго контроллера 8259 компьютера
AT. Команды операций второго и третьего типа используют порты
с адресами 20h и A0h.
Маскирование запросов прерываний мы уже описывали в главе, посвященной
прерываниям. Для маскирования какого-либо уровня прерывания надо
записать в регистр маски IMR по адресу 21h или A1h единицу в соответствующий
разряд регистра.
Команды обработки конца прерывания приведем в виде таблицы:
Биты байта команды Описание
D7 D6 D5 D4 D3 D2 D1 D0
0 0 1 0 0 0 0 0 Обычный конец прерывания.
0 1 1 0 0 B2 B1 B0 Специальный конец прерывания,
B0...B2 - двоично-десятичный код
сбрасываемого разряда в регистре
обслуживания прерывания ISR.
1 0 1 0 0 X X X Циклический сдвиг уровней приоритета с
обычным концом прерывания.
Дно приоритетного кольца
устанавливается по обслуженному запросу.
1 1 1 0 0 B2 B1 B0 Циклический сдвиг уровней приоритета
со специальным концом прерывания,
B0...B2 - двоично-десятичный код дна
приоритетного кольца.
1 0 0 0 0 X X X Разрешение вращения уровней приоритета.
0 0 0 0 0 X X X Сброс разрешения вращения уровней
приоритета.
1 1 0 0 0 B2 B1 B0 Циклический сдвиг уровней приоритета
без завершения прерывания,
B0...B2 - двоично-десятичный код дна
приоритетного кольца
Команды третьего типа выдаются также в порты с адресами 20h и
A0h. Они имеют следующий формат:
Биты байта команды Описание
D7 D6 D5 D4 D3 D2 D1 D0
0 0 0 0 1 1 X X Установка режима опроса.
0 0 0 0 1 0 1 1 Разрешение чтения регистра ISR.
0 0 0 0 1 0 1 0 Разрешение чтения регистра IRR.
0 1 1 0 1 0 0 0 Разрешение триггера специального маскирования.
0 1 0 0 1 0 0 0 Сброс триггера специального маскирования.
По команде обычного конца прерывания устанавливается в нулевое
состояние разряд ISR, соответствующий последнему обслуженному
запросу.
Команда специального конца прерывания устанавливает в нулевое
состояние тот разряд ISR, номер которого указан в разрядах B0...B2
команды.
Команда циклического сдвига уровней приоритета с обычным концом
прерывания устанавливает в ноль разряд ISR, соответствующий последнему
обслуженному запросу и этому же номеру запроса присваивается низший
уровень приоритета.
Аналогично работает команда циклического сдвига уровней приоритета
со специальным концом прерывания, только низший уровень приоритета
присваивается тому входу IRQ, номер которого указан в разрядах
B0...B2 команды.
Команда циклического сдвига уровней приоритета устанавливает статус
уровней приоритета без выполнения операции конца прерывания. Разряды
B0...B2 указывают дно приоритетного кольца.
После выполнения команд разрешения чтения регистров ISR или IRR
при выполнении команды ввода из порта 20h и A0h считывается соответственно
содержимое регистров ISR и IRR. Для получения содержимого регистра
IMR необходимо выполнить чтение портов с адресами соответственно
21h и A1h.
Команда разрешения триггера специального маскирования блокирует
действие тех разрядов ISR, которые замаскированы командой типа
1 (маскирования индивидуальных приоритетных уровней запроса прерывания).
Специальное маскирование используется для обслуживания такого
запроса, который блокируется старшим или равным по уровню приоритета
обслуженным запросом, хранящимся в ISR, не сбрасывая последний.
Чтение регистров ISR и IRR может использоваться резидентными программами
при проверке возможности своей активизации - можно проверить,
не выполняется ли в настоящий момент обработка какого-нибудь прерывания,
которая может конфликтовать с действиями резидентной программы.