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

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

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

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

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

16 ответов


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

основные идеи:

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

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

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

  • толкование
  • динамическая перекомпиляция
  • статический перекомпиляции

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

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

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

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

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

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

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

    времени
  • обработка прерываний

процессор сроки:

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

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

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

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

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

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

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

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

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

ресурсы:

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

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

эмуляция General ресурсы:

  • Софар -- Именно здесь я начал с эмуляции, сначала загрузив эмуляторы и в конечном итоге разграбив их огромные архивы документации. Это самый лучший ресурс, который вы можете иметь.
  • NGEmu -- не так много прямых ресурсов, но их форумы непобедимы.
  • RomHacking.net -- раздел Документы содержит ресурсы по архитектуре на популярных консолях!--20-->

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

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

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

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

дополнение:

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

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

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

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


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

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


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

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

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

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

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

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


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

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

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

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


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


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

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

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


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

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


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

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

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


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

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

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


также проверьте Darek Mihoca's Emulators.com для больших советов по оптимизации на уровне инструкций для Джитов и многих других лакомств по созданию эффективных эмуляторов.


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


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


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

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


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

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

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

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


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

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

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

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

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


Я написал статью о подражании система Chip-8 в JavaScript.

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

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