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






    Программы BIOS, обслуживающие клавиатуру, дают примеры различной
    программной техники.  Прежде всего программы обслуживания
    клавиатуры BIOS имеют большой обработчик прерываний, который
    преобразует коды сканирования клавиатуры в коды ASCII.  Обработчик
    прерываний обслуживает обычные и регистровые клавиши.  Программа
    обслуживания клавиатуры также поддерживает кольцевой буфер длиной
    15 символов, позволяя вам печатать быстрее, чем программа может
    обрабатывать нажатия клавиш.


    Поле данных программ клавиатуры начинается у смещения 17H в
    сегменте DATA.  Две флаговых переменных, KB_FLAG и KB_FLAG_1, имеют
    битовое значение и отслеживают текущее положение регистровых
    клавиш.  За определением этих переменных следуют выражения,
    показывающие назначение их битов.  Например, бит 3 переменной
    KB_FLAG следит за состоянием клавиши ALT.  Если она нажата, этот
    бит равен 1.  Если клавиша ALT не нажата, бит равен 0.  Биты
    переменной KB_FLAG определяют текущее состояние всех регистровых
    клавиш, обычных и триггерных.  Триггерные клавиши управления
    регистрами используют биты переменной KB_FLAG_1.  Эти клавиши
    изменяют состояние клавиатуры всякий раз, когда нажимаются.
    Например, клавиша CAPS LOCK переключает клавиатуру с больших букв
    на маленькие и наоборот каждый раз, когда нажимается.
 
      BIOS использует биты переменной KB_FLAG_1 для того, чтобы
    отслеживать, нажата ли в текущий момент клавиша CAPS LOCK (а также
    другие триггерные клавиши). BIOS должна отслеживать их из-за того,
    что все клавиши клавиатуры имеют встроенную функцию автоповторения
    по прошествии некоторого времени. Если бы BIOS переключала бит
    CAPS_STATE каждый раз, когда получала код "нажатия" от клавиши CAPS
    LOCK, автоповторение клавиши сделало бы невозможным для оператора
    определение текущего состояния клавиатуры. BIOS переключает бит
    клавиши CAPS_STATE, когда поступает первый код нажатия. Затем
    программа BIOS игнорирует все коды нажатия до тех пор, пока он не
    получит код отпускания от клавиши CAPS LOCK, означающий, что
    клавиша отпущена.
 
      BIOS использует переменную ALT_INPUT для обеспечения
    специального режима ввода в альтернативном регистре. Когда нажата
    клавиша альтернативного регистра, можно ввести десятичное число с
    помощью цифровой клавиатуры. Когда клавиша альтернативного регистра
    отпускается, программа клавиатуры возвращает символ кода ASCII,
    соответствующий этому десятичному числу. Такая техника позволяет
    оператору вводить в IBM PC любые символы, даже если их нет на
    клавиатуре. Например, нажмите клавишу ALT, затем напечатайте с
    помощью цифровой клавиатуры 1, 1, 1 и отпустите клавишу ALT.
    Появится символ "o". Этот символ имеет код со значением 111 в коде
    ASCII.
 
      Переменная ALT_INPUT хранит текущее значение кода, который
    вводится в альтернативном регистре. Когда на цифровой клавиатуре
    печатается цифра, и состояние клавиатуры показывает, что включен
    альтернативный регистр, программа BIOS умножает текущее значение
    переменной ALT_INPUT на 10, и прибавляет к нему новое число. Когда
    клавиша альтернативного регистра отпускается, в переменной
    ALT_INPUT содержится введенный символ. Обычно переменная ALT_INPUT
    устанавливается равной нулю, и программа BIOS не считает нулевое
    значение правильным результатом ввода в альтернативном регистре.
    Это позволяет оператору использовать клавишу альтернативного
    регистра вместе с другими клавишами, нажимая и отпуская ее (как это
    делается в интерпретаторе языка Бейсик, где ALT-A порождает строку
    символов AUTO и не вводя при этом кода 0 в момент отпускания этой
    клавиши.
 
      Остальные переменные поддерживают буфер клавиатуры. По мере
    того, как на клавиатуре печатаются символы, возникают прерывания.
    Программа KB_INT, входящая в BIOS принимает прерывание от
    клавиатуры, читает код сканирования из порта 60H, и определяет код
    ASCII этой клавиши. Затем программа BIOS записывает это значение в
    буфер клавиатуры KB_BUFFER. В этом буфере есть 16 слов - каждая
    клавиша записывается в виде слова. Первый байт - это код ASCII
    клавиши, второй байт - код сканирования или расширенный код
    сканирования клавиши. Использование расширенного кода сканирования
    позволяет передавать в прикладную программу символы, которые не
    имеют кода ASCII.
 
      У буфера есть два указателя. Переменная BUFFER_HEAD содержит
    смещение первого символа в буфере в сегменте DATA, соответствующего
    клавише, нажатой раньше других. Переменная BUFFER_TAIL указывает на
    символ, соответствующий самой последней нажатой клавише. Если
    указатели имеют одинаковые значения, буфер пуст.
 
      Когда обработчик прерывания BIOS реагирует на очередное нажатие
    клавиши, при котором должен быть сгенерирован символ, он помещает
    этот символ в буфер. Если буфер не заполнен, обработчик прерывания
    помещает символ по адресу, на который указывает переменная
    BUFFER_TAIL. Затем он увеличивает переменную BUFFER_TAIL на два,
    чтобы указывать на следующую ячейку буфера. Если увеличение
    указателя перемещает его за пределы буфера, указатель перемещается
    на начало буфера. Это означает, что буфер клавиатуры "закольцован".
    После шестнадцатого нажатия очередной символ попадает в начало
    буфера. Такая организация буфера также называется циклической, так
    как позиции буфера образуют замкнутый цикл, а не расположены в ряд.
 
      Программа клавиатуры BIOS, вызываемая по команде INT 16H, имеет
    три функции.  Одна из них удаляет символ из буфера.  Указатель
    BUFFER_HEAD указывает на первый символ буфера.  Если буфер не пуст,
    (что получается, если указатель начала равен указателю конца), BIOS
    удаляет слово по указателю BUFFER_HEAD и увеличивает указатель
    начала на два.  Если указатель превышает значение указателя
    BUFFER_END, он перемещается назад в начало буфера.      Подпрограмма K4
    в программе клавиатуры BIOS обеспечивает сдвиг указателя и, если
    необходимо, его перенос в начало.
 
      Другая функция клавиатуры возвращает текущее состояние буфера
    клавиатуры. Она сообщает вызвавшей программе, есть ли в буфере
    символ или нет. Программа может использовать эту информацию для
    того, чтобы избежать ожидания нажатия клавиши, если у нее есть чем
    заняться в это время. Такой вызов функции чтения состояния можно
    использовать для определения момента выхода из цикла. Во время
    каждого прохода по циклу можно проверить, введен ли уже символ с
    клавиатуры. Если нет, цикл продолжается. Если символ введен, цикл
    завершается. Тело цикла не может выполняться в случае использования
    циклящей программой функции чтения символа.
 
      На Фиг. 9.3 показан листинг программы на языке ассемблера,
    которая прибавляет единицу к четырехбайтовому целому числу всякий
    раз, когда она проходит через цикл. Когда оператор нажимает клавишу
    пробела, происходит выход из программы. Эта программа использует
    две функции BIOS. Когда регистр AH установлен в 1, BIOS возвращает
    состояние буфера клавиатуры. Если установлен флаг нуля, символа
    нет. Если символ есть, программа должна также прочитать этот
    символ, иначе он останется в буфере до тех пор, пока следующая
    программа (или эта же, но позднее) не запросит символ. В этом
    примере символ из буфера извлекается вызовом функции программы
    обслуживания клавиатуры BIOS с нулевым значением в регистре AH.
    BIOS возвращает символ в регистре AL, и программа сравнивает
    значение символа с пробелом. Этот пример показывает, как можно
    организовать проверку определенного символа в каждом проходе цикла.