superinstance-flux-runtime 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/lib/superinstance/flux-runtime/assembler.rb +305 -0
- data/lib/superinstance/flux-runtime/cli.rb +190 -0
- data/lib/superinstance/flux-runtime/disassembler.rb +197 -0
- data/lib/superinstance/flux-runtime/exceptions.rb +49 -0
- data/lib/superinstance/flux-runtime/flux_vm.rb +1020 -0
- data/lib/superinstance/flux-runtime/loader.rb +55 -0
- data/lib/superinstance/flux-runtime/opcode.rb +141 -0
- data/lib/superinstance/flux-runtime/runtime/agent.rb +128 -0
- data/lib/superinstance/flux-runtime/runtime/opcode.rb +57 -0
- data/lib/superinstance/flux-runtime/version.rb +8 -0
- data/lib/superinstance-flux-runtime.rb +22 -0
- metadata +70 -0
|
@@ -0,0 +1,1020 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'exceptions'
|
|
4
|
+
require_relative 'opcode'
|
|
5
|
+
|
|
6
|
+
module Flux
|
|
7
|
+
# Main FLUX ISA v3.0 Virtual Machine
|
|
8
|
+
#
|
|
9
|
+
# Register Model:
|
|
10
|
+
# - 16 GP registers (R0-R15, int32)
|
|
11
|
+
# - 16 FP registers (F0-F15, float64)
|
|
12
|
+
# - 16 VR registers (V0-V15, 256 bytes each)
|
|
13
|
+
# - PC, SP, FP_REG, FLAGS, STATE
|
|
14
|
+
#
|
|
15
|
+
# Memory: flat binary string, 64KB default
|
|
16
|
+
class FluxVM
|
|
17
|
+
include OpcodeRegistry
|
|
18
|
+
|
|
19
|
+
# Register aliases per ISA
|
|
20
|
+
RV = 8 # Return value
|
|
21
|
+
A0 = 9 # First argument
|
|
22
|
+
A1 = 10 # Second argument
|
|
23
|
+
SP_REG = 11 # Stack pointer
|
|
24
|
+
FP_REG = 12 # Frame pointer
|
|
25
|
+
FLAGS = 13 # Flags register
|
|
26
|
+
TP = 14 # Temporary
|
|
27
|
+
LR = 15 # Link register
|
|
28
|
+
|
|
29
|
+
# VM states
|
|
30
|
+
RUNNING = :running
|
|
31
|
+
HALTED = :halted
|
|
32
|
+
PANICKED = :panicked
|
|
33
|
+
YIELDED = :yielded
|
|
34
|
+
|
|
35
|
+
# Flag bits
|
|
36
|
+
FLAG_Z = 1 << 0
|
|
37
|
+
FLAG_S = 1 << 1
|
|
38
|
+
FLAG_C = 1 << 2
|
|
39
|
+
FLAG_V = 1 << 3
|
|
40
|
+
|
|
41
|
+
attr_accessor :gp, :fp, :vr
|
|
42
|
+
attr_accessor :pc, :sp, :fp_reg, :flags, :state
|
|
43
|
+
attr_reader :memory_size, :memory
|
|
44
|
+
|
|
45
|
+
# Opcode registry for runtime-registered opcodes
|
|
46
|
+
@@opcode_registry = {}
|
|
47
|
+
@@runtime_opcodes = {}
|
|
48
|
+
|
|
49
|
+
class << self
|
|
50
|
+
attr_accessor :opcode_registry, :runtime_opcodes
|
|
51
|
+
|
|
52
|
+
def register_opcode(opcode_class)
|
|
53
|
+
@@runtime_opcodes[opcode_class.opcode_id] = opcode_class
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def initialize(memory_size: 65536)
|
|
58
|
+
@memory_size = memory_size
|
|
59
|
+
@memory = [0] * memory_size # Simpler Array of integers
|
|
60
|
+
|
|
61
|
+
# General purpose registers (int32)
|
|
62
|
+
@gp = [0] * 16
|
|
63
|
+
|
|
64
|
+
# Floating point registers (float64)
|
|
65
|
+
@fp = [0.0] * 16
|
|
66
|
+
|
|
67
|
+
# Vector registers (256 bytes each as binary string)
|
|
68
|
+
@vr = Array.new(16) { "\x00" * 256 }
|
|
69
|
+
|
|
70
|
+
# System registers
|
|
71
|
+
@pc = 0
|
|
72
|
+
@sp = memory_size # Stack grows down
|
|
73
|
+
@fp_reg = 0
|
|
74
|
+
@flags = 0
|
|
75
|
+
@state = RUNNING
|
|
76
|
+
|
|
77
|
+
# Stats
|
|
78
|
+
@cycles = 0
|
|
79
|
+
@instruction_count = 0
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Load bytecode into memory starting at address 0
|
|
83
|
+
def load(bytecode_string)
|
|
84
|
+
bytecode = bytecode_string.dup.force_encoding('BINARY')
|
|
85
|
+
raise FluxRuntimeError, 'Bytecode too large' if bytecode.bytesize > @memory_size
|
|
86
|
+
|
|
87
|
+
bytecode.bytes.each_with_index do |byte, i|
|
|
88
|
+
@memory[i] = byte
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
@pc = 0
|
|
92
|
+
@sp = @memory_size
|
|
93
|
+
self
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Run the VM until halt/panic/yield or max_cycles reached
|
|
97
|
+
def run(max_cycles: nil)
|
|
98
|
+
@state = RUNNING
|
|
99
|
+
|
|
100
|
+
loop do
|
|
101
|
+
break if @state != RUNNING
|
|
102
|
+
break if max_cycles && @cycles >= max_cycles
|
|
103
|
+
|
|
104
|
+
step
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
self
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Execute one instruction
|
|
111
|
+
def step
|
|
112
|
+
raise FluxRuntimeError, 'VM not running' unless @state == RUNNING
|
|
113
|
+
|
|
114
|
+
opcode = fetch8
|
|
115
|
+
execute_opcode(opcode)
|
|
116
|
+
|
|
117
|
+
@instruction_count += 1
|
|
118
|
+
@cycles += 1
|
|
119
|
+
|
|
120
|
+
self
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Reset VM state
|
|
124
|
+
def reset
|
|
125
|
+
@memory = [0] * @memory_size
|
|
126
|
+
@gp = [0] * 16
|
|
127
|
+
@fp = [0.0] * 16
|
|
128
|
+
@vr = Array.new(16) { "\x00" * 256 }
|
|
129
|
+
@pc = 0
|
|
130
|
+
@sp = @memory_size
|
|
131
|
+
@fp_reg = 0
|
|
132
|
+
@flags = 0
|
|
133
|
+
@state = RUNNING
|
|
134
|
+
@cycles = 0
|
|
135
|
+
@instruction_count = 0
|
|
136
|
+
self
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Get register values as hash
|
|
140
|
+
def regs
|
|
141
|
+
{
|
|
142
|
+
pc: @pc,
|
|
143
|
+
sp: @sp,
|
|
144
|
+
fp: @fp_reg,
|
|
145
|
+
flags: @flags,
|
|
146
|
+
state: @state,
|
|
147
|
+
gp: @gp.dup,
|
|
148
|
+
fp_regs: @fp.dup,
|
|
149
|
+
vr: @vr.dup
|
|
150
|
+
}
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Current VM state
|
|
154
|
+
def state
|
|
155
|
+
@state
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Execution statistics
|
|
159
|
+
def stats
|
|
160
|
+
{
|
|
161
|
+
cycles: @cycles,
|
|
162
|
+
instruction_count: @instruction_count,
|
|
163
|
+
memory_used: @pc
|
|
164
|
+
}
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Memory read helpers
|
|
168
|
+
def read_memory(addr, bytes)
|
|
169
|
+
return nil if addr < 0 || addr + bytes > @memory_size
|
|
170
|
+
|
|
171
|
+
(0...bytes).map { |i| @memory[addr + i] }
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def read_memory_u8(addr)
|
|
175
|
+
return nil if addr < 0 || addr >= @memory_size
|
|
176
|
+
|
|
177
|
+
@memory[addr] & 0xFF
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def read_memory_i32(addr)
|
|
181
|
+
return nil if addr < 0 || addr + 4 > @memory_size
|
|
182
|
+
|
|
183
|
+
val = (@memory[addr] & 0xFF) |
|
|
184
|
+
((@memory[addr + 1] & 0xFF) << 8) |
|
|
185
|
+
((@memory[addr + 2] & 0xFF) << 16) |
|
|
186
|
+
((@memory[addr + 3] & 0xFF) << 24)
|
|
187
|
+
|
|
188
|
+
# Sign extend
|
|
189
|
+
(val << 24) >> 24
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def read_memory_u32(addr)
|
|
193
|
+
return nil if addr < 0 || addr + 4 > @memory_size
|
|
194
|
+
|
|
195
|
+
(@memory[addr] & 0xFF) |
|
|
196
|
+
((@memory[addr + 1] & 0xFF) << 8) |
|
|
197
|
+
((@memory[addr + 2] & 0xFF) << 16) |
|
|
198
|
+
((@memory[addr + 3] & 0xFF) << 24)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def read_memory_i16(addr)
|
|
202
|
+
return nil if addr < 0 || addr + 2 > @memory_size
|
|
203
|
+
|
|
204
|
+
val = (@memory[addr] & 0xFF) | ((@memory[addr + 1] & 0xFF) << 8)
|
|
205
|
+
(val << 16) >> 16 # Sign extend
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def read_memory_u16(addr)
|
|
209
|
+
return nil if addr < 0 || addr + 2 > @memory_size
|
|
210
|
+
|
|
211
|
+
(@memory[addr] & 0xFF) | ((@memory[addr + 1] & 0xFF) << 8)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Memory write helpers
|
|
215
|
+
def write_memory(addr, bytes, value)
|
|
216
|
+
return if addr < 0 || addr + bytes > @memory_size
|
|
217
|
+
|
|
218
|
+
case bytes
|
|
219
|
+
when 1
|
|
220
|
+
@memory[addr] = value & 0xFF
|
|
221
|
+
when 2
|
|
222
|
+
@memory[addr] = value & 0xFF
|
|
223
|
+
@memory[addr + 1] = (value >> 8) & 0xFF
|
|
224
|
+
when 4
|
|
225
|
+
@memory[addr] = value & 0xFF
|
|
226
|
+
@memory[addr + 1] = (value >> 8) & 0xFF
|
|
227
|
+
@memory[addr + 2] = (value >> 16) & 0xFF
|
|
228
|
+
@memory[addr + 3] = (value >> 24) & 0xFF
|
|
229
|
+
when 8
|
|
230
|
+
(0..7).each { |i| @memory[addr + i] = (value >> (i * 8)) & 0xFF }
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Flag setting helpers
|
|
235
|
+
def set_z(result)
|
|
236
|
+
@flags = (@flags & ~FLAG_Z) | (result.zero? ? FLAG_Z : 0)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def set_s(result)
|
|
240
|
+
@flags = (@flags & ~FLAG_S) | ((result < 0) ? FLAG_S : 0)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def set_c(result)
|
|
244
|
+
@flags = (@flags & ~FLAG_C) | (result < 0 ? FLAG_C : 0)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def set_v(result)
|
|
248
|
+
@flags = (@flags & ~FLAG_V) | (result < 0 ? FLAG_V : 0)
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def set_zn(result)
|
|
252
|
+
set_z(result)
|
|
253
|
+
set_s(result)
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def set_znv(result)
|
|
257
|
+
set_z(result)
|
|
258
|
+
set_s(result)
|
|
259
|
+
set_v(result)
|
|
260
|
+
set_c(result)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
# Stack helpers
|
|
264
|
+
def push(value)
|
|
265
|
+
@sp -= 4
|
|
266
|
+
raise FluxRuntimeError, 'Stack overflow' if @sp < 0
|
|
267
|
+
write_memory(@sp, 4, value)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def pop
|
|
271
|
+
raise FluxRuntimeError, 'Stack underflow' if @sp >= @memory_size
|
|
272
|
+
val = read_memory_i32(@sp)
|
|
273
|
+
@sp += 4
|
|
274
|
+
val
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
private
|
|
278
|
+
|
|
279
|
+
def fetch8
|
|
280
|
+
val = read_memory_u8(@pc)
|
|
281
|
+
@pc += 1
|
|
282
|
+
val
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def fetch16
|
|
286
|
+
lo = fetch8
|
|
287
|
+
hi = fetch8
|
|
288
|
+
(lo | (hi << 8)).tap { |v| (v << 16) >> 16 } # Sign-extend
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def fetchu16
|
|
292
|
+
lo = fetch8
|
|
293
|
+
hi = fetch8
|
|
294
|
+
lo | (hi << 8)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def fetchu32
|
|
298
|
+
lo = fetch16
|
|
299
|
+
hi = fetch16
|
|
300
|
+
lo | (hi << 16)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def fetch32
|
|
304
|
+
val = fetchu32
|
|
305
|
+
(val << 24) >> 24
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def execute_opcode(opcode)
|
|
309
|
+
# Check runtime opcodes first
|
|
310
|
+
if @@runtime_opcodes[opcode]
|
|
311
|
+
@@runtime_opcodes[opcode].execute(self)
|
|
312
|
+
return
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
case opcode
|
|
316
|
+
# Format A: opcode only (1 byte)
|
|
317
|
+
when 0x00 then opHalt
|
|
318
|
+
when 0x01 then opNop
|
|
319
|
+
when 0x02 then opRet
|
|
320
|
+
when 0x08 then opYield
|
|
321
|
+
when 0x09 then opPanic
|
|
322
|
+
when 0x0A then opUnreachable
|
|
323
|
+
|
|
324
|
+
# Format B: opcode + Rd + Rs (3 bytes)
|
|
325
|
+
when 0x10 then rd = fetch8; rs = fetch8; opPush(rd, rs)
|
|
326
|
+
when 0x11 then rd = fetch8; rs = fetch8; opPop(rd, rs)
|
|
327
|
+
when 0x12 then rd = fetch8; rs = fetch8; opDup(rd, rs)
|
|
328
|
+
when 0x13 then ra = fetch8; rb = fetch8; opSwap(ra, rb)
|
|
329
|
+
when 0x20 then rd = fetch8; rs = fetch8; opIMov(rd, rs)
|
|
330
|
+
when 0x40 then rd = fetch8; rs = fetch8; opFMov(rd, rs)
|
|
331
|
+
|
|
332
|
+
# Format C: opcode + Rd + Ra + Rb (4 bytes)
|
|
333
|
+
when 0x21 then rd = fetch8; ra = fetch8; rb = fetch8; opIAdd(rd, ra, rb)
|
|
334
|
+
when 0x22 then rd = fetch8; ra = fetch8; rb = fetch8; opISub(rd, ra, rb)
|
|
335
|
+
when 0x23 then rd = fetch8; ra = fetch8; rb = fetch8; opIMul(rd, ra, rb)
|
|
336
|
+
when 0x24 then rd = fetch8; ra = fetch8; rb = fetch8; opIDiv(rd, ra, rb)
|
|
337
|
+
when 0x25 then rd = fetch8; ra = fetch8; rb = fetch8; opIMod(rd, ra, rb)
|
|
338
|
+
when 0x26 then rd = fetch8; ra = fetch8; rb = fetch8; opINeg(rd, ra, rb)
|
|
339
|
+
when 0x27 then rd = fetch8; ra = fetch8; rb = fetch8; opIAbs(rd, ra, rb)
|
|
340
|
+
when 0x28 then rd = fetch8; opIInc(rd)
|
|
341
|
+
when 0x29 then rd = fetch8; opIDec(rd)
|
|
342
|
+
when 0x2A then rd = fetch8; ra = fetch8; rb = fetch8; opIMin(rd, ra, rb)
|
|
343
|
+
when 0x2B then rd = fetch8; ra = fetch8; rb = fetch8; opIMax(rd, ra, rb)
|
|
344
|
+
when 0x2C then rd = fetch8; ra = fetch8; rb = fetch8; opIAnd(rd, ra, rb)
|
|
345
|
+
when 0x2D then rd = fetch8; ra = fetch8; rb = fetch8; opIOr(rd, ra, rb)
|
|
346
|
+
when 0x2E then rd = fetch8; ra = fetch8; rb = fetch8; opIXor(rd, ra, rb)
|
|
347
|
+
when 0x2F then rd = fetch8; ra = fetch8; rb = fetch8; opIShl(rd, ra, rb)
|
|
348
|
+
when 0x30 then rd = fetch8; ra = fetch8; rb = fetch8; opIShr(rd, ra, rb)
|
|
349
|
+
when 0x31 then rd = fetch8; ra = fetch8; rb = fetch8; opINot(rd, ra, rb)
|
|
350
|
+
when 0x32 then rd = fetch8; ra = fetch8; rb = fetch8; opICmpEq(rd, ra, rb)
|
|
351
|
+
when 0x33 then rd = fetch8; ra = fetch8; rb = fetch8; opICmpNe(rd, ra, rb)
|
|
352
|
+
when 0x34 then rd = fetch8; ra = fetch8; rb = fetch8; opICmpLt(rd, ra, rb)
|
|
353
|
+
when 0x35 then rd = fetch8; ra = fetch8; rb = fetch8; opICmpLe(rd, ra, rb)
|
|
354
|
+
when 0x36 then rd = fetch8; ra = fetch8; rb = fetch8; opICmpGt(rd, ra, rb)
|
|
355
|
+
when 0x37 then rd = fetch8; ra = fetch8; rb = fetch8; opICmpGe(rd, ra, rb)
|
|
356
|
+
|
|
357
|
+
# Float Arithmetic
|
|
358
|
+
when 0x41 then rd = fetch8; ra = fetch8; rb = fetch8; opFAdd(rd, ra, rb)
|
|
359
|
+
when 0x42 then rd = fetch8; ra = fetch8; rb = fetch8; opFSub(rd, ra, rb)
|
|
360
|
+
when 0x43 then rd = fetch8; ra = fetch8; rb = fetch8; opFMul(rd, ra, rb)
|
|
361
|
+
when 0x44 then rd = fetch8; ra = fetch8; rb = fetch8; opFDiv(rd, ra, rb)
|
|
362
|
+
when 0x45 then rd = fetch8; ra = fetch8; rb = fetch8; opFMod(rd, ra, rb)
|
|
363
|
+
when 0x46 then rd = fetch8; ra = fetch8; rb = fetch8; opFNeg(rd, ra, rb)
|
|
364
|
+
when 0x47 then rd = fetch8; ra = fetch8; rb = fetch8; opFAbs(rd, ra, rb)
|
|
365
|
+
when 0x48 then rd = fetch8; ra = fetch8; rb = fetch8; opFSqrt(rd, ra, rb)
|
|
366
|
+
when 0x49 then rd = fetch8; ra = fetch8; rb = fetch8; opFFloor(rd, ra, rb)
|
|
367
|
+
when 0x4A then rd = fetch8; ra = fetch8; rb = fetch8; opFCeil(rd, ra, rb)
|
|
368
|
+
when 0x4B then rd = fetch8; ra = fetch8; rb = fetch8; opFRound(rd, ra, rb)
|
|
369
|
+
when 0x4C then rd = fetch8; ra = fetch8; rb = fetch8; opFMin(rd, ra, rb)
|
|
370
|
+
when 0x4D then rd = fetch8; ra = fetch8; rb = fetch8; opFMax(rd, ra, rb)
|
|
371
|
+
when 0x4E then rd = fetch8; ra = fetch8; rb = fetch8; opFSin(rd, ra, rb)
|
|
372
|
+
when 0x4F then rd = fetch8; ra = fetch8; rb = fetch8; opFCos(rd, ra, rb)
|
|
373
|
+
when 0x50 then rd = fetch8; ra = fetch8; rb = fetch8; opFExp(rd, ra, rb)
|
|
374
|
+
when 0x51 then rd = fetch8; ra = fetch8; rb = fetch8; opFLog(rd, ra, rb)
|
|
375
|
+
when 0x52 then rd = fetch8; ra = fetch8; rb = fetch8; opFClamp(rd, ra, rb)
|
|
376
|
+
when 0x53 then rd = fetch8; ra = fetch8; rb = fetch8; opFLerp(rd, ra, rb)
|
|
377
|
+
when 0x54 then rd = fetch8; ra = fetch8; rb = fetch8; opFCmpEq(rd, ra, rb)
|
|
378
|
+
when 0x55 then rd = fetch8; ra = fetch8; rb = fetch8; opFCmpNe(rd, ra, rb)
|
|
379
|
+
when 0x56 then rd = fetch8; ra = fetch8; rb = fetch8; opFCmpLt(rd, ra, rb)
|
|
380
|
+
when 0x57 then rd = fetch8; ra = fetch8; rb = fetch8; opFCmpLe(rd, ra, rb)
|
|
381
|
+
when 0x58 then rd = fetch8; ra = fetch8; rb = fetch8; opFCmpGt(rd, ra, rb)
|
|
382
|
+
when 0x59 then rd = fetch8; ra = fetch8; rb = fetch8; opFCmpGe(rd, ra, rb)
|
|
383
|
+
|
|
384
|
+
# Conversions
|
|
385
|
+
when 0x60 then rd = fetch8; ra = fetch8; rb = fetch8; opIToF(rd, ra, rb)
|
|
386
|
+
when 0x61 then rd = fetch8; ra = fetch8; rb = fetch8; opFToI(rd, ra, rb)
|
|
387
|
+
when 0x62 then rd = fetch8; ra = fetch8; rb = fetch8; opBToI(rd, ra, rb)
|
|
388
|
+
when 0x63 then rd = fetch8; ra = fetch8; rb = fetch8; opIToB(rd, ra, rb)
|
|
389
|
+
|
|
390
|
+
# Type/Meta
|
|
391
|
+
when 0x90 then rd = fetch8; ra = fetch8; rb = fetch8; opCast(rd, ra, rb)
|
|
392
|
+
when 0x91 then rd = fetch8; ra = fetch8; rb = fetch8; opSizeOf(rd, ra, rb)
|
|
393
|
+
when 0x92 then rd = fetch8; ra = fetch8; rb = fetch8; opTypeOf(rd, ra, rb)
|
|
394
|
+
|
|
395
|
+
# Bitwise
|
|
396
|
+
when 0xA0 then rd = fetch8; ra = fetch8; rb = fetch8; opBAnd(rd, ra, rb)
|
|
397
|
+
when 0xA1 then rd = fetch8; ra = fetch8; rb = fetch8; opBOr(rd, ra, rb)
|
|
398
|
+
when 0xA2 then rd = fetch8; ra = fetch8; rb = fetch8; opBXor(rd, ra, rb)
|
|
399
|
+
when 0xA3 then rd = fetch8; ra = fetch8; rb = fetch8; opBShl(rd, ra, rb)
|
|
400
|
+
when 0xA4 then rd = fetch8; ra = fetch8; rb = fetch8; opBShr(rd, ra, rb)
|
|
401
|
+
when 0xA5 then rd = fetch8; ra = fetch8; rb = fetch8; opBNot(rd, ra, rb)
|
|
402
|
+
|
|
403
|
+
# Vector
|
|
404
|
+
when 0xB0 then rd = fetch8; rb = fetch8; off = fetchu16; opVLoad(rd, rb, off)
|
|
405
|
+
when 0xB1 then rs = fetch8; rb = fetch8; off = fetchu16; opVStore(rs, rb, off)
|
|
406
|
+
when 0xB2 then rd = fetch8; ra = fetch8; rb = fetch8; opVAdd(rd, ra, rb)
|
|
407
|
+
when 0xB3 then rd = fetch8; ra = fetch8; rb = fetch8; opVMul(rd, ra, rb)
|
|
408
|
+
when 0xB4 then rd = fetch8; ra = fetch8; rb = fetch8; opVDot(rd, ra, rb)
|
|
409
|
+
|
|
410
|
+
# Memory (Format E)
|
|
411
|
+
when 0x70 then rd = fetch8; rb = fetch8; off = fetchu16; opLoad8(rd, rb)
|
|
412
|
+
when 0x71 then rd = fetch8; rb = fetch8; off = fetchu16; opLoad16(rd, rb)
|
|
413
|
+
when 0x72 then rd = fetch8; rb = fetch8; off = fetchu16; opLoad32(rd, rb)
|
|
414
|
+
when 0x73 then rd = fetch8; rb = fetch8; off = fetchu16; opLoad64(rd, rb)
|
|
415
|
+
when 0x74 then rs = fetch8; rb = fetch8; off = fetchu16; opStore8(rs, rb)
|
|
416
|
+
when 0x75 then rs = fetch8; rb = fetch8; off = fetchu16; opStore16(rs, rb)
|
|
417
|
+
when 0x76 then rs = fetch8; rb = fetch8; off = fetchu16; opStore32(rs, rb)
|
|
418
|
+
when 0x77 then rs = fetch8; rb = fetch8; off = fetchu16; opStore64(rs, rb)
|
|
419
|
+
when 0x78 then rd = fetch8; rb = fetch8; off = fetchu16; opLoadAddr(rd, rb)
|
|
420
|
+
when 0x79 then rd = fetch8; opStackAlloc(rd)
|
|
421
|
+
|
|
422
|
+
else
|
|
423
|
+
raise UnknownOpcodeError.new(opcode, @pc - 1)
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
public
|
|
428
|
+
|
|
429
|
+
# Format A opcodes (1 byte)
|
|
430
|
+
def opHalt
|
|
431
|
+
@state = HALTED
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def opNop
|
|
435
|
+
# No operation
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def opRet
|
|
439
|
+
@pc = @gp[LR]
|
|
440
|
+
end
|
|
441
|
+
|
|
442
|
+
def opYield
|
|
443
|
+
@state = YIELDED
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
def opPanic
|
|
447
|
+
@state = PANICKED
|
|
448
|
+
raise PanicError.new(pc: @pc - 1)
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def opUnreachable
|
|
452
|
+
raise FluxRuntimeError.new('Unreachable instruction executed', opcode: :Unreachable, pc: @pc - 1)
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
# Format G opcodes (variable)
|
|
456
|
+
def opJump
|
|
457
|
+
length = fetch8
|
|
458
|
+
offset = fetch16
|
|
459
|
+
@pc = @pc &+ offset
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def opJumpIf
|
|
463
|
+
length = fetch8
|
|
464
|
+
rd = fetch8
|
|
465
|
+
offset = fetch16
|
|
466
|
+
@pc = @pc &+ offset if @gp[rd] != 0
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
def opJumpIfNot
|
|
470
|
+
length = fetch8
|
|
471
|
+
rd = fetch8
|
|
472
|
+
offset = fetch16
|
|
473
|
+
@pc = @pc &+ offset if @gp[rd] == 0
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
def opCall
|
|
477
|
+
length = fetch8
|
|
478
|
+
func_idx = fetchu16
|
|
479
|
+
push(@pc)
|
|
480
|
+
@gp[LR] = @pc
|
|
481
|
+
@pc = func_idx
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def opCallIndirect
|
|
485
|
+
length = fetch8
|
|
486
|
+
reg = fetch8
|
|
487
|
+
push(@pc)
|
|
488
|
+
@gp[LR] = @pc
|
|
489
|
+
@pc = @gp[reg]
|
|
490
|
+
end
|
|
491
|
+
|
|
492
|
+
# Format B opcodes (3 bytes: opcode + Rd + Rs)
|
|
493
|
+
def opPush(rd, rs)
|
|
494
|
+
push(@gp[rs])
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def opPop(rd, rs)
|
|
498
|
+
@gp[rd] = pop
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def opDup(rd, rs)
|
|
502
|
+
@gp[rd] = @gp[rs]
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
def opSwap(ra, rb)
|
|
506
|
+
@gp[ra], @gp[rb] = @gp[rb], @gp[ra]
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def opIMov(rd, rs)
|
|
510
|
+
@gp[rd] = @gp[rs]
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
def opFMov(rd, rs)
|
|
514
|
+
@fp[rd] = @fp[rs]
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
# Format D opcodes (4 bytes: opcode + Rd + imm16)
|
|
518
|
+
def opIInc(rd)
|
|
519
|
+
imm = fetch16
|
|
520
|
+
result = @gp[rd] + imm
|
|
521
|
+
set_znv(result)
|
|
522
|
+
@gp[rd] = result
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
def opIDec(rd)
|
|
526
|
+
imm = fetch16
|
|
527
|
+
result = @gp[rd] - imm
|
|
528
|
+
set_znv(result)
|
|
529
|
+
@gp[rd] = result
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
def opStackAlloc(rd)
|
|
533
|
+
size = fetch16
|
|
534
|
+
@sp -= size
|
|
535
|
+
raise FluxRuntimeError, 'Stack overflow' if @sp < 0
|
|
536
|
+
@gp[rd] = @sp
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
# Format E opcodes (5 bytes: opcode + Rd + Rbase + off16)
|
|
540
|
+
def opLoad8(rd, rb)
|
|
541
|
+
off = fetchu16
|
|
542
|
+
addr = @gp[rb] + off
|
|
543
|
+
@gp[rd] = read_memory_u8(addr) || 0
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
def opLoad16(rd, rb)
|
|
547
|
+
off = fetchu16
|
|
548
|
+
addr = @gp[rb] + off
|
|
549
|
+
@gp[rd] = read_memory_u16(addr) || 0
|
|
550
|
+
end
|
|
551
|
+
|
|
552
|
+
def opLoad32(rd, rb)
|
|
553
|
+
off = fetchu16
|
|
554
|
+
addr = @gp[rb] + off
|
|
555
|
+
@gp[rd] = read_memory_i32(addr) || 0
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
def opLoad64(rd, rb)
|
|
559
|
+
off = fetchu16
|
|
560
|
+
addr = @gp[rb] + off
|
|
561
|
+
@gp[rd] = read_memory_u32(addr) || 0
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
def opStore8(rs, rb)
|
|
565
|
+
off = fetchu16
|
|
566
|
+
addr = @gp[rb] + off
|
|
567
|
+
write_memory(addr, 1, @gp[rs])
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
def opStore16(rs, rb)
|
|
571
|
+
off = fetchu16
|
|
572
|
+
addr = @gp[rb] + off
|
|
573
|
+
write_memory(addr, 2, @gp[rs])
|
|
574
|
+
end
|
|
575
|
+
|
|
576
|
+
def opStore32(rs, rb)
|
|
577
|
+
off = fetchu16
|
|
578
|
+
addr = @gp[rb] + off
|
|
579
|
+
write_memory(addr, 4, @gp[rs])
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
def opStore64(rs, rb)
|
|
583
|
+
off = fetchu16
|
|
584
|
+
addr = @gp[rb] + off
|
|
585
|
+
write_memory(addr, 8, @gp[rs])
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
def opLoadAddr(rd, rb)
|
|
589
|
+
off = fetchu16
|
|
590
|
+
@gp[rd] = @gp[rb] + off
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
# Integer Arithmetic (Format C)
|
|
594
|
+
def opIAdd(rd, ra, rb)
|
|
595
|
+
result = @gp[ra] + @gp[rb]
|
|
596
|
+
set_znv(result)
|
|
597
|
+
@gp[rd] = result
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
def opISub(rd, ra, rb)
|
|
601
|
+
result = @gp[ra] - @gp[rb]
|
|
602
|
+
set_znv(result)
|
|
603
|
+
@gp[rd] = result
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
def opIMul(rd, ra, rb)
|
|
607
|
+
result = @gp[ra] * @gp[rb]
|
|
608
|
+
set_znv(result)
|
|
609
|
+
@gp[rd] = result
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
def opIDiv(rd, ra, rb)
|
|
613
|
+
raise DivideByZeroError.new(@pc - 1) if @gp[rb] == 0
|
|
614
|
+
result = @gp[ra] / @gp[rb]
|
|
615
|
+
set_znv(result)
|
|
616
|
+
@gp[rd] = result
|
|
617
|
+
end
|
|
618
|
+
|
|
619
|
+
def opIMod(rd, ra, rb)
|
|
620
|
+
raise DivideByZeroError.new(@pc - 1) if @gp[rb] == 0
|
|
621
|
+
result = @gp[ra] % @gp[rb]
|
|
622
|
+
set_znv(result)
|
|
623
|
+
@gp[rd] = result
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
def opINeg(rd, ra, rb)
|
|
627
|
+
result = -@gp[ra]
|
|
628
|
+
set_zn(result)
|
|
629
|
+
@gp[rd] = result
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
def opIAbs(rd, ra, rb)
|
|
633
|
+
result = @gp[ra].abs
|
|
634
|
+
set_zn(result)
|
|
635
|
+
@gp[rd] = result
|
|
636
|
+
end
|
|
637
|
+
|
|
638
|
+
def opIMin(rd, ra, rb)
|
|
639
|
+
result = [@gp[ra], @gp[rb]].min
|
|
640
|
+
set_zn(result)
|
|
641
|
+
@gp[rd] = result
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
def opIMax(rd, ra, rb)
|
|
645
|
+
result = [@gp[ra], @gp[rb]].max
|
|
646
|
+
set_zn(result)
|
|
647
|
+
@gp[rd] = result
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
def opIAnd(rd, ra, rb)
|
|
651
|
+
result = @gp[ra] & @gp[rb]
|
|
652
|
+
set_zn(result)
|
|
653
|
+
@gp[rd] = result
|
|
654
|
+
end
|
|
655
|
+
|
|
656
|
+
def opIOr(rd, ra, rb)
|
|
657
|
+
result = @gp[ra] | @gp[rb]
|
|
658
|
+
set_zn(result)
|
|
659
|
+
@gp[rd] = result
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
def opIXor(rd, ra, rb)
|
|
663
|
+
result = @gp[ra] ^ @gp[rb]
|
|
664
|
+
set_zn(result)
|
|
665
|
+
@gp[rd] = result
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
def opIShl(rd, ra, rb)
|
|
669
|
+
result = @gp[ra] << (@gp[rb] & 31)
|
|
670
|
+
set_z(result)
|
|
671
|
+
set_c((@gp[ra] << (@gp[rb] & 31)) != result ? 1 : 0)
|
|
672
|
+
@gp[rd] = result
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
def opIShr(rd, ra, rb)
|
|
676
|
+
result = @gp[ra] >> (@gp[rb] & 31)
|
|
677
|
+
set_z(result)
|
|
678
|
+
@gp[rd] = result
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
def opINot(rd, ra, rb)
|
|
682
|
+
result = ~@gp[ra]
|
|
683
|
+
set_zn(result)
|
|
684
|
+
@gp[rd] = result
|
|
685
|
+
end
|
|
686
|
+
|
|
687
|
+
# Integer Comparisons
|
|
688
|
+
def opICmpEq(rd, ra, rb)
|
|
689
|
+
@gp[rd] = (@gp[ra] == @gp[rb]) ? 1 : 0
|
|
690
|
+
set_z(@gp[rd])
|
|
691
|
+
end
|
|
692
|
+
|
|
693
|
+
def opICmpNe(rd, ra, rb)
|
|
694
|
+
@gp[rd] = (@gp[ra] != @gp[rb]) ? 1 : 0
|
|
695
|
+
set_z(1 - @gp[rd])
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
def opICmpLt(rd, ra, rb)
|
|
699
|
+
@gp[rd] = (@gp[ra] < @gp[rb]) ? 1 : 0
|
|
700
|
+
set_z(@gp[rd])
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
def opICmpLe(rd, ra, rb)
|
|
704
|
+
@gp[rd] = (@gp[ra] <= @gp[rb]) ? 1 : 0
|
|
705
|
+
set_z(@gp[rd])
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
def opICmpGt(rd, ra, rb)
|
|
709
|
+
@gp[rd] = (@gp[ra] > @gp[rb]) ? 1 : 0
|
|
710
|
+
set_z(@gp[rd])
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
def opICmpGe(rd, ra, rb)
|
|
714
|
+
@gp[rd] = (@gp[ra] >= @gp[rb]) ? 1 : 0
|
|
715
|
+
set_z(@gp[rd])
|
|
716
|
+
end
|
|
717
|
+
|
|
718
|
+
# Float Arithmetic
|
|
719
|
+
def opFAdd(rd, ra, rb)
|
|
720
|
+
result = @fp[ra] + @fp[rb]
|
|
721
|
+
@fp[rd] = result
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
def opFSub(rd, ra, rb)
|
|
725
|
+
result = @fp[ra] - @fp[rb]
|
|
726
|
+
@fp[rd] = result
|
|
727
|
+
end
|
|
728
|
+
|
|
729
|
+
def opFMul(rd, ra, rb)
|
|
730
|
+
result = @fp[ra] * @fp[rb]
|
|
731
|
+
@fp[rd] = result
|
|
732
|
+
end
|
|
733
|
+
|
|
734
|
+
def opFDiv(rd, ra, rb)
|
|
735
|
+
result = @fp[ra] / @fp[rb]
|
|
736
|
+
@fp[rd] = result
|
|
737
|
+
end
|
|
738
|
+
|
|
739
|
+
def opFMod(rd, ra, rb)
|
|
740
|
+
result = @fp[ra] % @fp[rb]
|
|
741
|
+
@fp[rd] = result
|
|
742
|
+
end
|
|
743
|
+
|
|
744
|
+
def opFNeg(rd, ra, rb)
|
|
745
|
+
@fp[rd] = -@fp[ra]
|
|
746
|
+
end
|
|
747
|
+
|
|
748
|
+
def opFAbs(rd, ra, rb)
|
|
749
|
+
@fp[rd] = @fp[ra].abs
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
def opFSqrt(rd, ra, rb)
|
|
753
|
+
@fp[rd] = Math.sqrt(@fp[ra])
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
def opFFloor(rd, ra, rb)
|
|
757
|
+
@fp[rd] = @fp[ra].floor
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
def opFCeil(rd, ra, rb)
|
|
761
|
+
@fp[rd] = @fp[ra].ceil
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
def opFRound(rd, ra, rb)
|
|
765
|
+
@fp[rd] = @fp[ra].round
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
def opFMin(rd, ra, rb)
|
|
769
|
+
@fp[rd] = [@fp[ra], @fp[rb]].min
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
def opFMax(rd, ra, rb)
|
|
773
|
+
@fp[rd] = [@fp[ra], @fp[rb]].max
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
def opFSin(rd, ra, rb)
|
|
777
|
+
@fp[rd] = Math.sin(@fp[ra])
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
def opFCos(rd, ra, rb)
|
|
781
|
+
@fp[rd] = Math.cos(@fp[ra])
|
|
782
|
+
end
|
|
783
|
+
|
|
784
|
+
def opFExp(rd, ra, rb)
|
|
785
|
+
@fp[rd] = Math.exp(@fp[ra])
|
|
786
|
+
end
|
|
787
|
+
|
|
788
|
+
def opFLog(rd, ra, rb)
|
|
789
|
+
@fp[rd] = Math.log(@fp[ra])
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
def opFClamp(rd, ra, rb)
|
|
793
|
+
# FP[Rd] = clamp(FP[Ra], FP[Rb], Rc) - simplified, just min of ra,rb
|
|
794
|
+
@fp[rd] = [@fp[ra], @fp[rb]].min
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
def opFLerp(rd, ra, rb)
|
|
798
|
+
# FP[Rd] = FP[Ra] * t + FP[Rb] * (1-t), with t in Rc
|
|
799
|
+
# Simplified: use FP[Ra] as t, FP[Rb] as base
|
|
800
|
+
t = @fp[ra]
|
|
801
|
+
base = @fp[rb]
|
|
802
|
+
@fp[rd] = base * (1 - t) + base * t
|
|
803
|
+
end
|
|
804
|
+
|
|
805
|
+
# Float Comparisons
|
|
806
|
+
def opFCmpEq(rd, ra, rb)
|
|
807
|
+
@gp[rd] = (@fp[ra] == @fp[rb]) ? 1 : 0
|
|
808
|
+
set_z(@gp[rd])
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
def opFCmpNe(rd, ra, rb)
|
|
812
|
+
@gp[rd] = (@fp[ra] != @fp[rb]) ? 1 : 0
|
|
813
|
+
set_z(1 - @gp[rd])
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
def opFCmpLt(rd, ra, rb)
|
|
817
|
+
@gp[rd] = (@fp[ra] < @fp[rb]) ? 1 : 0
|
|
818
|
+
set_z(@gp[rd])
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
def opFCmpLe(rd, ra, rb)
|
|
822
|
+
@gp[rd] = (@fp[ra] <= @fp[rb]) ? 1 : 0
|
|
823
|
+
set_z(@gp[rd])
|
|
824
|
+
end
|
|
825
|
+
|
|
826
|
+
def opFCmpGt(rd, ra, rb)
|
|
827
|
+
@gp[rd] = (@fp[ra] > @fp[rb]) ? 1 : 0
|
|
828
|
+
set_z(@gp[rd])
|
|
829
|
+
end
|
|
830
|
+
|
|
831
|
+
def opFCmpGe(rd, ra, rb)
|
|
832
|
+
@gp[rd] = (@fp[ra] >= @fp[rb]) ? 1 : 0
|
|
833
|
+
set_z(@gp[rd])
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
# Conversions
|
|
837
|
+
def opIToF(rd, ra, rb)
|
|
838
|
+
@fp[rd] = @gp[ra].to_f
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
def opFToI(rd, ra, rb)
|
|
842
|
+
@gp[rd] = @fp[ra].to_i
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
def opBToI(rd, ra, rb)
|
|
846
|
+
@gp[rd] = (@gp[ra] != 0) ? 1 : 0
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
def opIToB(rd, ra, rb)
|
|
850
|
+
@gp[rd] = (@gp[ra] != 0) ? 1 : 0
|
|
851
|
+
end
|
|
852
|
+
|
|
853
|
+
# Type/Meta
|
|
854
|
+
def opCast(rd, ra, rb)
|
|
855
|
+
# Type-cast: simplified implementation
|
|
856
|
+
@gp[rd] = @gp[ra]
|
|
857
|
+
end
|
|
858
|
+
|
|
859
|
+
def opSizeOf(rd, ra, rb)
|
|
860
|
+
# Size of type in GP[Ra], result in GP[Rd]
|
|
861
|
+
@gp[rd] = 4 # Default size
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
def opTypeOf(rd, ra, rb)
|
|
865
|
+
# Runtime type tag
|
|
866
|
+
@gp[rd] = 0 # Integer type
|
|
867
|
+
end
|
|
868
|
+
|
|
869
|
+
# Bitwise
|
|
870
|
+
def opBAnd(rd, ra, rb)
|
|
871
|
+
result = @gp[ra] & @gp[rb]
|
|
872
|
+
set_zn(result)
|
|
873
|
+
@gp[rd] = result
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
def opBOr(rd, ra, rb)
|
|
877
|
+
result = @gp[ra] | @gp[rb]
|
|
878
|
+
set_zn(result)
|
|
879
|
+
@gp[rd] = result
|
|
880
|
+
end
|
|
881
|
+
|
|
882
|
+
def opBXor(rd, ra, rb)
|
|
883
|
+
result = @gp[ra] ^ @gp[rb]
|
|
884
|
+
set_zn(result)
|
|
885
|
+
@gp[rd] = result
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
def opBShl(rd, ra, rb)
|
|
889
|
+
result = @gp[ra] << (@gp[rb] & 31)
|
|
890
|
+
set_zn(result)
|
|
891
|
+
@gp[rd] = result
|
|
892
|
+
end
|
|
893
|
+
|
|
894
|
+
def opBShr(rd, ra, rb)
|
|
895
|
+
result = @gp[ra] >> (@gp[rb] & 31)
|
|
896
|
+
set_zn(result)
|
|
897
|
+
@gp[rd] = result
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
def opBNot(rd, ra, rb)
|
|
901
|
+
result = ~@gp[ra]
|
|
902
|
+
set_zn(result)
|
|
903
|
+
@gp[rd] = result
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
# Vector Operations
|
|
907
|
+
def opVLoad(rd, rb, off)
|
|
908
|
+
addr = @gp[rb] + off
|
|
909
|
+
(0...256).each do |i|
|
|
910
|
+
@vr[rd][i] = read_memory_u8(addr + i) || 0
|
|
911
|
+
end
|
|
912
|
+
end
|
|
913
|
+
|
|
914
|
+
def opVStore(rs, rb, off)
|
|
915
|
+
addr = @gp[rb] + off
|
|
916
|
+
@vr[rs].bytes.each_with_index do |byte, i|
|
|
917
|
+
write_memory(addr + i, 1, byte)
|
|
918
|
+
end
|
|
919
|
+
end
|
|
920
|
+
|
|
921
|
+
def opVAdd(rd, ra, rb)
|
|
922
|
+
# Component-wise addition
|
|
923
|
+
(0...256).each do |i|
|
|
924
|
+
a = @vr[ra][i].ord
|
|
925
|
+
b = @vr[rb][i].ord
|
|
926
|
+
result = (a + b) & 0xFF
|
|
927
|
+
@vr[rd][i] = result.chr
|
|
928
|
+
end
|
|
929
|
+
end
|
|
930
|
+
|
|
931
|
+
def opVMul(rd, ra, rb)
|
|
932
|
+
# Component-wise multiplication
|
|
933
|
+
(0...256).each do |i|
|
|
934
|
+
a = @vr[ra][i].ord
|
|
935
|
+
b = @vr[rb][i].ord
|
|
936
|
+
result = (a * b) & 0xFF
|
|
937
|
+
@vr[rd][i] = result.chr
|
|
938
|
+
end
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
def opVDot(rd, ra, rb)
|
|
942
|
+
# Dot product -> scalar in F0
|
|
943
|
+
sum = 0.0
|
|
944
|
+
(0...256).each do |i|
|
|
945
|
+
a = @vr[ra][i].ord
|
|
946
|
+
b = @vr[rb][i].ord
|
|
947
|
+
sum += a * b
|
|
948
|
+
end
|
|
949
|
+
@fp[rd] = sum
|
|
950
|
+
end
|
|
951
|
+
|
|
952
|
+
# A2A Opcodes (stub implementations)
|
|
953
|
+
def opASend
|
|
954
|
+
length = fetch8
|
|
955
|
+
agent_id = fetch8
|
|
956
|
+
reg = fetch8
|
|
957
|
+
$stderr.puts "A2A: ASend agent_id=#{agent_id} reg=#{reg}"
|
|
958
|
+
end
|
|
959
|
+
|
|
960
|
+
def opARecv
|
|
961
|
+
length = fetch8
|
|
962
|
+
agent_id = fetch8
|
|
963
|
+
reg = fetch8
|
|
964
|
+
$stderr.puts "A2A: ARecv agent_id=#{agent_id} reg=#{reg}"
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
def opAAsk
|
|
968
|
+
length = fetch8
|
|
969
|
+
agent_id = fetch8
|
|
970
|
+
reg = fetch8
|
|
971
|
+
$stderr.puts "A2A: AAsk agent_id=#{agent_id} reg=#{reg}"
|
|
972
|
+
end
|
|
973
|
+
|
|
974
|
+
def opATell
|
|
975
|
+
length = fetch8
|
|
976
|
+
agent_id = fetch8
|
|
977
|
+
reg = fetch8
|
|
978
|
+
$stderr.puts "A2A: ATell agent_id=#{agent_id} reg=#{reg}"
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
def opADelegate
|
|
982
|
+
length = fetch8
|
|
983
|
+
agent_id = fetch8
|
|
984
|
+
bc_start = fetchu16
|
|
985
|
+
$stderr.puts "A2A: ADelegate agent_id=#{agent_id} bc_start=#{bc_start}"
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
def opABroadcast
|
|
989
|
+
length = fetch8
|
|
990
|
+
reg = fetch8
|
|
991
|
+
$stderr.puts "A2A: ABroadcast reg=#{reg}"
|
|
992
|
+
end
|
|
993
|
+
|
|
994
|
+
def opASubscribe
|
|
995
|
+
length = fetch8
|
|
996
|
+
channel_id = fetch8
|
|
997
|
+
$stderr.puts "A2A: ASubscribe channel_id=#{channel_id}"
|
|
998
|
+
end
|
|
999
|
+
|
|
1000
|
+
def opAWait
|
|
1001
|
+
length = fetch8
|
|
1002
|
+
cond_reg = fetch8
|
|
1003
|
+
$stderr.puts "A2A: AWait cond_reg=#{cond_reg}"
|
|
1004
|
+
end
|
|
1005
|
+
|
|
1006
|
+
def opATrust
|
|
1007
|
+
length = fetch8
|
|
1008
|
+
agent_id = fetch8
|
|
1009
|
+
level = fetch8
|
|
1010
|
+
$stderr.puts "A2A: ATrust agent_id=#{agent_id} level=#{level}"
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
def opAVerify
|
|
1014
|
+
length = fetch8
|
|
1015
|
+
agent_id = fetch8
|
|
1016
|
+
result_reg = fetch8
|
|
1017
|
+
$stderr.puts "A2A: AVerify agent_id=#{agent_id} result_reg=#{result_reg}"
|
|
1018
|
+
end
|
|
1019
|
+
end
|
|
1020
|
+
end
|