1
0
Fork 0
[archived] A VM for the purpose of creating 1st generation style 3D games and graphical user interfaces that work on constrained systems, and the web using emscripten.
Go to file
zongor c69be1ef20 Update README.org 2026-02-27 21:51:19 -05:00
bench increase number of locals to 255, fix real to string, update reals implementation 2026-02-12 23:13:46 -08:00
docs rename some things, create new parser defs. 2025-11-09 22:23:55 -08:00
src WIP refactoring compiler to be less verbose 2026-02-27 00:15:32 -08:00
test Optimizations, have return ask if it is a heap value, move lexer up 2026-02-26 16:45:48 -08:00
.clocignore Optimizations, have return ask if it is a heap value, move lexer up 2026-02-26 16:45:48 -08:00
.gitattributes Update .gitattributes 2025-11-03 16:39:45 -05:00
.gitignore Optimizations, have return ask if it is a heap value, move lexer up 2026-02-26 16:45:48 -08:00
LICENSE change back to MIT since using some stuff from craftingintepreters 2025-06-15 15:54:49 -04:00
Makefile WIP refactoring compiler to be less verbose 2026-02-27 00:15:32 -08:00
README.org Update README.org 2026-02-27 21:51:19 -05:00
ROADMAP.org Update ROADMAP.org 2025-12-20 17:00:46 -05:00

README.org

Reality Engine VM

About

This was the VM that drove the assembler for the Undâr Programming Language.

After spending some months fighting to make the VM more preformant, I have come to the conlusion that a bytecode intepreted VM is too slow for embedded devices and retro hardware.

I am instead rewriting the compiler to be a transpiler that transpiles to both C and Uxn bytecode (maybe others?). See the "undar-lang" repo for more details.

There are some interesting things here, you can see a lot of early ideas for Undâr, and I think the assembler (Sċieppan) is kinda neat.

Getting Started

Requirements

Main

  • C compiler that supports C89

Optional

  • Git
  • Make
  • C compiler that supports ANSI C or later
  • SDL2

    • For GUI linux and web versions
  • Emscripten

    • For building the web version

Build

git clone https://git.alfrescocavern.com/zongor/undar-lang.git
cd undar-lang && make

Sċieppan is a intermediate representation. You can view some examples in the .ul.ir files in /test

Sample Program: hello.ul.ir

global str terminal_namespace = "/dev/term/0";
global str new_line = "\n";
global str hello = "nuqneH 'u'?";

function main () {
	str msg $0;

	load_address hello -> msg;
	call pln (msg);
	exit 0;
}

function pln (str message $0) {
	plex term $1;
	int msg_length $2;
	str nl $3;
	int nl_length $4;
	int mode $5;
	str term_ns $6;

	load_immediate 0 -> mode;
	load_address terminal_namespace -> term_ns;
	syscall OPEN term_ns mode term;
	string_length message -> msg_length;
	syscall WRITE term message msg_length;
	load_address new_line -> nl;
	string_length nl -> nl_length;
	syscall WRITE term nl nl_length;
	return;
}
./build/linux/undar-linux-debug ./test/hello.ul.ir

Memory Management

memory is managed via frame based arenas. function scopes defines a memory frame.

heap allocations using the internal malloc opcode push pointers within this frame. when a frame exits, the pointer is reset like stack based gc.

global str terminal_namespace = "/dev/term/0";
global str prompt = "Enter a string:";
global str new_line = "\n";

function main () {
	int mode $11;
	str term $10;

	load_address terminal_namespace -> term;
	load_immediate 0 -> mode;
	syscall OPEN term mode term;

	load_address prompt -> $7; 
	string_length $7 -> $8;
	syscall WRITE term $7 $8; // print prompt

	str user_string $9;
	load_immediate 32 -> $8;
	malloc $8 -> user_string;
	syscall READ term user_string $8; // read max 32 byte string

	call pln (user_string);
	exit 0;
}

function pln (str message $0) {
	plex term $1;
	int msg_length $2;
	str nl $3;
	int nl_length $4;
	int mode $5;
	str term_ns $6;

	load_immediate 0 -> mode;
	load_address terminal_namespace -> term_ns;
	syscall OPEN term_ns mode term;
	string_length message -> msg_length;
	syscall WRITE term message msg_length;
	load_address new_line -> nl;
	string_length nl -> nl_length;
	syscall WRITE term nl nl_length;
	return;
}

values passed to functions must be explicitly returned to propagate. heap values are copy on write, so if a value is modified in a child function it will change the parents value, unless the size of the structure changes then it will copy the parents value and append it to its own frame with the modification. this allows for the low resource usage of a C but the convenience of a Java/Go without the garbage collection.

Core Types

Type Description
byte Character/8 bit unsigned int
i8 8 bit signed int
u16 16 bit unsigned int
i16 16 bit signed int
int 32-bit signed integer
nat 32-bit natural number
real Q16.16 fixed-point real number
str fat pointer [length + data] string
bool true/false

primitive types like int, nat, real, etc. will always be safe to change in child frames.

complex types like str plex or arrays will be u32 pointers to their location in the 'heap'

License

MIT-0

Inspirations

  • Plan 9 / 9P - Unified I/O, Tunnels.
  • Lisp - Live coding, REPL, introspection.
  • Fortran - Array semantics.
  • C / Zig - Portability, control, minimalism.
  • Lua - Friendly syntax, portable, and minimal.
  • Lox - The start of my programming language creation journey.
  • Uxn - Major inspiration, espeically around the core VM.
  • Dusk OS - A much better system for doing permacomputing.
  • Dis VM - CISC VM structure
  • Retro Systems - N64, PS1, Mac Classic, Windows 95 - UI esthetics