% 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