Cамоучитель по Assembler

         

Глава 8


Персональный компьютер IBM


      Эта глава описывает устройство персонального компьютера фирмы
    IBM (IBM PC). Поскольку данная книга посвящена программированию на
    языке ассемблера для IBM PC, вполне уместно рассмотреть аппаратное
    обеспечение машины. Эта глава не предназначена для инженеров и
    техников; она скорее для тех, кто пишет на языке ассемблера
    программы, которые выполняются на IBM PC.
      Выше говорилось, что язык ассемблера не всегда самый подходящий
    язык программирования. Умение программировать непосредственно на
    машинном уровне позволяет программисту иметь много больше
    возможностей для управления машиной. Но в случае большого проекта
    подавляющее количество подробностей,

которое требуется языком
    ассемблера, затрудняет сосредоточие усилий на главной цели. Поэтому
    лучше всего использовать ассемблер только по мере необходмости.
 
      Желание использовать преимущества непосредственного управления
    аппаратурой - одна из причин, по которой спользуются языком
    ассемблера. Чтобы корректно решить эту задачу, вам необхдимо знать,
    что из себя представляет аппаратура и какие у нее возможности. Вот
    зачем нужна эта глава. Информация в данной главе адресуется
    программисту, а не инженеру. Мы рассмотрим здесь различные узлы
    аппаратуры, и как ими можно управлять.
      Эта глава - дополнение к Техническому Описанию Персонального
    Компьютера. Вы будете также пользоваться им для уточнения
    специфических аспектов программирования аппаратуры. Кроме тогно
    дополнительную информацию можно получить из справочных листков к
    отдельным микросхемам. В этой главе данные из этих источников не
    повторяются. Всюду где это нужно, в тексте воспроизводятся
    некоторые данные аппаратуры, иллюстрирующие отдельные программные
    возможности. Будут, конечно, приводиться и примеры работы
    аппаратуры.
      Описание базовой системы ввода-вывода BIOS (Basic Input/Output
    System), которая находится в постоянном запоминающем устройстве
    (ПЗУ) ЭВМ, будет отложено до следующей главы. Программы BIOS
    выполняют управление на аппаратном уровне устройствами IBM PC. В
    этой главе объясняется, что может делать аппаратура; следующая
    глава детализирует, что происходит с аппаратным обеспечением в
    процессе работы, а последняя глава поможет добиться от него того,
    что не реализовано в ПЗУ с программой BIOS.

Системное оборудование


      В каждом пункте этой главы мы будем обсуждать свои аспекты
    системы ввода-вывода IBM PC. В этом пункте речь пойдет о
    стандартных компонентах аппаратуры - о тех, которые находятся на
    процессорной плате системы. Другие части будут посвящены отдельным
    платам адаптеров ввода-вывода, которые по необходимости можно
    установить в систему.
      Центральным процессором IBM PC является Intel 8088, тот самый,
    естественно, который рассматривался на протяжении первых глав
    книги. У нас, как будто еще есть что о нем рассказать. Рядом с
    микросхемой 8088 на системной плате имеется пустое гнездо, в
    которую вставляется арифметический сопроцессор Intel 8087; он был
    рассмотрен в гл.7 и теперь уже должен быть знаком вам.
 
      Остальные компоненты системной платы выполняют функции, которые
    и превращают микропроцессор в ЭВМ. На системной плате находится до
    64K байт оперативной памяти, а также 40K байт памяти только для
    чтения (ПЗУ, постоянное запоминающее устройство). Это ПЗУ содержит
    интерпретатор языка Бейсик, а также систему BIOS, которую мы
    обсудим в следующей главе.
 
      На системной плате есть много компонент, необходимых для работы
    IBM PC. Мы рассмотрим только программируемые или полезные для
    программирования компоненты. На системной плате этими компонентами
    являются микросхемы программируемого периферийного интерфейса 8255,
    таймера-счетчика 8253, контроллера прерываний 8259, и контроллера
    прямого доступа в память 8237. Остальные микросхемы выполняют
    аппаратные функции, которые нельзя изменять с помощью
    программирования. Подробно, на элементном уровне, микросхемы
    рассматриваться не будут; если вас это интересует, обратитесь к
    каталлогу фирмы Intel, либо к другим справочным материалам. Вместо
    этого мы рассмотрим функции ввода-вывода, реализованные на
    системной плате IBM PC. Управляя этим средством доступа, мы сможем
    пльзоваться всеми перечисленными выше компонентами.

Динамик


      Внутри корпуса IBM PC есть маленький динамик. Программа может
    управлять звуками, генерируемыми этими динамиком. Для этого нужно
    управлять некоторыми выходными битами микросхемы 8255 и генератора
    тона в микросхеме 8253.
 
      На Фиг. 8.1 показана программа, которая управляет динамиком
    двумя разными способами. Первый способ, помеченный в листинге
    меткой DIRECT, непосредственно управляет динамиком. Бит 1 выводного
    порта 61H подключен к динамику. Всякий раз, когда программа меняет
    значение этого бита, диффузор динамика двигается либо наружу, либо
    внутрь. Быстро меняя значение этого бита, программа генерирует
    звук. Это иллюстрирует первая часть программы на Фиг. 8.1, она
    меняет значение бита 1, порождая высокочастотный тон. Скорость, с
    которой программа меняет бит 1, определяет частоту тона.
      Взяв на себя непосредственное управление динамиком, вы должны
           Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:05:08
            Фиг. 8.1 Управление динамиком                       Page     1-1
 
                                          PAGE  ,132
                                          TITLE Фиг. 8.1 Управление динамиком
             0000                   STACK SEGMENT STACK
             0000  0040[                        DW    64 DUP (?)
                     ????
                               ]
             0080                   STACK ENDS
 
             0000                   CODE  SEGMENT
                                          ASSUME      CS:CODE
             0000                   SPEAKER PROC      FAR
             0000  1E                     PUSH  DS          ; Адрес возврата
             0001  B8 0000                      MOV   AX, 0
             0004  50                     PUSH  AX
 
                                    ;-----      Задание режима работы динамика
             0005  2B C9                        SUB   CX, CX            ; Счетчик цикла
             0007  E4 61                        IN    AL, 61H
             0009  24 FE                        AND   AL, 0FEH
             000B  E6 61                        OUT   61H, AL     ; Установка разряда 0 порта 61H в 0 для
                                                            ;  задания прямого управления динамиком
             000D                   DIRECT:
             000D  0C 02                        OR    AL, 2
             000F  E6 61                        OUT   61H, AL     ; Включить динамик
             0011  24 FD                        AND   AL, 0FDH
             0013  E6 61                        OUT   61H, AL     ; Выключить динамик
             0015  E2 F6                        LOOP  DIRECT
 
                                    ;-----      Управление высотой звука динамика
             0017  B0 B6                        MOV   AL, 10110110b
             0019  E6 43                        OUT   43H, AL     ; Установка режима для 2-го канала
             001B  B8 03E8                      MOV   AX, 1000    ; Выбор высоты звука
             001E  E6 42                        OUT   42H, AL
             0020  8A C4                        MOV   AL, AH
             0022  E6 42                        OUT   42H, AL     ; Занесение высоты звука в порт динамика
 
             0024  E4 61                        IN    AL, 61H
             0026  8A E0                        MOV   AH, AL
             0028  0C 03                        OR    AL, 3
             002A  E6 61                        OUT   61H, AL     ; Выбор режима управления динамикаом
             002C  2B C9                        SUB   CX, CX
             002E                   KILL_TIME:
             002E  E2 FE                        LOOP  KILL_TIME   ; Цикл ожидания, во время которого
                                                            ;  работает динамик
             0030  8A C4                        MOV   AL, AH
             0032  E6 61                        OUT   61H, AL     ; Выключение динамика
 
             0034  CB                     RET
             0035                   SPEAKER ENDP
             0035                   CODE  ENDS
                                          END
 
            Фиг. 8.1 Управление динамиком
    прежде всего работать с выводным портом микросхемы 8255 системной
    платы. Программируемый периферийный
    интерфейс микросхемы 8255 (PPI) имеет всего три входных или
    выходных, порта. IBM PC    инициализирует микросхему 8255 так, чтобы получилось два входных
    порта - 60H и 62H - и один порт вывода, 61H. Порт 60H в первую
    очередь вводит значения с клавиатуры. Его можно
    также использовать для чтения положения переключателей на системной
    плате. Обычно состояния этих переключателей читаются только один
    раз, во время инициализации при включении питания системы.
    Результат программа BIOS записывает в память для дальнейшего
    использования. Поэтому с точки зрения наших целей можно считать,
    что порт 60H непосредственно обслуживает ввод с клавиатуры. Вообще
    входной порт выполняет важную функцию. Он служит буфером между
    микропроцессором и устройством ввода-вывода; он передает данные
    микропроцессору только тогда, когда последний запрашивает их
    командой IN. Все остальное время вводной порт задерживает данные и
    не допускает, чтобы они повлияли на работу микропроцессора.
 
      Другой порт ввода микросхемы 8255, порт 62H, обслуживает другие
    входы. Четыре его бита непосредственно соответствуют
    переключателям, показывающим объем памяти, подсоединенной к
    системному каналу ввода-вывода. Другие четыре бита имеют
    индивидуальное назначение. Два из них показывают тип системной
    ошибки. Программа обслуживания немаскируемого прерывания NMI
    использует эти биты для определения причины системной аварии. Бит 5
    порта 62H используется для обратной связи с одним из каналов
    таймера-счетчика. Этот бит служит индикатором текущего выхода
    второго канала микросхемы 8253. Бит 4 порта 62H отражает текущее
    состояние ввода с кассетного магнитофона. Сзади у IBM PC, рядом с
    разъемом для подключения клавиатуры, имеется разъем для подключения
    кассетного магнитофона. При чтении данных с кассеты, этот бит
    используется для определения текущего значения, вводимого с
    кассеты.
 
      Порт 61H - это порт вывода микросхемы 8255 в машине фирмы IBM.
    Всякий выходной порт захватывает (временно запоминает) данные,
    выводимые программой. Если бы аппаратура не запоминала данные, они
    бы пропали в течение микросекунды или около этого. Такое
    запоминание данных позволяет сохранять их значение в порте до тех
    пор, пока они снова не будут изменены программой. То есть, когда мы
    выводим значение, меняющее положение диффузора динамика, оно
    остается неизменными до тех пор, пока его не изменит программа.
 
      На Фиг.8.2 показано значение битов порта 61H. Эти данные взяты
    из из технического описания.
 
      При изучении управления динамиком имеют значение только биты 0
    и 1. Из всех других - только бит 3 - управление двигателем
    кассетного магнитофона - и бит 7 - сброс ввода с клавиатуры - имеют
    какое-то значение для наших программ. Остальные биты предназначены
    только для инициализации и диагностики. Чтобы полностью разобраться
    в них, нужно детально изучить принципиальные схемы системы.
 
      Возвращаясь к обсуждению управления динамиком, мы можем
    заметить, что биты 0 и 1 используются для непосредственного
         Бит                  Значение
      -----------------------------------------------------
         0      Порт 2 таймера (упраление динамиком)
         1      Прямое управление динамиком
         2      Мультиплексный порт 62H
         3      Управление мотором кассетного магнитофона
         4      Включение контроля доступа на системной
                  плате памяти
         5      Включение контроля доступа в памяти
                  каналов ввода-вывода
         6      Временной контроль клавиатуры
         7      Мультиплексный/сброса ввода с клавиатуры
                  порт 60H
      -----------------------------------------------------
            Фиг. 8.2 Значение битов порта 61H
 
    управления. Как показано на Фиг. 8.1, установка бита 0 в положение
    0 включает прямое управление динамиком, блокируя механизм генерации
    звука микросхемой 8253. Этот метод используется во второй части
    програмы.
 
      Обратите внимание на то, как программа сбрасывает бит 0.
    Команда OUT включает все 8 бит порта 61H. Способа изменить только
    бит 0, оставив остальные биты нетронутыми, не существует. Если в
    программе нужно изменить только бит 0, она должна считать из порта
    текущее значение других разрядов. К счастью, микросхема 8255
    допускает прямое программное чтение выводных портов.
    Последовательность команд
 
      IN    AL , 61H
      AND   AL , 0FFH
      OUT   61H, AL
 
    читает текущий код из выводного порта, затем команда AND сбрасывает
    младший бит, а команда OUT посылает результат в выводной порт. Если
    бы программа вывела в порт просто число 0, динамик работал бы
    верно, но клавиатура была бы выключена. Работая с любым портом
    вывода побитовой настройки, стройте программу так, чтобы она не
    влияла ни на один из других бит, если только вы не собираететсь
    изменять и их.
 
      Оставшаяся часть первой программы на Фиг.8.1 изменяет значение
    бита 1 выходного порта. Исходное значение порта 61H находится уже в
    регистре AL, так что программе не нужно читать его при каждом
    выполнении цикла. Регистр CX используется таким образом, чтобы
    выполнить цикл 64K раз. При выполнении программы вам, возможно, не
    удастся услышать звук, генерируемый программой. В этом случае
    попытайтесь вставить несколько добавочных команд NOP в цикл DIRECT.
    Это снизит частоту тона.
 
      Вторая часть программы на Фиг. 8.1 для генерации тональности
    использует таймер-счетчик 8253. Прежде чем двигаться дальше,
    обсудим функционирование микросхемы 8253, чтобы понять, как она
    используется в системе. Микросхема 8253 фирмы Intel содержит три
    16-битовых счетчика, которые могут быть использованы в системе для
    счета или задания временных интервалов. В один из счетчиков
    программа загружает 16-битовое значение. Содержимое счетчика
    уменьшается на единицу по каждому импульсу от таймера; частота
    импульсов, подводимых с таймера ко всем трем каналам, равна
    1.19МГц. Это означает, что содержимое счетчика уменьшается на
    единицу каждые 840 наносекунд. Каждый из трех каналов имеет выход.
    Строка контроля выхода изменяется всякий раз, когда содержимое
    счетчика достигает нуля. Командами управления определяют способ,
    которым микросхема 8253 ведет счет.
 
      Выходы этих трех каналов счетчика-таймера подключаются к
    различным узлам системной платы. Канал 0 подключается к контроллеру
    прерываний 8259. Система использует этот канал для порождения
    прерывания времени суток. Канал 1 соединен с контроллером прямого
    доступа к памяти (ПДП или DMA) 8237, и использовать этот канал
    схемы 8253 нельзя, так как смена кода в этом счетчике с большой
    вероятностью уничтожит вашу программу и все другие данные в памяти
    системы. Канал 2 подключен к динамику для генерации звука.
 
      Позже мы вернемся к каналу 0 микросхемы 8253. Канал 2 Дает
    выход на динамик. Для установки канала таймера программа посылает
    код 0B6H в порт 43H, управляющий порт микросхемы 8253. Тем самым
    канал 2 таймера-счетчика настраивается на работу в качестве
    делителя частоты. Таймер делит исходную частоту - в данном случае
    1.19МГц - на 16-битовое число, которое программа загружает в
    регистр канала 2. Регистр канала 2 расположен по адресу порта 42H
    (канал 0 - это порт 40H и, поскольку вы никогда не должны изменять
    содержимое канала 1, задачу определения адреса его порта мы
    оставляем вам). Программа в примере загружает в регистр канала
    число 1000. Это означает, что на выходе вы услышите частоту 1190Гц.
    На самом деле, вы услышите основную частоту 1190 Гц плюс обертоны,
    вызванные прямоугольной формой сигнала таймера.
 
      Заметим, что число 1000 - 16-битовое, в то время как порт 42H -
    8-битовый. Команда установки режима работы, которую мы послали в
    порт 43H, сообщила микросхеме 8253, что в нее будет выводиться
    16-битовое число в виде двух 8-битовых. Сначала посылается младший
    значащий байт, а за ним следует старший. Такая двухшаговая
    процедура загружает в канальный регистр требуемое значение.
 
      Далее программа должна дать управляющему порту 61H такую
    установку, чтобы он пропускал сигнал на динамик. Для этого
    программа устанавливает равными 1 биты 0 и 1 управляющего порта.
    Заметим, что программа в начале сохраняет первоначальное значение
    кода из управляющего порта и восстанавливает его в конце. Это
    отключает динамик по окончании звука. Если этот способ
    недостаточен, - например, если программа генерирует звук тогда,
    когда не совсем ясно, был ли выключен динамик - можно выключить
    его, сбросив в нуль бит 1 порта 61H.
 
      Эти два метода управления динамиком наиболее прямолинейны. Эти
    методы можно пытаться комбинировать в поисках интересных эффектов.
    После установки на вывод звука при помощи микросхемы 8253 можно
    модулировать выходной сигнал посредством битов 1, 0 или обоих,
    порта 61H, а также менять число в канальном счетчике при включенном
    динамике. Программу на Фиг. 8.1 можно изменить так, чтобы она
    выводила значение регистра CX при каждой итерации цикла. Это
    приведет к тому, что частота сигнала из динамика будет расти от
    очень низкого к очень высокому тону. Работая с этими тремя
    управляющими значениями, вы сможете создать множество интересных
    эффектов.

Клавиатура


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

Время суток


    Канал 0 таймера 8253 имеет специальное назначение в IBM PC. Выход
    этого канала таймера подключен к уровню прерывания 0 микросхемы
    8259. Это означает, что всякий раз, когда выход канала 0 имеет
    активный уровень сигнала, возникает прерывание (при условии, что
    все остальное установлено корректно). Процедура самопроверки при
    включении питания инициализирует канал 0 таймера, загружая в него
    число 0. Это дает наибольшее (не наименьшее) значение счетчика,
    которое может записать в него программа. Имея на входе частоту 1.19
    МГц, счетчик считает обратно к нулю чуть быстрее, чем за 55
    миллисекунд. Программа инициализации устанавливает таймер таким
    образом, что он считает непрерывно. Это означает, что прерывание 0
    возникает 18.2 раза в секунду.
 
      Как мы увидим в следующей главе, встроенная система программ
    BIOS использует это постоянное прерывание от таймера, чтобы следить
    за текущим временем. BIOS продвигает часы текущего времени вперед
    всякий раз, когда возникает прерывание. Затем, с помощью
    соответствующих вычислений, Вы можете преобразовать число циклов
    таймера в часы, минуты и секунды.
 
      Почему же выбрано значение 18.2? Почему счетчик не
    программируется так, чтобы давать прерывание 20 раз в секунду, или
    другое "хорошее" число раз? Это объясняет следующий пример.
 
      Системный таймер может выполнять функцию измерения времени
    отличного от времени дня. Время дня прекрасно подходит для
    определения интервалов времени, измеряемых в секундах или минутах.
    Но в некоторых ситуациях, возникающих при управлении
    вводом-выводом, нужно определять интервалы времени порядка одной -
    двух миллисекунд. Обычно программы отсчитывают такие интервалы с
    помощью временного цикла. Программа для такого цикла выглядит
    примерно так:
 
      MOV   CX, LOOP_VALUE
      HERE:LOOP  HERE
 
      Вы выбираете константу LOOP_VALUE так, что цикл выполняется в
    точности нужное число раз. Это очень хороший метод, если вам нужна
    задержка на определенное время. В выше приведенном примере
    начальное значение константы LOOP_VALUE, равное 0FFFFH, дает время
    выполнения около 250-миллисекунд.
 
      Но предположим, что вы хотите понаблюдать за внешним событием,
    и определить, сколко времени займет его наступление. Можно использовать
    вариант временного цикла такого, например, вида:
 
      MOV   CX, 0
      HERE:
      ; --- проверка возникновения события
      IN    AL, DX
      TEST  AL, MASK_BIT
      LOOPNE      HERE
      DONE:
      ; --- CX содержит число итераций цикла
 
      Таким способом вы считаете число итераций цикла, чтобы
    вычислить затраченное на него время. Этот метод предполагает, что
    событие возникнет до того, как содержимое регистра CX второй раз
    достигнет 0. Но если вам нужно измерить что-то с точностью до
    микросекунд, этот метод не удобен, так как каждая итерация цикла
    требует от 10 до 20 микросекунд. Системный таймер дает лучшее
    решение. Поскольку он изменяет свое значение каждые 840 наносекунд,
    вы сможете определить длительность события с точностью до
    микросекунды.
 
      На Фиг. 8.5 показан пример программы, вычисляющей время события
    с помощью системного таймера. В этом примере в качестве
    регистрируемого события используется канал 2 таймера. В первой

            Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:05:19
            Фиг. 8.5 Управление системным таймером                  Page         1-1
 
                                          PAGE    ,132
                                          TITLE   Фиг. 8.5 Управление системным таймером
 
             0000                   STACK   SEGMENT STACK
             0000  0040[                        DW      64 DUP (?)
                   ????
                               ]
             0080                   STACK   ENDS
 
             0000                   CODE    SEGMENT
                                          ASSUME  CS:CODE
             0000                   TIMER   PROC    FAR
             0000  1E                     PUSH    DS        ; Занесение адреса возврата
             0001  B8 0000                      MOV     AX, 0
             0004  50                     PUSH    AX
 
             0005  B0 B6                        MOV     AL, 10110110B   ; Выборка таймера 2
             0007  E6 43                        OUT     43H, AL
             0009  B8 0500                      MOV     AX, 500H
             000C  E6 42                        OUT     42H, AL         ; Таймер 2 установлен на 500 отсчетов
             000E  8A C4                        MOV     AL, AH
             0010  E6 42                        OUT     42H, AL
 
             0012  E8 001D R                    CALL    LOW_TO_HIGH     ; Выборка времени первого перехода с 0 на 1
             0015  8B D8                        MOV     BX, AX          ; Сохранение значения в регистре BX
             0017  E8 001D R                    CALL    LOW_TO_HIGH     ; Выборка времени второго перехода с 0 на 1
             001A  2B D8                        SUB     BX, AX          ; Вычитая получаем длину цикла
             001C  CB                     RET
             001D                   TIMER   ENDP
 
                  Фиг. 8.5 Управление системным таймером (начало)
                                    ;--------------------------------------------
                                    ; Эта подпрограмма ждет перехода с нижнего уровня
                                    ;  сигнала на верхний (с 0 на 1) в таймере 2
                                    ;  и возвращает в регистре AX значение счетчика таймера 0
                                    ;--------------------------------------------
             001D                   LOW_TO_HIGH     PROC    NEAR
             001D  E4 62                        IN      AL, 62H         ; Проверка разряда таймера 2
             001F  A8 20                        TEST    AL, 20H
             0021  75 FA                        JNZ     LOW_TO_HIGH     ; Цикл: сигнал таймера 2 на
                                                            ;  нижнем уровне
             0023                   WAIT_HIGH:
             0023  E4 62                        IN      AL, 62H         ; Проверка разряда таймера 2
             0025  A8 20                        TEST    AL, 20H
             0027  74 FA                        JZ      WAIT_HIGH       ; Цикл: сигнал таймера 2 на
                                                            ;  верхнем уровне
             0029  B0 00                        MOV     AL, 0           ; Послать команду в регистр управления тай-
             002B  E6 43                       OUT     43H, AL         ;  мером 2, которая "замораживает" таймер 2
             002D  90                     NOP
             002E  90                     NOP               ; Задержка, необходимая для 8253
             002F  E4 40                        IN      AL, 40H         ; Чтение младшего байта счетчика
             0031  8A E0                        MOV     AH, AL
             0033  90                     NOP
             0034  E4 40                        IN      AL, 40H         ; Чтение старшего байта счетчика
             0036  86 E0                        XCHG    AH, AL
             0038  C3                     RET               ; Возвращение значения в AX
             0039                   LOW_TO_HIGH     ENDP
             0039                   CODE    ENDS
                                          END
 
            Фиг. 8.5 Системный таймер (продолжение)
 
    части программы этот канал таймера загружается известным значением.
    Здесь мы произвольно выбрали число 500H. Обратите внимание, что эта
    часть программы идентична способу генерации звуков с помощью втого
    канала таймера.
 
      Наша программа вызывает подпрограмму LOW_TO_HIGH, которая
    возвращает значение таймера в тот момент, когда на выходе канала 2
    таймера отмечается переход от низкого к высокому уровню. Программа
    рследит именно за переходом; если бы она регистрировала только
    высокий уровень, было бы неизвестно, стал ли сигнал высоким только
    что или уже готов стать низким. Подпрограмма посылает нуль в
    управляющий регистр таймера (порт 43H), чтобы "заморозить" текущее
    значение канала 0. Это позволяет ей прочитать текущее значение
    таймера, продолжающего счет. Если бы программа временно не
    зафиксировала таймер, она не смогла бы прочитать без ошибки его
    16-битовое значение.
 
      Обратим внимание на то, что подпрограмма на Фиг. 8.5 содержит
    несколько команд NOP. Эти команды записаны в программе для выдержки
    временных соотношений. Если очень внимательно прочитать инструкции
    по микросхеме 8253, мы заметим, что между командами IN и OUT,
    выполняемыми этой микросхемой, проходит не меньше 1 микросекунды.
    Команда NOP занимает как раз достаточно времени, чтобы исключить
    нарушение требований микросхемы по времени.
      После возврата из подпрограммы программа сохраняет в регистре
    BX значение счетчика таймера во время первого перехода с низкого
    уровня на высокий. Затем программа снова вызывает подпрограмму,
    чтобы зарегистрировать следующий переход с низкого уровня на
    высокий на выходе канала 2 таймера. Потом она вычитает одно число
    из другого, чтобы определить время цикла канала 2.
 
      Мы уже говорили о том, что загрузка регистра 0 таймера
    значением счета 0 - очень полезна. Данная программа подтверждает
    это, так как она вычитает два значения таймера, не обращая внимания
    на то, какое из них больше, а какое меньше. Так как канал 0 таймера
    работает асинхронно по отношению к этой программе, нет никакой
    гарантии, что первое читаемое из него число больше второго.
    Например, предположим, что первый переход с низкого на высокий
    уровень происходит, когда таймер 0 имеет значение 100H. После 500H
    циклов значение числа в таймере будет 0FC00H. Счетчик таймера 0
    автоматически "проскочил" от значения 0 к значению 0FFFFH, и
    значение прочитанное вторым оказалось численно больше первого. Но
    из-за того, что регистр таймера снова начинает счет со значения
    0FFFFH, мы всегда можем вычитать эти два числа. При этом иногда
    будет появляться перенос, иногда нет, но разность этих двух чисел
    всегда будет равна числу отсчетов.
 
      Чтобы убедить вас в правильности этого положения, рассмотрим
    случай, когда счетчик загружается числом 8000H. Если первый переход
    возникает при значении 6000H, второй появится при значении 5B00H, и
    разница между ними составляет 500H. Но если первый переход
    возникает при значении 100H, второй возникает при значении 7C00H, и
    разница станет равна 8500H. Чтобы правильно отреагировать на эту
    ситуацию, программа должна была бы проверить, не произошло ли
    переполнение счетчика за время отсчета.
 
      При выполнении этой программы вы обнаружите, что значение в
    регистре BX составляет около 0A00H, и не равно ожидаемому значению
    500H. Так происходит потому, что таймер работает в режиме
    уменьшения содержимого счетчика на два по каждому временному
    импульсу. Чтобы разобраться в работе микросхемы 8253, нужно
    ознакомиться с инструкцией по ее программированию.
 
      Фиг. 8.6 дает сводку для управляющего слова микросхемы 8253.
    Для настройки одного из каналов на конкретный режим работы вы
    выводите это управляющее слово в порт 43H. Мы уже встречались с
    выводом некотрых значений в порт 43H. Чтобы "заморозить" счетчик,
    мы послали в этот порт нуль, а для настройки генератора тональности
    - код 0B6H. Посмотрим, откуда берутся эти значения.
 
      Два старших бита управляющего слова определяют канал таймера.
    Следующие два бита - выполняемую операцию. Когда мы выводим
    значение 0, выбирается таймер 0 и запирание данных в счетчике.
    Следующие 3 бита задают режим работы выбранного таймера. Эти биты
    не играют роли, когда счетчик заперт, но нужны при инициализации
    таймера. Оставшийся бит определяет, будет ли счетчик работать как
    16-битовое двоичное число или как четырехзначное десятичное в
    двоичном представлении.
A


      Формат управляющего слова
        D7   D6   D5    D4   D3   D2     D1   D0
      ЪДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДї
      і SC1і SC0і RL1і RL0і M2 і M1 і M0 і BCDі
      АДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДЩ
 
      Определение управления
      SC - выбор счетчика:
          SC1       SC0
      ЪДДДДДДДДДВДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДї
      і    0        і    0    і  задать счетчик 0       і
      ГДДДДДДДДДЕДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДґ
      і    0        і    1    і  задать счетчик 1       і
      ГДДДДДДДДДЕДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДґ
      і    1        і    0    і  задать счетчик 2       і
      ГДДДДДДДДДЕДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДґ
      і    1        і    1    і  неопределено         і
      АДДДДДДДДДБДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДЩ
 
      RL - чтение/загрузка:
        RL1  RL0
      ЪДДДДВДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
      і  0 і      0 і Операция запирания счетчика (см.  і
      і    і        і раздел процедуры READ/WRITE)      і
      ГДДДДЕДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
      і  1 і      0 і Считать/загрузить старший байт    і
      ГДДДДЕДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
      і  0 і      1 і Считать/загрузить младший байт    і
      ГДДДДЕДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
      і  1 і      1 і Считать/загрузить младший байт,   і
      і    і        і затем - старший                 і
      АДДДДБДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
 
      M - режим:
        M2  M1  M0
      ЪДДДВДДДВДДДВДДДДДДДДДДДї
      і 0 і 0 і 0 і Режим 0   і
      ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
      і 0 і 0 і 0 і Режим 1   і
      ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
      і X і 1 і 0 і Режим 2   і
      ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
      і X і 1 і 1 і Режим 3   і
      ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
      і 1 і 0 і 0 і Режим 4   і
      ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
      і 1 і 0 і 1 і Режим 5   і
      АДДДБДДДБДДДБДДДДДДДДДДДЩ
 
      BCD:
      ЪДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
      і   0 і 16-битовый двоичный счетчик        і
      ГДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
      і   1 і десятичный в двоичном представлении  і
      і     і (BCD) счетчик (4-х разрядный)        і
      АДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
 
          Фиг. 8.6 Программирование таймера/счетчика
           (с разрешения фирмы Intel; приоритет Intel 1981г.)A
      Управляющий код 0B6H, который использовался для генерации
    тональности, можно расписать таким образом:
 
      0B6H = 10110110B = 01 11 011 0
 
      Это управляющее слово выбирает канал 2. Счетчик этого канала
    работает с 16-битовым значением, младший байт которого загружается
    в   счетчик первым. Последный бит показывает, что счет будет
    двоичным. Можно видеть также, что выбирается третий режим работы.
 
      Микросхема 8253 может работать в шести разных режимах. Но для
    наших целей, в конфигурации системы IBM, удобны только два из них.
    Режим 3 устанавливается по умолчанию для всех трех каналов таймера.
    Это режим работы генератора прямоугольных импульсов: половину
    периода выход канала дает нижний уровень, а другую половину периода
    - верхний. Счетчик работает в этом режиме, вычитая из своего
    значения по два, а не по одному. Во время первого обратного счета
    выход низкий, а затем, во время второго счета - высокий. Так как
    счетчик считает по два, выход имеет высокий уровень точно половину
    заданного времени, и низкий тоже точно половину. Из-за того, что
    канал 0 таймера обычно работает в режиме 3, пример на Фиг. 8.5
    заканчивает счет со значением счетчика 0A00H, а не 500H, как
    ожидалось. Каждый отсчет таймера уменьшает содержимое счетчика на
    два.
 
      Так как счетчик считает двойками, он переполняется каждые 27
    микросекунд. Если вы хотите измерять события более длительные, то
    вам придется воспользоваться другим способом измерения времени.
 
      Другой режим таймера, который используется в IBM PC - это режим
    0. Этот режим называют прерыванием по завершению счета. В этом
    режиме таймер не работает непрерывно. После его установки таймер до
    тех пор не начинает считать (единицами), пока в него полностью не
    будет загружено число. Затем счетчик считает в сторону уменьшения с
    частотой синхроимпульсов, пока не достигнет нуля. В этот момент его
    выход становится высоким. Поскольку выход канала 0 таймера
    подключен к прерыванию 0 контроллера 8259, в системе возникает
    прерывание.
 
      Режим прерывания по завершению счета полезен, если вы хотите в
    определенный момент подать программе сигнал с помощью прерывания.
    Так как счетчик ограничен шестнадцатью битами, максимальный
    отсчитываемый интервал времени составляет 55 миллисекунд. Если этот
    интервал слишком мал, нужен другой метод измерения времени.
 
      Если вы хотите измерять интервал времени в секундах, нужно
    оставить таймер в его обычном режиме работы. Система BIOS позволяет
    захватывать управление системой каждые 55 миллисекунд, и в каждый
    такой момент вы можете решить, не исчерпался ли нужный промежуток
    времени.
      Если время нужной вам задержки находится между 55
    миллисекундами и 5 секундами, можно использовать метод без
    использования программ BIOS. Например, вам хочется сделать задержку
    на 150 миллисекунд. Используя режим прерывания по завершению счета,
    вы настраиваете таймер на прерывание через 50 миллисекунд (этому
    соответствует значенние счетчика около 59500). Обработчик
    прерывания программируется так, чтобы, получая управление первые
    два раза, он заново устанавливал таймер на 50 миллисекунд. По
    третьему прерыванию от таймера, когда 150 миллисекунд исчерпаны,
    можно предпринять нужные действия.
 
      При организации задержек через таймер всегда нужна некоторая
    осторожность. Как упоминалось выше, канал 1 таймера выполняет одну
    важную аппаратную функцию. Если вы модифицируете число в канале 1,
    ваша программа может немедленно разрушиться. Использование канала 2
    таймера безопасно. Этот канал подключен только к динамику и выходу
    кассетного магнитофона. Отсюда, очевидно, следует, что нельзя
    использовать канал 2 таймера для отсчета промежутков времени в одно
    время с попытками воспроизводить мелодии через динамик. И наконец,
    BIOS пользуется услугами таймера 0 для различных системных функций.
    При обсуждении BIOS будет видно, что прерывание по времени суток
    управляет не только текущим временем, но также обслуживает и
    двигатель накопителя на дискетах. Перед тем, как изменять настройку
    канала 0 таймера для любых целей, нужно понять, какие существующие
    функции вы можете при этом изменить.

Возможности системы


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

Видеоадаптеры


      Система IBM PC, которая попадет к вам в руки, может быть
    снабжена одним из двух различных дасплейных адаптеров. Один из них
    - адаптер монохромного дисплея и принтера (мы будем называть его
    монохромным адаптером, или иногда - черно-белой платой). Такой
    видео адаптер лучше всего подходит для деловых приложений.
    Черно-белая плата управляет монохромным дисплеем фирмы IBM.
    Монохромный адаптер работает в одном режиме, и может показывать на
    экране текст только одного цвета. Этот адаптер также содержит
    аппаратные узлы, необходимые для управления печатающим устройством.
    Такая комбинированная плата удобнее всего для деловых приложений.
 
      Другой видео адаптер - адаптер цветного графического
    монитора (мы будем называть его цветной платой). Цветная плата
    работает с дисплеями, использующими нормальные телевизионные
    частоты. Этот адаптер дает цветные изображения, а не только
    одноцветные, как монохромный. У него есть несколько режимов работы,
    включая такие, в которых можно управлять отдельными точками
    экрана.

Адаптер монохромного дисплея и принтера


      Сначала поговорим о монохромном дисплее, он - простейший из
    двух адаптеров. Мы отложим описание той части платы, которая
    работает с печатающим устройством, пока не дойдем до адаптера
    печатающего устройства. Схема адаптера печатающего устройства на
    монохромной плате идентична схеме отдельного адаптера печатающего
    устройства, поэтому способы программирования их также одинаковы.
 
      Черно-белая плата работает в одном режиме. Этот видео адаптер
    предназначен для вывода 25 строк символов по 80 символов в строке.
    Такое построение изображения называют режимом 80*25. Вы помещаете
    символы на экран, записывая коды ASCII в буфер дисплея. Буфер
    дисплея - это специальная область памяти, расположенная в адресном
    пространстве по адресу 0B0000H. Эта память - часть платы адаптера,
    а не системной памяти. Всякий раз, когда вы записываете символ в
    коде ASCII в буфер дисплея, он появляется в соответствующем месте
    экрана. Преобразование символа из кода ASCII в точки на экране
    выполняется аппаратно.
 
      Каждый символ на дисплее имеет атрибут. Атрибуты символов
    определяют вид, в которым адаптер выводит символы на экран. На Фиг.
    8.7 показаны атрибуты символов и их значения. Вам нужно знать эти
    значения, так как их тоже надо помещать в буфер дисплея. Позиция
    каждого символа в буфере дисплея занимает два байта. Четный байт
    пары содержит код символа, а нечетный - значение атрибута. По Фиг.
    8.7 можно определить значение атрибута, с которым выводить на экран
    символ. Обычно выводится белый (на самом деле зеленый) символ на
    черном фоне. Для этого случая значение атрибута равно 07H. Чтобы
    сделать изображение негативным, нужно изменить значение атрибута на
    70H. Атрибут 00H делает символ невидимым. Хотя код ASCII символа и
    записан в байт символа, значение атрибута не дает символу появиться
    на экране.
 
      Дисплейный буфер черно-белой платы содержит 4K байта памяти.
    Этого достаточно, чтобы иметь байты символов и атрибутов для каждой
    из 2000 позиций экрана. Первый символ буфера дисплея появляется в
    верхнем левом углу экрана, следующие два байта изображают следующий
    символ справа, и так далее. Первый символ второй строки находится в
    байтах 160 и 161. Теперь можно определить адрес любого символа на
    экране. Сначала определим позицию в верхнем левом углу экрана, как
    находящуюся в строке 0 и колонке 0; нижний правый угол находится в
    строке 24 и колонке 79. Тогда формулой вычисления адреса для
    произвольной строки и позиции будет
 
      адрес = 2*(строка*80 + колонка) + 0B0000H
 
      Умножение на 2 выравнивает адрес к двум байтам на позицию.
    Прибавление значения 0B0000H отражает начальный адрес буфера
    дисплея. Обычно в программе либо регистр DS, либо регистр ES
    загружается значением 0B0000H, и в остальном программа работает со
    смещениями в буфере дисплея.
      Значение                Атрибут
      ----------------------------------------------------------
      00H         ничего не выводится
      01H         подчеркнутые символы
      07H         белый символ на черном фоне
      0FH         ярко-белый символ, черный фон
      70H         черный символ, белый фон
      80H         при добавлении к любому другому символ
                  мигает
      ----------------------------------------------------------
      Фиг. 8.7 Символьные атрибуты для монохромного адаптера
 
      На Фиг. 8.8 в качестве примера для монохромного дисплея
    приведена программа, которая перемещает содержимое экрана на одну
    позицию вправо. Она выбрасывает крайнюю справа колонку, а слева
    помещает колонку из пробелов. Если вы хотите испытать эту
    программу, но имеете в своей системе только цветную плату, то
    программа работает при установке сегмента DISPLAY на адрес 0B800H.
    Оба видео адаптера очень похожи при работе в текстовом режиме, и
    различаются только адресами памяти и ввода-вывода.

            Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:05:26
            Фиг. 8.8 Горизонтальный сдвиг вправо                      Page     1-1
 
                                          PAGE  ,132
                                          TITLE Фиг. 8.8 Горизонтальный сдвиг вправо
 
             0000                   STACK SEGMENT STACK
             0000  0040[                        DW    64 DUP (?)
                     ????
                               ]
 
             0080                   STACK ENDS
 
             0000                   DISPLAY SEGMENT AT      0B800H
             0000                   DISPLAY_START     LABEL WORD
             0FA0                         ORG   4000
             0FA0                   DISPLAY_END LABEL WORD
             0FA0                   DISPLAY ENDS
 
             0000                   CODE  SEGMENT
                                          ASSUME      CS:CODE
             0000                   SIDE_SCROLL PROC  FAR
             0000  1E                     PUSH  DS
             0001  B8 0000                      MOV   AX, 0
             0004  50                     PUSH  AX
             0005  B8 ---- R              MOV   AX, DISPLAY
             0008  8E D8                        MOV   DS, AX
             000A  8E C0                        MOV   ES, AX
                                          ASSUME      DS:DISPLAY, ES:DISPLAY
 
                                    ;-----      Заполнение столбца 79 пробелами
 
                   Фиг. 8.8 Горизонтальный сдвиг вправо
             000C  B9 0019                      MOV   CX, 25
             000F  8D 3E 004E R                 LEA   DI, DISPLAY_START+78
             0013  B8 0720                      MOV   AX, 720H
             0016                   BLANK:
             0016  89 05                        MOV   [DI], AX
             0018  81 C7 00A0             ADD   DI, 160
             001C  E2 F8                        LOOP  BLANK
 
                                    ;-----      Сдвиг вправо
 
             001E  B9 07D0                      MOV   CX, 2000
             0021  8D 36 0F9E R                 LEA   SI, DISPLAY_END-2
             0025  8D 3E 0FA0 R                 LEA   DI, DISPLAY_END
             0029  FD                     STD
             002A  F3/ A5                       REP   MOVSW
 
             002C  A3 0000 R              MOV   DISPLAY_START, AX
 
             002F  CB                     RET
             0030                   SIDE_SCROLL ENDP
             0030                   CODE  ENDS
                                          END
 
               Фиг. 8.8 Горизонтальный сдвиг направо
 
      Программа на Фиг. 8.8 делает этот горизонтальный сдвиг очень
    простым способом. Правая колонка заполняется пробелами в результате
    записи 25 пробелов через каждые 160 байт памяти. Затем программа
    сдвигает весь дисплейный буфер по памяти на один байт вверх.
    Поскольку буфер дисплея непрерывно продолжается строка за строкой,
    символ, который был в колонке 79 строки 0, после сдвига оказывается
    в колонке 0 строки 1. Наконец, программа заменяет первый символ
    буфера пробелом.
 
      Монохромный адаптер имеет также несколько портов ввода-вывода,
    которые можно использовать при программаровании дисплея, но они
    будут рассмотрены очень бегло. Конструкция монохромного адаптера
    использует эти порты ввода-вывода в первую очередь для удобства
    аппаратной организации. Кроме того, программирование черно-белой
    платы в общих чертах аналогично цветной плате. Поскольку цветная
    плата имеет намного больше специальных возможностей в использовании
    портов ввода-вывода, мы поговорим о них в основном в следующем
    разделе.
 
      Монохромный адаптер порождает сигналы вертикальной и
    горизонтальной синхронизации, необходимые для нормального
    изображения, с помощью контроллера электронно-лучевой трубки 6845
    фирмы Motorola. Эта микрсхема содержит два порта ввода-вывода,
    имеющих адреса 3B4H и 3B5H. Адаптер также имеет управляющий порт
    3B8H и порт состояния 3BAH. После инициализации адаптера
    модифицировать коды в этих портах вряд ли стоит. Существуют и
    другие режимы работы, возможные для монохромной платы, но мы
    сконцентрируем наше внимание на цветной плате. Полное, детальное
    описание портов ввода-вывода монохромного адаптера можно найти в
    техническом описании.

Адаптер цветного графического монитора


    Другой видеоадаптер, который может быть установлен на IBM PC -
    адаптер цветного графического монитора. Цветная плата разработана в
    фирме IBM для подключения к устройствам подобным телевизору.
    Черно-белый адаптер работает только с монохромным дисплеем фирмы
    IBM, а цветную плату можно подключить к любому цветному или
    черно-белому монитору, использующему стандартные телевизионные
    сигналы. Или, вы можете отдельно приобрести радиочастотный
    модулятор, который позволит вам подключить выход цветной платы к
    вашему домашнему телевизору. Цветная плата может быть подключена к
    разнообразным мониторам, так как она работает на телевизионных
    частотах.
 
      Цветная плата имеет много режимов работы, и программы фирмы IBM
    обслуживают некоторые из этих режимов. Обслуживание других режимов
    оставлено вам. Цветная плата дает намного больше гибкости, чем
    монохромная.
 
      Для цветного графического адаптера возможны два текстовых
    режима. Один текстовый режим формирует экран, имеющий 25 строк по
    80 символов, идентичный монохромному адаптеру. Другой текстовый
    режим уменьшает количество символов в строке до 40. Этот режим с
    меньшим разрешением необходим, если вы хотите использовать цветную
    плату или с монитором, имеющим меньшее разрашение, или с домашним
    телевизором, так как 80-символьное изображение может оказаться
    нечитабельным при некоторых изображениях. Чтобы использовать все
    возможности цветной платы, вы должны работать с высококачественным
    монитором. Монитор с высокой разрешающей способностью позволит вам
    без искажений выводить полные 80-символьные строки.
 
      Цветная плата имеет также два графических режима. В этих
    режимах вы можете управлять каждой отдельной точкой экрана. В
    текстовых режимах независима каждая символьная позиция, а в
    графических режимах независимо управление каждой точкой.
    Графический режим среднего разрашения дает 200 строк растра, по 320
    точек в строке. Каждая из этих точек может иметь один из четырех
    возможных цветов. Это означает, что любая точка управляется двумя
    битами. Графический режим высокого разрешения дает 200 строк
    растра, каждая из которых состоит из 640 точек; в этом режиме
    возможны только два цвета, черный и белый.

Текстовый режим


      Два текстовых режима цветного графического адаптера дают
    простой способ вывода символов на экран. В текстовых режимах
    цветная плата аналогична монохромному адаптеру, но она позволяет
    указать цвет каждого символа. Так же, как и в монохромной плате,
    каждая символьная позиция цветной платы имеет байт атрибутов. Этот
 
      Номер бита  7  6  5  4  3  2  1  0
              ЪДДВДДДДДДДДВДДВДДДДДДДДї
              і Мі Ф  О  Ні Яі СИМВОЛ і Фиг. 8.9 Байт атрибута
              АДДБДДБДДБДДБДДБДДБДДБДДЩ          для ЦГА
 

                                - 289 -    
 
 
 
    байт атрибутов определяет цвета символов и фона каждой позиции.
      На Фиг.8.9 показана структура байта атрибутов в цветном
    текстовом режиме. Три бита, помеченных Ф О Н, определяют один из
    восьми возможных цветов фона. Три бита СИМВОЛ определяют цвет
    символа. Бит Я также влияет на цвет символа: его установка делает
    цвет символа более ярким. Тем самым обеспечивается выбор одного из
    16 цветов символа. Байт атрибута управляет единственным символом,
    позволяя выбрать любую комбинацию цветов фона и символа каждой
    позиции. Старший бит, помеченный буквой М, обычно вызывает мигание
    символа. Установка бита мигания равным 1 заставляет контроллер
    дисплея переключать цвет символа между его цветом и цветом фона со
    скоростью примерно четыре раза в секунду. Так как символ,
    изображенный в цвете фона, невидим, то получается эффект мигания.
    Можно заменить бит мигания четвертым битом цвета фона, разрешив при
    этом 16 цветов фона и 16 цветов символа. Это делает один из битов
    регистра выбора цветов. Еще надо обратить внимание на то, что
    одинаковая установка цветов символа и фона означает, что вы не
    видите символ. Символ есть, но это все равно что пытаться увидеть
    северного медведя в пургу - все одного цвета. На Фиг. 8.10 показаны
    все 16 цветов, возможных в текстовом режиме.
 
      I    R        G    B      Цвет
      -------------------------------------
      0    0        0    0       черный
      0    0        0    1       синий
      0    0        1    0       зеленый
      0    0        1    1       морской волны
      0    1        0    0       красный
      0    1        0    1       магента
      0    1        1    0       коричневый
      0    1        1    1       светло-серый
      1    0        0    0       темно-серый
      1    0        0    1       голубой
      1    0        1    0       светло-зеленый
      1    0        1    1       светлый морской
      1    1        0    0       розовый
      1    1        0    1       светлый магента
      1    1        1    0       желтый
      1    1        1    1       белый
      ------------------------------------------- Фиг. 8.10 Цвета
                               (Фирма IBM, приоритет 1981 г.)
 
      Если вы сравните байт атрибута для ЦГА с атрибутами для
    монохромного адаптера на Фиг. 8.7, то увидите, что они аналогичны.
    Конечно, вы не можете указать цвета монхромному адаптеру, но все
    остальное совпадает. Поскольку цветная плата не поддерживает
    атрибут подчеркивания, то установка монохромного атрибута
    подчеркивания соответствует голубому символу на черном фоне.
 
      Такая организация байта атрибутов является попыткой сделать два
    видео адаптера по-возможности совпадающими. Каждый символ в буфере
    дисплея находится по четному адресу, а байт атрибутов - по
    нечетному. Память цветного дисплея находится на видео адаптере, но
    по другому адресу: у монохромного дисплея она имеет адрес 0B0000H,
   а у цветного - 0B8000H. О сходстве дисплеев говорит то, что если
    при модификации программы для монохромного дисплея на Фиг. 8.8,
    изменить содержимое указателя AT сегмента на значение 0B800H,
    программа будет верно работать и на цветной плате. То есть одна и
    та же программа работает на любом видео адаптере при минимуме
    изменений.
 
      Для управления адаптером на цветной плате также используется
    контроллер ЭЛТ 6845 фирмы Motorola. Два порта ввода-вывода этого
    контроллера имеют адреса ввода-вывода 3D4H и 3D5H. На самом деле
    контроллер 6845 имеет 18 внутренних регистров. Доступ ко всем
    регистрам осуществляется с помощью двух портов ввода-вывода и
    косвенной адресации. Для обращения к регистру микросхемы 6845,
    нужно сначала загрузить индекс регистра в порт 3D4H, а затем читать
    этот регистр или записать в него данные через порт 3D5H.
 
      Приведем пример, чтобы пояснить, как работает контроллер. На
    Фиг. 8.11 перечислены все 18 регистров микросхемы 6845. В примере
    мы используем только регистры R10 и R11. Эти регистры определяют
    начальную и конечную строки растра одного знакоместа для курсора.
    Каждый символ, порождаемый цветной платой, состоит из восьми строк
    растра, имеющих номера от 0 до 7. Вы можете поместить курсор в
    любых из этих восьми строк. Регистр R10 сообщает микросхеме 6845,
    на какой строке начинается курсор, а регистр R11 определяет
    последнюю строку курсора. ROM BIOS инициализирует курсор,
    находящийся на строках 6 и 7; это делается загрузкой числа 6 в R10
    и числа 7 в R11.
 
      Прогамма на Фиг.8.12(а) модифицирует курсор цветной графической
    платы. Она смещает курсор так, что он оказывается на верхних пяти
    строках растра вместо нижних двух. Сначала программа загружает в
    индексный регистр контроллера 6845 (3D4H) число 10, а затем
    записывает номер начальной строки, равный 0, в регистр данных
    (3D5H). Затем, поместив 11 в индексный регистр, она устанавливает
    номер конечной строки равным 4. Теперь курсор имеет вид мигающего
    блока в верхней части позиции символа, а не митающего
    подчеркивания. Подобный этому способ модификации курсора
    используется несколькими редактирующими программами (редакторами)
    персональной ЭВМ, включая встроенный редактор интерпретатор языка
    Бейсик. При установке режима вставки во время редактирования,
    курсор становится жирнее; интерпретатор Бейсика делает это, меняя
    параметры в микросхеме 6845.
 
      Вернувшись к Фиг. 8.11, можно увидеть, что в микросхеме 6845
    есть и другие регистры. Большинство из них управляет сигналами
    горизонтальной и вертикальной синхронизации телевизионного растра.
    Вы можете модифицировать коды в этих регистрах для каких-либо
    действий дисплеем. Например, команда MODE системы DOS, которая
    может сдвигать катринку на экране влево и вправо, модифицирует
    регистр R2, задающий положение строчного синхроимпульса.
      Если вы захотите поэкспериментировать с этими регистрами, вам
    придется писать короткие программы, делающие требуемые изменения.
            ЪДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДВДДДДДДДДВДДДДДДДДї
            іРегистр і                    і Объект в  і          і            і
            і   # і    Регистр хранит          і программе і чтение і запись і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R0 і  Гориз. сумма        і Символ    і     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R1 і  Выводимая горизонталь     і Символ    і     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R2 і  Гориз. поз. синхронизации і Символ    і     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R3 і  Гориз. ширина синхронизации і Символ    і   Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R4 і  Вертикальный итог         і Симв. ряд і     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R5 і  Общая вертикальн.коррекция      іСкан.строкиі     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R6 і  Выводимая вертикаль       і Симв. ряд і     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R7 і  Поз. вертикальной синхрон.      і Симв. ряд і     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R8 і  Режим совмещения          і     -     і     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R9 і  Макс.адрес скан. строки   іСкан.строкиі     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R10      і  Начало курсора            іСкан.строкиі     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R11      і  Конец курсора       іСкан.строкиі     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R12      і  Начальный адрес (гориз.)  і     -     і     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R13      і  Начальный адрес (строка)  і     -     і     Нет  і      Да   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R14      і  Курсор (Гориз.)           і     -     і     Да   і      Да    і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R15      і  Курсор (Строка)           і     -     і     Да   і      Да    і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R16      і  Световое перо (гориз.)    і     -     і     Да   і      Нет   і
            ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
            і  R17      і  Световое перо(строка)     і     -     і     Да   і      Нет   і
            АДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДБДДДДДДДДБДДДДДДДДЩ

            Фиг. 8.11 Регистры микросхемы 6845
                 (с разрешения фирмы Motorola)
 
    Если попытаться изменять регистры с помощью утилиты DEBUG, то это
    может не сработать. Регистры R14 и R15 управляют позицией курсора,
    и если утилита DEBUG переместит курсор между вашими обращениями к
    индексному регистру и к регистру данных, изменения не произойдет.
    Так получилось потому, что утилита DEBUG изменила содержимое
    индексного регистра микросхемы 6845, и он уже больше не указывает
    на тот внутренний регистр, который вы хотели изменить.
 
      Другая интересная регистровая пара микросхемы 6845 - пара
    регистров начального адреса R12 и R13. Адаптер цветного
    графического дисплея имеет 16K байт памяти, а монохромная плата 4K
    байта. Дополнительная память в цветной плате используется для
    графических режимов, но она целиком в вашем распоряжении и в
    текстовых режимах. Для текстового режима 80*25 требуется 4K байта
    памяти, так что в буфере есть место для четырех разных страниц
    памяти. Сдвигать данные на экране можно переносом данных с одного
    места на другое, как это делалось на Фиг. 8.8. В случае же
    вертикального сдвига нужно лишь изменить начальный адрес в
    микросхеме 6845. Обычно начальный адрес равен 0. Если вы измените
    его на 80 (число символов в строке), отображение будет начинаться
    со второй строки. Это даст немедленный эффект сдвига всех данных
    экрана вверх на одну строку.
 
      На самом деле вы не изменяли данные, а сдвинули начало
    сканирования памяти дисплея. Можно рассматривать дисплей как окно
    80*25, через которое мы смотрим в 8192-символьный буфер дисплея.
 
      При использовании начального адреса для сдвига данных возникают
    сложности, когда вы приближаетесь к границе 16K байт. В этой точке
    отображение "заворачивается". Верхние строки извлекаются из конца
    буфера, а нижние строки - из его начала. Вы, конечно, сможете
    решить эту проблему, но для этого потребуются некоторые размышления
    и эксперименты.
 
    [Прим. перев.: стр. 252 текста оригинала в моей копии отсутствует.
    Очевидно, на ней находится только начало Фиг. 8.12]

           Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:05:31
           Фиг. 8.12 Программа управления цветным дисплеем        Page   1-1
 
                                         PAGE    ,132
                                         TITLE   Фиг. 8.12 Программа управления цветным дисплеем
 
            0000                   STACK   SEGMENT STACK
            0000  0040[                  DW      64 DUP (?)
                  ????
                              ]
            0080                   STACK   ENDS
 
            0000                   DISPLAY_BUFFER  SEGMENT AT 0B800H
            0000                   DISPLAY_START   LABEL   WORD
            0000                   DISPLAY_BUFFER  ENDS
 
            = 03D4                       CRT_INDEX         EQU     03D4H
            = 03D5                       CRT_DATA          EQU     03D5H
            = 03DA                       CRT_STATUS      EQU     03DAH
            = 000A                       CURSOR_START    EQU     10          ; Регистры управления курсором
            = 000B                       CURSOR_END      EQU     11          ;      в контроллере дисплея 6845
 
            0000                   CODE    SEGMENT
                                         ASSUME  CS:CODE
            0000                   COLOR_GRAPHICS  PROC    FAR
            0000  1E                           PUSH    DS              ; Адрес возврата в ДОС
            0001  2B C0                  SUB     AX, AX
            0003  50                           PUSH    AX
 
                   Фиг. 8.12 Программа управления цветным дисплеем (начало)
                                   ;-----  Фиг. 8.12 (а) Изменение курсора
 
            0004  BA 03D4                      MOV     DX, CRT_INDEX
            0007  B0 0A                  MOV     AL, CURSOR_START      ; Установка индексного регистра
            0009  EE                           OUT     DX, AL                ;      6845 на регистр начала курсора
            000A  42                           INC     DX
            000B  B0 00                  MOV     AL, 0
            000D  EE                           OUT     DX, AL                ; Установка начала курсора
 
            000E  4A                           DEC     DX
            000F  B0 0B                  MOV     AL, CURSOR_END
            0011  EE                           OUT     DX, AL                ; Выбор регистра конца курсора
            0012  42                           INC     DX
            0013  B0 04                  MOV     AL, 4
            0015  EE                           OUT     DX, AL                ; Установка конца курсора
 
                                   ;-----  Фиг. 8.12 (б) Использование регистра состояния 6845
 
            0016  B8 0002                      MOV     AX, 2
            0019  CD 10                  INT     10H             ; Выбор символьного режима 80*25
            001B  B8 ---- R                    MOV     AX, DISPLAY_BUFFER
            001E  8E C0                  MOV     ES, AX                ; Адрес буфера дисплейной памяти
            0020  B8 0720                      MOV     AX, 0720H             ; Вывод начинается с пробела
            0023                   NEXT_CHAR:
            0023  BF 0000                      MOV     DI, 0
            0026  B9 0050                      MOV     CX, 80
            0029  F3/ AB                       REP     STOSW                 ; Вывод строки из 80 символов
            002B  FE C0                  INC     AL              ; Следующий символ
            002D  75 F4                  JNZ     NEXT_CHAR
 
            002F  BB 0720                      MOV     BX, 0720H
            0032                   NEXT_CHAR_1:
            0032  B9 0050                      MOV     CX, 80
            0035  BF 0000                      MOV     DI, 0
            0038  BA 03DA                      MOV     DX, CRT_STATUS        ; Порт состояния для адаптера
                                                                 ; цветного дисплея
            003B                   WAIT_NO_RETRACE:
            003B  EC                           IN      AL, DX                ; Проверка на обратный ход луча
            003C  A8 01                  TEST    AL, 1
            003E  75 FB                  JNZ     WAIT_NO_RETRACE       ; Запрещение прерываний
            0040  FA                           CLI
            0041                   WAIT_RETRACE:
            0041  EC                           IN      AL, DX
            0042  A8 01                  TEST    AL, 1
            0044  74 FB                  JZ      WAIT_RETRACE          ; Ожидание обратного хода луча
            0046  8B C3                  MOV     AX, BX                ; Выборка символа
            0048  AB                           STOSW                   ; Занесение в дисплейный буфер
            0049  FB                           STI                     ; Разрешение прерываний
            004A  E2 EF                  LOOP    WAIT_NO_RETRACE
            004C  FE C3                  INC     BL
            004E  75 E2                  JNZ     NEXT_CHAR_1
 
                                   ;-----  Фиг. 8.12 (в) Вывод линии по диагонали
 
                  Фиг. 8.12 Программа управления цветным дисплеем (продолжение)
            0050  B8 0004                      MOV     AX, 4
            0053  CD 10                  INT     10H             ; Установка графического
                                                                 ;      режима 320*200
            0055  06                           PUSH    ES
            0056  1F                           POP     DS
            0057  B3 32                  MOV     BL, 50                ; Число групп строк
            0059  B1 02                  MOV     CL, 2                 ; Счетчик сдвига
            005B  BF 0000                      MOV     DI, 0
            005E                   DOT_LOOP:
            005E  B0 C0                  MOV     AL, 0C0H              ; В AL маска первой точки в байте
            0060  88 05                  MOV     [DI], AL
            0062  81 C7 2000                   ADD     DI, 2000H             ; Переключение на нечетную строку
            0066  D2 E8                  SHR     AL, CL                ; Сдвиг до следующей точки в байте
            0068  88 05                  MOV     [DI], AL
            006A  81 EF 1FB0                   SUB     DI, 2000H-80          ; Переключение на четную строку
            006E  D2 E8                  SHR     AL, CL
            0070  88 05                  MOV     [DI], AL
            0072  81 C7 2000                   ADD     DI, 2000H             ; Переключение на нечетную строку
            0076  D2 E8                  SHR     AL, CL
            0078  88 05                  MOV     [DI], AL
            007A  81 EF 1FAF                   SUB     DI, 2000H-81          ; Переключение на четную строку,
            007E  FE CB                  DEC     BL              ;      следующий байт
            0080  75 DC                  JNZ     DOT_LOOP
 
                                   ;-----  Возврат к символьному режиму 80*25
 
            0082  B8 0002                      MOV     AX, 2
            0085  CD 10                  INT     10H
            0087  CB                           RET
            0088                   COLOR_GRAPHICS  ENDP
            0088                   CODE    ENDS
                                         END
 
           Фиг. 8.12 Программа управления цветным дисплеем (продолжение)
 
      Цветной графический адаптер имеет еще три регистра ввода-
    вывода. Регистр режима находится по адресу ввода-вывода 03D8H. Этот
    регистр устанавливает аппаратные переключатели различных режимов
    отображения. Например, вы можете установить бит 5 этого регистра в
    "0" и получить 16 цветов фона в текстовых режимах, а установка бита
    5 в "1" переключает 7-й бит атрибута на функцию мигания. Полное
    описание структуры этого регистра, и всех других, дано в
    техническом описании.
 
      Регистр выбора цвета находится по адресу ввода-вывода 03D8H.
    Этот регистр устанавливает цвет окаймления в текстовых режимах.
    Поскольку сам по себе текст не занимает весь экран, текст можно
    окружить каким-либо выбираемым цветом. Кроме того, регистр выбора
    цвета может управлять выбором палитр в графических режимов, как мы
    увидим в следующем разделе. Младшие 4 бита этого регистра
    устанавливают для окаймления один из 16 цветов, перечисленных на
    Фиг. 8.10.
 
      И наконец, регистр состояния по адресу ввода-вывода 3DAH
    организует информационную обратную связь между цветной платой и
    программой. Например, программа может использовать этот регистр для
    определения текущего состояния светового пера, если оно подключено
    к системе. Более важным является то, что регистр состояния
    сообщает, когда безопасно читать или записывать данные в дисплейный
    буфер.
 
      Не вдаваясь в технические детали, заметим, что чтение или
    запись данных в буфер дисплея цветной платы может вызвать "снег" на
    экране, если вы будете это делать в неподходящие моменты времени.
    Это случается только в текстовом режиме с высоким разрешением
    80*25. Вспомните, что ранее приводился пример на Фиг. 8.12, в
    котором постоянно записывались данные в буфер дисплея. Если для
    этого примера использовать цветную плату, на экране появится масса
    помех. Чтобы избежать этого, можно использовать регистр
    состояния.
 
      Существуют моменты, когда можно безопасно работать с данными в
    буфере дисплея. В такие моменты бит 0 регистра состояния равен 1.
    Нужно подождать, когда бит 0 станет равным 1, а затем читать или
    записывать данные. На Фиг. 8.12б изображена программа, которая
    записывает символ на экран дисплея. Первые строки этой программы
    записывают данные в буфер, не используя регистр состояния. Эта
    часть программы 224 раза записывает 80 симвлов в первую строку
    буфера, что эквивалентно заполнению экрана около девяти раз. Когда
    вы запустите программу, то увидите короткую вспышку помех в тот
    момент, когда будут записываться данные.
 
      Вторая часть программы на Фиг. 8.12б повторяет те же действия,
    но на этот раз проверяя бит состояния. Обратите внимание, что эта
    часть программы проверяет бит состояния двумя различными способами.
    Сначала она ждет, пока бит состояния не станет равным 0. Затем, как
    только он станет равен 1, программа записывает данные. Так сделано
    потому, что интервал, в течение которого можно записывать данные,
    очень мал, и если бы программа делала проверку только на равенство
    1, она могла бы захватить бит состояния непосредственно перед его
    обращением в 0. В этом случае, чтобы избежать помех, микропроцессор
    уже не может записывать данные достаточно быстро, но такая
    организация цикла гарантирует, что бит состояния захватывается в
    первый же момент, когда он становится равным 1.
 
      Используя бит состояния, вы уже не увидите на экране никаких
    помех, но и заметите, что выполнение программы стало гораздо
    медленнее. Выполняться медленнее программу заставляет
    дополнительное время, затрачиваемое на ожидание бита состояния.
    Если вам нужно записать на экране много данных - например,
    организовать горизонтальный сдвиг, как на Фиг. 8.8, то потребуется
    другой способ. Простейший способ - сбросить в нуль разряд
    отображения в регистре режима. Бит 3 регистра режима (3D8H)
    управляет отображением на дисплее. Если сбросить этот бит в 0,
    экран погаснет. Чтобы переслать много данных в буфер цветного
    дисплея, вы можете выключить отображение и переслать данные без
    проверки бита состояния. Поскольку отображение выключено, на экране
    не возникнут помехи. Когда пересылка блока закончится, включите
    отображение. Вы заметите короткое мигание изображения в момент его
    выключения и включения. Фирма IBM использует этот метод для
    обслуживания вертикального сдвига цветного дисплея.

Графический режим


    Цветной графический адаптер имеет два режима отображения, в которых
    можно управлять отдельными точками экрана. Эти режимы называются
    режимами Полной Адресации точек (APA: All Points Addressable),
    поскольку с помощью этих режимов можно адресовать и изменять все
    точки. В действительности цветная плата допускает более двух
    режимов APA, но мы рассмотрим только те два, которые поддерживаются
    системой программирования. Используя информацию из технического
    описания, вы можете попробовать и другие режимы.
 
      Графический режим среднего разрешения обеспечивает вывод
    изображения из 320 точек и 200 строк растра. Каждая из этих точек
    может иметь один из четырех цветов. Это означает, что для каждой
    точки требуется для представления цвета 2 бита. В каждом байте
    графической памяти помещается четыре точки или пиксела (от англ.
    picture element - графический элемент, которые называют также
    "пелами"). Если вы умножите горизонтальный размер на вертикальный,
    а затем разделите на 4 - число точек в байте, то увидите, что в
    режиме среднего разрешения требуется 16000 байт. Именно поэтому
    цветная плата имеет память объемом 16K.
 
      На Фиг. 8.13 показано расположение элементов в каждом байте.
    Пара бит с номерами 6 и 7 отображается первой точкой (0), а биты 0
    и 1 представляют последнюю точку (3), отображаемую из этого байта.
    В   первых 80 байтах графической памяти содержится 320 точек
    строки растра 0, т.е. первой строки экрана.
 
         7   6     5    4     3   2      1   0
      ЪДДДДДДДДДВДДДДДДДДДВДДДДДДДДДВДДДДДДДДДї
      і       і       і       і     і
      і точка 0 і точка 1 і точка 2 і точка 3 і
      і    і        і    і    і     і    і    і      і
      АДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДЩ
 
            Фиг. 8.13 Битовая структура для графики 320*200
 
      Но байт 80 уже не содержит первые четыре точки строки 1. По
    причинам, которые объясняются конструкцией аппаратуры, четные и
    нечетные строки хранятся в разных концах графической памяти. Все
    нечетные строки имеют смещение 2000H байт от соответствующих четных
    строк. Поэтому строка 1 лежит в байтах от 2000H до 204FH. Строка 2
    - четная и находится по адресам от байта 50H до 9FH; строка 3
    находится по адресам от 2050H до 209FH, и так далее.
 
      На Фиг. 8.12в изображена программа, которая иллюстрирует
    структуру графической памяти. Эта программа рисует диагональную
    линию на дисплее 320*200. Линия начинается в точке (0, 0), верхнем
    левом углу, и идет до точки (199, 199), в самый низ и слегка правее
    центра. Первая часть программы вводит дисплей в режим APA среднего
    разрешения с помощью вызова программы BIOS. В следующей главе
    рассматривается, как это делается.
      В программе регистр DI используется в качестве указателя
    нужного байта в буфере дисплея. В целом программа выводит 200
    точек. В регистр BL загружается число 50, так как внутренний цикл
    пишет по четыре точки за одну итерацию. В регистр CL заносится 2 -
    значение счетчика переключений. Цикл заносит в регистр AL код 0C0H,
    что устанавливает старшие два бита на цвет 3; остальные три точки
    байта имеют цвет 0, т.е. цвет фона. После записи этого байта
    регистр AL сдвигается вправо на 2 бита, и теперь активизируется
    вторая точка байта. Прибавление значения 2000H к содержимому
    регистра DI смещает указатель на нечетную строку. Третья точка
    снова получается сдвигом регистра AL и вычитанием числа (2000H -
    80) из содержимого регистра DI. Это возвращает регистр DI назад в
    четную строку, но уже на следующие 80 байт. Наконец, после записи
    четвертого байта, регистр DI снова возвращается в четное поле, но
    еще и увеличивается, смещаясь тем самым на следующий байт строки
    растра. В примере цикл работает с четырьмя байтами, так как на
    каждый байт приходится четыре элемента.

Цвета в режиме APA 320*200


    А теперь рассмотрим цвета, которые можно получить в графическом
    режиме среднего разрешения. Так как точке отведено два бита, для
    нее можно указать один из четырех цветов. Цвет 0 (00B) - это цвет
    фона. В качестве этого цвета можно выбрать любой из 16 цветов,
    показанных на Фиг. 8.10, записав соответствующее 4-битовое значение
    в регистр выбора цвета (3D9H). Остальные три цвета определены
    фирмой IBM: вы не можете выбирать произвольно цвета 1, 2 и 3. Фирма
    IBM определила две различные палитры цветов, они показаны на Фиг.
    8.14. Палитру можно выбрать, устанавливая бит 5 регистра выбора
    цвета.
 
      Как показано на Фиг. 8.14, если сбросить бит 5 в 0, получатся
    цвета зеленый, красный и желтый вместе с выбранным цветом фона.
    Установка бита 5 равным 1 дает голубой, пурпурный и белый. Вы также
    можете модифицировать палитру и другим битом регистра выбора цвета.
    Установка бита 4 равным 1 делает цвета палитры более яркими.
    Программы инициализации BIOS обычно загружают в регистр выбора
    цвета значение 30H. Это соостветствует черному цвету фона (0) и и
    яркой палитре 1.
 
      Значение цвета    Палитра 0 цвета  Палитра 1 цвета
      --------------------------------------------------
       1 (01B)    Зеленый      Голубой
       2 (10B)    Красный      Фиолетовый
       3 (11B)    Желтый            Белый
                  бит 5 = 0   бит 5 = 1
      --------------------------------------------------
 
                              Фиг. 8.14 Цветные палитры
                                   для графики 320*200

Графика высокого разрешения


    Другой режим APA дает 640 точек в строке растра и 200 строк. В этом
    режиме каждая точка соответствует одному биту. Если этот бит
    содержит 0, точка черная. Если этот бит содержит 1, точка цветная;
    цвет выбирается с помощью регистра выбора цвета. Обычно этот
    регистр содержит значение 1111B (белый), давая черно-белую
    картинку. Вы можете выбрать любой другой цвет.
 
      Отображение элементов почти идентично графическому режиму
    нормального разрешения. Отличие заключается в том, что в байте
    содержится восемь точек. Старший значащий бит (бит 7) выводится
    первым, а бит 0 - последним. Здесь также строка содержит 80 байт;
    так же, как и при нормальном разрешении, четные строки находятся в
    начеле буфера дисплея, а нечетные - по адресу 2000H.

Адаптер параллельного принтера


    Чтобы подключить печатающее устройство фирмы IBM или любое другое,
    которое подключается через параллельный интерфейса, вам нужен
    адаптер параллельного печатающего устройства (принтера). Этот
    адаптер встроен в адаптер монохромного дисплея и принтера. Если вы
    используете адаптер цветного графического монитора, то нужен
    отдельный адаптер принтера. С точки зрения интерфейса с печатающим
    устройством, эти два адаптера идентичны, за исключением адресов
    ввода-вывода. Порты принтера на монохромной плате имеют адреса от
    3BCH до 3BEH, а отдельная плата принтера имеет адреса от 378H до
    37AH.
 
      Адаптер принтера имеет два выводных порта и один порт ввода.
    Этот адаптер очень похож на микросхему 8255, используемую для
    интерфейса клавиатуры. Фактически, сначала в конструкции платы
    печатающего устройства использовалась микросхема 8255. Но фирма IBM
    решила лучше делать адаптеры с раздельными компонентами.
      Выводной 8-битовый порт данных по адресу 3BCH или 378H передает
    данные принтеру. Адаптер посылает символьный код ASCII, помещаемый
    в   этот порт, прямо в принтер. Второй порт вывода, расположенный
    по адресам 3BEH или 37AH, имеет 5 выводных бит. В нем содержатся
    управляющие сигналы для принтера; эти линии управляют его работой и
    инициализацией. В частности, бит 0 инициирует передачу данных в
    принтер. Простая запись данных в порт вывода данных не означает
    пересылку символа на принтер. Для того, чтобы в него поступил
    символ, нужно установить бит строба (бит 0 порта 3BEH или 37AH)
    равным 1, а затем снова сбросить на 0. На Фиг. 8.15 показана
    короткая программа, передающая печатающему устройству строку
    символов. Подпрограмма с именем PRINT обеспечивает сам процесс
    передачи данных в принтер.
      Обратите внимание, что процедура PRINT читает код из вводного
    порта (3BCH или 379H). Этот порт возвращает информацию состояния
    печатающего устройства программе. В данном примере программа
    проверяет состояние, чтобы выводить следующий символ именно тогда,
    когда принтер готов его принять. Бит 7 состояния порта ввода
    показывает занятость принтера. Если этот бит содержит 1, печатающее
    устройство готово принимать следующий символ для печати. В
    противном случае программа должна подождать. Остальные 4 вводных
    бита этого порта отражают возможные ошибки на печатающем
    устройстве, например, отсутствие бумаги. Наш пример не контролирует
    эти ситуации. Техническое описание содержит структуры вводных и
    выводных портов платы адаптера печатающего устройства.
             Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:05:39
             Фиг. 8.15 Вывод на принтер                          Page     1-1
 
                                           PAGE ,132
                                           TITLE      Фиг. 8.15 Вывод на принтер
 
              0000                        STACK      SEGMENT STACK
              0000      0040[                   DW   64 DUP (?)
                      ????
                                ]
              0080                        STACK      ENDS
 
              = 0378                BASE EQU  378H
 
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE
 
              0000      94 A8 A3 2E 20 38 2E    MSG  DB   'Фиг. 8.15', 13, 10, '$'
                  31 35 0D 0A 24
              000C                        MAIN PROC FAR
              000C      1E                      PUSH DS         ; Адрес возврата
              000D      2B C0                   SUB  AX, AX
              000F      50                      PUSH AX
 
              0010      8D 1E 0000 R                  LEA  BX, MSG
              0014                        PRINT_LOOP:
              0014      2E: 8A 07               MOV  AL, CS:[BX]      ; Выбор символа из строки для вывода
              0017      3C 24                   CMP  AL, '$'         ; Конец строки?
              0019      74 06                   JE   MAIN_RETURN
              001B      E8 0022 R               CALL PRINT            ; Печать символа
              001E      43                      INC  BX
              001F      EB F3                   JMP  PRINT_LOOP ; Переход к следующему символу
              0021                        MAIN_RETURN:
              0021      CB                      RET
              0022                        MAIN ENDP
 
                                     ;-----  Эта подпрограмма печатает символ в регистр AL
 
              0022                        PRINT      PROC NEAR
              0022      BA 0378                  MOV  DX, BASE   ; Порт вывода данных на принтер
              0025      EE                      OUT  DX, AL      ; Занесение символа в порт вывода на принтер
              0026      42                      INC  DX         ; Адрес порта состояния принтера
              0027                        WAIT_BUSY:
              0027      EC                      IN   AL, DX      ; Опрос состояния принтера
              0028      A8 80                   TEST AL, 80H    ; Проверка разряда занятости принтера
              002A      74 FB                   JZ   WAIT_BUSY  ; Цикл до освобождения принтера
              002C      42                      INC  DX
              002D      B0 0D                   MOV  AL, 0DH    ; Установка разряда готовности данных
              002F      EE                      OUT  DX, AL
              0030      B0 0C                   MOV  AL, 0CH    ; Сброс разряда готовности данных
              0032      EE                      OUT  DX, AL
              0033      C3                      RET
              0034                        PRINT      ENDP
              0034                        CODE ENDS
                                           END  MAIN
 
                  Фиг. 8.15 Вывод на принтер
      Один из управляющих битов порта 3BEH (или 37AH) управляет
    линией прерывания от печатающего устройства. Для того, чтобы
    печатающее устройство могло посылать свой сигнал прерывания в
    контроллер 8259, этот бит нужно установить равным 1. Однако адаптер
    печатающего устройства выдает неверный сигнал прерывания, т.е.
    выбранный для этой цели сигнал не вызывает правильного прерывания.
    Поэтому не стоит и пытаться писать программу, которая бы
    использовала возможности прерывания от адаптера печатающего
    устройства (если вы не захотите физически изменить плату
    печатающего устройства). Далее мы приведем пример, который обходит
    эту проблему с помощью системного таймера.

Адаптер синхронных коммуникаций


      Адаптер асинхронных коммуникаций дает возможность связываться с
    IBM PC по последовательному интерфейсу. Этот адаптер дает
    возможность связываться с другими ЭВМ, службами баз данных, а также
    с другими источниками информации. Мы не будем обсуждать принципы
    работы этого канала, а поговорим о методах программирования этого
    конкретного адаптера IBM PC.
 
      Интегральная микросхема коммуникаций проделывает всю работу по
    приему и передаче символов по асинхронной линии. Элемент
    асинхронной связи ACE (Asynchronous Communication Element) 8250
    можно запрограммировать для управления самыми различными аспектами
    связи. При инициализации элемента ACE под пограммным контролем
    оказываются размер символа, частота передачи, символы останова и
    биты четности. Адаптер также позволяет проверять и задавать
    стандартные сигналы управления модемом (модулятора -
    демодулятора).
 
      С помощью элемента ACE символ передается просто посредством его
    записи в регистр передачи. Микросхема далее выполняет все, что
    соответствует кодам, которые вы передали ей при инициализации.
    Чтобы принять символ, вы просто читаете его из буфера приема.
    Существует регистр состояния, называемый регистром состояния линии,
    который показывает, когда буфер передачи пуст и может принять
    другой символ. Другой бит регистра состояния сообщает, когда
    элемент ACE уже принял символ из другой системы.
 
      В техническом описании приводятся и другие регистры, входящие в
    элемент ACE 8250. Эти регистры дают возможность управления модемом
    и определения его состояния. Вы также можете разрешить выработку
    прерывания при возникновении в элементе ACE различных условий. Это
    позволяет вашей программе быстро реагировать на любую смену внешних
    условий. east-font-family:"MS Mincho"'>
Программа на Фиг. 8.16 демонстрирует основные механизмы,
    необходимые для инициирования элемента ACE, посылки и приема
    символа. Базовый адрес ввода-вывода платы адаптера равен 3F8H, так
    что регистры элемента ACE расположены по адресам от 3F8H до 3FEH.
    Можно также модифицировать адаптер асинхронной связи фирмы IBM так,
    чтобы его регистры соответствовали адресам ввода-вывода от 2F8H до
    2FEH. С помощью такой модификации можно установить в персональную
    ЭВМ второй адаптер и связаться с двумя различными внешними
    устройствами. Фактически, можно подключить печатающее устройство к
    системе с помощью последовательного, а не параллельного сопряжения.
    В этом случае нужны два адаптера: один из них работает с печатающим
    устройством, а другой обслуживает внешние связи.
 
      Один из портов ввода-вывода элемента ACE выполняет несколько
    функций. Оба буфера, передачи и приема, находятся по адресу 3F8H,
    так что когда что-либо записывается по этому адресу, информация
    попадает в буфер передачи, но при чтении по этому адресу, вы
    получаете последний символ, принятый микросхемой ACE. Этот же порт
    ввода-вывода выполняет и третью функцию. Значение делителя,
    определяющее скорость работы адаптера, записывается в этот порт
    ввода-вывода. Микросхема ACE делит входную частоту на число,
    помещенное в регистр делителя, позволяя тем самым выбрать скорость
    от 50 до 9600 бод. Режим использования порта 3F8H задает один из
    битов управляющего регистра.

             Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:05:45
             Фиг. 8.16 Управление последовательным каналом             Page     1-1
 
 
                                           PAGE ,132
                                           TITLE      Фиг. 8.16 Управление последовательным каналом
 
              0000                        STACK      SEGMENT STACK
              0000      0040[                   DW   64 DUP (?)
                      ????
                                ]
              0080                        STACK      ENDS
 
              = 03F8                SERIAL  EQU      03F8H
 
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE
              0000                        ASYNC      PROC FAR
              0000      1E                      PUSH DS         ; Адрес возврата в ДОС
              0001      2B C0                   SUB  AX,AX
              0003      50                      PUSH AX
              0004      BA 03FB                  MOV  DX,SERIAL+3      ; Управляющий регистр
              0007      B0 80                   MOV  AL,80H
              0009      EE                      OUT  DX,AL            ; Настройка на установку скорости
              000A      B8 0180                  MOV  AX,384     ; Делитель частоты для скорости 300 бод
              000D      BA 03F8                  MOV  DX,SERIAL
              0010      EE                      OUT  DX,AL            ; Младшая часть делителя
              0011      8A C4                   MOV  AL,AH
 
                  Фиг. 8.16 Управление последовательным каналом (начало)
              0013      42                      INC  DX
              0014      EE                      OUT  DX,AL            ; Старшая часть делителя
              0015      BA 03FB                  MOV  DX,SERIAL+3      ; Управляющий регистр
              0018      B0 03                   MOV  AL,00000011b     ; Режим без проверки на четность,8 бит
              001A      EE                      OUT  DX,AL
 
                                     ;-----  Вывод символа в канал
 
              001B      BA 03FD                  MOV  DX,SERIAL+5      ; Регистр состояния канала
              001E                        SEND:
              001E      EC                      IN   AL,DX
              001F      A8 20                   TEST AL,20H
              0021      74 FB                   JZ   SEND
              0023      B0 41                   MOV  AL,'A'
              0025      BA 03F8                  MOV  DX,SERIAL
              0028      EE                      OUT  DX,AL
 
                                     ;-----  Прием символа
 
              0029      BA 03FD                  MOV  DX,SERIAL+5      ; Регистр состояния канала
              002C                        RECV:
              002C      EC                      IN   AL,DX
              002D      A8 02                   TEST AL,2
              002F      74 FB                   JZ   RECV
              0031      BA 03F8                  MOV  DX,SERIAL
              0034      EC                      IN   AL,DX
 
              0035      CB                      RET
              0036                        ASYNC      ENDP
              0036                        CODE ENDS
                                           END  ASYNC
 
      Фиг.8.16 Установка, пересылка и получение данных по
                      асинхронному каналу (продолжение)
 
      Первая часть программы примера инициализирует микросхему ACE
    8250. Первым делом программа настраивает скорость работы адаптера.
    Значение делителя, равное 384, устанавливает скорость 300 бод.
    Обратите внимание, что перед записью значения делителя программа
    заносит 1 в бит 7 управляющего регистра по адресу 3FBH.
    Окончательный вывод в порт 3FBH задает характеристики линии. В этом

             Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:05:50
             Фиг. 8.17 Обработка прерываний от последовательного канала  Page     1-1
 
 
                                           PAGE ,132
                                           TITLE      Фиг. 8.17 Обработка прерываний от последовательного канала
 
              0000                        ABS0 SEGMENT AT 0
              002C                              ORG  0BH*4
              002C                        ASYNC_INTERRUPT LABEL  WORD
              002C                        ABS0 ENDS
 
              0000                        STACK      SEGMENT STACK
 
                  Фиг. 8.17 Обработка прерываний от последовательного канала (начало)
              0000      0040[                   DW   64 DUP (?)
                      ????
                                ]
              0080                        STACK      ENDS
 
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE
              0000      0049 R                  BUFFER_POINTER  DW     BUFFER
 
              0002                        SET_INTERRUPT    PROC FAR
              0002      2B C0                   SUB  AX,AX
              0004      8E D8                   MOV  DS,AX
                                           ASSUME  DS:ABS0  ; Адресация по сегментному регистру DS
                                                             ;  в область векторов прерываний
                                     ;-----  Установка прерывания
              0006      C7 06 002C R 0024 R           MOV  ASYNC_INTERRUPT,offset INT_HANDLER
              000C      8C 0E 002C R                  MOV  ASYNC_INTERRUPT,CS     ; Занесение вектора прерывания
 
              0010      BA 03F9                  MOV  DX,03F9H   ; Регистр разрешения прерываний
              0013      B0 04                   MOV  AL,04H     ; Прерывание по приему из канала
              0015      EE                      OUT  DX,AL
 
              0016      E4 21                   IN   AL,21H     ; Регистр маски прерываний 8259
              0018      24 F7                   AND  AL,0F7H    ; Занесение 0 в разряд 3
              001A      E6 21                   OUT  21H,AL     ; Прерывание не маскируется
 
              001C      BA 03FC                  MOV  DX,3FCH    ; Регистр управления модемом
              001F      B0 08                   MOV  AL,08H     ; разряд OUT2
              0021      EE                      OUT  DX,AL
 
              0022      EB FE             HERE:      JMP  HERE       ; Конец задания режима работы последователь-
              0024                        SET_INTERRUPT    ENDP       ;  ного канала,ожидание прерывания
 
                                     ;-----  Программа обработки прерываний от последовательного канала по приему
 
              0024                        INT_HANDLER      PROC FAR
              0024      50                      PUSH AX         ; Сохрание используемых регистров
              0025      53                      PUSH BX
              0026      52                      PUSH DX
              0027      BA 03FD                  MOV  DX,3FDH    ; Регистр состояния канала
              002A      EC                      IN   AL,DX
              002B      A8 01                   TEST AL,01H     ; Был ли получен символ?
              002D      74 12                   JZ   INT_RETURN ; Нет,возврат из прерывания
              002F      BA 03F8                  MOV  DX,3F8H    ; Регистр приема данных
              0032      EC                      IN   AL,DX            ; Выбор символа из канала
              0033      2E: 8B 1E 0000 R        MOV  BX,BUFFER_POINTER
              0038      2E: 88 07               MOV  CS:[BX],AL ; Сохранение в буфере
              003B      43                      INC  BX
              003C      2E: 89 1E 0000 R        MOV  BUFFER_POINTER,BX
              0041                        INT_RETURN:
              0041      5A                      POP  DX         ; Восстановление регистров
              0042      5B                      POP  BX
              0043      B0 20                   MOV  AL,20H     ; Сброс контроллера прерываний
 
             Фиг. 8.17 Обработка прерываний от последовательного канала  (продолжение)
              0045      E6 20                   OUT  20H,AL
              0047      58                      POP  AX
              0048      CF                      IRET             ; Возврат из прерывания
              0049                        INT_HANDLER      ENDP
              0049      0080[             BUFFER  DB 128 DUP (?)
                       ??
                                ]
 
 
              00C9                        CODE ENDS
                                           END  SET_INTERRUPT
 
            Фиг. 8.17 Асинхронные прерывания (окончание)
 
      Оставшиеся две части примера посылают и принимают символ. В
    регистре состояния линии по адресу ввода-вывода 3FDH есть биты
    состояния буферов передачи и приема. Посылать символ до тех пор,
    пока буфер передачи не опустеет, нельзя; и естественно, нельзя
    читать символ до того, как он принят.
 
      Адаптер асинхронной связи также работает с прерываниями. Сигнал
    OUT2 в регистре управления модемом передает сигнал прерывания от
    микросхемы ACE системе. Регистр разрешения прерываний в микросхеме
    ACE выбирает те возможные изменения состояний, которые приведут к
    возбуждению внешнего прерывания. Адаптер асинхронной связи
    возбуждает прерывание уровня 3 контроллера прерываний 8259.
 
      Давайте посмотрим, как можно использовать прерывание от
    асинхронной платы для того, чтобы принимать символы. На Фиг. 8.17
    показана последовательность событий, необходимых для включения
    системы прерываний. В случае аппаратного прерывания, программа
    устанавливает вектор прерывания, соответствующий уровню 3
    контроллера 8259 (прерывание 0BH по адресу 58H), на адрес процедуры
    обслуживания прерывания. Затем она сбрасывает бит регистра маски,
    соответствующий прерыванию от платы связи. В микросхеме ACE 8250
    программа загружает регистр разрешения прерывания так, чтобы
    разрешить прерывания по состоянию приемной линии. И наконец,
    программа включает линию OUT2, чтобы в систему поступали
    прерывания. Когда все это работает, не возникает никаких проблем о
    бработке символов по мере их получения системой. Программа на Фиг.
    8.17 помещает эти символы в буфер, где их может не торопясь
    просматривать другая программа.

Адаптер управления играми


    Адаптер управления играми подключает к системе джойстики и другие
    органы управления игрой. Это все аналоговые устройства - т.е., они
    не могут работать с нулями и единицами. Их входные значения - это
    сопротивление, которое ЭВМ не может прочитать непосредственно.
    Адаптер управления играми преобразует значение сопротивления в
    нечто такое, с чем ЭВМ может иметь дело.
 
      Адаптер управления играми не преобразует значение сопротивления
    непосредственно в двоичное число. Вместо этого адаптер преобразует
    значение сопротивления во временную задержку. Чем больше
    сопротивление, тем больше временная задержка. Эту задержку
    компьютер может измерить. Преобразовать задержку в число,
    соответствующее положению джойстика, можно программным способом.
    Нашей задачей является написание программы, которая преобразует
    временную задержку в число.
 
      Адаптер управления играми обслуживает до четырех входов
    сопротивления. Механизм временной задержки по каждому из этих
    входов подключен к отдельному биту порта ввода-вывода 201H. Когда
    вы выводите любое число в порт 201H, четыре его младших бита
    сбрасываются в 0. Биты возвращаются в состояние 1 после некоторго
    интервала времени. Этот интервал времени определяется значением
    сопротивления, подключенного к адаптеру. Программа на Фиг. 8.18 -
    это пример определения значения сопротивления двух из четырех
    входных портов. Эта программа использует простой метод. Вместо
    определения временной задержки всех четырех портов одновременно,
    она обслуживает их последовательно. Количество времени, нужного для
    определения одной задержки, невелико. В результате, поочередная
    обработка этих задержек вместо одновременной выполняется без
    проблем.

             Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:05:57
             Фиг. 8.18 Адаптер управления играми                       Page     1-1
 
                                           PAGE ,132
                                           TITLE      Фиг. 8.18 Адаптер управления играми
 
              = 0201                GAME_PORT  EQU  201H
 
              0000                        STACK      SEGMENT STACK
              0000      0040[                   DW   64 DUP (?)
                      ????
                                ]
              0080                        STACK      ENDS
 
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE
              0000                        GAME_CONTROL     PROC FAR
              0000      1E                      PUSH DS         ; Адрес возврата
              0001      2B C0                   SUB  AX, AX
              0003      50                      PUSH AX
              0004      BA 0201                  MOV  DX, GAME_PORT
              0007      B8 B000                  MOV  AX, 0B000H ; Сегмент дисплейной памяти
              000A      8E D8                   MOV  DS, AX
 
              000C      B5 21                   MOV  CH, 21H    ; Символ, который будет записываться в буфер
              000E      B1 00                   MOV  CL, 0
              0010                        WRITE_LOOP:
              0010      B4 01                   MOV  AH, 1            ; Выбор координаты X
              0012      E8 0042 R               CALL POSITION
              0015      8B D8                   MOV  BX, AX      ; Сохранение координаты X в буфере
              0017      D1 EB                   SHR  BX, 1
              0019      D1 EB                   SHR  BX, 1            ; Деление на 4
 
                         Фиг. 8.18 Адаптер управления играми (начало)
              001B      B4 02                   MOV  AH, 2            ; Выбор координаты Y
              001D      E8 0042 R               CALL POSITION
              0020      D0 E8                   SHR  AL, 1
              0022      D0 E8                   SHR  AL, 1
              0024      D0 E8                   SHR  AL, 1
              0026      D0 E8                   SHR  AL, 1            ; Деление на 16
              0028      B4 A0                   MOV  AH, 160
              002A      F6 E4                   MUL  AH         ; Преобразование в смещение в буфере
              002C      03 D8                   ADD  BX, AX
              002E      88 2F                   MOV  [BX], CH   ; Сохранение символа
              0030      EC                      IN   AL, DX
              0031      24 10                   AND  AL, 10H
              0033      3A C1                   CMP  AL, CL
              0035      74 D9                   JE   WRITE_LOOP
              0037      8A C8                   MOV  CL, AL
              0039      80 F9 10                CMP  CL, 10H
              003C      75 D2                   JNE  WRITE_LOOP
              003E      FE C5                   INC  CH         ; Следующий символ
              0040      EB CE                   JMP  WRITE_LOOP
 
              0042                        GAME_CONTROL     ENDP
 
                                     ;-----  В AH бит маски
 
              0042                        POSITION   PROC NEAR
              0042      51                      PUSH CX
              0043      2B C9                   SUB  CX, CX      ; Начальное значение для цикла ввода
              0045      EE                      OUT  DX, AL      ; Запуск таймера
              0046                        POS_LOOP:
              0046      EC                      IN   AL, DX
              0047      84 C4                   TEST AL, AH
              0049      E0 FB                   LOOPNE  POS_LOOP ; Цикл пока 1 - таймер не закончил отсчет
              004B      B8 0000                  MOV  AX, 0
              004E      2B C1                   SUB  AX, CX      ; Определение значения счетчика
              0050      59                      POP  CX         ;  в диапазоне 0-255
              0051      C3                      RET
              0052                        POSITION   ENDP
              0052                        CODE ENDS
                                           END
 
                Фиг. 8.18 Адаптер управления играми (продолжение)
 
      Последняя часть программы на Фиг. 8.18 берет позицию X-Y,
    определенную по входу от джойстика, и записывает символ в
    соответствующую позицию дисплея. Адаптер управления играми также
    допускает четыре переключающих ввода, значения которых можно
    прочитать в старших четырех битах порта 201H. Программа в примере
    опрашивает один из этих битов переключения, чтобы перейти от одного
    символа к другому и вывести его на экран.

Адаптер дисковода


      Адаптер дисковода является интерфейсом между микропроцессором и
    накопителем на гибких магнитных дисках. Схемы, смонтированные на
    плате этого адаптера, обеспечивают все функции, необходимые для
    ввода и вывода данных на гибкий диск (дискету). Адаптер
    обеспечивает также физическое кодирование и декодирование данных,
    необходимое для использования дискет.
 
      Центральной частью адаптера дисковода фирмы IBM является
    микросхема контроллера гибкого диска FDC (Floppy Disk Controller)
    мPD765 фирмы NEC. Эта компонента также производится фирмой Intel
    как микросхема 8272. Микросхема FDC управляет потоком данных на
    дискету и с нее. Микросхема FDC имеет два порта ввода-вывода, один
    для данных, а другой для отражения состояния. Порт данных находится
    по адресу 3F4H, а порт состояния по адресу 3F5H. Порт данных -
    двунаправленный, т.е. в различные моменты времени можно и читать
    данные из этого порта, и записывать их в порт. Регистр состояния
    можно только читать в любой момент времени. Он сообщает, как в
    данный момент нужно работать с регистром данных.
 
      В регистре состояния есть 2 бита, которые используются во время
    работы с дисководом. Бит 6 - это признак ввода-вывода данных (DIO -
    Data Input/Output). Этот бит сообщает, каких действий в отношении
    регистра данных ожидает от вас контроллер. Если признак DIO равен
    1, микросхема FDC ждет от вас чтения регистра данных. Если DIO
    равен 0, FDC ждет записи в регистр данных. Бит 7 порта состояния -
    это бит запроса устройства (RQM - Request For Master). Он
    аналогичен биту "занято" печатающего устройства. Когда бит RQM
    содержит 1, микросхема FDC готова к тому, чтобы читался или
    записывался регистр данных. Если вы не уделите внимание биту RQM,
    то введете микросхему FDC в заблуждение, и после этого ничего не
    будет работать.
 
      Регистр данных в действительности не является единственным.
    Подобно контроллеру 6845, порт данных фактически состоит из группы
    регистров. Но в отличие от микросхемы 6845, регистра индекса
    регистров данных здесь нет. Данные, которые вы посылаете в
    контроллер, должны поступать в определенном порядке. Аналогично, в
    определенном порядке данные поступают из порта, когда вы их
    читаете.
 
      В техническом описании содержится диаграмма, показывающая
    входные и выходные комбинации для всех операций дисковода.
    Рассмотрим простейшую команду микросхемы FDC, опрос состояния
    механизма. Вы выполняете эту операцию тогда, когда хотите что-либо
    узнать о текущем состоянии дисковода. На Фиг. 8.19 показаны данные
    для команды опроса состояния, а на Фиг. 8.20 показана программа,
    выполняющая операцию опроса состояния дисковода.
 
      ----------------------------------
      Команда...................04H
      Модификатор команды.......00H
      статус возврата...........ST3    Фиг. 8.19 Команда опроса
      ----------------------------------       состояния
A
                 Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:06:03
             Фиг. 8.20 Проверка состояния дисковода              Page     1-1
 
                                           PAGE ,132
                                           TITLE      Фиг. 8.20 Проверка состояния дисковода
 
              0000                        STACK      SEGMENT STACK
              0000      0040[                   DW   64 DUP (?)
                      ????
                                ]
              0080                        STACK      ENDS
 
                                     FDC_STATUS RECORD  RQM:1, DIO:1, OTHER:6
 
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE
              0000                        SENSE      PROC FAR
              0000      1E                      PUSH DS         ; Адрес возврата
              0001      2B C0                   SUB  AX, AX
              0003      50                      PUSH AX
 
              0004      BA 03F4                  MOV  DX, 3F4H   ; Порт состояния контроллера дисков
              0007      B4 04                   MOV  AH, 04H    ; Команда состояния устройства
              0009      E8 001E R               CALL OUTPUT      ; Передача в контроллер
              000C      B4 00                   MOV  AH, 0            ; Второй байт команды
              000E      E8 001E R               CALL OUTPUT
 
                                     ;-----  Чтение состояния из контроллера дисков
 
              0011                        IN_DIO:
              0011      EC                      IN   AL, DX      ; Ждать, пока флаг DIO разрешит ввод
              0012      A8 80                   TEST AL, MASK RQM     ;  из контроллера
              0014      74 FB                   JZ   IN_DIO
              0016                        IN_RQM:
              0016      EC                      IN   AL, DX      ; Ждать, пока флаг RQM покажет, что
              0017      A8 80                   TEST AL, MASK RQM     ;  контроллер готов
              0019      74 FB                   JZ   IN_RQM
 
              001B      42                      INC  DX         ; Установка на порт данных
              001C      EC                      IN   AL, DX      ; Чтение состояния контроллера
              001D      CB                      RET              ; Конец примера
              001E                        SENSE      ENDP
 
                                     ;-----  Подпрограмма посылки байта в контроллер
 
              001E                        OUTPUT  PROC     NEAR
              001E      EC                      IN   AL, DX      ; Ожидание пока DIO разрешит чтение
              001F      A8 40                   TEST AL, MASK DIO     ;  из контроллера из контроллера
              0021      75 FB                   JNZ  OUTPUT
              0023                        OUT_RQM:
              0023      EC                      IN   AL, DX      ; Ожидание пока RQM покажет, что
              0024      A8 80                   TEST AL, MASK RQM     ;  контроллер готов
              0026      74 FB                   JZ   OUT_RQM
 
              0028      42                      INC  DX         ; Установка на порт данных
              0029      8A C4                   MOV  AL, AH      ; Посылаемые данные
              002B      EE                      OUT  DX, AL      ; Вывод в порт
              002C      4A                      DEC  DX         ; Установка на порт состояния
              002D      C3                      RET
              002E                        OUTPUT  ENDP
              002E                        CODE ENDS
                                           END  SENSEA
            Фиг. 8.20 Проверка состояния дисковода
      Каждое действие, выполняемое контроллером дисковода, состоит из
    трех фаз: команды, выполнения и результата. В фазе команды
    микросхема FDC ожидает данные, и это отражает бит DIO. Когда
    микросхема FDC устанавливает бит RQM, чтобы он указывал на
    готовность принять данные, программа может посылать команду в
    контроллер. В случае опроса состояния дисковода, она выводит в
    микросхему FDC два байта команды. Первый байт, 04H, является кодом
    операции этой команды. Второй байт сообщает, какой из механизмов
    опросить. В течение командной фазы признак DIO всегда показывает,
    что микросхема FDC ждет данные, и программа использует бит RQM для
    определения момента, когда можно посылать очередной байт данных.
 
      Теперь контроллер переходит в фазу выполнения. В течение этой
    фазы контроллер выполняет команду. В данном случае он опрашивает
    состояние дисковода. В течение этого времени бит RQM сообщает
    программе, чтобы она не использовала порт данных. После завершения
    операции признак DIO переключается на 1, сообщая программе, что она
    может читать регистр данных. По разрешению RQM программа может
    прочитать единственный байт состояния от этой операции. Как только
    программа прочитает всю информацию состояния признак DIO снова
    принимает значение 0, ожидая ввода следующей команды.
 
      Как видно из таблицы в техническом описании, команда опроса
    состояния дисковода - одна из самых простых. Команде чтения данных
    требуется девять байт данных во время командной фазы. Когда
    операция завершится, программа должна прочитать семь байт состояния
    из контроллера. Выполнение не начинается до тех пор, пока не
    присылается шестой командный байт, и вы не можете начать другую
    операцию, пока не будут прочитаны все семь байт состояния.
 
      По адресу ввода-вывода 3F2H находится цифровой выводной регистр
    контроллера дисковода. Этот выводной порт выполняет некоторые
    дополнительные операции управления дисководом. Основное назначение
    этого порта - управление двигателями дисковода. У механизмов
    дисководов 5 1/4 дюйма, используемых в IBM PC, двигатели работают
    не непрерывно. Программа должна включить двигатель перед чтением
    или записью на дискету - и выключить его после. Если вы оставите
    двигатель включенным на все время, это приведет к быстрому износу
    дискеты. Когда двигатель работает, на передней панели дисковода
    горит красная лампочка.
 
      Адаптер использует цифровой выводной регистр и для других
    целей. Два бита выбирают необходимый дисковод. Этот регистр также
    используется для сброса микросхемы FDC, так как существуют
    ошибочные ситуации, которые вводят контроллер в неопределенное
    состояние. В таких случаях единственный выход - сбросить контроллер
    и попробовать снова.

Прямой доступ у памяти


    Плата адаптера дисковода устроена фирмой IBM так, что она
    использует возможность прямого доступа в память системы (ПДП).
    Прямой доступ в память позволяет устройству ввода-вывода передавать
    данные непосредственно в память или из нее. При этом микропроцессор
    не "касается" данных. Принтер, например, требует передачи каждого
    печатаемого символа самим микропроцессором. В случае же обмена с
    дискетой микропроцессор был бы тяжелой обузой для достаточно
    быстрой передачи данных. Программа микропроцессора для передачи
    данных дисковода была бы очень похожа на программу Фиг. 8.15, где
    символы посылались в принтер. То есть программа должна была бы
    читать бит RQM, в цикле, чтобы проверить наличие очередного байта
    данных. Тем не менее, если микропроцессор не ответит дисководу
    достаточно быстро, то данные будут потеряны.
 
      В случае передачи данных с помощью ПДП микропроцессор должен
    только инициировать операцию. Все остальное выполняет контроллер
    ПДП 8237 фирмы Intel, расположенный на системной плате. В случае
    чтения с дискеты программа инициализирует ПДП для обслуживания
    передачи данных. Затем программа посылает команду в контроллер
    дисковода, чтобы он выполнил чтение. Во время выполнения программа
    не должна передавать данные, так как эту работу выполняет
    контроллер ПДП. Когда операция завершается, программа выполняет
    фазу обработки результата, как и раньше.
 
      Давайте посмотрим, как нужно настраивать ПДП на операцию чтения
    с дискеты. На Фиг. 8.21 показана программа, предназначенная для
    этой цели. ПДП имеет четыре канала. Дисковод подключен к каналу 2
    ПДП. Каналы 1 и 3 доступны через системный канал ввода-вывода для
    других устройств ввода-вывода, а канал 0 используется для очень
    важной аппаратной функции - поддерживания регенерации памяти. Если
    вы вмешаетесь в работу канала 0 ПДП, содержимое всей памяти
    системы, вероятнее всего, изменится.
 
      Каждый канал ПДП имеет два регистра: адресный регистр и регистр
    счетчика. Регистр адреса задает область памяти, куда передаются
    данные. В нашем случае операции чтения, значение в регистре адреса
    указывает начало буфера данных. Когда контроллер дисковода читает
    байт с дискеты, контроллер ПДП помещает этот байт в память по
    адресу, определяемому регистром адреса. После каждого байта
    контроллер ПДП увеличивает адресный регистр так, что он указывает
    на следующий байт буфера.
 
      На Фиг. 8.21 BUFFER - имя области данных. Программа определяет
    абсолютный адрес буфера BUFFER в системе. Для этого она прибавляет
    смещение BUFFER к сдвинутому (умноженному на 16) значению регистра
    CS, который содержит значение сегмента буфера. Затем программа
    помещает младшие 16 бит адреса в регистр адреса ПДП канала 2.
    Старшие 4 бита адреса помещаются в специальный регистр "страницы".
    В   действительности контроллер ПДП 8237 работает только с
    16-битовым адресом. В IBM PC этот регистр страницы добавлен для
    того, чтобы программа могла читать данные в любое место памяти.
    Имеется три регистра страницы, по одному для каналов 1, 2 и 3.
    Регистр страницы имеет размер всего 4 бита, и поэтому старшие биты
    регистра AL не играют роли при формировании физического адреса
    буфера данных.

             Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:06:09
             Фиг. 8.21 Настройка прямого доступа в память              Page     1-1
 
                                           PAGE ,132
                                           TITLE      Фиг. 8.21 Настройка прямого доступа в память
 
              0000                        STACK      SEGMENT STACK
              0000      0040[                   DW   64 DUP (?)
                      ????
                                ]
              0080                        STACK      ENDS
 
              = 0000                DMA  EQU  0          ; Адрес порта DMA
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE
              0000                        DMA_SET PROC     FAR
              0000      1E                      PUSH DS         ; Адрес возврата
              0001      2B C0                   SUB  AX, AX
              0003      50                      PUSH AX
 
              0004      B0 46                   MOV  AL, 46H    ; Установка DMA в режим чтения с дискеты
              0006      E6 0B                   OUT  DMA+11, AL ;  в память
              0008      E6 0C                   OUT  DMA+12, AL
              000A      8C C8                   MOV  AX, CS      ; Текущий адрес сегмента
              000C      B1 04                   MOV  CL, 4
              000E      D3 C0                   ROL  AX, CL      ; Умножение на 16
              0010      8A E8                   MOV  CH, AL      ; Старшие 4 разряда в регистре CH
              0012      24 F0                   AND  AL, 0F0H   ; Очистка младших разрядов
              0014      05 0032 R               ADD  AX, offset BUFFER      ; Прибавление адреса буфера
              0017      80 D5 00                ADC  CH, 0
              001A      E6 04                   OUT  DMA+4, AL  ; Вывод младшего байта адреса
              001C      8A C4                   MOV  AL, AH
              001E      E6 04                   OUT  DMA+4, AL  ; Вывод старшего байта адреса
              0020      8A C5                   MOV  AL, CH
              0022      E6 81                   OUT  081H, AL   ; Установка регистра страницы
 
              0024      B8 01FF                  MOV  AX, 511    ; Счетчик на один сектор
              0027      E6 05                   OUT  DMA+5, AL  ; Младший байт счетчика
              0029      8A C4                   MOV  AL, AH
              002B      E6 05                   OUT  DMA+5, AL  ; Старший байт счетчика
              002D      B0 02                   MOV  AL, 2            ; Открыть для прямого доступа канал 2
              002F      E6 0A                   OUT  DMA+10, AL
              0031      CB                      RET
              0032                        DMA_SET ENDP
              0032      0200[             BUFFER  DB 512 DUP (?)      ; Буфер для чтения с диска
                       ??
                                ]
              0232                        CODE ENDS
                                           END
 
             Фиг. 8.21 Настройка прямого доступа в память
      Программа также посылает в контроллер ПДП число передаваемых
    байт данных. Контроллер дисковода использует это значение,
    записанное в регистр счетчика канала 2, для завершения операции
    чтения данных. ПДП посылает устройству специальный управляющий
    сигнал, называемый завершением счета, когда оно записывает в память
    последний байт. Последняя команда, выдаваемая ПДП - разрешение
    работы канала 2. Теперь программа может войти в командную фазу
    контроллера дисковода.
 
      Адаптер дисковода соединяет множество компонентов программного
    и аппаратного обеспечение компьютера. Адаптер дисковода использует
    и ПДП, и прерывания для обслуживания работы дисковода. Сам по себе
    контроллер дисковода - сложное, "интеллектуальное" устройство
    управления, требующее получения "программы" перед началом работы. В
    следующей главе при обсуждении управления механизмом дисковода с
    помощью программы BIOS все это будет рассмотрено в комплексе.