Preserving old software is all about storing it and keeping it running.
With the most important part being the later one. The best way to keep things running is by emulating the old and obsolete hardware as accurate as possible.
In computing, an emulator is hardware or software that enables one computer system (called the host) to behave like another computer system (called the guest). An emulator typically enables the host system to run software or use peripheral devices designed for the guest system. Emulation refers to the ability of a computer program in an electronic device to emulate (or imitate) another program or device.Wikipedia: Emulator
There are a lot of different types of emulators for all sorts of purposes.
There’s things like bochs which is effectively emulating the hardware of a PC on chip-level and can run virtually anywhere:
Bochs is a highly portable open source IA-32 (x86) PC emulator written in C++, that runs on most popular platforms. It includes emulation of the Intel x86 CPU, common I/O devices, and a custom BIOS. Bochs can be compiled to emulate many different x86 CPUs, from early 386 to the most recent x86-64 Intel and AMD processors which may even not reached the market yet.bochs: the Open Source IA-32 Emulation Project
Emulators of game consoles are alike that – they are emulating the whole system hardware and are able to run original and unchanged code by replicating the exact hardware. Sometimes more and sometimes less exactly.
Hardware emulation in itself an extremely interesting field of software engineering. There’s the hard way to emulate everything accurately (and slowly) by doing what the actual old hardware would have done but maybe in software (or even in replicated hardware).
In regards of old game console hardware there are even now specialized distributions of lots of hardware/system emulators available for specific and readily available hardware like the RaspberryPi. Some of them recently have gotten some nice updates.