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

         

Глава 9


Базовая система ввода/вывода


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


      В данной книге программы BIOS изучаются по двум причинам: их
    использование дает пример техники программирования на языке
    ассемблера, особенно в случае управления системной аппаратурой, и
    еще существенней то, что программы BIOS играют важную роль в
    разработке программ на языке ассемблера для IBM PC. В предыдущих
    главах уже использовались некоторые функции программы BIOS; и,
    поскольку фирма IBM внесла эти функции в BIOS, дублировать их не
    стоит. Их надо использовать всюду, где это возможно.
 
      Вторая причина использования BIOS - это транспорта- бельность.
    Фирма IBM, поставляя BIOS, диктует уровень системного интерфейса
    программисту, работающему на языке ассемблера. Когда фирма IBM
    разрабатывала свою персональную ЭВМ, системные конструкторы знали,
    что не важно, насколько хорошо делается их работа первый раз, так
    как ее всегда можно сделать лучше. Время идет, и эволюция
    технологии позволяет делать ту же работу лучше.
 
      По мере того, как разрабатывается новая аппаратура для
    персональной ЭВМ, появляются и новые программные интерфейсы для
    нее. И если вы пишите программы, используя непосредственно
    аппаратуру, вам придется корректировать программы каждый раз, когда
    изменяется системная аппаратура. Это не имеет особого значения в
    случае индивидуального использования ваших программ, но важно, если
    вы пишите программы, которые будут использоваться многими. Или,
    если вы собираетесь тиражировать вашу программу, вам бы хотелось,
    чтобы она использовалась длительное время; т.е. вы не захотите
    поставлять новые версии программы всякий раз, когда кто-то создает
    новую системную аппаратуру.
 
      Интерфейс с BIOS - попытка разрешить эту проблему. Фирма IBM
    определила интерфейс с различными компонентами системы.
    Изготовители стараются поддерживать такой интерфейс для своей новой
    аппаратуры, а это означает, что даже если аппаратура и изменится,
    интерфейс с BIOS останется прежним. Ваша программа не потребует
    изменений.
 
      По мере того, как будут появляться новые аппаратные функции,
    вам нужно будет изменять программу для того, чтобы воспользоваться
    ими. В этом случае, вероятно, фирма IBM расщирит интерфейсы с BIOS.
    Но ваши старые программы, которые хорошо работали на старых
    машинах, будут продолжать работать и на новых машинах. Конечно, они
    не будут использовать новые функции, но если раньше ваша программа
    была полезной, весьма вероятно, что будет использоваться и далее.
 
      Предположим теперь, что фирма IBM решила модифицировать плату
    контроллера дисковода. Это могло бы потребоваться по разным
    причинам. Или фирма захотела уменьшить стоимость изготовления
    платы, или расширить возможности платы контроллера. В любом случае
    программный интерфейс с платой, который мы рассматривали в
    предыдущей главе, может оказаться другим. Но ПЗУ с BIOS, которое
    фирма IBM будет поставлять с таким новым контроллером, будет иметь
    тот же самый интерфейс. Это означает, что вызывающая
    последовательность и передача параметров через интерфейс останутся
    теми же. Если вы написали программу, использующую дискеты, и
    обращаетесь к BIOS при всех видах доступа к дискете, ваша программа
    будет выполняться правильно. Если же вы написали эту программу так,
    что она непосредственно работает с контроллером дисковода, скорее
    всего, она не будет работать с новым контроллером.
 
      BIOS состоит из нескольких различных частей. Первая часть -
    процедура самопроверки при включении питания POST. Эта программа
    выполняется всякий раз, когда включается питание, или когда
    делается системный сброс (одновременное нажатие клавиш
    CTL-ALT-DEL). Программа POST проверяет аппаратуру системы и
    инициализирует для нормальной работы некоторые узлы.
 
      BIOS также содержит драйверы устройств. Эти программы управляют
    работой устройств. Фирма IBM поставляет программы управления для
    всех часто используемых устройств. Но вообще для всех устройств
    фирмы IBM драйверы не поставляются. Кроме того, не все желательные
    функции доступны. Просто в ПЗУ нет места, чтобы реализовать все
    нужные вам функции.
 
      И наконец, BIOS содержит ряд программ системного сервиса. Эти
    программы непосредственно не управляют ни одним устройством, но они
    многое делают для работы системы.
 
      Эта глава описывает различные компоненты BIOS. Мы начнем с
    программы POST, поскольку она - первая в листинге ассемблера и
    первой выполняется при включении питания. Программы системного
    сервиса все связаны с системной платой, и поэтому они будут
    рассматриваться далее. И в конце мы рассмотрим, как фирма IBM
    обеспечивает работу различных функций ввода-вывода системы.

Замечания по листингу ROM BIOS


    Листинг BIOS дан в приложении A технического описания IBM PC.  Этот
    листинг - описание модуля ПЗУ объемом 8K, расположенного по
    адресам, начиная с 0FE000H в адресном пространстве микропроцессора
    8088.  Этот модуль ПЗУ - один из пяти модулей, размещенных на
    системной плате фирмой IBM.  Другие четыре модуля ПЗУ содержат в
    себе интерпретатор с языка Бейсик.    Исходные тексты программ
    Бейсика, так же, как и DOS, являются частной собственностью фирмы и
    не печатаются в техническом описании.  Но тексты программ входящих
    в BIOS фирма IBM опубликовала, так что каждый может изучить
    интерфейсы с BIOS.
 
      Листинг ассемблера в приложении A - это полный листинг
    содержимого ПЗУ. Это не листинг Макроассемблера фирмы IBM потому,
    что в то время, когда фирма IBM разрабатывала BIOS, Макроассемблер
    не существовал. Для разработки BIOS использовался Макроассемблер
    фирмы Intel, с помощью которого получился данный листинг. Ассемблер
    фирмы Intel идентичен ассемблеру фирмы IBM в использовании и
    синтаксисе. Как вы видите, ассемблер фирмы Intel не печатает в том
    же виде адресное поле, а также отличается некоторыми
    псевдооперациями ассемблера. Но с этими небольшими отличиями
    работать будет не сложно.
 
      В листинге программы BIOS описаны шесть различных сегментов. Из
    них по-настоящему интересны для нас лишь три. Сегмент ABS0,
    расположенный по адресу 0, содержит векторы прерываний, с которыми
    имеет дело BIOS и процедура POST. В этом сегменте нет никаких
    определений данных; он просто отводит место векторам. Эта область
    попадает в ОЗУ, и поэтому программа BIOS должна инициализировать ее
    после включения питания. Сегмент DATA, расположенный в параграфе
    40H или по абсолютному адресу 400H, определяет все поля данных,
    используемых в BIOS. Аналогично этот сегмент определяет места
    переменных, но не их начальные значения. Наконец, сегмент CODE
    начинается в параграфе 0F000H. В первых 56K байтах этого сегмента
    ничего нет, первый байт сегмента CODE имеет абсолютный адрес
    0FE000H или смещение 0E000H в сегменте. Эти данные, от 0FE000H до
    0FFFFFH, представляют содержимое модуля ПЗУ с BIOS объемом 8K. Эти
    программы вместе с ПЗУ с Бейсиком - единственные, которые
    содержатся в машине в момент начала работы.
 
      Еще одно замечание. Фирма IBM не разрабатывала BIOS в виде
    одного большого исходного текста. Каждая функция была разработана в
    виде отдельного модуля, а затем модули были связаны вместе,
    сформировав BIOS. Возможно вы увидите некоторые связки в программе.
    Для публикации фирма IBM скомбинировала все исходные тексты в один
    большой исходный текст и ассемблировала его. Такое единое
    ассемблирование позволило показать абсолютные адреса каждой функции
    BIOS.

Самотестирование при включении питания


      IBM PC выполняет процедуру самопроверки после каждого сброса
    системы, включая момент, когда появляется питание. Такая проверка
    преследует две цели: она выполняет быструю проверку основных
    элементов системы и инициализирует основные аппаратные компоненты.
 
      Как системный тест, процедура POST образует первую часть
    трехуровнего диагностического пакета фирмы IBM для ее персональной
    ЭВМ. Процедура POST выполняется всякий раз при включении системы.
    Эта быстрая проверка тестирует работу системы и обнаруживает ошибку
    до того, как она повлияет на выполнение программы. Программы,
    обеспечивающие второй уровень диагностики приходит вместе с каждой
    машиной в составе руководства по работе на IBM PC; эта дискета (или
    кассета) содержит программу диагностики, она проверяет оьдельно
    каждый компонент машины. Эта диагностическая программа определяет,
    какую часть машины покуптель должен вернуть для обслуживания, если
    найдена ошибка. Наконец, фирма IBM поставляет усовершенствованное
    диагностическое средство. Это средство, доступное за дополнительную
    плату, определяет, какой из сменных узлов не работает. Это
    диагностическое средство создано для обслуживающего персонала,
    работающего на таких машинах. Правда вы можете купить для себя и
    усовершенствованные диагностические тесты.
 
      Начало процедуры POST, возможно, будет трудно найти из-за того,
    что оно находится в самом конце листинга. Когда микропроцессор 8088
    сбрасывается (или когда включается питание), он начинает работу с
    адреса 0FFFF:0000H. Эта ячейка находится всего в 16 байтах от
    самого конца адресного пространства микропроцессора 8088. Этого
    места хватает для команды перехода на настоящую программу POST. Как
    вы видите, команда FAR JMP передает управление на метку START,
    которая и есть начало процедуры POST. Фирма IBM использует
    оставшиеся байты в конце памяти под дату; эта дата - момент выпуска
    ПЗУ в серию.
      Способ запуска процедуры POST также объясняет, почему фирма IBM
    расположила ПЗУ в верхних адресах памяти. Именно здесь
    микропроцессор начинает выполнение программы после сброса.
    Системное ПЗУ, содержащее программу инициализации машины, должно
    иметь некоторую информацию по адресу 0FFFFH:0000H. Так что есть
    смысл помещать все ПЗУ в конце памяти. Также, есть смысл поместить
    ОЗУ в нижних адресах, оставив в нем векторы прерываний. Возможность
    модификации кодов в этих векторах в большой степени увеличивает
    универсальность программы BIOS.
      Вообще процедура POST состоит из неинтересных кодов. Многие
    последовательности команд не имеют никакого смысла. Если вы
    посмотрите на начальную последовательность команд, то увидите, что
    они не делают ничего - если с микропроцессором ничего не случилось.
    Если вас не интересует написание диагностических программ нет
    смысла изучать технику процедуры POST. Отметим некоторые действия
    процедуры POST, чтобы показать область проверки ошибок. Процедура
    POST проверяет все ПЗУ системной платы, считая контрольную сумму.
    Этот тест складывает все байты модулей ПЗУ. При сложении перенос из
    8-битового результата игнорируется. Если окончательный результат
    нулевой, ПЗУ прошло проверку. Конечно, перед тем, как запустить ПЗУ
    в серию, фирма IBM обеспечила, чтобы сумма каждого ПЗУ была равна
    нулю. Если ПЗУ плохое, этот тест находит ошибку.
      Процедура POST также проверяет всю оперативную память в
    системе. Переключатели не системной плате сообщают процедуре POST,
    сколько у системы есть памяти в наличии. Каждый бит памяти
    проверяется, может ли он быть установлен в единицу и сброшен в
    нуль. По окончании теста процедура POST записывает нули по всем
    адресам памяти. Это означает, что если вы написали программу,
    которая будет работать сразу же после процедуры POST, содержимое
    всей памяти окажется нулевым. Но надеяться, что некоторая другая
    программа инициализирует поля данных вашей программы - плохой стиль
    программирования. чтобы быть в этом уверенным, лучше делать это
    самому.
      Последнее, что можно сказать про процедуру POST - то, что она
            Аппаратные прерывания
      ---------------------------------------------------------
       Номер
       прерывания             Использование в ROM BIOS
      ---------------------------------------------------------
        2   02H         Ошибка четности в памяти
        5   05H         Печать экрана
        8   08H         Текущее время
        9   09H         Клавиатура
       14   OEH         Дискета
 
                 Драйверы BIOS
      ---------------------------------------------------------
       Номер
       прерывания             Использование в ROM BIOS
      ---------------------------------------------------------
       16   10H         Видео
       17   11H         Проверка оборудования
       18   12H         Размер памяти
       19   13H         Дискета
       20   14H         Асинхронные
       21   15H         Кассета стриммера
       22   16H         Клавиатура
       23   17H         Принтер
       24   18H         Точка входа Бэйсика для кассеты
       25   19H         Точка входа в процедуру первичной
                        загрузки
       26   1AH         Текущее время
      ---------------------------------------------------------
 
            Процедуры управляемые пользователем
      ---------------------------------------------------------
       Номер
       прерывания             Использование в ROM BIOS
      ---------------------------------------------------------
       27   1BH         Прерывание клавиатуры
       28   1CH         Квантование времени
 
            Блоки параметров BIOS
      ---------------------------------------------------------
       Номер
       прерывания             Использование в ROM BIOS
      ---------------------------------------------------------
       29   1DH         Параметры видеомонитора
       30   1EH         Параметры дисковода
       31   1FH         Графические символы видеомонитора
      ---------------------------------------------------------
 
            Фиг. 9.1 Векторы прерываний, используемые
                  ROM BIOS
    инициализирует векторы прерываний для BIOS. Программы получают
    доступ к BIOS с помощью векторов прерывания. Сами по себе эти
    подпрограммы находятся в модуле ПЗУ, в том же, что и процедура
    POST. Перед тем, как процедура POST передаст управление
    операционной системе, она делает так, чтобы каждая входная точка
    BIOS была записана в соответствующий вектор прерывания. BIOS
    использует векторы прерываний для прерываний от 2 до 01FH.
    Техническое описание содержит листинг векторов прерывания, в
    котором показаны номера прерываний и первоначальное содержимое
    векторов. На Фиг.9.1 изображена часть этой таблицы, которая будет
    использоваться в описании BIOS.

Прерывания ROM BIOS


      Как показано в таблице на Фиг.9.1, BIOS использует векторы
    прерываний микропроцессора 8088. Эти векторы служат для нескольких
    различных целей. Первый блок векторов имеет дело непосредственно с
    аппаратными прерываниями. Программы обслуживающие эти прерывания
    получают управление всегда, когда возникает аппаратное прерывание.
    Например, прерывание от клавиатуры использует вектор прерывания 9,
    расположенный по адресу 9*4 или 24H. BIOS обслуживает не все
    прерывания инициируемые контроллером 8259. Некоторые прерывания
    зарезервированы за устройствами фирмы IBM, а другие вы можете
    использовать для своих целей. И даже в том случае, если фирма IBM
    зарезервировала какой-то вектор прерывания, вы все равно можете
    использовать его по-своему. Но если вы хотите тиражировать
    программу, нужно помнить, что у других пользователей компьютеры
    имеют не совсем такие же конфигурации, как у вас.

Драйверы доступа


      Драйверы устройств - это сердце BIOS. Эти программы дают
    возможность программисту, работающему на языке ассемблера, работать
    с устройствами IBM PC. Любая программа может управлять устройствами
    с помощью соответствующих последовательностей команд на аппаратном
    уровне. Тем не менее во многих случаях вы можете работать с
    устройствами стандартным образом, не вникая в их специфические
    особенности. Например, только небольшое число программ делают с
    дискетой что-либо еще кроме чтения и записи. В гл.8 была написана
    программа для чтения состояния дисковода. Если нужно прочитать
    некоторый сектор дискеты, можно использовать для этой цели BIOS и
    не переписывать эти программы заново. Программист, работающий на
    языке ассемблера, должен рассматривать BIOS как инструмент,
    сокращающий его работу.
 
      Функции BIOS вызываются с помощью программного прерывания.
    Параметры для функции передаются через регистры. Например,
    следующие команды опрашивают текущий режим дисплея
 
      MOV                              AH,            15
      INT    10H
 
      Команда INT 10H вызывет драйыер обслуживания дисплея, входящий
    в BIOS. Драйвер дисплея имеет большие возможности. Установка в
    регистре AH числа 15 сообщает ему, что программист хочет знать
 
    текущее состояние дисплея. BIOS возвращает информацию о состоянии
    через регистр AL.
 
      Каждый драйвер устройства входящий в BIOS имеет свои
    собственные входные и выходные параметры. В общем случае регистр AH
    определяет функцию для данного драйвера. Остальные регистры BIOS
    использует для любых других принимаемых или возвращаемых
    параметров. Каждая функция кратко описана в техническом описании
    IBM PC, а также снабжена другими важными замечаниями. При разборе
    драйверов мы вернемся к этим листингам, а перед этим рассмотрим
    другие векторы прерываний.

Процедуры пользователя


    Существуют некоторые системные функции, которые требуют
    непосредственного вмешательства пользовательской программы.  Для
    этого предназначены два прерывания.  Первое, с вектором 1BH -
    прекращение выполнения программы с по команде с клавиатуры.  Чтобы
    прервать выполняемую программу, пользователь системы нажимает
    клавиши CTL-BREAK.  В обычных случаях это возвращает управление в
    текущую программную систему - DOS или Бейсик.  Если пишется
    программа, которая самостоятельно должна обрабатывать подобное
    вмешательство пользователя, надо постоянно проверять, не нажал ли
    пользователь соответствующие клавиши на клавиатуре.  Или можно
    использовать прерывание по отпусканию.  Программа обслуживания
    клавиатуры BIOS всякий раз, когда возникает нажатие клавиши
    CTL-BREAK, дает програмное прерывани 1BH.  Обычно это прерывание
    указывает на возврат - команду IRET - так что ничего не происходит.
    Если мы хотим сразу знать о нажатии клавиши CTL-BREAK, тогда нужно
    сделать так, чтобы прерывание 1BH указывало на специальную
    подпрограмму нашей программы.  Эта подпрограмма сразу узнает о том,
    что пользователь захотел выйти из программы и сможет предпринять
    некоторые действия.
 
      Аналогично, можно написать программу, которой нужно
    периодическое прерывание. Например, игровая программа должна
    постоянно знать положение клавиши управления игрой. BIOS выдает
    прерывание 1CH всякий раз, когда срабатывает таймер. Как мы уже
    видели, это случается примерно 18.2 раз в секунду, или раз в 55
    миллисекунд. Можно написать программу, которая проверяет положение
    клавиш управления игрой каждый восемнадцатый раз возникновения
    прерывания, позволяя тем самым корректировать информацию об их
    положении примерно раз в секунду. Этот метод дает нам возможность
    периодического входа в заданную подпрограмму.

Блоки параметров


    Блоки параметров придают гибкость аппаратным программам ПЗУ.
    Векторы прерываний блоков параметров указывают на таблицы,
    используемые BIOS.  Блок параметров дисковода содержит данные,
    которые BIOS использует при управлении дисководом.      Поскольку
    различные типы дисководов имеют разные характеристики, BIOS имеет
    таблицу для всех типов дисководов поставляемых фирмой IBM.    Если вы
    захотели использовать другой тип дисковода вы можете модифицировать
    таблицу параметров и использовать это устройство.
      Существует также таблица параметров для задания режима работы
    дисплея. Если ваш дисплей нуждается в некоторых других временных
    соотношениях, можно модифицировать эту таблицу. Например, многие
    телевизоры не могут показывать полную ширину 40-символьного
    изображения. Один из параметров видеотаблицы управляет сдвигом
    изображения на экране дисплея по-горизонтальным. Команда MODE в DOS
    может сдвигать изображение на дисплее, модифицируя таблицу
    параметров.
 
      Последний блок параметров, использующий вектор прерываний BIOS,
    на самом деле является таблицей образов символов. BIOS обеспечивает
    вывод символов на дисплей во всех режимах работы дисплея. В
    графических режимах BIOS изображает символы, составляя их из
    соответствующих конфигураций точек. Таблица для первых 128 символов
    находится в ПЗУ, она расположена, начиная со смещения 0FA6EH в
    сегменте CODE. Вектор прерывания 01FH указывет на таблицу,
    используемую для оставщихся 128 символов. В ПЗУ для этой таблицы не
    нашлось места, так что ее должен организовать пользователь. Это
    позволяет вам заменить набор символов, выбранный фирмой IBM для
    старших 128 символов, своим собственным набором. Для этого нужно
    только сконструировать точечные образы символов, загрузить
    указатель на эту таблицу в вектор прерывания 01FH, и использовать
    для вывода символов графический режим работы дисплея. Эта
    возможность может оказаться очень полезной, так как позволяет
    конструировать и использовать свой собственный набор символов.
 
      Для того, чтобы изменить параметры, вам нужно изменить только
    вектор прерывания указывающий на блок параметров. Где-нибудь в
    своей программе вы составляете таблицу параметров, а затем
    модифицируете вектор прерывания так, чтобы он указывал на эту
    таблицу. Когда вы используете BIOS и ей требуется параметр, она
    обращается в вашу, а не в стандартную таблицу параметров,
    организованную в ПЗУ. Такие таблицы параметров делают BIOS очень
    гибкой. Хотя команды и находятся в ПЗУ, вы можете изменить действие
    BIOS, не заменяя ПЗУ на новое и не подменивая ни одной из программ,
    вхолдящих в BIOS.

Область данных ROM BIOS


    Сегмент DATA, расположенный по адресу 40H, содержит переменные,
    используемые в BIOS.  Мы не будем здесь перечислять все переменные
    и их функции.  Все они указаны в описании соответствующего драйвера
    устройства.
 
      Фирма IBM не меняет ни одну из этих ячеек без особой
    необходимости. Некоторые из драйверов, входящих в BIOS не только
    читают эти ячейки. Но для программы может оказаться довольно важным
    просматривать содержимое этих ячеек. В следующей главе приводится
    пример, в котором требуется изменить одну из переменных,
    поддерживаемых BIOS. Замена этого числа дает дополнительные
    возможности при использовании системы.
 
      Так как, скорее всего, фирма IBM не изменит местоположение ни
    одной из этих ячеек, разумнее использовать эти данные
    непосредственно, и это вполне возможно. Некоторые из переменных
    могут потерять смысл по мере того, как люди будут разрабатывать
    новые версии аппаратуры. Например, если фирма IBM разработает
    систему, у которой не будет никакой памяти (что совершенно
    невероятно), исчезнет необходимость в ячейках, которые содержат
    текущий объем памяти. В этом случае фирма IBM могла бы найти другой
    вид использования этой ячейки. Но если найдется функция, имеющая
    форму, сходную с текущей, то вероятнее всего переменная будет
    использоваться тем же способом.

Прогарммы драйверов устройств


    Теперь мы обсудим один за другим драйверы устройств.  Вместо того,
    чтобы рассматривать их в порядке номеров, давайте рассмотрим их в
    порядке роста сложности.  Простейшие из них - программы системного
    сервиса, с них мы и начнем.

Системный сервис


    Два драйвера в BIOS дают самый простой системный сервис.  Они
    предназначены для определения объема памяти ЭВМ и конфигурации
    внешних устройств.
 
      Программа определения объема памяти не имеет параметров. BIOS
    возвращает в регистре AX объем памяти системы, измеренный в
    килобайтах (1024 байт). Если система имеет память 64K байт, в
    регистре AX возвратится число 64. Любая программа, использующая всю
    память системы, должна запрашивать у BIOS объем памяти, чтобы
    определить, где находится ее конец. Программа могла бы определить
    объем памяти, записав и прочитав подряд ячейки памяти, сравнивая
    записанное и прочитанное значение. Но, как покажет пример в
    следующей главе, важно писать все прикладные программы так, чтобы
    они использовали для определения объема памяти подпрограмму,
    возвращающую этот объем. Изменяя значение верхнего предела памяти,
    можно зарезервировать участок в верхних адресах памяти. После того,
    как программа изменит значение общего объема памяти, корректно
    написанная прикладная программа не нарушит границу памяти.
 
      Программа проверки конфигурации внешних устройств не имеет
    входных параметров. Эта программа возвращает в регистре AX
    16-битовый код, показывающий, какие устройства подключены к
    конкретной системе. В прологе распечатки этой программы в
    техническом руководстве по IBM PC указывается, что означает каждый
    бит. Эта функция BIOS - простейший способ определения, существует
    ли конкретное устройство в системе, или нет.
 
      Последняя системная сервисная программа проверяет время суток.
    У этой программы есть две функции: чтение времени и установка
    времени. Время измеряется в квантах таймера, начиная с того
    момента, когда машина включается, и отсчитывается от полуночи. BIOS
    не преобразует это значение в часы, минуты и секунды. Но в листинге
    BIOS показаны нужные для преобразования константы. Чтобы определить
    время в часах, разделите 24-битовое значение таймера на 65543,
    число квантов таймера в часе. Чтобы определить минуты, разделите
    остаток от предыдущего деления на 1092, количество квантов в
    минуте, и так далее.
 
      Если точность преобразования значения времени не очень критична
    для вас, можно воспользоваться более простым методом. Так как
    количество квантов, соответствующее 24 часам не помещается в одно
    слово, значение таймера представляется трехбайтовым целым числом.
    Значение старшего байта отличается не более, чем на 1% от времени в
    часах. Младшее слово можно разделить на 1092, чтобы определить
    число минут, а деление остатка на 18 дает число секунд.
 
      Функция времени дня использует аппаратное прерывание,
    прерывание по кванту таймера. Это прерывание имеет уровень 0 в
    контроллере прерываний 8259, и имеет вектор прерывания 8 в
    микропроцессоре 8088. Эта программа получает управление каждые 55
    миллисекунд. Основное назначение этой программы - увеличение
    счетчика квантов таймера программы времени дня. Если программа
    выключит прерывания на значительный промежуток времени, то весьма
    вероятно, что время суток перестанет быть правильным.
 
      Прерывание от таймера используется также программой
    обслуживания дисковода. Двигатели дисковода включены не постоянно;
    BIOS включает двигатели только на время доступа к дискете. Но BIOS
    не выключает двигатель сразу же после выполнения операции. Есть
    некоторый интервал времени между включением двигателя и тем
    моментом, когда он разгонится и будет вращаться достаточно быстро,
    для того, чтобы можно было читать данные. Если программа обращается
    к дисководу почти сразу после предыдущего обращения, лучше оставить
    двигатель включенным, а не выключать и включать его. Программа
    обработки аппаратного прерывания от таймера учитывает это.
    Обработчик дискового прерывания загружает число в переменную,
    которая называется MOTOR_COUNT, когда завершается операция обмена с
    дискеттой. Прерывание от таймера уменьшает значение этого счетчика.
    Когда значение переменной MOTOR_COUNT достигает 0, выключается
    двигатель дисковода. Программа обслуживания дисковода проверяет
    этот счетчик, перед обращением к дискете. Если двигатель еще не
    включен, нужна задержка, пока двигатель не разгонится. Обычно
    двигатель дисковода продолжает работать две секунды после
    завершения предыдущей операции. Это время - один из параметров
    дисковода, и вы можете изменить его значение. Выбор этого значения
    поддерживает балланс между повышением производительности и
    снижением износа поверхности дискеты.
 
      Все эти три сервисные программы BIOS передают числа из ячеек
    памяти в вызывающую программу. Можно избежать использования BIOS
    путем непосредственного чтения этих ячеек. Но зачастую проще
    вызвать BIOS, чем организовывать адресацию к сегменту DATA
    используемому в BIOS. С "наивной" точки зрения, проще использовать
    программу BIOS.

Принтер и асинхронные коммуникации


    Программы входящие в BIOS обслуживающие печатающее устройство и
    последовательный канал очень похожи.  Основная разница -
    возможность чтения символов из асинхронного адаптера.  Обе
    программы имеют функции инициализации адаптера, вывода символа, и
    чтения состояния адаптера.      На Фиг.9.2 приведен список функций,
    реализуемых этими программами BIOS.
 
      Как видно из рисунка, эти две программы BIOS не совпадают.
    Значение регистра AH, необходимое для задания конкретного действия,
    разное для обеих программ и нам приходится с этим мириться.
 
      Эти программы BIOS могут обслуживать более одного адаптера. В
    поле данных BIOS по адресу 40:0H имеется областть из восьми слов.
    BIOS использует эту область для хранения адресов адаптеров
    печатающих устройств и последовательных каналов. Четыре слова со
    смещением 0, которые помечены RS_232_BASE, являются местом для
    хранения адресов портов четырех адаптеров последовательных каналов.
    По смещению 8, помеченного PRINT_BASE, находится соответствующая
    область для адаптеров печатающих устройств. Процедура POST
    инициализирует эту область данных в зависимости от того, какие
    устройства она обнаружит в системе. При поиске печатающих устройств
    процедура POST сначала ищет черно-белую плату, затем адаптер
    печатающего устройства по адресу ввода-вывода 378H и, наконец
    адаптер печатающего устройства по адресу 278H. Если процедура POST
    находит адаптер печатающего устройства по любому из этих адресов,
    она помещает значение его базового адреса в область данных.
    Аналогичную работу процедура POST делает с адаптерами
    последовательного канала, сначала она ищет плату по адресу
    ввода-вывода 3F8H, а затем по адресу 2F8H.
 
      Программы BIOS написаны независимо от адресов ввода-вывода
    конкретных плат адаптеров. В регистр DX помещается входной
    параметр, указывающий, какую из имеющихся плат должна использовать
    программа входящая в BIOS. Например, если у вас есть монохромная
    плата, имеющая порт печатающего устройства по адресу ввода-вывода
    3BCH, то этот адрес появится первым в таблице PRINT_BASE. Если вы
    вызовете программу печати BIOS и загрузите в регистр DX 0,
    программа BIOS направит ввод-вывод в этот адаптер. Если вы также
    имеете отдельный адаптер печатающего устройства, расположенный по
    адресу ввода-вывода 378H, установка регистра DX в 1 позволит
    программисту работать с этим адаптером. Посмотрев в текст программы
    обслуживания печатающего устройства и последовательного канала,
    можно увидеть, что она использует регистр DX для выбора
    соответствующего значения из таблицы базовых адресов в сегменте
    DATA используемого BIOS. После того, как BIOS определит это
    значение, весь ввод-вывод она будет делать, используя модификации
    этого базового адреса. В программах есть некоторое количество
    команд увеличения или уменьшения, работающих с регистром DX. Это
    позволяет BIOS работать с разными регистрами адаптера ввода-вывода
 
      Иден.(Значение AH)  Функция печати   Функция коммуникаций
      -------------------------------------------------------------
         0          Печать символа    Инициализация адаптера
         1          Инициализация     Посылка символа
         2          Чтение состояния  Получение символа
         3            -           Чтение состояния
      -------------------------------------------------------------
 
            Фиг. 9.2 Печать и асинхронные коммуникации
   без использования абсолютных значений. Все ссылки ввода-вывода
    делаются относительно первоначального адреса, взятого из таблицы
    базовых адресов.
      Функции инициализации печати не требуется от пользователя
    никаких входных параметров. Программа инициализации сбрасывает
    печатающее устройство и подготавливает порт управления адаптера
    печатающего устройства для дальнейшей работы. Но с другой стороны,
    инициализация интерфейса RS232 требует от пользователя информации о
    параметрах линии связи. Детали кода инициализации, передаваемого
    программе с помощью регистра AL, показаны в прологе к программе
    обслуживания последовательного канала.
 
      Другие функции BIOS поддержки печати и последовательного канала
    дают возможность записывать (для последовательной связи также
    читать) данные в устройство. Особенно важно то, что ввод-вывод
    делается синхронно. Это означает, что когда программа передает
    управление BIOS, чтобы она выполнила нужную функцию, управление не
    возвращается до тех пор, пока работа не будет завершена. Когда
    символ печатается, управление остается в программе печати до тех
    пор, пока она не передаст символ в устройство печати. Если
    печатающее устройство занято, BIOS образует цикл, ожидая конца
    работы печатающего устройства. Когда символ передается по каналу
    асинхронной связи, программа BIOS ждет, пока аппаратура разрешит
    передачу следующего символа. Аналогично программа приема
    последовательного канала ждет до тех пор, пока адаптер не принял
    символ. Если внешнее устройство никогда не пришлет символ,
    программа, вызвавшая функцию BIOS, никогда не получит управление
    назад.
 
      По этой причине обе программы содержат функцию состояния. Она
    позволяет программе решить, может ли BIOS выполнить операцию в
    текущий момент времени. Функция состояния печати сообщает, занято
    ли печатающее устройство в данный момент. Программа состояния
    последовательного канала показывает, может ли символ быть передан
    или принят в данный момент. Программа может использовать эти
    программы состояния, чтобы определить, можно ли непосредственно
    выполнить операцию. Вы можете решить сделать в вашей программе
    что-либо еще в то время, пока операция ввода-вывода не может
    выполняться. Если вы проверяете появление некоторого внешнего
    события, например приема символа адаптером, программа состояния
    позволит не останавливать программу до тех пор, пока символ не
    принят. Проверка появления символа позволит вам продолжить работу с
    ним при условии, что до этого программа выполняла другие действия.
 
      Важно отметить также способ обработки ошибок программ BIOS.
    Используя программы BIOS, очень трудно "подвесить" систему. За
    исключеннием того случая, когда вы ожидаете символ из
    последовательного канала, BIOS всегда возвращают управление
    вызвавшей программе, даже если возникла ошибка внешнего устройства.
    В каждом цикле, который ожидает выполнения некоторого действия
    внешним устройством, BIOS использует счетчик. Например, когда
    программа печати ожидает завершения работы печатающего устройства,
    в регистрах BL и CX находится счетчик. Если значение счетчика в
    этих регистрах становится нулевым до того, как печатающее
    устройство освободится, BIOS возвращает управление с ошибкой
    исчерпания времени. Это означает, что выключение печатающего
    устройства до того, как оно закончило печать, не вызовет
    "зависания" системы. BIOS в конце концов вернет управление
    программе, указывая, что произошла ошибка устройства печати.
 
      В BIOS возникают небольшие трудности в связи с исчерпанием
    времени. Когда в печатающее устройство попадает символ перевода
    страницы 0CH, бумага пропускается до начала очередной страницы.
    Если на текущей странице более 51 строки, печатающее устройство
    будет двигать бумагу долго, и возникнет ошибка по исчерпанию
    времени. То есть можно получить индикацию ошибки даже тогда, когда
    печать работает правильно. Величина, задающая интервал времени, в
    течение которого контролируется печатающее устройство,
    скорректировано во второй версии программы BIOS и устраняет эту
    проблему. Если вы имеете первую версию, вы можете заново повторить
    операцию печати, вызвавшую ошибку исчерпания времени. Получение
    ошибки вновь гарантирует, что это не ошибка программы BIOS.

Данные клавиатуры


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

Процедура BIOS клавиатуры изнутри


    Мы не собираемся построчно анализировать программу клавиатуры BIOS.
    Но в ней, однако, есть интересные места.  Некоторые из них мы
    упомянули раньше, например подпрограмму K4, которая сдвигает
    указатель буфера.
      Программа KB_INT использует несколько таблиц значений клавиш.
    Если вы посмотрите программу, то увидите, что эти таблицы
    используются различными способами. Таблицы, содержащие значения
    кодов сканирования, используются для поиска шаблонов. BIOS
    сравнивает код сканирования клавиатуры со значениями в таблице.
             Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:06:15
             Фиг. 9.3 Состояние клавиатуры                             Page     1-1
 
                                           PAGE ,132
                                           TITLE      Фиг. 9.3 Состояние клавиатуры
              0000                        STACK      SEGMENT STACK
              0000      0040[                   DW   64 DUP (?)
                      ????
                                ]
              0080                        STACK      ENDS
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE
              0000      0000              LITTLE  DW 0
              0002      0000              BIG  DW   0
              0004                        COUNT      PROC FAR
              0004      1E                      PUSH DS         ; Адрес возврата в ДОС
              0005      2B C0                   SUB  AX, AX
              0007      50                      PUSH AX
              0008                        ADD_ONE:
              0008      2E: FF 06 0000 R        INC  LITTLE
              000D      75 05                   JNZ  STILL_LOW
              000F      2E: FF 06 0002 R        INC  BIG
              0014                        STILL_LOW:
              0014      B4 01                   MOV  AH, 1            ; Программа опроса статуса клавиатуры
              0016      CD 16                   INT  16H
              0018      74 EE                   JZ   ADD_ONE    ; Переход, если нет символа в буфере ввода
              001A      B4 00                   MOV  AH, 0
              001C      CD 16                   INT  16H        ; Чтение символа
              001E      3C 20                   CMP  AL, ' '         ; Сравнение с пробелом
              0020      75 E6                   JNZ  ADD_ONE    ; Переход, если не пробел
              0022      CB                      RET              ; Возврат в ДОС
              0023                        COUNT      ENDP
              0023                        CODE ENDS
                                           END  COUNT
 
             Фиг. 9.3 Состояние клавиатуры
 
    Команда REPNE SCASB, используемая после метки K16, позволяет BIOS
    просмотреть таблицу в поисках соответствия с одной из регистровых
    клавиш. Когда BIOS находит соответствие в таблице кодов
    сканирования, она использует смещение в таблице для получения
    значения маски, используемого вместе с переменной KB_FLAG. Так как
    все регистровые клавиши представлены битами в переменных флагов,
    единая программа, пользуясь этими таблицами, может управлять
    регистровыми клавишами.
 
      BIOS использует также другие таблицы для перекодировки кодов
    сканирования в коды ASCII. Определив текущее состояние регистров,
    BIOS загружает в регистр BX указатель на нужную таблицу кодов
    ASCII. Затем программа преобразует код сканирования в правильное
    начальное значение выбранной таблицы (вычитая начальный адрес
    таблицы). Команда XLAT переводит код сканирования в правильный код
    ASCII. Этот прием используется там, где BIOS порождает коды
    псевдосканирования цифровой клавиатуры в режиме использования
    регистра клавиатуры CONTROL (метка K63).
 
      Подпрограмма ERROR_BEEP - пример управления динамиком, которое
    мы разбирали в предыдущей главе; она порождает сигнал, который BIOS
    посылает всегда, когда оператор вводит символ, а буфер полон. Так
    как этот сигнал может возникнуть всякий раз, когда система
    обслуживает прерывание от клавиатуры, было бы неразумно менять
    значение счетчика в канале таймера, управляя динамиком. Для этой
    цели BIOS использует непосредственное управление динамиком. Если
    уже генерируется какой-либо звук, он обрывается и появляется сигнал
    о переполнении клавиатуры. Если вы внимательно послушаете сигнал
    переполнения, то заметите, что он слегка дрожит. Возникающее 18 раз
    в секунду прерывание таймера меняет тон, прерывая цикл прямого
    управления динамиком. Как было предложено в предыдущей главе, вы
    можете исследовать последствия использования различных временных
    циклов таймера на выходную тональность динамика.

Кассета


    Программа управления кассетным магнитофоном в BIOS - это пример
    работы с последовательным устройством с помощью временных циклов.
    Но из-за отличий временных параметров команд, программа
    обслуживания кассетного магнитофона BIOS во всех критических
    случаях использует таймер-счетчик 8253.  Здесь будут рассмотрены
    только две программы использующие таймер - READ_HALF_BIT и
    WRITE_BIT.
 
      В техническом описании содержится вся информация о методе
    кодировки данных, записываемых на кассету. Программа WRITE_BIT
    записывает на ленту один бит данных. Выход канала 2
    таймера/счетчика непосредственно подключается к выводному порту
    кассетного адаптера. Поэтому запись бита данных заключается в
    установке правильной частоты канала 2 таймера и ожидании одного
    полного цикла. Программа WRITE_BIT делает именно это, но в обратном
    порядке. Когда программа WRITE_BIT получает управление, предыдущий
    бит еще находится в процессе записи. Два цикла ожидания в программе
    WRITE_BIT обеспечивают задержку на пол-цикла, необходимую для
    завершения записи предыдущего бита. Когда запись бита завершена,
    BIOS заносит новое значение частоты в канал 2 таймера. Программа
    WRITE_BIT возвращает управление вызвавшей программе тогда, когда
    новая частота начала выдаваться на ленту. Программа управления
    кассетным магнитофоном достаточно быстрая (или скорость выдачи бит
    в кассету достаточно медленная - это зависит от вашей точки
    зрения), чтобы программа WRITE_BIT вызвалась снова до того, как
    таймер завершит первые полцикла записи бита.
 
      Программа READ_HALF_BIT выполняет противоположную работу. Эта
    программа ждет до тех пор, пока бит ввода с кассетного механизма
    (бит 4 порта 62H) не изменит состояние. Каждая смена состояния
    этого бита соответствует чтению половины бита. Программа кассетного
    механизма вычитает текущее значение таймера из его значения при
    предыдущей смене бита. Это число соответствует времени, которое
    потребовалось сигналу кассеты, чтобы перейти из одного состояния в
    другое. Сложение двух полубитовых переходов дает общую длительность
    цикла этого бита. Так как времена циклов у нулей и единиц разные,
    программа READ_BYTE может определить значение текущего бита. Из
    восьми прочтенных битов она формирует байт.
 
      Программа READ_HALF_BIT иллюстрирует использование канала 0
    таймера для целей измерения времени. BIOS замораживает значение
    счетчика таймера, а затем читает его в регистр AX. Использование
    значения 0, загружаемого в счетчик 0 таймера позволяет вычитать
    любые два значения таймера, не анализируя, какое из них больше; в
    любом случае получится верная разность.
 
      Программа управления кассетным магнитофоном BIOS содержит в
    себе подпрограммы, выполняющие четыре функции. Две из них - блочные
    операции ввода-вывода, чтение блока и запись блока. Для
    эффективного использования ленты данные записываются на нее блоками
    по 256 байт. BIOS проверяет правильность ввода этих блоков с
    помощью циклического избыточного кода CRC (Cyclic Redundacy Check).
    Проверка ошибок с помощью CRC выявляет почти все ошибки, которые
    могут возникнуть на ленте. Это позволяет IBM PC использовать
    кассеты в качестве средства памяти с уверенностью, что вновь
    читаемые с них данные правильны. Кроме того, BIOS помещает данные в
    блоки в связи с несовершенством механизма кассетного магнитофона,
    проявляющемся при записи блоков любого размера. Программа обязана
    ждать до тех пор, пока двигатель кассетного магнитофона не
    включится и разгонится до нужной скорости. Программа также должна
    записывать на ленту синхронизирующие импульсы для того, чтобы
    микропроцессор вошел в синхронизацию с данными тогда, когда они
    будут читаться. Наконец, BIOS записывает слово CRC и конечный байт
    в конце каждого блока. Вся эта дополнительная работа происходит с
    любым блоком данных, независимо от того, один это байт или 10000
    байт. Фирма IBM выбрала размер блока, равный 256, как компромисс
    между слижком большим размером блока и нерациональным
    использованием ленты.
 
      Другие две функции программы управления кассетным магнитофоном
    BIOS - просто включают двигатель ммагнитофона и выключают его. Если
    вы думаете о разработке простого способа подсоединения вашей
    аппаратуры к IBM PC, имейте в виду, что кассетный порт очень удобен
    для этой цели. С помощью разъема кассетного магнитофона,
    расположенного сзади корпуса машины, вы можете подключиться к
    последовательной линии ввода-вывода. Существует также реле, которое
    позволяет управлять низковольтным слаботочным двигателем. Но есть
    одна вещь, о которой надо помнить. Выходной бит подключается прямо
    к входному биту, когда реле двигателя включено. Такое соединение
    позволяет диагностическим программам фирмы IBM проверять входные и
    выходные цепи кассетного механизма без записи и чтения данных. Если
    вы отдельно используете последовательные вход и выход, нужно
    включить реле двигателя - даже если двигателя нет.

Области данных драйвера BIOS дискеты


    Области данных дискового драйвера BIOS начинаются у смещения 3EH в
    сегменте DATA.  Первые четыре байта поля данных хранят информацию
    состояния дисководов между операциями.  Семибайтовый буфер с именем
    NEC_STATUS хранит информацию о состоянии контроллера, возвращаемую
    контроллером дисководов фирмы NEC после операций чтения и записи.
    Как видно из управляющих программ, этот буфер позволяет BIOS
    расшифровывать любую ошибку и предоставлять все ошибки в виде
    простого набора кодов ошибок.  Эти коды ошибок программа BIOS
    помещает в байт с именем DISKETTE_STATUS, одновременно возвращая
    его в вызывающую программу в регистре AH после выполнения операций
    ввода-вывода.  Операторы ассемблера после имени DISKETTE_STATUS
    перечисляют все коды ошибок, которые может получить вызывающая
    программа.
 
      Контроллер дисковода фирмы NEC знает положение головки
    чтения-записи в каждом из четырех дисководов, которые он может
    обслуживать. Но для этого контроллер должен войти в синхронизацию с
    этими механизмами до того, как он начнет точно отслеживать текущее
    положение головок; синхронизация нужна потому, что после включения
    питания или после сброса контроллер фирмы NEC не знает, где
    находятся головки. Байт SEEK_STATUS использует младшие 4 бита, по
    одному биту на механизм, чтобы указать, известно ли контроллеру
    текущее положение головок или нет. Когда BIOS посылает сигнал
    сброса в контроллер, он заносит нуль в этот байт. Перед каждой
    операцией обмена данными с дисководами BIOS проверяет этот байт
    установки. Если содержимое бита, соответствующего механизму, с
    которым идет работа, равно 0, BIOS посылает команду рекалибровки
    перед командой установки. На этапе рекалибровки головка
    чтения-записи устанавливается на дорожку 0, и теперь контроллер и
    механизм согласованы в смысле положения головки. Все последующие
    операции установки делаются без предварительной рекалибровки.
 
      Операция рекалибровки играет важную роль и при обычной работе
    для устранения условий появления ошибки. После любой ошибки
    рекомендуется сбросить контроллер. Этим обеспечивается сброс
    условия появления ошибки в контроллере. Байт SEEK_STATUS при этом
    устанавливается равным нулю. Поэтому перед тем, как прикладная
    программа повторит операцию (неудачную операцию нужно повторять по
    крайней мере три раза, так как большинство таких ошибок устранимы и
    не повторяются), выполнится рекалибровка механизма. Это
    автоматически устраняет ошибку, вызванную неправильной установкой,
    когда головка не попала на нужную дорожку. В обычных случаях
    рекалибровка и повторная установка на эту же дорожку устраняет
    ошибку.
 
      Байты MOTOR_STATUS и MOTOR_COUNT управляют двигателем
    дисковода. Адаптер дисковода имеет управляющий регистр, который
    позволяет выбрать двигатель дисковода, который включается в двнное
    время. В этот управляющий регистр можно только записывать данные,
    читать из него нельзя, и байт MOTOR_STATUS является его образом в
    памяти. Перед тем, как выполнить операцию записи-чтения на дискете,
    вы должны дать возможность двигателю разогнаться до необходимой
    скорости, подождав некоторое время - около половины секунды. Если
    двигатель уже работает, ждать не нужно. Чтение конкретного бита в
    этом байте состояния позволяет определить, нужно ли ожидание.
 
      Далее после выполнения операции важно оставить двигатель
    включенным. Есть вероятность, что доступ к дискете вскоре
    повторится; однако здесь нужно выбирать между износом дискеты и
    увеличением времени доступа. BIOS не допускает непрерывного
    вращения двигателей дисководов, для этого в ячейке MOTOR_COUNT
    находится уменьшающийся счетчик. При каждом прерывании от таймера
    этот счетчик уменьшается, и когда счетчик достигает нуля, все
    двигатели выключаются. Обычно временные параметры установлены так,
    что двигатель работет примерно две секунды после завершения
    операции.
 
      В тексте программы обслуживания дисководов BIOS можно увидеть,
    что величина MOTOR_COUNT на одном из первых шагов устанавливается
    равной 255. Тем самым гарантируется, что прерывание от таймера не
    выключит двигатель дисковода в течение операции. Текущее значение,
    представляющее две секунды, записывается в байт счетчика перед
    возвратом из BIOS в вызывающую программу.
 
      На Фиг.9.4 приведены команды управления дисководом. Команда
    сброса пересылает в контроллер параметры механизма, такие как режим
    работы ПДП и скорость предачи. Команда сброса также выполняет
    аппаратный сброс контроллера. Фирма IBM рекомендует выполнять это
    действие после любой ошибки. Это необходимо, так как некоторые
    ошибки (в частности, ошибка по исчерпыванию времени операции,
    получающаяся, если в дисководе нет дискеты) ставят контроллер в
    затруднительное положение. После таких ошибок вернуть контроллер к
    нормальной работе можно только с помощью сброса.

Команды чтения и записи


    Команды чтения и записи испоьзуют регистры микропроцессора 8088 как
    входные параметры.  Эти параметры указывают дорожку, сектор,
    головку и дисковод, на котором должна выполняться операция.  Парой
    регистров ES:BX вызывающая программа указывает буфер, и драйвер
    дисковода запускает операцию ПДП в этом буфере.  Подпрограмма
    DMA_SETUP вычисляет физический адрес буфера.  Эта программа также
    вычисляет общее число пересылаемых байт, используя входной
    параметр, задающий количество секторов, а также табличный параметр
    - размер сектора.  Затем эта программа посылает значение счетчика и
    адрес в контроллер ПДП.  Заметим, что эта программа определяет
    перекрытие буфером границы области размером 64K.  Поскольку
    четырехбитовый регистр страницы не изменяется при передаче данных,
    то если адрес ПДП переходит через значение 0FFFFH, передача данных
    будет неверной.  Эта программа сигнализирует об ошибке, не допуская
    выполнения ошибочной операции ввода-вывода.
           AH           Функция
      -------------------------------------------------
           0            Инициализация адаптера дисковода
           1            Читать состояние от последней операции
           2            Чтение с диска в память
           3            Запись из памяти на диск
           4            Проверка дискеты
           5            Форматирование дорожки дискеты
      -------------------------------------------------
 
            Фиг. 9.4 Функции BIOS для дисковода

Команда проверки


    Команда проверки аналогична команде чтения, за исключением того,
    что данные не записываются в память, а просто отбрасываются.  У
    контроллера ПДП есть специальная команда, называемая командой
    проверки, выполняя которую ПДП отвечает на запросы контроллера
    дисковода и переключает шину ЭВМ в необходимый режим.  Но в этом
    случае ПДП не выполняет другую часть своего цикла, в которой данные
    записываются в память.  Команда проверки используется для проверки
    того, правильно ли записались данные на дискету.  Операционная
    система использует операцию проверки во время выполнения команды
    FORMAT.  Проверка в этом случае ищет дефектные места на дискете, и
    когда выявляет эти дефектные области, операционная система помещает
    их за пределами справочника дискеты.  Это позволяет использовать
    дефектную дискету, а не выбрасывать ее.
      Команда проверки, хотя и может определить, что в данных на
    дискете есть ошибка, не гарантирует, что данные записались
    правильно. Предположим, что в цепи записи на дискету есть
    неисправность. Такая ошибка не вызовет появления ошибочной ситуации
    во время записи, но на дискету данные не запишутся. Если вы
    проверите область данных, команда проверки прочитает ранее
    записанные данные (которые вы хотели модифицировать) без ошибки, и
    вы будете считать, что все прошло нормально. Если вы хотите
    удостовериться в том, что данные записаны верно, вы должны
    прочитать данные назад в другой буфер после записи и затем сравнить
    оба буфера. Это гарантирует, что данные записались верно.

Команда форматирования


    Команда форматирования инициализирует новую дискету.  Когда вы
    инициализируете дискету, происходит запись на нее маркеров
    идентификации секторов.  Эти поля контроллер использует при
    операциях чтения и записи для опознавания секторов.  Например, во
    время операции чтения BIOS посылает четыре байта идентификации
    сектора в контроллер дисковода.  Эти четыре байта обычно
    соответствуют номеру дорожки, номеру головки, номеру сектора и
    размеру сектора, и называются номером цилиндра-головки-записи CHRN.
    Контроллер использует значение номера CHRN сравнивая его со
    значениями, записанными в поля идентификации секторов во время
    форматирования.
      Это означает, что контроллер не обращает внимания на то, что
    записано в поле номера CHRN на дискете, т.е. сектора могут
    пронумерованы в произвольном порядке, не от первого до восьмого на
    каждой дорожке. Как только контроллер находит сектор, у которого
    поле номера CHRN совпадает с заданным, он читает сектор. Значения
 
             Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:06:20
             Фиг. 9.5 Форматирование дискеты                     Page     1-1
 
                                           PAGE ,132
                                           TITLE      Фиг. 9.5 Форматирование дискеты
              0000                        STACK      SEGMENT STACK
              0000      0040[                   DW   64 DUP (?)
                      ????
                                ]
              0080                        STACK      ENDS
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE,ES:CODE
              0000      00 00 01 02 00 00 02    ID_BUFFER  DB   0, 0, 1, 2, 0, 0, 2, 2
                  02
              0008      00 00 03 02 00 00 04                DB   0, 0, 3, 2, 0, 0, 4, 2
                  02
              0010      00 00 05 02 00 00 06                DB   0, 0, 5, 2, 0, 0, 6, 2
                  02
              0018      00 00 07 02 00 00 08                DB   0, 0, 7, 2, 0, 0, 8, 2
                  02
 
              0020                        FORMAT  PROC     FAR
              0020      1E                      PUSH DS         ; Адрес возврата в ДОС
              0021      2B C0                   SUB  AX, AX
              0023      50                      PUSH AX
 
              0024      8D 1E 0000 R                  LEA  BX, ID_BUFFER    ; Занесение адреса буфера в ES:BX
              0028      0E                      PUSH CS
              0029      07                      POP  ES
              002A      B9 0001                  MOV  CX, 1            ; Трек 0, сектор 1
              002D      BA 0000                  MOV  DX, 0            ; Дисковод 0, сторона 0
              0030                        TRACK_LOOP:
              0030      8D 3E 0000 R                  LEA  DI, ID_BUFFER    ; Необходимо для занесения номера
              0034      B0 08                   MOV  AL, 8            ;  трека в буфер форматирования
              0036                        ID_SETUP:
              0036      26: 88 2D               MOV  ES:[DI], CH      ; Занесение номера трека (цилиндра)
              0039      83 C7 04                ADD  DI, 4            ; Переход на следующее поле
              003C      FE C8                   DEC  AL
              003E      75 F6                   JNZ  ID_SETUP   ; Цикл по полям в буфере
              0040      B8 0501                  MOV  AX, 501H   ; Форматирование
              0043      CD 13                   INT  13H
              0045      FE C5                   INC  CH         ; Переход на следующий трек
              0047      80 FD 40                CMP  CH, 40H    ; Все сформатировано?
              004A      75 E4                   JNE  TRACK_LOOP ; Цикл по трекам
              004C      CB                      RET              ; Возврат в ДОС
              004D                        FORMAT  ENDP
              004D                        CODE ENDS
                                           END  FORMAT
 
             Фиг. 9.5 Форматирование дискеты
   номера CHRN контроллер помещает на дискету во время операции
    форматирования. Вы имеете возможность записать в качестве значений
    номера CHRN любые значения, которые выберете. Буфер данных для
    команды форматирования содержит байты номера CHRN для каждого
    сектора дискеты. Это означает, что буфер данных может содержать
    например такие значения:
 
      DB    10,0,1,2,10,0,2,2
      DB    10,0,3,2,10,0,4,2
 
      для дорожки 10 стороны 0 дискеты. Это пример поля данных,
    которое использует команда FORMAT операционной системы PC DOS или
    MS DOS. На Фиг. 9.5 показана программа, которая форматирует
    одностороннюю дискету с обычными значениями номера CHRN. Заменять
    этой программой команду FORMAT операционной системы PC DOS нельзя,
    так как система PC DOS также проверяет дискету и записывает на
    дискету справочник и таблицу расположения файлов. Еще вы можете
    заметить, что эта программа сразу же после запуска начинает
    форматировать дискету в дисководе A:. Вы должны быть готовы к
    этому, если собираетесь выполнить эту программу.
 
      Вы можете использовать команду форматирования в том случае,
    если хотите защитить дискету от копирования. Защита от копирования
    означает, что дискета шифруется таким образом, что ее становится
    трудно скопировать. Так как утилита DISKCOPY предполагает, что
    идентификаторы секторов записаны обычным образом, она не может
    копировать дискету с не стандартными номерами секторов. Записав на
    дискету идентификатор сектора, отличный от нормального, вы защитите
    ее от копирования.
 
      В качестве примера давайте защитим дискету от копирования,
    записав не стандартный номер сектора на дорожку 10. Пример,
    приведенный выше, показывает обычные номера секторов. Если вместо
    них буфер данных будет содержать значения DB 10, 0, 10, 2, 10, 0,
    2, 2 DB 10, 0, 3, 2, 10, 0, 4, 2
 
      дорожка 10 не будет иметь сектора 1. Вместо него на ней
    появится сектор 10, которого не бывает на нормальной дискете
    системы PC DOS. Программа DISKCOPY не может скопировать дорожку 10
    правильно. Если теперь данная программа проверит (с помощью команды
    проверки) наличие сектора 10 на дорожке 10 дискеты, отсутствие
    ошибки будет означать, что дискета оригинальная, а не копия.
 
      Этот способ защиты от копирования не совсем надежен. Каждый
    опытный пользователь (и даже некоторые программы копирования) могут
    обнаружить защиту такого типа и обойти ее. Но модификация
    идентификаторов секторов не может производиться произвольно. Для
    определения адреса установки головок BIOS использует номер дорожки
    из поле CHRN, так что номер цилиндра должен соответствовать номеру
    цилиндра, на котором находится сектор. Код в байте номера головки
    определяет установку электронного переключателя, выбирающего
    головку, поэтому это значение должно быть задано корректно. Длина
    поля берется из таблицы параметров, а не из регистров при вызове,
    так что ее изменить трудно. К тому же, это число использует и BIOS,
    и контроллер, определяя длину сектора, так что изменить его вы
    сможете только после тщательной подготовки. Свободно изменяемым
    остается только номер сектора. Перед тем, как вы начнете изменять
    номера секторов, запомните, что если при этом вы собираетесь еще
    использовать эту дискету в рамках DOS, система будет пытаться
    использовать сектор, который вы заменили сектором со своим
    нестандартным номером, если вы не модифицируете таблицу
    расположения файлов дискеты так, чтобы зарезервировать этот сектор.
    Если вам нужно считывать по нескольку секторов (что позволяет
    драйвер дисковода BIOS), номера у секторов должны быть
    последовательными, но не обязательно начинаться с первого.
 
      В общем, команда форматирования дает некоторое средство защиты
    от копирования. Однако абсолютно надежный метод защиты еще не
    найден. Только хороший выбор техники шифрования поможет оставить
    честных людей честными.

Области данных дисплея


    Секция поля данных BIOS, озаглавленная VIDEO DISPLAY DATA AREA и
    начинающаяся со смещения 49H, содержит переменные, используемые
    видеопрограммой.  Все эти ячейки данных содержат значения,
    используемые для работы с дисплейным адаптером в текущий момент
    времени.  Многие из этих значений копируют данные, находящихся в
    регистрах дисплейных адаптеров, из которых запрещено чтение.
    Видеопрограмма BIOS должна знать текущее значение таких переменных,
    как CRT_MODE_SET и CRT_PALETTE при модификации регистров.  В
    отличие от порта вывода на системной плате (порт 61H), BIOS не
    может прочитать эти регистры перед их изменением.  Это означает,
    что BIOS должна поддерживать в памяти образ регистра.
 
      Все поля данных имеют содержательные комментарии, которые
    поясняют назначение данных во время вашей работы с текстом BIOS.
    Отдельного комментария заслуживает поле CURSOR_POSN. Так как
    цветной графический адаптер может поддерживать более одной страницы
    изображения в текстовом режиме, на каждой странице имеется свое
    место для курсора. Контроллер CRT 6845 обслуживает только курсор
    текущей страницы. Когда BIOS переключается со страницы на страницу,
    контроллер запоминает положение курсора на соответствующей
    странице. Так как цветная плата может содержать максимум восемь
    страниц в 40-символьном режиме, имеется восемь ячеек для хранения
    текущего положения курсора на каждой странице.

Функции ввода-вывода дисплея


    Программа дисплея BIOS имеет много функций, все они перечислены на
    Фиг.9.6.  В связи с тем, что видеопрограмма имеет так много
    функций, она использует таблицу переходов к этим функциям.    Эта
    таблица названа M1 и содержит смещения каждой точки входа программы
    дисплея BIOS.  Первая часть программы VIDEO_IO извлекает код из
    регистра AH и преобразует его в адрес перехода.  Первая часть
    программы выполняет еще и некоторые другие действия, включая
    проверку поля EQUIP_FLAG.
 
      Фирма IBM написала видеопрограмму BIOS так, чтобы она могла
    работать с двумя дисплейными адаптерами, как с цветным графическим,
    так и с монохромным. Но BIOS также подразумевает, что из них
    активен только один. Это означает, что вы не сможете использовать
    BIOS для того, чтобы записать символ в цветной дисплей, а затем
    сразу использовать BIOS для записи символа в монохромный дисплей.
    Видеопрограмма BIOS может иметь дело только с одним дисплейным
    адаптером.
 
           AH           Функция
      -------------------------------------------------
           0            Инициализация адаптера дисплея
           1            Установка размера и формы курсора
           2            Установка позиции курсора
           3            Чтение позиции курсора
           4            Чтение позиции светового пера
           5            Назначение текущей страницы
           6            Сдвиг вверх
           7            Сдвиг вниз
           8            Чтение символа
           9            Запись символа и атрибута
          10            Запись одного символа
          11            Выбор палитры
          12            Запись точки
          13            Чтение точки
          14            Запись на телетайп
      -------------------------------------------------
 
            Фиг. 9.4 Функции BIOS для видеомонитора
 
      Всякий раз, когда программа вызывает видеопрограмму BIOS, она
    определяет, какой дисплейный адаптер имеется в системе с помощью
    проверки битов поля EQUIP_FLAG, которые соответствуют текущему
    дисплею. Если биты 5 и 4 оба равны 1, то в системе присутствует
    монохромный адаптер. Любая другая установка бит говорит о том, что
    в системе работает цветной адаптер. Фирма IBM написала эту
    программу таким способом, исходя из того, что система может иметь
    только один дисплейный адаптер. Перед первым включением машины вы
    должны установить переключатели на системной плате в положение,
    показывающее, какой адаптер дисплея используется.
 
      Информация флагов оборудования в поле EQUIP_FLAG определяет,
    какой из адресов буфера будет использовать видеопрограмма BIOS. Для
    монохромной платы BIOS загружает в регистр ES значение 0B000H, а
    для цветной платы - значение 0B800H. Это позволяет остальным
    программам дисплея BIOS работать без использования информации о
    том, какой адаптер работает в системе. Все ссылки к буферу делаются
    относительно регистра ES.
      Вы можете решить, что, поскольку поле EQUIP_FLAG показывает,
    какой адаптер используется, можно переключаться от одного адаптера
    к другому просто изменяя биты в слове флагов. К сожалению, это не
    так, Адрес ввода-вывода контроллера 6845 отличается для двух
    адаптеров, и BIOS записывает этот базовый адрес в свою область
    данных. Видеопрограмма BIOS заносит в переменную ADDR_6845 этот
    адрес только при инициализации адаптера (команда AH = 0). Поэтому
    переключение от одного дисплея к другому также требует
    корректировки этой переменной.
 
      Даже если переменная CURSOR_POSN содержит восемь позиций, она
    не может обслуживать переключение на другой дисплей. Вы должны
    сбрасывать положение курсора в области данных BIOS всякий раз при
    переключении с одного адаптера на другой. Если вы не сделаете
    этого, изображение курсора не будет соответствовать его положению,
    записанному в области данных, и символ на экране будет записываться
    в неверную позицию.
 
      Фирма IBM опубликовала методы смены одного дисплея другим, как
    с помощью программы на языке ассемблера, так и с помощью программы
    на Бейсике. В этих методах требуется для указания адаптера, который
    вы хотите использовать, изменить переменную EQUIP_FLAG, а затем
    использовать видеопрерывание INT 10H при AH = 0. Эта функция
    инициализирует адаптер и обеспечивает правильную установку всех
    полей данных программы BIOS. После этого BIOS может работать с тем
    дисплейным адаптером, который указан. При этом картинка на другом
    дисплее остается видимой. Кроме того, дисплейный буфер того
    адаптера продолжает отображать любые изменения текста и графики,
    занесенной в него. Так что вы можете измекнять содержимое
    дисплейного буфера с помощью вашей программы (а не с помощью BIOS),
    чтобы скорректировать информацию, находящуюся на экране, с которого
    вы только что переключились.
 
      Давайте рассмотрим простой пример. Вы имеете IBM PC с двумя
    адаптерами - цветным графическим и монохромным, и к каждому
    адаптеру подключен дисплей. Когда вы сначала включаете машину,
    система использует монохромный дисплей. Именно с учетом этого вы и
    должны установить переключатели на системной плате, так как
    монохромный дисплей может быть поврежден, если не будет
    инициализирован сразу же после включения питания. Инструкция по
    работе рекомендует, чтобы вы установили переключатели в положение,
    показывающее, что в системе присутствует монохромный адаптер.
 
      После этого вы можете использовать видеопрограмму BIOS с
    монохромным дисплеем. Чтобы перейти на цветной адаптер, можно
    выполнить программу на Фиг.П9.7. Эта программа включает цветной
    адаптер в 80-символьном текстовом режиме. Символы, которые были
    высвечены на монохромном дисплее, на нем и остаются, а вы теперь
    можете использовать видеопрограмму BIOS для работы с цветным
    графическим дисплеем. Но если вам потребуется изменить содержимое
    монохромного дисплея, вы сможете сделать это, записав новые символы
    или атрибуты в буфер дисплея по адресу 0B000H. Это не изменит
    положения курсора, но изменит картинку. В этом случае если вы
    хотите изменять текст одновременно на цветном и монохромном
    дисплеях, вы должны написать собственную программу обслуживания
    монохромного дисплея. Или вы можете выяснить, какие значения надо
    изменить в поле данных BIOS, чтобы курсор перешел назад, и
    выполнить нужные действия, не инициализируя адаптер каждый раз.
 
             Microsoft (R) Macro Assembler Version 5.00                1/1/80 04:06:26
             Фиг. 9.7 Переключение на цветной дисплей            Page     1-1
 
 
                                           PAGE ,132
                                           TITLE      Фиг. 9.7 Переключение на цветной дисплей
              0000                        STACK      SEGMENT STACK
              0000      0040[                   DW   64 DUP (?)
                      ????
                                ]
 
              0080                        STACK      ENDS
              0000                        ABS0 SEGMENT AT 0
              0410                              ORG  410H
              0410                        EQUIP_FLAG LABEL      BYTE ; Будет изменяться только младший
              0410                        ABS0 ENDS             ;  байт поля флагов
 
 
              0000                        CODE SEGMENT
                                           ASSUME  CS:CODE,DS:ABS0
                                     COLOR      PROC FAR
              0000      1E                      PUSH DS         ; Адрес возврата в ДОС
              0001      2B C0                   SUB  AX, AX
              0003      50                      PUSH AX
 
              0004      8E D8                   MOV  DS, AX      ; Загрузка адреса сегмента ABS0 в регистр DS
              0006      80 26 0410 R CF          AND  EQUIP_FLAG, 11001111b  ; Указание на цветной дисплей как
              000B      80 0E 0410 R 20          OR   EQUIP_FLAG, 00100000b  ;  на основной (режим 80*25)
              0010      B8 0003                  MOV  AX, 3
              0013      CD 10                   INT  10H        ; Сброс дисплея
              0015      C3                      RET              ; Возврат в ДОС
                                     COLOR      ENDP
              0016                        CODE ENDS
                                           END
 
             Фиг. 9.7 Переключение на цветной дисплей

Установка режима


    Когда программа выполняет прерывание INT 10H при AH = 0, она
    вызывает функцию установки режима видеопрограммы BIOS.  Если в
    переменной EQUIP_FLAG отмечено, что в системе есть монохромная
    плата, не важно, какое значение оказалось в регистре AL.  В этом
    случае программа BIOS настраивает монохромный адаптер на режим 7,
    что означает текстовый режим 80*50, поддерживаемый черно-белой
    платой.
 
      В случае цветной графической платы значение в регистре AL
    определяет, в какой из двух графических или двух текстовых режимов
    введет программа BIOS дисплейный адаптер. Вы видите, что имеются
    черно-белые режимы наряду с цветными для текста, а также графика
    320*200. Эти черно-белые режимы на самом деле не выключают цвета,
    они только выключают сигнал цветности, который используется в
    телевизоре для определения цвета каждой точки. Если вы используете
    RGB-монитор, цвета останутся на местах. Если же вы используете
    цветной (или черно-белый) видеомонитор или телевизор, установка
    черно-белого режима цветной платы выключит цвета и даст более
    четкое изображение на экране. Если вы занимаетесь задачей, в
    которой цвета не нужны, то получите несколько лучшее изображение,
    выбрав один из черно-белых режимов вместо цветного.
 
      Когда выполняется программа установки режима, она настраивает
    адаптер и поля данных видеопрограммы BIOS на обслуживание нужного
    режима работы. Программа установки режима заполняет пробелами буфер
    дисплея и помещает курсор в верхнем левом углу экрана. До тех пор,
    пока вы не будете достаточно знакомы с устройством дисплея, вы
    должны использовать программу установки режима BIOS. Хотя и нет
    ничего плохого в смене кодов дисплея на ваши собственные, очень
    трудно отлаживать программу, которая модифицирует дисплей. Если вы
    сделаете что-либо неверно, дисплей станет неработоспособным, и
    исчезнет возможность определить, что же неверно.
 
      Функции видеопрограммы, соответствующие номерам от 1 до 5
    служат для работы с регистрами микросхемы 6845. Как вы помните из
    описания системной аппаратуры, микросхема 6845 содержит регистры,
    управляющие формой и положением курсора, а также временными
    характеристиками отображения. Эти подпрограммы видеопрограммы BIOS
    позволяют модифицировать отображение, не зная базового адреса
    микросхемы 6845. Эти подпрограммы входят в число сервисных программ
    BIOS.

Сдвиг изображения


    Программы сдвига перемещают текстовую информацию либо вверх, либо
    вниз, в зависимости от вызванной функции.  Программы сдвига также
    обеспечивают некоторые средства организации окон (фрагментов
    экрана) на экране дисплея - т.е.  BIOS может сдвигать только часть
    содержимого экрана.  Входные параметры программы сдвига определяют
    прямоугольник, расположенный на экране.  Он задает верхний левый и
    правый нижний углы области сдвига.    Видеопрограмма BIOS сдвигает
    данные только в этой области.  Остальная часть экрана не меняется.
 
      Мы уже видели пользу сдвига окон при изучении операционной
    системы и языка Бейсик, которые использовали для сдвига BIOS. Если
    работает 80-символьный дисплей, DOS устанавливает верхний левый
    угол окна сдвига равным (0, 0), а нижний правый угол (24, 79). Так
    сдвигается весь экран. Но Бейсик использует двадцать пятую строку
    для индикации состояния дисплея, и только 24 строки отводит под
    изображение программы. Когда Бейсик сдвигает экран с помощью
    базовой системы ввода-вывода, он устанавливает верхний левый угол в
    точке (0, 0), а правый нижний угол - в точке (23, 79). Из-за того,
    что последняя строка остается за пределами сдвига, она не
    перемещается во время сдвига. В следующей главе приведен пример
    сдвига окна, вызываемого из программы на Бейсике.
 
      Видеопрограмма BIOS выполняет сдвиги с помощью переноса
    символов и атрибутов в дисплейном буфере. Программа сдвига не
    меняет стартового адреса дисплейного буфера; такой метод сдвига был
    бы быстрее, но не позволяет прикладной программе определять, куда
    должны попасть отдельные символы. Способ сдвига, реализуемый в
    BIOS, подходит для обычной работы экрана. Заметим также, что
    программа сдвигает изображение при необходимости более чем на одну
    строку. Обычно программа сдвигает изображение на одну строку.
    Функция сдвига видеопрограммы BIOS позволяет сдвинуть содержимое
    экрана на несколько строк. Если же количество строк сдвига равно
    нулю, программа BIOS очищает экран. Это - быстрый способ очистки
    всего экрана или его части.
 
      Когда программа работает в 80-символьном режиме на цветном
    графическом адаптере, она не может записывать или читать его текст
    в произвольные моменты времени. Если программа будет модифицировать
    буфер не в строго определенные моменты времени, на экране появятся
    помехи. Так как программа сдвига читает и записывает большие
    количества данных, она должна быть написана с учетом проблемы
    помех. Если посмотреть текст программы обслуживания операции
    сдвига, то можно увидеть, что BIOS обслуживает режим 80*25 цветной
    платы (переменная CRT_MODE равна 2 или 3), как специальный случай.
    В случае операций сдвига эта подпрограмма BIOS ждет до тех пор,
    пока не возникнет вертикальный обратный ход луча дисплея. Это
    означает, что аппаратура адаптера выдала на экран все содержимое
    буфера и готова начать новый кадр. (Аппаратура адаптера повторяет
    этот процесс регенерации экрана 60 раз в секунду). При появлении
    вертикального обратного хода программа BIOS выключает дисплей и
    выполняет сдвиг. Когда программа сдвига переместит все символы, она
    снова включает дисплей. Это вызывает короткое мигание дисплея. Если
    вы внимательно посмотрите на экран во время сдвига, то заметите,
    что верхние его шесть строк несколько темнее остальных. Это
    происходит из-за того, что операция сдвига занимает несколько
    большее время, чем один период регенерации экрана. Поэтому верхние
    шесть строк выключаются на два интервала регенерации, а весь
    остальной экран - только на один интервал. Метод, допускающий
    появление помех на экране, настолько непригляден, что описанный
    метод предпочтительнее. Вы можете написать несколько программ,
    чтобы попробовать другие методы.
 
      Когда экран находится в графическом режиме, начинает работать
    другая часть программы сдвига. Хотя это и существенная часть
    программы BIOS, ее обсуждение отложим до тех пор, пока не
    рассмотрим чтение и запись символов на экран.

Чтение и запись символов


    Подпрограммы видеопрограммы BIOS, соответствующие номерам от 8 до
    10, обрабатывают символы на дисплее.  Все эти три программы
    работают с текущим положением курсора.  Чтобы записать конкретный
    символ на экран, программа должна прежде всего задать положение
    курсора с помощью видеопрограммы BIOS при AH-2.  После вывода
    символа курсор не продвигается автоматически после того, как символ
    записан на экране.  Если программе нужно записать более одного
    символа, она дожна переместить курсор на следующую позицию перед
    записью символа.  То же самое справедливо и для чтения символов с
    дисплея.  Так как все символьные операции происходят там, где
    расположен курсор, программа, использующая видеопрограмму BIOS, не
    сможет определить, по какому адресу расположен символ в буфере.
    Программы чтения и записи символа определяют, где он расположен, а
    вызывающая программа должна знать только строку и колонку символа.
 
      Имеются две формы программы записи символа. Одна из этих
    программ требует указания как символа, так и атрибутов (мигание,
    яркость, цвета и так далее), чтобы поместить символ по текущему
    адресу курсора. Другая программа записи символа записывает только
    символ и не меняет атрибуты этой позиции. Эти две различные формы
    программ записи символа позволяют вызывающей программе принимать
    текущие атрибуты позиции символа, не выясняя, какие они. Функция
    чтения символа возвращает и символ, и его атрибуты по адресу
    курсора. Иметь здесь две разные функции не надо - информация
    доступна, и если нужна вам, используйте ее.
 
      В связи с проблемой помех цветной графической платы в программы
    чтения и записи встроена проверка горизонтального обратного хода.
    Эта проверка нужна для того, чтобы на экране не появился "снег" во
    время работы микропроцессора. Эта проверка выполняется всегда,
    независимо от того, в каком режиме находится дисплей; она
    производится даже тогда, когда используется монохромная плата.
    Максимальное время ожидания сигнала горизонтального обратного хода
    составляет примерно 63 микросекунды, или 63 миллионных долей
    секунды. Это ожидание - минимальное в процессе выдачи символа на
    экран. У фирмы IBM не оказалось достаточно места в ПЗУ, чтобы
    написать подпрограммы, проверяющие специальные случаи. Так что BIOS
    всегда ждет сигнала отсутствия помех перед чтением и записью.

Текст в графических режимах


    Одной из важных возможностей программы BIOS фирмы IBM является
    способность показывать на экране текст даже тогда, когда цветной
    графический адаптер работает в графическом режиме.      Это
    осуществляется с помощью таблицы образов символов по адресу
    0FFFFH:0FA6EH.  Эта таблица содержит образы символов для первых 128
    символов.  Если нужно, пользователь может загрузить в вектор
    прерывания 01FH указатель на таблицу образов оставшихся 128
    символов.
 
      Как видно в листинге BIOS, когда цветная графическая плата
    находится в графическом режиме, программа записи символа переходит
    к специальной части под названием GRAPHICS_WRITE. Эта часть
    программы извлекает образ символа из таблицы в ПЗУ или из таблицы
    пользователя и помещает точки в соответствующие места памяти
    дисплея. В этой программе есть несколько интересных мест. В режиме
    среднего разрешения программа BIOS расширяет 8-битовый по ширине
    образ символа в 16-битовый. Подпрограмма S21 (EXPAND_BYTE) помещает
    в     регистр AL строку образа символа и расширяет ее до полного
    слова, возвращаемого в регистре AX.
 
      Программа записи символов должна также учитывать адресацию
    четных и нечетных полей графической платы. В подпрограмме
    GRAPHICS_WRITE происходит запись различных строк образов в байты,
    расположенные на расстоянии 2000H друг от друга. Это лучше всего
    видно в подпрограмме записи для режима с высоким разрешением. В
    этом режиме BIOS может записывать символы со строками образа прямо
    в буфер дисплея. Но вместо использования команды REP MOVSB для
    пересылки восьми байт используется цикл для обслуживания четных и
    нечетных полей. Сначала BIOS записывает четное поле с помощью
    команды STOSB. Затем записывается нечетное поле с помощью команды
    MOV по адресу [DI+2000H-1].
 
      Другая возможность программ записи символов - запись символов
    на экран с помощью функции "исключающее или". Это обычный способ
    выдачи на экран символов, которые затем надо удалить. Когда
    программа BIOS записывает символ на дисплей при включенном бите
    XOR, он берет функцию "исключающее или" от содержимого буфера и
    образа символа. Обычно это дает символ в читабельной форме, но его
    фактический вид зависит от фона, на котором он записывается. Но
    когда программа BIOS снова записывает символ на то же место, опять
    используя функцию XOR, символ исчезает, и экран возвращается к
    своему первоначальному виду. Этот метод предпочтительнее того, при
    котором записывается символ, а затем поверх него выдается пробел.
    Запись пробела не восстановит экран к виду, который он имел до
    записи символа. Вы можете очень эффективно использовать эту
    возможность записи со стиранием в случаях, когда вам надо выдать
    временное сообщение на экран.
 
      Программа чтения символа работает аналогично, когда дисплей
    находится в графическом режиме; BIOS извлекает образ символа из
    дисплейного буфера, а затем сравнивает этот образ с образами
    таблицы символов. Когда она находит символ, это отвечает, что по
    данному адресу находится найденный символ. Эта программа работает
    только в случае точного соответствия, так что если часть другой
    графической картинки вторгнется в позицию символа, BIOS не сможет
    распознать символ. Более того, эта программа позволяет программисту
    считать графический режим идентичным текстовому режиму. Пока
    программа использует для взаимодействия с дисплеем BIOS, она может
    работать с текстом независимо от режима работы дисплея.
 
      Вспомним теперь, что и программы сдвига изображения тоже имеют
    специальные части для обслуживания графических режимов. Если вы
    вернетесь к соответствующей части BIOS, то обнаружите, что она
    определяет окна сдвига в графическом дисплее и выполняет сдвиг
    способом, который идентичен сдвигу в текстовом режиме. Сдвиг в
    графических режимах происходит несколько медленне, чем в текстовом
    режиме, в первую очередь из-за того, что программа должна переслать
    все 16000 байт, а не 2000 или 4000 байт, нужных в текстовом режиме.
    Это дает 4- - 8-кратное увеличение времени сдвига, и оно становится
    заметно больше.
 
      Способность BIOS обрабатывать символы в графических режимах
    дает большие возможности. Становится достаточно простым нарисовать
    график или картинку, а затем использовать символы для пометки
    отдельных частей рисунка. Кроме того, вы можете отвести часть
    экрана под графическое изображение, а другое окно использовать для
    текста. В это окно вы можете заносить обычный текст с помощью
    программ символьного вывода, а также сдвигать его. В других случаях
    вы можете записывать символы на дисплей, не обращая внимания на его
    текущий режим. BIOS сама определит, в каком режиме находится
    дисплей, и правильно запишет символы.

Графика


    Видеопрограмма BIOS имеет несколько функций, которые обслуживают
    графику на IBM PC.  Устанавливая регистр AH равным 11, программа
    может сделать выбор цвета в графическом режиме.  Эта подпрограмма
    устроена так, что она работает с истинной палитрой, а не с
    предопределенными палитрами цветной платы.  Если графический режим
    320*200 имеет истинную палитру, то это означает, что должно
    существовать отображение в четыре цвета, возможных для каждой
    точки, из четырех цветов, которые хотела бы иметь программа.  В
    настоящее время это делается для цвета фона в режиме нормального
    разрешения.  Вы можете выбрать любой цвет в качестве цвета 0, цвета
    фона.  Интерфейс этой программы был разработан для того, чтобы
    позволять определение истинной палитры цветов, если фирма IBM
    когда-либо модифицирует аппаратуру так, чтобы позволять это.
 
      Чтобы достичь этой цели, значение точки определяется в регистре
    BH. В регистре BL определяется цвет, который присвоит адаптер этой
    точке. Например, если содержимое регистра BH равно 0; регистр BL
    содержит значение цвета фона. BIOS обслуживает значение регистра
    BH, равное только 0 или 1 , так как можно выбрать только цвет фона
    и одну из двух предопределенных палитр. Пролог BIOS определяет
    палитру. С помощью этой функции можно также определить цвет
    окаймления в текстовых режимах.
 
      Две другие графические подпрограммы позволяют читать либо
    записывать конкретные точки графического экрана. В простейших
    случаях эта функция BIOS позволяет вам определить строку и колонку
    без определения их отображения в буфер дисплея. При построении
    больших картин, а также при выполнении любой графической работы эти
    функции требуют очень много времени. Программа должна вызывать BIOS
    при выдаче каждой точки на экран. В случае режима высокого
    разрешения программа должна вызвать BIOS 128000 раз, чтобы
    изобразить каждую точку правильно. Хотя программы, входящие в BIOS
    выполняется очень быстро, она должна вычислять адрес буфера всякий
    раз, когда получает информацию о строке и колонке. Для этого
    действия требуется умножение и несколько сложений, и следовательно,
    требуется некоторое время. В общем случае программа записывает
    график с помощью стартового положения точки и смещений относительно
    этого положения. Это означает, что программа вычисляет положение
    первой точки с помощью алгоритма отображения в буфер, а положения
    остальных точек отсчитывает от текущего адреса буфера.

Выдача на телетайп


    Функция выдачи на телетайп видеопрограммы BIOS предназначена для
    тех программ, которые хотят использовать дисплей в простейшей
    форме.  Эта функция представляет дисплей в виде телетайпа.    Данная
    программа выполняет обслуживание установки курсора и выдачи
    символа.  После того, как BIOS заносит символ в текущую позицию, он
    перемещает курсор в следующую позицию.  Если курсор попал за
    пределы строки, программа BIOS сдвигает дисплей вверх на одну
    строку, и помещает курсор в первую позицию следующей строки.
 
      Кроме того, что программа выдачи на телетайп дает удобный метод
    выдачи символов на экран, она служит хорошим примером использования
    видеопрограммы BIOS для обслуживания символов. Эта программа
    записывает символы, перемещает курсор, а также сдвигает экран,
    когда это небходимо, а также реагирует на некоторые служебные
    символы. Символ возврата на шаг назад перемещает курсор на одну
    позицию назад, возврат каретки перемещает курсор в начало строки, а
    перевод строки переносит курсор на следующую строку, если надо
    сдвигая экран. И наконец, символ звукового сигнала (код 7) вызывает
    генерацию звука с помощью динамика. ОС использует эту функцию BIOS
    для поддержки большинства своих дисплейных функций.