Даже если бы вы могли напрямую обращаться к аппаратным регистрам, оборачивать код вокруг решения использовать регистр вместо памяти намного медленнее.
Чтобы получить производительность, вам нужно заранее спроектировать производительность.
Несколько примеров.
Подготовьте виртуальную машину x86, настроив все ловушки для перехвата кода, оставляя пространство виртуальной памяти. Выполните код напрямую, не эмулируйте, переходите к нему и запускайте. Когда код достигает своего пространства памяти / ввода-вывода, чтобы поговорить с устройством и т. Д., Перехватите его и эмулируйте это устройство или все, к чему оно обращалось, затем верните управление обратно в программу. Если код привязан к процессору, он будет работать очень быстро, если привязан к вводу / выводу, то будет медленным, но не таким медленным, как эмуляция каждой инструкции.
Статический двоичный перевод. Разберите и переведите код перед выполнением, например, инструкция 0x34,0x2E превратится в ascii в файле .c:
al ^ = 0x2E;
из = 0;
ср = 0;
SF = ал
Идеально для выполнения тонны удаления мертвого кода (если следующая инструкция также изменяет флаги, не изменяйте их здесь и т. Д.). И пусть оптимизатор в компиляторе сделает все остальное. Таким образом, вы можете получить прирост производительности по сравнению с эмулятором, насколько хороший прирост производительности зависит от того, насколько хорошо вы можете оптимизировать код. Будучи новой программой, она работает на оборудовании, регистрирует память и все остальное, поэтому код, связанный с процессором, медленнее, чем виртуальная машина, в некоторых случаях вам не приходится иметь дело с процессором, который делает исключения для перехвата памяти / ввода-вывода, поскольку вы симулировали память обращается к коду, но это все еще имеет свою стоимость и в любом случае вызывает смоделированное устройство, поэтому экономия там отсутствует.
Динамический перевод, похожий на sbt, но вы делаете это во время выполнения, я слышал, что это было сделано, например, при моделировании кода x86 на каком-то другом процессоре, скажем, dec alpha, код медленно превращается в нативные альфа-инструкции из инструкций x86, поэтому в следующий раз он выполняет альфа-инструкцию напрямую, а не эмулирует инструкцию x86. Каждый раз с помощью кода программа выполняется быстрее.
Или, может быть, просто перепроектируйте ваш эмулятор, чтобы он был более эффективным с точки зрения исполнения. Посмотрите на эмулируемые процессоры в MAME, например, читаемость и ремонтопригодность кода были принесены в жертву производительности. Когда было написано, что это важно, сегодня с многоядерными гигагерцовыми процессорами вам не нужно так усердно работать, чтобы эмулировать 1,5 ГГц 6502 или 3 ГГц z80. Такое простое решение, как поиск следующего кода операции в таблице и решение не эмулировать некоторые или все вычисления флага для инструкции, может дать вам ощутимый импульс.
Итог, если вы заинтересованы в использовании аппаратных регистров x86, Ax, BX и т. Д. Для эмуляции регистров AX, BX и т. Д. При запуске программы, единственный эффективный способ сделать это - фактически выполнить инструкцию, и не выполнять и перехватывать, как при пошаговом отладчике, а выполнять длинные строки инструкций, не давая им покинуть пространство виртуальной машины. Есть разные способы сделать это, и результаты производительности могут отличаться, и это не значит, что это будет быстрее, чем эффективный эмулятор. Это ограничивает вас для согласования процессора с программой. Эмуляция регистров с эффективным кодом и действительно хорошим компилятором (хорошим оптимизатором) даст вам разумную производительность и переносимость, так как вам не нужно будет подбирать аппаратное обеспечение для запускаемой программы.