ColaVM Specification



Architecture

The component controlling each of the other components' operations is the Control Unit (CU).

The core of the ColaVM is a stack (ST), on which all the operations are performed. Each element of the ST is a 32-bit integer.

It also consists of a Variable Array (VA), in which variables can be stored for later use. The VA can hold 256 32-bit integers.

The execution is done via a Program Counter (PC). The PC points at the instruction which is being executed. The PC model allows for easy change-of-flow of execution during jumps.

The last component is the Instruction Memory (IM). The IM holds all the instructions of the program, and is the memory whose elements PC points to.

Instruction Set

The instructions are all variable-sized. Variable-sized instructions allow for compact and dense compiled binaries.

Every operation has both an 8-bit and a 32-bit counterpart. This greatly optimizes the binary size for operations with small arguments.

There are special OpCodes for pushing common constants 0-9 on the stack. This reduces the expense of pushing these common constants from 2 bytes to 1 byte of required intruction memory, further reducing the binary size. This idea is borrowed from the Java Virtual Machine.

OpCodes for incrementing and decrementing reduce the overhead of adding and subtracting 1, reducing the instruction byte count from 2 to 1.

It is to be noted that the programmer writing the source code will not explicitly write separate variants for the 8-bit and the 32-bit instructions, nor the explicit PushConst(0-9) instructions. The programmer will write generic instructions like "PRINT", "PUSH", "JUMP" and the assembler will resolve them into the respctive variant.

OpCodes

Each instruction operates on the stack unless stated otherwise. Values are 32-bit signed integers. Instructions with an argument store that argument immediately after the opcode.

Instruction Arguments

Assembler

The ColaVM assembler is called Fill.

The assembler goes through the source code twice.

During the first pass, the assembler collects all the labels and resolves them to instruction addresses. It also resolves each generic instruction ("PRINT", "PUSH", "JUMP") to the respective 8-bit or 32-bit variant.

During the second pass, the assembler packs each resolved instruction into the binary.