Эмуляция - это многогранная область. Вот основные идеи и функциональные компоненты. Я собираюсь разбить его на части, а затем заполнить детали с помощью правок. Многие вещи, которые я собираюсь описать, потребуют знания внутренней работы процессоров - знание сборки необходимо. Если я немного расплывчат в некоторых вещах, пожалуйста, задавайте вопросы, чтобы я мог продолжать улучшать этот ответ.
Основная идея:
Эмуляция работает путем обработки поведения процессора и отдельных компонентов. Вы строите каждую отдельную часть системы, а затем соединяете ее так же, как это делают аппаратные средства.
Эмуляция процессора:
Существует три способа обработки эмуляции процессора:
- интерпретация
- Динамическая перекомпиляция
- Статическая перекомпиляция
Со всеми этими путями у вас одна и та же общая цель: выполнить фрагмент кода, чтобы изменить состояние процессора и взаимодействовать с «оборудованием». Состояние процессора - это конгломерат регистров процессора, обработчиков прерываний и т. Д. Для заданной цели процессора. Для 6502, нужно иметь ряд 8-разрядных целых чисел , представляющих регистры: A
, X
, Y
, P
, и S
; у вас также будет 16-битный PC
регистр.
При интерпретации вы начинаете с IP
(указатель инструкций - также вызывается PC
, счетчик программ) и читаете инструкцию из памяти. Ваш код анализирует эту инструкцию и использует эту информацию для изменения состояния процессора, как указано вашим процессором. Основная проблема с интерпретацией заключается в том, что это очень медленно; каждый раз, когда вы обрабатываете данную инструкцию, вы должны декодировать ее и выполнить необходимую операцию.
С динамической перекомпиляцией вы перебираете код, очень похожий на интерпретацию, но вместо того, чтобы просто выполнять коды операций, вы создаете список операций. Получив инструкцию перехода, вы компилируете этот список операций в машинный код для вашей хост-платформы, затем кешируете этот скомпилированный код и выполняете его. Затем, когда вы снова попадете в данную группу инструкций, вам нужно будет только выполнить код из кэша. (Кстати, большинство людей на самом деле не составляют список инструкций, а компилируют их в машинный код на лету - это усложняет оптимизацию, но это выходит за рамки этого ответа, если не заинтересовано достаточно людей)
При статической перекомпиляции вы делаете то же самое, что и при динамической перекомпиляции, но вы следуете ветвям. Вы заканчиваете тем, что строите кусок кода, который представляет весь код в программе, который затем может быть выполнен без дальнейшего вмешательства. Это был бы отличный механизм, если бы не следующие проблемы:
- Код, которого нет в программе для начала (например, сжатый, зашифрованный, созданный / измененный во время выполнения и т. Д.), Не будет перекомпилирован, поэтому он не будет работать
- Доказано, что поиск всего кода в заданном двоичном коде эквивалентен проблеме остановки
Все это делает статическую перекомпиляцию совершенно невозможной в 99% случаев. Для получения дополнительной информации Майкл Стейл провел большое исследование статической перекомпиляции - лучшее, что я видел.
Другая сторона эмуляции процессора - это способ взаимодействия с оборудованием. Это действительно имеет две стороны:
- Время процессора
- Обработка прерываний
Время процессора:
Некоторые платформы - особенно старые консоли, такие как NES, SNES и т. Д. - требуют, чтобы ваш эмулятор имел строгую синхронизацию, чтобы быть полностью совместимым. С NES у вас есть PPU (блок обработки пикселей), который требует, чтобы процессор вставлял пиксели в свою память в точные моменты. Если вы используете интерпретацию, вы можете легко считать циклы и эмулировать правильное время; с динамической / статической перекомпиляцией все становится намного сложнее.
Обработка прерываний:
Прерывания - это основной механизм взаимодействия ЦПУ с оборудованием. Как правило, ваши аппаратные компоненты сообщают процессору, о каких прерываниях он заботится. Это довольно просто - когда ваш код генерирует данное прерывание, вы смотрите на таблицу обработчиков прерываний и вызываете правильный обратный вызов.
Аппаратная эмуляция:
Эмуляция данного аппаратного устройства имеет две стороны:
- Эмуляция функциональности устройства
- Эмуляция реальных интерфейсов устройства
Возьмите случай с жестким диском. Функциональность эмулируется путем создания резервного хранилища, процедур чтения / записи / форматирования и т. Д. Эта часть обычно очень проста.
Фактический интерфейс устройства немного сложнее. Как правило, это некоторая комбинация регистров отображения памяти (например, частей памяти, которые устройство отслеживает на предмет изменений для выполнения сигнализации) и прерываний. Для жесткого диска у вас может быть область отображения памяти, в которую вы помещаете команды чтения, записи и т. Д., А затем считываете эти данные обратно.
Я бы более подробно рассказал, но есть миллион способов, которыми вы можете воспользоваться. Если у вас есть какие-либо конкретные вопросы здесь, не стесняйтесь спрашивать, и я добавлю информацию.
Ресурсы:
Я думаю, что я дал довольно хорошее введение здесь, но есть тонна дополнительных областей. Я более чем рад помочь с любыми вопросами; Я был очень расплывчат в большей части этого просто из-за огромной сложности.
Обязательные ссылки Википедии:
Общие ресурсы эмуляции:
- Zophar - это то место, где я начал с эмуляции, сначала скачал эмуляторы и в конце концов разграбил их огромные архивы документации. Это самый лучший ресурс, который вы можете иметь.
- НГему - Немного прямых ресурсов, но их форумы непобедимы.
- RomHacking.net - раздел документов содержит ресурсы, касающиеся архитектуры компьютеров для популярных консолей.
Эмулятор проектов по ссылке:
- IronBabel - это платформа эмуляции для .NET, написанная на Nemerle и перекомпилирующая код в C # на лету. Отказ от ответственности: это мой проект, так что извините за бесстыдную вилку.
- BSnes - Отличный эмулятор SNES с идеальной точностью цикла.
- MAME - эмулятор игровых автоматов . Отличная ссылка.
- 6502asm.com - это эмулятор JavaScript 6502 с небольшим интересным форумом.
- dynarec'd 6502asm - это небольшой взлом, который я сделал за день или два. Я взял существующий эмулятор с 6502asm.com и изменил его, чтобы динамически перекомпилировать код в JavaScript для значительного увеличения скорости.
Рекомендации по перекомпиляции процессора:
- Исследование статической перекомпиляции, выполненное Майклом Стейлом (ссылка выше), завершилось в этой статье, и вы можете найти источник и тому подобное здесь .
Приложение:
Прошло уже больше года с тех пор, как этот ответ был представлен, и со всем вниманием, которое он получал, я подумал, что пришло время обновить некоторые вещи.
Возможно, самая захватывающая вещь в эмуляции сейчас - это libcpu , созданная вышеупомянутым Майклом Стейлом. Это библиотека, предназначенная для поддержки большого количества ядер ЦП, которые используют LLVM для перекомпиляции (статическая и динамическая!). У этого есть огромный потенциал, и я думаю, что он сделает большие вещи для эмуляции.
На мое внимание также было обращено внимание на emu-docs , в котором находится отличное хранилище системной документации, что очень полезно для целей эмуляции. Я не провел там много времени, но, похоже, у них много отличных ресурсов.
Я рад, что этот пост был полезен, и я надеюсь, что смогу сорваться с задницы и закончить свою книгу по этому вопросу к концу года / началу следующего года.