Обновить

С go на C++ за две недели. Переписываю эмулятор ZX Spectrum

Уровень сложностиСредний
Время на прочтение17 мин
Охват и читатели20K
Всего голосов 75: ↑74 и ↓1+88
Комментарии28

Комментарии 28

Уважуха автору!

Интересно если бы на расте писал, то была бы проблема с этой невыроаненной памятью?

Была бы

Раст защищает от небезопасного доступа к памяти (гонки данных, висячие указатели), но он не может защитить от логических ошибок - если у тебя в коде баг, из-за которого ты пишешь в массив screen за его пределами, но при этом попадаешь в соседний массив memory, то с точки зрения раст все будет легально - работаешь в пределах выделенной тебе памяти, он не знает что эти два массива для тебя разные сущности

В Rust нельзя писать за пределами массива. В safe части за этим следить прграммисту не надо, в unsafe необходимо.

Вся история - отличная реклама хорошей отладки)

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

Поучительно, но не очень эффективно :)

Расскажите подробнее, пожалуйста, про JTAG-отладчик для эмулятора спектрума. Мне очень, очень интересно.

Надо еще добавить поддержку Beta Interface с дисками. В свое время много читал про TR-DOS, но так и не видел их живьем. Следом еще один шаг до всяких пентагонов, АТМ-Турбо и прочих Spectrum Next.

Я некоторое время назад развлекался, делая с нуля эмулятор Орион-128 исключительно на основе подшивки Радио (а также готового эмулятора z80 и даташитов микросхем). Я забрался довольно далеко в этом деле, но в конце концов был демотивирован тем, что еще надо сделать тучу всего, а все это уже было сделано десяток раз различными людьми, в том числе и в MAME.

Мне кажется, что написание собственного ретроэмулятора - это деятельность, близко похожая на написание собственной ОС. Многие берутся, мало кто доводит дело хоть до какой-то вменяемой работающей версии, и в результате неизменно получается что-то до противного похожее на 100500 уже существующих изделий. Притом работа в обоих этих направления, вообще говоря, полезна для саморазвития; надо только потом принять, что настоящий выхлоп от этой задачи - не получившийся код, а пройденный путь.

с огромным удовольствием прочитал!))) спасибо за замечательную хронику) а главное с подробностями, которые интересны с точки зрения понимания архитектуры ZX.

автор, может быть реализовать эмулятор под КУВТ-2 (MSX) машинку? там тоже Z80, но видео процессор от TI. 9918/9938/9958

Все возможно. Есть только один минус - я эти КУВТ только на картинках видел :)

Я понимаю, что нелепо спрашивать почему был выбран язык X, а не Y. Но всё же, почему плюсы, а не rust?

Если С++ я хоть немного знаю, то rust я даже идеологию не понимаю.

Спасибо. Ну тогда все правильно, это логичный выбор, писать на том, что лучше знаешь.

Ну где еще можно на халяву пожечь сотни миллионов токенов и получить хоть что-то работающее?

В гугле... https://aistudio.google.com там gemini 2.5 pro с 1млн контекстом и удобным интерфейсом.

А что давали в cloud.ru?

Все тоже самое, что и сейчас, но бесплатно. https://cloud.ru/products/evolution-foundation-models . Я в основном самый жирный Qwen использовал

Мне умельцы в своё время впилили дисковод с TR-DOS и magic button. С тех пор я к кассетам не возвращался. Бали ещё игры с множеством картинок только для дисковода. Тут похоже какая у кого настальгия. Я бы наверно делал эмулятор того что было у меня :)

в прошлой статье, проблема Go была в том, что нет возможности выставить приортитет потоков

в этой статье проблема в какой-то буферизации каналов, которая делается чтобы избежать каких-то фризов

а есть ли вообще полное понимание проблемы или это очередные, ничего не значащие предположения?

Если честно, то я не понял вопроса. Тут фризы совершенно никак не связаны с эмулятором и являются багом (или фичей) самого exolon

вопрос о том, почему невозможно написать нормальный эмулятор на Go

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

не, написано, что с Go что-то не так -- лаги, буферизация и фризы

В go все межпотоковое взаимодействие устроено на каналах. И все обычно используют буферизированные, иначе вылазит куча проблем с фризами на ровном месте

и вот хотелось бы с этого места поподробнее, что там с буферизацией и от каких фризов она спасает

Чего-то сложно стало следить за развитием темы сразу в двух местах :) Поэтому в одно. Суть проблемы простая: гошный шедулер даже при наличии ресурсов пытается экономить все доступное. Наиболее легко это демонстрируется на простейшей связки Задача1 - канал - задача 2. В "старом" эмуляторе это клавиатура-обработчик нажатий или генератор звука - вывод звука. наверняка еще где-то есть, но уже лень вспоминать. Ставим дебажный вывод в задаче 1 и задаче 2. Буферизацию (в смысле вывода отключаем, ну или флушим сразу). Идеальное поведение в выводе 121212121212 . то есть задача 1 что-то написала, задача 2 что-то прочитала. Реальное 11111122222111112222. то есть пишем что-то, потом гошный шедулер понимает, что вообще-то надо дать ресурсов и запускает задачу 2. Ок, вырубаем буферизирование в канале. Ждем 121212 .... получаем 1wwww2wwww1, где w - просто ждет чего-то. охреневаем мрачно. добавляем профилирование (там вроде еще видны остатки в makefile) и видим туже самую картину, только в виде красивой html странички. Вот отсюда и лаги с фризами. Повторюсь, они маленькие и в обычной жизни не заметны. Ну никто не будет разбираться, на сколько миллисекунд плавает генерация веб страницы.

для той же клавиатуры пара тройка миллисекунд лага роли не играет при частоте кадров в 50 Гц

в задержки на ровном месте в десятки миллисекунд (при куче свободного CPU ресурса) как-то не верится

ну чего мне с вами спорить-то? :) клонируете репу, загружаете batty, гоняете каретку влево-вправо и наблюдаете лаги. Плюете мне в кипу (ну не трушный гошник я), загружаете gospeccy, загружаете опять-же batty и наблюдаете опять лаги. микроскопические уровня "оно поехало на Н мс позже" или "остановилось на Н мс позже", но они есть, прекрасно чувствуются и сильно мешают играть. Если лень, то с эффектом можно ознакомиться где-нить еще, нагуглив "input lag" при подлючении через hdmi приставок к телику.

я верю, что работает оно плохо

я о том, чтобы докопаться до истинных причин и понять, что это неустранимая вещь на уровне языка

А ну тут я пасс. Мне хватило того, что я вижу

Мне кажется, такую программу можно и однопоточную написать. А если вам нужно чередование двух задач, вызывайте их явно подряд.

Кстати, любопытно, как код с каналами перевёлся на кресты. Мьютексы и общие данные?

Что не так с go? Самая большая боль это лаги. Нажимаешь ты, к примеру, клавишу "стрелка влево", а игра начинает реагировать с задержкой. Хоть задержка и небольшая, но самое неприятное в том, что эта задержка плавающая. Поначалу я списывал все на свои кривые руки, дескать не постиг всего goшного дзена и все такое прочее. Однако скачав и запустив gospeccy (как видно из названия, он тоже написан на go), я обнаружил там те же самые проблемы, пусть и в меньшей степени. После Н часов разборок выяснилось (тут капитан очевидность), что в go все межпотоковое взаимодействие устроено на каналах. И все обычно используют буферизированные, иначе вылазит куча проблем с фризами на ровном месте. И если для обычных программ это не вызывает никаких проблем, то в эмуляторах, где обычно важен каждый тик в синхронизации, это ад и ужас.

Сборщик мусора ни при чём?

не буду утверждать 100%. Но вроде нет.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации