Как работают эмуляторы и как они написаны? [закрыто]


968

Как работают эмуляторы? Когда я вижу эмуляторы NES / SNES или C64, меня это поражает.

http://www.tommowalker.co.uk/snemzelda.png

Нужно ли имитировать процессор этих машин, интерпретируя его конкретные инструкции по сборке? Что еще входит в это? Как они обычно разработаны?

Можете ли вы дать какой-нибудь совет тем, кто заинтересован в написании эмулятора (особенно игровой системы)?


15
Самая важная вещь, которую вам нужно найти, - это «руководство программиста» для этой системы, поскольку в нем подробно описывается «контракт» между поставщиком программного обеспечения и программистами, а также скрываются детали, которые не имеют отношения к делу и могут измениться. Ваши шансы зависят от популярности системы.
Ури

155
Хороший выбор игры.
Кристиан Ромо


16
Для всех, кто интересуется Emulation vs Simulation
Lazer

8
С тех пор, как я впервые играл в эту игру, я всегда удивлялся, почему Хайрул завален валунами из 8 шаров :-)
Вивиан Ривер,

Ответы:


1124

Эмуляция - это многогранная область. Вот основные идеи и функциональные компоненты. Я собираюсь разбить его на части, а затем заполнить детали с помощью правок. Многие вещи, которые я собираюсь описать, потребуют знания внутренней работы процессоров - знание сборки необходимо. Если я немного расплывчат в некоторых вещах, пожалуйста, задавайте вопросы, чтобы я мог продолжать улучшать этот ответ.

Основная идея:

Эмуляция работает путем обработки поведения процессора и отдельных компонентов. Вы строите каждую отдельную часть системы, а затем соединяете ее так же, как это делают аппаратные средства.

Эмуляция процессора:

Существует три способа обработки эмуляции процессора:

  • интерпретация
  • Динамическая перекомпиляция
  • Статическая перекомпиляция

Со всеми этими путями у вас одна и та же общая цель: выполнить фрагмент кода, чтобы изменить состояние процессора и взаимодействовать с «оборудованием». Состояние процессора - это конгломерат регистров процессора, обработчиков прерываний и т. Д. Для заданной цели процессора. Для 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 , в котором находится отличное хранилище системной документации, что очень полезно для целей эмуляции. Я не провел там много времени, но, похоже, у них много отличных ресурсов.

Я рад, что этот пост был полезен, и я надеюсь, что смогу сорваться с задницы и закончить свою книгу по этому вопросу к концу года / началу следующего года.


37
Это уже готовится, чтобы быть эпическим ответом. Если вы можете указать мне какие-либо ресурсы, в конце концов это будет оценено. Я смотрю на систему SNES или NES, чтобы подражать ей, и делаю ее своим семестровым проектом.
mmcdole

8
Безусловно. Я собираюсь собрать хороший список ресурсов. Если у вас, ребята, есть какие-то конкретные запросы, я сделаю все возможное, чтобы удовлетворить их.
Коди Брошиус

3
@thenonhacker, проект IronBabel, на который есть ссылки в моем разделе ресурсов, принадлежит мне. (Бесстыдная вилка помечена;))
Коди Брошиус

1
«Было доказано, что поиск всего кода в заданном двоичном файле эквивалентен проблеме останова» - Ссылка, пожалуйста? Или это должно быть «Было доказано, что поиск всего кода в любом двоичном файле эквивалентен проблеме Halting»? Также не могу получить доступ к статье
Стейла

4
Вы упоминаете, что пишете книгу; Можете ли вы дать нам обновленную информацию об этом? Мне, например, было бы интересно прочитать это.
Алекс

126

Парень по имени Виктор Мойя дель Баррио написал свою диссертацию на эту тему. Много полезной информации на 152 страницах. Вы можете скачать PDF здесь .

Если вы не хотите регистрироваться в scribd , вы можете найти в PDF название Google «Изучение методов эмуляции программирования» . Есть несколько разных источников для PDF.


43

Эмуляция может показаться пугающей, но на самом деле она гораздо проще, чем симуляция.

Любой процессор обычно имеет хорошо написанную спецификацию, которая описывает состояния, взаимодействия и т. Д.

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

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

Конечно, эмуляторы для видеоигр обычно заботятся о производительности, поэтому они не используют наивные реализации, а также включают в себя код, который взаимодействует с ОС хост-системы, например, для использования рисования и звука.

Учитывая очень низкую производительность старых видеоигр (NES / SNES и т. Д.), В современных системах эмуляция довольно проста. На самом деле, еще более удивительно, что вы можете просто загрузить набор каждой игры SNES или любой игры Atari 2600, если учесть, что когда эти системы были популярны, свободный доступ к каждому картриджу был бы мечтой.


1
Каковы различия между эмуляцией и симуляцией?
Вэй Ху

2
@Wei: Вообще говоря, предполагается, что эмулятор ведет себя «внешне», как система, которую он эмулирует, но нечего сказать, что он должен быть реализован подобным образом. Симулятор реализован таким образом, что имитирует симулируемую систему, и в результате ведет себя как он.
Ури

Когда вы видите «Симулятор», думайте, что он похож, а эмулятор «эмулирует»
mP.


29

Я знаю, что этот вопрос немного устарел, но я бы хотел кое-что добавить к обсуждению. Большинство ответов здесь сосредоточены вокруг эмуляторов, интерпретирующих машинные инструкции систем, которые они эмулируют.

Однако есть очень известное исключение из этого, называемое «UltraHLE» ( статья в WIKIpedia ). UltraHLE, один из самых известных эмуляторов, когда-либо созданных, эмулировал коммерческие игры Nintendo 64 (с приличной производительностью на домашних компьютерах) в то время, когда многие считали, что это невозможно. Фактически, Nintendo все еще производила новые названия для Nintendo 64, когда был создан UltraHLE!

Впервые я увидел статьи об эмуляторах в печатных журналах, где раньше я видел их только в Интернете.

Концепция UltraHLE заключалась в том, чтобы сделать невозможное возможным путем эмуляции вызовов библиотеки C вместо вызовов на уровне машины.


22

Стоит обратить внимание на попытку Имрана Назара написать эмулятор Gameboy на JavaScript.


1
Как получить необработанные инструкции для кода игры Gameboy?
Pacerier

На «сером рынке» продается несколько устройств. Вы не найдете их ни в одном крупном магазине в развитом мире. Эти устройства способны копировать инструкции из игрового картриджа в файлы, которые обычно называются «ПЗУ». Google "Gameboy Roms", но остерегайтесь небезопасных ссылок и сайтов атак!
Река Вивиан

18

Создав свой собственный эмулятор микрокомпьютера BBC 80-х годов (напишите в Google VBeeb), есть ряд вещей, которые нужно знать.

  • Вы не подражаете реальной вещи как таковой, это будет копия. Вместо этого вы подражаете государству . Хороший пример - калькулятор, на самом деле у него есть кнопки, экран, чехол и т. Д. Но для эмуляции калькулятора вам нужно всего лишь эмулировать кнопки вверх или вниз, какие сегменты ЖК-дисплея и т. Д. В основном, набор цифр представляя все возможные комбинации вещей, которые могут измениться в калькуляторе.
  • Вам нужен только интерфейс эмулятора, чтобы он появлялся и вел себя как настоящий. Чем убедительнее это, тем ближе эмуляция. То, что происходит за кулисами, может быть чем угодно. Но для простоты написания эмулятора существует ментальное отображение, которое происходит между реальной системой, то есть чипами, дисплеями, клавиатурами, печатными платами и абстрактным компьютерным кодом.
  • Чтобы эмулировать компьютерную систему, проще всего разбить ее на более мелкие порции и эмулировать эти порции по отдельности. Затем соедините все вместе для готового продукта. Очень похоже на набор черных ящиков с входами и выходами, которые прекрасно подходят для объектно-ориентированного программирования. Вы можете далее подразделить эти куски, чтобы облегчить жизнь.

С практической точки зрения, вы обычно пишете для скорости и точности эмуляции. Это связано с тем, что программное обеспечение в целевой системе будет (может) работать медленнее, чем исходное оборудование в исходной системе. Это может ограничить выбор языка программирования, компиляторов, целевой системы и т. Д.
Кроме того, вы должны описать то, что вы готовы эмулировать, например, нет необходимости эмулировать состояние напряжения транзисторов в микропроцессоре, но это, вероятно, необходимо эмулировать состояние набора регистров микропроцессора.
Вообще говоря, чем меньше уровень детализации эмуляции, тем выше точность воспроизведения исходной системы.
Наконец, информация для более старых систем может быть неполной или не существовать. Поэтому необходимо приобрести оригинальное оборудование или, по крайней мере, оценить другой хороший эмулятор, который кто-то написал!


17

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

Простой подход состоит в том, чтобы интерпретировать инструкции по одному. Это хорошо работает, но медленно. Более быстрый подход - это перекомпиляция - перевод исходного машинного кода в целевой машинный код. Это сложнее, так как большинство инструкций не будут отображаться один на один. Вместо этого вам придется делать сложные обходные пути, которые включают дополнительный код. Но в конце концов это намного быстрее. Большинство современных эмуляторов делают это.


1
Самое плохое - это отсутствие документации на сегодняшний день. Когда вы обнаружите, что модифицированное ядро ​​Z80 в GameBoy Color имеет недокументированные операции с флагами, игра, которую вы тестируете, использует вас, и вы действительно начинаете терять веру.
Каллум Роджерс

1
Пиво: это машинный код (единственное число), а не машинный код (множественное число); так же, как это азбука Морзе, а не азбука Морзе .
Лоуренс Дол

1
@Vilx: На самом деле нет - термин «машинный код», относящийся к набору команд для CPU, использовался с момента появления программного обеспечения и не является множественным. Это относится к « набору инструкций », форме единственного числа, а не к форме «инструкций» во множественном числе. То же, что и программный код, азбука Морзе и т. Д. Использование формы множественного числа закралось от неправильного использования, как правило, теми, кто говорит по-английски в качестве второго языка.
Лоуренс Дол

1
@Software Monkey - Но нельзя ли использовать слово «код» для обозначения одного элемента из набора? Например: « ... --- ...- эти три азбуки Морзе представляют три буквы S, O, S.» Потому ...что это код, представляющий букву "S". Нет?
Vilx-

1
Нет, код неисчисляемое существительное, у него нет формы во множественном числе, как вода или песок ..
Иван

15

При разработке эмулятора вы интерпретируете сборку процессора, на которой работает система (Z80, 8080, процессор PS и т. Д.).

Вам также необходимо эмулировать все периферийные устройства, которые есть в системе (видеовыход, контроллер).

Вы должны начать писать эмуляторы для систем simpe, таких как старый добрый Game Boy (использующий процессор Z80, я не ошибаюсь) ИЛИ для C64.


9
C64 "простая" система? В то время как 6510 является относительно простым (как только вы покрыли незарегистрированные опкоды), звук (SID) и видео (VIC) Чипы ничего , кроме простой. Чтобы достичь приемлемого уровня совместимости, вам нужно их эмулировать - аппаратные ошибки и все такое.
Moobaa

10

Эмулятор очень сложно создать, так как вам нужно смоделировать множество хаков (например, необычных эффектов), проблем с синхронизацией и т. Д.

Пример этого см. По адресу http://queue.acm.org/detail.cfm?id=1755886 .

Это также покажет вам, почему вам нужен мульти-ГГц процессор для эмуляции 1 МГц.


9

Также проверьте Дарек Mihocka в Emulators.com за большой совет по оптимизации на уровне инструкций для JITs, и многих других вкусности на построение эффективных эмуляторов.


7

Я никогда не делал ничего такого, чтобы эмулировать игровую консоль, но однажды я прошел курс, где было задание написать эмулятор для машины, описанной в Структурной компьютерной организации Эндрю Таненбаумса . Это было весело, и это дало мне много моментов ага. Возможно, вы захотите взять эту книгу перед тем, как начать писать настоящий эмулятор.


4

Советы по эмуляции реальной системы или вашей собственной вещи? Я могу сказать, что эмуляторы работают, эмулируя все оборудование. Может быть, не в цепи (как перемещение битов, как HW сделал бы. Перемещение байта является конечным результатом, поэтому копирование байта в порядке). Эмулятор очень сложно создать, так как вам нужно смоделировать множество хаков (например, необычных эффектов), проблем с синхронизацией и т. Д. Если один (входной) фрагмент не верен, вся система может потерпеть неудачу или в лучшем случае иметь ошибку / сбой.


4

Shared Source Device Emulator содержит работоспособна исходный код эмулятора PocketPC / Smartphone (Требуется Visual Studio, работает на Windows). Я работал над V1 и V2 бинарного релиза.

Он решает многие проблемы эмуляции: - эффективный перевод адресов с гостевого виртуального на гостевой физический на виртуальный хост - JIT-компиляция гостевого кода - моделирование периферийных устройств, таких как сетевые адаптеры, сенсорный экран и аудио - интеграция пользовательского интерфейса, для клавиатуры и мыши хоста - сохранение / восстановление состояния, для симуляции резюме из режима пониженного энергопотребления


1

Чтобы добавить ответ, предоставленный @Cody Brocious
В контексте виртуализации, когда вы эмулируете новую систему (CPU, I / O и т. Д.) На виртуальной машине, мы можем увидеть следующие категории эмуляторов.

Интерпретация: bochs является примером интерпретатора, это эмулятор ПК для x86, он берет каждую инструкцию из гостевой системы, переводит ее в другой набор инструкций (хоста ISA) для получения желаемого эффекта. Да, он очень медленный, не кэшируйте ничего, поэтому каждая инструкция проходит один и тот же цикл.

Динамический эмулятор: Qemu - динамический эмулятор. Он выполняет на лету перевод гостевой инструкции, а также кеширует результаты. Лучшая часть заключается в том, что как можно больше команд выполняется непосредственно в хост-системе, что ускоряет эмуляцию. Также, как упомянул Коди, он делит код на блоки (1 поток выполнения).

Статический эмулятор: насколько я знаю, нет статического эмулятора, который мог бы помочь в виртуализации.


1

Как бы я начал эмуляцию.

1. Получите книги, основанные на низкоуровневом программировании, они понадобятся вам для «притворной» операционной системы Nintendo ... game boy ...

2. Получите книги по эмуляции, и, возможно, по разработке. (вы не будете делать ОС, но ближе всего к нему.

3. посмотрите на некоторые эмуляторы с открытым исходным кодом, особенно те, для которых вы хотите создать эмулятор.

4. скопируйте фрагменты более сложного кода в ваш IDE / компилятор. Это избавит вас от написания длинного кода. Это то, что я делаю для разработки ОС, использую район Linux


1

Я написал статью об эмуляции Chip-8 в JavaScript .

Это отличное место для начала, так как система не очень сложна, но вы все равно узнаете, как работают коды операций, стек, регистры и т. Д.

Я скоро напишу более длинное руководство для NES.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.