Dokka wrote on 2024-01-17, 13:52:
I apologize for the noob question, but why do you need a recompiler to emulate old PCs on a modern processor with x86-64 archite […]
I apologize for the noob question, but why do you need a recompiler to emulate old PCs on a modern processor with x86-64 architecture?
Don't x86-64 processors have a native, backwards compatible instruction set?
Probably some applications require particularly accurate emulation of older systems, but for mass gaming use, isn’t it possible to create a separate accelerated mode?
The Internet is full of examples of installing Win 98-95 and even MS DOS on modern computers, and for gaming use of old operating systems, the only thing missing is video drivers with support for 3D acceleration for modern video cards and sound drivers.
The key point of the videos you've seen of running DOS on a modern PC is that every Intel CPU, even to this day, boots up in a mode functionally equivalent to a 40 year old PC, for legacy reasons. You can run old code on it, and your 4080 GPU still knows how to act like a VGA from 1993, but it's mostly a party trick. People don't want to shut down their systems and reboot into DOS, and even then, you're stuck with the hardware you have in your system. This mode is pretty much unavailable once you've booted into a modern 64-bit OS.
So that leaves us with running code while booted into our OS, which can be done either through virtualization, or what is called Native Code Execution (NCE), which is done on ARM by emulators like Yuzu, to make games playable on your ARM-powered smartphone. The biggest drawback is that it limits you to hosts with the same architecture as the emulated machine, with a fairly similar ISA. So no more 86Box on your Macbook.
NCE isn't going to help you run 16-bit DOS programs when you are happily running the host in 64-bit mode, nor is it going to timewarp the circa-2020 Intel ISA back to 1993 for you, or pretend you have a type of bus or specific piece of hardware that you do not. If you have to rewrite a bunch of code to accommodate these differences, you're already basically doing recompilation. I think it works well for Yuzu because the guest device and the devices emulating it are from relatively the same timeframe.
The mentioned emulators are also trying to be fairly accurate in terms of the speed and timings of the machines they emulate for maximum compatibility, which is made difficult when the native code executes at a blistering rate compared to what you're trying to emulate. There's a lot of code out there that never assumed the astonishing single-threaded speed of a modern PC - divisions by 0 or games that run at unplayable speeds are common symptoms. This has been an issue even on games as recent as Skyrim - above a certain FPS the physics engine goes haywire. This is an issue with recompilation as well, but you have more control over the intended timing of translated blocks.
When virtualizing the CPU, emulating specific, era-accurate hardware can be tricky, too. Take for example a hypothetical VGA card - reading and writing to the memory-mapped VRAM has side effects. Reading sets the cards internal latches, and writing memory passes bytes through the card's write mode pipeline. These side effects can't be handled by a simple mapped buffer, so we may have to do an expensive context switch called an 'VM Exit'. Hypervisors typically have special drivers for their video cards and other devices to take advantage of internal optimizations. We start getting into situations where high level emulation is more practical, but PCem and 86box are low-level emulators.
Nothing I've said is insurmountable, I think, it's just a matter if there is enough talent, resources, time and effort available to accomplish it.
MartyPC: A cycle-accurate IBM PC/XT emulator | https://github.com/dbalsom/martypc