Сколько видел исходников эмуляторов - практически везде дешифровка команд производится последовательно, например, начиная с кода 0x00 и до 0xFF. И вот подумалось мне, что такой подход нерационален и отрицательно сказывается на быстродействии эмуляции в системах, где скорость критична, а компилятор не оптимален. Как правило, все начинается с команды 'NOP' - это вообще нонсенс. Как часто используется NOP в качестве команды? Ну разве что для формирования задержек при работе с железом. А ведь можно упорядочить дешифрацию, используя статистику использования команд, чтобы не тратить время на анализ редко используемых команд.
Ради интереса я сделал выборки для 10 программ. Массив из 256 байт-счетчиков - индекс соответствует коду команды. Алгоритм прост: младший бит устанавливается, если команда
выполняется хотя бы раз, в следующий раз к значению счетчика прибавляется 2. Как только счетчик переполняется, его значение делится на 2. Младший бит сохраняется.
Вот например, статистика игры "Пьяный лифтер":
Code:
00: 00 03 00 00 00 2F 03 00 │ 00 03 00 00 00 9B 31 21
10: 00 03 91 93 00 00 00 03 │ 00 35 00 00 00 00 00 03
20: 00 07 03 B3 00 00 00 00 │ 00 00 03 03 00 00 00 00
30: 00 00 00 00 07 03 03 00 │ 00 00 00 00 00 00 03 03
40: 00 00 00 00 00 00 00 09 │ 00 00 00 00 00 00 00 00
50: 00 00 00 00 00 00 03 00 │ 00 00 00 00 00 00 03 00
60: 00 00 00 00 00 00 00 00 │ 00 00 00 00 00 00 00 00
70: 00 00 03 03 00 00 00 03 │ 00 00 00 00 00 03 A9 00
80: 00 00 00 00 00 00 00 00 │ 00 00 00 00 00 00 00 00
90: 00 00 00 00 00 00 00 00 │ 00 00 00 00 00 00 00 00
A0: 00 00 00 00 00 00 00 00 │ 00 00 00 00 00 00 00 00
B0: 00 00 00 00 00 00 00 00 │ 09 00 00 00 00 00 09 00
C0: 00 03 CB 03 00 03 03 00 │ 00 00 11 00 00 00 00 00
D0: 00 03 03 03 00 00 00 00 │ 00 00 03 03 00 00 00 00
E0: 00 03 00 5F 00 05 15 00 │ 00 00 00 61 00 00 00 00
F0: 00 00 03 00 00 00 00 00 │ 00 00 03 00 00 00 03 00
Общая картина такова, что, безусловным лидером в большинстве случаев является команда JNZ. Но это не касается рекомпиляций с MSX, где используются очень эффективные процедуры работы с графикой. Там лидируют команды инкремента пар регистров. Но зато явно видны аутсайдеры, которые практически никогда не используются. А значит, их можно поставить в конец конвейера дешифратора команд.
Очередь можно формировать динамически в зависимости от выполняемого кода.
С другой стороны, хороший компилятор вполне может сам преобразовать эту линейность в таблицу указателей, так что в этом случае как ни расставляй, на быстродействии это никак не скажется )) К тому же современные процессоры могут перемолоть все что угодно.
Но в некоторых случаях и такой подход может пригодиться. Может это ускорит онлайн-эмулятор на JavaScript, я просто не в курсе, как браузер выполняет JS, происходит ли компиляция-оптимизация и является ли там эмуляция процессора узким горлышком.