Compare commits

..

3 Commits

Author SHA1 Message Date
zongor 51f7c33011 wip stack oriented VM 2025-10-14 00:07:29 -07:00
zongor 054012418b remove string lookup for devices use handles instead 2025-10-14 00:07:29 -07:00
zongor 4e5ebdb749 wip stack oriented VM 2025-10-12 22:11:54 -07:00
69 changed files with 3493 additions and 4199 deletions

4
.gitattributes vendored
View File

@ -1,2 +1,2 @@
*.ul linguist-language=C
*.zl linguist-language=Zig
*.ul linguist-language=fortran
*.zl linguist-language=zig

View File

@ -55,16 +55,16 @@ endif
# --- EMSCRIPTEN-SPECIFIC ---
ifeq ($(PLATFORM), emscripten)
LDFLAGS += -s USE_SDL=2\
-s ASYNCIFY \
LDFLAGS += -s USE_SDL=2 -s WASM=1 \
-s ALLOW_MEMORY_GROWTH=1 \
--preload-file test/paint.rom@paint.rom \
--shell-file $(ARCH_DIR)/shell_minimal.html
-s MAX_WEBGL_VERSION=2 \
--preload-file test/paint-bw.rom@paint.rom \
-s INITIAL_MEMORY=16MB
# For release: optimize, strip debug, minimize size
ifeq ($(BUILD_MODE), release)
PLATFORM_CFLAGS += -O2
LDFLAGS += -O2
PLATFORM_CFLAGS += -O2 -flto
LDFLAGS += -O2 -flto
endif
# Output: HTML + JS + WASM
@ -80,19 +80,17 @@ endif
VM_SOURCES := \
$(SRC_DIR)/vm/vm.c \
$(SRC_DIR)/vm/device.c \
$(SRC_DIR)/vm/libc.c
$(SRC_DIR)/vm/str.c
ifeq ($(BUILD_MODE), release)
PLATFORM_SOURCE := $(ARCH_DIR)/main.c \
$(ARCH_DIR)/devices.c\
$(SRC_DIR)/tools/parser.c \
$(SRC_DIR)/tools/lexer.c \
$(SRC_DIR)/tools/assembler.c
else
PLATFORM_SOURCE := $(ARCH_DIR)/main.c \
$(ARCH_DIR)/devices.c \
$(SRC_DIR)/tools/parser.c \
$(SRC_DIR)/tools/lexer.c \
$(SRC_DIR)/tools/assembler.c
endif
@ -154,34 +152,22 @@ clean-all:
@rm -rf build/
@echo "All cleaned."
# --- TEST COMPILATION TARGET ---
# Compiles all .asm.lisp test files to .rom using the debug VM executable
# Usage: make compile-tests PLATFORM=linux
compile-tests: $(BUILD_DIR)/undar-$(PLATFORM)$(TARGET_SUFFIX)
@echo "Compiling test assembly files for $(PLATFORM)..."
@for f in ./test/*.asm.lisp; do \
base=$$(basename "$$f" .asm.lisp); \
echo " [$$base] $$f -> ./test/$$base.rom"; \
$(BUILD_DIR)/undar-$(PLATFORM)$(TARGET_SUFFIX) "$$f" -o "./test/$$base.rom"; \
done
@echo "Compilation complete: $$(ls -1 ./test/*.rom | wc -l) ROM files generated"
# Update help target to include new command
# --- HELP ---
help:
@echo "Undar VM"
@echo ""
@echo "Targets:"
@echo " make -> debug build (default: linux)"
@echo " make debug -> same as above"
@echo " make release -> optimized, stripped build"
@echo " make compile-tests -> compile all test assembly files"
@echo " make release -> optimized, stripped build"
@echo " make clean -> clean current platform"
@echo " make clean-all-> clean all platforms"
@echo " make clean-all→ clean all platforms"
@echo ""
@echo "Platforms:"
@echo " make PLATFORM=linux -> GCC + SDL2"
@echo " make PLATFORM=emscripten -> Emscripten + SDL2 for Web"
@echo " make PLATFORM=avr -> (example) AVR-GCC"
@echo ""
@echo "Output:"
@echo " Linux: build/linux/undar-linux-<debug|release>"
@echo " Web: build/emscripten/undar.html (+ .js, .wasm)"
@echo " Web: build/emscripten/undar.html (+ .js, .wasm)"

View File

@ -10,22 +10,22 @@
#+BEGIN_SRC
[ᚢ ᛫ ᛫ ᛫
᛫ ᛫
᛫ ᛫
᛫ ᛫ ᛫ ]
᛫ ᛫
᛫ ᛫
᛫ ᛫ ᛫ ]
#+END_SRC
* Undâr
Undâr is a programming language for the purpose of creating 3D games and graphical user interfaces that work on constrained systems, microcontrollers, retro consoles, and the web using emscripten. The language emphasizes hardware longevity, energy efficiency, and the preservation of digital art and games for future generations.
Undâr is a programming language for the purpose of creating three dimensional video games and graphical user interfaces that work on constrained systems, microcontrollers, retro consoles, and the using emscripten. The language emphasizes hardware longevity, energy efficiency, and the preservation of digital art and games for future generations.
It has an internal REPL that allows for quick development as well as the ability to dump the program to a binary rom for preserving that program/game/etc.
It runs on the =Reality Engine=, a VM written in freestanding C89, has a CISC like instruction format of one byte opcode and a variable byte operand. 32 general purpose registers.
It runs on the =Reality Engine=, a 32 bit stack based VM written in freestanding C89.
* Philosophy
Undâr conforms to permacomputing principles.
Undâr it conforms to permacomputing principles.
"permacomputing encourages the maximization of hardware lifespan, minimization of energy usage and focuses on the use of already available computational resources.
it values maintenance and refactoring of systems to keep them efficient, instead of planned obsolescence, permacomputing practices planned longevity.
@ -34,7 +34,7 @@ it is about using computation only when it has a strengthening effect on ecosyst
Undâr is designed to ensure that programs created today will remain executable for a very long time, even through technological collapse.
This is achieved through:
- A standardized bytecode format that maps 1:1 to human-readable assembly
- A standardized bytecode format that maps 1:1 to human-readable assembly (Sċieppan)
- A VM specification that can be implemented easily
- Hardware abstractions for the VM implementation
- ROM files that contain all necessary information for execution
@ -58,23 +58,14 @@ The Undâr compiler will be written in Sċieppan, as well as core VM tests.
#+BEGIN_SRC lisp
((code
(label main
(load-immediate $1 &hello-str) ; load hello string ptr
(call &pln ($1) nil)
(halt)) ; done
(label pln
(load-immediate $1 &terminal-namespace) ; get terminal device
(load-immediate $11 0)
(syscall OPEN $1 $1 $11)
(load-immediate $3 &new-line)
(string-length $2 $0)
(syscall WRITE $1 $0 $2)
(string-length $4 $3)
(syscall WRITE $1 $3 $4)
(return nil)))
(load &terminal-namespace) ; load terminal namespace
(load &hello-str) ; load hello string ptr
(string-length) ; get length to write to stdout
(syscall WRITE) ; do the write syscall
(halt))) ; done
(data
(label terminal-namespace "/dev/term/0")
(label new-line "\n")
(label hello-str "nuqneH 'u'?")))
(label hello-str "nuqneH 'u'?\n")))
#+END_SRC
#+BEGIN_SRC sh
@ -90,31 +81,37 @@ 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 lisp
((code
(label main
(load-immediate $0 &terminal-namespace) ; get terminal device
(load-immediate $11 0)
(syscall OPEN $0 $0 $11)
(load-immediate $1 &help) ; print help message
(call &pln ($0 $1) nil)
(load-immediate $1 32) ; read in a string of max 32 char length
(malloc $4 $1) ; allocate memory for the string
(syscall READ $0 $4 $1) ; read the string
(call &pln ($0 $4) nil) ; print the string
((code
(label main ; this example adds 2 numbers together
(load-immediate $0 1) ; pushes 1 onto the stack for the function call
(push $0)
(load-immediate $0 1)
(push $0)
(call &add) ; here a new frame is generated
(pop $0) ; the element is returned and the memory for the pln is "freed" automatically because the child frame is done
(halt))
(label pln
(load-immediate $3 &new-line)
(string-length $2 $1)
(syscall WRITE $0 $1 $2)
(label add
(pop $0)
(pop $1)
(add-int $2 $1 $0) ; add the arguments
(int-to-string $3 $2) ; convert to a string (heap allocation)
(push $3)
(call &pln) ; call print function
(push $2)
(return)) ; return to main function
(label pln
(load-immediate $0 &terminal-namespace) ; load the namespace for the terminal
(load-immediate $3 &new-line) ; and a newline char
(pop $1) ; pointer to string
(string-length $2 $1) ; get the length
(syscall WRITE $0 $1 $2) ; write the string
(string-length $4 $3)
(syscall WRITE $0 $3 $4)
(return nil)))
(data
(label terminal-namespace "/dev/term/0")
(label help "Enter a string: ")
(return))) ; return back to add function
(data ; allocates strings at compile time
(label terminal-namespace "/dev/term/0")
(label new-line "\n")))
#+END_SRC
@ -122,14 +119,15 @@ values passed to functions must be explicitly returned to propagate. heap values
**Core Types**
| Type | Description |
|------+------------------------------------|
| =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 |
| =byte= | Character/8 bit unsigned int |
| Type | Description |
|------+-------------------------------------------|
| =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 |
| =char= | Character |
| =ref= | Reference prefix for passing by reference |
A ref type allows pass by reference similar to a pointer in c. most types will be pass by value with some types being explicitly pass by reference.
@ -137,7 +135,7 @@ primitive types like int, nat, real, etc. will always be safe to change in child
* Roadmap
[[./ROADMAP.org][Compiler, Plex, Immidate mode GUI, Constructive solid geometry, Tunnels, Actor model]]
[[./ROADMAP.org][Coroutines, Compiler, Memory Refactor, Plex, Immidate mode GUI, Constructive solid geometry, tunnels]]
* License

View File

@ -10,34 +10,20 @@
* Roadmap
** Memory System Improvements
in the beta phase the bump allocator will be removed and replaced with the following system: instead of the bump allocator memory and registers being separate, the frames are in vm memory and then dynamically allocate a frame and register with a size each time a function gets called of a particular arena size. the syntax would be fnN where N is the number is the size in kb for that particular frame, however the compiler will split up the available memory for that architecture into function arenas of the defined "theoretical maximum" of running coroutines. the "maximum" is going to be whatever is hardcoded for the VM, like 1MB or 100MB or 1GB or whatever. The true max will be <4GB because that is all that can be addressed by a u32. the sizes we can say that for a particular architecture has n many 128kb function and y many 8kb functions and so on; then the compiler could partition the system and report that the program requires x of this many slots of this size and y slots of another size. for strings we will extend the syntax we can use str8 is 8 bytes or str16 is 16 bytes or whatever, that way we have a shorthand that is consistent with the rest of the language and is friendly to new developers; however we would keep array syntax the same as in c-like languages `<type>[size]`. the stack and return stack need to be removed as well; like imagine you push some value onto the stack and then switch coroutines and then in that one it pops or pushes that would break. instead we will have a tiny stack per frame for function arguments and have a "return register" to allocate where the function should return to when it finishes. if it gets called recursively it will just take up a new block of the same size. recursive calls should be discouraged in general for this reason, its not a good technique for embedded development or permacomputing. so yes, it *will* compile, but guarantee the compiler *will* make surreal comments about your code. The compiler output in general should have an [[esolangs.org/wiki/INTERCAL][INTERCAL]] feel to it; the compiler needs to not take itself too seriously, but that does not mean it should not give useful advice to the programmer.
** Coroutine System
coroutine system that uses the yield keyword so that functions can run out of order. make all functions coroutines i.e. they should be first class objects in the vm. the system will work similar to a real time microkernel based os like qnx. when a coroutine yields the system will continue from the last function that was running, or it will continue in the "main function" which may spawn new coroutines. each call will allocate a new block in memory. there will also be a "behavior" system where a specific coroutine might have "restart on fail" where others might have "exit on fail" or still others might have "crash on fail", this allows for systems to react to changing external factors. in the long long term (post 1.0) i want to make coroutines similar to beam where they run mutithreaded an use mailboxes and message passing to communicate.
** Example: Hello world (=hello.ul=)
*WIP syntax, not final implementation**
#+BEGIN_SRC ul
/**
* Constants
*/
const str nl = "\n";
plex Terminal {
nat handle;
}
/**
* Main function
*/
function main() {
pln("nuqneH 'u'?");
}
/**
* Print with a newline
*/
function pln(str message) {
Terminal term = open("/dev/term/0", 0);
write(term, message, message.length);
write(term, nl, nl.length);
fn main(int argc, str[] argv) {
print("nuqneH 'u'?");
}
#+END_SRC
@ -45,161 +31,42 @@ function pln(str message) {
**WIP syntax, not final implementation**
Common:
#+BEGIN_SRC ul
/**
* Camera.
*/
plex Camera {
int setting;
real pov;
real[3] up;
real[3] pos;
real[3] look;
use "common.ul";
init(real[3] pos, real[3] look) {
this.setting = CAMERA_PERSPECTIVE;
this.pov = 45.0;
this.up = [0.0, 1.0, 0.0];
this.pos = pos;
this.look = look;
}
}
/**
* Player.
*/
plex Player {
Client client;
str username;
real[3] pos;
nat color;
Camera camera;
init(str username, real[3] pos, Color color) {
this.client = Client("tcp://localhost:25565");
this.username = username;
this.pos = pos;
this.color = color;
this.camera =
Camera([this.pos.x + 10.0, this.pos.y + 10.0, this.pos.z], this.pos);
}
login(str password) Player[] { // looks like a method but really it just has an implied "Player this" as the first argument
this.client.attach(this.username, password);
this.players = client.open("players");
return players.read();
}
logout() {
this.players.flush();
this.client.clunk();
}
update() {
if (key_down("right")) {
this.pos.x += 0.2;
this.client.write(Command(this.username, KEY_RIGHT))
}
if (key_down("left")) {
this.pos.x -= 0.2;
this.client.write(Command(this.username, KEY_LEFT))
}
if (key_down("down")) {
this.pos.z += 0.2;
this.client.write(Command(this.username, KEY_DOWN))
}
if (key_down("up")) {
this.pos.z -= 0.2;
this.client.write(Command(this.username, KEY_UP))
}
this.camera.sync();
}
}
const nat RED = rgb332([255, 0, 0]);
const nat WHITE = rgb332([0, 0, 0]);
const nat PURPLE = rgb332([255, 255, 0]);
#+END_SRC
Client:
#+BEGIN_SRC ul
use <str.ul>; // from stdlib
use "common.ul"; // from local
function main(int argc, str[] argv) {
nat screen_width = 800;
nat screen_height = 450;
if (argv < 2) {
pln("usage: undar client.ul <username> <password>");
exit(-1);
}
str username = argv[1];
str password = argv[2];
Player me(username, [0.0, 1.0, 2.0], PURPLE);
fn256 main(int argc, str[] argv) {
nat w = 800, h = 450;
Player me(argv[1], [0.0, 1.0, 2.0], PURPLE);
bool running = true;
while (running) {
window("zwl client", screen_width, screen_height) {
splitbox(parent.size 0.25) {
window("Client", w, h) {
splitbox(parent.size, 0.25) {
canvas() {
if (button("logout")) {
if (button("Logout")) {
me.logout();
running = false;
}
}
}
splitbox(parent.size 0.75) {
splitbox(parent.size, 0.75) {
canvas() {
model(Floor([0, 0, 0], 30));
me.update();
model(Cube(me.pos, [0.5, 0.5, 0.5], me.appearance));
if (Player[] players = me.server.read("players")) {
for (p in players) {
model(Cube(p.pos, [0.5, 0.5, 0.5], p.apperance));
model(Cube(me.pos, [0.5,0.5,0.5], me.color));
if (Player[] others = me.server.read("players")) {
for (p in others) {
model(Cube(p.pos, [0.5,0.5,0.5], p.color));
}
}
}
}
}
}
exits("Client Closed Successfully");
}
#+END_SRC
Server:
#+BEGIN_SRC ul
use "common.ul";
function main(int argc, str[] argv) {
Server s("tcp://0.0.0.0:25565");
bool running = true;
Player[] players = [Player("user", [0.0, 0.0, 0.0], RED)];
while (running) {
if (Client client = s.accept("players")) {
if (Message message = client.get()) {
if (message.t == "close") {
client.close();
running = false;
} else if (message.t == "players") {
client.write(players);
} else {
print("unknown message {message}");
}
}
}
}
exits(nil);
}
#+END_SRC
** Plex
A =plex= is a structure which, works like a struct but syntactically looks like a class. the naming of "plex" comes from douglas ross's paper "a generalized technique for symbol manipulation and numerical calculation". It is used instead of "class" or "struct" is to make a break from the historical baggage of "classes". unlike classes it does not describe a object in real life and copy it, but it allows for a convenient way to mediate states and handling. i.e. compositions + encodings instead of oop/polymorphisms. for example, instead of having a struct with a bool flag in it (like for a game alive/dead), we can create a multilist where the structs move from a "alive" list to a "dead" list; or things like that. instances of a plex in memory are called "atoms".
@ -254,11 +121,11 @@ Devices are accessed via a namespace "path/to/device" and are implemented outsid
*** Immediate Mode GUI
UI elements are draw directly on the canvas and syntactically are spacial to show which elements are child elements of each other. Calling a function is the equivalent of a redraw of that element
UI elements are draw directly on the canvas and syntaically are spacial to show which elements are child elements of each other. Calling a function is the equivelent of a redraw of that element
*** 3D Modeling
3D Primitives + Constructive solid geometry (Similar to OpenSCAD or .kkrieger) allow for the construction of more complex 3D models from the manipulation of primitives. It also has the ability to create textures dynamically similar to .kkrieger, textures can be imported and auto mipmapped from larger sizes down to the internal RGB332 + 8x8 - 32x32 tile system.
3D Primitives + Constructive solid geometry (Simialr to OpenSCAD or .kkrieger) allow for the construction of more complex 3D models from the manipulation of primitives. It also has the ablity to create textures dynamically similar to .kkrieger, textures can be imported and auto mipmaped from larger sizes down to the internal RGB332 + 8x8 - 32x32 tile system.
** Tunnels: Unified I/O (Plan 9 / 9P-Inspired)
@ -290,44 +157,3 @@ if (server.attach(auth)) {
| =.clunk()= | Close communication |
| =.stat()= | returns the status of the file resource |
| =.version()= | returns the version code for the connected tunnel |
** Actor System
*** Core Principles
- Deterministic memory management with no garbage collection or manual free
- Zero fragmentation via contiguous arena allocation
- Isolated memory spaces for all actors (no shared memory)
- Compile-time memory bounds enforcement
*** Memory Architecture
- Actor memory is partitioned into fixed-size arenas
- Two primary arenas:
- =Main Thread Arena= (top of memory)
- =Actor Arenas= (bottom-up allocation)
- Arena layout:
#+begin_src text
|---------------------| <-- Top of memory
| MAIN THREAD | (e.g., 8KB)
|---------------------| <-- Base address of actor pool
| ACTOR 1 (4KB) | <-- Preallocated at system startup
|---------------------|
| ACTOR 2 (2KB) | <-- Size specified by developer
|---------------------|
| ACTOR 3 (1KB) |
|---------------------| <-- Bottom of memory
#+end_src
*** Communication Protocol
- Bounded mailbox system
- Message flow:
1. Main thread sends via =send_message()=
2. Message copied into actor's mailbox
3. Actor processes in =on_message()= during next cycle
4. Actor sends response via =send_response()=
*** Failure Behaviors
| Behavior | Action | Certification Impact | Example Use Case |
|----------+-------------------------+----------------------+-------------------------|
| =RESTART= | Reset arena offset to 0 | 2 artifacts | Network reconnection |
| =EXIT= | Free arena | 1 artifact | Session termination |
| =CRASH= | Halt entire VM | 1 artifact | Critical subsystem fail |

17
bench/add.ul Normal file
View File

@ -0,0 +1,17 @@
Device term("/dev/term/0");
str new-line = "\n";
fn1 main() {
int sum = add(1, 1);
pln(sum.str);
}
fn1 add(int a, int b) int {
return a + b;
}
fn1 pln(str string) {
term.write(string);
term.write(new-line);
return;
}

18
bench/fib.ul Normal file
View File

@ -0,0 +1,18 @@
Device term("/dev/term/0");
str new-line = "\n";
fn1 main() {
print(fib(35).str);
exit(0);
}
fn1 fib(int n) int {
if (n < 2) return n;
return fib(n - 2) + fib(n - 1);
}
fn1 pln(str string) {
term.write(string);
term.write(new-line);
return;
}

12
bench/hello.ul Normal file
View File

@ -0,0 +1,12 @@
Device term("/dev/term/0");
str new-line = "\n";
fn1 main(int argc, str[] argv) {
print("nuqneH 'u'?");
}
fn1 pln(str string) {
term.write(string);
term.write(new-line);
return;
}

21
bench/loop.ul Normal file
View File

@ -0,0 +1,21 @@
Device term("/dev/term/0");
str new-line = "\n";
fn1 main() {
real a = 5.0;
do (int i = 5000, 0, -1) {
a = a + 5.0;
}
nat b = a as nat;
pln("Enter a string:");
str32 user_string = term.read();
pln(a.str);
pln(b.str);
pln(user_string);
}
fn1 pln(str string) {
term.write(string);
term.write(new-line);
return;
}

13
bench/simple.ul Normal file
View File

@ -0,0 +1,13 @@
Device term("/dev/term/0");
str new-line = "\n";
fn1 main(int argc, str[] argv) {
int sum = 1 + 2;
pln(sum.str);
}
fn1 pln(str string) {
term.write(string);
term.write(new-line);
return;
}

View File

@ -1,3 +0,0 @@
#!/bin/sh
magick -background none -density 384 undar.svg -define icon:auto-resize favicon.ico
magick -background none -density 100 undar.svg -define icon:auto-resize undar.png

46
docs/draw.ul Normal file
View File

@ -0,0 +1,46 @@
Device screen("/dev/screen/0");
u8[] colors = [0,255,36,73,146,182,128,224,144,
252,9,18,12,16,28,159,2,3,10,19,131,147,130,227,129,226,
72,141,136,241,208,244];
fn main() {
screen.open(0);
screen.draw();
int x = 10;
int y = 20;
for (int i = 0; i < colors.length; i+=2) {
draw_outline_swatch(colors[i], x, y);
draw_outline_swatch(colors[i + 1], x + 20, y);
x += 20;
y += 20;
}
screen.draw();
exit(0);
}
fn draw_outline_swatch(u8 color, int x, int y) {
u8 gray = colors[5];
int outline_size = 20;
int fill_size = 17;
int offset = 2;
draw_box(gray, x, y, outline_size, outline_size);
int swatch_pos = x + 2;
int offset_pos = y + 2;
draw_box(color, swatch_pos, offset_pos, fill_size, fill_size);
return;
}
fn draw_box(u8 color, int x, int y, int width, int height) {
int screen_width = screen.width;
int pos = y * 640 + x;
do (int i = height; i > 0; i--) {
int row = pos + width;
int pixel = offset;
do (int j = ; pos;j++) {
screen.buffer[j] = color;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 KiB

View File

@ -0,0 +1,42 @@
use "common.ztl";
function main(int argc, str[] argv) {
nat screen_width = 800;
nat screen_height = 450;
if (argv < 2) {
exits("usage: zre client.ul <username> <password>");
}
str username = argv[1];
str password = argv[2];
Player me(username, [0.0, 1.0, 2.0], PURPLE);
bool running = true;
while (running) {
window("zwl client", screen_width, screen_height) {
splitbox(parent.size 0.25) {
canvas() {
if (button("logout")) {
me.logout();
running = false;
}
}
}
splitbox(parent.size 0.75) {
canvas() {
model(Floor([0, 0, 0], 30));
me.update();
model(Cube(me.pos, [0.5, 0.5, 0.5], me.appearance));
if (Player[] players = me.server.read("players")) {
for (p in players) {
model(Cube(p.pos, [0.5, 0.5, 0.5], p.apperance));
}
}
}
}
}
}
exits("Client Closed Successfully");
}

View File

@ -0,0 +1,69 @@
!!
! Note that these look like classes but act like structs
! the methods actually have a implied struct as their first argument
!!
!!
! Camera.
!!
plex Camera {
init(real[3] pos, real[3] look) {
this.setting = "CAMERA_PERSPECTIVE";
this.pov = 45.0;
this.up = [0.0, 1.0, 0.0];
this.pos = pos;
this.look = look;
}
}
!!
! Player.
!!
plex Player {
init(str username, real[3] pos, Color color) {
this.client = Client("tcp://localhost:25565");
this.username = username;
this.pos = pos;
this.color = color;
this.camera =
Camera([this.pos.x + 10.0, this.pos.y + 10.0, this.pos.z], this.pos);
}
login(str password) Player[] { ! looks like a method but really it just has an implied "Player this" as the first argument
this.client.attach(this.username, password);
this.players = client.open("players");
return players.read();
}
logout() {
this.players.flush();
this.client.clunk();
}
update() {
if (key_down("right")) {
this.pos.x += 0.2;
this.client.write(Command(this.username, KEY_RIGHT))
}
if (key_down("left")) {
this.pos.x -= 0.2;
this.client.write(Command(this.username, KEY_LEFT))
}
if (key_down("down")) {
this.pos.z += 0.2;
this.client.write(Command(this.username, KEY_DOWN))
}
if (key_down("up")) {
this.pos.z -= 0.2;
this.client.write(Command(this.username, KEY_UP))
}
this.camera.sync();
}
}
const RED is [255, 0, 0];
const WHITE is [0, 0, 0];
const PURPLE is [255, 255, 0];

View File

@ -0,0 +1,22 @@
use "common.ztl";
function main(int argc, str[] argv) {
Server s("tcp://0.0.0.0:25565");
bool running = true;
Player[] players = [Player("user", [0.0, 0.0, 0.0], RED)];
while (running) {
if (Client client = s.accept("players")) {
if (Message message = client.get()) {
if (message.t == "close") {
client.close();
running = false;
} else if (message.t == "players") {
client.write(players);
} else {
print("unknown message {message}");
}
}
}
}
exits(nil);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -1,56 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32mm"
height="32mm"
viewBox="0 0 32 32"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="undar.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showguides="false"
inkscape:zoom="5.252469"
inkscape:cx="31.413798"
inkscape:cy="77.392175"
inkscape:window-width="1939"
inkscape:window-height="932"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:#000000;stroke:#ffffff;stroke-width:0.259677;stroke-opacity:0.80000001"
d="M 9.8701612,2.1298382 H 2.1298382 V 29.870162 h 7.740323 V 27.874455 H 3.9914349 V 4.0257595 h 5.8787263 z"
id="path1" />
<path
style="fill:#000000;stroke:#ffffff;stroke-width:0.259677;stroke-opacity:0.80000001"
d="m 22.129839,2.1298386 h 7.740323 V 29.870161 h -7.740323 v -1.995707 h 5.878726 V 4.02576 h -5.878726 z"
id="path1-3" />
<path
d="m 9.9966523,7.2192166 c 0.00192,1.1921857 0,17.6324454 0,17.6324454 H 11.947933 V 10.838 c 0,0 6.10676,1.037363 7.80512,3.238279 0.180102,0.233395 0,10.775383 0,10.775383 h 1.951281 L 21.704,13.017 C 21.719643,11.169234 18.492009,9.5084126 16.302239,8.6458806 13.47112,7.5307272 9.9947373,6.0270309 9.9966523,7.2192166 Z"
style="stroke:#ffffff;stroke-width:0.292319;stroke-opacity:0.80000001"
id="path3"
sodipodi:nodetypes="zcccscccsz" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

732
docs/undârsċieppan-w.svg Normal file
View File

@ -0,0 +1,732 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="159.448px"
height="94.120px"
viewBox="0 -2850 8809.5 5200"
version="1.1"
id="svg45"
sodipodi:docname="equation.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview45"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="5.5369495"
inkscape:cx="68.358941"
inkscape:cy="52.465713"
inkscape:window-width="1991"
inkscape:window-height="932"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="g30" />
<defs
id="defs1">
<path
id="MJX-5-NCM-N-23A1"
d="M614 1500L321 1500L321 0L387 0L387 1432L614 1432C636 1432 647 1443 647 1466C647 1485 633 1500 614 1500Z" />
<path
id="MJX-5-NCM-N-23A3"
d="M614 68L387 68L387 1500L321 1500L321 0L614 0C636 0 647 11 647 34C647 53 633 68 614 68Z" />
<path
id="MJX-5-NCM-N-23A2"
d="M321 0L387 0L387 1000L321 1000Z" />
<path
id="MJX-5-NCM-N-22C5"
d="M192 250C192 279 168 303 139 303C110 303 86 279 86 250C86 221 110 197 139 197C168 197 192 221 192 250Z" />
<path
id="MJX-5-NCM-N-23A4"
d="M280 0L346 0L346 1500L53 1500C31 1500 20 1489 20 1466C20 1443 31 1432 53 1432L280 1432Z" />
<path
id="MJX-5-NCM-N-23A6"
d="M53 0L346 0L346 1500L280 1500L280 68L53 68C31 68 20 57 20 34C20 11 31 0 53 0Z" />
<path
id="MJX-5-NCM-N-23A5"
d="M280 0L346 0L346 1000L280 1000Z" />
</defs>
<g
stroke="#FFFFFF"
fill="#FFFFFF"
stroke-width="0"
transform="scale(1,-1)"
id="g45">
<g
data-mml-node="math"
data-latex="\begin{bmatrix} ᚢ &amp; \cdot &amp; \cdot &amp; \cdot \\ \cdot &amp;&amp; \cdot &amp; \cdot \\ \cdot &amp; \cdot &amp;&amp; \cdot \\ \cdot &amp; \cdot &amp; \cdot &amp; ᚾ \end{bmatrix}"
data-semantic-structure="(37 0 (9 (2 1) (4 3) (6 5) (8 7)) (18 (11 10) (13 12) (15 14) (17 16)) (27 (20 19) (22 21) (24 23) (26 25)) (36 (29 28) (31 30) (33 32) (35 34)) 38)"
id="g44">
<g
data-mml-node="TeXAtom"
data-mjx-texclass="INNER"
data-latex-item="{bmatrix}"
data-latex="\begin{bmatrix} ᚢ &amp; \cdot &amp; \cdot &amp; \cdot \\ \cdot &amp;&amp; \cdot &amp; \cdot \\ \cdot &amp; \cdot &amp;&amp; \cdot \\ \cdot &amp; \cdot &amp; \cdot &amp; ᚾ \end{bmatrix}"
data-semantic-type="matrix"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:1"
data-semantic-id="37"
data-semantic-children="9,18,27,36"
data-semantic-content="0,38"
data-semantic-attributes="latex:\begin{bmatrix} ᚢ &amp; \cdot &amp; \cdot &amp; \cdot \\ \cdot &amp;&amp; \cdot &amp; \cdot \\ \cdot &amp; \cdot &amp;&amp; \cdot \\ \cdot &amp; \cdot &amp; \cdot &amp; ᚾ \end{bmatrix};texclass:INNER"
data-semantic-owns="0 9 18 27 36 38"
aria-level="0"
data-speech-node="true"
id="g43">
<g
data-mml-node="mo"
data-mjx-texclass="OPEN"
data-semantic-type="fence"
data-semantic-role="open"
data-semantic-annotation="depth:2"
data-semantic-id="0"
data-semantic-parent="37"
data-semantic-attributes="texclass:OPEN"
aria-level="1"
data-speech-node="true"
id="g3"
transform="translate(662.99988)">
<use
data-c="23A1"
xlink:href="#MJX-5-NCM-N-23A1"
transform="translate(0,1350)"
id="use1" />
<use
data-c="23A3"
xlink:href="#MJX-5-NCM-N-23A3"
transform="translate(0,-2350)"
id="use2" />
<svg
width="667"
height="2400"
y="-950"
x="0"
viewBox="0 600 667 2400"
version="1.1"
id="svg3">
<use
data-c="23A2"
xlink:href="#MJX-5-NCM-N-23A2"
transform="scale(1,3.6)"
id="use3" />
</svg>
</g>
<g
data-mml-node="mtable"
transform="matrix(0.86153012,0,0,1,1268.3375,0)"
id="g40">
<g
data-mml-node="mtr"
data-semantic-type="row"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:2"
data-semantic-id="9"
data-semantic-children="2,4,6,8"
data-semantic-parent="37"
data-semantic-owns="2 4 6 8"
aria-level="1"
data-speech-node="true"
transform="translate(0,2100)"
id="g12">
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="2"
data-semantic-children="1"
data-semantic-parent="9"
data-semantic-owns="1"
aria-level="2"
data-speech-node="true"
id="g5"
transform="translate(256.52028)">
<g
data-mml-node="mi"
data-latex="ᚢ"
data-semantic-type="identifier"
data-semantic-role="unknown"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="1"
data-semantic-parent="2"
data-semantic-attributes="latex:ᚢ"
aria-level="3"
data-speech-node="true"
id="g4">
<text
data-variant="italic"
transform="scale(1,-1)"
font-size="884px"
font-family="serif"
font-style="italic"
id="text3">ᚢ</text>
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="4"
data-semantic-children="3"
data-semantic-parent="9"
data-semantic-owns="3"
aria-level="2"
data-speech-node="true"
transform="translate(2587.6)"
id="g7">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="3"
data-semantic-parent="4"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g6">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use5" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="6"
data-semantic-children="5"
data-semantic-parent="9"
data-semantic-owns="5"
aria-level="2"
data-speech-node="true"
transform="translate(4698.1)"
id="g9">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="5"
data-semantic-parent="6"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g8">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use7" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="8"
data-semantic-children="7"
data-semantic-parent="9"
data-semantic-owns="7"
aria-level="2"
data-speech-node="true"
transform="translate(6555.1798)"
id="g11">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="7"
data-semantic-parent="8"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g10">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use9" />
</g>
</g>
</g>
<g
data-mml-node="mtr"
data-semantic-type="row"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:2"
data-semantic-id="18"
data-semantic-children="11,13,15,17"
data-semantic-parent="37"
data-semantic-owns="11 13 15 17"
aria-level="1"
data-speech-node="true"
transform="translate(0,700)"
id="g21">
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="11"
data-semantic-children="10"
data-semantic-parent="18"
data-semantic-owns="10"
aria-level="2"
data-speech-node="true"
transform="translate(463.5)"
id="g14">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="10"
data-semantic-parent="11"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g13">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use12" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="13"
data-semantic-children="12"
data-semantic-parent="18"
data-semantic-owns="12"
aria-level="2"
data-speech-node="true"
transform="translate(2461.5202)"
id="g16">
<g
data-mml-node="mi"
data-latex="ᚱ"
data-semantic-type="identifier"
data-semantic-role="unknown"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="12"
data-semantic-parent="13"
data-semantic-attributes="latex:ᚱ"
aria-level="3"
data-speech-node="true"
id="g15">
<text
data-variant="italic"
transform="scale(1,-1)"
font-size="884px"
font-family="serif"
font-style="italic"
id="text14">ᚱ</text>
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="15"
data-semantic-children="14"
data-semantic-parent="18"
data-semantic-owns="14"
aria-level="2"
data-speech-node="true"
transform="translate(4698.1)"
id="g18">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="14"
data-semantic-parent="15"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g17">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use16" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="17"
data-semantic-children="16"
data-semantic-parent="18"
data-semantic-owns="16"
aria-level="2"
data-speech-node="true"
transform="translate(6555.1798)"
id="g20">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="16"
data-semantic-parent="17"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g19">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use18" />
</g>
</g>
</g>
<g
data-mml-node="mtr"
data-semantic-type="row"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:2"
data-semantic-id="27"
data-semantic-children="20,22,24,26"
data-semantic-parent="37"
data-semantic-owns="20 22 24 26"
aria-level="1"
data-speech-node="true"
transform="translate(0,-700)"
id="g30">
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="20"
data-semantic-children="19"
data-semantic-parent="27"
data-semantic-owns="19"
aria-level="2"
data-speech-node="true"
transform="translate(463.5)"
id="g23">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="19"
data-semantic-parent="20"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g22">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use21" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="22"
data-semantic-children="21"
data-semantic-parent="27"
data-semantic-owns="21"
aria-level="2"
data-speech-node="true"
transform="translate(2587.6)"
id="g25">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="21"
data-semantic-parent="22"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g24">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use23" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="24"
data-semantic-children="23"
data-semantic-parent="27"
data-semantic-owns="23"
aria-level="2"
data-speech-node="true"
transform="translate(4504.7202)"
id="g27">
<g
data-mml-node="mi"
data-latex="ᛋ"
data-semantic-type="identifier"
data-semantic-role="unknown"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="23"
data-semantic-parent="24"
data-semantic-attributes="latex:ᛋ"
aria-level="3"
data-speech-node="true"
id="g26">
<text
data-variant="italic"
transform="scale(1,-1)"
font-size="884px"
font-family="serif"
font-style="italic"
id="text25">ᛋ</text>
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="26"
data-semantic-children="25"
data-semantic-parent="27"
data-semantic-owns="25"
aria-level="2"
data-speech-node="true"
transform="translate(6555.1798)"
id="g29">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="25"
data-semantic-parent="26"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g28">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use27" />
</g>
</g>
</g>
<g
data-mml-node="mtr"
data-semantic-type="row"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:2"
data-semantic-id="36"
data-semantic-children="29,31,33,35"
data-semantic-parent="37"
data-semantic-owns="29 31 33 35"
aria-level="1"
data-speech-node="true"
transform="translate(0,-2100)"
id="g39">
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="29"
data-semantic-children="28"
data-semantic-parent="36"
data-semantic-owns="28"
aria-level="2"
data-speech-node="true"
transform="translate(463.5)"
id="g32">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="28"
data-semantic-parent="29"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g31">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use30" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="31"
data-semantic-children="30"
data-semantic-parent="36"
data-semantic-owns="30"
aria-level="2"
data-speech-node="true"
transform="translate(2587.6)"
id="g34">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="30"
data-semantic-parent="31"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g33">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use32" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="33"
data-semantic-children="32"
data-semantic-parent="36"
data-semantic-owns="32"
aria-level="2"
data-speech-node="true"
transform="translate(4698.1)"
id="g36">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="32"
data-semantic-parent="33"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g35">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use34" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="35"
data-semantic-children="34"
data-semantic-parent="36"
data-semantic-owns="34"
aria-level="2"
data-speech-node="true"
transform="translate(6426)"
id="g38">
<g
data-mml-node="mi"
data-latex="ᚾ"
data-semantic-type="identifier"
data-semantic-role="unknown"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="34"
data-semantic-parent="35"
data-semantic-attributes="latex:ᚾ"
aria-level="3"
data-speech-node="true"
id="g37">
<text
data-variant="italic"
transform="scale(1,-1)"
font-size="884px"
font-family="serif"
font-style="italic"
id="text36">ᚾ</text>
</g>
</g>
</g>
</g>
<g
data-mml-node="mo"
data-mjx-texclass="CLOSE"
data-semantic-type="fence"
data-semantic-role="close"
data-semantic-annotation="depth:2"
data-semantic-id="38"
data-semantic-parent="37"
data-semantic-attributes="texclass:CLOSE"
aria-level="1"
data-speech-node="true"
transform="translate(7369)"
id="g42">
<use
data-c="23A4"
xlink:href="#MJX-5-NCM-N-23A4"
transform="translate(0,1350)"
id="use40" />
<use
data-c="23A6"
xlink:href="#MJX-5-NCM-N-23A6"
transform="translate(0,-2350)"
id="use41" />
<svg
width="667"
height="2400"
y="-950"
x="0"
viewBox="0 600 667 2400"
version="1.1"
id="svg42">
<use
data-c="23A5"
xlink:href="#MJX-5-NCM-N-23A5"
transform="scale(1,3.6)"
id="use42" />
</svg>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 26 KiB

732
docs/undârsċieppan.svg Normal file
View File

@ -0,0 +1,732 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="159.448px"
height="94.120px"
viewBox="0 -2850 8809.5 5200"
version="1.1"
id="svg45"
sodipodi:docname="equation.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview45"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="5.5369495"
inkscape:cx="68.358941"
inkscape:cy="52.465713"
inkscape:window-width="1991"
inkscape:window-height="932"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="g30" />
<defs
id="defs1">
<path
id="MJX-5-NCM-N-23A1"
d="M614 1500L321 1500L321 0L387 0L387 1432L614 1432C636 1432 647 1443 647 1466C647 1485 633 1500 614 1500Z" />
<path
id="MJX-5-NCM-N-23A3"
d="M614 68L387 68L387 1500L321 1500L321 0L614 0C636 0 647 11 647 34C647 53 633 68 614 68Z" />
<path
id="MJX-5-NCM-N-23A2"
d="M321 0L387 0L387 1000L321 1000Z" />
<path
id="MJX-5-NCM-N-22C5"
d="M192 250C192 279 168 303 139 303C110 303 86 279 86 250C86 221 110 197 139 197C168 197 192 221 192 250Z" />
<path
id="MJX-5-NCM-N-23A4"
d="M280 0L346 0L346 1500L53 1500C31 1500 20 1489 20 1466C20 1443 31 1432 53 1432L280 1432Z" />
<path
id="MJX-5-NCM-N-23A6"
d="M53 0L346 0L346 1500L280 1500L280 68L53 68C31 68 20 57 20 34C20 11 31 0 53 0Z" />
<path
id="MJX-5-NCM-N-23A5"
d="M280 0L346 0L346 1000L280 1000Z" />
</defs>
<g
stroke="#000000"
fill="#000000"
stroke-width="0"
transform="scale(1,-1)"
id="g45">
<g
data-mml-node="math"
data-latex="\begin{bmatrix} ᚢ &amp; \cdot &amp; \cdot &amp; \cdot \\ \cdot &amp;&amp; \cdot &amp; \cdot \\ \cdot &amp; \cdot &amp;&amp; \cdot \\ \cdot &amp; \cdot &amp; \cdot &amp; ᚾ \end{bmatrix}"
data-semantic-structure="(37 0 (9 (2 1) (4 3) (6 5) (8 7)) (18 (11 10) (13 12) (15 14) (17 16)) (27 (20 19) (22 21) (24 23) (26 25)) (36 (29 28) (31 30) (33 32) (35 34)) 38)"
id="g44">
<g
data-mml-node="TeXAtom"
data-mjx-texclass="INNER"
data-latex-item="{bmatrix}"
data-latex="\begin{bmatrix} ᚢ &amp; \cdot &amp; \cdot &amp; \cdot \\ \cdot &amp;&amp; \cdot &amp; \cdot \\ \cdot &amp; \cdot &amp;&amp; \cdot \\ \cdot &amp; \cdot &amp; \cdot &amp; ᚾ \end{bmatrix}"
data-semantic-type="matrix"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:1"
data-semantic-id="37"
data-semantic-children="9,18,27,36"
data-semantic-content="0,38"
data-semantic-attributes="latex:\begin{bmatrix} ᚢ &amp; \cdot &amp; \cdot &amp; \cdot \\ \cdot &amp;&amp; \cdot &amp; \cdot \\ \cdot &amp; \cdot &amp;&amp; \cdot \\ \cdot &amp; \cdot &amp; \cdot &amp; ᚾ \end{bmatrix};texclass:INNER"
data-semantic-owns="0 9 18 27 36 38"
aria-level="0"
data-speech-node="true"
id="g43">
<g
data-mml-node="mo"
data-mjx-texclass="OPEN"
data-semantic-type="fence"
data-semantic-role="open"
data-semantic-annotation="depth:2"
data-semantic-id="0"
data-semantic-parent="37"
data-semantic-attributes="texclass:OPEN"
aria-level="1"
data-speech-node="true"
id="g3"
transform="translate(662.99988)">
<use
data-c="23A1"
xlink:href="#MJX-5-NCM-N-23A1"
transform="translate(0,1350)"
id="use1" />
<use
data-c="23A3"
xlink:href="#MJX-5-NCM-N-23A3"
transform="translate(0,-2350)"
id="use2" />
<svg
width="667"
height="2400"
y="-950"
x="0"
viewBox="0 600 667 2400"
version="1.1"
id="svg3">
<use
data-c="23A2"
xlink:href="#MJX-5-NCM-N-23A2"
transform="scale(1,3.6)"
id="use3" />
</svg>
</g>
<g
data-mml-node="mtable"
transform="matrix(0.86153012,0,0,1,1268.3375,0)"
id="g40">
<g
data-mml-node="mtr"
data-semantic-type="row"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:2"
data-semantic-id="9"
data-semantic-children="2,4,6,8"
data-semantic-parent="37"
data-semantic-owns="2 4 6 8"
aria-level="1"
data-speech-node="true"
transform="translate(0,2100)"
id="g12">
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="2"
data-semantic-children="1"
data-semantic-parent="9"
data-semantic-owns="1"
aria-level="2"
data-speech-node="true"
id="g5"
transform="translate(256.52028)">
<g
data-mml-node="mi"
data-latex="ᚢ"
data-semantic-type="identifier"
data-semantic-role="unknown"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="1"
data-semantic-parent="2"
data-semantic-attributes="latex:ᚢ"
aria-level="3"
data-speech-node="true"
id="g4">
<text
data-variant="italic"
transform="scale(1,-1)"
font-size="884px"
font-family="serif"
font-style="italic"
id="text3">ᚢ</text>
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="4"
data-semantic-children="3"
data-semantic-parent="9"
data-semantic-owns="3"
aria-level="2"
data-speech-node="true"
transform="translate(2587.6)"
id="g7">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="3"
data-semantic-parent="4"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g6">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use5" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="6"
data-semantic-children="5"
data-semantic-parent="9"
data-semantic-owns="5"
aria-level="2"
data-speech-node="true"
transform="translate(4698.1)"
id="g9">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="5"
data-semantic-parent="6"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g8">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use7" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="8"
data-semantic-children="7"
data-semantic-parent="9"
data-semantic-owns="7"
aria-level="2"
data-speech-node="true"
transform="translate(6555.1798)"
id="g11">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="7"
data-semantic-parent="8"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g10">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use9" />
</g>
</g>
</g>
<g
data-mml-node="mtr"
data-semantic-type="row"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:2"
data-semantic-id="18"
data-semantic-children="11,13,15,17"
data-semantic-parent="37"
data-semantic-owns="11 13 15 17"
aria-level="1"
data-speech-node="true"
transform="translate(0,700)"
id="g21">
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="11"
data-semantic-children="10"
data-semantic-parent="18"
data-semantic-owns="10"
aria-level="2"
data-speech-node="true"
transform="translate(463.5)"
id="g14">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="10"
data-semantic-parent="11"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g13">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use12" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="13"
data-semantic-children="12"
data-semantic-parent="18"
data-semantic-owns="12"
aria-level="2"
data-speech-node="true"
transform="translate(2461.5202)"
id="g16">
<g
data-mml-node="mi"
data-latex="ᚱ"
data-semantic-type="identifier"
data-semantic-role="unknown"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="12"
data-semantic-parent="13"
data-semantic-attributes="latex:ᚱ"
aria-level="3"
data-speech-node="true"
id="g15">
<text
data-variant="italic"
transform="scale(1,-1)"
font-size="884px"
font-family="serif"
font-style="italic"
id="text14">ᚱ</text>
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="15"
data-semantic-children="14"
data-semantic-parent="18"
data-semantic-owns="14"
aria-level="2"
data-speech-node="true"
transform="translate(4698.1)"
id="g18">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="14"
data-semantic-parent="15"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g17">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use16" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="17"
data-semantic-children="16"
data-semantic-parent="18"
data-semantic-owns="16"
aria-level="2"
data-speech-node="true"
transform="translate(6555.1798)"
id="g20">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="16"
data-semantic-parent="17"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g19">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use18" />
</g>
</g>
</g>
<g
data-mml-node="mtr"
data-semantic-type="row"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:2"
data-semantic-id="27"
data-semantic-children="20,22,24,26"
data-semantic-parent="37"
data-semantic-owns="20 22 24 26"
aria-level="1"
data-speech-node="true"
transform="translate(0,-700)"
id="g30">
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="20"
data-semantic-children="19"
data-semantic-parent="27"
data-semantic-owns="19"
aria-level="2"
data-speech-node="true"
transform="translate(463.5)"
id="g23">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="19"
data-semantic-parent="20"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g22">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use21" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="22"
data-semantic-children="21"
data-semantic-parent="27"
data-semantic-owns="21"
aria-level="2"
data-speech-node="true"
transform="translate(2587.6)"
id="g25">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="21"
data-semantic-parent="22"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g24">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use23" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="24"
data-semantic-children="23"
data-semantic-parent="27"
data-semantic-owns="23"
aria-level="2"
data-speech-node="true"
transform="translate(4504.7202)"
id="g27">
<g
data-mml-node="mi"
data-latex="ᛋ"
data-semantic-type="identifier"
data-semantic-role="unknown"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="23"
data-semantic-parent="24"
data-semantic-attributes="latex:ᛋ"
aria-level="3"
data-speech-node="true"
id="g26">
<text
data-variant="italic"
transform="scale(1,-1)"
font-size="884px"
font-family="serif"
font-style="italic"
id="text25">ᛋ</text>
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="26"
data-semantic-children="25"
data-semantic-parent="27"
data-semantic-owns="25"
aria-level="2"
data-speech-node="true"
transform="translate(6555.1798)"
id="g29">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="25"
data-semantic-parent="26"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g28">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use27" />
</g>
</g>
</g>
<g
data-mml-node="mtr"
data-semantic-type="row"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:2"
data-semantic-id="36"
data-semantic-children="29,31,33,35"
data-semantic-parent="37"
data-semantic-owns="29 31 33 35"
aria-level="1"
data-speech-node="true"
transform="translate(0,-2100)"
id="g39">
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="29"
data-semantic-children="28"
data-semantic-parent="36"
data-semantic-owns="28"
aria-level="2"
data-speech-node="true"
transform="translate(463.5)"
id="g32">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="28"
data-semantic-parent="29"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g31">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use30" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="31"
data-semantic-children="30"
data-semantic-parent="36"
data-semantic-owns="30"
aria-level="2"
data-speech-node="true"
transform="translate(2587.6)"
id="g34">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="30"
data-semantic-parent="31"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g33">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use32" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="33"
data-semantic-children="32"
data-semantic-parent="36"
data-semantic-owns="32"
aria-level="2"
data-speech-node="true"
transform="translate(4698.1)"
id="g36">
<g
data-mml-node="mo"
data-latex="\cdot"
data-semantic-type="operator"
data-semantic-role="multiplication"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="32"
data-semantic-parent="33"
data-semantic-attributes="latex:\cdot"
aria-level="3"
data-speech-node="true"
id="g35">
<use
data-c="22C5"
xlink:href="#MJX-5-NCM-N-22C5"
id="use34" />
</g>
</g>
<g
data-mml-node="mtd"
data-semantic-type="cell"
data-semantic-role="squarematrix"
data-semantic-annotation="depth:3"
data-semantic-id="35"
data-semantic-children="34"
data-semantic-parent="36"
data-semantic-owns="34"
aria-level="2"
data-speech-node="true"
transform="translate(6426)"
id="g38">
<g
data-mml-node="mi"
data-latex="ᚾ"
data-semantic-type="identifier"
data-semantic-role="unknown"
data-semantic-annotation="nemeth:number;depth:4"
data-semantic-id="34"
data-semantic-parent="35"
data-semantic-attributes="latex:ᚾ"
aria-level="3"
data-speech-node="true"
id="g37">
<text
data-variant="italic"
transform="scale(1,-1)"
font-size="884px"
font-family="serif"
font-style="italic"
id="text36">ᚾ</text>
</g>
</g>
</g>
</g>
<g
data-mml-node="mo"
data-mjx-texclass="CLOSE"
data-semantic-type="fence"
data-semantic-role="close"
data-semantic-annotation="depth:2"
data-semantic-id="38"
data-semantic-parent="37"
data-semantic-attributes="texclass:CLOSE"
aria-level="1"
data-speech-node="true"
transform="translate(7369)"
id="g42">
<use
data-c="23A4"
xlink:href="#MJX-5-NCM-N-23A4"
transform="translate(0,1350)"
id="use40" />
<use
data-c="23A6"
xlink:href="#MJX-5-NCM-N-23A6"
transform="translate(0,-2350)"
id="use41" />
<svg
width="667"
height="2400"
y="-950"
x="0"
viewBox="0 600 667 2400"
version="1.1"
id="svg42">
<use
data-c="23A5"
xlink:href="#MJX-5-NCM-N-23A5"
transform="scale(1,3.6)"
id="use42" />
</svg>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -4,25 +4,18 @@
#include <emscripten.h>
#include <emscripten/html5.h>
i32 console_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) {
USED(mode);
USED(size);
ConsoleDeviceData *console = (ConsoleDeviceData *)data;
console->handle = handle;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &console->handle, sizeof(u32));
return 0; /* Success */
i32 console_open(void *data, u32 mode) {
USED(mode);
USED(data);
return 0;
}
i32 console_read(void *data, u8 *buffer, u32 size) {
USED(data);
for (u32 i = 0; i < size; i++) {
u8 ch = getchar();
if (ch == '\0')
break;
if (ch == '\n')
break;
if (ch == '\0' || ch == '\n') break;
buffer[i] = ch;
}
return 0;
@ -38,7 +31,6 @@ i32 console_write(void *data, const u8 *buffer, u32 size) {
i32 console_close(void *data) {
USED(data);
/* Nothing to close — stdin/stdout are process-owned */
return 0;
}
@ -46,47 +38,134 @@ i32 console_ioctl(void *data, u32 cmd, const u8 *buffer) {
USED(data);
USED(cmd);
USED(buffer);
return -1; /* Unsupported */
return -1;
}
i32 screen_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) {
i32 screen_open(void *data, u32 mode) {
USED(mode);
USED(size);
ScreenDeviceData *screen = (ScreenDeviceData *)data;
screen->handle = handle;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &screen->handle, sizeof(u32));
memcpy(&info[4], &screen->width, sizeof(u32));
memcpy(&info[8], &screen->height, sizeof(u32));
memcpy(&info[12], &screen->buffer_size, sizeof(u32));
screen->screen_buffer = (u8*)(buffer + 16);
// Initialize with proper values
screen->width = 640;
screen->height = 480;
screen->size = 640 * 480;
screen->window = NULL;
screen->renderer = NULL;
screen->texture = NULL;
screen->window =
SDL_CreateWindow("Reality Engine VM", SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, screen->width, screen->height,
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI);
#ifdef __EMSCRIPTEN__
emscripten_set_canvas_element_size("#canvas", screen->width, screen->height);
#endif
screen->window = SDL_CreateWindow(
"Reality Engine VM",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
screen->width,
screen->height,
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI
);
if (!screen->window) {
fprintf(stderr, "Failed to create SDL window: %s\n", SDL_GetError());
return -1;
}
screen->renderer =
SDL_CreateRenderer(screen->window, -1, SDL_RENDERER_ACCELERATED);
// Create renderer with hardware acceleration
screen->renderer = SDL_CreateRenderer(
screen->window, -1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
);
if (!screen->renderer) {
fprintf(stderr, "Failed to create SDL renderer: %s\n", SDL_GetError());
return -1;
}
screen->texture = SDL_CreateTexture(screen->renderer, SDL_PIXELFORMAT_RGB332,
SDL_TEXTUREACCESS_STREAMING,
screen->width, screen->height);
// Create the texture with RGB332 format
screen->texture = SDL_CreateTexture(
screen->renderer,
SDL_PIXELFORMAT_RGB332,
SDL_TEXTUREACCESS_STREAMING,
screen->width,
screen->height
);
if (!screen->texture) {
fprintf(stderr, "SDL_CreateTexture failed: %s\n", SDL_GetError());
// If RGB332 isn't supported, try RGB888
screen->texture = SDL_CreateTexture(
screen->renderer,
SDL_PIXELFORMAT_RGB888,
SDL_TEXTUREACCESS_STREAMING,
screen->width,
screen->height
);
if (!screen->texture) {
fprintf(stderr, "Failed to create SDL texture: %s\n", SDL_GetError());
return -1;
}
printf("Using RGB888 format (conversion needed)\n");
} else {
printf("Using direct RGB332 format\n");
}
return 0;
}
i32 screen_write(void *data, const u8 *buffer, u32 size) {
ScreenDeviceData *screen = (ScreenDeviceData *)data;
if (size > screen->size) {
printf("Screen write size mismatch: %d > %d\n", size, screen->size);
return -1;
}
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
// Update texture with new frame data
SDL_UpdateTexture(screen->texture, NULL, buffer, screen->width);
// Clear and render
SDL_RenderClear(screen->renderer);
SDL_Rect output_rect;
SDL_RenderGetViewport(screen->renderer, &output_rect);
// Calculate aspect ratio preserving scaling
float scale_x = (float)output_rect.w / screen->width;
float scale_y = (float)output_rect.h / screen->height;
float scale = SDL_min(scale_x, scale_y);
SDL_Rect dstrect = {
(i32)((output_rect.w - screen->width * scale) / 2),
(i32)((output_rect.h - screen->height * scale) / 2),
(i32)(screen->width * scale),
(i32)(screen->height * scale)
};
SDL_RenderCopy(screen->renderer, screen->texture, NULL, &dstrect);
SDL_RenderPresent(screen->renderer);
return 0;
}
i32 screen_close(void *data) {
ScreenDeviceData *screen = (ScreenDeviceData *)data;
if (screen->texture) {
SDL_DestroyTexture(screen->texture);
screen->texture = NULL;
}
if (screen->renderer) {
SDL_DestroyRenderer(screen->renderer);
screen->renderer = NULL;
}
if (screen->window) {
SDL_DestroyWindow(screen->window);
screen->window = NULL;
}
return 0;
}
@ -97,63 +176,95 @@ i32 screen_read(void *data, u8 *buffer, u32 size) {
return -1;
}
i32 screen_write(void *data, const u8 *buffer, u32 size) {
i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer) {
ScreenDeviceData *screen = (ScreenDeviceData *)data;
if (size > screen->buffer_size * sizeof(u8)) {
switch (cmd) {
case IOCTL_GET_INFO: {
u8 *info = (u8 *)buffer;
u32 size;
memcpy(&size, &info[0], sizeof(u32));
if (size < 16) {
return -1;
}
memcpy(&info[4], &screen->pos, sizeof(u32));
memcpy(&info[8], &screen->size, sizeof(u32));
memcpy(&info[12], &screen->width, sizeof(u32));
memcpy(&info[16], &screen->height, sizeof(u32));
return 0;
}
default:
return -1;
}
// Update texture with new frame data
SDL_UpdateTexture(screen->texture, NULL, buffer, screen->width);
screen->update = true;
return 0;
}
i32 screen_close(void *data) {
ScreenDeviceData *screen = (ScreenDeviceData *)data;
if (screen->window) {
SDL_DestroyWindow(screen->window);
screen->window = NULL;
}
return 0;
}
i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer) {
USED(data);
USED(cmd);
USED(buffer);
return 0;
}
/* MOUSE */
i32 mouse_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) {
i32 mouse_open(void *data, u32 mode) {
USED(mode);
USED(size);
MouseDeviceData *mouse = (MouseDeviceData *)data;
mouse->handle = handle;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &mouse->handle, sizeof(u32));
return 0;
}
i32 mouse_read(void *data, u8 *buffer, u32 size) {
MouseDeviceData *mouse_data = (MouseDeviceData *)data;
if (size < 12)
return -1;
if (size < 12) return -1;
SDL_PumpEvents();
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
// Mouse events
case SDL_MOUSEMOTION:
mouse_data->x = event.motion.x;
mouse_data->y = event.motion.y;
break;
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_LEFT) mouse_data->btn1 = 1;
if (event.button.button == SDL_BUTTON_RIGHT) mouse_data->btn2 = 1;
if (event.button.button == SDL_BUTTON_MIDDLE) mouse_data->btn3 = 1;
if (event.button.button == SDL_BUTTON_X1) mouse_data->btn4 = 1;
break;
case SDL_MOUSEBUTTONUP:
if (event.button.button == SDL_BUTTON_LEFT) mouse_data->btn1 = 0;
if (event.button.button == SDL_BUTTON_RIGHT) mouse_data->btn2 = 0;
if (event.button.button == SDL_BUTTON_MIDDLE) mouse_data->btn3 = 0;
if (event.button.button == SDL_BUTTON_X1) mouse_data->btn4 = 0;
break;
// Touch events (map to mouse_data as left-click equivalent)
case SDL_FINGERMOTION:
case SDL_FINGERDOWN:
case SDL_FINGERUP: {
float x = event.tfinger.x * 640;
float y = event.tfinger.y * 480;
mouse_data->x = (int)x;
mouse_data->y = (int)y;
// Only treat the first finger as mouse input (ignore multi-touch beyond 1 finger)
if (event.tfinger.fingerId == 0) {
if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) {
mouse_data->btn1 = 1;
} else if (event.type == SDL_FINGERUP) {
mouse_data->btn1 = 0;
}
}
break;
}
}
}
u8 *info = (u8 *)buffer;
memcpy(&info[4], &mouse_data->x, sizeof(u32));
memcpy(&info[8], &mouse_data->y, sizeof(u32));
memcpy(&info[12], &mouse_data->btn1, sizeof(u8));
memcpy(&info[13], &mouse_data->btn2, sizeof(u8));
memcpy(&info[14], &mouse_data->btn3, sizeof(u8));
memcpy(&info[15], &mouse_data->btn4, sizeof(u8));
memcpy(&info[0], &mouse_data->x, sizeof(u32));
memcpy(&info[4], &mouse_data->y, sizeof(u32));
memcpy(&info[8], &mouse_data->btn1, sizeof(u8));
memcpy(&info[9], &mouse_data->btn2, sizeof(u8));
memcpy(&info[10], &mouse_data->btn3, sizeof(u8));
memcpy(&info[11], &mouse_data->btn4, sizeof(u8));
return 0;
}
@ -169,26 +280,18 @@ i32 mouse_close(void *data) {
return 0;
}
i32 keyboard_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) {
i32 keyboard_open(void *data, u32 mode) {
USED(data);
USED(mode);
USED(size);
KeyboardDeviceData *kbd = (KeyboardDeviceData *)data;
kbd->handle = handle;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &kbd->handle, sizeof(u32));
return 0;
}
i32 keyboard_read(void *data, u8 *buffer, u32 size) {
KeyboardDeviceData *kbd = (KeyboardDeviceData *)data;
if (size < (u32)kbd->key_count)
return -1;
if (size < (u32)kbd->key_count) return -1;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &kbd->handle, sizeof(u32));
memcpy(buffer, kbd->keys, kbd->key_count);
return 0;
}
@ -196,10 +299,10 @@ i32 keyboard_write(void *data, const u8 *buffer, u32 size) {
USED(data);
USED(buffer);
USED(size);
return -1; /* not writable */
return -1;
}
i32 keyboard_close(void *data) {
USED(data);
return 0;
}
}

View File

@ -1,17 +1,13 @@
#include "../../vm/device.h"
#include "../../vm/vm.h"
#include <SDL2/SDL.h>
#define IOCTL_GET_INFO 0x01
/* Screen device data */
typedef struct screen_device_data_s {
u32 handle;
u32 width;
u32 height;
u32 buffer_size;
u8 *screen_buffer;
u32 update;
u32 pos;
u32 size;
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
@ -19,49 +15,42 @@ typedef struct screen_device_data_s {
/* Mouse device data */
typedef struct mouse_device_data_s {
u32 handle;
u32 x;
u32 y;
u8 btn1;
u8 btn2;
u8 btn3;
u8 btn4;
u32 pos;
u32 size;
} MouseDeviceData;
/* Keyboard device data */
typedef struct keyboard_device_data_s {
u32 handle;
const u8 *keys;
i32 key_count;
u32 pos;
u32 size;
} KeyboardDeviceData;
/* Console device data */
typedef struct console_device_data_s {
u32 handle;
u32 size;
} ConsoleDeviceData;
i32 screen_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size);
i32 screen_open(void *data, u32 mode);
i32 screen_read(void *data, u8 *buffer, u32 size);
i32 screen_write(void *data, const u8 *buffer, u32 size);
i32 screen_close(void *data);
i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer);
i32 mouse_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size);
i32 mouse_open(void *data, u32 mode);
i32 mouse_read(void *data, u8 *buffer, u32 size);
i32 mouse_write(void *data, const u8 *buffer, u32 size);
i32 mouse_close(void *data);
i32 keyboard_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size);
i32 keyboard_open(void *data, u32 mode);
i32 keyboard_read(void *data, u8 *buffer, u32 size);
i32 keyboard_write(void *data, const u8 *buffer, u32 size);
i32 keyboard_close(void *data);
i32 console_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size);
i32 console_open(void *data, u32 mode);
i32 console_read(void *data, u8 *buffer, u32 size);
i32 console_write(void *data, const u8 *buffer, u32 size);
i32 console_close(void *data);
i32 console_ioctl(void *data, u32 cmd, const u8 *buffer);
i32 console_ioctl(void *data, u32 cmd, const u8 *buffer);

View File

@ -1,5 +1,5 @@
#include "../../vm/device.h"
#include "../../vm/vm.h"
#include "../../vm/device.h"
#include "devices.h"
#include <SDL2/SDL.h>
#include <emscripten.h>
@ -30,84 +30,11 @@ static DeviceOps console_device_ops = {
static ScreenDeviceData screen_data = {0};
static MouseDeviceData mouse_data = {0};
static ConsoleDeviceData console_data = {0};
void mainloop() {
SDL_Event event;
SDL_PumpEvents();
while (SDL_PollEvent(&event)) {
switch (event.type) {
// Mouse events
case SDL_MOUSEMOTION:
mouse_data.x = event.motion.x;
mouse_data.y = event.motion.y;
break;
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_LEFT)
mouse_data.btn1 = 1;
if (event.button.button == SDL_BUTTON_RIGHT)
mouse_data.btn2 = 1;
if (event.button.button == SDL_BUTTON_MIDDLE)
mouse_data.btn3 = 1;
if (event.button.button == SDL_BUTTON_X1)
mouse_data.btn4 = 1;
break;
case SDL_MOUSEBUTTONUP:
if (event.button.button == SDL_BUTTON_LEFT)
mouse_data.btn1 = 0;
if (event.button.button == SDL_BUTTON_RIGHT)
mouse_data.btn2 = 0;
if (event.button.button == SDL_BUTTON_MIDDLE)
mouse_data.btn3 = 0;
if (event.button.button == SDL_BUTTON_X1)
mouse_data.btn4 = 0;
break;
// Touch events (map to mouse_data as left-click equivalent)
case SDL_FINGERMOTION:
case SDL_FINGERDOWN:
case SDL_FINGERUP: {
float x = event.tfinger.x * 640;
float y = event.tfinger.y * 480;
mouse_data.x = (int)x;
mouse_data.y = (int)y;
// Only treat the first finger as mouse input (ignore multi-touch beyond 1
// finger)
if (event.tfinger.fingerId == 0) {
if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) {
mouse_data.btn1 = 1;
} else if (event.type == SDL_FINGERUP) {
mouse_data.btn1 = 0;
}
}
break;
}
}
}
// Run VM for a fixed number of cycles or a time slice
int cycles_this_frame = 0;
int max_cycles_per_frame = 2000; // Adjust this value
while (cycles_this_frame < max_cycles_per_frame) {
if (!step_vm(&vm)) {
emscripten_cancel_main_loop();
return;
}
cycles_this_frame++;
}
// Render only if the screen buffer was updated AND at a reasonable rate
if (screen_data.update) {
if (screen_data.renderer && screen_data.texture) {
SDL_RenderCopy(screen_data.renderer, screen_data.texture, NULL, NULL);
SDL_RenderPresent(screen_data.renderer);
}
screen_data.update = false; // Reset flag after rendering
if (!step_vm(&vm)) {
emscripten_cancel_main_loop();
printf("VM execution completed\n");
}
}
@ -123,6 +50,7 @@ bool loadVM(const char *filename, VM *vm) {
fread(&vm->cp, sizeof(u32), 1, file) != 1 ||
fread(&vm->fp, sizeof(u32), 1, file) != 1 ||
fread(&vm->sp, sizeof(u32), 1, file) != 1 ||
fread(&vm->rp, sizeof(u32), 1, file) != 1 ||
fread(&vm->mp, sizeof(u32), 1, file) != 1 ||
fread(&vm->dc, sizeof(u32), 1, file) != 1 ||
fread(&vm->flag, sizeof(i32), 1, file) != 1) {
@ -156,17 +84,17 @@ int main(int argc, char **argv) {
}
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
#ifdef __EMSCRIPTEN__
#ifdef __EMSCRIPTEN__
emscripten_set_canvas_element_size("#canvas", 640, 480);
#endif
#endif
loadVM("paint.rom", &vm);
printf("VM loaded successfully\n");
// Initialize device data
screen_data.width = 640;
screen_data.height = 480;
screen_data.buffer_size = screen_data.width * screen_data.height;
screen_data.size = 640 * 480;
screen_data.window = NULL;
screen_data.renderer = NULL;
screen_data.texture = NULL;
@ -177,15 +105,12 @@ int main(int argc, char **argv) {
mouse_data.btn2 = 0;
mouse_data.btn3 = 0;
mouse_data.btn4 = 0;
mouse_data.size = 16;
mouse_data.size = 12;
// Register devices
vm_register_device(&vm, "/dev/screen/0", "screen", &screen_data,
&screen_ops, 16 + screen_data.buffer_size);
vm_register_device(&vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops,
mouse_data.size);
vm_register_device(&vm, "/dev/term/0", "terminal", &console_data,
&console_device_ops, 4);
vm_register_device(&vm, "/dev/screen/0", "screen", &screen_data, &screen_ops);
vm_register_device(&vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops);
vm_register_device(&vm, "/dev/term/0", "terminal", NULL, &console_device_ops);
// Set up main loop
emscripten_set_main_loop(mainloop, 0, 1);

View File

@ -1,288 +0,0 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Emscripten-Generated Code</title>
<style>
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
textarea.emscripten { font-family: monospace; width: 80%; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { border: 0px none; background-color: black; }
.spinner {
height: 50px;
width: 50px;
margin: 0px auto;
-webkit-animation: rotation .8s linear infinite;
-moz-animation: rotation .8s linear infinite;
-o-animation: rotation .8s linear infinite;
animation: rotation 0.8s linear infinite;
border-left: 10px solid rgb(0,150,240);
border-right: 10px solid rgb(0,150,240);
border-bottom: 10px solid rgb(0,150,240);
border-top: 10px solid rgb(100,0,200);
border-radius: 100%;
background-color: rgb(200,100,250);
}
@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-moz-keyframes rotation {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(360deg);}
}
@-o-keyframes rotation {
from {-o-transform: rotate(0deg);}
to {-o-transform: rotate(360deg);}
}
@keyframes rotation {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
line-height: 1.6;
color: #ddd;
background: black;
padding: 0;
margin: 0;
}
main {
max-width: 700px;
margin: 0 auto;
padding: 1.5rem;
}
header {
background: #111;
padding: 1rem 1.5rem;
border-bottom: 1px solid #222;
text-align: center;
}
header h1 {
font-size: 1.5rem;
font-weight: 600;
color: #ddd;
}
nav a {
color: #ddd;
padding: 12px 15px;
text-decoration: none;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
flex-grow: 1;
}
nav a:hover {
background-color: #1b1b1b;
}
a {
color: #ddd;
}
textarea {
background: #111;
padding: 1rem 1.5rem;
border-top: 1px solid #222;
text-align: center;
margin-top: 2rem;
font-size: 0.9rem;
color: #ddd;
}
p {
margin-bottom: 1.25rem;
}
code {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
background-color: #1a1a1a;
padding: 0.2em 0.4em;
border-radius: 3px;
font-size: 0.9em;
}
pre {
background: #262620;
color: #f8f8f2;
padding: 1rem;
border-radius: 5px;
overflow-x: auto;
margin: 1.5rem 0;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 0.95rem;
line-height: 1.5;
}
pre code {
background: transparent;
padding: 0;
font-size: 1em;
color: #f8f8f2;
}
@media (min-width: 768px) {
main {
padding: 2rem;
}
header h1 {
font-size: 2rem;
}
}
@media (prefers-color-scheme: light) {
body {
background-color: white;
color: black;
}
header {
background: #ddd;
color: black;
}
a {
color: black;
}
nav a {
color: black;
}
nav a:hover {
background-color: #eee;
color: black;
}
main {
background-color: white;
}
pre {
background-color: #f5f5f5;
border: 1px solid #ddd;
}
pre code {
color: #333;
}
textarea {
background: #ddd;
}
}
</style>
</head>
<body>
<hr/>
<figure style="overflow:visible;" id="spinner"><div class="spinner"></div><center style="margin-top:0.5em"><strong>emscripten</strong></center></figure>
<div class="emscripten" id="status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
</div>
<hr/>
<div class="emscripten">
<input type="checkbox" id="resize">Resize canvas
<input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer
&nbsp;&nbsp;&nbsp;
<input type="button" value="Fullscreen" onclick="Module.requestFullscreen(document.getElementById('pointerLock').checked,
document.getElementById('resize').checked)">
</div>
<hr/>
<textarea class="emscripten" id="output" rows="8"></textarea>
<hr>
<script type='text/javascript'>
var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress');
var spinnerElement = document.getElementById('spinner');
var canvasElement = document.getElementById('canvas');
var outputElement = document.getElementById('output');
if (outputElement) outputElement.value = ''; // clear browser cache
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvasElement.addEventListener("webglcontextlost", (e) => {
alert('WebGL context lost. You will need to reload the page.');
e.preventDefault();
}, false);
var Module = {
print(...args) {
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&amp;");
//text = text.replace(/</g, "&lt;");
//text = text.replace(/>/g, "&gt;");
//text = text.replace('\n', '<br>', 'g');
console.log(...args);
if (outputElement) {
var text = args.join(' ');
outputElement.value += text + "\n";
outputElement.scrollTop = outputElement.scrollHeight; // focus on bottom
}
},
canvas: canvasElement,
setStatus(text) {
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
if (text === Module.setStatus.last.text) return;
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
var now = Date.now();
if (m && now - Module.setStatus.last.time < 30) return; // if this is a progress update, skip it if too soon
Module.setStatus.last.time = now;
Module.setStatus.last.text = text;
if (m) {
text = m[1];
progressElement.value = parseInt(m[2])*100;
progressElement.max = parseInt(m[4])*100;
progressElement.hidden = false;
spinnerElement.hidden = false;
} else {
progressElement.value = null;
progressElement.max = null;
progressElement.hidden = true;
if (!text) spinnerElement.hidden = true;
}
statusElement.innerHTML = text;
},
totalDependencies: 0,
monitorRunDependencies(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
};
Module.setStatus('Downloading...');
window.onerror = () => {
Module.setStatus('Exception thrown, see JavaScript console');
spinnerElement.style.display = 'none';
Module.setStatus = (text) => {
if (text) console.error('[post-exception status] ' + text);
};
};
</script>
{{{ SCRIPT }}}
</body>
</html>

View File

@ -3,14 +3,10 @@
#include <string.h>
#include <unistd.h>
i32 console_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) {
i32 console_open(void *data, u32 mode) {
USED(mode);
USED(size);
ConsoleDeviceData *console = (ConsoleDeviceData *)data;
console->handle = handle;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &console->handle, sizeof(u32));
USED(data);
/* Nothing to open — stdin/stdout are always available */
return 0; /* Success */
}
@ -48,18 +44,9 @@ i32 console_ioctl(void *data, u32 cmd, const u8 *buffer) {
return -1; /* Unsupported */
}
i32 screen_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) {
i32 screen_open(void *data, u32 mode) {
USED(mode);
USED(size);
ScreenDeviceData *screen = (ScreenDeviceData *)data;
screen->handle = handle;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &screen->handle, sizeof(u32));
memcpy(&info[4], &screen->width, sizeof(u32));
memcpy(&info[8], &screen->height, sizeof(u32));
memcpy(&info[12], &screen->buffer_size, sizeof(u32));
screen->screen_buffer = (u8*)(buffer + 16);
screen->window =
SDL_CreateWindow("Reality Engine VM", SDL_WINDOWPOS_CENTERED,
@ -99,13 +86,32 @@ i32 screen_read(void *data, u8 *buffer, u32 size) {
i32 screen_write(void *data, const u8 *buffer, u32 size) {
ScreenDeviceData *screen = (ScreenDeviceData *)data;
if (size > screen->buffer_size * sizeof(u8)) {
if (size > screen->size * sizeof(u8)) {
return -1;
}
// Update texture with new frame data
SDL_UpdateTexture(screen->texture, NULL, buffer, screen->width);
screen->update = true;
// Clear and render
SDL_RenderClear(screen->renderer);
SDL_Rect output_rect;
SDL_RenderGetViewport(screen->renderer, &output_rect);
// Calculate aspect ratio preserving scaling
float scale_x = (float)output_rect.w / screen->width;
float scale_y = (float)output_rect.h / screen->height;
float scale = SDL_min(scale_x, scale_y);
SDL_Rect dstrect = {
(i32)((output_rect.w - screen->width * scale) / 2),
(i32)((output_rect.h - screen->height * scale) / 2),
(i32)(screen->width * scale),
(i32)(screen->height * scale)
};
SDL_RenderCopy(screen->renderer, screen->texture, NULL, &dstrect);
SDL_RenderPresent(screen->renderer);
return 0;
}
@ -121,42 +127,61 @@ i32 screen_close(void *data) {
}
i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer) {
USED(data);
USED(cmd);
USED(buffer);
return 0;
ScreenDeviceData *screen = (ScreenDeviceData *)data;
switch (cmd) {
case IOCTL_GET_INFO: {
u8 *info = (u8 *)buffer;
u32 size;
memcpy(&size, &info[0], sizeof(u32));
if (size < 16) {
return -1;
}
memcpy(&info[4], &screen->pos, sizeof(u32));
memcpy(&info[8], &screen->size, sizeof(u32));
memcpy(&info[12], &screen->width, sizeof(u32));
memcpy(&info[16], &screen->height, sizeof(u32));
return 0;
}
default:
return -1; // Error
}
}
/* MOUSE */
i32 mouse_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) {
i32 mouse_open(void *data, u32 mode) {
USED(data);
USED(mode);
USED(size);
MouseDeviceData *mouse = (MouseDeviceData *)data;
mouse->handle = handle;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &mouse->handle, sizeof(u32));
return 0;
}
i32 mouse_read(void *data, u8 *buffer, u32 size) {
USED(data);
USED(buffer);
USED(size);
return -1;
}
i32 mouse_refresh(void *data, u8 *buffer) {
MouseDeviceData *mouse_data = (MouseDeviceData *)data;
u8 *info = (u8 *)buffer;
memcpy(&info[4], &mouse_data->x, sizeof(u32));
memcpy(&info[8], &mouse_data->y, sizeof(u32));
memcpy(&info[12], &mouse_data->btn1, sizeof(u8));
memcpy(&info[13], &mouse_data->btn2, sizeof(u8));
memcpy(&info[14], &mouse_data->btn3, sizeof(u8));
memcpy(&info[15], &mouse_data->btn4, sizeof(u8));
if (size < 12)
return -1;
SDL_PumpEvents();
int x, y;
Uint32 state = SDL_GetMouseState(&x, &y);
mouse_data->x = x;
mouse_data->y = y;
mouse_data->btn1 = (state & SDL_BUTTON(SDL_BUTTON_LEFT)) ? 1 : 0;
mouse_data->btn2 = (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) ? 1 : 0;
mouse_data->btn3 = (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) ? 1 : 0;
mouse_data->btn4 = (state & SDL_BUTTON(SDL_BUTTON_X1)) ? 1 : 0;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &mouse_data->x, sizeof(u32));
memcpy(&info[4], &mouse_data->y, sizeof(u32));
memcpy(&info[8], &mouse_data->btn1, sizeof(u8));
memcpy(&info[9], &mouse_data->btn2, sizeof(u8));
memcpy(&info[10], &mouse_data->btn3, sizeof(u8));
memcpy(&info[11], &mouse_data->btn4, sizeof(u8));
return 0;
}
@ -172,15 +197,9 @@ i32 mouse_close(void *data) {
return 0;
}
i32 keyboard_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) {
i32 keyboard_open(void *data, u32 mode) {
USED(data);
USED(mode);
USED(size);
KeyboardDeviceData *kbd = (KeyboardDeviceData *)data;
kbd->handle = handle;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &kbd->handle, sizeof(u32));
return 0;
}
@ -190,8 +209,7 @@ i32 keyboard_read(void *data, u8 *buffer, u32 size) {
if (size < (u32)kbd->key_count)
return -1;
u8 *info = (u8 *)buffer;
memcpy(&info[0], &kbd->handle, sizeof(u32));
memcpy(buffer, kbd->keys, kbd->key_count);
return 0;
}

View File

@ -6,12 +6,10 @@
/* Screen device data */
typedef struct screen_device_data_s {
u32 handle;
u32 width;
u32 height;
u32 buffer_size;
u8 *screen_buffer;
u32 update;
u32 pos;
u32 size;
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
@ -19,46 +17,41 @@ typedef struct screen_device_data_s {
/* Mouse device data */
typedef struct mouse_device_data_s {
u32 handle;
u32 x;
u32 y;
u8 btn1;
u8 btn2;
u8 btn3;
u8 btn4;
u32 pos;
u32 size;
} MouseDeviceData;
/* Keyboard device data */
typedef struct keyboard_device_data_s {
u32 handle;
i32 key_count;
const u8 *keys;
i32 key_count;
u32 pos;
u32 size;
} KeyboardDeviceData;
/* Console device data */
typedef struct console_device_data_s {
u32 handle;
u32 size;
} ConsoleDeviceData;
i32 screen_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size);
i32 screen_open(void *data, u32 mode);
i32 screen_read(void *data, u8 *buffer, u32 size);
i32 screen_write(void *data, const u8 *buffer, u32 size);
i32 screen_close(void *data);
i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer);
i32 mouse_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size);
i32 mouse_open(void *data, u32 mode);
i32 mouse_read(void *data, u8 *buffer, u32 size);
i32 mouse_refresh(void *data, u8 *buffer);
i32 mouse_write(void *data, const u8 *buffer, u32 size);
i32 mouse_close(void *data);
i32 keyboard_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size);
i32 keyboard_open(void *data, u32 mode);
i32 keyboard_read(void *data, u8 *buffer, u32 size);
i32 keyboard_write(void *data, const u8 *buffer, u32 size);
i32 keyboard_close(void *data);
i32 console_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size);
i32 console_open(void *data, u32 mode);
i32 console_read(void *data, u8 *buffer, u32 size);
i32 console_write(void *data, const u8 *buffer, u32 size);
i32 console_close(void *data);

View File

@ -1,5 +1,4 @@
#include "../../tools/assembler.h"
#include "../../tools/lexer.h"
#include "../../tools/parser.h"
#include "../../vm/vm.h"
#include "devices.h"
@ -15,34 +14,31 @@ static DeviceOps screen_ops = {.open = screen_open,
.read = screen_read,
.write = screen_write,
.close = screen_close,
.ioctl = screen_ioctl,
.refresh = nil};
.ioctl = screen_ioctl};
static DeviceOps mouse_ops = {.open = mouse_open,
.read = mouse_read,
.write = mouse_write,
.close = mouse_close,
.ioctl = nil,
.refresh = mouse_refresh};
.ioctl = nil};
static DeviceOps keyboard_ops = {.open = keyboard_open,
.read = keyboard_read,
.write = keyboard_write,
.close = keyboard_close,
.ioctl = nil,
.refresh = nil};
.ioctl = nil};
static DeviceOps console_device_ops = {.open = console_open,
.read = console_read,
.write = console_write,
.close = console_close,
.ioctl = console_ioctl,
.refresh = nil};
static DeviceOps console_device_ops = {
.open = console_open,
.read = console_read,
.write = console_write,
.close = console_close,
.ioctl = console_ioctl,
};
static ScreenDeviceData screen_data = {0};
static MouseDeviceData mouse_data = {0};
static KeyboardDeviceData keyboard_data = {0};
static ConsoleDeviceData console_data = {0};
// Function to save VM state to ROM file
bool saveVM(const char *filename, VM *vm) {
@ -57,6 +53,7 @@ bool saveVM(const char *filename, VM *vm) {
fwrite(&vm->cp, sizeof(u32), 1, file) != 1 ||
fwrite(&vm->fp, sizeof(u32), 1, file) != 1 ||
fwrite(&vm->sp, sizeof(u32), 1, file) != 1 ||
fwrite(&vm->rp, sizeof(u32), 1, file) != 1 ||
fwrite(&vm->mp, sizeof(u32), 1, file) != 1 ||
fwrite(&vm->dc, sizeof(u32), 1, file) != 1 ||
fwrite(&vm->flag, sizeof(i32), 1, file) != 1) {
@ -95,6 +92,7 @@ bool loadVM(const char *filename, VM *vm) {
fread(&vm->cp, sizeof(u32), 1, file) != 1 ||
fread(&vm->fp, sizeof(u32), 1, file) != 1 ||
fread(&vm->sp, sizeof(u32), 1, file) != 1 ||
fread(&vm->rp, sizeof(u32), 1, file) != 1 ||
fread(&vm->mp, sizeof(u32), 1, file) != 1 ||
fread(&vm->dc, sizeof(u32), 1, file) != 1 ||
fread(&vm->flag, sizeof(i32), 1, file) != 1) {
@ -123,47 +121,6 @@ bool loadVM(const char *filename, VM *vm) {
// Function to compile and optionally save
bool compileAndSave(const char *source_file, const char *output_file, VM *vm) {
USED(vm);
USED(output_file);
FILE *f = fopen(source_file, "rb");
if (!f) {
perror("fopen");
return false;
}
static char source[MAX_SRC_SIZE + 1];
fseek(f, 0, SEEK_END);
long len = ftell(f);
fseek(f, 0, SEEK_SET);
if (len >= MAX_SRC_SIZE) {
fprintf(stderr, "Source is larger than buffer\n");
fclose(f);
return false;
}
size_t read = fread(source, 1, len, f);
source[read] = '\0';
fclose(f);
initLexer(source);
Token token;
do {
token = nextToken();
if (token.type == TOKEN_ERROR) {
printf("ERROR at line %d: %.*s\n", token.line, token.length, token.start);
break; // Stop on error, or continue if you want to see more
}
if (token.type != TOKEN_EOF) {
printf("Line %d [%s]: %.*s\n", token.line, tokenTypeToString(token.type),
token.length, token.start);
}
} while (token.type != TOKEN_EOF);
return true;
}
// Function to assemble and optionally save
bool assembleAndSave(const char *source_file, const char *output_file, VM *vm) {
FILE *f = fopen(source_file, "rb");
if (!f) {
perror("fopen");
@ -189,6 +146,9 @@ bool assembleAndSave(const char *source_file, const char *output_file, VM *vm) {
printf("Parse failed.\n");
return false;
} else {
#ifdef ASM_DEBUG
expr_print(ast, 0);
#endif
assemble(vm, ast);
expr_free(ast);
@ -273,137 +233,114 @@ void repl(VM *vm) {
}
// If unbalanced, continue reading more lines
}
exit(vm->flag);
exit(0);
}
/*
* This needs to be done dynamically eventually
*/
void register_sdl_devices(VM *vm) {
screen_data.width = 640;
screen_data.height = 480;
screen_data.size = screen_data.width * screen_data.height;
vm_register_device(vm, "/dev/screen/0", "screen", &screen_data, &screen_ops);
mouse_data.x = 0;
mouse_data.y = 0;
mouse_data.btn1 = 0;
mouse_data.btn2 = 0;
mouse_data.btn3 = 0;
mouse_data.btn4 = 0;
mouse_data.size = 12;
vm_register_device(vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops);
keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count);
vm_register_device(vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
&keyboard_ops);
}
#define ASM_DEBUG
#ifdef ASM_DEBUG
const char *opcode_to_string(Opcode op) {
static const char *names[] = {
[OP_HALT] = "halt",
[OP_JMP] = "jump",
[OP_JMPF] = "jump-if-flag",
[OP_CALL] = "call",
[OP_RETURN] = "return",
/* Immediate loads (only 32-bit variant needed) */
[OP_LOAD_IMM] = "load-immediate",
/* Register-indirect loads */
[OP_LOAD_IND_8] = "load-indirect-8",
[OP_LOAD_IND_16] = "load-indirect-16",
[OP_LOAD_IND_32] = "load-indirect-32",
/* Absolute address loads */
[OP_LOAD_ABS_8] = "load-absolute-8",
[OP_LOAD_ABS_16] = "load-absolute-16",
[OP_LOAD_ABS_32] = "load-absolute-32",
/* Base+offset loads */
[OP_LOAD_OFF_8] = "load-offset-8",
[OP_LOAD_OFF_16] = "load-offset-16",
[OP_LOAD_OFF_32] = "load-offset-32",
/* Absolute address stores */
[OP_STORE_ABS_8] = "store-absolute-8",
[OP_STORE_ABS_16] = "store-absolute-16",
[OP_STORE_ABS_32] = "store-absolute-32",
/* Register-indirect stores */
[OP_STORE_IND_8] = "store-indirect-8",
[OP_STORE_IND_16] = "store-indirect-16",
[OP_STORE_IND_32] = "store-indirect-32",
/* Base+offset stores */
[OP_STORE_OFF_8] = "store-offset-8",
[OP_STORE_OFF_16] = "store-offset-16",
[OP_STORE_OFF_32] = "store-offset-32",
/* Memory operations */
[OP_MALLOC] = "malloc",
[OP_MEMSET_8] = "memset-8",
[OP_MEMSET_16] = "memset-16",
[OP_MEMSET_32] = "memset-32",
/* Register operations */
[OP_REG_MOV] = "register-move",
[OP_SYSCALL] = "syscall",
/* Bit operations */
[OP_BIT_SHIFT_LEFT] = "bit-shift-left",
[OP_BIT_SHIFT_RIGHT] = "bit-shift-right",
[OP_BIT_SHIFT_R_EXT] = "bit-shift-r-ext",
[OP_BAND] = "bit-and",
[OP_BOR] = "bit-or",
[OP_BXOR] = "bit-xor",
/* Integer arithmetic */
[OP_ADD_INT] = "add-int",
[OP_SUB_INT] = "sub-int",
[OP_MUL_INT] = "mul-int",
[OP_DIV_INT] = "div-int",
[OP_ABS_INT] = "abs-int", // ← NEW
[OP_NEG_INT] = "neg-int", // ← NEW
/* Natural number arithmetic */
[OP_ADD_NAT] = "add-nat",
[OP_SUB_NAT] = "sub-nat",
[OP_MUL_NAT] = "mul-nat",
[OP_DIV_NAT] = "div-nat",
[OP_ABS_NAT] = "abs-nat", // ← NEW
[OP_NEG_NAT] = "neg-nat", // ← NEW
/* Floating point operations */
[OP_ADD_REAL] = "add-real",
[OP_SUB_REAL] = "sub-real",
[OP_MUL_REAL] = "mul-real",
[OP_DIV_REAL] = "div-real",
[OP_ABS_REAL] = "abs-real", // ← NEW
[OP_NEG_REAL] = "neg-real", // ← NEW
/* Type conversions */
[OP_INT_TO_REAL] = "int-to-real",
[OP_NAT_TO_REAL] = "nat-to-real",
[OP_REAL_TO_INT] = "real-to-int",
[OP_REAL_TO_NAT] = "real-to-nat",
/* Integer comparisons */
[OP_JEQ_INT] = "jump-eq-int",
[OP_JNEQ_INT] = "jump-neq-int",
[OP_JGT_INT] = "jump-gt-int",
[OP_JLT_INT] = "jump-lt-int",
[OP_JLE_INT] = "jump-le-int",
[OP_JGE_INT] = "jump-ge-int",
/* Natural number comparisons */
[OP_JEQ_NAT] = "jump-eq-nat",
[OP_JNEQ_NAT] = "jump-neq-nat",
[OP_JGT_NAT] = "jump-gt-nat",
[OP_JLT_NAT] = "jump-lt-nat",
[OP_JLE_NAT] = "jump-le-nat",
[OP_JGE_NAT] = "jump-ge-nat",
/* Floating point comparisons */
[OP_JEQ_REAL] = "jump-eq-real",
[OP_JNEQ_REAL] = "jump-neq-real",
[OP_JGE_REAL] = "jump-ge-real",
[OP_JGT_REAL] = "jump-gt-real",
[OP_JLT_REAL] = "jump-lt-real",
[OP_JLE_REAL] = "jump-le-real",
/* String operations */
[OP_STRLEN] = "string-length",
[OP_STREQ] = "string-eq",
[OP_STRCAT] = "string-concat",
[OP_STR_GET_CHAR] = "string-get-char",
[OP_STR_FIND_CHAR] = "string-find-char",
[OP_STR_SLICE] = "string-slice",
/* String conversions */
[OP_INT_TO_STRING] = "int-to-string",
[OP_NAT_TO_STRING] = "nat-to-string",
[OP_REAL_TO_STRING] = "real-to-string",
[OP_STRING_TO_INT] = "string-to-int",
[OP_STRING_TO_NAT] = "string-to-nat",
[OP_STRING_TO_REAL] = "string-to-real"};
[OP_HALT] = "halt",
[OP_JMP] = "jump",
[OP_JMPF] = "jump-if-flag",
[OP_CALL] = "call",
[OP_RETURN] = "return",
[OP_LOAD_8] = "load-8",
[OP_LOAD_16] = "load-16",
[OP_LOAD_32] = "load",
[OP_STORE_8] = "store-8",
[OP_STORE_16] = "store-16",
[OP_STORE_32] = "store",
[OP_MALLOC] = "malloc",
[OP_MEMSET_8] = "memset-8",
[OP_MEMSET_16] = "memset-16",
[OP_MEMSET_32] = "memset",
[OP_PUSH] = "push",
[OP_POP] = "pop",
[OP_DUP] = "dup",
[OP_EXCH] = "exch",
[OP_OVER] = "over",
[OP_PICK] = "pick",
[OP_ROT] = "rot",
[OP_DEPTH] = "depth",
[OP_SYSCALL] = "syscall",
[OP_SLL] = "bit-shift-left",
[OP_SRL] = "bit-shift-right",
[OP_SRE] = "bit-shift-re",
[OP_BAND] = "bit-and",
[OP_BOR] = "bit-or",
[OP_BXOR] = "bit-xor",
[OP_ADD_INT] = "add-int",
[OP_SUB_INT] = "sub-int",
[OP_MUL_INT] = "mul-int",
[OP_DIV_INT] = "div-int",
[OP_ADD_UINT] = "add-nat",
[OP_SUB_UINT] = "sub-nat",
[OP_MUL_UINT] = "mul-nat",
[OP_DIV_UINT] = "div-nat",
[OP_ADD_REAL] = "add-real",
[OP_SUB_REAL] = "sub-real",
[OP_MUL_REAL] = "mul-real",
[OP_DIV_REAL] = "div-real",
[OP_INT_TO_REAL] = "int-to-real",
[OP_UINT_TO_REAL] = "nat-to-real",
[OP_REAL_TO_INT] = "real-to-int",
[OP_REAL_TO_UINT] = "real-to-nat",
[OP_JEQ_INT] = "jump-eq-int",
[OP_JNEQ_INT] = "jump-neq-int",
[OP_JGT_INT] = "jump-gt-int",
[OP_JLT_INT] = "jump-lt-int",
[OP_JLE_INT] = "jump-le-int",
[OP_JGE_INT] = "jump-ge-int",
[OP_JEQ_UINT] = "jump-eq-nat",
[OP_JNEQ_UINT] = "jump-neq-nat",
[OP_JGT_UINT] = "jump-gt-nat",
[OP_JLT_UINT] = "jump-lt-nat",
[OP_JLE_UINT] = "jump-le-nat",
[OP_JGE_UINT] = "jump-ge-nat",
[OP_JEQ_REAL] = "jump-eq-real",
[OP_JNEQ_REAL] = "jump-neq-real",
[OP_JGE_REAL] = "jump-ge-real",
[OP_JGT_REAL] = "jump-gt-real",
[OP_JLT_REAL] = "jump-lt-real",
[OP_JLE_REAL] = "jump-le-real",
[OP_STRLEN] = "string-length",
[OP_STREQ] = "string-eq",
[OP_STRCAT] = "string-concat",
[OP_STR_GET_CHAR] = "string-get-char",
[OP_STR_FIND_CHAR] = "string-find-char",
[OP_STR_SLICE] = "string-slice",
[OP_INT_TO_STRING] = "int-to-string",
[OP_UINT_TO_STRING] = "nat-to-string",
[OP_REAL_TO_STRING] = "real-to-string",
[OP_STRING_TO_INT] = "string-to-int",
[OP_STRING_TO_UINT] = "string-to-nat",
[OP_STRING_TO_REAL] = "string-to-real",
};
if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) {
return "<invalid-opcode>";
@ -415,15 +352,18 @@ const char *opcode_to_string(Opcode op) {
#endif
i32 main(i32 argc, char *argv[]) {
bool gui_mode = false;
bool dump_rom = false;
char *input_file = nil;
char *output_file = nil;
bool is_rom = false;
bool is_assembly = false;
// Parse command line arguments
for (i32 i = 1; i < argc; i++) {
if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--dump-rom") == 0) {
if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gui") == 0) {
gui_mode = true;
} else if (strcmp(argv[i], "-o") == 0 ||
strcmp(argv[i], "--dump-rom") == 0) {
dump_rom = true;
} else if (input_file == nil) {
// This is the input file
@ -434,9 +374,6 @@ i32 main(i32 argc, char *argv[]) {
if (ext && (strcmp(ext, ".rom") == 0)) {
is_rom = true;
}
if (ext && (strcmp(ext, ".lisp") == 0)) {
is_assembly = true;
}
} else if (output_file == nil && dump_rom) {
// This is the output file for -o flag
output_file = argv[i];
@ -450,14 +387,8 @@ i32 main(i32 argc, char *argv[]) {
if (is_rom) {
// Load ROM file directly
compilation_success = loadVM(input_file, &vm);
} else if (is_assembly) {
// Compile Lisp file
if (dump_rom && output_file) {
compilation_success = assembleAndSave(input_file, output_file, &vm);
} else {
compilation_success = assembleAndSave(input_file, nil, &vm);
}
} else {
// Compile Lisp file
if (dump_rom && output_file) {
compilation_success = compileAndSave(input_file, output_file, &vm);
} else {
@ -484,138 +415,48 @@ i32 main(i32 argc, char *argv[]) {
return EXIT_SUCCESS;
}
vm_register_device(&vm, "/dev/term/0", "terminal", &console_data,
&console_device_ops, 4);
vm_register_device(&vm, "/dev/term/0", "terminal", nil, &console_device_ops);
if (gui_mode) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("SDL initialization failed: %s\n", SDL_GetError());
return 1;
}
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("SDL initialization failed: %s\n", SDL_GetError());
return 1;
}
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
screen_data.width = 640;
screen_data.height = 480;
screen_data.size = screen_data.width * screen_data.height;
screen_data.width = 640;
screen_data.height = 480;
screen_data.buffer_size = screen_data.width * screen_data.height;
vm_register_device(&vm, "/dev/screen/0", "screen",
&screen_data, &screen_ops);
vm_register_device(&vm, "/dev/screen/0", "screen", &screen_data, &screen_ops,
16 + screen_data.buffer_size);
mouse_data.x = 0;
mouse_data.y = 0;
mouse_data.btn1 = 0;
mouse_data.btn2 = 0;
mouse_data.btn3 = 0;
mouse_data.btn4 = 0;
mouse_data.size = 12;
mouse_data.x = 0;
mouse_data.y = 0;
mouse_data.btn1 = 0;
mouse_data.btn2 = 0;
mouse_data.btn3 = 0;
mouse_data.btn4 = 0;
vm_register_device(&vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops);
vm_register_device(&vm, "/dev/mouse/0", "mouse", &mouse_data, &mouse_ops, 16);
keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count);
vm_register_device(&vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
&keyboard_ops);
keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count);
vm_register_device(&vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
&keyboard_ops, keyboard_data.key_count + 4);
SDL_Event event;
bool running = true;
SDL_PumpEvents();
while (running) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = false;
break;
// Mouse events
case SDL_MOUSEMOTION:
mouse_data.x = event.motion.x;
mouse_data.y = event.motion.y;
break;
case SDL_MOUSEBUTTONDOWN:
if (event.button.button == SDL_BUTTON_LEFT)
mouse_data.btn1 = 1;
if (event.button.button == SDL_BUTTON_RIGHT)
mouse_data.btn2 = 1;
if (event.button.button == SDL_BUTTON_MIDDLE)
mouse_data.btn3 = 1;
if (event.button.button == SDL_BUTTON_X1)
mouse_data.btn4 = 1;
break;
case SDL_MOUSEBUTTONUP:
if (event.button.button == SDL_BUTTON_LEFT)
mouse_data.btn1 = 0;
if (event.button.button == SDL_BUTTON_RIGHT)
mouse_data.btn2 = 0;
if (event.button.button == SDL_BUTTON_MIDDLE)
mouse_data.btn3 = 0;
if (event.button.button == SDL_BUTTON_X1)
mouse_data.btn4 = 0;
break;
// Touch events (map to mouse_data as left-click equivalent)
case SDL_FINGERMOTION:
case SDL_FINGERDOWN:
case SDL_FINGERUP: {
float x = event.tfinger.x * 640;
float y = event.tfinger.y * 480;
mouse_data.x = (int)x;
mouse_data.y = (int)y;
// Only treat the first finger as mouse input (ignore multi-touch
// beyond 1 finger)
if (event.tfinger.fingerId == 0) {
if (event.type == SDL_FINGERDOWN || event.type == SDL_FINGERMOTION) {
mouse_data.btn1 = 1;
} else if (event.type == SDL_FINGERUP) {
mouse_data.btn1 = 0;
}
bool running = true;
while (running) {
if (!step_vm(&vm)) {
running = false;
break;
}
break;
}
}
}
// Run VM for a fixed number of cycles or a time slice
int cycles_this_frame = 0;
int max_cycles_per_frame = 100; // Adjust this value
while (cycles_this_frame < max_cycles_per_frame) {
#ifdef ASM_DEBUG
printf("| %s %d\n", opcode_to_string(vm.code[vm.pc]), vm.pc);
#endif
if (!step_vm(&vm)) {
running = false;
break;
}
cycles_this_frame++;
}
// Render only if the screen buffer was updated AND at a reasonable rate
if (screen_data.update) {
if (screen_data.renderer && screen_data.texture) {
// Clear and render
SDL_RenderClear(screen_data.renderer);
SDL_Rect output_rect;
SDL_RenderGetViewport(screen_data.renderer, &output_rect);
// Calculate aspect ratio preserving scaling
float scale_x = (float)output_rect.w / screen_data.width;
float scale_y = (float)output_rect.h / screen_data.height;
float scale = SDL_min(scale_x, scale_y);
SDL_Rect dstrect = {
(i32)((output_rect.w - screen_data.width * scale) / 2),
(i32)((output_rect.h - screen_data.height * scale) / 2),
(i32)(screen_data.width * scale),
(i32)(screen_data.height * scale)};
SDL_RenderCopy(screen_data.renderer, screen_data.texture, NULL,
&dstrect);
SDL_RenderPresent(screen_data.renderer);
}
screen_data.update = false; // Reset flag after rendering
} else {
bool running = true;
while (running) {
running = step_vm(&vm);
}
}
return vm.flag;
return EXIT_SUCCESS;
}

View File

@ -1,6 +1,5 @@
#include "assembler.h"
#include "parser.h"
typedef enum { SYMBOL_CODE, SYMBOL_DATA } SymbolType;
typedef enum { SYMBOL_CODE, SYMBOL_DATA, SYMBOL_PLEX } SymbolType;
typedef struct {
char *name;
@ -27,6 +26,10 @@ void symbol_table_add(SymbolTable *table, const char *name, u32 address,
// Check for duplicates
for (int i = 0; i < table->count; i++) {
if (strcmp(table->symbols[i].name, name) == 0) {
// Allow plex redefinition for compiler evolution
if (type == SYMBOL_PLEX && table->symbols[i].type == SYMBOL_PLEX) {
return;
}
fprintf(stderr, "Error: Duplicate label '%s'\n", name);
exit(1);
}
@ -66,72 +69,44 @@ u32 find_label_in_table(SymbolTable *table, const char *name) {
int get_instruction_byte_size(ExprNode *node) {
const char *opname = node->token;
// Return (1 + 1)
if (strcmp(opname, "return") == 0) {
return 2; // 1 byte opcode + 1 byte return register
}
if (strcmp(opname, "neg-int") == 0 ||
strcmp(opname, "abs-int") == 0 ||
strcmp(opname, "neg-nat") == 0 ||
strcmp(opname, "abs-nat") == 0 ||
strcmp(opname, "neg-real") == 0 ||
strcmp(opname, "abs-real") == 0 ||
strcmp(opname, "int-to-string") == 0 ||
strcmp(opname, "load-indirect-8") == 0 ||
strcmp(opname, "nat-to-string") == 0 ||
strcmp(opname, "load-indirect-16") == 0 ||
strcmp(opname, "real-to-string") == 0 ||
strcmp(opname, "load-indirect-32") == 0 ||
strcmp(opname, "int-to-real") == 0 ||
strcmp(opname, "store-indirect-8") == 0 ||
strcmp(opname, "nat-to-real") == 0 ||
strcmp(opname, "store-indirect-16") == 0 ||
strcmp(opname, "real-to-int") == 0 ||
strcmp(opname, "store-indirect-32") == 0 ||
strcmp(opname, "real-to-nat") == 0 || strcmp(opname, "nat-to-int") == 0 ||
strcmp(opname, "int-to-nat") == 0 ||
strcmp(opname, "string-length") == 0 ||
strcmp(opname, "store-absolute-32") == 0 ||
strcmp(opname, "store-absolute-8") == 0 ||
strcmp(opname, "store-absolute-16") == 0 ||
// Simple opcodes (1 byte)
if (strcmp(opname, "halt") == 0 || strcmp(opname, "return") == 0 ||
strcmp(opname, "pop") == 0 || strcmp(opname, "malloc") == 0 ||
strcmp(opname, "int-to-string") == 0 || strcmp(opname, "dup") == 0 ||
strcmp(opname, "get-8") == 0 || strcmp(opname, "nat-to-string") == 0 ||
strcmp(opname, "get-16") == 0 || strcmp(opname, "real-to-string") == 0 ||
strcmp(opname, "get") == 0 || strcmp(opname, "int-to-real") == 0 ||
strcmp(opname, "put-8") == 0 || strcmp(opname, "nat-to-real") == 0 ||
strcmp(opname, "put-16") == 0 || strcmp(opname, "real-to-int") == 0 ||
strcmp(opname, "put") == 0 || strcmp(opname, "real-to-nat") == 0 ||
strcmp(opname, "nat-to-int") == 0 || strcmp(opname, "int-to-nat") == 0 ||
strcmp(opname, "string-length") == 0 || strcmp(opname, "store") == 0 ||
strcmp(opname, "store-8") == 0 || strcmp(opname, "store-16") == 0 ||
strcmp(opname, "memset") == 0 || strcmp(opname, "memset") == 0 ||
strcmp(opname, "memset-8") == 0 || strcmp(opname, "memset-16") == 0 ||
strcmp(opname, "register-move") == 0 || strcmp(opname, "malloc") == 0) {
return 3;
}
// Register-register-register opcodes (4 bytes: 1 + 3)
if (strcmp(opname, "add-int") == 0 || strcmp(opname, "sub-int") == 0 ||
strcmp(opname, "mul-int") == 0 || strcmp(opname, "div-int") == 0 ||
strcmp(opname, "add-nat") == 0 || strcmp(opname, "sub-nat") == 0 ||
strcmp(opname, "mul-nat") == 0 || strcmp(opname, "div-nat") == 0 ||
strcmp(opname, "add-real") == 0 || strcmp(opname, "sub-real") == 0 ||
strcmp(opname, "bit-shift-left") == 0 ||
strcmp(opname, "bit-shift-right") == 0 ||
strcmp(opname, "bit-shift-r-ext") == 0 ||
strcmp(opname, "register-move") == 0 || strcmp(opname, "add-int") == 0 ||
strcmp(opname, "sub-int") == 0 || strcmp(opname, "mul-int") == 0 ||
strcmp(opname, "div-int") == 0 || strcmp(opname, "add-nat") == 0 ||
strcmp(opname, "sub-nat") == 0 || strcmp(opname, "mul-nat") == 0 ||
strcmp(opname, "div-nat") == 0 || strcmp(opname, "add-real") == 0 ||
strcmp(opname, "sub-real") == 0 || strcmp(opname, "over") == 0 ||
strcmp(opname, "bit-shift-left") == 0 || strcmp(opname, "exch") == 0 ||
strcmp(opname, "bit-shift-right") == 0 || strcmp(opname, "pick") == 0 ||
strcmp(opname, "bit-and") == 0 || strcmp(opname, "bit-or") == 0 ||
strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 ||
strcmp(opname, "div-real") == 0) {
return 4;
strcmp(opname, "div-real") == 0 || strcmp(opname, "load") == 0 ||
strcmp(opname, "load-immediate") == 0 || strcmp(opname, "load-16") == 0 ||
strcmp(opname, "load-8") == 0 || strcmp(opname, "syscall") == 0 ||
strcmp(opname, "rot") == 0 || strcmp(opname, "depth") == 0) {
return 1;
}
// (5 bytes: 1 + 4)
if (strcmp(opname, "halt") == 0 || strcmp(opname, "jump-if-flag") == 0 ||
strcmp(opname, "jump") == 0) {
return 5;
}
// Load, Load-immediate (6 bytes: 1 + 1 + 4)
if (strcmp(opname, "load-absolute-32") == 0 ||
strcmp(opname, "load-immediate") == 0 ||
strcmp(opname, "load-absolute-16") == 0 ||
strcmp(opname, "load-absolute-8") == 0) {
return 6;
}
// jump compare (7 bytes: 1 + 4 + 1 + 1)
if (strcmp(opname, "jump-eq-int") == 0 ||
// multibyte opcodes (5 bytes: opcode + u32)
if (strcmp(opname, "call") == 0 ||
strcmp(opname, "push") == 0 ||
strcmp(opname, "jump") == 0 ||
strcmp(opname, "jump-if-flag") == 0 ||
strcmp(opname, "jump-eq-int") == 0 ||
strcmp(opname, "jump-neq-int") == 0 ||
strcmp(opname, "jump-gt-int") == 0 ||
strcmp(opname, "jump-lt-int") == 0 ||
@ -148,33 +123,8 @@ int get_instruction_byte_size(ExprNode *node) {
strcmp(opname, "jump-gt-real") == 0 ||
strcmp(opname, "jump-lt-real") == 0 ||
strcmp(opname, "jump-le-real") == 0 ||
strcmp(opname, "jump-ge-real") == 0 ||
strcmp(opname, "store-offset-8") == 0 ||
strcmp(opname, "store-offset-16") == 0 ||
strcmp(opname, "store-offset-32") == 0 ||
strcmp(opname, "load-offset-8") == 0 ||
strcmp(opname, "load-offset-16") == 0 ||
strcmp(opname, "load-offset-32") == 0) {
return 7;
}
// Call (1 + 4 + 1 + args + 1)
if (strcmp(opname, "call") == 0) {
ExprNode *args_node = node->children[1];
u32 args_count;
if (strcmp(args_node->token, "nil") == 0) {
args_count = 0;
} else {
args_count = 1 + args_node->child_count;
}
return 1 + 1 + 1 + 4 + args_count;
}
// Syscall (1 + syscall_id (4) + args)
if (strcmp(opname, "syscall") == 0) {
return 1 + 4 + (node->child_count > 0 ? node->child_count - 1 : 0);
strcmp(opname, "jump-ge-real") == 0) {
return 5;
}
fprintf(stderr, "Unknown opcode for sizing: %s\n", opname);
@ -264,6 +214,11 @@ u32 allocate_data(VM *vm, SymbolTable *table, const char *name, u32 size) {
void emit_byte(VM *vm, u8 byte) { vm->code[vm->cp++] = byte; }
void emit_u16(VM *vm, u16 value) {
write_u16(vm, code, vm->cp, value);
vm->cp += 4;
}
void emit_u32(VM *vm, u32 value) {
write_u32(vm, code, vm->cp, value);
vm->cp += 4;
@ -271,12 +226,6 @@ void emit_u32(VM *vm, u32 value) {
void emit_opcode(VM *vm, Opcode op) { emit_byte(vm, op); }
int parse_register(const char *reg_str) {
if (reg_str[0] != '$')
return -1;
return atoi(reg_str + 1);
}
u32 resolve_symbol(SymbolTable *table, const char *ref) {
// Handle symbol references (e.g., &label)
if (ref[0] == '&') {
@ -390,14 +339,13 @@ void process_data_block(VM *vm, SymbolTable *table, ExprNode *block) {
// Case 1: String literal (enclosed in quotes)
if (token[0] == '"' && token[strlen(token) - 1] == '"') {
char *unwrapped = unwrap_string(token);
int len = strlen(unwrapped);
u32 addr = allocate_data(vm, table, name, len + 1 + 4);
int len = strlen(unwrapped) + 1;
u32 addr = allocate_data(vm, table, name, len + 4);
write_u32(vm, memory, addr, len);
for (int i = 0; i < len; i++) {
write_u8(vm, memory, addr + 4 + i, unwrapped[i]);
}
write_u8(vm, memory, addr + 4 + len, '\0');
free(unwrapped);
}
// Case 2: Hexadecimal integer (0x...)
@ -431,7 +379,7 @@ void process_data_block(VM *vm, SymbolTable *table, ExprNode *block) {
u32 addr = allocate_data(vm, table, name, 4);
write_u32(vm, memory, addr, value);
//vm->mp += 4;
vm->mp += 4;
}
} else {
fprintf(stderr, "Unsupported data item\n");
@ -449,8 +397,6 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
}
} else if (strcmp(opname, "halt") == 0) {
emit_opcode(vm, OP_HALT);
u32 addr = resolve_symbol(table, node->children[0]->token);
emit_u32(vm, addr);
} else if (strcmp(opname, "jump") == 0) {
emit_opcode(vm, OP_JMP);
u32 addr = resolve_symbol(table, node->children[0]->token);
@ -461,254 +407,50 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
emit_u32(vm, addr);
} else if (strcmp(opname, "call") == 0) {
emit_opcode(vm, OP_CALL);
if (node->child_count < 3) {
fprintf(stderr, "Error: call requires (args) and return register\n");
return;
}
// Parse function address (first child)
u32 addr = resolve_symbol(table, node->children[0]->token);
if (addr == (u32)-1) {
fprintf(stderr, "Error: undefined symbol '%s'\n",
node->children[0]->token);
return;
}
emit_u32(vm, addr);
// Parse argument list (second child)
ExprNode *args_node = node->children[1];
u8 arg_count = 0;
if (args_node->child_count > 0) {
// Multiple arguments case
arg_count = args_node->child_count + 1; // +1 for the token
} else {
// Single argument case - token is the argument
arg_count = (args_node->token[0] != '\0') ? 1 : 0;
}
emit_byte(vm, arg_count);
// Emit arguments based on representation
if (arg_count > 0) {
// First argument is always the token
const char *reg_str = args_node->token;
int reg = parse_register(reg_str);
if (reg < 0) {
fprintf(stderr, "Error: invalid argument register '%s'\n", reg_str);
return;
}
emit_byte(vm, (u8)reg);
// Emit children if present
for (size_t i = 0; i < args_node->child_count; i++) {
reg_str = args_node->children[i]->token;
reg = parse_register(reg_str);
if (reg < 0) {
fprintf(stderr, "Error: invalid argument register '%s'\n", reg_str);
return;
}
emit_byte(vm, (u8)reg);
}
}
// Parse return register (third child)
const char *return_reg_str = node->children[2]->token;
int return_reg = parse_register(return_reg_str);
if (return_reg < 0) {
if (strcmp(return_reg_str, "nil") == 0) {
return_reg = 0xFF;
} else {
fprintf(stderr, "Error: invalid return register '%s'\n",
return_reg_str);
return;
}
}
emit_byte(vm, (u8)return_reg);
} else if (strcmp(opname, "return") == 0) {
emit_opcode(vm, OP_RETURN);
if (node->child_count != 1) {
fprintf(stderr, "Error: return requires exactly one argument\n");
return;
}
const char *reg_str = node->children[0]->token;
int reg = parse_register(reg_str);
// Handle "nil" as special case (no return value)
if (reg < 0) {
if (strcmp(reg_str, "nil") == 0) {
reg = 0xFF; // Special value for "no return"
} else {
fprintf(stderr, "Error: invalid return register '%s'\n", reg_str);
return;
}
}
emit_byte(vm, (u8)reg);
} else if (strcmp(opname, "load-immediate") == 0) {
emit_opcode(vm, OP_LOAD_IMM);
int reg = parse_register(node->children[0]->token);
u32 addr = resolve_symbol(table, node->children[1]->token);
emit_byte(vm, reg);
emit_u32(vm, addr);
} else if (strcmp(opname, "load-absolute-8") == 0) {
emit_opcode(vm, OP_LOAD_ABS_8);
int dest = parse_register(node->children[0]->token);
u32 addr = resolve_symbol(table, node->children[1]->token);
emit_byte(vm, dest);
emit_u32(vm, addr);
} else if (strcmp(opname, "load-absolute-16") == 0) {
emit_opcode(vm, OP_LOAD_ABS_16);
int dest = parse_register(node->children[0]->token);
u32 addr = resolve_symbol(table, node->children[1]->token);
emit_byte(vm, dest);
emit_u32(vm, addr);
} else if (strcmp(opname, "load-absolute-32") == 0) {
emit_opcode(vm, OP_LOAD_ABS_32);
int dest = parse_register(node->children[0]->token);
u32 addr = resolve_symbol(table, node->children[1]->token);
emit_byte(vm, dest);
emit_u32(vm, addr);
} else if (strcmp(opname, "load-indirect-8") == 0) {
emit_opcode(vm, OP_LOAD_IND_8);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "load-indirect-16") == 0) {
emit_opcode(vm, OP_LOAD_IND_16);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "load-indirect-32") == 0) {
emit_opcode(vm, OP_LOAD_IND_32);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "return") == 0) {
emit_opcode(vm, OP_RETURN);
} else if (strcmp(opname, "load-8") == 0) {
emit_opcode(vm, OP_LOAD_8);
} else if (strcmp(opname, "load-16") == 0) {
emit_opcode(vm, OP_LOAD_16);
} else if (strcmp(opname, "load") == 0) {
emit_opcode(vm, OP_LOAD_32);
} else if (strcmp(opname, "malloc") == 0) {
emit_opcode(vm, OP_MALLOC);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
u32 addr = resolve_symbol(table, node->children[0]->token);
emit_u32(vm, addr);
} else if (strcmp(opname, "memset-8") == 0) {
emit_opcode(vm, OP_MEMSET_8);
int dest = parse_register(node->children[0]->token);
int value = parse_register(node->children[1]->token);
int count = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, value);
emit_byte(vm, count);
} else if (strcmp(opname, "memset-16") == 0) {
emit_opcode(vm, OP_MEMSET_16);
int dest = parse_register(node->children[0]->token);
int value = parse_register(node->children[1]->token);
int count = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, value);
emit_byte(vm, count);
} else if (strcmp(opname, "memset") == 0) {
emit_opcode(vm, OP_MEMSET_32);
int dest = parse_register(node->children[0]->token);
int value = parse_register(node->children[1]->token);
int count = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, value);
emit_byte(vm, count);
} else if (strcmp(opname, "store-absolute-8") == 0) {
emit_opcode(vm, OP_STORE_ABS_8);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "store-absolute-16") == 0) {
emit_opcode(vm, OP_STORE_ABS_16);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "store-absolute-32") == 0) {
emit_opcode(vm, OP_STORE_ABS_32);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "store-indirect-8") == 0) {
emit_opcode(vm, OP_STORE_IND_8);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "store-indirect-16") == 0) {
emit_opcode(vm, OP_STORE_IND_16);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "store-indirect-32") == 0) {
emit_opcode(vm, OP_STORE_IND_32);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "store-offset-8") == 0) {
emit_opcode(vm, OP_STORE_OFF_8);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
u32 addr = resolve_symbol(table, node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_u32(vm, addr);
} else if (strcmp(opname, "store-offset-16") == 0) {
emit_opcode(vm, OP_STORE_OFF_16);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
u32 addr = resolve_symbol(table, node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_u32(vm, addr);
} else if (strcmp(opname, "store-offset-32") == 0) {
emit_opcode(vm, OP_STORE_OFF_32);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
u32 addr = resolve_symbol(table, node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_u32(vm, addr);
} else if (strcmp(opname, "load-offset-8") == 0) {
emit_opcode(vm, OP_LOAD_OFF_8);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
u32 addr = resolve_symbol(table, node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_u32(vm, addr);
} else if (strcmp(opname, "load-offset-16") == 0) {
emit_opcode(vm, OP_LOAD_OFF_16);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
u32 addr = resolve_symbol(table, node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_u32(vm, addr);
} else if (strcmp(opname, "load-offset-32") == 0) {
emit_opcode(vm, OP_LOAD_OFF_32);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
u32 addr = resolve_symbol(table, node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_u32(vm, addr);
} else if (strcmp(opname, "register-move") == 0) {
emit_opcode(vm, OP_REG_MOV);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "store-8") == 0) {
emit_opcode(vm, OP_STORE_8);
} else if (strcmp(opname, "store-16") == 0) {
emit_opcode(vm, OP_STORE_16);
} else if (strcmp(opname, "store") == 0) {
emit_opcode(vm, OP_STORE_32);
} else if (strcmp(opname, "push") == 0) {
emit_opcode(vm, OP_PUSH);
u32 value = resolve_symbol(table, node->children[0]->token);
emit_u32(vm, value);
} else if (strcmp(opname, "pop") == 0) {
emit_opcode(vm, OP_POP);
} else if (strcmp(opname, "dup") == 0) {
emit_opcode(vm, OP_DUP);
} else if (strcmp(opname, "over") == 0) {
emit_opcode(vm, OP_OVER);
} else if (strcmp(opname, "rot") == 0 ) {
emit_opcode(vm, OP_ROT);
} else if (strcmp(opname, "depth") == 0) {
emit_opcode(vm, OP_DEPTH);
} else if (strcmp(opname, "exch") == 0) {
emit_opcode(vm, OP_EXCH);
} else if (strcmp(opname, "pick") == 0) {
emit_opcode(vm, OP_PICK);
} else if (strcmp(opname, "syscall") == 0) {
emit_opcode(vm, OP_SYSCALL);
@ -727,448 +469,149 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
syscall_id = SYSCALL_DEVICE_CLOSE;
else if (strcmp(syscall_name, "IOCTL") == 0)
syscall_id = SYSCALL_DEVICE_IOCTL;
else if (strcmp(syscall_name, "REFRESH") == 0)
syscall_id = SYSCALL_DEVICE_REFRESH;
emit_u32(vm, syscall_id);
// Emit register arguments
for (size_t i = 1; i < node->child_count; ++i) {
int reg = parse_register(node->children[i]->token);
emit_byte(vm, reg);
}
} else if (strcmp(opname, "bit-shift-left") == 0) {
emit_opcode(vm, OP_BIT_SHIFT_LEFT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
emit_opcode(vm, OP_SLL);
} else if (strcmp(opname, "bit-shift-right") == 0) {
emit_opcode(vm, OP_BIT_SHIFT_RIGHT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "bit-shift-r-ext") == 0) {
emit_opcode(vm, OP_BIT_SHIFT_R_EXT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
emit_opcode(vm, OP_SRL);
} else if (strcmp(opname, "bit-shift-re") == 0) {
emit_opcode(vm, OP_SRE);
} else if (strcmp(opname, "bit-and") == 0) {
emit_opcode(vm, OP_BAND);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "bit-or") == 0) {
emit_opcode(vm, OP_BOR);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "bit-xor") == 0) {
emit_opcode(vm, OP_BXOR);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "add-int") == 0) {
emit_opcode(vm, OP_ADD_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "sub-int") == 0) {
emit_opcode(vm, OP_SUB_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "mul-int") == 0) {
emit_opcode(vm, OP_MUL_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "div-int") == 0) {
emit_opcode(vm, OP_DIV_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "abs-int") == 0) {
emit_opcode(vm, OP_ABS_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "neg-int") == 0) {
emit_opcode(vm, OP_NEG_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "add-nat") == 0) {
emit_opcode(vm, OP_ADD_NAT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
emit_opcode(vm, OP_ADD_UINT);
} else if (strcmp(opname, "sub-nat") == 0) {
emit_opcode(vm, OP_SUB_NAT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
emit_opcode(vm, OP_SUB_UINT);
} else if (strcmp(opname, "mul-nat") == 0) {
emit_opcode(vm, OP_MUL_NAT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
emit_opcode(vm, OP_MUL_UINT);
} else if (strcmp(opname, "div-nat") == 0) {
emit_opcode(vm, OP_DIV_NAT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "abs-nat") == 0) {
emit_opcode(vm, OP_ABS_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "neg-nat") == 0) {
emit_opcode(vm, OP_NEG_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_opcode(vm, OP_DIV_UINT);
} else if (strcmp(opname, "add-real") == 0) {
emit_opcode(vm, OP_ADD_REAL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "sub-real") == 0) {
emit_opcode(vm, OP_SUB_REAL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "mul-real") == 0) {
emit_opcode(vm, OP_MUL_REAL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "div-real") == 0) {
emit_opcode(vm, OP_DIV_REAL);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "abs-real") == 0) {
emit_opcode(vm, OP_ABS_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "neg-real") == 0) {
emit_opcode(vm, OP_NEG_INT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
} else if (strcmp(opname, "int-to-real") == 0) {
emit_opcode(vm, OP_INT_TO_REAL);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "nat-to-real") == 0) {
emit_opcode(vm, OP_NAT_TO_REAL);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
emit_opcode(vm, OP_UINT_TO_REAL);
} else if (strcmp(opname, "real-to-int") == 0) {
emit_opcode(vm, OP_REAL_TO_INT);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "real-to-nat") == 0) {
emit_opcode(vm, OP_REAL_TO_NAT);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
emit_opcode(vm, OP_REAL_TO_UINT);
} else if (strcmp(opname, "jump-eq-int") == 0) {
emit_opcode(vm, OP_JEQ_INT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-neq-int") == 0) {
emit_opcode(vm, OP_JNEQ_INT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-gt-int") == 0) {
emit_opcode(vm, OP_JGT_INT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-lt-int") == 0) {
emit_opcode(vm, OP_JLT_INT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-le-int") == 0) {
emit_opcode(vm, OP_JLE_INT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-ge-int") == 0) {
emit_opcode(vm, OP_JGE_INT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-eq-nat") == 0) {
emit_opcode(vm, OP_JEQ_NAT);
emit_opcode(vm, OP_JEQ_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-neq-nat") == 0) {
emit_opcode(vm, OP_JNEQ_NAT);
emit_opcode(vm, OP_JNEQ_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-gt-nat") == 0) {
emit_opcode(vm, OP_JGT_NAT);
emit_opcode(vm, OP_JGT_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-lt-nat") == 0) {
emit_opcode(vm, OP_JLT_NAT);
emit_opcode(vm, OP_JLT_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-le-nat") == 0) {
emit_opcode(vm, OP_JLE_NAT);
emit_opcode(vm, OP_JLE_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-ge-nat") == 0) {
emit_opcode(vm, OP_JGE_NAT);
emit_opcode(vm, OP_JGE_UINT);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-eq-real") == 0) {
emit_opcode(vm, OP_JEQ_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-neq-real") == 0) {
emit_opcode(vm, OP_JNEQ_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-gt-real") == 0) {
emit_opcode(vm, OP_JGT_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-lt-real") == 0) {
emit_opcode(vm, OP_JLT_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-le-real") == 0) {
emit_opcode(vm, OP_JLE_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "jump-ge-real") == 0) {
emit_opcode(vm, OP_JGE_REAL);
u32 addr = resolve_symbol(table, node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_u32(vm, addr);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-length") == 0) {
emit_opcode(vm, OP_STRLEN);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "string-eq") == 0) {
emit_opcode(vm, OP_STREQ);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-concat") == 0) {
emit_opcode(vm, OP_STRCAT);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-get-char") == 0) {
emit_opcode(vm, OP_STR_GET_CHAR);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-find-char") == 0) {
emit_opcode(vm, OP_STR_FIND_CHAR);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
} else if (strcmp(opname, "string-slice") == 0) {
emit_opcode(vm, OP_STR_SLICE);
int dest = parse_register(node->children[0]->token);
int src1 = parse_register(node->children[1]->token);
int src2 = parse_register(node->children[2]->token);
int src3 = parse_register(node->children[3]->token);
emit_byte(vm, dest);
emit_byte(vm, src1);
emit_byte(vm, src2);
emit_byte(vm, src3);
} else if (strcmp(opname, "int-to-string") == 0) {
emit_opcode(vm, OP_INT_TO_STRING);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "nat-to-string") == 0) {
emit_opcode(vm, OP_NAT_TO_STRING);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
emit_opcode(vm, OP_UINT_TO_STRING);
} else if (strcmp(opname, "real-to-string") == 0) {
emit_opcode(vm, OP_REAL_TO_STRING);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "string-to-int") == 0) {
emit_opcode(vm, OP_STRING_TO_INT);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else if (strcmp(opname, "string-to-nat") == 0) {
emit_opcode(vm, OP_STRING_TO_NAT);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
emit_opcode(vm, OP_STRING_TO_UINT);
} else if (strcmp(opname, "string-to-real") == 0) {
emit_opcode(vm, OP_STRING_TO_REAL);
int dest = parse_register(node->children[0]->token);
int src = parse_register(node->children[1]->token);
emit_byte(vm, dest);
emit_byte(vm, src);
} else {
fprintf(stderr, "Unknown opcode: %s\n", opname);
}

View File

@ -11,9 +11,9 @@
#include <ctype.h>
#define AS_FIXED(v) ((float)(i32)(v) / 65536.0f)
#define TO_FIXED(f) ((i32)( \
#define TO_FIXED(f) ((u32)((i32)( \
((f) >= 0.0f) ? ((f) * 65536.0f + 0.5f) : ((f) * 65536.0f - 0.5f) \
))
)))
void assemble(VM *vm, ExprNode *program);

2
src/tools/build.sh Normal file
View File

@ -0,0 +1,2 @@
gcc math_gen.c -o math_gen -lm
./math_gen > ./math.h

View File

@ -1,406 +0,0 @@
#include <string.h>
#include "../vm/common.h"
#include "lexer.h"
typedef struct {
const char *start;
const char *current;
int line;
} Lexer;
Lexer lexer;
void initLexer(const char *source) {
lexer.start = source;
lexer.current = source;
lexer.line = 1;
}
static bool isAlpha(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
}
static bool isDigit(char c) { return c >= '0' && c <= '9'; }
static bool isAtEnd() { return *lexer.current == '\0'; }
static char advance() {
lexer.current++;
return lexer.current[-1];
}
static char peek() { return *lexer.current; }
static char peekNext() {
if (isAtEnd())
return '\0';
return lexer.current[1];
}
static bool match(char expected) {
if (isAtEnd())
return false;
if (*lexer.current != expected)
return false;
lexer.current++;
return true;
}
static Token makeToken(TokenType type) {
Token token;
token.type = type;
token.start = lexer.start;
token.length = (int)(lexer.current - lexer.start);
token.line = lexer.line;
return token;
}
static Token errorToken(const char *message) {
Token token;
token.type = TOKEN_ERROR;
token.start = message;
token.length = (int)strlen(message);
token.line = lexer.line;
return token;
}
static void skipWhitespace() {
for (;;) {
char c = peek();
switch (c) {
case ' ':
case '\r':
case '\t':
advance();
break;
case '\n':
lexer.line++;
advance();
break;
case '/':
if (peekNext() == '/') {
// Single-line comment: skip until newline or end of file
advance();
while (peek() != '\n' && !isAtEnd())
advance();
} else if (peekNext() == '*') {
// Multi-line comment: skip until '*/' or end of file
advance();
advance();
while (!isAtEnd()) {
if (peek() == '\n') lexer.line++;
if (peek() == '*' && peekNext() == '/') {
advance();
advance();
break; // Exit loop, comment ended
}
advance();
}
} else {
return; // Not a comment, let tokenization handle it
}
break;
default:
return;
}
}
}
static TokenType checkKeyword(int start, int length, const char *rest,
TokenType type) {
if (lexer.current - lexer.start == start + length &&
memcmp(lexer.start + start, rest, length) == 0) {
return type;
}
return TOKEN_IDENTIFIER;
}
static TokenType identifierType() {
switch (lexer.start[0]) {
case 'a':
return checkKeyword(1, 2, "nd", TOKEN_OPERATOR_AND);
case 'c':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 'l':
return checkKeyword(2, 3, "ose", TOKEN_KEYWORD_CLOSE);
case 'o':
return checkKeyword(2, 3, "nst", TOKEN_KEYWORD_CONST);
}
}
break;
case 'e':
return checkKeyword(1, 3, "lse", TOKEN_KEYWORD_ELSE);
case 'f':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 'a':
return checkKeyword(2, 3, "lse", TOKEN_KEYWORD_FALSE);
case 'o':
return checkKeyword(2, 1, "r", TOKEN_KEYWORD_FOR);
}
return checkKeyword(1, 7, "unction", TOKEN_KEYWORD_FN);
}
break;
case 'i':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 'f':
return checkKeyword(2, 0, "", TOKEN_KEYWORD_IF);
case 'n':
if (lexer.current - lexer.start > 2) {
switch (lexer.start[2]) {
case 'i':
return checkKeyword(3, 2, "t", TOKEN_KEYWORD_INIT);
case 't':
return checkKeyword(3, 1, "", TOKEN_TYPE_INT);
}
}
break;
}
}
break;
case 'n':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 'a':
return checkKeyword(2, 1, "t", TOKEN_TYPE_NAT);
case 'i':
return checkKeyword(2, 1, "l", TOKEN_KEYWORD_NIL);
}
}
break;
case 'o':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 'p':
return checkKeyword(2, 2, "en", TOKEN_KEYWORD_OPEN);
case 'r':
return checkKeyword(2, 0, "", TOKEN_OPERATOR_OR);
}
}
break;
case 'p':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 'l':
return checkKeyword(2, 2, "ex", TOKEN_KEYWORD_PLEX);
}
}
break;
case 'r':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 'e':
if (lexer.current - lexer.start > 2) {
switch (lexer.start[2]) {
case 'a':
return checkKeyword(3, 1, "d", TOKEN_KEYWORD_READ);
case 'f':
return checkKeyword(3, 4, "resh", TOKEN_KEYWORD_REFRESH);
case 't':
return checkKeyword(3, 3, "urn", TOKEN_KEYWORD_RETURN);
}
}
break;
}
}
break;
case 's':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 't':
return checkKeyword(2, 1, "r", TOKEN_TYPE_STR);
}
}
break;
case 't':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 'h':
return checkKeyword(2, 2, "is", TOKEN_KEYWORD_THIS);
case 'r':
return checkKeyword(2, 2, "ue", TOKEN_KEYWORD_TRUE);
}
}
break;
case 'u':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 's':
return checkKeyword(2, 1, "e", TOKEN_KEYWORD_USE);
}
}
break;
case 'w':
if (lexer.current - lexer.start > 1) {
switch (lexer.start[1]) {
case 'h':
return checkKeyword(2, 3, "ile", TOKEN_KEYWORD_WHILE);
case 'r':
return checkKeyword(2, 3, "ite", TOKEN_KEYWORD_WRITE);
}
}
break;
}
return TOKEN_IDENTIFIER;
}
static Token identifier() {
while (isAlpha(peek()) || isDigit(peek()))
advance();
return makeToken(identifierType());
}
static Token number() {
while (isDigit(peek()))
advance();
/* Look for a fractional part. */
if (peek() == '.' && isDigit(peekNext())) {
/* Consume the ".". */
advance();
while (isDigit(peek()))
advance();
return makeToken(TOKEN_FLOAT_LITERAL);
}
return makeToken(TOKEN_INT_LITERAL);
}
static Token string() {
while (peek() != '"' && !isAtEnd()) {
if (peek() == '\n')
lexer.line++;
advance();
}
if (isAtEnd())
return errorToken("Unterminated string.");
/* The closing quote. */
advance();
return makeToken(TOKEN_STRING_LITERAL);
}
Token nextToken() {
skipWhitespace();
lexer.start = lexer.current;
if (isAtEnd())
return makeToken(TOKEN_EOF);
char c = advance();
if (isAlpha(c))
return identifier();
if (isDigit(c))
return number();
switch (c) {
case '(':
return makeToken(TOKEN_LPAREN);
case ')':
return makeToken(TOKEN_RPAREN);
case '{':
return makeToken(TOKEN_LBRACE);
case '}':
return makeToken(TOKEN_RBRACE);
case '[':
return makeToken(TOKEN_LBRACKET);
case ']':
return makeToken(TOKEN_RBRACKET);
case ';':
return makeToken(TOKEN_SEMICOLON);
case ',':
return makeToken(TOKEN_COMMA);
case '.':
return makeToken(TOKEN_DOT);
case '-':
return makeToken(TOKEN_MINUS);
case '+':
return makeToken(TOKEN_PLUS);
case '/':
return makeToken(TOKEN_SLASH);
case '*':
return makeToken(TOKEN_STAR);
case '!':
return makeToken(match('=') ? TOKEN_BANG_EQ : TOKEN_BANG);
case '=':
return makeToken(match('=') ? TOKEN_EQ_EQ : TOKEN_EQ);
case '<':
return makeToken(match('=') ? TOKEN_LTE : TOKEN_LT);
case '>':
return makeToken(match('=') ? TOKEN_GTE : TOKEN_GT);
case '"':
return string();
}
return errorToken("Unexpected character.");
}
const char* tokenTypeToString(TokenType type) {
switch (type) {
case TOKEN_EOF: return "EOF";
case TOKEN_IDENTIFIER: return "IDENTIFIER";
case TOKEN_INT_LITERAL: return "INT_LITERAL";
case TOKEN_UINT_LITERAL: return "UINT_LITERAL";
case TOKEN_FLOAT_LITERAL: return "FLOAT_LITERAL";
case TOKEN_STRING_LITERAL: return "STRING_LITERAL";
case TOKEN_TYPE_INT: return "TYPE_INT";
case TOKEN_TYPE_NAT: return "TYPE_NAT";
case TOKEN_TYPE_REAL: return "TYPE_REAL";
case TOKEN_TYPE_STR: return "TYPE_STR";
case TOKEN_KEYWORD_PLEX: return "KEYWORD_PLEX";
case TOKEN_KEYWORD_FN: return "KEYWORD_FN";
case TOKEN_KEYWORD_CONST: return "KEYWORD_CONST";
case TOKEN_KEYWORD_IF: return "KEYWORD_IF";
case TOKEN_KEYWORD_ELSE: return "KEYWORD_ELSE";
case TOKEN_KEYWORD_WHILE: return "KEYWORD_WHILE";
case TOKEN_KEYWORD_FOR: return "KEYWORD_FOR";
case TOKEN_KEYWORD_RETURN: return "KEYWORD_RETURN";
case TOKEN_KEYWORD_USE: return "KEYWORD_USE";
case TOKEN_KEYWORD_INIT: return "KEYWORD_INIT";
case TOKEN_KEYWORD_THIS: return "KEYWORD_THIS";
case TOKEN_KEYWORD_OPEN: return "TOKEN_KEYWORD_OPEN";
case TOKEN_KEYWORD_READ: return "TOKEN_KEYWORD_READ";
case TOKEN_KEYWORD_WRITE: return "TOKEN_KEYWORD_WRITE";
case TOKEN_KEYWORD_REFRESH: return "TOKEN_KEYWORD_REFRESH";
case TOKEN_KEYWORD_CLOSE: return "TOKEN_KEYWORD_CLOSE";
case TOKEN_KEYWORD_NIL: return "KEYWORD_NIL";
case TOKEN_KEYWORD_TRUE: return "KEYWORD_TRUE";
case TOKEN_KEYWORD_FALSE: return "KEYWORD_FALSE";
case TOKEN_OPERATOR_IS: return "OPERATOR_IS";
case TOKEN_OPERATOR_NOT: return "OPERATOR_NOT";
case TOKEN_OPERATOR_AND: return "OPERATOR_AND";
case TOKEN_OPERATOR_OR: return "OPERATOR_OR";
case TOKEN_BANG: return "BANG";
case TOKEN_BANG_EQ: return "BANG_EQ";
case TOKEN_EQ: return "EQ";
case TOKEN_EQ_EQ: return "EQ_EQ";
case TOKEN_GT: return "GT";
case TOKEN_LT: return "LT";
case TOKEN_GTE: return "GTE";
case TOKEN_LTE: return "LTE";
case TOKEN_DOT: return "DOT";
case TOKEN_COMMA: return "COMMA";
case TOKEN_COLON: return "COLON";
case TOKEN_SEMICOLON: return "SEMICOLON";
case TOKEN_PLUS: return "PLUS";
case TOKEN_MINUS: return "MINUS";
case TOKEN_STAR: return "STAR";
case TOKEN_SLASH: return "SLASH";
case TOKEN_LPAREN: return "LPAREN";
case TOKEN_RPAREN: return "RPAREN";
case TOKEN_LBRACE: return "LBRACE";
case TOKEN_RBRACE: return "RBRACE";
case TOKEN_LBRACKET: return "LBRACKET";
case TOKEN_RBRACKET: return "RBRACKET";
case TOKEN_ERROR: return "ERROR";
default: return "UNKNOWN_TOKEN";
}
}

View File

@ -1,74 +0,0 @@
#ifndef UNDAR_LEXER_H
#define UNDAR_LEXER_H
typedef enum {
TOKEN_EOF,
TOKEN_IDENTIFIER,
TOKEN_INT_LITERAL,
TOKEN_UINT_LITERAL,
TOKEN_FLOAT_LITERAL,
TOKEN_STRING_LITERAL,
TOKEN_TYPE_INT,
TOKEN_TYPE_NAT,
TOKEN_TYPE_REAL,
TOKEN_TYPE_STR,
TOKEN_KEYWORD_PLEX,
TOKEN_KEYWORD_FN,
TOKEN_KEYWORD_CONST,
TOKEN_KEYWORD_IF,
TOKEN_KEYWORD_ELSE,
TOKEN_KEYWORD_WHILE,
TOKEN_KEYWORD_FOR,
TOKEN_KEYWORD_RETURN,
TOKEN_KEYWORD_USE,
TOKEN_KEYWORD_INIT,
TOKEN_KEYWORD_THIS,
TOKEN_KEYWORD_OPEN,
TOKEN_KEYWORD_READ,
TOKEN_KEYWORD_WRITE,
TOKEN_KEYWORD_REFRESH,
TOKEN_KEYWORD_CLOSE,
TOKEN_KEYWORD_NIL,
TOKEN_KEYWORD_TRUE,
TOKEN_KEYWORD_FALSE,
TOKEN_OPERATOR_IS,
TOKEN_OPERATOR_NOT,
TOKEN_OPERATOR_AND,
TOKEN_OPERATOR_OR,
TOKEN_BANG,
TOKEN_BANG_EQ,
TOKEN_EQ,
TOKEN_EQ_EQ,
TOKEN_GT,
TOKEN_LT,
TOKEN_GTE,
TOKEN_LTE,
TOKEN_DOT,
TOKEN_COMMA,
TOKEN_COLON,
TOKEN_SEMICOLON,
TOKEN_PLUS,
TOKEN_MINUS,
TOKEN_STAR,
TOKEN_SLASH,
TOKEN_LPAREN,
TOKEN_RPAREN,
TOKEN_LBRACE,
TOKEN_RBRACE,
TOKEN_LBRACKET,
TOKEN_RBRACKET,
TOKEN_ERROR
} TokenType;
typedef struct {
TokenType type;
const char *start;
int length;
int line;
} Token;
void initLexer(const char *source);
Token nextToken();
const char* tokenTypeToString(TokenType type);
#endif

31
src/tools/math_gen.c Normal file
View File

@ -0,0 +1,31 @@
#include <math.h>
#include <stdint.h>
#include <stdio.h>
int main() {
printf("#ifndef ZRE_TRIG_TABLES_H\n#define ZRE_TRIG_TABLES_H\n#include <stdint.h>\n\n");
// Generate SINE table (256 entries, Q16.16 format)
printf("const int32_t sin_table[256] = {\n");
for (int i = 0; i < 256; i++) {
double angle = i * 2 * M_PI / 256.0; // 0-360° in radians
double value = sin(angle) * 65536.0; // Scale to Q16.16
int32_t fixed = (int32_t)(value + 0.5); // Round to nearest
printf(" %d,", fixed);
if (i % 8 == 7) printf("\n");
}
printf("};\n\n");
// Generate COSINE table (256 entries, Q16.16 format)
printf("const int32_t cos_table[256] = {\n");
for (int i = 0; i < 256; i++) {
double angle = i * 2 * M_PI / 256.0; // 0-360° in radians
double value = cos(angle) * 65536.0; // Scale to Q16.16
int32_t fixed = (int32_t)(value + 0.5); // Round to nearest
printf(" %d,", fixed);
if (i % 8 == 7) printf("\n");
}
printf("};\n");
printf("#endif\n");
return 0;
}

View File

@ -6,9 +6,19 @@
#include <string.h>
#include <uchar.h>
// Helper function to allocate memory and handle errors
void *safe_malloc(size_t size) {
void *ptr = malloc(size);
if (!ptr) {
fprintf(stderr, "Memory allocation failed\n");
exit(1);
}
return ptr;
}
// Helper function to create a new node
static ExprNode *expr_node_create(const char *token, int line) {
ExprNode *node = (ExprNode *)malloc(sizeof(ExprNode));
ExprNode *node = (ExprNode *)safe_malloc(sizeof(ExprNode));
node->token = strdup(token ? token : "");
node->children = NULL;
node->child_count = 0;
@ -86,7 +96,7 @@ static char *parse_token(const char **ptr, int line) {
}
size_t len = end - start;
char *token = (char *)malloc(len + 1);
char *token = (char *)safe_malloc(len + 1);
memcpy(token, start, len);
token[len] = '\0';
@ -103,7 +113,7 @@ static ExprNode *parse_list(const char **ptr, int line) {
if (**ptr == ')') {
// Empty list
(*ptr)++;
return expr_node_create("\0", line);
return expr_node_create("nil", line);
}
// Parse all children first
@ -115,7 +125,7 @@ static ExprNode *parse_list(const char **ptr, int line) {
if (child) {
// Resize temp children array
ExprNode **new_temp =
(ExprNode **)malloc(sizeof(ExprNode *) * (temp_count + 1));
(ExprNode **)safe_malloc(sizeof(ExprNode *) * (temp_count + 1));
// Copy existing children
for (size_t i = 0; i < temp_count; i++) {
@ -149,7 +159,7 @@ static ExprNode *parse_list(const char **ptr, int line) {
node->child_count = temp_count - 1;
if (node->child_count > 0) {
node->children =
(ExprNode **)malloc(sizeof(ExprNode *) * node->child_count);
(ExprNode **)safe_malloc(sizeof(ExprNode *) * node->child_count);
for (size_t i = 0; i < node->child_count; i++) {
node->children[i] = temp_children[i + 1];
}

View File

@ -1,5 +1,5 @@
#ifndef UNDAR_COMMON_H
#define UNDAR_COMMON_H
#ifndef ZRE_COMMON_H
#define ZRE_COMMON_H
#include <stddef.h>
#include <stdint.h>
@ -20,6 +20,6 @@ typedef int32_t i32;
#define USED(x) ((void)(x))
#define AS_INT(v) ((i32)(v))
#define AS_NAT(v) ((u32)(v))
#define AS_UINT(v) ((u32)(v))
#endif

View File

@ -1,8 +1,8 @@
#include "device.h"
#include "libc.h"
#include "str.h"
i32 vm_register_device(VM *vm, const char *path, const char *type, void *data,
DeviceOps *ops, u32 size) {
DeviceOps *ops) {
Device *dev;
if (vm->dc >= DEVICES_SIZE)
@ -18,7 +18,6 @@ i32 vm_register_device(VM *vm, const char *path, const char *type, void *data,
dev->data = data;
dev->ops = ops;
dev->size = size;
dev->flags = 0;
return dev->handle;
}
@ -33,3 +32,26 @@ Device *find_device_by_path(VM *vm, const char *path) {
}
return NULL;
}
/* Find device by type (useful for checking capabilities) */
Device *find_device_by_type(VM *vm, const char *type) {
u32 i;
for (i = 0; i < vm->dc; i++) {
if (streq(vm->devices[i].type, type)) {
return &vm->devices[i];
}
}
return NULL;
}
/* Find all devices of a type */
i32 find_devices_by_type(VM *vm, const char *type, Device **results,
u32 max_results) {
u32 i, count = 0;
for (i = 0; i < vm->dc && count < max_results; i++) {
if (streq(vm->devices[i].type, type)) {
results[count++] = &vm->devices[i];
}
}
return count;
}

View File

@ -1,9 +1,11 @@
#ifndef UNDAR_DEVICE_H
#define UNDAR_DEVICE_H
#ifndef ZRE_DEVICE_H
#define ZRE_DEVICE_H
#include "opcodes.h"
i32 vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops, u32 size);
i32 vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops);
Device* find_device_by_path(VM *vm, const char *path);
Device* find_device_by_type(VM *vm, const char *type);
i32 find_devices_by_type(VM *vm, const char *type, Device **results, uint32_t max_results);
#endif

View File

@ -1,241 +0,0 @@
#include "libc.h"
void memcopy(u8 *dest, const u8 *src, u32 n) {
size_t i;
size_t words;
size_t bytes;
size_t unroll;
size_t remainder;
u32 *d32;
const u32 *s32;
u8 *d8;
const u8 *s8;
/* Fast path for small copies (common case) */
if (n <= 8) {
for (i = 0; i < n; i++) {
dest[i] = src[i];
}
return;
}
/* Check for word alignment (assuming 32-bit words) */
if ((((size_t)dest) & 0x3) == 0 && (((size_t)src) & 0x3) == 0) {
/* Both pointers are 4-byte aligned - copy by words */
d32 = (u32 *)dest;
s32 = (const u32 *)src;
words = n / 4;
bytes = n % 4;
/* Loop unrolling - 4x unroll for better performance */
unroll = words / 4;
remainder = words % 4;
for (i = 0; i < unroll; i++) {
d32[0] = s32[0];
d32[1] = s32[1];
d32[2] = s32[2];
d32[3] = s32[3];
d32 += 4;
s32 += 4;
}
/* Handle remaining words */
for (i = 0; i < remainder; i++) {
*d32++ = *s32++;
}
/* Handle trailing bytes */
d8 = (u8 *)d32;
s8 = (const u8 *)s32;
for (i = 0; i < bytes; i++) {
d8[i] = s8[i];
}
} else {
/* Unaligned copy - byte by byte but with loop unrolling */
unroll = n / 4;
remainder = n % 4;
for (i = 0; i < unroll; i++) {
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = src[3];
dest += 4;
src += 4;
}
for (i = 0; i < remainder; i++) {
dest[i] = src[i];
}
}
}
i32 strcopy(char *to, const char *from, u32 length) {
u32 i;
if (to == nil || from == nil) return -1;
if (length == 0) {return 0;}
for (i = 0; i < length - 1 && from[i] != '\0'; i++) {
to[i] = from[i];
}
to[i] = '\0';
return 0;
}
bool streq(const char *s1, const char *s2) {
if (s1 == nil && s2 == nil) return true;
if (s1 == nil || s2 == nil) return false;
while (*s1 && *s2) {
if (*s1 != *s2) return false;
s1++;
s2++;
}
return (*s1 == '\0' && *s2 == '\0');
}
u32 strlength(const char *str) {
u32 i;
if (str == nil) {return 0;}
for (i = 0; str[i] != '\0'; i++) {
; /* twiddle thumbs, 'i' is doing all the work*/
}
return i;
}
u32 strnlength(const char *str, u32 max_len) {
u32 i;
if (str == nil) {return 0;}
for (i = 0; i < max_len && str[i] != '\0'; i++) {
; /* twiddle thumbs, 'i' is doing all the work*/
}
return i;
}
/* Static digit lookup table (0-9) */
const char digits[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
/* Writes decimal digits of 'value' backwards into 'buf_end' (inclusive),
stopping at 'buf_start'. Returns pointer to first written digit. */
char *write_digits_backwards(u32 value, char *buf_end, char *buf_start) {
char *p = buf_end;
if (value == 0) {
*--p = '0';
} else {
u32 num = value;
while (num && p > buf_start) {
*--p = digits[num % 10];
num /= 10;
}
}
return p;
}
void nat_to_string(u32 value, char *buffer) {
char temp[16];
char *start;
char *end = temp + sizeof(temp) - 1;
*end = '\0';
start = write_digits_backwards(value, end, temp);
strcopy(buffer, start, end - start + 1); /* +1 for null terminator */
}
void int_to_string(i32 value, char *buffer) {
char temp[17]; /* Extra space for '-' */
i32 negative = 0;
u32 abs_value;
char *end = temp + sizeof(temp) - 1;
*end = '\0';
if (value == (-2147483647 - 1)) { /* INT32_MIN */
strcopy(buffer, "-2147483648", 12);
return;
}
if (value == 0) {
*--end = '0';
} else {
if (value < 0) {
negative = 1;
abs_value = (u32)(-value);
} else {
abs_value = (u32)value;
}
end = write_digits_backwards(abs_value, end, temp);
if (negative) {
*--end = '-';
}
}
strcopy(buffer, end, temp + sizeof(temp) - end);
}
void fixed_to_string(i32 value, char *buffer) {
char temp[32];
i32 negative;
u32 int_part;
u32 frac_part, frac_digits, original_frac_digits;
char *end = temp + sizeof(temp) - 1;
char *frac_start;
*end = '\0';
negative = 0;
if (value < 0) {
negative = 1;
value = -value;
}
int_part = AS_NAT(value >> 16);
frac_part = AS_NAT(value & 0xFFFF);
/* Convert fractional part to 5 decimal digits */
original_frac_digits = (frac_part * 100000U) / 65536U;
frac_digits = original_frac_digits;
if (frac_digits > 0) {
/* Write fractional digits backwards */
frac_start = write_digits_backwards(frac_digits, end, temp);
/* Remove trailing zeros by moving the start pointer */
while (*(end - 1) == '0' && end > frac_start) {
end--;
}
/* If all fractional digits were zeros after removing trailing zeros,
we need to add back one zero to represent the .0 */
if (end == frac_start) {
*--end = '0';
}
/* Add decimal point */
*--end = '.';
} else if (frac_part > 0) {
/* Handle case where original_frac_digits was rounded to 0 but frac_part was not 0 */
/* This means we have a very small fractional part that should be represented as .0 */
*--end = '0';
*--end = '.';
} else if (frac_part == 0) {
/* No fractional part - just add .0 if we have an integer part */
if (int_part != 0) {
*--end = '0';
*--end = '.';
}
}
if (int_part == 0 && frac_digits == 0 && frac_part == 0) {
*--end = '0';
} else {
end = write_digits_backwards(int_part, end, temp);
}
if (negative) {
*--end = '-';
}
strcopy(buffer, end, temp + sizeof(temp) - end);
}

View File

@ -1,126 +1,108 @@
#ifndef UNDAR_OPCODES_H
#define UNDAR_OPCODES_H
#ifndef ZRE_OPCODES_H
#define ZRE_OPCODES_H
#include "common.h"
typedef enum {
OP_HALT, /* halt : terminate execution with code [src1] */
OP_CALL, /* call : creates a new frame */
OP_RETURN, /* return : returns from a frame to the parent frame */
OP_SYSCALL, /* syscall : src1 src2 src3 src4 more? does a system call based on args */
OP_LOAD_IMM, /* load-immediate : registers[dest] = constant */
OP_LOAD_IND_8, /* load-indirect-8 : registers[dest] = memory[registers[src1]] as u8 */
OP_LOAD_IND_16, /* load-indirect-16 : registers[dest] = memory[registers[src1]] as u8 */
OP_LOAD_IND_32, /* load-indirect-32 : registers[dest] = memory[registers[src1]] as u32 */
OP_LOAD_ABS_8, /* load-absolute-8 : registers[dest] = memory[src1 as u32] */
OP_LOAD_ABS_16, /* load-absolute-16 : registers[dest] = memory[src1 as u32] */
OP_LOAD_ABS_32, /* load-absolute-32 : registers[dest] = memory[src1 as u32] */
OP_LOAD_OFF_8, /* load-offset-8 : registers[dest] = memory[registers[src1] + offset] as u8 */
OP_LOAD_OFF_16, /* load-offset-16 : registers[dest] = memory[registers[src1] + offset] as u16 */
OP_LOAD_OFF_32, /* load-offset-32 : registers[dest] = memory[registers[src1] + offset] as u32 */
OP_STORE_ABS_8, /* store-absolute-8 : memory[dest] = src1 && 0xFF */
OP_STORE_ABS_16, /* store-absolute-16 : memory[dest] = src1 && 0xFFFF */
OP_STORE_ABS_32, /* store-absolute-32 : memory[dest] = src1 */
OP_STORE_IND_8, /* store-indirect-8 : memory[dest] = registers[src1] && 0xFF */
OP_STORE_IND_16, /* store-indirect-16 : memory[dest] = registers[src1] && 0xFFFF*/
OP_STORE_IND_32, /* store-indirect-32 : memory[dest] = registers[src1] */
OP_STORE_OFF_8, /* store-offset-8 : memory[registers[dest] + offset] = registers[src1] && 0xFF */
OP_STORE_OFF_16, /* store-offset-16 : memory[registers[dest] + offset] = registers[src1] && 0xFFFF */
OP_STORE_OFF_32, /* store-offset-32 : memory[registers[dest] + offset] = registers[src1] */
OP_MALLOC, /* malloc : dest = fat ptr to memory of ((src1 as size) + 4) */
OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */
OP_MEMSET_16, /* memset-16 : dest <-> dest+count = src1 as u8 */
OP_MEMSET_32, /* memset-32 : dest <-> dest+count = src1 as u32 */
OP_REG_MOV, /* register-move : registers[dest] = registers[src1] */
OP_ADD_INT, /* add-int : registers[dest] = registers[src1] + registers[src2] */
OP_SUB_INT, /* sub-int : registers[dest] = registers[src1] - registers[src2] */
OP_MUL_INT, /* mul-int : registers[dest] = registers[src1] * registers[src2] */
OP_DIV_INT, /* div-int : registers[dest] = registers[src1] / registers[src2] */
OP_ABS_INT, /* abs-int : registers[dest] = | registers[src1] | */
OP_NEG_INT, /* neg-int : registers[dest] = -registers[src1] */
OP_ADD_NAT, /* add-nat : registers[dest] = registers[src1] + registers[src2] */
OP_SUB_NAT, /* sub-nat : registers[dest] = registers[src1] - registers[src2] */
OP_MUL_NAT, /* mul-nat : registers[dest] = registers[src1] * registers[src2] */
OP_DIV_NAT, /* div-nat : registers[dest] = registers[src1] / registers[src2] */
OP_ABS_NAT, /* abs-nat : registers[dest] = | registers[src1] | */
OP_NEG_NAT, /* neg-nat : registers[dest] = -registers[src1] */
OP_ADD_REAL, /* add-real : registers[dest] = registers[src1] + registers[src2] */
OP_SUB_REAL, /* sub-real : registers[dest] = registers[src1] - registers[src2] */
OP_MUL_REAL, /* mul-real : registers[dest] = registers[src1] * registers[src2] */
OP_DIV_REAL, /* div-real : registers[dest] = registers[src1] / registers[src2] */
OP_ABS_REAL, /* abs-real : registers[dest] = | registers[src1] | */
OP_NEG_REAL, /* neg-real : registers[dest] = -registers[src1] */
OP_INT_TO_REAL, /* int-to-real : registers[dest] = registers[src1] as real */
OP_NAT_TO_REAL, /* nat-to-real : registers[dest] = registers[src1] as real */
OP_REAL_TO_INT, /* real-to-int : registers[dest] = registers[src1] as int */
OP_REAL_TO_NAT, /* real-to-nat : registers[dest] = registers[src1] as nat */
OP_BIT_SHIFT_LEFT, /* bit-shift-left : registers[dest] = registers[src1] << registers[src2] */
OP_BIT_SHIFT_RIGHT,/* bit-shift-right : registers[dest] = registers[src1] >> registers[src2] */
OP_BIT_SHIFT_R_EXT,/* bit-shift-r-ext : registers[dest] as i32 = registers[src1] >> registers[src2] */
OP_BAND, /* bit-and : registers[dest] = registers[src1] & registers[src2] */
OP_BOR, /* bit-or : registers[dest] = registers[src1] | registers[src2] */
OP_BXOR, /* bit-xor : registers[dest] = registers[src1] ^ registers[src2] */
OP_JMP, /* jump : jump to &dest unconditionally */
OP_JMPF, /* jump-if-flag : jump to &dest if flag != 0 */
OP_JEQ_INT, /* jump-eq-int : jump to &dest if registers[src1] as int == registers[src2] as int */
OP_JNEQ_INT, /* jump-neq-int : jump to &dest if registers[src1] as int != registers[src2] as int */
OP_JGT_INT, /* jump-gt-int : jump to &dest if registers[src1] as int > registers[src2] as int */
OP_JLT_INT, /* jump-lt-int : jump to &dest if registers[src1] as int < registers[src2] as int */
OP_JLE_INT, /* jump-le-int : jump to &dest if registers[src1] as int <= registers[src2] as int */
OP_JGE_INT, /* jump-ge-int : jump to &dest if registers[src1] as int >= registers[src2] as int */
OP_JEQ_NAT, /* jump-eq-nat : jump to &dest if registers[src1] as nat == registers[src2] as nat */
OP_JNEQ_NAT, /* jump-neq-nat : jump to &dest if registers[src1] as nat != registers[src2] as nat */
OP_JGT_NAT, /* jump-gt-nat : jump to &dest if registers[src1] as nat > registers[src2] as nat */
OP_JLT_NAT, /* jump-lt-nat : jump to &dest if registers[src1] as nat < registers[src2] as nat */
OP_JLE_NAT, /* jump-le-nat : jump to &dest if registers[src1] as nat <= registers[src2] as nat */
OP_JGE_NAT, /* jump-ge-nat : jump to &dest if registers[src1] as nat >= registers[src2] as nat */
OP_JEQ_REAL, /* jump-eq-real : jump to &dest if registers[src1] as real == registers[src2] as real */
OP_JNEQ_REAL, /* jump-neq-real : jump to &dest if registers[src1] as real != registers[src2] as real */
OP_JGE_REAL, /* jump-ge-real : jump to &dest if registers[src1] as real >= registers[src2] as real */
OP_JGT_REAL, /* jump-gt-real : jump to &dest if registers[src1] as real > registers[src2] as real */
OP_JLT_REAL, /* jump-lt-real : jump to &dest if registers[src1] as real < registers[src2] as real */
OP_JLE_REAL, /* jump-le-real : jump to &dest if registers[src1] as real <= registers[src2] as real */
OP_STRLEN, /* string-length : registers[dest] = length of str at src1 ptr */
OP_STREQ, /* string-eq : registers[dest] = src1 ptr string == src2 ptr string */
OP_STRCAT, /* string-concat : registers[dest] = ptr of src1 ptr string + src2 ptr string */
OP_STR_GET_CHAR, /* string-get-char : registers[dest] = ptr of src1 ptr str, src2 index of str */
OP_STR_FIND_CHAR, /* string-find-char : registers[dest] = ptr of src1 ptr string, src2 nat8 char */
OP_STR_SLICE, /* string-slice : registers[dest] = ptr of src1 ptr str, src2 start index, src3 end index */
OP_INT_TO_STRING, /* int-to-string : registers[dest] = src1 as str */
OP_NAT_TO_STRING, /* nat-to-string : registers[dest] = src1 as str */
OP_REAL_TO_STRING, /* real-to-string : registers[dest] = src1 as str */
OP_STRING_TO_INT, /* string-to-int : registers[dest] = src1 as int */
OP_STRING_TO_NAT, /* string-to-nat : registers[dest] = src1 as nat */
OP_STRING_TO_REAL /* string-to-real : registers[dest] = src1 as real */
OP_HALT, /* [obj1 `halt` - | terminate execution with code ] */
OP_JMP, /* [dest `jump` - | jump to address dest unconditionally ] */
OP_JMPF, /* [dest `jump-if-flag` - | jump to address dest if flag is ne 0 ] */
OP_CALL, /* [&code_ref `call` - | creates a new frame ] */
OP_RETURN, /* [obj1 `return` - | returns from a frame to the parent frame, pushes obj1 on stack ] */
OP_LOAD_8, /* [&dest `load-8` u8 | push memory[obj1] onto stack as u8 ] */
OP_LOAD_16, /* [&dest `load-16` u16 | push memory[obj1] onto stack as u16 ] */
OP_LOAD_32, /* [&dest `load` u32 | push memory[obj1] onto stack as u32 ] */
OP_STORE_8, /* [&dest obj1 `store-8` - | memory[dest] = obj1 << 8 ] */
OP_STORE_16, /* [&dest obj1 `store-16`- | memory[dest] = obj1 << 16 ] */
OP_STORE_32, /* [&dest obj1 `store` - | memory[dest] = obj1 ] */
OP_MALLOC, /* [size `malloc` ptr | allocate 'size + 4' of memory and push ptr to memory on stack ] */
OP_MEMSET_8, /* [ `memset-8` | dest <-> dest+count = obj1 as u8 ] */
OP_MEMSET_16, /* [ `memset-16` | dest <-> dest+count = obj1 as u8 ] */
OP_MEMSET_32, /* [ `memset-32` | dest <-> dest+count = obj1 as u32 ] */
OP_PUSH, /* [ `push` | push const of ref ] */
OP_POP, /* [ `pop` | pop cosnt or ref ] */
OP_DUP, /* [ obj1 `dup` obj1 obj1 | ] */
OP_EXCH, /* [ obj1 obj2 `exch` obj2 obj1 | ] */
OP_OVER, /* [ obj1 obj2 `over` obj1 obj2 obj1 | ] */
OP_PICK, /* [ N `pick` objN | ] */
OP_ROT, /* [ obj1 obj2 obj3 `rot` obj2 obj3 obj1 | ] */
OP_DEPTH, /* [ - `depth` stack_size | ] */
OP_SYSCALL, /* [ `syscall` | obj1 obj2 obj3 obj4 more? does a system call based on args ] */
OP_SLL, /* [ `bit-shift-left` | dest = obj1 << obj2 ] */
OP_SRL, /* [ `bit-shift-right` | dest = obj1 >> obj2 ] */
OP_SRE, /* [ `bit-shift-re` | dest as i32 = obj1 >> obj2 ] */
OP_BAND, /* [ `bit-and` | dest = obj1 & obj2 ] */
OP_BOR, /* [ `bit-or` | dest = obj1 | obj2 ] */
OP_BXOR, /* [ `bit-xor` | dest = obj1 ^ obj2 ] */
OP_ADD_INT, /* [ `add-int` | dest = obj1 + obj2 ] */
OP_SUB_INT, /* [ `sub-int` | dest = obj1 - obj2 ] */
OP_MUL_INT, /* [ `mul-int` | dest = obj1 * obj2 ] */
OP_DIV_INT, /* [ `div-int` | dest = obj1 / obj2 ] */
OP_ADD_UINT, /* [ `add-nat` | dest = obj1 + obj2 ] */
OP_SUB_UINT, /* [ `sub-nat` | dest = obj1 - obj2 ] */
OP_MUL_UINT, /* [ `mul-nat` | dest = obj1 * obj2 ] */
OP_DIV_UINT, /* [ `div-nat` | dest = obj1 / obj2 ] */
OP_ADD_REAL, /* [ `add-real` | dest = obj1 + obj2 ] */
OP_SUB_REAL, /* [ `sub-real` | dest = obj1 - obj2 ] */
OP_MUL_REAL, /* [ `mul-real` | dest = obj1 * obj2 ] */
OP_DIV_REAL, /* [ `div-real` | dest = obj1 / obj2 ] */
OP_INT_TO_REAL, /* [ `int-to-real` | dest = obj1 as real ] */
OP_UINT_TO_REAL, /* [ `nat-to-real` | dest = obj1 as real ] */
OP_REAL_TO_INT, /* [ `real-to-int` | dest = obj1 as int ] */
OP_REAL_TO_UINT, /* [ `real-to-nat` | dest = obj1 as uint ] */
OP_JEQ_INT, /* [ `jump-eq-int` | jump to address dest if obj1 as int == obj2 as int ] */
OP_JNEQ_INT, /* [ `jump-neq-int` | jump to address dest if obj1 as int != obj2 as int ] */
OP_JGT_INT, /* [ `jump-gt-int` | jump to address dest if obj1 as int > obj2 as int ] */
OP_JLT_INT, /* [ `jump-lt-int` | jump to address dest if obj1 as int < obj2 as int ] */
OP_JLE_INT, /* [ `jump-le-int` | jump to address dest if obj1 as int <= obj2 as int ] */
OP_JGE_INT, /* [ `jump-ge-int` | jump to address dest if obj1 as int >= obj2 as int ] */
OP_JEQ_UINT, /* [ `jump-eq-nat` | jump to address dest if obj1 as uint == obj2 as uint ] */
OP_JNEQ_UINT, /* [ `jump-neq-nat` | jump to address dest if obj1 as uint != obj2 as uint ] */
OP_JGT_UINT, /* [ `jump-gt-nat` | jump to address dest if obj1 as uint > obj2 as uint ] */
OP_JLT_UINT, /* [ `jump-lt-nat` | jump to address dest if obj1 as uint < obj2 as uint ] */
OP_JLE_UINT, /* [ `jump-le-nat` | jump to address dest if obj1 as uint <= obj2 as uint ] */
OP_JGE_UINT, /* [ `jump-ge-nat` | jump to address dest if obj1 as uint >= obj2 as uint ] */
OP_JEQ_REAL, /* [ `jump-eq-real` | jump to address dest if obj1 as real == obj2 as real ] */
OP_JNEQ_REAL, /* [ `jump-neq-real` | jump to address dest if obj1 as real != obj2 as real ] */
OP_JGE_REAL, /* [ `jump-ge-real` | jump to address dest if obj1 as real >= obj2 as real ] */
OP_JGT_REAL, /* [ `jump-gt-real` | jump to address dest if obj1 as real > obj2 as real ] */
OP_JLT_REAL, /* [ `jump-lt-real` | jump to address dest if obj1 as real < obj2 as real ] */
OP_JLE_REAL, /* [ `jump-le-real` | jump to address dest if obj1 as real <= obj2 as real ] */
OP_STRLEN, /* [&str `string-length` len &str | length of string from str ptr ] */
OP_STREQ, /* [ `string-eq` | dest = obj1 ptr string == obj2 ptr string ] */
OP_STRCAT, /* [ `string-concat` | dest = ptr of obj1 ptr string + obj2 ptr string ] */
OP_STR_GET_CHAR, /* [ `string-get-char` | dest = ptr of obj1 ptr str, obj2 index of str ] */
OP_STR_FIND_CHAR, /* [ `string-find-char` | dest = ptr of obj1 ptr string, obj2 uint8 char ] */
OP_STR_SLICE, /* [ `string-slice` | dest = ptr of obj1 ptr str, obj2 start index, obj3 end index ] */
OP_INT_TO_STRING, /* [ `int-to-string` | dest = obj1 as str ] */
OP_UINT_TO_STRING, /* [ `nat-to-string` | dest = obj1 as str ] */
OP_REAL_TO_STRING, /* [ `real-to-string` | dest = obj1 as str ] */
OP_STRING_TO_INT, /* [ `string-to-int` | dest = obj1 as int ] */
OP_STRING_TO_UINT, /* [ `string-to-nat` | dest = obj1 as uint ] */
OP_STRING_TO_REAL /* [ `string-to-real` | dest = obj1 as real ] */
} Opcode;
#define MAX_REGS 32
typedef struct frame_s {
u32 registers[MAX_REGS]; /* R0-R31 */
u32 start; /* start of memory block */
u32 end; /* end of memory block */
u32 return_reg; /* register to store return value in parent */
u32 heap_mask; /* bitfield: 1 bit per register (R0=bit0, R1=bit1, etc) */
u32 start; /* start and end of global allocated block */
u32 end;
} Frame;
typedef enum {
SYSCALL_EXIT = 0,
SYSCALL_DEVICE_OPEN,
SYSCALL_DEVICE_READ,
SYSCALL_DEVICE_WRITE,
SYSCALL_DEVICE_CLOSE,
SYSCALL_DEVICE_IOCTL,
SYSCALL_DEVICE_REFRESH
SYSCALL_DEVICE_OPEN, /* */
SYSCALL_DEVICE_READ, /* */
SYSCALL_DEVICE_WRITE, /* */
SYSCALL_DEVICE_CLOSE, /* */
SYSCALL_DEVICE_IOCTL /* */
} SyscallID;
typedef struct device_ops_s {
i32 (*open)(void *device_data, u32 mode, u32 handle, u8 *buffer, u32 size);
i32 (*open)(void *device_data, u32 mode);
i32 (*read)(void *device_data, u8 *buffer, u32 size);
i32 (*write)(void *device_data, const u8 *buffer, u32 size);
i32 (*close)(void *device_data);
i32 (*ioctl)(void *device_data, u32 cmd,
const u8 *buffer); /* optional control */
i32 (*refresh)(void *device_data, u8 *buffer);
} DeviceOps;
#define DEVICE_TYPE_MAX_LENGTH 16 /* 15 chars + null terminator */
@ -134,7 +116,6 @@ typedef struct device_s {
DeviceOps *ops; /* operations vtable */
u32 flags; /* permissions, status, etc. */
u32 handle; /* id for fast access in VM */
u32 size; /* id for fast access in VM */
} Device;
#define MEMORY_SIZE (640 * 480 + 65536)
@ -143,18 +124,20 @@ typedef struct device_s {
#define STACK_SIZE 256
#define DEVICES_SIZE 8
typedef struct vm_s {
u32 pc; /* program counter */
u32 cp; /* code pointer (last allocated opcode) */
u32 fp; /* frame pointer (current frame) */
u32 sp; /* stack pointer (top of stack) */
u32 mp; /* memory pointer (last allocated value) */
u32 dc; /* device count */
i32 flag; /* flag (temporary results like SYSCALL status) */
Frame frames[FRAMES_SIZE]; /* function call frames */
u32 stack[STACK_SIZE]; /* main stack */
u32 pc; /* program counter */
u32 cp; /* code pointer (last allocated opcode) */
u32 fp; /* frame pointer (current frame) */
u32 sp; /* stack pointer (top of stack) */
u32 rp; /* return stack pointer (top of stack) */
u32 mp; /* memory pointer (last allocated value) */
u32 dc; /* device count */
i32 flag; /* flag (temporary results like SYSCALL status) */
Frame frames[FRAMES_SIZE]; /* function call frames */
u32 stack[STACK_SIZE]; /* main stack */
u32 return_stack[FRAMES_SIZE]; /* return stack (for call recursion) */
Device devices[DEVICES_SIZE]; /* device definitions */
u8 code[CODE_SIZE]; /* code block */
u8 memory[MEMORY_SIZE]; /* memory block */
u8 code[CODE_SIZE]; /* code block */
u8 memory[MEMORY_SIZE]; /* memory block */
} VM;
#define read_u8(vm, location, addr) ((vm)->location[addr])

143
src/vm/str.c Normal file
View File

@ -0,0 +1,143 @@
#include "str.h"
i32 strcopy(char *to, const char *from, u32 length) {
u32 i;
if (to == nil || from == nil) return -1;
if (length == 0) {return 0;}
for (i = 0; i < length - 1 && from[i] != '\0'; i++) {
to[i] = from[i];
}
to[i] = '\0';
return 0;
}
bool streq(const char *s1, const char *s2) {
if (s1 == nil && s2 == nil) return true;
if (s1 == nil || s2 == nil) return false;
while (*s1 && *s2) {
if (*s1 != *s2) return false;
s1++;
s2++;
}
return (*s1 == '\0' && *s2 == '\0');
}
u32 strlength(const char *str) {
u32 i;
if (str == nil) {return 0;}
for (i = 0; str[i] != '\0'; i++) {
; /* twiddle thumbs, 'i' is doing all the work*/
}
return i;
}
u32 strnlength(const char *str, u32 max_len) {
u32 i;
if (str == nil) {return 0;}
for (i = 0; i < max_len && str[i] != '\0'; i++) {
; /* twiddle thumbs, 'i' is doing all the work*/
}
return i;
}
/* Static digit lookup table (0-9) */
const char digits[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
/* Writes decimal digits of 'value' backwards into 'buf_end' (inclusive),
stopping at 'buf_start'. Returns pointer to first written digit. */
char *write_digits_backwards(u32 value, char *buf_end, char *buf_start) {
char *p = buf_end;
if (value == 0) {
*--p = '0';
} else {
u32 num = value;
while (num && p > buf_start) {
*--p = digits[num % 10];
num /= 10;
}
}
return p;
}
void uint_to_string(u32 value, char *buffer) {
char temp[16];
char *start;
char *end = temp + sizeof(temp) - 1;
*end = '\0';
start = write_digits_backwards(value, end, temp);
strcopy(buffer, start, end - start + 1); /* +1 for null terminator */
}
void int_to_string(i32 value, char *buffer) {
char temp[17]; /* Extra space for '-' */
i32 negative = 0;
u32 abs_value;
char *end = temp + sizeof(temp) - 1;
*end = '\0';
if (value == (-2147483647 - 1)) { /* INT32_MIN */
strcopy(buffer, "-2147483648", 12);
return;
}
if (value == 0) {
*--end = '0';
} else {
if (value < 0) {
negative = 1;
abs_value = (u32)(-value);
} else {
abs_value = (u32)value;
}
end = write_digits_backwards(abs_value, end, temp);
if (negative) {
*--end = '-';
}
}
strcopy(buffer, end, temp + sizeof(temp) - end);
}
void fixed_to_string(i32 value, char *buffer) {
char temp[32];
i32 negative;
u32 int_part;
u32 frac_part, frac_digits;
char *end = temp + sizeof(temp) - 1;
*end = '\0';
negative = 0;
if (value < 0) {
negative = 1;
value = -value;
}
int_part = AS_UINT(value >> 16);
frac_part = AS_UINT(value & 0xFFFF);
/* Convert fractional part to 5 decimal digits */
frac_digits = (frac_part * 100000U) / 65536U;
if (frac_digits > 0) {
end = write_digits_backwards(frac_digits, end, temp);
*--end = '.';
}
if (int_part == 0 && frac_digits == 0) {
*--end = '0';
} else {
end = write_digits_backwards(int_part, end, temp);
}
if (negative) {
*--end = '-';
}
strcopy(buffer, end, temp + sizeof(temp) - end);
}

View File

@ -1,5 +1,5 @@
#ifndef UNDAR_STR_H
#define UNDAR_STR_H
#ifndef ZRE_STR_H
#define ZRE_STR_H
#include "common.h"
@ -7,8 +7,7 @@ bool streq(const char *s1, const char *s2);
i32 strcopy(char* to, const char *from, u32 length);
u32 strlength(const char *str);
u32 strnlength(const char *str, u32 max_len);
void memcopy(u8 *dest, const u8 *src, u32 n);
void nat_to_string(u32 value, char *buffer);
void uint_to_string(u32 value, char *buffer);
void int_to_string(i32 value, char *buffer);
void fixed_to_string(i32 value, char *buffer);

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,12 @@
#ifndef UNDAR_VM_H
#define UNDAR_VM_H
#ifndef ZRE_VM_H
#define ZRE_VM_H
#include "opcodes.h"
bool step_vm(VM *vm);
u32 str_alloc(VM *vm, Frame *frame, const char *str, u32 length);
void fixed_to_string(i32 value, char *buffer);
void int_to_string(i32 value, char *buffer);
void uint_to_string(u32 value, char *buffer);
#endif

View File

@ -1,26 +1,27 @@
((code
(label main
(load-immediate $0 1)
(load-immediate $1 1)
(call &add ($0 $1) $2)
(int-to-string $3 $2)
(call &pln ($3) nil)
(halt 0))
(push 1)
(push 1)
(call &add)
(int-to-string)
(call &pln)
(halt))
(label add
(add-int $2 $1 $0)
(return $2))
(add-int)
(return))
(label pln
(load-immediate $1 &terminal-namespace) ; get terminal device
(load-immediate $11 0)
(syscall OPEN $1 $1 $11)
(string-length $2 $0)
(syscall WRITE $1 $0 $2)
(load-immediate $3 &new-line)
(string-length $4 $3)
(syscall WRITE $1 $3 $4)
(return nil)))
(label pln
(dup)
(string-length)
(push &terminal-namespace)
(syscall WRITE)
(push &new-line)
(dup)
(string-length)
(push &terminal-namespace)
(syscall WRITE)
(return)))
(data
(label terminal-namespace "/dev/term/0")
(label new-line "\n")))

Binary file not shown.

View File

@ -1,31 +0,0 @@
/**
* Constants
*/
const str nl = "\n";
plex Terminal {
nat handle;
}
/**
* Main function
*/
function main() {
pln(add(1, 1).str);
}
/**
* Add two numbers together
*/
function add(int a, int b) int {
return a + b;
}
/**
* Print with a newline
*/
function pln(str message) {
Terminal term = open("/dev/term/0", 0);
write(term, message, message.length);
write(term, nl, nl.length);
}

View File

@ -1,33 +1,44 @@
((code
(label main
(load-immediate $0 35)
(call &fib ($0) $0)
(int-to-string $1 $0)
(call &pln ($1) nil)
(halt 0))
(label fib
(load-immediate $1 2)
(jump-lt-int &base-case $0 $1)
(load-immediate $3 2)
(sub-int $4 $0 $3)
(call &fib ($4) $5)
(load-immediate $3 1)
(sub-int $4 $0 $3)
(call &fib ($4) $6)
(add-int $7 $6 $5)
(return $7)
(label base-case
(return $0)))
(label pln
(load-immediate $1 &terminal-namespace) ; get terminal device
(load-immediate $11 0)
(syscall OPEN $1 $1 $11)
(load-immediate $3 &new-line)
(string-length $2 $0)
(syscall WRITE $1 $0 $2)
(string-length $4 $3)
(syscall WRITE $1 $3 $4)
(return nil)))
(label main
(push 35)
(call &fib)
(int-to-string)
(call &pln)
(halt))
(label fib
(dup) ; dup num
(push 2) ; Base case: n < 2
(jump-lt-int &base-case)
(dup)
(push 2) ; First call: fib(n-2)
(sub-int) ; n - 2
(call &fib)
(over) ; get n over the previous answer
(push 1) ; Second call: fib(n-1)
(sub-int) ; n-1 (using saved n)
(call &fib) ; Result in $2
; Combine results
(add-int) ; fib(n-2) + fib(n-1)
(return) ; Return result
(label base-case
(return))) ; Return n directly
(label pln
(dup)
(string-length)
(push &terminal-namespace)
(syscall WRITE)
(push &new-line)
(dup)
(string-length)
(push &terminal-namespace)
(syscall WRITE)
(return)))
(data
(label terminal-namespace "/dev/term/0")
(label new-line "\n")))
(label terminal-namespace "/dev/term/0")
(label new-line "\n")))

Binary file not shown.

View File

@ -1,32 +0,0 @@
/**
* Constants
*/
const str nl = "\n";
plex Terminal {
nat handle;
}
/**
* Main function
*/
function main() {
pln(fib(35).str);
}
/**
* Recursively calculate fibonacci
*/
function fib(int n) int {
if (n < 2) return n;
return fib(n - 2) + fib(n - 1);
}
/**
* Print with a newline
*/
function pln(str message) {
Terminal term = open("/dev/term/0", 0);
write(term, message, message.length);
write(term, nl, nl.length);
}

View File

@ -1,19 +1,11 @@
((code
(label main
(load-immediate $0 &terminal-namespace) ; load terminal namespace
(syscall OPEN $0 $0 $0)
(load-immediate $1 &hello-str) ; load hello string ptr
(call &pln ($1) nil)
(halt 0)) ; done
(label pln
(load-immediate $1 &terminal-namespace) ; get terminal device
(load-immediate $11 0)
(syscall OPEN $1 $1 $11)
(load-immediate $3 &new-line)
(string-length $2 $0)
(syscall WRITE $1 $0 $2)
(string-length $4 $3)
(syscall WRITE $1 $3 $4)
(return nil)))
(string-length $2 $1) ; get length to write to stdout
(syscall WRITE $0 $1 $2) ; do the write syscall
(halt))) ; done
(data
(label terminal-namespace "/dev/term/0")
(label new-line "\n")
(label hello-str "nuqneH 'u'?")))
(label hello-str "nuqneH 'u'?\n")))

Binary file not shown.

View File

@ -1,24 +0,0 @@
/**
* Constants
*/
const str nl = "\n";
plex Terminal {
nat handle;
}
/**
* Main function
*/
function main() {
pln("nuqneH 'u'?");
}
/**
* Print with a newline
*/
function pln(str message) {
Terminal term = open("/dev/term/0", 0);
write(term, message, message.length);
write(term, nl, nl.length);
}

View File

@ -10,35 +10,34 @@
(add-int $1 $1 $3)
(jump-ge-int &loop-body $1 $2))
(load-immediate $10 &terminal-namespace)
(load-immediate $11 0)
(syscall OPEN $10 $10 $11) ; Terminal term = open(namespace, flags)
(real-to-nat $1 $0)
(load-immediate $7 &prompt)
(load-immediate $7 &help)
(string-length $8 $7)
(syscall WRITE $10 $7 $8) ; print prompt
(syscall WRITE $10 $7 $8)
(load-immediate $8 32)
(malloc $11 $8)
(syscall READ $10 $11 $8) ; read in max 32 byte string
(call &pln ($11) nil)
(malloc $11 $8)
(syscall READ $10 $2 $8 $11)
(push $2)
(call &pln)
(nat-to-string $4 $1)
(call &pln ($4) nil)
(push $4)
(call &pln)
(real-to-string $3 $0)
(call &pln ($3) nil)
(halt 0))
(label pln
(load-immediate $1 &terminal-namespace) ; get terminal device
(load-immediate $11 0)
(syscall OPEN $1 $1 $11)
(load-immediate $3 &new-line)
(string-length $2 $0)
(syscall WRITE $1 $0 $2)
(string-length $4 $3)
(syscall WRITE $1 $3 $4)
(return nil)))
(push $3)
(call &pln)
(halt))
(label pln
(load-immediate $0 &terminal-namespace)
(syscall OPEN $0 $0 $0)
(load-immediate $3 &new-line)
(pop $1)
(string-length $2 $1)
(syscall WRITE $0 $1 $2)
(string-length $4 $3)
(syscall WRITE $0 $3 $4)
(return)))
(data
(label terminal-namespace "/dev/term/0")
(label prompt "Enter a string: ")
(label help "Enter a string: ")
(label new-line "\n")))

Binary file not shown.

View File

@ -1,33 +0,0 @@
/**
* Constants
*/
const str nl = "\n";
plex Terminal {
nat handle;
}
/**
* Main function
*/
function main() {
Terminal term = open("/dev/term/0", 0);
real a = 5.0;
do (int i = 5000, 0, -1) {
a = a + 5.0;
}
nat b = a as nat;
pln(term, "Enter a string:");
str user_string = term.read(32);
pln(term, a.str);
pln(term, b.str);
pln(term, user_string);
}
/**
* Print with a newline
*/
function pln(Terminal term, str message) {
write(term, message, message.length);
write(term, nl, nl.length);
}

View File

@ -1,25 +1,25 @@
((code
(label main
(load-immediate $0 &terminal-namespace) ; get terminal device
(load-immediate $11 0)
(syscall OPEN $0 $0 $11)
(load-immediate $1 &help) ; print help message
(call &pln ($0 $1) nil)
(push $1)
(call &pln)
(load-immediate $1 32) ; read in a string of max 32 char length
(malloc $4 $1) ; allocate memory for the string
(syscall READ $0 $4 $1) ; read the string
(call &pln ($0 $4) nil) ; print the string
(halt 0))
(label pln
(load-immediate $3 &new-line)
(string-length $2 $1)
(syscall WRITE $0 $1 $2)
(string-length $4 $3)
(syscall WRITE $0 $3 $4)
(return nil)))
(malloc $2 $1) ; allocate memory for the string
(syscall READ $0 $3 $1 $2) ; read the string
(push $3)
(call &pln) ; print the string
(halt))
(label pln
(load-immediate $0 &terminal-namespace)
(syscall OPEN $0 $0 $0)
(load-immediate $3 &new-line)
(pop $1)
(string-length $2 $1)
(syscall WRITE $0 $1 $2)
(string-length $4 $3)
(syscall WRITE $0 $3 $4)
(return)))
(data
(label terminal-namespace "/dev/term/0")
(label help "Enter a string: ")

Binary file not shown.

View File

@ -1,26 +0,0 @@
/**
* Constants
*/
const str nl = "\n";
plex Terminal {
nat handle;
}
/**
* Main function
*/
function main() {
Terminal term = open("/dev/term/0", 0);
pln(term, "Enter a string: ");
pln(term, term.read(32));
return 0;
}
/**
* Print with a newline
*/
function pln(Terminal term, str message) {
write(term, message, message.length);
write(term, nl, nl.length);
}

View File

@ -1,76 +1,121 @@
((code
(label main
(load-immediate $30 4) ; fat ptr size
; Open screen
; use load immediate because it is a pointer to a string, not a value
(load-immediate $0 &screen-namespace)
(load-immediate $11 0)
(syscall OPEN $0 $18 $11) ; open(out Plex screen, in namespace, in flags)
(syscall OPEN $0 $11)
(load-offset-32 $20 $0 8) ; load width
(load-offset-32 $22 $0 12) ; load size
(load-immediate $1 16) ; offset for screen buffer
(add-nat $21 $0 $1)
(load-immediate $16 1) ; device info call
(load-immediate $17 16) ; sizeof screen device info
(malloc $18 $17)
(syscall IOCTL $0 $16 $18)
(load-immediate $1 12) ; offset for width
(add-nat $19 $18 $1)
(get $20 $19) ; load width
(load-immediate $1 8) ; offset for size
(add-nat $19 $18 $1)
(get $22 $19) ; load size
(malloc $21 $22) ; malloc frame buffer
; open mouse
(load-immediate $16 &mouse-namespace)
(syscall OPEN $15 $16 $11) ; open(out Plex mouse, in namespace, in flags)
(load-immediate $3 12) ; malloc sizeof mouse data
(malloc $4 $3)
; outline_swatch(screen, BLACK, 1, 1);
(load-absolute-32 $1 &BLACK)
(load-immediate $12 1)
(load-immediate $13 1)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(load-immediate $14 20) ; box size
; outline_swatch(screen, WHITE, 1, 1);
(load-absolute-32 $1 &WHITE)
(load-immediate $12 21)
(load-immediate $13 1)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
; screen.draw();
(syscall WRITE $0 $21 $22)
(label draw-loop
; load mouse click data
(syscall REFRESH $15)
(load-offset-8 $9 $15 16) ; load btn1 pressed
(syscall READ $16 $2 $3 $4)
(jump-eq-nat &draw-loop $9 $11)
(load-immediate $5 4) ; offset for x
(add-nat $6 $5 $2)
(get $7 $6) ; load x
(load-offset-32 $7 $15 8) ; load x
(load-offset-32 $8 $15 12) ; load y
(load-immediate $5 8) ; offset for y
(add-nat $6 $5 $2)
(get $8 $6) ; load y
(load-immediate $14 20) ; box size
(load-immediate $5 12) ; offset for btn1
(add-nat $6 $5 $2)
(get-8 $9 $6) ; load btn1 pressed
(load-immediate $5 13) ; offset for btn2
(add-nat $6 $5 $2)
(get-8 $10 $6) ; load btn2 pressed
; first row
(load-absolute-32 $1 &BLACK)
(push $21)
(push $20)
(load $1 &BLACK)
(push $1)
(load-immediate $12 1)
(push $12)
(load-immediate $13 1)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(syscall WRITE $0 $21 $22)
(load-absolute-32 $1 &WHITE)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
(push $21)
(push $20)
(load $1 &WHITE)
(push $1)
(load-immediate $12 21)
(push $12)
(load-immediate $13 1)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(push $13)
(call &draw-outlined-swatch)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
(syscall WRITE $0 $21 $22)
(load-absolute-32 $22 &SELECTED-COLOR) ; color
(load-immediate $1 5) ; size of brush
(jump-eq-nat &draw-loop $9 $11)
(call &draw-box ($21 $20 $22 $7 $8 $1 $1) nil)
(mul-nat $15 $8 $20) ; $15 = y * width
(add-nat $15 $15 $7) ; $15 += x
(add-nat $15 $21 $15) ; $15 = base + pixel_offset
(add-nat $15 $15 $30)
(load $22 &SELECTED-COLOR) ; color
(store-8 $15 $22) ; draw color at screen [x,y]
(jump &draw-loop))
(jump-eq-nat &draw-loop $10 $11))
; Flush and halt
(halt 0))
(halt))
(label set-color-if-clicked
; (click_x, click_y, box_x, box_y, color, box_size)
(label set-color-if-clicked
; Pop inputs from stack (in reverse order of pushing)
(pop $12) ; $12 = btn1 down?
(pop $11) ; $11 = color
(pop $0) ; $0 = click_x
(pop $1) ; $1 = click_y
(pop $2) ; $2 = box_x
(pop $3) ; $3 = box_y
(pop $5) ; $5 = box_size
; Compute right = box_x + box_size
(add-int $6 $2 $5) ; $6 = right edge
@ -83,65 +128,98 @@
(jump-gt-int &fail $0 $6)
(jump-lt-int &fail $1 $3)
(jump-gt-int &fail $1 $7)
; If btn1 is pressed (==1), set color
(jump-eq-int &fail $12 1)
(load-immediate $10 &SELECTED-COLOR)
(store-absolute-8 $10 $4)
(store-8 $10 $11)
(label fail)
(return nil))
(return))
(label draw-outlined-swatch
; (base, color, x, y, width)
(pop $3) ; y
(pop $2) ; x
(pop $1) ; color
(pop $20)
(pop $21)
; Constants
(load-absolute-32 $5 &GRAY)
(load-absolute-32 $10 &SELECTED-COLOR)
(load $4 &GRAY)
(load $10 &SELECTED-COLOR)
(jump-eq-int &set-selected $10 $1)
(jump-eq-int &end-set-selected $5 $5)
(jump-eq-int &end-set-selected $4 $4)
(label set-selected)
(load-absolute-32 $5 &DARK-GRAY)
(load $4 &DARK-GRAY)
(label end-set-selected)
(load-immediate $6 20) ; outline size
(load-immediate $7 17) ; fill size
(load-immediate $8 2) ; offset
(load-immediate $5 20) ; outline size
(load-immediate $6 17) ; fill size
(load-immediate $7 2) ; offset
(call &draw-box ($0 $4 $5 $2 $3 $6 $6) nil)
(push $21) ; base
(push $20) ; width
(push $4) ; color (gray)
(push $2) ; x
(push $3) ; y
(push $5) ; width (20)
(push $5) ; height (20)
(call &draw-box)
(add-int $9 $2 $8) ; x + 2
(add-int $10 $3 $8) ; y + 2
(add-int $8 $2 $7) ; x + 2
(add-int $9 $3 $7) ; y + 2
(call &draw-box ($0 $4 $1 $9 $10 $7 $7) nil)
(push $21) ; base
(push $20) ; width
(push $1) ; color (original)
(push $8) ; x + 2
(push $9) ; y + 2
(push $6) ; width (17)
(push $6) ; height (17)
(call &draw-box)
(return nil))
(return))
; draw-box(color, x, y)
; Pops: y, x, color
(label draw-box
; (base, screen_width, color, x_start, y_start, width, height)
; Pop arguments (reverse order)
(pop $14) ; height
(pop $12) ; width
(pop $13) ; y_start
(pop $11) ; x_start
(pop $3) ; color
(pop $2) ; width
(pop $21) ; base
; Constants
(load-immediate $1 1) ; increment
; Compute start address: base + y*640 + x
(mul-int $15 $4 $1) ; $15 = y * 640
(add-int $15 $15 $3) ; $15 += x
(add-nat $15 $0 $15) ; $15 = base + pixel_offset
(mul-int $15 $13 $2) ; $15 = y * 640
(add-int $15 $15 $11) ; $15 += x
(add-nat $15 $21 $15) ; $15 = base + pixel_offset
(load-immediate $25 4)
(add-nat $15 $15 $25) ; need to add offset for fat pointer size
(add-nat $15 $15 $25) ; need to add offset for fat pointer size
(register-move $4 $15)
; Outer loop: height times
(load-immediate $30 1) ; increment
(register-move $5 $14) ; $5 = row counter
(label draw-box-outer
(add-int $27 $15 $5) ; $27 = row end = current + width
(register-move $29 $15) ; $7 = pixel pointer
(memset-8 $29 $2 $5) ; draw row
(add-int $15 $15 $1) ; next row (+= 640)
(sub-int $6 $6 $30) ; decrement row count
(jump-gt-int &draw-box-outer $6 0))
(return nil)))
(add-int $6 $4 $12) ; $6 = row end = current + width
(register-move $7 $4) ; $7 = pixel pointer
(memset-8 $7 $3 $12)
(add-int $4 $4 $2) ; next row (+= 640)
(sub-int $5 $5 $1) ; decrement row count
(jump-gt-int &draw-box-outer $5 0))
(return)))
(data
(label screen-namespace "/dev/screen/0")
(label mouse-namespace "/dev/mouse/0")
(label SELECTED-COLOR 255)
(label BLACK 0)
(label WHITE 255)
(label DARK-GRAY 73)
(label GRAY 146)
(label LIGHT-GRAY 182)))
(label BLACK 0)
(label WHITE 255)
(label DARK-GRAY 73)
(label GRAY 146)))

Binary file not shown.

View File

@ -1,118 +0,0 @@
/**
* Constants
*/
const byte BLACK = 0;
const byte WHITE = 255;
const byte DARK_GRAY = 73;
const byte GRAY = 146;
const byte LIGHT_GRAY = 182;
byte selected_color = 255;
interface Device {
nat handle;
}
plex Screen implements Device {
nat handle;
nat width;
nat height;
byte[] buffer;
draw() {
unsafe {
write(this, this.buffer, this.buffer_size);
}
}
}
plex Mouse implements Device {
nat handle;
nat x;
nat y;
bool left;
bool right;
bool middle;
bool btn4;
}
/**
* Main function
*/
function main() {
Screen screen = open("/dev/screen/0", 0);
Mouse mouse = open("/dev/mouse/0", 0);
outline_swatch(screen, BLACK, 1, 1);
outline_swatch(screen, WHITE, 21, 1);
screen.draw();
loop {
mouse.refresh();
if (!mouse.left) continue;
int box_size = 20;
int x = 1;
int y = 1;
byte color = BLACK;
outlined_swatch(screen, color, x, y);
set_color(box_size, x, y, mouse.x, mouse.y, color);
color = WHITE;
x = 21;
outlined_swatch(screen, color, x, y);
set_color(box_size, x, y, mouse.x, mouse.y, color);
screen.draw();
rectangle(screen, selected_color, x, y, 5, 5);
}
exit(0);
}
/**
* Checks if the click is within the bound and update the selected color if so.
*/
function set_color(int box_size, int bx, int by, int mx, int my, byte color) {
int right = bx + box_size;
int bottom = by + box_size;
if (mx < bx) return;
if (mx > right) return;
if (my < by) return;
if (my > bottom) return;
selected_color = color;
return;
}
/**
* Draw a color box with a grey outline, if selected use a darker color
*/
function outline_swatch(Device screen, byte color, int x, int y) {
byte bg_color = GRAY;
if (selected_color == color) {
bg_color = DARK_GRAY;
}
rectangle(screen, bg_color, x, y, 20, 20);
rectangle(screen, color, x + 2, y + 2, 17, 17);
return;
}
/**
* Draw a rectangle
*/
function rectangle(Device screen, byte color, int x, int y, int width, int height) {
// we need unsafe because we are using pointers `&` and `memset` directly
// unsafe takes the guardrails off and allows you to access/modify memory directly
unsafe {
int pixel = y * width + x + &screen.buffer + 4;
do (int i = height; i > 0; i--) {
int row = pixel + width;
memset(screen.buffer, row, color, width);
pixel += width;
}
}
return;
}

View File

@ -4,160 +4,269 @@
; use load immediate because it is a pointer to a string, not a value
(load-immediate $0 &screen-namespace)
(load-immediate $11 0)
(syscall OPEN $0 $0 $11) ; Screen screen = open(namespace, flags)
(syscall OPEN $0 $0 $11)
(load-offset-32 $20 $0 8) ; load width
(load-offset-32 $22 $0 12) ; load size
(load-immediate $1 16) ; pointer offset for screen buffer
(add-nat $21 $0 $1)
; open mouse
(load-immediate $16 &mouse-namespace)
(syscall OPEN $15 $16 $11) ; Mouse mouse = open(namespace, flags)
; outline_swatch(screen, BLACK, 1, 1);
(load-absolute-32 $1 &BLACK)
(load-immediate $12 1)
(load-immediate $13 1)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
; outline_swatch(screen, WHITE, 1, 1);
(load-absolute-32 $1 &WHITE)
(load-immediate $12 21)
(load-immediate $13 1)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(load-absolute-32 $1 &CHARCOAL)
(load-immediate $12 1)
(load-immediate $13 21)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(load-absolute-32 $1 &DARK-GRAY)
(load-immediate $12 21)
(load-immediate $13 21)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(load-absolute-32 $1 &RED)
(load-immediate $12 1)
(load-immediate $13 41)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(load-absolute-32 $1 &ORANGE)
(load-immediate $12 21)
(load-immediate $13 41)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(load-absolute-32 $1 &YELLOW)
(load-immediate $12 1)
(load-immediate $13 61)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(load-absolute-32 $1 &GREEN)
(load-immediate $12 21)
(load-immediate $13 61)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(load-absolute-32 $1 &BLUE)
(load-immediate $12 1)
(load-immediate $13 81)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(load-absolute-32 $1 &PURPLE)
(load-immediate $12 21)
(load-immediate $13 81)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
; screen.draw();
(load-immediate $16 1) ; device info call
(load-immediate $17 16) ; sizeof screen device info
(malloc $18 $17)
(syscall IOCTL $0 $16 $18)
(load-immediate $1 12) ; offset for width
(add-nat $19 $18 $1)
(get $20 $19) ; load width
(load-immediate $1 8) ; offset for size
(add-nat $19 $18 $1)
(get $22 $19) ; load size
(malloc $21 $22) ; malloc frame buffer
(syscall WRITE $0 $21 $22)
(load-immediate $16 &mouse-namespace)
(load-immediate $3 12) ; malloc sizeof mouse data
(malloc $4 $3)
(syscall OPEN $16 $16 $4)
(label draw-loop
; load mouse click data
(syscall REFRESH $15)
(load-offset-8 $9 $15 16) ; load btn1 pressed
(jump-eq-nat &draw-loop $9 $11)
(load-offset-32 $7 $15 8) ; load x
(load-offset-32 $8 $15 12) ; load y
(syscall READ $16 $2 $3 $4)
(load-immediate $5 4) ; offset for x
(add-nat $6 $5 $2)
(get $7 $6) ; load x
(load-immediate $5 8) ; offset for y
(add-nat $6 $5 $2)
(get $8 $6) ; load y
(load-immediate $5 12) ; offset for btn1
(add-nat $6 $5 $2)
(get-8 $9 $6) ; load btn1 pressed
(load-immediate $5 13) ; offset for btn2
(add-nat $6 $5 $2)
(get-8 $10 $6) ; load btn2 pressed
(load-immediate $14 20) ; box size
; outline_swatch(screen, BLACK, 1, 1);
(load-absolute-32 $1 &BLACK)
; first row
(push $21)
(push $20)
(load $1 &BLACK)
(push $1)
(load-immediate $12 1)
(push $12)
(load-immediate $13 1)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(syscall WRITE $0 $21 $22)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
; outline_swatch(screen, WHITE, 1, 1);
(load-absolute-32 $1 &WHITE)
(push $21)
(push $20)
(load $1 &WHITE)
(push $1)
(load-immediate $12 21)
(push $12)
(load-immediate $13 1)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(load-absolute-32 $1 &CHARCOAL)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
; row 2
(push $21)
(push $20)
(load $1 &CHARCOAL)
(push $1)
(load-immediate $12 1)
(push $12)
(load-immediate $13 21)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(load-absolute-32 $1 &DARK-GRAY)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
(push $21)
(push $20)
(load $1 &DARK-GRAY)
(push $1)
(load-immediate $12 21)
(push $12)
(load-immediate $13 21)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(load-absolute-32 $1 &RED)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
; row 3
(push $21)
(push $20)
(load $1 &RED)
(push $1)
(load-immediate $12 1)
(push $12)
(load-immediate $13 41)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(load-absolute-32 $1 &ORANGE)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
(push $21)
(push $20)
(load $1 &ORANGE)
(push $1)
(load-immediate $12 21)
(push $12)
(load-immediate $13 41)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(load-absolute-32 $1 &YELLOW)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
; row 3
(push $21)
(push $20)
(load $1 &YELLOW)
(push $1)
(load-immediate $12 1)
(push $12)
(load-immediate $13 61)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(load-absolute-32 $1 &GREEN)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
(push $21)
(push $20)
(load $1 &GREEN)
(push $1)
(load-immediate $12 21)
(push $12)
(load-immediate $13 61)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(load-absolute-32 $1 &BLUE)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
; row 4
(push $21)
(push $20)
(load $1 &BLUE)
(push $1)
(load-immediate $12 1)
(push $12)
(load-immediate $13 81)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(load-absolute-32 $1 &PURPLE)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
(push $21)
(push $20)
(load $1 &PURPLE)
(push $1)
(load-immediate $12 21)
(push $12)
(load-immediate $13 81)
(call &draw-outlined-swatch ($21 $1 $12 $13 $20) nil)
(call &set-color-if-clicked ($7 $8 $12 $13 $1 $14) nil)
(push $13)
(call &draw-outlined-swatch)
(push $14) ; box_size (20)
(push $13) ; box_y
(push $12) ; box_x
(push $8) ; click_y
(push $7) ; click_x
(push $1) ; color
(push $9) ; is btn1 clicked?
(call &set-color-if-clicked)
(syscall WRITE $0 $21 $22)
(load-absolute-32 $22 &SELECTED-COLOR) ; color
(jump-eq-nat &draw-loop $9 $11)
(load $22 &SELECTED-COLOR) ; color
(load-immediate $1 5) ; size of brush
(call &draw-box ($21 $20 $22 $7 $8 $1 $1) nil)
(push $21) ;base
(push $20) ;width
(push $22) ; color
(push $7) ;x
(push $8) ;y
(push $1)
(push $1)
(call &draw-box)
(jump &draw-loop))
(jump-eq-nat &draw-loop $10 $11))
; Flush and halt
(halt 0))
(halt))
(label set-color-if-clicked
; (click_x, click_y, box_x, box_y, color, box_size)
(label set-color-if-clicked
; Pop inputs from stack (in reverse order of pushing)
(pop $12) ; $12 = btn1 down?
(pop $11) ; $11 = color
(pop $0) ; $0 = click_x
(pop $1) ; $1 = click_y
(pop $2) ; $2 = box_x
(pop $3) ; $3 = box_y
(pop $5) ; $5 = box_size
; Compute right = box_x + box_size
(add-int $6 $2 $5) ; $6 = right edge
@ -165,68 +274,116 @@
; Compute bottom = box_y + box_size
(add-int $7 $3 $5) ; $7 = bottom edge
; Bounds check: x in [box_x, right] and y in [box_y, bottom]
(jump-lt-int &fail $0 $2)
(jump-gt-int &fail $0 $6)
(jump-lt-int &fail $1 $3)
(jump-gt-int &fail $1 $7)
; Check 1: click_x >= box_x ?
(jump-ge-int &check2 $0 $2)
(return)
(label check2)
; Check 2: click_x <= right ?
(jump-le-int &check3 $0 $6)
(return)
(label check3)
; Check 3: click_y >= box_y ?
(jump-ge-int &check4 $1 $3)
(return)
(label check4)
; Check 4: click_y <= bottom ?
(jump-le-int &check5 $1 $7)
(return)
(label check5) ; if it was selected then set the color
(load-immediate $13 1)
(jump-eq-int &set-color $12 $13)
(return)
(label set-color)
(load-immediate $10 &SELECTED-COLOR)
(store-absolute-8 $10 $4)
(label fail)
(return nil))
(store-8 $10 $11)
(return))
(label draw-outlined-swatch
; (base, color, x, y, width)
(pop $3) ; y
(pop $2) ; x
(pop $1) ; color
(pop $20)
(pop $21)
; Constants
(load-absolute-32 $5 &GRAY)
(load-absolute-32 $10 &SELECTED-COLOR)
(load $4 &GRAY)
(load $10 &SELECTED-COLOR)
(jump-eq-int &set-selected $10 $1)
(jump-eq-int &end-set-selected $5 $5)
(jump-eq-int &end-set-selected $4 $4)
(label set-selected)
(load-absolute-32 $5 &DARK-GRAY)
(load $4 &DARK-GRAY)
(label end-set-selected)
(load-immediate $6 20) ; outline size
(load-immediate $7 17) ; fill size
(load-immediate $8 2) ; offset
(load-immediate $5 20) ; outline size
(load-immediate $6 17) ; fill size
(load-immediate $7 2) ; offset
(call &draw-box ($0 $4 $5 $2 $3 $6 $6) nil)
(push $21) ; base
(push $20) ; width
(push $4) ; color (gray)
(push $2) ; x
(push $3) ; y
(push $5) ; width (20)
(push $5) ; height (20)
(call &draw-box)
(add-int $9 $2 $8) ; x + 2
(add-int $10 $3 $8) ; y + 2
(add-int $8 $2 $7) ; x + 2
(add-int $9 $3 $7) ; y + 2
(call &draw-box ($0 $4 $1 $9 $10 $7 $7) nil)
(push $21) ; base
(push $20) ; width
(push $1) ; color (original)
(push $8) ; x + 2
(push $9) ; y + 2
(push $6) ; width (17)
(push $6) ; height (17)
(call &draw-box)
(return nil))
(return))
; draw-box(color, x, y)
; Pops: y, x, color
(label draw-box
; (base, screen_width, color, x_start, y_start, width, height)
; Pop arguments (reverse order)
(pop $14) ; height
(pop $12) ; width
(pop $13) ; y_start
(pop $11) ; x_start
(pop $3) ; color
(pop $2) ; width
(pop $21) ; base
; Constants
(load-immediate $1 1) ; increment
; Compute start address: base + y*640 + x
(mul-int $15 $4 $1) ; $15 = y * 640
(add-int $15 $15 $3) ; $15 += x
(add-nat $15 $0 $15) ; $15 = base + pixel_offset
(mul-int $15 $13 $2) ; $15 = y * 640
(add-int $15 $15 $11) ; $15 += x
(add-nat $15 $21 $15) ; $15 = base + pixel_offset
(load-immediate $25 4)
(add-nat $15 $15 $25) ; need to add offset for fat pointer size
(add-nat $15 $15 $25) ; need to add offset for fat pointer size
(register-move $4 $15)
; Outer loop: height times
(load-immediate $30 1) ; increment
(register-move $5 $14) ; $5 = row counter
(label draw-box-outer
(add-int $27 $15 $5) ; $27 = row end = current + width
(register-move $29 $15) ; $7 = pixel pointer
(memset-8 $29 $2 $5) ; draw row
(add-int $15 $15 $1) ; next row (+= 640)
(sub-int $6 $6 $30) ; decrement row count
(jump-gt-int &draw-box-outer $6 0))
(return nil)))
(add-int $6 $4 $12) ; $6 = row end = current + width
(register-move $7 $4) ; $7 = pixel pointer
(memset-8 $7 $3 $12) ; draw row
(add-int $4 $4 $2) ; next row (+= 640)
(sub-int $5 $5 $1) ; decrement row count
(jump-gt-int &draw-box-outer $5 0))
(return)))
(data
(label screen-namespace "/dev/screen/0")
(label mouse-namespace "/dev/mouse/0")
(label SELECTED-COLOR 255)
(label mouse-namespace "/dev/mouse/0")
(label SELECTED-COLOR 255)
(label BLACK 0)
(label WHITE 255)
(label CHARCOAL 36)

Binary file not shown.

View File

@ -1,118 +0,0 @@
/**
* Constants
*/
const byte BLACK = 0;
const byte WHITE = 255;
const byte DARK_GRAY = 73;
const byte GRAY = 146;
const byte LIGHT_GRAY = 182;
byte selected_color = 255;
interface Device {
nat handle;
}
plex Screen implements Device {
nat handle;
nat width;
nat height;
byte[] buffer;
draw() {
unsafe {
write(this, this.buffer, this.buffer.length);
}
}
}
plex Mouse implements Device {
nat handle;
nat x;
nat y;
bool left;
bool right;
bool middle;
bool btn4;
}
/**
* Main function
*/
function main() {
Screen screen = open("/dev/screen/0", 0);
Mouse mouse = open("/dev/mouse/0", 0);
outline_swatch(screen, BLACK, 1, 1);
outline_swatch(screen, WHITE, 21, 1);
screen.draw();
loop {
mouse.refresh();
if (!mouse.left) continue;
int box_size = 20;
int x = 1;
int y = 1;
byte color = BLACK;
outlined_swatch(screen, color, x, y);
set_color(box_size, x, y, mouse.x, mouse.y, color);
color = WHITE;
x = 21;
outlined_swatch(screen, color, x, y);
set_color(box_size, x, y, mouse.x, mouse.y, color);
screen.draw();
rectangle(screen, selected_color, x, y, 5, 5);
}
exit(0);
}
/**
* Checks if the click is within the bound and update the selected color if so.
*/
function set_color(int box_size, int bx, int by, int mx, int my, byte color) {
int right = bx + box_size;
int bottom = by + box_size;
if (mx < bx) return;
if (mx > right) return;
if (my < by) return;
if (my > bottom) return;
selected_color = color;
return;
}
/**
* Draw a color box with a grey outline, if selected use a darker color
*/
function outline_swatch(Device screen, byte color, int x, int y) {
byte bg_color = GRAY;
if (selected_color == color) {
bg_color = DARK_GRAY;
}
rectangle(screen, bg_color, x, y, 20, 20);
rectangle(screen, color, x + 2, y + 2, 17, 17);
return;
}
/**
* Draw a rectangle
*/
function rectangle(Device screen, byte color, int x, int y, int width, int height) {
// we need unsafe because we are using pointers `.ptr` and `memset` directly
// unsafe takes the guardrails off and allows you to access/modify memory directly
unsafe {
int base = y * screen.width + x + screen.buffer.ptr + 4;
do (int i = height; i > 0; i--) {
int row = base + width;
memset(screen.buffer, row, color, width);
base += screen.width;
}
}
return;
}

View File

@ -1,21 +1,22 @@
((code
(label main
(load-absolute-32 $0 &x)
(load-absolute-32 $1 &y)
(label main
(load-immediate $0 &x)
(load-immediate $1 &y)
(add-real $2 $1 $0)
(real-to-string $3 $2)
(call &pln ($3) nil)
(halt 0))
(label pln
(load-immediate $1 &terminal-namespace) ; get terminal device
(load-immediate $11 0)
(syscall OPEN $1 $1 $11)
(load-immediate $3 &new-line)
(string-length $2 $0)
(syscall WRITE $1 $0 $2)
(string-length $4 $3)
(syscall WRITE $1 $3 $4)
(return nil)))
(push $3)
(call &pln)
(halt))
(label pln
(load-immediate $0 &terminal-namespace)
(syscall OPEN $0 $0 $0)
(load-immediate $3 &new-line)
(pop $1)
(string-length $2 $1)
(syscall WRITE $0 $1 $2)
(string-length $4 $3)
(syscall WRITE $0 $3 $4)
(return)))
(data (label terminal-namespace "/dev/term/0")
(label new-line "\n")
(label x 1.0)

Binary file not shown.

View File

@ -1,26 +0,0 @@
/**
* Constants
*/
const str nl = "\n";
const real x = 1.0;
const real y = 1.0;
plex Terminal {
nat handle;
}
/**
* Main function
*/
function main() {
pln((x + y).str);
}
/**
* Print with a newline
*/
function pln(str message) {
Terminal term = open("/dev/term/0", 0);
write(term, message, message.length);
write(term, nl, nl.length);
}

View File

@ -1,68 +1,76 @@
((code
(label main
; Open screen
; use load immediate because it is a pointer to a string, not a value
(load-immediate $18 &screen-namespace)
(syscall OPEN $0 $18 $11) ; open(out Plex screen, in namespace, in flags)
(load-immediate $0 &screen-namespace)
(load-immediate $11 0)
(syscall OPEN $0 $0 $11)
(load-immediate $32 &terminal-namespace)
(syscall OPEN $32 $32 $11)
(nat-to-string $5 $0)
(call &pln ($5) nil)
(load-immediate $16 1) ; device info call
(load-immediate $17 16) ; sizeof screen device info
(malloc $18 $17)
(syscall IOCTL $0 $16 $18)
(load-immediate $1 12) ; offset for width
(add-nat $19 $18 $1)
(get $20 $19) ; load width
(load-immediate $1 8) ; offset for size
(add-nat $19 $18 $1)
(get $22 $19) ; load size
(malloc $21 $22) ; malloc frame buffer
(syscall WRITE $0 $21 $22)
(load-offset-32 $20 $0 8) ; load width
(nat-to-string $5 $20)
(call &pln ($5) nil)
(load-offset-32 $22 $0 12) ; load size
(nat-to-string $5 $22)
(call &pln ($5) nil)
(load-immediate $1 16) ; offset for screen buffer
(add-nat $21 $0 $1)
(nat-to-string $5 $21)
(call &pln ($5) nil)
; open mouse
(load-immediate $16 &mouse-namespace)
(syscall OPEN $15 $16 $11) ; open(out Plex mouse, in namespace, in flags)
(load-immediate $3 12) ; malloc sizeof mouse data
(malloc $4 $3)
(syscall OPEN $16 $16 $4)
(syscall WRITE $0 $21 $22) ; redraw
(nat-to-string $5 $4)
(push $32)
(push $5)
(call &pln)
(label draw-loop
; load mouse click data
(syscall REFRESH $15)
(load-offset-8 $9 $15 16) ; load btn1 pressed
(syscall READ $16 $2 $3 $4)
(load-immediate $5 12) ; offset for btn1
(add-nat $6 $5 $2)
(get-8 $9 $6) ; load btn1 pressed
(jump-eq-nat &draw-loop $9 $11)
(load-offset-32 $7 $15 8) ; load x
(load-offset-32 $8 $15 12) ; load y
(load-immediate $5 4) ; offset for x
(add-nat $6 $5 $2)
(get $7 $6) ; load x
(load-immediate $5 8) ; offset for y
(add-nat $6 $5 $2)
(get $8 $6) ; load y
; Compute start address: y*width + x
(mul-nat $30 $8 $20) ; $15 = y * width
(add-nat $30 $30 $7) ; $15 += x
(add-nat $30 $30 $21) ; $15 += pixel_offset
(mul-nat $15 $8 $20) ; $15 = y * width
(add-nat $15 $15 $7) ; $15 += x
(add-nat $15 $21 $15) ; $15 = base + pixel_offset
(load-immediate $1 4) ; need to add offset for fat pointer size
(add-nat $30 $30 $1)
(add-nat $15 $15 $1)
(load-absolute-32 $3 &WHITE) ; color
(store-absolute-8 $30 $3) ; draw color at screen [x,y]
(load $3 &WHITE) ; color
(store-8 $15 $3) ; draw color at screen [x,y]
(syscall WRITE $0 $21 $22) ; redraw
(jump &draw-loop))
(halt 0))
(label pln
(load-immediate $1 &terminal-namespace) ; get terminal device
(load-immediate $11 0)
(syscall OPEN $1 $1 $11)
(load-immediate $3 &new-line)
(string-length $2 $0)
(syscall WRITE $1 $0 $2)
(string-length $4 $3)
(syscall WRITE $1 $3 $4)
(return nil)))
(load-immediate $5 13) ; offset for btn2
(add-nat $6 $5 $2)
(get-8 $10 $6) ; load btn2 pressed
(jump-eq-nat &draw-loop $10 $11))
(halt))
(label pln
(load-immediate $3 &new-line)
(pop $1)
(pop $0)
(string-length $2 $1)
(syscall WRITE $0 $1 $2)
(string-length $4 $3)
(syscall WRITE $0 $3 $4)
(return)))
(data
(label screen-namespace "/dev/screen/0")
(label mouse-namespace "/dev/mouse/0")

Binary file not shown.

View File

@ -1,69 +0,0 @@
/**
* Constants
*/
const str nl = "\n";
const nat WHITE = 255;
/**
* Devices
*/
plex Terminal {
nat handle;
}
plex Screen {
nat handle;
nat width;
nat height;
byte[] buffer;
draw() {
write(this, this.buffer, this.buffer_size);
}
}
plex Mouse {
nat handle;
nat x;
nat y;
bool left;
bool right;
bool middle;
bool btn4;
nat size;
}
/**
* Main function
*/
function main() {
Screen screen = open("/dev/screen/0", 0);
pln(screen.handle.str);
pln(screen.width.str);
pln(screen.size.str);
unsafe {
pln(screen.screen_buffer.ptr.str);
}
Mouse mouse = open("/dev/mouse/0", 0);
screen.draw();
loop {
if (mouse.btn1) {
unsafe {
screen.buffer[mouse.y * width + mouse.x +
screen.buffer.ptr + 4] = WHITE;
screen.draw();
}
}
}
}
/**
* Print with a newline
*/
function pln(str message) {
Terminal term = open("/dev/term/0", 0);
write(term, message, message.length);
write(term, nl, nl.length);
}