Refactor to varied length opcodes, update structure, fix Makefile, WIP: number toS

This commit is contained in:
zongor 2025-09-17 23:16:38 -07:00
parent 94a1375d51
commit dd7cc62a3e
36 changed files with 987 additions and 744 deletions

2
.gitignore vendored
View File

@ -104,6 +104,6 @@ dkms.conf
zre zre
zre.wasm zre.wasm
memory_dump.bin memory_dump.bin
src/build/ build/
.gdb_history .gdb_history
.vscode .vscode

153
Makefile Normal file
View File

@ -0,0 +1,153 @@
# --- CONFIGURABLE DEFAULTS ---
PLATFORM ?= linux
BUILD_MODE ?= debug # 'debug' or 'deploy'
# --- DIRECTORIES ---
SRC_DIR := src
BUILD_DIR := build/$(PLATFORM)
ARCH_DIR := $(SRC_DIR)/arch/$(PLATFORM)
# --- COMPILERS ---
ifeq ($(PLATFORM), emscripten)
CC := emcc
else
CC ?= gcc
endif
# --- SHARED FLAGS ---
BASE_CFLAGS := -I$(SRC_DIR) -Wall -Wextra -Werror -pedantic
# --- CORE-SPECIFIC FLAGS (freestanding, no stdlib) ---
CORE_CFLAGS := $(BASE_CFLAGS) -std=c89 -ffreestanding -nostdlib -fno-builtin
# --- PLATFORM-SPECIFIC FLAGS ---
PLATFORM_CFLAGS := $(BASE_CFLAGS)
# --- MODE & PLATFORM SPECIFIC FLAGS ---
ifeq ($(BUILD_MODE), deploy)
CORE_CFLAGS += -O2 -DNDEBUG
PLATFORM_CFLAGS += -O2 -DNDEBUG
LDFLAGS += -s
TARGET_SUFFIX := -release
else
CORE_CFLAGS += -g -DDEBUG
PLATFORM_CFLAGS += -g -DDEBUG
TARGET_SUFFIX := -debug
endif
# --- LINUX-SPECIFIC (SDL, libc) ---
ifeq ($(PLATFORM), linux)
PLATFORM_CFLAGS += $(shell pkg-config --cflags sdl2 2>/dev/null)
LDFLAGS += $(shell pkg-config --libs sdl2 2>/dev/null) -lm
TARGET = $(BUILD_DIR)/zre-$(PLATFORM)$(TARGET_SUFFIX)
endif
# --- EMSCRIPTEN-SPECIFIC ---
ifeq ($(PLATFORM), emscripten)
# Core still compiled freestanding (emcc supports this)
# Platform layer gets Emscripten/SDL flags
PLATFORM_CFLAGS += -s USE_SDL=2 -s WASM=1
LDFLAGS += -s USE_SDL=2 -s WASM=1
# For deploy: optimize, strip debug, minimize size
ifeq ($(BUILD_MODE), deploy)
PLATFORM_CFLAGS += -O3
LDFLAGS += -O3 --closure 1
else
# For debug: preserve names, generate source maps
PLATFORM_CFLAGS += -gsource-map
LDFLAGS += -gsource-map --source-map-base .
endif
# Output: HTML + JS + WASM
TARGET = $(BUILD_DIR)/zre.html
endif
# --- FALLBACK TARGET (if no platform matched) ---
ifndef TARGET
TARGET = $(BUILD_DIR)/zre-$(PLATFORM)$(TARGET_SUFFIX)
endif
# --- CORE SOURCES (flat in src/) ---
CORE_SOURCES := \
$(SRC_DIR)/str.c \
$(SRC_DIR)/vm.c \
$(SRC_DIR)/device.c \
$(SRC_DIR)/test.c
# --- PLATFORM SOURCE ---
PLATFORM_SOURCE := $(ARCH_DIR)/main.c \
$(ARCH_DIR)/devices.c
# --- OBJECT FILES ---
CORE_OBJS := $(CORE_SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
PLATFORM_OBJ := $(PLATFORM_SOURCE:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
# --- DEPENDENCIES ---
DEPS := $(CORE_OBJS:.o=.d) $(PLATFORM_OBJ:.o=.d)
.PHONY: all debug deploy clean clean-all help
# Default target
all: $(TARGET)
# 'debug' target — just set BUILD_MODE and build
debug: BUILD_MODE = debug
debug: $(TARGET)
# 'deploy' target — just set BUILD_MODE and build
deploy: BUILD_MODE = deploy
deploy: $(TARGET)
# Main build rule
$(TARGET): $(CORE_OBJS) $(PLATFORM_OBJ)
@mkdir -p $(dir $@)
$(CC) $(PLATFORM_CFLAGS) $(LDFLAGS) -o $@ $^
@echo "Built: $@"
@if [ "$(PLATFORM)" = "emscripten" ]; then \
echo "Open in browser: file://$(shell pwd)/$@"; \
fi
# --- COMPILE CORE (freestanding) ---
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
@mkdir -p $(dir $@)
$(CC) $(CORE_CFLAGS) -MMD -MP -c $< -o $@
# --- COMPILE PLATFORM ---
$(BUILD_DIR)/arch/$(PLATFORM)/%.o: $(ARCH_DIR)/%.c
@mkdir -p $(dir $@)
$(CC) $(PLATFORM_CFLAGS) -MMD -MP -c $< -o $@
# --- AUTO-DEPENDENCIES ---
-include $(DEPS)
# --- CLEAN ---
clean:
@echo "Cleaning build artifacts for $(PLATFORM)..."
@rm -rf $(BUILD_DIR)
@echo "Cleaned."
clean-all:
@echo "Cleaning ALL build artifacts..."
@rm -rf build/
@echo "All cleaned."
# --- HELP ---
help:
@echo "Undar VM"
@echo ""
@echo "Targets:"
@echo " make -> debug build (default: linux)"
@echo " make debug -> same as above"
@echo " make deploy -> optimized, stripped build"
@echo " make clean -> clean current platform"
@echo " make clean-all→ clean all platforms"
@echo ""
@echo "Platforms:"
@echo " make PLATFORM=linux -> GCC + SDL2"
@echo " make PLATFORM=emscripten -> Emscripten + SDL2 for Web"
@echo " make PLATFORM=avr -> (example) AVR-GCC"
@echo ""
@echo "Output:"
@echo " Linux: build/linux/zre-linux-<debug|release>"
@echo " Web: build/emscripten/zre.html (+ .js, .wasm)"

View File

@ -1,5 +1,5 @@
local a = 5.0 local a = 5.0
for i = 50000, 0, -1 do for i = 5000, 0, -1 do
a = a + 5.0 a = a + 5.0
end end
local b = math.floor(a) local b = math.floor(a)

View File

@ -1,5 +1,5 @@
my $a = 5.0; my $a = 5.0;
for (my $i = 50000; $i >= 0; $i--) { for (my $i = 5000; $i >= 0; $i--) {
$a += 5.0; $a += 5.0;
} }
my $b = int($a); my $b = int($a);

View File

@ -1,5 +1,5 @@
a = 5.0 a = 5.0
for i in range(50000, -1, -1): for i in range(5000, -1, -1):
a += 5.0 a += 5.0
b = int(a) b = int(a)
user_string = input("Enter a string:") user_string = input("Enter a string:")

View File

@ -1,9 +1,9 @@
real a = 5.0; real a = 5.0;
do (int i = 50000, 0, -1) { do (int i = 5000, 0, -1) {
a = a + 5.0; a = a + 5.0;
} }
int b = a as nat; int b = a as nat;
print "Enter a string:"); print("Enter a string:");
str user_string = read(); str user_string = read();
print a.str; print a.str;
print b.str; print b.str;

View File

@ -1,5 +1,5 @@
let a = 5.0; let a = 5.0;
for (let i = 50000; i > 0; i = i - 1) { for (let i = 5000; i > 0; i = i - 1) {
a = a + 5.0; a = a + 5.0;
} }
let b = a; let b = a;

View File

@ -1,91 +0,0 @@
# Compiler configurations
# -----------------------
# Native build (gcc)
CC_NATIVE = gcc
CFLAGS_NATIVE = -g -std=c89 -Wall -Wextra -Werror -Wno-unused-parameter -I. #-O2
LDFLAGS_NATIVE =
LDLIBS_NATIVE = -lSDL2
# WASM build (emscripten)
CC_WASM = emcc
CFLAGS_WASM = -g -std=c89 -Wall -Wextra -Werror -Wno-unused-parameter -I.
LDFLAGS_WASM = -s WASM=1 -g -s USE_SDL=2
LDLIBS_WASM =
# Source and build configuration
# ----------------------------
COMMON_SRC = $(wildcard *.c)
# Separate architecture sources
ARCH_SRC_LINUX = $(wildcard arch/linux/*.c)
ARCH_SRC_EMSCRIPTEN = $(wildcard arch/emscripten/*.c)
# Object directories
OBJ_DIR_NATIVE = build/native/obj
OBJ_DIR_WASM = build/wasm/obj
# Common objects from root
OBJ_NATIVE = $(addprefix $(OBJ_DIR_NATIVE)/,$(notdir $(COMMON_SRC:.c=.o)))
OBJ_WASM = $(addprefix $(OBJ_DIR_WASM)/,$(notdir $(COMMON_SRC:.c=.o)))
# Architecture-specific objects
OBJ_ARCH_NATIVE = $(addprefix $(OBJ_DIR_NATIVE)/,$(notdir $(ARCH_SRC_LINUX:.c=.o)))
OBJ_ARCH_WASM = $(addprefix $(OBJ_DIR_WASM)/,$(notdir $(ARCH_SRC_EMSCRIPTEN:.c=.o)))
# Executables
EXEC_NATIVE = zre
EXEC_WASM = zre.wasm
# Phony targets
.PHONY: all clean install wasm native emscripten linux macos
# Default target builds the native version
all: native
# Native build rules
# ------------------
native: linux
linux: $(EXEC_NATIVE)
$(EXEC_NATIVE): $(OBJ_NATIVE) $(OBJ_ARCH_NATIVE)
$(CC_NATIVE) $(LDFLAGS_NATIVE) $^ $(LDLIBS_NATIVE) -o $@
# WASM build rules
# ----------------
wasm: emscripten
emscripten: $(EXEC_WASM)
$(EXEC_WASM): $(OBJ_WASM) $(OBJ_ARCH_WASM)
$(CC_WASM) $(LDFLAGS_WASM) $^ $(LDLIBS_WASM) -o $@
# Object file rules
# -----------------
$(OBJ_DIR_NATIVE)/%.o: %.c
@mkdir -p $(dir $@)
$(CC_NATIVE) $(CFLAGS_NATIVE) -c $< -o $@
$(OBJ_DIR_WASM)/%.o: %.c
@mkdir -p $(dir $@)
$(CC_WASM) $(CFLAGS_WASM) -c $< -o $@
# Architecture-specific source rules
$(OBJ_DIR_NATIVE)/%.o: arch/linux/%.c
@mkdir -p $(dir $@)
$(CC_NATIVE) $(CFLAGS_NATIVE) -c $< -o $@
$(OBJ_DIR_WASM)/%.o: arch/emscripten/%.c
@mkdir -p $(dir $@)
$(CC_WASM) $(CFLAGS_WASM) -c $< -o $@
# Clean build artifacts
# ---------------------
clean:
rm -rf $(OBJ_DIR_NATIVE) $(OBJ_DIR_WASM) $(EXEC_NATIVE) $(EXEC_WASM)
# Install target (example)
# ------------------------
install: native
install -d $(DESTDIR)/usr/local/bin
install $(EXEC_NATIVE) $(DESTDIR)/usr/local/bin/

View File

@ -1,6 +1,43 @@
#include "devices.h" #include "devices.h"
#include <unistd.h>
#include <string.h>
int screen_open(void *data, uint32_t mode) { i32 console_open(void *data, u32 mode) {
USED(mode);
USED(data);
/* Nothing to open — stdin/stdout are always available */
return 0; /* Success */
}
i32 console_read(void *data, u8 *buffer, u32 size) {
USED(data);
ssize_t result = read(STDIN_FILENO, buffer, size);
if (result < 0) return -1; /* Error */
return (i32)result; /* Bytes read */
}
i32 console_write(void *data, const u8 *buffer, u32 size) {
USED(data);
ssize_t result = write(STDOUT_FILENO, buffer, size);
if (result < 0) return -1; /* Error */
return (i32)result; /* Bytes written */
}
i32 console_close(void *data) {
USED(data);
/* Nothing to close — stdin/stdout are process-owned */
return 0;
}
i32 console_ioctl(void *data, u32 cmd, void *args) {
USED(data);
USED(cmd);
USED(args);
return -1; /* Unsupported */
}
i32 screen_open(void *data, u32 mode) {
USED(mode);
ScreenDeviceData *screen = (ScreenDeviceData *)data; ScreenDeviceData *screen = (ScreenDeviceData *)data;
@ -27,12 +64,17 @@ int screen_open(void *data, uint32_t mode) {
return 0; return 0;
} }
int screen_read(void *data, uint8_t *buffer, uint32_t size) { return -1; } i32 screen_read(void *data, u8 *buffer, u32 size) {
USED(data);
USED(buffer);
USED(size);
return -1;
}
int screen_write(void *data, const uint8_t *buffer, uint32_t size) { i32 screen_write(void *data, const u8 *buffer, u32 size) {
ScreenDeviceData *screen = (ScreenDeviceData *)data; ScreenDeviceData *screen = (ScreenDeviceData *)data;
if (size > screen->framebuffer_size * sizeof(uint8_t)) { if (size > screen->framebuffer_size * sizeof(u8)) {
return -1; return -1;
} }
@ -40,7 +82,7 @@ int screen_write(void *data, const uint8_t *buffer, uint32_t size) {
return 0; return 0;
} }
int screen_close(void *data) { i32 screen_close(void *data) {
ScreenDeviceData *screen = (ScreenDeviceData *)data; ScreenDeviceData *screen = (ScreenDeviceData *)data;
if (screen->texture) { if (screen->texture) {
@ -59,15 +101,19 @@ int screen_close(void *data) {
} }
/* MOUSE */ /* MOUSE */
int mouse_open(void *data, uint32_t mode) { return 0; } i32 mouse_open(void *data, u32 mode) {
USED(data);
USED(mode);
return 0;
}
int mouse_read(void *data, uint8_t *buffer, uint32_t size) { i32 mouse_read(void *data, u8 *buffer, u32 size) {
MouseDeviceData *mouse = (MouseDeviceData *)data; MouseDeviceData *mouse = (MouseDeviceData *)data;
if (size < 3 * sizeof(uint32_t)) if (size < 3 * sizeof(u32))
return -1; return -1;
uint32_t *out = (uint32_t *)buffer; u32 *out = (u32 *)buffer;
out[0] = mouse->x; out[0] = mouse->x;
out[1] = mouse->y; out[1] = mouse->y;
out[2] = (mouse->btn1 | (mouse->btn2 << 1) | (mouse->btn3 << 2) | out[2] = (mouse->btn1 | (mouse->btn2 << 1) | (mouse->btn3 << 2) |
@ -75,24 +121,42 @@ int mouse_read(void *data, uint8_t *buffer, uint32_t size) {
return 0; return 0;
} }
int mouse_write(void *data, const uint8_t *buffer, uint32_t size) { return -1; } i32 mouse_write(void *data, const u8 *buffer, u32 size) {
USED(data);
USED(buffer);
USED(size);
return -1;
}
int mouse_close(void *data) { return 0; } i32 mouse_close(void *data) {
USED(data);
return 0;
}
int keyboard_open(void *data, uint32_t mode) { return 0; } i32 keyboard_open(void *data, u32 mode) {
USED(data);
USED(mode);
return 0;
}
int keyboard_read(void *data, uint8_t *buffer, uint32_t size) { i32 keyboard_read(void *data, u8 *buffer, u32 size) {
KeyboardDeviceData *kbd = (KeyboardDeviceData *)data; KeyboardDeviceData *kbd = (KeyboardDeviceData *)data;
if (size < (uint32_t)kbd->key_count) if (size < (u32)kbd->key_count)
return -1; return -1;
memcpy(buffer, kbd->keys, kbd->key_count); memcpy(buffer, kbd->keys, kbd->key_count);
return 0; return 0;
} }
int keyboard_write(void *data, const uint8_t *buffer, uint32_t size) { i32 keyboard_write(void *data, const u8 *buffer, u32 size) {
USED(data);
USED(buffer);
USED(size);
return -1; /* not writable */ return -1; /* not writable */
} }
int keyboard_close(void *data) { return 0; } i32 keyboard_close(void *data) {
USED(data);
return 0;
}

View File

@ -4,10 +4,10 @@
/* Screen device data */ /* Screen device data */
typedef struct screen_device_data_s { typedef struct screen_device_data_s {
uint32_t width; u32 width;
uint32_t height; u32 height;
uint32_t framebuffer_pos; u32 framebuffer_pos;
uint32_t framebuffer_size; u32 framebuffer_size;
VM* vm; VM* vm;
SDL_Window *window; SDL_Window *window;
SDL_Renderer *renderer; SDL_Renderer *renderer;
@ -16,32 +16,37 @@ typedef struct screen_device_data_s {
/* Mouse device data */ /* Mouse device data */
typedef struct mouse_device_data_s { typedef struct mouse_device_data_s {
uint32_t x; u32 x;
uint32_t y; u32 y;
uint8_t btn1; u8 btn1;
uint8_t btn2; u8 btn2;
uint8_t btn3; u8 btn3;
uint8_t btn4; u8 btn4;
} MouseDeviceData; } MouseDeviceData;
/* Keyboard device data */ /* Keyboard device data */
typedef struct keyboard_device_data_s { typedef struct keyboard_device_data_s {
const uint8_t *keys; const u8 *keys;
int32_t key_count; i32 key_count;
} KeyboardDeviceData; } KeyboardDeviceData;
int screen_open(void *data, uint32_t mode); i32 screen_open(void *data, u32 mode);
int screen_read(void *data, uint8_t *buffer, uint32_t size); i32 screen_read(void *data, u8 *buffer, u32 size);
int screen_write(void *data, const uint8_t *buffer, uint32_t size); i32 screen_write(void *data, const u8 *buffer, u32 size);
int screen_close(void *data); i32 screen_close(void *data);
int mouse_open(void *data, uint32_t mode); i32 mouse_open(void *data, u32 mode);
int mouse_read(void *data, uint8_t *buffer, uint32_t size); i32 mouse_read(void *data, u8 *buffer, u32 size);
int mouse_write(void *data, const uint8_t *buffer, uint32_t size); i32 mouse_write(void *data, const u8 *buffer, u32 size);
int mouse_close(void *data); i32 mouse_close(void *data);
int keyboard_open(void *data, uint32_t mode); i32 keyboard_open(void *data, u32 mode);
int keyboard_read(void *data, uint8_t *buffer, uint32_t size); i32 keyboard_read(void *data, u8 *buffer, u32 size);
int keyboard_write(void *data, const uint8_t *buffer, uint32_t size); i32 keyboard_write(void *data, const u8 *buffer, u32 size);
int keyboard_close(void *data); i32 keyboard_close(void *data);
i32 console_open(void *data, u32 mode);
i32 console_read(void *data, u8 *buffer, u32 size);
i32 console_write(void *data, const u8 *buffer, u32 size);
i32 console_close(void *data);
i32 console_ioctl(void *data, u32 cmd, void *args);

View File

@ -26,11 +26,21 @@ static DeviceOps keyboard_ops = {.open = keyboard_open,
.close = keyboard_close, .close = keyboard_close,
.ioctl = NULL}; .ioctl = NULL};
static DeviceOps console_device_ops = {
.open = console_open,
.read = console_read,
.write = console_write,
.close = console_close,
.ioctl = console_ioctl,
};
static ScreenDeviceData screen_data = {0}; static ScreenDeviceData screen_data = {0};
static MouseDeviceData mouse_data = {0}; static MouseDeviceData mouse_data = {0};
static KeyboardDeviceData keyboard_data = {0}; static KeyboardDeviceData keyboard_data = {0};
void compileFile(const char *path, VM *vm) { void compileFile(const char *path, VM *vm) {
USED(vm);
FILE *f = fopen(path, "rb"); FILE *f = fopen(path, "rb");
if (!f) { if (!f) {
perror("fopen"); perror("fopen");
@ -84,13 +94,13 @@ enum FlagType {
#define MAX_INPUT_FILES 16 /* Adjust based on your system's constraints */ #define MAX_INPUT_FILES 16 /* Adjust based on your system's constraints */
struct CompilerConfig { struct CompilerConfig {
uint32_t flags; u32 flags;
char *input_files[MAX_INPUT_FILES]; char *input_files[MAX_INPUT_FILES];
int input_file_count; i32 input_file_count;
}; };
int parse_arguments(int argc, char *argv[], struct CompilerConfig *config) { i32 parse_arguments(i32 argc, char *argv[], struct CompilerConfig *config) {
int i; i32 i;
/* Initialize config */ /* Initialize config */
config->flags = 0; config->flags = 0;
@ -131,6 +141,9 @@ int parse_arguments(int argc, char *argv[], struct CompilerConfig *config) {
return 0; return 0;
} }
/*
* This needs to be done dynamically eventually
*/
void register_sdl_devices(VM *vm) { void register_sdl_devices(VM *vm) {
screen_data.vm = vm; screen_data.vm = vm;
screen_data.width = 640; screen_data.width = 640;
@ -156,7 +169,7 @@ void register_sdl_devices(VM *vm) {
&keyboard_ops); &keyboard_ops);
} }
int main(int argc, char *argv[]) { i32 main(i32 argc, char *argv[]) {
struct CompilerConfig config = {0}; struct CompilerConfig config = {0};
if (parse_arguments(argc, argv, &config) != 0) { if (parse_arguments(argc, argv, &config) != 0) {
@ -172,7 +185,7 @@ int main(int argc, char *argv[]) {
if (config.flags & FLAG_TEST_MODE) { if (config.flags & FLAG_TEST_MODE) {
compile_internal_test(config.input_files[0], &vm); compile_internal_test(config.input_files[0], &vm);
} else { } else {
int j; i32 j;
for (j = 0; j < config.input_file_count; j++) { for (j = 0; j < config.input_file_count; j++) {
compileFile(config.input_files[j], &vm); compileFile(config.input_files[j], &vm);
} }
@ -206,9 +219,10 @@ int main(int argc, char *argv[]) {
} }
} }
bool running = true; bool running = true;
vm_register_device(&vm, "/dev/term/0", "terminal", nil, &console_device_ops);
if (config.flags & FLAG_GUI_MODE) { if (config.flags & FLAG_GUI_MODE) {
uint32_t i; u32 i;
register_sdl_devices(&vm); register_sdl_devices(&vm);
while (running) { while (running) {
for (i = 0; i < vm.dc; i++) { for (i = 0; i < vm.dc; i++) {
@ -260,7 +274,7 @@ int main(int argc, char *argv[]) {
if (screen->texture && screen->renderer) { if (screen->texture && screen->renderer) {
SDL_UpdateTexture(screen->texture, NULL, SDL_UpdateTexture(screen->texture, NULL,
&vm.memory[screen->framebuffer_pos], &vm.memory[screen->framebuffer_pos],
screen->width * sizeof(uint32_t)); screen->width * sizeof(u32));
SDL_RenderClear(screen->renderer); SDL_RenderClear(screen->renderer);
@ -271,9 +285,9 @@ int main(int argc, char *argv[]) {
float scale = SDL_min(scale_x, scale_y); float scale = SDL_min(scale_x, scale_y);
SDL_Rect dstrect = { SDL_Rect dstrect = {
(int)((output_rect.w - screen->width * scale) / 2), (i32)((output_rect.w - screen->width * scale) / 2),
(int)((output_rect.h - screen->height * scale) / 2), (i32)((output_rect.h - screen->height * scale) / 2),
(int)(screen->width * scale), (int)(screen->height * scale)}; (i32)(screen->width * scale), (i32)(screen->height * scale)};
SDL_RenderCopy(screen->renderer, screen->texture, NULL, &dstrect); SDL_RenderCopy(screen->renderer, screen->texture, NULL, &dstrect);
SDL_RenderPresent(screen->renderer); SDL_RenderPresent(screen->renderer);

View File

@ -1,22 +1,19 @@
#ifndef ZRE_COMMON_H #ifndef ZRE_COMMON_H
#define ZRE_COMMON_H #define ZRE_COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include <stdint.h> #include <stdint.h>
typedef unsigned char u8; typedef uint8_t u8;
typedef signed char i8; typedef int8_t i8;
typedef unsigned short u16; typedef uint16_t u16;
typedef signed short i16; typedef int16_t i16;
typedef unsigned long u32; typedef uint32_t u32;
typedef signed long i32; typedef int32_t i32;
/* For 64-bit, use compiler extensions or split into hi/lo u32 on pure C89 platforms */ #define nil NULL
#if defined(__GNUC__) || defined(_MSC_VER)
typedef unsigned long long u64; #define USED(x) ((void)(x))
typedef signed long long i64;
#endif
#endif #endif

View File

@ -1,53 +1,57 @@
#include "device.h" #include "device.h"
#include "str.h"
#include <string.h> i32 vm_register_device(VM *vm, const char *path, const char *type, void *data,
DeviceOps *ops) {
Device *dev;
int vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops) { if (vm->dc >= DEVICES_SIZE)
if (vm->dc >= DEVICES_SIZE) return -1; return -1;
Device *dev = &vm->devices[vm->dc++]; dev = &vm->devices[vm->dc++];
strncpy(dev->path, path, DEVICE_PATH_MAX_LENGTH); strcopy(dev->path, path, DEVICE_PATH_MAX_LENGTH);
dev->path[DEVICE_PATH_MAX_LENGTH - 1] = '\0'; dev->path[DEVICE_PATH_MAX_LENGTH - 1] = '\0';
strncpy(dev->type, type, DEVICE_TYPE_MAX_LENGTH); strcopy(dev->type, type, DEVICE_TYPE_MAX_LENGTH);
dev->type[DEVICE_TYPE_MAX_LENGTH - 1] = '\0'; dev->type[DEVICE_TYPE_MAX_LENGTH - 1] = '\0';
dev->data = data; dev->data = data;
dev->ops = ops; dev->ops = ops;
dev->flags = 0; dev->flags = 0;
return 0; return 0;
} }
/* Find device by path */ /* Find device by path */
Device* find_device_by_path(VM *vm, const char *path) { Device *find_device_by_path(VM *vm, const char *path) {
uint32_t i; u32 i;
for (i = 0; i < vm->dc; i++) { for (i = 0; i < vm->dc; i++) {
if (strcmp(vm->devices[i].path, path) == 0) { if (streq(vm->devices[i].path, path)) {
return &vm->devices[i]; return &vm->devices[i];
}
} }
return NULL; }
return NULL;
} }
/* Find device by type (useful for checking capabilities) */ /* Find device by type (useful for checking capabilities) */
Device* find_device_by_type(VM *vm, const char *type) { Device *find_device_by_type(VM *vm, const char *type) {
uint32_t i; u32 i;
for (i = 0; i < vm->dc; i++) { for (i = 0; i < vm->dc; i++) {
if (strcmp(vm->devices[i].type, type) == 0) { if (streq(vm->devices[i].type, type)) {
return &vm->devices[i]; return &vm->devices[i];
}
} }
return NULL; }
return NULL;
} }
/* Find all devices of a type */ /* Find all devices of a type */
int find_devices_by_type(VM *vm, const char *type, Device **results, uint32_t max_results) { i32 find_devices_by_type(VM *vm, const char *type, Device **results,
uint32_t i, count = 0; u32 max_results) {
for (i = 0; i < vm->dc && count < max_results; i++) { u32 i, count = 0;
if (strcmp(vm->devices[i].type, type) == 0) { for (i = 0; i < vm->dc && count < max_results; i++) {
results[count++] = &vm->devices[i]; if (streq(vm->devices[i].type, type)) {
} results[count++] = &vm->devices[i];
} }
return count; }
return count;
} }

View File

@ -3,9 +3,9 @@
#include "opcodes.h" #include "opcodes.h"
int vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops); i32 vm_register_device(VM *vm, const char *path, const char *type, void *data, DeviceOps *ops);
Device* find_device_by_path(VM *vm, const char *path); Device* find_device_by_path(VM *vm, const char *path);
Device* find_device_by_type(VM *vm, const char *type); Device* find_device_by_type(VM *vm, const char *type);
int find_devices_by_type(VM *vm, const char *type, Device **results, uint32_t max_results); i32 find_devices_by_type(VM *vm, const char *type, Device **results, uint32_t max_results);
#endif #endif

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

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

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

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

View File

@ -2,27 +2,18 @@
#define ZRE_OPCODES_H #define ZRE_OPCODES_H
#include "common.h" #include "common.h"
#include <stdint.h>
typedef enum { typedef enum {
OP_HALT, /* halt : terminate execution */ OP_HALT, /* halt : terminate execution */
OP_JMP, /* jump : jump to address dest unconditionally */ OP_JMP, /* jump : jump to address dest unconditionally */
OP_GET_PC, /* pc : dest = current program counter */ OP_CALL, /* call : creates a new frame */
OP_CALL, /* call : creates a new frame */ OP_RETURN, /* retn : returns from a frame to the parent frame */
OP_RETURN, /* retn : returns from a frame to the parent frame */ OP_LOAD, /* load : dest = &[next memory location] */
OP_LOAD, /* load : dest = &[next memory location] */ OP_LOAD_IMM, /* load : dest = &[next memory location] */
OP_STORE, /* stor : next memory location = src1 as float */ OP_STORE, /* stor : next memory location = src1 as float */
OP_PUSH, /* push : push str ref from register onto the stack and copy str */ OP_PUSH, /* push : push str ref from register onto the stack and copy str */
OP_POP, /* pop : pop int from stack onto the register */ OP_POP, /* pop : pop int from stack onto the register */
OP_REG_MOV, /* rmov : dest = src1 */ OP_REG_MOV, /* rmov : dest = src1 */
OP_REG_SWAP, /* rswp : dest = src1, src1 = dest */
OP_GET_ACC, /* gacc : dest = accumulator */
OP_MEM_SWAP, /* mswp : &dest = &src1, &src1 = &dest */
OP_MEM_MOV, /* mmov : &dest = &src1 */
OP_MEM_ALLOC, /* aloc : dest [next memory location as size] */
OP_GET, /* get : dest = ptr : dest = memory[ptr] */
OP_PUT, /* put : ptr = src1 : memory[ptr] = src */
OP_OFFSET, /* offs : dest = ptr + src1 : dest = p + o */
OP_SYSCALL, /* sysc : */ OP_SYSCALL, /* sysc : */
OP_ADD_INT, /* addi : dest = src1 + src2 */ OP_ADD_INT, /* addi : dest = src1 + src2 */
OP_SUB_INT, /* subi : dest = src1 - src2 */ OP_SUB_INT, /* subi : dest = src1 - src2 */
@ -58,36 +49,17 @@ typedef enum {
OP_INT_TO_STRING, /* itos : dest = src1 as str */ OP_INT_TO_STRING, /* itos : dest = src1 as str */
OP_UINT_TO_STRING, /* utos : dest = src1 as str */ OP_UINT_TO_STRING, /* utos : dest = src1 as str */
OP_REAL_TO_STRING, /* rtos : dest = src1 as str */ OP_REAL_TO_STRING, /* rtos : dest = src1 as str */
OP_CMP_STRING, /* cmps : dest = (str == src2) as bool */
OP_STRING_TO_INT, /* stoi : dest = src1 as int */ OP_STRING_TO_INT, /* stoi : dest = src1 as int */
OP_STRING_TO_UINT, /* stou : dest = src1 as uint */ OP_STRING_TO_UINT, /* stou : dest = src1 as uint */
OP_STRING_TO_REAL, /* stor : dest = src1 as real */ OP_STRING_TO_REAL /* stor : dest = src1 as real */
/* to remove (replace with device), just for testing for now */
OP_DBG_PRINT_STRING, /* puts : write a string to stdout */
OP_DBG_READ_STRING, /* gets : read a string from stdin */
} Opcode; } Opcode;
/* defines a uint32 opcode */
#define OP(opcode, dest, src1, src2) \
((opcode << 24) | (dest << 16) | (src1 << 8) | (src2))
typedef union value_u {
int32_t i; /* Integers */
float f; /* Float */
uint32_t u; /* Unsigned integers, also used for pointer address */
char c[4]; /* 4 Byte char array for string packing */
} Value;
typedef struct slice_s {
uint32_t start;
uint32_t end;
} Slice;
#define MAX_REGS 32 #define MAX_REGS 32
typedef struct frame_s { typedef struct frame_s {
Value registers[MAX_REGS]; /* R0-R31 */ u32 registers[MAX_REGS]; /* R0-R31 */
uint32_t rp; /* register pointer (last unused) */ u32 rp; /* register pointer (last unused) */
Slice allocated; /* start and end of global allocated block */ u32 start; /* start and end of global allocated block */
u32 end;
} Frame; } Frame;
typedef enum { typedef enum {
@ -96,16 +68,15 @@ typedef enum {
SYSCALL_DEVICE_READ, SYSCALL_DEVICE_READ,
SYSCALL_DEVICE_WRITE, SYSCALL_DEVICE_WRITE,
SYSCALL_DEVICE_CLOSE, SYSCALL_DEVICE_CLOSE,
SYSCALL_DEVICE_IOCTL, SYSCALL_DEVICE_IOCTL
} SyscallID; } SyscallID;
typedef struct device_ops_s { typedef struct device_ops_s {
int (*open)(void *device_data, uint32_t mode); i32 (*open)(void *device_data, u32 mode);
int (*read)(void *device_data, uint8_t *buffer, uint32_t size); i32 (*read)(void *device_data, u8 *buffer, u32 size);
int (*write)(void *device_data, const uint8_t *buffer, uint32_t size); i32 (*write)(void *device_data, const u8 *buffer, u32 size);
int (*close)(void *device_data); i32 (*close)(void *device_data);
int (*ioctl)(void *device_data, uint32_t cmd, i32 (*ioctl)(void *device_data, u32 cmd, void *args); /* optional control */
void *args); /* optional control */
} DeviceOps; } DeviceOps;
#define DEVICE_TYPE_MAX_LENGTH 24 /* 23 chars + null terminator */ #define DEVICE_TYPE_MAX_LENGTH 24 /* 23 chars + null terminator */
@ -117,7 +88,7 @@ typedef struct device_s {
etc. */ etc. */
void *data; /* device-specific data */ void *data; /* device-specific data */
DeviceOps *ops; /* operations vtable */ DeviceOps *ops; /* operations vtable */
uint32_t flags; /* permissions, status, etc. */ u32 flags; /* permissions, status, etc. */
} Device; } Device;
#define MEMORY_SIZE (640 * 480 + 65536) #define MEMORY_SIZE (640 * 480 + 65536)
@ -126,20 +97,61 @@ typedef struct device_s {
#define STACK_SIZE 256 #define STACK_SIZE 256
#define DEVICES_SIZE 8 #define DEVICES_SIZE 8
typedef struct vm_s { typedef struct vm_s {
uint32_t pc; /* program counter */ u32 pc; /* program counter */
uint32_t cp; /* code pointer (last allocated opcode) */ u32 cp; /* code pointer (last allocated opcode) */
uint32_t fp; /* frame pointer (current frame) */ u32 fp; /* frame pointer (current frame) */
uint32_t sp; /* stack pointer (top of stack) */ u32 sp; /* stack pointer (top of stack) */
uint32_t rp; /* return stack pointer (top of stack) */ u32 rp; /* return stack pointer (top of stack) */
uint32_t mp; /* memory pointer (last allocated value) */ u32 mp; /* memory pointer (last allocated value) */
uint32_t dc; /* device count */ u32 dc; /* device count */
uint32_t acc; /* accumulator (temporary results like SYSCALL status) */ u32 acc; /* accumulator (temporary results like SYSCALL status) */
Device devices[DEVICES_SIZE]; /* device definitions */ Frame frames[FRAMES_SIZE]; /* function call frames */
Frame frames[FRAMES_SIZE]; /* function call frames */ u32 stack[STACK_SIZE]; /* main stack */
Value stack[STACK_SIZE]; /* main stack */ u32 return_stack[STACK_SIZE]; /* return stack (for call recursion) */
Value return_stack[STACK_SIZE]; /* return stack (for call recursion) */ Device devices[DEVICES_SIZE]; /* device definitions */
Value code[CODE_SIZE]; /* code block */ u8 code[CODE_SIZE]; /* code block */
Value memory[MEMORY_SIZE]; /* memory block */ u8 memory[MEMORY_SIZE]; /* memory block */
} VM; } VM;
#define AS_INT(v) ((i32)(v))
#define AS_UINT(v) ((u32)(v))
#define AS_FIXED(v) ((float)(i32)(v) / 65536.0f)
#define TO_FIXED(f) ((u32)((i32)( \
((f) >= 0.0f) ? ((f) * 65536.0f + 0.5f) : ((f) * 65536.0f - 0.5f) \
)))
#define read_u8(vm, location, addr) ((vm)->location[addr])
#define read_u16(vm, location, addr) \
(((uint16_t)(vm)->location[(addr)] << 8) | \
((uint16_t)(vm)->location[(addr) + 1]))
#define read_u32(vm, location, addr) \
(((u32)(vm)->location[(addr)] << 24) | \
((u32)(vm)->location[(addr) + 1] << 16) | \
((u32)(vm)->location[(addr) + 2] << 8) | ((u32)(vm)->location[(addr) + 3]))
#define write_u8(vm, location, addr, value) \
do { \
if ((addr) < sizeof((vm)->location)) { \
(vm)->location[(addr)] = (value); \
} \
} while (0)
#define write_u16(vm, location, addr, value) \
do { \
if ((addr) + 1 < sizeof((vm)->location)) { \
(vm)->location[(addr)] = ((value) >> 8) & 0xFF; \
(vm)->location[(addr) + 1] = (value) & 0xFF; \
} \
} while (0)
#define write_u32(vm, location, addr, value) \
do { \
if ((addr) + 3 < sizeof((vm)->location)) { \
(vm)->location[(addr)] = ((value) >> 24) & 0xFF; \
(vm)->location[(addr) + 1] = ((value) >> 16) & 0xFF; \
(vm)->location[(addr) + 2] = ((value) >> 8) & 0xFF; \
(vm)->location[(addr) + 3] = (value) & 0xFF; \
} \
} while (0)
#endif #endif

44
src/str.c Normal file
View File

@ -0,0 +1,44 @@
#include "str.h"
i32 strcopy(char *to, const char *from, u32 length) {
u32 i;
if (to == nil || from == nil) return -1;
if (length == 0) {return 0;}
for (i = 0; i < length - 1 && from[i] != '\0'; i++) {
to[i] = from[i];
}
to[i] = '\0';
return 0;
}
bool streq(const char *s1, const char *s2) {
if (s1 == nil && s2 == nil) return true;
if (s1 == nil || s2 == nil) return false;
while (*s1 && *s2) {
if (*s1 != *s2) return false;
s1++;
s2++;
}
return (*s1 == '\0' && *s2 == '\0');
}
u32 strlen(const char *str) {
u32 i;
if (str == nil) {return 0;}
for (i = 0; str[i] != '\0'; i++) {
; /* twiddle thumbs, 'i' is doing all the work*/
}
return i;
}
u32 strnlen(const char *str, u32 max_len) {
u32 i;
if (str == nil) {return 0;}
for (i = 0; i < max_len && str[i] != '\0'; i++) {
; /* twiddle thumbs, 'i' is doing all the work*/
}
return i;
}

10
src/str.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef ZRE_STR_H
#define ZRE_STR_H
#include "common.h"
i32 strcopy(char* to, const char *from, u32 length);
u32 strlen(const char* str);
bool streq(const char *s1, const char *s2);
#endif

View File

@ -1,194 +1,135 @@
#include "test.h" #include "test.h"
#include "opcodes.h"
#include "str.h"
#include "vm.h" #include "vm.h"
#include <string.h>
uint32_t real_alloc(VM *vm, float v) { u32 real_alloc(VM *vm, float v) {
uint32_t addr = vm->mp; i32 fixed = TO_FIXED(v);
vm->memory[vm->mp++].f = v; u32 addr = vm->mp;
vm->frames[vm->fp].allocated.end++; write_u32(vm, memory, vm->mp, fixed);
vm->mp += 4;
vm->frames[vm->fp].end += 4;
return addr; return addr;
} }
uint32_t nat_alloc(VM *vm, uint32_t v) { u32 nat_alloc(VM *vm, u32 v) {
uint32_t addr = vm->mp; u32 addr = vm->mp;
vm->memory[vm->mp++].u = v; write_u32(vm, memory, vm->mp, v);
vm->frames[vm->fp].allocated.end++; vm->mp += 4;
vm->frames[vm->fp].end += 4;
return addr; return addr;
} }
uint32_t int_alloc(VM *vm, int32_t v) { u32 int_alloc(VM *vm, i32 v) {
uint32_t addr = vm->mp; u32 addr = vm->mp;
vm->memory[vm->mp++].i = v; write_u32(vm, memory, vm->mp, v);
vm->frames[vm->fp].allocated.end++; vm->mp += 4;
vm->frames[vm->fp].end += 4;
return addr; return addr;
} }
/* Array of test mappings */ /* Array of test mappings */
struct TestMapping internal_tests[] = { struct TestMapping internal_tests[] = {
{"simple.ul", test_simple_compile}, {"simple.ul", test_simple_compile},
{"loop.ul", test_loop_compile},
{"add.ul", test_add_function_compile},
{"fib.ul", test_recursive_function_compile},
{"window.ul", test_window_click_compile}, {"window.ul", test_window_click_compile},
/* Add more test mappings here */ {NULL, NULL} /* Sentinel to mark end of array */
{NULL, NULL} /* Sentinel to mark end of array */
}; };
bool compile_internal_test(const char* filename, VM* vm) { bool compile_internal_test(const char *filename, VM *vm) {
int i; i32 i;
for (i = 0; internal_tests[i].filename != NULL; i++) { for (i = 0; internal_tests[i].filename != NULL; i++) {
if (strcmp(internal_tests[i].filename, filename) == 0) { if (streq(internal_tests[i].filename, filename)) {
return internal_tests[i].test_func(vm); return internal_tests[i].test_func(vm);
}
} }
return false; }
return false;
} }
bool test_simple_compile(VM *vm) { bool test_simple_compile(VM *vm) {
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); u32 ptr;
vm->code[vm->cp++].u = nat_alloc(vm, 1); u32 terminal_path_addr = str_alloc(vm, "/dev/term/0", 12);
vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); vm->code[vm->cp++] = OP_LOAD;
vm->code[vm->cp++].u = nat_alloc(vm, 2); vm->code[vm->cp++] = 0;
vm->code[vm->cp++].u = OP(OP_ADD_UINT, 2, 1, 0); /* let sum = 1 + 2; */ ptr = real_alloc(vm, 1.0f);
vm->code[vm->cp++].u = OP(OP_UINT_TO_STRING, 3, 2, 0); write_u32(vm, code, vm->cp, ptr); vm->cp+=4;
vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 3, 0); /* print(sum.toS()); */
vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); /* explicit halt */
return true;
}
bool test_loop_compile(VM *vm) { vm->code[vm->cp++] = OP_LOAD;
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* let a = 5.0 */ vm->code[vm->cp++] = 1;
vm->code[vm->cp++].u = real_alloc(vm, 5.0f); ptr = real_alloc(vm, 2.0f);
vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* do (i = 50000, 0, -1) { */ write_u32(vm, code, vm->cp, ptr); vm->cp+=4;
vm->code[vm->cp++].u = int_alloc(vm, 10000);
vm->code[vm->cp++].u = OP(OP_LOAD, 2, 0, 0); /* loop check value */
vm->code[vm->cp++].u = int_alloc(vm, 0);
vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); /* loop incriment value */
vm->code[vm->cp++].u = int_alloc(vm, -1);
vm->code[vm->cp++].u = OP(OP_LOAD, 5, 0, 0); /* a */
vm->code[vm->cp++].u = real_alloc(vm, 5.0f);
vm->code[vm->cp++].u = OP(OP_LOAD, 4, 0, 0); /* loop start */
uint32_t addr = vm->cp + 1;
vm->code[vm->cp++].u = int_alloc(vm, addr);
vm->code[vm->cp++].u = OP(OP_ADD_REAL, 0, 0, 5); /* a += 5.0; */
vm->code[vm->cp++].u = OP(OP_ADD_INT, 1, 1, 3); /* (implied by loop) i = i + (-1) */
vm->code[vm->cp++].u = OP(OP_JGE_INT, 4, 1, 2); /* } */
vm->code[vm->cp++].u = OP(OP_REAL_TO_UINT, 1, 0, 0); /* let b = a as nat; */
vm->code[vm->cp++].u = OP(OP_LOAD, 6, 0, 0);
uint32_t str_addr = str_alloc(vm, "Enter a string:", 16);
vm->code[vm->cp++].u = nat_alloc(vm, str_addr);
vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 6, 0); /* print("Enter a string: "); */
vm->code[vm->cp++].u = OP(OP_DBG_READ_STRING, 2, 0, 0); /* let user_string = gets(); */
vm->code[vm->cp++].u = OP(OP_UINT_TO_STRING, 3, 1, 0);
vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 3, 0); /* print(a.toS()); */
vm->code[vm->cp++].u = OP(OP_REAL_TO_STRING, 3, 0, 0);
vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 3, 0); /* print(b.toS()); */
vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 2, 0); /* print(user_string); */
vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); /* program done */
return true;
}
bool test_add_function_compile(VM *vm) { vm->code[vm->cp++] = OP_ADD_UINT;
/* fn main() */ vm->code[vm->cp++] = 2;
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* 1 */ vm->code[vm->cp++] = 1;
vm->code[vm->cp++].u = int_alloc(vm, 1); vm->code[vm->cp++] = 0; /* let sum = 1 + 2; */
vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0);
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* 1 */
vm->code[vm->cp++].u = int_alloc(vm, 1);
vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0);
vm->code[vm->cp++].u = OP(OP_CALL, 0, 0, 0); /* ); */
vm->code[vm->cp++].u = 12;
vm->code[vm->cp++].u = OP(OP_POP, 0, 0, 0); /* get return value */
vm->code[vm->cp++].u = OP(OP_INT_TO_STRING, 1, 0, 0);
vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 1, 0); /* print(sum.toS()); */
vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0);
/* fn add() */
vm->code[vm->cp++].u = OP(OP_POP, 0, 0, 0); /* a int */
vm->code[vm->cp++].u = OP(OP_POP, 1, 0, 0); /* b int */
vm->code[vm->cp++].u = OP(OP_ADD_INT, 2, 1, 0); /* a + b */
vm->code[vm->cp++].u = OP(OP_PUSH, 2, 0, 0); /* push on stack */
vm->code[vm->cp++].u = OP(OP_RETURN, 0, 0, 0);
return true;
}
bool test_recursive_function_compile(VM *vm) { vm->code[vm->cp++] = OP_REAL_TO_STRING;
/* fn main() */ vm->code[vm->cp++] = 4;
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* 35 */ vm->code[vm->cp++] = 2;
vm->code[vm->cp++].u = int_alloc(vm, 35);
vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0); vm->code[vm->cp++] = OP_LOAD_IMM;
vm->code[vm->cp++].u = OP(OP_CALL, 0, 0, 0); /* ); */ vm->code[vm->cp++] = 3;
vm->code[vm->cp++].u = 9; write_u32(vm, code, vm->cp, terminal_path_addr); vm->cp+=4;
vm->code[vm->cp++].u = OP(OP_POP, 0, 0, 0); /* get return value */
vm->code[vm->cp++].u = OP(OP_INT_TO_STRING, 1, 0, 0); vm->code[vm->cp++] = OP_SYSCALL;
vm->code[vm->cp++].u = OP(OP_DBG_PRINT_STRING, 0, 1, 0); /* print(fib(35).toS()); */ write_u32(vm, code, vm->cp, AS_UINT(SYSCALL_DEVICE_WRITE)); vm->cp+=4;
vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); write_u32(vm, code, vm->cp, AS_UINT(2)); vm->cp+=4;
/* fn fib() */ vm->code[vm->cp++] = 3;
vm->code[vm->cp++].u = OP(OP_POP, 0, 0, 0); /* n int */ /* syscall_id=WRITE, arg_count=2, start_reg=3 ; print(sum.toS()); */
vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* 2 */ vm->code[vm->cp++] = OP_HALT; /* explicit halt */
vm->code[vm->cp++].u = int_alloc(vm, 2);
vm->code[vm->cp++].u = OP(OP_LOAD, 2, 0, 0); /* &fib */
vm->code[vm->cp++].u = int_alloc(vm, 32);
vm->code[vm->cp++].u = OP(OP_JLT_INT, 2, 0, 1);
vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); /* 2 */
vm->code[vm->cp++].u = int_alloc(vm, 2);
vm->code[vm->cp++].u = OP(OP_SUB_INT, 4, 0, 3);
vm->code[vm->cp++].u = OP(OP_PUSH, 4, 0, 0);
vm->code[vm->cp++].u = OP(OP_CALL, 0, 0, 0); /* fib(n - 2) */
vm->code[vm->cp++].u = 9;
vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); /* 1 */
vm->code[vm->cp++].u = int_alloc(vm, 1);
vm->code[vm->cp++].u = OP(OP_SUB_INT, 4, 0, 3);
vm->code[vm->cp++].u = OP(OP_PUSH, 4, 0, 0);
vm->code[vm->cp++].u = OP(OP_CALL, 0, 0, 0); /* fib(n - 1) */
vm->code[vm->cp++].u = 9;
vm->code[vm->cp++].u = OP(OP_POP, 4, 0, 0);
vm->code[vm->cp++].u = OP(OP_POP, 5, 0, 0);
vm->code[vm->cp++].u = OP(OP_ADD_INT, 6, 5, 4);
vm->code[vm->cp++].u = OP(OP_PUSH, 6, 0, 0);
vm->code[vm->cp++].u = OP(OP_RETURN, 0, 0, 0);
vm->code[vm->cp++].u = OP(OP_PUSH, 0, 0, 0);
vm->code[vm->cp++].u = OP(OP_RETURN, 0, 0, 0);
return true; return true;
} }
bool test_window_click_compile(VM *vm) { bool test_window_click_compile(VM *vm) {
uint32_t screen_path_addr = str_alloc(vm, "/dev/screen/0", 14); u32 test_pixel_addr, loop_start, screen_path_addr = str_alloc(vm, "/dev/screen/0", 14);
/*uint32_t mouse_path_addr = str_alloc(vm, "/dev/mouse/0", 12);*/
/* Open screen device: R0=path, R1=mode */
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* R0 = screen path */
vm->code[vm->cp++].u = nat_alloc(vm, screen_path_addr);
vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* R1 = mode (0) */
vm->code[vm->cp++].u = int_alloc(vm, 0);
vm->code[vm->cp++].u = OP(OP_SYSCALL, SYSCALL_DEVICE_OPEN, 0, 2); /* syscall_id, first_reg=0, arg_count=2 */
/* Check if open succeeded (result in vm->acc) */
vm->code[vm->cp++].u = OP(OP_GET_ACC, 2, 0, 0); /* Move result to R2 */
/* Create simple test pixel data */
uint32_t test_pixel_addr = vm->mp;
vm->memory[vm->mp].c[0] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64);
vm->memory[vm->mp].c[1] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64);
vm->memory[vm->mp].c[2] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64);
vm->memory[vm->mp++].c[3] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64);
vm->frames[vm->fp].allocated.end++;
/* Main loop to check for mouse input */ vm->code[vm->cp++] = OP_LOAD; /* R0 = screen path */
uint32_t loop_start = vm->cp; vm->code[vm->cp++] = 0;
vm->code[vm->cp++] = nat_alloc(vm, screen_path_addr);
/* Write to screen: R0=path, R1=buffer, R2=size */ vm->code[vm->cp++] = OP_LOAD; /* R1 = mode (0) */
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); vm->code[vm->cp++] = 1;
vm->code[vm->cp++].u = nat_alloc(vm, screen_path_addr); vm->code[vm->cp++] = int_alloc(vm, 0);
vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0);
vm->code[vm->cp++].u = nat_alloc(vm, test_pixel_addr);
vm->code[vm->cp++].u = OP(OP_LOAD, 2, 0, 0);
vm->code[vm->cp++].u = int_alloc(vm, 1);
vm->code[vm->cp++].u = OP(OP_SYSCALL, SYSCALL_DEVICE_WRITE, 0, 3); /* syscall_id, first_reg=0, arg_count=3 */
vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0); vm->code[vm->cp++] = OP_SYSCALL;
vm->code[vm->cp++].u = nat_alloc(vm, loop_start); vm->code[vm->cp++] = SYSCALL_DEVICE_OPEN;
vm->code[vm->cp++].u = OP(OP_JMP, 3, 0, 0); /* Infinite loop for testing */ vm->code[vm->cp++] = 0; /* first_reg */
vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0); vm->code[vm->cp++] = 2; /* arg_count */
return true; test_pixel_addr = vm->mp;
vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64);
vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64);
vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64);
vm->memory[vm->mp++] = (char)((255 / 32) << 5) | ((0 / 32) << 2) | (0 / 64);
vm->frames[vm->fp].end += 4;
loop_start = vm->cp;
vm->code[vm->cp++] = OP_LOAD;
vm->code[vm->cp++] = 0;
vm->code[vm->cp++] = nat_alloc(vm, screen_path_addr);
vm->code[vm->cp++] = OP_LOAD;
vm->code[vm->cp++] = 1;
vm->code[vm->cp++] = nat_alloc(vm, test_pixel_addr);
vm->code[vm->cp++] = OP_LOAD;
vm->code[vm->cp++] = 2;
vm->code[vm->cp++] = int_alloc(vm, 1);
vm->code[vm->cp++] = OP_SYSCALL;
vm->code[vm->cp++] = SYSCALL_DEVICE_WRITE;
vm->code[vm->cp++] = 0; /* first_reg */
vm->code[vm->cp++] = 3; /* arg_count */
vm->code[vm->cp++] = OP_LOAD;
vm->code[vm->cp++] = 3;
vm->code[vm->cp++] = nat_alloc(vm, loop_start);
vm->code[vm->cp++] = OP_JMP;
vm->code[vm->cp++] = 3;
vm->code[vm->cp++] = OP_HALT;
return true;
} }

690
src/vm.c
View File

@ -1,56 +1,50 @@
#include "vm.h" #include "vm.h"
#include "device.h" #include "device.h"
#include "opcodes.h" #include "opcodes.h"
#include <string.h> #include "str.h"
/* no inline fn in ANSI C :( */ /* no inline fn in ANSI C :( */
#define COMPARE_AND_JUMP(type, accessor, op) \ #define COMPARE_AND_JUMP(type, op) \
do { \ do { \
type value = vm->frames[vm->fp].registers[src1].accessor; \ type value, value2; \
type value2 = vm->frames[vm->fp].registers[src2].accessor; \ dest = read_u8(vm, code, vm->pc); \
vm->pc = \ vm->pc++; \
(value op value2) ? vm->frames[vm->fp].registers[dest].u : vm->pc; \ src1 = read_u8(vm, code, vm->pc); \
vm->pc++; \
src2 = read_u8(vm, code, vm->pc); \
vm->pc++; \
value = vm->frames[vm->fp].registers[src1]; \
value2 = vm->frames[vm->fp].registers[src2]; \
vm->pc = (value op value2) ? vm->frames[vm->fp].registers[dest] : vm->pc; \
return true; \ return true; \
} while (0) } while (0)
#define MATH_OP(accessor, op) \ #define MATH_OP(type, op) \
do { \ do { \
vm->frames[vm->fp].registers[dest].accessor = \ dest = read_u8(vm, code, vm->pc); \
vm->frames[vm->fp] \ vm->pc++; \
.registers[src1] \ src1 = read_u8(vm, code, vm->pc); \
.accessor op vm->frames[vm->fp] \ vm->pc++; \
.registers[src2] \ src2 = read_u8(vm, code, vm->pc); \
.accessor; \ vm->pc++; \
vm->frames[vm->fp].registers[dest] = (type)vm->frames[vm->fp] \
.registers[src1] op(type) \
vm->frames[vm->fp] \
.registers[src2]; \
return true; \ return true; \
} while (0) } while (0)
/** u32 str_alloc(VM *vm, const char *str, u32 length) {
* Embeds a string into the VM u32 str_addr = vm->mp;
*/ u32 i = 0;
uint32_t str_alloc(VM *vm, const char *str, uint32_t length) { vm->mp += 4;
uint32_t str_addr = vm->mp++; while (i < length) {
uint32_t temp = 0; vm->memory[vm->mp++] = str[i++];
while (temp < length) {
uint32_t idx = temp % 4;
vm->memory[vm->mp].c[idx] = str[temp];
temp++;
if (idx == 3)
vm->mp++;
} }
vm->memory[vm->mp++] = '\0';
uint32_t i, rem = temp % 4; write_u32(vm, memory, str_addr, length);
if (rem != 0) { vm->frames[vm->fp].end = vm->mp;
for (i = rem; i < 4; i++) {
vm->memory[vm->mp].c[i] = '\0';
}
vm->mp++;
}
vm->memory[str_addr].u = length;
vm->frames[vm->fp].allocated.end = vm->mp;
return str_addr; return str_addr;
} }
@ -58,143 +52,112 @@ uint32_t str_alloc(VM *vm, const char *str, uint32_t length) {
* Step to the next opcode in the vm. * Step to the next opcode in the vm.
*/ */
bool step_vm(VM *vm) { bool step_vm(VM *vm) {
/* Get current instruction & Advance to next instruction */ u8 opcode, dest, src1, src2;
uint32_t instruction = vm->code[vm->pc++].u; u32 v, ptr;
i32 value;
uint8_t opcode = (instruction >> 24) & 0xFF; /* Get current instruction & Advance to next instruction */
uint8_t dest = (instruction >> 16) & 0xFF; opcode = vm->code[vm->pc++];
uint8_t src1 = (instruction >> 8) & 0xFF;
uint8_t src2 = instruction & 0xFF;
switch (opcode) { switch (opcode) {
case OP_HALT: { case OP_HALT: {
return false; return false;
} }
case OP_CALL: { case OP_CALL: {
uint32_t jmp = vm->code[vm->pc++].u; /* location of function in code */ u32 jmp = read_u32(vm, code, vm->pc); /* location of function in code */
vm->return_stack[vm->rp++].u = vm->pc; /* set return address */ vm->pc += 4;
vm->fp++; /* increment to the next free frame */ vm->return_stack[vm->rp++] = vm->pc; /* set return address */
vm->frames[vm->fp].allocated.start = vm->fp++; /* increment to the next free frame */
vm->mp; /* set start of new memory block */ vm->frames[vm->fp].start = vm->mp; /* set start of new memory block */
vm->pc = jmp; vm->pc = jmp;
return true; return true;
} }
case OP_RETURN: { case OP_RETURN: {
vm->frames[vm->fp].rp = 0; /* reset register ptr */ vm->frames[vm->fp].rp = 0; /* reset register ptr */
vm->pc = vm->return_stack[--vm->rp].u; /* set pc to return address */ vm->pc = vm->return_stack[--vm->rp]; /* set pc to return address */
vm->mp = vm->mp =
vm->frames[vm->fp--].allocated.start; /* reset memory pointer to start vm->frames[vm->fp--].start; /* reset memory pointer to start
of old slice, pop the frame */ of old slice, pop the frame */
return true; return true;
} }
case OP_LOAD_IMM: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
v = read_u32(vm, code, vm->pc);
vm->pc += 4;
vm->frames[vm->fp].registers[dest] = v;
return true;
}
case OP_LOAD: { case OP_LOAD: {
uint32_t ptr = vm->code[vm->pc++].u; dest = read_u8(vm, code, vm->pc);
Value v = vm->memory[ptr]; vm->pc++;
ptr = read_u32(vm, code, vm->pc);
vm->pc += 4;
v = read_u32(vm, memory, ptr);
vm->frames[vm->fp].registers[dest] = v; vm->frames[vm->fp].registers[dest] = v;
return true; return true;
} }
case OP_STORE: { case OP_STORE: {
uint32_t ptr = vm->code[vm->pc++].u; src1 = read_u8(vm, code, vm->pc);
vm->memory[ptr] = vm->frames[vm->fp].registers[src1]; vm->pc++;
return true; ptr = read_u32(vm, code, vm->pc);
} vm->pc += 4;
case OP_PUT: { v = vm->frames[vm->fp].registers[src1];
uint32_t addr = vm->frames[vm->fp].registers[dest].u; write_u32(vm, memory, ptr, v);
vm->memory[addr] = vm->frames[vm->fp].registers[src1];
return true;
}
case OP_GET: {
uint32_t addr = vm->frames[vm->fp].registers[src1].u;
vm->frames[vm->fp].registers[dest] = vm->memory[addr];
return true;
}
case OP_OFFSET: {
uint32_t ptr = vm->frames[vm->fp].registers[src1].u;
uint32_t offset = vm->frames[vm->fp].registers[src2].u;
uint32_t result = ptr + offset;
vm->frames[vm->fp].registers[dest].u = result;
return true; return true;
} }
case OP_PUSH: { case OP_PUSH: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
vm->stack[++vm->sp] = vm->frames[vm->fp].registers[dest]; vm->stack[++vm->sp] = vm->frames[vm->fp].registers[dest];
return true; return true;
} }
case OP_POP: { case OP_POP: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
vm->frames[vm->fp].registers[dest] = vm->stack[vm->sp--]; vm->frames[vm->fp].registers[dest] = vm->stack[vm->sp--];
return true; return true;
} }
case OP_MEM_ALLOC: {
uint32_t mem_dest = (uint32_t)vm->frames[vm->fp]
.allocated.end; /* get start of unallocated */
vm->frames[vm->fp].registers[dest].u =
mem_dest; /* store ptr of array to dest register */
uint32_t size = (uint32_t)vm->frames[vm->fp].registers[src1].u;
vm->memory[mem_dest].u = size;
vm->frames[vm->fp].allocated.end +=
size; /* increment to end of allocated */
return true;
}
case OP_MEM_MOV: {
uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u;
uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u;
vm->memory[dest_addr] = vm->memory[src_addr];
return true;
}
case OP_MEM_SWAP: {
uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u;
uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u;
vm->memory[dest_addr].u ^= vm->memory[src_addr].u;
vm->memory[src_addr].u ^= vm->memory[dest_addr].u;
vm->memory[dest_addr].u ^= vm->memory[src_addr].u;
return true;
}
case OP_REG_SWAP: {
vm->frames[vm->fp].registers[dest].u ^=
vm->frames[vm->fp].registers[src1].u;
vm->frames[vm->fp].registers[src1].u ^=
vm->frames[vm->fp].registers[dest].u;
vm->frames[vm->fp].registers[dest].u ^=
vm->frames[vm->fp].registers[src1].u;
return true;
}
case OP_REG_MOV: { case OP_REG_MOV: {
vm->frames[vm->fp].registers[dest].i = vm->frames[vm->fp].registers[src1].i; dest = read_u8(vm, code, vm->pc);
return true; vm->pc++;
} src1 = read_u8(vm, code, vm->pc);
case OP_GET_ACC: { vm->pc++;
vm->frames[vm->fp].registers[dest].u = vm->acc; vm->frames[vm->fp].registers[dest] = vm->frames[vm->fp].registers[src1];
return true;
}
case OP_GET_PC: {
vm->frames[vm->fp].registers[dest].u = vm->pc;
return true; return true;
} }
case OP_JMP: { case OP_JMP: {
vm->pc = vm->frames[vm->fp].registers[dest].u; /* Jump to address */ dest = read_u8(vm, code, vm->pc);
vm->pc++;
vm->pc = vm->frames[vm->fp].registers[dest]; /* Jump to address */
return true; return true;
} }
case OP_SYSCALL: { case OP_SYSCALL: {
uint32_t syscall_id = dest; u32 syscall_id, arg_count;
uint32_t arg_count = src2; u8 first_reg;
uint32_t first_reg = src1;
syscall_id = read_u32(vm, code, vm->pc);
vm->pc += 4;
arg_count = read_u32(vm, code, vm->pc);
vm->pc += 4;
first_reg = read_u8(vm, code, vm->pc);
vm->pc++;
switch (syscall_id) { switch (syscall_id) {
case SYSCALL_DEVICE_OPEN: { case SYSCALL_DEVICE_OPEN: {
if (arg_count >= 2) { if (arg_count >= 2) {
uint32_t path_ptr = Device *dev;
vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */ u32 path_ptr, mode, str_src;
uint32_t mode = path_ptr =
vm->frames[vm->fp].registers[first_reg + 1].u; /* R1: mode */ vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */
/* uint32_t length = vm->memory[path_ptr].u; */ mode = vm->frames[vm->fp].registers[first_reg + 1]; /* R1: mode */
uint32_t str_src = path_ptr + 1; str_src = path_ptr + 1;
const char *path = (const char *)&vm->memory[str_src];
Device *dev = find_device_by_path(vm, path); dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]);
if (dev) { if (dev) {
if (dev->ops->open) { if (dev->ops->open) {
int result = dev->ops->open(dev->data, mode); vm->acc = dev->ops->open(dev->data, mode);
vm->acc = result;
} else { } else {
vm->acc = 1; /* success, no open needed */ vm->acc = 1; /* success, no open needed */
} }
@ -209,23 +172,21 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_READ: { case SYSCALL_DEVICE_READ: {
if (arg_count >= 3) { if (arg_count >= 3) {
uint32_t path_ptr = Device *dev;
vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */ u32 path_ptr, buffer_ptr, size, str_src;
uint32_t buffer_ptr = vm->frames[vm->fp]
.registers[first_reg + 1]
.u; /* R1: buffer pointer */
uint32_t size =
vm->frames[vm->fp].registers[first_reg + 2].u; /* R2: size */
/* uint32_t length = vm->memory[path_ptr].u; */
uint32_t str_src = path_ptr + 1;
const char *path = (const char *)&vm->memory[str_src]; path_ptr =
Device *dev = find_device_by_path(vm, path); vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */
buffer_ptr = vm->frames[vm->fp]
.registers[first_reg + 1]; /* R1: buffer pointer */
size = vm->frames[vm->fp].registers[first_reg + 2]; /* R2: size */
str_src = path_ptr + 1;
dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]);
if (dev && dev->ops->read) { if (dev && dev->ops->read) {
int result = dev->ops->read(dev->data, vm->acc =
(uint8_t *)&vm->memory[buffer_ptr], size); dev->ops->read(dev->data, (u8 *)&vm->memory[buffer_ptr], size);
vm->acc = result;
} else { } else {
vm->acc = 0; vm->acc = 0;
} }
@ -236,24 +197,20 @@ bool step_vm(VM *vm) {
} }
case SYSCALL_DEVICE_WRITE: { case SYSCALL_DEVICE_WRITE: {
if (arg_count >= 3) { if (arg_count >= 2) {
uint32_t path_ptr = Device *dev;
vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */ u32 path_ptr, buffer_ptr, size, str_src;
uint32_t buffer_ptr = vm->frames[vm->fp] path_ptr =
.registers[first_reg + 1] vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */
.u; /* R1: buffer pointer */ buffer_ptr = vm->frames[vm->fp]
uint32_t size = .registers[first_reg + 1]; /* R1: buffer pointer */
vm->frames[vm->fp].registers[first_reg + 2].u; /* R2: size */ size = read_u32(vm, memory, buffer_ptr); /* R2: size */
/* uint32_t length = vm->memory[path_ptr].u; */ str_src = path_ptr += 4;
uint32_t str_src = path_ptr + 1;
const char *path = (const char *)&vm->memory[str_src];
Device *dev = find_device_by_path(vm, path);
dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]);
if (dev && dev->ops->write) { if (dev && dev->ops->write) {
int result = dev->ops->write( vm->acc = dev->ops->write(dev->data,
dev->data, (const uint8_t *)&vm->memory[buffer_ptr], size); (const u8 *)&vm->memory[buffer_ptr], size);
vm->acc = result;
} else { } else {
vm->acc = 0; vm->acc = 0;
} }
@ -265,16 +222,16 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_CLOSE: { case SYSCALL_DEVICE_CLOSE: {
if (arg_count >= 1) { if (arg_count >= 1) {
uint32_t path_ptr = Device *dev;
vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */ u32 path_ptr, str_src;
/* uint32_t length = vm->memory[path_ptr].u; */ path_ptr =
uint32_t str_src = path_ptr + 1; vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */
str_src = path_ptr + 1;
const char *path = (const char *)&vm->memory[str_src]; dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]);
Device *dev = find_device_by_path(vm, path);
if (dev && dev->ops->close) { if (dev && dev->ops->close) {
int result = dev->ops->close(dev->data); i32 result = dev->ops->close(dev->data);
vm->acc = result; vm->acc = result;
} else { } else {
vm->acc = 0; vm->acc = 0;
@ -287,22 +244,20 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_IOCTL: { case SYSCALL_DEVICE_IOCTL: {
if (arg_count >= 3) { if (arg_count >= 3) {
uint32_t path_ptr = Device *dev;
vm->frames[vm->fp].registers[first_reg].u; /* R0: device path */ u32 path_ptr, args_ptr, cmd, str_src;
uint32_t cmd = vm->frames[vm->fp] path_ptr =
.registers[first_reg + 1] vm->frames[vm->fp].registers[first_reg]; /* R0: device path */
.u; /* R1: ioctl command */ cmd =
uint32_t args_ptr = vm->frames[vm->fp] vm->frames[vm->fp].registers[first_reg + 1]; /* R1: ioctl command */
.registers[first_reg + 2] args_ptr =
.u; /* R2: args pointer */ vm->frames[vm->fp].registers[first_reg + 2]; /* R2: args pointer */
/* uint32_t length = vm->memory[path_ptr].u; */ str_src = path_ptr + 1;
uint32_t str_src = path_ptr + 1;
const char *path = (const char *)&vm->memory[str_src]; dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]);
Device *dev = find_device_by_path(vm, path);
if (dev && dev->ops && dev->ops->ioctl) { if (dev && dev->ops && dev->ops->ioctl) {
int result = dev->ops->ioctl(dev->data, cmd, &vm->memory[args_ptr]); i32 result = dev->ops->ioctl(dev->data, cmd, &vm->memory[args_ptr]);
vm->acc = result; vm->acc = result;
} else { } else {
vm->acc = 0; /* error or no ioctl support */ vm->acc = 0; /* error or no ioctl support */
@ -325,210 +280,309 @@ bool step_vm(VM *vm) {
return true; return true;
} }
case OP_ADD_INT: case OP_ADD_INT:
MATH_OP(i, +); MATH_OP(i32, +);
case OP_SUB_INT: case OP_SUB_INT:
MATH_OP(i, -); MATH_OP(i32, -);
case OP_MUL_INT: case OP_MUL_INT:
MATH_OP(i, *); MATH_OP(i32, *);
case OP_DIV_INT: case OP_DIV_INT:
MATH_OP(i, /); MATH_OP(i32, /);
case OP_ADD_UINT: case OP_ADD_UINT:
MATH_OP(u, +); MATH_OP(u32, +);
case OP_SUB_UINT: case OP_SUB_UINT:
MATH_OP(u, -); MATH_OP(u32, -);
case OP_MUL_UINT: case OP_MUL_UINT:
MATH_OP(u, *); MATH_OP(u32, *);
case OP_DIV_UINT: case OP_DIV_UINT:
MATH_OP(u, /); MATH_OP(u32, /);
case OP_ADD_REAL: case OP_MUL_REAL: {
MATH_OP(f, +); dest = read_u8(vm, code, vm->pc);
case OP_SUB_REAL: vm->pc++;
MATH_OP(f, -); src1 = read_u8(vm, code, vm->pc);
case OP_MUL_REAL: vm->pc++;
MATH_OP(f, *); src2 = read_u8(vm, code, vm->pc);
case OP_DIV_REAL: vm->pc++;
MATH_OP(f, /); vm->frames[vm->fp].registers[dest] = (vm->frames[vm->fp].registers[src1] *
vm->frames[vm->fp].registers[src2]) >>
16;
return true;
}
case OP_DIV_REAL: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
src2 = read_u8(vm, code, vm->pc);
vm->pc++;
vm->frames[vm->fp].registers[dest] =
(vm->frames[vm->fp].registers[src1] << 16) /
vm->frames[vm->fp].registers[src2];
return true;
}
case OP_ADD_REAL: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
src2 = read_u8(vm, code, vm->pc);
vm->pc++;
vm->frames[vm->fp].registers[dest] =
vm->frames[vm->fp].registers[src1] + vm->frames[vm->fp].registers[src2];
return true;
}
case OP_SUB_REAL: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
src2 = read_u8(vm, code, vm->pc);
vm->pc++;
vm->frames[vm->fp].registers[dest] =
vm->frames[vm->fp].registers[src1] - vm->frames[vm->fp].registers[src2];
return true;
}
case OP_REAL_TO_INT: { case OP_REAL_TO_INT: {
vm->frames[vm->fp].registers[dest].i = dest = read_u8(vm, code, vm->pc);
(int32_t)(vm->frames[vm->fp].registers[src1].f); vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
value = vm->frames[vm->fp].registers[src1];
if (value >= 0) {
vm->frames[vm->fp].registers[dest] = value >> 16;
} else {
vm->frames[vm->fp].registers[dest] = -((-value) >> 16);
}
return true; return true;
} }
case OP_INT_TO_REAL: { case OP_INT_TO_REAL: {
vm->frames[vm->fp].registers[dest].f = dest = read_u8(vm, code, vm->pc);
(float)(vm->frames[vm->fp].registers[src1].i); vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
vm->frames[vm->fp].registers[dest] =
(vm->frames[vm->fp].registers[src1] << 16);
return true; return true;
} }
case OP_REAL_TO_UINT: { case OP_REAL_TO_UINT: {
vm->frames[vm->fp].registers[dest].u = dest = read_u8(vm, code, vm->pc);
(uint32_t)(vm->frames[vm->fp].registers[src1].f); vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
value = vm->frames[vm->fp].registers[src1];
if (value < 0) {
vm->frames[vm->fp].registers[dest] = 0;
} else {
vm->frames[vm->fp].registers[dest] = AS_UINT(value >> 16);
}
return true; return true;
} }
case OP_UINT_TO_REAL: { case OP_UINT_TO_REAL: {
vm->frames[vm->fp].registers[dest].f = dest = read_u8(vm, code, vm->pc);
(float)(vm->frames[vm->fp].registers[src1].u); vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
vm->frames[vm->fp].registers[dest] =
AS_INT(vm->frames[vm->fp].registers[src1] << 16);
return true; return true;
} }
case OP_JEQ_UINT: { case OP_JEQ_UINT: {
COMPARE_AND_JUMP(uint32_t, u, ==); COMPARE_AND_JUMP(u32, ==);
} }
case OP_JGT_UINT: { case OP_JGT_UINT: {
COMPARE_AND_JUMP(uint32_t, u, >); COMPARE_AND_JUMP(u32, >);
} }
case OP_JLT_UINT: { case OP_JLT_UINT: {
COMPARE_AND_JUMP(uint32_t, u, <); COMPARE_AND_JUMP(u32, <);
} }
case OP_JLE_UINT: { case OP_JLE_UINT: {
COMPARE_AND_JUMP(uint32_t, u, <=); COMPARE_AND_JUMP(u32, <=);
} }
case OP_JGE_UINT: { case OP_JGE_UINT: {
COMPARE_AND_JUMP(uint32_t, u, >=); COMPARE_AND_JUMP(u32, >=);
} }
case OP_JEQ_INT: { case OP_JEQ_INT: {
COMPARE_AND_JUMP(int32_t, i, ==); COMPARE_AND_JUMP(i32, ==);
} }
case OP_JGT_INT: { case OP_JGT_INT: {
COMPARE_AND_JUMP(int32_t, i, >); COMPARE_AND_JUMP(i32, >);
} }
case OP_JLT_INT: { case OP_JLT_INT: {
COMPARE_AND_JUMP(int32_t, i, <); COMPARE_AND_JUMP(i32, <);
} }
case OP_JLE_INT: { case OP_JLE_INT: {
COMPARE_AND_JUMP(int32_t, i, <=); COMPARE_AND_JUMP(i32, <=);
} }
case OP_JGE_INT: { case OP_JGE_INT: {
COMPARE_AND_JUMP(int32_t, i, >=); COMPARE_AND_JUMP(i32, >=);
} }
case OP_JEQ_REAL: { case OP_JEQ_REAL: {
COMPARE_AND_JUMP(int32_t, i, ==); COMPARE_AND_JUMP(i32, ==);
} }
case OP_JGT_REAL: { case OP_JGT_REAL: {
COMPARE_AND_JUMP(float, u, >); COMPARE_AND_JUMP(i32, >);
} }
case OP_JLT_REAL: { case OP_JLT_REAL: {
COMPARE_AND_JUMP(float, u, <); COMPARE_AND_JUMP(i32, <);
} }
case OP_JGE_REAL: { case OP_JGE_REAL: {
COMPARE_AND_JUMP(float, u, >=); COMPARE_AND_JUMP(i32, >=);
} }
case OP_JLE_REAL: { case OP_JLE_REAL: {
COMPARE_AND_JUMP(float, u, <=); COMPARE_AND_JUMP(i32, <=);
} }
case OP_INT_TO_STRING: { case OP_INT_TO_STRING: {
int32_t a = (int32_t)vm->frames[vm->fp].registers[src1].i; /* get value */
char buffer[32]; char buffer[32];
int len = sprintf(buffer, "%d", a); dest = read_u8(vm, code, vm->pc);
uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */ vm->pc++;
vm->frames[vm->fp].registers[dest].u = ptr; src1 = read_u8(vm, code, vm->pc);
vm->pc++;
int_to_string(AS_INT(vm->frames[vm->fp].registers[src1]), buffer);
ptr = str_alloc(vm, buffer, strlen(buffer));
vm->frames[vm->fp].registers[dest] = ptr;
return true; return true;
} }
case OP_UINT_TO_STRING: { case OP_UINT_TO_STRING: {
uint32_t a = (uint32_t)vm->frames[vm->fp].registers[src1].u; /* get value */
char buffer[32]; char buffer[32];
int len = sprintf(buffer, "%d", a); dest = read_u8(vm, code, vm->pc);
uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */ vm->pc++;
vm->frames[vm->fp].registers[dest].u = ptr; src1 = read_u8(vm, code, vm->pc);
vm->pc++;
uint_to_string(vm->frames[vm->fp].registers[src1], buffer);
ptr = str_alloc(vm, buffer, strlen(buffer));
vm->frames[vm->fp].registers[dest] = ptr;
return true; return true;
} }
case OP_REAL_TO_STRING: { case OP_REAL_TO_STRING: {
float a = (float)vm->frames[vm->fp].registers[src1].f; /* get value */
char buffer[32]; char buffer[32];
int len = sprintf(buffer, "%f", a); dest = read_u8(vm, code, vm->pc);
uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */ vm->pc++;
vm->frames[vm->fp].registers[dest].u = ptr; src1 = read_u8(vm, code, vm->pc);
vm->pc++;
fixed_to_string(AS_INT(vm->frames[vm->fp].registers[src1]), buffer);
ptr = str_alloc(vm, buffer, strlen(buffer)); /* copy buffer to dest */
vm->frames[vm->fp].registers[dest] = ptr;
return true; return true;
} }
case OP_STRING_TO_INT: { case OP_STRING_TO_INT: {
uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; /* not implemented yet */
uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; return false;
char *endptr;
int32_t value = (int32_t)strtol((char*)&vm->memory[src_addr + 1], &endptr, 10);
vm->memory[dest_addr].i = value;
return true;
} }
case OP_STRING_TO_UINT: { case OP_STRING_TO_UINT: {
uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; /* not implemented yet */
uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; return false;
long value = atol((char*)&vm->memory[src_addr + 1]);
vm->memory[dest_addr].u = value;
return true;
} }
case OP_STRING_TO_REAL: { case OP_STRING_TO_REAL: {
uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u; /* not implemented yet */
uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u; return false;
float value = atof((char*)&vm->memory[src_addr + 1]);
vm->memory[dest_addr].u = value;
return true;
}
case OP_DBG_READ_STRING: {
uint32_t str_addr = vm->mp++;
uint32_t length = 0;
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
uint32_t idx = length % 4;
vm->memory[vm->mp].c[idx] = (char)ch;
length++;
if (idx == 3)
vm->mp++;
}
uint32_t i, rem = length % 4;
if (rem != 0) {
for (i = rem; i < 4; i++) {
vm->memory[vm->mp].c[i] = '\0';
}
vm->mp++;
}
vm->memory[str_addr].u = length;
vm->frames[vm->fp].allocated.end = vm->mp;
vm->frames[vm->fp].registers[dest].u = str_addr;
return true;
}
case OP_DBG_PRINT_STRING: {
uint32_t ptr = (uint32_t)vm->frames[vm->fp].registers[src1].u;
uint32_t length = vm->memory[ptr].u;
uint32_t str_src = ptr + 1;
uint32_t i;
for (i = 0; i < length; i++) {
uint8_t ch = vm->memory[str_src + (i / 4)].c[i % 4];
if (ch == '\0')
break;
putchar(ch);
}
putchar('\n');
return true;
}
case OP_CMP_STRING: {
uint32_t addr1 = (uint32_t)vm->frames[vm->fp].registers[src1].u;
uint32_t addr2 = (uint32_t)vm->frames[vm->fp].registers[src2].u;
uint32_t length1 = vm->memory[addr1 - 1].u;
uint32_t length2 = vm->memory[addr2 - 1].u;
uint32_t equal =
1; /* we dont have a native boolean type so we use uint32_t */
if (length1 != length2) {
equal = 0;
} else {
uint32_t i = 0;
while (i < length1) {
uint32_t char1 = vm->memory[addr1 + i].u;
uint32_t char2 = vm->memory[addr2 + i].u;
if (char1 != char2) {
equal = 0;
break;
}
if ((char1 & 0xFF) == '\0' && (char2 & 0xFF) == '\0') {
equal = 1;
break;
}
}
}
vm->memory[dest].u = equal;
return true;
} }
} }
return false; /* something bad happened */ return false; /* something bad happened */
} }
/* Static digit lookup table (0-9) */
const char digits[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
/* Writes decimal digits of 'value' backwards into 'buf_end' (inclusive),
stopping at 'buf_start'. Returns pointer to first written digit. */
char *write_digits_backwards(u32 value, char *buf_end, char *buf_start) {
char *p = buf_end;
if (value == 0) {
*--p = '0';
} else {
u32 num = value;
while (num && p > buf_start) {
*--p = digits[num % 10];
num /= 10;
}
}
return p;
}
void uint_to_string(u32 value, char *buffer) {
char temp[16];
char *start;
char *end = temp + sizeof(temp) - 1;
*end = '\0';
start = write_digits_backwards(value, end, temp);
strcopy(buffer, start, end - start + 1); /* +1 for null terminator */
}
void int_to_string(i32 value, char *buffer) {
char temp[17]; /* Extra space for '-' */
i32 negative = 0;
u32 abs_value;
char *end = temp + sizeof(temp) - 1;
*end = '\0';
if (value == (-2147483647 - 1)) { /* INT32_MIN */
strcopy(buffer, "-2147483648", 12);
return;
}
if (value == 0) {
*--end = '0';
} else {
if (value < 0) {
negative = 1;
abs_value = (u32)(-value);
} else {
abs_value = (u32)value;
}
end = write_digits_backwards(abs_value, end, temp);
if (negative) {
*--end = '-';
}
}
strcopy(buffer, end, temp + sizeof(temp) - end);
}
void fixed_to_string(i32 value, char *buffer) {
char temp[32];
i32 negative;
u32 int_part;
u32 frac_part, frac_digits;
char *end = temp + sizeof(temp) - 1;
*end = '\0';
negative = 0;
if (value < 0) {
negative = 1;
value = -value;
}
int_part = AS_UINT(value >> 16);
frac_part = AS_UINT(value & 0xFFFF);
/* Convert fractional part to 5 decimal digits */
frac_digits = (frac_part * 100000U) / 65536U;
/* Trim trailing zeros */
while (frac_digits > 0 && frac_digits % 10 == 0) {
frac_digits /= 10;
}
if (frac_digits > 0) {
end = write_digits_backwards(frac_digits, end, temp);
*--end = '.';
}
if (int_part == 0 && frac_digits == 0) {
*--end = '0';
} else {
end = write_digits_backwards(int_part, end, temp);
}
if (negative) {
*--end = '-';
}
strcopy(buffer, end, temp + sizeof(temp) - end);
}

View File

@ -4,6 +4,9 @@
#include "opcodes.h" #include "opcodes.h"
bool step_vm(VM *vm); bool step_vm(VM *vm);
uint32_t str_alloc(VM *vm, const char *str, uint32_t length); u32 str_alloc(VM *vm, const char *str, u32 length);
void fixed_to_string(i32 value, char *buffer);
void int_to_string(i32 value, char *buffer);
void uint_to_string(u32 value, char *buffer);
#endif #endif

View File

@ -1,6 +1,6 @@
main: main:
lodr $0 5.0 lodr $0 5.0
lodi $1 50000 lodi $1 5000
lodi $2 0 lodi $2 0
lodi $3 -1 lodi $3 -1
loop_body: loop_body: