// AVM ISA v1 — C++ Port (Strict Functional Execution) #include #include #include #include #include #include constexpr int32_t Q16_SCALE = 65536; inline int32_t q16_mul(int32_t a, int32_t b) { return static_cast( (static_cast(a) * static_cast(b)) / Q16_SCALE); } inline int32_t q16_div(int32_t a, int32_t b) { if (b == 0) throw std::runtime_error("div by zero"); return static_cast( (static_cast(a) * Q16_SCALE) / b); } // ── Value ───────────────────────────────────────── struct AvmVal { enum Ty { Q0_16, Q16_16, Bool }; Ty ty; int32_t raw; AvmVal(Ty t, int32_t r) : ty(t), raw(r) {} static AvmVal q16(int32_t x) { return {Q16_16, x}; } static AvmVal q0(int32_t x) { if (x < -32767) x = -32767; if (x > 32767) x = 32767; return {Q0_16, x}; } static AvmVal boolean(bool x) { return {Bool, x ? 1 : 0}; } }; // ── Primitives ───────────────────────────────────── enum class Prim : int32_t { AddSatQ0, SubSatQ0, AddSatQ16, SubSatQ16, MulSatQ16, DivSatQ16, LtQ16, EqQ16, And, Or, Not }; AvmVal exec_prim(Prim op, const AvmVal& a, const std::optional& b) { auto bv = [&]() -> const AvmVal& { return b.value(); }; switch (op) { case Prim::AddSatQ16: return AvmVal::q16(a.raw + bv().raw); case Prim::SubSatQ16: return AvmVal::q16(a.raw - bv().raw); case Prim::MulSatQ16: return AvmVal::q16(q16_mul(a.raw, bv().raw)); case Prim::DivSatQ16: return AvmVal::q16(q16_div(a.raw, bv().raw)); case Prim::LtQ16: return AvmVal::boolean(a.raw < bv().raw); case Prim::EqQ16: return AvmVal::boolean(a.raw == bv().raw); case Prim::And: return AvmVal::boolean(a.raw && bv().raw); case Prim::Or: return AvmVal::boolean(a.raw || bv().raw); case Prim::Not: return AvmVal::boolean(!a.raw); default: throw std::runtime_error("unknown prim"); } } // ── Instruction ──────────────────────────────────── enum class InstrOp : int8_t { PushQ16, PushBool, Pop, Dup, Swap, Load, Store, Jump, JumpIf, Prim, Halt }; struct Instr { InstrOp op; int32_t arg; bool arg2{false}; }; inline Instr push_q16(int32_t x) { return {InstrOp::PushQ16, x, false}; } inline Instr push_bool(bool x) { return {InstrOp::PushBool, static_cast(x), true}; } inline Instr pop() { return {InstrOp::Pop, 0, false}; } inline Instr dup() { return {InstrOp::Dup, 0, false}; } inline Instr swap() { return {InstrOp::Swap, 0, false}; } inline Instr load(int i) { return {InstrOp::Load, i, false}; } inline Instr store(int i) { return {InstrOp::Store, i, false}; } inline Instr jump(int t) { return {InstrOp::Jump, t, false}; } inline Instr jump_if(int t) { return {InstrOp::JumpIf, t, false}; } inline Instr prim(Prim p) { return {InstrOp::Prim, static_cast(p), false}; } inline Instr halt() { return {InstrOp::Halt, 0, false}; } // ── State ────────────────────────────────────────── struct State { int pc{0}; std::vector stack; std::vector> locals; bool halted{false}; State() : pc(0), locals(16, std::nullopt) {} State(int pc_, std::vector stack_, std::vector> locals_, bool halted_) : pc(pc_), stack(std::move(stack_)), locals(std::move(locals_)), halted(halted_) {} }; // ── Step ─────────────────────────────────────────── State step(const State& s, const std::vector& prog) { if (s.halted) throw std::runtime_error("halted"); if (s.pc < 0 || s.pc >= (int)prog.size()) return State{}; auto instr = prog[s.pc]; State ns{s.pc + 1, s.stack, s.locals, false}; auto& st = ns.stack; switch (instr.op) { case InstrOp::PushQ16: st.push_back(AvmVal::q16(instr.arg)); break; case InstrOp::PushBool: st.push_back(AvmVal::boolean(instr.arg)); break; case InstrOp::Pop: st.pop_back(); break; case InstrOp::Dup: st.push_back(st.back()); break; case InstrOp::Swap: std::swap(st[st.size()-2], st[st.size()-1]); break; case InstrOp::Load: { auto v = ns.locals[instr.arg]; if (!v.has_value()) throw std::runtime_error("missing local"); st.push_back(v.value()); break; } case InstrOp::Store: { ns.locals[instr.arg] = st.back(); st.pop_back(); break; } case InstrOp::Jump: ns.pc = instr.arg; break; case InstrOp::JumpIf: { if (st.back().raw) ns.pc = instr.arg; st.pop_back(); break; } case InstrOp::Prim: { auto p = static_cast(instr.arg); int arity = (p == Prim::Not) ? 1 : 2; std::optional b; if (arity == 2) { b = st.back(); st.pop_back(); } auto a = st.back(); st.pop_back(); st.push_back(exec_prim(p, a, b)); break; } case InstrOp::Halt: ns.halted = true; break; } return ns; } State run(const State& init, const std::vector& prog, int fuel) { State s = init; for (int i = 0; i < fuel && !s.halted; i++) s = step(s, prog); return s; }