Тесты, тесты, тесты. Прошлое, настоящее и будущее.
Когда я начинал проект эмулятора Радио-86РК на JavaScript написание, собственно, модели процессора Intel 8080 (КР580ВМ80А) было мучительной задачей. Конечно, в сравнении со современными процессорами старичок 8080 выглядит как Жигули первой модели перед новой БМВ. Но все равно, реализовать логику около двух сотен команд с десятком регистров и при этом нигде не налажать практически невозможно. Поэтому отладка выглядела так: делается изменение, затем пробуется парочка программ для РК (в основном игры), и если игра визуально не глючит, то значит все более менее нормально.
Так я привел эмулятор примерно в работающее состояние, и большинство программ для РК типа “работали”. Но, увы, после завершения отладки, мне больше не хотелось трогать код эмуляции процессора, так как перепроверка все была реально мучительной и более того ненадежной. Но по-хорошему, код эмуляция нуждался в доработках.
На следующем витке эмуляторного приступа, когда я решил запустить РК на Maximite, я разыскал доступные тесты для Intel 8080, написанные на его же собственном коде, и оформил их прямо в сборке стационарно. В итоге проект эмулятора процессора отпочковался в подпроект i8080-core. Это чистый эмулятор Intel 8080, непривязанный к конкретной аппаратуре. В процессе сборки запускаются четыре теста, один из которых, 8080-8085 CPU Exerciser, является, пожалуй, единственным способ убедиться в “похожести” эмулятора на реальный процессор. Он был адаптирован Вячеславом Славинским в процессе работы над эмулятором компьютера Вектор на FPGA.
Интересная особенность этого теста в том, что он не проверяет поведение процессора по документации, а просто проводит множество вычислений, задействуя как можно больше команд в как можно большем количестве комбинаций, считает контрольную сумму (CRC32) результат и сравнивает с эталонной. Эталонные значения были изначально получены прогоном теста на реальном процессоре.
С одной стороны данный тест не дает точного места, где происходит сбой, а просто говорит, например, что где-то в командах арифметики что-то работает не так, поэтому контрольная сумма не совпадает.
В другой стороны этот тест позволяет сравнить реальное поведение процессора, а не “документированное”, так как порой, как это водится, есть недокументированное или плохо документированное поведение.
Например, есть основные логические операции: OR, AND, XOR. Так как это неарифметические операции, то флаг половинчатого переноса AC (из младшей тетрады в старшую) просто обнуляется. Так написано в документации. Но в реальности команда AND особенная. В ней флаг AC устанавливается (внимание!) равным третьему биту операции OR между аргументами команды, а не просто в ноль. Данное поведение, все таки было задокументировано, но в более поздней документации по 8085.
Или, например, в командах инкремента и сложения, тот же флаг AC вычисляется как положено по документации. Но в командах декремента и вычитания этот флаг имеет инвертированное значение!
В общем, много интересного, “упущенного” в официальной документации.
В итоге я использовал “простые” тесты для начальной минимальной проверки, и затем CPU Exerciser для окончательной. Кстати, на реальном процессоре при частоте 2MHz этот тест работает около двух часов. Это не особо большая проблема для эмулятора на С, но для версии на JavaScript может стать проблемой.
Итак, после внедрения тестов я мог уже корячить код эмулятора i8080-core без особых проблем, играясь с оптимизацией, структурой и т.д.
И вот я решил вернуться к эмулятору на JavaScript и проверить его на тестах. Как я и предполагал, ни один из тестов полностью не проходил.
Я попробовал править существующую реализацию, но в процессе переписал код эмулятора 8080 практически заново, благо голова была свежа после работы над i8080-core. За пару дней я реализовал все команды и прикрутил тесты. По ним я выловил все глюки, и теперь i8080-js проходит все тесты, включая 8080-8085 CPU Exerciser, тем самым являясь реально точной репликой КР580ВМ80А.
В код эмулятора теперь разбит на компоненты (I8080, Memory, IO), что позволяет его легко использовать для эмуляции конкретной аппаратуры. Декодирование команд упрощено и теперь работает по принципу дизассемблера.
Тестирование можно проводить прямо в браузере через JavaScript Console, или с использованием интерпретаторов JavaScript V8 или SpiderMonkey, работающих из командной строки. Второй способ предпочтительнее, так как последний тест 8080-8085 CPU Exerciser на V8 работает около получаса, а на SpiderMonkey около трех часов.
Итак, код эмулятора i8080-js – http://github.com/begoon/i8080-js/
Идем далее, эмулятор Радио-86РК. Я его тоже фактически переписал с нуля, используя наработки от свежей версии на Maximite. Старая версия 0.6 все еще доступна, но новый эмулятор (версия 1.0 и выше) теперь будет хоститься на GitHub’е.
Код теперь также разбит на модули (UI, Screen, Keyboard, Memory, IO, Runner). Большая монолитная HTML-страница теперь состоит из нескольких скриптов и каталога с программами, которые загружаются динамически. Улучшена работа клавиатурой.
Попробовать эмулятор в деле: demin.ws/rk
Исходники на GitHub’e: http://github.com/begoon/rk86-js/
При отладке эмулятора был интересный эпизод, связанный, конечно, с тестированием. После отладки эмулятора процессора я был уверен, что в нем ошибок нет, ибо все тесты проходят. Более того, игровые программы, на которых я обычно провожу визуальное тестирование, работают. Но вот незадача – ни один из Бейсиков не работал. Все выводили на экран мусор и висли. Путем трассировки я выяснил, что команда RST была реализована неверно (адрес перехода вычислялся неправильно). Ни один из тестов эту команду почему-то не проверяет, игровые программы не используют, а вот Бейсики – практически все.
Итак, винтажный эмулятор Радио-86РК на JavaScript возвращается. Обновляйте закладки – demin.ws/rk
Впечатления и эмоции можно высказывать тут, ошибки и предложения лучше сразу файлить в трекер:
Посты по теме:
P.S. Не премяните заценить мой Сокобан (файл soroban.bin) и демку (файл rk86demo.bin).
P.P.S. Несколько скринов.