From Esolang
Jump to navigation Jump to search

The Legasm Virtual Machine is a RISC virtual machine implemented in software, invented by Philippe Clavel and David Madore in 1998. The machine was originally intended to serve some purpose in the Legendes II game engine, but eventually got abandonned, then later development of the game engine got abandonned too. Legasm is thus arguably not esoteric nor a toy language.

The machine has 256 registers, each 32 bits, of which 232 are general purpose registers, the rest either have some special function or are reserved for special purposes for the future. Four of the registers contain unchangable constants, one has the (writable) instruction pointer (similarly to 32-bit ARM), one has a carry flag for arithmetic, and one has a stack pointer.

Memory is also addressed in 32-bit words, and contains both data and instructions, which thus allows self-modifying code, though self-modification doesn't seem necessary for useful programs. Memory is conventionally divided to two parts: main memory, which have small positive addresses starting from 0, and stack, which has small negative addresses going down from 0. Arithmetic instructions do operations only on the registers, but there are memory load/store, indirect load/store, push, pop, and call instructions to access memory.

Each instruction is encoded as a 32-bit word. The instructions available are:

  • Immediate load or add instructions, loading 16 bits from the instruction.
  • Arithmetic: add, subtract, add with carry, subtract with borrow, and four bitwise operations. These have two register input operands and a register output operand. They all modify the carry bit, to an undefined value in case of the four bitwise operations, but keep unchanged the other 31 bits in the register that contains the carry bit. None of the instructions read the carry bit, the confusingly named add with carry and subtract with borrow instructions just add and subtract a constant 1 carry respectively.
  • Comparisons, with two input register operands and writing 0 or 1 to an output register operand. Both signed and unsigned integer compares are available.
  • Shift and rotate.
  • Load and store memory. Address can be direct, which is computed as the sum of two registers, or indirect, in which case the effective address is read from memory based on the direct address.
  • Conditional jump and call. These jump using a 16-bit offset if an input register operand is zero or nonzero; the call versions push the address of the next instruction to the stack.
  • Push and pop a register operand to/from stack. Pop can be used to return from subroutine because the instruction pointer is mapped to a register.
  • Service call (system call) – this instruction doesn't do anything yet, but presumably this is how the machine would be integrated into whatever it's used for.