вторник, 11 июля 2017 г.

Компьютер "Zиркон-Б"

Некоторое время назад я писал о своём проекте компьютера на базе ПЛИС (см. "Проект Янтарь"). Некоторое время этот проект занимал меня, но со временем душа стала просить чего-то более "физического". Все-таки работа с FPGA - это всё то же глядение в монитор и нажимание кнопок. После нескольких небольших проектов, вроде колесных роботов с мозгами на AVR-ах я решил сделать второй подход к компьютерной тематике. На этот раз я решил собрать компьютер из "обычных" микросхем. Мой выбор пал на легендарный процессор Z80, олицетворявший целую эпоху персональных компьютеров.

Надо сказать, этот "материал" поддался мне не сразу. Программа в компьютере (или даже прошивка для ПЛИС) имеет от собранной электрической схемы одно важное отличие. В компьютере не может быть так, чтобы конкретный оператор сложения в 17-ой строке начал сбоить из-за того, что был неаккуратно набран при вводе программы. Когда имеешь дело с электрическими схемами, подобного рода проблем не избежать. Очень весело было убить час, изучая логическую схему и программу прошивки, чтобы обнаружить, что проблема была из-за плохо воткнутого в гнездо проводка. Более того, из-за таких ошибок я умудрился угробить три процессора (благо, я купил их с запасом).

Однако после нескольких прототипов и экспериментов, мне удалось собрать на макетной плате компактный, но в то же время полнофункциональный компьютер со следующими характеристиками:
  1. Процессор Z84C00 (CMOS-вариант Zilog Z80) с тактовой частотой 2 МГц.
  2. 32 КБ ПЗУ
  3. 32 КБ статической ОЗУ
  4. Последовательный порт ввода-вывода для связи с Большим компьютером
Все это я назвал "Zиркон-Б". "Zиркон" - это потому что  Z80 + название какого-нибудь драгоценного камня, а "Б" - потому что это уже вторая конструкция в этом проекте.


Несмотря на всю простоту этой конструкции, у меня ушло достаточно много времени на то, чтобы её собрать и заставить стабильно работать. Зато я обогатился целым набором трюков, которые облегчили мне жизнь при конструировании этого компьютера:
  1. Для соединений я активно применял самодельные шины из проводов, "заточенные" под конкретное место в схеме. Это в разы снижает трудоёмкость монтажа и демонтажа схемы. 
  2. При подключении микросхемы статической памяти совершенно не обязательно соблюдать последовательность подключения адресных линий, т.к. читать и писать всегда будет только процессор. Это облегчает монтаж (можно шины использовать). Для ПЗУ это не работает, т.к. читает данные процессор, а пишет - программатор.
  3. Всю логику генерации управляющих сигналов я реализовал на микросхеме программируемой логики Atmel ATF16V8. Это позволило избежать клубка спагетти и оставить одну микросхему вместо трёх-четырёх.
  4. Весь ввод-вывод реализован на микроконтроллере Atmel Atmega32A. Это потребовало применить техническую хитрость, о которой я скажу ниже. Зато появилась возможность в дальнейшем расширять возможности системы за счёт программирования контроллера. Это жульничество, конечно, но на первых этапах позволяет сэкономить время.
  5. Для подключения микросхемы ПЗУ я на макетную плату посадил ZIF-панель. Держится так себе, но на порядок снижает количество вырванных из гнезд проводов при снятии микросхемы ПЗУ для перепрошивки.
  6. RC-осциллятор на базе триггера Шмитта (74HCT14) генерирует хороший тактовый сигнал только на небольших частотах (100-200 герц).

Подключение Atmega32 к процессору Z80:
Идея использовать контроллер для управления системой несет в себе большой потенциал развития системы, но требует некоторых ухищрений для своей реализации. Дело в том, что процессор Z80 в машинном цикле ввода-вывода даёт строго два такта, в течение которых устройство должно отреагировать. Микроконтроллер не успеет отработать функцию за два такта. Специально для работы с такими "медленными" устройствами в процессоре предусмотрен сигнал WAIT#. Если внешнее устройство подаст на него логический ноль, то процессор приостановит цикл обращения и будет ждать, пока сигнал не вернут в значение "1". Значит нам надо сделать так, чтобы контроллер, обнаружив обращение к себе, выдал нужный сигнал, так? Не так. Контроллер не успеет даже этот сигнал выдать, т.к. это тоже реализовано программно.

Чтобы выйти из ситуации необходимо применить аппаратное решение, которое бы "ловило" процессор в момент обращения к контроллеру. К счастью у меня была под рукой микросхема 74HCT74 - два D-триггера со сбросом и предустановкой. Один из триггеров я подсоединил к системе так, чтобы при обнаружении порога на сигнале выбора микроконтроллера (CE#), он защёлкивался и "держал" процессор. Когда контроллер завершал свои дела, он подавал триггеру сигнал на сброс и "отпускал" процессор.

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

Это решение - буферная микросхема 74HCT245, которая при "пропадании" сигнала CE# просто изолирует микроконтроллер от шины данных ровно тогда, когда надо.

Микросхема ATF16V8:
Эта маленькая микросхема стала для меня огромным подспорьем при разработке логических схем. Она достаточно проста и немногофункциональна (по сравнению с современными FPGA и CPLD), но сочетает в себе два важных свойства:
  1. DIP-корпус, который можно монтировать на макетной плате
  2. Поддержку широким спектром программаторов.
При этом в неё можно "зашить" комбинационную логическую схему, которую в ином случае пришлось бы "разводить" руками с использованием нескольких обычных логических схем 7400-й серии и кучи проводков со всеми вытекающими следствиями - комок "лапши" на макетной плате, случайные сбои из-за плохих контактов и невозможность уже на второй день разобраться в том, что же ты такого нагородил.

Программируется эта микросхема на весьма малоизвестном проприетарном языке CUPL.

Программирование:
Для программирования системы я применял сразу несколько инструментов. Прошивку микроконтроллера я писал при помощи Atmel Studio 7. Программы для самого компьютера я готовил при помощи набора инструментария SDCC, куда входят ассемблер и компилятор языка С.  Для программируемой логики есть старая программа WinCupl, заставляющая вспомнить с ностальгие времена Windows 3.11 и 95.

Для заливки программ в микроконтроллер, PLD и ПЗУ использую недорогой программатор WizardProg87i (судя по всему - российский клон китайского MiniPRO TL866), который умеет программировать много разных микросхем. Контроллер он умеет программировать некоторые микросхемы так же и через ISP-подключение, что позволяет программировать его без демонтажа с макетной платы. Конкретно, я так программировал Atmega32 (attiny в режие ISP этот программатор "не умеет").



Полный список компонент:

Вот полный список компонент, которые я использовал, чтобы собрать систему:
  1. Процессор Z84C00AB6
  2. 32K EEPROM Atmel AT28C256
  3. 128K SRAM Ultron UT621024-70LL (используется только 32К)
  4. Микроконтроллер Atmel ATMEGA32A
  5. Буфер 74HCT245 - 2 шт.
  6. Сдвоенный D-триггер 74HCT74
  7. Микросхема программируемой логики Atmel ATF16V8B
  8. Кварцевый генератор частоты 2 МГц.
  9. Адаптер USB<->UART Wavesahre FT232
  10. ZIF-панель SCL-28 (для монтажа ПЗУ).
  11. Макетная плата SYB-800
  12. Провода, резисторы - много.
Наполеоновские планы:
Как видно, на макетной плате осталось ещё больше половины места - есть куда расширяться. Следующие шаги, которые я планирую сделать для развития этого проекта:

  1. Добавить MMU, который позволит адресовать 1 МГ адресного пространства через механизм переключения банков.
  2. Добавить поддержку SD-карты.
  3. Воткнуть "нормальный" UART вместо микроконтроллера.
  4. Сделать самодельный VGA-адаптер
  5. Собрать механическую клавиатуру с закосом "под старину" - клавиатуры старых компьютеров в до-IBM-PC-шную эпоху