VML upstream: 22 language front ends × 17 backends

The VML bundled with your copy of Dolaima is a trimmed-down distribution of the upstream project VML Toolchain. This page is about the upstream project in full — it is a “many front ends → one IR → many backends” compiler toolchain that stands on its own and runs on the desktop without Dolaima.

How it relates to the copy inside Dolaima

In one line: one project, two shipping scopes. Upstream is the complete project (desktop IDE and hardware emulators included); the copy inside Dolaima is the subset trimmed to the goal “compile and run in-process on phone and desktop”.

The copy bundled with DolaimaUpstream VML Toolchain
How it gets inSource copy (vendoring) into this repository, called in-processA repository of its own, built and released on its own
Assembler / VM / front endsYes (27)Yes (22)
17 backend translatorsYes (a build dependency, not decoration)Yes
Standard library and samplesLibrary complete; samples are a selected subsetYes (the full sample tree)
Desktop IDENoYes (VMLIde)
Hardware emulatorsNoYes (ConsoleEmulator / FullDevicesEmulator)
Documentation site and web demosNoYes (this page is distilled from it)

Nothing that was dropped touches the main line of “write code, compile it, run it on your phone” — what was dropped is desktop debugging and demonstration machinery. The flip side: upstream can do more than the bundled copy. To drive an old machine emulator, burn to a microcontroller, or use the desktop IDE, go upstream.

On the numbers: the upstream home page says “22 languages × 18 architectures”, but the list it enumerates has 17 backends (the copy in this repository holds 17 as well: 5 for 8-bit, 2 for 16-bit, 7 for 32-bit and 3 virtual machines). This page counts what is enumerated, so it says 17.

What it is

A bus for compilers: the front ends compile each language into one intermediate representation, and the backends translate that representation onto each architecture. Write it in C, Python, Rust, Go or Java — compile to VML assembly, then translate to 6502, ARM, RISC-V, x86 or any other target.

source      .c .bas .pas .py .lua .fth .rs .go .ld .java .js .cs
            .swift .cpp .kt .scm .rb .dart .m .r .d .f90

   ↓  22 front-end compilers

one IR      VML assembly (.vml) → VMB binary (.vmb)

   ↓  17 backend translators

targets     6502 / Z80 / 8051 / AVR / PIC / MSP430 / PIC24 / ARM-CM
            x86 / MIPS / RISC-V / 68000 / PowerPC / SPARC / JVM / .NET / Wasm

One convention runs through the whole project: every language is compiled with the same command, and the compiler is picked by file extension. Learn the command line once, use it for all 22.

vmltool hello.c  -o hello.vml
vmltool -r hello.vml

22 language front ends

Each language has its own front-end compiler, and all of them run the same four-stage pipeline: lexing → parsing → code generation → VML assembly. Sixteen are production-grade (90% or more complete); six are newer and aimed at teaching.

LanguageExtensionCompleteCalling convention
C.c~96%cdecl
Forth.fth~94%stack
JavaScript.js~94%stdcall
C++.cpp~93%cdecl
Rust.rs~93%stdcall
Kotlin.kt~93%stdcall
Scheme.scm~93%stdcall
Ladder.ld~93%—
BASIC.bas~92%CCv2
Pascal.pas~92%pascal
Lua.lua~91%stdcall
Go.go~90%stdcall
Python.py~90%stdcall
C#.cs~90%stdcall
Java.java~90%stdcall
Swift.swift~90%stdcall
Ruby.rb~85%stdcall
Dart.dart~80%stdcall
Objective-C.m~80%cdecl
R.r~80%stdcall
D.d~80%stdcall
Fortran.f90~80%stdcall

The front ends share code: every language uses the common lexer base and code-generator base; the C-like languages (C, Go, Rust, JavaScript) share the expression and type-system layer; the object-oriented ones (C++, Java, C#, Swift, Kotlin) share another layer for classes, inheritance and virtual functions.

Four calling conventions (cdecl, CCv2, pascal, stdcall) decide how arguments travel and who cleans the stack. That layer is what lets the 22 languages call each other.

17 target backends

Translation has four stages: parse VML instructions → map instructions and registers → emit target assembly → format the artifact (HEX / BIN / ELF / S19). The 8-bit targets emulate registers in zero-page memory; ARM Cortex-M and RISC-V map 1:1.

WidthArchitectureTypically found in
8-bit6502Apple II / C64 / NES
8-bitZ80CP/M / ZX Spectrum / MSX
8-bit8051Classic embedded MCUs
8-bitAVRArduino / ATmega328P
8-bitPICMicrochip PIC16F84A
16-bitMSP430TI ultra-low power
16-bitPIC24Microchip 16-bit
32-bitARM Cortex-MSTM32 / Cortex-M
32-bitx86IBM PC / general computing
32-bitMIPSPIC32 / networking gear
32-bitRISC-VSiFive / open ISA
32-bit68000Amiga / Atari ST
32-bitPowerPCXilinx PPC405 / consoles
32-bitSPARCLEON3 / space-grade
VMJVMJava bytecode
VM.NETCLR / CIL
VMWasmBrowser / WebAssembly

Burning firmware is one command, from source all the way to an image:

vml2hex blink.c -arch arm-cm -f hex -o blink.hex

Three optimisation levels: -O0 none (debugging), -O1 dead-code elimination plus constant folding (the default), -O2 adding copy propagation and loop optimisation (release). Six output formats: Intel HEX (default), Binary, Motorola S19, ELF, DOS EXE and Text Dump.

Runtimes and emulators

The same VMB bytecode runs on several runtimes — covering everything from “as fast as possible” to “on an old machine”:

RuntimeLanguageNotes
VMLRuntimeC# (.NET)The core execution engine: 92 instructions, 16 general registers R0–R15, 8 float registers F0–F7, 4 doubles D0–D3, 30-plus syscalls, interrupts and exceptions (CLI / STI / IRET, TRY / CATCH), MMIO device emulation, VMB load and save
VMLRuntimeCC99A native cross-platform runtime, dependency-free at roughly 100 KB: all 92 of 92 opcodes aligned one-for-one with the C# runtime, VGA 80×25 text rendering, PC speaker emulation and WAV recording, statically linkable into a single file
ConsoleEmulatorC# (.NET)Terminal emulator: VGA text mode, scripted keystrokes, and emulation of six classic machines (Apple II / Commodore 64 / ZX Spectrum / MSX / Amstrad CPC / Commodore PET)
FullDevicesEmulatorC# (Avalonia)A graphical full-device emulator: device visualisation and live status panels
VMLIdeC# (Avalonia)A cross-platform desktop IDE (about 70% complete): editing, breakpoints, stepping and register inspection, device visualisation, an AI panel

Memory is a fixed 32-bit address space: code from 0x000000, data from 0x000400, the heap growing up from 0x008000 and the stack growing down from the top. 0xE000 holds the FFI function pointer table and 0xF000 the MMIO device registers.

The CLI toolchain

ToolWhat it does
VMLToolThe main tool: a GCC-style command line that picks the compiler by extension and can compile-and-run in one go, or stop at assembly, or preprocess only
VMLAssemblerAssembler and disassembler: VML text ↔ VMB binary, both directions; label resolution, directives, expression evaluation and library linking all live here
VMLToHexCompile, link, translate and format: 17 target architectures, 6 output formats, three optimisation levels
VMLPackerPacks a program into a standalone executable, and can cross-pack for other platforms; a C version produces smaller static binaries
GenLibCompiles C sources into a VML static shared library and generates the module wrappers and bindings for all 22 languages
GenDynScans the exported symbols of a .dylib / .so / .dll and generates the FFI wrapper plus call bindings for 22 languages
GenDevGenerates device driver code for 22 languages from an XML device description (register addresses, peripheral init functions)

The generators share one idea: generate once, get all 22 languages. Write a C library and GenLib produces the calling convention for the other 21 languages too.

FFI, the foreign function interface

A VML program can call native shared libraries — and all 22 languages write it in their own native syntax, with no hand-written assembly. Four syscalls carry the call chain:

SyscallNumberWhat it does
dl_open#370Load a shared library, return a handle
dl_sym#371Look a function up by name, return a function pointer id
dl_close#372Unload the library
native_call#373Call a native function (integer / pointer arguments, up to 8)
native_call_0#374Call a native function with no arguments
native_call_f#375Call a native function with float arguments — built for OpenGL-style interfaces

The upstream showpiece is the same rotating OpenGL cube written 22 times, every version calling the same VML wrapper and the same native library. Each language's main loop looks like this:

fn main() {
    gl_setup();
    while gl_should_close() == 0 {
        gl_frame();
    }
    gl_teardown();
}

One detail is worth knowing: naming habits differ between languages (Lua and Forth add a prefix, Pascal and C# need a forward declaration), so the wrapper exports every alias at once and each language can use its most natural spelling.

OS mode and MCU mode

The same compiler wears two faces, chosen by the mode switch:

OS modeMCU mode
OutputA desktop applicationDependency-free bare-metal firmware, all the way to a burnable HEX
Dynamic library loadingYes (FFI)No
GraphicsThe OpenGL stackNo
C standard libraryCompleteThe BIOS keeps malloc and file I/O
Left out—Async, threads, garbage collection

This is not two projects sharing a file here and there: it is the same front ends and the same standard library, with a different backend and runtime. Code that is written correctly compiles in both modes.

Where to start

📘 The VML inside Dolaima

The bundled copy is the trimmed distribution: 27 languages compile and run as soon as you install, with samples and games included, all offline.

Read the VML overview

🧭 Write your first program

From “hello” to drawing windows and writing a small game, step by step, with code you can paste and run.

Read the tutorial

🔗 The upstream repository

The full sources, changelog, roadmap and documentation live upstream — including the complete 22 languages × many architectures write-up.

Open the repository

📥 Run it on your phone

On mobile, open the Files tab and the sample folder is already there, ready to compile and run.

Download Dolaima


Building upstream and running the first program (inside the upstream repository):

git clone https://gitee.com/aleckstygit/vml.git
dotnet build VMLToolchain.sln
vmltool hello.c -o hello.vml
vmltool -r hello.vml

This page is distilled from the upstream project's own introduction pages (its web/ directory); the figures and tables follow its wording. The “17 backends” count is our own enumeration rather than a figure confirmed upstream. Upstream licence: MIT License. The copy bundled with Dolaima is vendored into third_party/vml/ in this repository; the local adaptations are documented in the README there.