Writing an emulator is almost as much fun as writing a compiler. And when you are done, you will have another level of appreciation of how computers work.
http://schierlm.github.io/OberonEmulator/
I sent a bunch of patches to rework the in-browser emulator a couple weeks ago. If you don't know C, I recommend reading through the JS emulator's source. (View source should suffice—it's all unminified vanilla JS; there's no opinionated JS framework involved.)
With it running in the browser, the emulator frontend treats the web platform as its widget toolkit. The code to interface with that is in webdriver.js[2] and takes about 1000 lines of code. The CPU and memory operations themselves are implemented in risc.js[3] and only take about 1/3 that.
To follow along with instruction fetching/decoding/execution, you'll need to understand the ISA. There's a good 3-page overview linked from projectoberon.com under the title "RISC Architecture"[4]. A more in-depth description of the design is also available[5].
I have some tentative work for a machine-code level debugger online[6]. It's unfinished, however, so it comes with no documentation and the toolbar icons are missing. (There are tooltips, however.) So you can play with it if you feel like watching the registers and flags change while stepping through machine instructions.
1. https://github.com/pdewacht/oberon-risc-emu/
2. https://github.com/schierlm/OberonEmulator/blob/master/JS/we...
3. https://github.com/schierlm/OberonEmulator/blob/master/JS/ri...
4. https://www.inf.ethz.ch/personal/wirth/FPGA-relatedWork/RISC...
5. https://www.inf.ethz.ch/personal/wirth/FPGA-relatedWork/RISC...
6. https://www.colbyrussell.com/staging/aubergine/emu.html?imag...