Во времена повсеместного господства планшетов и смартфонов, сложно поверить, что совсем недавно, можно было получить немалое удовольствие, играя с калькулятором. Разумеется, я имею в виду не обычный (или даже инженерный) калькулятор, а программируемый. Я хочу рассказать об устройстве, которое буквально перевернуло мою жизнь и фактически подтолкнуло меня к тому, чтобы стать программистом.
В конце 70-ых годов прошлого века, с вычислительной техникой в СССР было туго. Мой отец работал программистом. В моей памяти навсегда останутся и походы на его работу в ЦУМ, где я играл в Ним с вычислительной машиной Минск и продолжительные набивания программ латунными кольцами на планшетах для Искр, использовавшихся в то время Сбербанком. Иметь, в своем личном распоряжении, что-то, способное выполнять программы, я, конечно, не мог даже мечтать.
Все изменилось с появлением программируемых микрокалькуляторов (ПМК). Теперь мечтать я мог. Именно этим я и занимался, зачитываясь статьями в Технике молодежи, поскольку приобрести это программируемое чудо в Казани, не представлялось возможным. Но, в один прекрасный день, мы с родителями выбрались в Москву.
Приложив немалые усилия, я убедил родителей приобрести совсем не дешевый по тем временам МК-61 и, на сдачу, подшивку старых журналов Квант, после чего, забаррикадировавшись на квартире у наших родственников, перестал реагировать на внешние раздражители, вплоть до самого отъезда.
Я перечитал все, что печаталось в то время по программируемым калькуляторам, завел общую тетрадь и прилежно переписывал в нее особенно понравившиеся программы. Постепенно я подошел к тому, что смог вносить в них свои исправления и доработки (опыт полученный в бдениях по программированию Искр не пропал даром). Через некоторое время, я смог писать программы самостоятельно.
Когда я уже довольно хорошо освоился с МК-61, одному моему другу приобрели улучшенную версию — МК-52. По системе команд она практически не отличалась от МК-61, но имела возможность сохранять программы в ППЗУ и поставлялась с несколькими картриджами с уже готовыми программами. Разумеется, я сразу захотел написать что-то специально для нее.
Энтузиастами было предложено множество схемотехнических решений этой проблемы. Как-то раз я даже видел статью, описывающую устройство для хранения программ калькуляторов на магнитных лентах. Выпуск МК-52 поставил окончательную точку в этом не простом вопросе.
Выбор пал на «Морской бой». Я уже давно хотел его сделать, но никак не мог втиснуть весь требуемый функционал в куцее адресное пространство калькулятора. Возможность подгружать программы из ППЗУ позволила разбить программу на две части. Первый блок — расставлял корабли, второй (собственно игровой) обеспечивал диалог с пользователем. Часть подпрограмм использовалась обоими блоками.
Поскольку в таком виде эта наскальная живопись расшифровке практически не поддается, приведу этот код в более читаемом виде:
00|46 01.07 02.12 03.08 04.11 05.34 06.15 07.45 08|53 09:75
10.06 11.53 12:67 13.5E 14:08 15.62 16.53 17:37 18.6E 19.01
20.11 21.4E 22|53 23:34 24.6E 25.02 26.10 27.4E 28.53 29:34
30.5D 31:08 32.63 33.50 34|62 35.02 36.10 37|65 38.12 39.01
40.10 41.DE 42.38 43.BE 44.52 45.11 46.4E 47.53 48:58
49.6E
50.02 51.10 52.4E 53.53 54:58 55.5D 56:22 57.27 58|61 59|65
60.12 61.01 62.10 63.DE 64.38 65.BE 66.52 67|65 68.12 69.01
70.10 71.DE 72.37 73.35 74.52 75|66 76.01 77.01 78.12 79.20
80.10 81.35 82.46 83.07 84.12 85.07 86.10 87.4E 88.65 89.04
90.15 91.12 92.45 93.01 94.11 95.59 96:A2 97.65 98.07 99.15
A0.13 A1.45 A2|52
00.40 01.50 02.57 03:41 04.0B 05.15 06.45 07.14 08.06 09.10
10.4E 11.02 12.53 13:67 14.57 15:22 16.0F 17.DE 18.39 19.BE
20.64 21.52 22|53 23:75 24.01 25.53 26:67 27.5E 28.22 29.15
30.53 31:59 32.6E 33.06 34.11 35.62 36.12 37.65 38.17 39.11
40.52 41|53 42:58 43.6E 44.01 45.11 46.4E 47.53 48:58
Здесь я использую коды команд, поскольку их обозначения, предложенные производителем ПМК, не очень удобны для распечатки «листингов». Соответствие кодов командам можно посмотреть по табличке (любезно нарисованной мной в те же годы):
- Арифметические команды (10-13), выполняющие соответствующее действие с двумя нижними регистрами оперативного стека (X, Y) и помещавшими результат в X
- Команды записи и чтения из регистров памяти (40-4E и 60-6E соответственно)
- Команды, управляющие выполнением программы (50-5E), из числа которых следует отметить команду останова (50), а также команды вызова подпрограммы (53) и возврата из нее (52)
- Весьма полезными были команды косвенной адресации (B0-BE, D0-DE), позволявшие обращаться к регистру памяти, номер которого был записан в другой регистр
Хотя в кодах команд и использовались шестнадцатеричные цифры, их отображение на экране вызывало в памяти кадры из кинофильма «Хищник»:
Для удобства, я выделил в коде адреса команд переходов (двоеточием после адреса команды), а также точки входа (вертикальной чертой). Это позволяет более наглядно увидеть взаимосвязь подпрограмм (особенно интересна команда вызова подпрограммы, расположенная по адресу 22 и обеспечивавшая своего рода «полиморфизм». При обращении к этой подпрограмме, управление передавалось в различные места, в зависимости от того, какой именно блок был загружен).
Можно заметить, что переходы в середину (а не в начало) подпрограммы не являлись чем-то экстраординарным. Из-за крайне ограниченного размера адресуемой памяти, экономить приходилось буквально на всем. Особым шиком считались переходы на адрес другого перехода (трактуемый в этом случае как код команды).
Поскольку работающего калькулятора под рукой уже нет, я использовал эмулятор:
Все подготовленные образы были загружены на GitHub.
Первый образ можно использовать для расстановки «кораблей»:
Начальное значение для генератора псевдослучайных чисел (0.1234567) может быть изменено. После запуска на выполнение (в/о с/п), программа работает довольно долго, выводя, в конечном итоге, адрес для загрузки игрового модуля из ППЗУ (возможность автоматического обращения к ППЗУ из программы отсутствовала):
Так как эмулятор (по крайней мере та версия которую я использовал) полностью проигнорировала мои попытки обращения к ППЗУ, я подготовил образ с вбитым руками игровым модулем и уже выполненной расстановкой кораблей.
Сама расстановка хранится в регистрах памяти с 7-го по D. Вот пример второй строки (8-ой регистр):
Двойки кодируют положение «кораблей». На основе приведенного выше начального значения, была сгенерирована следующая расстановка:
0 0 0 0 1 0 1
0 0 1 0 0 0 0
1 0 0 0 0 1 0
0 0 1 0 0 0 0
0 0 0 0 0 0 0
0 1 0 0 0 0 1
0 0 0 1 0 0 0
Можно заметить, что программа разместила девять не соприкасающихся «однопалубных кораблей» на поле размером 7x7 клеток. Конечно, в таком виде, игра больше напоминает всем известный Сапер, но на что-то большее ресурсов калькулятора мне не хватило.
Чтобы начать игру, необходимо ввести количество кораблей (9 в/о с/п) после чего, вводить координаты «выстрелов» (например 2 В^ 2 с/п). Так как мы подсмотрели расположение «кораблей», нам не составило никакого труда потопить «однопалубник»:
Впрочем, второй раз попасть по нему уже не удастся:
Попробуем (2 В^ 2 с/п). Как и ожидалось, калькулятор наносит ответный удар:
Первая цифра здесь — координата по вертикали (начиная снизу-вверх), вторая — по горизонтали (слева-направо).
Чуть позже я заметил, что изменив всего пару команд (в самом первом фото с текстом программы, они отмечены красным), можно добиться того, чтобы размещаемые корабли могли соприкасаться, но не углами, а сторонами (образы 0003 и 0004). В результате получалась следующая расстановка «многопалубников»:
0 0 0 0 1 0 0
0 0 0 0 0 0 0
0 0 1 0 0 1 0
0 0 1 0 0 0 0
0 0 0 0 0 0 0
1 1 0 1 0 0 1
0 0 0 1 0 0 0
Не бог весть что, но неплохо, с учетом того, что изменить пришлось всего две команды.
Отдельно следует сказать о багах (даже скорее о Багах), хотя это тема для отдельной статьи, если не их цикла. Дело в том, что калькуляторы описываемой серии были буквально напичканы различными примерами ошибок и недокументированного поведения. В среде любителей, это привело к развитию культуры изучения этих недокументированных возможностей, известной под обобщенным названием ЕГГОГ-ология.
Некоторые образчики таких багов забавны, иные — опасны, а отдельные из них удивительно полезны. Хорошим примером такого потенциально полезного поведения является выполнение команды «ввод порядка» (ВП) после записи в регистр памяти. В режиме выполнения программы, она приводила к «отрезанию» первой цифры числа в регистре X (отображаемом на индикаторе), причем при пошаговом выполнении (да да, было и такое), команда отрабатывала вполне штатно. Добиться каким-либо другим вменяемым способом такого результата, было невозможно.
Напуганный столь нестандартным поведением команды ВП я внес исправление в программу, изменив последовательность команд 35.ВП 36.1, на 35.ИП2 36.x (во 2-ом регистре пришлось хранить константу 10). Поскольку живого калькулятора нет, я уже не могу проверить, приводила ли команда ВП, в этом контексте к ошибке. Под эмулятором оба варианта работают вполне штатно.
К сожалению, мне не известна реализация эмулятора воспроизводящая все примеры недокументированного поведения.
Уже после всего этого, были Микроши, БК-шки и Спектрумы. Была ЕС-1046, с которой я столкнулся в институте. Были PDP-шки и VAX-ы. До появления IBM PC, ждать оставалось недолго.
Автор: GlukKazan