Более двух десятков лет назад мы разрабатывали устройство, передающее и принимающее данные, используя телевизионный сигнал. Это сейчас все избалованы гигагерцами и гигабайтами, а тогда, имея компьютер типа IBM/PC-AT, на таких скоростях можно было работать только с помощью встроенного контроллера прямого доступа к памяти (ПДП), реализованного в виде микросхем 8237А-5. Это устройство позволяло писать или читать данные, не привлекая центральный процессор.
Отработка ПО заняла несколько недель, и когда все, наконец, заработало, я решил привести исходные тексты на ассемблере в окончательный и красивый вид. С одной стороны, в этот момент, поскольку все уже работает, существенных исправлений в тексте не предвидится, с другой стороны – в памяти еще удерживается множество деталей, которые лучше увековечить понятными комментариями, так как очень скоро все эти детали забудутся. Заодно, можно глобально заменить все неудачные названия переменных на более внятные, исправить орфографические ошибки, красиво подвинуть строки и т.п.
И вот, при заключительном просмотре текста, я вдруг увидел глупую описку в программировании ПДП. Адрес в 16-разрядной 8237А-5 приходилось задавать по частям и при задании номера «страницы» (т.е. номера куска памяти в 128 Кбайт) вместо команды
OUT DX,AL
было написано
OUT DX,AX
что совершенно бессмысленно, поскольку все используемые в ПДП порты 8-разрядные.
Исправил ляпсус, перетранслировал – НЕ работает! Вернул опять бессмысленный AX вместо AL – работает. Не может быть!
Начинаю рассуждать. Команда OUT выполняется ведь подобно обычной записи в память, только специальный сигнал INOUT на шине выставляется. Следовательно, если вместо AL я выдаю AX, то это равнозначно тому, что я в один порт (в данном случае 83H) выдаю значение из AL, а в соседний, т.е. получается в 84H – значение из AH, а там в этот момент просто ноль.
А что это за порт такой? Вот же таблица всех портов из тогда единственной имевшейся у нас книги Фроловых «Аппаратное обеспечение IBM PC»:
Назначение и адреса регистров страниц контроллера для IBM AT:
81h Регистр страниц канала 2
82h Регистр страниц канала 3
83h Регистр страниц канала 1
87h Регистр страниц канала 0
89h Регистр страниц канала 6
8Bh Регистр страниц канала 5
8Ah Регистр страниц канала 7
8Fh Регенерация динамической памяти
Нет вообще здесь никакого порта 84H!
Честно говоря, я и сейчас не знаю, что это такое. Может быть, разрешение на работу данного ПДП из всего каскада, а может какая-то особенность конкретной материнской платы или еще одна часть адреса, позволяющая задать его больше чем 16 Мбайт.
Теперь, в эпоху Интернета, доступа к электронным библиотекам и компьютерным форумам, наверное, несложно докопаться, что именно делала запись нуля в неведомый мне порт 84Н. Но это уже неинтересно, поскольку все эти ПДП (DMA) давно ушли в прошлое вместе с шиной ISA и другими древними интерфейсами.
Однако речь о другом. Какое невероятное, прямо волшебное везение для программиста! Кто толкнул меня под руку написать AX вместо AL и именно в этом месте? Ведь ни в одном примере этого не было. Напиши я как положено AL, и мы провозились бы месяцы, подозревая, конечно, неправильную работу нового устройства, а не настройку ПДП. Да и как догадаться, что нужно обратиться к порту, которого даже нет в документации! А сроки были жесткие и не уложись мы в них, проект вообще был бы закрыт с наклеиванием на нас ярлыка неумех и неудачников.
Я стал вспоминать, были ли у меня другие случаи программистского везения. Были, конечно. Например, сляпанный наскоро тест, покрывавший ничтожную часть области возможных значений, вдруг с первого (!) запуска ловил комбинацию параметров, выявлявших тонкую и редко воспроизводимую ошибку.
Но все-таки этот случай везения в моей программистской практике из ряда вон выходящий. Вот и не верь после этого в ангелов-хранителей. Причем специализированных, уберегающих от ошибок в программах на ассемблере.
ultrinfaern
Чисто технически команда OUT выдает на шину адреса номер порта, а на шину данных сами данные. И адреса портов это не память, поэтому адрес порта может увеличиваться на единицу, а данные могут быть любого размера.Там нет никакого инкремента адреса, поэтому непонятно откуда взялся порт 84, точнее ваше предположение скорее всего неправильно насчет этого порта. Возможно баг в самом устройстве. Да и непонятно как устройство дожно на это все реагировать. Вообще было бы интересно докопаться до истинной причины.
Dukarav Автор
впоследствии это место оформили так:
out 83h,al
mov al,0
out 84h,al ; подсказка свыше
ultrinfaern
Я уже открыл документацию по контроллеру. Хотя по документации номер порта четный — это адрес, а нечетный — счетчик. А у вас нечетные порты — адрес. возможно четные — количество. Там возможно специально сделали, чтобы за одну команду можно было грузить как адрес так и количество. Или это баг, превратившийся в фичу. :)
FGV
Что то сомневаюсь, скорее всего так:
out 83h,al; запись первого байта — мл. часть адреса
mov al,0
out 83h,al; запись второго байта — ст. часть адреса
Цитата из даташита:
Собственно out dx,ax мог сработать если система была на 8088, там шина данных восьмибитная и ввод/вывод 16-ти бит шел в два захода.
VSukhomlinov
у меня 2 гипотезы:
1) эта запись вызывала задержку на шине, которая для чего то была необходима — проверка — записать в какой-то другой порт.
2) это мало документированная фича для работы с адресами выше 16МБ, где адрес 24-бита уже недостаточно.
docs.freebsd.org/doc/3.4-RELEASE/usr/share/doc/handbook/dma.html
A new implementation of the 8237, called the 82374, allows 16 bits of page register to be specified, allows access to the entire 32 bit address space, without the use of bounce buffers.
DmitryLTL
J0nny
Судя по тому, что про порт 84h ничего не известно в документации, то возможной причиной могло быть разница в задержке выполнения инструкции? То есть out dx, ax выполняется дольше, и за счет этого дальнейший код не отрабатывает раньше положенного.
alecv
Коллеги, начиная с адреса 80H в архитектуре PC сидит «страничный регистр». Контроллеры DMA i8237A в AT-шке сидят на адресах 00H (совместим с XT-шкой) и C0H (есть только в AT, обслуживает DMA 4..7). Проблема в том, что i8237A может обслуживать только сегмент 64К. Для переключения сегментов (в этом месте используют термин «страница») нужен регистр страниц. В IBM PC AT 5170 он сделан на микросхеме 74LS612, а в IBM PC XT 5160 — на микросхеме 74LS670. В чипсетах — их функциональные копии.
wiki.osdev.org/DMA
aodfaq.wikidot.com/pc-dma-addressing
и книжки Mindshare «ISA System archeticture» и «EISA System architecture» в помощь.