Code cleanup, add halt return type, add neg and abs ops, fix strings,
This commit is contained in:
parent
feaebcec1d
commit
739c3638a6
2
Makefile
2
Makefile
|
|
@ -80,7 +80,7 @@ endif
|
||||||
VM_SOURCES := \
|
VM_SOURCES := \
|
||||||
$(SRC_DIR)/vm/vm.c \
|
$(SRC_DIR)/vm/vm.c \
|
||||||
$(SRC_DIR)/vm/device.c \
|
$(SRC_DIR)/vm/device.c \
|
||||||
$(SRC_DIR)/vm/str.c
|
$(SRC_DIR)/vm/libc.c
|
||||||
|
|
||||||
ifeq ($(BUILD_MODE), release)
|
ifeq ($(BUILD_MODE), release)
|
||||||
PLATFORM_SOURCE := $(ARCH_DIR)/main.c \
|
PLATFORM_SOURCE := $(ARCH_DIR)/main.c \
|
||||||
|
|
|
||||||
32
README.org
32
README.org
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
* Undâr
|
* Undâr
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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 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.
|
||||||
|
|
||||||
|
|
@ -66,11 +66,10 @@ The Undâr compiler will be written in Sċieppan, as well as core VM tests.
|
||||||
(load-immediate $11 0)
|
(load-immediate $11 0)
|
||||||
(syscall OPEN $1 $1 $11)
|
(syscall OPEN $1 $1 $11)
|
||||||
(load-immediate $3 &new-line)
|
(load-immediate $3 &new-line)
|
||||||
(load-offset-32 $7 $1 4) ; load handle
|
|
||||||
(string-length $2 $0)
|
(string-length $2 $0)
|
||||||
(syscall WRITE $7 $0 $2)
|
(syscall WRITE $1 $0 $2)
|
||||||
(string-length $4 $3)
|
(string-length $4 $3)
|
||||||
(syscall WRITE $7 $3 $4)
|
(syscall WRITE $1 $3 $4)
|
||||||
(return nil)))
|
(return nil)))
|
||||||
(data
|
(data
|
||||||
(label terminal-namespace "/dev/term/0")
|
(label terminal-namespace "/dev/term/0")
|
||||||
|
|
@ -102,18 +101,16 @@ heap allocations using the internal malloc opcode push pointers within this fram
|
||||||
|
|
||||||
(load-immediate $1 32) ; read in a string of max 32 char length
|
(load-immediate $1 32) ; read in a string of max 32 char length
|
||||||
(malloc $4 $1) ; allocate memory for the string
|
(malloc $4 $1) ; allocate memory for the string
|
||||||
(load-offset-32 $7 $0 4) ; load handle
|
(syscall READ $0 $4 $1) ; read the string
|
||||||
(syscall READ $7 $2 $1 $4) ; read the string
|
|
||||||
|
|
||||||
(call &pln ($0 $4) nil) ; print the string
|
(call &pln ($0 $4) nil) ; print the string
|
||||||
(halt))
|
(halt))
|
||||||
(label pln
|
(label pln
|
||||||
(load-immediate $3 &new-line)
|
(load-immediate $3 &new-line)
|
||||||
(load-offset-32 $7 $0 4) ; load handle
|
|
||||||
(string-length $2 $1)
|
(string-length $2 $1)
|
||||||
(syscall WRITE $7 $1 $2)
|
(syscall WRITE $0 $1 $2)
|
||||||
(string-length $4 $3)
|
(string-length $4 $3)
|
||||||
(syscall WRITE $7 $3 $4)
|
(syscall WRITE $0 $3 $4)
|
||||||
(return nil)))
|
(return nil)))
|
||||||
(data
|
(data
|
||||||
(label terminal-namespace "/dev/term/0")
|
(label terminal-namespace "/dev/term/0")
|
||||||
|
|
@ -125,15 +122,14 @@ values passed to functions must be explicitly returned to propagate. heap values
|
||||||
|
|
||||||
**Core Types**
|
**Core Types**
|
||||||
|
|
||||||
| Type | Description |
|
| Type | Description |
|
||||||
|--------+-------------------------------------------|
|
|------+------------------------------------|
|
||||||
| =int= | 32-bit signed integer |
|
| =int= | 32-bit signed integer |
|
||||||
| =nat= | 32-bit natural number |
|
| =nat= | 32-bit natural number |
|
||||||
| =real= | Q16.16 fixed-point real number |
|
| =real= | Q16.16 fixed-point real number |
|
||||||
| =str= | fat pointer [length + data] string |
|
| =str= | fat pointer [length + data] string |
|
||||||
| =bool= | true/false |
|
| =bool= | true/false |
|
||||||
| =char= | Character |
|
| =byte= | Character/8 bit unsigned int |
|
||||||
| =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.
|
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.
|
||||||
|
|
||||||
|
|
|
||||||
256
ROADMAP.org
256
ROADMAP.org
|
|
@ -10,57 +10,34 @@
|
||||||
|
|
||||||
* Roadmap
|
* Roadmap
|
||||||
|
|
||||||
** Actor System
|
|
||||||
|
|
||||||
* Actor-Based Concurrency Model (Frame-Managed Memory)
|
|
||||||
|
|
||||||
** 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
|
|
||||||
- Mission-critical certified (DO-178C Level A compliant)
|
|
||||||
|
|
||||||
** 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 |
|
|
||||||
|
|
||||||
** Example: Hello world (=hello.ul=)
|
** Example: Hello world (=hello.ul=)
|
||||||
|
|
||||||
*WIP syntax, not final implementation**
|
*WIP syntax, not final implementation**
|
||||||
|
|
||||||
#+BEGIN_SRC ul
|
#+BEGIN_SRC ul
|
||||||
fn main(int argc, str[] argv) {
|
/**
|
||||||
print("nuqneH 'u'?");
|
* 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);
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
|
@ -68,42 +45,161 @@ fn main(int argc, str[] argv) {
|
||||||
|
|
||||||
**WIP syntax, not final implementation**
|
**WIP syntax, not final implementation**
|
||||||
|
|
||||||
#+BEGIN_SRC ul
|
Common:
|
||||||
use "common.ul";
|
|
||||||
|
|
||||||
fn256 main(int argc, str[] argv) {
|
#+BEGIN_SRC ul
|
||||||
nat w = 800, h = 450;
|
/**
|
||||||
Player me(argv[1], [0.0, 1.0, 2.0], PURPLE);
|
* Camera.
|
||||||
|
*/
|
||||||
|
plex Camera {
|
||||||
|
int setting;
|
||||||
|
real pov;
|
||||||
|
real[3] up;
|
||||||
|
real[3] pos;
|
||||||
|
real[3] look;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
bool running = true;
|
bool running = true;
|
||||||
while (running) {
|
while (running) {
|
||||||
window("Client", w, h) {
|
window("zwl client", screen_width, screen_height) {
|
||||||
splitbox(parent.size, 0.25) {
|
splitbox(parent.size 0.25) {
|
||||||
canvas() {
|
canvas() {
|
||||||
if (button("Logout")) {
|
if (button("logout")) {
|
||||||
me.logout();
|
me.logout();
|
||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
splitbox(parent.size, 0.75) {
|
splitbox(parent.size 0.75) {
|
||||||
canvas() {
|
canvas() {
|
||||||
model(Floor([0, 0, 0], 30));
|
model(Floor([0, 0, 0], 30));
|
||||||
me.update();
|
me.update();
|
||||||
model(Cube(me.pos, [0.5,0.5,0.5], me.color));
|
model(Cube(me.pos, [0.5, 0.5, 0.5], me.appearance));
|
||||||
if (Player[] others = me.server.read("players")) {
|
if (Player[] players = me.server.read("players")) {
|
||||||
for (p in others) {
|
for (p in players) {
|
||||||
model(Cube(p.pos, [0.5,0.5,0.5], p.color));
|
model(Cube(p.pos, [0.5, 0.5, 0.5], p.apperance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exits("Client Closed Successfully");
|
exits("Client Closed Successfully");
|
||||||
}
|
}
|
||||||
#+END_SRC
|
#+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
|
** 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".
|
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".
|
||||||
|
|
@ -194,3 +290,45 @@ if (server.attach(auth)) {
|
||||||
| =.clunk()= | Close communication |
|
| =.clunk()= | Close communication |
|
||||||
| =.stat()= | returns the status of the file resource |
|
| =.stat()= | returns the status of the file resource |
|
||||||
| =.version()= | returns the version code for the connected tunnel |
|
| =.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
|
||||||
|
- Mission-critical certified (DO-178C Level A compliant)
|
||||||
|
|
||||||
|
*** 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 |
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
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);
|
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
/**
|
|
||||||
* Note that these look like classes but act like structs
|
|
||||||
* the methods actually have a implied struct as their first argument
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Camera.
|
|
||||||
*/
|
|
||||||
plex Camera {
|
|
||||||
int setting;
|
|
||||||
real pov;
|
|
||||||
real[3] up;
|
|
||||||
real[3] pos;
|
|
||||||
real[3] look;
|
|
||||||
|
|
||||||
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]);
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
@ -26,16 +26,13 @@ typedef struct mouse_device_data_s {
|
||||||
u8 btn2;
|
u8 btn2;
|
||||||
u8 btn3;
|
u8 btn3;
|
||||||
u8 btn4;
|
u8 btn4;
|
||||||
u32 size;
|
|
||||||
} MouseDeviceData;
|
} MouseDeviceData;
|
||||||
|
|
||||||
/* Keyboard device data */
|
/* Keyboard device data */
|
||||||
typedef struct keyboard_device_data_s {
|
typedef struct keyboard_device_data_s {
|
||||||
u32 handle;
|
u32 handle;
|
||||||
const u8 *keys;
|
|
||||||
i32 key_count;
|
i32 key_count;
|
||||||
u32 pos;
|
const u8 *keys;
|
||||||
u32 size;
|
|
||||||
} KeyboardDeviceData;
|
} KeyboardDeviceData;
|
||||||
|
|
||||||
/* Console device data */
|
/* Console device data */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include "../../tools/assembler.h"
|
#include "../../tools/assembler.h"
|
||||||
#include "../../tools/parser.h"
|
|
||||||
#include "../../tools/lexer.h"
|
#include "../../tools/lexer.h"
|
||||||
|
#include "../../tools/parser.h"
|
||||||
#include "../../vm/vm.h"
|
#include "../../vm/vm.h"
|
||||||
#include "devices.h"
|
#include "devices.h"
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
|
|
@ -32,14 +32,12 @@ static DeviceOps keyboard_ops = {.open = keyboard_open,
|
||||||
.ioctl = nil,
|
.ioctl = nil,
|
||||||
.refresh = nil};
|
.refresh = nil};
|
||||||
|
|
||||||
static DeviceOps console_device_ops = {
|
static DeviceOps console_device_ops = {.open = console_open,
|
||||||
.open = console_open,
|
.read = console_read,
|
||||||
.read = console_read,
|
.write = console_write,
|
||||||
.write = console_write,
|
.close = console_close,
|
||||||
.close = console_close,
|
.ioctl = console_ioctl,
|
||||||
.ioctl = console_ioctl,
|
.refresh = nil};
|
||||||
.refresh = nil
|
|
||||||
};
|
|
||||||
|
|
||||||
static ScreenDeviceData screen_data = {0};
|
static ScreenDeviceData screen_data = {0};
|
||||||
static MouseDeviceData mouse_data = {0};
|
static MouseDeviceData mouse_data = {0};
|
||||||
|
|
@ -156,11 +154,8 @@ bool compileAndSave(const char *source_file, const char *output_file, VM *vm) {
|
||||||
break; // Stop on error, or continue if you want to see more
|
break; // Stop on error, or continue if you want to see more
|
||||||
}
|
}
|
||||||
if (token.type != TOKEN_EOF) {
|
if (token.type != TOKEN_EOF) {
|
||||||
printf("Line %d [%s]: %.*s\n",
|
printf("Line %d [%s]: %.*s\n", token.line, tokenTypeToString(token.type),
|
||||||
token.line,
|
token.length, token.start);
|
||||||
tokenTypeToString(token.type),
|
|
||||||
token.length,
|
|
||||||
token.start);
|
|
||||||
}
|
}
|
||||||
} while (token.type != TOKEN_EOF);
|
} while (token.type != TOKEN_EOF);
|
||||||
|
|
||||||
|
|
@ -278,137 +273,137 @@ void repl(VM *vm) {
|
||||||
}
|
}
|
||||||
// If unbalanced, continue reading more lines
|
// If unbalanced, continue reading more lines
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(vm->flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ASM_DEBUG
|
#ifdef ASM_DEBUG
|
||||||
const char *opcode_to_string(Opcode op) {
|
const char *opcode_to_string(Opcode op) {
|
||||||
static const char *names[] = {
|
static const char *names[] = {
|
||||||
[OP_HALT] = "halt",
|
[OP_HALT] = "halt",
|
||||||
[OP_JMP] = "jump",
|
[OP_JMP] = "jump",
|
||||||
[OP_JMPF] = "jump-if-flag",
|
[OP_JMPF] = "jump-if-flag",
|
||||||
[OP_CALL] = "call",
|
[OP_CALL] = "call",
|
||||||
[OP_RETURN] = "return",
|
[OP_RETURN] = "return",
|
||||||
|
|
||||||
/* Immediate loads (only 32-bit variant needed) */
|
/* Immediate loads (only 32-bit variant needed) */
|
||||||
[OP_LOAD_IMM] = "load-immediate",
|
[OP_LOAD_IMM] = "load-immediate",
|
||||||
|
|
||||||
/* Register-indirect loads */
|
/* Register-indirect loads */
|
||||||
[OP_LOAD_IND_8] = "load-indirect-8",
|
[OP_LOAD_IND_8] = "load-indirect-8",
|
||||||
[OP_LOAD_IND_16] = "load-indirect-16",
|
[OP_LOAD_IND_16] = "load-indirect-16",
|
||||||
[OP_LOAD_IND_32] = "load-indirect-32",
|
[OP_LOAD_IND_32] = "load-indirect-32",
|
||||||
|
|
||||||
/* Absolute address loads */
|
/* Absolute address loads */
|
||||||
[OP_LOAD_ABS_8] = "load-absolute-8",
|
[OP_LOAD_ABS_8] = "load-absolute-8",
|
||||||
[OP_LOAD_ABS_16] = "load-absolute-16",
|
[OP_LOAD_ABS_16] = "load-absolute-16",
|
||||||
[OP_LOAD_ABS_32] = "load-absolute-32",
|
[OP_LOAD_ABS_32] = "load-absolute-32",
|
||||||
|
|
||||||
/* Base+offset loads */
|
/* Base+offset loads */
|
||||||
[OP_LOAD_OFF_8] = "load-offset-8",
|
[OP_LOAD_OFF_8] = "load-offset-8",
|
||||||
[OP_LOAD_OFF_16] = "load-offset-16",
|
[OP_LOAD_OFF_16] = "load-offset-16",
|
||||||
[OP_LOAD_OFF_32] = "load-offset-32",
|
[OP_LOAD_OFF_32] = "load-offset-32",
|
||||||
|
|
||||||
/* Absolute address stores */
|
/* Absolute address stores */
|
||||||
[OP_STORE_ABS_8] = "store-absolute-8",
|
[OP_STORE_ABS_8] = "store-absolute-8",
|
||||||
[OP_STORE_ABS_16] = "store-absolute-16",
|
[OP_STORE_ABS_16] = "store-absolute-16",
|
||||||
[OP_STORE_ABS_32] = "store-absolute-32",
|
[OP_STORE_ABS_32] = "store-absolute-32",
|
||||||
|
|
||||||
/* Register-indirect stores */
|
/* Register-indirect stores */
|
||||||
[OP_STORE_IND_8] = "store-indirect-8",
|
[OP_STORE_IND_8] = "store-indirect-8",
|
||||||
[OP_STORE_IND_16] = "store-indirect-16",
|
[OP_STORE_IND_16] = "store-indirect-16",
|
||||||
[OP_STORE_IND_32] = "store-indirect-32",
|
[OP_STORE_IND_32] = "store-indirect-32",
|
||||||
|
|
||||||
/* Base+offset stores */
|
/* Base+offset stores */
|
||||||
[OP_STORE_OFF_8] = "store-offset-8",
|
[OP_STORE_OFF_8] = "store-offset-8",
|
||||||
[OP_STORE_OFF_16] = "store-offset-16",
|
[OP_STORE_OFF_16] = "store-offset-16",
|
||||||
[OP_STORE_OFF_32] = "store-offset-32",
|
[OP_STORE_OFF_32] = "store-offset-32",
|
||||||
|
|
||||||
/* Memory operations */
|
/* Memory operations */
|
||||||
[OP_MALLOC] = "malloc",
|
[OP_MALLOC] = "malloc",
|
||||||
[OP_MEMSET_8] = "memset-8",
|
[OP_MEMSET_8] = "memset-8",
|
||||||
[OP_MEMSET_16] = "memset-16",
|
[OP_MEMSET_16] = "memset-16",
|
||||||
[OP_MEMSET_32] = "memset-32",
|
[OP_MEMSET_32] = "memset-32",
|
||||||
|
|
||||||
/* Stack operations */
|
/* Register operations */
|
||||||
[OP_PUSH] = "push",
|
[OP_REG_MOV] = "register-move",
|
||||||
[OP_POP] = "pop",
|
[OP_SYSCALL] = "syscall",
|
||||||
|
|
||||||
/* Register operations */
|
/* Bit operations */
|
||||||
[OP_REG_MOV] = "register-move",
|
[OP_BIT_SHIFT_LEFT] = "bit-shift-left",
|
||||||
[OP_SYSCALL] = "syscall",
|
[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",
|
||||||
|
|
||||||
/* Bit operations */
|
/* Integer arithmetic */
|
||||||
[OP_SLL] = "bit-shift-left",
|
[OP_ADD_INT] = "add-int",
|
||||||
[OP_SRL] = "bit-shift-right",
|
[OP_SUB_INT] = "sub-int",
|
||||||
[OP_SRE] = "bit-shift-re",
|
[OP_MUL_INT] = "mul-int",
|
||||||
[OP_BAND] = "bit-and",
|
[OP_DIV_INT] = "div-int",
|
||||||
[OP_BOR] = "bit-or",
|
[OP_ABS_INT] = "abs-int", // ← NEW
|
||||||
[OP_BXOR] = "bit-xor",
|
[OP_NEG_INT] = "neg-int", // ← NEW
|
||||||
|
|
||||||
/* Integer arithmetic */
|
/* Natural number arithmetic */
|
||||||
[OP_ADD_INT] = "add-int",
|
[OP_ADD_NAT] = "add-nat",
|
||||||
[OP_SUB_INT] = "sub-int",
|
[OP_SUB_NAT] = "sub-nat",
|
||||||
[OP_MUL_INT] = "mul-int",
|
[OP_MUL_NAT] = "mul-nat",
|
||||||
[OP_DIV_INT] = "div-int",
|
[OP_DIV_NAT] = "div-nat",
|
||||||
|
[OP_ABS_NAT] = "abs-nat", // ← NEW
|
||||||
|
[OP_NEG_NAT] = "neg-nat", // ← NEW
|
||||||
|
|
||||||
/* Natural number arithmetic */
|
/* Floating point operations */
|
||||||
[OP_ADD_NAT] = "add-nat",
|
[OP_ADD_REAL] = "add-real",
|
||||||
[OP_SUB_NAT] = "sub-nat",
|
[OP_SUB_REAL] = "sub-real",
|
||||||
[OP_MUL_NAT] = "mul-nat",
|
[OP_MUL_REAL] = "mul-real",
|
||||||
[OP_DIV_NAT] = "div-nat",
|
[OP_DIV_REAL] = "div-real",
|
||||||
|
[OP_ABS_REAL] = "abs-real", // ← NEW
|
||||||
|
[OP_NEG_REAL] = "neg-real", // ← NEW
|
||||||
|
|
||||||
/* Floating point operations */
|
/* Type conversions */
|
||||||
[OP_ADD_REAL] = "add-real",
|
[OP_INT_TO_REAL] = "int-to-real",
|
||||||
[OP_SUB_REAL] = "sub-real",
|
[OP_NAT_TO_REAL] = "nat-to-real",
|
||||||
[OP_MUL_REAL] = "mul-real",
|
[OP_REAL_TO_INT] = "real-to-int",
|
||||||
[OP_DIV_REAL] = "div-real",
|
[OP_REAL_TO_NAT] = "real-to-nat",
|
||||||
|
|
||||||
/* Type conversions */
|
/* Integer comparisons */
|
||||||
[OP_INT_TO_REAL] = "int-to-real",
|
[OP_JEQ_INT] = "jump-eq-int",
|
||||||
[OP_NAT_TO_REAL] = "nat-to-real",
|
[OP_JNEQ_INT] = "jump-neq-int",
|
||||||
[OP_REAL_TO_INT] = "real-to-int",
|
[OP_JGT_INT] = "jump-gt-int",
|
||||||
[OP_REAL_TO_NAT] = "real-to-nat",
|
[OP_JLT_INT] = "jump-lt-int",
|
||||||
|
[OP_JLE_INT] = "jump-le-int",
|
||||||
|
[OP_JGE_INT] = "jump-ge-int",
|
||||||
|
|
||||||
/* Integer comparisons */
|
/* Natural number comparisons */
|
||||||
[OP_JEQ_INT] = "jump-eq-int",
|
[OP_JEQ_NAT] = "jump-eq-nat",
|
||||||
[OP_JNEQ_INT] = "jump-neq-int",
|
[OP_JNEQ_NAT] = "jump-neq-nat",
|
||||||
[OP_JGT_INT] = "jump-gt-int",
|
[OP_JGT_NAT] = "jump-gt-nat",
|
||||||
[OP_JLT_INT] = "jump-lt-int",
|
[OP_JLT_NAT] = "jump-lt-nat",
|
||||||
[OP_JLE_INT] = "jump-le-int",
|
[OP_JLE_NAT] = "jump-le-nat",
|
||||||
[OP_JGE_INT] = "jump-ge-int",
|
[OP_JGE_NAT] = "jump-ge-nat",
|
||||||
|
|
||||||
/* Natural number comparisons */
|
/* Floating point comparisons */
|
||||||
[OP_JEQ_NAT] = "jump-eq-nat",
|
[OP_JEQ_REAL] = "jump-eq-real",
|
||||||
[OP_JNEQ_NAT] = "jump-neq-nat",
|
[OP_JNEQ_REAL] = "jump-neq-real",
|
||||||
[OP_JGT_NAT] = "jump-gt-nat",
|
[OP_JGE_REAL] = "jump-ge-real",
|
||||||
[OP_JLT_NAT] = "jump-lt-nat",
|
[OP_JGT_REAL] = "jump-gt-real",
|
||||||
[OP_JLE_NAT] = "jump-le-nat",
|
[OP_JLT_REAL] = "jump-lt-real",
|
||||||
[OP_JGE_NAT] = "jump-ge-nat",
|
[OP_JLE_REAL] = "jump-le-real",
|
||||||
|
|
||||||
/* Floating point comparisons */
|
/* String operations */
|
||||||
[OP_JEQ_REAL] = "jump-eq-real",
|
[OP_STRLEN] = "string-length",
|
||||||
[OP_JNEQ_REAL] = "jump-neq-real",
|
[OP_STREQ] = "string-eq",
|
||||||
[OP_JGE_REAL] = "jump-ge-real",
|
[OP_STRCAT] = "string-concat",
|
||||||
[OP_JGT_REAL] = "jump-gt-real",
|
[OP_STR_GET_CHAR] = "string-get-char",
|
||||||
[OP_JLT_REAL] = "jump-lt-real",
|
[OP_STR_FIND_CHAR] = "string-find-char",
|
||||||
[OP_JLE_REAL] = "jump-le-real",
|
[OP_STR_SLICE] = "string-slice",
|
||||||
|
|
||||||
/* String operations */
|
/* String conversions */
|
||||||
[OP_STRLEN] = "string-length",
|
[OP_INT_TO_STRING] = "int-to-string",
|
||||||
[OP_STREQ] = "string-eq",
|
[OP_NAT_TO_STRING] = "nat-to-string",
|
||||||
[OP_STRCAT] = "string-concat",
|
[OP_REAL_TO_STRING] = "real-to-string",
|
||||||
[OP_STR_GET_CHAR] = "string-get-char",
|
[OP_STRING_TO_INT] = "string-to-int",
|
||||||
[OP_STR_FIND_CHAR] = "string-find-char",
|
[OP_STRING_TO_NAT] = "string-to-nat",
|
||||||
[OP_STR_SLICE] = "string-slice",
|
[OP_STRING_TO_REAL] = "string-to-real"};
|
||||||
|
|
||||||
/* 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"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) {
|
if (op < 0 || op >= (int)(sizeof(names) / sizeof(names[0]))) {
|
||||||
return "<invalid-opcode>";
|
return "<invalid-opcode>";
|
||||||
|
|
@ -420,7 +415,6 @@ const char *opcode_to_string(Opcode op) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
i32 main(i32 argc, char *argv[]) {
|
i32 main(i32 argc, char *argv[]) {
|
||||||
bool gui_mode = false;
|
|
||||||
bool dump_rom = false;
|
bool dump_rom = false;
|
||||||
char *input_file = nil;
|
char *input_file = nil;
|
||||||
char *output_file = nil;
|
char *output_file = nil;
|
||||||
|
|
@ -429,10 +423,7 @@ i32 main(i32 argc, char *argv[]) {
|
||||||
|
|
||||||
// Parse command line arguments
|
// Parse command line arguments
|
||||||
for (i32 i = 1; i < argc; i++) {
|
for (i32 i = 1; i < argc; i++) {
|
||||||
if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "--gui") == 0) {
|
if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--dump-rom") == 0) {
|
||||||
gui_mode = true;
|
|
||||||
} else if (strcmp(argv[i], "-o") == 0 ||
|
|
||||||
strcmp(argv[i], "--dump-rom") == 0) {
|
|
||||||
dump_rom = true;
|
dump_rom = true;
|
||||||
} else if (input_file == nil) {
|
} else if (input_file == nil) {
|
||||||
// This is the input file
|
// This is the input file
|
||||||
|
|
@ -496,145 +487,135 @@ i32 main(i32 argc, char *argv[]) {
|
||||||
vm_register_device(&vm, "/dev/term/0", "terminal", &console_data,
|
vm_register_device(&vm, "/dev/term/0", "terminal", &console_data,
|
||||||
&console_device_ops, 4);
|
&console_device_ops, 4);
|
||||||
|
|
||||||
if (gui_mode) {
|
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
printf("SDL initialization failed: %s\n", SDL_GetError());
|
||||||
printf("SDL initialization failed: %s\n", SDL_GetError());
|
return 1;
|
||||||
return 1;
|
}
|
||||||
}
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
|
||||||
|
|
||||||
screen_data.width = 640;
|
screen_data.width = 640;
|
||||||
screen_data.height = 480;
|
screen_data.height = 480;
|
||||||
screen_data.buffer_size = screen_data.width * screen_data.height;
|
screen_data.buffer_size = screen_data.width * screen_data.height;
|
||||||
|
|
||||||
vm_register_device(&vm, "/dev/screen/0", "screen", &screen_data,
|
vm_register_device(&vm, "/dev/screen/0", "screen", &screen_data, &screen_ops,
|
||||||
&screen_ops, 16 + screen_data.buffer_size);
|
16 + screen_data.buffer_size);
|
||||||
|
|
||||||
mouse_data.x = 0;
|
mouse_data.x = 0;
|
||||||
mouse_data.y = 0;
|
mouse_data.y = 0;
|
||||||
mouse_data.btn1 = 0;
|
mouse_data.btn1 = 0;
|
||||||
mouse_data.btn2 = 0;
|
mouse_data.btn2 = 0;
|
||||||
mouse_data.btn3 = 0;
|
mouse_data.btn3 = 0;
|
||||||
mouse_data.btn4 = 0;
|
mouse_data.btn4 = 0;
|
||||||
mouse_data.size = 16;
|
|
||||||
|
|
||||||
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);
|
||||||
mouse_data.size);
|
|
||||||
|
|
||||||
keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count);
|
keyboard_data.keys = SDL_GetKeyboardState(&keyboard_data.key_count);
|
||||||
vm_register_device(&vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
|
vm_register_device(&vm, "/dev/keyboard/0", "keyboard", &keyboard_data,
|
||||||
&keyboard_ops, keyboard_data.key_count + 4);
|
&keyboard_ops, keyboard_data.key_count + 4);
|
||||||
|
|
||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
bool running = true;
|
bool running = true;
|
||||||
SDL_PumpEvents();
|
SDL_PumpEvents();
|
||||||
while (running) {
|
while (running) {
|
||||||
while (SDL_PollEvent(&event)) {
|
while (SDL_PollEvent(&event)) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case SDL_QUIT:
|
case SDL_QUIT:
|
||||||
running = false;
|
running = false;
|
||||||
break;
|
break;
|
||||||
// Mouse events
|
// Mouse events
|
||||||
case SDL_MOUSEMOTION:
|
case SDL_MOUSEMOTION:
|
||||||
mouse_data.x = event.motion.x;
|
mouse_data.x = event.motion.x;
|
||||||
mouse_data.y = event.motion.y;
|
mouse_data.y = event.motion.y;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_MOUSEBUTTONDOWN:
|
case SDL_MOUSEBUTTONDOWN:
|
||||||
if (event.button.button == SDL_BUTTON_LEFT)
|
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;
|
mouse_data.btn1 = 1;
|
||||||
if (event.button.button == SDL_BUTTON_RIGHT)
|
} else if (event.type == SDL_FINGERUP) {
|
||||||
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;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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;
|
// Run VM for a fixed number of cycles or a time slice
|
||||||
while (running) {
|
int cycles_this_frame = 0;
|
||||||
running = step_vm(&vm);
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return vm.flag;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,17 +66,18 @@ u32 find_label_in_table(SymbolTable *table, const char *name) {
|
||||||
int get_instruction_byte_size(ExprNode *node) {
|
int get_instruction_byte_size(ExprNode *node) {
|
||||||
const char *opname = node->token;
|
const char *opname = node->token;
|
||||||
|
|
||||||
// Simple opcodes (1 byte)
|
|
||||||
if (strcmp(opname, "halt") == 0) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return (1 + 1)
|
// Return (1 + 1)
|
||||||
if (strcmp(opname, "return") == 0) {
|
if (strcmp(opname, "return") == 0) {
|
||||||
return 2; // 1 byte opcode + 1 byte return register
|
return 2; // 1 byte opcode + 1 byte return register
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(opname, "int-to-string") == 0 ||
|
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, "load-indirect-8") == 0 ||
|
||||||
strcmp(opname, "nat-to-string") == 0 ||
|
strcmp(opname, "nat-to-string") == 0 ||
|
||||||
strcmp(opname, "load-indirect-16") == 0 ||
|
strcmp(opname, "load-indirect-16") == 0 ||
|
||||||
|
|
@ -108,6 +109,7 @@ int get_instruction_byte_size(ExprNode *node) {
|
||||||
strcmp(opname, "add-real") == 0 || strcmp(opname, "sub-real") == 0 ||
|
strcmp(opname, "add-real") == 0 || strcmp(opname, "sub-real") == 0 ||
|
||||||
strcmp(opname, "bit-shift-left") == 0 ||
|
strcmp(opname, "bit-shift-left") == 0 ||
|
||||||
strcmp(opname, "bit-shift-right") == 0 ||
|
strcmp(opname, "bit-shift-right") == 0 ||
|
||||||
|
strcmp(opname, "bit-shift-r-ext") == 0 ||
|
||||||
strcmp(opname, "bit-and") == 0 || strcmp(opname, "bit-or") == 0 ||
|
strcmp(opname, "bit-and") == 0 || strcmp(opname, "bit-or") == 0 ||
|
||||||
strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 ||
|
strcmp(opname, "bit-xor") == 0 || strcmp(opname, "mul-real") == 0 ||
|
||||||
strcmp(opname, "div-real") == 0) {
|
strcmp(opname, "div-real") == 0) {
|
||||||
|
|
@ -115,7 +117,8 @@ int get_instruction_byte_size(ExprNode *node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// (5 bytes: 1 + 4)
|
// (5 bytes: 1 + 4)
|
||||||
if (strcmp(opname, "jump-if-flag") == 0 || strcmp(opname, "jump") == 0) {
|
if (strcmp(opname, "halt") == 0 || strcmp(opname, "jump-if-flag") == 0 ||
|
||||||
|
strcmp(opname, "jump") == 0) {
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -387,13 +390,14 @@ void process_data_block(VM *vm, SymbolTable *table, ExprNode *block) {
|
||||||
// Case 1: String literal (enclosed in quotes)
|
// Case 1: String literal (enclosed in quotes)
|
||||||
if (token[0] == '"' && token[strlen(token) - 1] == '"') {
|
if (token[0] == '"' && token[strlen(token) - 1] == '"') {
|
||||||
char *unwrapped = unwrap_string(token);
|
char *unwrapped = unwrap_string(token);
|
||||||
int len = strlen(unwrapped) + 1;
|
int len = strlen(unwrapped);
|
||||||
u32 addr = allocate_data(vm, table, name, len + 4);
|
u32 addr = allocate_data(vm, table, name, len + 1 + 4);
|
||||||
|
|
||||||
write_u32(vm, memory, addr, len);
|
write_u32(vm, memory, addr, len);
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
write_u8(vm, memory, addr + 4 + i, unwrapped[i]);
|
write_u8(vm, memory, addr + 4 + i, unwrapped[i]);
|
||||||
}
|
}
|
||||||
|
write_u8(vm, memory, addr + 4 + len, '\0');
|
||||||
free(unwrapped);
|
free(unwrapped);
|
||||||
}
|
}
|
||||||
// Case 2: Hexadecimal integer (0x...)
|
// Case 2: Hexadecimal integer (0x...)
|
||||||
|
|
@ -427,7 +431,7 @@ void process_data_block(VM *vm, SymbolTable *table, ExprNode *block) {
|
||||||
|
|
||||||
u32 addr = allocate_data(vm, table, name, 4);
|
u32 addr = allocate_data(vm, table, name, 4);
|
||||||
write_u32(vm, memory, addr, value);
|
write_u32(vm, memory, addr, value);
|
||||||
vm->mp += 4;
|
//vm->mp += 4;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unsupported data item\n");
|
fprintf(stderr, "Unsupported data item\n");
|
||||||
|
|
@ -445,6 +449,8 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
||||||
}
|
}
|
||||||
} else if (strcmp(opname, "halt") == 0) {
|
} else if (strcmp(opname, "halt") == 0) {
|
||||||
emit_opcode(vm, OP_HALT);
|
emit_opcode(vm, OP_HALT);
|
||||||
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
|
emit_u32(vm, addr);
|
||||||
} else if (strcmp(opname, "jump") == 0) {
|
} else if (strcmp(opname, "jump") == 0) {
|
||||||
emit_opcode(vm, OP_JMP);
|
emit_opcode(vm, OP_JMP);
|
||||||
u32 addr = resolve_symbol(table, node->children[0]->token);
|
u32 addr = resolve_symbol(table, node->children[0]->token);
|
||||||
|
|
@ -732,7 +738,7 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
||||||
emit_byte(vm, reg);
|
emit_byte(vm, reg);
|
||||||
}
|
}
|
||||||
} else if (strcmp(opname, "bit-shift-left") == 0) {
|
} else if (strcmp(opname, "bit-shift-left") == 0) {
|
||||||
emit_opcode(vm, OP_SLL);
|
emit_opcode(vm, OP_BIT_SHIFT_LEFT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
int dest = parse_register(node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
int src1 = parse_register(node->children[1]->token);
|
||||||
int src2 = parse_register(node->children[2]->token);
|
int src2 = parse_register(node->children[2]->token);
|
||||||
|
|
@ -740,15 +746,15 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
||||||
emit_byte(vm, src1);
|
emit_byte(vm, src1);
|
||||||
emit_byte(vm, src2);
|
emit_byte(vm, src2);
|
||||||
} else if (strcmp(opname, "bit-shift-right") == 0) {
|
} else if (strcmp(opname, "bit-shift-right") == 0) {
|
||||||
emit_opcode(vm, OP_SRL);
|
emit_opcode(vm, OP_BIT_SHIFT_RIGHT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
int dest = parse_register(node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
int src1 = parse_register(node->children[1]->token);
|
||||||
int src2 = parse_register(node->children[2]->token);
|
int src2 = parse_register(node->children[2]->token);
|
||||||
emit_byte(vm, dest);
|
emit_byte(vm, dest);
|
||||||
emit_byte(vm, src1);
|
emit_byte(vm, src1);
|
||||||
emit_byte(vm, src2);
|
emit_byte(vm, src2);
|
||||||
} else if (strcmp(opname, "bit-shift-re") == 0) {
|
} else if (strcmp(opname, "bit-shift-r-ext") == 0) {
|
||||||
emit_opcode(vm, OP_SRE);
|
emit_opcode(vm, OP_BIT_SHIFT_R_EXT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
int dest = parse_register(node->children[0]->token);
|
||||||
int src1 = parse_register(node->children[1]->token);
|
int src1 = parse_register(node->children[1]->token);
|
||||||
int src2 = parse_register(node->children[2]->token);
|
int src2 = parse_register(node->children[2]->token);
|
||||||
|
|
@ -811,6 +817,18 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
||||||
emit_byte(vm, dest);
|
emit_byte(vm, dest);
|
||||||
emit_byte(vm, src1);
|
emit_byte(vm, src1);
|
||||||
emit_byte(vm, src2);
|
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) {
|
} else if (strcmp(opname, "add-nat") == 0) {
|
||||||
emit_opcode(vm, OP_ADD_NAT);
|
emit_opcode(vm, OP_ADD_NAT);
|
||||||
int dest = parse_register(node->children[0]->token);
|
int dest = parse_register(node->children[0]->token);
|
||||||
|
|
@ -843,6 +861,18 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
||||||
emit_byte(vm, dest);
|
emit_byte(vm, dest);
|
||||||
emit_byte(vm, src1);
|
emit_byte(vm, src1);
|
||||||
emit_byte(vm, src2);
|
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);
|
||||||
} else if (strcmp(opname, "add-real") == 0) {
|
} else if (strcmp(opname, "add-real") == 0) {
|
||||||
emit_opcode(vm, OP_ADD_REAL);
|
emit_opcode(vm, OP_ADD_REAL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
int dest = parse_register(node->children[0]->token);
|
||||||
|
|
@ -875,6 +905,18 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) {
|
||||||
emit_byte(vm, dest);
|
emit_byte(vm, dest);
|
||||||
emit_byte(vm, src1);
|
emit_byte(vm, src1);
|
||||||
emit_byte(vm, src2);
|
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) {
|
} else if (strcmp(opname, "int-to-real") == 0) {
|
||||||
emit_opcode(vm, OP_INT_TO_REAL);
|
emit_opcode(vm, OP_INT_TO_REAL);
|
||||||
int dest = parse_register(node->children[0]->token);
|
int dest = parse_register(node->children[0]->token);
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ static void skipWhitespace() {
|
||||||
advance();
|
advance();
|
||||||
advance();
|
advance();
|
||||||
while (!isAtEnd()) {
|
while (!isAtEnd()) {
|
||||||
|
if (peek() == '\n') lexer.line++;
|
||||||
if (peek() == '*' && peekNext() == '/') {
|
if (peek() == '*' && peekNext() == '/') {
|
||||||
advance();
|
advance();
|
||||||
advance();
|
advance();
|
||||||
|
|
@ -120,6 +121,16 @@ static TokenType identifierType() {
|
||||||
switch (lexer.start[0]) {
|
switch (lexer.start[0]) {
|
||||||
case 'a':
|
case 'a':
|
||||||
return checkKeyword(1, 2, "nd", TOKEN_OPERATOR_AND);
|
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':
|
case 'e':
|
||||||
return checkKeyword(1, 3, "lse", TOKEN_KEYWORD_ELSE);
|
return checkKeyword(1, 3, "lse", TOKEN_KEYWORD_ELSE);
|
||||||
case 'f':
|
case 'f':
|
||||||
|
|
@ -134,23 +145,77 @@ static TokenType identifierType() {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
return checkKeyword(1, 1, "f", TOKEN_KEYWORD_IF);
|
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':
|
case 'n':
|
||||||
return checkKeyword(1, 2, "il", TOKEN_KEYWORD_NIL);
|
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':
|
case 'o':
|
||||||
return checkKeyword(1, 1, "r", TOKEN_OPERATOR_OR);
|
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':
|
case 'p':
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
case 'l':
|
case 'l':
|
||||||
return checkKeyword(2, 2, "ex", TOKEN_KEYWORD_PLEX);
|
return checkKeyword(2, 2, "ex", TOKEN_KEYWORD_PLEX);
|
||||||
case 'r':
|
|
||||||
return checkKeyword(2, 3, "int", TOKEN_KEYWORD_PRINT);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
return checkKeyword(1, 5, "eturn", TOKEN_KEYWORD_RETURN);
|
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':
|
case 't':
|
||||||
if (lexer.current - lexer.start > 1) {
|
if (lexer.current - lexer.start > 1) {
|
||||||
switch (lexer.start[1]) {
|
switch (lexer.start[1]) {
|
||||||
|
|
@ -161,10 +226,24 @@ static TokenType identifierType() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'u':
|
||||||
return checkKeyword(1, 2, "et", TOKEN_KEYWORD_LET);
|
if (lexer.current - lexer.start > 1) {
|
||||||
|
switch (lexer.start[1]) {
|
||||||
|
case 's':
|
||||||
|
return checkKeyword(2, 1, "e", TOKEN_KEYWORD_USE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
return checkKeyword(1, 4, "hile", TOKEN_KEYWORD_WHILE);
|
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;
|
return TOKEN_IDENTIFIER;
|
||||||
|
|
@ -278,7 +357,6 @@ const char* tokenTypeToString(TokenType type) {
|
||||||
case TOKEN_TYPE_STR: return "TYPE_STR";
|
case TOKEN_TYPE_STR: return "TYPE_STR";
|
||||||
case TOKEN_KEYWORD_PLEX: return "KEYWORD_PLEX";
|
case TOKEN_KEYWORD_PLEX: return "KEYWORD_PLEX";
|
||||||
case TOKEN_KEYWORD_FN: return "KEYWORD_FN";
|
case TOKEN_KEYWORD_FN: return "KEYWORD_FN";
|
||||||
case TOKEN_KEYWORD_LET: return "KEYWORD_LET";
|
|
||||||
case TOKEN_KEYWORD_CONST: return "KEYWORD_CONST";
|
case TOKEN_KEYWORD_CONST: return "KEYWORD_CONST";
|
||||||
case TOKEN_KEYWORD_IF: return "KEYWORD_IF";
|
case TOKEN_KEYWORD_IF: return "KEYWORD_IF";
|
||||||
case TOKEN_KEYWORD_ELSE: return "KEYWORD_ELSE";
|
case TOKEN_KEYWORD_ELSE: return "KEYWORD_ELSE";
|
||||||
|
|
@ -288,7 +366,11 @@ const char* tokenTypeToString(TokenType type) {
|
||||||
case TOKEN_KEYWORD_USE: return "KEYWORD_USE";
|
case TOKEN_KEYWORD_USE: return "KEYWORD_USE";
|
||||||
case TOKEN_KEYWORD_INIT: return "KEYWORD_INIT";
|
case TOKEN_KEYWORD_INIT: return "KEYWORD_INIT";
|
||||||
case TOKEN_KEYWORD_THIS: return "KEYWORD_THIS";
|
case TOKEN_KEYWORD_THIS: return "KEYWORD_THIS";
|
||||||
case TOKEN_KEYWORD_PRINT: return "KEYWORD_PRINT";
|
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_NIL: return "KEYWORD_NIL";
|
||||||
case TOKEN_KEYWORD_TRUE: return "KEYWORD_TRUE";
|
case TOKEN_KEYWORD_TRUE: return "KEYWORD_TRUE";
|
||||||
case TOKEN_KEYWORD_FALSE: return "KEYWORD_FALSE";
|
case TOKEN_KEYWORD_FALSE: return "KEYWORD_FALSE";
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,6 @@ typedef enum {
|
||||||
TOKEN_TYPE_STR,
|
TOKEN_TYPE_STR,
|
||||||
TOKEN_KEYWORD_PLEX,
|
TOKEN_KEYWORD_PLEX,
|
||||||
TOKEN_KEYWORD_FN,
|
TOKEN_KEYWORD_FN,
|
||||||
TOKEN_KEYWORD_LET,
|
|
||||||
TOKEN_KEYWORD_CONST,
|
TOKEN_KEYWORD_CONST,
|
||||||
TOKEN_KEYWORD_IF,
|
TOKEN_KEYWORD_IF,
|
||||||
TOKEN_KEYWORD_ELSE,
|
TOKEN_KEYWORD_ELSE,
|
||||||
|
|
@ -24,7 +23,11 @@ typedef enum {
|
||||||
TOKEN_KEYWORD_USE,
|
TOKEN_KEYWORD_USE,
|
||||||
TOKEN_KEYWORD_INIT,
|
TOKEN_KEYWORD_INIT,
|
||||||
TOKEN_KEYWORD_THIS,
|
TOKEN_KEYWORD_THIS,
|
||||||
TOKEN_KEYWORD_PRINT,
|
TOKEN_KEYWORD_OPEN,
|
||||||
|
TOKEN_KEYWORD_READ,
|
||||||
|
TOKEN_KEYWORD_WRITE,
|
||||||
|
TOKEN_KEYWORD_REFRESH,
|
||||||
|
TOKEN_KEYWORD_CLOSE,
|
||||||
TOKEN_KEYWORD_NIL,
|
TOKEN_KEYWORD_NIL,
|
||||||
TOKEN_KEYWORD_TRUE,
|
TOKEN_KEYWORD_TRUE,
|
||||||
TOKEN_KEYWORD_FALSE,
|
TOKEN_KEYWORD_FALSE,
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,9 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <uchar.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
|
// Helper function to create a new node
|
||||||
static ExprNode *expr_node_create(const char *token, int line) {
|
static ExprNode *expr_node_create(const char *token, int line) {
|
||||||
ExprNode *node = (ExprNode *)safe_malloc(sizeof(ExprNode));
|
ExprNode *node = (ExprNode *)malloc(sizeof(ExprNode));
|
||||||
node->token = strdup(token ? token : "");
|
node->token = strdup(token ? token : "");
|
||||||
node->children = NULL;
|
node->children = NULL;
|
||||||
node->child_count = 0;
|
node->child_count = 0;
|
||||||
|
|
@ -96,7 +86,7 @@ static char *parse_token(const char **ptr, int line) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t len = end - start;
|
size_t len = end - start;
|
||||||
char *token = (char *)safe_malloc(len + 1);
|
char *token = (char *)malloc(len + 1);
|
||||||
memcpy(token, start, len);
|
memcpy(token, start, len);
|
||||||
token[len] = '\0';
|
token[len] = '\0';
|
||||||
|
|
||||||
|
|
@ -113,7 +103,7 @@ static ExprNode *parse_list(const char **ptr, int line) {
|
||||||
if (**ptr == ')') {
|
if (**ptr == ')') {
|
||||||
// Empty list
|
// Empty list
|
||||||
(*ptr)++;
|
(*ptr)++;
|
||||||
return expr_node_create("nil", line);
|
return expr_node_create("\0", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse all children first
|
// Parse all children first
|
||||||
|
|
@ -125,7 +115,7 @@ static ExprNode *parse_list(const char **ptr, int line) {
|
||||||
if (child) {
|
if (child) {
|
||||||
// Resize temp children array
|
// Resize temp children array
|
||||||
ExprNode **new_temp =
|
ExprNode **new_temp =
|
||||||
(ExprNode **)safe_malloc(sizeof(ExprNode *) * (temp_count + 1));
|
(ExprNode **)malloc(sizeof(ExprNode *) * (temp_count + 1));
|
||||||
|
|
||||||
// Copy existing children
|
// Copy existing children
|
||||||
for (size_t i = 0; i < temp_count; i++) {
|
for (size_t i = 0; i < temp_count; i++) {
|
||||||
|
|
@ -159,7 +149,7 @@ static ExprNode *parse_list(const char **ptr, int line) {
|
||||||
node->child_count = temp_count - 1;
|
node->child_count = temp_count - 1;
|
||||||
if (node->child_count > 0) {
|
if (node->child_count > 0) {
|
||||||
node->children =
|
node->children =
|
||||||
(ExprNode **)safe_malloc(sizeof(ExprNode *) * node->child_count);
|
(ExprNode **)malloc(sizeof(ExprNode *) * node->child_count);
|
||||||
for (size_t i = 0; i < node->child_count; i++) {
|
for (size_t i = 0; i < node->child_count; i++) {
|
||||||
node->children[i] = temp_children[i + 1];
|
node->children[i] = temp_children[i + 1];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef ZRE_COMMON_H
|
#ifndef UNDAR_COMMON_H
|
||||||
#define ZRE_COMMON_H
|
#define UNDAR_COMMON_H
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "str.h"
|
#include "libc.h"
|
||||||
|
|
||||||
i32 vm_register_device(VM *vm, const char *path, const char *type, void *data,
|
i32 vm_register_device(VM *vm, const char *path, const char *type, void *data,
|
||||||
DeviceOps *ops, u32 size) {
|
DeviceOps *ops, u32 size) {
|
||||||
|
|
@ -33,26 +33,3 @@ Device *find_device_by_path(VM *vm, const char *path) {
|
||||||
}
|
}
|
||||||
return NULL;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
#ifndef ZRE_DEVICE_H
|
#ifndef UNDAR_DEVICE_H
|
||||||
#define ZRE_DEVICE_H
|
#define UNDAR_DEVICE_H
|
||||||
|
|
||||||
#include "opcodes.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, u32 size);
|
||||||
Device* find_device_by_path(VM *vm, const char *path);
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "str.h"
|
#include "libc.h"
|
||||||
|
|
||||||
void memcopy(u8 *dest, const u8 *src, u32 n) {
|
void memcopy(u8 *dest, const u8 *src, u32 n) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef ZRE_STR_H
|
#ifndef UNDAR_STR_H
|
||||||
#define ZRE_STR_H
|
#define UNDAR_STR_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef ZRE_OPCODES_H
|
#ifndef UNDAR_OPCODES_H
|
||||||
#define ZRE_OPCODES_H
|
#define UNDAR_OPCODES_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
|
@ -31,49 +31,55 @@ typedef enum {
|
||||||
OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */
|
OP_MEMSET_8, /* memset-8 : dest <-> dest+count = src1 as u8 */
|
||||||
OP_MEMSET_16, /* memset-16 : 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_MEMSET_32, /* memset-32 : dest <-> dest+count = src1 as u32 */
|
||||||
OP_REG_MOV, /* register-move : dest = src1 */
|
OP_REG_MOV, /* register-move : registers[dest] = registers[src1] */
|
||||||
OP_ADD_INT, /* add-int : registers[dest] = registers[src1] + registers[src2] */
|
OP_ADD_INT, /* add-int : registers[dest] = registers[src1] + registers[src2] */
|
||||||
OP_SUB_INT, /* sub-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_MUL_INT, /* mul-int : registers[dest] = registers[src1] * registers[src2] */
|
||||||
OP_DIV_INT, /* div-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_ADD_NAT, /* add-nat : registers[dest] = registers[src1] + registers[src2] */
|
||||||
OP_SUB_NAT, /* sub-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_MUL_NAT, /* mul-nat : registers[dest] = registers[src1] * registers[src2] */
|
||||||
OP_DIV_NAT, /* div-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_ADD_REAL, /* add-real : registers[dest] = registers[src1] + registers[src2] */
|
||||||
OP_SUB_REAL, /* sub-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_MUL_REAL, /* mul-real : registers[dest] = registers[src1] * registers[src2] */
|
||||||
OP_DIV_REAL, /* div-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_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_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_INT, /* real-to-int : registers[dest] = registers[src1] as int */
|
||||||
OP_REAL_TO_NAT, /* real-to-nat : registers[dest] = registers[src1] as nat */
|
OP_REAL_TO_NAT, /* real-to-nat : registers[dest] = registers[src1] as nat */
|
||||||
OP_SLL, /* bit-shift-left : registers[dest] = registers[src1] << registers[src2] */
|
OP_BIT_SHIFT_LEFT, /* bit-shift-left : registers[dest] = registers[src1] << registers[src2] */
|
||||||
OP_SRL, /* bit-shift-right : registers[dest] = registers[src1] >> registers[src2] */
|
OP_BIT_SHIFT_RIGHT,/* bit-shift-right : registers[dest] = registers[src1] >> registers[src2] */
|
||||||
OP_SRE, /* bit-shift-re : registers[dest] as i32 = 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_BAND, /* bit-and : registers[dest] = registers[src1] & registers[src2] */
|
||||||
OP_BOR, /* bit-or : 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_BXOR, /* bit-xor : registers[dest] = registers[src1] ^ registers[src2] */
|
||||||
OP_JMP, /* jump : jump to address dest unconditionally */
|
OP_JMP, /* jump : jump to &dest unconditionally */
|
||||||
OP_JMPF, /* jump-if-flag : jump to address dest if flag is ne 0 */
|
OP_JMPF, /* jump-if-flag : jump to &dest if flag != 0 */
|
||||||
OP_JEQ_INT, /* jump-eq-int : jump to address dest if registers[src1] as int == registers[src2] as int */
|
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 address 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 address 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 address 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 address 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 address 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 address dest if registers[src1] as nat == registers[src2] as nat */
|
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 address 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 address 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 address 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 address 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 address 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 address dest if registers[src1] as real == registers[src2] as real */
|
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 address 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 address 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 address 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 address 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 address 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_STRLEN, /* string-length : registers[dest] = length of str at src1 ptr */
|
||||||
OP_STREQ, /* string-eq : registers[dest] = src1 ptr string == src2 ptr string */
|
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_STRCAT, /* string-concat : registers[dest] = ptr of src1 ptr string + src2 ptr string */
|
||||||
|
|
|
||||||
36
src/vm/vm.c
36
src/vm/vm.c
|
|
@ -1,7 +1,7 @@
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
#include "str.h"
|
#include "libc.h"
|
||||||
|
|
||||||
#define COMPARE_AND_JUMP(type, op) \
|
#define COMPARE_AND_JUMP(type, op) \
|
||||||
do { \
|
do { \
|
||||||
|
|
@ -93,6 +93,7 @@ bool step_vm(VM *vm) {
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case OP_HALT: {
|
case OP_HALT: {
|
||||||
|
vm->flag = read_u32(vm, code, vm->pc);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
case OP_CALL: {
|
case OP_CALL: {
|
||||||
|
|
@ -721,11 +722,11 @@ bool step_vm(VM *vm) {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_SLL:
|
case OP_BIT_SHIFT_LEFT:
|
||||||
BIT_OP(<<);
|
BIT_OP(<<);
|
||||||
case OP_SRL:
|
case OP_BIT_SHIFT_RIGHT:
|
||||||
BIT_OP(>>);
|
BIT_OP(>>);
|
||||||
case OP_SRE:
|
case OP_BIT_SHIFT_R_EXT:
|
||||||
MATH_OP(i32, >>);
|
MATH_OP(i32, >>);
|
||||||
case OP_BAND:
|
case OP_BAND:
|
||||||
BIT_OP(&);
|
BIT_OP(&);
|
||||||
|
|
@ -741,6 +742,30 @@ bool step_vm(VM *vm) {
|
||||||
MATH_OP(i32, *);
|
MATH_OP(i32, *);
|
||||||
case OP_DIV_INT:
|
case OP_DIV_INT:
|
||||||
MATH_OP(i32, /);
|
MATH_OP(i32, /);
|
||||||
|
case OP_ABS_INT: {
|
||||||
|
dest = read_u8(vm, code, vm->pc);
|
||||||
|
vm->pc++;
|
||||||
|
src1 = read_u8(vm, code, vm->pc);
|
||||||
|
vm->pc++;
|
||||||
|
|
||||||
|
value = frame->registers[src1];
|
||||||
|
if (value < 0) {
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame->registers[dest] = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case OP_NEG_INT: {
|
||||||
|
dest = read_u8(vm, code, vm->pc);
|
||||||
|
vm->pc++;
|
||||||
|
src1 = read_u8(vm, code, vm->pc);
|
||||||
|
vm->pc++;
|
||||||
|
|
||||||
|
value = frame->registers[src1];
|
||||||
|
frame->registers[dest] = -value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
case OP_ADD_NAT:
|
case OP_ADD_NAT:
|
||||||
MATH_OP(u32, +);
|
MATH_OP(u32, +);
|
||||||
case OP_SUB_NAT:
|
case OP_SUB_NAT:
|
||||||
|
|
@ -901,6 +926,7 @@ bool step_vm(VM *vm) {
|
||||||
int_to_string(AS_INT(frame->registers[src1]), buffer);
|
int_to_string(AS_INT(frame->registers[src1]), buffer);
|
||||||
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
|
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
|
||||||
frame->registers[dest] = ptr;
|
frame->registers[dest] = ptr;
|
||||||
|
set_heap_status(vm, dest, true); /* Mark as heap pointer */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_NAT_TO_STRING: {
|
case OP_NAT_TO_STRING: {
|
||||||
|
|
@ -912,6 +938,7 @@ bool step_vm(VM *vm) {
|
||||||
nat_to_string(frame->registers[src1], buffer);
|
nat_to_string(frame->registers[src1], buffer);
|
||||||
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
|
ptr = str_alloc(vm, frame, buffer, strlength(buffer));
|
||||||
frame->registers[dest] = ptr;
|
frame->registers[dest] = ptr;
|
||||||
|
set_heap_status(vm, dest, true); /* Mark as heap pointer */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_REAL_TO_STRING: {
|
case OP_REAL_TO_STRING: {
|
||||||
|
|
@ -924,6 +951,7 @@ bool step_vm(VM *vm) {
|
||||||
ptr = str_alloc(vm, frame, buffer,
|
ptr = str_alloc(vm, frame, buffer,
|
||||||
strlength(buffer)); /* copy buffer to dest */
|
strlength(buffer)); /* copy buffer to dest */
|
||||||
frame->registers[dest] = ptr;
|
frame->registers[dest] = ptr;
|
||||||
|
set_heap_status(vm, dest, true); /* Mark as heap pointer */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case OP_STRLEN: {
|
case OP_STRLEN: {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
#ifndef ZRE_VM_H
|
#ifndef UNDAR_VM_H
|
||||||
#define ZRE_VM_H
|
#define UNDAR_VM_H
|
||||||
|
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
|
|
||||||
bool step_vm(VM *vm);
|
bool step_vm(VM *vm);
|
||||||
u32 str_alloc(VM *vm, Frame *frame, const char *str, u32 length);
|
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 nat_to_string(u32 value, char *buffer);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
(call &add ($0 $1) $2)
|
(call &add ($0 $1) $2)
|
||||||
(int-to-string $3 $2)
|
(int-to-string $3 $2)
|
||||||
(call &pln ($3) nil)
|
(call &pln ($3) nil)
|
||||||
(halt))
|
(halt 0))
|
||||||
|
|
||||||
(label add
|
(label add
|
||||||
(add-int $2 $1 $0)
|
(add-int $2 $1 $0)
|
||||||
|
|
@ -15,9 +15,9 @@
|
||||||
(load-immediate $1 &terminal-namespace) ; get terminal device
|
(load-immediate $1 &terminal-namespace) ; get terminal device
|
||||||
(load-immediate $11 0)
|
(load-immediate $11 0)
|
||||||
(syscall OPEN $1 $1 $11)
|
(syscall OPEN $1 $1 $11)
|
||||||
(load-immediate $3 &new-line)
|
|
||||||
(string-length $2 $0)
|
(string-length $2 $0)
|
||||||
(syscall WRITE $1 $0 $2)
|
(syscall WRITE $1 $0 $2)
|
||||||
|
(load-immediate $3 &new-line)
|
||||||
(string-length $4 $3)
|
(string-length $4 $3)
|
||||||
(syscall WRITE $1 $3 $4)
|
(syscall WRITE $1 $3 $4)
|
||||||
(return nil)))
|
(return nil)))
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
(call &fib ($0) $0)
|
(call &fib ($0) $0)
|
||||||
(int-to-string $1 $0)
|
(int-to-string $1 $0)
|
||||||
(call &pln ($1) nil)
|
(call &pln ($1) nil)
|
||||||
(halt))
|
(halt 0))
|
||||||
(label fib
|
(label fib
|
||||||
(load-immediate $1 2)
|
(load-immediate $1 2)
|
||||||
(jump-lt-int &base-case $0 $1)
|
(jump-lt-int &base-case $0 $1)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
(label main
|
(label main
|
||||||
(load-immediate $1 &hello-str) ; load hello string ptr
|
(load-immediate $1 &hello-str) ; load hello string ptr
|
||||||
(call &pln ($1) nil)
|
(call &pln ($1) nil)
|
||||||
(halt)) ; done
|
(halt 0)) ; done
|
||||||
(label pln
|
(label pln
|
||||||
(load-immediate $1 &terminal-namespace) ; get terminal device
|
(load-immediate $1 &terminal-namespace) ; get terminal device
|
||||||
(load-immediate $11 0)
|
(load-immediate $11 0)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
(call &pln ($4) nil)
|
(call &pln ($4) nil)
|
||||||
(real-to-string $3 $0)
|
(real-to-string $3 $0)
|
||||||
(call &pln ($3) nil)
|
(call &pln ($3) nil)
|
||||||
(halt))
|
(halt 0))
|
||||||
(label pln
|
(label pln
|
||||||
(load-immediate $1 &terminal-namespace) ; get terminal device
|
(load-immediate $1 &terminal-namespace) ; get terminal device
|
||||||
(load-immediate $11 0)
|
(load-immediate $11 0)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ function main() {
|
||||||
}
|
}
|
||||||
nat b = a as nat;
|
nat b = a as nat;
|
||||||
pln(term, "Enter a string:");
|
pln(term, "Enter a string:");
|
||||||
str user_string = read(term, 32);
|
str user_string = term.read(32);
|
||||||
pln(term, a.str);
|
pln(term, a.str);
|
||||||
pln(term, b.str);
|
pln(term, b.str);
|
||||||
pln(term, user_string);
|
pln(term, user_string);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
(syscall READ $0 $4 $1) ; read the string
|
(syscall READ $0 $4 $1) ; read the string
|
||||||
|
|
||||||
(call &pln ($0 $4) nil) ; print the string
|
(call &pln ($0 $4) nil) ; print the string
|
||||||
(halt))
|
(halt 0))
|
||||||
(label pln
|
(label pln
|
||||||
(load-immediate $3 &new-line)
|
(load-immediate $3 &new-line)
|
||||||
(string-length $2 $1)
|
(string-length $2 $1)
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
(jump &draw-loop))
|
(jump &draw-loop))
|
||||||
|
|
||||||
; Flush and halt
|
; Flush and halt
|
||||||
(halt))
|
(halt 0))
|
||||||
|
|
||||||
(label set-color-if-clicked
|
(label set-color-if-clicked
|
||||||
; (click_x, click_y, box_x, box_y, color, box_size)
|
; (click_x, click_y, box_x, box_y, color, box_size)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ plex Screen implements Device {
|
||||||
nat handle;
|
nat handle;
|
||||||
nat width;
|
nat width;
|
||||||
nat height;
|
nat height;
|
||||||
nat buffer_size;
|
|
||||||
byte[] buffer;
|
byte[] buffer;
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
|
|
@ -50,22 +49,22 @@ function main() {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
mouse.refresh();
|
mouse.refresh();
|
||||||
if (not mouse.left) continue;
|
if (!mouse.left) continue;
|
||||||
|
|
||||||
int box_size = 20;
|
int box_size = 20;
|
||||||
int x = 1;
|
int x = 1;
|
||||||
int y = 1;
|
int y = 1;
|
||||||
byte color = BLACK;
|
byte color = BLACK;
|
||||||
outlined_swatch(screen, color, x, y);
|
outlined_swatch(screen, color, x, y);
|
||||||
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
||||||
|
|
||||||
color = WHITE;
|
color = WHITE;
|
||||||
x = 21;
|
x = 21;
|
||||||
outlined_swatch(screen, color, x, y);
|
outlined_swatch(screen, color, x, y);
|
||||||
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
||||||
screen.draw();
|
screen.draw();
|
||||||
|
|
||||||
rectangle(screen, selected_color, x, y, 5, 5);
|
rectangle(screen, selected_color, x, y, 5, 5);
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@
|
||||||
(jump &draw-loop))
|
(jump &draw-loop))
|
||||||
|
|
||||||
; Flush and halt
|
; Flush and halt
|
||||||
(halt))
|
(halt 0))
|
||||||
|
|
||||||
(label set-color-if-clicked
|
(label set-color-if-clicked
|
||||||
; (click_x, click_y, box_x, box_y, color, box_size)
|
; (click_x, click_y, box_x, box_y, color, box_size)
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,11 @@ plex Screen implements Device {
|
||||||
nat handle;
|
nat handle;
|
||||||
nat width;
|
nat width;
|
||||||
nat height;
|
nat height;
|
||||||
nat buffer_size;
|
|
||||||
byte[] buffer;
|
byte[] buffer;
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
unsafe {
|
unsafe {
|
||||||
write(this, this.buffer, this.buffer_size);
|
write(this, this.buffer, this.buffer.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -50,22 +49,22 @@ function main() {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
mouse.refresh();
|
mouse.refresh();
|
||||||
if (not mouse.left) continue;
|
if (!mouse.left) continue;
|
||||||
|
|
||||||
int box_size = 20;
|
int box_size = 20;
|
||||||
int x = 1;
|
int x = 1;
|
||||||
int y = 1;
|
int y = 1;
|
||||||
byte color = BLACK;
|
byte color = BLACK;
|
||||||
outlined_swatch(screen, color, x, y);
|
outlined_swatch(screen, color, x, y);
|
||||||
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
||||||
|
|
||||||
color = WHITE;
|
color = WHITE;
|
||||||
x = 21;
|
x = 21;
|
||||||
outlined_swatch(screen, color, x, y);
|
outlined_swatch(screen, color, x, y);
|
||||||
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
set_color(box_size, x, y, mouse.x, mouse.y, color);
|
||||||
screen.draw();
|
screen.draw();
|
||||||
|
|
||||||
rectangle(screen, selected_color, x, y, 5, 5);
|
rectangle(screen, selected_color, x, y, 5, 5);
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
@ -105,14 +104,14 @@ function outline_swatch(Device screen, byte color, int x, int y) {
|
||||||
* Draw a rectangle
|
* Draw a rectangle
|
||||||
*/
|
*/
|
||||||
function rectangle(Device screen, byte color, int x, int y, int width, int height) {
|
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
|
// 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 takes the guardrails off and allows you to access/modify memory directly
|
||||||
unsafe {
|
unsafe {
|
||||||
int pixel = y * width + x + &screen.buffer + 4;
|
int base = y * screen.width + x + screen.buffer.ptr + 4;
|
||||||
do (int i = height; i > 0; i--) {
|
do (int i = height; i > 0; i--) {
|
||||||
int row = pixel + width;
|
int row = base + width;
|
||||||
memset(screen.buffer, row, color, width);
|
memset(screen.buffer, row, color, width);
|
||||||
pixel += width;
|
base += screen.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
(add-real $2 $1 $0)
|
(add-real $2 $1 $0)
|
||||||
(real-to-string $3 $2)
|
(real-to-string $3 $2)
|
||||||
(call &pln ($3) nil)
|
(call &pln ($3) nil)
|
||||||
(halt))
|
(halt 0))
|
||||||
(label pln
|
(label pln
|
||||||
(load-immediate $1 &terminal-namespace) ; get terminal device
|
(load-immediate $1 &terminal-namespace) ; get terminal device
|
||||||
(load-immediate $11 0)
|
(load-immediate $11 0)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
(syscall WRITE $0 $21 $22) ; redraw
|
(syscall WRITE $0 $21 $22) ; redraw
|
||||||
|
|
||||||
(jump &draw-loop))
|
(jump &draw-loop))
|
||||||
(halt))
|
(halt 0))
|
||||||
(label pln
|
(label pln
|
||||||
(load-immediate $1 &terminal-namespace) ; get terminal device
|
(load-immediate $1 &terminal-namespace) ; get terminal device
|
||||||
(load-immediate $11 0)
|
(load-immediate $11 0)
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,10 @@ plex Screen {
|
||||||
nat handle;
|
nat handle;
|
||||||
nat width;
|
nat width;
|
||||||
nat height;
|
nat height;
|
||||||
nat buffer_size;
|
byte[] buffer;
|
||||||
byte[] screen_buffer;
|
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
write(&this, this.screen_buffer, this.buffer_size);
|
write(this, this.buffer, this.buffer_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,16 +41,20 @@ function main() {
|
||||||
pln(screen.handle.str);
|
pln(screen.handle.str);
|
||||||
pln(screen.width.str);
|
pln(screen.width.str);
|
||||||
pln(screen.size.str);
|
pln(screen.size.str);
|
||||||
pln(screen.screen_buffer.ptr.str);
|
unsafe {
|
||||||
|
pln(screen.screen_buffer.ptr.str);
|
||||||
|
}
|
||||||
|
|
||||||
Mouse mouse = open("/dev/mouse/0", 0);
|
Mouse mouse = open("/dev/mouse/0", 0);
|
||||||
screen.draw();
|
screen.draw();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if (mouse.btn1) {
|
if (mouse.btn1) {
|
||||||
screen.screen_buffer[mouse.y * width + mouse.x +
|
unsafe {
|
||||||
screen.screen_buffer.ptr + 4] = WHITE;
|
screen.buffer[mouse.y * width + mouse.x +
|
||||||
screen.draw();
|
screen.buffer.ptr + 4] = WHITE;
|
||||||
|
screen.draw();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -60,7 +63,7 @@ function main() {
|
||||||
* Print with a newline
|
* Print with a newline
|
||||||
*/
|
*/
|
||||||
function pln(str message) {
|
function pln(str message) {
|
||||||
Terminal term();
|
Terminal term = open("/dev/term/0", 0);
|
||||||
write(term, message, message.length);
|
write(term, message, message.length);
|
||||||
write(term, nl, nl.length);
|
write(term, nl, nl.length);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue