SilverSight/octave/AVMIsa/avm.m
allaun f6cbddcbf2 feat(tests): Python AVM port rewrite + test harness, Go test harness
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 → 🔄
2026-06-30 17:56:09 -05:00

131 lines
3.8 KiB
Matlab

% AVM ISA v1 — Octave Port (Strict Functional Execution)
% All functions are pure (no global mutation).
Q16_SCALE = 65536;
function r = q16_mul(a, b)
r = int32((int64(a) * int64(b)) / Q16_SCALE);
end
function r = q16_div(a, b)
if b == 0, error("div by zero"); end
r = int32((int64(a) * Q16_SCALE) / int64(b));
end
% ── Constructors ──────────────────────────────────
function v = make_q16(x)
v.ty = 'q16'; v.val = int32(x);
end
function v = make_bool(x)
v.ty = 'bool'; v.val = int32(x);
end
function i = make_instr(op, arg)
i.op = int8(op); i.arg = int32(arg);
end
% ── Instructions ──────────────────────────────────
function i = push_q16(x); i = make_instr(0, x); end
function i = push_bool(x); i = make_instr(1, x); end
function i = pop(); i = make_instr(2, 0); end
function i = dup(); i = make_instr(3, 0); end
function i = swap(); i = make_instr(4, 0); end
function i = load(x); i = make_instr(5, x); end
function i = store(x); i = make_instr(6, x); end
function i = jump(x); i = make_instr(7, x); end
function i = jump_if(x); i = make_instr(8, x); end
function i = prim(x); i = make_instr(9, x); end
function i = halt(); i = make_instr(10, 0); end
% Primitives
PRIM_ADD=0; PRIM_SUB=1; PRIM_MUL=2; PRIM_DIV=3;
PRIM_LT=4; PRIM_EQ=5; PRIM_AND=6; PRIM_OR=7; PRIM_NOT=8;
% ── State ─────────────────────────────────────────
function s = new_state(n)
s.pc = 1;
s.stack = cell(1024, 1); s.sp = 0;
s.locals = cell(n, 1);
s.halted = false;
end
function s = state_push(s, v)
s.sp = s.sp + 1;
s.stack{s.sp} = v;
end
function [v, s] = state_pop(s)
v = s.stack{s.sp};
s.sp = s.sp - 1;
end
% ── Step ──────────────────────────────────────────
function ns = step(state, prog)
ns = state;
if ns.halted, return; end
if ns.pc < 1 || ns.pc > length(prog)
ns.halted = true; return;
end
instr = prog{ns.pc};
switch instr.op
case 0 % push_q16
ns = state_push(ns, make_q16(instr.arg));
case 1 % push_bool
ns = state_push(ns, make_bool(instr.arg));
case 2 % pop
[~, ns] = state_pop(ns);
case 3 % dup
ns = state_push(ns, ns.stack{ns.sp});
case 4 % swap
[a, ns] = state_pop(ns); [b, ns] = state_pop(ns);
ns = state_push(ns, a); ns = state_push(ns, b);
case 5 % load
ns = state_push(ns, ns.locals{instr.arg + 1});
case 6 % store
[v, ns] = state_pop(ns);
ns.locals{instr.arg + 1} = v;
case 7 % jump
ns.pc = instr.arg; return;
case 8 % jump_if
[v, ns] = state_pop(ns);
if v.val != 0, ns.pc = instr.arg; end
case 9 % prim
arity = 2;
if instr.arg == PRIM_NOT, arity = 1; end
if arity >= 2, [b, ns] = state_pop(ns); end
[a, ns] = state_pop(ns);
switch instr.arg
case PRIM_ADD
r = make_q16(a.val + b.val);
case PRIM_SUB
r = make_q16(a.val - b.val);
case PRIM_MUL
r = make_q16(q16_mul(a.val, b.val));
case PRIM_DIV
r = make_q16(q16_div(a.val, b.val));
case PRIM_LT
r = make_bool(a.val < b.val);
case PRIM_EQ
r = make_bool(a.val == b.val);
case PRIM_AND
r = make_bool(a.val && b.val);
case PRIM_OR
r = make_bool(a.val || b.val);
case PRIM_NOT
r = make_bool(a.val == 0);
end
ns = state_push(ns, r);
case 10 % halt
ns.halted = true;
end
ns.pc = ns.pc + 1;
end
function s = run(init, prog, fuel)
s = init;
for i = 1:fuel
if s.halted, break; end
s = step(s, prog);
end
end