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

4
.gitignore vendored
View File

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

View File

@ -1,39 +1,69 @@
# Compiler and flags
CC = gcc
CFLAGS += -std=c89 -g -Wall -Wextra -Werror -Wno-unused-parameter
LDFLAGS +=
LDLIBS +=
# Compiler configurations
# -----------------------
# Native build (gcc)
CC_NATIVE = gcc
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
# ----------------------------
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
EXEC = zre
EXEC_NATIVE = 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: all clean test install
# -------------
.PHONY: all clean install wasm
# Default target
all: $(EXEC)
# Default target builds both versions
all: native wasm
# Main build rule
$(EXEC): $(OBJ)
$(CC) $(LDFLAGS) $(OBJ) $(LDLIBS) -o $@
# Native build rules
# ------------------
native: $(EXEC_NATIVE)
# Pattern rule for object files
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
$(EXEC_NATIVE): $(OBJ_NATIVE)
$(CC_NATIVE) $(LDFLAGS_NATIVE) $^ $(LDLIBS_NATIVE) -o $@
# Test target with dependency
test: $(EXEC)
@echo "Running tests..."
./$(EXEC)
@echo "Tests completed successfully."
# WASM build rules
# ----------------
wasm: $(EXEC_WASM)
$(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:
$(RM) $(OBJ) $(EXEC)
$(RM) -r $(OBJ_DIR_NATIVE) $(OBJ_DIR_WASM) $(EXEC_NATIVE) $(EXEC_WASM)
# Install target (example)
install: $(EXEC)
# ------------------------
install: native
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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "vm.h"
#include <string.h>
#include <unistd.h>
/* #define MEMORY_SIZE 65536 /\* 64KB memory (adjustable) *\/ */
#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() {
int core_dump(Data *memory, uint32_t memory_size) {
FILE *file = fopen("memory_dump.bin", "wb");
if (!file) {
perror("Failed to open file");
return EXIT_FAILURE;
}
size_t written = fwrite(memory, 1, MEMORY_SIZE, file);
if (written != MEMORY_SIZE) {
size_t written = fwrite(memory, 1, memory_size, file);
if (written != memory_size) {
fprintf(stderr, "Incomplete write: %zu bytes written out of %u\n", written,
MEMORY_SIZE);
memory_size);
fclose(file);
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 */
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;
uint32_t buffer_addr = dest_addr + 1;
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 */
while (pc < MEMORY_SIZE - 4) {
while (pc < memory_size - 4) {
Opcode opcode = memory[pc].u;
uint32_t src1_addr = memory[pc + 1].u;
@ -100,8 +68,8 @@ void run_vm() {
uint32_t dest_addr = memory[pc + 3].u;
pc += 4; /* Advance to next instruction */
if (src1_addr >= MEMORY_SIZE || src2_addr >= MEMORY_SIZE ||
dest_addr >= MEMORY_SIZE) {
if (src1_addr >= memory_size || src2_addr >= memory_size ||
dest_addr >= memory_size) {
printf("Invalid memory address!\n");
exit(1);
}
@ -173,14 +141,14 @@ void run_vm() {
int32_t a = (int32_t)memory[src1_addr].u;
char buffer[32];
sprintf(buffer, "%d", a);
pack_string(buffer, strlen(buffer), dest_addr);
pack_string(memory, buffer, strlen(buffer), dest_addr);
break;
}
case OP_F32_TO_STRING: {
float a = memory[src1_addr].f;
char buffer[32];
sprintf(buffer, "%f", a);
pack_string(buffer, strlen(buffer), dest_addr);
pack_string(memory, buffer, strlen(buffer), dest_addr);
break;
}
case OP_PRINT_STRING: {
@ -229,6 +197,26 @@ void run_vm() {
memory[dest_addr].u = length;
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:
printf("Unknown opcode: %d\n", opcode);
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