I got this idea from a friend, but whenever I wanted to learn a new language, I would quickly hack out a 4001 emulator in that language. Its an interesting but quick challenge.
I wish there were more people who thought about and understood these low-level basics; it feels like today, almost everyone who uses a computer is at such a far level of abstraction from the base hardware that they've lost the intuition for how computers behave the way they do and everything seems mysterious to them.
This book is highly recommended to anyone interested in how computers work; it starts off with very basic electronics and goes up to a full CPU, plus some software stuff near the end:
http://www.charlespetzold.com/code/
I've written an (incomplete) 8086 emulator in C++ [1] as part of a bigger project [2]. This kind of thing is really fun to do and gives you a lot of insight of how CPUs work (as a black box, though).
This guy spent three years disassembling the Outrun arcade ROM, then 2 years re-implementing it in C++, then extending his engine with features like high fps and new game modes, and is now onto creating extender tools like track and time editors.
Along the way he found several new bugs and provides a fixed ROM which can be flashed to the arcade board. He's also got a project to develop an SoC which uses his engine to run an arcade cabinet, completely replacing the original board.
It's a phenomenal effort and an amazing blog to read back through.
A nice book I have found on the topic of virtual machines as they relate to programming languages is http://www.amazon.com/Compiler-Design-Machines-Reinhard-Wilh.... It is a pretty good book although the focus is less on emulating actual hardware and more on designing and implementing custom virtual machines as compilation targets for imperative, functional, and logic languages.
I kinda wish there were more meetups that focused on this kind of stuff instead of the latest and greatest frameworks. This kind of fundamental theory is applicable in any kind of application and framework setting.
I've done this in Racket. It was quite a fun little learning project. I've been meaning to dust off the core and add some more I/O hardware to it though.
http://pastebin.com/YkhRsuih - C
http://pastebin.com/L79CeeGB - Haskell
http://pastebin.com/LybWwGzm - JS
http://pastebin.com/ZVDiRmP6 - MHS this language cant take input (its an educational toy language for a course)