mirror of
https://github.com/allaunthefox/SilverSight.git
synced 2026-07-31 01:25:21 +00:00
Lean (reference), Python, Rust, C, C++, Go, Julia, R, Scala, Fortran, Coq, Octave — all implementing the same AVM ISA v1 specification. Every port implements: - Full type universe: Q0_16, Q16_16, Bool - 11 primitives with floor division (Lean Int.ediv), V6 signed comparison, symmetric clamping [-2147483647, 2147483647] - 12 instruction opcodes with stack depth limit (1024) - Fuel-bounded run loop - Error handling (stack under/overflow, type mismatch, div-by-zero, jump OOB)
197 lines
7.7 KiB
C
197 lines
7.7 KiB
C
/* AVM ISA v1 — C Port (Strict Functional Execution) */
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* ── Constants ─────────────────────────────────────────────── */
|
|
#define AVM_CLAMP_MIN (-2147483647)
|
|
#define AVM_CLAMP_MAX 2147483647
|
|
#define AVM_Q0_MIN (-32767)
|
|
#define AVM_Q0_MAX 32767
|
|
#define Q16_SCALE 65536
|
|
#define AVM_MAX_STACK 1024
|
|
#define AVM_MAX_LOCALS 256
|
|
|
|
/* ── Clamp ─────────────────────────────────────────────────── */
|
|
static inline int32_t avm_clamp(int64_t x) {
|
|
if (x > AVM_CLAMP_MAX) return AVM_CLAMP_MAX;
|
|
if (x < AVM_CLAMP_MIN) return AVM_CLAMP_MIN;
|
|
return (int32_t)x;
|
|
}
|
|
|
|
static inline int32_t avm_q0_clamp(int64_t x) {
|
|
if (x > AVM_Q0_MAX) return AVM_Q0_MAX;
|
|
if (x < AVM_Q0_MIN) return AVM_Q0_MIN;
|
|
return (int32_t)x;
|
|
}
|
|
|
|
/* Floor division matching Lean Int.ediv (rounds toward -inf) */
|
|
static inline int32_t floor_div(int64_t a, int64_t b) {
|
|
if (b == 0) return 0;
|
|
int64_t q = a / b;
|
|
int64_t r = a % b;
|
|
if (r != 0 && ((a ^ b) < 0)) q--;
|
|
return (int32_t)q;
|
|
}
|
|
|
|
static inline bool lt_q16_v6(int32_t a, int32_t b) {
|
|
bool sa = a < 0, sb = b < 0;
|
|
return (sa != sb) ? sa : (a < b);
|
|
}
|
|
|
|
/* ── Types ─────────────────────────────────────────────────── */
|
|
typedef enum { TY_Q0, TY_Q16, TY_BOOL } AvmTy;
|
|
|
|
typedef struct {
|
|
AvmTy ty;
|
|
union { int32_t i; bool b; } val;
|
|
} AnyVal;
|
|
|
|
/* ── Instructions ──────────────────────────────────────────── */
|
|
typedef enum {
|
|
OP_PUSH_Q16, OP_PUSH_BOOL, OP_PUSH_Q0,
|
|
OP_POP, OP_DUP, OP_SWAP, OP_LOAD, OP_STORE,
|
|
OP_JUMP, OP_JUMP_IF, OP_PRIM, OP_HALT
|
|
} OpCode;
|
|
|
|
typedef enum {
|
|
PRIM_ADD_Q0, PRIM_SUB_Q0, PRIM_ADD_Q16, PRIM_SUB_Q16,
|
|
PRIM_MUL_Q16, PRIM_DIV_Q16, PRIM_LT_Q16, PRIM_EQ_Q16,
|
|
PRIM_AND, PRIM_OR, PRIM_NOT
|
|
} PrimCode;
|
|
|
|
typedef struct { OpCode op; int32_t arg; bool arg2; } Instr;
|
|
|
|
/* ── State ─────────────────────────────────────────────────── */
|
|
typedef struct {
|
|
int pc;
|
|
AnyVal stack[AVM_MAX_STACK];
|
|
int sp;
|
|
AnyVal locals[AVM_MAX_LOCALS];
|
|
bool local_set[AVM_MAX_LOCALS];
|
|
bool halted;
|
|
} State;
|
|
|
|
void init_state(State *s, int n_locals) {
|
|
s->pc = 0; s->sp = 0; s->halted = false;
|
|
for (int i = 0; i < n_locals && i < AVM_MAX_LOCALS; i++) s->local_set[i] = false;
|
|
}
|
|
|
|
/* ── Primitive execution ───────────────────────────────────── */
|
|
AnyVal eval_prim(PrimCode p, AnyVal a, AnyVal b) {
|
|
AnyVal r = { .ty = TY_Q0, .val.i = 0 };
|
|
if (p == PRIM_ADD_Q0) {
|
|
if (a.ty != TY_Q0 || b.ty != TY_Q0) return r;
|
|
r.ty = TY_Q0; r.val.i = avm_q0_clamp((int64_t)a.val.i + b.val.i);
|
|
} else if (p == PRIM_SUB_Q0) {
|
|
if (a.ty != TY_Q0 || b.ty != TY_Q0) return r;
|
|
r.ty = TY_Q0; r.val.i = avm_q0_clamp((int64_t)a.val.i - b.val.i);
|
|
} else if (p == PRIM_ADD_Q16) {
|
|
if (a.ty != TY_Q16 || b.ty != TY_Q16) return r;
|
|
r.ty = TY_Q16; r.val.i = avm_clamp((int64_t)a.val.i + b.val.i);
|
|
} else if (p == PRIM_SUB_Q16) {
|
|
if (a.ty != TY_Q16 || b.ty != TY_Q16) return r;
|
|
r.ty = TY_Q16; r.val.i = avm_clamp((int64_t)a.val.i - b.val.i);
|
|
} else if (p == PRIM_MUL_Q16) {
|
|
if (a.ty != TY_Q16 || b.ty != TY_Q16) return r;
|
|
r.ty = TY_Q16;
|
|
r.val.i = avm_clamp(floor_div((int64_t)a.val.i * b.val.i, Q16_SCALE));
|
|
} else if (p == PRIM_DIV_Q16) {
|
|
if (a.ty != TY_Q16 || b.ty != TY_Q16 || b.val.i == 0) return r;
|
|
r.ty = TY_Q16;
|
|
r.val.i = avm_clamp(floor_div((int64_t)a.val.i * Q16_SCALE, b.val.i));
|
|
} else if (p == PRIM_LT_Q16) {
|
|
if (a.ty != TY_Q16 || b.ty != TY_Q16) return r;
|
|
r.ty = TY_BOOL; r.val.b = lt_q16_v6(a.val.i, b.val.i);
|
|
} else if (p == PRIM_EQ_Q16) {
|
|
if (a.ty != TY_Q16 || b.ty != TY_Q16) return r;
|
|
r.ty = TY_BOOL; r.val.b = (a.val.i == b.val.i);
|
|
} else if (p == PRIM_AND) {
|
|
if (a.ty != TY_BOOL || b.ty != TY_BOOL) return r;
|
|
r.ty = TY_BOOL; r.val.b = a.val.b && b.val.b;
|
|
} else if (p == PRIM_OR) {
|
|
if (a.ty != TY_BOOL || b.ty != TY_BOOL) return r;
|
|
r.ty = TY_BOOL; r.val.b = a.val.b || b.val.b;
|
|
} else if (p == PRIM_NOT) {
|
|
if (a.ty != TY_BOOL) return r;
|
|
r.ty = TY_BOOL; r.val.b = !a.val.b;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
/* ── Step ──────────────────────────────────────────────────── */
|
|
int step(State *s, const Instr *prog, int prog_len) {
|
|
if (s->halted) return -1;
|
|
if (s->pc < 0 || s->pc >= prog_len) { s->halted = true; return 0; }
|
|
|
|
Instr instr = prog[s->pc];
|
|
int npc = s->pc + 1;
|
|
|
|
/* Check stack depth for growing ops */
|
|
if (instr.op <= OP_PUSH_Q0 || instr.op == OP_DUP || instr.op == OP_LOAD) {
|
|
if (s->sp >= AVM_MAX_STACK) return -2; /* stack overflow */
|
|
}
|
|
|
|
if (instr.op == OP_PUSH_Q16) {
|
|
s->stack[s->sp].ty = TY_Q16; s->stack[s->sp].val.i = avm_clamp(instr.arg); s->sp++;
|
|
} else if (instr.op == OP_PUSH_BOOL) {
|
|
s->stack[s->sp].ty = TY_BOOL; s->stack[s->sp].val.b = instr.arg2; s->sp++;
|
|
} else if (instr.op == OP_PUSH_Q0) {
|
|
s->stack[s->sp].ty = TY_Q0; s->stack[s->sp].val.i = avm_q0_clamp(instr.arg); s->sp++;
|
|
} else if (instr.op == OP_POP) {
|
|
if (s->sp <= 0) return -3; /* empty stack */
|
|
s->sp--;
|
|
} else if (instr.op == OP_DUP) {
|
|
if (s->sp <= 0) return -3;
|
|
s->stack[s->sp] = s->stack[s->sp - 1]; s->sp++;
|
|
} else if (instr.op == OP_SWAP) {
|
|
if (s->sp < 2) return -4; /* underflow */
|
|
AnyVal tmp = s->stack[s->sp - 1];
|
|
s->stack[s->sp - 1] = s->stack[s->sp - 2];
|
|
s->stack[s->sp - 2] = tmp;
|
|
} else if (instr.op == OP_LOAD) {
|
|
int i = instr.arg;
|
|
if (i < 0 || i >= AVM_MAX_LOCALS || !s->local_set[i]) return -5; /* missing local */
|
|
s->stack[s->sp] = s->locals[i]; s->sp++;
|
|
} else if (instr.op == OP_STORE) {
|
|
if (s->sp <= 0) return -3;
|
|
int i = instr.arg;
|
|
if (i < 0 || i >= AVM_MAX_LOCALS) return -5;
|
|
s->locals[i] = s->stack[--s->sp]; s->local_set[i] = true;
|
|
} else if (instr.op == OP_JUMP) {
|
|
if (instr.arg < 0 || instr.arg >= prog_len) return -6; /* jump OOB */
|
|
npc = instr.arg;
|
|
} else if (instr.op == OP_JUMP_IF) {
|
|
if (s->sp <= 0) return -3;
|
|
AnyVal v = s->stack[--s->sp];
|
|
if (v.ty != TY_BOOL) return -7; /* type mismatch */
|
|
if (v.val.b) {
|
|
if (instr.arg < 0 || instr.arg >= prog_len) return -6;
|
|
npc = instr.arg;
|
|
}
|
|
} else if (instr.op == OP_PRIM) {
|
|
PrimCode p = (PrimCode)instr.arg;
|
|
int arity = (p == PRIM_NOT) ? 1 : 2;
|
|
if (s->sp < arity) return -4;
|
|
AnyVal b = (arity >= 2) ? s->stack[--s->sp] : (AnyVal){0};
|
|
AnyVal a = s->stack[--s->sp];
|
|
s->stack[s->sp++] = eval_prim(p, a, b);
|
|
} else if (instr.op == OP_HALT) {
|
|
s->halted = true;
|
|
}
|
|
|
|
s->pc = npc;
|
|
return 0;
|
|
}
|
|
|
|
/* ── Run (fuel-bounded) ────────────────────────────────────── */
|
|
int run(State *s, const Instr *prog, int prog_len, int fuel) {
|
|
for (int i = 0; i < fuel; i++) {
|
|
if (s->halted) return 0;
|
|
int err = step(s, prog, prog_len);
|
|
if (err) return err;
|
|
}
|
|
return 0;
|
|
}
|