Недавно я закончил реализацию своего хобби-проекта по воссозданию IBM-PC XT из 80-х годов на основе оригинальных деталей с использованием современных технологий. У меня была чёткая цель: возможность играть на этом ПК в EGA-версию Monkey Island 1 со всеми примочками. То есть мне нужна была поддержка мыши, жёсткий диск с возможностью записи для сохранения игры и версия озвучки через карту Adlib, которая мне нравилась больше всего.

Эта задумка у меня возникла, когда я узнал о существовании маломощной вариации Intel 8088, который использовался в XT. Низкое энергопотребление значительно упрощает подключение процессора к ПЛИС, ввод-вывод которой обычно работает на 3,3 В. Всё это вкупе с маломощной микросхемой SRAM на 1 МБ (CY62158EV30), призванной обеспечить XT его 640 КБ памяти, и стало основой для будущей системы.

Начал я с проектирования аппаратной части, которая затем послужила в качестве макетной платы при реализации ПО и gateware. Что я в итоге добавил:

  • сокет DIP-40 для маломощного процессора NEC V20;

  • микросхему SRAM на 1 МБ в качестве системной памяти;

  • плату ПЛИС icesugar-pro с Lattice LFE5U-25F;

  • двойной разъём PS/2 для подключения клавиатуры и мыши;

  • гнездо для карты micro SD, выступающей в роли жёсткого диска;

  • аутентичный ЦАП YM3014B;

  • пьезодинамик для системных звуковых сигналов, управляемый через программируемый интервальный таймер (programmable interval timer, PIT);

  • а также кнопку сброса и пару светодиодов для индикации состояния.

Всю схему я начертил в программе EasyEDA CAD, так как уже с ней знаком, и она хорошо интегрируется с сервисом сборки печатных плат JLCPCB. К стороннему сервису я обратился, поскольку паять вручную некоторые компоненты было бы слишком сложно. Хотя мне всё же пришлось впаивать микросхемы SRAM, так как у LCSC их не было, и я заказал эти детали в другом месте.

Первым шагом стало написание контроллера шины для процессора. Тактовый генератор V20 менее требовательный, чем у исходного i8088, так как позволяет снижать частоту вплоть до 0 Гц и использует стандартный рабочий цикл, равный 50%. Механизм работы внешнего интерфейса Intel 8080 основан на циклах шины. В начале цикла процессор активирует определённые выводы, сообщая другим устройствам, что он собирается сделать… считать память, отправить данные на ввод-вывод и так далее. Каждый тип цикла шины соответствует конкретной последовательности событий, которые происходят в течение нескольких тактов. Было несложно создать конечный автомат, способный обнаруживать начало цикла шины, определять его тип и создавать или потреблять данные в соответствии с задачей процессора. Главным здесь было обеспечить выполнение всех требований тайминга, чтобы сигналы, которые процессор генерирует, «снимались» в правильное время, а те, которые он ожидает, правильно подавались ему к моменту их считывания.

Пример диаграммы тайминга цикла записи данных в память
Пример диаграммы тайминга цикла записи данных в память

В качестве первого теста контроллера шины я написал на NASM простенькую программу под V20 с одной целью помигать светодиодом, привязанным к адресу порта ввода-вывода. Вроде и просто, но мигание светодиодом можно назвать аппаратным эквивалентом программного «Hello, world». В самой первой версии программа просто загружалась в блочную RAM ПЛИС и использовалась непосредственно как часть системной памяти.

Позднее я реализовал доступ к памяти более продуманным образом. К примеру, BIOS загружалась в блочную память ПЛИС, чтобы процессор выполнял чтение памяти оттуда, а не с системного чипа SRAM. А вот видеопамять реализована иначе. Запись процессор выполняет и в блок видео памяти, и в системную SRAM, но чтение всегда производит только из SRAM. Это также означает, что мне доступен свободный порт чтения в блоке видеопамяти, который можно использовать генератором VGA-сигналов для вывода содержимого этой памяти.

После успешной реализации мигания я установил вместо BIOS виртуальную копию Supersoft/Landmark Diagnostic ROM и написал простой CGA-адаптер для вывода видео. Затем я использовал диагностическую ROM для тестирования интерфейса SRAM, а также некоторой необходимой XT периферии, например programmable-interval-timer (i8253) и programmable-interrupt-controller (i8259).

Убедившись в стабильности базовой системы, я заменил диагностическую ROM стандартной XT BIOS с https://www.phatcode.net. Было удивительно наблюдать, как BIOS начинает загружаться и… жалуется на отсутствие загрузочного диска.

Для доступа к «диску» я создал на Verilog небольшой контроллер, который сделал доступным процессору через свободные порты ввода-вывода. Затем я написал option ROM для обработки вызовов BIOS INT13H (дисковая служба), в которой были процедуры для отправки команд на SD-карту через SPI. Непростой задачей оказалось изучение используемого SD-картой протокола и написание кода ассемблера под 8088 для выполнения корректных операций. Сам же процесс сопоставления оказался несложен, так как и SD-карта, и DOS оперируют секторами по 512 байт.

При написании option ROM я много времени сэкономил за счёт разработки и отладки кода с помощью самодельного программного эмулятора платы. Часть истории его создания можно найти на GitHub.

Самым же сложным во всём проекте оказалось, как ни странно, заставить работать мышь. Мыши из эпохи XT обычно подключались к последовательному порту UART. Я же разместил на плате разъём PS/2, и у этих мышей уже совсем другой протокол. В своих попытках подключить хвостатую я начал изучать матчасть по устройствам PS/2. В итоге выяснялось, что мне потребуется реализовать намного более сложный контроллер клавиатуры, а ещё и то, что используемая BIOS не поддерживает столь современную периферию. Я чувствовал, что моих знаний для всего этого не хватит.

Всё усложняется тем, что PS/2 это двунаправленный протокол, и компьютер должен опрашивать мышь для получения от неё обновлённых данных. Предполагаемая сложность начинала выходить за рамки желаемой. Вот с клавиатурой, напротив, работать относительно легко, просто отправляя сигналы нажатия клавиш, без опроса.

Тогда я пошёл альтернативным путём написал на Verilog код для прямого взаимодействия с мышью PS/2, который на раннем этапе загрузки заставлял её начинать передачу событий так, будто их запрашивают. В итоге, когда мост получает эти события, он их транслирует и передаёт компьютеру через псевдо-UART. То есть я реализовал простой мост для преобразования сигналов PS/2-мыши в сигналы Serial-мыши. Получилось немного запутанно, но работает исправно.

В ходе этого процесса пришлось вскрыть запасную мышку, чтобы подключить логический анализатор к её площадкам clk и dat. Это позволило мне перехватывать данные взаимодействия мыши с ПК и мониторить их. Так я получил ценную информацию о фактической работе протокола и выяснил, что конкретно ожидала получить реальная мышь.

Я также узнал, что наличие перед глазами графика формы сигнала намного упрощает тестирование компонентов в verilator (симулятор Verilog), так как я мог подробно смоделировать сигналы, которые мышь должна видеть при работе на ПЛИС.

Чтобы лучше понять протокол PS/2, мне пришлось вручную разметить график формы сигнала
Чтобы лучше понять протокол PS/2, мне пришлось вручную разметить график формы сигнала

Как и в XT, здесь один из каналов PIT используется для подачи через внутренний динамик простых звуковых сигналов. Я расширил эту функциональность, сделав так, чтобы при доступе к «диску» на динамик передавались короткие импульсы, создавая грубую звуковую эмуляцию движения головки. Думаю, опыт работы становится намного аутентичней, когда ты слышишь, как компьютер «обдумывает» выполняемые задачи. Что же касается музыки, то здесь встроенный динамик быстро теряет своё очарование. Написать реализацию YM3812 (FM-микросхема, которая использовалась в картах Adlib) мне не под силу, но Хосе Техада уже создал прекрасную опенсорсную версию, которая прекрасно подошла в мой проект.

Я же написал на Verilog небольшой модуль для получения генерируемых этой программой данных PCM и преобразования их в нестандартный формат с плавающей запятой 3:10, который требуется ЦАП YM3014 на моей плате. Это очень похоже на работу реального железа Adlib, когда YM3812 генерирует и отправляет последовательные аудиоданные на ЦАП YM3014. Возможно, современный ЦАП I2S работал бы чище, но мне было интересно поиграться именно с оригинальным устройством. В результате мне удалось добиться того самого приятного и чёткого FM-звука, который так меня радовал за игрой на ПК в детстве.

В YM3014 используется 10-битный ЦАП, передающий данные в 3-битный делитель для расширения динамического диапазона
В YM3014 используется 10-битный ЦАП, передающий данные в 3-битный делитель для расширения динамического диапазона

Здесь я не затронул многие другие элементы проекта, такие как поддержка CGA и EGA графики. Я реализовал даже мост USB-UART для отправки файлов с ПК-хоста прямиком на SD-карту. Ещё я выточил на станке с ЧПУ прозрачные акриловые панели, чтобы завершить общий дизайн и защитить плату.

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

Кому интересно, исходный код, схема и Gerber-файлы лежат на GitHub. Спасибо за чтение!

Комментарии (1)


  1. Ilya_JOATMON
    23.11.2025 10:03

    Есть еще проект PCXT для Mister Fpga.