Class: Flux::FluxVM
Overview
Main FLUX ISA v3.0 Virtual Machine
Register Model:
-
16 GP registers (R0-R15, int32)
-
16 FP registers (F0-F15, float64)
-
16 VR registers (V0-V15, 256 bytes each)
-
PC, SP, FP_REG, FLAGS, STATE
Memory: flat binary string, 64KB default
Constant Summary
collapse
- RV =
8
- A0 =
9
- A1 =
10
- SP_REG =
11
- FP_REG =
12
- FLAGS =
13
- TP =
14
- LR =
15
- RUNNING =
:running
- HALTED =
:halted
- PANICKED =
:panicked
- YIELDED =
:yielded
- FLAG_Z =
1 << 0
- FLAG_S =
1 << 1
- FLAG_C =
1 << 2
- FLAG_V =
1 << 3
- @@opcode_registry =
Opcode registry for runtime-registered opcodes
{}
- @@runtime_opcodes =
{}
OpcodeRegistry::OPCODE_CLASSES, OpcodeRegistry::OPCODE_NAMES
Class Attribute Summary collapse
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
-
#initialize(memory_size: 65536) ⇒ FluxVM
constructor
A new instance of FluxVM.
-
#load(bytecode_string) ⇒ Object
Load bytecode into memory starting at address 0.
-
#opAAsk ⇒ Object
-
#opABroadcast ⇒ Object
-
#opADelegate ⇒ Object
-
#opARecv ⇒ Object
-
#opASend ⇒ Object
A2A Opcodes (stub implementations).
-
#opASubscribe ⇒ Object
-
#opATell ⇒ Object
-
#opATrust ⇒ Object
-
#opAVerify ⇒ Object
-
#opAWait ⇒ Object
-
#opBAnd(rd, ra, rb) ⇒ Object
-
#opBNot(rd, ra, rb) ⇒ Object
-
#opBOr(rd, ra, rb) ⇒ Object
-
#opBShl(rd, ra, rb) ⇒ Object
-
#opBShr(rd, ra, rb) ⇒ Object
-
#opBToI(rd, ra, rb) ⇒ Object
-
#opBXor(rd, ra, rb) ⇒ Object
-
#opCall ⇒ Object
-
#opCallIndirect ⇒ Object
-
#opCast(rd, ra, rb) ⇒ Object
-
#opDup(rd, rs) ⇒ Object
-
#opFAbs(rd, ra, rb) ⇒ Object
-
#opFAdd(rd, ra, rb) ⇒ Object
-
#opFCeil(rd, ra, rb) ⇒ Object
-
#opFClamp(rd, ra, rb) ⇒ Object
-
#opFCmpEq(rd, ra, rb) ⇒ Object
-
#opFCmpGe(rd, ra, rb) ⇒ Object
-
#opFCmpGt(rd, ra, rb) ⇒ Object
-
#opFCmpLe(rd, ra, rb) ⇒ Object
-
#opFCmpLt(rd, ra, rb) ⇒ Object
-
#opFCmpNe(rd, ra, rb) ⇒ Object
-
#opFCos(rd, ra, rb) ⇒ Object
-
#opFDiv(rd, ra, rb) ⇒ Object
-
#opFExp(rd, ra, rb) ⇒ Object
-
#opFFloor(rd, ra, rb) ⇒ Object
-
#opFLerp(rd, ra, rb) ⇒ Object
-
#opFLog(rd, ra, rb) ⇒ Object
-
#opFMax(rd, ra, rb) ⇒ Object
-
#opFMin(rd, ra, rb) ⇒ Object
-
#opFMod(rd, ra, rb) ⇒ Object
-
#opFMov(rd, rs) ⇒ Object
-
#opFMul(rd, ra, rb) ⇒ Object
-
#opFNeg(rd, ra, rb) ⇒ Object
-
#opFRound(rd, ra, rb) ⇒ Object
-
#opFSin(rd, ra, rb) ⇒ Object
-
#opFSqrt(rd, ra, rb) ⇒ Object
-
#opFSub(rd, ra, rb) ⇒ Object
-
#opFToI(rd, ra, rb) ⇒ Object
-
#opHalt ⇒ Object
Format A opcodes (1 byte).
-
#opIAbs(rd, ra, rb) ⇒ Object
-
#opIAdd(rd, ra, rb) ⇒ Object
Integer Arithmetic (Format C).
-
#opIAnd(rd, ra, rb) ⇒ Object
-
#opICmpEq(rd, ra, rb) ⇒ Object
-
#opICmpGe(rd, ra, rb) ⇒ Object
-
#opICmpGt(rd, ra, rb) ⇒ Object
-
#opICmpLe(rd, ra, rb) ⇒ Object
-
#opICmpLt(rd, ra, rb) ⇒ Object
-
#opICmpNe(rd, ra, rb) ⇒ Object
-
#opIDec(rd) ⇒ Object
-
#opIDiv(rd, ra, rb) ⇒ Object
-
#opIInc(rd) ⇒ Object
Format D opcodes (4 bytes: opcode + Rd + imm16).
-
#opIMax(rd, ra, rb) ⇒ Object
-
#opIMin(rd, ra, rb) ⇒ Object
-
#opIMod(rd, ra, rb) ⇒ Object
-
#opIMov(rd, rs) ⇒ Object
-
#opIMul(rd, ra, rb) ⇒ Object
-
#opINeg(rd, ra, rb) ⇒ Object
-
#opINot(rd, ra, rb) ⇒ Object
-
#opIOr(rd, ra, rb) ⇒ Object
-
#opIShl(rd, ra, rb) ⇒ Object
-
#opIShr(rd, ra, rb) ⇒ Object
-
#opISub(rd, ra, rb) ⇒ Object
-
#opIToB(rd, ra, rb) ⇒ Object
-
#opIToF(rd, ra, rb) ⇒ Object
-
#opIXor(rd, ra, rb) ⇒ Object
-
#opJump ⇒ Object
Format G opcodes (variable).
-
#opJumpIf ⇒ Object
-
#opJumpIfNot ⇒ Object
-
#opLoad16(rd, rb) ⇒ Object
-
#opLoad32(rd, rb) ⇒ Object
-
#opLoad64(rd, rb) ⇒ Object
-
#opLoad8(rd, rb) ⇒ Object
Format E opcodes (5 bytes: opcode + Rd + Rbase + off16).
-
#opLoadAddr(rd, rb) ⇒ Object
-
#opNop ⇒ Object
-
#opPanic ⇒ Object
-
#opPop(rd, rs) ⇒ Object
-
#opPush(rd, rs) ⇒ Object
Format B opcodes (3 bytes: opcode + Rd + Rs).
-
#opRet ⇒ Object
-
#opSizeOf(rd, ra, rb) ⇒ Object
-
#opStackAlloc(rd) ⇒ Object
-
#opStore16(rs, rb) ⇒ Object
-
#opStore32(rs, rb) ⇒ Object
-
#opStore64(rs, rb) ⇒ Object
-
#opStore8(rs, rb) ⇒ Object
-
#opSwap(ra, rb) ⇒ Object
-
#opTypeOf(rd, ra, rb) ⇒ Object
-
#opUnreachable ⇒ Object
-
#opVAdd(rd, ra, rb) ⇒ Object
-
#opVDot(rd, ra, rb) ⇒ Object
-
#opVLoad(rd, rb, off) ⇒ Object
-
#opVMul(rd, ra, rb) ⇒ Object
-
#opVStore(rs, rb, off) ⇒ Object
-
#opYield ⇒ Object
-
#pop ⇒ Object
-
#push(value) ⇒ Object
-
#read_memory(addr, bytes) ⇒ Object
-
#read_memory_i16(addr) ⇒ Object
-
#read_memory_i32(addr) ⇒ Object
-
#read_memory_u16(addr) ⇒ Object
-
#read_memory_u32(addr) ⇒ Object
-
#read_memory_u8(addr) ⇒ Object
-
#regs ⇒ Object
Get register values as hash.
-
#reset ⇒ Object
-
#run(max_cycles: nil) ⇒ Object
Run the VM until halt/panic/yield or max_cycles reached.
-
#set_c(result) ⇒ Object
-
#set_s(result) ⇒ Object
-
#set_v(result) ⇒ Object
-
#set_z(result) ⇒ Object
-
#set_zn(result) ⇒ Object
-
#set_znv(result) ⇒ Object
-
#stats ⇒ Object
-
#step ⇒ Object
-
#write_memory(addr, bytes, value) ⇒ Object
opcode_name
Constructor Details
#initialize(memory_size: 65536) ⇒ FluxVM
Returns a new instance of FluxVM.
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 57
def initialize(memory_size: 65536)
@memory_size = memory_size
@memory = [0] * memory_size
@gp = [0] * 16
@fp = [0.0] * 16
@vr = Array.new(16) { "\x00" * 256 }
@pc = 0
@sp = memory_size @fp_reg = 0
@flags = 0
@state = RUNNING
@cycles = 0
@instruction_count = 0
end
|
Class Attribute Details
.opcode_registry ⇒ Object
Returns the value of attribute opcode_registry.
50
51
52
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 50
def opcode_registry
@opcode_registry
end
|
.runtime_opcodes ⇒ Object
Returns the value of attribute runtime_opcodes.
50
51
52
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 50
def runtime_opcodes
@runtime_opcodes
end
|
Instance Attribute Details
#flags ⇒ Object
Returns the value of attribute flags.
42
43
44
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 42
def flags
@flags
end
|
#fp ⇒ Object
Returns the value of attribute fp.
41
42
43
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 41
def fp
@fp
end
|
#fp_reg ⇒ Object
Returns the value of attribute fp_reg.
42
43
44
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 42
def fp_reg
@fp_reg
end
|
#gp ⇒ Object
Returns the value of attribute gp.
41
42
43
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 41
def gp
@gp
end
|
#memory ⇒ Object
Returns the value of attribute memory.
43
44
45
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 43
def memory
@memory
end
|
#memory_size ⇒ Object
Returns the value of attribute memory_size.
43
44
45
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 43
def memory_size
@memory_size
end
|
#pc ⇒ Object
Returns the value of attribute pc.
42
43
44
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 42
def pc
@pc
end
|
#sp ⇒ Object
Returns the value of attribute sp.
42
43
44
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 42
def sp
@sp
end
|
#state ⇒ Object
154
155
156
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 154
def state
@state
end
|
#vr ⇒ Object
Returns the value of attribute vr.
41
42
43
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 41
def vr
@vr
end
|
Class Method Details
.register_opcode(opcode_class) ⇒ Object
52
53
54
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 52
def register_opcode(opcode_class)
@@runtime_opcodes[opcode_class.opcode_id] = opcode_class
end
|
Instance Method Details
#load(bytecode_string) ⇒ Object
Load bytecode into memory starting at address 0
83
84
85
86
87
88
89
90
91
92
93
94
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 83
def load(bytecode_string)
bytecode = bytecode_string.dup.force_encoding('BINARY')
raise FluxRuntimeError, 'Bytecode too large' if bytecode.bytesize > @memory_size
bytecode.bytes.each_with_index do |byte, i|
@memory[i] = byte
end
@pc = 0
@sp = @memory_size
self
end
|
#opAAsk ⇒ Object
967
968
969
970
971
972
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 967
def opAAsk
length = fetch8
agent_id = fetch8
reg = fetch8
$stderr.puts "A2A: AAsk agent_id=#{agent_id} reg=#{reg}"
end
|
#opABroadcast ⇒ Object
988
989
990
991
992
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 988
def opABroadcast
length = fetch8
reg = fetch8
$stderr.puts "A2A: ABroadcast reg=#{reg}"
end
|
#opADelegate ⇒ Object
981
982
983
984
985
986
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 981
def opADelegate
length = fetch8
agent_id = fetch8
bc_start = fetchu16
$stderr.puts "A2A: ADelegate agent_id=#{agent_id} bc_start=#{bc_start}"
end
|
#opARecv ⇒ Object
960
961
962
963
964
965
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 960
def opARecv
length = fetch8
agent_id = fetch8
reg = fetch8
$stderr.puts "A2A: ARecv agent_id=#{agent_id} reg=#{reg}"
end
|
#opASend ⇒ Object
A2A Opcodes (stub implementations)
953
954
955
956
957
958
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 953
def opASend
length = fetch8
agent_id = fetch8
reg = fetch8
$stderr.puts "A2A: ASend agent_id=#{agent_id} reg=#{reg}"
end
|
#opASubscribe ⇒ Object
994
995
996
997
998
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 994
def opASubscribe
length = fetch8
channel_id = fetch8
$stderr.puts "A2A: ASubscribe channel_id=#{channel_id}"
end
|
#opATell ⇒ Object
974
975
976
977
978
979
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 974
def opATell
length = fetch8
agent_id = fetch8
reg = fetch8
$stderr.puts "A2A: ATell agent_id=#{agent_id} reg=#{reg}"
end
|
#opATrust ⇒ Object
1006
1007
1008
1009
1010
1011
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 1006
def opATrust
length = fetch8
agent_id = fetch8
level = fetch8
$stderr.puts "A2A: ATrust agent_id=#{agent_id} level=#{level}"
end
|
#opAVerify ⇒ Object
1013
1014
1015
1016
1017
1018
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 1013
def opAVerify
length = fetch8
agent_id = fetch8
result_reg = fetch8
$stderr.puts "A2A: AVerify agent_id=#{agent_id} result_reg=#{result_reg}"
end
|
#opAWait ⇒ Object
1000
1001
1002
1003
1004
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 1000
def opAWait
length = fetch8
cond_reg = fetch8
$stderr.puts "A2A: AWait cond_reg=#{cond_reg}"
end
|
#opBAnd(rd, ra, rb) ⇒ Object
870
871
872
873
874
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 870
def opBAnd(rd, ra, rb)
result = @gp[ra] & @gp[rb]
set_zn(result)
@gp[rd] = result
end
|
#opBNot(rd, ra, rb) ⇒ Object
900
901
902
903
904
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 900
def opBNot(rd, ra, rb)
result = ~@gp[ra]
set_zn(result)
@gp[rd] = result
end
|
#opBOr(rd, ra, rb) ⇒ Object
876
877
878
879
880
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 876
def opBOr(rd, ra, rb)
result = @gp[ra] | @gp[rb]
set_zn(result)
@gp[rd] = result
end
|
#opBShl(rd, ra, rb) ⇒ Object
888
889
890
891
892
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 888
def opBShl(rd, ra, rb)
result = @gp[ra] << (@gp[rb] & 31)
set_zn(result)
@gp[rd] = result
end
|
#opBShr(rd, ra, rb) ⇒ Object
894
895
896
897
898
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 894
def opBShr(rd, ra, rb)
result = @gp[ra] >> (@gp[rb] & 31)
set_zn(result)
@gp[rd] = result
end
|
#opBToI(rd, ra, rb) ⇒ Object
845
846
847
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 845
def opBToI(rd, ra, rb)
@gp[rd] = (@gp[ra] != 0) ? 1 : 0
end
|
#opBXor(rd, ra, rb) ⇒ Object
882
883
884
885
886
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 882
def opBXor(rd, ra, rb)
result = @gp[ra] ^ @gp[rb]
set_zn(result)
@gp[rd] = result
end
|
#opCall ⇒ Object
476
477
478
479
480
481
482
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 476
def opCall
length = fetch8
func_idx = fetchu16
push(@pc)
@gp[LR] = @pc
@pc = func_idx
end
|
#opCallIndirect ⇒ Object
484
485
486
487
488
489
490
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 484
def opCallIndirect
length = fetch8
reg = fetch8
push(@pc)
@gp[LR] = @pc
@pc = @gp[reg]
end
|
#opCast(rd, ra, rb) ⇒ Object
854
855
856
857
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 854
def opCast(rd, ra, rb)
@gp[rd] = @gp[ra]
end
|
#opDup(rd, rs) ⇒ Object
501
502
503
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 501
def opDup(rd, rs)
@gp[rd] = @gp[rs]
end
|
#opFAbs(rd, ra, rb) ⇒ Object
748
749
750
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 748
def opFAbs(rd, ra, rb)
@fp[rd] = @fp[ra].abs
end
|
#opFAdd(rd, ra, rb) ⇒ Object
719
720
721
722
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 719
def opFAdd(rd, ra, rb)
result = @fp[ra] + @fp[rb]
@fp[rd] = result
end
|
#opFCeil(rd, ra, rb) ⇒ Object
760
761
762
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 760
def opFCeil(rd, ra, rb)
@fp[rd] = @fp[ra].ceil
end
|
#opFClamp(rd, ra, rb) ⇒ Object
792
793
794
795
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 792
def opFClamp(rd, ra, rb)
@fp[rd] = [@fp[ra], @fp[rb]].min
end
|
#opFCmpEq(rd, ra, rb) ⇒ Object
806
807
808
809
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 806
def opFCmpEq(rd, ra, rb)
@gp[rd] = (@fp[ra] == @fp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opFCmpGe(rd, ra, rb) ⇒ Object
831
832
833
834
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 831
def opFCmpGe(rd, ra, rb)
@gp[rd] = (@fp[ra] >= @fp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opFCmpGt(rd, ra, rb) ⇒ Object
826
827
828
829
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 826
def opFCmpGt(rd, ra, rb)
@gp[rd] = (@fp[ra] > @fp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opFCmpLe(rd, ra, rb) ⇒ Object
821
822
823
824
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 821
def opFCmpLe(rd, ra, rb)
@gp[rd] = (@fp[ra] <= @fp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opFCmpLt(rd, ra, rb) ⇒ Object
816
817
818
819
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 816
def opFCmpLt(rd, ra, rb)
@gp[rd] = (@fp[ra] < @fp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opFCmpNe(rd, ra, rb) ⇒ Object
811
812
813
814
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 811
def opFCmpNe(rd, ra, rb)
@gp[rd] = (@fp[ra] != @fp[rb]) ? 1 : 0
set_z(1 - @gp[rd])
end
|
#opFCos(rd, ra, rb) ⇒ Object
780
781
782
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 780
def opFCos(rd, ra, rb)
@fp[rd] = Math.cos(@fp[ra])
end
|
#opFDiv(rd, ra, rb) ⇒ Object
734
735
736
737
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 734
def opFDiv(rd, ra, rb)
result = @fp[ra] / @fp[rb]
@fp[rd] = result
end
|
#opFExp(rd, ra, rb) ⇒ Object
784
785
786
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 784
def opFExp(rd, ra, rb)
@fp[rd] = Math.exp(@fp[ra])
end
|
#opFFloor(rd, ra, rb) ⇒ Object
756
757
758
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 756
def opFFloor(rd, ra, rb)
@fp[rd] = @fp[ra].floor
end
|
#opFLerp(rd, ra, rb) ⇒ Object
797
798
799
800
801
802
803
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 797
def opFLerp(rd, ra, rb)
t = @fp[ra]
base = @fp[rb]
@fp[rd] = base * (1 - t) + base * t
end
|
#opFLog(rd, ra, rb) ⇒ Object
788
789
790
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 788
def opFLog(rd, ra, rb)
@fp[rd] = Math.log(@fp[ra])
end
|
#opFMax(rd, ra, rb) ⇒ Object
772
773
774
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 772
def opFMax(rd, ra, rb)
@fp[rd] = [@fp[ra], @fp[rb]].max
end
|
#opFMin(rd, ra, rb) ⇒ Object
768
769
770
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 768
def opFMin(rd, ra, rb)
@fp[rd] = [@fp[ra], @fp[rb]].min
end
|
#opFMod(rd, ra, rb) ⇒ Object
739
740
741
742
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 739
def opFMod(rd, ra, rb)
result = @fp[ra] % @fp[rb]
@fp[rd] = result
end
|
#opFMov(rd, rs) ⇒ Object
513
514
515
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 513
def opFMov(rd, rs)
@fp[rd] = @fp[rs]
end
|
#opFMul(rd, ra, rb) ⇒ Object
729
730
731
732
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 729
def opFMul(rd, ra, rb)
result = @fp[ra] * @fp[rb]
@fp[rd] = result
end
|
#opFNeg(rd, ra, rb) ⇒ Object
744
745
746
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 744
def opFNeg(rd, ra, rb)
@fp[rd] = -@fp[ra]
end
|
#opFRound(rd, ra, rb) ⇒ Object
764
765
766
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 764
def opFRound(rd, ra, rb)
@fp[rd] = @fp[ra].round
end
|
#opFSin(rd, ra, rb) ⇒ Object
776
777
778
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 776
def opFSin(rd, ra, rb)
@fp[rd] = Math.sin(@fp[ra])
end
|
#opFSqrt(rd, ra, rb) ⇒ Object
752
753
754
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 752
def opFSqrt(rd, ra, rb)
@fp[rd] = Math.sqrt(@fp[ra])
end
|
#opFSub(rd, ra, rb) ⇒ Object
724
725
726
727
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 724
def opFSub(rd, ra, rb)
result = @fp[ra] - @fp[rb]
@fp[rd] = result
end
|
#opFToI(rd, ra, rb) ⇒ Object
841
842
843
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 841
def opFToI(rd, ra, rb)
@gp[rd] = @fp[ra].to_i
end
|
#opHalt ⇒ Object
Format A opcodes (1 byte)
430
431
432
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 430
def opHalt
@state = HALTED
end
|
#opIAbs(rd, ra, rb) ⇒ Object
632
633
634
635
636
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 632
def opIAbs(rd, ra, rb)
result = @gp[ra].abs
set_zn(result)
@gp[rd] = result
end
|
#opIAdd(rd, ra, rb) ⇒ Object
Integer Arithmetic (Format C)
594
595
596
597
598
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 594
def opIAdd(rd, ra, rb)
result = @gp[ra] + @gp[rb]
set_znv(result)
@gp[rd] = result
end
|
#opIAnd(rd, ra, rb) ⇒ Object
650
651
652
653
654
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 650
def opIAnd(rd, ra, rb)
result = @gp[ra] & @gp[rb]
set_zn(result)
@gp[rd] = result
end
|
#opICmpEq(rd, ra, rb) ⇒ Object
688
689
690
691
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 688
def opICmpEq(rd, ra, rb)
@gp[rd] = (@gp[ra] == @gp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opICmpGe(rd, ra, rb) ⇒ Object
713
714
715
716
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 713
def opICmpGe(rd, ra, rb)
@gp[rd] = (@gp[ra] >= @gp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opICmpGt(rd, ra, rb) ⇒ Object
708
709
710
711
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 708
def opICmpGt(rd, ra, rb)
@gp[rd] = (@gp[ra] > @gp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opICmpLe(rd, ra, rb) ⇒ Object
703
704
705
706
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 703
def opICmpLe(rd, ra, rb)
@gp[rd] = (@gp[ra] <= @gp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opICmpLt(rd, ra, rb) ⇒ Object
698
699
700
701
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 698
def opICmpLt(rd, ra, rb)
@gp[rd] = (@gp[ra] < @gp[rb]) ? 1 : 0
set_z(@gp[rd])
end
|
#opICmpNe(rd, ra, rb) ⇒ Object
693
694
695
696
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 693
def opICmpNe(rd, ra, rb)
@gp[rd] = (@gp[ra] != @gp[rb]) ? 1 : 0
set_z(1 - @gp[rd])
end
|
#opIDec(rd) ⇒ Object
525
526
527
528
529
530
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 525
def opIDec(rd)
imm = fetch16
result = @gp[rd] - imm
set_znv(result)
@gp[rd] = result
end
|
#opIDiv(rd, ra, rb) ⇒ Object
612
613
614
615
616
617
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 612
def opIDiv(rd, ra, rb)
raise DivideByZeroError.new(@pc - 1) if @gp[rb] == 0
result = @gp[ra] / @gp[rb]
set_znv(result)
@gp[rd] = result
end
|
#opIInc(rd) ⇒ Object
Format D opcodes (4 bytes: opcode + Rd + imm16)
518
519
520
521
522
523
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 518
def opIInc(rd)
imm = fetch16
result = @gp[rd] + imm
set_znv(result)
@gp[rd] = result
end
|
#opIMax(rd, ra, rb) ⇒ Object
644
645
646
647
648
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 644
def opIMax(rd, ra, rb)
result = [@gp[ra], @gp[rb]].max
set_zn(result)
@gp[rd] = result
end
|
#opIMin(rd, ra, rb) ⇒ Object
638
639
640
641
642
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 638
def opIMin(rd, ra, rb)
result = [@gp[ra], @gp[rb]].min
set_zn(result)
@gp[rd] = result
end
|
#opIMod(rd, ra, rb) ⇒ Object
619
620
621
622
623
624
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 619
def opIMod(rd, ra, rb)
raise DivideByZeroError.new(@pc - 1) if @gp[rb] == 0
result = @gp[ra] % @gp[rb]
set_znv(result)
@gp[rd] = result
end
|
#opIMov(rd, rs) ⇒ Object
509
510
511
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 509
def opIMov(rd, rs)
@gp[rd] = @gp[rs]
end
|
#opIMul(rd, ra, rb) ⇒ Object
606
607
608
609
610
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 606
def opIMul(rd, ra, rb)
result = @gp[ra] * @gp[rb]
set_znv(result)
@gp[rd] = result
end
|
#opINeg(rd, ra, rb) ⇒ Object
626
627
628
629
630
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 626
def opINeg(rd, ra, rb)
result = -@gp[ra]
set_zn(result)
@gp[rd] = result
end
|
#opINot(rd, ra, rb) ⇒ Object
681
682
683
684
685
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 681
def opINot(rd, ra, rb)
result = ~@gp[ra]
set_zn(result)
@gp[rd] = result
end
|
#opIOr(rd, ra, rb) ⇒ Object
656
657
658
659
660
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 656
def opIOr(rd, ra, rb)
result = @gp[ra] | @gp[rb]
set_zn(result)
@gp[rd] = result
end
|
#opIShl(rd, ra, rb) ⇒ Object
668
669
670
671
672
673
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 668
def opIShl(rd, ra, rb)
result = @gp[ra] << (@gp[rb] & 31)
set_z(result)
set_c((@gp[ra] << (@gp[rb] & 31)) != result ? 1 : 0)
@gp[rd] = result
end
|
#opIShr(rd, ra, rb) ⇒ Object
675
676
677
678
679
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 675
def opIShr(rd, ra, rb)
result = @gp[ra] >> (@gp[rb] & 31)
set_z(result)
@gp[rd] = result
end
|
#opISub(rd, ra, rb) ⇒ Object
600
601
602
603
604
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 600
def opISub(rd, ra, rb)
result = @gp[ra] - @gp[rb]
set_znv(result)
@gp[rd] = result
end
|
#opIToB(rd, ra, rb) ⇒ Object
849
850
851
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 849
def opIToB(rd, ra, rb)
@gp[rd] = (@gp[ra] != 0) ? 1 : 0
end
|
#opIToF(rd, ra, rb) ⇒ Object
837
838
839
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 837
def opIToF(rd, ra, rb)
@fp[rd] = @gp[ra].to_f
end
|
#opIXor(rd, ra, rb) ⇒ Object
662
663
664
665
666
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 662
def opIXor(rd, ra, rb)
result = @gp[ra] ^ @gp[rb]
set_zn(result)
@gp[rd] = result
end
|
#opJump ⇒ Object
Format G opcodes (variable)
456
457
458
459
460
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 456
def opJump
length = fetch8
offset = fetch16
@pc = @pc &+ offset
end
|
#opJumpIf ⇒ Object
462
463
464
465
466
467
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 462
def opJumpIf
length = fetch8
rd = fetch8
offset = fetch16
@pc = @pc &+ offset if @gp[rd] != 0
end
|
#opJumpIfNot ⇒ Object
469
470
471
472
473
474
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 469
def opJumpIfNot
length = fetch8
rd = fetch8
offset = fetch16
@pc = @pc &+ offset if @gp[rd] == 0
end
|
#opLoad16(rd, rb) ⇒ Object
546
547
548
549
550
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 546
def opLoad16(rd, rb)
off = fetchu16
addr = @gp[rb] + off
@gp[rd] = read_memory_u16(addr) || 0
end
|
#opLoad32(rd, rb) ⇒ Object
552
553
554
555
556
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 552
def opLoad32(rd, rb)
off = fetchu16
addr = @gp[rb] + off
@gp[rd] = read_memory_i32(addr) || 0
end
|
#opLoad64(rd, rb) ⇒ Object
558
559
560
561
562
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 558
def opLoad64(rd, rb)
off = fetchu16
addr = @gp[rb] + off
@gp[rd] = read_memory_u32(addr) || 0
end
|
#opLoad8(rd, rb) ⇒ Object
Format E opcodes (5 bytes: opcode + Rd + Rbase + off16)
540
541
542
543
544
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 540
def opLoad8(rd, rb)
off = fetchu16
addr = @gp[rb] + off
@gp[rd] = read_memory_u8(addr) || 0
end
|
#opLoadAddr(rd, rb) ⇒ Object
588
589
590
591
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 588
def opLoadAddr(rd, rb)
off = fetchu16
@gp[rd] = @gp[rb] + off
end
|
#opNop ⇒ Object
434
435
436
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 434
def opNop
end
|
#opPanic ⇒ Object
446
447
448
449
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 446
def opPanic
@state = PANICKED
raise PanicError.new(pc: @pc - 1)
end
|
#opPop(rd, rs) ⇒ Object
497
498
499
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 497
def opPop(rd, rs)
@gp[rd] = pop
end
|
#opPush(rd, rs) ⇒ Object
Format B opcodes (3 bytes: opcode + Rd + Rs)
493
494
495
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 493
def opPush(rd, rs)
push(@gp[rs])
end
|
#opRet ⇒ Object
438
439
440
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 438
def opRet
@pc = @gp[LR]
end
|
#opSizeOf(rd, ra, rb) ⇒ Object
859
860
861
862
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 859
def opSizeOf(rd, ra, rb)
@gp[rd] = 4 end
|
#opStackAlloc(rd) ⇒ Object
532
533
534
535
536
537
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 532
def opStackAlloc(rd)
size = fetch16
@sp -= size
raise FluxRuntimeError, 'Stack overflow' if @sp < 0
@gp[rd] = @sp
end
|
#opStore16(rs, rb) ⇒ Object
570
571
572
573
574
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 570
def opStore16(rs, rb)
off = fetchu16
addr = @gp[rb] + off
write_memory(addr, 2, @gp[rs])
end
|
#opStore32(rs, rb) ⇒ Object
576
577
578
579
580
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 576
def opStore32(rs, rb)
off = fetchu16
addr = @gp[rb] + off
write_memory(addr, 4, @gp[rs])
end
|
#opStore64(rs, rb) ⇒ Object
582
583
584
585
586
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 582
def opStore64(rs, rb)
off = fetchu16
addr = @gp[rb] + off
write_memory(addr, 8, @gp[rs])
end
|
#opStore8(rs, rb) ⇒ Object
564
565
566
567
568
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 564
def opStore8(rs, rb)
off = fetchu16
addr = @gp[rb] + off
write_memory(addr, 1, @gp[rs])
end
|
#opSwap(ra, rb) ⇒ Object
505
506
507
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 505
def opSwap(ra, rb)
@gp[ra], @gp[rb] = @gp[rb], @gp[ra]
end
|
#opTypeOf(rd, ra, rb) ⇒ Object
864
865
866
867
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 864
def opTypeOf(rd, ra, rb)
@gp[rd] = 0 end
|
#opUnreachable ⇒ Object
451
452
453
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 451
def opUnreachable
raise FluxRuntimeError.new('Unreachable instruction executed', opcode: :Unreachable, pc: @pc - 1)
end
|
#opVAdd(rd, ra, rb) ⇒ Object
921
922
923
924
925
926
927
928
929
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 921
def opVAdd(rd, ra, rb)
(0...256).each do |i|
a = @vr[ra][i].ord
b = @vr[rb][i].ord
result = (a + b) & 0xFF
@vr[rd][i] = result.chr
end
end
|
#opVDot(rd, ra, rb) ⇒ Object
941
942
943
944
945
946
947
948
949
950
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 941
def opVDot(rd, ra, rb)
sum = 0.0
(0...256).each do |i|
a = @vr[ra][i].ord
b = @vr[rb][i].ord
sum += a * b
end
@fp[rd] = sum
end
|
#opVLoad(rd, rb, off) ⇒ Object
907
908
909
910
911
912
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 907
def opVLoad(rd, rb, off)
addr = @gp[rb] + off
(0...256).each do |i|
@vr[rd][i] = read_memory_u8(addr + i) || 0
end
end
|
#opVMul(rd, ra, rb) ⇒ Object
931
932
933
934
935
936
937
938
939
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 931
def opVMul(rd, ra, rb)
(0...256).each do |i|
a = @vr[ra][i].ord
b = @vr[rb][i].ord
result = (a * b) & 0xFF
@vr[rd][i] = result.chr
end
end
|
#opVStore(rs, rb, off) ⇒ Object
914
915
916
917
918
919
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 914
def opVStore(rs, rb, off)
addr = @gp[rb] + off
@vr[rs].bytes.each_with_index do |byte, i|
write_memory(addr + i, 1, byte)
end
end
|
#opYield ⇒ Object
442
443
444
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 442
def opYield
@state = YIELDED
end
|
#pop ⇒ Object
270
271
272
273
274
275
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 270
def pop
raise FluxRuntimeError, 'Stack underflow' if @sp >= @memory_size
val = read_memory_i32(@sp)
@sp += 4
val
end
|
#push(value) ⇒ Object
264
265
266
267
268
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 264
def push(value)
@sp -= 4
raise FluxRuntimeError, 'Stack overflow' if @sp < 0
write_memory(@sp, 4, value)
end
|
#read_memory(addr, bytes) ⇒ Object
168
169
170
171
172
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 168
def read_memory(addr, bytes)
return nil if addr < 0 || addr + bytes > @memory_size
(0...bytes).map { |i| @memory[addr + i] }
end
|
#read_memory_i16(addr) ⇒ Object
201
202
203
204
205
206
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 201
def read_memory_i16(addr)
return nil if addr < 0 || addr + 2 > @memory_size
val = (@memory[addr] & 0xFF) | ((@memory[addr + 1] & 0xFF) << 8)
(val << 16) >> 16 end
|
#read_memory_i32(addr) ⇒ Object
180
181
182
183
184
185
186
187
188
189
190
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 180
def read_memory_i32(addr)
return nil if addr < 0 || addr + 4 > @memory_size
val = (@memory[addr] & 0xFF) |
((@memory[addr + 1] & 0xFF) << 8) |
((@memory[addr + 2] & 0xFF) << 16) |
((@memory[addr + 3] & 0xFF) << 24)
(val << 24) >> 24
end
|
#read_memory_u16(addr) ⇒ Object
208
209
210
211
212
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 208
def read_memory_u16(addr)
return nil if addr < 0 || addr + 2 > @memory_size
(@memory[addr] & 0xFF) | ((@memory[addr + 1] & 0xFF) << 8)
end
|
#read_memory_u32(addr) ⇒ Object
192
193
194
195
196
197
198
199
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 192
def read_memory_u32(addr)
return nil if addr < 0 || addr + 4 > @memory_size
(@memory[addr] & 0xFF) |
((@memory[addr + 1] & 0xFF) << 8) |
((@memory[addr + 2] & 0xFF) << 16) |
((@memory[addr + 3] & 0xFF) << 24)
end
|
#read_memory_u8(addr) ⇒ Object
174
175
176
177
178
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 174
def read_memory_u8(addr)
return nil if addr < 0 || addr >= @memory_size
@memory[addr] & 0xFF
end
|
#regs ⇒ Object
Get register values as hash
140
141
142
143
144
145
146
147
148
149
150
151
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 140
def regs
{
pc: @pc,
sp: @sp,
fp: @fp_reg,
flags: @flags,
state: @state,
gp: @gp.dup,
fp_regs: @fp.dup,
vr: @vr.dup
}
end
|
#reset ⇒ Object
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 124
def reset
@memory = [0] * @memory_size
@gp = [0] * 16
@fp = [0.0] * 16
@vr = Array.new(16) { "\x00" * 256 }
@pc = 0
@sp = @memory_size
@fp_reg = 0
@flags = 0
@state = RUNNING
@cycles = 0
@instruction_count = 0
self
end
|
#run(max_cycles: nil) ⇒ Object
Run the VM until halt/panic/yield or max_cycles reached
97
98
99
100
101
102
103
104
105
106
107
108
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 97
def run(max_cycles: nil)
@state = RUNNING
loop do
break if @state != RUNNING
break if max_cycles && @cycles >= max_cycles
step
end
self
end
|
#set_c(result) ⇒ Object
243
244
245
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 243
def set_c(result)
@flags = (@flags & ~FLAG_C) | (result < 0 ? FLAG_C : 0)
end
|
#set_s(result) ⇒ Object
239
240
241
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 239
def set_s(result)
@flags = (@flags & ~FLAG_S) | ((result < 0) ? FLAG_S : 0)
end
|
#set_v(result) ⇒ Object
247
248
249
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 247
def set_v(result)
@flags = (@flags & ~FLAG_V) | (result < 0 ? FLAG_V : 0)
end
|
#set_z(result) ⇒ Object
235
236
237
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 235
def set_z(result)
@flags = (@flags & ~FLAG_Z) | (result.zero? ? FLAG_Z : 0)
end
|
#set_zn(result) ⇒ Object
251
252
253
254
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 251
def set_zn(result)
set_z(result)
set_s(result)
end
|
#set_znv(result) ⇒ Object
256
257
258
259
260
261
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 256
def set_znv(result)
set_z(result)
set_s(result)
set_v(result)
set_c(result)
end
|
#stats ⇒ Object
159
160
161
162
163
164
165
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 159
def stats
{
cycles: @cycles,
instruction_count: @instruction_count,
memory_used: @pc
}
end
|
#step ⇒ Object
111
112
113
114
115
116
117
118
119
120
121
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 111
def step
raise FluxRuntimeError, 'VM not running' unless @state == RUNNING
opcode = fetch8
execute_opcode(opcode)
@instruction_count += 1
@cycles += 1
self
end
|
#write_memory(addr, bytes, value) ⇒ Object
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
# File 'lib/superinstance/flux-runtime/flux_vm.rb', line 215
def write_memory(addr, bytes, value)
return if addr < 0 || addr + bytes > @memory_size
case bytes
when 1
@memory[addr] = value & 0xFF
when 2
@memory[addr] = value & 0xFF
@memory[addr + 1] = (value >> 8) & 0xFF
when 4
@memory[addr] = value & 0xFF
@memory[addr + 1] = (value >> 8) & 0xFF
@memory[addr + 2] = (value >> 16) & 0xFF
@memory[addr + 3] = (value >> 24) & 0xFF
when 8
(0..7).each { |i| @memory[addr + i] = (value >> (i * 8)) & 0xFF }
end
end
|