Волшебный чемодан
История о закрытии гештальта.
В старшие школьные годы, в библиотеке мне попалась книга «Простейшая микро-ЭВМ», где для школьников подробно объяснялось, как спаять свою вычислительную машину на микропроцессоре КР580ИК80А. Помню, что книгу зачитал просто до дыр, и в целом она определила мою судьбу в области электроники и программирования. Но тогда я понимал, что у меня не хватит пороха и возможностей сделать эту вычислительную машину, так как не было ни средств, ни опыта, ни подходящего наставника. Книгу я вернул обратно в библиотеку, отксерив некоторые листы.
В конце этого года spiritus_sancti обмолвился, что у него есть лишний УМК — Учебный Микропроцессорный Комплект. И тут я понял, вот она — мечта моего детства, она есть в железе и она реальна! И тут же начал просить мне его прислать. И с этого момента начинаются увлекательные предновогодние приключения.
Книга «Простейшая микро-ЭВМ»
Подобных проектов было несколько, самый известный — это ЮТ-88, но увы, он прошёл мимо меня. А книга «Простейшая микро-ЭВМ» Буреев Л.Н., Дудко А.Л., В.Н. Захаров меня тогда потрясла. И покуда шла организация отправки и доставки, я озадачился покупкой данной книги. Оказалось, что книга относительно редкая, и несколько раз сделка у меня сорвалась, но таки удалось её удачно найти на книжном аукционе. И наконец я её получил, даже раньше самого УМК.
Прочитал её с не меньшим удовольствием, даже наоборот, скорее понимая, что я смогу применить всё на практике. Поэтому в этот раз внимательно смотрел все исходные коды, впитывая основы ассемблера i8080 и понимая, что мне это всё может пригодиться. Единственная особенность книги, что данные приводятся не в шестнадцатеричном привычном формате, а в восьмеричном, что добавляет некоторые нюансы в понимании. Её прочитал буквально за день и потом ещё несколько ночей внимательно разбирал приведённые примеры программ.
На одной из страниц приводится пример аппаратной реализации, внешний вид которой меня очень вдохновлял в то время.
Попутно с этой книгой, искал всю известную информацию по УМК-80, и как оказалось, в сети очень мало данных об этом. Но об этом поговорим позже.
Распаковка волшебного чемодана
Наверное, это самый желанный и ожидаемый подарок для меня в последнее время. И я с нетерпением ждал отправки, затем каждые два часа обновлял статус доставки и ждал, когда же он придёт. И наконец настал тот удивительный миг, когда я получил этот чемодан!
Долгожданный чемодан моей мечты.
Конечно же, скорее его нужно открыть:
О да, это он! Конечно же, я понимаю что многие читатели делали на подобных аппаратах лабораторные работы в институте. Но у меня не было таких лабораторных работ и я даже не знал, что такие устройства существовали в природе и именно поэтому для меня это настоящая радость открытий. Особенно радует его полная комплектность и, наверное, работоспособность.
Когда появляется новая электрическая игрушка, мы её стараемся воткнуть в сеть и насладится её работой. То же самое сделал и я, включаю, светодиоды зажигаются на пару секунд, а затем БАБАХ!
Гаснет свет во всей квартире, а из чемодана идёт волшебный дым. Новый год с фейерверкером… Печали моей не было предела, не успел получить, а уже сломал…
Диагностика и ремонт
Зная из личной практики, если откуда-то пошёл волшебный дым, лучше это обратно в розетку не включать. Поэтому я включил выбитые автоматы и начал разбирать УМК для его диагностики и ремонта.
Внутри он оказался очень добротно сделан, прям даже снимаю шляпу перед инженерами:
Потроха.
Блок питания обычный трансформаторный, внутри всё очень аккуратно. Более всего подивили накрутки на контакты, как самый надёжный способ соединения (более надёжный чем пайка).
Накрутки на контакты.
У меня было ощущение, что я прям прикоснулся к великой истории вычислительных машин. Много слышал о накрутках, но никогда не видел, тем более в работающем устройстве.
Виновник взрыва отыскался быстро — это был металлобумажный конденсатор на 0,1 мкФ, который пробился и взорвался. Как оказалось — это очень частая проблема, у другого товарища случилась такая же неприятность.
Взорванный конденсатор.
Поскольку конденсатор стоит во входном фильтре, и по сути он ни на что особо не влияет, поэтому я просто его грубо выкусил. На данный момент закупил керамический конденсатор на 0,1 мкФ на 400 В, просто не доходят руки его поставить (всё стабильно работает и так).
Первый запуск после ремонта. Ещё не убран обратно в чемодан.
После всех процедур и проверок всё убрал в чемодан и закрепил на винты.
Архитектура
▍ Вступление
У меня на руках Учебный Микропроцессорный комплект, производства завода VEF. Обычно в литературе он называется, как УМК-80. Хочу обратить внимание, что есть несколько типов учебных микропроцессорных комплектов, с архитектурой i8080, например, УМПК-80, они достаточно сильно отличаются между собой. Здесь же я рассказываю только о своём, УМК-80.
Когда я искал литературу, а затем писал код, то столкнулся с тем, что в разной литературе даётся разная информация. И как-то не удалось мне встретить одну книжку, в которой будет всё-всё-всё расписано так, что бери да программируй. Например, в одной книге даётся хорошее описание аппаратной части, но примеры кода используют процедуры, которые содержатся в дополнительной ПЗУ, когда-то зашитой преподавателем (у меня таковой нет). В другой книге даётся полезная информация по программированию, но адреса памяти и портов не соответствуют моей ЭВМ. В третьей книге используется контроллера RS-232, которого у меня нет, и разумеется там должно быть дополнительное ПЗУ для работы с этим контроллером.
Поэтому мне пришлось собирать информацию по крупицам, по всеярунету, в великом походе по граблям, половина из которых были детские.
В какой-то момент меня одолело такое сильное отчаяние, что я решил даже взять и переписать всю программу монитор из ПЗУ вручную, затем её дизассемблировать и посмотреть, что же там происходит. Просто снял на видео от первого до 1024d адреса и потом начал набирать вручную. Но потом понял, что это займёт неадекватно много времени и плюнул на это занятие.
Если кто сможет из видео распознать hex и сложить в текстовый документ, буду очень признателен. Лично я сломался после первых 256 байт и часа ввода.
▍ Описание архитектуры
Одну из самых ценных книжек мне скинул sfrolov: Рыбин А. А. «Методические указания по выполнению РГЗ». Не знаю, как там с авторскими правами, поэтому ссылки на книгу приводить не буду. Но она легко ищется в интернете. В данной книге даются хорошие основы, схема, а главное порты реально соответствуют моей машине (это первое издание, в котором полностью всё совпало). Далее идут примеры кода, которые у меня уже не работают, потому что используются внешние процедуры. Цитаты буду приводить из разных книг, чтобы меня не обвинили в плагиате или чрезмерном цитировании.
Внешний вид ЭВМ.
- Микропроцессор: КР580ВМ80, аналог i8080
- ПЗУ: 1 килобайт, в ней содержится программа «Монитор».
- ОЗУ: 1 килобайт (расположена начиная с адреса 0×0800).
Внутри есть панелька, куда можно поставить дополнительное ПЗУ и туда уже записать свою программу. Пока думаю, где взять флешку pin-to-pin совместимую (или близкую) к К573РФ1.
Распределение адресного пространства памяти в УМК-80:
Любопытно взглянуть на структурную схему УМК-80.
У меня нету ни RS-232 и всего 1 кБ ПЗУ, но в остальном архитектура точно такая же.
Любопытно, что есть аппаратные клавиши, которые управляют работой процессора, например, СБ (сброс) или РБ/ШГ (переключатель в пошаговый режим), а также есть просто кнопки, которые обслуживаются программой «Монитор» и их можно использовать в своих программах.
Самое интересное, что процессор можно перевести в режим пошагового исполнения инструкций (переключатель «РБ/ШГ»), тогда загораются все светодиоды (адреса, данных, состояния) и можно двигаться по шагам программы кнопкой «ШГ» (шаг). Можно делать шаг машинного цикла или шаг команды.
УМК-80 в пошаговом режиме исполнения команд.
Это уникальный режим, который позволяет проводить отладку, и выполнять инструкции по шагам, наблюдая, что же делает процессор в каждый свой такт.
Клавиатура с цифровыми клавишами и буквенными используется в программе монитор. Например, чтобы заложить значение в память, нажимаем клавишу «П», затем клавишу пробел и вводим адрес. Можно заменить значение ячейки, после изменения нажимаем снова пробел и переходим к следующей ячейке. По окончании нажимаем «ВП». Чтобы стартануть программу, нужно нажать клавишу «СТ», затем ввести адрес программы, откуда начать выполнение и клавишу «ВП».
▍ Порты ввода-вывода
Одной из проблем, что в разной литературе указанны различные цифры портов ввода-вывода. Поэтому пришлось попробовать все возможные варианты и найти подходящий для моей ЭВМ. Привожу её в таблицу:
Распределение адресного пространства портов внешних устройств в УМК-80:
▍ Дисплей и клавиатура
Поскольку мне хотелось сделать какую-то демку, то пришлось разобраться с тем как же работает дисплей. Хитрость в том, что дисплей и клавиатура висят на одном и том же порту. Чтобы зажечь индикатор, необходимо в один порт F8 выставить бит, который соответствует выбранному индикатору, а в порт F9 вывести символ.
О дисплее я ещё расскажу подробнее ниже, как же с ним работать.
Клавиатура представляет собой обычную матричную клавиатуру, с режимом сканирования (когда есть «бегущий бит»), и считывается по соответствующей таблице. Клавиатуру тоже можно использовать в своих программах.
Схема клавиатуры.
Можно понять, как всё это работает, по схеме матричного сканирования дисплея и клавиатуры.
Всего этого достаточно, чтобы написать свою первую программу.
Эмулятор
Для тех, кто не может достать такое чудо чудное, существует бесплатный, программный эмулятор «Симулятор УМПК-80». Обращаю внимание, что это УМПК-80, но всё же он достаточно близок по архитектуре, хотя конечно же отличия есть. Главное его достоинство в том, что на нём можно даже отлаживать свои программы. И на первых этапах я использовал его как транслятор для программ.
Однако я столкнулся с тем, что у него есть ошибки в работе некоторых ассемблеровских инструкций, также если его свернуть, не всегда можно развернуть обратно и просто иногда бывает его вышибает с кучей сообщений. Тем не менее, это весьма классная штука, если хочется «пощупать».
Транслятор
На самом деле, в идеальном мире для этого аппарата пишется программа на ассемблере на листочке, затем по таблице системы команд процессора 8080, например, этой, программа переводится в машинные коды и затем уже переносится вручную в ЭВМ.
Меня достаточно быстро задолбало так делать (сделал одну минипрограмму), и я начал искать способы трансляции ассемблера. Одним из требований было — это устанавливать адрес начала инструкции. Это очень удобно, если какие-то куски программы могут меняться, а какие-то функции нет. Чтобы не перенабирать целиком всю программу, а только отдельные участки. Вообще, работа с этим аппаратом немного отличается от традиционного программирования, потому что ты «скомпилированную» программу правишь в машинных кодах «на лету».
Изначально, как уже сказал, использовал Симулятор УМПК-80 для компиляции программ, и да, это даже работало. Но во-первых, программа глючная, а во-вторых, она не позволяет делать отступы и размещать процедуры в произвольных областях памяти. Плюс, невозможно называть константы. Поэтому пришлось искать альтернативный вариант.
В результате поиска, я остановился на zasm. Для того чтобы его скомпилировать, необходимо выполнить следующие строки:
sudo apt install gcc g++ make automake git zlib1g-dev
git https://github.com/Megatokio/zasm.git
cd zasm
git checkout $(git tag | tail -n 1)
unlink Libraries
git clone https://github.com/Megatokio/Libraries.git Libraries
cd Linux
make
Далее zasm можно скопировать в удобное для себя место, например, в домашнюю директорию:
mkdir -p ~/bin
cp zasm ~/bin
Лично я скопировал его в папку с программами, где пишу код. Для того чтобы транслировать программу для нашего процессора, нужно выполнить:
./zasm --asm8080 test.asm
В результате после компиляции будет создан rom-файл с именем программы, в данном случае test.rom. Его содержимое можно посмотреть, например, с помощью hexdump:
hexdump test.rom -v -e '/1 "%02X\n"'
21
92
24
06
01
...
Но мне не понравился такой подход, потому что не пишутся адреса. Когда программа очень длинная, удобно сопоставлять строку с реальным адресом. В результате набросал программу на си, которая выводит код с реальными адресами.
#include
int main ( int argc, char *argv[] ) {
if ( argc != 2 ) {
printf( "usage: %s filename", argv[0] );
} else {
FILE *file = fopen( argv[1], "r" );
if ( file == 0 ) {
printf( "Could not open filen" );
} else {
int x;
int i = 0x0800;
while ( ( x = fgetc( file ) ) != EOF ) {
printf("%04x %02x\n", i++, (unsigned int)0x00FF & x);
}
fclose( file );
}
}
return 0;
}
Такой вариант намного удобнее для того чтобы переносить его в память УМК-80.
./print_prg test.rom
0800 21
0801 92
0802 24
0803 06
0804 01
...
Рекомендую документацию по zasm.
Пробная программа
Наверное я уже утомил теоретической частью, давайте же что-нибудь на нём сделаем. Самый простой вариант — это выведем на экран какой-либо символ.
Как вы помните из раздела по железу, для того чтобы вывести символ, нам нужно в порт F8 записать бит экрана (от 0 до 5 бита) и затем в порт F9 вывести символ. Давайте зажжём все светодиоды индикатора и запишем просто FF. После этого делаем безусловный переход в начало программы и повторяем её. Итого, программа будет очень простой:
m1:
mvi A, 01
out F8
mvi a, ff
out F9
jmp m1
Пробуем всё это скомпилировать zasm и у нас ничего не получается, потому что нужно всё оформить по красоте. Хотя в симуляторе она соберётся и можно машкоды взять из него. Но мы пойдём по правильному пути.
ORG 0800h
m1:
mvi A, 01h
out 0F8h
mvi a, 0ffh
out 0F9h
jmp m1
Указываем с какого адреса начинается программа: 0800h и указываем что переменные у нас в шестнадцатеричном формате (обратите внимание на формат записи). Можно теперь всё собрать и посмотреть программой на си.
Для того чтобы ввести программу, включаем наш чемодан. После жмём СБ (сбрасываем его). Нажимаем кнопку «П» (ввод программы), вводим адрес: 0800 и нажимаем пробел. У нас будет гореть приглашение к вводу программы:
Приглашение к вводу данных в память.
После ввода этой ячейки памяти, нажимаем пробел и переходим на следующую ячейку, пока не введём всю программу. По окончании нажимаем «ВП».
Для запуска, нажать клавишу «СТ», ввести стартовый адрес, в нашем случае 0800 и нажать «ВП». В результате получится светящийся всеми сегментами индикатор.
Выводим текст
Для того чтобы сформировать на индикаторах символы, необходимо их кодировать и сложить в памяти. У программы «Монитор» есть своя таблица, но без декодирования я не знаю где она лежит. Поэтому я воспользовался программой «Segment Code Generator».
Удобно выставить какому биту соответствует какой светодиод и формат кода вывода. На скриншоте выше стоит корректный вариант для УМК. Формируем коды для символов и размещаем их в памяти, далее будет динамическая индикация.
Набросаем тестовую программу:
ORG 0800h
start:
mvi b, 01 ; Стартовый бит дисплея
;регистр b указывает какой индикатор
mvi d, 08h ;откуда берём код индикатора
mvi e, 20h ;0820 (d+e)
m2:
call out_p
mov a, b
cpi 20h
jz start; если подошли к концу, то перейти на m1
rlc ; сдвинуть влево
mov b, a
inx d ;инкрементируем указатель на даннырый сделан очень добротно и воспитал большое количество хороших спее
jmp m2
out_p: ;подпрограмма вывода
mov a, b; регистр В хранит порядковый бит сегмента
out 0F8h; зажигаем соответствующий сегмент
ldax d ;загружаем в А содержимое по адресу ячейки D+E
out 0F9h
ret
ORG 0820h;Адрес с данными
DB 73h, 6Eh, 7Fh, 5Eh, 39h, 00h
Вначале мы загружаем в регистр B бит первого индикатора, в регистровую пару D и E — адрес, откуда брать данные.
Вызываем подпрограмму вывода данных, известную нам из прошлого примера. Только мы загружаем в регистр А данные по адресу, лежащему в регистровой паре D+E. Поскольку у нас все операции идут только с регистром А, то приходится в него загружать содержимое регистра B. 0×20 — это адрес последнего дисплея, если мы на нём, то сбрасываемся в начало. Если нет, то сдвигаем А влево и записываем B и делаем безусловный переход на метку m2.
Компилируем, выводим на экран и вбиваем в УМК код. Даже снял кинцо, как я вводил программу (конечно же не без ошибок, но кто не без греха, пусть бросит в меня камень). Можно оценить, как вводится код.
Далее идёт ручная проверка и корректировка по ходу пьесы.
В результате получим такую красоту:
РУВdС
Видна паразитная засветка, это потому что я не выдерживаю паузу между выводом на каждый индикатор, поэтому порт не успевает закрыться и немного подсвечивает соседний индикатор. Это хорошо видно на последнем, на котором отчётливо читается буква «С», хотя там ничего не выводится.
Паузу не стал добавлять, чтобы не переусложнять код.
Выводы
Игрушка просто потрясающая. Никогда ранее не программировал для процессоров i8080, и с архитектурой их был не знаком. Хотя писал на ассемблере для AVR, C51, x86, чуток для ARM. Но тут смутило, что всё делается через один регистр, что немного напрягает. С другой стороны, простота адресации, полная прозрачность, возможность редактировать программы налету прямо в машкодах — это просто потрясает. Получил просто невероятное удовольствие от разработки. Вообще, мне очень нравится писать на ассемблере, это полезно делать, чтобы мозг не зачах, как-то освежает, что ли.
В данной статье привёл только самые простые программы, потому что читатель просто уснёт от объёмов выкладок. Но, к сожалению, на таком стенде большие программы очень сложно отлаживать.
Для своего времени это великолепный обучающий стенд, который сделан очень добротно и воспитал большое количество хороших специалистов. Но сегодня он совершенно не актуален и не нужен. Некоторые могут возразить, мол принципы остались те же. Но нет, посмотрите архитектуры современных процессоров, вся эта возня в машинных кодах совершенно бесполезна и бессмысленна. Это всё равно что учить проектировщиков современных двигателей спортивных автомобилей, по учебникам постройки паровых двигателей для судов начала ХХ века. И там и там поршни, и там и там двигатель, и там и там идёт преобразование энергии и принципы схожи, но информация не актуальная, а может быть даже вредная.
Внимание розыск
Пользуясь случаем, хочу спросить у преподавателей и людей, которые имели опыт пользования этим устройством помощи в поиске документации на него. А также, быть может у кого есть описание интерфейсного разъёма и дочерней платы к нему:
Быть может у кого-то есть схема дочерней платы с интерфейсом RS-232 и программой? В целом я представляю, как её собрать самостоятельно, но зачем изобретать велосипед?
Может, кто подскажет, каким программатором сегодня можно прошить ПЗУ, для данного УМК, чтобы добавить свой функционал. За любую посильную информационную помощь буду очень признателен. Слишком мало информации в интернете.
Используемая литература
Так получилось, что информации очень мало, и многое собирал по крупицам, по всему интернету. Поэтому приведу список тех самых актуальных книг, которые у меня настольные, при работе с данным чемоданом. На деле, при поиске информации я перечитал около десятка книг.
- «Простейшая микро-ЭВМ Буреев» Л. Н., Дудко А. Л., Захаров В.Н. Книга, с которой я начал. Очень полезная в плане понимания что и как работает.
- «Методические указания по выполнению РГЗ» Рыбин А. А. — полезная книга, но примеры кода смотреть бессмысленно, потому что используют внутренние подпрограммы.
- «Цифровые и микропроцессорные устройства. Лабораторный практикум» Ю.В. Алхимов (2009 г).
- Микропроцессор 8080 — короткая заметка, со списком команд микропроцессора. Очень удобна в работе.
- Левенталь Л., Сэйвилл У. «Программирование на языке ассемблера для процессоров 8080 и 8085.» –М.: Радио и связь, 1987. — практически настольная книга. Очень классно изучать, как, например, передавать параметры в функцию и как возвращать обратно, ветвления массивы и т.д. Просто настольная книга.