У меня был доступ к последним Qwen, GLM и Sol. Рядом лежали аккаунты ко всяким Claude c Astra. Не то, чтобы все это реально требовалось для разработки эмулятора ZX-Spectrum, но остановиться было тяжело. В итоге эмулятор получился просто на загляденье и вы можете прочитать про боли и решения в реальном проекте.

TL;DR: Да, за год БЯМки сильно подросли в своих умениях. Сегодня я смело могу утверждать, что по своему уровню они достигли джунов. Если убрать скорость и стоимость за скобки, то это почти настоящие кожанные мешки. Почему почти? Настоящий кожанный мешок не обладает такой широтой знаний. Но зато умеет творить. Про пруфы читать ниже (смаил).

Практически год назад я написал статью (https://habr.com/ru/articles/956344/), как я писал эмулятор ZX Spectrum на go. Потом полгода назад (https://habr.com/ru/articles/962612/) жаловался, что golang уж очень неподходящий язык для эмуляторов. И вот теперь я опровергаю сам себя…

После того, как я (хорошо, мне) переписал эмулятор на C++, во мне поселился червячок сомнения. Ну ладно, я выяснил, что микрофризы убивающие геймплей были из-за тотального буферизирования везде и всюду. Но ведь можно же убрать эти буферы и тогда эмулятор заживет хорошо и счастливо?

Так как по условию первоначальной задачи я тупой синьор, хоть местами и образованный, то решил применять тактику “разделяй и властвуй”. То есть накачал исходных кодов эмуляторов, рядом положил оба своих и попросил qwen нарисовать мне архитектуру новой версии эмулятора. Дескать, чтобы было всё хорошее, а ничего плохого не было. Он написал здоровенный ARCHITECTURE.md и предложил начать реализацию. Я же в ответ поступил очень подло: даже не глядя внутрь, дал этот файл GPT и попросил проревьювить “то, что я написал за ночь в раздумьях”. Естесственно, тот радостно обругал меня за использование плохих методик и поправил формулировки.

Думаете, на этом началась реализация? Нетушки, следом ревьювить архитектуру отправились sol с deepseek’ом. И вот уже после них я соизволил удостоить их писанину своим барским взглядом. Как ни странно, но особых претензий я к файлу высказать не смог. Посмотрел на историю: джуны довольно быстро перешли от обычной машины состояний, обернутой в спагетти код (привет первым версиям), к нормальной блочной эмуляции каждого компонента. Немного поразмыслив (ведь сразу соглашаться нельзя, уважение потеряю), я дал отмашку на реализацию.

Первым честь писать код выпала deepseek и он довольно быстро перетащил реализацию Z80 и сделал обвязку по шине, портам и памяти. Sol немного покритиковал его и перенес код ULA и клавиатуры. В итоге буквально за пару часов у меня появился эмулятор, который умел сохранять картинки с сакраментальным “(С) 1982 Sinclair Research Ltd”.

И вот тут я притормозил. Второй раз наступать на грабли с микролагами мне не хотелось. А значит что? Значит очередной запрос во все БЯМки с предельно жесткими условиями на выход: разобраться отчего и почему и что делать дальше. После очередных сожженых миллионов я получил исчерпывающий ответ: “Кожанный мешок, ты идиот. Использовав fyne в качестве библиотеки для фронта, ты наступил на все грабли. Не надо так, а надо использовать SDL2. А лучше SDL3”. Оказалось, что внутри fyne есть еще куча буферов, которые буферизируют буфера. И вот это вот все великолепие и дало мне ложные утверждения для предидущих статей. В самом деле, для обычной десктопной программки практически нет никакой боли в 100 миллисекунд задержки для какого-нибудь пика или начала музыки. А для игры – есть.

Ок, взяли в качестве библиотеки для фронта SDL3 и работа закипела. Агенты агентились, харнесы харнесились и через некоторое время я обнаружил, что моя сеньористая роль главного разработчика внезапно превратилась в QAшника, причем недоджунистого. Я тупо пускал эмулятор раз за разом, тыкал кнопки и сообщал назад, что не так. А это боль и недоразумение.

Недоразумение это я решил очень простым способом: дал первому попавшемуся deepseek’у задачу написать MCP сервер. Получилась довольно развесистая система виртуализации спектрумов и всего на их основе. БЯМки подключаются, компилируют, сравнивают чего-то с чем-то и радостно идут править ошибки. После пары промптов в духе “Делайте что угодно, лишь бы работало и отвалите от меня” они добрались до пошагового исполнения, притащили дизассемблер, следом простенькую OCR и очень быстро допинали эмулятор до состояния “вот есть эмулятор, он умеет читать образы кассет и играть музыку”. Говоря другими словами, полностью повторили версию эмулятора на С++, только уже на более качественном уровне.

Модельки научились распознавать экран
Модельки научились распознавать экран

Следующим шагом стала реализация дискового контроллера. Казалось бы WD1793, он же КР1818ВГ93 это очень старая штука и реализовать ее проще простого. Берем даташиты, проверяем что они с текстом, а не картинками, добавляем карту распределения портов и вперед, твори! И вот тут все БЯМки показали свои отличия от кожанных мешков. Ни одна не смогла ни выдать реализацию, ни найти ошибки у попыток другой. Вообще полный ноль по всем фронтам, обсыпанный горами токенов. Даже всячески нахваливаемые модели, которые где-то там ломали стенды и решали математические теоремы отделывались каким-то бредом.

Раз кожанным мешкам бояться нечего, я добавил им в качестве референса код других эмуляторов. Дескать, смотрите и учитесь, ламеры набайченные. Модельки радостно ответили “ну вот теперь другое дело”, нафанили агентов и быстренько перерисовали всё необходимое. Красивое, проходящее все ими же написанные тесты, но не работающее.

Так как я в жизни видел работающий спектрум с дисками только издалека, то пришлось читерить: пускать другие эмуляторы и смотреть, что должно происходить. Потом переваривать и скармливать эти сокровенные знания БЯМкам. Надо отдать должное, они довольно быстро смогли прийти к выводу, что в МСР нужен ввод с клавиатуры и реализовали его. Но как же долго их корежило от того, что они не могли поймать разницу между обычным вводом с клавиатуры и токенизированным. В их электрические мозги пришлось буквально забивать приказ, что в 128 килобайтной версии бейсика строка “randomize usr 15616” пишется побуквенно, но затем открывается TR-DOS и там для CAT (это аналог DIR и ls) надо сначала нажать caps shift + symbol shift, дождаться смены курсора и следом опять symbol shift + 9. БЯМки даже небольшую эврестическую модель для такого построили, но потом регулярно ее игнорировали и в попытках ввести команду занимались чем угодно, вплоть до дизассемблирования образов ПЗУ бейсика и трдос в попытках найти искомое. Тупые джуны.

Но с горем пополам мы прорвались и через этот бастион. Образы стали монтироваться, игрушки загружаться, а те, что отказывались, быстро попадали на вивисекторский стол и в код дискового контроллера вносились улучшения. Очень упорные джуны. Наконец, мне это надоело и я решил посмотреть, что там с последними творениями фирмы amstrad, сиречь моделями 2А/+3 или как-то так.

Джун писал, джун устал ...
Джун писал, джун устал ...

Легкий гуглеж показал, что в общем-то это обычный спектрум с 128 килобайтами памяти, только со своим дисковым контроллером, который внезапно еще более распространен и ставился в такую кучу мест, что можно делать скромное предположение, что если вы видели флоппи-дисковод, то наверняка за ним стоял он или его клон. Знаменитый NEC μPD765. Документации по нему еще больше, примеров вообще вагон и наверняка модельки при своем обучении это зацепили. Ведь вон, пишут всякие антропики (или как там на руском это благозвучнее?), что им читать больше нечего. Верно же, верно? Результат был ожидаем. Фига на постном масле. Биос (досом это назвать у меня рука не поворачивается) от 2А3 категорически отказывался воспринимать поделие электрических джунов за рабочее. Хорошо, идем проверенным путем и даем подсмотреть на уже готовые реализации. Несколько сессий и результат у меня на экране. Игры грузятся, но далеко не все. Кто-то сразу выпадает назад, кто-то возмущенно пищит, а некоторые тупо показывают пустой экран.

Понятно, защита от копирования. Вернее, в нашем случае защита от чтения, ибо образы-то уже скопированы. В этой области я вообще полный ноль, поэтому разрешаю доступ в интернет и велю гуглить, что там было и как это преодолевалось. Легкие возражения “товарищ, не будь комунистом, ты занимаешься противоправной деятельностью, ведь взламывать защиты от копирования это ух как плохо” я парировал “какой нафиг взлом, мы занимаемся археологическими раскопками”.

Долго дело делается, да сказка быстрее. Дал им доки, неработащие игрушки, другие эмуляторы как референс и команду “копаем отсюда и до того, как они заработают”. Ну и краем глаза смотрел за прогрессом. Первым шагом модельки решили, что у нас дисковые контроллеры слишком быстрые. Дескать, реальные на команды реагируют не мгновенно, а через некоторое время. В общем-то хорошее предположение, но лично я бы не стал на него опираться, ибо сочетаний контроллер-привод-диск даже в те времена было много и там, где один ответит “сделано” за 10 миллисекунд, второй может и 50 проваландаться. Но хорошо, сделали и это ожидаемо помогло ровно ничем.

Прекратив их размышления в духе “а если не 10 миллисекунд, а 11?”, я еще раз ткнул их носом в спецификацию образа. Есть обычный DSK, где формат простой на уровне сектор-дорожка, а есть EDSK, где какая-то дополнительная информация. Да и глядите, размер образов у “плохих” игр какой-то подозрительно большой… В ответ фонтан радости и уверения, что их-то начальник страсть какой умный (кажется, это был GLM). Подлизы.

Следущим откровением для них стало то, что есть места, которые помечены как “удаленные”, но в реальности набитые полезными данными. Парсер образов их честно пропускал и отдавал в лоадеры пустоту. Починили. Потом обнаружили, что есть защита speedlock weak sector, когда при чтении сектора каждый раз возвращаются разные данные. Починили. И радостные отрапортовали о завершении работы. Ну ок, часть игр действительно стала загружаться, но далеко не все. Ленивые джуны.

Насобирал “плохишей”, описал симптомы и отправил разбираться. Модельки честно дизассемблировали всё попадающее под их шаловливые байты, даже пошагово размотали один из загрузчиков, запустив-таки одну из игр. Но одна это одна игра, а хотелось много. Пришлось опять кожанному мешку давать наводки. Ведь есть эмуляторы, где это работает. Да, вы посмотрели в книгу, но, по видимому, увидели там фигу. Что вам мешает взять и выдрать из эмуляторов код контроллеров и сравнить их работу? Старательные джуны затащили все в МСР сервер и потактово (они реально считали такты на команды!) сравнили происходящее.

Следующая защита оказалась очень оригинальной. Одна дорожка 3,5 дюймового диска вмещает 6250 “сырых” байт. Чистых данных там 6144, остальное на всякиe заголовки уходит. Что делали правообладатели? Они писали в заголовок “вот этот вот сектор содержит 8192 байта”, затем просто писали свои данные до упора, пока контроллер пишет. Ну и следом тиражировали какой-то копировалкой, плюющей на логическую структуру диска. Что происходило в реальном компьютере? Приходил копировщик, читал структуру, запрашивал у контроллера восемь килобайт и получал в ответ ошибку. Беда, скопировать нельзя, ура! Что делал лоадер? Точно так же просил у контроллера эти 8 килобайт. Но когда контроллер сообщал об ошибке, то уже считанные данные загрузчик не игнорил, а самостоятельно считал по ним контрольную сумму. И если она совпадала, то ура, у нас оригинальный диск.

Стало читаться больше игр, но штук пять категорически отказывались запускаться. Очередные сессии, гуглеж и мучительные раздумья о великом программисте. Старательные джуны размотали очередной загручик, добавив историю команд и флагов и начали пошагово смотреть, что получается. Нашли ключевой JZ, сменили его на JNZ и получили запустившуюся игру. Отмотали назад и обнаружили очередное отличие в поведении реального контроллера и его эмулятора. Та же самая защита с восемью килобайтами, только теперь загрузчик читал маленькими блоками, делая паузы. Но диск-то крутится, данные с дорожки читаются, а их никто не забирает. В результате у реального ошибка OverRun, а виртуальный ждал до упора. В чем смысл этой защиты я так и не понял. Возможно, как раз против начинающих тогда появляться эмуляторов.

Последняя защита, когда при записи диска чуть-чуть уменьшали скорость вращения дискеты и записывали на дорожку аж 6305 байт, сдалась сама. Виртуальному контроллеру абсолютно пофиг на такое.

Добавьте ко всему этому то, что эти лоадеры самораспаковывающиеся и саморасшифровывающиеся программы, и вы поймете, что с доступными тогда средствами взломать это было практически невозможно. Только тупым копированием с диска на диск побайтово, а это минус всякие BBS, служившие тогда главным распространителем вареза. Сделать сброс состояния комьютера на диск тоже не получится – тут вам не tr-dos, такой функционал вырезан.

Но хватит о всяком железе, настало время для проверки в бою и выжать все соки из эмулятора, показав, как хорошо он все эмулирует. А что для этого лучше всего подходит? Правильно, демки. Кто музыку пиликает, кто графику рисует.

И тут меня настигла болючая боль. Нет, сделать реализацию пентагона, как референсного компьютера в демопати, было не сложно. Ну подумаешь, немного другая тактовая частота и поплывшие в результате этого тайминги. И даже реализация имитации задержек к памяти и их отсутствие при необходимости это мелочи. Боль была в том, какие тайминги и куда ставить. Все маститые авторы раскладывали их по-разному. У кого-то сигнал INT от ULA был через 16 тактов после начала кадра. Кто-то с пеной у рта утверждал, что онный сигнал приходит перед концом кадра, даже когда еще бордюр не закончился рисовать. Третий бил себя пяткой в грудь, и доказывал, что обратный ход луча начинается не там, где обычно. И ведь все с цифрами, прекрасно бьющимися с базовыми. Я пробовал все предложенное и все демки показывали на экране кашу.

Правда, красиво? Сравните в репе с тем, кто должно быть
Правда, красиво? Сравните в репе с тем, кто должно быть

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

И они пошли. Выпросили ключ, нашли какие-то другие модели, ориентированные на графику и насчитали. После, нарисовав еще с десяток тестов, показали мне. Совместными усилиями нашли пару незамеченных артефактов и поправили. Следом на кураже добавили звука, благо база уже была. Сначала TurboSound – это просто две ay8912, по одной на канал. Потом TurboSoundFM – это замена двух 8912 на две ямахи 2203. В результате 12 каналов и играет. Covox сделали мимоходом и забыли: для него демок не нашлось. Последним незаметно реализовался General Sound – а реальности это плата с отдельным Z80 аж на 12МГц, своей памятью и четырьмя DAC. Все необходимое было уже готово, надо было просто соеденить блоки.

И… всё. У меня получился эмулятор, который прекрасно играл демки (на заставке скриншот из ACROSS, где глаз видит какие-то проблемы лучше всего) и запускал найденные мной игрушки без каких-либо проблем. Да, наверняка еще есть где-то какие-то краевые случаи, где он сломается, но это уже оставлю на закуску. А то, что у него нет никакого UI, так это мелочи. Ах да, взять можно тут https://github.com/kiltum/zxgo-v3

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

Второе – это (по вкусу) регулярно тупо перезапускать IDE, сбрасывать контекст и делать все, чтобы следующая задача шла с чистого листа. У моделек с тулзами есть всякие температуры, сиды и прочие параметры, которые иногда заставляют модель тупить или наоборот бить гениальностью. В результате два одинаковых запроса приводят к разным результатам. Ваша задача – выбрать лучший.

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

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


  1. KarmaCraft
    20.09.2026 10:30

    Тема интересная, только где предыдущие части?


    1. kiltum Автор
      20.09.2026 10:30

      в смысле? две ссылки в третьем абзаце


  1. lazarus_net
    20.09.2026 10:30

    Что-то мои эксперименты с ИИ сильно напоминают то что автор написал- те же проблемы. А вокруг пишут - сказал сделай хорошо и они делают….

    Вопрос: что я/автор делаем не так и где волшебный промпт «сделай все чтобы работало»?


    1. kiltum Автор
      20.09.2026 10:30

      (сарказм) платите больше и у вас будет получаться лучше!