Введение
      Соглашения о числах, принятые в этой книге.
      Введение

   Глава 1. Системные ресурсы.
      Раздел 1. Ревизия системных ресурсов.
        Доступ к микросхеме интерфейса с периферией 8255.
        Определение типа IBM PC.
        Определение версии MS DOS.
        Определение числа и типов адаптеров дисплея.
        Определение числа и типа дисковых накопителей.
        Определение числа и типа периферийных устройств.
        Ревизия количества памяти.
      Раздел 2. Управление прерываниями.
        Программирование контроллера прерываний 8259.
        Запрет/разрешение отдельных аппаратных прерываний.
        Написание собственного прерывания.
        Дополнение к существующему прерыванию.
      Раздел 3. Управление программами.
        Манипуляции с памятью.
        Запуск одной программы из другой.
        Использование команд интерфейса с пользователем из программы.
        Сохранение программы в памяти после завершения.
        Загрузка и запуск программных оверлеев.
        Преобразование программ из типа .EXE в тип .COM.
   Глава 2. Таймеры и звук.
      Раздел 1. Установка и чтение таймера.
        Программирование микросхемы таймера 8253/8254.
        Установка/чтение времени.
        Установка/чтение даты.
        Установка/чтение часов реального времени.
        Задержка программных операций.
        Операции запрограммированные во времени.
        Управление работой в реальном времени.
        Генерация случайных чисел с помощью микросхемы таймера.
      Раздел 2. Создание звука.
        Программирование генератора звука 76496 (только PCjr).
        Генерация тона.
        Генерация звука одновременно с другими действиями.
        Гудок динамика.
        Генерация набора тонов.
        Генерация строки тонов, одновременно с другими операциями.
        Создание плавного перехода тонов.
        Создание звуковых эффектов.
        Одновременная генерация разных звуков.
   Глава 3. Клавиатура.
      Раздел 1. Управление клавиатурой.
        Очистка буфера клавиатуры.
        Проверка символов в буфере.
        Ожидать ввод символа и не выводить его на экран.
        Ожидание нажатия клавиши и эхо на экран.
        Прием символа без ожидания.
        Получение строки символов.
        Проверка/установка статуса клавиш-переключателей.
        Написание процедуры  ввода  с клавиатуры общего назначения.
        Перепрограммирование прерывания клавиатуры.
Раздел 2. Доступ к отдельным клавишам.
        Использование клавиш  <BackSpace>,  <Enter>,  <Escape> и <Tab>.
        Использование клавиш-переключателей: <Shift>, <Ctrl>  и  <Alt>.
        Использование клавиш-переключателей: NumLock,  CapsLock, Ins и ScrollLock.
        Использование цифровой дополнительной клавиатуры и  кла-
        виш перемещения курсора.
        Использование функциональных клавиш.
        Перепрограммирование отдельных клавиш.
        Создание макроопределений для отдельных клавиш.
        Создание процедуры обработки Ctrl-Break.
        Перепрограммирование клавиши PrtSc.
      Раздел 3: Сводка кодов клавиш и применений.
        Предопределенное использование клавиш.
        Сводная таблица скан-кодов.
        Сводная таблица кодов ASCII
        Сводка кодов псевдографики для построения рамок.
        Сводная таблица расширенных кодов.
   Глава 4. Вывод на терминал.
      Раздел 1. Управление выводом на терминал.
        Программирование контроллера дисплея 6845.
        Установка/проверка режима дисплея.
        Установка атрибутов/цветов символов.
        Установка цвета границы экрана.
        Очистка части/всего экрана.
        Переключение между видеоадапторами.
      Раздел 2. Управление курсором.
        Установка курсора в абсолютную позицию.
        Относительное позиционирование курсора
        Включение и выключение курсора.
        Изменение формы курсора.
        Чтение/сохранение/восстановление позиции курсора.
        Создание альтернативных типов курсора.
      Раздел 3. Вывод символов на экран.
        Вывод на экран одного символа.
        Вывод строки символов на экран.
        Чтение символа и его атрибутов в данной позиции.
        Создание специальных символов.
        Сводка данных для описания символов.
      Раздел 4. Вывод точечной графики.
        Установка цветов для точечной графики.
        Рисование точки на экране (монохромный, цветной и PCjr).
        Рисование точки на экране (EGA).
        Определение цвета точки экрана.
        Рисование линий на экране.
        Заполнение областей экрана.
        Графический вывод с использованием символов псевдографики.
      Раздел 5. Сдвиг экрана и страницы.
        Вертикальный сдвиг текстового экрана.
        Сдвиг текстового экрана горизонтально.
        Переключение между текстовыми страницами.
        Сдвиг между страницами текста.
   Глава 5. Дисковые накопители.
      Раздел 1. Управление распределением диска.
        Чтение таблицы размещения файлов.
        Определение доступного дискового пространства.
        Получение/установка размера файла.
        Восстановление  после  ошибок,  связанных  с  нехваткой
        пространства на диске.
Раздел 2. Работа с каталогами диска.
        Чтение/изменение корневого каталога.
        Создание/удаление подкаталога.
        Чтение/изменение подкаталога.
        Получение/установка текущего каталога.
        Получение/установка времени  и даты последнего доступа к
        файлу.
        Спрятанные и защищенные от записи файлы.
        Чтение/изменение метки тома.
      Раздел 3. Подготовка к работе с файлами.
        Установка/проверка накопителя по умолчанию.
        Создание/удаление файла.
        Открытие/закрытие файла.
        Переименование файла;  изменение позиции файла в каталоге.
        Подготовка к файловым операциям.
        Анализ информации командной строки.
      Раздел 4. Чтение и запись файла.
        Программирование контроллера НГМД 765 и микросхемы пря-
        мого доступа к памяти 8237.
        Чтение/запись определенных секторов.
        Запись в последовательные файлы.
        Чтение из последовательных файлов.
        Запись в файлы прямого доступа.
        Чтение из файлов прямого доступа.
        Проверка данных после операций чтения/записи.
        Определение дисковых ошибок и восстановление после них.
   Глава 6. Принтер.
      Раздел 1. Управление работой принтера.
        Инициализация  порта  принтера/повторная  инициализация
        принтера.
        Проверка того, что принтер связан с машиной.
        Интерпретация  ошибок принтера и  восстановление  после них.
        Переключение между двумя или несколькими принтерами.
      Раздел 2. Установка спецификаций печати.
        Установка текстового и графического режимов.
        Управление расстоянием между строками.
        Управление движением бумаги.
        Управление положением печатающей головки.
        Установка позиций табуляции.
        Изменение шрифта печати.
        Сравнение возможностей принтеров IBM.
      Раздел 3. Посылка данных на принтер.
        Вывод текстовых или графических данных на принтер.
        Выравнивание правого поля.
        Пропорциональная печать.
        Печать специальных символов.
        Копирование экрана на принтер (дамп экрана).
   Глава 7. Ввод/вывод.
      Раздел 1. Доступ к последовательному порту.
        Программирование микросхемы UART 8250.
        Инициализация последовательного порта.
        Установка текущего коммуникационного порта.
        Определение статуса коммуникационного порта.
        Инициализация и управление модемом.
        Передача данных.
        Получение данных.
        Посылка/получение  данных с  помощью  коммуникационного
        прерывания.
        Сводка управляющих кодов, используемых при коммуникации.
      Раздел 2. Создание драйвера устройства.
        Создание заголовка драйвера.
        Создание стратегии устройства.
        Создание обработчика прерывания устройства.
        Доступ к драйверу устройства.
        Обнаружение и анализ ошибок устройства.
      Раздел 3. Использование специальных устройств ввода/вывода.
        Чтение/запись с кассетного магнитофона.
        Чтение позиции светового пера.
        Получение аналогового ввода через игровой порт.
        Получение цифрового ввода из игрового порта.

   Приложения.
      Приложение А.  Двоичные и шестнадцатиричные числа и  адре-
      сация памяти.
      Приложение Б. Битовые операции в Бейсике.
      Приложение В. Основные сведения об языке ассемблера.
      Приложение Г.  Включение ассемблерных процедур в программы
      на Бейсике.
      Приложение Д. Использование драйвера устройства ANSI.SYS.
      Приложение Е. Набор инструкций микропроцессора 8088.
      Приложение Ж. Набор инструкций микропроцессора 80286.
      Приложение З. Толковый словарь IBM PC.







   Одной  из первых задач после загрузки задачи является проверка
куда мы попали: на каком  типе  IBM  PC  запущена  задача?... под
какой версией MS DOS?... сколько имеется памяти?...  все ли необ-
ходимое оборудование  присутствует? Имеется три способа получения
этой информации.  Наименее элегантный способ - спросить об этом у
пользователя (но знает ли он ответы?). Намного лучше получить всю
доступную  информацию  из установки переключателей  на  системной
плате.  Но эта установка не всегда соответствует реальности. Поэ-
тому  лучше всего использовать третью возможность - получить пря-
мой доступ к требуемому оборудованию  или прочитать нужную инфор-
мацию из области данных BIOS.  Поскольку установка переключателей
может служить отправной точкой  для  получения требуемой информа-
ции, то этот раздел начинается с обсуждения микросхемы,  содержа-
щей эту информацию - микросхемы интерфейса с периферией 8255.
   Программа может  получить  доступ  к оборудованию только двумя
способами.  Она может обратиться к любому из портов ввода/вывода,
соответствующему   присоединенному   оборудованию  (обычно бывает
занята  лишь малая доля из 65535 возможных адресов портов).   Или
программа может обратиться к любому из более чем миллиону адресов
оперативной  памяти.  Сводная таблица адресов портов приведена  в
[7.3.0]. На рис. 1-1  показано  как  распределены в памяти опера-
ционная система и программы.





   Микросхема  интерфейса с периферией Intel 8255 - лучшее место,
с которого надо начинать, чтобы получить  информацию об имеющемся
оборудовании. Эта микросхема предназначена для многих целей.  Она
сообщает об  установке  переключателей  на  системной плате.  Она
принимает для компьютера ввод с клавиатуры.  Она управляет  рядом
периферийных устройств, включая микросхему таймера 8253. Из машин
семейства  IBM  PC  только AT не использует микросхему  8255;  он
хранит информацию об оборудовании  вместе с часами реального вре-
мени  в специальной микросхеме с независимым питанием.  Однако AT
использует те же адреса портов, что  и 8255, для работы с клавиа-
турой и управления микросхемой таймера.
   Микросхема 8255 имеет три однобайтных регистра, называемых  от
порта A до порта C. Адреса этих портов от 60H до 62H сответствен-
но.  Все три порта можно читать, но писать можно только в порт B.
Для PC, установка бита 7 порта B в  1 изменяет информацию, содер-
жащуюся в порте A.  Аналогично для PC установка бита 2 определяет
содержимое  четырех  младших  битов  порта  C, а установка бита 3
делает то же самое для XT. Содержимое этих регистров следующее:

   Порт A (60H)
      когда в порте B бит 7=0
         биты 0-7 PC,XT,PCjr,AT: 8-битные скан-коды с клавиатуры
      когда в порте B бит 7=1 для PC
         бит 0    PC: 0 = нет накопителей на дискетах
             1    PC: не используется
           2-3    PC: число банков памяти на системной плате
           4-5    PC: тип дисплея (11 = монохромный,
                      10 = цветной 80*25, 01 = цветной 40*25)
           6-7    PC: число накопителей на дискетах

   Порт B (61H)
         бит 0    PC,XT,PCjr: управляет каналом 2 таймера 8253
             1    PC,XT,PCjr: вывод на динамик
             2    PC: выбор содержимого порта C
                  PCjr: 1 = символьный режим, 0 = графический
             3    PC,PCjr: 1 = кассетный мотор выключен
                  XT: выбор содержимого порта C
             4    PC,XT: 0 = разрешение ОЗУ
                  PCjr: 1 = запрет динамика и мотора кассеты
             5    PC,XT: 0 = разрешение ошибок щелей расширения
             6    PC,XT: 1 = разрешение часов клавиатуры
           5-6    PCjr: выбор динамика (00 = 8253, 01 = кассета,
                  10 = ввод/вывод, 11 = микросхема 76496)
             7    PC: выбор содержимого порта A
                  PC,XT: подтверждение клавиатуры


   Порт C (62H)
      когда в порте B бит 2=1 для PC или бит 3=1 для XT
      биты 0-3    PC: нижняя половина переключателя 2 конфи-
                  гурации (ОЗУ на плате расширения)
             0    PCjr: 1 = введенный символ потерян
             1    XT: 1 = есть мат. сопроцессор
                  PCjr: есть карта модема
             2    PCjr: есть карта НГМД
           2-3    XT: число банков памяти на системной плате
             3    PCjr: 0 = 128K памяти
             4    PC,PCjr: ввод с кассеты
                  XT: не используется
             5    PC,XT,PCjr: выход канала 2 8253
             6    PC,XT: 1 = проверка ошибок щелей расширения
                  PCjr: 1 = данные с клавиатуры
             7    PC,XT: 1 = контроль ошибок четности
                  PCjr: 0 = кабель клавиатуры подсоединен
      когда в порте B бит 2=0 для PC или бит 3=0 для XT
      биты 0-3    PC: верхняя половина переключателя 2 конфи-
                  гурации (не используется)
           0-1    XT: тип дисплея (11 = монохромный,
                  10 = цветной 80*25, 01 = цветной 40*25)
           2-3    XT: число накопителей НГМД (00 = 1 и т.д.)
           4-7    PC,XT: то же, что и с установленными битами

   Отметим,  что 0 в одном из битов регистра соответствует  уста-
новке переключателя "off".
   AT хранит  информацию  о  конфигурации  в  микросхеме MC146818
фирмы  Motorola, вместе с часами реального времени.  Он вовсе  не
имеет микросхемы 8255, хотя для управления  микросхемой таймера и
приема  данных с клавиатуры используются те же самые адреса  пор-
тов.  Микросхема имеет 64 регистра, пронумерованных от 00 до 3FH.
Для  чтения  регистра  нужно сначала послать его номер в  порт  с
адресом 70H, а затем  прочитать  его  через  порт  71H. Различные
параметры  конфигурации  обсуждаются  на  последующих  страницах.
Приведем здесь только краткую сводку:

   Номер регистра               Использование
       10H             тип накопителя НГМД
       12H             тип накопителя фиксированного диска
       14H             периферия
       15H             память на системной плате (младший байт)
       16H             память на системной плате (старший байт)
       17H             общая память (младший байт)
       18H             общая память (старший байт)
       30H             память сверх 1 мегабайта (младший байт)
       31H             память сверх 1 мегабайта (старший байт)


   Высокий уровень.

   В данной книге имеется  множество примеров доступа к этим пор-
там.  Ниже приводится программа на Бейсике, устанавливающая число
дисковых накопителей, присоединенных  к IBM PC. Прежде чем прочи-
тать два старших бита порта A, бит 7 порта B должен быть установ-
лен в 1.  Существенно, что Вы  должны вернуть значение этого бита
назад в 0 перед дальнейшей работой, иначе клавиатура будет запер-
та и для  восстановления  работоспособности  машины  Вам придется
выключить  ее.  Бейсик не позволяет двоичное представление чисел,
что затрудняет работу  с  цепочками  битов.  Простая подпрограмма
может  заменить любое целое вплоть до 255 (максимальное значение,
которое может принимать номер порта) на восьмисимвольную двоичную
строку.   После  этого строковая функция MID$ позволяет  вырезать
нужные биты для анализа. Основы битовых операций в Бейсике описа-
ны в приложении Б.

100 A = INP(&H61)            'получаем значение из порта B
110 A = A OR 128             'устанавливаем бит 7
120 OUT &H61,A               'посылаем байт назад в порт B
130 B = INP(&H60)            'получаем значение из порта A
140 A = A AND 128            'сбрасываем бит 7
150 OUT &H61,A               'восстанавливаем значение порта B
160 GOSUB 1000               'преобразуем в двоичную строку
170 NUMDISK$ = RIGHT$(B$,1)  'получаем нулевой бит
180 IF D$ = 1 THEN NUMDISK = 0: GOTO 230 'нет дисков
190 C$ = LEFT$(B$,2)         'берем два старших бита строки
200 TALLEY = 0               'переменная для числа дисков
210 IF RIGHT$(C$,1) = "1" THEN TALLEY = 2 'берем старший бит
220 IF LEFT$(C$,1) = "1" THEN TALLEY = TALLEY + 1 'и младший
230 TALLEY = TALLEY + 1      'счет начинается с 1, а не с 0
                             'теперь имеем число накопителей
1000 '''Подпрограмма преобразования байта в двоичную строку
1010 B$ = ""                 'заводим строку
1020 FOR N = 7 TO 0 STEP -1  'проверка очередной степени 2
1030 Z = B - 2^N             '
1040 IF Z >= 0 THEN B = Z: B$ = B$+"1" ELSE B$ = B$+"0"
1050 NEXT                    'повторяем для каждого бита
1060 RETURN                  'все закончено

   Низкий уровень.

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

   IN   AL,61H          ;получаем значение из порта B
   OR   AL,10000000B    ;устанавливаем бит 7 в 1
   OUT  61H,AL          ;заменяем байт
   IN   AL,60H          ;получаем значение из порта A
   MOV  CL,6            ;подготовка для сдвига AL
   SHR  AL,CL           ;сдвигаем 2 старших бита на 6 позиций
   INC  AL              ;начинаем счет с 1, а не с 0
   MOV  NUM_DRIVES,AL   ;получаем число накопителей
   IN   AL,61H          ;подготовка к восстановлению порта B
   AND  AL,01111111B    ;сбрасываем бит 7
   OUT  61H,AL          ;восстанавливаем байт





   Имеются проблемы совместимости между различными типами IBM PC.
Для  того чтобы программа могла работать на любом из IBM PC,  ис-
пользуя все его возможности,  необходимо  чтобы она могла опреде-
лить  тип машины, в которую она загружена.  Эта информация содер-
жится во втором с конца байте памяти  по адресу FFFFE в ROM-BIOS,
с использованием следующих ключевых чисел.

             Компьютер                Код
                PC                     FF
                XT                     FE
                PCjr                   FD
                AT                     FC

   Высокий уровень.

   В Бейсике надо просто использовать PEEK для чтения значения:

100 DEF SEG = &HF000        'указываем на верхние 64K памяти
110 X = PEEK(&HFFFE)        'читаем второй с конца байт
120 IF X = &HFD THEN ...    '... тогда это PCjr

   Низкий уровень.

   В языке ассемблера:

;--- Определение типа компьютера:
   MOV  AX,0F000H           ;указывает ES на ПЗУ
   MOV  ES,AX               ;
   MOV  AL,ES:[0FFFEH]      ;получаем байт
   CMP  AL,0FDH             ;это PCjr?
   JE   INITIALIZE_JR       ;переходим на инициализацию





   По  мере развития MS DOS к ней добавлялись новые  возможности,
многие из которых существенно  облегчают  написание  определенных
частей программы по сравнению с предыдущими версиями. Чтобы иметь
гарантию что программа будет работать  с любой версией MS DOS она
должна  использовать  только функции, доступные в MS DOS 1.0.   В
системе предусмотрено  прерывание,  возвращающее  номер версии MS
DOS.   Это  число может использоваться для проверки  выполнимости
Вашей программы.  Минимально, программа может при старте выдавать
сообщение об ошибке, сообщая что ей нужна другая версия MS DOS.

   Средний уровень.

   Функция  30H  прерывания 21H возвращает номер версии  MS  DOS.
Старший номер версии (2  из  2.10)  возвращается  в AL, а младший
номер  версии (10 из 2.10) возвращается в AH (обратите  внимание,
что младший номер .1 возвращает  значение  AH, а не 1H). AL может
содержать 0, что указывает на версию MS DOS меньшую чем 2.0.  Это
прерывание меняет содержимое  регистров  BX и CX, в которых возв-
ращается значение 0.

;--- Определение версии MS DOS:
   MOV   AH,30H            ;номер функции получения версии
   INT   21H               ;получить номер версии
   CMP   AL,2              ;проверка на версию 2.х
   JL    WRONG_DOS         ;если меньше 2, то выдать сообщение





   Программе  может оказаться необходима информация о том,  будет
ли она работать в  системе  с  монохромным  адаптером,  с цветной
графической картой или с EGA, а также о наличии второго адаптера.
В  пункте  [4.1.6]  объяснено как передать управление  от  одного
адаптера к другому.  Байт  статуса оборудования, хранящийся в об-
ласти  данных  ROM-BIOS  по адресу 0040:0010  сообщает  установку
переключателя 1,  который  показывает  какая  из  карт активна. В
принципе должны иметь значение 11 для монохромной карты, 10 - для
цветной карты 80*25, 01 - для  цветной  карты 40*25 и 00 для EGA.
Однако  при наличии EGA он может установить биты отличными от 00,
в зависимости от установки его собственных переключателей. Поэто-
му Вы должны сначала другими средствами установить наличие EGA, а
затем, если его нет, то  по  данным  BIOS  определить является ли
активным  цветной или монохромный адаптер.  Для проверки  наличия
EGA надо прочитать байт по адресу  0040:0087. Если он равен 0, то
EGA отсутствует.  Если этот байт ненулевой, то когда бит 3=0, EGA
является активным адаптером, а  когда он равен 1, то активен вто-
рой адаптер.
   Когда  присутствует EGA, то проверка наличия монохромного  или
цветного адаптера осуществляется записью значения в регистр адре-
са курсора микросхемы 6845 [4.1.1] и последующего чтения значения
и проверки их на совпадение. Для  монохромной карты пошлите 0FH в
порт  3B4H, чтобы указать на регистр курсора, а затем прочитать и
записать адрес курсора через порт 3B5H. Соответствующие порты для
цветной карты 3D4H и 3D5H. Когда карта отсутствует, то порт возв-
ращает значение 0FFH; но поскольку это значение может содержаться
в регистре, то недостаточно простой проверки на это значение.
   Имеются два добавочных вопроса, на которые могут потребоваться
ответы при наличии  EGA:  сколько  имеется  памяти на его карте и
какой  тип  монитора  подсоединен? Для определения  типа  дисплея
проверьте бит 1 по  адресу  0040:0087;  когда  он  установлен, то
подсоединен  ммонохромный дисплей, а когда он равен нулю -  цвет-
ной.  Если Ваша программа  использует цветной графический режим с
350  строками,  то надо также определить присоединен  ли  дисплей
IRGB или  R'G'B'RGB,  где  последняя  аббревиатура  соответствует
улучшеному  цветному  дисплею IBM.  Это  определяется  установкой
четырех переключателей на карте EGA.  Установка этих переключате-
лей возвращается в CL при обращении к функции 12H прерывания 10H.
Цепочка четырех младших битов  должна  быть  0110 для улучшенного
цветного  дисплея.  Та же самая функция сообщает и наличие памяти
на карте EGA.  Она возвращает  BL,  содержащий 0 для 64K, 1 - для
128, 2 - для 192 и 3 - для полных 256K памяти дисплея.



   Высокий уровень.

   Приведенные фрагменты кода определяют тип текущего монитора  и
режим его работы, а  также  определяют  какие типы видеоадаптеров
имеются в машине:

100 '''определение активного адаптера
110 DEF SEG = &H40         'указываем на область данных BIOS
120 X = PEEK(&H87)         'проверка на наличие EGA
130 IF X = 0 THEN 200      'EGA отсутствует, идем дальше
140 IF X AND 8 = 0 THEN... 'активный монитор EGA
 .
 .
200 X = PEEK(&H10)         'читаем байт статуса оборудования
210 Y = X AND 48           'выделяем биты 4 и 5
220 IF Y = 48 THEN ...     '... тогда монохромный (00110000)
230 IF Y = 32 THEN ...     '... тогда цветной 80*25 (00100000)
240 IF Y = 16 THEN ...     '... тогда цветной 40*25 (00010000)

   Следующий  пример  проверяет наличие монохромной карты,  когда
активной является карта  EGA  или  цветная.  Тот  же пример можно
использовать для проверки наличия цветной карты если использовать
адреса портов &H3D4 и &H3D5.

100 '''проверка наличия монохромной карты
110 OUT &H3B4,&HF          'адрес регистра курсора
120 X = INP(&H3B5)         'чтение и сохранение значения
130 OUT &H3B5,100          'посылаем в регистр любое значение
140 IF INP(&H3B5)<>100 THEN... 'если карта есть - вернется то же
150 OUT &H3B5,X            'восстанавливаем значение регистра

   Низкий уровень.

   Приведенные примеры соответствуют примерам на Бейсике.

;--- Определение активного адаптера:
   MOV   AX,40H        ;указываем ES на область данных BIOS
   MOV   ES,AX         ;
   MOV   AL,ES:[87H]   ;проверяем наличие EGA
   CMP   AL,0          ;
   JE    NO_EGA        ;если 0040:0087 = 0, то EGA нет
   TEST  AL,00001000B  ;EGA есть, проверяем бит 3
   JNZ   EGA_NOT_ACTIVE;если бит 3=1, то EGA неактивен
    .
    .
EGA_NOT_ACTIVE:
   MOV   AL,ES:[10H]   ;проверяем байт статуса дисплея
   AND   AL,00110000B  ;выделяем биты 4 и 5
   CMP   AL,48         ;это монохромная карта?
   JE    MONOCHROME    ;переход если да

   Предполагая  наличие монохромной карты проверим установлена ли
цветная карта (неактивная):



;--- Установлена ли неактивная цветная карта?
   MOV   DX,3D4H       ;указываем на регистр адреса 6845
   MOV   AL,0FH        ;запрашиваем регистр курсора
   OUT   DX,AL         ;указываем на регистр
   INC   DX            ;указываем на регистр данных
   IN    AL,DX         ;получаем текущее значение
   XCNG  AH,AL         ;сохраняем значение
   MOV   AL,100        ;тестовое значение 100
   OUT   DX,AL         ;посылаем его
   IN    AL,DX         ;считываем его снова
   CMP   AL,100        ;сравниваем значения
   JNE   NO_CARD       ;переход если нет карты
   XCNG  AH,AL         ;иначе есть цветная карта
   OUT   DX,AL         ;тогда восстанавливаем значение





   На  всех  машинах  кроме AT (который будет  обсуждаться  ниже)
регистры микросхемы 8255 интерфейса  с периферией содержат инфор-
мацию о том, сколько НГМД имеет машина.  В примерах [1.1.1] пока-
зано как получить эту  информацию.   Информация  определяющая тип
диска содержится в таблице размещения файлов (FAT) диска, которая
следит за использованием дискового пространства.  Первый байт FAT
содержит один из следующих кодов:

      Код                    Тип диска

       FF            двухсторонний, 8 секторов
       FE            односторонний, 8 секторов
       FD            двухсторонний, 9 секторов
       FC            односторонний, 9 секторов
       F9            двухсторонний, 15 секторов
       F8            фиксированный диск

   Сама таблица размещение файлов не является  файлом.  Она может
быть считана при помощи функций DOS  или BIOS непосредственно чи-
тающих определенные сектора диска. В  пункте  [5.1.1]  содержится
вся информация необходимая для нахождения и чтения FAT. К счастью,
операционная  система  обеспечивает  функцию,  которая  возвращает
идентификационный байт диска.
   Данные BIOS не показывают число  жестких дисков в системе, так
как переключатели предназначены только для гибких дисков.  Однако
Вы можете использовать указанную функцию операционной системы для
поиска накопителей.  Она возвращает значение 0CDH, вместо  одного
из упомянутых кодов, когда  накопители  отсутствуют.  Надо просто
проверять  все  большие и большие номера накопителей, до тех  пор
пока не будет обнаружено указанное значение.
   AT уникален в том смысле, что  его  информация  о конфигурации
говорит  какой тип накопителя используется.  Эту информацию можно
получить из порта с  адресом  71H,  предварительно  послав  номер
регистра в порт 70H. Для НГМД номер регистра равен 10H.  Информа-
ция о первом  накопителе  содержится  в битах 7-4, а о втором - в
битах 3-0. В обоих случаях цепочка битов 0000 говорит об отсутст-
вии накопителя, 0001 - о двухстороннем накопителе с плотностью 48
дорожек  на дюйм, а 0010 - о накопителе большой емкости (96 доро-
жек на дюйм).  Информация о  фиксированном диске содержится в ре-
гистре 12H. И снова биты 7-4 и 3-0 соответствуют первому и второ-
му накопителям.  0000 указывает на отсутствие накопителя.  Другие
15 возможных значений описывают емкость и конструкцию накопителя.
Эти коды сложные; если Вам  по  какой-то  причине потребуется эта
информация, обратитесь к техническому руководству по AT.

   Средний уровень.

   Функция  1CH прерывания 21H возвращает информацию об указанном
накопителе.  Поместите номер  накопителя в DL, причем 0 = накопи-
тель  по  умолчанию, 1 = A, и т.д.  При возвращении  DX  содержит
число кластеров в FAT, AL  -  число  секторов  в кластере, а CX -
число байтов в секторе.  DS:BX указывает на байт, содержащий  код
идентификации диска из FAT, согласно приведенной таблице.  В сле-
дующем примере определяется тип накопителя A:


;---определение типа диска
   MOV   AH,1CH        ;функция MS DOS
   MOV   DL,1          ;выбор накопителя A
   INT   21H           ;получение информации
   MOV   DL,[BX]       ;получение типа накопителя
   CMP   DL,0FDH       ;двухсторонний, 9 секторов?
   JE    DBL_9         ;и т.д.

   BIOS AT имеет функцию, сообщающую общие параметры накопителей.
Это функция 8 прерывания 13H.  Она возвращает число накопителей в
DL, максимальное число сторон накопителя в DH, максимальное число
секторов в CL и дорожек в CH, а  код  статуса ошибки накопителя в
AH (см. пункт [5.4.8]).
   Другая функция BIOS AT возвращает тип накопителя.  Это функция
15H прерывания 13H, которая требует номера накопителя в DL.  В AH
возвращается  код,  причем 0 = нет накопителя,  1 =  дискета  без
обнаружения изменений, 2 = дискета с обнаружением изменений и 3 =
фиксированный диск. В случае фиксированного диска в CX:DX возвра-
щается число секторов по 512 байт.





   При старте ROM-BIOS  проверяет   присоединенное  оборудование,
сообщая  о  результатах своей проверки в регистр  статуса.   Этот
регистр занимает два байта, начиная  с 0040:0010. Нижеприведенные
значения  битов относятся ко всем машинам, пока не оговорено  об-
ратное:
   бит 0    если 1, то присутствует НГМД
   1        XT,AT:1 = есть мат. сопроцессор (PC,PCjr:не использ.)
   2-3      11 = базовая память 64K (AT:не используется)
   4-5      Активный видеоадаптер (11 = монохромный,
            10 = цветной 80*25, 01 = цветной 40*25)
   6-7      число НГМД (если бит 0 = 1)
   8        PCjr:0 = есть DMA (PC,XT,AT:не используется)
   9-11     число адаптеров коммуникации
   12       1 = есть игровой порт (AT:не используется)
   13       PCjr:есть серийный принтер (PC,XT,AT:не использ.)
   14-15    число присоединенных принтеров

   Большая часть информация расшифровывается примитивно. Но обра-
тите внимание, что информация о дисковых накопителях распределена
между битами 0 и 6-7. Значение 0 в битах 6-7 указывает, что  име-
ется один дисковый накопитель; чтобы узнать об отсутствии накопи-
телей надо проверить бит 0.
   Число портов коммуникации может быть получено из области  дан-
ных BIOS. BIOS отводит четыре 2-байтных поля для хранения базовых
адресов вплоть до четырех  COM  портов  (MS DOS использует только
два из них). Базовый адрес - это младший из адресов портов, отно-
сящихся к группе портов, имеющих доступ к данному каналу коммуни-
кации.  Эти четыре поля начинаются с адреса 0040:0008. Порту COM1
соответствует адрес :0008, а COM2  - 000A. Если это поле содержит
0, то соответствующий порт отсутствует. Таким образом, если слово
по адресу :0008 отлично от  нуля,  а по адресу 000A - нулевое, то
имеется один порт коммуникации.
   AT  хранит  информацию о периферии в регистре  14H  микросхемы
конфигурации. Сначала запишите  14H в порт с адресом 70H, а затем
прочитайте содержимое регистра через порт 71H. Вот значение битов
этого регистра:

   биты 7-6   00 = 1 НГМД, 01 = 2 НГМД
        5-4   01 = вывод на цветной дисплей, 40 строк
              10 = вывод на цветной дисплей, 80 строк
              11 = вывод на монохромный дисплей
        3-2   не используется
          1   1 = имеется мат. сопроцессор
          0   0 = нет НГМД, 1 = имеется НГМД

   Высокий уровень.

   В Бейсике  нужно  просто  прочитать  байты  статуса из области
данных BIOS. В приложении Б объяснено выполнение битовых операций
в Бейсике. В приведенном примере  проверка наличия дисковых нако-
пителей достигается проверкой четности  младшего байта статусного
регистра (четный - нет накопителей).


100 DEF SEG = 0          'указывыаем на дно памяти
110 X = PEEK(&H410)      'получаем младший байт регистра
120 IF X MOD 2 = 0 THEN 140 'он четный - нет накопителей
130 PRINT "Имеется диск" 'иначе имеется накопитель
140 GOTO 160             'идем ко второму сообщению
150 PRINT "Нет накопителей"  'второе сообщение
160 ...                  'продолжаем...

   Проверка наличия COM1:

100 DEF SEG = 40H        'указываем на область данных BIOS
110 PORT = PEEK(0) + 256*PEEK(1) 'получаем слово со смещением 0
120 IF PORT = 0 THEN...  '... то нет адаптера COM1

   Средний уровень.

   Прерывание 11H BIOS возвращает байт статуса оборудования в AX.
На  входе ничего подавать не надо.  В примере определяется  число
дисковых накопителей.

; ---получение числа дисковых накопителей:
   INT   11H         ;получаем байт статуса
   TEST  AL,0        ;имеются накопители?
   JZ    NO_DRIVES   ;переход, если нет
   AND   AL,1100000B ;выделяем биты 5-6
   MOV   CL,5        ;подготовка к сдвигу регистра
   SHR   AL,CL       ;сдвиг вправо на 5 битов
   INC   AL          ;добавляем 1, т.к. отсчет идет с 1

   Низкий уровень.

   Ассемблерная  программа  работает  так  же, как и программа на
Бейсике.   В примере читается информация о конфигурации  для  AT,
определяя установлен ли математический сопроцессор:

   MOV   AL,14H      ;номер регистра
   OUT   70H,AL      ;посылаем запрос
   IN    AL,71H      ;читаем регистр
   TEST  AL,10B      ;проверяем бит 1
   JZ    NO_COPROCESSOR ;если не установлен, то сопроцессора нет





   Вопрос:  "Сколько  имеется памяти?",- может иметь три  смысла.
О каком количестве памяти  сообщают  переключатели, установленные
на  системной плате? Сколько микросхем памяти реально установлено
в машине? И, наконец, сколько остается  свободной памяти, которую
DOS  может  использовать для выполнения  Ваших  программ?  Машина
может иметь 10 банков памяти по  64K, но переключатели могут ука-
зывать  на наличие только 320K, оставляя половину памяти для  ка-
ких-либо специальных целей.  А  как  может Ваша программа узнать,
сколько  из доступных 320K она может использовать, учитывая,  что
другое программное обеспечение может быть загружено резидентным в
верхнюю или нижнюю часть памяти?
   Ответ на каждый вопрос можно получить своим способом. Для PC и
XT установка  переключателей  может  быть  просто прочитана через
порт B микросхемы интерфейса с периферией 8255.  В пункте [1.1.1]
описано как это делается. BIOS  хранит  двухбайтную переменную по
адресу  0040:0013, которая сообщает число  килобайт  используемой
памяти. Для PCjr бит 3 порта  62H  (порт C микросхемы 8255) равен
нулю,  когда  машина имеет добавочные 64K памяти.  AT дает  особо
полную информацию о памяти.   Регистры 15H (младший) и 16H (стар-
ший)  микросхемы информации о конфигурации говорят сколько памяти
установлено на системной плате  (возможны  три  значения: 0100H -
для  256K, 0200H - для 512K и 0280H для 512K плюс 128K  на  плате
расширения). Память канала ввода/вывода для AT сообщается регист-
рами  17H и 18H (с инкрементом 512K).  Память  сверх 1  мегабайта
доступна через регистры  30H  и  31H  (опять  с инкрементом 512K,
вплоть до 15 мегабайт).  Если AT имеет 128K на плате  расширения,
то установлен бит 7 регистра  33.   Во  всех случаях надо сначала
послать номер регистра в порт 70H, а затем прочитать значение  из
порта 71H.
   Легко  написать  программу,  которая  прямо  тестирует наличие
памяти через определенные интервалы адресного пространства.  Пос-
кольку минимальная порция памяти 16  килобайт, то достаточно про-
верить одну ячейку памяти в каждом 16-килобайтном сегменте, чтобы
убедиться, что все 16K  присутствуют.  Когда данная ячейка памяти
отсутствует,  то  при чтении из нее получаем значение  233.   Для
проверки можно записать в ячейку произвольное  число, отличное от
233 и сразу же считать его.  Если вместо посланного числа возвра-
щается 233, то соответствующий банк памяти отсутствует. Не приме-
няйте  этот способ на AT, где при попытке писать в несуществующую
память вступает в действие  встроенная  обработка  несуществующей
памяти.   Диагностика AT настолько хороша, что Вы можете  целиком
положиться на системную информацию о конфигурации.
   Память  постоянно  занимается  частями  операционной  системы,
драйверами устройств, резидентными программами обработки прерыва-
ний и управляющими блоками MS DOS.  При проверке банков памяти Вы
не  должны  вносить необратимых  изменений в  содержимое  памяти.
Сначала надо сохранить значение, хранящееся в тестируемой ячейке,
затем проверить ее и восстановить первоначальное значение.
   Имеется еще одна проблема. Если Ваша процедура хотя бы времен-
но модифицирует свой код, то это может привести к краху.  Поэтому
для проверки надо выбирать такую ячейку из блока 64K, которая  не
будет занята текстом Вашей процедуры.  Для этого поместите проце-
дуру тестирования впереди программы, а для тестирования  выберите


ячейку со смещением равным смещению для кодового сегмента. Напри-
мер,  если  регистр кодового сегмента содержит 13E2,  то  сегмент
начинается со смещения 13E2 во  втором  64K-байтном блоке памяти.
Поскольку Ваша подпрограмма проверки не может находиться по этому
адресу, то Вы можете безопасно  проверять  значение  3E2 в каждом
блоке.   Запрет  прерываний [1.2.2] позволяет не  беспокоиться  о
модификации  кода  из-за  аппаратных  прерываний,  которые  могут
происходить во время проверки.
   Определение  количества памяти реально доступной  операционной
системе также требует некоторого  фокуса.  Когда программа первый
раз получает управление, то DOS отводит ей всю доступную  память,
включая верхнюю область  памяти,  содержащую  нерезидентную часть
DOS (которая автоматически перезагружается, если она была модифи-
цирована). Для запуска другой  программы из текущей или для того,
чтобы  сделать программу подходящей для многопользовательсой сис-
темы, необходимо урезать программу до требуемого размера. В пунк-
те [1.3.1] описано как это сделать с помощью функции 4AH прерыва-
ния 21H.
   Эта же функция может быть использована для расширения отведен-
ной  памяти.  Поскольку программе отводится вся доступная  память
при загрузке, то такое расширение  невозможно при старте. Если Вы
попробуете  сделать  это, то будет установлен  флаг  переноса,  в
регистре AX появится код ошибки  8, а в регистре BX будет возвра-
щено  максимальное  число доступных 16-байтных  параграфов.   Эта
информация как раз и нужна.  Значит надо выдать запрос со слишком
большим  значением  в регистре BX ( скажем, F000H параграфов),  а
затем выполните прерывание.   Позаботьтесь о том, чтобы выполнить
эту  функцию в самом начале программы, пока регистр ES еще  имеет
начальное значение.

   Высокий уровень.

   Интерпретатор  Бейсика  использует  только 64K (хотя операторы
PEEK  и POKE позволяют доступ к памяти за пределами  64K).   Доля
памяти доступная в  настоящий  момент  возвращается функцией FRE.
Эта функция имеет фиктивный аргумент, который может быть числовым
или символьной строкой.  BYTES  =  FRE(x)  передает в BYTES число
свободных байтов. BYTES = FRE(x$) делает то же самое.  Но строко-
вый аргумент вынуждает очистку области данных перед тем как возв-
ратить  число байтов.  Заметим, что если размер  рабочей  области
устанавливается с помощью  оператора CLEAR, то количество памяти,
сообщаемое  функцией  FRE  будет на от 2.5 до 4  килобайт  меньше
из-за потребностей рабочей области интерпретатора.
   Транслятор Бейсика не накладывает ограничение 64K на суммарный
объем кода и данных.  Но сам компилятор ограничен тем количеством
памяти, которое он может использовать при компиляции.  Если этого
пространства  недостаточно,  то уничтожьте  все  ненужные  номера
строк при помощи ключа  компиляции  /N.  Можно также использовать
более короткие имена переменных.


   Средний уровень.

   Прерывание 12H BIOS проверяет установку переключателей и возв-
ращает в AX количество килобайт  памяти  в системе.  Эта величина
вычисляется  из установки регистров микросхемы 8255 или, для  AT,
микросхемы  конфигурации/часов.   Входных  регистров нет.  Имейте
ввиду,  что  установка  переключателей может быть  неверной,  что
ограничивает достоверность такого подхода.
   Для определения  числа  16-байтных  параграфов,  доступных для
DOS, используйте функцию 4AH прерывания 21H.  ES должен иметь  то
же значение, что при старте задачи:

;---определение числа параграфов доступных для DOS
   MOV   AH,4AH        ;указываем нужную функцию
   MOV   BX,0FFFFH     ;требуем слишком большую память
   INT   21H           ;BX содержит число доступных параграфов

   AT использует функцию 88H  прерывания 15H для проверки наличия
расширенной памяти, которая ищет память вне адресного пространст-
ва процессора в обычном режиме  адресации.  Говорят, что она ищет
память за отметкой 1 мегабайта.  При этом на системной плате дол-
жно  быть от 512 до 640 килобайт памяти, чтобы эта функция  рабо-
тала.  Число килобайтных блоков расширенной памяти возвращается в
AX.

   Низкий уровень.

   Первый пример проверяет  число  банков  памяти по 64K в первых
десяти 64-килобайтных сегментах памяти.  Если Вы будете проверять
старшие 6 банков памяти, то имейте ввиду, что имеются видеобуфер,
начиная  с  B000:0000 (и, возможно, A000:0000) и ПЗУ,  начиная  с
F000:0000 (и, возможно, C000:0000).

;---проверка каждого банка памяти:
   CLI                  ;запрет аппаратных прерываний
   MOV   AX,CS          ;получаем значение кодового сегмента
   AND   AX,0FFFH       ;сбрасываем старшие 4 бита
   MOV   ES,AX          ;помещаем указатель в ES
   MOV   DI,0           ;DI считает число банков памяти
   MOV   CX,10          ;будем проверять 10 банков
   MOV   BL,'X'         ;для проверки используем 'X'
NEXT:
   MOV   DL,ES:[0]      ;сохраняем значение тестируемой ячейки
   MOV   ES:[0],BL      ;помещаем 'X' в эту ячейку
   MOV   DH,ES:[0]      ;читаем тестируемую ячейку
   MOV   ES:[0],DL      ;восстанавливаем значение
   CMP   DH,'X'         ;совпадает с тем, что писали?
   JNE   GO_AHEAD       ;если нет, то банк отсутствует
   INC   DI             ;увеличиваем число банков
GO_AHEAD:
   MOV   AX,ES          ;готовим увеличение указателя
   ADD   AX,1000H       ;указываем на следующие 64K
   MOV   ES,AX          ;возвращаем указатель в ES
   LOOP  NEXT           ;обрабатываем следующий банк
   STI                  ;разрешаем аппаратные прерывания





   Прерывания  это готовые процедуры, которые компьютер  вызывает
для выполнения определенной задачи. Существуют аппаратные и прог-
раммные прерывания.  Аппаратные прерывания инициируются аппарату-
рой, либо с системной платы,  либо с  карты расширения. Они могут
быть  вызваны сигналом микросхемы таймера, сигналом от  принтера,
нажатием клавиши на клавиатуре и множеством  других причин. Аппа-
ратные прерывания не координируются с работой программного  обес-
печения. Когда вызывается прерывание, то процессор оставляет свою
работу,  выполняет  прерывание, а затем возвращается  на  прежнее
место. Для того чтобы иметь  возможность вернуться точно в нужное
место программы, адрес этого места (CS:IP) запоминается на стеке,
вместе с регистром флагов.  Затем в CS:IP загружается адрес прог-
раммы обработки прерывания и ей передается  управление. Программы
обработки  прерываний иногда называют драйверами прерываний.  Они
всегда завершаются  инструкцией  IRET  (возврат  из  прерывания),
которая завершает процесс, начатый прерыванием, возвращая  старые
значения CS:IP и регистра  флагов, тем самым давая программе воз-
можность продолжить выполнение из того же состояния.
   С  другой стороны, программные прерывания на самом деле ничего
не прерывают.  На самом деле это обычные процедуры, которые вызы-
ваются  Вашими программами для выполнения рутинной работы,  такой
как прием нажатия клавиши на клавиатуре или вывод на экран. Одна-
ко  эти  подпрограммы содержатся не внутри Вашей  программы, а  в
операционной системе и механизм  прерываний  дает Вам возможность
обратиться к ним. Программные прерывания могут вызываться друг из
друга. Например, все прерывания  обработки ввода с клавиатуры DOS
используют прерывания обработки ввода с клавиатуры BIOS для полу-
чения символа из буфера клавиатуры.  Отметим, что аппаратное пре-
рываение  может получить управление при  выполнении  программного
прерывания. При  этом  не  возникает  конфликтов,  так как каждая
подпрограмма обработки прерывания сохраняет значения всех исполь-
зуемых ею регистров и  затем  восстанавливает  их при выходе, тем
самым не оставляя следов того, что она занимала процессор.
   Адреса программ прерываний называют векторами.  Каждый  вектор
имеет длину четыре байта. В  первом слове хранится значение IP, а
во втором - CS.  Младшие 1024 байт памяти содержат вектора преры-
ваний, таким образом имеется место  для 256 векторов. Вместе взя-
тые  они  называются таблицей векторов.  Вектор для прерывания  0
начинается с ячейки 0000:0000, прерывания  1 - с 0000:0004, 2 - с
0000:0008 и т.д. Если посмотреть на четыре байта, начиная с адре-
са 0000:0020, в которых содержится вектор прерывания 8H (прерыва-
ние  времени суток), то Вы обнаружите там A5FE00F0.  Имея  ввиду,
что младший байт  слова  расположен  сначала и что порядок IP:CS,
это  4-байтное значение переводится в F000:FEA5.   Это  стартовый
адрес программы ПЗУ, выполняющей прерывание 8H. На рис. 1-2 пока-
зана схема выполнения программой прерывания 21H.





   Для  управления аппаратными прерываниями во всех типах IBM  PC
используется микросхема  программируемого  контроллера прерываний
Intel 8259. Поскольку в ккаждый момент времени может поступить не
один запрос, микросхема имеет схему  приоритетов. Имеется 8 уров-
ней приоритетов, кроме AT, у которого их 16, и обращения к  соот-
ветствующим уровням обозначаются сокращениями от IRQ0 до IRQ7 (от
IRQ0 до IRQ15), что означает запрос на прерывание.   Максимальный
приоритет соответствует уровню  0.   Добавочные  8 уровней для AT
обрабатываются второй микросхемой 8259; этот второй набор уровней
имеет приоритет между IRQ2  и  IRQ3.  Запросы  на  прерывание 0-7
соответствуют векторам прерываний от 8H до 0FH; для AT запросы на
прерывания 8-15 обслуживаются векторами  от 70H до 77H. Ниже при-
ведены назначения этих прерываний:

   Аппаратные прерывания в порядке приоритета.

   IRQ 0     таймер
       1     клавиатура
       2     канал ввода/вывода
          8  часы реального времени (только AT)
          9  программно переводятся в IRQ2 (только AT)
         10  резерв
         11  резерв
         12  резерв
         13  мат. сопроцессор (только AT)
         14  контроллер фиксированного диска (только AT)
         15  резерв
       3     COM1 (COM2 для AT)
       4     COM2 (модем для PCjr, COM1 для AT)
       5     фиксированный диск (LPT2 для AT)
       6     контроллер дискет
       7     LPT1

   Прерыванию  времени суток [2.1.0] дан максимальный  приоритет,
поскольку если оно будет  постоянно  теряться, то будут неверными
показания системных часов. Прерывание от клавиатуры [3.1.0] вызы-
вается при  на