mirror of
https://github.com/allaunthefox/SilverSight.git
synced 2026-07-31 01:25:21 +00:00
Python port rewritten to match spec: - Added Q0_16, PUSH_Q0, PUSH_BOOL as separate opcodes - Added V6 comparison (lt_q16_v6) - Added floor division (Lean Int.ediv) - Added stack depth limit (AVM_MAX_STACK = 1024) - Added type checking in exec_prim - All 10 tests passing Go AVM port: added test_avm_test.go with 8 test cases Milestone: Python → ✅, Go → 🔄
148 lines
5.2 KiB
C
148 lines
5.2 KiB
C
/* AVM ISA v1 — C Port (Strict Functional Execution) */
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
|
|
#define Q16_SCALE 65536
|
|
#define AVM_Q0_MIN (-32767)
|
|
#define AVM_Q0_MAX 32767
|
|
#define AVM_Q16_MIN (-2147483648)
|
|
#define AVM_Q16_MAX 2147483647
|
|
|
|
/* ── Types ─────────────────────────────────────── */
|
|
typedef enum { VAL_Q0, VAL_Q16, VAL_BOOL } ValType;
|
|
typedef struct { ValType ty; int32_t val; } AvmVal;
|
|
|
|
AvmVal avm_q0(int32_t x) {
|
|
if (x < AVM_Q0_MIN) x = AVM_Q0_MIN;
|
|
if (x > AVM_Q0_MAX) x = AVM_Q0_MAX;
|
|
return (AvmVal){VAL_Q0, x};
|
|
}
|
|
AvmVal avm_q16(int32_t x) { return (AvmVal){VAL_Q16, x}; }
|
|
AvmVal avm_bool(bool x) { return (AvmVal){VAL_BOOL, x ? 1 : 0}; }
|
|
|
|
/* ── Primitives ─────────────────────────────────── */
|
|
typedef enum {
|
|
PRIM_ADD_Q16, PRIM_SUB_Q16, PRIM_MUL_Q16, PRIM_DIV_Q16,
|
|
PRIM_LT_Q16, PRIM_EQ_Q16, PRIM_AND, PRIM_OR, PRIM_NOT
|
|
} Prim;
|
|
|
|
typedef struct { AvmVal *data; int len, cap; } Stack;
|
|
typedef struct { AvmVal *data; int len; } Locals;
|
|
|
|
typedef struct State {
|
|
int pc;
|
|
Stack stack;
|
|
Locals locals;
|
|
int halted;
|
|
} State;
|
|
|
|
int64_t q16_mul(int32_t a, int32_t b) {
|
|
return (int64_t)a * (int64_t)b / Q16_SCALE;
|
|
}
|
|
int64_t q16_div(int32_t a, int32_t b) {
|
|
if (b == 0) return AVM_Q16_MAX;
|
|
return (int64_t)a * Q16_SCALE / b;
|
|
}
|
|
|
|
/* ── Instr ──────────────────────────────────────── */
|
|
typedef enum {
|
|
INSTR_PUSH_Q16, INSTR_PUSH_BOOL, INSTR_POP, INSTR_DUP, INSTR_SWAP,
|
|
INSTR_LOAD, INSTR_STORE, INSTR_JUMP, INSTR_JUMP_IF, INSTR_PRIM, INSTR_HALT
|
|
} InstrOp;
|
|
|
|
typedef struct { InstrOp op; int32_t arg; int arg2; } Instr;
|
|
|
|
Instr i_push_q16(int32_t x) { return (Instr){INSTR_PUSH_Q16, x, 0}; }
|
|
Instr i_push_bool(int x) { return (Instr){INSTR_PUSH_BOOL, x, 0}; }
|
|
Instr i_pop(void) { return (Instr){INSTR_POP, 0, 0}; }
|
|
Instr i_dup(void) { return (Instr){INSTR_DUP, 0, 0}; }
|
|
Instr i_swap(void) { return (Instr){INSTR_SWAP, 0, 0}; }
|
|
Instr i_load(int i) { return (Instr){INSTR_LOAD, i, 0}; }
|
|
Instr i_store(int i) { return (Instr){INSTR_STORE, i, 0}; }
|
|
Instr i_jump(int t) { return (Instr){INSTR_JUMP, t, 0}; }
|
|
Instr i_jump_if(int t) { return (Instr){INSTR_JUMP_IF, t, 0}; }
|
|
Instr i_prim(Prim p) { return (Instr){INSTR_PRIM, p, 0}; }
|
|
Instr i_halt(void) { return (Instr){INSTR_HALT, 0, 0}; }
|
|
|
|
/* ── Step ───────────────────────────────────────── */
|
|
int step(State *s, Instr *prog, int prog_len) {
|
|
if (s->halted) return -1;
|
|
if (s->pc < 0 || s->pc >= prog_len) { s->halted = 1; return 0; }
|
|
|
|
Instr instr = prog[s->pc];
|
|
s->pc++;
|
|
AvmVal a, b;
|
|
|
|
switch (instr.op) {
|
|
case INSTR_PUSH_Q16:
|
|
s->stack.data[s->stack.len++] = avm_q16(instr.arg);
|
|
break;
|
|
case INSTR_PUSH_BOOL:
|
|
s->stack.data[s->stack.len++] = avm_bool(instr.arg);
|
|
break;
|
|
case INSTR_POP: s->stack.len--; break;
|
|
case INSTR_DUP:
|
|
s->stack.data[s->stack.len] = s->stack.data[s->stack.len - 1];
|
|
s->stack.len++;
|
|
break;
|
|
case INSTR_SWAP: {
|
|
AvmVal t = s->stack.data[s->stack.len - 1];
|
|
s->stack.data[s->stack.len - 1] = s->stack.data[s->stack.len - 2];
|
|
s->stack.data[s->stack.len - 2] = t;
|
|
break;
|
|
}
|
|
case INSTR_LOAD:
|
|
s->stack.data[s->stack.len++] = s->locals.data[instr.arg];
|
|
break;
|
|
case INSTR_STORE:
|
|
s->locals.data[instr.arg] = s->stack.data[--s->stack.len];
|
|
break;
|
|
case INSTR_JUMP: s->pc = instr.arg; break;
|
|
case INSTR_JUMP_IF:
|
|
if (s->stack.data[--s->stack.len].val) s->pc = instr.arg;
|
|
break;
|
|
case INSTR_PRIM: {
|
|
int arity = (instr.arg == PRIM_NOT) ? 1 : 2;
|
|
if (arity == 2) b = s->stack.data[--s->stack.len];
|
|
a = s->stack.data[--s->stack.len];
|
|
switch (instr.arg) {
|
|
case PRIM_ADD_Q16:
|
|
s->stack.data[s->stack.len++] = avm_q16(a.val + b.val);
|
|
break;
|
|
case PRIM_SUB_Q16:
|
|
s->stack.data[s->stack.len++] = avm_q16(a.val - b.val);
|
|
break;
|
|
case PRIM_MUL_Q16:
|
|
s->stack.data[s->stack.len++] = avm_q16(q16_mul(a.val, b.val));
|
|
break;
|
|
case PRIM_DIV_Q16:
|
|
s->stack.data[s->stack.len++] = avm_q16(q16_div(a.val, b.val));
|
|
break;
|
|
case PRIM_LT_Q16:
|
|
s->stack.data[s->stack.len++] = avm_bool(a.val < b.val);
|
|
break;
|
|
case PRIM_EQ_Q16:
|
|
s->stack.data[s->stack.len++] = avm_bool(a.val == b.val);
|
|
break;
|
|
case PRIM_AND:
|
|
s->stack.data[s->stack.len++] = avm_bool(a.val && b.val);
|
|
break;
|
|
case PRIM_OR:
|
|
s->stack.data[s->stack.len++] = avm_bool(a.val || b.val);
|
|
break;
|
|
case PRIM_NOT:
|
|
s->stack.data[s->stack.len++] = avm_bool(!a.val);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
case INSTR_HALT: s->halted = 1; break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int run(State *s, Instr *prog, int prog_len, int fuel) {
|
|
for (int i = 0; i < fuel && !s->halted; i++)
|
|
if (step(s, prog, prog_len)) return -1;
|
|
return 0;
|
|
}
|