From bcff8b38598b85cd65a59b407c2029dd3493c694 Mon Sep 17 00:00:00 2001 From: Creeper Lv Date: Mon, 25 May 2026 15:21:34 +1000 Subject: [PATCH] Implemented using Antigravity and it actually works! --- Headers/SagittariusInternal.h | 15 +- Headers/SagittariusPanic.h | 6 +- Source/Assembler/SagittariusAssembler.c | 868 ++++++++++++++++++++++++ Source/Assembler/main.c | 152 ++++- Source/Standalone/main.c | 92 ++- Source/VM/Sagittarius.c | 147 +++- Source/VM/SagittariusInternal.c | 604 +++++++++++++++++ 7 files changed, 1858 insertions(+), 26 deletions(-) create mode 100644 Source/Assembler/SagittariusAssembler.c create mode 100644 Source/VM/SagittariusInternal.c diff --git a/Headers/SagittariusInternal.h b/Headers/SagittariusInternal.h index be7763d..10ee7f7 100644 --- a/Headers/SagittariusInternal.h +++ b/Headers/SagittariusInternal.h @@ -1,10 +1,17 @@ +#ifndef _SAGITTARIUS_INTERNAL_H_ +#define _SAGITTARIUS_INTERNAL_H_ + #include "Sagittarius.h" +#include "SagittariusPanic.h" #include + internal bool SagMath2Add(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T); internal bool SagMath2Sub(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T); internal bool SagMath2Mul(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T); internal bool SagMath2Div(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T); internal bool SagMath2Mod(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T); +internal bool SagMath2Pow(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T); + internal bool SagMath1Sin(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t T); internal bool SagMath1Cos(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t T); internal bool SagMath1Tan(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t T); @@ -26,8 +33,14 @@ internal bool SagMv(SagittariusCore *core, SagittariusInst inst); internal bool SagCp(SagittariusCore *core, SagittariusInst inst); internal bool SagSave(SagittariusCore *core, SagittariusInst inst); internal bool SagLoad(SagittariusCore *core, SagittariusInst inst); +internal bool SagJmp(SagittariusCore *core, SagittariusInst inst); +internal bool SagJmpIf(SagittariusCore *core, SagittariusInst inst); +internal bool SagCall(SagittariusCore *core, SagittariusInst inst); +internal bool SagRet(SagittariusCore *core, SagittariusInst inst); internal bool SagCmp(SagittariusCore *core, SagittariusInst inst); internal bool SagMathV(SagittariusCore *core, SagittariusInst inst); internal bool SagHalt(SagittariusCore *core, SagittariusInst inst); internal bool SagSyscall(SagittariusCore *core, SagittariusInst inst); -internal bool SagTSyscall(SagittariusCore *core, SagittariusInst inst); \ No newline at end of file +internal bool SagTSyscall(SagittariusCore *core, SagittariusInst inst); + +#endif \ No newline at end of file diff --git a/Headers/SagittariusPanic.h b/Headers/SagittariusPanic.h index 2450853..41e4de1 100644 --- a/Headers/SagittariusPanic.h +++ b/Headers/SagittariusPanic.h @@ -14,7 +14,7 @@ typedef struct NoticiableMsg uint64_t NoticiableId; char* msg; } NoticiableMsg; -#define Sagittarius_Msg_Generic 0x0000_0000_0000_0000 -#define Sagittarius_Msg_Unknown 0xFFFFFFFFFFFFFFFF -#define Sagittarius_Msg_OOB 0x1000_0000_0000_0000 +#define Sagittarius_Msg_Generic 0x0000000000000000ULL +#define Sagittarius_Msg_Unknown 0xFFFFFFFFFFFFFFFFULL +#define Sagittarius_Msg_OOB 0x1000000000000000ULL #endif \ No newline at end of file diff --git a/Source/Assembler/SagittariusAssembler.c b/Source/Assembler/SagittariusAssembler.c new file mode 100644 index 0000000..e61bf82 --- /dev/null +++ b/Source/Assembler/SagittariusAssembler.c @@ -0,0 +1,868 @@ +#include "../../Headers/Assembler/SagittariusAssembler.h" +#include +#include +#include + +/* Lexer / scanner helpers */ +bool Sag_NextWord(FILE* f, Sag_Str* out) { + if (!f || !out) return false; + + int c; + // Skip whitespace and comments + while (1) { + c = fgetc(f); + if (c == EOF) return false; + + if (c == ' ' || c == '\t' || c == '\n' || c == '\r') { + continue; + } + if (c == ';' || c == '#') { + // Skip until end of line + while (1) { + c = fgetc(f); + if (c == EOF || c == '\n' || c == '\r') break; + } + continue; + } + break; + } + + // Read word/token + uint64_t cap = 32; + uint64_t len = 0; + char *buf = malloc(cap); + if (!buf) return false; + + if (c == '"') { + // Read string literal + buf[len++] = c; + while (1) { + c = fgetc(f); + if (c == EOF) { + free(buf); + return false; + } + if (len + 2 >= cap) { + cap *= 2; + buf = realloc(buf, cap); + } + buf[len++] = c; + if (c == '"') { + break; + } + } + } else { + // Read normal word until whitespace, comment, or EOF + buf[len++] = c; + while (1) { + c = fgetc(f); + if (c == EOF) break; + if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == ';' || c == '#') { + ungetc(c, f); + break; + } + if (len + 2 >= cap) { + cap *= 2; + buf = realloc(buf, cap); + } + buf[len++] = c; + } + } + + buf[len] = '\0'; + out->head = buf; + out->start = 0; + out->length = len; + return true; +} + +bool Sag_MatchStr(Sag_Str* str, char** match_list, uint64_t match_count, uint64_t* out_index) { + if (!str || !str->head) return false; + for (uint64_t i = 0; i < match_count; ++i) { + if (strlen(match_list[i]) == str->length && + strncmp(str->head + str->start, match_list[i], str->length) == 0) { + if (out_index) *out_index = i; + return true; + } + } + return false; +} + +static uint64_t get_instruction_arg_count(const char *name) { + if (strcmp(name, "add") == 0 || strcmp(name, "sub") == 0 || strcmp(name, "mul") == 0 || + strcmp(name, "div") == 0 || strcmp(name, "mod") == 0 || strcmp(name, "pow") == 0) { + return 4; + } + if (strcmp(name, "sin") == 0 || strcmp(name, "cos") == 0 || strcmp(name, "tan") == 0 || + strcmp(name, "sinh") == 0 || strcmp(name, "cosh") == 0 || strcmp(name, "tanh") == 0 || + strcmp(name, "asin") == 0 || strcmp(name, "acos") == 0 || strcmp(name, "atan") == 0 || + strcmp(name, "abs") == 0 || strcmp(name, "exp") == 0) { + return 3; + } + if (strcmp(name, "cvt") == 0) return 4; + if (strcmp(name, "set") == 0) return 3; + if (strncmp(name, "set.", 4) == 0) return 2; // alias! + if (strcmp(name, "mv") == 0) return 3; + if (strcmp(name, "cp") == 0) return 3; + if (strcmp(name, "save") == 0) return 3; + if (strcmp(name, "load") == 0) return 3; + if (strcmp(name, "jmp") == 0) return 3; + if (strcmp(name, "jmp_if") == 0) return 4; + if (strcmp(name, "call") == 0) return 4; + if (strcmp(name, "ret") == 0) return 1; + if (strcmp(name, "cmp") == 0) return 5; + if (strcmp(name, "mathv") == 0) return 6; + if (strcmp(name, "halt") == 0) return 0; + if (strcmp(name, "syscall") == 0) return 2; + if (strcmp(name, "tsyscall") == 0) return 3; + return 0xFFFFFFFFFFFFFFFFULL; +} + +bool Sag_Scan(FILE* f, Sag_IntermediateProgram* out) { + if (!f || !out) return false; + + out->insts = NULL; + out->inst_count = 0; + out->data = NULL; + out->data_count = 0; + out->Consts = NULL; + out->Consts_count = 0; + + typedef enum Section { SEC_CODE, SEC_DATA, SEC_CONST } Section; + Section active_sec = SEC_CODE; + Sag_Str* pending_label = NULL; + + Sag_Str word; + while (Sag_NextWord(f, &word)) { + // Check for sections + if (strcmp(word.head, ".code:") == 0) { + active_sec = SEC_CODE; + free(word.head); + continue; + } + if (strcmp(word.head, ".data:") == 0) { + active_sec = SEC_DATA; + free(word.head); + continue; + } + if (strcmp(word.head, ".const:") == 0) { + active_sec = SEC_CONST; + free(word.head); + continue; + } + + // Check if label definition + if (word.length > 1 && word.head[word.length - 1] == ':') { + word.head[word.length - 1] = '\0'; + word.length--; + pending_label = malloc(sizeof(Sag_Str)); + *pending_label = word; + continue; + } + + if (active_sec == SEC_CODE) { + uint64_t arg_count = get_instruction_arg_count(word.head); + if (arg_count == 0xFFFFFFFFFFFFFFFFULL) { + // Unknown instruction name + printf("Error: Unknown instruction '%s'\n", word.head); + free(word.head); + return false; + } + + Sag_IntermediateInst ii; + ii.inst.data = 0; + ii.label = pending_label; + pending_label = NULL; // Consumed + ii.arg_count = arg_count; + + ii.args = malloc((arg_count + 1) * sizeof(Sag_Str)); + ii.args[0] = word; // First is instruction name + + for (uint64_t a = 1; a <= arg_count; ++a) { + if (!Sag_NextWord(f, &ii.args[a])) { + printf("Error: Missing argument for '%s'\n", word.head); + free(ii.args); + return false; + } + } + + out->insts = realloc(out->insts, (out->inst_count + 1) * sizeof(Sag_IntermediateInst)); + out->insts[out->inst_count] = ii; + out->inst_count++; + + } else if (active_sec == SEC_DATA) { + // Read next 2 words (type and value) + Sag_Str type_str, val_str; + if (!Sag_NextWord(f, &type_str) || !Sag_NextWord(f, &val_str)) { + printf("Error: Incomplete data section entry\n"); + return false; + } + + out->data = realloc(out->data, (out->data_count + 3) * sizeof(Sag_Str)); + out->data[out->data_count] = word; // name + out->data[out->data_count + 1] = type_str; // type + out->data[out->data_count + 2] = val_str; // value + out->data_count += 3; + + } else if (active_sec == SEC_CONST) { + // Read next 1 word (value) + Sag_Str val_str; + if (!Sag_NextWord(f, &val_str)) { + printf("Error: Incomplete const section entry\n"); + return false; + } + + out->Consts = realloc(out->Consts, (out->Consts_count + 2) * sizeof(Sag_Str)); + out->Consts[out->Consts_count] = word; // name + out->Consts[out->Consts_count + 1] = val_str; // value + out->Consts_count += 2; + } + } + return true; +} + +bool Sag_Combine(Sag_IntermediateProgram* L, Sag_IntermediateProgram* R, Sag_IntermediateProgram* out) { + if (!L || !R || !out) return false; + + out->inst_count = L->inst_count + R->inst_count; + if (out->inst_count > 0) { + out->insts = malloc(out->inst_count * sizeof(Sag_IntermediateInst)); + if (L->inst_count > 0) memcpy(out->insts, L->insts, L->inst_count * sizeof(Sag_IntermediateInst)); + if (R->inst_count > 0) memcpy(out->insts + L->inst_count, R->insts, R->inst_count * sizeof(Sag_IntermediateInst)); + } else { + out->insts = NULL; + } + + out->data_count = L->data_count + R->data_count; + if (out->data_count > 0) { + out->data = malloc(out->data_count * sizeof(Sag_Str)); + if (L->data_count > 0) memcpy(out->data, L->data, L->data_count * sizeof(Sag_Str)); + if (R->data_count > 0) memcpy(out->data + L->data_count, R->data, R->data_count * sizeof(Sag_Str)); + } else { + out->data = NULL; + } + + out->Consts_count = L->Consts_count + R->Consts_count; + if (out->Consts_count > 0) { + out->Consts = malloc(out->Consts_count * sizeof(Sag_Str)); + if (L->Consts_count > 0) memcpy(out->Consts, L->Consts, L->Consts_count * sizeof(Sag_Str)); + if (R->Consts_count > 0) memcpy(out->Consts + L->Consts_count, R->Consts, R->Consts_count * sizeof(Sag_Str)); + } else { + out->Consts = NULL; + } + + return true; +} + +/* Base64 & String parsing helpers */ +static inline int b64_char_val(char c) { + if (c >= 'A' && c <= 'Z') return c - 'A'; + if (c >= 'a' && c <= 'z') return c - 'a' + 26; + if (c >= '0' && c <= '9') return c - '0' + 52; + if (c == '+') return 62; + if (c == '/') return 63; + return -1; +} + +static inline uint8_t* base64_decode(const char* in, size_t* out_len) { + size_t len = strlen(in); + size_t padding = 0; + if (len > 0 && in[len - 1] == '=') padding++; + if (len > 1 && in[len - 2] == '=') padding++; + + *out_len = (len * 3) / 4 - padding; + uint8_t* out = malloc(*out_len); + if (!out) return NULL; + + size_t j = 0; + uint32_t val = 0; + int valb = -8; + for (size_t i = 0; i < len; ++i) { + char c = in[i]; + if (c == '=') break; + int v = b64_char_val(c); + if (v == -1) continue; + val = (val << 6) | v; + valb += 6; + if (valb >= 0) { + out[j++] = (val >> valb) & 0xFF; + valb -= 8; + } + } + return out; +} + +static inline uint8_t* parse_string_bytes(const char* in, size_t* out_len) { + size_t len = strlen(in); + size_t start = 0; + size_t end = len; + if (len >= 2 && in[0] == '"' && in[len - 1] == '"') { + start = 1; + end = len - 1; + } + + uint8_t* out = malloc(len + 1); + size_t j = 0; + for (size_t i = start; i < end; ++i) { + if (in[i] == '\\' && i + 1 < end) { + i++; + switch (in[i]) { + case 'n': out[j++] = '\n'; break; + case 't': out[j++] = '\t'; break; + case 'r': out[j++] = '\r'; break; + case '\"': out[j++] = '\"'; break; + case '\\': out[j++] = '\\'; break; + default: out[j++] = in[i]; break; + } + } else { + out[j++] = in[i]; + } + } + out[j++] = '\0'; + *out_len = j; + return out; +} + +static inline uint8_t* read_file_bytes(const char* path, size_t* out_len) { + // Strip quotes if path has them + size_t len = strlen(path); + char* clean_path = malloc(len + 1); + size_t start = 0, end = len; + if (len >= 2 && path[0] == '"' && path[len-1] == '"') { + start = 1; + end = len - 1; + } + size_t j = 0; + for (size_t i = start; i < end; ++i) clean_path[j++] = path[i]; + clean_path[j] = '\0'; + + FILE* f = fopen(clean_path, "rb"); + free(clean_path); + if (!f) return NULL; + + fseek(f, 0, SEEK_END); + long sz = ftell(f); + if (sz < 0) { fclose(f); return NULL; } + fseek(f, 0, SEEK_SET); + + uint8_t* out = malloc(sz); + if (out) { + size_t read_bytes = fread(out, 1, sz, f); + *out_len = read_bytes; + } + fclose(f); + return out; +} + +typedef struct LabelMap { + const char* name; + uint64_t offset; +} LabelMap; + +static inline const char* lookup_const(Sag_IntermediateProgram* prog, const char* name) { + for (uint64_t i = 0; i < prog->Consts_count; i += 2) { + if (strcmp(prog->Consts[i].head, name) == 0) { + return prog->Consts[i+1].head; + } + } + return NULL; +} + +static inline bool resolve_token(Sag_IntermediateProgram* prog, LabelMap* labels, size_t label_count, const char* token, int64_t* out_int, double* out_double) { + const char* resolved = lookup_const(prog, token); + if (resolved) { + token = resolved; + } + + for (size_t i = 0; i < label_count; ++i) { + if (strcmp(labels[i].name, token) == 0) { + *out_int = labels[i].offset; + *out_double = (double)labels[i].offset; + return true; + } + } + + char* end; + if (strncmp(token, "0x", 2) == 0 || strncmp(token, "0X", 2) == 0) { + *out_int = strtoll(token, &end, 16); + *out_double = (double)*out_int; + if (*end == '\0') return true; + } + + double d = strtod(token, &end); + if (*end == '\0') { + *out_double = d; + *out_int = (int64_t)d; + return true; + } + + return false; +} + +static inline sagittarius_type parse_type(const char* name) { + if (strcmp(name, "uint8") == 0) return st_uint8; + if (strcmp(name, "uint16") == 0) return st_uint16; + if (strcmp(name, "uint32") == 0) return st_uint32; + if (strcmp(name, "uint64") == 0) return st_uint64; + if (strcmp(name, "int8") == 0) return st_int8; + if (strcmp(name, "int16") == 0) return st_int16; + if (strcmp(name, "int32") == 0) return st_int32; + if (strcmp(name, "int64") == 0) return st_int64; + if (strcmp(name, "single") == 0 || strcmp(name, "float") == 0) return st_single; + if (strcmp(name, "double") == 0) return st_double; + return st_uint8; +} + +static inline uint8_t parse_math2_op(const char* name) { + if (strcmp(name, "add") == 0) return sag_math2_add; + if (strcmp(name, "sub") == 0) return sag_math2_sub; + if (strcmp(name, "mul") == 0) return sag_math2_mul; + if (strcmp(name, "div") == 0) return sag_math2_div; + if (strcmp(name, "mod") == 0) return sag_math2_mod; + if (strcmp(name, "pow") == 0) return sag_math2_pow; + return 0; +} + +static inline uint8_t parse_math1_op(const char* name) { + if (strcmp(name, "sin") == 0) return sag_math1_sin; + if (strcmp(name, "cos") == 0) return sag_math1_cos; + if (strcmp(name, "tan") == 0) return sag_math1_tan; + if (strcmp(name, "sinh") == 0) return sag_math1_sinh; + if (strcmp(name, "cosh") == 0) return sag_math1_cosh; + if (strcmp(name, "tanh") == 0) return sag_math1_tanh; + if (strcmp(name, "asin") == 0) return sag_math1_asin; + if (strcmp(name, "acos") == 0) return sag_math1_acos; + if (strcmp(name, "atan") == 0) return sag_math1_atan; + if (strcmp(name, "abs") == 0) return sag_math1_abs; + if (strcmp(name, "exp") == 0) return sag_math1_exp; + return 0; +} + +bool Sag_Finalize(Sag_IntermediateProgram* intermediate, SagittariusProgram* out) { + if (!intermediate || !out) return false; + + // Pass 1: Calculate Code Labels & instruction sizes + size_t label_capacity = 32; + size_t label_count = 0; + LabelMap* labels = malloc(label_capacity * sizeof(LabelMap)); + + uint64_t byte_offset = 0; + for (uint64_t i = 0; i < intermediate->inst_count; ++i) { + Sag_IntermediateInst* ii = &intermediate->insts[i]; + if (ii->label) { + if (label_count >= label_capacity) { + label_capacity *= 2; + labels = realloc(labels, label_capacity * sizeof(LabelMap)); + } + labels[label_count].name = ii->label->head; + labels[label_count].offset = byte_offset; + label_count++; + } + + // Calculate instruction size + const char* name = ii->args[0].head; + uint64_t sz = 8; + if (strcmp(name, "set") == 0 || strncmp(name, "set.", 4) == 0) { + sz = 16; + } else if (strcmp(name, "call") == 0) { + // Immediate mode if third argument is "1" + if (ii->arg_count >= 2 && strcmp(ii->args[2].head, "1") == 0) { + sz = 16; + } + } + byte_offset += sz; + } + + uint64_t total_inst_bytes = byte_offset; + out->instCount = total_inst_bytes / 8; + out->instructions = malloc(out->instCount * sizeof(SagittariusInst)); + memset(out->instructions, 0, out->instCount * sizeof(SagittariusInst)); + + // Pass 2: Resolve Data Section & Data Labels + uint64_t data_capacity = 1024; + uint64_t data_size = 0; + uint8_t* data_buf = malloc(data_capacity); + + for (uint64_t i = 0; i < intermediate->data_count; i += 3) { + const char* d_name = intermediate->data[i].head; + const char* d_type = intermediate->data[i+1].head; + const char* d_val = intermediate->data[i+2].head; + + // Record label offset relative to program start (which is loaded at 0 in final VM space) + if (label_count >= label_capacity) { + label_capacity *= 2; + labels = realloc(labels, label_capacity * sizeof(LabelMap)); + } + labels[label_count].name = d_name; + labels[label_count].offset = total_inst_bytes + data_size; + label_count++; + + size_t entry_len = 0; + uint8_t* entry_bytes = NULL; + if (strcmp(d_type, "string") == 0) { + entry_bytes = parse_string_bytes(d_val, &entry_len); + } else if (strcmp(d_type, "base64") == 0) { + entry_bytes = base64_decode(d_val, &entry_len); + } else if (strcmp(d_type, "file") == 0) { + entry_bytes = read_file_bytes(d_val, &entry_len); + } + + if (entry_bytes && entry_len > 0) { + if (data_size + entry_len > data_capacity) { + while (data_size + entry_len > data_capacity) data_capacity *= 2; + data_buf = realloc(data_buf, data_capacity); + } + memcpy(data_buf + data_size, entry_bytes, entry_len); + data_size += entry_len; + free(entry_bytes); + } + } + + out->data_size = data_size; + if (data_size > 0) { + out->data = malloc(data_size); + memcpy(out->data, data_buf, data_size); + } else { + out->data = NULL; + } + free(data_buf); + + // Pass 3: Assemble & Encode instructions + uint64_t final_inst_idx = 0; + for (uint64_t i = 0; i < intermediate->inst_count; ++i) { + Sag_IntermediateInst* ii = &intermediate->insts[i]; + const char* name = ii->args[0].head; + + uint64_t current_inst_offset = final_inst_idx * 8; + SagittariusInst main_inst; + main_inst.data = 0; + + if (strcmp(name, "add") == 0 || strcmp(name, "sub") == 0 || strcmp(name, "mul") == 0 || + strcmp(name, "div") == 0 || strcmp(name, "mod") == 0 || strcmp(name, "pow") == 0) { + + uint8_t opcode = math2; + sagittarius_type type = parse_type(ii->args[1].head); + uint8_t op = parse_math2_op(name); + + int64_t L = 0, R = 0, Dest = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[2].head, &L, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &R, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[4].head, &Dest, &dummy); + + main_inst.data = opcode | ((uint64_t)type << 8) | ((uint64_t)op << 16) | + ((uint64_t)(L & 0xFF) << 24) | ((uint64_t)(R & 0xFF) << 32) | + ((uint64_t)(Dest & 0xFF) << 40); + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "sin") == 0 || strcmp(name, "cos") == 0 || strcmp(name, "tan") == 0 || + strcmp(name, "sinh") == 0 || strcmp(name, "cosh") == 0 || strcmp(name, "tanh") == 0 || + strcmp(name, "asin") == 0 || strcmp(name, "acos") == 0 || strcmp(name, "atan") == 0 || + strcmp(name, "abs") == 0 || strcmp(name, "exp") == 0) { + + uint8_t opcode = math1; + sagittarius_type type = parse_type(ii->args[1].head); + uint8_t op = parse_math1_op(name); + + int64_t L = 0, Dest = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[2].head, &L, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &Dest, &dummy); + + main_inst.data = opcode | ((uint64_t)type << 8) | ((uint64_t)op << 16) | + ((uint64_t)(L & 0xFF) << 24) | ((uint64_t)(Dest & 0xFF) << 32); + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "cvt") == 0) { + uint8_t opcode = cvt; + int64_t src_reg = 0, dst_reg = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &src_reg, &dummy); + sagittarius_type src_type = parse_type(ii->args[2].head); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &dst_reg, &dummy); + sagittarius_type dst_type = parse_type(ii->args[4].head); + + main_inst.data = opcode | ((uint64_t)(src_reg & 0xFF) << 8) | ((uint64_t)src_type << 16) | + ((uint64_t)(dst_reg & 0xFF) << 24) | ((uint64_t)dst_type << 32); + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "set") == 0) { + uint8_t opcode = set; + int64_t length = 0, reg = 0, val_int = 0; + double val_double = 0; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &length, &val_double); + resolve_token(intermediate, labels, label_count, ii->args[2].head, ®, &val_double); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &val_int, &val_double); + + main_inst.data = opcode | ((uint64_t)(length & 0xFF) << 8) | ((uint64_t)(reg & 0xFF) << 16); + out->instructions[final_inst_idx++] = main_inst; + + SagittariusInst payload_inst; + payload_inst.data = (uint64_t)val_int; + out->instructions[final_inst_idx++] = payload_inst; + + } else if (strncmp(name, "set.", 4) == 0) { + uint8_t opcode = set; + sagittarius_type type = parse_type(name + 4); + uint8_t length = 8; + switch (type) { + case st_uint8: case st_int8: length = 1; break; + case st_uint16: case st_int16: length = 2; break; + case st_uint32: case st_int32: case st_single: length = 4; break; + default: length = 8; break; + } + + int64_t reg = 0, val_int = 0; + double val_double = 0; + resolve_token(intermediate, labels, label_count, ii->args[1].head, ®, &val_double); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &val_int, &val_double); + + main_inst.data = opcode | ((uint64_t)length << 8) | ((uint64_t)(reg & 0xFF) << 16); + out->instructions[final_inst_idx++] = main_inst; + + SagittariusInst payload_inst; + payload_inst.data = 0; + if (type == st_single) { + float f = (float)val_double; + uint32_t u32; + memcpy(&u32, &f, 4); + payload_inst.data = u32; + } else if (type == st_double) { + double d = val_double; + uint64_t u64; + memcpy(&u64, &d, 8); + payload_inst.data = u64; + } else { + payload_inst.data = (uint64_t)val_int; + } + out->instructions[final_inst_idx++] = payload_inst; + + } else if (strcmp(name, "mv") == 0 || strcmp(name, "cp") == 0) { + uint8_t opcode = (strcmp(name, "mv") == 0) ? mv : cp; + int64_t length = 0, src_reg = 0, dst_reg = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &length, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &src_reg, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &dst_reg, &dummy); + + main_inst.data = opcode | ((uint64_t)(length & 0xFF) << 8) | + ((uint64_t)(src_reg & 0xFF) << 16) | ((uint64_t)(dst_reg & 0xFF) << 24); + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "save") == 0) { + uint8_t opcode = save; + int64_t length = 0, src_reg = 0, dest_mem_ptr_reg = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &length, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &src_reg, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &dest_mem_ptr_reg, &dummy); + + main_inst.data = opcode | ((uint64_t)(length & 0xFF) << 8) | + ((uint64_t)(src_reg & 0xFF) << 16) | ((uint64_t)(dest_mem_ptr_reg & 0xFF) << 24); + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "load") == 0) { + uint8_t opcode = load; + int64_t length = 0, dest_reg = 0, src_mem_ptr_reg = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &length, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &dest_reg, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &src_mem_ptr_reg, &dummy); + + main_inst.data = opcode | ((uint64_t)(length & 0xFF) << 8) | + ((uint64_t)(dest_reg & 0xFF) << 16) | ((uint64_t)(src_mem_ptr_reg & 0xFF) << 24); + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "jmp") == 0) { + uint8_t opcode = jmp; + int64_t mode = 0, val_mode = 0, target_val = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &mode, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &val_mode, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &target_val, &dummy); + + if (val_mode == 1 && mode == 1) { + // Relative immediate: adjust target label to be relative offset + target_val = target_val - current_inst_offset; + } + + main_inst.data = opcode | ((uint64_t)(mode & 0xFF) << 8) | ((uint64_t)(val_mode & 0xFF) << 16); + if (val_mode == 0) { + main_inst.data |= ((uint64_t)(target_val & 0xFF) << 24); + } else { + main_inst.data |= ((uint64_t)(uint32_t)target_val << 24); + } + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "jmp_if") == 0) { + uint8_t opcode = jmp_if; + int64_t mode = 0, val_mode = 0, flag_reg = 0, target_val = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &mode, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &val_mode, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &flag_reg, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[4].head, &target_val, &dummy); + + if (val_mode == 1 && mode == 1) { + target_val = target_val - current_inst_offset; + } + + main_inst.data = opcode | ((uint64_t)(mode & 0xFF) << 8) | ((uint64_t)(val_mode & 0xFF) << 16) | + ((uint64_t)(flag_reg & 0xFF) << 24); + if (val_mode == 0) { + main_inst.data |= ((uint64_t)(target_val & 0xFF) << 32); + } else { + main_inst.data |= ((uint64_t)(uint32_t)target_val << 32); + } + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "call") == 0) { + uint8_t opcode = call; + int64_t mode = 0, val_mode = 0, reg_to_rem = 0, target_val = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &mode, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &val_mode, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[3].head, ®_to_rem, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[4].head, &target_val, &dummy); + + if (val_mode == 0) { + main_inst.data = opcode | ((uint64_t)(mode & 0xFF) << 8) | ((uint64_t)(val_mode & 0xFF) << 16) | + ((uint64_t)(reg_to_rem & 0xFF) << 24) | ((uint64_t)(target_val & 0xFF) << 32); + out->instructions[final_inst_idx++] = main_inst; + } else { + if (mode == 1) { + target_val = target_val - current_inst_offset; + } + main_inst.data = opcode | ((uint64_t)(mode & 0xFF) << 8) | ((uint64_t)(val_mode & 0xFF) << 16) | + ((uint64_t)(reg_to_rem & 0xFF) << 24); + out->instructions[final_inst_idx++] = main_inst; + + SagittariusInst payload_inst; + payload_inst.data = (uint64_t)target_val; + out->instructions[final_inst_idx++] = payload_inst; + } + + } else if (strcmp(name, "ret") == 0) { + uint8_t opcode = ret; + int64_t reg = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, ®, &dummy); + + main_inst.data = opcode | ((uint64_t)(reg & 0xFF) << 8); + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "cmp") == 0) { + uint8_t opcode = cmp; + sagittarius_type type = parse_type(ii->args[1].head); + + uint8_t op_val = 0; + const char* op_name = ii->args[2].head; + if (strcmp(op_name, "eq") == 0) op_val = 0; + else if (strcmp(op_name, "ne") == 0) op_val = 1; + else if (strcmp(op_name, "lt") == 0) op_val = 2; + else if (strcmp(op_name, "le") == 0) op_val = 3; + else if (strcmp(op_name, "gt") == 0) op_val = 4; + else if (strcmp(op_name, "ge") == 0) op_val = 5; + + int64_t L = 0, R = 0, Dest = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[3].head, &L, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[4].head, &R, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[5].head, &Dest, &dummy); + + main_inst.data = opcode | ((uint64_t)type << 8) | ((uint64_t)op_val << 16) | + ((uint64_t)(L & 0xFF) << 24) | ((uint64_t)(R & 0xFF) << 32) | + ((uint64_t)(Dest & 0xFF) << 40); + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "mathv") == 0) { + uint8_t opcode = mathv; + int64_t w = 0, h = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &w, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &h, &dummy); + + uint8_t op_val = 0; + const char* op_name = ii->args[3].head; + if (strcmp(op_name, "add") == 0) op_val = 0; + else if (strcmp(op_name, "sub") == 0) op_val = 1; + else if (strcmp(op_name, "mul") == 0) op_val = 2; + else if (strcmp(op_name, "div") == 0) op_val = 3; + + int64_t L_ptr = 0, R_ptr = 0, Dest_ptr = 0; + resolve_token(intermediate, labels, label_count, ii->args[4].head, &L_ptr, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[5].head, &R_ptr, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[6].head, &Dest_ptr, &dummy); + + main_inst.data = opcode | ((uint64_t)(w & 0xFF) << 8) | ((uint64_t)(h & 0xFF) << 16) | + ((uint64_t)op_val << 24) | ((uint64_t)(L_ptr & 0xFF) << 32) | + ((uint64_t)(R_ptr & 0xFF) << 40) | ((uint64_t)(Dest_ptr & 0xFF) << 48); + + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "halt") == 0) { + main_inst.data = halt; + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "syscall") == 0) { + uint8_t opcode = syscall; + int64_t ns_reg = 0, func_reg = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &ns_reg, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &func_reg, &dummy); + + main_inst.data = opcode | ((uint64_t)(ns_reg & 0xFF) << 8) | ((uint64_t)(func_reg & 0xFF) << 16); + out->instructions[final_inst_idx++] = main_inst; + + } else if (strcmp(name, "tsyscall") == 0) { + uint8_t opcode = tsyscall; + int64_t ns_reg = 0, func_reg = 0, result_reg = 0; + double dummy; + resolve_token(intermediate, labels, label_count, ii->args[1].head, &ns_reg, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[2].head, &func_reg, &dummy); + resolve_token(intermediate, labels, label_count, ii->args[3].head, &result_reg, &dummy); + + main_inst.data = opcode | ((uint64_t)(ns_reg & 0xFF) << 8) | ((uint64_t)(func_reg & 0xFF) << 16) | + ((uint64_t)(result_reg & 0xFF) << 24); + out->instructions[final_inst_idx++] = main_inst; + } + } + + free(labels); + return true; +} + +bool Sag_WriteProgram(FILE* f, SagittariusProgram* program) { + if (!f || !program) return false; + + if (fwrite(SAGITTARUIS_PROGRAM_HEAD, 1, 8, f) != 8) return false; + + uint32_t version = SAGITTARIUS_PROGRAM_FORMAT_VERSION; + if (fwrite(&version, 4, 1, f) != 1) return false; + + if (fwrite(&program->instCount, 8, 1, f) != 1) return false; + if (fwrite(&program->data_size, 8, 1, f) != 1) return false; + + if (program->instCount > 0) { + if (fwrite(program->instructions, sizeof(SagittariusInst), program->instCount, f) != program->instCount) { + return false; + } + } + + if (program->data_size > 0) { + if (fwrite(program->data, 1, program->data_size, f) != program->data_size) { + return false; + } + } + + return true; +} diff --git a/Source/Assembler/main.c b/Source/Assembler/main.c index 4c5ce76..736fed0 100644 --- a/Source/Assembler/main.c +++ b/Source/Assembler/main.c @@ -1,12 +1,146 @@ #include "../../Headers/Assembler/SagittariusAssembler.h" -/** - * Usage: - * - * SagittariusAssembler ... -o - * - * If no output file is specified, the assembler will output to .out. - */ -int main(int ac,char** av){ - printf("Copyright (C) 2026 Creeper Lv.\n"); +#include +#include +#include + +int main(int ac, char** av) { + printf("Copyright (C) 2026 Creeper Lv.\n"); + if (ac < 2) { + printf("Usage: SagittariusAssembler ... [-o ]\n"); + return 1; + } + + char* output_file = NULL; + char** input_files = malloc(ac * sizeof(char*)); + int input_count = 0; + + for (int i = 1; i < ac; ++i) { + if (strcmp(av[i], "-o") == 0) { + if (i + 1 < ac) { + output_file = av[i+1]; + i++; + } else { + printf("Error: Missing output file after -o\n"); + free(input_files); + return 1; + } + } else { + input_files[input_count++] = av[i]; + } + } + + if (input_count == 0) { + printf("Error: No input files specified\n"); + free(input_files); + return 1; + } + + char* dynamic_out = NULL; + if (!output_file) { + size_t len = strlen(input_files[0]); + dynamic_out = malloc(len + 5); + sprintf(dynamic_out, "%s.out", input_files[0]); + output_file = dynamic_out; + } + + printf("Assembling %d file(s) into '%s'...\n", input_count, output_file); + + Sag_IntermediateProgram combined; + memset(&combined, 0, sizeof(combined)); + + for (int i = 0; i < input_count; ++i) { + FILE* f = fopen(input_files[i], "r"); + if (!f) { + printf("Error: Cannot open input file '%s'\n", input_files[i]); + free(input_files); + if (dynamic_out) free(dynamic_out); + return 1; + } + + Sag_IntermediateProgram ip; + memset(&ip, 0, sizeof(ip)); + if (!Sag_Scan(f, &ip)) { + printf("Error scanning '%s'\n", input_files[i]); + fclose(f); + free(input_files); + if (dynamic_out) free(dynamic_out); + return 1; + } + fclose(f); + + if (i == 0) { + combined = ip; + } else { + Sag_IntermediateProgram temp; + memset(&temp, 0, sizeof(temp)); + if (!Sag_Combine(&combined, &ip, &temp)) { + printf("Error combining intermediate programs\n"); + free(input_files); + if (dynamic_out) free(dynamic_out); + return 1; + } + free(combined.insts); + free(combined.data); + free(combined.Consts); + free(ip.insts); + free(ip.data); + free(ip.Consts); + combined = temp; + } + } + + // Finalize + SagittariusProgram prog; + memset(&prog, 0, sizeof(prog)); + if (!Sag_Finalize(&combined, &prog)) { + printf("Error: Finalization failed!\n"); + free(combined.insts); + free(combined.data); + free(combined.Consts); + free(input_files); + if (dynamic_out) free(dynamic_out); + return 1; + } + + // Write output + FILE* out_f = fopen(output_file, "wb"); + if (!out_f) { + printf("Error: Cannot open output file '%s' for writing\n", output_file); + free(combined.insts); + free(combined.data); + free(combined.Consts); + free(prog.instructions); + if (prog.data) free(prog.data); + free(input_files); + if (dynamic_out) free(dynamic_out); + return 1; + } + + if (!Sag_WriteProgram(out_f, &prog)) { + printf("Error writing to output file '%s'\n", output_file); + fclose(out_f); + free(combined.insts); + free(combined.data); + free(combined.Consts); + free(prog.instructions); + if (prog.data) free(prog.data); + free(input_files); + if (dynamic_out) free(dynamic_out); + return 1; + } + fclose(out_f); + + printf("Successfully assembled! Instruction count: %llu, Data size: %llu bytes\n", + (unsigned long long)prog.instCount, (unsigned long long)prog.data_size); + + // Cleanup + free(combined.insts); + free(combined.data); + free(combined.Consts); + free(prog.instructions); + if (prog.data) free(prog.data); + free(input_files); + if (dynamic_out) free(dynamic_out); + return 0; } \ No newline at end of file diff --git a/Source/Standalone/main.c b/Source/Standalone/main.c index 64eee42..be4f777 100644 --- a/Source/Standalone/main.c +++ b/Source/Standalone/main.c @@ -1,10 +1,94 @@ #include "../../Headers/Sagittarius.h" +#include +#include +#include + int32_t syscall_print(SagittariusCore* core){ - uint64_t str_offset=core->reg.head[40]; - printf("%s",core->memory->data+str_offset); + uint64_t str_offset = 0; + memcpy(&str_offset, &core->reg.head[40], 8); + if (str_offset >= core->memory->size) { + printf("[Syscall Print Error: String offset 0x%llx is OOB]\n", (unsigned long long)str_offset); + return -1; + } + printf("%s", (char*)(core->memory->data + str_offset)); return 0; } -int main(int ac,char** av){ - printf("Copyright (C) 2026 Creeper Lv.\n"); + +int32_t my_panic_handler(SagittariusCore *core, uint64_t panic_id, const char *msg) { + printf("\n--- VM PANIC! ID: 0x%llx, PC: 0x%llx ---\n", (unsigned long long)panic_id, (unsigned long long)core->pc); + printf("Message: %s\n", msg); + exit(1); + return 0; +} + +int main(int ac, char** av) { + if (ac < 2) { + printf("Usage: Sagittarius \n"); + return 1; + } + + char* filepath = av[1]; + FILE* f = fopen(filepath, "rb"); + if (!f) { + printf("Error: Cannot open file '%s'\n", filepath); + return 1; + } + + fseek(f, 0, SEEK_END); + long sz = ftell(f); + if (sz < 0) { fclose(f); return 1; } + fseek(f, 0, SEEK_SET); + + uint8_t* byte_buf = malloc(sz); + if (!byte_buf) { + fclose(f); + return 1; + } + + size_t read_bytes = fread(byte_buf, 1, sz, f); + fclose(f); + + SagittariusProgram* prog = sagittarius_load_program_from_byte_array(byte_buf, read_bytes); + free(byte_buf); + + if (!prog) { + printf("Error: Failed to load program from '%s'\n", filepath); + return 1; + } + + // Create VM with 1 MB memory + SagittariusVM* vm = sagittarius_vm_new(1024 * 1024); + vm->panic_handler = my_panic_handler; + + // Register print syscall (namespace 0, function 0 -> ID 0) + sagittarius_register_syscall(vm, 0, syscall_print); + + // Load program at offset 0 + sagittarius_load_program_to_mem(vm, prog, 0); + + // Run VM + while (1) { + if (vm->core.pc >= vm->Memory.size) { + printf("Error: PC out of bounds!\n"); + break; + } + + SagittariusInst inst; + memcpy(&inst, &vm->Memory.data[vm->core.pc], sizeof(SagittariusInst)); + + uint8_t opcode = inst.data & 0xFF; + if (opcode == 14) { // halt opcode + break; + } + + sagittarius_step(vm); + } + + // Cleanup + sagittarius_vm_free(vm); + free(prog->instructions); + if (prog->data) free(prog->data); + free(prog); + return 0; } \ No newline at end of file diff --git a/Source/VM/Sagittarius.c b/Source/VM/Sagittarius.c index 40704ca..f555caa 100644 --- a/Source/VM/Sagittarius.c +++ b/Source/VM/Sagittarius.c @@ -1,24 +1,153 @@ #include "../../Headers/Sagittarius.h" #include "../../Headers/SagittariusInternal.h" #include +#include + SAGITTARIUS_API SagittariusVM* sagittarius_vm_new(uint64_t memory_size){ - SagittariusVM* vm=malloc(sizeof(SagittariusVM)); - vm->Memory.data=malloc(memory_size); - vm->Memory.size=memory_size; + SagittariusVM* vm = malloc(sizeof(SagittariusVM)); + if (!vm) return NULL; + + vm->Memory.data = malloc(memory_size); + vm->Memory.size = memory_size; + + // Clear registers + memset(vm->core.reg.head, 0, sizeof(vm->core.reg.head)); + + // Link core + vm->core.memory = &vm->Memory; + vm->core.vm = vm; + vm->core.pc = 0; + + // Initialize syscalls + vm->SagittariusSyscallEntries = NULL; + vm->SagittariusSyscallCount = 0; + vm->SagittariusSyscallCapacity = 0; + + vm->panic_handler = NULL; + return vm; } SAGITTARIUS_API void sagittarius_vm_free(SagittariusVM* vm){ - free(vm); + if (vm) { + if (vm->Memory.data) free(vm->Memory.data); + if (vm->SagittariusSyscallEntries) free(vm->SagittariusSyscallEntries); + free(vm); + } } -SAGITTARIUS_API void sagittarius_step(SagittariusVM* vm){ - +SAGITTARIUS_API void sagittarius_register_syscall(SagittariusVM *vm, uint64_t id, SagittariusSyscall syscall) { + if (!vm) return; + if (vm->SagittariusSyscallCount >= vm->SagittariusSyscallCapacity) { + vm->SagittariusSyscallCapacity = vm->SagittariusSyscallCapacity == 0 ? 4 : vm->SagittariusSyscallCapacity * 2; + vm->SagittariusSyscallEntries = realloc(vm->SagittariusSyscallEntries, vm->SagittariusSyscallCapacity * sizeof(SagittariusSyscallEntry)); + } + vm->SagittariusSyscallEntries[vm->SagittariusSyscallCount].id = id; + vm->SagittariusSyscallEntries[vm->SagittariusSyscallCount].syscall = syscall; + vm->SagittariusSyscallCount++; } + SAGITTARIUS_API void sagittarius_mem_resize(SagittariusVM* vm, uint64_t new_size){ - vm->Memory.data=realloc(vm->Memory.data,new_size); - vm->Memory.size=new_size; + if (vm) { + vm->Memory.data = realloc(vm->Memory.data, new_size); + vm->Memory.size = new_size; + } } + SAGITTARIUS_API uint64_t sagittarius_mem_getsize(SagittariusVM* vm){ - return vm->Memory.size; + return vm ? vm->Memory.size : 0; +} + +SAGITTARIUS_API void sagittarius_load_program_to_mem(SagittariusVM *vm, SagittariusProgram *program, uint64_t offset) { + if (!vm || !program) return; + + uint64_t required_size = offset + program->instCount * 8 + program->data_size; + if (required_size > vm->Memory.size) { + sagittarius_mem_resize(vm, required_size); + } + + if (program->instCount > 0) { + memcpy(vm->Memory.data + offset, program->instructions, program->instCount * 8); + } + if (program->data_size > 0) { + memcpy(vm->Memory.data + offset + program->instCount * 8, program->data, program->data_size); + } + + vm->core.pc = offset; +} + +SAGITTARIUS_API SagittariusProgram *sagittarius_load_program_from_byte_array(uint8_t *data, uint64_t size) { + if (size < 28) return NULL; + if (memcmp(data, SAGITTARUIS_PROGRAM_HEAD, 7) != 0) return NULL; + + uint32_t version; + memcpy(&version, data + 8, 4); + if (version != SAGITTARIUS_PROGRAM_FORMAT_VERSION) return NULL; + + uint64_t instCount; + memcpy(&instCount, data + 12, 8); + + uint64_t data_size; + memcpy(&data_size, data + 20, 8); + + if (size < 28 + instCount * 8 + data_size) return NULL; + + SagittariusProgram *prog = malloc(sizeof(SagittariusProgram)); + prog->instCount = instCount; + if (instCount > 0) { + prog->instructions = malloc(instCount * sizeof(SagittariusInst)); + memcpy(prog->instructions, data + 28, instCount * 8); + } else { + prog->instructions = NULL; + } + + prog->data_size = data_size; + if (data_size > 0) { + prog->data = malloc(data_size); + memcpy(prog->data, data + 28 + instCount * 8, data_size); + } else { + prog->data = NULL; + } + + return prog; +} + +SAGITTARIUS_API void sagittarius_step(SagittariusVM *vm) { + if (!vm) return; + if (vm->core.pc >= vm->Memory.size) { + if (vm->panic_handler) vm->panic_handler(&vm->core, Sagittarius_Msg_OOB, "PC out of bounds"); + return; + } + + SagittariusInst inst; + memcpy(&inst, &vm->Memory.data[vm->core.pc], sizeof(SagittariusInst)); + + uint8_t opcode = inst.data & 0xFF; + bool success = false; + + switch ((SagittariusInstDef)opcode) { + case math2: success = Math2Op(&vm->core, inst); break; + case math1: success = Math1Op(&vm->core, inst); break; + case cvt: success = SagCvt(&vm->core, inst); break; + case set: success = SagSet(&vm->core, inst); break; + case mv: success = SagMv(&vm->core, inst); break; + case cp: success = SagCp(&vm->core, inst); break; + case save: success = SagSave(&vm->core, inst); break; + case load: success = SagLoad(&vm->core, inst); break; + case jmp: success = SagJmp(&vm->core, inst); break; + case jmp_if: success = SagJmpIf(&vm->core, inst); break; + case call: success = SagCall(&vm->core, inst); break; + case ret: success = SagRet(&vm->core, inst); break; + case cmp: success = SagCmp(&vm->core, inst); break; + case mathv: success = SagMathV(&vm->core, inst); break; + case halt: success = SagHalt(&vm->core, inst); break; + case syscall: success = SagSyscall(&vm->core, inst); break; + case tsyscall: success = SagTSyscall(&vm->core, inst); break; + default: { + if (vm->panic_handler) vm->panic_handler(&vm->core, Sagittarius_Msg_Unknown, "Unknown opcode"); + break; + } + } + + (void)success; } \ No newline at end of file diff --git a/Source/VM/SagittariusInternal.c b/Source/VM/SagittariusInternal.c new file mode 100644 index 0000000..b807af5 --- /dev/null +++ b/Source/VM/SagittariusInternal.c @@ -0,0 +1,604 @@ +#include "../../Headers/SagittariusInternal.h" +#include "../../Headers/SagittariusPanic.h" +#include +#include +#include + +/* Safe register read/write helpers */ +static inline void reg_read(SagittariusCore *core, uint8_t reg_idx, void *dest, sagittarius_type t) { + size_t sz = 0; + switch (t) { + case st_uint8: case st_int8: sz = 1; break; + case st_uint16: case st_int16: sz = 2; break; + case st_uint32: case st_int32: case st_single: sz = 4; break; + case st_uint64: case st_int64: case st_double: sz = 8; break; + } + memcpy(dest, &core->reg.head[reg_idx], sz); +} + +static inline void reg_write(SagittariusCore *core, uint8_t reg_idx, const void *src, sagittarius_type t) { + size_t sz = 0; + switch (t) { + case st_uint8: case st_int8: sz = 1; break; + case st_uint16: case st_int16: sz = 2; break; + case st_uint32: case st_int32: case st_single: sz = 4; break; + case st_uint64: case st_int64: case st_double: sz = 8; break; + } + memcpy(&core->reg.head[reg_idx], src, sz); +} + +/* Macro for math2 (add, sub, mul) */ +#define MATH2_OP_IMPL(name, op) \ +internal bool SagMath2##name(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T) { \ + switch (t) { \ + case st_uint8: { uint8_t l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + case st_uint16: { uint16_t l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + case st_uint32: { uint32_t l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + case st_uint64: { uint64_t l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + case st_int8: { int8_t l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + case st_int16: { int16_t l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + case st_int32: { int32_t l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + case st_int64: { int64_t l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + case st_single: { float l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + case st_double: { double l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = l op r; reg_write(core, T, &res, t); break; } \ + default: return false; \ + } \ + return true; \ +} + +MATH2_OP_IMPL(Add, +) +MATH2_OP_IMPL(Sub, -) +MATH2_OP_IMPL(Mul, *) + +#define DIV_CASE(st_type, c_type) \ +case st_type: { \ + c_type l, r, res; \ + reg_read(core, L, &l, t); \ + reg_read(core, R, &r, t); \ + if (r == 0) { \ + if (core->vm->panic_handler) core->vm->panic_handler(core, Sagittarius_Msg_Generic, "Division by zero"); \ + return false; \ + } \ + res = l / r; \ + reg_write(core, T, &res, t); \ + break; \ +} + +#define DIV_FLOAT_CASE(st_type, c_type) \ +case st_type: { \ + c_type l, r, res; \ + reg_read(core, L, &l, t); \ + reg_read(core, R, &r, t); \ + res = l / r; \ + reg_write(core, T, &res, t); \ + break; \ +} + +internal bool SagMath2Div(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T) { + switch (t) { + DIV_CASE(st_uint8, uint8_t) + DIV_CASE(st_uint16, uint16_t) + DIV_CASE(st_uint32, uint32_t) + DIV_CASE(st_uint64, uint64_t) + DIV_CASE(st_int8, int8_t) + DIV_CASE(st_int16, int16_t) + DIV_CASE(st_int32, int32_t) + DIV_CASE(st_int64, int64_t) + DIV_FLOAT_CASE(st_single, float) + DIV_FLOAT_CASE(st_double, double) + default: return false; + } + return true; +} + +#define MOD_CASE(st_type, c_type) \ +case st_type: { \ + c_type l, r, res; \ + reg_read(core, L, &l, t); \ + reg_read(core, R, &r, t); \ + if (r == 0) { \ + if (core->vm->panic_handler) core->vm->panic_handler(core, Sagittarius_Msg_Generic, "Modulo by zero"); \ + return false; \ + } \ + res = l % r; \ + reg_write(core, T, &res, t); \ + break; \ +} + +internal bool SagMath2Mod(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T) { + switch (t) { + MOD_CASE(st_uint8, uint8_t) + MOD_CASE(st_uint16, uint16_t) + MOD_CASE(st_uint32, uint32_t) + MOD_CASE(st_uint64, uint64_t) + MOD_CASE(st_int8, int8_t) + MOD_CASE(st_int16, int16_t) + MOD_CASE(st_int32, int32_t) + MOD_CASE(st_int64, int64_t) + case st_single: { float l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = fmodf(l, r); reg_write(core, T, &res, t); break; } + case st_double: { double l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = fmod(l, r); reg_write(core, T, &res, t); break; } + default: return false; + } + return true; +} + +#define POW_CASE(st_type, c_type) \ +case st_type: { \ + c_type l, r, res; \ + reg_read(core, L, &l, t); \ + reg_read(core, R, &r, t); \ + res = (c_type)pow((double)l, (double)r); \ + reg_write(core, T, &res, t); \ + break; \ +} + +internal bool SagMath2Pow(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t R, uint8_t T) { + switch (t) { + POW_CASE(st_uint8, uint8_t) + POW_CASE(st_uint16, uint16_t) + POW_CASE(st_uint32, uint32_t) + POW_CASE(st_uint64, uint64_t) + POW_CASE(st_int8, int8_t) + POW_CASE(st_int16, int16_t) + POW_CASE(st_int32, int32_t) + POW_CASE(st_int64, int64_t) + case st_single: { float l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = powf(l, r); reg_write(core, T, &res, t); break; } + case st_double: { double l, r, res; reg_read(core, L, &l, t); reg_read(core, R, &r, t); res = pow(l, r); reg_write(core, T, &res, t); break; } + default: return false; + } + return true; +} + +internal bool Math2Op(SagittariusCore *core, SagittariusInst inst) { + uint8_t t = (inst.data >> 8) & 0xFF; + uint8_t op = (inst.data >> 16) & 0xFF; + uint8_t L = (inst.data >> 24) & 0xFF; + uint8_t R = (inst.data >> 32) & 0xFF; + uint8_t T = (inst.data >> 40) & 0xFF; + bool status = false; + switch (op) { + case sag_math2_add: status = SagMath2Add(core, (sagittarius_type)t, L, R, T); break; + case sag_math2_sub: status = SagMath2Sub(core, (sagittarius_type)t, L, R, T); break; + case sag_math2_mul: status = SagMath2Mul(core, (sagittarius_type)t, L, R, T); break; + case sag_math2_div: status = SagMath2Div(core, (sagittarius_type)t, L, R, T); break; + case sag_math2_mod: status = SagMath2Mod(core, (sagittarius_type)t, L, R, T); break; + case sag_math2_pow: status = SagMath2Pow(core, (sagittarius_type)t, L, R, T); break; + default: return false; + } + if (status) { + core->pc += 8; + } + return status; +} + +/* Math1 unary operators helper */ +static inline double my_abs(double v) { return v < 0 ? -v : v; } +static inline float my_absf(float v) { return v < 0 ? -v : v; } + +#define MATH1_OP_IMPL(name, func, float_func) \ +internal bool SagMath1##name(SagittariusCore *core, sagittarius_type t, uint8_t L, uint8_t T) { \ + switch (t) { \ + case st_uint8: { uint8_t l, res; reg_read(core, L, &l, t); res = (uint8_t)func((double)l); reg_write(core, T, &res, t); break; } \ + case st_uint16: { uint16_t l, res; reg_read(core, L, &l, t); res = (uint16_t)func((double)l); reg_write(core, T, &res, t); break; } \ + case st_uint32: { uint32_t l, res; reg_read(core, L, &l, t); res = (uint32_t)func((double)l); reg_write(core, T, &res, t); break; } \ + case st_uint64: { uint64_t l, res; reg_read(core, L, &l, t); res = (uint64_t)func((double)l); reg_write(core, T, &res, t); break; } \ + case st_int8: { int8_t l, res; reg_read(core, L, &l, t); res = (int8_t)func((double)l); reg_write(core, T, &res, t); break; } \ + case st_int16: { int16_t l, res; reg_read(core, L, &l, t); res = (int16_t)func((double)l); reg_write(core, T, &res, t); break; } \ + case st_int32: { int32_t l, res; reg_read(core, L, &l, t); res = (int32_t)func((double)l); reg_write(core, T, &res, t); break; } \ + case st_int64: { int64_t l, res; reg_read(core, L, &l, t); res = (int64_t)func((double)l); reg_write(core, T, &res, t); break; } \ + case st_single: { float l, res; reg_read(core, L, &l, t); res = float_func(l); reg_write(core, T, &res, t); break; } \ + case st_double: { double l, res; reg_read(core, L, &l, t); res = func(l); reg_write(core, T, &res, t); break; } \ + default: return false; \ + } \ + return true; \ +} + +MATH1_OP_IMPL(Sin, sin, sinf) +MATH1_OP_IMPL(Cos, cos, cosf) +MATH1_OP_IMPL(Tan, tan, tanf) +MATH1_OP_IMPL(Sinh, sinh, sinhf) +MATH1_OP_IMPL(Cosh, cosh, coshf) +MATH1_OP_IMPL(Tanh, tanh, tanhf) +MATH1_OP_IMPL(Asin, asin, asinf) +MATH1_OP_IMPL(Acos, acos, acosf) +MATH1_OP_IMPL(Atan, atan, atanf) +MATH1_OP_IMPL(Abs, my_abs, my_absf) +MATH1_OP_IMPL(Exp, exp, expf) + +internal bool Math1Op(SagittariusCore *core, SagittariusInst inst) { + uint8_t t = (inst.data >> 8) & 0xFF; + uint8_t op = (inst.data >> 16) & 0xFF; + uint8_t L = (inst.data >> 24) & 0xFF; + uint8_t T = (inst.data >> 32) & 0xFF; + bool status = false; + switch (op) { + case sag_math1_sin: status = SagMath1Sin(core, (sagittarius_type)t, L, T); break; + case sag_math1_cos: status = SagMath1Cos(core, (sagittarius_type)t, L, T); break; + case sag_math1_tan: status = SagMath1Tan(core, (sagittarius_type)t, L, T); break; + case sag_math1_sinh: status = SagMath1Sinh(core, (sagittarius_type)t, L, T); break; + case sag_math1_cosh: status = SagMath1Cosh(core, (sagittarius_type)t, L, T); break; + case sag_math1_tanh: status = SagMath1Tanh(core, (sagittarius_type)t, L, T); break; + case sag_math1_asin: status = SagMath1Asin(core, (sagittarius_type)t, L, T); break; + case sag_math1_acos: status = SagMath1Acos(core, (sagittarius_type)t, L, T); break; + case sag_math1_atan: status = SagMath1Atan(core, (sagittarius_type)t, L, T); break; + case sag_math1_abs: status = SagMath1Abs(core, (sagittarius_type)t, L, T); break; + case sag_math1_exp: status = SagMath1Exp(core, (sagittarius_type)t, L, T); break; + default: return false; + } + if (status) { + core->pc += 8; + } + return status; +} + +/* CVT (Conversion) */ +#define CVT_CASE_SRC(src_c_type, src_t) \ +case src_t: { \ + src_c_type val; \ + reg_read(core, src_reg, &val, src_t); \ + switch (dst_type) { \ + case st_uint8: { uint8_t r = (uint8_t)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + case st_uint16: { uint16_t r = (uint16_t)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + case st_uint32: { uint32_t r = (uint32_t)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + case st_uint64: { uint64_t r = (uint64_t)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + case st_int8: { int8_t r = (int8_t)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + case st_int16: { int16_t r = (int16_t)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + case st_int32: { int32_t r = (int32_t)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + case st_int64: { int64_t r = (int64_t)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + case st_single: { float r = (float)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + case st_double: { double r = (double)val; reg_write(core, dst_reg, &r, dst_type); break; } \ + } \ + break; \ +} + +internal bool SagCvt(SagittariusCore *core, SagittariusInst inst) { + uint8_t src_reg = (inst.data >> 8) & 0xFF; + uint8_t src_type = (inst.data >> 16) & 0xFF; + uint8_t dst_reg = (inst.data >> 24) & 0xFF; + uint8_t dst_type = (inst.data >> 32) & 0xFF; + + switch ((sagittarius_type)src_type) { + CVT_CASE_SRC(uint8_t, st_uint8) + CVT_CASE_SRC(uint16_t, st_uint16) + CVT_CASE_SRC(uint32_t, st_uint32) + CVT_CASE_SRC(uint64_t, st_uint64) + CVT_CASE_SRC(int8_t, st_int8) + CVT_CASE_SRC(int16_t, st_int16) + CVT_CASE_SRC(int32_t, st_int32) + CVT_CASE_SRC(int64_t, st_int64) + CVT_CASE_SRC(float, st_single) + CVT_CASE_SRC(double, st_double) + default: return false; + } + core->pc += 8; + return true; +} + +/* Set, Mv, Cp, Save, Load */ +internal bool SagSet(SagittariusCore *core, SagittariusInst inst) { + uint8_t length = (inst.data >> 8) & 0xFF; + uint8_t reg_idx = (inst.data >> 16) & 0xFF; + + if (core->pc + 15 >= core->memory->size) { + if (core->vm->panic_handler) core->vm->panic_handler(core, Sagittarius_Msg_OOB, "Set payload out of bounds"); + return false; + } + + uint64_t payload = 0; + memcpy(&payload, &core->memory->data[core->pc + 8], 8); + + if (length > 8) length = 8; + memcpy(&core->reg.head[reg_idx], &payload, length); + + core->pc += 16; + return true; +} + +internal bool SagMv(SagittariusCore *core, SagittariusInst inst) { + uint8_t length = (inst.data >> 8) & 0xFF; + uint8_t src_reg = (inst.data >> 16) & 0xFF; + uint8_t dst_reg = (inst.data >> 24) & 0xFF; + + if (length > 8) length = 8; + memmove(&core->reg.head[dst_reg], &core->reg.head[src_reg], length); + core->pc += 8; + return true; +} + +internal bool SagCp(SagittariusCore *core, SagittariusInst inst) { + uint8_t length = (inst.data >> 8) & 0xFF; + uint8_t src_reg = (inst.data >> 16) & 0xFF; + uint8_t dst_reg = (inst.data >> 24) & 0xFF; + + if (length > 8) length = 8; + memcpy(&core->reg.head[dst_reg], &core->reg.head[src_reg], length); + core->pc += 8; + return true; +} + +internal bool SagSave(SagittariusCore *core, SagittariusInst inst) { + uint8_t length = (inst.data >> 8) & 0xFF; + uint8_t src_reg = (inst.data >> 16) & 0xFF; + uint8_t dest_mem_ptr_reg = (inst.data >> 24) & 0xFF; + + uint64_t mem_addr = 0; + memcpy(&mem_addr, &core->reg.head[dest_mem_ptr_reg], 8); + + if (mem_addr + length > core->memory->size) { + if (core->vm->panic_handler) core->vm->panic_handler(core, Sagittarius_Msg_OOB, "Memory write out of bounds"); + return false; + } + + if (length > 8) length = 8; + memcpy(&core->memory->data[mem_addr], &core->reg.head[src_reg], length); + core->pc += 8; + return true; +} + +internal bool SagLoad(SagittariusCore *core, SagittariusInst inst) { + uint8_t length = (inst.data >> 8) & 0xFF; + uint8_t dest_reg = (inst.data >> 16) & 0xFF; + uint8_t src_mem_ptr_reg = (inst.data >> 24) & 0xFF; + + uint64_t mem_addr = 0; + memcpy(&mem_addr, &core->reg.head[src_mem_ptr_reg], 8); + + if (mem_addr + length > core->memory->size) { + if (core->vm->panic_handler) core->vm->panic_handler(core, Sagittarius_Msg_OOB, "Memory read out of bounds"); + return false; + } + + if (length > 8) length = 8; + memcpy(&core->reg.head[dest_reg], &core->memory->data[mem_addr], length); + core->pc += 8; + return true; +} + +/* Control flow: Jmp, JmpIf, Call, Ret */ +internal bool SagJmp(SagittariusCore *core, SagittariusInst inst) { + uint8_t mode = (inst.data >> 8) & 0xFF; // 0 = absolute, 1 = relative + uint8_t val_mode = (inst.data >> 16) & 0xFF; // 0 = register, 1 = immediate + + uint64_t target_val = 0; + if (val_mode == 0) { + uint8_t reg_idx = (inst.data >> 24) & 0xFF; + memcpy(&target_val, &core->reg.head[reg_idx], 8); + } else { + int32_t imm; + memcpy(&imm, &((uint8_t*)&inst.data)[3], 4); + target_val = (int64_t)imm; // Sign extended + } + + if (mode == 0) { + core->pc = target_val; + } else { + core->pc += target_val; + } + return true; +} + +internal bool SagJmpIf(SagittariusCore *core, SagittariusInst inst) { + uint8_t mode = (inst.data >> 8) & 0xFF; + uint8_t val_mode = (inst.data >> 16) & 0xFF; + uint8_t flag_reg = (inst.data >> 24) & 0xFF; + + uint8_t flag = 0; + memcpy(&flag, &core->reg.head[flag_reg], 1); + + if (flag != 0) { + uint64_t target_val = 0; + if (val_mode == 0) { + uint8_t reg_idx = (inst.data >> 32) & 0xFF; + memcpy(&target_val, &core->reg.head[reg_idx], 8); + } else { + int32_t imm; + memcpy(&imm, &((uint8_t*)&inst.data)[4], 4); + target_val = (int64_t)imm; // Sign extended + } + + if (mode == 0) { + core->pc = target_val; + } else { + core->pc += target_val; + } + } else { + core->pc += 8; + } + return true; +} + +internal bool SagCall(SagittariusCore *core, SagittariusInst inst) { + uint8_t mode = (inst.data >> 8) & 0xFF; + uint8_t val_mode = (inst.data >> 16) & 0xFF; + uint8_t reg_to_rem = (inst.data >> 24) & 0xFF; + + if (val_mode == 0) { + uint8_t reg_idx = (inst.data >> 32) & 0xFF; + uint64_t target_pc = 0; + memcpy(&target_pc, &core->reg.head[reg_idx], 8); + + uint64_t ret_pc = core->pc + 8; + memcpy(&core->reg.head[reg_to_rem], &ret_pc, 8); + + if (mode == 0) { + core->pc = target_pc; + } else { + core->pc += target_pc; + } + } else { + if (core->pc + 15 >= core->memory->size) { + if (core->vm->panic_handler) core->vm->panic_handler(core, Sagittarius_Msg_OOB, "Call payload out of bounds"); + return false; + } + uint64_t target_pc = 0; + memcpy(&target_pc, &core->memory->data[core->pc + 8], 8); + + uint64_t ret_pc = core->pc + 16; + memcpy(&core->reg.head[reg_to_rem], &ret_pc, 8); + + if (mode == 0) { + core->pc = target_pc; + } else { + core->pc += target_pc; + } + } + return true; +} + +internal bool SagRet(SagittariusCore *core, SagittariusInst inst) { + uint8_t reg_to_restore = (inst.data >> 8) & 0xFF; + uint64_t target_pc = 0; + memcpy(&target_pc, &core->reg.head[reg_to_restore], 8); + core->pc = target_pc; + return true; +} + +/* Compare */ +#define CMP_CASE(st_type, c_type, sz) \ +case st_type: { \ + c_type l, r; \ + reg_read(core, L, &l, (sagittarius_type)t); \ + reg_read(core, R, &r, (sagittarius_type)t); \ + switch (op) { \ + case 0: res = (l == r); break; \ + case 1: res = (l != r); break; \ + case 2: res = (l < r); break; \ + case 3: res = (l <= r); break; \ + case 4: res = (l > r); break; \ + case 5: res = (l >= r); break; \ + default: res = 0; break; \ + } \ + break; \ +} + +internal bool SagCmp(SagittariusCore *core, SagittariusInst inst) { + uint8_t t = (inst.data >> 8) & 0xFF; + uint8_t op = (inst.data >> 16) & 0xFF; + uint8_t L = (inst.data >> 24) & 0xFF; + uint8_t R = (inst.data >> 32) & 0xFF; + uint8_t T = (inst.data >> 40) & 0xFF; + + uint8_t res = 0; + switch ((sagittarius_type)t) { + CMP_CASE(st_uint8, uint8_t, 1) + CMP_CASE(st_uint16, uint16_t, 2) + CMP_CASE(st_uint32, uint32_t, 4) + CMP_CASE(st_uint64, uint64_t, 8) + CMP_CASE(st_int8, int8_t, 1) + CMP_CASE(st_int16, int16_t, 2) + CMP_CASE(st_int32, int32_t, 4) + CMP_CASE(st_int64, int64_t, 8) + CMP_CASE(st_single, float, 4) + CMP_CASE(st_double, double, 8) + default: return false; + } + memcpy(&core->reg.head[T], &res, 1); + core->pc += 8; + return true; +} + +/* MathV (Vector Math) */ +internal bool SagMathV(SagittariusCore *core, SagittariusInst inst) { + uint8_t w = (inst.data >> 8) & 0xFF; + uint8_t h = (inst.data >> 16) & 0xFF; + uint8_t op = (inst.data >> 24) & 0xFF; + uint8_t L_ptr_reg = (inst.data >> 32) & 0xFF; + uint8_t R_ptr_reg = (inst.data >> 40) & 0xFF; + uint8_t Dest_ptr_reg = (inst.data >> 48) & 0xFF; + + uint64_t l_addr = 0, r_addr = 0, d_addr = 0; + memcpy(&l_addr, &core->reg.head[L_ptr_reg], 8); + memcpy(&r_addr, &core->reg.head[R_ptr_reg], 8); + memcpy(&d_addr, &core->reg.head[Dest_ptr_reg], 8); + + uint64_t size_in_bytes = (uint64_t)w * h * 8; + if (l_addr + size_in_bytes > core->memory->size || + r_addr + size_in_bytes > core->memory->size || + d_addr + size_in_bytes > core->memory->size) { + if (core->vm->panic_handler) core->vm->panic_handler(core, Sagittarius_Msg_OOB, "Vector math OOB access"); + return false; + } + + for (uint64_t i = 0; i < (uint64_t)w * h; ++i) { + double l_val = 0, r_val = 0, d_val = 0; + memcpy(&l_val, &core->memory->data[l_addr + i * 8], 8); + memcpy(&r_val, &core->memory->data[r_addr + i * 8], 8); + switch (op) { + case 0: d_val = l_val + r_val; break; + case 1: d_val = l_val - r_val; break; + case 2: d_val = l_val * r_val; break; + case 3: { + if (r_val == 0.0) { + if (core->vm->panic_handler) core->vm->panic_handler(core, Sagittarius_Msg_Generic, "Vector division by zero"); + return false; + } + d_val = l_val / r_val; + break; + } + default: d_val = 0; break; + } + memcpy(&core->memory->data[d_addr + i * 8], &d_val, 8); + } + + core->pc += 8; + return true; +} + +/* Halt */ +internal bool SagHalt(SagittariusCore *core, SagittariusInst inst) { + (void)core; (void)inst; + return true; +} + +/* Syscall & TSyscall */ +internal bool SagSyscall(SagittariusCore *core, SagittariusInst inst) { + uint8_t ns_reg = (inst.data >> 8) & 0xFF; + uint8_t func_reg = (inst.data >> 16) & 0xFF; + + uint64_t ns = 0, func_id = 0; + memcpy(&ns, &core->reg.head[ns_reg], 8); + memcpy(&func_id, &core->reg.head[func_reg], 8); + + uint64_t syscall_id = (ns << 32) | func_id; + + bool found = false; + for (uint64_t i = 0; i < core->vm->SagittariusSyscallCount; ++i) { + if (core->vm->SagittariusSyscallEntries[i].id == syscall_id) { + core->vm->SagittariusSyscallEntries[i].syscall(core); + found = true; + break; + } + } + + if (!found) { + if (core->vm->panic_handler) core->vm->panic_handler(core, Sagittarius_Msg_Unknown, "Unregistered syscall called"); + return false; + } + + core->pc += 8; + return true; +} + +internal bool SagTSyscall(SagittariusCore *core, SagittariusInst inst) { + uint8_t ns_reg = (inst.data >> 8) & 0xFF; + uint8_t func_reg = (inst.data >> 16) & 0xFF; + uint8_t result_reg = (inst.data >> 24) & 0xFF; + + uint64_t ns = 0, func_id = 0; + memcpy(&ns, &core->reg.head[ns_reg], 8); + memcpy(&func_id, &core->reg.head[func_reg], 8); + + uint64_t syscall_id = (ns << 32) | func_id; + + uint8_t result = 0; + for (uint64_t i = 0; i < core->vm->SagittariusSyscallCount; ++i) { + if (core->vm->SagittariusSyscallEntries[i].id == syscall_id) { + result = 1; + break; + } + } + + memcpy(&core->reg.head[result_reg], &result, 1); + core->pc += 8; + return true; +}