This is something I coded back on the 27th of October, and is going to be used in Hacker's Edge to allow players to create their own viruses and worms which can affect the stability of servers. It will not run out of the box, as I did not include the binary file. However, if you comment out the loading of this binary file, you will be placed into a coding interface, which is very simple. Essentially, I built this as a foundation for other Python applications I might build that I want to be scriptable in a machine-like language. Binary files are very small and easier to distribute across platforms, and are more difficult to tamper with. Of course, they still can be edited. The goal of this was to make a simple virtual machine within Python, but executes controlled code. It will hopefully not allow scripters to exploit anything in the underlying system.
This is also more of a byte-code virtual machine than anything else. What I plan on building perhaps is a simple scripting language which can then be compiled into this simple byte-code. The byte-code virtual machine will then execute it in the controlled environment.
At the moment extending the CPU is more like copying the entire Python file into your program and making the modifications there. This simulator is class-based, but at this moment, extending it really won't help at extending it's abilities. Furthermore, there is also a main set of CPU op-codes, and then there is an interrupt table, which is used for higher level functions like accessing storage and copying large memory blocks. The CPU has a simple set of registers, which are AX, BX, CX, and DX. If you have dabbled with Assembly before, these are no doubt familiar. They should also be familiar to anyone who has taken a Computer Science course, as these are the core registers in most current CPUs, including Intel, and I believe ARM.
The built-in byte-code assembler is just that, an assembler like language, but with some changes to make it easier to use in some senses. It fully supports JMPs, and conditionals as well. Currently the op-codes are rather limited, however for most applications, altering the interrupt table should be what you do. The point of the interrupt table in this simulator is to access application-specific functions, like how real interrupt tables on Intel CPUs. You normally use a software interrupt to access a specific software/driver/OS feature. The CPU op-codes are mostly entirely mathematical, with the exception here or there for CPU-specific operations.
A very interesting idea would be to implement some sort of dynamic compiler, whereas it takes this byte-code and dynamically constructs a Python statement which is then passed directly to eval or similar functions. This may speed up the overall execution of the CPU simulator, but I haven't been able to test it with CPU intensive data yet, so the simulator is not noticeably slower than Python code running natively itself.
A small bit of trivia before I close this post: Back in the good old DOS days, 1994 abouts, I used to program in Microsoft QBasic on my IBM PS/2 Tallgrass 80286 machine. I was roughly 11 years old at the time. The most interesting part of my coding was that I was writing a simple virtual machine to run simple scripts for RPG games I was making. Back then, like now, I believe in modular code. So rather than building all my RPG games logic directly into QBasic, I built the logic using my own simple assembler-like language, which was then binary loaded into the game when it needed to run. The source code BAS file was basically a simple RPG Game Engine, nothing more. The map files connected to say which script file to load for various actions taken by the player. The Engine just needed to know what initial map to load, and with what tileset. This enabled the engine to be reused for various projects.
You can browse or download the Simple CPU simulator code from my Bitbucket.