mirror of
https://github.com/allaunthefox/SilverSight.git
synced 2026-08-20 16:37:29 +00:00
fix(avm-ports): add Q0_16 support to Julia and R ports
Julia port: - Extended type tracking from Bool (is_q16) to Int8 tri-state (TYPE_BOOL/Q16/Q0) - Added ADD_SAT_Q0 / SUB_SAT_Q0 primitive handling - Added avm_q0_clamp for symmetric Q0_16 range [-32767, 32767] R port: - Added PRIM_ADD_Q0 / PRIM_SUB_Q0 primitives - Added push_q0 instruction, make_q0 / is_q0 helpers - Added avm_q0_clamp for symmetric Q0_16 range - Fixed LOAD to preserve type tag on restore All three ports now support the full AVM ISA type universe (Q0_16, Q16_16, Bool).
This commit is contained in:
parent
aeb87d86c8
commit
1ae311c63f
5 changed files with 203 additions and 112 deletions
|
|
@ -1,2 +1,17 @@
|
||||||
COQAUX1 03441a4df6ed6fdae62bc8cdd91bb74d /home/allaun/SilverSight/coq/CoreFormalism/Q16_16.v
|
COQAUX1 ceddd47b5a988a61f1c6220b6dcc1771 /home/allaun/SilverSight/coq/CoreFormalism/Q16_16.v
|
||||||
|
0 0 VernacProof "tac:no using:no"
|
||||||
|
164 168 proof_build_time "0.001"
|
||||||
|
0 0 le_neg2147483648_2147483647 "0.001"
|
||||||
|
159 163 context_used ""
|
||||||
|
164 168 proof_check_time "0.000"
|
||||||
|
0 0 VernacProof "tac:no using:no"
|
||||||
|
245 249 proof_build_time "0.000"
|
||||||
|
0 0 le_2147483647_2147483647 "0.000"
|
||||||
|
240 244 context_used ""
|
||||||
|
245 249 proof_check_time "0.000"
|
||||||
|
0 0 VernacProof "tac:no using:no"
|
||||||
|
1092 1096 proof_build_time "0.002"
|
||||||
|
0 0 clamp_bounded "0.002"
|
||||||
|
1055 1089 context_used ""
|
||||||
|
1092 1096 proof_check_time "0.001"
|
||||||
0 0 VernacProof "tac:no using:no"
|
0 0 VernacProof "tac:no using:no"
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,82 @@
|
||||||
DIGEST 03441a4df6ed6fdae62bc8cdd91bb74d
|
DIGEST ceddd47b5a988a61f1c6220b6dcc1771
|
||||||
FQ16_16
|
FQ16_16
|
||||||
R72:77 Stdlib.ZArith.ZArith <> <> lib
|
R72:77 Stdlib.ZArith.ZArith <> <> lib
|
||||||
R79:81 Stdlib.micromega.Lia <> <> lib
|
R79:81 Stdlib.micromega.Lia <> <> lib
|
||||||
mod 91:96 <> Q16_16
|
prf 91:117 <> le_neg2147483648_2147483647
|
||||||
def 135:145 Q16_16 q16_min_raw
|
R133:136 Stdlib.ZArith.BinInt <> ::Z_scope:x_'<='_x not
|
||||||
R149:149 Corelib.Numbers.BinNums <> Z ind
|
prf 176:199 <> le_2147483647_2147483647
|
||||||
def 180:190 Q16_16 q16_max_raw
|
R214:217 Stdlib.ZArith.BinInt <> ::Z_scope:x_'<='_x not
|
||||||
R194:194 Corelib.Numbers.BinNums <> Z ind
|
mod 258:263 <> Q16_16
|
||||||
def 224:232 Q16_16 q16_scale
|
def 302:312 Q16_16 q16_min_raw
|
||||||
R237:237 Corelib.Numbers.BinNums <> Z ind
|
R316:316 Corelib.Numbers.BinNums <> Z ind
|
||||||
def 263:270 Q16_16 in_range
|
def 347:357 Q16_16 q16_max_raw
|
||||||
R277:277 Corelib.Numbers.BinNums <> Z ind
|
|
||||||
binder 273:273 <> x:1
|
|
||||||
R310:313 Corelib.Init.Logic <> ::type_scope:x_'/\'_x not
|
|
||||||
R305:308 Stdlib.ZArith.BinInt <> ::Z_scope:x_'<='_x not
|
|
||||||
R294:304 Q16_16 Q16_16 q16_min_raw def
|
|
||||||
R309:309 Q16_16 <> x:1 var
|
|
||||||
R315:318 Stdlib.ZArith.BinInt <> ::Z_scope:x_'<='_x not
|
|
||||||
R314:314 Q16_16 <> x:1 var
|
|
||||||
R319:329 Q16_16 Q16_16 q16_max_raw def
|
|
||||||
def 346:354 Q16_16 clamp_raw
|
|
||||||
R361:361 Corelib.Numbers.BinNums <> Z ind
|
R361:361 Corelib.Numbers.BinNums <> Z ind
|
||||||
binder 357:357 <> i:2
|
def 391:399 Q16_16 q16_scale
|
||||||
R366:366 Corelib.Numbers.BinNums <> Z ind
|
R404:404 Corelib.Numbers.BinNums <> Z ind
|
||||||
R378:385 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
def 430:437 Q16_16 in_range
|
||||||
R399:399 Q16_16 <> i:2 var
|
R444:444 Corelib.Numbers.BinNums <> Z ind
|
||||||
R387:397 Q16_16 Q16_16 q16_max_raw def
|
binder 440:440 <> x:1
|
||||||
R430:437 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
R477:480 Corelib.Init.Logic <> ::type_scope:x_'/\'_x not
|
||||||
R441:451 Q16_16 Q16_16 q16_min_raw def
|
R472:475 Stdlib.ZArith.BinInt <> ::Z_scope:x_'<='_x not
|
||||||
R439:439 Q16_16 <> i:2 var
|
R461:471 Q16_16 Q16_16 q16_min_raw def
|
||||||
R479:479 Q16_16 <> i:2 var
|
R476:476 Q16_16 <> x:1 var
|
||||||
R458:468 Q16_16 Q16_16 q16_min_raw def
|
R482:485 Stdlib.ZArith.BinInt <> ::Z_scope:x_'<='_x not
|
||||||
R406:416 Q16_16 Q16_16 q16_max_raw def
|
R481:481 Q16_16 <> x:1 var
|
||||||
prf 493:505 Q16_16 clamp_bounded
|
R486:496 Q16_16 Q16_16 q16_max_raw def
|
||||||
R512:512 Corelib.Numbers.BinNums <> Z ind
|
def 513:521 Q16_16 clamp_raw
|
||||||
binder 508:508 <> x:3
|
R528:528 Corelib.Numbers.BinNums <> Z ind
|
||||||
R517:524 Q16_16 Q16_16 in_range def
|
binder 524:524 <> i:2
|
||||||
R527:535 Q16_16 Q16_16 clamp_raw def
|
R533:533 Corelib.Numbers.BinNums <> Z ind
|
||||||
R537:537 Q16_16 <> x:3 var
|
R545:552 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
||||||
R561:569 Q16_16 Q16_16 clamp_raw def
|
R566:566 Q16_16 <> i:2 var
|
||||||
R572:579 Q16_16 Q16_16 in_range def
|
R554:564 Q16_16 Q16_16 q16_max_raw def
|
||||||
R592:599 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
R597:604 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
||||||
R601:611 Q16_16 Q16_16 q16_max_raw def
|
R608:618 Q16_16 Q16_16 q16_min_raw def
|
||||||
R592:599 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
R606:606 Q16_16 <> i:2 var
|
||||||
R601:611 Q16_16 Q16_16 q16_max_raw def
|
R646:646 Q16_16 <> i:2 var
|
||||||
R641:651 Q16_16 Q16_16 q16_min_raw def
|
R625:635 Q16_16 Q16_16 q16_min_raw def
|
||||||
R654:664 Q16_16 Q16_16 q16_max_raw def
|
R573:583 Q16_16 Q16_16 q16_max_raw def
|
||||||
R695:706 Stdlib.ZArith.BinInt Z lt_le_incl thm
|
prf 660:672 Q16_16 clamp_bounded
|
||||||
|
R679:679 Corelib.Numbers.BinNums <> Z ind
|
||||||
|
binder 675:675 <> x:3
|
||||||
|
R684:691 Q16_16 Q16_16 in_range def
|
||||||
|
R694:702 Q16_16 Q16_16 clamp_raw def
|
||||||
|
R704:704 Q16_16 <> x:3 var
|
||||||
|
R728:736 Q16_16 Q16_16 clamp_raw def
|
||||||
|
R739:746 Q16_16 Q16_16 in_range def
|
||||||
|
R759:766 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
||||||
|
R768:778 Q16_16 Q16_16 q16_max_raw def
|
||||||
|
R759:766 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
||||||
|
R768:778 Q16_16 Q16_16 q16_max_raw def
|
||||||
|
R808:818 Q16_16 Q16_16 q16_min_raw def
|
||||||
|
R821:831 Q16_16 Q16_16 q16_max_raw def
|
||||||
|
R848:874 Q16_16 <> le_neg2147483648_2147483647 thm
|
||||||
|
R884:892 Stdlib.ZArith.BinInt Z le_refl thm
|
||||||
|
R848:874 Q16_16 <> le_neg2147483648_2147483647 thm
|
||||||
|
R884:892 Stdlib.ZArith.BinInt Z le_refl thm
|
||||||
|
R908:915 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
||||||
|
R919:929 Q16_16 Q16_16 q16_min_raw def
|
||||||
|
R908:915 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
||||||
|
R919:929 Q16_16 Q16_16 q16_min_raw def
|
||||||
|
R959:969 Q16_16 Q16_16 q16_min_raw def
|
||||||
|
R972:982 Q16_16 Q16_16 q16_max_raw def
|
||||||
|
R999:1007 Stdlib.ZArith.BinInt Z le_refl thm
|
||||||
|
R1017:1043 Q16_16 <> le_neg2147483648_2147483647 thm
|
||||||
|
R999:1007 Stdlib.ZArith.BinInt Z le_refl thm
|
||||||
|
R1017:1043 Q16_16 <> le_neg2147483648_2147483647 thm
|
||||||
|
R1068:1075 Stdlib.ZArith.BinInt Z nlt_ge thm
|
||||||
|
R1068:1075 Stdlib.ZArith.BinInt Z nlt_ge thm
|
||||||
|
R1068:1075 Stdlib.ZArith.BinInt Z nlt_ge thm
|
||||||
|
prf 1108:1123 Q16_16 clamp_idempotent
|
||||||
|
R1130:1130 Corelib.Numbers.BinNums <> Z ind
|
||||||
|
binder 1126:1126 <> x:4
|
||||||
|
R1138:1145 Q16_16 Q16_16 in_range def
|
||||||
|
R1147:1147 Q16_16 <> x:4 var
|
||||||
|
binder 1134:1134 <> h:5
|
||||||
|
R1163:1165 Corelib.Init.Logic <> ::type_scope:x_'='_x not
|
||||||
|
R1152:1160 Q16_16 Q16_16 clamp_raw def
|
||||||
|
R1162:1162 Q16_16 <> x:4 var
|
||||||
|
R1166:1166 Q16_16 <> x:4 var
|
||||||
|
R1218:1226 Q16_16 Q16_16 clamp_raw def
|
||||||
|
R1239:1246 Stdlib.ZArith.ZArith_dec <> Z_lt_dec def
|
||||||
|
R1248:1258 Q16_16 Q16_16 q16_max_raw def
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,12 @@
|
||||||
(* Coq Formalization of Q16_16 Fixed-Point Arithmetic *)
|
(* Coq Formalization of Q16_16 Fixed-Point Arithmetic *)
|
||||||
Require Import ZArith Lia.
|
Require Import ZArith Lia.
|
||||||
|
|
||||||
|
Lemma le_neg2147483648_2147483647 : (-2147483648 <= 2147483647)%Z.
|
||||||
|
Proof. lia. Qed.
|
||||||
|
|
||||||
|
Lemma le_2147483647_2147483647 : (2147483647 <= 2147483647)%Z.
|
||||||
|
Proof. lia. Qed.
|
||||||
|
|
||||||
Module Q16_16.
|
Module Q16_16.
|
||||||
Open Scope Z_scope.
|
Open Scope Z_scope.
|
||||||
|
|
||||||
|
|
@ -19,9 +26,9 @@ Module Q16_16.
|
||||||
Proof.
|
Proof.
|
||||||
unfold clamp_raw, in_range.
|
unfold clamp_raw, in_range.
|
||||||
case (Z_lt_dec q16_max_raw x); intros H1.
|
case (Z_lt_dec q16_max_raw x); intros H1.
|
||||||
- unfold q16_min_raw, q16_max_raw; split; [unfold q16_min_raw, q16_max_raw; lia | apply Z.lt_le_incl; exact H1].
|
- unfold q16_min_raw, q16_max_raw; split; [apply le_neg2147483648_2147483647 | apply Z.le_refl].
|
||||||
- case (Z_lt_dec x q16_min_raw); intros H2.
|
- case (Z_lt_dec x q16_min_raw); intros H2.
|
||||||
+ unfold q16_min_raw, q16_max_raw; split; [apply Z.lt_le_incl; exact H2 | unfold q16_min_raw, q16_max_raw; lia].
|
+ unfold q16_min_raw, q16_max_raw; split; [apply Z.le_refl | apply le_neg2147483648_2147483647].
|
||||||
+ split; apply Z.nlt_ge; assumption.
|
+ split; apply Z.nlt_ge; assumption.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
|
|
@ -29,8 +36,8 @@ Module Q16_16.
|
||||||
Proof.
|
Proof.
|
||||||
destruct h as [Hlo Hhi].
|
destruct h as [Hlo Hhi].
|
||||||
unfold clamp_raw.
|
unfold clamp_raw.
|
||||||
case (Z_lt_dec q16_max_raw x); intros Hgt; [exfalso; lia|].
|
case (Z_lt_dec q16_max_raw x); intros Hgt; [exfalso; exact (Zlt_not_le _ _ Hgt Hhi) |].
|
||||||
case (Z_lt_dec x q16_min_raw); intros Hlt; [exfalso; lia|].
|
case (Z_lt_dec x q16_min_raw); intros Hlt; [exfalso; exact (Zlt_not_le _ _ Hlt Hlo) |].
|
||||||
reflexivity.
|
reflexivity.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
|
|
@ -56,22 +63,23 @@ Module Q16_16.
|
||||||
Theorem add_in_range (a b : Z) (ha : in_range a) (hb : in_range b)
|
Theorem add_in_range (a b : Z) (ha : in_range a) (hb : in_range b)
|
||||||
(hsum : in_range (a + b)) : add a b = a + b.
|
(hsum : in_range (a + b)) : add a b = a + b.
|
||||||
Proof.
|
Proof.
|
||||||
unfold add; rewrite clamp_idempotent; [reflexivity| exact hsum].
|
unfold add; rewrite clamp_idempotent; trivial.
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
Theorem sub_self (a : Z) (ha : in_range a) : sub a a = zero.
|
Theorem sub_self (a : Z) (ha : in_range a) : sub a a = zero.
|
||||||
Proof.
|
Proof.
|
||||||
unfold sub, zero; rewrite Z.sub_diag.
|
unfold sub, zero; rewrite Z.sub_diag.
|
||||||
apply clamp_idempotent; unfold in_range; unfold q16_min_raw, q16_max_raw; lia.
|
apply clamp_idempotent; unfold in_range; unfold q16_min_raw, q16_max_raw.
|
||||||
|
split; [apply le_neg2147483648_2147483647 | apply le_2147483647_2147483647].
|
||||||
Qed.
|
Qed.
|
||||||
|
|
||||||
Theorem mul_comm (a b : Z) : mul a b = mul b a.
|
Theorem mul_comm (a b : Z) : mul a b = mul b a.
|
||||||
Proof. unfold mul; rewrite Z.mul_comm; reflexivity. Qed.
|
Proof. unfold mul; rewrite Z.mul_comm; reflexivity. Qed.
|
||||||
|
|
||||||
Theorem in_range_zero : in_range 0.
|
Theorem in_range_zero : in_range 0.
|
||||||
Proof. unfold in_range, q16_min_raw, q16_max_raw; lia. Qed.
|
Proof. unfold in_range, q16_min_raw, q16_max_raw. split; [apply le_neg2147483648_2147483647 | apply le_2147483647_2147483647]. Qed.
|
||||||
|
|
||||||
Theorem in_range_one : in_range 1.
|
Theorem in_range_one : in_range 1.
|
||||||
Proof. unfold in_range, q16_min_raw, q16_max_raw; lia. Qed.
|
Proof. unfold in_range, q16_min_raw, q16_max_raw. split; [apply le_neg2147483648_2147483647 | apply le_2147483647_2147483647]. Qed.
|
||||||
|
|
||||||
End Q16_16.
|
End Q16_16.
|
||||||
|
|
|
||||||
|
|
@ -69,22 +69,29 @@ end
|
||||||
# ── AVM constants ───────────────────────────────────────────────────
|
# ── AVM constants ───────────────────────────────────────────────────
|
||||||
const AVM_CLAMP_MIN = -2147483647
|
const AVM_CLAMP_MIN = -2147483647
|
||||||
const AVM_CLAMP_MAX = 2147483647
|
const AVM_CLAMP_MAX = 2147483647
|
||||||
|
const AVM_Q0_MIN = -32767
|
||||||
|
const AVM_Q0_MAX = 32767
|
||||||
const AVM_MAX_STACK = 1024
|
const AVM_MAX_STACK = 1024
|
||||||
|
|
||||||
|
# Type tags: 0=Bool, 1=Q16_16, 2=Q0_16
|
||||||
|
const TYPE_BOOL = Int8(0)
|
||||||
|
const TYPE_Q16 = Int8(1)
|
||||||
|
const TYPE_Q0 = Int8(2)
|
||||||
|
|
||||||
# ── State ──────────────────────────────────────────────────────────
|
# ── State ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
struct State
|
struct State
|
||||||
pc::Int
|
pc::Int
|
||||||
stack::Vector{Union{Int32, Bool}}
|
stack::Vector{Union{Int32, Bool}}
|
||||||
is_q16::Vector{Bool} # true=Q16_16, false=Bool
|
types::Vector{Int8} # 0=Bool, 1=Q16_16, 2=Q0_16
|
||||||
locals::Vector{Union{Nothing, Union{Int32, Bool}}}
|
locals::Vector{Union{Nothing, Union{Int32, Bool}}}
|
||||||
local_types::Vector{Bool} # true=Q16_16, false=Bool (or nothing)
|
local_types::Vector{Int8}
|
||||||
halted::Bool
|
halted::Bool
|
||||||
end
|
end
|
||||||
|
|
||||||
function State(n_locals::Int=0)
|
function State(n_locals::Int=0)
|
||||||
State(1, Union{Int32, Bool}[], Bool[],
|
State(1, Union{Int32, Bool}[], Int8[],
|
||||||
[nothing for _ in 1:n_locals], [false for _ in 1:n_locals],
|
[nothing for _ in 1:n_locals], zeros(Int8, n_locals),
|
||||||
false)
|
false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -94,37 +101,41 @@ q16_val(v::Int32) = v
|
||||||
|
|
||||||
# ── Primitive execution ────────────────────────────────────────────
|
# ── Primitive execution ────────────────────────────────────────────
|
||||||
|
|
||||||
# AVM symmetric clamp (excludes INT32_MIN for negation involution)
|
|
||||||
avm_clamp(x::Int64) = Int32(min(AVM_CLAMP_MAX, max(AVM_CLAMP_MIN, x)))
|
avm_clamp(x::Int64) = Int32(min(AVM_CLAMP_MAX, max(AVM_CLAMP_MIN, x)))
|
||||||
|
avm_q0_clamp(x::Int64) = Int32(min(AVM_Q0_MAX, max(AVM_Q0_MIN, x)))
|
||||||
|
|
||||||
# V6 signed comparison for AVM
|
|
||||||
lt_q16_v6(a::Int32, b::Int32) = (a < 0) != (b < 0) ? (a < 0) : (a < b)
|
lt_q16_v6(a::Int32, b::Int32) = (a < 0) != (b < 0) ? (a < 0) : (a < b)
|
||||||
|
|
||||||
function exec_prim(op::Prim, a::Union{Int32, Bool}, b::Union{Int32, Bool, Nothing})
|
function exec_prim(op::Prim, a::Union{Int32, Bool}, b::Union{Int32, Bool, Nothing})
|
||||||
if op == ADD_SAT_Q16
|
if op == ADD_SAT_Q0
|
||||||
return (avm_clamp(Int64(a::Int32) + Int64(b::Int32)), true)
|
a::Int32; b::Int32
|
||||||
|
return (avm_q0_clamp(Int64(a) + Int64(b)), TYPE_Q0)
|
||||||
|
elseif op == SUB_SAT_Q0
|
||||||
|
a::Int32; b::Int32
|
||||||
|
return (avm_q0_clamp(Int64(a) - Int64(b)), TYPE_Q0)
|
||||||
|
elseif op == ADD_SAT_Q16
|
||||||
|
return (avm_clamp(Int64(a::Int32) + Int64(b::Int32)), TYPE_Q16)
|
||||||
elseif op == SUB_SAT_Q16
|
elseif op == SUB_SAT_Q16
|
||||||
return (avm_clamp(Int64(a::Int32) - Int64(b::Int32)), true)
|
return (avm_clamp(Int64(a::Int32) - Int64(b::Int32)), TYPE_Q16)
|
||||||
elseif op == MUL_SAT_Q16
|
elseif op == MUL_SAT_Q16
|
||||||
# Floor division matching Lean Int.ediv: (a * b) / 65536
|
|
||||||
prod = Int64(a::Int32) * Int64(b::Int32)
|
prod = Int64(a::Int32) * Int64(b::Int32)
|
||||||
result = div(prod, Q16_16.Q16_SCALE) # div = floor division in Julia
|
result = div(prod, Q16_16.Q16_SCALE)
|
||||||
return (avm_clamp(result), true)
|
return (avm_clamp(result), TYPE_Q16)
|
||||||
elseif op == DIV_SAT_Q16
|
elseif op == DIV_SAT_Q16
|
||||||
b::Int32 == 0 && error(DIVISION_BY_ZERO)
|
b::Int32 == 0 && error(DIVISION_BY_ZERO)
|
||||||
num = Int64(b::Int32) * Q16_16.Q16_SCALE
|
num = Int64(b::Int32) * Q16_16.Q16_SCALE
|
||||||
result = div(num, Int64(a::Int32)) # div = floor division in Julia
|
result = div(num, Int64(a::Int32))
|
||||||
return (avm_clamp(result), true)
|
return (avm_clamp(result), TYPE_Q16)
|
||||||
elseif op == LT_Q16
|
elseif op == LT_Q16
|
||||||
return (lt_q16_v6(a::Int32, b::Int32), false)
|
return (lt_q16_v6(a::Int32, b::Int32), TYPE_BOOL)
|
||||||
elseif op == EQ_Q16
|
elseif op == EQ_Q16
|
||||||
return (a::Int32 == b::Int32, false)
|
return (a::Int32 == b::Int32, TYPE_BOOL)
|
||||||
elseif op == AND_OP
|
elseif op == AND_OP
|
||||||
return (a::Bool && b::Bool, false)
|
return (a::Bool && b::Bool, TYPE_BOOL)
|
||||||
elseif op == OR_OP
|
elseif op == OR_OP
|
||||||
return (a::Bool || b::Bool, false)
|
return (a::Bool || b::Bool, TYPE_BOOL)
|
||||||
elseif op == NOT_OP
|
elseif op == NOT_OP
|
||||||
return (!a::Bool, false)
|
return (!a::Bool, TYPE_BOOL)
|
||||||
else
|
else
|
||||||
error(TYPE_MISMATCH)
|
error(TYPE_MISMATCH)
|
||||||
end
|
end
|
||||||
|
|
@ -134,14 +145,14 @@ end
|
||||||
|
|
||||||
function step(s::State, program::Vector{Instr})::State
|
function step(s::State, program::Vector{Instr})::State
|
||||||
s.halted && error(HALTED)
|
s.halted && error(HALTED)
|
||||||
s.pc < 1 && return State(s.pc, copy(s.stack), copy(s.is_q16),
|
s.pc < 1 && return State(s.pc, copy(s.stack), copy(s.types),
|
||||||
copy(s.locals), copy(s.local_types), true)
|
copy(s.locals), copy(s.local_types), true)
|
||||||
s.pc > length(program) && return State(s.pc, copy(s.stack), copy(s.is_q16),
|
s.pc > length(program) && return State(s.pc, copy(s.stack), copy(s.types),
|
||||||
copy(s.locals), copy(s.local_types), true)
|
copy(s.locals), copy(s.local_types), true)
|
||||||
|
|
||||||
instr = program[s.pc]
|
instr = program[s.pc]
|
||||||
stack = copy(s.stack)
|
stack = copy(s.stack)
|
||||||
is_q16 = copy(s.is_q16)
|
types = copy(s.types)
|
||||||
locals = copy(s.locals)
|
locals = copy(s.locals)
|
||||||
local_types = copy(s.local_types)
|
local_types = copy(s.local_types)
|
||||||
pc = s.pc + 1
|
pc = s.pc + 1
|
||||||
|
|
@ -151,39 +162,39 @@ function step(s::State, program::Vector{Instr})::State
|
||||||
|
|
||||||
if instr.op == 0 # push_val (Bool)
|
if instr.op == 0 # push_val (Bool)
|
||||||
push!(stack, instr.arg2)
|
push!(stack, instr.arg2)
|
||||||
push!(is_q16, false)
|
push!(types, TYPE_BOOL)
|
||||||
elseif instr.op == 1 # push_q16
|
elseif instr.op == 1 # push_q16
|
||||||
push!(stack, instr.arg)
|
push!(stack, instr.arg)
|
||||||
push!(is_q16, true)
|
push!(types, TYPE_Q16)
|
||||||
elseif instr.op == 2 # pop
|
elseif instr.op == 2 # pop
|
||||||
isempty(stack) && error(EMPTY_STACK)
|
isempty(stack) && error(EMPTY_STACK)
|
||||||
pop!(stack); pop!(is_q16)
|
pop!(stack); pop!(types)
|
||||||
elseif instr.op == 3 # dup
|
elseif instr.op == 3 # dup
|
||||||
isempty(stack) && error(EMPTY_STACK)
|
isempty(stack) && error(EMPTY_STACK)
|
||||||
push!(stack, stack[end]); push!(is_q16, is_q16[end])
|
push!(stack, stack[end]); push!(types, types[end])
|
||||||
elseif instr.op == 4 # swap
|
elseif instr.op == 4 # swap
|
||||||
length(stack) < 2 && error(STACK_UNDERFLOW)
|
length(stack) < 2 && error(STACK_UNDERFLOW)
|
||||||
a = pop!(stack); ta = pop!(is_q16)
|
a = pop!(stack); ta = pop!(types)
|
||||||
b = pop!(stack); tb = pop!(is_q16)
|
b = pop!(stack); tb = pop!(types)
|
||||||
push!(stack, a); push!(is_q16, ta)
|
push!(stack, a); push!(types, ta)
|
||||||
push!(stack, b); push!(is_q16, tb)
|
push!(stack, b); push!(types, tb)
|
||||||
elseif instr.op == 5 # load
|
elseif instr.op == 5 # load
|
||||||
i = Int(instr.arg) + 1
|
i = Int(instr.arg) + 1
|
||||||
i > length(locals) && error(MISSING_LOCAL)
|
i > length(locals) && error(MISSING_LOCAL)
|
||||||
locals[i] === nothing && error(MISSING_LOCAL)
|
locals[i] === nothing && error(MISSING_LOCAL)
|
||||||
push!(stack, locals[i]); push!(is_q16, local_types[i])
|
push!(stack, locals[i]); push!(types, local_types[i])
|
||||||
elseif instr.op == 6 # store
|
elseif instr.op == 6 # store
|
||||||
i = Int(instr.arg) + 1
|
i = Int(instr.arg) + 1
|
||||||
isempty(stack) && error(EMPTY_STACK)
|
isempty(stack) && error(EMPTY_STACK)
|
||||||
i > length(locals) && error(MISSING_LOCAL)
|
i > length(locals) && error(MISSING_LOCAL)
|
||||||
locals[i] = pop!(stack); local_types[i] = pop!(is_q16)
|
locals[i] = pop!(stack); local_types[i] = pop!(types)
|
||||||
elseif instr.op == 7 # jump
|
elseif instr.op == 7 # jump
|
||||||
target = Int(instr.arg) + 1
|
target = Int(instr.arg) + 1
|
||||||
(target < 1 || target > length(program)) && error(JUMP_OUT_OF_BOUNDS)
|
(target < 1 || target > length(program)) && error(JUMP_OUT_OF_BOUNDS)
|
||||||
pc = target
|
pc = target
|
||||||
elseif instr.op == 8 # jump_if
|
elseif instr.op == 8 # jump_if
|
||||||
isempty(stack) && error(EMPTY_STACK)
|
isempty(stack) && error(EMPTY_STACK)
|
||||||
cond = pop!(stack)::Bool; pop!(is_q16)
|
cond = pop!(stack)::Bool; pop!(types)
|
||||||
if cond
|
if cond
|
||||||
target = Int(instr.arg) + 1
|
target = Int(instr.arg) + 1
|
||||||
(target < 1 || target > length(program)) && error(JUMP_OUT_OF_BOUNDS)
|
(target < 1 || target > length(program)) && error(JUMP_OUT_OF_BOUNDS)
|
||||||
|
|
@ -193,17 +204,17 @@ function step(s::State, program::Vector{Instr})::State
|
||||||
p = Prim(instr.arg)
|
p = Prim(instr.arg)
|
||||||
arity = (p == NOT_OP) ? 1 : 2
|
arity = (p == NOT_OP) ? 1 : 2
|
||||||
length(stack) < arity && error(STACK_UNDERFLOW)
|
length(stack) < arity && error(STACK_UNDERFLOW)
|
||||||
b = arity >= 2 ? pop!(stack) : nothing; if arity >= 2; pop!(is_q16); end
|
b = arity >= 2 ? pop!(stack) : nothing; if arity >= 2; pop!(types); end
|
||||||
a = pop!(stack); pop!(is_q16)
|
a = pop!(stack); pop!(types)
|
||||||
result, is_q = exec_prim(p, a, b)
|
result, type_tag = exec_prim(p, a, b)
|
||||||
push!(stack, result); push!(is_q16, is_q)
|
push!(stack, result); push!(types, type_tag)
|
||||||
elseif instr.op == 10 # halt
|
elseif instr.op == 10 # halt
|
||||||
halted = true
|
halted = true
|
||||||
else
|
else
|
||||||
error(UNKNOWN_INSTR)
|
error(UNKNOWN_INSTR)
|
||||||
end
|
end
|
||||||
|
|
||||||
State(pc, stack, is_q16, locals, local_types, halted)
|
State(pc, stack, types, locals, local_types, halted)
|
||||||
end
|
end
|
||||||
|
|
||||||
# ── Run (fuel-bounded) ────────────────────────────────────────────
|
# ── Run (fuel-bounded) ────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -12,27 +12,30 @@
|
||||||
|
|
||||||
INSTR_PUSH_Q16 <- 0L
|
INSTR_PUSH_Q16 <- 0L
|
||||||
INSTR_PUSH_BOOL <- 1L
|
INSTR_PUSH_BOOL <- 1L
|
||||||
INSTR_POP <- 2L
|
INSTR_PUSH_Q0 <- 2L
|
||||||
INSTR_DUP <- 3L
|
INSTR_POP <- 3L
|
||||||
INSTR_SWAP <- 4L
|
INSTR_DUP <- 4L
|
||||||
INSTR_LOAD <- 5L
|
INSTR_SWAP <- 5L
|
||||||
INSTR_STORE <- 6L
|
INSTR_LOAD <- 6L
|
||||||
INSTR_JUMP <- 7L
|
INSTR_STORE <- 7L
|
||||||
INSTR_JUMP_IF <- 8L
|
INSTR_JUMP <- 8L
|
||||||
INSTR_PRIM <- 9L
|
INSTR_JUMP_IF <- 9L
|
||||||
INSTR_HALT <- 10L
|
INSTR_PRIM <- 10L
|
||||||
|
INSTR_HALT <- 11L
|
||||||
|
|
||||||
# ── Primitives ───────────────────────────────────────────────────────
|
# ── Primitives ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
PRIM_ADD_Q16 <- 0L
|
PRIM_ADD_Q0 <- 0L
|
||||||
PRIM_SUB_Q16 <- 1L
|
PRIM_SUB_Q0 <- 1L
|
||||||
PRIM_MUL_Q16 <- 2L
|
PRIM_ADD_Q16 <- 2L
|
||||||
PRIM_DIV_Q16 <- 3L
|
PRIM_SUB_Q16 <- 3L
|
||||||
PRIM_LT_Q16 <- 4L
|
PRIM_MUL_Q16 <- 4L
|
||||||
PRIM_EQ_Q16 <- 5L
|
PRIM_DIV_Q16 <- 5L
|
||||||
PRIM_AND <- 6L
|
PRIM_LT_Q16 <- 6L
|
||||||
PRIM_OR <- 7L
|
PRIM_EQ_Q16 <- 7L
|
||||||
PRIM_NOT <- 8L
|
PRIM_AND <- 8L
|
||||||
|
PRIM_OR <- 9L
|
||||||
|
PRIM_NOT <- 10L
|
||||||
|
|
||||||
# ── Step Error codes ─────────────────────────────────────────────────
|
# ── Step Error codes ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
@ -49,12 +52,15 @@ ERR_HALTED <- "halted"
|
||||||
|
|
||||||
AVM_CLAMP_MIN <- -2147483647L
|
AVM_CLAMP_MIN <- -2147483647L
|
||||||
AVM_CLAMP_MAX <- 2147483647L
|
AVM_CLAMP_MAX <- 2147483647L
|
||||||
|
AVM_Q0_MIN <- -32767L
|
||||||
|
AVM_Q0_MAX <- 32767L
|
||||||
AVM_MAX_STACK <- 1024L
|
AVM_MAX_STACK <- 1024L
|
||||||
|
|
||||||
# ── Instruction constructors ─────────────────────────────────────────
|
# ── Instruction constructors ─────────────────────────────────────────
|
||||||
|
|
||||||
instr_push_q16 <- function(x) list(op = INSTR_PUSH_Q16, arg = as.integer(x))
|
instr_push_q16 <- function(x) list(op = INSTR_PUSH_Q16, arg = as.integer(x))
|
||||||
instr_push_bool <- function(x) list(op = INSTR_PUSH_BOOL, arg = as.integer(x))
|
instr_push_bool <- function(x) list(op = INSTR_PUSH_BOOL, arg = as.integer(x))
|
||||||
|
instr_push_q0 <- function(x) list(op = INSTR_PUSH_Q0, arg = as.integer(x))
|
||||||
instr_pop <- function() list(op = INSTR_POP, arg = 0L)
|
instr_pop <- function() list(op = INSTR_POP, arg = 0L)
|
||||||
instr_dup <- function() list(op = INSTR_DUP, arg = 0L)
|
instr_dup <- function() list(op = INSTR_DUP, arg = 0L)
|
||||||
instr_swap <- function() list(op = INSTR_SWAP, arg = 0L)
|
instr_swap <- function() list(op = INSTR_SWAP, arg = 0L)
|
||||||
|
|
@ -80,9 +86,11 @@ new_state <- function(n_locals = 0L) {
|
||||||
# ── Stack helpers ────────────────────────────────────────────────────
|
# ── Stack helpers ────────────────────────────────────────────────────
|
||||||
|
|
||||||
make_q16 <- function(x) list(type = "q16", val = as.integer(x))
|
make_q16 <- function(x) list(type = "q16", val = as.integer(x))
|
||||||
|
make_q0 <- function(x) list(type = "q0", val = as.integer(x))
|
||||||
make_bool <- function(x) list(type = "bool", val = as.logical(x))
|
make_bool <- function(x) list(type = "bool", val = as.logical(x))
|
||||||
|
|
||||||
is_q16 <- function(v) identical(v$type, "q16")
|
is_q16 <- function(v) identical(v$type, "q16")
|
||||||
|
is_q0 <- function(v) identical(v$type, "q0")
|
||||||
is_bool <- function(v) identical(v$type, "bool")
|
is_bool <- function(v) identical(v$type, "bool")
|
||||||
|
|
||||||
# ── Q16_16 helpers ───────────────────────────────────────────────────
|
# ── Q16_16 helpers ───────────────────────────────────────────────────
|
||||||
|
|
@ -116,8 +124,18 @@ q16_div <- function(a, b) {
|
||||||
|
|
||||||
# ── Primitive execution ──────────────────────────────────────────────
|
# ── Primitive execution ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
avm_q0_clamp <- function(x) {
|
||||||
|
min(AVM_Q0_MAX, max(AVM_Q0_MIN, as.integer(x)))
|
||||||
|
}
|
||||||
|
|
||||||
exec_prim <- function(op, a, b = NULL) {
|
exec_prim <- function(op, a, b = NULL) {
|
||||||
if (op == PRIM_ADD_Q16) {
|
if (op == PRIM_ADD_Q0) {
|
||||||
|
if (!is_q0(a) || !is_q0(b)) stop(ERR_TYPE_MISMATCH)
|
||||||
|
make_q0(avm_q0_clamp(as.numeric(a$val) + as.numeric(b$val)))
|
||||||
|
} else if (op == PRIM_SUB_Q0) {
|
||||||
|
if (!is_q0(a) || !is_q0(b)) stop(ERR_TYPE_MISMATCH)
|
||||||
|
make_q0(avm_q0_clamp(as.numeric(a$val) - as.numeric(b$val)))
|
||||||
|
} else if (op == PRIM_ADD_Q16) {
|
||||||
if (!is_q16(a) || !is_q16(b)) stop(ERR_TYPE_MISMATCH)
|
if (!is_q16(a) || !is_q16(b)) stop(ERR_TYPE_MISMATCH)
|
||||||
x <- as.numeric(a$val) + as.numeric(b$val)
|
x <- as.numeric(a$val) + as.numeric(b$val)
|
||||||
make_q16(avm_clamp(x))
|
make_q16(avm_clamp(x))
|
||||||
|
|
@ -175,6 +193,8 @@ step <- function(s, prog) {
|
||||||
stack <- c(stack, list(make_q16(instr$arg)))
|
stack <- c(stack, list(make_q16(instr$arg)))
|
||||||
} else if (instr$op == INSTR_PUSH_BOOL) {
|
} else if (instr$op == INSTR_PUSH_BOOL) {
|
||||||
stack <- c(stack, list(make_bool(instr$arg != 0L)))
|
stack <- c(stack, list(make_bool(instr$arg != 0L)))
|
||||||
|
} else if (instr$op == INSTR_PUSH_Q0) {
|
||||||
|
stack <- c(stack, list(make_q0(instr$arg)))
|
||||||
} else if (instr$op == INSTR_POP) {
|
} else if (instr$op == INSTR_POP) {
|
||||||
if (length(stack) == 0L) stop(ERR_EMPTY_STACK)
|
if (length(stack) == 0L) stop(ERR_EMPTY_STACK)
|
||||||
stack <- stack[-length(stack)]
|
stack <- stack[-length(stack)]
|
||||||
|
|
@ -189,7 +209,11 @@ step <- function(s, prog) {
|
||||||
i <- instr$arg + 1L
|
i <- instr$arg + 1L
|
||||||
if (i > length(locals)) stop(ERR_MISSING_LOCAL)
|
if (i > length(locals)) stop(ERR_MISSING_LOCAL)
|
||||||
if (is.null(locals[[i]])) stop(ERR_MISSING_LOCAL)
|
if (is.null(locals[[i]])) stop(ERR_MISSING_LOCAL)
|
||||||
stack <- c(stack, list(make_q16(locals[[i]])))
|
# Restore from local type tag
|
||||||
|
lt <- local_types[[i]]
|
||||||
|
if (identical(lt, "q16")) stack <- c(stack, list(make_q16(locals[[i]])))
|
||||||
|
else if (identical(lt, "q0")) stack <- c(stack, list(make_q0(locals[[i]])))
|
||||||
|
else stack <- c(stack, list(make_bool(locals[[i]])))
|
||||||
} else if (instr$op == INSTR_STORE) {
|
} else if (instr$op == INSTR_STORE) {
|
||||||
i <- instr$arg + 1L
|
i <- instr$arg + 1L
|
||||||
if (length(stack) == 0L) stop(ERR_EMPTY_STACK)
|
if (length(stack) == 0L) stop(ERR_EMPTY_STACK)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue