SVC16: Simplest Virtual Computer
github.com
github.com
Others have mentioned Subleq (Subtract And Branch If Less Than Or Equal To), but there's more useful designs that meet all the design constraints. They state that "It is also not intended to be as simple and elegant as it could possibly be.", but it's called "The Simplest Virtual Computer" - that kind of name is a challenge.
As always it is a tradeoff, and given many designs don't need much block memory, or need so much memory that external memory is a better choice anyway.
If I understand it correctly, the entire register file except for PC is effectively memory-mapped, it uses 16-bit word addressing and the peripherals (framebuffer + mouse) are accessed through dedicated instructions. Instructions are four words long, the first one only having 16 valid opcodes and the rest referencing either direct memory addresses or raw word values.
1830s, in fact—the original computer, Babbage’s Analytical Engine!
It's a bit weird that this particular instruction set annoys me so much. Perhaps annoys is the wrong word, maybe irritates is better. The entire thing I can get behind except for the instruction encoding. The instructions are too large for the space available. 128k of ram for programs and 128k for screen (and workspace area, given sync), but at 8 bytes per instruction it eats up the limited resource too quickly.
I guess that irritation comes from the efficiency hacks that these constrained environments encourage. It revives an age of clever tricks to get the most of of a little. The instruction size pokes at that aesthetic like a lump in a pillow.
I'm not sure what would be a better solution while preserving simplicity. maybe a single extra dereference to turn
opcode arg1 arg2 arg3
@(IP) @(IP+1) @(IP+2) @(IP+3) ;; IP+=4
into @(@IP) @(@IP+1) @(@IP+2) @(@IP+3) ;; IP+=1
which would be one system word per instruction lookup, from a dictionary of instructions in RAM (coders would have to be careful not to lose the ability to generate all constant values if they eliminated certain dictionary entries(Tiny programs would get bigger , Larger programs would be smaller when they reuse instructions.
If you wanted to work against the idea of 'simplest' and embrace the notion of weird-features-because-of-technical-debt, you could make an 'upgraded' machine that has a second bank of 128k (64k words) as dedicated program memory, that is initialized at startup with the numbers 0x0000 to 0xffff. This would make the machine run SVC16 programs unmodified. You could then either have it use program ROMs or add a single instruction
StoreProgMem @progMem(@arg1+@arg3) =(@arg2+@arg3)
Which would enable writing the program space.Egads, I've been nerd sniped!
I'm very surprised this smallest machine is not a stack machine.
Another way could be to use registers, possibly just one register. Like in old machines that had an accumulator, which was implied. So „Add x“ adds x to the accumulator.
In some sense, there is already a register file in the proposed VM, the whole memory.
Another, related way, to reduce instruction size is to not allow all operands to be 16 bit, that is, have some registers that are more „special“ than others. For example, say the first 16 memory locations are special. Then it’s possible to have a
Opcode, arg1, arg2, arg3
Encoding using 4 bits each, for 16 bit instructions. The problem is that some instructions will need a full 16 bit argument, for example some load immediate, or goto.Common ways to deal with that:
1) variable width instructions (16/32 bit) - makes machine less simple.
2) always use 32 bit instructions, meaning instructions are
opcode, arg4bit, arg4bit, arg16bit.
This is simpler, but still pretty wasteful for instruction length. Could also use opcode4bit, arg6bit, arg6bit, arg16bit
This turns the first 64 memory locations into special registers, but uses awkward 6bit values.3) use 8 bit immediates with hi/lo access (like arm). So then u have instructions like
mov_hi dest4, imm8
nov_lo dest4, imm8
Setting the hi/lo byte of the register file (I.e. the first 16 memory locations). This in turn means there will be more instructions, they will not work directly on memory (like goto needs 2 loads). So while there is the nice property that instruction length equals word length, it also means more kinds of instructions (perhaps, like jump relative), more complicated instructions, and more instructions needing to be executed to accomplish similar tasks (eg 3 instructions for arbitrary jump).All these considerations are probably counter to wanting a maximally simple machine.
17ms for a multiplication, wow. Incredible to think that's now the budget for an entire 3D rendered frame.
Like others in this thread I was very skeptical of the SVC16 design, but this real computer feels weirdly unbalanced in the same kind of way. 31-bit instructions, but only 4K words of memory (16KB) in total? 17ms multiplication, but it can also do division? Very strange.
68000 generates a bus error if you try unaligned 16/32-bit access.
Not being byte-addressable was a real pain. There was a C compiler, but off-the-shelf C code hardly ever worked properly because everyone assumes CHAR_BIT is 8.
https://colorforth.github.io/index.html
Second part of the game requires writing self-modifying code which is quite mindboggling!
https://en.wikipedia.org/wiki/CARDboard_Illustrative_Aid_to_...
the official specification for Nock, the assembly language used by the Urbit virtual machine, fits on a t-shirt: The Nock specification is only 200 words long It can be compressed to 371 bytes Nock is a low-level, homoiconic combinator language that's similar to JVM code. It's designed to be simple, and is interpreted by Vere. Hoon is the practical layer of Urbit, and it compiles itself to Nock, the simple layer.
Adding two words to create an address is a fun variation of segment pointers, but even more wasteful than x86 16-bit segment+offset pointers (not a complaint, just an observation).
I'm curious why you think it's wasteful?
It seems similar to the 6809 indexed addressing modes which I liked (a long time ago).
It has simple processors, simple compilers etc.
I wish I could find it.
Such projects can grow and eventually somebody learning on this builds the next Language or Qemu.
Code golf is somewhere in the middle, Often you have a fixed goal, but there is no one 'right' solution, creativity can find many paths to achieve the desired output while reducing line or character count.
So I do
Dweets https://beta.dwitter.net/u/lerc/top
My own fantasy console https://k8.fingswotidun.com/static/ide/?gist=ad96329670965dc...
A stack machine image generator limited to 50 characters of program code https://c50.fingswotidun.com/
Why do it? Why play with Lego? It's interesting and you get to see what you make.
The proliferation of fantasy consoles is simply because making a fantasy console appeals to the same aesthetic. See what you can make.