Implemented using Antigravity and it actually works!
This commit is contained in:
+138
-9
@@ -1,24 +1,153 @@
|
||||
#include "../../Headers/Sagittarius.h"
|
||||
#include "../../Headers/SagittariusInternal.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,604 @@
|
||||
#include "../../Headers/SagittariusInternal.h"
|
||||
#include "../../Headers/SagittariusPanic.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
/* 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;
|
||||
}
|
||||
Reference in New Issue
Block a user