Следующее устройство ввода-вывода, которое мы рассмотрим, -
клавиатура. Клавиатура отделена от ЭВМ и подключено к системе
четырехжильным проводом. Хотя внутри клавиатуры и находится
отдельный микропроцессор, для его программирования нет простого
способа, так что мы оставим эту задачу инженерам фирмы IBM. Мы же
можем заняться информацией, которую клавиатура посылает в систему.
Цепь обслуживания клавиатуры на системной плате подключена к
системе прерываний. Кадый раз, как эта цепь регистрирует нажатие
клавиши, она возбуждает прерывание в системе. Это прерывание
передает управление обработчику прерываний от клавиатуры. Эта
процедура получает от клавиатуры данные и сохраняет их для
дальнейшего использования. Обработчик прерываний клавиатуры
обслуживает также специальные случаи, например, перезагрузка
системы (CTL-ALT-DEL) и снятие програмы (CTL-BREAK). Но мы не будем
рассказывать, как это делается, до следующей главы, поскольку все
это обслуживает встроенная система программ BIOS. Пока же осмотрим,
как можно управлять аппаратурой обслуживания клавиатуры.
Когда клавиатура посылает сигнал прерывания, он, прежде, чем
попадет в микропроцессор 8088, проходит через контроллер прерываний
8259. Этот контроллер обслуживает систему прерываний IBM PC почти
во всех ее аспектах.
Микросхема 8259 может обслужить до восьми прерывающих
устройств. К линиям прерываний в IBM PC подключен системный таймер,
клавиатура, адаптер асинхронной связи, фиксированный диск
(винчестер), накопитель на гибких магнитных дисках и печатающее
устройство. Остальные уровни прерываний доступны другим устройствам
ввода-вывода, подключенным к системному каналу ввода-вывода.
Конструктивно каждое из прерывающих устройств назначено к своему
входу прерывания микросхемы 8259. Вход прерывания, к которому
подключено прерывающее устройство, называется уровнем прерывания
этого устройства. Как мы сейчас увидим, микросхема 8259
упорядочивает приоритеты прерываний в соответствии с уровнем. На
Фиг. 8.3 показаны уровни прерываний каждого устройства ЭВМ.
Прерывание от каждого устройства можно по-отдельности
заблокировать или разблокировать. Микросхема 8259 работает точно
так же, как микропроцессор 8088, который имеет флаг прерываний,
разрешающий или запрещающий прерывания по командам STI и CLI. Но
8259 имеет восемь флагов прерываний - по одному на каждое возможное
прерывающее устройство. Эти флаги содержит регистр маски прерываний
IMR (Interrupt Mask Register), расположенный в порту по адресу 21H.
Бит 7 соответствует прерыванию 7, бит 6 - прерыванию 6, и так
далее. Если вы установите бит в 1, устройство не может вызвать
прерывание; если же бит сброшен в 0, контроллер прерываний передает
прерывание дальше, микропроцессору 8088. Разумеется, даже если
какое-либо прерывание разблокировано в регистре IMR, прежде чем это
прерывание сможет произойти, необходимо также сбросить флаг
прерываний в микропроцессоре 8088.
В зависимости от уровня прерывания контроллер назначает
приоритеты каждому прерывающему устройству. Уровень прерывания
определяется аппаратным подключением и не может быть изменен
программным путем. Прерывание номер 0 имеет высший приоритет,
прерывание номер 7 - низший. Если любые два устройства пытаются
одновременно возбудить прерывание, обслуживается устройство более
высокого приоритета. Обслуживание устройства более низкого
приоритета откладывается до тех пор, пока не будет обслужено
устройство с более высоким приоритетом. Микросхема 8259
автоматически реализует такое разбиение по приоритетам, но в
Уровень Устройство
--------------------------------------------------
0 Канал таймера 0
1 Клавиатура
2 -
3 Асинхронные коммуникации
4 Упорядоченные асинхронные коммуникации
5 Фиксированный диск
6 Дискета
7 Принтер
--------------------------------------------------
Фиг. 8.3 Уровни прерываний для микросхемы 8259
управлении прерываниями должна принимать участие и ваша программа;
именно, она должна сообщить контроллеру 8259 о том, что она
закончила работу с текущим прервавшим устройством. Такая команда
называется EOI (конец прерывания), она сообщает микросхеме 8259,
что обработка прерывания от устройства с наивысшим приоритетом
закончилась, и теперь вызвать прерывание в системе может устройство
с более низким приоритетом.
Контроллер 8259 также предотвращает прерывание микропроцессора
устройством с более низким приоритетом, если система в этот момент
обслуживает прерывание с более высоким приоритетом. Микросхема 8259
запоминает текущее активное прерывание, и считает, что
микропроцессор обслуживает это прерывание до тех пор, пока не
получит команду EOI. Микросхема 8259 делает это с помощью двух
внутренних регистров. Первый из них идентифицирует устройства,
которые к настоящему моменту выдали запрос на прерывание; этот
регистр называется регистром запросов прерываний IRR. Другой
регистр следит за текущими обслуживаемыми прерываниями, и
называется регистром обслуживаемых прерываний ISR. Если вы забыли
выполнить команду EOI, микропроцессор сможет прерывать только
программы обработки прерываний от устройств с боле высоким
приоритетом. Если вы не выполнили команду EOI после прерывания от
таймера, система попадает в останов. Так как таймер имеет наивысший
приоритет, отсутствие завершения его прерывания блокирует
возбуждение всех других прерываний.
Контроллер 8259, кроме того, упорядочивает все прерывания. Это
означает, что контроллер заставляет микропроцессор правильно
выбирать обработчик прерываний. Когда контроллер распознает
прерывание, он вынуждвет микропроцессор 8088 начинать работу по
адресу, указанному в одном из 256 векторов прерываний в первом
килобайте памяти. IBM PC отображает восемь уровней прерывания
контроллера 8259 на вектора прерываний от 8 до 0FH включительно.
Так, если поступает прерывание от клавиатуры (уровень 1),
начинается выполнение программы по адресу CS:IP, определенному
двойным словом в векторе прерываний 9, лежащему по адресам от 24H
до 27H.
Давайте посмотрим, как все это вместе происходит в IBM PC.
Сначала процедура самопроверки при включении питания (POST)
инициализирует контроллер 8259 с соответствующей управляющей и
упорядочивающей информацией. В это же время процедура POST снимает
маску прерываний от таймера, клавиатуры, а также прерываний от
дискет в регистре маски прерываний микросхемы 8259. После
завершения процедуры POST включается система прерываний по команде
STI. Теперь система готова к приему прерываний.
Вы нажимаете клавишу на клавиатуре. Клавиатура посылает символ
в системную плату, где он записывается в регистр и возбуждает
прерывание уровня 1. Далее начинает работу микросхема 8259. Она
устанавливает бит 1 в регистре IRR, отмечая запрос на прерывание.
Если не установлены ни нулевой, ни первый биты регистра ISR,
показывающие обслуживание прерывания с более высоким приоритетом,
контроллер возбуждает вход прерывания микропроцессора 8088. Когда
микропроцессор окажется готов к приему прерывания, он выполнит цикл
подтверждения прерывания. Микропроцессор 8088 поместит в стек
текущее содержимое регистра флагов, CS и IP. Контроллер 8259
отвечает на цикл подтверждения прерывания номером прерывания, в
данном случае это 9; затем контроллер установит равным единице бит
1 в регистре ISR, показывая, что прерывание 1 обслуживается. Тем
временем микропроцессор 8088 загружает пару регистров CS:IP из
ячеек 24H- 27H и начинает работу с указанного в них адреса.
Затем микропроцессор выполняет программу обработки прерываний
от клавиатуры. На Фиг. 8.4 показана схема обработчика прерывания от
клавиатуры. Обратите внимание, что первая команда, которую должна
выполнить эта программа, сохраняет содержимое регистра AX в стеке.
Это делается потому, что программа изменяет содержимое регистра AX.
Если обработчик прерываний не восстановит первоначальное значение
этого регистра перед возвратом в прерванную программу, возникнет
ошибка выполнения. Это ведь очень трудно - писать верно работающие
программы, если во время их выполнения содержимое регистров будет
произвольно изменяться другими программами. Если обработчику
прерывания потребуется больше регистров, то он должен все их
сохранить, а затем восстановить.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:14
Фиг. 8.4 Управление клавиатурой Page 1-1
PAGE ,132
TITLE Фиг. 8.4 Управление клавиатурой
0000 CODE SEGMENT
ASSUME CS:CODE
0000 KEYBOARD_INTERRUPT PROC FAR
0000 50 PUSH AX ; Сохранение регистра AX
0001 E4 60 IN AL, 60H ; Выборка номера клавиши
0003 50 PUSH AX ; Сохранение номера клавиши
0004 E4 61 IN AL, 61H
0006 8A E0 MOV AH, AL ; Сохранение текущего значения регистра AL
0008 0C 80 OR AL, 80H
000A E6 61 OUT 61H, AL ; Сигнал об успешном получении символа
000C 8A C4 MOV AL, AH
000E E6 61 OUT 61H, AL ; Возврат Клавиатуры в нормальный режим
0010 58 POP AX
; ...
0011 B0 20 MOV AL, 20H
0013 E6 20 OUT 20H, AL ; Сигнал об окончании прерывания
0015 58 POP AX ; Восстановление регистра AX
0016 CF IRET ; Возвращение в прерванную программу
0017 KEYBOARD_INTERRUPT ENDP
0017 CODE ENDS
END
Фиг. 8.4 Контроль клавиатуры
Обработчик прерывания читает код клавиши, так называемый код
сканирования, из порта 60H. Программа доложна "убрать" прерывание,
сообщив устройству ввода-вывода, что оно должно снять запрос на
прерывание. Программа сбрасывает прерывание от клавиатуры,
устанавливая бит 7 порта 61H. Это не только отменяет запрос на
прерывание, но и сообщает клавиатуре, что она может присылать
следующий символ в микропроцессор 8088. Теперь программа прерывания
может обработать код от клавиши.
Когда обслуживание прерывания завершено, обработчик прерывания
посылает в микросхему 8259 команду EOI. Она сбрасывает в 0 бит 1 в
регистре ISR, и теперь могут произойти любые ожидающие обслуживания
прерывания с меньшими приоритетами. Выполнение команды EOI состоит
в посылке в порт 20H кода 20H. Программа обработки прерывания
восстанавливает содержимое регистра AX, команда IRET
восстанавливает регистры флагов IP, CS, а также приводит флаги к их
первоначальному виду до прерывания.
Точно такая же последовательность событий происходит в случае
любого прерывания, исходящего от микросхемы 8259 и обслуживаемого
микропроцессором 8088. Единственная разница заключается в том,
какое именно прерывание возникает. От этого изменяется установка
битов в регистрах IRR и ISR, и номер вектора прерывания,
выдаваемого микропроцессору 8088. Обработчик прерывания должен все
также сохранять состояние микропроцессора в момент прерывания, а
программа должна выполнить команду EOI в конце обработки
прерывания, или когда определит, что выполняемая программа может
принять прерывание меньшего приоритета. И еще одно предостережение.
Ваша программа обработки прерывания не должена посылать две команды
EOI. Если выполняющаяся программа обработки прерывания прервала
работу обработчика с меньшим приоритетом, вторая команда EOI
поступит вместо этой команды от обработчика с меньшим приоритетом.
Это может привести к неприемлимым последствиям, почему вам и не
следует допускать такого наложения.
Итак, мы обработали прерывание от клавиатуры, правильно
установили все биты и выполнили все команды. Что же мы получили?
Клавиатура посылает в микропроцессор "коды сканирования". Их
значения отражают расположение клавиш на клавиатуре и не имеют
никакого отношения к символу, изображенному на клавише. Например,
клавише ESC возвращает код сканирования 1, клавиша "1" - код 2, и
так далее. Клавише DEL соответствует код сканирования 83. Каждая
клавиша имеет свой собственный уникальный код сканирования. Так что
данные из порта 60H не могут рассматриваться как символ кода ASCII.
Код сканирования нужно еще перекодировать в правильный код
символа.
Клавиатура передает несколько больше, чем только эти 83 кода
сканирования. Первые коды, от 1 до 83, известные как "коды нажатия"
клавиатура посылает, при нажатии клавиши. Когда клавиша
отпускается, клавиатура посылает другой код сканирования, "код
отпускания". Код отпускания формируется прибавлением числа 128 к
коду нажатия. То есть коды отпускания попадают в диапазон от 129 до
211; их легко распознать по 7-му биту, равному 1.
Поскольку клавиатура посылает различные коды для каждого
нажатия и отпускания клавиши, программа может отследить состояние
каждой клавиши. Вы узнаете о нажатии клавиши, получив от клавиатуры
код нажатия. Клавиша нажата, пока вы не получите код отпускания,
сообщающий, что клавиша отпущена. Для большинства клавиш эта
информация не важна, но для регистровых клавиш (например, клавиши
верхнего регистра) она решающая. Например, большие буквы
формируются только тогда, когда клавиша верхнего регистра нажата.
Так как такая информация доступна от любой клавиши клавиатуры IBM,
работа с регистровыми клавишами не составляет труда. Если вы
пожелаете изменить кодировку клавиатуры, устроив свое собственное
расположение клавиш, любая клавиша может трактоваться вами как
регистровая.
И наконец, каждая клавиша клавиатуры IBM имеет встроенный
механизм автоповторения. Если вы держите любую клавишу нажатой
более 1/2 секунды, клавиатура начинает посылать коды нажатия со
скоростью 10 раз в секунду. Это удобно для обычных клавиш, особенно
для клавиш управления курсором. Вы просто держите их нажатыми, и
курсор движется в нужное место. Но если у вас есть клавиши,
выполняющие некоторую работу только в момент первого нажатия (и не
может использовать автоповторение), вы опять-таки должны
отслеживать нажатия и отпускания этой клавиши. Только первый код
нажатия должен вызывать ее срабатывание, а остальные коды нажатия
вы должны игнорировать.