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.wasm
memory_dump.bin
src/build/
build/
.gdb_history
.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
for i = 50000, 0, -1 do
for i = 5000, 0, -1 do
a = a + 5.0
end
local b = math.floor(a)

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
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;
}
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 <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;
@ -27,12 +64,17 @@ int screen_open(void *data, uint32_t mode) {
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;
if (size > screen->framebuffer_size * sizeof(uint8_t)) {
if (size > screen->framebuffer_size * sizeof(u8)) {
return -1;
}
@ -40,7 +82,7 @@ int screen_write(void *data, const uint8_t *buffer, uint32_t size) {
return 0;
}
int screen_close(void *data) {
i32 screen_close(void *data) {
ScreenDeviceData *screen = (ScreenDeviceData *)data;
if (screen->texture) {
@ -59,15 +101,19 @@ int screen_close(void *data) {
}
/* 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;
if (size < 3 * sizeof(uint32_t))
if (size < 3 * sizeof(u32))
return -1;
uint32_t *out = (uint32_t *)buffer;
u32 *out = (u32 *)buffer;
out[0] = mouse->x;
out[1] = mouse->y;
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;
}
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;
if (size < (uint32_t)kbd->key_count)
if (size < (u32)kbd->key_count)
return -1;
memcpy(buffer, kbd->keys, kbd->key_count);
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 */
}
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 */
typedef struct screen_device_data_s {
uint32_t width;
uint32_t height;
uint32_t framebuffer_pos;
uint32_t framebuffer_size;
u32 width;
u32 height;
u32 framebuffer_pos;
u32 framebuffer_size;
VM* vm;
SDL_Window *window;
SDL_Renderer *renderer;
@ -16,32 +16,37 @@ typedef struct screen_device_data_s {
/* Mouse device data */
typedef struct mouse_device_data_s {
uint32_t x;
uint32_t y;
uint8_t btn1;
uint8_t btn2;
uint8_t btn3;
uint8_t btn4;
u32 x;
u32 y;
u8 btn1;
u8 btn2;
u8 btn3;
u8 btn4;
} MouseDeviceData;
/* Keyboard device data */
typedef struct keyboard_device_data_s {
const uint8_t *keys;
int32_t key_count;
const u8 *keys;
i32 key_count;
} KeyboardDeviceData;
int screen_open(void *data, uint32_t mode);
int screen_read(void *data, uint8_t *buffer, uint32_t size);
int screen_write(void *data, const uint8_t *buffer, uint32_t size);
int screen_close(void *data);
i32 screen_open(void *data, u32 mode);
i32 screen_read(void *data, u8 *buffer, u32 size);
i32 screen_write(void *data, const u8 *buffer, u32 size);
i32 screen_close(void *data);
int mouse_open(void *data, uint32_t mode);
int mouse_read(void *data, uint8_t *buffer, uint32_t size);
int mouse_write(void *data, const uint8_t *buffer, uint32_t size);
int mouse_close(void *data);
i32 mouse_open(void *data, u32 mode);
i32 mouse_read(void *data, u8 *buffer, u32 size);
i32 mouse_write(void *data, const u8 *buffer, u32 size);
i32 mouse_close(void *data);
int keyboard_open(void *data, uint32_t mode);
int keyboard_read(void *data, uint8_t *buffer, uint32_t size);
int keyboard_write(void *data, const uint8_t *buffer, uint32_t size);
int keyboard_close(void *data);
i32 keyboard_open(void *data, u32 mode);
i32 keyboard_read(void *data, u8 *buffer, u32 size);
i32 keyboard_write(void *data, const u8 *buffer, u32 size);
i32 keyboard_close(void *data);
i32 console_open(void *data, u32 mode);
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,
.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 MouseDeviceData mouse_data = {0};
static KeyboardDeviceData keyboard_data = {0};
void compileFile(const char *path, VM *vm) {
USED(vm);
FILE *f = fopen(path, "rb");
if (!f) {
perror("fopen");
@ -84,13 +94,13 @@ enum FlagType {
#define MAX_INPUT_FILES 16 /* Adjust based on your system's constraints */
struct CompilerConfig {
uint32_t flags;
u32 flags;
char *input_files[MAX_INPUT_FILES];
int input_file_count;
i32 input_file_count;
};
int parse_arguments(int argc, char *argv[], struct CompilerConfig *config) {
int i;
i32 parse_arguments(i32 argc, char *argv[], struct CompilerConfig *config) {
i32 i;
/* Initialize config */
config->flags = 0;
@ -131,6 +141,9 @@ int parse_arguments(int argc, char *argv[], struct CompilerConfig *config) {
return 0;
}
/*
* This needs to be done dynamically eventually
*/
void register_sdl_devices(VM *vm) {
screen_data.vm = vm;
screen_data.width = 640;
@ -156,7 +169,7 @@ void register_sdl_devices(VM *vm) {
&keyboard_ops);
}
int main(int argc, char *argv[]) {
i32 main(i32 argc, char *argv[]) {
struct CompilerConfig 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) {
compile_internal_test(config.input_files[0], &vm);
} else {
int j;
i32 j;
for (j = 0; j < config.input_file_count; j++) {
compileFile(config.input_files[j], &vm);
}
@ -206,9 +219,10 @@ int main(int argc, char *argv[]) {
}
}
bool running = true;
vm_register_device(&vm, "/dev/term/0", "terminal", nil, &console_device_ops);
if (config.flags & FLAG_GUI_MODE) {
uint32_t i;
u32 i;
register_sdl_devices(&vm);
while (running) {
for (i = 0; i < vm.dc; i++) {
@ -260,7 +274,7 @@ int main(int argc, char *argv[]) {
if (screen->texture && screen->renderer) {
SDL_UpdateTexture(screen->texture, NULL,
&vm.memory[screen->framebuffer_pos],
screen->width * sizeof(uint32_t));
screen->width * sizeof(u32));
SDL_RenderClear(screen->renderer);
@ -271,9 +285,9 @@ int main(int argc, char *argv[]) {
float scale = SDL_min(scale_x, scale_y);
SDL_Rect dstrect = {
(int)((output_rect.w - screen->width * scale) / 2),
(int)((output_rect.h - screen->height * scale) / 2),
(int)(screen->width * scale), (int)(screen->height * scale)};
(i32)((output_rect.w - screen->width * scale) / 2),
(i32)((output_rect.h - screen->height * scale) / 2),
(i32)(screen->width * scale), (i32)(screen->height * scale)};
SDL_RenderCopy(screen->renderer, screen->texture, NULL, &dstrect);
SDL_RenderPresent(screen->renderer);

View File

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

View File

@ -1,16 +1,19 @@
#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) return -1;
if (vm->dc >= DEVICES_SIZE)
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';
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->data = data;
@ -21,9 +24,9 @@ int vm_register_device(VM *vm, const char *path, const char *type, void *data, D
/* Find device by path */
Device *find_device_by_path(VM *vm, const char *path) {
uint32_t i;
u32 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];
}
}
@ -32,9 +35,9 @@ Device* find_device_by_path(VM *vm, const char *path) {
/* Find device by type (useful for checking capabilities) */
Device *find_device_by_type(VM *vm, const char *type) {
uint32_t i;
u32 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];
}
}
@ -42,10 +45,11 @@ Device* find_device_by_type(VM *vm, const char *type) {
}
/* Find all devices of a type */
int find_devices_by_type(VM *vm, const char *type, Device **results, uint32_t max_results) {
uint32_t i, count = 0;
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 (strcmp(vm->devices[i].type, type) == 0) {
if (streq(vm->devices[i].type, type)) {
results[count++] = &vm->devices[i];
}
}

View File

@ -3,9 +3,9 @@
#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_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

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
#include "common.h"
#include <stdint.h>
typedef enum {
OP_HALT, /* halt : terminate execution */
OP_JMP, /* jump : jump to address dest unconditionally */
OP_GET_PC, /* pc : dest = current program counter */
OP_CALL, /* call : creates a new frame */
OP_RETURN, /* retn : returns from a frame to the parent frame */
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_PUSH, /* push : push str ref from register onto the stack and copy str */
OP_POP, /* pop : pop int from stack onto the register */
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_ADD_INT, /* addi : 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_UINT_TO_STRING, /* utos : 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_UINT, /* stou : dest = src1 as uint */
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 */
OP_STRING_TO_REAL /* stor : dest = src1 as real */
} 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
typedef struct frame_s {
Value registers[MAX_REGS]; /* R0-R31 */
uint32_t rp; /* register pointer (last unused) */
Slice allocated; /* start and end of global allocated block */
u32 registers[MAX_REGS]; /* R0-R31 */
u32 rp; /* register pointer (last unused) */
u32 start; /* start and end of global allocated block */
u32 end;
} Frame;
typedef enum {
@ -96,16 +68,15 @@ typedef enum {
SYSCALL_DEVICE_READ,
SYSCALL_DEVICE_WRITE,
SYSCALL_DEVICE_CLOSE,
SYSCALL_DEVICE_IOCTL,
SYSCALL_DEVICE_IOCTL
} SyscallID;
typedef struct device_ops_s {
int (*open)(void *device_data, uint32_t mode);
int (*read)(void *device_data, uint8_t *buffer, uint32_t size);
int (*write)(void *device_data, const uint8_t *buffer, uint32_t size);
int (*close)(void *device_data);
int (*ioctl)(void *device_data, uint32_t cmd,
void *args); /* optional control */
i32 (*open)(void *device_data, u32 mode);
i32 (*read)(void *device_data, u8 *buffer, u32 size);
i32 (*write)(void *device_data, const u8 *buffer, u32 size);
i32 (*close)(void *device_data);
i32 (*ioctl)(void *device_data, u32 cmd, void *args); /* optional control */
} DeviceOps;
#define DEVICE_TYPE_MAX_LENGTH 24 /* 23 chars + null terminator */
@ -117,7 +88,7 @@ typedef struct device_s {
etc. */
void *data; /* device-specific data */
DeviceOps *ops; /* operations vtable */
uint32_t flags; /* permissions, status, etc. */
u32 flags; /* permissions, status, etc. */
} Device;
#define MEMORY_SIZE (640 * 480 + 65536)
@ -126,20 +97,61 @@ typedef struct device_s {
#define STACK_SIZE 256
#define DEVICES_SIZE 8
typedef struct vm_s {
uint32_t pc; /* program counter */
uint32_t cp; /* code pointer (last allocated opcode) */
uint32_t fp; /* frame pointer (current frame) */
uint32_t sp; /* stack pointer (top of stack) */
uint32_t rp; /* return stack pointer (top of stack) */
uint32_t mp; /* memory pointer (last allocated value) */
uint32_t dc; /* device count */
uint32_t acc; /* accumulator (temporary results like SYSCALL status) */
Device devices[DEVICES_SIZE]; /* device definitions */
u32 pc; /* program counter */
u32 cp; /* code pointer (last allocated opcode) */
u32 fp; /* frame pointer (current frame) */
u32 sp; /* stack pointer (top of stack) */
u32 rp; /* return stack pointer (top of stack) */
u32 mp; /* memory pointer (last allocated value) */
u32 dc; /* device count */
u32 acc; /* accumulator (temporary results like SYSCALL status) */
Frame frames[FRAMES_SIZE]; /* function call frames */
Value stack[STACK_SIZE]; /* main stack */
Value return_stack[STACK_SIZE]; /* return stack (for call recursion) */
Value code[CODE_SIZE]; /* code block */
Value memory[MEMORY_SIZE]; /* memory block */
u32 stack[STACK_SIZE]; /* main stack */
u32 return_stack[STACK_SIZE]; /* return stack (for call recursion) */
Device devices[DEVICES_SIZE]; /* device definitions */
u8 code[CODE_SIZE]; /* code block */
u8 memory[MEMORY_SIZE]; /* memory block */
} 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

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,43 +1,44 @@
#include "test.h"
#include "opcodes.h"
#include "str.h"
#include "vm.h"
#include <string.h>
uint32_t real_alloc(VM *vm, float v) {
uint32_t addr = vm->mp;
vm->memory[vm->mp++].f = v;
vm->frames[vm->fp].allocated.end++;
u32 real_alloc(VM *vm, float v) {
i32 fixed = TO_FIXED(v);
u32 addr = vm->mp;
write_u32(vm, memory, vm->mp, fixed);
vm->mp += 4;
vm->frames[vm->fp].end += 4;
return addr;
}
uint32_t nat_alloc(VM *vm, uint32_t v) {
uint32_t addr = vm->mp;
vm->memory[vm->mp++].u = v;
vm->frames[vm->fp].allocated.end++;
u32 nat_alloc(VM *vm, u32 v) {
u32 addr = vm->mp;
write_u32(vm, memory, vm->mp, v);
vm->mp += 4;
vm->frames[vm->fp].end += 4;
return addr;
}
uint32_t int_alloc(VM *vm, int32_t v) {
uint32_t addr = vm->mp;
vm->memory[vm->mp++].i = v;
vm->frames[vm->fp].allocated.end++;
u32 int_alloc(VM *vm, i32 v) {
u32 addr = vm->mp;
write_u32(vm, memory, vm->mp, v);
vm->mp += 4;
vm->frames[vm->fp].end += 4;
return addr;
}
/* Array of test mappings */
struct TestMapping internal_tests[] = {
{"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},
/* Add more test mappings here */
{NULL, NULL} /* Sentinel to mark end of array */
};
bool compile_internal_test(const char *filename, VM *vm) {
int i;
i32 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);
}
}
@ -45,150 +46,90 @@ bool compile_internal_test(const char* filename, VM* vm) {
}
bool test_simple_compile(VM *vm) {
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0);
vm->code[vm->cp++].u = nat_alloc(vm, 1);
vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0);
vm->code[vm->cp++].u = nat_alloc(vm, 2);
vm->code[vm->cp++].u = OP(OP_ADD_UINT, 2, 1, 0); /* let sum = 1 + 2; */
vm->code[vm->cp++].u = OP(OP_UINT_TO_STRING, 3, 2, 0);
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;
}
u32 ptr;
u32 terminal_path_addr = str_alloc(vm, "/dev/term/0", 12);
vm->code[vm->cp++] = OP_LOAD;
vm->code[vm->cp++] = 0;
ptr = real_alloc(vm, 1.0f);
write_u32(vm, code, vm->cp, ptr); vm->cp+=4;
bool test_loop_compile(VM *vm) {
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* let a = 5.0 */
vm->code[vm->cp++].u = real_alloc(vm, 5.0f);
vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* do (i = 50000, 0, -1) { */
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;
}
vm->code[vm->cp++] = OP_LOAD;
vm->code[vm->cp++] = 1;
ptr = real_alloc(vm, 2.0f);
write_u32(vm, code, vm->cp, ptr); vm->cp+=4;
bool test_add_function_compile(VM *vm) {
/* fn main() */
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_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;
}
vm->code[vm->cp++] = OP_ADD_UINT;
vm->code[vm->cp++] = 2;
vm->code[vm->cp++] = 1;
vm->code[vm->cp++] = 0; /* let sum = 1 + 2; */
bool test_recursive_function_compile(VM *vm) {
/* fn main() */
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0); /* 35 */
vm->code[vm->cp++].u = int_alloc(vm, 35);
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 = 9;
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(fib(35).toS()); */
vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0);
/* fn fib() */
vm->code[vm->cp++].u = OP(OP_POP, 0, 0, 0); /* n int */
vm->code[vm->cp++].u = OP(OP_LOAD, 1, 0, 0); /* 2 */
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);
vm->code[vm->cp++] = OP_REAL_TO_STRING;
vm->code[vm->cp++] = 4;
vm->code[vm->cp++] = 2;
vm->code[vm->cp++] = OP_LOAD_IMM;
vm->code[vm->cp++] = 3;
write_u32(vm, code, vm->cp, terminal_path_addr); vm->cp+=4;
vm->code[vm->cp++] = OP_SYSCALL;
write_u32(vm, code, vm->cp, AS_UINT(SYSCALL_DEVICE_WRITE)); vm->cp+=4;
write_u32(vm, code, vm->cp, AS_UINT(2)); vm->cp+=4;
vm->code[vm->cp++] = 3;
/* syscall_id=WRITE, arg_count=2, start_reg=3 ; print(sum.toS()); */
vm->code[vm->cp++] = OP_HALT; /* explicit halt */
return true;
}
bool test_window_click_compile(VM *vm) {
uint32_t screen_path_addr = str_alloc(vm, "/dev/screen/0", 14);
/*uint32_t mouse_path_addr = str_alloc(vm, "/dev/mouse/0", 12);*/
u32 test_pixel_addr, loop_start, screen_path_addr = str_alloc(vm, "/dev/screen/0", 14);
/* 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 */
vm->code[vm->cp++] = OP_LOAD; /* R0 = screen path */
vm->code[vm->cp++] = 0;
vm->code[vm->cp++] = nat_alloc(vm, screen_path_addr);
/* Check if open succeeded (result in vm->acc) */
vm->code[vm->cp++].u = OP(OP_GET_ACC, 2, 0, 0); /* Move result to R2 */
vm->code[vm->cp++] = OP_LOAD; /* R1 = mode (0) */
vm->code[vm->cp++] = 1;
vm->code[vm->cp++] = int_alloc(vm, 0);
/* 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++;
vm->code[vm->cp++] = OP_SYSCALL;
vm->code[vm->cp++] = SYSCALL_DEVICE_OPEN;
vm->code[vm->cp++] = 0; /* first_reg */
vm->code[vm->cp++] = 2; /* arg_count */
/* Main loop to check for mouse input */
uint32_t loop_start = vm->cp;
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;
/* Write to screen: R0=path, R1=buffer, R2=size */
vm->code[vm->cp++].u = OP(OP_LOAD, 0, 0, 0);
vm->code[vm->cp++].u = nat_alloc(vm, screen_path_addr);
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 */
loop_start = vm->cp;
vm->code[vm->cp++].u = OP(OP_LOAD, 3, 0, 0);
vm->code[vm->cp++].u = nat_alloc(vm, loop_start);
vm->code[vm->cp++].u = OP(OP_JMP, 3, 0, 0); /* Infinite loop for testing */
vm->code[vm->cp++].u = OP(OP_HALT, 0, 0, 0);
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;
}

682
src/vm.c
View File

@ -1,56 +1,50 @@
#include "vm.h"
#include "device.h"
#include "opcodes.h"
#include <string.h>
#include "str.h"
/* no inline fn in ANSI C :( */
#define COMPARE_AND_JUMP(type, accessor, op) \
#define COMPARE_AND_JUMP(type, op) \
do { \
type value = vm->frames[vm->fp].registers[src1].accessor; \
type value2 = vm->frames[vm->fp].registers[src2].accessor; \
vm->pc = \
(value op value2) ? vm->frames[vm->fp].registers[dest].u : vm->pc; \
type value, value2; \
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++; \
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; \
} while (0)
#define MATH_OP(accessor, op) \
#define MATH_OP(type, op) \
do { \
vm->frames[vm->fp].registers[dest].accessor = \
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] = (type)vm->frames[vm->fp] \
.registers[src1] op(type) \
vm->frames[vm->fp] \
.registers[src1] \
.accessor op vm->frames[vm->fp] \
.registers[src2] \
.accessor; \
.registers[src2]; \
return true; \
} while (0)
/**
* Embeds a string into the VM
*/
uint32_t str_alloc(VM *vm, const char *str, uint32_t length) {
uint32_t str_addr = vm->mp++;
uint32_t temp = 0;
while (temp < length) {
uint32_t idx = temp % 4;
vm->memory[vm->mp].c[idx] = str[temp];
temp++;
if (idx == 3)
vm->mp++;
u32 str_alloc(VM *vm, const char *str, u32 length) {
u32 str_addr = vm->mp;
u32 i = 0;
vm->mp += 4;
while (i < length) {
vm->memory[vm->mp++] = str[i++];
}
vm->memory[vm->mp++] = '\0';
uint32_t i, rem = temp % 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;
write_u32(vm, memory, str_addr, length);
vm->frames[vm->fp].end = vm->mp;
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.
*/
bool step_vm(VM *vm) {
/* Get current instruction & Advance to next instruction */
uint32_t instruction = vm->code[vm->pc++].u;
u8 opcode, dest, src1, src2;
u32 v, ptr;
i32 value;
uint8_t opcode = (instruction >> 24) & 0xFF;
uint8_t dest = (instruction >> 16) & 0xFF;
uint8_t src1 = (instruction >> 8) & 0xFF;
uint8_t src2 = instruction & 0xFF;
/* Get current instruction & Advance to next instruction */
opcode = vm->code[vm->pc++];
switch (opcode) {
case OP_HALT: {
return false;
}
case OP_CALL: {
uint32_t jmp = vm->code[vm->pc++].u; /* location of function in code */
vm->return_stack[vm->rp++].u = vm->pc; /* set return address */
u32 jmp = read_u32(vm, code, vm->pc); /* location of function in code */
vm->pc += 4;
vm->return_stack[vm->rp++] = vm->pc; /* set return address */
vm->fp++; /* increment to the next free frame */
vm->frames[vm->fp].allocated.start =
vm->mp; /* set start of new memory block */
vm->frames[vm->fp].start = vm->mp; /* set start of new memory block */
vm->pc = jmp;
return true;
}
case OP_RETURN: {
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->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 */
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: {
uint32_t ptr = vm->code[vm->pc++].u;
Value v = vm->memory[ptr];
dest = read_u8(vm, code, vm->pc);
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;
return true;
}
case OP_STORE: {
uint32_t ptr = vm->code[vm->pc++].u;
vm->memory[ptr] = vm->frames[vm->fp].registers[src1];
return true;
}
case OP_PUT: {
uint32_t addr = vm->frames[vm->fp].registers[dest].u;
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;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
ptr = read_u32(vm, code, vm->pc);
vm->pc += 4;
v = vm->frames[vm->fp].registers[src1];
write_u32(vm, memory, ptr, v);
return true;
}
case OP_PUSH: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
vm->stack[++vm->sp] = vm->frames[vm->fp].registers[dest];
return true;
}
case OP_POP: {
dest = read_u8(vm, code, vm->pc);
vm->pc++;
vm->frames[vm->fp].registers[dest] = vm->stack[vm->sp--];
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: {
vm->frames[vm->fp].registers[dest].i = vm->frames[vm->fp].registers[src1].i;
return true;
}
case OP_GET_ACC: {
vm->frames[vm->fp].registers[dest].u = vm->acc;
return true;
}
case OP_GET_PC: {
vm->frames[vm->fp].registers[dest].u = vm->pc;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
src1 = read_u8(vm, code, vm->pc);
vm->pc++;
vm->frames[vm->fp].registers[dest] = vm->frames[vm->fp].registers[src1];
return true;
}
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;
}
case OP_SYSCALL: {
uint32_t syscall_id = dest;
uint32_t arg_count = src2;
uint32_t first_reg = src1;
u32 syscall_id, arg_count;
u8 first_reg;
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) {
case SYSCALL_DEVICE_OPEN: {
if (arg_count >= 2) {
uint32_t path_ptr =
vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */
uint32_t mode =
vm->frames[vm->fp].registers[first_reg + 1].u; /* R1: mode */
/* uint32_t length = vm->memory[path_ptr].u; */
uint32_t str_src = path_ptr + 1;
const char *path = (const char *)&vm->memory[str_src];
Device *dev;
u32 path_ptr, mode, str_src;
path_ptr =
vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */
mode = vm->frames[vm->fp].registers[first_reg + 1]; /* R1: mode */
str_src = path_ptr + 1;
Device *dev = find_device_by_path(vm, path);
dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]);
if (dev) {
if (dev->ops->open) {
int result = dev->ops->open(dev->data, mode);
vm->acc = result;
vm->acc = dev->ops->open(dev->data, mode);
} else {
vm->acc = 1; /* success, no open needed */
}
@ -209,23 +172,21 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_READ: {
if (arg_count >= 3) {
uint32_t path_ptr =
vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */
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;
Device *dev;
u32 path_ptr, buffer_ptr, size, str_src;
const char *path = (const char *)&vm->memory[str_src];
Device *dev = find_device_by_path(vm, path);
path_ptr =
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) {
int result = dev->ops->read(dev->data,
(uint8_t *)&vm->memory[buffer_ptr], size);
vm->acc = result;
vm->acc =
dev->ops->read(dev->data, (u8 *)&vm->memory[buffer_ptr], size);
} else {
vm->acc = 0;
}
@ -236,24 +197,20 @@ bool step_vm(VM *vm) {
}
case SYSCALL_DEVICE_WRITE: {
if (arg_count >= 3) {
uint32_t path_ptr =
vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */
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];
Device *dev = find_device_by_path(vm, path);
if (arg_count >= 2) {
Device *dev;
u32 path_ptr, buffer_ptr, size, str_src;
path_ptr =
vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */
buffer_ptr = vm->frames[vm->fp]
.registers[first_reg + 1]; /* R1: buffer pointer */
size = read_u32(vm, memory, buffer_ptr); /* R2: size */
str_src = path_ptr += 4;
dev = find_device_by_path(vm, (const char *)&vm->memory[str_src]);
if (dev && dev->ops->write) {
int result = dev->ops->write(
dev->data, (const uint8_t *)&vm->memory[buffer_ptr], size);
vm->acc = result;
vm->acc = dev->ops->write(dev->data,
(const u8 *)&vm->memory[buffer_ptr], size);
} else {
vm->acc = 0;
}
@ -265,16 +222,16 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_CLOSE: {
if (arg_count >= 1) {
uint32_t path_ptr =
vm->frames[vm->fp].registers[first_reg].u; /* R0: path pointer */
/* uint32_t length = vm->memory[path_ptr].u; */
uint32_t str_src = path_ptr + 1;
Device *dev;
u32 path_ptr, str_src;
path_ptr =
vm->frames[vm->fp].registers[first_reg]; /* R0: path pointer */
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->close) {
int result = dev->ops->close(dev->data);
i32 result = dev->ops->close(dev->data);
vm->acc = result;
} else {
vm->acc = 0;
@ -287,22 +244,20 @@ bool step_vm(VM *vm) {
case SYSCALL_DEVICE_IOCTL: {
if (arg_count >= 3) {
uint32_t path_ptr =
vm->frames[vm->fp].registers[first_reg].u; /* R0: device path */
uint32_t cmd = vm->frames[vm->fp]
.registers[first_reg + 1]
.u; /* R1: ioctl command */
uint32_t args_ptr = vm->frames[vm->fp]
.registers[first_reg + 2]
.u; /* R2: args pointer */
/* uint32_t length = vm->memory[path_ptr].u; */
uint32_t str_src = path_ptr + 1;
Device *dev;
u32 path_ptr, args_ptr, cmd, str_src;
path_ptr =
vm->frames[vm->fp].registers[first_reg]; /* R0: device path */
cmd =
vm->frames[vm->fp].registers[first_reg + 1]; /* R1: ioctl command */
args_ptr =
vm->frames[vm->fp].registers[first_reg + 2]; /* R2: args pointer */
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 && 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;
} else {
vm->acc = 0; /* error or no ioctl support */
@ -325,210 +280,309 @@ bool step_vm(VM *vm) {
return true;
}
case OP_ADD_INT:
MATH_OP(i, +);
MATH_OP(i32, +);
case OP_SUB_INT:
MATH_OP(i, -);
MATH_OP(i32, -);
case OP_MUL_INT:
MATH_OP(i, *);
MATH_OP(i32, *);
case OP_DIV_INT:
MATH_OP(i, /);
MATH_OP(i32, /);
case OP_ADD_UINT:
MATH_OP(u, +);
MATH_OP(u32, +);
case OP_SUB_UINT:
MATH_OP(u, -);
MATH_OP(u32, -);
case OP_MUL_UINT:
MATH_OP(u, *);
MATH_OP(u32, *);
case OP_DIV_UINT:
MATH_OP(u, /);
case OP_ADD_REAL:
MATH_OP(f, +);
case OP_SUB_REAL:
MATH_OP(f, -);
case OP_MUL_REAL:
MATH_OP(f, *);
case OP_DIV_REAL:
MATH_OP(f, /);
MATH_OP(u32, /);
case OP_MUL_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]) >>
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: {
vm->frames[vm->fp].registers[dest].i =
(int32_t)(vm->frames[vm->fp].registers[src1].f);
dest = read_u8(vm, code, vm->pc);
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;
}
case OP_INT_TO_REAL: {
vm->frames[vm->fp].registers[dest].f =
(float)(vm->frames[vm->fp].registers[src1].i);
dest = read_u8(vm, code, vm->pc);
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;
}
case OP_REAL_TO_UINT: {
vm->frames[vm->fp].registers[dest].u =
(uint32_t)(vm->frames[vm->fp].registers[src1].f);
dest = read_u8(vm, code, vm->pc);
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;
}
case OP_UINT_TO_REAL: {
vm->frames[vm->fp].registers[dest].f =
(float)(vm->frames[vm->fp].registers[src1].u);
dest = read_u8(vm, code, vm->pc);
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;
}
case OP_JEQ_UINT: {
COMPARE_AND_JUMP(uint32_t, u, ==);
COMPARE_AND_JUMP(u32, ==);
}
case OP_JGT_UINT: {
COMPARE_AND_JUMP(uint32_t, u, >);
COMPARE_AND_JUMP(u32, >);
}
case OP_JLT_UINT: {
COMPARE_AND_JUMP(uint32_t, u, <);
COMPARE_AND_JUMP(u32, <);
}
case OP_JLE_UINT: {
COMPARE_AND_JUMP(uint32_t, u, <=);
COMPARE_AND_JUMP(u32, <=);
}
case OP_JGE_UINT: {
COMPARE_AND_JUMP(uint32_t, u, >=);
COMPARE_AND_JUMP(u32, >=);
}
case OP_JEQ_INT: {
COMPARE_AND_JUMP(int32_t, i, ==);
COMPARE_AND_JUMP(i32, ==);
}
case OP_JGT_INT: {
COMPARE_AND_JUMP(int32_t, i, >);
COMPARE_AND_JUMP(i32, >);
}
case OP_JLT_INT: {
COMPARE_AND_JUMP(int32_t, i, <);
COMPARE_AND_JUMP(i32, <);
}
case OP_JLE_INT: {
COMPARE_AND_JUMP(int32_t, i, <=);
COMPARE_AND_JUMP(i32, <=);
}
case OP_JGE_INT: {
COMPARE_AND_JUMP(int32_t, i, >=);
COMPARE_AND_JUMP(i32, >=);
}
case OP_JEQ_REAL: {
COMPARE_AND_JUMP(int32_t, i, ==);
COMPARE_AND_JUMP(i32, ==);
}
case OP_JGT_REAL: {
COMPARE_AND_JUMP(float, u, >);
COMPARE_AND_JUMP(i32, >);
}
case OP_JLT_REAL: {
COMPARE_AND_JUMP(float, u, <);
COMPARE_AND_JUMP(i32, <);
}
case OP_JGE_REAL: {
COMPARE_AND_JUMP(float, u, >=);
COMPARE_AND_JUMP(i32, >=);
}
case OP_JLE_REAL: {
COMPARE_AND_JUMP(float, u, <=);
COMPARE_AND_JUMP(i32, <=);
}
case OP_INT_TO_STRING: {
int32_t a = (int32_t)vm->frames[vm->fp].registers[src1].i; /* get value */
char buffer[32];
int len = sprintf(buffer, "%d", a);
uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */
vm->frames[vm->fp].registers[dest].u = ptr;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
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;
}
case OP_UINT_TO_STRING: {
uint32_t a = (uint32_t)vm->frames[vm->fp].registers[src1].u; /* get value */
char buffer[32];
int len = sprintf(buffer, "%d", a);
uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */
vm->frames[vm->fp].registers[dest].u = ptr;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
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;
}
case OP_REAL_TO_STRING: {
float a = (float)vm->frames[vm->fp].registers[src1].f; /* get value */
char buffer[32];
int len = sprintf(buffer, "%f", a);
uint32_t ptr = str_alloc(vm, buffer, len); /* copy buffer to dest */
vm->frames[vm->fp].registers[dest].u = ptr;
dest = read_u8(vm, code, vm->pc);
vm->pc++;
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;
}
case OP_STRING_TO_INT: {
uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u;
uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u;
char *endptr;
int32_t value = (int32_t)strtol((char*)&vm->memory[src_addr + 1], &endptr, 10);
vm->memory[dest_addr].i = value;
return true;
/* not implemented yet */
return false;
}
case OP_STRING_TO_UINT: {
uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u;
uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u;
long value = atol((char*)&vm->memory[src_addr + 1]);
vm->memory[dest_addr].u = value;
return true;
/* not implemented yet */
return false;
}
case OP_STRING_TO_REAL: {
uint32_t src_addr = (uint32_t)vm->frames[vm->fp].registers[src1].u;
uint32_t dest_addr = (uint32_t)vm->frames[vm->fp].registers[dest].u;
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;
/* not implemented yet */
return false;
}
}
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"
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

View File

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