one girl's diary of improvisational engineering

Robot Odyssey Chip Disassembler

I’ve been spending more time hacking on Robot Odyssesy lately. Most of it has had a specific purpose… I’ll write a separate blog post on that project once it’s a bit more fully baked. In the mean time, the reverse engineering has had some useful side-effects.

Chip Simulation

If you haven’t heard of Robot Odyssey, it’s a game where you build logic circuits that control robots in order to solve puzzles. You can build circuits directly inside the robots, but you can also program them into ‘chips’- small 8-pin integrated circuits. The game also comes with several chips: a clock generator, 4-bit counter, and the infamous “wallhugger”, a chip you can stick in your robot to have it follow the walls of a maze.

Once you ‘burn’ a circuit into a chip, you can load and save it but you can’t see inside. So this has made the built-in chips a bit of a mystery. There’s no way in-game to see how they work, and for all we know they could be ‘magic’ in some way. I had speculated a bit on how they store the compiled chips. Was it some kind of super-optimized machine code? Or maybe some kind of encoded Programmable Array Logic that was especially quick to simulate on an 8086 processor?

Well, it turns out that the code for simulating chips is clever in places, but the file format is quite straightforward. It’s sort of halfway between an electrical netlist and a bytecode language. On every in-game clock tick, every bytecode instruction in the chip executes in order. Instructions can represent logic gates (AND, OR, XOR, NOT, RS flip-flop), or they can enter/exit a nested chip. Bytecode parameters can be one of two data types: The state of a pin, or a list of pin addresses.

Second opcode (07). This exits a chip. Since this is the outermost chip, after this opcode is the end of the chip’s electrical data. The parameters for this opcode are a list of lists which describes ‘nodes’, or places where we need to copy a pin state directly from one place to another.

First list:

Source address (00 02). This is Pin 3.

First destination (00 09). This is the first pin of the AND gate.

End of list (FF)

Second list:

Source address (00 03). This is Pin 4.

First destination (00 0a). This is the second pin of the AND gate.

End of list (FF)

End of list (FF)

Afterwards is garbage. In this case, (FF FF FF). This is probably left over in memory at the time the chip was compiled, and doesn’t mean anything. The chip interpreter doesn’t read this data.

Chip Disassembler

So, I figured out (I think) the entire file format, and wrote a Python script to disassemble it into something a little more human-readable. The above example chip disassembles to: