Programing

에뮬레이터는 어떻게 작동하며 어떻게 작성됩니까?

lottogame 2020. 9. 28. 07:52
반응형

에뮬레이터는 어떻게 작동하며 어떻게 작성됩니까? [닫은]


에뮬레이터는 어떻게 작동합니까? NES / SNES 또는 C64 에뮬레이터를 보면 놀랍습니다.

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

특정 조립 지침을 해석하여 해당 기계의 프로세서를 에뮬레이션해야합니까? 그 밖에 무엇이 들어가나요? 일반적으로 어떻게 설계됩니까?

에뮬레이터 (특히 게임 시스템) 작성에 관심이있는 사람에게 조언을 해줄 수 있습니까?


에뮬레이션은 다각적 인 영역입니다. 다음은 기본 아이디어와 기능적 구성 요소입니다. 나는 그것을 조각으로 나누고 편집을 통해 세부 사항을 채울 것입니다. 제가 설명 할 많은 것들은 프로세서의 내부 작동에 대한 지식을 필요로합니다. 어셈블리 지식이 필요합니다. 특정 사항에 대해 너무 모호한 경우이 답변을 계속 개선 할 수 있도록 질문 해주세요.

기본 아이디어 :

에뮬레이션은 프로세서 및 개별 구성 요소의 동작을 처리하여 작동합니다. 시스템의 각 개별 부분을 구축 한 다음 하드웨어에서 와이어처럼 부분을 연결합니다.

프로세서 에뮬레이션 :

프로세서 에뮬레이션을 처리하는 방법에는 세 가지가 있습니다.

  • 해석
  • 동적 재 컴파일
  • 정적 재 컴파일

이러한 모든 경로를 통해 전체적인 목표는 동일합니다. 코드를 실행하여 프로세서 상태를 수정하고 '하드웨어'와 상호 작용합니다. 프로세서 상태는 주어진 프로세서 대상에 대한 프로세서 레지스터, 인터럽트 처리기 등의 집합체입니다. 6502의 경우, 레지스터를 나타내는 8 비트 정수의 번호를 가지고 것 : A, X, Y, P, 그리고 S; 16 비트 PC레지스터도 있습니다.

해석을 통해 IP(명령 포인터- PC프로그램 카운터 라고도 함) 에서 시작하여 메모리에서 명령을 읽습니다. 코드는이 명령어를 구문 분석하고이 정보를 사용하여 프로세서에서 지정한대로 프로세서 상태를 변경합니다. 해석의 핵심 문제는 매우 느리다는 것입니다. 주어진 명령을 처리 할 때마다이를 디코딩하고 필요한 작업을 수행해야합니다.

동적 재 컴파일을 사용하면 해석과 비슷하게 코드를 반복하지만 단순히 opcode를 실행하는 대신 작업 목록을 작성합니다. 분기 명령어에 도달하면이 작업 목록을 호스트 플랫폼의 기계어 코드로 컴파일 한 다음이 컴파일 된 코드를 캐시하고 실행합니다. 그런 다음 주어진 명령 그룹에 다시 도달하면 캐시에서 코드를 실행하기 만하면됩니다. (BTW, 대부분의 사람들은 실제로 명령 목록을 작성하지 않고 즉시 기계 코드로 컴파일합니다. 이로 인해 최적화하기가 더 어렵지만 충분한 사람들이 관심을 보이지 않는 한이 답변의 범위를 벗어납니다)

정적 재 컴파일을 사용하면 동적 재 컴파일과 동일하게 수행하지만 분기를 따릅니다. 결국 프로그램의 모든 코드를 나타내는 코드 청크를 작성하게되며 추가 간섭없이 실행할 수 있습니다. 다음 문제가 아니라면 이것은 훌륭한 메커니즘이 될 것입니다.

  • 프로그램에없는 코드 (예 : 압축, 암호화, 런타임시 생성 / 수정 등)는 다시 컴파일되지 않으므로 실행되지 않습니다.
  • 주어진 바이너리에서 모든 코드를 찾는 것이 Halting 문제 와 동일하다는 것이 입증되었습니다.

이것들이 결합되어 99 %의 경우 정적 재 컴파일을 완전히 불가능하게 만듭니다. 자세한 정보를 위해 Michael Steil은 정적 재 컴파일에 대한 훌륭한 연구를 수행했습니다.

프로세서 에뮬레이션의 다른 측면은 하드웨어와 상호 작용하는 방식입니다. 여기에는 두 가지 측면이 있습니다.

  • 프로세서 타이밍
  • 인터럽트 처리

프로세서 타이밍 :

특정 플랫폼, 특히 NES, SNES 등과 같은 구형 콘솔에서는 에뮬레이터가 완전히 호환 되려면 엄격한 타이밍이 필요합니다. NES를 사용하면 CPU가 정확한 순간에 픽셀을 메모리에 넣어야하는 PPU (픽셀 처리 장치)가 있습니다. 해석을 사용하면 쉽게주기를 계산하고 적절한 타이밍을 에뮬레이션 할 수 있습니다. 동적 / 정적 재 컴파일을 사용하면 상황이 / lot / 더 복잡해집니다.

인터럽트 처리 :

인터럽트는 CPU가 하드웨어와 통신하는 기본 메커니즘입니다. 일반적으로 하드웨어 구성 요소는 CPU에 어떤 인터럽트를 처리하는지 알려줍니다. 이것은 매우 간단합니다. 코드가 주어진 인터럽트를 던질 때 인터럽트 핸들러 테이블을보고 적절한 콜백을 호출합니다.

하드웨어 에뮬레이션 :

주어진 하드웨어 장치를 에뮬레이션하는 데는 두 가지 측면이 있습니다.

  • 장치의 기능 모방
  • 실제 장치 인터페이스 에뮬레이션

하드 드라이브의 경우를 살펴보십시오. 이 기능은 백업 스토리지, 읽기 / 쓰기 / 포맷 루틴 등을 생성하여 에뮬레이션됩니다.이 부분은 일반적으로 매우 간단합니다.

장치의 실제 인터페이스는 조금 더 복잡합니다. 이것은 일반적으로 메모리 매핑 레지스터 (예 : 장치가 신호를 수행하기 위해 변경 사항을 감시하는 메모리 부분)와 인터럽트의 일부 조합입니다. 하드 드라이브의 경우 읽기 명령, 쓰기 등을 배치 한 다음이 데이터를 다시 읽는 메모리 매핑 영역이있을 수 있습니다.

더 자세히 설명하겠습니다.하지만이를 사용할 수있는 방법은 백만 가지가 있습니다. 여기에 특정 질문이있는 경우 언제든지 문의하시면 정보를 추가하겠습니다.

자원:

내가 소개 여기 꽤 좋은를 제공했다고 생각하지만, 거기 추가 영역은. 질문이 있으면 기꺼이 도와 드리겠습니다. 나는 단지 엄청난 복잡성으로 인해 이것의 대부분에서 매우 모호했습니다.

필수 Wikipedia 링크 :

일반 에뮬레이션 리소스 :

  • Zophar -- This is where I got my start with emulation, first downloading emulators and eventually plundering their immense archives of documentation. This is the absolute best resource you can possibly have.
  • NGEmu -- Not many direct resources, but their forums are unbeatable.
  • RomHacking.net -- The documents section contains resources regarding machine architecture for popular consoles

Emulator projects to reference:

  • IronBabel -- This is an emulation platform for .NET, written in Nemerle and recompiles code to C# on the fly. Disclaimer: This is my project, so pardon the shameless plug.
  • BSnes -- An awesome SNES emulator with the goal of cycle-perfect accuracy.
  • MAME -- The arcade emulator. Great reference.
  • 6502asm.com -- This is a JavaScript 6502 emulator with a cool little forum.
  • dynarec'd 6502asm -- This is a little hack I did over a day or two. I took the existing emulator from 6502asm.com and changed it to dynamically recompile the code to JavaScript for massive speed increases.

Processor recompilation references:

  • The research into static recompilation done by Michael Steil (referenced above) culminated in this paper and you can find source and such here.

Addendum:

It's been well over a year since this answer was submitted and with all the attention it's been getting, I figured it's time to update some things.

Perhaps the most exciting thing in emulation right now is libcpu, started by the aforementioned Michael Steil. It's a library intended to support a large number of CPU cores, which use LLVM for recompilation (static and dynamic!). It's got huge potential, and I think it'll do great things for emulation.

emu-docs has also been brought to my attention, which houses a great repository of system documentation, which is very useful for emulation purposes. I haven't spent much time there, but it looks like they have a lot of great resources.

I'm glad this post has been helpful, and I'm hoping I can get off my arse and finish up my book on the subject by the end of the year/early next year.


A guy named Victor Moya del Barrio wrote his thesis on this topic. A lot of good information on 152 pages. You can download the PDF here.

If you don't want to register with scribd, you can google for the PDF title, "Study of the techniques for emulation programming". There are a couple of different sources for the PDF.


Emulation may seem daunting but is actually quite easier than simulating.

Any processor typically has a well-written specification that describes states, interactions, etc.

If you did not care about performance at all, then you could easily emulate most older processors using very elegant object oriented programs. For example, an X86 processor would need something to maintain the state of registers (easy), something to maintain the state of memory (easy), and something that would take each incoming command and apply it to the current state of the machine. If you really wanted accuracy, you would also emulate memory translations, caching, etc., but that is doable.

In fact, many microchip and CPU manufacturers test programs against an emulator of the chip and then against the chip itself, which helps them find out if there are issues in the specifications of the chip, or in the actual implementation of the chip in hardware. For example, it is possible to write a chip specification that would result in deadlocks, and when a deadline occurs in the hardware it's important to see if it could be reproduced in the specification since that indicates a greater problem than something in the chip implementation.

Of course, emulators for video games usually care about performance so they don't use naive implementations, and they also include code that interfaces with the host system's OS, for example to use drawing and sound.

Considering the very slow performance of old video games (NES/SNES, etc.), emulation is quite easy on modern systems. In fact, it's even more amazing that you could just download a set of every SNES game ever or any Atari 2600 game ever, considering that when these systems were popular having free access to every cartridge would have been a dream come true.


I know that this question is a bit old, but I would like to add something to the discussion. Most of the answers here center around emulators interpreting the machine instructions of the systems they emulate.

However, there is a very well-known exception to this called "UltraHLE" (WIKIpedia article). UltraHLE, one of the most famous emulators ever created, emulated commercial Nintendo 64 games (with decent performance on home computers) at a time when it was widely considered impossible to do so. As a matter of fact, Nintendo was still producing new titles for the Nintendo 64 when UltraHLE was created!

For the first time, I saw articles about emulators in print magazines where before, I had only seen them discussed on the web.

The concept of UltraHLE was to make possible the impossible by emulating C library calls instead of machine level calls.


Something worth taking a look at is Imran Nazar's attempt at writing a Gameboy emulator in JavaScript.


Having created my own emulator of the BBC Microcomputer of the 80s (type VBeeb into Google), there are a number of things to know.

  • You're not emulating the real thing as such, that would be a replica. Instead, you're emulating State. A good example is a calculator, the real thing has buttons, screen, case etc. But to emulate a calculator you only need to emulate whether buttons are up or down, which segments of LCD are on, etc. Basically, a set of numbers representing all the possible combinations of things that can change in a calculator.
  • You only need the interface of the emulator to appear and behave like the real thing. The more convincing this is the closer the emulation is. What goes on behind the scenes can be anything you like. But, for ease of writing an emulator, there is a mental mapping that happens between the real system, i.e. chips, displays, keyboards, circuit boards, and the abstract computer code.
  • To emulate a computer system, it's easiest to break it up into smaller chunks and emulate those chunks individually. Then string the whole lot together for the finished product. Much like a set of black boxes with inputs and outputs, which lends itself beautifully to object oriented programming. You can further subdivide these chunks to make life easier.

Practically speaking, you're generally looking to write for speed and fidelity of emulation. This is because software on the target system will (may) run more slowly than the original hardware on the source system. That may constrain the choice of programming language, compilers, target system etc.
Further to that you have to circumscribe what you're prepared to emulate, for example its not necessary to emulate the voltage state of transistors in a microprocessor, but its probably necessary to emulate the state of the register set of the microprocessor.
Generally speaking the smaller the level of detail of emulation, the more fidelity you'll get to the original system.
Finally, information for older systems may be incomplete or non-existent. So getting hold of original equipment is essential, or at least prising apart another good emulator that someone else has written!


Yes, you have to interpret the whole binary machine code mess "by hand". Not only that, most of the time you also have to simulate some exotic hardware that doesn't have an equivalent on the target machine.

The simple approach is to interpret the instructions one-by-one. That works well, but it's slow. A faster approach is recompilation - translating the source machine code to target machine code. This is more complicated, as most instructions will not map one-to-one. Instead you will have to make elaborate work-arounds that involve additional code. But in the end it's much faster. Most modern emulators do this.


When you develop an emulator you are interpreting the processor assembly that the system is working on (Z80, 8080, PS CPU, etc.).

You also need to emulate all peripherals that the system has (video output, controller).

You should start writing emulators for the simpe systems like the good old Game Boy (that use a Z80 processor, am I not not mistaking) OR for C64.


Emulator are very hard to create since there are many hacks (as in unusual effects), timing issues, etc that you need to simulate.

For an example of this, see http://queue.acm.org/detail.cfm?id=1755886.

That will also show you why you ‘need’ a multi-GHz CPU for emulating a 1MHz one.


Also check out Darek Mihocka's Emulators.com for great advice on instruction-level optimization for JITs, and many other goodies on building efficient emulators.


I've never done anything so fancy as to emulate a game console but I did take a course once where the assignment was to write an emulator for the machine described in Andrew Tanenbaums Structured Computer Organization. That was fun an gave me a lot of aha moments. You might want to pick that book up before diving in to writing a real emulator.


Advice on emulating a real system or your own thing? I can say that emulators work by emulating the ENTIRE hardware. Maybe not down to the circuit (as moving bits around like the HW would do. Moving the byte is the end result so copying the byte is fine). Emulator are very hard to create since there are many hacks (as in unusual effects), timing issues, etc that you need to simulate. If one (input) piece is wrong the entire system can do down or at best have a bug/glitch.


The Shared Source Device Emulator contains buildable source code to a PocketPC/Smartphone emulator (Requires Visual Studio, runs on Windows). I worked on V1 and V2 of the binary release.

It tackles many emulation issues: - efficient address translation from guest virtual to guest physical to host virtual - JIT compilation of guest code - simulation of peripheral devices such as network adapters, touchscreen and audio - UI integration, for host keyboard and mouse - save/restore of state, for simulation of resume from low-power mode


To add the answer provided by @Cody Brocious
In the context of virtualization where you are emulating a new system(CPU , I/O etc ) to a virtual machine we can see the following categories of emulators.

Interpretation: bochs is an example of interpreter , it is a x86 PC emulator,it takes each instruction from guest system translates it in another set of instruction( of the host ISA) to produce the intended effect.Yes it is very slow , it doesn't cache anything so every instruction goes through the same cycle.

Dynamic emalator: Qemu is a dynamic emulator. It does on the fly translation of guest instruction also caches results.The best part is that executes as many instructions as possible directly on the host system so that emulation is faster. Also as mentioned by Cody, it divides the code into blocks ( 1 single flow of execution).

Static emulator: As far I know there are no static emulator that can be helpful in virtualization.


How I would start emulation.

1.Get books based around low level programming, you'll need it for the "pretend" operating system of the Nintendo...game boy...

2.Get books on emulation specifically, and maybe os development. (you won't be making an os, but the closest to it.

3.look at some open source emulators, especially ones of the system you want to make an emulator for.

4.copy snippets of the more complex code into your IDE/compliler. This will save you writing out long code. This is what I do for os development, use a district of linux


I wrote an article about emulating the Chip-8 system in JavaScript.

It's a great place to start as the system isn't very complicated, but you still learn how opcodes, the stack, registers, etc work.

I will be writing a longer guide soon for the NES.

참고 URL : https://stackoverflow.com/questions/448673/how-do-emulators-work-and-how-are-they-written

반응형