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)
170 lines
6.9 KiB
Matlab
170 lines
6.9 KiB
Matlab
% AVM ISA v1 — Octave/MATLAB Port (Strict Functional Execution)
|
|
% Mirrors formal/SilverSight/AVMIsa/Step.lean
|
|
|
|
classdef AVM
|
|
properties (Constant)
|
|
AVM_CLAMP_MIN = -2147483647
|
|
AVM_CLAMP_MAX = 2147483647
|
|
AVM_Q0_MIN = -32767
|
|
AVM_Q0_MAX = 32767
|
|
Q16_SCALE = 65536
|
|
AVM_MAX_STACK = 1024
|
|
|
|
TY_Q0 = 0; TY_Q16 = 1; TY_BOOL = 2
|
|
|
|
OP_PUSH_Q16 = 0; OP_PUSH_BOOL = 1; OP_PUSH_Q0 = 2
|
|
OP_POP = 3; OP_DUP = 4; OP_SWAP = 5
|
|
OP_LOAD = 6; OP_STORE = 7; OP_JUMP = 8
|
|
OP_JUMP_IF = 9; OP_PRIM = 10; OP_HALT = 11
|
|
|
|
PRIM_ADD_Q0 = 0; PRIM_SUB_Q0 = 1
|
|
PRIM_ADD_Q16 = 2; PRIM_SUB_Q16 = 3
|
|
PRIM_MUL_Q16 = 4; PRIM_DIV_Q16 = 5
|
|
PRIM_LT_Q16 = 6; PRIM_EQ_Q16 = 7
|
|
PRIM_AND = 8; PRIM_OR = 9; PRIM_NOT = 10
|
|
end
|
|
|
|
methods (Static)
|
|
function r = avm_clamp(x)
|
|
if x > AVM.AVM_CLAMP_MAX; r = AVM.AVM_CLAMP_MAX;
|
|
elseif x < AVM.AVM_CLAMP_MIN; r = AVM.AVM_CLAMP_MIN;
|
|
else; r = int32(x); end
|
|
end
|
|
|
|
function r = avm_q0_clamp(x)
|
|
if x > AVM.AVM_Q0_MAX; r = AVM.AVM_Q0_MAX;
|
|
elseif x < AVM.AVM_Q0_MIN; r = AVM.AVM_Q0_MIN;
|
|
else; r = int32(x); end
|
|
end
|
|
|
|
function r = floor_div(a, b)
|
|
if b == 0; error('division by zero'); end
|
|
q = idivide(a, b, 'floor');
|
|
r = int32(q);
|
|
end
|
|
|
|
function r = lt_q16_v6(a, b)
|
|
sa = a < 0; sb = b < 0;
|
|
if sa ~= sb; r = sa; else; r = a < b; end
|
|
end
|
|
|
|
function v = val_q16(x)
|
|
v = struct('ty', AVM.TY_Q16, 'i', AVM.avm_clamp(x), 'b', false);
|
|
end
|
|
|
|
function v = val_q0(x)
|
|
v = struct('ty', AVM.TY_Q0, 'i', AVM.avm_q0_clamp(x), 'b', false);
|
|
end
|
|
|
|
function v = val_bool(x)
|
|
v = struct('ty', AVM.TY_BOOL, 'i', int32(0), 'b', x);
|
|
end
|
|
|
|
function s = init_state(n_locals)
|
|
if nargin < 1; n_locals = 0; end
|
|
s = struct('pc', int32(0), 'stack', {}, 'locals', cell(n_locals, 1), 'halted', false);
|
|
end
|
|
|
|
function r = exec_prim(p, a, b)
|
|
r = AVM.val_q0(0);
|
|
if p == AVM.PRIM_ADD_Q0
|
|
if a.ty ~= AVM.TY_Q0 || b.ty ~= AVM.TY_Q0; return; end
|
|
r = AVM.val_q0(double(a.i) + double(b.i));
|
|
elseif p == AVM.PRIM_SUB_Q0
|
|
if a.ty ~= AVM.TY_Q0 || b.ty ~= AVM.TY_Q0; return; end
|
|
r = AVM.val_q0(double(a.i) - double(b.i));
|
|
elseif p == AVM.PRIM_ADD_Q16
|
|
if a.ty ~= AVM.TY_Q16 || b.ty ~= AVM.TY_Q16; return; end
|
|
r = AVM.val_q16(double(a.i) + double(b.i));
|
|
elseif p == AVM.PRIM_SUB_Q16
|
|
if a.ty ~= AVM.TY_Q16 || b.ty ~= AVM.TY_Q16; return; end
|
|
r = AVM.val_q16(double(a.i) - double(b.i));
|
|
elseif p == AVM.PRIM_MUL_Q16
|
|
if a.ty ~= AVM.TY_Q16 || b.ty ~= AVM.TY_Q16; return; end
|
|
r = AVM.val_q16(AVM.floor_div(double(a.i) * double(b.i), AVM.Q16_SCALE));
|
|
elseif p == AVM.PRIM_DIV_Q16
|
|
if a.ty ~= AVM.TY_Q16 || b.ty ~= AVM.TY_Q16 || b.i == 0; return; end
|
|
r = AVM.val_q16(AVM.floor_div(double(a.i) * AVM.Q16_SCALE, double(b.i)));
|
|
elseif p == AVM.PRIM_LT_Q16
|
|
if a.ty ~= AVM.TY_Q16 || b.ty ~= AVM.TY_Q16; return; end
|
|
r = AVM.val_bool(AVM.lt_q16_v6(a.i, b.i));
|
|
elseif p == AVM.PRIM_EQ_Q16
|
|
if a.ty ~= AVM.TY_Q16 || b.ty ~= AVM.TY_Q16; return; end
|
|
r = AVM.val_bool(a.i == b.i);
|
|
elseif p == AVM.PRIM_AND
|
|
if a.ty ~= AVM.TY_BOOL || b.ty ~= AVM.TY_BOOL; return; end
|
|
r = AVM.val_bool(a.b && b.b);
|
|
elseif p == AVM.PRIM_OR
|
|
if a.ty ~= AVM.TY_BOOL || b.ty ~= AVM.TY_BOOL; return; end
|
|
r = AVM.val_bool(a.b || b.b);
|
|
elseif p == AVM.PRIM_NOT
|
|
if a.ty ~= AVM.TY_BOOL; return; end
|
|
r = AVM.val_bool(~a.b);
|
|
end
|
|
end
|
|
|
|
function [s, err] = step(s, prog)
|
|
err = 0; n = length(prog);
|
|
if s.halted; err = -1; return; end
|
|
if s.pc < 1 || s.pc > n; s.halted = true; return; end
|
|
|
|
instr = prog{s.pc}; npc = s.pc + 1;
|
|
|
|
growing = any(instr.op == [AVM.OP_PUSH_Q16, AVM.OP_PUSH_BOOL, AVM.OP_PUSH_Q0, AVM.OP_DUP, AVM.OP_LOAD]);
|
|
if growing && length(s.stack) >= AVM.AVM_MAX_STACK; err = -2; return; end
|
|
|
|
if instr.op == AVM.OP_PUSH_Q16
|
|
s.stack{end+1} = AVM.val_q16(instr.arg);
|
|
elseif instr.op == AVM.OP_PUSH_BOOL
|
|
s.stack{end+1} = AVM.val_bool(instr.arg2);
|
|
elseif instr.op == AVM.OP_PUSH_Q0
|
|
s.stack{end+1} = AVM.val_q0(instr.arg);
|
|
elseif instr.op == AVM.OP_POP
|
|
if isempty(s.stack); err = -3; return; end; s.stack(end) = [];
|
|
elseif instr.op == AVM.OP_DUP
|
|
if isempty(s.stack); err = -3; return; end
|
|
s.stack{end+1} = s.stack{end};
|
|
elseif instr.op == AVM.OP_SWAP
|
|
if length(s.stack) < 2; err = -4; return; end
|
|
tmp = s.stack{end}; s.stack{end} = s.stack{end-1}; s.stack{end-1} = tmp;
|
|
elseif instr.op == AVM.OP_LOAD
|
|
i = instr.arg + 1;
|
|
if i > length(s.locals) || isempty(s.locals{i}); err = -5; return; end
|
|
s.stack{end+1} = s.locals{i};
|
|
elseif instr.op == AVM.OP_STORE
|
|
if isempty(s.stack); err = -3; return; end
|
|
i = instr.arg + 1;
|
|
if i > length(s.locals); err = -5; return; end
|
|
s.locals{i} = s.stack{end}; s.stack(end) = [];
|
|
elseif instr.op == AVM.OP_JUMP
|
|
t = instr.arg + 1;
|
|
if t < 1 || t > n; err = -6; return; end; npc = t;
|
|
elseif instr.op == AVM.OP_JUMP_IF
|
|
if isempty(s.stack); err = -3; return; end
|
|
v = s.stack{end}; s.stack(end) = [];
|
|
if v.ty ~= AVM.TY_BOOL; err = -7; return; end
|
|
if v.b; t = instr.arg + 1;
|
|
if t < 1 || t > n; err = -6; return; end; npc = t; end
|
|
elseif instr.op == AVM.OP_PRIM
|
|
arity = 2; if instr.arg == AVM.PRIM_NOT; arity = 1; end
|
|
if length(s.stack) < arity; err = -4; return; end
|
|
b = []; if arity >= 2; b = s.stack{end}; s.stack(end) = []; end
|
|
a = s.stack{end}; s.stack(end) = [];
|
|
s.stack{end+1} = AVM.exec_prim(instr.arg, a, b);
|
|
elseif instr.op == AVM.OP_HALT
|
|
s.halted = true;
|
|
end
|
|
s.pc = npc;
|
|
end
|
|
|
|
function s = run(init, prog, fuel)
|
|
if nargin < 3; fuel = 10000; end
|
|
s = init;
|
|
for i = 1:fuel
|
|
if s.halted; return; end
|
|
[s, err] = AVM.step(s, prog);
|
|
if err; error(['AVM error: ' num2str(err)]); end
|
|
end
|
|
end
|
|
end
|
|
end
|