Аппаратное обеспечение персонального компьютера

         

Установка таймера с сигнализацией


BIOS компьютеров IBM PC/AT содержит еще две интересные функции для работы с таймером. Это функции 83h и 86h прерывания INT 15h.

Функция 83h INT 15h позволяет запустить таймер на счет, указав адрес некоторого байта в оперативной памяти. Программа, запустившая таймер, сразу после запуска получает управление. По истечении времени, заданного при запуске таймера, функция устанавливает старший бит указанного байта в единицу, сигнализируя таким образом программе о завершении указанного временного интервала. Программа может также отменить работу таймера в этом режиме.

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

Приведем формат вызова функции 83h прерывания INT 15h:

Регистры на входе:

AH = 83h

AL = код подфункции:

                0 – установить интервал, запустить таймер;

                1 - отменить работу таймера;

CX = старший байт времени работы счетчика, задается в микросекундах;

DX = младший байт счетчика;

ES:BX = адрес байта, в котором по истечении интервала времени будет установлен старший бит

Регистры на выходе:

Регистры не используются





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


Для установки времени можно использовать функцию 2Dh:

Регистры на входе:

AH = 2Dh

CH = часы (0-24);

CL = минуты (0-59);

DH = секунды(0-59);

DL = сотые доли секунды (0-99)

Регистры на выходе:

AL = 0, если установка выполнена правильно;

AL = FFh, если при установке были заданы неправильные параметры



Установка временных характеристик клавиатуры


Мы уже рассказывали о возможности изменения временных характеристик клавиатуры. Если BIOS, установленная в вашей машине, изготовлена после 15 декабря 1985 года, вы можете воспользоваться функцией 03h для ускорения (или замедления) работы клавиатуры:

Регистры на входе:

AH = 03h;

AL = 05h;

BL = Период автоповтора (количество повторов за одну секунду)

BH = Задержка включения режима автоповтора

Регистры на выходе:

Не используются

Период автоповтора задается следующим образом:

Содержимое регистра BL

Период автоповтора

0

30,0

1

26,7

2

24,0

4

20,0

8

15,0

0Ah

10,0

0Dh

9,2

10h

7,5

14h

5,0

1Fh

2,0

Для задержки включения режима автоповтора вы можете указывать следующие значения:

Содержимое регистра BH

Задержка включения режима автоповтора, mc

0

250

1

500

2

750

3

1000

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

union REGS  rg;

. . .

rg.h.al = 5;

rg.h.ah = 3;

// Устанавливаем максимальное быстродействие клавиатуры

rg.h.bl = 0;

rg.h.bh = 0;

int86(0x16, &rg, &rg);

. . .

// Восстанавливаем исходное быстродействие клавиатуры

rg.h.bl = 0xa;

rg.h.bh = 1;

int86(0x16, &rg, &rg);



Вещественные числа


Перед тем как приступить к изучению форматов вещественных чисел, используемых сопроцессором, вспомним о числах с плавающей точкой, встречающихся в научных расчетах.

В общем виде эти числа можно записать следующим образом:

(знак)(мантисса)*10(знак)(порядок)

Например: -1.35*105.

Здесь знак - это минус, мантисса - 1.35, порядок - 5. Порядок тоже может иметь знак. В этом представлении чисел для вас вряд ли есть что либо новое. Вспомним также такое понятие, как норамализованное представление чисел:

если целая часть мантиссы числа состоит из одной цифры, не равной нулю, то число с плавающей точкой называется нормализованным

В чем преимущества использования нормализованных чисел?

В том, что для фиксированной разрядной сетки числа (то есть для фиксированного количества цифр в числе) нормализованные числа имеют наибольшую точность. Кроме того, нормализованное представление исключает неоднозначность - каждое число с плавающей точкой может быть представлено различными (ненормализованными) способами:

123.5678*105 = 12.35678*106

= 1.235678*107 = 0.1235678*108

Для тех, кто программировал на языках высокого уровня, знакомо следующее представление чисел с плавающей точкой:

(знак)(мантисса)E(знак)(порядок)

Например, -5.35E-2 означает число -5.35*10-2. Такое представление называется научной нотацией.

Арифметический сопроцессор может работать с вещественными числами в трех форматах:

одинарной точности;

двойной точности;

расширенной точности

Эти числа занимают в памяти, соответственно, 4, 8 или 10 байт (рис. 10.1).

Рис. 10.1. Различные представления вещественных чисел

В любом представлении старший бит определяет знак вещественного числа:

0 - положительное число;

1 - отрицательное число

Все равные по абсолютному значению положительные и отрицательные числа отличаются только этим битом. В остальном числа с разным знаком полностью симметричны. Для представления отрицательных чисел здесь не используется дополнительный код, как это сделано в центральном процессоре.


Арифметический сопроцессор работает с нормализованными числами, поэтому поле мантиссы содержит мантиссу нормализованного числа.

Так как здесь используется двоичное представление чисел, сформулируем определение нормализованного числа для двоичного представления:

если целая часть мантисса числа в двоичном представлении равна 1, то число с плавающей точкой называется нормализованным

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

Для наглядности представим мантиссу числа в следующей форме:

n.nnnnnnnnnn...n

Здесь символом n обозначается либо 0, либо 1. Нормализованные числа в самой левой позиции содержат 1, поэтому их можно изобразить еще и в таком виде:

1.nnnnnnnnnn...n

Представление с расширенной точностью используется сопроцессором для выполнения всех операций. И даже более - все операции с числами сопроцессор выполняет над числами только в формате с расширенной точностью. В этом формате хранится и "лишний" бит целой части нормализованного числа.

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

Поле порядка - это степень числа 2, на которую умножается мантисса, плюс смещение, равное 127 для одинарной точности, 1023 - для двойной точности и 16383 - для расширенной точности.

Для того, чтобы определить абсолютное значение числа с плавающей точкой, можно воспользоваться следующими формулами:

Одинарная точность:

1.(цифры мантиссы)*2(P-127)

Двойная точность:

1.(цифры мантиссы)*2(P-1023)

Расширенная точность:

1.(цифры мантиссы)*2(P-16383)

Знак числа, как мы уже говорили, определяется старшим битом.

Приведем конкретный пример. Пусть мы имеем число с одинарной точностью, которое в двоичном виде выглядит следующим образом:



1 01111110 11000000000000000000000

Для этого числа знаковый бит равен 1 (отрицательное число), порядок равен 126, мантисса - 11 (в двоичной системе счисления).

Значение этого числа равно:

1.11 * 2(126-127) = -1.75 * 2-1 = -0,875

Рассмотрим теперь особые случаи представления вещественных чисел.

нуль - это такое число, у которого порядок и мантисса равны нулю. Нуль может иметь положительный или отрицательный знаки, которые игнорируются в операциях сравнения. Таким образом, имеется два нуля - положительный и отрицательный;

наименьшее положительное число - это число, которое имеет нулевой знаковый бит, значение порядка, равное 1, и значение мантиссы, равное нулю. В зависимости от представления наименьшее положительное число имеет следующие значения: 1,17*10-38 (одинарная точность), 2.23*10-308

(двойная точность), 3.37*10-4932 (расширенная точность);

наибольшее отрицательное число - полностью совпадает с наименьшим положительным числом, но имеет бит знака, установленный в 1;

наибольшее положительное число - это число, которое имеет нулевой знаковый бит, поле порядка, в котором все биты кроме самого младшего, равны 1, и содержит единицы во всех разрядах мантиссы. В зависимости от представления наибольшее положительное число имеет следующие значения: 3.37*1038

(одинарная точность), 1.67*10308 (двойная точность), 1.2*104932

(расширенная точность);

наименьшее отрицательное число - полностью совпадает с наибольшим положительным числом, но имеет бит знака, установленный в 1;

положительная и отрицательная бесконечность - это число содержит все единицы в поле порядка и все нули в поле мантиссы. В зависимости от состояния знакового бита может быть положительная и отрицательная бесконечности. Бесконечность может получиться, например, как результат деления конечного числа на нуль;

нечисло - содержит все единицы в поле порядка и любое значение в поле мантиссы. Нечисло может возникнуть в результате выполнения неправильной операции при замаскированных особых случаях (ошибкам при работе с сопроцессоре будет посвящен отдельный раздел этой главы);

неопределенность - содержит в поле порядка все единицы, а в поле мантиссы - число 1000..0 (для одинарной и двойной точности) или 11000..0 (для расширенной точности, так как в этом формате хранится старший бит мантиссы).

Для большей наглядности сведем все возможные представления вещественных чисел вместе на рис. 10.2.



Рис. 10.2. Возможные предстваления вещественных чисел


Включить эмуляцию светового пера


Световое перо теперь можно увидеть разве лишь в музее. Однако вы можете заменить световое перо на мышь, если ваша программа использует световое перо (например, она написана на языке Бейсик и вызывает функцию PEN). Для включения эмуляции светового пера вы можете воспользоваться функцией 0Dh:

Регистры на входе:

AX = 000Dh

Регистры на выходе:

Регистры не используются

После включения режима эмуляции драйвер запоминает координаты курсора в момент, когда пользователь нажимает на клавиши мыши. Эти координаты могут быть впоследствии считаны функцией PEN или функцией 04h прерывания INT 10h, предназначенной для работы со световым пером.



Включить курсор мыши


Функция 01h позволяет включать или выключать курсор мыши:

Регистры на входе:

AX = 0001h

Регистры на выходе:

Регистры не используются

Для управления видимостью курсора драйвер мыши использует внутренний счетчик. Этот счетчик можно увеличивать, вызывая функцию 01h прерывания INT 33h, или уменьшать при помощи функции 02h этого же прерывания.

После инициализации драйвера функцией 00h счетчик устанавливается равным -1. После первого вызова функции 01h счетчик становится равным 0. При этом курсор мыши становится видимым, его можно перемещать по экрану.

Если счетчик равен 0, то следующие вызовы функции 01h игнорируются драйвером. Для того, чтобы погасить курсор, используйте функцию 02h, которая при вызове уменьшает каждый раз содержимое счетчика на единицу.

Функция 01h сбрасывает область, в которой курсор не отображается (если такая область была ранее установлена функцией 10h).



Восстановить драйвер мыши


Функция 20h восстанавливает связь между мышью и драйвером, отключенную вызовом функции 1Fh.

Регистры на входе:

AX = 0020h

Регистры на выходе:

Регистры не используются



Восстановить состояние драйвера


Функция 17h позволяет восстановить состояние драйвера из буфера, в который оно было записано при помощи функции 16h.

Регистры на входе:

AX = 0017h

ES:DX = адрес буфера, содержащего состояние драйвера

Регистры на выходе:

Регистры не используются



Возобновление проигрывания звуковой дорожки


Команда останавливает проигрывание звуковой дорожки.

Формат заголовка запроса:

// ---------------

// Код команды 136

// ---------------

#pragma pack(1)

typedef struct _RsumePlay

{            

  ReqHdr rh;

} RsumePlay;

Заполнение полей заголовка запроса:

Поле

Описание

rh.wStatus

После вызова драйвера содержит слово состояния



Возврат каретки


Код команды: 0Dh

По этой команде распечатываются все символы из буфера принтера, затем печатающая головка возвращается к началу строки. В зависимости от состояния переключателя конфигурации может дополнительно выполняться прогон бумаги на одну строку.



Второй способ проигрывания музыки


Программа может генерировать звуки и другим способом, не используя таймер. Для этого нужно сбросить младший бит порта 61h и, управляя битом 1 этого порта, формировать импульсы для громкоговорителя. Иными словами, программа должна периодически то устанавливать этот бит,  то сбрасывать. Высота генерируемого звука будет соответствовать периоду изменения состояния указанного бита.

Можно также комбинировать описанные способы, получая разнообразные звуковые эффекты.



Несмотря на широкое распространение новых


Несмотря на широкое распространение новых операционных систем, таких как Microsoft Windows 95, Microsoft Windows NT и IBM OS/2 Warp, а также новых технологий программирования, ориентированных на Internet и средства высокого уровня, до сих пор остается актуальным создание программ, работающих с аппаратурой компьютера через порты, прерывания и функции драйверов. Многие разработчики занимаются созданием драйверов для нестандартной аппаратуры, и поэтому нуждаются в описании регистров периферийных устройств и методик работы с этими устройствами на уровне регистров и прерываний.
Перечисленные выше вопросы были рассмотрены нами во 2 томе «Библиотеки системного программиста» с названием «Аппаратное обеспечение IBM PC”, который был издан в 1992 году. С тех пор аппаратура персонального компьютера претерпела определенные изменения, не говоря уже о возникновении и широком распространении новых периферийных устройств. Поэтому мы решили переиздать упомянутый том «Библиотеки системного программиста», обновив и дополнив его новой информацией.
Первая глава нашей книги посвящена определению конфигурации компьютера. Мы научим вас определять состав аппаратных средств компьютера с помощью функций BIOS, а также анализируя содержимое энергонезависимой памяти CMOS. Много внимания мы уделим определению типа центрального процессора. С помощью программы, исходные тексты которой есть в первой главе, можно распознать процессоры начиная от теперь уже исторической модели Intel 8086 до суперсовременного Intel Pentium II.
Во второй главе мы расскажем о работе с клавиатурой на уровне портов ввода/вывода, прерываний, функций BIOS и MS-DOS. Вся эта информация необходима разработчикам диалоговых программ для операционной системы MS-DOS. Что же касается приложений Microsoft Windows, то способы работы с клавиатурой в среде этой операционной системы мы описали в 11 томе “Библиотеки системного программиста”, который называется “Операционная система Microsoft Windows для программиста”.
Третья глава посвящена мыши.
Это устройство удобно для пользователя, поэтому вам не стоит игнорировать мышь в своих программах. Помимо традиционных функций драйвера мыши мы описали методику программирования новой мыши Microsoft IntelliPoint в среде Microsoft Windows (в среде MS-DOS эта мышь работает как обычная двухкнопочная). Мышь Microsoft IntelliPoint имеет новый орган управления - небольшое колесико, которое можно вращать, а также нажимать подобно обычной клавише.
В четвертой главе описаны способы работы с часами реального времени. Вы можете применять эти часы для определения текущей даты и времени или для установки будильника, после срабатывания которого компьютер начнет выполнять какие-либо действия.
В пятой главе мы рассмотрели другое устройство компьютера, имеющее отношение ко времени - системный таймер. Этот таймер удобно использовать для организации программных задержек, для генерации звуковых сигналов, как простых, так и музыкальных, а также как генератор случайных чисел.
В шестой и седьмой главах нашей книги мы рассмотрели последовательный асинхнонный адаптер и параллельный адаптер. Первый из них чаще всего используется для подключения модема, а второй - для подключения принтера. Пользуясь информацией, приведенной в нашей книге, вы сможете программировать эти адаптеры на уровне портов ввода/вывода, функций BIOS и MS-DOS.
Восьмая глава посвящена контроллеру прямого доступа к памяти. В ней мы рассказали о назначении портов этого контроллера в компьютерах IBM PC/XT и IBM PC/AT.
В девятой главе описана методика работы с устройством чтения компакт-дисков, которым сейчас оборудован практически каждый компьютер. Мы рассмотрели применение функций программного расширения MSCDEX, а также команд драйвера устройства чтения компакт-дисков. Эта информация поможет вам определить различные характеристики устройства и параметры компакт-дисков, такие, например, как способность проигрывать звуковые компакт-диски, количество, размер и тип дорожек на компакт-диске и так далее. Обращаясь непосредственно к драйверу устройства, ваша программа сможет выполнять непосредственное чтение секторов и дорожек компакт-диска, запускать и останавливать проигрывание звуковых дорожек и другие аналогичные операции.


Десятая глава необходима тем, кто разрабатывает программы, связанные с вычислениями. В этой главе мы рассказали про арифметический сопроцессор и привели методики его программирования. Этот сопроцессор значительно ускоряет арифметические вычисления, особенно вычисления с плавающей запятой. В качестве примера мы привели исходные тексты программы, проверяющий сопроцессор на наличие ошибки при выполнении команды деления, которая встречалась в первых моделях процессора Pentium.
И, наконец, последняя, одиннадцатая глава посвящена работе с расширенной памятью с помощью интерфейса драйвера HIMEM.SYS. Используя функции этого интерфейса, ваша программа, предназначенная для операционной системы MS-DOS, сможет воспользоваться расширенной памятью, недоступной для непосредственной адресации в реальном режиме работы процессора.
Исходные тексты всех программ вы можете купить на дискете, которая продается вместе с книгой. Эти тексты, так же как и исходные тексты программ из всех предыдущих томов “Библиотеки системного программиста”, вы можете найти на нашем авторском компакт-диске. Подробая информация об авторском компакт-диске есть в сети Internet на нашем сервере по адресу http://www.glasnet.ru/~frolov или http://www.dials.ccas.ru/frolov.

Ввод строки символов


Функция 0Ah предназначена для ввода с клавиатуры строки символов:

Регистры на входе:

AH = 0Ah

DS:DX = адрес буфера для ввода строки

Регистры на выходе:

Буфер содержит введенную строку

Функция проверяет комбинации клавиш <Control+C> и <Control+Break>

Перед вызовом функции необходимо специальным образом подготовить буфер, адрес которого передается в регистрах DS:DX - в первый байт буфера следует записать максимальную длину max вводимой строки (в диапазоне от 1 до 244).

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

Ввод осуществляется до тех пор, пока либо количество введенных символов не достигнет max-1, либо пока не будет нажата клавиша <Enter> с кодом 0Dh. Если оператор уже ввел max-1 символ и продолжает вводить символы дальше, функция выдает звуковой сигнал и игнорирует вводимые символы до тех пор, пока не будет нажата клавиша <Enter>.

При вводе строки можно использовать стандартные средства редактирования MS-DOS, используемые при вводе команд в режиме командной строки.



Вводс консоли и вывод на консоль


Функция 06h может использоваться как для ввода с консоли, так и для вывода символов на консоль. Режим работы функции зависит от содержимого регистра DL при вызове функции. Если в этом регистре находится значение 0FFh, функция выполняет ввод с консоли, в противном случае символ, код которого записан в этот регистр, выводится на консоль.

Регистры на входе:

AH = 06h

DL = 0FFh - для ввода символа с консоли;

или

DL = код символа, не равный 0FFh - для вывода символа на консоль

Регистры на выходе:

ZF = 0, если в буфере имеется код нажатой клавиши;

ZF = 1, если буфер клавиатуры пуст;

AL = код ASCII символа или 0, если AH содержит расширенный код ASCII символа;

AH = скан-код или расширенный код ASCII символа, если AL=0

Функция проверяет комбинации клавиш <Control+C> и <Control+Break>

Очевидно, что с помощью этой функции нельзя вывести на консоль символ с кодом 0FFh.

Основное отличие функции 06h от всех описанных ранее заключается в том, что эта функция не ожидает, пока пользователь нажмет на клавишу. Если буфер клавиатуры пуст, функция просто устанавливает флаг процессора ZF. Если же в буфере клавиатуры имеются символы, флаг ZF сбрасывается и в регистр AL функция записывает код ASCII символа.



Выключить эмуляцию светового пера


Функция 0Eh выключает режим эмуляции светового пера.

Регистры на входе:

AX = 000Eh

Регистры на выходе:

Регистры не используются



Выключить курсор мыши


Функция 02h уменьшает на единицу счетчик видимости курсора. Если содержимое счетчика становится равным -1, изображение курсора пропадает с экрана.

Регистры на входе:

AX = 0002h

Регистры на выходе:

Регистры не используются

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

Это связано с тем, что драйвер мыши запоминает старое значение атрибута символа, на который указывал курсор до обновления содержимого видеопамяти. Вы изменили атрибут, записав новое значение непосредственно в экранную память. Теперь, если установить курсор мыши на другой символ, изображение старого символа будет испорчено - появится прямоугольник (как бы еще одно изображение курсора мыши).



Вывод байта на принтер через параллельный адаптер


Для того, чтобы вывести символ на принтер, программа вначале должна убедится, что уровень сигнала на линии BUSY (бит 7 порта 379h) равен 0, а уровень сигнала на линии ACK (бит 6 порта 379h) - единице. После этого следует установить код выходного символа на линиях DATA (порт 378h).

Затем не ранее, чем через 0,5 мкс линию STROBE (бит 0 порта 37Ah) необходимо перевести в состояние логического 0. При этом выходной символ запишется во внутренний буфер принтера. Уровень логического нуля необходимо удерживать в течение как минимум 0,5 мкс. Это время нужно для того, чтобы символ записался в буфер принтера. После истечения интервала времени линию STROBE нужно опять перевести в состояние логической единицы.

После того, как программа установит линию STROBE в состояние логического нуля, выходная линия принтера BUSY устаналвивается в единицу, сигнализируя о том, что принтер занять обработкой полученного символа и временно не может принимать другие символы.

Когда принтер полность обработает выведенный символ, линия ACK перейдет в состояние 0. Приблизительно через 5 мкс после этого линия BUSY также перейдет в состояние 0.

Еще через 5 мкс линия ACK примет состояние 1. Теперь принтер готов принят следующий байт данных.



Вызов драйвера CD-ROM


Функция 10h предназначена для прямого вызова драйвера устройства чтения CD-ROM:

Регистры на входе:

AX = 1510h;

CX = номер устройства чтения CD-ROM;

ES:BX = адрес предварительно заполненного заголовка запроса драйвера

Регистры на выходе:

Не используются

Перед вызовом этой функции вы должны подготовить заголовок запроса.

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



Задать диапазон движения курсора по горизонтали


Функция 07h позволяет ограничить диапазон перемещений курсора мыши по горизонтали:

Регистры на входе:

AX = 0007h

CX = минимальная координата X;

DX = максимальная координата X

Регистры на выходе:

Регистры не используются



Задать диапазон движения курсора по вертикали


Функция 08h позволяет ограничить диапазон перемещений курсора мыши по вертикали.

Регистры на входе:

AX = 0008h

CX = минимальная координата Y;

DX = максимальная координата Y

Регистры на выходе:

Регистры не используются



Задать форму курсора в графическом режиме


С помощью функции 09h программа, работающая в графическом режиме, может изменить форму курсора мыши и положение точки внутри изображения курсора, координаты которой используются в качестве координат курсора остальными функциями.

Регистры на входе:

AX = 0009h

BX = номер позиции точки-указателя графического курсора (от -16 до 16);

CX = номер строки точки-указателя (от -16 до 16);

ES:DX = указатель на растровое изображение курсора

Регистры на выходе:

Регистры не используются

Регистры ES:DX указывают на область памяти размером 64 байт. Эта область состоит из двух массивов длиной по 32 байт. Первый массив представляет собой логическую маску размером 16х16 бит, которая накладывается на участок видеопамяти с использованием логической операции “И”. Второй массив - тоже маска размером 16х16 бит, но она накладывается с использованием логической операции “Исключающее ИЛИ”, инвертируя отдельные точки изображения.

Номера позиции и строки точки-указателя, устанавливаемые по умолчанию, равны 0 (BX=CX=0). Это соответствует верхней левой точке в изображении курсора. Значения BX=CX=15 соответствуют нижней правой точке.



Задать форму курсора в текстовом режиме


С помощью функции 0Ah программа может изменять форму курсора мыши в текстовом режиме.

Регистры на входе:

AX = 000Ah

BX = тип курсора:

                0 - определяемый программно;

                1 - определяемый аппаратно;

CX = маска экрана (для BX=0) или начальная строка курсора (для BX=1);

DX = маска курсора (для BX=0) или конечная строка курсора (для BX=1)

Регистры на выходе:

Регистры не используются

В зависимости от содержимого регистра BX драйвер мыши использует курсор, определяемый аппаратными средствами, либо курсор, определяемый программно. По умолчанию используется “программный курсор”, который отображается в виде символа с инвертированным значением атрибута. Курсор, сформированный аппаратными средствами, выглядит аналогично обычному текстовому курсору, его форма - прямоугольник. Размер этого прямоугольника можно задавать при помощи регистров CX и DX.

Для курсора, определяемого программно, вначале выполняется операция логического “И” над содержимым видеопамяти в том месте, куда указывает курсор, и маской экрана. Затем выполняется операция “Исключающее ИЛИ” с маской курсора.

Младший байт масок соответствует коду ASCII символа, старший - это байт атрибута символа.

Значения, используемые по умолчанию - BX=7700h, CX=FFFFh.

Если вам надо изменить цвет курсора, не меняя его форму, задайте CX=00FFh, BX=xx00h, где xx определяет цвет (смотри описание формата байта атрибутов в 21 томе «Библиотеки системного программиста», который называется «Программирование видеоадаптеров»).



Задать скорость перемещения курсора мыши


Функция 0Fh определяет чуствительность мыши к перемещению по поверхности стола, то есть устанавливает соответствие между величиной перемещения мыши по столу и величиной перемещения курсора мыши по экрану.

Регистры на входе:

AX = 000Fh

CX = количество миков на 8 точек по горизонтали;

DX = количество миков на 8 точек по вертикали

Регистры на выходе:

Регистры не используются

При инициализации драйвера мыши используются следующие значения: CX=8, DX=16.



Задать увеличенный графический курсор


Функция 12h позволяет задать увеличенный по размеру курсор мыши, но она определена только для мыши системы PC MOUSE.

Регистры на входе:

AX = 0012h

BH = ширина курсора в словах;

CH = количество строк в изображении курсора;

BL = номер позиции точки-указателя графического курсора (от -16 до 16);

CL = номер строки точки-указателя (от -16 до 16);

ES:DX = указатель на растровое изображение курсора

Регистры на выходе:

Регистры не используются



Заголовок запроса


Структура и размер заголовка запроса зависит от кода выполняемой команды, однако начальная часть заголовка всегда одна и та же. Для удобства формирования заголовка запроса мы подготовили структуру ReqHdr, соответствующую начальной части заголовка запроса, а также структуры для всех основных команд.

Определение структуры ReqHdr приведено ниже:

typedef unsigned char BYTE;

typedef unsigned int  WORD;

typedef unsigned long DWORD;

#pragma pack(1)

typedef struct _ReqHdr

{

  BYTE bSize;        // размер заголовка запроса в байтах

  BYTE bSubUnit;     // номер устройства subunit

  BYTE bCmd;         // код команды

  WORD wStatus;      // слово состояния

  BYTE bReserved[8]; // зарезервировано

} ReqHdr;

Для удобства мы также определили типы BYTE, WORD и DWORD, которыми будем пользоваться в этой главе.

Поле bSize должно содержать общий размер заголовка запроса, который складывается из размера структуры ReqHdr и размера дополнительной структуры, формат которой зависит от кода команды.

В поле bSubUnit необходиом занести номер устройства, обслуживаемого данным драйвером. Этот номер нетрудно определить с помощью функции 01h расширения MSCDEX.EXE.

В поле bCmd необходимо записать код команды, которую должен выполнить драйвер. Коды и описание команд мы приведем ниже.

После выполнения команды драйвер записывает в поле wStatus слово состояния, по которому можно судить о результате выполнения.

Формат слова состояния:

Поле

Описание

0-7

Код ошибки (если в слове состояния установлен бит 15)

8

Выполнение команды завершено

9

Устройство занято

10-14

Зарезервировано

15

При выполнении команды произошла ошибка

Если команда выполнилась (с ошибкой или без ошибки), в слове состояния установлен бит 8.

При возникновении ошибки также устанавливается бит 15. При этом в поле 0-7 находится код ошибки.

Список кодов ошибок приведен ниже:

Код ошибки

Описание

00h

Защита записи

01h

Неизвестное устройство

02h

Устройство не готово

03h

Неизвестная команда

04h

Ошибка циклической контрольной суммы CRC

05h

Неправильная длина структуры  запроа

06h

Ошибка при поиске

07h

Неизвестный носитель данных

08h

Сектор не найден

09h

В принтере нет бумаги

0Ah

Ошиба при записи

0Bh

Ошибка при чтении

0Ch

Общая ошибка

0Dh

Зарезервировано

0Eh

Зарезервировано

0Fh

Неправильная смена диска

Здесь приведены коды ошибок не только для устройства чтения CD-ROM, но и для других устройств (например, для принтера).



Загрузка констант


FLDZ    0 -> ST(0) - Загрузить нуль

FLD1    1 -> ST(0) - Загрузить единицу

FLDPI   p -> ST(0) - Загрузить число p ("пи")

FLDL2T  loge10 -> ST(0) - Загрузить loge10

FLDL2E  log2e -> ST(0) - Загрузить log2e

FLDLG2  log102 -> ST(0) - Загрузить log102

FLDLN2  loge2 -> ST(0) - Загрузить loge2

Загрузка констант выполняется намного быстрее специальными командами, нежели командами загрузки данных из оперативной памяти.



Закрывание приемного устройства для компакт-диска


// ---------------

// Код функции 5

// ---------------

#pragma pack(1)

typedef struct _CloseTray

{

  BYTE   bFunctionCode;

} CloseTray;

Поле

Описание

bFunctionCode

Код функции



Закрывание устройства


Команда закрывает устройство чтения CD-ROM, открытое предыдущей командой.

Формат заголовка запроса:

// ---------------

// Код команды 14

// ---------------

#pragma pack(1)

typedef struct _RsumePlay

{            

  ReqHdr rh;

} RsumePlay;

Заполнение полей заголовка запроса:

Поле

Описание

rh.wStatus

После вызова драйвера содержит слово состояния



Заменить драйвер событий


Функция 14h аналогична функции 0Ch, однако ее основное назначение - временная замена драйвера событий. Например, подпрограмма в начале своей работы может установить свой драйвер событий, а перед завершением - активизировать драйвер, использовавшийся ранее.

Регистры на входе:

AX = 0014h

CX = маска вызова;

ES:DX = адрес подключаемого драйвера событий

Регистры на выходе:

CX = маска предыдущего драйвера событий;

ES:DX = адрес предыдущего (заменяемого) драйвера событий



Запись IOCTL Output


При помощи команды IOCTL Output программа может заставить драйвер выполнять различные операции, такие как управление механизмом извлечения компакт-диска.

Формат заголовка запроса:

// ---------------

// Код команды 12

// ---------------

#pragma pack(1)

typedef struct _IOCTL_Output

{            

  ReqHdr rh;

  BYTE   bMediaDescriptor;

  DWORD  lpTransferAddress;

  WORD   wDataSize;

  WORD   wStartSector;

  DWORD  lpVolID;

} IOCTL_Output;      

Заполнение полей заголовка запроса:

Поле

Описание

rh.wStatus

После вызова драйвера содержит слово состояния

bMediaDescriptor

Байт описания среды носителя данных, должен быть равен нулю

lpTransferAddress

Адрес буфера

wDataSize

Размер буфера

wStartSector

Номер начального сектора, должен быть равен нулю

lpVolID

Указатель на идентификатор тома, если при выполнении команды возникла ошибка с кодом 0Fh

Рассмотрим форматы заголовков различных функций, выполняемых в рамках команды IOCTL Output.



Запись символов в буфер клавиатуры


С помощью функции 05h можно вставить символы в буфер клавиатуры, как будто они были введены оператором.

Регистры на входе:

AH = 05h;

CL = код ASCII записываемого символа;

CH = скан-код записываемого символа, или 0

Регистры на выходе:

AL = 0  - запись выполнена успешно;

AL = 1  - буфер клавиатуры переполнен

Приведенная ниже фрагмент программы записывает в буфер клавиатуры пять символов '*'. Если запустить программу, соедржащую этот фрагмент кода, а затем посмотреть на системное приглашение, то вы увидите что-нибудь похожее на C:\>*****.

union REGS  rg;

int   i;

for(i=0; i<5; i++)

{

  rg.h.ah = 5;

  rg.h.cl = '*';

  rg.h.ch = 9;

  int86(0x16, &rg, &rg);

}



Запись в стек


FLD     ST(0) <- память, вещественный формат

FILD    ST(0) <- память, целый формат

FBLD    ST(0) <- память, десятичный формат

Команды FLD, FILD, FBLD загружают в вершину стека вещественное, целое и десятичное числа, соответственно.

При выполнении этих команд операнд считывается из оперативной памяти, преобразуется в формат с расширенной точностью. Затем поле ST регистра состояния уменьшается на единицу и выполняется запись операнда в численный регистр, определяемый новым значением поля ST. То есть операнд записывается в стек численных регистров, а указатель стека (поле ST) уменьшается на единицу. По своему действию эти команды напоминают команду PUSH центрального процессора.

Непосредственно перед загрузкой численного регистра проверяется содержимое поля TAG0. Если это содержимое не равно 11 (пустой регистр), в регистре состояния устанавливается флаг IE (недействительная операция) и вырабатывается прерывание (если в регистре управления не установлена маска IM - маска недействительной операции).



Запись в устройство управляющей строки


// ---------------

// Код функции 4

// ---------------

#pragma pack(1)

typedef struct _DriveControlBytes

{            

  BYTE bFunctionCode;

  BYTE bWriteBuff[...]; // размер зависит от устройства

} DriveControlBytes;

Поле

Описание

bFunctionCode

Код функции

bWriteBuff

Буфер с управляющими данными, которые будут записаны в устройство чтения CD-ROM. Формат зависит от типа устройства



Запросить область HMA


Регистры на входе:

AH = 01h

DX = размер памяти в байтах в области HMA, которая будет использоваться резидентными программами или драйверами. Обычная программа должна указывать значение DX, равное 0FFFFh

Регистры на выходе:

AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка

Ошибки:

BL = 80h, 81h, 90h, 91h, 92h (описание кодов ошибок будет приведено после описания всех функций)

С помощью этой функции программа может зарезервировать для себя область HMA. Задаваемый в регистре DX размер памяти сравнивается с указанным в параметре драйвера /HMAMIN=. Область HMA распределяется запросившей программе только в том случае, если запрошенный в регистре DX размер больше или равен указанному в параметре /HMAMIN. Такой механизм позволяет ограничить использование области HMA только теми программами, которые используют ее наилучшим образом.

Поясним это на примере. Пусть при инициализации операционной системы из файла AUTOEXEC.BAT запускаются две программы. Одна из них использует 10 Кбайт из области HMA и запускается первой (в регистре DX функции 01h эта программа указывает значение 10240). Вторая запускаемая программа использует 40 Кбайт и запускается после первой. Очевидно, что вторая программа использует область HMA более эффективно. Но так как область HMA уже распределена первой программе, вторая программа не сможет получить ее для себя.

Задавая параметр /HMAMIN=40, мы запретим распределение области HMA тем программам, которые используют в ней меньше 40 Кбайт. Теперь первая программа не получит доступ к области HMA, даже если она будет запускаться до второй, использующей 40 Кбайт памяти из области HMA.



Запросить область UMB


Регистры на входе:

AH = 10h

DX = размер запрашиваемого блока UMB в параграфах

Регистры на выходе:

AX = 0001h - если функция выполнена успешно, 0000h - если произошла ошибка;

BX = сегмент полученного UMB;

DX = размер полученного блока или размер максимального свободного блока UMB (если невозможно выделить блок требуемого размера)

Ошибки:

BL = 80h, B0h, B1h

Эта функция позволяет программе получить дступ к блокам UMB, лежащих в пределах первого мегабайта адресного пространства. Для использования этих блоков не требуется управлять линией A20.

Если вам надо определить размер доступной области UMB, задайте при вызове этой функции DX=0FFFFh.



Запуск процесса печати файла


Данная функция запускает процесс фоновой печати.

Регистры на входе:

AH = 01h;

AL = 01h;

DS:DX = адрес структуры, с помощью которой функции передается путь к распечатываемому файлу

Регистры на выходе:

AH = состояние системы буферизованной печати

Формат структуры, адрес которой передается функции в регистровой паре DS:DX, представлен ниже:

Смещение

Длина

Описание

0

1

Уровень запроса, равен 0

1

4

Полный адрес строки в формате ASCIIZ,                                 содержащей путь к файлу



и 12h используются для хранения


В компьютерах IBM PS/2 ячейки памяти CMOS с адресами 11h и 12h используются для хранения типа, соответственно, первого и второго НМД.