SilverSight/c/avm.c
allaun 863da04f21 feat(avm-ports): port AVM ISA to all 12 scientific languages
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)
2026-06-30 17:42:38 -05:00

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;
}