So, I spend my afternoon reverse engineering this CPU, which I did enjoy a lot. Though it would have been helpful if you actually labelled some of the components of the CPU.... Here's what I figured out:
I've also reworded some of the stuff you wrote in "Instruction Set.txt" and came up with an assembly language. It"s a little weird, since basically every single instruction can apply modifications to the MEM register, put things into DATA for one cycle, branch and do another thing. So, it's like every instruction is actually 4 instructions.
EDIT: To avoid some confusion, I should say the text file I attached also contains the Fibonacci numbers program, translated into assembly. This is the program @Haku included in the world download, I didn't come up with it myself.
In reality the machine also store a lot more "states" than it appears to. I guess this is just a thing that terraria wiring does in general, but it really makes it hard to wrap your brain around this thing. I kind of fixed this by calling DATA and ALU "pseudo registers". Cause they have a state, they can store things, therefor, they are registers.
I drew a little chart about, how you can actually move data between all these registers. The fact that some operations set registers and some XOR them, is really confusing. It also means you have to give out a lot more instructions to do simple things.
Making the memory address part of the instruction actually set the address would make things a hell of a lot more understandable. I don't think it would too difficult to wire that up either. The XORing might make some room for reusing code for accessing different places in memory, but that's not very useful without more powerful branching facilities.
The other major weirdness is with the output of the ALU (what I call the ALU register) and the accumulator. Having ACC there as an extra buffer is pretty redundant. Also it means you have to pretty much do ADD twice, every time you want to do an addition, just to reset the ALU register. What would make more sense would be to have what is now called ALU be the new ACC. Basically connecting the ALU directly to DATA through a gate. So, ST.ACC would no longer be necessary. Instead you can have an extra instructtion to clear, what we now call ACC, but used to be the old ALU register.
I don't know if that makes any sense. What I mean to say, is instead of this:
Code:
MEM[MEM] --(XOR)--> | | --(SET)--> MEM[MEM]
IN --(XOR)--> | DATA | --(SET)--> A
| | --(SET)--> B
(A + B) --(XOR)--> ALU --(SET)--> | ACC | --(XOR)--> | | --(SET)--> OUT
You should have this:
Code:
MEM[MEM] --(XOR)--> | | --(SET)--> MEM[MEM]
IN --(XOR)--> | DATA | --(SET)--> A
| | --(SET)--> B
(A + B) --(SET)--> | ACC | --(XOR)--> | | --(SET)--> OUT
The whole manually enabling the output of certain components to DATA is a bit non standard, this really fells like something the instruction decoder should figure out. But it does work pretty well, and it cuts down on the number of opcodes you need. So, yeah, it's not a bad idea actually.
Another weird thing I can see is with the carry bit of the ALU... It's not actually connected to the carry input of the ALU. The point of this bit in a real CPU, apart from being a branch condition, is to lets you easily add numbers that are bigger than the registers and the ALU can handle. Here to do that, you'd have to like do a branch based on the carry, set the carry in if it's one, and then also reset it at the end somehow.
Other than the occasional weirdness, this does seem like a pretty capable little CPU.

I do understand though that these sort of conventions, and the reasons they are this way, are probably not self evident to most people. Like, the only reason I know about this is because I had several university courses specifically about this, so I had no choice but to learn it...