begin breaking up into modules, add wasm

This commit is contained in:
zongor 2025-06-11 22:41:49 -04:00
parent 244baf55f1
commit bb9e30a1c1
6 changed files with 188 additions and 113 deletions

2
.gitignore vendored
View File

@ -102,4 +102,6 @@ Mkfile.old
dkms.conf dkms.conf
zre zre
zre.wasm
memory_dump.bin memory_dump.bin
src/build/

View File

@ -1,39 +1,69 @@
# Compiler and flags # Compiler configurations
CC = gcc # -----------------------
CFLAGS += -std=c89 -g -Wall -Wextra -Werror -Wno-unused-parameter # Native build (gcc)
LDFLAGS += CC_NATIVE = gcc
LDLIBS += CFLAGS_NATIVE = -std=c89 -Wall -Wextra -Werror -Wno-unused-parameter
LDFLAGS_NATIVE =
LDLIBS_NATIVE =
# WASM build (emscripten)
CC_WASM = emcc
CFLAGS_WASM = -std=c89 -Wall -Wextra -Werror -Wno-unused-parameter #-s WASM=1
LDFLAGS_WASM = #-s WASM=1
LDLIBS_WASM =
# Source and build configuration # Source and build configuration
# ----------------------------
SRC = $(wildcard *.c) SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o) EXEC_NATIVE = zre
EXEC = zre EXEC_WASM = zre.wasm
# Build directories
OBJ_DIR_NATIVE = build/native/obj
OBJ_DIR_WASM = build/wasm/obj
# Create output paths
OBJ_NATIVE = $(addprefix $(OBJ_DIR_NATIVE)/,$(notdir $(SRC:.c=.o)))
OBJ_WASM = $(addprefix $(OBJ_DIR_WASM)/,$(notdir $(SRC:.c=.o)))
# Phony targets # Phony targets
.PHONY: all clean test install # -------------
.PHONY: all clean install wasm
# Default target # Default target builds both versions
all: $(EXEC) all: native wasm
# Main build rule # Native build rules
$(EXEC): $(OBJ) # ------------------
$(CC) $(LDFLAGS) $(OBJ) $(LDLIBS) -o $@ native: $(EXEC_NATIVE)
# Pattern rule for object files $(EXEC_NATIVE): $(OBJ_NATIVE)
%.o: %.c $(CC_NATIVE) $(LDFLAGS_NATIVE) $^ $(LDLIBS_NATIVE) -o $@
$(CC) $(CFLAGS) -c $< -o $@
# Test target with dependency # WASM build rules
test: $(EXEC) # ----------------
@echo "Running tests..." wasm: $(EXEC_WASM)
./$(EXEC)
@echo "Tests completed successfully." $(EXEC_WASM): $(OBJ_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 $@
# Clean build artifacts # Clean build artifacts
# ---------------------
clean: clean:
$(RM) $(OBJ) $(EXEC) $(RM) -r $(OBJ_DIR_NATIVE) $(OBJ_DIR_WASM) $(EXEC_NATIVE) $(EXEC_WASM)
# Install target (example) # Install target (example)
install: $(EXEC) # ------------------------
install: native
install -d $(DESTDIR)/usr/local/bin install -d $(DESTDIR)/usr/local/bin
install $(EXEC) $(DESTDIR)/usr/local/bin/ install $(EXEC_NATIVE) $(DESTDIR)/usr/local/bin/

9
src/common.h Normal file
View File

@ -0,0 +1,9 @@
#ifndef ZRE_COMMON_H
#define ZRE_COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#endif

54
src/main.c Normal file
View File

@ -0,0 +1,54 @@
#include "vm.h"
/* #define MEMORY_SIZE 65536 /\* 64KB memory (adjustable) *\/ */
#define MEMORY_SIZE 1024
int main() {
Data memory[MEMORY_SIZE]; /* Memory array */
int i = 0;
memory[i++].u = OP_ADD_F32;
memory[i++].u = 102;
memory[i++].u = 103;
memory[i++].u = 103;
memory[i++].u = OP_SUB;
memory[i++].u = 100;
memory[i++].u = 101;
memory[i++].u = 100;
memory[i++].u = OP_JGZ;
memory[i++].u = 100;
memory[i++].u = 0;
memory[i++].u = 0;
memory[i++].u = OP_F32_TO_INT;
memory[i++].u = 103;
memory[i++].u = 0;
memory[i++].u = 103;
memory[i++].u = OP_INT_TO_STRING;
memory[i++].u = 103;
memory[i++].u = 0;
memory[i++].u = 104;
memory[i++].u = OP_PRINT_STRING;
memory[i++].u = 105;
memory[i++].u = 0;
memory[i++].u = 0;
memory[i++].u = OP_READ_STRING;
memory[i++].u = 0;
memory[i++].u = 0;
memory[i++].u = 109;
memory[i++].u = OP_PRINT_STRING;
memory[i++].u = 110;
memory[i++].u = 0;
memory[i++].u = 0;
memory[i++].u = OP_HALT;
memory[i++].u = 0;
memory[i++].u = 0;
memory[i++].u = 0;
memory[100].u = 5;
memory[101].u = 1;
memory[102].f = 5.f;
memory[103].f = 5.f;
run_vm(memory, MEMORY_SIZE);
return core_dump(memory, MEMORY_SIZE);
}

120
src/vm.c
View File

@ -1,49 +1,17 @@
#include <stdbool.h> #include "vm.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
/* #define MEMORY_SIZE 65536 /\* 64KB memory (adjustable) *\/ */ int core_dump(Data *memory, uint32_t memory_size) {
#define MEMORY_SIZE 1024
typedef union {
float f;
uint32_t u;
} Data;
Data memory[MEMORY_SIZE]; /* Memory array */
typedef enum {
OP_HALT, /* terminate execution */
OP_ADD, /* dest = src1 + src2 */
OP_SUB, /* dest = src1 - src2 */
OP_MUL, /* dest = src1 * src2 */
OP_DIV, /* dest = src1 / src2 */
OP_ADD_F32, /* dest = src1 + src2 */
OP_SUB_F32, /* dest = src1 - src2 */
OP_MUL_F32, /* dest = src1 * src2 */
OP_DIV_F32, /* dest = src1 / src2 */
OP_F32_TO_INT, /* dest = src1 as int */
OP_INT_TO_F32, /* dest = src1 as f32 */
OP_MOV, /* dest = src1 */
OP_JMP, /* jump to address src1 unconditionally */
OP_JGZ, /* jump to address dest if src1 > 0 */
OP_INT_TO_STRING, /* dest = src1 as str */
OP_F32_TO_STRING, /* dest = src2 as str */
OP_READ_STRING,
OP_PRINT_STRING,
} Opcode;
int core_dump() {
FILE *file = fopen("memory_dump.bin", "wb"); FILE *file = fopen("memory_dump.bin", "wb");
if (!file) { if (!file) {
perror("Failed to open file"); perror("Failed to open file");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
size_t written = fwrite(memory, 1, MEMORY_SIZE, file); size_t written = fwrite(memory, 1, memory_size, file);
if (written != MEMORY_SIZE) { if (written != memory_size) {
fprintf(stderr, "Incomplete write: %zu bytes written out of %u\n", written, fprintf(stderr, "Incomplete write: %zu bytes written out of %u\n", written,
MEMORY_SIZE); memory_size);
fclose(file); fclose(file);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -61,7 +29,7 @@ uint32_t set_char(uint32_t word, int index, uint8_t ch) {
} }
/* Pack string into union-based memory */ /* Pack string into union-based memory */
void pack_string(const char *str, uint32_t length, uint32_t dest_addr) { void pack_string(Data *memory, const char *str, uint32_t length, uint32_t dest_addr) {
memory[dest_addr].u = length; memory[dest_addr].u = length;
uint32_t buffer_addr = dest_addr + 1; uint32_t buffer_addr = dest_addr + 1;
int word_index = 0; int word_index = 0;
@ -89,10 +57,10 @@ void pack_string(const char *str, uint32_t length, uint32_t dest_addr) {
} }
} }
void run_vm() { void run_vm(Data *memory, uint32_t memory_size) {
uint32_t pc = 0; /* Program counter */ uint32_t pc = 0; /* Program counter */
while (pc < MEMORY_SIZE - 4) { while (pc < memory_size - 4) {
Opcode opcode = memory[pc].u; Opcode opcode = memory[pc].u;
uint32_t src1_addr = memory[pc + 1].u; uint32_t src1_addr = memory[pc + 1].u;
@ -100,8 +68,8 @@ void run_vm() {
uint32_t dest_addr = memory[pc + 3].u; uint32_t dest_addr = memory[pc + 3].u;
pc += 4; /* Advance to next instruction */ pc += 4; /* Advance to next instruction */
if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE || if (src1_addr >= memory_size || src2_addr >= memory_size ||
dest_addr >= MEMORY_SIZE) { dest_addr >= memory_size) {
printf("Invalid memory address!\n"); printf("Invalid memory address!\n");
exit(1); exit(1);
} }
@ -173,14 +141,14 @@ void run_vm() {
int32_t a = (int32_t)memory[src1_addr].u; int32_t a = (int32_t)memory[src1_addr].u;
char buffer[32]; char buffer[32];
sprintf(buffer, "%d", a); sprintf(buffer, "%d", a);
pack_string(buffer, strlen(buffer), dest_addr); pack_string(memory, buffer, strlen(buffer), dest_addr);
break; break;
} }
case OP_F32_TO_STRING: { case OP_F32_TO_STRING: {
float a = memory[src1_addr].f; float a = memory[src1_addr].f;
char buffer[32]; char buffer[32];
sprintf(buffer, "%f", a); sprintf(buffer, "%f", a);
pack_string(buffer, strlen(buffer), dest_addr); pack_string(memory, buffer, strlen(buffer), dest_addr);
break; break;
} }
case OP_PRINT_STRING: { case OP_PRINT_STRING: {
@ -229,6 +197,26 @@ void run_vm() {
memory[dest_addr].u = length; memory[dest_addr].u = length;
break; break;
} }
case OP_CMP_STRING: {
uint32_t addr1 = src1_addr;
uint32_t addr2 = src2_addr;
uint32_t length1 = memory[src1_addr - 1].u;
int equal = 1;
uint32_t i;
for (i = 0; i < length1;) {
uint32_t word1 = memory[addr1 + i].u;
uint32_t word2 = memory[addr2 + i].u;
if (word1 != word2) {
equal = 0;
break;
}
if ((word1 & 0xFF) == '\0' && (word2 & 0xFF) == '\0')
break;
}
memory[dest_addr].u = equal;
break;
}
default: default:
printf("Unknown opcode: %d\n", opcode); printf("Unknown opcode: %d\n", opcode);
return; return;
@ -236,47 +224,3 @@ void run_vm() {
} }
} }
int main() {
int i = 0;
memory[i++].u = OP_ADD_F32;
memory[i++].u = 102;
memory[i++].u = 103;
memory[i++].u = 103;
memory[i++].u = OP_SUB;
memory[i++].u = 100;
memory[i++].u = 101;
memory[i++].u = 100;
memory[i++].u = OP_JGZ;
memory[i++].u = 100;
memory[i++].u = 0;
memory[i++].u = 0;
memory[i++].u = OP_F32_TO_INT;
memory[i++].u = 103;
memory[i++].u = 0;
memory[i++].u = 103;
memory[i++].u = OP_INT_TO_STRING;
memory[i++].u = 103;
memory[i++].u = 0;
memory[i++].u = 104;
memory[i++].u = OP_PRINT_STRING;
memory[i++].u = 105;
memory[i++].u = 0;
memory[i++].u = 0;
memory[i++].u = OP_READ_STRING;
memory[i++].u = 0;
memory[i++].u = 0;
memory[i++].u = 109;
memory[i++].u = OP_PRINT_STRING;
memory[i++].u = 110;
memory[i++].u = 0;
memory[i++].u = 0;
memory[i++].u = OP_HALT;
memory[100].u = 5;
memory[101].u = 1;
memory[102].f = 5.f;
memory[103].f = 5.f;
run_vm();
return core_dump();
}

36
src/vm.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef ZRE_VM_H
#define ZRE_VM_H
#include "common.h"
typedef union {
float f;
uint32_t u;
} Data;
typedef enum {
OP_HALT, /* terminate execution */
OP_ADD, /* dest = src1 + src2 */
OP_SUB, /* dest = src1 - src2 */
OP_MUL, /* dest = src1 * src2 */
OP_DIV, /* dest = src1 / src2 */
OP_ADD_F32, /* dest = src1 + src2 */
OP_SUB_F32, /* dest = src1 - src2 */
OP_MUL_F32, /* dest = src1 * src2 */
OP_DIV_F32, /* dest = src1 / src2 */
OP_F32_TO_INT, /* dest = src1 as int */
OP_INT_TO_F32, /* dest = src1 as f32 */
OP_MOV, /* dest = src1 */
OP_JMP, /* jump to address src1 unconditionally */
OP_JGZ, /* jump to address dest if src1 > 0 */
OP_INT_TO_STRING, /* dest = src1 as str */
OP_F32_TO_STRING, /* dest = src2 as str */
OP_READ_STRING,
OP_PRINT_STRING,
OP_CMP_STRING,
} Opcode;
void run_vm(Data *memory, uint32_t memory_size);
int core_dump(Data *memory, uint32_t memory_size);
#endif