While working on some SuperH binaries, I wanted to get a deep understanding on how the SuperH CPU works and get a way to simply visualise the register values.
From that problem, I decided to create a simple front-end that displays CPU memory.
The first version was a simple floating panel, with code getting read and the basic operations
ADD getting supported.
The UI wasn't any synchronized with the code reading loop, and we had to press "refresh" every few seconds to see the register updating. Still, I added some "Memo" pattern to watch the change between cycles and follow register updates easily. Small feature, but high profit !
Getting the assembly synced
The next major challenge was to get the binary instructions dissembled and synced with the registers UI. After searching for the best way to draw a text, I decided that using a Canvas element was best suited for this case, and would provide some UI freedom and smooth integration if correctly managed :
Adding support for basic branching, I provided buttons to run and step that would update the register state at any change. Since I tried to get my code as reactive as possible, the Memo feature of the register got working out of the box without any change to the code base, and that was awesome !
With more and more OPCodes getting implemented, I put a strict unit testing to every OPCode and followed by GUI testing. That way, if any regression would surface I'd easily catch them.
Enabling easier branch visualisation
After getting the basic OPCode working, I found difficult to catch on with
BF and others jump OPCodes. I added a cool IDA-like arrow visualisation.
I programmed the arrow to dynamically disappear and re-use themselves to save repaint cycles on the canvas. The Canvas UI feels responsive at any time and don't suffer window-resize lag that TK unfortunately have.
Editing ASM on the fly
After getting the basic emulator done, I wanted to be able to modify the stack to replace OPCode with a custom one, or change the
PC (Pointer) position. Using the useful "right click menu", I added an option to edit the current OPCode that would reassemble it and preview on the dialog :
Re-using the official SuperH OPCodes specs, I wrote a simple HTML parser that would generate python code and RuK-specific OPCode specs automatically. The code has to be reliable, and since this was generated I manually merged one by one the OPCode checking for possible misunderstandings of the pseudocode. The good point was that I could re-use it to add verbose logging to the console :
When working on some big project (that aren't simply made as PoC) I try to make a documentation on how to use the code base and how to do common procedures. I wrote for now two files, one on how to use the "Core" responsible for handling raw binary and emulating it and another on how to add and edit the OPCodes.
The last one explained how they are identified in the
opcodes file and the use of masking. I then explained how the emulator would look them up and execute code, and finally how to write your unit testing for it.
As I always do for public-purpose project, I put a README.md file explaining the main features of the program, how to install it and how to get started with the GUI. I also discussed the Unit Testing and Design Choices since I often get questions on "why not using that" or "why not doing this".
What I learned from this
Writing Canvas code is generally difficult. I found TK Canvas a bit special at first, but easily got into it. CPU are complex things, but writing an emulator for some RISC ISA helped me to understand so much about their working. Writing UI with TK isn't my favorite, but can sure look fine.
I'd love to get back on this project later and add some more features, like a complete Linux ELF reader, and some IO directly linked to memory !
Want more ?
I've got a lot of other awesome projectsSee them all !