PDA

Просмотр полной версии : ZX68 - новый эмулятор Спектрума для PalmOS



CityAceE
09.02.2006, 14:30
ZX68 is the name for a ZX Spectrum emulator witten in assembler for the Motorola 68000 CPU and all compatible variants. The idea is to do a ZX Spectrum emulator that can be executed on any machine based on the Motorola 68000. The emulation core can be exactly the same for all the machines, the only diference will be the code to access specific hardware of the host machine, like the screen, keyboard, sound hardware and file access.

Actually I am working in versions for 680x0 based Amigas and PalmOS compatible devices, my intention is to do versions for Macintosh, Atari ST, Linux m68k and any other plataform based or compatible with the Motorola 68000 CPU.

http://zx68.8k.com/

CityAceE
11.02.2006, 11:01
Ну вот, решил проверить скорость работы эмулятора ZX68. Безусловно, точно замерить скорость эмуляции не реально, поэтому я решил воспользваться игрой AticAtac. Там в начале игры появляются часы, которые на настоящем Спектруме отсчитывают секунды близкие к реальным. Так вот я изготовил два снепшота для эмуляторов ZX68 и ZX-Pilot и поочерёдно запустил их на обоих эмуляторах на своём КПК. Для замерения времени я воспользовался обычным секундомером нажав на "Старт" при появлении на экране эмуляторов 00:01 и нажимал на "Стоп" при появлении цифры 00:30, то есть губо говоря измерял за сколько времени эмуляторы обрабатывают 29 секунд эмуляруемого времени. Итак, счётчик в игре AticAtac изменился с 00:01 до 00:30 под эмулятором ZX68 за 3 минуты 45 секунд, а под эмулятором ZX-Pilot за 1 минуту 20 секунд. Конечно, такой замер ни в коем случае не может говорить о том, что ZX-Pilot работает в 3 раза быстрее, чем ZX68, но он как минимум может говорить, что ZX-Pilot всё же быстрее.

Кроме того, мне было любопытно взгялнуть а как же устроен этот эмулятор внутри. Каково же было моё удивление, когда я обнаружил, что главный цикл ядра эмуляции совпадает с моим по сути 1:1. Пусть это всего лишь несколько строк кода, но от них зависит очень много. Я ни в коем случае не пытаюсь обвинить автора ZX68 в плагиате, но тем не менее факт очень любопытный. Можно сказать, что эти несколько строк я вынашивал месяц. Вполне вероятно, что нам обоим в голову пришла одинаковая идея, правда с промежутком в три года А даже если автор и использовал мою идею, то мне совсем не жалко!

Ещё мне кажется, что у ZX68 нет будущего - уж слишко грубо сделана в нём эмуляция. Что уж говорить, если в этом эмуляторе никак не учитывается количество тактов, за которое исполняется каждая команда Z80.

Правда, автор ZX68 сделал запрет на запись в область ПЗУ Спектрума. Я также делал в своём эмуляторе на первых порах, но позже отказался от него во имя скорости, пожертвовав совместимостью.

Ещё осталось непонятным почему на всех сайтах, где лежит ZX68 в Интернете, в качестве иллюстрации используется анимированный GIF, изготовленный мною для иллюстрации работы ZX-Pilot'а!

Titus
11.02.2006, 22:58
Кроме того, мне было любопытно взгялнуть а как же устроен этот эмулятор внутри. Каково же было моё удивление, когда я обнаружил, что главный цикл ядра эмуляции совпадает с моим по сути 1:1. Пусть это всего лишь несколько строк кода, но от них зависит очень много. Я ни в коем случае не пытаюсь обвинить автора ZX68 в плагиате, но тем не менее факт очень любопытный. Можно сказать, что эти несколько строк я вынашивал месяц. Вполне вероятно, что нам обоим в голову пришла одинаковая идея, правда с промежутком в три года А даже если автор и использовал мою идею, то мне совсем не жалко

Интересно, какие эти несколько строк?

p.s.: Под 680x0 я сам в свое время для Амиги делал эмулятор Спектрума и Денди...

Vladimir Kladov
12.02.2006, 08:35
Или что вообще такого уникального можно придумать для эмуляции Z80, кроме почти (? да нет, при чем тут почти - абсолютно) единственно возможного цикла выборки и исполнения команд?

CityAceE
12.02.2006, 12:15
Интересно, какие эти несколько строк?

Или что вообще такого уникального можно придумать для эмуляции Z80, кроме почти (? да нет, при чем тут почти - абсолютно) единственно возможного цикла выборки и исполнения команд?

Я подумал и понял, что действительно тут может быть только одно единственно верное решение! Это же подтвердил и автор ZX68, когда я поросил его прокомментировать:

"This is incredible, our main loops are almost
identical, thank you very much for your help. Maybe we
can join our projects to do a better emulator.

Greetings from Spain."

А циклы выглядят так:

ZX-Pilot:
moveq #0,d7 ;4
move.b (a1)+,d7 ;8
add.w d7,d7 ;4
move.w (a2,d7.w),d7 ;14
jmp (a3,d7.w) ;14

ZX68:
clr.w d7 ;4
move.b (a4)+,d7 ;8
lsl.w #1,d7 ;8
move.w (a1,d7.w),d7 ;14
jmp (a3,d7.w) ;14

Различаются только первая и четвертая строки, которы делают одно и то же: первая обнуляет регистр d7, а вторая умножает его на 2, с той разницей, что в моём варианте удаётся сэкономить 4 такта :)

Titus
12.02.2006, 16:04
Или что вообще такого уникального можно придумать для эмуляции Z80, кроме почти (? да нет, при чем тут почти - абсолютно) единственно возможного цикла выборки и исполнения команд?

При написании цикла эмуляции на медленных процессорах нельзя действовать просто "в лоб". Даже для 68000 схема быстрого цикла далеко не так очевидна, как может показаться на первый взгляд. Не говоря уже о реализации на более сложных процессорах, например на 68030, где, помимо всего прочего, необходимо учитывать особенности работы кеша данных и команд.

CityAceE
12.02.2006, 16:32
Даже для 68000 схема быстрого цикла далеко не так очевидна, как может показаться на первый взгляд.
И как ты оцениваешь то, что я представил? ;)

Titus
12.02.2006, 18:28
И как ты оцениваешь то, что я представил? ;)
ZX-Pilot:
moveq #0,d7 ;4
move.b (a1)+,d7 ;8
add.w d7,d7 ;4
move.w (a2,d7.w),d7 ;14
jmp (a3,d7.w) ;14
Для 68000 неплохо, но почему, например, не:

moveq #0,D7 ;4
move.b (A1)+,D7 ;8
add.w D7,D7 ;4
move.w (A2,A7.w),A7 ;14
move.l D7,A3 ;4
jmp (A3) ;8 (на 2 такта быстрее)

или:

moveq #0,D6 ;4
move.b (A1)+,D6 ;8
add.w D6,D6 ;4
move.l D6,A3 ;4
move.w (A3),D7 ;8
move.l D7,A3 ;4
jmp (A3) ;8 (на 4 такта быстрее)

или, если использовать вместо байт 16-битные слова, где младший байт равен нулю, то выборка сведется к:

move.w (A1)+,D7 ;8
move.l D7,A3 ;4
jmp (A3) ;8 (на 24 такта быстрее, хотя приведет к потерям в обработчиках некоторых команд) ;)

p.s.: Если, конечно, я правильно помню 68000

CityAceE
13.02.2006, 03:03
p.s.: Если, конечно, я правильно помню 68000
Видимо ты подзабыл его :)

Ключевой момент - jmp (a3,d7.w)! В a3 хранится начало таблицы адресов выборки команд, в d7 сдвиг относительно команды NOP. jmp (a3,d7.w) обозначает что нужно перейти на адрес a3+d7. А ты предлагаешь просто перехоть по адресу d7 :)

Titus
13.02.2006, 03:43
Видимо ты подзабыл его :)

Ключевой момент - jmp (a3,d7.w)! В a3 хранится начало таблицы адресов выборки команд, в d7 сдвиг относительно команды NOP. jmp (a3,d7.w) обозначает что нужно перейти на адрес a3+d7. А ты предлагаешь просто перехоть по адресу d7 :)

D7 - базовый адрес подпрограмм эмуляции команд выровненный на границу 64Кб, где D7[31..16] - собственно базовый адрес, а D7[15..0] - смещение выбираемое по таблице.

Т.е. взамен внутрикомандного A3.l+D7.w, выполняемого за 6 тактов, мы получаем A3 = D7.l[31..16]+D7.w за 4 такта ;)

Vladimir Kladov
13.02.2006, 18:38
Есть еще 1 вариант. Не делать никуда jump, а сразу выполнять операцию по таблице. См. мой Z (правда, он для PC, но важна идея).

Titus
13.02.2006, 18:40
Есть еще 1 вариант. Не делать никуда jump, а сразу выполнять операцию по таблице. См. мой Z (правда, он для PC, но важна идея).

Как это не делать джамп? ;)
Приведи пример :)

Vladimir Kladov
13.02.2006, 19:58
Все в исходниках Z. Адрес дать? Вот: http://bonanzas.rinet.ru/zx/z.zip

Titus
13.02.2006, 20:07
Все в исходниках Z. Адрес дать? Вот: http://bonanzas.rinet.ru/zx/z.zip

;-----------------------------------------;
; call certain instruction procedure ;
;-----------------------------------------;
call word ptr seg_Op:[JumpTable+bx]

извиняюсь великодушно, а калл это уже не джамп??? ;)

goodboy
14.02.2006, 11:50
ещё один интересный момент на сайте есть скрин из игрушки Sentinel,
надпись и карта выводятся не полностью - точно такая же ситуация в амиговском эмуле ZxAm

Vladimir Kladov
14.02.2006, 17:16
call это хуже. Но дело не в этом. Я же в Z стремился к меньшему размеру. Но если стремиться только к скорости, то можно по таблицам:
1 - увеличивать t тактов,
2 - дальше выполнять операцию
3 - и на финише операции формировать флажки. Примерно это и сделано. Но я стремился к минимальному размеру при соблюдении максимальной корректности, так что основную идею пришлось эксплуатировать совсем не в плане быстродействия. Потому и CALL а не JUMP - чтобы вернуться в то (общее) место, где по таблицам все завершающие части делаются.

А вообще jump'а можно избежать в большом количестве команд (если jump или call тормозит больше чем самомодификация кода эмулятора). Т.е. по таблице выбирается байт, который самомодифицирует следующую команду, и она становится или jump'ом, или начинает ту операцию, которая без jump'а начинает делать что-нибудь (опять по таблицам). Например: LD r1,r2 - их аж 64 команды, и видимо, это одна из частых разновидностей команд. Самомодификация еще пары кодов команд в самом эмуляторе (например, смещения в структуре подправляются), или если хорошая регистровая адресация есть - по 2 регистрам - то в 2 регистра выбираются номера регистров по коду операции, и дальше выполняется - опять без jump'ов выборка из одного "регистра" Z80, и засовывание в другой "регистр" Z80. Остается только 1 jump - на место, где следующая команда выбирается.

Может быть пример и не очень хороший, может быть, имеет смысл ускорять совсем не эти 64 команды (тем более там голову сломишь, что делать с HALT и (HL)), может быть имеет смысл ускорять как раз jump'ы и call'ы, но идея именно такая.

(Вот в PC я точно знаю, что jump, что самомодификация - все равно конвейер останавливается. А на других платформах - вдруг самомодификация дешевле).

Titus
14.02.2006, 17:52
(Вот в PC я точно знаю, что jump, что самомодификация - все равно конвейер останавливается. А на других платформах - вдруг самомодификация дешевле).

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

Что же касается процессоров без кеша (например 68000), то на них почти ВСЕГДА предпочтительней делать джамп по любому поводу и без повода, сколько позволяет свободная память, поскольку отсутствует главный тормозящий фактор кэшевых систем - загрузка линейки кеша команд.

CityAceE
15.02.2006, 02:50
ещё один интересный момент на сайте есть скрин из игрушки Sentinel,
надпись и карта выводятся не полностью - точно такая же ситуация в амиговском эмуле ZxAm
Возможно это связано вот с чем:

"Well, I am using the same technique used by Peter McGavin in his Spectrum emulator for the Amiga, doing interrupts after 2500 Z80 branch instructions, but I am refreshing the complete screen in every interruption, this way the screen will be refreshed too often some times, I will try to control this with a timer."

goodboy
15.02.2006, 10:28
скорее всего ошибка не в обновлении экрана, а в установке флагов какой нибудь командой

CityAceE
15.02.2006, 14:12
Да нет, не в обновлении дело. Просто при эмуляции НИКАК не учитывается время исполнения инструкций процессора, а прерывание случается после каждых 2500 инструкций перехода. Я так понимаю, что это сделано во имя скорости эмуляции. Скорее всего дело именно в таком подходе к прерываниям.