Глава 8
Персональный компьютер IBM
Эта глава описывает устройство персонального компьютера фирмы
IBM (IBM PC). Поскольку данная книга посвящена программированию на
языке ассемблера для IBM PC, вполне уместно рассмотреть аппаратное
обеспечение машины. Эта глава не предназначена для инженеров и
техников; она скорее для тех, кто пишет на языке ассемблера
программы, которые выполняются на IBM PC.
Выше говорилось, что язык ассемблера не всегда самый подходящий
язык программирования. Умение программировать непосредственно на
машинном уровне позволяет программисту иметь много больше
возможностей для управления машиной. Но в случае большого проекта
подавляющее количество подробностей,
которое требуется языком
ассемблера, затрудняет сосредоточие усилий на главной цели. Поэтому
лучше всего использовать ассемблер только по мере необходмости.
Желание использовать преимущества непосредственного управления
аппаратурой - одна из причин, по которой спользуются языком
ассемблера. Чтобы корректно решить эту задачу, вам необхдимо знать,
что из себя представляет аппаратура и какие у нее возможности. Вот
зачем нужна эта глава. Информация в данной главе адресуется
программисту, а не инженеру. Мы рассмотрим здесь различные узлы
аппаратуры, и как ими можно управлять.
Эта глава - дополнение к Техническому Описанию Персонального
Компьютера. Вы будете также пользоваться им для уточнения
специфических аспектов программирования аппаратуры. Кроме тогно
дополнительную информацию можно получить из справочных листков к
отдельным микросхемам. В этой главе данные из этих источников не
повторяются. Всюду где это нужно, в тексте воспроизводятся
некоторые данные аппаратуры, иллюстрирующие отдельные программные
возможности. Будут, конечно, приводиться и примеры работы
аппаратуры.
Описание базовой системы ввода-вывода BIOS (Basic Input/Output
System), которая находится в постоянном запоминающем устройстве
(ПЗУ) ЭВМ, будет отложено до следующей главы. Программы BIOS
выполняют управление на аппаратном уровне устройствами IBM PC. В
этой главе объясняется, что может делать аппаратура; следующая
глава детализирует, что происходит с аппаратным обеспечением в
процессе работы, а последняя глава поможет добиться от него того,
что не реализовано в ПЗУ с программой BIOS.
Системное оборудование
В каждом пункте этой главы мы будем обсуждать свои аспекты
системы ввода-вывода IBM PC. В этом пункте речь пойдет о
стандартных компонентах аппаратуры - о тех, которые находятся на
процессорной плате системы. Другие части будут посвящены отдельным
платам адаптеров ввода-вывода, которые по необходимости можно
установить в систему.
Центральным процессором IBM PC является Intel 8088, тот самый,
естественно, который рассматривался на протяжении первых глав
книги. У нас, как будто еще есть что о нем рассказать. Рядом с
микросхемой 8088 на системной плате имеется пустое гнездо, в
которую вставляется арифметический сопроцессор Intel 8087; он был
рассмотрен в гл.7 и теперь уже должен быть знаком вам.
Остальные компоненты системной платы выполняют функции, которые
и превращают микропроцессор в ЭВМ. На системной плате находится до
64K байт оперативной памяти, а также 40K байт памяти только для
чтения (ПЗУ, постоянное запоминающее устройство). Это ПЗУ содержит
интерпретатор языка Бейсик, а также систему BIOS, которую мы
обсудим в следующей главе.
На системной плате есть много компонент, необходимых для работы
IBM PC. Мы рассмотрим только программируемые или полезные для
программирования компоненты. На системной плате этими компонентами
являются микросхемы программируемого периферийного интерфейса 8255,
таймера-счетчика 8253, контроллера прерываний 8259, и контроллера
прямого доступа в память 8237. Остальные микросхемы выполняют
аппаратные функции, которые нельзя изменять с помощью
программирования. Подробно, на элементном уровне, микросхемы
рассматриваться не будут; если вас это интересует, обратитесь к
каталлогу фирмы Intel, либо к другим справочным материалам. Вместо
этого мы рассмотрим функции ввода-вывода, реализованные на
системной плате IBM PC. Управляя этим средством доступа, мы сможем
пльзоваться всеми перечисленными выше компонентами.
Динамик
Внутри корпуса IBM PC есть маленький динамик. Программа может
управлять звуками, генерируемыми этими динамиком. Для этого нужно
управлять некоторыми выходными битами микросхемы 8255 и генератора
тона в микросхеме 8253.
На Фиг. 8.1 показана программа, которая управляет динамиком
двумя разными способами. Первый способ, помеченный в листинге
меткой DIRECT, непосредственно управляет динамиком. Бит 1 выводного
порта 61H подключен к динамику. Всякий раз, когда программа меняет
значение этого бита, диффузор динамика двигается либо наружу, либо
внутрь. Быстро меняя значение этого бита, программа генерирует
звук. Это иллюстрирует первая часть программы на Фиг. 8.1, она
меняет значение бита 1, порождая высокочастотный тон. Скорость, с
которой программа меняет бит 1, определяет частоту тона.
Взяв на себя непосредственное управление динамиком, вы должны
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:08
Фиг. 8.1 Управление динамиком Page 1-1
PAGE ,132
TITLE Фиг. 8.1 Управление динамиком
0000 STACK SEGMENT STACK
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
0000 CODE SEGMENT
ASSUME CS:CODE
0000 SPEAKER PROC FAR
0000 1E PUSH DS ; Адрес возврата
0001 B8 0000 MOV AX, 0
0004 50 PUSH AX
;----- Задание режима работы динамика
0005 2B C9 SUB CX, CX ; Счетчик цикла
0007 E4 61 IN AL, 61H
0009 24 FE AND AL, 0FEH
000B E6 61 OUT 61H, AL ; Установка разряда 0 порта 61H в 0 для
; задания прямого управления динамиком
000D DIRECT:
000D 0C 02 OR AL, 2
000F E6 61 OUT 61H, AL ; Включить динамик
0011 24 FD AND AL, 0FDH
0013 E6 61 OUT 61H, AL ; Выключить динамик
0015 E2 F6 LOOP DIRECT
;----- Управление высотой звука динамика
0017 B0 B6 MOV AL, 10110110b
0019 E6 43 OUT 43H, AL ; Установка режима для 2-го канала
001B B8 03E8 MOV AX, 1000 ; Выбор высоты звука
001E E6 42 OUT 42H, AL
0020 8A C4 MOV AL, AH
0022 E6 42 OUT 42H, AL ; Занесение высоты звука в порт динамика
0024 E4 61 IN AL, 61H
0026 8A E0 MOV AH, AL
0028 0C 03 OR AL, 3
002A E6 61 OUT 61H, AL ; Выбор режима управления динамикаом
002C 2B C9 SUB CX, CX
002E KILL_TIME:
002E E2 FE LOOP KILL_TIME ; Цикл ожидания, во время которого
; работает динамик
0030 8A C4 MOV AL, AH
0032 E6 61 OUT 61H, AL ; Выключение динамика
0034 CB RET
0035 SPEAKER ENDP
0035 CODE ENDS
END
Фиг. 8.1 Управление динамиком
прежде всего работать с выводным портом микросхемы 8255 системной
платы. Программируемый периферийный
интерфейс микросхемы 8255 (PPI) имеет всего три входных или
выходных, порта. IBM PC инициализирует микросхему 8255 так, чтобы получилось два входных
порта - 60H и 62H - и один порт вывода, 61H. Порт 60H в первую
очередь вводит значения с клавиатуры. Его можно
также использовать для чтения положения переключателей на системной
плате. Обычно состояния этих переключателей читаются только один
раз, во время инициализации при включении питания системы.
Результат программа BIOS записывает в память для дальнейшего
использования. Поэтому с точки зрения наших целей можно считать,
что порт 60H непосредственно обслуживает ввод с клавиатуры. Вообще
входной порт выполняет важную функцию. Он служит буфером между
микропроцессором и устройством ввода-вывода; он передает данные
микропроцессору только тогда, когда последний запрашивает их
командой IN. Все остальное время вводной порт задерживает данные и
не допускает, чтобы они повлияли на работу микропроцессора.
Другой порт ввода микросхемы 8255, порт 62H, обслуживает другие
входы. Четыре его бита непосредственно соответствуют
переключателям, показывающим объем памяти, подсоединенной к
системному каналу ввода-вывода. Другие четыре бита имеют
индивидуальное назначение. Два из них показывают тип системной
ошибки. Программа обслуживания немаскируемого прерывания NMI
использует эти биты для определения причины системной аварии. Бит 5
порта 62H используется для обратной связи с одним из каналов
таймера-счетчика. Этот бит служит индикатором текущего выхода
второго канала микросхемы 8253. Бит 4 порта 62H отражает текущее
состояние ввода с кассетного магнитофона. Сзади у IBM PC, рядом с
разъемом для подключения клавиатуры, имеется разъем для подключения
кассетного магнитофона. При чтении данных с кассеты, этот бит
используется для определения текущего значения, вводимого с
кассеты.
Порт 61H - это порт вывода микросхемы 8255 в машине фирмы IBM.
Всякий выходной порт захватывает (временно запоминает) данные,
выводимые программой. Если бы аппаратура не запоминала данные, они
бы пропали в течение микросекунды или около этого. Такое
запоминание данных позволяет сохранять их значение в порте до тех
пор, пока они снова не будут изменены программой. То есть, когда мы
выводим значение, меняющее положение диффузора динамика, оно
остается неизменными до тех пор, пока его не изменит программа.
На Фиг.8.2 показано значение битов порта 61H. Эти данные взяты
из из технического описания.
При изучении управления динамиком имеют значение только биты 0
и 1. Из всех других - только бит 3 - управление двигателем
кассетного магнитофона - и бит 7 - сброс ввода с клавиатуры - имеют
какое-то значение для наших программ. Остальные биты предназначены
только для инициализации и диагностики. Чтобы полностью разобраться
в них, нужно детально изучить принципиальные схемы системы.
Возвращаясь к обсуждению управления динамиком, мы можем
заметить, что биты 0 и 1 используются для непосредственного
Бит Значение
-----------------------------------------------------
0 Порт 2 таймера (упраление динамиком)
1 Прямое управление динамиком
2 Мультиплексный порт 62H
3 Управление мотором кассетного магнитофона
4 Включение контроля доступа на системной
плате памяти
5 Включение контроля доступа в памяти
каналов ввода-вывода
6 Временной контроль клавиатуры
7 Мультиплексный/сброса ввода с клавиатуры
порт 60H
-----------------------------------------------------
Фиг. 8.2 Значение битов порта 61H
управления. Как показано на Фиг. 8.1, установка бита 0 в положение
0 включает прямое управление динамиком, блокируя механизм генерации
звука микросхемой 8253. Этот метод используется во второй части
програмы.
Обратите внимание на то, как программа сбрасывает бит 0.
Команда OUT включает все 8 бит порта 61H. Способа изменить только
бит 0, оставив остальные биты нетронутыми, не существует. Если в
программе нужно изменить только бит 0, она должна считать из порта
текущее значение других разрядов. К счастью, микросхема 8255
допускает прямое программное чтение выводных портов.
Последовательность команд
IN AL , 61H
AND AL , 0FFH
OUT 61H, AL
читает текущий код из выводного порта, затем команда AND сбрасывает
младший бит, а команда OUT посылает результат в выводной порт. Если
бы программа вывела в порт просто число 0, динамик работал бы
верно, но клавиатура была бы выключена. Работая с любым портом
вывода побитовой настройки, стройте программу так, чтобы она не
влияла ни на один из других бит, если только вы не собираететсь
изменять и их.
Оставшаяся часть первой программы на Фиг.8.1 изменяет значение
бита 1 выходного порта. Исходное значение порта 61H находится уже в
регистре AL, так что программе не нужно читать его при каждом
выполнении цикла. Регистр CX используется таким образом, чтобы
выполнить цикл 64K раз. При выполнении программы вам, возможно, не
удастся услышать звук, генерируемый программой. В этом случае
попытайтесь вставить несколько добавочных команд NOP в цикл DIRECT.
Это снизит частоту тона.
Вторая часть программы на Фиг. 8.1 для генерации тональности
использует таймер-счетчик 8253. Прежде чем двигаться дальше,
обсудим функционирование микросхемы 8253, чтобы понять, как она
используется в системе. Микросхема 8253 фирмы Intel содержит три
16-битовых счетчика, которые могут быть использованы в системе для
счета или задания временных интервалов. В один из счетчиков
программа загружает 16-битовое значение. Содержимое счетчика
уменьшается на единицу по каждому импульсу от таймера; частота
импульсов, подводимых с таймера ко всем трем каналам, равна
1.19МГц. Это означает, что содержимое счетчика уменьшается на
единицу каждые 840 наносекунд. Каждый из трех каналов имеет выход.
Строка контроля выхода изменяется всякий раз, когда содержимое
счетчика достигает нуля. Командами управления определяют способ,
которым микросхема 8253 ведет счет.
Выходы этих трех каналов счетчика-таймера подключаются к
различным узлам системной платы. Канал 0 подключается к контроллеру
прерываний 8259. Система использует этот канал для порождения
прерывания времени суток. Канал 1 соединен с контроллером прямого
доступа к памяти (ПДП или DMA) 8237, и использовать этот канал
схемы 8253 нельзя, так как смена кода в этом счетчике с большой
вероятностью уничтожит вашу программу и все другие данные в памяти
системы. Канал 2 подключен к динамику для генерации звука.
Позже мы вернемся к каналу 0 микросхемы 8253. Канал 2 Дает
выход на динамик. Для установки канала таймера программа посылает
код 0B6H в порт 43H, управляющий порт микросхемы 8253. Тем самым
канал 2 таймера-счетчика настраивается на работу в качестве
делителя частоты. Таймер делит исходную частоту - в данном случае
1.19МГц - на 16-битовое число, которое программа загружает в
регистр канала 2. Регистр канала 2 расположен по адресу порта 42H
(канал 0 - это порт 40H и, поскольку вы никогда не должны изменять
содержимое канала 1, задачу определения адреса его порта мы
оставляем вам). Программа в примере загружает в регистр канала
число 1000. Это означает, что на выходе вы услышите частоту 1190Гц.
На самом деле, вы услышите основную частоту 1190 Гц плюс обертоны,
вызванные прямоугольной формой сигнала таймера.
Заметим, что число 1000 - 16-битовое, в то время как порт 42H -
8-битовый. Команда установки режима работы, которую мы послали в
порт 43H, сообщила микросхеме 8253, что в нее будет выводиться
16-битовое число в виде двух 8-битовых. Сначала посылается младший
значащий байт, а за ним следует старший. Такая двухшаговая
процедура загружает в канальный регистр требуемое значение.
Далее программа должна дать управляющему порту 61H такую
установку, чтобы он пропускал сигнал на динамик. Для этого
программа устанавливает равными 1 биты 0 и 1 управляющего порта.
Заметим, что программа в начале сохраняет первоначальное значение
кода из управляющего порта и восстанавливает его в конце. Это
отключает динамик по окончании звука. Если этот способ
недостаточен, - например, если программа генерирует звук тогда,
когда не совсем ясно, был ли выключен динамик - можно выключить
его, сбросив в нуль бит 1 порта 61H.
Эти два метода управления динамиком наиболее прямолинейны. Эти
методы можно пытаться комбинировать в поисках интересных эффектов.
После установки на вывод звука при помощи микросхемы 8253 можно
модулировать выходной сигнал посредством битов 1, 0 или обоих,
порта 61H, а также менять число в канальном счетчике при включенном
динамике. Программу на Фиг. 8.1 можно изменить так, чтобы она
выводила значение регистра CX при каждой итерации цикла. Это
приведет к тому, что частота сигнала из динамика будет расти от
очень низкого к очень высокому тону. Работая с этими тремя
управляющими значениями, вы сможете создать множество интересных
эффектов.
Клавиатура
Следующее устройство ввода-вывода, которое мы рассмотрим, -
клавиатура. Клавиатура отделена от ЭВМ и подключено к системе
четырехжильным проводом. Хотя внутри клавиатуры и находится
отдельный микропроцессор, для его программирования нет простого
способа, так что мы оставим эту задачу инженерам фирмы IBM. Мы же
можем заняться информацией, которую клавиатура посылает в систему.
Цепь обслуживания клавиатуры на системной плате подключена к
системе прерываний. Кадый раз, как эта цепь регистрирует нажатие
клавиши, она возбуждает прерывание в системе. Это прерывание
передает управление обработчику прерываний от клавиатуры. Эта
процедура получает от клавиатуры данные и сохраняет их для
дальнейшего использования. Обработчик прерываний клавиатуры
обслуживает также специальные случаи, например, перезагрузка
системы (CTL-ALT-DEL) и снятие програмы (CTL-BREAK). Но мы не будем
рассказывать, как это делается, до следующей главы, поскольку все
это обслуживает встроенная система программ BIOS. Пока же осмотрим,
как можно управлять аппаратурой обслуживания клавиатуры.
Когда клавиатура посылает сигнал прерывания, он, прежде, чем
попадет в микропроцессор 8088, проходит через контроллер прерываний
8259. Этот контроллер обслуживает систему прерываний IBM PC почти
во всех ее аспектах.
Микросхема 8259 может обслужить до восьми прерывающих
устройств. К линиям прерываний в IBM PC подключен системный таймер,
клавиатура, адаптер асинхронной связи, фиксированный диск
(винчестер), накопитель на гибких магнитных дисках и печатающее
устройство. Остальные уровни прерываний доступны другим устройствам
ввода-вывода, подключенным к системному каналу ввода-вывода.
Конструктивно каждое из прерывающих устройств назначено к своему
входу прерывания микросхемы 8259. Вход прерывания, к которому
подключено прерывающее устройство, называется уровнем прерывания
этого устройства. Как мы сейчас увидим, микросхема 8259
упорядочивает приоритеты прерываний в соответствии с уровнем. На
Фиг. 8.3 показаны уровни прерываний каждого устройства ЭВМ.
Прерывание от каждого устройства можно по-отдельности
заблокировать или разблокировать. Микросхема 8259 работает точно
так же, как микропроцессор 8088, который имеет флаг прерываний,
разрешающий или запрещающий прерывания по командам STI и CLI. Но
8259 имеет восемь флагов прерываний - по одному на каждое возможное
прерывающее устройство. Эти флаги содержит регистр маски прерываний
IMR (Interrupt Mask Register), расположенный в порту по адресу 21H.
Бит 7 соответствует прерыванию 7, бит 6 - прерыванию 6, и так
далее. Если вы установите бит в 1, устройство не может вызвать
прерывание; если же бит сброшен в 0, контроллер прерываний передает
прерывание дальше, микропроцессору 8088. Разумеется, даже если
какое-либо прерывание разблокировано в регистре IMR, прежде чем это
прерывание сможет произойти, необходимо также сбросить флаг
прерываний в микропроцессоре 8088.
В зависимости от уровня прерывания контроллер назначает
приоритеты каждому прерывающему устройству. Уровень прерывания
определяется аппаратным подключением и не может быть изменен
программным путем. Прерывание номер 0 имеет высший приоритет,
прерывание номер 7 - низший. Если любые два устройства пытаются
одновременно возбудить прерывание, обслуживается устройство более
высокого приоритета. Обслуживание устройства более низкого
приоритета откладывается до тех пор, пока не будет обслужено
устройство с более высоким приоритетом. Микросхема 8259
автоматически реализует такое разбиение по приоритетам, но в
Уровень Устройство
--------------------------------------------------
0 Канал таймера 0
1 Клавиатура
2 -
3 Асинхронные коммуникации
4 Упорядоченные асинхронные коммуникации
5 Фиксированный диск
6 Дискета
7 Принтер
--------------------------------------------------
Фиг. 8.3 Уровни прерываний для микросхемы 8259
управлении прерываниями должна принимать участие и ваша программа;
именно, она должна сообщить контроллеру 8259 о том, что она
закончила работу с текущим прервавшим устройством. Такая команда
называется EOI (конец прерывания), она сообщает микросхеме 8259,
что обработка прерывания от устройства с наивысшим приоритетом
закончилась, и теперь вызвать прерывание в системе может устройство
с более низким приоритетом.
Контроллер 8259 также предотвращает прерывание микропроцессора
устройством с более низким приоритетом, если система в этот момент
обслуживает прерывание с более высоким приоритетом. Микросхема 8259
запоминает текущее активное прерывание, и считает, что
микропроцессор обслуживает это прерывание до тех пор, пока не
получит команду EOI. Микросхема 8259 делает это с помощью двух
внутренних регистров. Первый из них идентифицирует устройства,
которые к настоящему моменту выдали запрос на прерывание; этот
регистр называется регистром запросов прерываний IRR. Другой
регистр следит за текущими обслуживаемыми прерываниями, и
называется регистром обслуживаемых прерываний ISR. Если вы забыли
выполнить команду EOI, микропроцессор сможет прерывать только
программы обработки прерываний от устройств с боле высоким
приоритетом. Если вы не выполнили команду EOI после прерывания от
таймера, система попадает в останов. Так как таймер имеет наивысший
приоритет, отсутствие завершения его прерывания блокирует
возбуждение всех других прерываний.
Контроллер 8259, кроме того, упорядочивает все прерывания. Это
означает, что контроллер заставляет микропроцессор правильно
выбирать обработчик прерываний. Когда контроллер распознает
прерывание, он вынуждвет микропроцессор 8088 начинать работу по
адресу, указанному в одном из 256 векторов прерываний в первом
килобайте памяти. IBM PC отображает восемь уровней прерывания
контроллера 8259 на вектора прерываний от 8 до 0FH включительно.
Так, если поступает прерывание от клавиатуры (уровень 1),
начинается выполнение программы по адресу CS:IP, определенному
двойным словом в векторе прерываний 9, лежащему по адресам от 24H
до 27H.
Давайте посмотрим, как все это вместе происходит в IBM PC.
Сначала процедура самопроверки при включении питания (POST)
инициализирует контроллер 8259 с соответствующей управляющей и
упорядочивающей информацией. В это же время процедура POST снимает
маску прерываний от таймера, клавиатуры, а также прерываний от
дискет в регистре маски прерываний микросхемы 8259. После
завершения процедуры POST включается система прерываний по команде
STI. Теперь система готова к приему прерываний.
Вы нажимаете клавишу на клавиатуре. Клавиатура посылает символ
в системную плату, где он записывается в регистр и возбуждает
прерывание уровня 1. Далее начинает работу микросхема 8259. Она
устанавливает бит 1 в регистре IRR, отмечая запрос на прерывание.
Если не установлены ни нулевой, ни первый биты регистра ISR,
показывающие обслуживание прерывания с более высоким приоритетом,
контроллер возбуждает вход прерывания микропроцессора 8088. Когда
микропроцессор окажется готов к приему прерывания, он выполнит цикл
подтверждения прерывания. Микропроцессор 8088 поместит в стек
текущее содержимое регистра флагов, CS и IP. Контроллер 8259
отвечает на цикл подтверждения прерывания номером прерывания, в
данном случае это 9; затем контроллер установит равным единице бит
1 в регистре ISR, показывая, что прерывание 1 обслуживается. Тем
временем микропроцессор 8088 загружает пару регистров CS:IP из
ячеек 24H- 27H и начинает работу с указанного в них адреса.
Затем микропроцессор выполняет программу обработки прерываний
от клавиатуры. На Фиг. 8.4 показана схема обработчика прерывания от
клавиатуры. Обратите внимание, что первая команда, которую должна
выполнить эта программа, сохраняет содержимое регистра AX в стеке.
Это делается потому, что программа изменяет содержимое регистра AX.
Если обработчик прерываний не восстановит первоначальное значение
этого регистра перед возвратом в прерванную программу, возникнет
ошибка выполнения. Это ведь очень трудно - писать верно работающие
программы, если во время их выполнения содержимое регистров будет
произвольно изменяться другими программами. Если обработчику
прерывания потребуется больше регистров, то он должен все их
сохранить, а затем восстановить.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:14
Фиг. 8.4 Управление клавиатурой Page 1-1
PAGE ,132
TITLE Фиг. 8.4 Управление клавиатурой
0000 CODE SEGMENT
ASSUME CS:CODE
0000 KEYBOARD_INTERRUPT PROC FAR
0000 50 PUSH AX ; Сохранение регистра AX
0001 E4 60 IN AL, 60H ; Выборка номера клавиши
0003 50 PUSH AX ; Сохранение номера клавиши
0004 E4 61 IN AL, 61H
0006 8A E0 MOV AH, AL ; Сохранение текущего значения регистра AL
0008 0C 80 OR AL, 80H
000A E6 61 OUT 61H, AL ; Сигнал об успешном получении символа
000C 8A C4 MOV AL, AH
000E E6 61 OUT 61H, AL ; Возврат Клавиатуры в нормальный режим
0010 58 POP AX
; ...
0011 B0 20 MOV AL, 20H
0013 E6 20 OUT 20H, AL ; Сигнал об окончании прерывания
0015 58 POP AX ; Восстановление регистра AX
0016 CF IRET ; Возвращение в прерванную программу
0017 KEYBOARD_INTERRUPT ENDP
0017 CODE ENDS
END
Фиг. 8.4 Контроль клавиатуры
Обработчик прерывания читает код клавиши, так называемый код
сканирования, из порта 60H. Программа доложна "убрать" прерывание,
сообщив устройству ввода-вывода, что оно должно снять запрос на
прерывание. Программа сбрасывает прерывание от клавиатуры,
устанавливая бит 7 порта 61H. Это не только отменяет запрос на
прерывание, но и сообщает клавиатуре, что она может присылать
следующий символ в микропроцессор 8088. Теперь программа прерывания
может обработать код от клавиши.
Когда обслуживание прерывания завершено, обработчик прерывания
посылает в микросхему 8259 команду EOI. Она сбрасывает в 0 бит 1 в
регистре ISR, и теперь могут произойти любые ожидающие обслуживания
прерывания с меньшими приоритетами. Выполнение команды EOI состоит
в посылке в порт 20H кода 20H. Программа обработки прерывания
восстанавливает содержимое регистра AX, команда IRET
восстанавливает регистры флагов IP, CS, а также приводит флаги к их
первоначальному виду до прерывания.
Точно такая же последовательность событий происходит в случае
любого прерывания, исходящего от микросхемы 8259 и обслуживаемого
микропроцессором 8088. Единственная разница заключается в том,
какое именно прерывание возникает. От этого изменяется установка
битов в регистрах IRR и ISR, и номер вектора прерывания,
выдаваемого микропроцессору 8088. Обработчик прерывания должен все
также сохранять состояние микропроцессора в момент прерывания, а
программа должна выполнить команду EOI в конце обработки
прерывания, или когда определит, что выполняемая программа может
принять прерывание меньшего приоритета. И еще одно предостережение.
Ваша программа обработки прерывания не должена посылать две команды
EOI. Если выполняющаяся программа обработки прерывания прервала
работу обработчика с меньшим приоритетом, вторая команда EOI
поступит вместо этой команды от обработчика с меньшим приоритетом.
Это может привести к неприемлимым последствиям, почему вам и не
следует допускать такого наложения.
Итак, мы обработали прерывание от клавиатуры, правильно
установили все биты и выполнили все команды. Что же мы получили?
Клавиатура посылает в микропроцессор "коды сканирования". Их
значения отражают расположение клавиш на клавиатуре и не имеют
никакого отношения к символу, изображенному на клавише. Например,
клавише ESC возвращает код сканирования 1, клавиша "1" - код 2, и
так далее. Клавише DEL соответствует код сканирования 83. Каждая
клавиша имеет свой собственный уникальный код сканирования. Так что
данные из порта 60H не могут рассматриваться как символ кода ASCII.
Код сканирования нужно еще перекодировать в правильный код
символа.
Клавиатура передает несколько больше, чем только эти 83 кода
сканирования. Первые коды, от 1 до 83, известные как "коды нажатия"
клавиатура посылает, при нажатии клавиши. Когда клавиша
отпускается, клавиатура посылает другой код сканирования, "код
отпускания". Код отпускания формируется прибавлением числа 128 к
коду нажатия. То есть коды отпускания попадают в диапазон от 129 до
211; их легко распознать по 7-му биту, равному 1.
Поскольку клавиатура посылает различные коды для каждого
нажатия и отпускания клавиши, программа может отследить состояние
каждой клавиши. Вы узнаете о нажатии клавиши, получив от клавиатуры
код нажатия. Клавиша нажата, пока вы не получите код отпускания,
сообщающий, что клавиша отпущена. Для большинства клавиш эта
информация не важна, но для регистровых клавиш (например, клавиши
верхнего регистра) она решающая. Например, большие буквы
формируются только тогда, когда клавиша верхнего регистра нажата.
Так как такая информация доступна от любой клавиши клавиатуры IBM,
работа с регистровыми клавишами не составляет труда. Если вы
пожелаете изменить кодировку клавиатуры, устроив свое собственное
расположение клавиш, любая клавиша может трактоваться вами как
регистровая.
И наконец, каждая клавиша клавиатуры IBM имеет встроенный
механизм автоповторения. Если вы держите любую клавишу нажатой
более 1/2 секунды, клавиатура начинает посылать коды нажатия со
скоростью 10 раз в секунду. Это удобно для обычных клавиш, особенно
для клавиш управления курсором. Вы просто держите их нажатыми, и
курсор движется в нужное место. Но если у вас есть клавиши,
выполняющие некоторую работу только в момент первого нажатия (и не
может использовать автоповторение), вы опять-таки должны
отслеживать нажатия и отпускания этой клавиши. Только первый код
нажатия должен вызывать ее срабатывание, а остальные коды нажатия
вы должны игнорировать.
Время суток
Канал 0 таймера 8253 имеет специальное назначение в IBM PC. Выход
этого канала таймера подключен к уровню прерывания 0 микросхемы
8259. Это означает, что всякий раз, когда выход канала 0 имеет
активный уровень сигнала, возникает прерывание (при условии, что
все остальное установлено корректно). Процедура самопроверки при
включении питания инициализирует канал 0 таймера, загружая в него
число 0. Это дает наибольшее (не наименьшее) значение счетчика,
которое может записать в него программа. Имея на входе частоту 1.19
МГц, счетчик считает обратно к нулю чуть быстрее, чем за 55
миллисекунд. Программа инициализации устанавливает таймер таким
образом, что он считает непрерывно. Это означает, что прерывание 0
возникает 18.2 раза в секунду.
Как мы увидим в следующей главе, встроенная система программ
BIOS использует это постоянное прерывание от таймера, чтобы следить
за текущим временем. BIOS продвигает часы текущего времени вперед
всякий раз, когда возникает прерывание. Затем, с помощью
соответствующих вычислений, Вы можете преобразовать число циклов
таймера в часы, минуты и секунды.
Почему же выбрано значение 18.2? Почему счетчик не
программируется так, чтобы давать прерывание 20 раз в секунду, или
другое "хорошее" число раз? Это объясняет следующий пример.
Системный таймер может выполнять функцию измерения времени
отличного от времени дня. Время дня прекрасно подходит для
определения интервалов времени, измеряемых в секундах или минутах.
Но в некоторых ситуациях, возникающих при управлении
вводом-выводом, нужно определять интервалы времени порядка одной -
двух миллисекунд. Обычно программы отсчитывают такие интервалы с
помощью временного цикла. Программа для такого цикла выглядит
примерно так:
MOV CX, LOOP_VALUE
HERE:LOOP HERE
Вы выбираете константу LOOP_VALUE так, что цикл выполняется в
точности нужное число раз. Это очень хороший метод, если вам нужна
задержка на определенное время. В выше приведенном примере
начальное значение константы LOOP_VALUE, равное 0FFFFH, дает время
выполнения около 250-миллисекунд.
Но предположим, что вы хотите понаблюдать за внешним событием,
и определить, сколко времени займет его наступление. Можно использовать
вариант временного цикла такого, например, вида:
MOV CX, 0
HERE:
; --- проверка возникновения события
IN AL, DX
TEST AL, MASK_BIT
LOOPNE HERE
DONE:
; --- CX содержит число итераций цикла
Таким способом вы считаете число итераций цикла, чтобы
вычислить затраченное на него время. Этот метод предполагает, что
событие возникнет до того, как содержимое регистра CX второй раз
достигнет 0. Но если вам нужно измерить что-то с точностью до
микросекунд, этот метод не удобен, так как каждая итерация цикла
требует от 10 до 20 микросекунд. Системный таймер дает лучшее
решение. Поскольку он изменяет свое значение каждые 840 наносекунд,
вы сможете определить длительность события с точностью до
микросекунды.
На Фиг. 8.5 показан пример программы, вычисляющей время события
с помощью системного таймера. В этом примере в качестве
регистрируемого события используется канал 2 таймера. В первой
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:19
Фиг. 8.5 Управление системным таймером Page 1-1
PAGE ,132
TITLE Фиг. 8.5 Управление системным таймером
0000 STACK SEGMENT STACK
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
0000 CODE SEGMENT
ASSUME CS:CODE
0000 TIMER PROC FAR
0000 1E PUSH DS ; Занесение адреса возврата
0001 B8 0000 MOV AX, 0
0004 50 PUSH AX
0005 B0 B6 MOV AL, 10110110B ; Выборка таймера 2
0007 E6 43 OUT 43H, AL
0009 B8 0500 MOV AX, 500H
000C E6 42 OUT 42H, AL ; Таймер 2 установлен на 500 отсчетов
000E 8A C4 MOV AL, AH
0010 E6 42 OUT 42H, AL
0012 E8 001D R CALL LOW_TO_HIGH ; Выборка времени первого перехода с 0 на 1
0015 8B D8 MOV BX, AX ; Сохранение значения в регистре BX
0017 E8 001D R CALL LOW_TO_HIGH ; Выборка времени второго перехода с 0 на 1
001A 2B D8 SUB BX, AX ; Вычитая получаем длину цикла
001C CB RET
001D TIMER ENDP
Фиг. 8.5 Управление системным таймером (начало)
;--------------------------------------------
; Эта подпрограмма ждет перехода с нижнего уровня
; сигнала на верхний (с 0 на 1) в таймере 2
; и возвращает в регистре AX значение счетчика таймера 0
;--------------------------------------------
001D LOW_TO_HIGH PROC NEAR
001D E4 62 IN AL, 62H ; Проверка разряда таймера 2
001F A8 20 TEST AL, 20H
0021 75 FA JNZ LOW_TO_HIGH ; Цикл: сигнал таймера 2 на
; нижнем уровне
0023 WAIT_HIGH:
0023 E4 62 IN AL, 62H ; Проверка разряда таймера 2
0025 A8 20 TEST AL, 20H
0027 74 FA JZ WAIT_HIGH ; Цикл: сигнал таймера 2 на
; верхнем уровне
0029 B0 00 MOV AL, 0 ; Послать команду в регистр управления тай-
002B E6 43 OUT 43H, AL ; мером 2, которая "замораживает" таймер 2
002D 90 NOP
002E 90 NOP ; Задержка, необходимая для 8253
002F E4 40 IN AL, 40H ; Чтение младшего байта счетчика
0031 8A E0 MOV AH, AL
0033 90 NOP
0034 E4 40 IN AL, 40H ; Чтение старшего байта счетчика
0036 86 E0 XCHG AH, AL
0038 C3 RET ; Возвращение значения в AX
0039 LOW_TO_HIGH ENDP
0039 CODE ENDS
END
Фиг. 8.5 Системный таймер (продолжение)
части программы этот канал таймера загружается известным значением.
Здесь мы произвольно выбрали число 500H. Обратите внимание, что эта
часть программы идентична способу генерации звуков с помощью втого
канала таймера.
Наша программа вызывает подпрограмму LOW_TO_HIGH, которая
возвращает значение таймера в тот момент, когда на выходе канала 2
таймера отмечается переход от низкого к высокому уровню. Программа
рследит именно за переходом; если бы она регистрировала только
высокий уровень, было бы неизвестно, стал ли сигнал высоким только
что или уже готов стать низким. Подпрограмма посылает нуль в
управляющий регистр таймера (порт 43H), чтобы "заморозить" текущее
значение канала 0. Это позволяет ей прочитать текущее значение
таймера, продолжающего счет. Если бы программа временно не
зафиксировала таймер, она не смогла бы прочитать без ошибки его
16-битовое значение.
Обратим внимание на то, что подпрограмма на Фиг. 8.5 содержит
несколько команд NOP. Эти команды записаны в программе для выдержки
временных соотношений. Если очень внимательно прочитать инструкции
по микросхеме 8253, мы заметим, что между командами IN и OUT,
выполняемыми этой микросхемой, проходит не меньше 1 микросекунды.
Команда NOP занимает как раз достаточно времени, чтобы исключить
нарушение требований микросхемы по времени.
После возврата из подпрограммы программа сохраняет в регистре
BX значение счетчика таймера во время первого перехода с низкого
уровня на высокий. Затем программа снова вызывает подпрограмму,
чтобы зарегистрировать следующий переход с низкого уровня на
высокий на выходе канала 2 таймера. Потом она вычитает одно число
из другого, чтобы определить время цикла канала 2.
Мы уже говорили о том, что загрузка регистра 0 таймера
значением счета 0 - очень полезна. Данная программа подтверждает
это, так как она вычитает два значения таймера, не обращая внимания
на то, какое из них больше, а какое меньше. Так как канал 0 таймера
работает асинхронно по отношению к этой программе, нет никакой
гарантии, что первое читаемое из него число больше второго.
Например, предположим, что первый переход с низкого на высокий
уровень происходит, когда таймер 0 имеет значение 100H. После 500H
циклов значение числа в таймере будет 0FC00H. Счетчик таймера 0
автоматически "проскочил" от значения 0 к значению 0FFFFH, и
значение прочитанное вторым оказалось численно больше первого. Но
из-за того, что регистр таймера снова начинает счет со значения
0FFFFH, мы всегда можем вычитать эти два числа. При этом иногда
будет появляться перенос, иногда нет, но разность этих двух чисел
всегда будет равна числу отсчетов.
Чтобы убедить вас в правильности этого положения, рассмотрим
случай, когда счетчик загружается числом 8000H. Если первый переход
возникает при значении 6000H, второй появится при значении 5B00H, и
разница между ними составляет 500H. Но если первый переход
возникает при значении 100H, второй возникает при значении 7C00H, и
разница станет равна 8500H. Чтобы правильно отреагировать на эту
ситуацию, программа должна была бы проверить, не произошло ли
переполнение счетчика за время отсчета.
При выполнении этой программы вы обнаружите, что значение в
регистре BX составляет около 0A00H, и не равно ожидаемому значению
500H. Так происходит потому, что таймер работает в режиме
уменьшения содержимого счетчика на два по каждому временному
импульсу. Чтобы разобраться в работе микросхемы 8253, нужно
ознакомиться с инструкцией по ее программированию.
Фиг. 8.6 дает сводку для управляющего слова микросхемы 8253.
Для настройки одного из каналов на конкретный режим работы вы
выводите это управляющее слово в порт 43H. Мы уже встречались с
выводом некотрых значений в порт 43H. Чтобы "заморозить" счетчик,
мы послали в этот порт нуль, а для настройки генератора тональности
- код 0B6H. Посмотрим, откуда берутся эти значения.
Два старших бита управляющего слова определяют канал таймера.
Следующие два бита - выполняемую операцию. Когда мы выводим
значение 0, выбирается таймер 0 и запирание данных в счетчике.
Следующие 3 бита задают режим работы выбранного таймера. Эти биты
не играют роли, когда счетчик заперт, но нужны при инициализации
таймера. Оставшийся бит определяет, будет ли счетчик работать как
16-битовое двоичное число или как четырехзначное десятичное в
двоичном представлении.
A
Формат управляющего слова
D7 D6 D5 D4 D3 D2 D1 D0
ЪДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДї
і SC1і SC0і RL1і RL0і M2 і M1 і M0 і BCDі
АДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДЩ
Определение управления
SC - выбор счетчика:
SC1 SC0
ЪДДДДДДДДДВДДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДї
і 0 і 0 і задать счетчик 0 і
ГДДДДДДДДДЕДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДґ
і 0 і 1 і задать счетчик 1 і
ГДДДДДДДДДЕДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДґ
і 1 і 0 і задать счетчик 2 і
ГДДДДДДДДДЕДДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДґ
і 1 і 1 і неопределено і
АДДДДДДДДДБДДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДЩ
RL - чтение/загрузка:
RL1 RL0
ЪДДДДВДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і 0 і 0 і Операция запирания счетчика (см. і
і і і раздел процедуры READ/WRITE) і
ГДДДДЕДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і 1 і 0 і Считать/загрузить старший байт і
ГДДДДЕДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і 0 і 1 і Считать/загрузить младший байт і
ГДДДДЕДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і 1 і 1 і Считать/загрузить младший байт, і
і і і затем - старший і
АДДДДБДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
M - режим:
M2 M1 M0
ЪДДДВДДДВДДДВДДДДДДДДДДДї
і 0 і 0 і 0 і Режим 0 і
ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
і 0 і 0 і 0 і Режим 1 і
ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
і X і 1 і 0 і Режим 2 і
ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
і X і 1 і 1 і Режим 3 і
ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
і 1 і 0 і 0 і Режим 4 і
ГДДДЕДДДЕДДДЕДДДДДДДДДДДґ
і 1 і 0 і 1 і Режим 5 і
АДДДБДДДБДДДБДДДДДДДДДДДЩ
BCD:
ЪДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДї
і 0 і 16-битовый двоичный счетчик і
ГДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ
і 1 і десятичный в двоичном представлении і
і і (BCD) счетчик (4-х разрядный) і
АДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ
Фиг. 8.6 Программирование таймера/счетчика
(с разрешения фирмы Intel; приоритет Intel 1981г.)A
Управляющий код 0B6H, который использовался для генерации
тональности, можно расписать таким образом:
0B6H = 10110110B = 01 11 011 0
Это управляющее слово выбирает канал 2. Счетчик этого канала
работает с 16-битовым значением, младший байт которого загружается
в счетчик первым. Последный бит показывает, что счет будет
двоичным. Можно видеть также, что выбирается третий режим работы.
Микросхема 8253 может работать в шести разных режимах. Но для
наших целей, в конфигурации системы IBM, удобны только два из них.
Режим 3 устанавливается по умолчанию для всех трех каналов таймера.
Это режим работы генератора прямоугольных импульсов: половину
периода выход канала дает нижний уровень, а другую половину периода
- верхний. Счетчик работает в этом режиме, вычитая из своего
значения по два, а не по одному. Во время первого обратного счета
выход низкий, а затем, во время второго счета - высокий. Так как
счетчик считает по два, выход имеет высокий уровень точно половину
заданного времени, и низкий тоже точно половину. Из-за того, что
канал 0 таймера обычно работает в режиме 3, пример на Фиг. 8.5
заканчивает счет со значением счетчика 0A00H, а не 500H, как
ожидалось. Каждый отсчет таймера уменьшает содержимое счетчика на
два.
Так как счетчик считает двойками, он переполняется каждые 27
микросекунд. Если вы хотите измерять события более длительные, то
вам придется воспользоваться другим способом измерения времени.
Другой режим таймера, который используется в IBM PC - это режим
0. Этот режим называют прерыванием по завершению счета. В этом
режиме таймер не работает непрерывно. После его установки таймер до
тех пор не начинает считать (единицами), пока в него полностью не
будет загружено число. Затем счетчик считает в сторону уменьшения с
частотой синхроимпульсов, пока не достигнет нуля. В этот момент его
выход становится высоким. Поскольку выход канала 0 таймера
подключен к прерыванию 0 контроллера 8259, в системе возникает
прерывание.
Режим прерывания по завершению счета полезен, если вы хотите в
определенный момент подать программе сигнал с помощью прерывания.
Так как счетчик ограничен шестнадцатью битами, максимальный
отсчитываемый интервал времени составляет 55 миллисекунд. Если этот
интервал слишком мал, нужен другой метод измерения времени.
Если вы хотите измерять интервал времени в секундах, нужно
оставить таймер в его обычном режиме работы. Система BIOS позволяет
захватывать управление системой каждые 55 миллисекунд, и в каждый
такой момент вы можете решить, не исчерпался ли нужный промежуток
времени.
Если время нужной вам задержки находится между 55
миллисекундами и 5 секундами, можно использовать метод без
использования программ BIOS. Например, вам хочется сделать задержку
на 150 миллисекунд. Используя режим прерывания по завершению счета,
вы настраиваете таймер на прерывание через 50 миллисекунд (этому
соответствует значенние счетчика около 59500). Обработчик
прерывания программируется так, чтобы, получая управление первые
два раза, он заново устанавливал таймер на 50 миллисекунд. По
третьему прерыванию от таймера, когда 150 миллисекунд исчерпаны,
можно предпринять нужные действия.
При организации задержек через таймер всегда нужна некоторая
осторожность. Как упоминалось выше, канал 1 таймера выполняет одну
важную аппаратную функцию. Если вы модифицируете число в канале 1,
ваша программа может немедленно разрушиться. Использование канала 2
таймера безопасно. Этот канал подключен только к динамику и выходу
кассетного магнитофона. Отсюда, очевидно, следует, что нельзя
использовать канал 2 таймера для отсчета промежутков времени в одно
время с попытками воспроизводить мелодии через динамик. И наконец,
BIOS пользуется услугами таймера 0 для различных системных функций.
При обсуждении BIOS будет видно, что прерывание по времени суток
управляет не только текущим временем, но также обслуживает и
двигатель накопителя на дискетах. Перед тем, как изменять настройку
канала 0 таймера для любых целей, нужно понять, какие существующие
функции вы можете при этом изменить.
Возможности системы
Эта часть главы описывает программные аспекты некоторых
системных возможностей. Не каждая система обладает теми
возможностями, которые мы опишем. Мы обсудим те из них, которые вы
сможете обнаружить в большинстве систем. Обсуждение коснется двух
видео адаптеров, адаптера дисковода, адаптера печатающего
устройства, адаптера асинхронных коммуникаций и игрового
адаптера.
Видеоадаптеры
Система IBM PC, которая попадет к вам в руки, может быть
снабжена одним из двух различных дасплейных адаптеров. Один из них
- адаптер монохромного дисплея и принтера (мы будем называть его
монохромным адаптером, или иногда - черно-белой платой). Такой
видео адаптер лучше всего подходит для деловых приложений.
Черно-белая плата управляет монохромным дисплеем фирмы IBM.
Монохромный адаптер работает в одном режиме, и может показывать на
экране текст только одного цвета. Этот адаптер также содержит
аппаратные узлы, необходимые для управления печатающим устройством.
Такая комбинированная плата удобнее всего для деловых приложений.
Другой видео адаптер - адаптер цветного графического
монитора (мы будем называть его цветной платой). Цветная плата
работает с дисплеями, использующими нормальные телевизионные
частоты. Этот адаптер дает цветные изображения, а не только
одноцветные, как монохромный. У него есть несколько режимов работы,
включая такие, в которых можно управлять отдельными точками
экрана.
Адаптер монохромного дисплея и принтера
Сначала поговорим о монохромном дисплее, он - простейший из
двух адаптеров. Мы отложим описание той части платы, которая
работает с печатающим устройством, пока не дойдем до адаптера
печатающего устройства. Схема адаптера печатающего устройства на
монохромной плате идентична схеме отдельного адаптера печатающего
устройства, поэтому способы программирования их также одинаковы.
Черно-белая плата работает в одном режиме. Этот видео адаптер
предназначен для вывода 25 строк символов по 80 символов в строке.
Такое построение изображения называют режимом 80*25. Вы помещаете
символы на экран, записывая коды ASCII в буфер дисплея. Буфер
дисплея - это специальная область памяти, расположенная в адресном
пространстве по адресу 0B0000H. Эта память - часть платы адаптера,
а не системной памяти. Всякий раз, когда вы записываете символ в
коде ASCII в буфер дисплея, он появляется в соответствующем месте
экрана. Преобразование символа из кода ASCII в точки на экране
выполняется аппаратно.
Каждый символ на дисплее имеет атрибут. Атрибуты символов
определяют вид, в которым адаптер выводит символы на экран. На Фиг.
8.7 показаны атрибуты символов и их значения. Вам нужно знать эти
значения, так как их тоже надо помещать в буфер дисплея. Позиция
каждого символа в буфере дисплея занимает два байта. Четный байт
пары содержит код символа, а нечетный - значение атрибута. По Фиг.
8.7 можно определить значение атрибута, с которым выводить на экран
символ. Обычно выводится белый (на самом деле зеленый) символ на
черном фоне. Для этого случая значение атрибута равно 07H. Чтобы
сделать изображение негативным, нужно изменить значение атрибута на
70H. Атрибут 00H делает символ невидимым. Хотя код ASCII символа и
записан в байт символа, значение атрибута не дает символу появиться
на экране.
Дисплейный буфер черно-белой платы содержит 4K байта памяти.
Этого достаточно, чтобы иметь байты символов и атрибутов для каждой
из 2000 позиций экрана. Первый символ буфера дисплея появляется в
верхнем левом углу экрана, следующие два байта изображают следующий
символ справа, и так далее. Первый символ второй строки находится в
байтах 160 и 161. Теперь можно определить адрес любого символа на
экране. Сначала определим позицию в верхнем левом углу экрана, как
находящуюся в строке 0 и колонке 0; нижний правый угол находится в
строке 24 и колонке 79. Тогда формулой вычисления адреса для
произвольной строки и позиции будет
адрес = 2*(строка*80 + колонка) + 0B0000H
Умножение на 2 выравнивает адрес к двум байтам на позицию.
Прибавление значения 0B0000H отражает начальный адрес буфера
дисплея. Обычно в программе либо регистр DS, либо регистр ES
загружается значением 0B0000H, и в остальном программа работает со
смещениями в буфере дисплея.
Значение Атрибут
----------------------------------------------------------
00H ничего не выводится
01H подчеркнутые символы
07H белый символ на черном фоне
0FH ярко-белый символ, черный фон
70H черный символ, белый фон
80H при добавлении к любому другому символ
мигает
----------------------------------------------------------
Фиг. 8.7 Символьные атрибуты для монохромного адаптера
На Фиг. 8.8 в качестве примера для монохромного дисплея
приведена программа, которая перемещает содержимое экрана на одну
позицию вправо. Она выбрасывает крайнюю справа колонку, а слева
помещает колонку из пробелов. Если вы хотите испытать эту
программу, но имеете в своей системе только цветную плату, то
программа работает при установке сегмента DISPLAY на адрес 0B800H.
Оба видео адаптера очень похожи при работе в текстовом режиме, и
различаются только адресами памяти и ввода-вывода.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:26
Фиг. 8.8 Горизонтальный сдвиг вправо Page 1-1
PAGE ,132
TITLE Фиг. 8.8 Горизонтальный сдвиг вправо
0000 STACK SEGMENT STACK
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
0000 DISPLAY SEGMENT AT 0B800H
0000 DISPLAY_START LABEL WORD
0FA0 ORG 4000
0FA0 DISPLAY_END LABEL WORD
0FA0 DISPLAY ENDS
0000 CODE SEGMENT
ASSUME CS:CODE
0000 SIDE_SCROLL PROC FAR
0000 1E PUSH DS
0001 B8 0000 MOV AX, 0
0004 50 PUSH AX
0005 B8 ---- R MOV AX, DISPLAY
0008 8E D8 MOV DS, AX
000A 8E C0 MOV ES, AX
ASSUME DS:DISPLAY, ES:DISPLAY
;----- Заполнение столбца 79 пробелами
Фиг. 8.8 Горизонтальный сдвиг вправо
000C B9 0019 MOV CX, 25
000F 8D 3E 004E R LEA DI, DISPLAY_START+78
0013 B8 0720 MOV AX, 720H
0016 BLANK:
0016 89 05 MOV [DI], AX
0018 81 C7 00A0 ADD DI, 160
001C E2 F8 LOOP BLANK
;----- Сдвиг вправо
001E B9 07D0 MOV CX, 2000
0021 8D 36 0F9E R LEA SI, DISPLAY_END-2
0025 8D 3E 0FA0 R LEA DI, DISPLAY_END
0029 FD STD
002A F3/ A5 REP MOVSW
002C A3 0000 R MOV DISPLAY_START, AX
002F CB RET
0030 SIDE_SCROLL ENDP
0030 CODE ENDS
END
Фиг. 8.8 Горизонтальный сдвиг направо
Программа на Фиг. 8.8 делает этот горизонтальный сдвиг очень
простым способом. Правая колонка заполняется пробелами в результате
записи 25 пробелов через каждые 160 байт памяти. Затем программа
сдвигает весь дисплейный буфер по памяти на один байт вверх.
Поскольку буфер дисплея непрерывно продолжается строка за строкой,
символ, который был в колонке 79 строки 0, после сдвига оказывается
в колонке 0 строки 1. Наконец, программа заменяет первый символ
буфера пробелом.
Монохромный адаптер имеет также несколько портов ввода-вывода,
которые можно использовать при программаровании дисплея, но они
будут рассмотрены очень бегло. Конструкция монохромного адаптера
использует эти порты ввода-вывода в первую очередь для удобства
аппаратной организации. Кроме того, программирование черно-белой
платы в общих чертах аналогично цветной плате. Поскольку цветная
плата имеет намного больше специальных возможностей в использовании
портов ввода-вывода, мы поговорим о них в основном в следующем
разделе.
Монохромный адаптер порождает сигналы вертикальной и
горизонтальной синхронизации, необходимые для нормального
изображения, с помощью контроллера электронно-лучевой трубки 6845
фирмы Motorola. Эта микрсхема содержит два порта ввода-вывода,
имеющих адреса 3B4H и 3B5H. Адаптер также имеет управляющий порт
3B8H и порт состояния 3BAH. После инициализации адаптера
модифицировать коды в этих портах вряд ли стоит. Существуют и
другие режимы работы, возможные для монохромной платы, но мы
сконцентрируем наше внимание на цветной плате. Полное, детальное
описание портов ввода-вывода монохромного адаптера можно найти в
техническом описании.
Адаптер цветного графического монитора
Другой видеоадаптер, который может быть установлен на IBM PC -
адаптер цветного графического монитора. Цветная плата разработана в
фирме IBM для подключения к устройствам подобным телевизору.
Черно-белый адаптер работает только с монохромным дисплеем фирмы
IBM, а цветную плату можно подключить к любому цветному или
черно-белому монитору, использующему стандартные телевизионные
сигналы. Или, вы можете отдельно приобрести радиочастотный
модулятор, который позволит вам подключить выход цветной платы к
вашему домашнему телевизору. Цветная плата может быть подключена к
разнообразным мониторам, так как она работает на телевизионных
частотах.
Цветная плата имеет много режимов работы, и программы фирмы IBM
обслуживают некоторые из этих режимов. Обслуживание других режимов
оставлено вам. Цветная плата дает намного больше гибкости, чем
монохромная.
Для цветного графического адаптера возможны два текстовых
режима. Один текстовый режим формирует экран, имеющий 25 строк по
80 символов, идентичный монохромному адаптеру. Другой текстовый
режим уменьшает количество символов в строке до 40. Этот режим с
меньшим разрешением необходим, если вы хотите использовать цветную
плату или с монитором, имеющим меньшее разрашение, или с домашним
телевизором, так как 80-символьное изображение может оказаться
нечитабельным при некоторых изображениях. Чтобы использовать все
возможности цветной платы, вы должны работать с высококачественным
монитором. Монитор с высокой разрешающей способностью позволит вам
без искажений выводить полные 80-символьные строки.
Цветная плата имеет также два графических режима. В этих
режимах вы можете управлять каждой отдельной точкой экрана. В
текстовых режимах независима каждая символьная позиция, а в
графических режимах независимо управление каждой точкой.
Графический режим среднего разрашения дает 200 строк растра, по 320
точек в строке. Каждая из этих точек может иметь один из четырех
возможных цветов. Это означает, что любая точка управляется двумя
битами. Графический режим высокого разрешения дает 200 строк
растра, каждая из которых состоит из 640 точек; в этом режиме
возможны только два цвета, черный и белый.
Текстовый режим
Два текстовых режима цветного графического адаптера дают
простой способ вывода символов на экран. В текстовых режимах
цветная плата аналогична монохромному адаптеру, но она позволяет
указать цвет каждого символа. Так же, как и в монохромной плате,
каждая символьная позиция цветной платы имеет байт атрибутов. Этот
Номер бита 7 6 5 4 3 2 1 0
ЪДДВДДДДДДДДВДДВДДДДДДДДї
і Мі Ф О Ні Яі СИМВОЛ і Фиг. 8.9 Байт атрибута
АДДБДДБДДБДДБДДБДДБДДБДДЩ для ЦГА
- 289 -
байт атрибутов определяет цвета символов и фона каждой позиции.
На Фиг.8.9 показана структура байта атрибутов в цветном
текстовом режиме. Три бита, помеченных Ф О Н, определяют один из
восьми возможных цветов фона. Три бита СИМВОЛ определяют цвет
символа. Бит Я также влияет на цвет символа: его установка делает
цвет символа более ярким. Тем самым обеспечивается выбор одного из
16 цветов символа. Байт атрибута управляет единственным символом,
позволяя выбрать любую комбинацию цветов фона и символа каждой
позиции. Старший бит, помеченный буквой М, обычно вызывает мигание
символа. Установка бита мигания равным 1 заставляет контроллер
дисплея переключать цвет символа между его цветом и цветом фона со
скоростью примерно четыре раза в секунду. Так как символ,
изображенный в цвете фона, невидим, то получается эффект мигания.
Можно заменить бит мигания четвертым битом цвета фона, разрешив при
этом 16 цветов фона и 16 цветов символа. Это делает один из битов
регистра выбора цветов. Еще надо обратить внимание на то, что
одинаковая установка цветов символа и фона означает, что вы не
видите символ. Символ есть, но это все равно что пытаться увидеть
северного медведя в пургу - все одного цвета. На Фиг. 8.10 показаны
все 16 цветов, возможных в текстовом режиме.
I R G B Цвет
-------------------------------------
0 0 0 0 черный
0 0 0 1 синий
0 0 1 0 зеленый
0 0 1 1 морской волны
0 1 0 0 красный
0 1 0 1 магента
0 1 1 0 коричневый
0 1 1 1 светло-серый
1 0 0 0 темно-серый
1 0 0 1 голубой
1 0 1 0 светло-зеленый
1 0 1 1 светлый морской
1 1 0 0 розовый
1 1 0 1 светлый магента
1 1 1 0 желтый
1 1 1 1 белый
------------------------------------------- Фиг. 8.10 Цвета
(Фирма IBM, приоритет 1981 г.)
Если вы сравните байт атрибута для ЦГА с атрибутами для
монохромного адаптера на Фиг. 8.7, то увидите, что они аналогичны.
Конечно, вы не можете указать цвета монхромному адаптеру, но все
остальное совпадает. Поскольку цветная плата не поддерживает
атрибут подчеркивания, то установка монохромного атрибута
подчеркивания соответствует голубому символу на черном фоне.
Такая организация байта атрибутов является попыткой сделать два
видео адаптера по-возможности совпадающими. Каждый символ в буфере
дисплея находится по четному адресу, а байт атрибутов - по
нечетному. Память цветного дисплея находится на видео адаптере, но
по другому адресу: у монохромного дисплея она имеет адрес 0B0000H,
а у цветного - 0B8000H. О сходстве дисплеев говорит то, что если
при модификации программы для монохромного дисплея на Фиг. 8.8,
изменить содержимое указателя AT сегмента на значение 0B800H,
программа будет верно работать и на цветной плате. То есть одна и
та же программа работает на любом видео адаптере при минимуме
изменений.
Для управления адаптером на цветной плате также используется
контроллер ЭЛТ 6845 фирмы Motorola. Два порта ввода-вывода этого
контроллера имеют адреса ввода-вывода 3D4H и 3D5H. На самом деле
контроллер 6845 имеет 18 внутренних регистров. Доступ ко всем
регистрам осуществляется с помощью двух портов ввода-вывода и
косвенной адресации. Для обращения к регистру микросхемы 6845,
нужно сначала загрузить индекс регистра в порт 3D4H, а затем читать
этот регистр или записать в него данные через порт 3D5H.
Приведем пример, чтобы пояснить, как работает контроллер. На
Фиг. 8.11 перечислены все 18 регистров микросхемы 6845. В примере
мы используем только регистры R10 и R11. Эти регистры определяют
начальную и конечную строки растра одного знакоместа для курсора.
Каждый символ, порождаемый цветной платой, состоит из восьми строк
растра, имеющих номера от 0 до 7. Вы можете поместить курсор в
любых из этих восьми строк. Регистр R10 сообщает микросхеме 6845,
на какой строке начинается курсор, а регистр R11 определяет
последнюю строку курсора. ROM BIOS инициализирует курсор,
находящийся на строках 6 и 7; это делается загрузкой числа 6 в R10
и числа 7 в R11.
Прогамма на Фиг.8.12(а) модифицирует курсор цветной графической
платы. Она смещает курсор так, что он оказывается на верхних пяти
строках растра вместо нижних двух. Сначала программа загружает в
индексный регистр контроллера 6845 (3D4H) число 10, а затем
записывает номер начальной строки, равный 0, в регистр данных
(3D5H). Затем, поместив 11 в индексный регистр, она устанавливает
номер конечной строки равным 4. Теперь курсор имеет вид мигающего
блока в верхней части позиции символа, а не митающего
подчеркивания. Подобный этому способ модификации курсора
используется несколькими редактирующими программами (редакторами)
персональной ЭВМ, включая встроенный редактор интерпретатор языка
Бейсик. При установке режима вставки во время редактирования,
курсор становится жирнее; интерпретатор Бейсика делает это, меняя
параметры в микросхеме 6845.
Вернувшись к Фиг. 8.11, можно увидеть, что в микросхеме 6845
есть и другие регистры. Большинство из них управляет сигналами
горизонтальной и вертикальной синхронизации телевизионного растра.
Вы можете модифицировать коды в этих регистрах для каких-либо
действий дисплеем. Например, команда MODE системы DOS, которая
может сдвигать катринку на экране влево и вправо, модифицирует
регистр R2, задающий положение строчного синхроимпульса.
Если вы захотите поэкспериментировать с этими регистрами, вам
придется писать короткие программы, делающие требуемые изменения.
ЪДДДДДДДДВДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДВДДДДДДДДДДДВДДДДДДДДВДДДДДДДДї
іРегистр і і Объект в і і і
і # і Регистр хранит і программе і чтение і запись і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R0 і Гориз. сумма і Символ і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R1 і Выводимая горизонталь і Символ і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R2 і Гориз. поз. синхронизации і Символ і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R3 і Гориз. ширина синхронизации і Символ і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R4 і Вертикальный итог і Симв. ряд і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R5 і Общая вертикальн.коррекция іСкан.строкиі Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R6 і Выводимая вертикаль і Симв. ряд і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R7 і Поз. вертикальной синхрон. і Симв. ряд і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R8 і Режим совмещения і - і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R9 і Макс.адрес скан. строки іСкан.строкиі Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R10 і Начало курсора іСкан.строкиі Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R11 і Конец курсора іСкан.строкиі Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R12 і Начальный адрес (гориз.) і - і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R13 і Начальный адрес (строка) і - і Нет і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R14 і Курсор (Гориз.) і - і Да і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R15 і Курсор (Строка) і - і Да і Да і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R16 і Световое перо (гориз.) і - і Да і Нет і
ГДДДДДДДДЕДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЕДДДДДДДДДДДЕДДДДДДДДЕДДДДДДДДґ
і R17 і Световое перо(строка) і - і Да і Нет і
АДДДДДДДДБДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДБДДДДДДДДДДДБДДДДДДДДБДДДДДДДДЩ
Фиг. 8.11 Регистры микросхемы 6845
(с разрешения фирмы Motorola)
Если попытаться изменять регистры с помощью утилиты DEBUG, то это
может не сработать. Регистры R14 и R15 управляют позицией курсора,
и если утилита DEBUG переместит курсор между вашими обращениями к
индексному регистру и к регистру данных, изменения не произойдет.
Так получилось потому, что утилита DEBUG изменила содержимое
индексного регистра микросхемы 6845, и он уже больше не указывает
на тот внутренний регистр, который вы хотели изменить.
Другая интересная регистровая пара микросхемы 6845 - пара
регистров начального адреса R12 и R13. Адаптер цветного
графического дисплея имеет 16K байт памяти, а монохромная плата 4K
байта. Дополнительная память в цветной плате используется для
графических режимов, но она целиком в вашем распоряжении и в
текстовых режимах. Для текстового режима 80*25 требуется 4K байта
памяти, так что в буфере есть место для четырех разных страниц
памяти. Сдвигать данные на экране можно переносом данных с одного
места на другое, как это делалось на Фиг. 8.8. В случае же
вертикального сдвига нужно лишь изменить начальный адрес в
микросхеме 6845. Обычно начальный адрес равен 0. Если вы измените
его на 80 (число символов в строке), отображение будет начинаться
со второй строки. Это даст немедленный эффект сдвига всех данных
экрана вверх на одну строку.
На самом деле вы не изменяли данные, а сдвинули начало
сканирования памяти дисплея. Можно рассматривать дисплей как окно
80*25, через которое мы смотрим в 8192-символьный буфер дисплея.
При использовании начального адреса для сдвига данных возникают
сложности, когда вы приближаетесь к границе 16K байт. В этой точке
отображение "заворачивается". Верхние строки извлекаются из конца
буфера, а нижние строки - из его начала. Вы, конечно, сможете
решить эту проблему, но для этого потребуются некоторые размышления
и эксперименты.
[Прим. перев.: стр. 252 текста оригинала в моей копии отсутствует.
Очевидно, на ней находится только начало Фиг. 8.12]
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:31
Фиг. 8.12 Программа управления цветным дисплеем Page 1-1
PAGE ,132
TITLE Фиг. 8.12 Программа управления цветным дисплеем
0000 STACK SEGMENT STACK
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
0000 DISPLAY_BUFFER SEGMENT AT 0B800H
0000 DISPLAY_START LABEL WORD
0000 DISPLAY_BUFFER ENDS
= 03D4 CRT_INDEX EQU 03D4H
= 03D5 CRT_DATA EQU 03D5H
= 03DA CRT_STATUS EQU 03DAH
= 000A CURSOR_START EQU 10 ; Регистры управления курсором
= 000B CURSOR_END EQU 11 ; в контроллере дисплея 6845
0000 CODE SEGMENT
ASSUME CS:CODE
0000 COLOR_GRAPHICS PROC FAR
0000 1E PUSH DS ; Адрес возврата в ДОС
0001 2B C0 SUB AX, AX
0003 50 PUSH AX
Фиг. 8.12 Программа управления цветным дисплеем (начало)
;----- Фиг. 8.12 (а) Изменение курсора
0004 BA 03D4 MOV DX, CRT_INDEX
0007 B0 0A MOV AL, CURSOR_START ; Установка индексного регистра
0009 EE OUT DX, AL ; 6845 на регистр начала курсора
000A 42 INC DX
000B B0 00 MOV AL, 0
000D EE OUT DX, AL ; Установка начала курсора
000E 4A DEC DX
000F B0 0B MOV AL, CURSOR_END
0011 EE OUT DX, AL ; Выбор регистра конца курсора
0012 42 INC DX
0013 B0 04 MOV AL, 4
0015 EE OUT DX, AL ; Установка конца курсора
;----- Фиг. 8.12 (б) Использование регистра состояния 6845
0016 B8 0002 MOV AX, 2
0019 CD 10 INT 10H ; Выбор символьного режима 80*25
001B B8 ---- R MOV AX, DISPLAY_BUFFER
001E 8E C0 MOV ES, AX ; Адрес буфера дисплейной памяти
0020 B8 0720 MOV AX, 0720H ; Вывод начинается с пробела
0023 NEXT_CHAR:
0023 BF 0000 MOV DI, 0
0026 B9 0050 MOV CX, 80
0029 F3/ AB REP STOSW ; Вывод строки из 80 символов
002B FE C0 INC AL ; Следующий символ
002D 75 F4 JNZ NEXT_CHAR
002F BB 0720 MOV BX, 0720H
0032 NEXT_CHAR_1:
0032 B9 0050 MOV CX, 80
0035 BF 0000 MOV DI, 0
0038 BA 03DA MOV DX, CRT_STATUS ; Порт состояния для адаптера
; цветного дисплея
003B WAIT_NO_RETRACE:
003B EC IN AL, DX ; Проверка на обратный ход луча
003C A8 01 TEST AL, 1
003E 75 FB JNZ WAIT_NO_RETRACE ; Запрещение прерываний
0040 FA CLI
0041 WAIT_RETRACE:
0041 EC IN AL, DX
0042 A8 01 TEST AL, 1
0044 74 FB JZ WAIT_RETRACE ; Ожидание обратного хода луча
0046 8B C3 MOV AX, BX ; Выборка символа
0048 AB STOSW ; Занесение в дисплейный буфер
0049 FB STI ; Разрешение прерываний
004A E2 EF LOOP WAIT_NO_RETRACE
004C FE C3 INC BL
004E 75 E2 JNZ NEXT_CHAR_1
;----- Фиг. 8.12 (в) Вывод линии по диагонали
Фиг. 8.12 Программа управления цветным дисплеем (продолжение)
0050 B8 0004 MOV AX, 4
0053 CD 10 INT 10H ; Установка графического
; режима 320*200
0055 06 PUSH ES
0056 1F POP DS
0057 B3 32 MOV BL, 50 ; Число групп строк
0059 B1 02 MOV CL, 2 ; Счетчик сдвига
005B BF 0000 MOV DI, 0
005E DOT_LOOP:
005E B0 C0 MOV AL, 0C0H ; В AL маска первой точки в байте
0060 88 05 MOV [DI], AL
0062 81 C7 2000 ADD DI, 2000H ; Переключение на нечетную строку
0066 D2 E8 SHR AL, CL ; Сдвиг до следующей точки в байте
0068 88 05 MOV [DI], AL
006A 81 EF 1FB0 SUB DI, 2000H-80 ; Переключение на четную строку
006E D2 E8 SHR AL, CL
0070 88 05 MOV [DI], AL
0072 81 C7 2000 ADD DI, 2000H ; Переключение на нечетную строку
0076 D2 E8 SHR AL, CL
0078 88 05 MOV [DI], AL
007A 81 EF 1FAF SUB DI, 2000H-81 ; Переключение на четную строку,
007E FE CB DEC BL ; следующий байт
0080 75 DC JNZ DOT_LOOP
;----- Возврат к символьному режиму 80*25
0082 B8 0002 MOV AX, 2
0085 CD 10 INT 10H
0087 CB RET
0088 COLOR_GRAPHICS ENDP
0088 CODE ENDS
END
Фиг. 8.12 Программа управления цветным дисплеем (продолжение)
Цветной графический адаптер имеет еще три регистра ввода-
вывода. Регистр режима находится по адресу ввода-вывода 03D8H. Этот
регистр устанавливает аппаратные переключатели различных режимов
отображения. Например, вы можете установить бит 5 этого регистра в
"0" и получить 16 цветов фона в текстовых режимах, а установка бита
5 в "1" переключает 7-й бит атрибута на функцию мигания. Полное
описание структуры этого регистра, и всех других, дано в
техническом описании.
Регистр выбора цвета находится по адресу ввода-вывода 03D8H.
Этот регистр устанавливает цвет окаймления в текстовых режимах.
Поскольку сам по себе текст не занимает весь экран, текст можно
окружить каким-либо выбираемым цветом. Кроме того, регистр выбора
цвета может управлять выбором палитр в графических режимов, как мы
увидим в следующем разделе. Младшие 4 бита этого регистра
устанавливают для окаймления один из 16 цветов, перечисленных на
Фиг. 8.10.
И наконец, регистр состояния по адресу ввода-вывода 3DAH
организует информационную обратную связь между цветной платой и
программой. Например, программа может использовать этот регистр для
определения текущего состояния светового пера, если оно подключено
к системе. Более важным является то, что регистр состояния
сообщает, когда безопасно читать или записывать данные в дисплейный
буфер.
Не вдаваясь в технические детали, заметим, что чтение или
запись данных в буфер дисплея цветной платы может вызвать "снег" на
экране, если вы будете это делать в неподходящие моменты времени.
Это случается только в текстовом режиме с высоким разрешением
80*25. Вспомните, что ранее приводился пример на Фиг. 8.12, в
котором постоянно записывались данные в буфер дисплея. Если для
этого примера использовать цветную плату, на экране появится масса
помех. Чтобы избежать этого, можно использовать регистр
состояния.
Существуют моменты, когда можно безопасно работать с данными в
буфере дисплея. В такие моменты бит 0 регистра состояния равен 1.
Нужно подождать, когда бит 0 станет равным 1, а затем читать или
записывать данные. На Фиг. 8.12б изображена программа, которая
записывает символ на экран дисплея. Первые строки этой программы
записывают данные в буфер, не используя регистр состояния. Эта
часть программы 224 раза записывает 80 симвлов в первую строку
буфера, что эквивалентно заполнению экрана около девяти раз. Когда
вы запустите программу, то увидите короткую вспышку помех в тот
момент, когда будут записываться данные.
Вторая часть программы на Фиг. 8.12б повторяет те же действия,
но на этот раз проверяя бит состояния. Обратите внимание, что эта
часть программы проверяет бит состояния двумя различными способами.
Сначала она ждет, пока бит состояния не станет равным 0. Затем, как
только он станет равен 1, программа записывает данные. Так сделано
потому, что интервал, в течение которого можно записывать данные,
очень мал, и если бы программа делала проверку только на равенство
1, она могла бы захватить бит состояния непосредственно перед его
обращением в 0. В этом случае, чтобы избежать помех, микропроцессор
уже не может записывать данные достаточно быстро, но такая
организация цикла гарантирует, что бит состояния захватывается в
первый же момент, когда он становится равным 1.
Используя бит состояния, вы уже не увидите на экране никаких
помех, но и заметите, что выполнение программы стало гораздо
медленнее. Выполняться медленнее программу заставляет
дополнительное время, затрачиваемое на ожидание бита состояния.
Если вам нужно записать на экране много данных - например,
организовать горизонтальный сдвиг, как на Фиг. 8.8, то потребуется
другой способ. Простейший способ - сбросить в нуль разряд
отображения в регистре режима. Бит 3 регистра режима (3D8H)
управляет отображением на дисплее. Если сбросить этот бит в 0,
экран погаснет. Чтобы переслать много данных в буфер цветного
дисплея, вы можете выключить отображение и переслать данные без
проверки бита состояния. Поскольку отображение выключено, на экране
не возникнут помехи. Когда пересылка блока закончится, включите
отображение. Вы заметите короткое мигание изображения в момент его
выключения и включения. Фирма IBM использует этот метод для
обслуживания вертикального сдвига цветного дисплея.
Графический режим
Цветной графический адаптер имеет два режима отображения, в которых
можно управлять отдельными точками экрана. Эти режимы называются
режимами Полной Адресации точек (APA: All Points Addressable),
поскольку с помощью этих режимов можно адресовать и изменять все
точки. В действительности цветная плата допускает более двух
режимов APA, но мы рассмотрим только те два, которые поддерживаются
системой программирования. Используя информацию из технического
описания, вы можете попробовать и другие режимы.
Графический режим среднего разрешения обеспечивает вывод
изображения из 320 точек и 200 строк растра. Каждая из этих точек
может иметь один из четырех цветов. Это означает, что для каждой
точки требуется для представления цвета 2 бита. В каждом байте
графической памяти помещается четыре точки или пиксела (от англ.
picture element - графический элемент, которые называют также
"пелами"). Если вы умножите горизонтальный размер на вертикальный,
а затем разделите на 4 - число точек в байте, то увидите, что в
режиме среднего разрешения требуется 16000 байт. Именно поэтому
цветная плата имеет память объемом 16K.
На Фиг. 8.13 показано расположение элементов в каждом байте.
Пара бит с номерами 6 и 7 отображается первой точкой (0), а биты 0
и 1 представляют последнюю точку (3), отображаемую из этого байта.
В первых 80 байтах графической памяти содержится 320 точек
строки растра 0, т.е. первой строки экрана.
7 6 5 4 3 2 1 0
ЪДДДДДДДДДВДДДДДДДДДВДДДДДДДДДВДДДДДДДДДї
і і і і і
і точка 0 і точка 1 і точка 2 і точка 3 і
і і і і і і і і і
АДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДЩ
Фиг. 8.13 Битовая структура для графики 320*200
Но байт 80 уже не содержит первые четыре точки строки 1. По
причинам, которые объясняются конструкцией аппаратуры, четные и
нечетные строки хранятся в разных концах графической памяти. Все
нечетные строки имеют смещение 2000H байт от соответствующих четных
строк. Поэтому строка 1 лежит в байтах от 2000H до 204FH. Строка 2
- четная и находится по адресам от байта 50H до 9FH; строка 3
находится по адресам от 2050H до 209FH, и так далее.
На Фиг. 8.12в изображена программа, которая иллюстрирует
структуру графической памяти. Эта программа рисует диагональную
линию на дисплее 320*200. Линия начинается в точке (0, 0), верхнем
левом углу, и идет до точки (199, 199), в самый низ и слегка правее
центра. Первая часть программы вводит дисплей в режим APA среднего
разрешения с помощью вызова программы BIOS. В следующей главе
рассматривается, как это делается.
В программе регистр DI используется в качестве указателя
нужного байта в буфере дисплея. В целом программа выводит 200
точек. В регистр BL загружается число 50, так как внутренний цикл
пишет по четыре точки за одну итерацию. В регистр CL заносится 2 -
значение счетчика переключений. Цикл заносит в регистр AL код 0C0H,
что устанавливает старшие два бита на цвет 3; остальные три точки
байта имеют цвет 0, т.е. цвет фона. После записи этого байта
регистр AL сдвигается вправо на 2 бита, и теперь активизируется
вторая точка байта. Прибавление значения 2000H к содержимому
регистра DI смещает указатель на нечетную строку. Третья точка
снова получается сдвигом регистра AL и вычитанием числа (2000H -
80) из содержимого регистра DI. Это возвращает регистр DI назад в
четную строку, но уже на следующие 80 байт. Наконец, после записи
четвертого байта, регистр DI снова возвращается в четное поле, но
еще и увеличивается, смещаясь тем самым на следующий байт строки
растра. В примере цикл работает с четырьмя байтами, так как на
каждый байт приходится четыре элемента.
Цвета в режиме APA 320*200
А теперь рассмотрим цвета, которые можно получить в графическом
режиме среднего разрешения. Так как точке отведено два бита, для
нее можно указать один из четырех цветов. Цвет 0 (00B) - это цвет
фона. В качестве этого цвета можно выбрать любой из 16 цветов,
показанных на Фиг. 8.10, записав соответствующее 4-битовое значение
в регистр выбора цвета (3D9H). Остальные три цвета определены
фирмой IBM: вы не можете выбирать произвольно цвета 1, 2 и 3. Фирма
IBM определила две различные палитры цветов, они показаны на Фиг.
8.14. Палитру можно выбрать, устанавливая бит 5 регистра выбора
цвета.
Как показано на Фиг. 8.14, если сбросить бит 5 в 0, получатся
цвета зеленый, красный и желтый вместе с выбранным цветом фона.
Установка бита 5 равным 1 дает голубой, пурпурный и белый. Вы также
можете модифицировать палитру и другим битом регистра выбора цвета.
Установка бита 4 равным 1 делает цвета палитры более яркими.
Программы инициализации BIOS обычно загружают в регистр выбора
цвета значение 30H. Это соостветствует черному цвету фона (0) и и
яркой палитре 1.
Значение цвета Палитра 0 цвета Палитра 1 цвета
--------------------------------------------------
1 (01B) Зеленый Голубой
2 (10B) Красный Фиолетовый
3 (11B) Желтый Белый
бит 5 = 0 бит 5 = 1
--------------------------------------------------
Фиг. 8.14 Цветные палитры
для графики 320*200
Графика высокого разрешения
Другой режим APA дает 640 точек в строке растра и 200 строк. В этом
режиме каждая точка соответствует одному биту. Если этот бит
содержит 0, точка черная. Если этот бит содержит 1, точка цветная;
цвет выбирается с помощью регистра выбора цвета. Обычно этот
регистр содержит значение 1111B (белый), давая черно-белую
картинку. Вы можете выбрать любой другой цвет.
Отображение элементов почти идентично графическому режиму
нормального разрешения. Отличие заключается в том, что в байте
содержится восемь точек. Старший значащий бит (бит 7) выводится
первым, а бит 0 - последним. Здесь также строка содержит 80 байт;
так же, как и при нормальном разрешении, четные строки находятся в
начеле буфера дисплея, а нечетные - по адресу 2000H.
Адаптер параллельного принтера
Чтобы подключить печатающее устройство фирмы IBM или любое другое,
которое подключается через параллельный интерфейса, вам нужен
адаптер параллельного печатающего устройства (принтера). Этот
адаптер встроен в адаптер монохромного дисплея и принтера. Если вы
используете адаптер цветного графического монитора, то нужен
отдельный адаптер принтера. С точки зрения интерфейса с печатающим
устройством, эти два адаптера идентичны, за исключением адресов
ввода-вывода. Порты принтера на монохромной плате имеют адреса от
3BCH до 3BEH, а отдельная плата принтера имеет адреса от 378H до
37AH.
Адаптер принтера имеет два выводных порта и один порт ввода.
Этот адаптер очень похож на микросхему 8255, используемую для
интерфейса клавиатуры. Фактически, сначала в конструкции платы
печатающего устройства использовалась микросхема 8255. Но фирма IBM
решила лучше делать адаптеры с раздельными компонентами.
Выводной 8-битовый порт данных по адресу 3BCH или 378H передает
данные принтеру. Адаптер посылает символьный код ASCII, помещаемый
в этот порт, прямо в принтер. Второй порт вывода, расположенный
по адресам 3BEH или 37AH, имеет 5 выводных бит. В нем содержатся
управляющие сигналы для принтера; эти линии управляют его работой и
инициализацией. В частности, бит 0 инициирует передачу данных в
принтер. Простая запись данных в порт вывода данных не означает
пересылку символа на принтер. Для того, чтобы в него поступил
символ, нужно установить бит строба (бит 0 порта 3BEH или 37AH)
равным 1, а затем снова сбросить на 0. На Фиг. 8.15 показана
короткая программа, передающая печатающему устройству строку
символов. Подпрограмма с именем PRINT обеспечивает сам процесс
передачи данных в принтер.
Обратите внимание, что процедура PRINT читает код из вводного
порта (3BCH или 379H). Этот порт возвращает информацию состояния
печатающего устройства программе. В данном примере программа
проверяет состояние, чтобы выводить следующий символ именно тогда,
когда принтер готов его принять. Бит 7 состояния порта ввода
показывает занятость принтера. Если этот бит содержит 1, печатающее
устройство готово принимать следующий символ для печати. В
противном случае программа должна подождать. Остальные 4 вводных
бита этого порта отражают возможные ошибки на печатающем
устройстве, например, отсутствие бумаги. Наш пример не контролирует
эти ситуации. Техническое описание содержит структуры вводных и
выводных портов платы адаптера печатающего устройства.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:39
Фиг. 8.15 Вывод на принтер Page 1-1
PAGE ,132
TITLE Фиг. 8.15 Вывод на принтер
0000 STACK SEGMENT STACK
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
= 0378 BASE EQU 378H
0000 CODE SEGMENT
ASSUME CS:CODE
0000 94 A8 A3 2E 20 38 2E MSG DB 'Фиг. 8.15', 13, 10, '$'
31 35 0D 0A 24
000C MAIN PROC FAR
000C 1E PUSH DS ; Адрес возврата
000D 2B C0 SUB AX, AX
000F 50 PUSH AX
0010 8D 1E 0000 R LEA BX, MSG
0014 PRINT_LOOP:
0014 2E: 8A 07 MOV AL, CS:[BX] ; Выбор символа из строки для вывода
0017 3C 24 CMP AL, '$' ; Конец строки?
0019 74 06 JE MAIN_RETURN
001B E8 0022 R CALL PRINT ; Печать символа
001E 43 INC BX
001F EB F3 JMP PRINT_LOOP ; Переход к следующему символу
0021 MAIN_RETURN:
0021 CB RET
0022 MAIN ENDP
;----- Эта подпрограмма печатает символ в регистр AL
0022 PRINT PROC NEAR
0022 BA 0378 MOV DX, BASE ; Порт вывода данных на принтер
0025 EE OUT DX, AL ; Занесение символа в порт вывода на принтер
0026 42 INC DX ; Адрес порта состояния принтера
0027 WAIT_BUSY:
0027 EC IN AL, DX ; Опрос состояния принтера
0028 A8 80 TEST AL, 80H ; Проверка разряда занятости принтера
002A 74 FB JZ WAIT_BUSY ; Цикл до освобождения принтера
002C 42 INC DX
002D B0 0D MOV AL, 0DH ; Установка разряда готовности данных
002F EE OUT DX, AL
0030 B0 0C MOV AL, 0CH ; Сброс разряда готовности данных
0032 EE OUT DX, AL
0033 C3 RET
0034 PRINT ENDP
0034 CODE ENDS
END MAIN
Фиг. 8.15 Вывод на принтер
Один из управляющих битов порта 3BEH (или 37AH) управляет
линией прерывания от печатающего устройства. Для того, чтобы
печатающее устройство могло посылать свой сигнал прерывания в
контроллер 8259, этот бит нужно установить равным 1. Однако адаптер
печатающего устройства выдает неверный сигнал прерывания, т.е.
выбранный для этой цели сигнал не вызывает правильного прерывания.
Поэтому не стоит и пытаться писать программу, которая бы
использовала возможности прерывания от адаптера печатающего
устройства (если вы не захотите физически изменить плату
печатающего устройства). Далее мы приведем пример, который обходит
эту проблему с помощью системного таймера.
Адаптер синхронных коммуникаций
Адаптер асинхронных коммуникаций дает возможность связываться с
IBM PC по последовательному интерфейсу. Этот адаптер дает
возможность связываться с другими ЭВМ, службами баз данных, а также
с другими источниками информации. Мы не будем обсуждать принципы
работы этого канала, а поговорим о методах программирования этого
конкретного адаптера IBM PC.
Интегральная микросхема коммуникаций проделывает всю работу по
приему и передаче символов по асинхронной линии. Элемент
асинхронной связи ACE (Asynchronous Communication Element) 8250
можно запрограммировать для управления самыми различными аспектами
связи. При инициализации элемента ACE под пограммным контролем
оказываются размер символа, частота передачи, символы останова и
биты четности. Адаптер также позволяет проверять и задавать
стандартные сигналы управления модемом (модулятора -
демодулятора).
С помощью элемента ACE символ передается просто посредством его
записи в регистр передачи. Микросхема далее выполняет все, что
соответствует кодам, которые вы передали ей при инициализации.
Чтобы принять символ, вы просто читаете его из буфера приема.
Существует регистр состояния, называемый регистром состояния линии,
который показывает, когда буфер передачи пуст и может принять
другой символ. Другой бит регистра состояния сообщает, когда
элемент ACE уже принял символ из другой системы.
В техническом описании приводятся и другие регистры, входящие в
элемент ACE 8250. Эти регистры дают возможность управления модемом
и определения его состояния. Вы также можете разрешить выработку
прерывания при возникновении в элементе ACE различных условий. Это
позволяет вашей программе быстро реагировать на любую смену внешних
условий. east-font-family:"MS Mincho"'>
Программа на Фиг. 8.16 демонстрирует основные механизмы,
необходимые для инициирования элемента ACE, посылки и приема
символа. Базовый адрес ввода-вывода платы адаптера равен 3F8H, так
что регистры элемента ACE расположены по адресам от 3F8H до 3FEH.
Можно также модифицировать адаптер асинхронной связи фирмы IBM так,
чтобы его регистры соответствовали адресам ввода-вывода от 2F8H до
2FEH. С помощью такой модификации можно установить в персональную
ЭВМ второй адаптер и связаться с двумя различными внешними
устройствами. Фактически, можно подключить печатающее устройство к
системе с помощью последовательного, а не параллельного сопряжения.
В этом случае нужны два адаптера: один из них работает с печатающим
устройством, а другой обслуживает внешние связи.
Один из портов ввода-вывода элемента ACE выполняет несколько
функций. Оба буфера, передачи и приема, находятся по адресу 3F8H,
так что когда что-либо записывается по этому адресу, информация
попадает в буфер передачи, но при чтении по этому адресу, вы
получаете последний символ, принятый микросхемой ACE. Этот же порт
ввода-вывода выполняет и третью функцию. Значение делителя,
определяющее скорость работы адаптера, записывается в этот порт
ввода-вывода. Микросхема ACE делит входную частоту на число,
помещенное в регистр делителя, позволяя тем самым выбрать скорость
от 50 до 9600 бод. Режим использования порта 3F8H задает один из
битов управляющего регистра.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:45
Фиг. 8.16 Управление последовательным каналом Page 1-1
PAGE ,132
TITLE Фиг. 8.16 Управление последовательным каналом
0000 STACK SEGMENT STACK
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
= 03F8 SERIAL EQU 03F8H
0000 CODE SEGMENT
ASSUME CS:CODE
0000 ASYNC PROC FAR
0000 1E PUSH DS ; Адрес возврата в ДОС
0001 2B C0 SUB AX,AX
0003 50 PUSH AX
0004 BA 03FB MOV DX,SERIAL+3 ; Управляющий регистр
0007 B0 80 MOV AL,80H
0009 EE OUT DX,AL ; Настройка на установку скорости
000A B8 0180 MOV AX,384 ; Делитель частоты для скорости 300 бод
000D BA 03F8 MOV DX,SERIAL
0010 EE OUT DX,AL ; Младшая часть делителя
0011 8A C4 MOV AL,AH
Фиг. 8.16 Управление последовательным каналом (начало)
0013 42 INC DX
0014 EE OUT DX,AL ; Старшая часть делителя
0015 BA 03FB MOV DX,SERIAL+3 ; Управляющий регистр
0018 B0 03 MOV AL,00000011b ; Режим без проверки на четность,8 бит
001A EE OUT DX,AL
;----- Вывод символа в канал
001B BA 03FD MOV DX,SERIAL+5 ; Регистр состояния канала
001E SEND:
001E EC IN AL,DX
001F A8 20 TEST AL,20H
0021 74 FB JZ SEND
0023 B0 41 MOV AL,'A'
0025 BA 03F8 MOV DX,SERIAL
0028 EE OUT DX,AL
;----- Прием символа
0029 BA 03FD MOV DX,SERIAL+5 ; Регистр состояния канала
002C RECV:
002C EC IN AL,DX
002D A8 02 TEST AL,2
002F 74 FB JZ RECV
0031 BA 03F8 MOV DX,SERIAL
0034 EC IN AL,DX
0035 CB RET
0036 ASYNC ENDP
0036 CODE ENDS
END ASYNC
Фиг.8.16 Установка, пересылка и получение данных по
асинхронному каналу (продолжение)
Первая часть программы примера инициализирует микросхему ACE
8250. Первым делом программа настраивает скорость работы адаптера.
Значение делителя, равное 384, устанавливает скорость 300 бод.
Обратите внимание, что перед записью значения делителя программа
заносит 1 в бит 7 управляющего регистра по адресу 3FBH.
Окончательный вывод в порт 3FBH задает характеристики линии. В этом
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:50
Фиг. 8.17 Обработка прерываний от последовательного канала Page 1-1
PAGE ,132
TITLE Фиг. 8.17 Обработка прерываний от последовательного канала
0000 ABS0 SEGMENT AT 0
002C ORG 0BH*4
002C ASYNC_INTERRUPT LABEL WORD
002C ABS0 ENDS
0000 STACK SEGMENT STACK
Фиг. 8.17 Обработка прерываний от последовательного канала (начало)
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
0000 CODE SEGMENT
ASSUME CS:CODE
0000 0049 R BUFFER_POINTER DW BUFFER
0002 SET_INTERRUPT PROC FAR
0002 2B C0 SUB AX,AX
0004 8E D8 MOV DS,AX
ASSUME DS:ABS0 ; Адресация по сегментному регистру DS
; в область векторов прерываний
;----- Установка прерывания
0006 C7 06 002C R 0024 R MOV ASYNC_INTERRUPT,offset INT_HANDLER
000C 8C 0E 002C R MOV ASYNC_INTERRUPT,CS ; Занесение вектора прерывания
0010 BA 03F9 MOV DX,03F9H ; Регистр разрешения прерываний
0013 B0 04 MOV AL,04H ; Прерывание по приему из канала
0015 EE OUT DX,AL
0016 E4 21 IN AL,21H ; Регистр маски прерываний 8259
0018 24 F7 AND AL,0F7H ; Занесение 0 в разряд 3
001A E6 21 OUT 21H,AL ; Прерывание не маскируется
001C BA 03FC MOV DX,3FCH ; Регистр управления модемом
001F B0 08 MOV AL,08H ; разряд OUT2
0021 EE OUT DX,AL
0022 EB FE HERE: JMP HERE ; Конец задания режима работы последователь-
0024 SET_INTERRUPT ENDP ; ного канала,ожидание прерывания
;----- Программа обработки прерываний от последовательного канала по приему
0024 INT_HANDLER PROC FAR
0024 50 PUSH AX ; Сохрание используемых регистров
0025 53 PUSH BX
0026 52 PUSH DX
0027 BA 03FD MOV DX,3FDH ; Регистр состояния канала
002A EC IN AL,DX
002B A8 01 TEST AL,01H ; Был ли получен символ?
002D 74 12 JZ INT_RETURN ; Нет,возврат из прерывания
002F BA 03F8 MOV DX,3F8H ; Регистр приема данных
0032 EC IN AL,DX ; Выбор символа из канала
0033 2E: 8B 1E 0000 R MOV BX,BUFFER_POINTER
0038 2E: 88 07 MOV CS:[BX],AL ; Сохранение в буфере
003B 43 INC BX
003C 2E: 89 1E 0000 R MOV BUFFER_POINTER,BX
0041 INT_RETURN:
0041 5A POP DX ; Восстановление регистров
0042 5B POP BX
0043 B0 20 MOV AL,20H ; Сброс контроллера прерываний
Фиг. 8.17 Обработка прерываний от последовательного канала (продолжение)
0045 E6 20 OUT 20H,AL
0047 58 POP AX
0048 CF IRET ; Возврат из прерывания
0049 INT_HANDLER ENDP
0049 0080[ BUFFER DB 128 DUP (?)
??
]
00C9 CODE ENDS
END SET_INTERRUPT
Фиг. 8.17 Асинхронные прерывания (окончание)
Оставшиеся две части примера посылают и принимают символ. В
регистре состояния линии по адресу ввода-вывода 3FDH есть биты
состояния буферов передачи и приема. Посылать символ до тех пор,
пока буфер передачи не опустеет, нельзя; и естественно, нельзя
читать символ до того, как он принят.
Адаптер асинхронной связи также работает с прерываниями. Сигнал
OUT2 в регистре управления модемом передает сигнал прерывания от
микросхемы ACE системе. Регистр разрешения прерываний в микросхеме
ACE выбирает те возможные изменения состояний, которые приведут к
возбуждению внешнего прерывания. Адаптер асинхронной связи
возбуждает прерывание уровня 3 контроллера прерываний 8259.
Давайте посмотрим, как можно использовать прерывание от
асинхронной платы для того, чтобы принимать символы. На Фиг. 8.17
показана последовательность событий, необходимых для включения
системы прерываний. В случае аппаратного прерывания, программа
устанавливает вектор прерывания, соответствующий уровню 3
контроллера 8259 (прерывание 0BH по адресу 58H), на адрес процедуры
обслуживания прерывания. Затем она сбрасывает бит регистра маски,
соответствующий прерыванию от платы связи. В микросхеме ACE 8250
программа загружает регистр разрешения прерывания так, чтобы
разрешить прерывания по состоянию приемной линии. И наконец,
программа включает линию OUT2, чтобы в систему поступали
прерывания. Когда все это работает, не возникает никаких проблем о
бработке символов по мере их получения системой. Программа на Фиг.
8.17 помещает эти символы в буфер, где их может не торопясь
просматривать другая программа.
Адаптер управления играми
Адаптер управления играми подключает к системе джойстики и другие
органы управления игрой. Это все аналоговые устройства - т.е., они
не могут работать с нулями и единицами. Их входные значения - это
сопротивление, которое ЭВМ не может прочитать непосредственно.
Адаптер управления играми преобразует значение сопротивления в
нечто такое, с чем ЭВМ может иметь дело.
Адаптер управления играми не преобразует значение сопротивления
непосредственно в двоичное число. Вместо этого адаптер преобразует
значение сопротивления во временную задержку. Чем больше
сопротивление, тем больше временная задержка. Эту задержку
компьютер может измерить. Преобразовать задержку в число,
соответствующее положению джойстика, можно программным способом.
Нашей задачей является написание программы, которая преобразует
временную задержку в число.
Адаптер управления играми обслуживает до четырех входов
сопротивления. Механизм временной задержки по каждому из этих
входов подключен к отдельному биту порта ввода-вывода 201H. Когда
вы выводите любое число в порт 201H, четыре его младших бита
сбрасываются в 0. Биты возвращаются в состояние 1 после некоторго
интервала времени. Этот интервал времени определяется значением
сопротивления, подключенного к адаптеру. Программа на Фиг. 8.18 -
это пример определения значения сопротивления двух из четырех
входных портов. Эта программа использует простой метод. Вместо
определения временной задержки всех четырех портов одновременно,
она обслуживает их последовательно. Количество времени, нужного для
определения одной задержки, невелико. В результате, поочередная
обработка этих задержек вместо одновременной выполняется без
проблем.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:05:57
Фиг. 8.18 Адаптер управления играми Page 1-1
PAGE ,132
TITLE Фиг. 8.18 Адаптер управления играми
= 0201 GAME_PORT EQU 201H
0000 STACK SEGMENT STACK
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
0000 CODE SEGMENT
ASSUME CS:CODE
0000 GAME_CONTROL PROC FAR
0000 1E PUSH DS ; Адрес возврата
0001 2B C0 SUB AX, AX
0003 50 PUSH AX
0004 BA 0201 MOV DX, GAME_PORT
0007 B8 B000 MOV AX, 0B000H ; Сегмент дисплейной памяти
000A 8E D8 MOV DS, AX
000C B5 21 MOV CH, 21H ; Символ, который будет записываться в буфер
000E B1 00 MOV CL, 0
0010 WRITE_LOOP:
0010 B4 01 MOV AH, 1 ; Выбор координаты X
0012 E8 0042 R CALL POSITION
0015 8B D8 MOV BX, AX ; Сохранение координаты X в буфере
0017 D1 EB SHR BX, 1
0019 D1 EB SHR BX, 1 ; Деление на 4
Фиг. 8.18 Адаптер управления играми (начало)
001B B4 02 MOV AH, 2 ; Выбор координаты Y
001D E8 0042 R CALL POSITION
0020 D0 E8 SHR AL, 1
0022 D0 E8 SHR AL, 1
0024 D0 E8 SHR AL, 1
0026 D0 E8 SHR AL, 1 ; Деление на 16
0028 B4 A0 MOV AH, 160
002A F6 E4 MUL AH ; Преобразование в смещение в буфере
002C 03 D8 ADD BX, AX
002E 88 2F MOV [BX], CH ; Сохранение символа
0030 EC IN AL, DX
0031 24 10 AND AL, 10H
0033 3A C1 CMP AL, CL
0035 74 D9 JE WRITE_LOOP
0037 8A C8 MOV CL, AL
0039 80 F9 10 CMP CL, 10H
003C 75 D2 JNE WRITE_LOOP
003E FE C5 INC CH ; Следующий символ
0040 EB CE JMP WRITE_LOOP
0042 GAME_CONTROL ENDP
;----- В AH бит маски
0042 POSITION PROC NEAR
0042 51 PUSH CX
0043 2B C9 SUB CX, CX ; Начальное значение для цикла ввода
0045 EE OUT DX, AL ; Запуск таймера
0046 POS_LOOP:
0046 EC IN AL, DX
0047 84 C4 TEST AL, AH
0049 E0 FB LOOPNE POS_LOOP ; Цикл пока 1 - таймер не закончил отсчет
004B B8 0000 MOV AX, 0
004E 2B C1 SUB AX, CX ; Определение значения счетчика
0050 59 POP CX ; в диапазоне 0-255
0051 C3 RET
0052 POSITION ENDP
0052 CODE ENDS
END
Фиг. 8.18 Адаптер управления играми (продолжение)
Последняя часть программы на Фиг. 8.18 берет позицию X-Y,
определенную по входу от джойстика, и записывает символ в
соответствующую позицию дисплея. Адаптер управления играми также
допускает четыре переключающих ввода, значения которых можно
прочитать в старших четырех битах порта 201H. Программа в примере
опрашивает один из этих битов переключения, чтобы перейти от одного
символа к другому и вывести его на экран.
Адаптер дисковода
Адаптер дисковода является интерфейсом между микропроцессором и
накопителем на гибких магнитных дисках. Схемы, смонтированные на
плате этого адаптера, обеспечивают все функции, необходимые для
ввода и вывода данных на гибкий диск (дискету). Адаптер
обеспечивает также физическое кодирование и декодирование данных,
необходимое для использования дискет.
Центральной частью адаптера дисковода фирмы IBM является
микросхема контроллера гибкого диска FDC (Floppy Disk Controller)
мPD765 фирмы NEC. Эта компонента также производится фирмой Intel
как микросхема 8272. Микросхема FDC управляет потоком данных на
дискету и с нее. Микросхема FDC имеет два порта ввода-вывода, один
для данных, а другой для отражения состояния. Порт данных находится
по адресу 3F4H, а порт состояния по адресу 3F5H. Порт данных -
двунаправленный, т.е. в различные моменты времени можно и читать
данные из этого порта, и записывать их в порт. Регистр состояния
можно только читать в любой момент времени. Он сообщает, как в
данный момент нужно работать с регистром данных.
В регистре состояния есть 2 бита, которые используются во время
работы с дисководом. Бит 6 - это признак ввода-вывода данных (DIO -
Data Input/Output). Этот бит сообщает, каких действий в отношении
регистра данных ожидает от вас контроллер. Если признак DIO равен
1, микросхема FDC ждет от вас чтения регистра данных. Если DIO
равен 0, FDC ждет записи в регистр данных. Бит 7 порта состояния -
это бит запроса устройства (RQM - Request For Master). Он
аналогичен биту "занято" печатающего устройства. Когда бит RQM
содержит 1, микросхема FDC готова к тому, чтобы читался или
записывался регистр данных. Если вы не уделите внимание биту RQM,
то введете микросхему FDC в заблуждение, и после этого ничего не
будет работать.
Регистр данных в действительности не является единственным.
Подобно контроллеру 6845, порт данных фактически состоит из группы
регистров. Но в отличие от микросхемы 6845, регистра индекса
регистров данных здесь нет. Данные, которые вы посылаете в
контроллер, должны поступать в определенном порядке. Аналогично, в
определенном порядке данные поступают из порта, когда вы их
читаете.
В техническом описании содержится диаграмма, показывающая
входные и выходные комбинации для всех операций дисковода.
Рассмотрим простейшую команду микросхемы FDC, опрос состояния
механизма. Вы выполняете эту операцию тогда, когда хотите что-либо
узнать о текущем состоянии дисковода. На Фиг. 8.19 показаны данные
для команды опроса состояния, а на Фиг. 8.20 показана программа,
выполняющая операцию опроса состояния дисковода.
----------------------------------
Команда...................04H
Модификатор команды.......00H
статус возврата...........ST3 Фиг. 8.19 Команда опроса
---------------------------------- состояния
A
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:06:03
Фиг. 8.20 Проверка состояния дисковода Page 1-1
PAGE ,132
TITLE Фиг. 8.20 Проверка состояния дисковода
0000 STACK SEGMENT STACK
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
FDC_STATUS RECORD RQM:1, DIO:1, OTHER:6
0000 CODE SEGMENT
ASSUME CS:CODE
0000 SENSE PROC FAR
0000 1E PUSH DS ; Адрес возврата
0001 2B C0 SUB AX, AX
0003 50 PUSH AX
0004 BA 03F4 MOV DX, 3F4H ; Порт состояния контроллера дисков
0007 B4 04 MOV AH, 04H ; Команда состояния устройства
0009 E8 001E R CALL OUTPUT ; Передача в контроллер
000C B4 00 MOV AH, 0 ; Второй байт команды
000E E8 001E R CALL OUTPUT
;----- Чтение состояния из контроллера дисков
0011 IN_DIO:
0011 EC IN AL, DX ; Ждать, пока флаг DIO разрешит ввод
0012 A8 80 TEST AL, MASK RQM ; из контроллера
0014 74 FB JZ IN_DIO
0016 IN_RQM:
0016 EC IN AL, DX ; Ждать, пока флаг RQM покажет, что
0017 A8 80 TEST AL, MASK RQM ; контроллер готов
0019 74 FB JZ IN_RQM
001B 42 INC DX ; Установка на порт данных
001C EC IN AL, DX ; Чтение состояния контроллера
001D CB RET ; Конец примера
001E SENSE ENDP
;----- Подпрограмма посылки байта в контроллер
001E OUTPUT PROC NEAR
001E EC IN AL, DX ; Ожидание пока DIO разрешит чтение
001F A8 40 TEST AL, MASK DIO ; из контроллера из контроллера
0021 75 FB JNZ OUTPUT
0023 OUT_RQM:
0023 EC IN AL, DX ; Ожидание пока RQM покажет, что
0024 A8 80 TEST AL, MASK RQM ; контроллер готов
0026 74 FB JZ OUT_RQM
0028 42 INC DX ; Установка на порт данных
0029 8A C4 MOV AL, AH ; Посылаемые данные
002B EE OUT DX, AL ; Вывод в порт
002C 4A DEC DX ; Установка на порт состояния
002D C3 RET
002E OUTPUT ENDP
002E CODE ENDS
END SENSEA
Фиг. 8.20 Проверка состояния дисковода
Каждое действие, выполняемое контроллером дисковода, состоит из
трех фаз: команды, выполнения и результата. В фазе команды
микросхема FDC ожидает данные, и это отражает бит DIO. Когда
микросхема FDC устанавливает бит RQM, чтобы он указывал на
готовность принять данные, программа может посылать команду в
контроллер. В случае опроса состояния дисковода, она выводит в
микросхему FDC два байта команды. Первый байт, 04H, является кодом
операции этой команды. Второй байт сообщает, какой из механизмов
опросить. В течение командной фазы признак DIO всегда показывает,
что микросхема FDC ждет данные, и программа использует бит RQM для
определения момента, когда можно посылать очередной байт данных.
Теперь контроллер переходит в фазу выполнения. В течение этой
фазы контроллер выполняет команду. В данном случае он опрашивает
состояние дисковода. В течение этого времени бит RQM сообщает
программе, чтобы она не использовала порт данных. После завершения
операции признак DIO переключается на 1, сообщая программе, что она
может читать регистр данных. По разрешению RQM программа может
прочитать единственный байт состояния от этой операции. Как только
программа прочитает всю информацию состояния признак DIO снова
принимает значение 0, ожидая ввода следующей команды.
Как видно из таблицы в техническом описании, команда опроса
состояния дисковода - одна из самых простых. Команде чтения данных
требуется девять байт данных во время командной фазы. Когда
операция завершится, программа должна прочитать семь байт состояния
из контроллера. Выполнение не начинается до тех пор, пока не
присылается шестой командный байт, и вы не можете начать другую
операцию, пока не будут прочитаны все семь байт состояния.
По адресу ввода-вывода 3F2H находится цифровой выводной регистр
контроллера дисковода. Этот выводной порт выполняет некоторые
дополнительные операции управления дисководом. Основное назначение
этого порта - управление двигателями дисковода. У механизмов
дисководов 5 1/4 дюйма, используемых в IBM PC, двигатели работают
не непрерывно. Программа должна включить двигатель перед чтением
или записью на дискету - и выключить его после. Если вы оставите
двигатель включенным на все время, это приведет к быстрому износу
дискеты. Когда двигатель работает, на передней панели дисковода
горит красная лампочка.
Адаптер использует цифровой выводной регистр и для других
целей. Два бита выбирают необходимый дисковод. Этот регистр также
используется для сброса микросхемы FDC, так как существуют
ошибочные ситуации, которые вводят контроллер в неопределенное
состояние. В таких случаях единственный выход - сбросить контроллер
и попробовать снова.
Прямой доступ у памяти
Плата адаптера дисковода устроена фирмой IBM так, что она
использует возможность прямого доступа в память системы (ПДП).
Прямой доступ в память позволяет устройству ввода-вывода передавать
данные непосредственно в память или из нее. При этом микропроцессор
не "касается" данных. Принтер, например, требует передачи каждого
печатаемого символа самим микропроцессором. В случае же обмена с
дискетой микропроцессор был бы тяжелой обузой для достаточно
быстрой передачи данных. Программа микропроцессора для передачи
данных дисковода была бы очень похожа на программу Фиг. 8.15, где
символы посылались в принтер. То есть программа должна была бы
читать бит RQM, в цикле, чтобы проверить наличие очередного байта
данных. Тем не менее, если микропроцессор не ответит дисководу
достаточно быстро, то данные будут потеряны.
В случае передачи данных с помощью ПДП микропроцессор должен
только инициировать операцию. Все остальное выполняет контроллер
ПДП 8237 фирмы Intel, расположенный на системной плате. В случае
чтения с дискеты программа инициализирует ПДП для обслуживания
передачи данных. Затем программа посылает команду в контроллер
дисковода, чтобы он выполнил чтение. Во время выполнения программа
не должна передавать данные, так как эту работу выполняет
контроллер ПДП. Когда операция завершается, программа выполняет
фазу обработки результата, как и раньше.
Давайте посмотрим, как нужно настраивать ПДП на операцию чтения
с дискеты. На Фиг. 8.21 показана программа, предназначенная для
этой цели. ПДП имеет четыре канала. Дисковод подключен к каналу 2
ПДП. Каналы 1 и 3 доступны через системный канал ввода-вывода для
других устройств ввода-вывода, а канал 0 используется для очень
важной аппаратной функции - поддерживания регенерации памяти. Если
вы вмешаетесь в работу канала 0 ПДП, содержимое всей памяти
системы, вероятнее всего, изменится.
Каждый канал ПДП имеет два регистра: адресный регистр и регистр
счетчика. Регистр адреса задает область памяти, куда передаются
данные. В нашем случае операции чтения, значение в регистре адреса
указывает начало буфера данных. Когда контроллер дисковода читает
байт с дискеты, контроллер ПДП помещает этот байт в память по
адресу, определяемому регистром адреса. После каждого байта
контроллер ПДП увеличивает адресный регистр так, что он указывает
на следующий байт буфера.
На Фиг. 8.21 BUFFER - имя области данных. Программа определяет
абсолютный адрес буфера BUFFER в системе. Для этого она прибавляет
смещение BUFFER к сдвинутому (умноженному на 16) значению регистра
CS, который содержит значение сегмента буфера. Затем программа
помещает младшие 16 бит адреса в регистр адреса ПДП канала 2.
Старшие 4 бита адреса помещаются в специальный регистр "страницы".
В действительности контроллер ПДП 8237 работает только с
16-битовым адресом. В IBM PC этот регистр страницы добавлен для
того, чтобы программа могла читать данные в любое место памяти.
Имеется три регистра страницы, по одному для каналов 1, 2 и 3.
Регистр страницы имеет размер всего 4 бита, и поэтому старшие биты
регистра AL не играют роли при формировании физического адреса
буфера данных.
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:06:09
Фиг. 8.21 Настройка прямого доступа в память Page 1-1
PAGE ,132
TITLE Фиг. 8.21 Настройка прямого доступа в память
0000 STACK SEGMENT STACK
0000 0040[ DW 64 DUP (?)
????
]
0080 STACK ENDS
= 0000 DMA EQU 0 ; Адрес порта DMA
0000 CODE SEGMENT
ASSUME CS:CODE
0000 DMA_SET PROC FAR
0000 1E PUSH DS ; Адрес возврата
0001 2B C0 SUB AX, AX
0003 50 PUSH AX
0004 B0 46 MOV AL, 46H ; Установка DMA в режим чтения с дискеты
0006 E6 0B OUT DMA+11, AL ; в память
0008 E6 0C OUT DMA+12, AL
000A 8C C8 MOV AX, CS ; Текущий адрес сегмента
000C B1 04 MOV CL, 4
000E D3 C0 ROL AX, CL ; Умножение на 16
0010 8A E8 MOV CH, AL ; Старшие 4 разряда в регистре CH
0012 24 F0 AND AL, 0F0H ; Очистка младших разрядов
0014 05 0032 R ADD AX, offset BUFFER ; Прибавление адреса буфера
0017 80 D5 00 ADC CH, 0
001A E6 04 OUT DMA+4, AL ; Вывод младшего байта адреса
001C 8A C4 MOV AL, AH
001E E6 04 OUT DMA+4, AL ; Вывод старшего байта адреса
0020 8A C5 MOV AL, CH
0022 E6 81 OUT 081H, AL ; Установка регистра страницы
0024 B8 01FF MOV AX, 511 ; Счетчик на один сектор
0027 E6 05 OUT DMA+5, AL ; Младший байт счетчика
0029 8A C4 MOV AL, AH
002B E6 05 OUT DMA+5, AL ; Старший байт счетчика
002D B0 02 MOV AL, 2 ; Открыть для прямого доступа канал 2
002F E6 0A OUT DMA+10, AL
0031 CB RET
0032 DMA_SET ENDP
0032 0200[ BUFFER DB 512 DUP (?) ; Буфер для чтения с диска
??
]
0232 CODE ENDS
END
Фиг. 8.21 Настройка прямого доступа в память
Программа также посылает в контроллер ПДП число передаваемых
байт данных. Контроллер дисковода использует это значение,
записанное в регистр счетчика канала 2, для завершения операции
чтения данных. ПДП посылает устройству специальный управляющий
сигнал, называемый завершением счета, когда оно записывает в память
последний байт. Последняя команда, выдаваемая ПДП - разрешение
работы канала 2. Теперь программа может войти в командную фазу
контроллера дисковода.
Адаптер дисковода соединяет множество компонентов программного
и аппаратного обеспечение компьютера. Адаптер дисковода использует
и ПДП, и прерывания для обслуживания работы дисковода. Сам по себе
контроллер дисковода - сложное, "интеллектуальное" устройство
управления, требующее получения "программы" перед началом работы. В
следующей главе при обсуждении управления механизмом дисковода с
помощью программы BIOS все это будет рассмотрено в комплексе.