Более двух десятков лет назад мы разрабатывали устройство, передающее и принимающее данные, используя телевизионный сигнал. Это сейчас все избалованы гигагерцами и гигабайтами, а тогда, имея компьютер типа 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, и мы провозились бы месяцы, подозревая, конечно, неправильную работу нового устройства, а не настройку ПДП. Да и как догадаться, что нужно обратиться к порту, которого даже нет в документации! А сроки были жесткие и не уложись мы в них, проект вообще был бы закрыт с наклеиванием на нас ярлыка неумех и неудачников.

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

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