2017-03-21

Programming the Wireworld Computer

I previously wrote on Wireworld here: World of wires
It’s an interesting and entertaining cellular automaton, particularly the ease of simulating logic circuits it offers. Please take a look at the text and browse the links provided if you need a refresher on the rules of Wireworld.
One of the most fascinating things ever done in Wireworld is an implementation of a complete working computer (by David Moore,Mark Owen et al.). The computer (and its verbose description) can be found at: https://quinapalus.com/wi-index.html. The computer is presented there running a hard-coded prime search program (by Michael Fryers). Ever since I saw the computer, I thought it would be very fun to have a go at programming it. And wouldn’t it be great to have an interactive online tool to do just that?
The simulator is available here: Wireworld simulator
The program simulates the Quinapalus machine, and provides an interface to inject the instructions/data into its register bank. The machine can then be restarted to run a completely custom program.
The programming of the machine boils down to inserting a proper arrangement of pixels into its general purpose registers. I had to strip down the already working demonstration to revert it to its bare-metal state. In order to do that, I removed every unnecessary electron and synchronized the machine so that the electrons in the registers are aligned. The program can then insert the electrons and tails into the registers at their proper positions. The blank state machine is presented in Fig. 1.

Fig. 1. The blank state of the Quinapalus machine.
The simulation uses my own implementation of Wireworld rules. It’s most certainly not the fastest one available. It is probably possible to save the image generated by the program and import it into the dedicated cellular automaton running software, such as Golly (http://golly.sourceforge.net/). In the future, I’ll think about adding an export feature.
There are also further limitations. It is currently only possible to program the machine using hex codes for the instructions and the data. It would be good to add the possibility of using mnemonics, and - who knows - maybe even a C wrapper? ;)
The memory of the machine is of course limited. Moreover, the program only allows for writing into the registers R1-R52.
I must admit that I am no Javascript wizz. It took me long enough to get the demo working, and the code could arguably use some polish! Here it is: https://github.com/dagothar/wireworld-compiler
If you run into any problems running the code, please let me know. Any suggestions are welcome! I’m looking forward to improve the “compiler”.
(I haven’t probably synchronized the computer completely. Whenever it starts with a new program, it first prints out ‘65535’, then reverts to ‘00000’ before it starts printing out the commanded output. This is perhaps governed by the state of the frequency divisor at the bottom of the unit, but I haven’t yet figured how to set it appropriately.)

Programming the machine

Instruction set for the Wireworld computer is quite short. To be precise, the machine can only execute one instruction:
MOV Rd, Rs                  Move content of register Rs to register Rd
To quote its creators:

We wanted to make the Wireworld computer as simple as we could while still being able to run worthwhile programs. We therefore settled on a highly orthogonal RISC architecture.
The description of the instruction set (repeated below) is available at: https://quinapalus.com/wires10.html
Since only one instruction is available, all the more complicated operations are done using writing to/reading from special purpose registers. These registers are as follows:
Register Action on read Action on write
R0 Returns 0 Sends value to display
R53 Returns AND of R54 with NOT R53 Writes value to register
R54 Returns bitwise AND of R53 with NOT R54 Writes value to register
R55 Returns 0 Writes value to register
R56 Returns value in R55 if register R56 is non-zero, and the value in R57 otherwise Writes value to register
R57 Returns 0 Writes value to register
R58 Returns R58 rotated right one place Writes value to register
R59 Returns R59 rotated left one place Writes value to register
R60 Reads value from the register Writes value to register
R61 Returns sum of R60 and R61 Writes value to register
R62 Returns NOT R62 Writes value to register
R63 Returns program counter value Causes branch (jump) to the given target
How to arrive at the hexadecimal representation given the mnemonic? Each command consists of two bytes (16 bits altogether). The two bytes contain the address of the destination/source respectively, e.g. MOV R60, R7 translates to 0x3c07 (00111100 00000111 ⇐=> 60, 7).

How to use the simulator?

Simply click ‘Start’ to launch the machine in its current state. The RAM is initially empty, and thus the computer will not do much. Left running on its own, the computer will repeatedly refresh the display with ‘00000’.
You can ‘Stop’ the machine at any time. If you wish, you can ‘Step’ through the simulation manually.
The interface on the left is used for programming the machine. In the text area, enter the hex codes of the instructions (or data) in separate lines. For example:
0x0001
0x0002
...
(Take care, I do not do much validation of the input at this point! If stuff breaks, simply reload the page.)
Click ‘Load’ to load the program into the memory. The machine will be reset and stopped, and you’ll have to ‘Launch’ it again.

Sample program

Now that we have dealt with the boring background, let’s try something practical.
The original program presented on the Quinapalus machine was a prime finder. Let’s try something a bit less sophisticated. How about just counting up (0, 1, 2, …)?
We can do that by writing the following code:
R1    MOV R0, R7    ; send R7 (counter) to the display
R2    MOV R60, R7  ; send counter to R60 (adder input 1)
R3    MOV R61, R8  ; send R8 (1) to adder input 2
R4    MOV R7, R61  ; send the addition result to counter
R5    MOV R63, R9  ; move R9 (R1 address) to jump back to the beginning
R6    MOV R0, R7    ; send counter to display again (branch delay)
R7    0                      ; contains counter
R8    1                      ; 1 for incrementing
R9    1                      ; jump target: R1
Then we have to compile it by hand. The compiled code is:
0x0007
0x3c07
0x3d08
0x073d
0x3f09
0x0007
0x0000
0x0001
0x0001
Go launch the simulator and try to run the program. It will be a while before it counts up a single tick (reserve at least a couple of hours to witness the true glory). The code has room for improvements. See if you can make it run smoother!

Fig. 2. Counter program reaching 2!

No comments:

Post a Comment