Assembler для начинающих






    Следующее устройство ввода-вывода, которое мы рассмотрим, -
    клавиатура. Клавиатура отделена от ЭВМ и подключено к системе
    четырехжильным проводом. Хотя внутри клавиатуры и находится
    отдельный микропроцессор, для его программирования нет простого
    способа, так что мы оставим эту задачу инженерам фирмы 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 раз в секунду. Это удобно для обычных клавиш, особенно
    для клавиш управления курсором. Вы просто держите их нажатыми, и
    курсор движется в нужное место. Но если у вас есть клавиши,
    выполняющие некоторую работу только в момент первого нажатия (и не
    может использовать автоповторение), вы опять-таки должны
   отслеживать нажатия и отпускания этой клавиши. Только первый код
    нажатия должен вызывать ее срабатывание, а остальные коды нажатия
    вы должны игнорировать.