In fact, your emulator (rather rudely) is possible on linux with clean user space code.
To create an emulator, simply add a second thread or process (using shared memory, or perhaps the mmap'd and inotify file), observing a memory that mimics the displayed memory.
For a real hardware driver, you need a tiny bit of kernel code, but it may just be what maps the actual hardware addresses in user space to the corresponding permissions. In fact, this regresses the modern multi-user operating environment to the point that it acts like an old dos panel or a simple microcontroller - not a good practice, but it is functional, at least where security is not a concern.
Another thing you might consider is running the code in a virtual machine.
If the code you are going to execute is your own, it is best to write it in a portable way, in order to abstract from accessing the hardware to functions that you can rewrite for each platform (for example, OS, hardware version, or physical / emulated). These methods are more useful if this is someone else's existing code that you need to create the environment. Another thing that you can consider (if the original is not too tightly integrated) uses library-level interception at the level of dynamic libraries of certain functions, for example, LD_PRELOAD on linux or dll wrappers in windows. Or, for that matter, fixing the binary.
source share