1
0
Fork 0
reality-engine/README.org

180 lines
5.5 KiB
Org Mode

#+TITLE: Reality Engine VM
#+AUTHOR: Zongor
#+EMAIL: archive@undar-lang.org
#+DATE: [2025-04-05]
#+LANGUAGE: en
#+OPTIONS: H:4 num:t toc:t \n:nil @:t ::t |:t ^:t -:t f:t *:t <:t
#+STARTUP: align fold nodlcheck hidestars oddeven lognotestate
#+TAGS: { TODO(t) NEXT(n) DONE(d) | HOLD(h) WAITING(w) CANCELLED(c) }
#+PROPERTY: header-args :tangle-mode (identity #o0644)
* 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
#+BEGIN_SRC sh
git clone https://git.alfrescocavern.com/zongor/undar-lang.git
cd undar-lang && make
#+END_SRC
=Sċieppan= is a intermediate representation.
You can view some examples in the =.ul.ir= files in =/test=
**Sample Program: =hello.ul.ir=**
#+BEGIN_SRC sh
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;
}
#+END_SRC
#+BEGIN_SRC sh
./build/linux/undar-linux-debug ./test/hello.ul.ir
#+END_SRC
* 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.
#+BEGIN_SRC sh
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;
}
#+END_SRC
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'
* Roadmap
[[./ROADMAP.org][Compiler, Plex, Immidate mode GUI, Constructive solid geometry, Tunnels, Actor model]]
* License
MIT-0
* Inspirations
- [[https://plan9.io/][Plan 9]] / 9P - Unified I/O, Tunnels.
- [[https://en.wikipedia.org/wiki/Lisp_(programming_language)][Lisp]] - Live coding, REPL, introspection.
- [[https://fortran-lang.org/][Fortran]] - Array semantics.
- [[https://en.wikipedia.org/wiki/C_(programming_language)][C]] / [[https://ziglang.org/][Zig]] - Portability, control, minimalism.
- [[https://lua.org][Lua]] - Friendly syntax, portable, and minimal.
- [[https://www.craftinginterpreters.com/the-lox-language.html][Lox]] - The start of my programming language creation journey.
- [[https://wiki.xxiivv.com/site/uxn.html][Uxn]] - Major inspiration, espeically around the core VM.
- [[http://duskos.org/][Dusk OS]] - A much better system for doing permacomputing.
- [[https://doc.cat-v.org/inferno/4th_edition/dis_VM_specification][Dis VM]] - CISC VM structure
- Retro Systems - N64, PS1, Mac Classic, Windows 95 - UI esthetics