В институте курсе на четвертом нас учили программировать в байткодах для микропроцессора 8080. Для этого использовался программируемый контроллер Электроника МС 2702. Недавно мне захотелось вспомнить, как это было. Как ни странно, МС 2702 в наши дни можно найти на барахолках. Проблема заключается в том, что контроллер представляет собой черную коробку и подключаемый пульт для программирования. Для какого-то взаимодействия с пользователем требуется дополнительное оборудование, например, внешний терминал.
Знакомство с железом
Так совпало, что где-то в это же время мне на глаза попалось устройство под названием УМК-80. Притом, в хорошем состоянии и в полной комплектации. Почитав про УМК-80, был сделан вывод, что он лучше подходит для задачи.
Вот как выглядит УМК-80:
В комплекте шла эксплуатационная документация и плата для прототипирования:
Плата вставляется в разъем, который находится справа от надписи «УМК». Документация не только рассказывает, как пользоваться УМК-80, но и содержит подробную схему устройства, исходный код программы-монитора, а также описание выводов макетной платы. В сети доступны сканы документации [PDF] , которые выложила xlat8086 ( ЖЖ , Telegram ). Документация моего экземпляра немного отличается, но качественно такая же.
Суть устройства заключается в следующем. Машинный код программы вводится в шестнадцатеричном коде при помощи клавиатуры. Затем также при помощи клавиатуры передается управление на заданный адрес. Взаимодействие с пользователем осуществляется при помощи шести семисегментных индикаторов и клавиатуры. Устройство позволяет задавать до двух точек останова, исполнять программу в пошаговом режиме, отображать и модифицировать содержимое регистров, вычислять контрольную сумму массива памяти, заполнять массив памяти константой, копировать массив памяти в адресном пространстве. Другими словами, перед нами простой ретро-компьютер со встроенным отладчиком.
УМК-80 выпускался в двух версиях: РР3.059.004 — переносной вариант в чемодане, РР3.059.004-01 — настольный вариант. У меня последний. Вес устройства составляет 6 кг при размерах 45 x 35 x 12 см. Судя по вкладышу, найденному в эксплуатационной документации, данный экземпляр был произведен в ноябре 1988 года. Устройство имеет серийный номер 12243. Цена не указана.
Здесь использован процессор КР580ВМ80А работающей на частоте ~2 МГц. На борту имеется 1 Кб ОЗУ и 2 Кб ПЗУ. При этом 1 Кб ПЗУ зарезервирован для нужд пользователя. В документации заявлено использование ОЗУ 2 x КР541РУ2, но по факту стоят 2 x К537РУ13, по 512 байт статической памяти в каждой. ПЗУ — 2 x К573РФ1, по 1 Кб на каждую. К573РФ1 плох тем, что прошивается напряжением 26 В. Это очень много. Мой КРОТ-РФ данную ПЗУ не прошьет.
Адресное пространство поделено таким образом. Адреса 0 x 0000..0 x 03FF выделены под программу-монитор, 0 x 0400..0 x 07FF — ПЗУ пользователя, 0 x 0800..0 x 0BFF — адресное пространство ОЗУ.
Ожидая доставку УМК-80, я решил собрать больше информации об устройстве. Так я наткнулся на серию постов Сергея a.k.a. dlinyj: первый , второй , третий . Сергей предупреждает, что при первом включении УМК-80 может взорваться конденсатор.
На следующей фотографии этот конденсатор обведен в прямоугольник:
Конденсатор был заменен пленочным конденсатором 0.1 мкФ 630 В. UPD: Позже я выяснил, что здесь следует использовать конденсатор класса X2 .
Характерно, что устройство легко разбирается. Платы здесь держатся на разъемах и шасси. Ослабляем два винта, обведенные на фотографии кругами, и получаем доступ к основным платам. Сергей предлагает достать основную плату и вставить ее в разъем платы расширения. Шины общие, разъемы одинаковые, в связи с чем нет причин, почему это не должно работать. Можно смотреть осциллографом , что происходит с платой, подменять ПЗУ, и так далее.
В своем экземпляре я решил так не делать и ограничился лишь осмотром маркировок компонентов. На микросхемах ПЗУ не были заклеены кварцевые окошки. Это не страшно, поскольку стереть ПЗУ без специализированного УФ стирателя практически невозможно. Тем не менее, кварцевые окошки были заклеены медным скотчем, на всякий случай.
Несколько клавиш на клавиатуре заедали. Если понажимать проблемные клавиши несколько минут, то они разрабатываются, и проблема уходит.
После включения у меня загорелись светодиоды +5 В и +12 В. Это означает, что данные напряжения отсутствуют (хорошо, когда есть документация). Было решено проверить предохранители. Выяснилось, что один из них пробит. Здесь используются керамические предохранители ВП1-1. Они имеют длину 15 мм и максимальный диаметр 4 мм. Такие предохранители легко доступны в наши дни. После замены предохранителя все заработало.
Пишем код
Программировать было решено в машинных кодах, иначе как-то не спортивно. Ассемблер 8080 легко переводится в соответствующие опкоды по табличке, к примеру, этой или этой . Ассемблер 8080 является восьмибитным предком современного ассемблера x86/x64 , в связи с чем программирование на нем не вызывает затруднений. Детальное описание ассемблера 8080 содержится в документе Intel 8080 Assembly Language Programming Manual [PDF] .
Вот простейшая программа:
0802 C3 00 08 JMP 0x0800
Здесь левая колонка — это адреса, по центру — опкоды, справа — код на ассемблере. Программа в цикле пишет 0 x AA в регистр A.
После включения устройства нажимаем СБ (сброс), П (память), вводим 0800, _ (пробел), 3E, _, AA, _, C3, _, 00, _, 08, _, ВП (выполнить). Чтобы запустить программу, говорим СТ (старт), 0800, ВП. Теперь программа крутится в цикле. Нажимаем ПР, чтобы прервать ее выполнение. Затем нажимаем РГ, А. Должны увидеть A - AA
, то есть, имя регистра и его содержимое.
Теперь попробуем написать программу, выводящую что-то на семисегментные индикаторы. Выбор индикатора осуществляется записью в порт 0 x F8. Если записать 0b1, будет выбран самый левый индикатор, если 0b10, то второй слева, если 0b100, то третий, и так далее. Какие светодиоды нужно зажечь определяется записью в порт 0 x F9. Нумерация сегментов стандартная . Запись 0b1 означает зажечь сегмент A, 0b10 — сегмент B, 0b100 — сегмент C, и так далее.
Допустим, мы хотим вывести «HELLO». Переводим буквы в битовые маски:
E = 0b01111001 = 0x79
L = 0b00111000 = 0x38
O = 0b00111111 = 0x3F
Вот программа, выводящая букву H:
0802 D3 F8 OUT 0xF8
0804 3E 76 MVI A, 0x76 ; выводим символ H
0806 D3 F9 OUT 0xF9
0808 C3 00 08 JMP 0x0800 ; программа зациклена
С помощью команды П можно поменять содержимое памяти по адресам 0801 и 0805, после чего снова запустить программу. Убеждаемся, что вывод других букв и использование других индикаторов тоже работают.
Осталось вывести «HELLO». Вот моя первая, наивная версия:
0802 0E 05 MVI C, 0x05 ; выводим 5 символов
0804 26 08 MVI H, 0x08 ; адрес массива символов
0806 2E 18 MVI L, 0x18
0808 78 MOV A, B ; выбор индикатора
0809 D3 F8 OUT 0xF8
080B 07 RLC ; сдвинуть A влево
080C 47 MOV B, A ; это будет следующий сегмент
080D 7E MOV A, M ; A <- (HL)
080E D3 F9 OUT 0xF9 ; выводим символ
0810 23 INX H ; инкремент HL
0811 0D DCR C ; декремент счетчика
0812 C2 08 08 JNZ 0x0808 ; продолжить если не ноль
0815 С3 00 08 JMP 0x0800 ; программа зациклена
0818 76 ‘H’
0819 79 ‘E’
081A 38 ‘L’
081B 38 ‘L’
081C 3F ‘O’
Эта программа выводит мусор. Но почему?
Для ответа на вопрос запустим программу в пошаговом режиме. Для этого нажимаем клавишу РБ/ШГ. Это клавиша с фиксацией, она остается зажатой. Запускаем программу командой СТ, 0800, ВП. Далее жмем ШГ. Одно нажатие — выполнение одной команды.
Если зажата клавиша КМ/ЦК, программа останавливается после выполнения каждого рабочего цикла процессора. Выполнение одной команды занимает несколько циклов. Такая детализация в данном случае не требуется. Поэтому стоит убедиться, что КМ/ЦК не зажата.
В пошаговом режиме видим, что индикаторы обновляются таким образом:
2. _H____
3. _E____
4. __E___
5. __L___
…и так дале…
Вот оно что! В одном индикаторе поочередно отображаются две буквы. В первом индикаторе это H и O, во втором — H и E, и так далее. Решение заключается в том, чтобы выключать индикаторы на время обновления кода буквы.
Исправленная программа:
0802 0E 05 MVI C, 0x05 ; выводим 5 символов
0804 26 08 MVI H, 0x08 ; адрес массива символов
0806 2E 1B MVI L, 0x1B
0808 97 SUB A ; очистить A
0809 D3 F8 OUT 0xF8 ; выключить все индикаторы
080B 7E MOV A, M ; A <- (HL)
080C D3 F9 OUT 0xF9 ; выводим символ
080E 78 MOV A, B ; выбор индикатора
080F D3 F8 OUT 0xF8
0811 07 RLC ; сдвинуть A влево
0812 47 MOV B, A ; это будет следующий сегмент
0813 23 INX H ; инкремент HL
0814 0D DCR C ; декремент счетчика
0815 C2 08 08 JNZ 0x0808 ; продолжить если не ноль
0818 С3 00 08 JMP 0x0800 ; программа зациклена
081B 76 ‘H’
081C 79 ‘E’
081D 38 ‘L’
081E 38 ‘L’
081F 3F ‘O’
А так выглядит результат:
Был написан «Привет, мир!» для УМК-80. Заинтересованным читателям в качестве упражнения предлагается написать бегущую строку. Если задача покажется вам слишкой простой, попробуйте написать небольшую игру — «крестики-нолики», «угадай число», или что-то в таком духе.
Заключение
Кому-то УМК-80 может показаться примитивным и неинтересным устройством, однако не стоит его недооценивать. На разъем для подключения внешней платы выведены системные шины. Благодаря этому факту УМК-80 является очень расширяемой платформой. Можно увеличить объем ОЗУ и ПЗУ, добавить полноценную клавиатуру и вывод информации на монитор, воспроизведение звука на КР580ВИ53 , подружить устройство с магнитофоном или научить его читать SD-карты . Простор для творчества здесь очень велик.
Дополнение: Советский персональный компьютер Микроша