Info Guide
#08
30 ноября 2005 |
|
Sofтинка - Эмулятор ZX Spectrum на ZX Spectrum.
ZXZXEmul Продолжая тему шутки, опубликованной в ACNews#29 (на самом деле идея ещё старше), я решил написать эмулятор ZX Spectrum на ZX Spectrum. Ничего невозможного тут нет,в методах тоже нет ничего необычного. По су─ ти,эмулятор заменяет собой медленную трас─ сировку, которая бывает в отладчиках,и сам может стать ядром такого отладчика (конеч─ но, не в теперешнем виде, который слишком ориентирован на скорость).При этом имеется важное удобство - в ПЗУ можно подставлять свою прошивку,а распределение памяти можно взять вообще от другой модели компьютера. И можно, скажем, эмулировать мышь при её отсутствии. Другое полезное свойство эму─ лятора,достижимое в обычных отладчиках то─ лько при перешивании ПЗУ (трассировку не считаем, т.к.гонять сложную программу,име─ ющую пользовательский интерфейс, под трас─ сировкой невозможно) - точки останова мож─ но укладывать в один байт. При этом стек программы не портится (это уже не достижи─ мо в обычных отладчиках). Эмулятор пишется следующим образом. Сначала отлаживаем систему команд при ОЗУ 16k и имеющемся ПЗУ.(Этот режим удобен тем, что при эмуляции не нужно переключать странички.) Команды выбираются по таблице (для каждого кода команды - адрес подпрог─ раммы),при этом указатель на текущую кома─ нду хранится в DE. Основной набор регист─ ров удобнее всего хранить в альтернативном наборе, а основные A, BC, HL оставить для разного рода вычислений.Можно было бы раз─ местить в регистрах и эмулируемый SP, но выигрыш,видимо,будет очень небольшой. Зато весьма упрощает задачу использование IX в качестве текущего индексного регистра. (Не текущий индексный регистр должен лежать где-то в переменной в памяти, равно как и регистры альтернативного набора.) Команды с префиксами расписаны в отде─ льных таблицах. При смене текущего индекс─ ного префикса индексные регистры обменива─ ются (IX<->память) . Этим убилось 2 зайца: IY можно занять под что-то полезное; нужен всего один набор выполнялок индексных ко─ манд. Эмулятор, естественно,с первого раза не заработал, хотя был написан всего за два дня, с использованием макросов (чтобы был шанс быстро заменить по всей программе глючный фрагмент, если он будет найден). Отладка происходила так. Эмулируем сброс. Видим, что он не рабо─ тает. Идём по прошивке ПЗУ шаг за шагом, останавливая Unreal Speccy условными точ─ ками останова (pc==nnnn)&&(de==mmmm), где nnnn - адрес начала выбиралки команды, а mmmm - адрес в ПЗУ, на котором мы хотим остановиться.Остановив,списываем регистры. Запускаем второй экземпляр Unreal Speccy и смотрим, какие в этой точке ПЗУ в действи─ тельности должны быть регистры.Параллельно изучаем маршрут, по которому наш эмулятор выполняет ПЗУ (записываем все адреса ветв─ ления). Если видим, что наш эмулятор пошёл не туда, куда надо (а куда надо, нам пока─ зывает второй экземпляр Unreal Speccy ),то это именно тот случай,когда надо проверить регистры. Заодно проверяем эмулированные системные переменные. Чтобы дойти до сообщения "Sinclair Re─ search Ltd", в нашем эмуляторе даже не ну─ жно эмулировать прерывания.Однако эмулиро─ вать прерывания так или иначе понадобится. Для начала была сделана "честная" эму─ ляция IM1 (пока без IM2) с настоящим выпо─ лнением каждой команды обработчика.До вхо─ да в обработчик (то есть до эмуляции RST #38 ) нужно делать две вещи: проверить эмулируемый триггер разрешения прерываний (заодно сбросив его) и закончить эмуляцию текущей эмулируемой команды.Для того,чтобы закончить эмуляцию текущей эмулируемой ко─ манды, мы просто ставим перехват в начале выбиралки команды. Позже обработчик прерываний был услож─ нён: появилось IM2, а для IM1 была сделана возможность вместо "честной" эмуляции под─ ключить вызов настоящего #38. Это сущест─ венно быстрее. Естественно, перед таким вызовом проверяется, там ли IY, а если не там, то нужно "честно" эмулировать глюки эмулируемой программы :) Ограничение памяти (16k вместо 48k) бы─ ло сделано очень просто:запрещена запись в ячейки выше #7fff. В конце концов (на пятый день) эмуляция 16k заработала, и в эмулируемом бейсике стало возможно выполнять операторы. Следующий шаг - 48k. Для него понадоби─ лись макросы работы с памятью. Эмулятору нужны операции с памятью: 1. взятие кода команды или параметра команды; 2. запись в виртуальное ОЗУ; 3. чтение из виртуального ОЗУ; и др. Перечисленные - основные.Виртуальное ОЗУ размещается в верхних страницах памя─ ти. Написав такие макросы, я получил возмо─ жность организовать перехват вывода на эк─ ран:если эмулируемая pg5 лежит не в реаль─ ной pg5 (это переключается в исходнике - попробуйте),то команды записи на экран мо─ жно перенаправлять и туда, и туда, причём на реальный экран можно писать не всегда, а по какому-то условию (для примера я реа─ лизовал отсечение правой части экрана - там можно разместить, скажем, какие-то ин─ дикаторы). После отладки 48k (заодно была отрабо─ тана возможность смены прошивки ПЗУ) я пе─ решёл к 128k. Различие здесь уже не такое принципиальное,как между 16k и 48k. Просто нужно добавить обработку OUT (#fd) и реа─ лизовать в эмуляторе соответствующую пере─ менную. Точнее,переменных нужно две: какая страница ОЗУ включена с точки зрения эму─ лируемой программы и какую на самом деле нужно включать при работе с адресами >=#c000. Для отладки 128 бейсика нужно реализо─ вать и переключение страниц ПЗУ. Я заодно реализовал и возможность переключения страниц в окнах #4000 и #8000, для будущей эмуляции АТМ. Это потребовало лишь замены LD A,константа на LD A,(переменная) и пра─ ктически не замедлило эмуляцию. 48 бейсик работал, несмотря на то, что некоторые команды эмулировались неправиль─ но. Погоняв 128 бейсик, а также Mr Gluk Reset Service, я протестировал остальные команды.Не проверенными остались недокуме─ нтированные команды с индексно-регистровой адресацией, но я их и не реализовывал. Обратите внимание, что при включенном 128 бейсике не должен работать выход в TR-DOS по #3dxx! Иначе не считает каль─ кулятор 128 бейсика! Я это нашёл не сразу, т.к. на моём реальном пентагоне #3dxx ра─ ботает и при включенном 128 бейсике. Точ─ нее, #3dxx у меня в этом случае включает 0-ю страницу ПЗУ, где Gluk Service. Но са─ мого 128 бейсика у меня в ПЗУ нет, вместо него Quick Commander. Эмулятор получился такого громоздкого размера потому, что я хотел найти потолок скорости. Для реальной задачи трассировки все макросы работы с памятью надо было бы загнать в подпрограммы,а многие выполнялки команд следовало бы объединить. Впрочем, потолка я не достиг.При данном методе (по─ следовательное выполнение команд без дина─ мической рекомпиляции и без предсказания следующих команд) тормоз в выборе страницы (команд,данных,стека) можно было бы сильно уменьшить, если заставить DE указывать не на виртуальный адрес в памяти программы, а на реальный адрес (#c000-#ffff), гаранти─ ровав при этом, что в начале выбиралки ко─ манды включена именно страница команд. Для этого я реализовал флажок margins (0=ста─ рый режим, 1=новый), написал новое ядро эмуляции и сделал разные макросы возврата из выполнялок разных команд (просто выход, выход с включением страницы команд,выход с пересчётом виртуального DE в реальный и т.д.). В том виде, как я это реализовал, пока не обойдён случай, когда программа пересекает границу окон памяти. Но обойти его можно. К сожалению,сам режим margins=1 даже в этом упрощённом виде мне так и не удалось отладить - может быть, у вас полу─ чится? Есть ещё один вариант ускорения выбора команд - копировать из страницы команд сразу много байт и потом выполнять команды в нижней памяти. Разумеется, нужно много проверок. Как обычно,я растерял в своих разорван─ ных бумажках записи замеров времени для первого метода (margins=0, который работа─ ет) и для второго (margins=1, который не работает). Выигрыш по скорости в новом методе (при выполнении процедуры сброса), если мне не изменяет память, где-то 25%. Конечно, самый быстрый режим - это 16k. Эмуляции #3d13 оказалось недостаточно, чтобы заработали дисковые программы. Види─ мо, нужно поддержать ещё какие-то точки. Mr Gluk Reset Service видит каталог, но не может запускать бейсики.Впрочем,дискдоктор работает. Я не сделал ни одной управляющей кнопки эмулятора, просто отметил в обработчике прерываний то место,где должны проверяться кнопки.Рекомендую задействовать комбинацию SS/Enter, выдавать по ней меню, в числе опций которого (сбросы, загрузка/выгрузка снапшотов, отладчик и т.д.) должна быть и такая: "передать эмулируемой программе на─ жатие SS/Enter в течение 10 прерываний". Исходники лежат в приложении. Они рас─ считаны на компиляцию на Pentagon 512/1M (сам эмулятор тоже рассчитан на работу на Pentagon 512/1M ). Вам будет нетрудно ис─ править под другую модель памяти. Alone C
Другие статьи номера:
Похожие статьи:
В этот день... 21 ноября