I wanted to have a modular emulator that is flexible and easy to develop new features on. I also wanted something that is very close to the reality. For example, I wanted to be able to develop new emulated peripheral later that I could "plug" in my emulator, just the way you plug peripherals to your machine.
I decided to use a three layers design. Here are these three layers in one schema :
The core layer contains all components, and only them, needed to have a working computer. That means that we could instantiate only a core layer and play with it. That's interesting for studying purpose but it results in a deaf and blind computer. The core layer can be seen as the computer seen from inside itself (inside this layer, programs are running as if they were in the real computer).
The hardware layer is a software representation of the emulated computer. This representation is independent from the graphical interface. For example, a video output is represented by a pixel matrix, a joystick button by a simple flag.
This layer should contain representation of all the objects from the emulated world, like floppy disks or ROM cartriges. It should also contain all the logic of the emulator so the next layer is just in charge of the user interface.
GUI layer is in charge of representing the hardware layer to the user.