Возвращаясь к компьютеру Z80: 6 шагов
Возвращаясь к компьютеру Z80: 6 шагов
Anonim
Возвращаясь к компьютеру Z80
Возвращаясь к компьютеру Z80
Возвращаясь к компьютеру Z80
Возвращаясь к компьютеру Z80

В прошлом я написал руководство о том, как построить компьютер на базе Z80, и спроектировал схему как можно более упрощенной, чтобы ее можно было построить как можно проще. Я написал небольшую программу, используя ту же идею простоты. Этот дизайн работал неплохо, но мне он не совсем понравился. Я начал с того, что переписал для него программу, которая позволяла программировать ее во время выполнения. Это было сделано для того, чтобы я мог тестировать фрагменты кода без необходимости выделять его для EEPROM, что, в свою очередь, потребовало бы от меня перепрограммирования EEPROM. Мне это не показалось забавным. Затем я начал думать о пространствах памяти. Если бы я хотел связать часть оборудования (в основном, ввода-вывода), фрагмент кода потенциально мог бы превысить объем памяти, доступной для системы. Помните, что в схеме использовался только младший байт адресной шины, а затем младший бит старшего байта использовался для выбора между пространством ПЗУ и ОЗУ. Это означало, что у меня было всего 253 байта свободного места. Вы можете спросить, почему 253 вместо 256. Это потому, что мой новый код вводит три байта данных в конце написанной программы (это будет рассмотрено позже, поскольку я модифицировал его для работы над новым дизайном).

п

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

п

Если вы последовали моему первоначальному сообщению и планируете следовать этому, вы меня возненавидите. Если вы начинаете с нуля, значит, вам повезло. Просто возьмите части из списка (или их эквиваленты) и следуйте им.

Запасы:

LM7805 - регулятор 5 Вольт Z80 - ЦП; мозги системы AT28C64B - EEPROM. «Постоянное» хранилище данных, используемое для прошивки компьютера IDT6116SA - SRAM; используется для хранения кода пользователя и / или общего хранилища данных NE555 - Системные часы 74HC374 - Восьмеричный D-Latch с / OE; в качестве входа использована микросхема 74LS273 - Octal D-Latch с / MR; Микросхема вывода TLC59211 - микросхема драйвера светодиода (используется для управления светодиодами 74LS273, поскольку она сама по себе не может выдавать ток) MC14572 - Это микросхема «Line Driver», но я обнаружил, что она идеально подходит для логики управления памятью. Он имеет 4 инвертора и встроенный логический элемент NAND и NOR 74LS32 - Quad OR gateCD4001 - Quad NOR gateCD4040 - 12-ступенчатый счетчик пульсаций; Нарисованный, но не реализованный делитель тактовой частоты (для работы системы на более низких тактовых частотах) 2 резистора 10 кОм - один используется в схеме таймера 555, поэтому используйте любое значение, которое вы хотите для него 4 резистора 1 кОм - один используется для 555, так что используйте для этого все, что захотите. Другой используется для управления светодиодами, поэтому измените его, если вы хотите, чтобы шина резистора 8x330 Ом 8 светодиодов шины резистора 10 кОм 11 - три используются для состояния системы, а остальные восемь являются выходами. Для 8 я использовал гистограмму (HDSP-4836). 4 конденсатора - два используются в LM7805; 0,22 мкФ и 0,1 мкФ. Один для таймера 555, так что используйте то, что считаете правильным. Последний - для сброса при включении; 100 мкФ2 Н. О. Кнопки - одна используется для ввода, другая для сброса 8 DIP-переключателей SPST - ввод данных; Я использовал стиль Piano Key styleWire. Много-много проволоки

п

ПРИМЕЧАНИЕ. Версия MC14572 со сквозным отверстием устарела, но версия SMD все еще активна (даже не для статуса «не для нового дизайна»), поэтому вам может потребоваться приобрести печатную плату, чтобы вы могли ее использовать. Второй 74LS32 может использоваться вместо MC14572 (см. Схему «Схема выбора памяти» в предыдущем документе).

Шаг 1. Краткий обзор изменений + схемы

Краткий обзор изменений + схемы
Краткий обзор изменений + схемы

Как читать схемы: Стрелка, направленная на микросхему, является входом: Вход> -Стрелка, направленная от микросхемы, является выходом: Выход <-Шины используют линию вместо стрелки: Шина | -

п

Большинство фишек нарисовано с точной распиновкой. На этих фишках нарисовано небольшое углубление. На большинстве микросхем также есть номера контактов и метки. Их может быть немного трудно читать. Карандаш у меня затупился.

п

Что касается схемных соединений, компоновка нового дизайна в основном не отличается от оригинала. Я подключил младший полубайт старшего байта адреса к памяти, а затем использовал младший бит старшего полубайта (A12) для выбора RAM / ROM. Это означало, что объем ПЗУ изменился с 0000-00FF до 0000-0FFF. Пространство RAM изменилось с 0100-01FF на 1000-1FFF. Я также поменял местами логику управления памятью для лучшего дизайна и добавил два новых светодиода состояния (и некоторую логику клея). Я также нарисовал (но не подключал) схему делителя часов. Он должен был выполнять две функции. Очевидная функция - уменьшить тактовую частоту. Другая функция предназначена для ШИМ (широтно-импульсной модуляции), поскольку 555 не генерирует волны с коэффициентом заполнения 50%. В этой схеме это не имеет значения, но если вы захотите использовать часы для управления некоторыми светодиодами, вы обязательно заметите эффекты (один (набор) светодиодов будет тусклее, чем другой). Вся остальная схемотехника практически не изменилась.

Шаг 2: ЦП, память и управление памятью

ЦП, память и управление памятью
ЦП, память и управление памятью
ЦП, память и управление памятью
ЦП, память и управление памятью
ЦП, память и управление памятью
ЦП, память и управление памятью
ЦП, память и управление памятью
ЦП, память и управление памятью

Это та часть, где читатели моей предыдущей версии меня ненавидят. В первоначальной сборке я просто как бы бросал детали на плату в таком месте, которое выглядело так, как будто не создавало особых проблем с подключением. Результат выглядел так, будто кто-то бросил на него тарелку со спагетти, и это было похоже на «провода!» Я хотел немного его почистить, поэтому начал с копирования всего, кроме ЦП, ОЗУ и ПЗУ. Я вытащил почти всю входную цепь, выходную цепь и склеивающую логику. Мне было почти больно это делать, но это было необходимо. Я оставил нетронутыми все соединения для передачи данных и младший байт адресной шины. Затем я подключил следующие четыре бита адресной шины (A8-A11) к микросхеме ПЗУ. На этот раз я постарался обойти чип, чтобы его было легче подтянуть для перепрограммирования. Я также перебросил адресные соединения на микросхему RAM.

п

Разобравшись с этим, мне нужно было подключить логику управления памятью. В исходной схеме я подключил линию процессора / MREQ непосредственно к / CE к обеим микросхемам памяти, а затем подключил / WR к / WE ОЗУ. Затем у меня были логические ИЛИ / RD и / MREQ ЦП, а также A9. По сути, он был настроен так, что все запросы к памяти активировали как ОЗУ, так и ПЗУ, но A9 использовался для выбора, какой из чипов / OE будет выбран. Это было нормально, и все потому, что микросхемы оставались неактивными до тех пор, пока не был сделан запрос памяти, а затем только один / OE был бы активен во время запроса на чтение. Это предотвратило перекрестные помехи, но внесло неудобный нюанс. Поскольку A9 использовался только для определения того, какой из чипов выводил данные, и поскольку ЦП имел прямой доступ к выводу RAM / WE, любые запросы записи будут проходить. Это было нормально для ПЗУ, потому что его режим записи запрещен подключением / WE напрямую к источнику питания 5 В. ОЗУ, однако, будет записываться независимо от A9. Это означало, что попытка записи в место в ПЗУ будет записывать в то же место в пространстве ОЗУ.

п

Одним из решений для этого может быть изменение схемы управления так, чтобы ЦП имел прямой доступ к контактам / OE и / WE микросхемы, а затем с помощью MREQ и A12 выбрать, какие микросхемы / CE будут управляться. Я поддержал эту идею, но вместо использования четырех вентилей NOR и инвертора, как в оригинальной конструкции, я нашел неудобный маленький чип, который идеально подходил для этой задачи. Мне пришлось создать схему, в которой использовались только логические элементы, имеющиеся в микросхеме, но это было достаточно просто. A12 подается непосредственно в ворота NAND и NOR. / MREQ подается в ворота NOR, а его дополнение передается в ворота NAND. Логический элемент NAND используется для управления / CE для RAM, а выход NOR инвертируется и используется для управления ROM / CE. Это делает так, что / MREQ должен быть низким до выбора любого чипа, а затем A12 выбирает, какой из них будет выбран. При такой настройке теперь любые запросы на запись в ПЗУ не будут делать ничего. Это также экономит электроэнергию, потому что активен только один чип вместо обоих. Что касается самой логической микросхемы, у нас все еще есть два неиспользуемых инвертора. К одному привыкнешь позже, но мы доберемся туда, когда доберемся.

Шаг 3. Светодиодные индикаторы состояния системы

Светодиодные индикаторы состояния системы
Светодиодные индикаторы состояния системы
Светодиодные индикаторы состояния системы
Светодиодные индикаторы состояния системы

Перед тем, как я начал этот проект, я пытался взаимодействовать с определенной ИС, но у меня были проблемы с этим. Неуверенный в том, что происходит, я использовал светодиодный индикатор для монтажа на панели (одна из тех сборок, в которые встроен резистор). Это натолкнуло меня на ностальгическую идею, которая используется до сих пор: светодиоды состояния используются для индикации того, выполняется ли чтение из памяти или запись в нее. Он должен был использоваться вместе с уже имеющимся у меня входным светодиодом. Светодиод входа был подключен к генератору сигнала / WAIT, чтобы указать нам, что система … ну, ожидает ввода (я доберусь туда, не беспокойтесь). Я подумал о добавлении светодиода для индикации записи ввода-вывода, но решил, что изменение выходных светодиодов уже будет отличным индикатором этого. Подумав, могу еще добавить. Тем не менее, я считаю полезным знать, читается ли память или записывается. В любом случае, это полезно для отладки программ. На самом деле я активно использовал его как таковой, пытаясь заставить мою программу работать: «Почему она записывается в память? Этого еще не должно быть!"

п

Для управления этими светодиодами я использовал четырехъядерный вентиль ИЛИ-НЕ. Я использовал все ворота. Только два из них использовались для генерации сигналов состояния, но у микросхемы нет мощности для фактического управления светодиодами. Они способны потреблять такую большую мощность, поэтому я использовал два других элемента NOR в качестве инверторов и подключил светодиоды как таковые. Поскольку один светодиод используется для индикации чтения, а другой - для записи, а запросы на чтение и запись не будут выполняться одновременно, мне удалось использовать только один резистор для обоих светодиодов. Что касается сигналов, которые мне нужно было декодировать, это тоже было достаточно просто. Я хотел, чтобы все запросы на чтение из памяти отображались, поэтому первый вентиль NOR имел / MREQ и / RD на своих входах. Статус записи был немного сложнее, но так же легко. Я по-прежнему использовал / MREQ в качестве одного входа, но использование / WR в качестве другого вызовет незначительный нюанс, которого я хотел бы избежать. Это указывало бы на ВСЕ запросы на запись. Я хотел только те, которые действительно прошли. Так как бы мне это сделать? Ну, помните, как я настроил систему, чтобы можно было писать только в ОЗУ? Я использовал RAM / CE в качестве другого входа в вентиль NOR. Это означает, что светодиод будет гореть только тогда, когда выбрано ОЗУ и выполняется запрос на запись. Что касается цвета светодиода, я выбрал оранжевый в качестве индикатора чтения (но я нашел только желтые) и красный в качестве индикатора записи.

Шаг 4: ввод и вывод

Вход и выход
Вход и выход
Вход и выход
Вход и выход
Вход и выход
Вход и выход

На предыдущем шаге вы могли заметить, что я уже добавил некоторые остальные компоненты на плату. Я зарезервировал место, чтобы случайно не разместить провода там, где мне нужен компонент (таким образом, мне пришлось бы найти новое место для указанного компонента). Вы также могли заметить, что я оставил входные переключатели на месте и подключил их к шине питания. Я решил, что исходное место было идеальным местом, и решил разместить выходные светодиоды поблизости (вверху). Справа от индикатора находится входная защелка. Выше находится выходная защелка, а слева от нее - драйвер светодиода. Я начал с подключения дисплея к драйверу, так как это было проще всего. Затем я подключил переключатели к входной стороне входной защелки. Затем я подключил выходную часть выходной защелки к драйверу светодиода. Это может показаться неудобным приказом подключить их, но на то была причина. Вход выходной защелки должен был быть подключен к шине данных, а также выход входной защелки. Идея заключалась в том, чтобы соединить выходы входной защелки с входами выходной защелки, что я и сделал. Тогда все, что мне нужно было сделать, это подключить этот беспорядок к шине данных. Не имело значения, где эти соединения находились физически, потому что все они были электрически связаны. Компьютер почти готов.

Шаг 5: сброс и завершение ввода и вывода

Извините, для этого шага нет фото. Обратитесь к предыдущему шагу для картинок.

п

Возможно, вы заметили на последней картинке предыдущего шага, у меня была зеленая кнопка и установлен еще один логический чип. Фишка - это вентиль ИЛИ. Два шлюза используются для генерации сигнала / WAIT. Ну, один генерирует сигнал с помощью OR-ing / IORQ и / RD от процессора. Выходной сигнал подается на второй вентиль, где он снова получает ИЛИ на кнопку. Кнопка устанавливает высокий уровень на входе затвора, тем самым повышая уровень выхода. Этот вывод подается на вывод процессоров / WAIT. Пока он не нажат, резистор удерживает на входе низкий уровень. Сначала я использовал резистор 10 кОм, но LS32 фактически подавал напряжение на входе. Резистор не опустил его достаточно низко, и мне пришлось заменить его на 1К. В любом случае, идея состоит в том, что при запросе чтения ввода-вывода первый и второй логические элементы ИЛИ приказывают процессору подождать. Как только вы установите переключатели входа в любое положение, вы нажимаете кнопку, и это выводит ЦП из состояния ожидания. Зеленый светодиод «input», как я назвал его на предыдущем шаге, подключен так, что когда на выводе / WAIT устанавливается низкий уровень, он загорается.

п

Но мы еще не закончили. Входному триггеру необходим сигнал, чтобы он знал, когда вводимые данные действительны и должны быть отправлены в ЦП. Этот тактовый вывод активен на высоком уровне. Раньше мы просто подключали его к кнопке. Это все еще допустимый вариант, но на этот раз я решил поместить его на тот же выход, что и второй вентиль ИЛИ. Эта микросхема также имеет вывод / OE, который необходимо запустить. Если бы он был на высоком уровне, он никогда не вставил бы данные в шину. Если его держать на низком уровне, он всегда будет управлять автобусом. Чтобы исправить это, я просто использовал третий вентиль OR. Входами являются / IORQ и / RD, а выход идет непосредственно на / OE защелки.

п

Выходная защелка также требует, чтобы тактовый штифт приводился в действие. Опять же, активный высокий. В моей схеме я нарисовал четвертый логический элемент ИЛИ, напрямую управляя выводом, используя / IORQ и / WR. Это означало, что тактовый вывод будет удерживаться в высоком уровне до тех пор, пока не будет сделан запрос на запись, затем он будет сначала понижаться, а затем снова повышаться. Это, вероятно, было бы хорошо, потому что шина данных все еще содержала бы действительные данные на ней сразу после попытки записи, но с инженерной точки зрения это был мусор. Я не заметил эту ошибку до тех пор, пока не сделал последние фотографии, но я разорвал это соединение, а затем подал выход логического элемента ИЛИ в один из неиспользуемых инверторов из логики управления памятью, а затем подключил его выход к тактовому выводу.. Я также исправил схему и обнаружил еще одну сделанную мной ошибку. Я тоже поправил.

п

Когда все это, наконец, было сделано, мне предстояло выполнить очень небольшой объем работы: схему сброса. Я добавил кнопку на плату и использовал резистор 10 кОм, чтобы удерживать одну сторону высоко. Другая сторона идет прямо на землю. Сторона с высоким уровнем - это выход / RESET, который поступал на каждую микросхему с контактом / RESET (ЦП и выходная защелка). Чтобы выполнить сброс при включении питания, я добавил конденсатор к выходу / RESET. Идея состоит в том, что резистор большого номинала заставит относительно большой конденсатор медленно заряжаться и удерживать контакты / RESET на низком уровне в течение некоторого количества тактовых циклов (процессору требуется четыре тактовых цикла). Вы, наверное, уже догадались, в чем отрицательная сторона этой схемы. Он такой же отрицательный, как и в предыдущей версии, потому что это та же схема. Когда кнопка нажата, конденсатор по существу закорачивается через кнопку. Это плохо как для крышки, так и для кнопки, поэтому, если вы хотите сделать свою сборку более постоянной, вы можете изменить ее дизайн. Я думал о другом таймере 555, настроенном в моностабильном режиме. Но на этом компьютерная схема закончена. Ура. Теперь это нужно запрограммировать.

Шаг 6: программирование

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

п

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

п

Инициализация просто устанавливает некоторые значения регистров для использования программой. Программный цикл немного сложнее, но не намного. Сначала он принимает входные данные в регистр A порта 00. Затем регистр E записывается в память. В первых двух циклах регистр E содержит ненужные данные, поэтому мы пытаемся записать их в последние два байта пространства ПЗУ, потому что на самом деле они не будут записаны; указатель адреса (IY) затем увеличивается. Значение, хранящееся в D, затем перемещается в E, чтобы записать следующее. Затем A загружается в D, а L и E копируются в H. HL - это место, где происходит сравнение значений путем вычитания и проверки ZF (нулевой флаг). Первое сравниваемое значение сохраняется в регистрах B и C. B и C обрабатываются как один 16-битный регистр BC. Если значения совпадают, программа переходит прямо в пространство ОЗУ, где, как предполагается, находится пользовательский код. Если код в BC не соответствует, то HL перезагружается с начальными значениями из D и E и снова сравнивается со значением в SP так же, как это было по сравнению с BC. Если совпадение, результат будет тем же, но в память записываются три дополнительных байта. Байты - это код, который заставляет ЦП возвращаться к самому началу своей программы (программный сброс). Однако, если второе сравнение не дало совпадения, программа переходит к тому месту, где она получает значение от пользователя.

п

LD SP, EDBFH; exe-код (добавляет прыжок)

п

LD IY, FFEH; указатель начальной памяти для хранения кода

п

LD BC, EDC3H; код exe (без цикла)

п

петля; директива ассемблера, поэтому нам не нужно знать, где в памяти находится эта часть

п

IN A, (00H); получить данные программы

п

LD (IY + 00H), E; E содержит код для сохранения

п

INC IY; перейти к следующей ячейке памяти

п

LD E, D; ld D в E

п

LD D, A; ld A в D

п

LD H, E; ld E в H

п

LD L, D; ld D в L

п

ИЛИ A; сбросить флаг переноса

п

SBC HL, BC; возвращает 0, если был введен exe-код 2

п

JP Z, 1000H; если да, перейдите к программе и выполните ее

п

LD H, E; в противном случае обновите их до правильных значений

п

LD L, D

п

ИЛИ A; первое вычитание могло установить флаг переноса. Очистить это

п

SBC HL, SP; возвращает 0, если был введен exe-код 1

п

JP NZ, петля; если нет, повторите процесс (начиная с получения значения)

п

LD (IY + 00H), C3H; в противном случае введите код перехода в конце пользовательской программы

п

LD (IY + 01H), 00H; прыжок в основном действует как программный сброс

п

LD (IY + 02H), 00H; это полный сброс в случае изменения регистров

п

JP 1000H; перейти к пользовательской программе и запустить ее