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

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

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

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

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

Ответ 1

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

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

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

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

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

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

Со всеми этими путями у вас есть общая цель: выполните часть кода, чтобы изменить состояние процессора и взаимодействовать с "оборудованием". Состояние процессора - это конгломерация регистров процессора, обработчиков прерываний и т.д. Для заданного целевого процессора. Для 6502 у вас будет число 8-разрядных целых чисел, представляющих регистры: A, X, Y, P и S; у вас также будет 16-разрядный регистр PC.

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

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

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

  • Код, который не находится в программе для начала (например, сжатый, зашифрованный, сгенерированный/измененный во время выполнения и т.д.), не будет перекомпилирован, поэтому он не будет запускаться
  • Было доказано, что поиск всего кода в данном двоичном эквиваленте эквивалентен проблема с остановкой

Они объединяются, чтобы сделать статическую перекомпиляцию полностью неосуществимой в 99% случаев. Для получения дополнительной информации Майкл Стейл провел большое исследование статической перекомпиляции - лучшее, что я видел.

Другая сторона эмуляции процессора - это способ взаимодействия с оборудованием. Это действительно имеет две стороны:

  • Время процессора
  • Обработка прерываний

Время работы процессора:

Некоторые платформы - особенно старые консоли, такие как NES, SNES и т.д. - требуют, чтобы ваш эмулятор имел строгое время для полной совместимости. С помощью NES у вас есть процессор PPU (блок обработки пикселей), который требует, чтобы процессор аккуратно помещал пиксели в свою память. Если вы используете интерпретацию, вы можете легко подсчитывать циклы и эмулировать правильное время; с динамической/статической перекомпиляцией, все это/много/сложнее.

Обработка прерываний:

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

Эмуляция оборудования:

Есть две стороны для эмуляции данного аппаратного устройства:

  • Эмуляция функциональности устройства
  • Эмулирование реальных интерфейсов устройства

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

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

Я бы углубился в подробности, но есть миллион способов, которыми вы можете пойти с ним. Если у вас есть какие-то конкретные вопросы, не стесняйтесь спрашивать, и я добавлю информацию.

Ресурсы:

Я думаю, что здесь был очень хороший ввод, но есть дополнительные тонны. Я более чем счастлив помочь с любыми вопросами; Я был очень расплывчатым в большинстве случаев просто из-за огромной сложности.

Обязательные ссылки в Википедии:

Общие ресурсы эмуляции:

  • Zophar - вот где я начал с эмуляции, сначала загрузил эмуляторы и в итоге разграбил их огромные архивы документации. Это самый лучший ресурс, который у вас может быть.
  • NGEmu - Не так много прямых ресурсов, но их форумы непобедимы.
  • RomHacking.net - Раздел документов содержит ресурсы, касающиеся архитектуры машин для популярных консолей.

Проекты эмулятора для ссылки:

  • IronBabel - это платформа эмуляции .NET, написанная в Nemerle и перекомпилирующая код на С# на лету. Отказ от ответственности: Это мой проект, поэтому прошу прощения за бесстыдную версию.
  • BSnes - Удивительный эмулятор SNES с целью обеспечения точности цикла.
  • MAME - аркадный эмулятор. Отличная рекомендация.
  • 6502asm.com - Это эмулятор JavaScript 6502 с прохладным небольшим форумом.
  • dynarec'd 6502asm - Это небольшой взлом, который я сделал за день или два. Я взял существующий эмулятор от 6502asm.com и изменил его, чтобы динамически перекомпилировать код для JavaScript для увеличения скорости.

Ссылки на перекомпиляцию процессора:

  • Исследование статической перекомпиляции, сделанное Майклом Стелом (ссылка на выше), завершилась в этой статье, и вы можете найти источник и такие здесь.

Добавление:

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

Возможно, самая захватывающая вещь в эмуляции прямо сейчас - libcpu, начатая вышеупомянутым Майклом Стилом. Это библиотека, предназначенная для поддержки большого количества ядер процессора, которые используют LLVM для перекомпиляции (статические и динамические!). Он получил огромный потенциал, и я думаю, что он будет делать большие вещи для эмуляции.

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

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

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

Ответ 7

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

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

Ответ 8

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

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

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

Ответ 9

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

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

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

Ответ 10

Также ознакомьтесь с Darek Mihocka Emulators.com за отличные советы по оптимизации уровня инструкций для JIT и многие другие преимущества по созданию эффективных эмуляторов.

Ответ 11

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

Ответ 12

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

Ответ 13

эмулятор общего источника устройств содержит встроенный исходный код для эмулятора PocketPC/Smartphone (требуется Visual Studio, работает в Windows). Я работал над V1 и V2 двоичной версии.

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

Ответ 14

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

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

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

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

Ответ 15

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

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

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

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

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

Ответ 16

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

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

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