// AVM ISA v1 — Go Port (Strict Functional Execution) package avm import "errors" const Q16Scale = 65536 func q16Mul(a, b int32) int32 { return int32((int64(a) * int64(b)) / Q16Scale) } func q16Div(a, b int32) (int32, error) { if b == 0 { return 0, errors.New("div by zero") } return int32((int64(a) * Q16Scale) / b), nil } // ── Value ───────────────────────────────────────── type ValType int const ( ValQ0 ValType = iota ValQ16 ValBool ) type AvmVal struct { Ty ValType; Raw int32 } func Q16(x int32) AvmVal { return AvmVal{ValQ16, x} } func Bool(x bool) AvmVal { if x { return AvmVal{ValBool, 1} } return AvmVal{ValBool, 0} } // ── Primitives ───────────────────────────────────── type Prim int const ( AddQ16 Prim = iota; SubQ16; MulQ16; DivQ16; LtQ16; EqQ16; And; Or; Not ) func execPrim(p Prim, a, b AvmVal) (AvmVal, error) { switch p { case AddQ16: return Q16(a.Raw + b.Raw), nil case SubQ16: return Q16(a.Raw - b.Raw), nil case MulQ16: return Q16(q16Mul(a.Raw, b.Raw)), nil case DivQ16: r, e := q16Div(a.Raw, b.Raw) return Q16(r), e case LtQ16: return Bool(a.Raw < b.Raw), nil case EqQ16: return Bool(a.Raw == b.Raw), nil case And: return Bool(a.Raw != 0 && b.Raw != 0), nil case Or: return Bool(a.Raw != 0 || b.Raw != 0), nil case Not: return Bool(a.Raw == 0), nil } return AvmVal{}, errors.New("unknown prim") } // ── Instruction ──────────────────────────────────── type InstrOp int const ( PushQ16 InstrOp = iota; PushBool; Pop; Dup; Swap; Load; Store; Jump; JumpIf; PrimOp; Halt ) type Instr struct { Op InstrOp; Arg int32; Arg2 bool } func Push(x int32) Instr { return Instr{PushQ16, x, false} } func PushB(x bool) Instr { return Instr{PushBool, boolTo32(x), true} } func Pop() Instr { return Instr{Pop, 0, false} } func Dup() Instr { return Instr{Dup, 0, false} } func Swap() Instr { return Instr{Swap, 0, false} } func Load(i int) Instr { return Instr{Load, int32(i), false} } func Store(i int) Instr { return Instr{Store, int32(i), false} } func Jump(t int) Instr { return Instr{Jump, int32(t), false} } func JumpIf(t int) Instr { return Instr{JumpIf, int32(t), false} } func PrimOp(p Prim) Instr{ return Instr{PrimOp, int32(p), false} } func Halt() Instr { return Instr{Halt, 0, false} } func boolTo32(x bool) int32 { if x { return 1 }; return 0 } // ── State ────────────────────────────────────────── type State struct { Pc int Stack []AvmVal Locals []*AvmVal Halted bool } func NewState(n int) State { return State{0, []AvmVal{}, make([]*AvmVal, n), false} } // ── Step ─────────────────────────────────────────── func Step(s State, prog []Instr) (State, error) { if s.Halted { return s, errors.New("halted") } if s.Pc < 0 || s.Pc >= len(prog) { s.Halted = true; return s, nil } instr := prog[s.Pc] ns := State{s.Pc + 1, append([]AvmVal{}, s.Stack...), append([]*AvmVal{}, s.Locals...), false} st := &ns.Stack switch instr.Op { case PushQ16: *st = append(*st, Q16(instr.Arg)) case PushBool: *st = append(*st, Bool(instr.Arg != 0)) case Pop: *st = (*st)[:len(*st)-1] case Dup: *st = append(*st, (*st)[len(*st)-1]) case Swap: (*st)[len(*st)-2], (*st)[len(*st)-1] = (*st)[len(*st)-1], (*st)[len(*st)-2] case Load: if ns.Locals[instr.Arg] == nil { return s, errors.New("missing local") } *st = append(*st, *ns.Locals[instr.Arg]) case Store: ns.Locals[instr.Arg] = &(*st)[len(*st)-1] *st = (*st)[:len(*st)-1] case Jump: ns.Pc = int(instr.Arg) case JumpIf: v := (*st)[len(*st)-1]; *st = (*st)[:len(*st)-1] if v.Raw != 0 { ns.Pc = int(instr.Arg) } case PrimOp: { p := Prim(instr.Arg) arity := 2; if p == Not { arity = 1 } var b AvmVal if arity == 2 { b = (*st)[len(*st)-1]; *st = (*st)[:len(*st)-1] } a := (*st)[len(*st)-1]; *st = (*st)[:len(*st)-1] r, e := execPrim(p, a, b) if e != nil { return s, e } *st = append(*st, r) } case Halt: ns.Halted = true } return ns, nil } func Run(init State, prog []Instr, fuel int) (State, error) { s := init for i := 0; i < fuel && !s.Halted; i++ { var e error s, e = Step(s, prog) if e != nil { return s, e } } return s, nil }