Глава 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
для поддержки большинства своих дисплейных функций.