Команды ввода из порта и вывода в порт

Физически порт ввода-вывода представляет регистр разрядностью 8, 16 или 32 бита. Доступ к устройствам ввода-вывода, системным устройствам компьютера осуществляется посредством этих регистров, причем каждый из этих регистров должен иметь возможность уникальной идентификации. С этой целью архитектурно процессор поддерживает так называемое адресное пространство ввода-вывода. Адресное пространство ввода-вывода физически независимо от пространства оперативной памяти и имеет ограниченный объем, составляющий 216, или 65 536, адресов ввода-вывода.

Таким образом, порт ввода-вывода можно определить как 8-, 16- или 32-раз­рядный аппаратный регистр, имеющий определенный адрес в адресном пространстве ввода-вывода. Вся работа системы с устройствами на самом низком уровне выполняется с использованием портов ввода-вывода. На рис. 1 показана сильно упрощенная концептуальная схема управления оборудова­нием компьютера.

Программа пользователя

Функции операционной системы

Функции BIOS *

    Пространство портов ввода-вывода    
Аппаратура компьютера

Рис. 1. Концептуальная схема управления оборудованием компьютера

Как видно из рисунка, самым нижним уровнем является уровень BIOS, на ко­тором работа с оборудованием ведется напрямую через порты. Тем самым реализуется концепция независимости от оборудования. При замене оборудования потребуется лишь подправить соответствующие функции BIOS, переориентировав их на новые адреса и логику работы портов.

Принципиально управлять устройствами напрямую через порты несложно.

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

in <аккумулятор>,<номер_порга> — ввод в аккумулятор из порта с номером <номер_порта>;

out <номер_порта>,<аккумулятор> — вывод содержимого аккумулятора в порт с номером <номер_порта>.

Возможные значения операндов этих команд приведены в приложении. Необходимо отметить, что использовать эти команды вы сможете без проблем только в программе, предназначенной для MS-DOS. При попытке их запуска в программе для Windows вы получите ошибку. Это не означает невозможности запуска исполняемого модуля описанной далее программы в сеансе Windows. Более того, Windows поддержит реализацию полного цикла разработки данной программы, но сделано это будет в специальном режиме работы — режиме виртуального процессора х86.

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

Вначале мы перечислим, какие аппаратные ресурсы будут задействованы и как ими надо управлять. В большинстве компьютеров есть внутренний динамик. Раньше он использовался для того, чтобы издавать звуки при работе самых различный приложений, вплоть до игровых. Сейчас у него осталась единственная важная функция — воспроизведение звуков, которые генерирует BIOS на этапе тестирования и начальной загрузки.

Несмотря на то что прямой доступ к портам ввода-вывода доступен только из среды MS-DOS, сведения о номерах портов и особенностях работы с ними полезны и при программировании для Windows. Если системы Windows 95/98 практически не закрывают доступ к портам, то в Windows NT/2000/XP любая попытка обращения к ним приведет к возникновению ошибки. Причина в том, что порты являются критически важным ресурсом, и механизмы защиты Windows NT/2000/XP не могут допустить их монополизацию каким-либо приложением. Операционная система Windows NT/2000/XP предоставляет программисту функции API для работы с устройствами, посредством которых в конечном итоге и осуществляется доступ к портам посредством команд IN и OUT. Попытка использовать эти команды в программе пользователя в среде Windows NT/2000/XP приведет к возникновению исключения по недопустимому коду операции. Важно понимать, что на низком уровне управление аппаратурой компьютера ведется с использованием тех же портов, что и при работе в MS-DOS, то есть физика остается, меняется логика управления аппаратурой. Если программе удастся получить уровень привилегий ядра (такой уровень имеют драйверы устройств), то в этом случае она может беспрепятственно использовать команды IN и OUT и работать с устройством так же, как в среде MS-DOS. Существуют специальные программы, которые позволяют получить доступ к портам ввода/вывода из программы пользователя, исключая необходимость написания драйвера.

Как это ни удивительно, но специальной схемы генерации звука для внутрен­него динамика нет. Сигнал для управления динамиком формируется в результате совместной работы следующих микросхем:

SS программируемого периферийного интерфейса (ППИ) І8255; таймера

Каналы таймера имеют одинаковую структуру, основу которой составляют три регистра:регистр ввода-вывода разрядностью 8 битов,регистр-фиксатор (latch register) ^регистр-счетчик (counter register), оба по 16 битов. Все ре-гистры связаны между собой следующим образом. В регистр ввода-вывода извне помещается некоторое значение. Источником этого значения может быть либо системное программное обеспечение, либо программа пользователя. Каждый регистр ввода-вывода имеет адрес в адресном пространстве ввода-вывода (номер порта ввода-вывода). Регистр ввода-вывода канала 2 имеет номер порта ввода-вывода 42h. Помещаемые в него значения немедленно попадают в регистр-фиксатор, где значение сохраняется до тех пор, пока в регистр ввода-вывода не будет записано новое значение. Далее описана структура слова состояния:

Бит 0 определяет тип константы пересчета: 0 — константа задана двоичным числом, 1 — константа задана двоично-десятичным (BCD) числом. Константа пересчета — значение, загружаемое извне в регистр-фиксатор; в нашем случае загружаться будет двоичное число, поэтому значение этого поля будет равно 0.

Биты 1-3 определяют режим работы микросхемы таймера. Всего можно опре­делить шесть режимов, но обычно используется третий — 011.

Биты 4-5 определяют тип операции: 00 — передать значение счетчика в регистр-фиксатор (то есть возможны не только операция записи значения в канал, но и извлечение значения регистра-счетчика из него), 10 — записать в регистр-фиксатор только старший байт, 01 - записать в регистр-фиксатор только младший байт, 11 - записать в регистр-фиксатор сначала старший байт, затем младший. В нашем случае значение поля будет 11. Поэтому формирование 16-разрядного регистра-фиксатора через 8-разрядный регистр ввода-вывода производится следующим образом: запись производится в два приема, первый байт из регистра ввода-вывода записывается на место старшего байта регистра-фиксатора, второй байт — на место младшего байта. Нетрудно догадаться, что в регистр ввода-вывода эти байты помещаются командами IN и OUT.

Биты 6-7 определяют номер программируемого канала. В нашем случае они равны 10.

Для формирования любого звука необходимо задать его длительность и высоту. После того как значение из регистра ввода-вывода попало в регистр-фиксатор, оно моментально записывается в регистр-счетчик. Сразу же после этого значение регистра-счетчика начинает уменьшаться на единицу с приходом каждого импульса от системных часов. На выходе любого из трех каналов таймера стоит схема логического умножения. Эта схема имеет два входа и один выход. Значение регистра-счетчика участвует в формировании сигнала на одном из входов схемы логического умножения И. Сигнал на втором входе этой схемы зависит от состояния бита О регистра микросхемы интерфейса с периферией (порт 61h). Когда значение в регистре-счетчике становится равным нулю, на соответствующем входе схемы И формируется единица. И если при этом на втором входе, значение которого зависит от бита О порта 61h, также 1, то импульс от системных часов проходит на выход канала 2. Одновременно с пропуском импульса в канале 2 немедленно производится загрузка содержимого регистра-фиксатора (которое не изменилось, если его не изменили извне) в регистр-счетчик. Весь процесс с уменьшением содержимого регистра-счетчика повторяется заново. Чем меньшее значение загружено в регистр-фиксатор, тем чаще будет происходить обнуление регистра-счетчика и тем чаще импульсы будут проходить на выход канала 2. А это означает большее значение высоты звука. Понятно, что максимальное значение частоты на входе 1 динамика — 1,19 МГц. Таким образом, импульс с выхода канала 2 попадает на динамик, и если на последний подан ток, то возникает долгожданный звук. Подачей тока на динамик управляет бит 1 порта 61h.

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

1. Посредством порта 43h выбрать канал, задать режим работы и тип операции передачи значения в канал. В нашем случае соответствующее значение будет равно

2. Подать ток на динамик, установив бит 1 порта 61h.

3. Используя регистр АХ, поместить нужное значение в порт 42h, определив тем самым нужную высоту тона.

Далее в листинге приведена программа, реализующая некоторые звуки. Для удобства в программе была использована макрокоманда delay, выполняющая задержку работы программы на заданное время Введенная таким образом макрокоманда в тексте программы синтаксически ничем не отличается от других команд ассемблера, и это позволяет программисту при необходимости расширить стандартный набор команд ассемблера. Стоит отметить, что дан­ная макрокоманда чувствительна к производительности процессора, из-за чего звуки на компьютерах с разными моделями процессоров могут не совпадать. Сегмент кода, как обычно, начинается с настройки сегментного регистра DS на начало сегмента данных. После этого строками 37-38 мы выполняем действия первого этапа — настройку канала 2, которая заключается в записи в регистр управления (порт 43h) байта состояния OB6h. На втором шаге мы должны установить биты 0 и 1 порта 61h. Предварительно необходимо извлечь содержимое этого порта. Это делается для того, чтобы выполнять установку битов 0 и 1, не изменяя содержимого остальных битов порта 61h . Принцип формирования сигнала сирены заключается в том, что в цикле на единицу изменяется содержимое регистра-счетчика и делается небольшая задержка для того, чтобы сигнал некоторое время звучал с нужной высотой. Постепенное повышение, а затем понижение высоты и дает нам эффект сирены. Контроль осуществляется с помощью переменной cnt, содержимое которой увеличивается на 1 и контролируется на равенство 5 . Если cnt = 5, то команда СМР устанавливает определенные флаги. Последующая команда условного перехода анализирует эти флаги и в зависимости от их состояния передает управление либо на метку, указанную в качестве операнда этой команды, либо на следующую за JNE команду. В данном случае цикл организуется командой for, которая в качестве операнда имеет имя метки. На эту метку и передается управление при выполнении команды for. Но до того как передать управление, команда for

 

анализирует содержимое регистра ЕСХ/СХ, и если оно равно нулю, управление передается не на метку, а на следующую за ШОР команду. Если содержимое регистра ЕСХ/СХ не равно нулю, то оно уменьшается на единицу и управление передается на метку. Таким образом в ЕСХ/СХ хранится счетчик цикла..

model small

stack 100h

delay macro time

Local ext,і ter

Push cx

Mov ex.time

ext:

push cx

mov cx,5O00

iter:

loop і ter

pop cx

loop ex

Pop cx

Endm

.data; сегмент данных

tonelow dw 2651; нижняя граница звучания 450 Гц

cnt db 0; счетчик для выхода из программы

temp dw 7; верхняя граница звучания

. code; сегмент кода

maіn:; точка входа в программу

mov ax, @data; связываем регистр ds с сегментом

mov ds , ax; данных через регистр ах

mov ax,0;очищаем ах

ао-заносим слово состояния 10110110b(0B6h) в командный регистр (порт 43h),

raovaL0B6h

out 43h,al

in al,61h

or al,3

out 61h,al

mov cx,2083

musicup:

addtonelow.l delay 1

mov dx,tonelow

bop musicІЇр

mOV CX.2083

rausicdown:

mov ax,temp

out 42h,al

mov al,ah

out 42h,al

sub temp.l

delay 1

loop

musicdown

nosound:

in al,61h

and al,0FCh

out 61h,al

mov dx,2651

mov inc

cmp

jne

exit: mov int

end main

tonelow.dx

cnt

cnt ,5

go