codecin 5.4.2__py3-none-any.whl
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.
- codecin/__init__.py +27 -0
- codecin/aot.py +229 -0
- codecin/assembler.py +548 -0
- codecin/cache.py +71 -0
- codecin/cin.py +2558 -0
- codecin/cli.py +282 -0
- codecin/config.py +58 -0
- codecin/console.py +183 -0
- codecin/cpu.py +1654 -0
- codecin/crom.py +222 -0
- codecin/debugger.py +659 -0
- codecin/disasm.py +86 -0
- codecin/errors.py +58 -0
- codecin/isa.py +457 -0
- codecin/jit.py +270 -0
- codecin/libcodecin_native.so +0 -0
- codecin/logger.py +145 -0
- codecin/memory.py +348 -0
- codecin/native/aot/aot.go +70 -0
- codecin/native/aot/build.go +219 -0
- codecin/native/aot/stub_main.go.txt +22 -0
- codecin/native/build.ps1 +33 -0
- codecin/native/build.sh +48 -0
- codecin/native/cmd/codecin/main.go +287 -0
- codecin/native/compiler/codegen.go +1938 -0
- codecin/native/compiler/compile_test.go +164 -0
- codecin/native/compiler/parser.go +1071 -0
- codecin/native/compiler/syscalls.go +86 -0
- codecin/native/compiler/tokenizer.go +336 -0
- codecin/native/compiler/types.go +213 -0
- codecin/native/engine/audio.go +152 -0
- codecin/native/engine/audio_other.go +46 -0
- codecin/native/engine/audio_windows.go +43 -0
- codecin/native/engine/canvas.go +271 -0
- codecin/native/engine/crom.go +86 -0
- codecin/native/engine/encode.go +93 -0
- codecin/native/engine/engine_test.go +198 -0
- codecin/native/engine/isa_gen.go +445 -0
- codecin/native/engine/system.go +190 -0
- codecin/native/engine/termux.go +113 -0
- codecin/native/engine/version_gen.go +7 -0
- codecin/native/engine/vm.go +1157 -0
- codecin/native/go.mod +3 -0
- codecin/native/ir/ir.go +48 -0
- codecin/native/main.go +225 -0
- codecin/native.py +336 -0
- codecin/registers.py +130 -0
- codecin/stats.py +235 -0
- codecin-5.4.2.dist-info/METADATA +985 -0
- codecin-5.4.2.dist-info/RECORD +54 -0
- codecin-5.4.2.dist-info/WHEEL +5 -0
- codecin-5.4.2.dist-info/entry_points.txt +2 -0
- codecin-5.4.2.dist-info/licenses/LICENSE +7 -0
- codecin-5.4.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1157 @@
|
|
|
1
|
+
// Package engine 是 Code CIN 的原生字节码 VM (Go 实现)。
|
|
2
|
+
//
|
|
3
|
+
// 语义与 codecin/cpu.py 解释器严格一致:
|
|
4
|
+
// - PC 语义: 取指后先 pc++ 再执行; CALL/BL 压入的是已自增的 pc
|
|
5
|
+
// - 栈: 8 字节 qword, 自顶向下; sp 初值由调用方传入
|
|
6
|
+
// - 寄存器: 33 个槽, R[31]=XZR 只读, R[32]=SP
|
|
7
|
+
// - 遇到不支持的指令立即返回 StatusUnsupported, pc 指向该指令, 供 Python 回退
|
|
8
|
+
//
|
|
9
|
+
// 字节码格式 (UCBC v1):
|
|
10
|
+
//
|
|
11
|
+
// magic[4] version u8 entry u32 count u32
|
|
12
|
+
// 指令: opcode u8 argc u8 ; 操作数: kind u8 value i64 extra i64 (小端)
|
|
13
|
+
package engine
|
|
14
|
+
|
|
15
|
+
import (
|
|
16
|
+
"encoding/binary"
|
|
17
|
+
"fmt"
|
|
18
|
+
"math"
|
|
19
|
+
"math/rand"
|
|
20
|
+
"strconv"
|
|
21
|
+
"strings"
|
|
22
|
+
"time"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
// 执行状态码 (与 c-shared 桥接层 / Python native.py 一致)。
|
|
26
|
+
const (
|
|
27
|
+
StatusOK = 0
|
|
28
|
+
StatusDone = 1
|
|
29
|
+
StatusUnsupported = 2
|
|
30
|
+
StatusError = 3
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
// 操作数种类/操作码/SYS 功能号常量由 isa_gen.go 提供 (单一事实来源:
|
|
34
|
+
// python script/gen_native_isa.py 自 codecin/isa.py 生成, 请勿在此重复定义)。
|
|
35
|
+
|
|
36
|
+
const mask64 = uint64(0xFFFFFFFFFFFFFFFF)
|
|
37
|
+
|
|
38
|
+
type operand struct {
|
|
39
|
+
kind uint8
|
|
40
|
+
value int64
|
|
41
|
+
extra int64
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type instruction struct {
|
|
45
|
+
opcode uint8
|
|
46
|
+
args []operand
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
type vmState struct {
|
|
50
|
+
prog []instruction
|
|
51
|
+
entry int
|
|
52
|
+
mem []byte
|
|
53
|
+
regs [33]uint64
|
|
54
|
+
sp uint64
|
|
55
|
+
pc int
|
|
56
|
+
heapPtr uint64
|
|
57
|
+
steps uint64
|
|
58
|
+
flags struct{ N, Z, C, V bool }
|
|
59
|
+
out strings.Builder
|
|
60
|
+
outOver bool // 输出超过 maxOutputBytes (截断并置错误)
|
|
61
|
+
sysIdx int
|
|
62
|
+
rng *rand.Rand
|
|
63
|
+
inData []byte
|
|
64
|
+
inPos int
|
|
65
|
+
emptyStr uint64 // 预留空串地址 (宿主调用返回失败时的安全空串)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// maxOutputBytes 限制单次运行的输出总量: 程序用无限打印不能把宿主 OOM。
|
|
69
|
+
const maxOutputBytes = 16 << 20 // 16 MiB
|
|
70
|
+
|
|
71
|
+
// outWrite 追加输出; 超过上限则截断并标记 outOver。
|
|
72
|
+
func (vm *vmState) outWrite(s string) {
|
|
73
|
+
if vm.outOver {
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
remaining := maxOutputBytes - vm.out.Len()
|
|
77
|
+
if remaining <= 0 {
|
|
78
|
+
vm.outOver = true
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
if len(s) > remaining {
|
|
82
|
+
s = s[:remaining]
|
|
83
|
+
vm.outOver = true
|
|
84
|
+
}
|
|
85
|
+
vm.out.WriteString(s)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// outByte 追加单字节输出 (同上限)。
|
|
89
|
+
func (vm *vmState) outByte(b byte) {
|
|
90
|
+
if vm.outOver {
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
if vm.out.Len() >= maxOutputBytes {
|
|
94
|
+
vm.outOver = true
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
vm.out.WriteByte(b)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Result 是 Run 的执行结果。
|
|
101
|
+
type Result struct {
|
|
102
|
+
Status int
|
|
103
|
+
Pc int
|
|
104
|
+
Sp uint64
|
|
105
|
+
HeapPtr uint64
|
|
106
|
+
Steps uint64
|
|
107
|
+
Regs [33]uint64
|
|
108
|
+
Output string
|
|
109
|
+
ErrMsg string
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
func decodeBytecode(bc []byte) ([]instruction, int, bool) {
|
|
113
|
+
if len(bc) < 13 || string(bc[:4]) != "UCBC" {
|
|
114
|
+
return nil, 0, false
|
|
115
|
+
}
|
|
116
|
+
if bc[4] != bcVersion {
|
|
117
|
+
// 版本字节此前从不校验: 未知格式会被按当前布局强行解释
|
|
118
|
+
return nil, 0, false
|
|
119
|
+
}
|
|
120
|
+
entry := binary.LittleEndian.Uint32(bc[5:9])
|
|
121
|
+
count := binary.LittleEndian.Uint32(bc[9:13])
|
|
122
|
+
// count 来自不可信输入: 先按"每条指令至少 2 字节头部"夹取。
|
|
123
|
+
// 旧实现直接把它当 make 容量 (count=0xFFFFFFFF → 137GB 预分配),
|
|
124
|
+
// 一个 13 字节的文件就能让宿主 OOM。
|
|
125
|
+
if maxCount := uint32((len(bc) - 13) / 2); count > maxCount {
|
|
126
|
+
return nil, 0, false
|
|
127
|
+
}
|
|
128
|
+
pos := 13
|
|
129
|
+
prog := make([]instruction, 0, count)
|
|
130
|
+
for i := uint32(0); i < count; i++ {
|
|
131
|
+
if pos+2 > len(bc) {
|
|
132
|
+
return nil, 0, false
|
|
133
|
+
}
|
|
134
|
+
opcode := bc[pos]
|
|
135
|
+
argc := int(bc[pos+1])
|
|
136
|
+
pos += 2
|
|
137
|
+
if int(opcode) >= len(argCounts) {
|
|
138
|
+
return nil, 0, false
|
|
139
|
+
}
|
|
140
|
+
// 参数个数必须与操作码匹配: 否则 execute 中的 args[i] 会越界 panic。
|
|
141
|
+
// -1 表示变长 (B / JALR / SYS), 只设一个合理上限。
|
|
142
|
+
if want := int(argCounts[opcode]); want >= 0 {
|
|
143
|
+
if argc != want {
|
|
144
|
+
return nil, 0, false
|
|
145
|
+
}
|
|
146
|
+
} else if argc > 6 {
|
|
147
|
+
return nil, 0, false
|
|
148
|
+
}
|
|
149
|
+
ins := instruction{opcode: opcode}
|
|
150
|
+
for j := 0; j < argc; j++ {
|
|
151
|
+
if pos+17 > len(bc) {
|
|
152
|
+
return nil, 0, false
|
|
153
|
+
}
|
|
154
|
+
op := operand{
|
|
155
|
+
kind: bc[pos],
|
|
156
|
+
value: int64(binary.LittleEndian.Uint64(bc[pos+1 : pos+9])),
|
|
157
|
+
extra: int64(binary.LittleEndian.Uint64(bc[pos+9 : pos+17])),
|
|
158
|
+
}
|
|
159
|
+
pos += 17
|
|
160
|
+
ins.args = append(ins.args, op)
|
|
161
|
+
}
|
|
162
|
+
prog = append(prog, ins)
|
|
163
|
+
}
|
|
164
|
+
return prog, int(entry), true
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Run 执行程序字节码, 返回结果快照。mem 会被原地修改 (数据段/堆/栈写入)。
|
|
168
|
+
func Run(bc []byte, mem []byte, entry, sp, heapBase int64, inData []byte,
|
|
169
|
+
maxSteps int64) *Result {
|
|
170
|
+
|
|
171
|
+
prog, ent, ok := decodeBytecode(bc)
|
|
172
|
+
if !ok {
|
|
173
|
+
return &Result{Status: StatusError, ErrMsg: "bad bytecode"}
|
|
174
|
+
}
|
|
175
|
+
if entry >= 0 {
|
|
176
|
+
ent = int(entry)
|
|
177
|
+
}
|
|
178
|
+
vm := &vmState{
|
|
179
|
+
prog: prog,
|
|
180
|
+
entry: ent,
|
|
181
|
+
mem: mem,
|
|
182
|
+
sp: uint64(sp),
|
|
183
|
+
pc: ent,
|
|
184
|
+
heapPtr: uint64(heapBase),
|
|
185
|
+
rng: rand.New(rand.NewSource(time.Now().UnixNano())),
|
|
186
|
+
inData: inData,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
finish := func(status int, errMsg string) *Result {
|
|
190
|
+
// 输出超限一并报错: 不能把"被截断的输出"当成正常结果
|
|
191
|
+
if vm.outOver && status != StatusError {
|
|
192
|
+
status = StatusError
|
|
193
|
+
if errMsg == "" {
|
|
194
|
+
errMsg = "output limit exceeded (16 MiB)"
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return &Result{
|
|
198
|
+
Status: status,
|
|
199
|
+
Pc: vm.pc,
|
|
200
|
+
Sp: vm.sp,
|
|
201
|
+
HeapPtr: vm.heapPtr,
|
|
202
|
+
Steps: vm.steps,
|
|
203
|
+
Regs: vm.regs,
|
|
204
|
+
Output: vm.out.String(),
|
|
205
|
+
ErrMsg: errMsg,
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
for {
|
|
210
|
+
if maxSteps > 0 && int64(vm.steps) >= maxSteps {
|
|
211
|
+
// 步数用尽不等于正常停机: 旧实现返回 StatusDone, 与 HALT 无法区分,
|
|
212
|
+
// 于是被截断的程序在 Python 侧被当成 halted=true 正常结束。
|
|
213
|
+
return finish(StatusError,
|
|
214
|
+
fmt.Sprintf("instruction limit reached (%d steps)", maxSteps))
|
|
215
|
+
}
|
|
216
|
+
if vm.pc < 0 || vm.pc >= len(vm.prog) {
|
|
217
|
+
return finish(StatusDone, "")
|
|
218
|
+
}
|
|
219
|
+
ins := vm.prog[vm.pc]
|
|
220
|
+
if !opcodeSupported(ins.opcode) {
|
|
221
|
+
return finish(StatusUnsupported, "")
|
|
222
|
+
}
|
|
223
|
+
// 未知 SYS 功能号: 交给解释器 (pc 不自增)
|
|
224
|
+
if ins.opcode == opSYS {
|
|
225
|
+
if len(ins.args) == 0 || ins.args[0].kind != kindImm ||
|
|
226
|
+
!syscallSupported(uint64(ins.args[0].value)) {
|
|
227
|
+
return finish(StatusUnsupported, "")
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// 与解释器一致: 先自增 pc
|
|
231
|
+
vm.pc++
|
|
232
|
+
vm.steps++
|
|
233
|
+
halt, err := vm.execute(ins)
|
|
234
|
+
if err != "" {
|
|
235
|
+
return finish(StatusError, err)
|
|
236
|
+
}
|
|
237
|
+
if halt {
|
|
238
|
+
return finish(StatusOK, "")
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
func opcodeSupported(op uint8) bool {
|
|
244
|
+
switch op {
|
|
245
|
+
case opMOV, opLOAD, opSTORE, opADD, opSUB, opMUL, opDIV, opAND, opOR, opXOR,
|
|
246
|
+
opSHL, opSHR, opINC, opDEC, opCMP, opJMP, opJZ, opJNZ, opJE, opJL, opJG,
|
|
247
|
+
opPUSH, opPOP, opCALL, opRET, opIN, opOUT, opHALT, opLSL, opLSR, opASR,
|
|
248
|
+
opMVN, opB, opBL, opNOP, opLB, opLH, opLW, opLD, opSB, opSH, opSW, opSD,
|
|
249
|
+
opADDI, opXORI, opORI, opANDI, opSYS:
|
|
250
|
+
return true
|
|
251
|
+
}
|
|
252
|
+
return false
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// syscallSupported: 原生 VM 已实现的 SYS 功能号。
|
|
256
|
+
// 现已在 Go 侧实现全部宿主调用 (0..sysTERMUXSMS), 供独立 Go CLI 使用。
|
|
257
|
+
func syscallSupported(id uint64) bool {
|
|
258
|
+
return id <= sysTERMUXSMS
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ---------------- 操作数/寄存器/内存 ----------------
|
|
262
|
+
|
|
263
|
+
func (vm *vmState) reg(n int) uint64 {
|
|
264
|
+
if n == 32 {
|
|
265
|
+
return vm.sp
|
|
266
|
+
}
|
|
267
|
+
if n == 31 || n < 0 || n > 32 {
|
|
268
|
+
return 0
|
|
269
|
+
}
|
|
270
|
+
return vm.regs[n]
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
func (vm *vmState) setReg(n int, v uint64) {
|
|
274
|
+
if n == 32 {
|
|
275
|
+
vm.sp = v
|
|
276
|
+
} else if n == 31 || n < 0 || n > 32 {
|
|
277
|
+
// XZR 只读
|
|
278
|
+
} else {
|
|
279
|
+
vm.regs[n] = v
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
func (vm *vmState) memAddr(op operand) (uint64, bool) {
|
|
284
|
+
base := op.value
|
|
285
|
+
off := uint64(op.extra)
|
|
286
|
+
if base >= 0 {
|
|
287
|
+
return (vm.reg(int(base)) + off) & mask64, true
|
|
288
|
+
}
|
|
289
|
+
return off & mask64, true
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
func (vm *vmState) val(op operand) (uint64, bool) {
|
|
293
|
+
switch op.kind {
|
|
294
|
+
case kindReg:
|
|
295
|
+
return vm.reg(int(op.value)), true
|
|
296
|
+
case kindImm:
|
|
297
|
+
return uint64(op.value), true
|
|
298
|
+
case kindFloat:
|
|
299
|
+
return uint64(op.value), true
|
|
300
|
+
case kindStr:
|
|
301
|
+
return uint64(op.value), true
|
|
302
|
+
case kindMem:
|
|
303
|
+
addr, ok := vm.memAddr(op)
|
|
304
|
+
if !ok {
|
|
305
|
+
return 0, false
|
|
306
|
+
}
|
|
307
|
+
v, e := vm.readQ(addr)
|
|
308
|
+
return v, e == ""
|
|
309
|
+
case kindCond:
|
|
310
|
+
if vm.condition(uint8(op.value)) {
|
|
311
|
+
return 1, true
|
|
312
|
+
}
|
|
313
|
+
return 0, true
|
|
314
|
+
case kindVec, kindVecLane:
|
|
315
|
+
// CIN 不生成向量操作数; 向量指令整体不支持
|
|
316
|
+
return 0, false
|
|
317
|
+
}
|
|
318
|
+
return 0, false
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
func (vm *vmState) checkAddr(addr uint64, width int) string {
|
|
322
|
+
if uint64(len(vm.mem)) < uint64(width) || addr > uint64(len(vm.mem))-uint64(width) {
|
|
323
|
+
return "address " + strconv.FormatUint(addr, 16) + " out of bounds"
|
|
324
|
+
}
|
|
325
|
+
return ""
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
func (vm *vmState) readQ(addr uint64) (uint64, string) {
|
|
329
|
+
if e := vm.checkAddr(addr, 8); e != "" {
|
|
330
|
+
return 0, e
|
|
331
|
+
}
|
|
332
|
+
return binary.LittleEndian.Uint64(vm.mem[addr : addr+8]), ""
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
func (vm *vmState) writeQ(addr, v uint64) string {
|
|
336
|
+
if e := vm.checkAddr(addr, 8); e != "" {
|
|
337
|
+
return e
|
|
338
|
+
}
|
|
339
|
+
binary.LittleEndian.PutUint64(vm.mem[addr:addr+8], v)
|
|
340
|
+
return ""
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
func toSigned(v uint64) int64 { return int64(v) }
|
|
344
|
+
|
|
345
|
+
// ---------------- 条件标志 ----------------
|
|
346
|
+
|
|
347
|
+
func (vm *vmState) condition(code uint8) bool {
|
|
348
|
+
n, z, c, v := vm.flags.N, vm.flags.Z, vm.flags.C, vm.flags.V
|
|
349
|
+
switch code {
|
|
350
|
+
case 0: // EQ
|
|
351
|
+
return z
|
|
352
|
+
case 1: // NE
|
|
353
|
+
return !z
|
|
354
|
+
case 2: // CS
|
|
355
|
+
return c
|
|
356
|
+
case 3: // CC
|
|
357
|
+
return !c
|
|
358
|
+
case 4: // MI
|
|
359
|
+
return n
|
|
360
|
+
case 5: // PL
|
|
361
|
+
return !n
|
|
362
|
+
case 6: // VS
|
|
363
|
+
return v
|
|
364
|
+
case 7: // VC
|
|
365
|
+
return !v
|
|
366
|
+
case 8: // HI
|
|
367
|
+
return c && !z
|
|
368
|
+
case 9: // LS
|
|
369
|
+
return !c || z
|
|
370
|
+
case 10: // GE
|
|
371
|
+
return n == v
|
|
372
|
+
case 11: // LT
|
|
373
|
+
return n != v
|
|
374
|
+
case 12: // GT
|
|
375
|
+
return !z && (n == v)
|
|
376
|
+
case 13: // LE
|
|
377
|
+
return z || (n != v)
|
|
378
|
+
case 14: // AL
|
|
379
|
+
return true
|
|
380
|
+
default: // NV
|
|
381
|
+
return false
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
func (vm *vmState) setFlagsSub(a, b uint64) {
|
|
386
|
+
res := (a - b) & mask64
|
|
387
|
+
sa := int64(a)
|
|
388
|
+
sb := int64(b)
|
|
389
|
+
sr := sa - sb
|
|
390
|
+
vm.flags.Z = res == 0
|
|
391
|
+
vm.flags.N = res&(1<<63) != 0
|
|
392
|
+
vm.flags.C = a >= b
|
|
393
|
+
vm.flags.V = sr > math.MaxInt64 || sr < math.MinInt64
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// ---------------- 栈 ----------------
|
|
397
|
+
|
|
398
|
+
func (vm *vmState) push(v uint64) string {
|
|
399
|
+
vm.sp = (vm.sp - 8) & mask64
|
|
400
|
+
if vm.sp < vm.heapPtr+4096 {
|
|
401
|
+
return "Stack overflow (collides with heap)"
|
|
402
|
+
}
|
|
403
|
+
return vm.writeQ(vm.sp, v)
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
func (vm *vmState) pop() (uint64, string) {
|
|
407
|
+
if vm.sp >= uint64(len(vm.mem))-8 {
|
|
408
|
+
return 0, "Stack underflow"
|
|
409
|
+
}
|
|
410
|
+
v, e := vm.readQ(vm.sp)
|
|
411
|
+
if e != "" {
|
|
412
|
+
return 0, e
|
|
413
|
+
}
|
|
414
|
+
vm.sp = (vm.sp + 8) & mask64
|
|
415
|
+
return v, ""
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ---------------- 浮点辅助 ----------------
|
|
419
|
+
|
|
420
|
+
func bitsToF(b uint64) float64 { return math.Float64frombits(b) }
|
|
421
|
+
func fToBits(f float64) uint64 { return math.Float64bits(f) }
|
|
422
|
+
|
|
423
|
+
// formatFloat 与 Python _format_float 对齐 (repr 最短表示 + 去尾零)
|
|
424
|
+
func formatFloat(f float64) string {
|
|
425
|
+
if math.IsNaN(f) {
|
|
426
|
+
return "NaN"
|
|
427
|
+
}
|
|
428
|
+
if math.IsInf(f, 1) {
|
|
429
|
+
return "+Inf"
|
|
430
|
+
}
|
|
431
|
+
if math.IsInf(f, -1) {
|
|
432
|
+
return "-Inf"
|
|
433
|
+
}
|
|
434
|
+
return strconv.FormatFloat(f, 'g', -1, 64)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
func (vm *vmState) readCString(addr uint64) string {
|
|
438
|
+
var sb strings.Builder
|
|
439
|
+
for addr < uint64(len(vm.mem)) {
|
|
440
|
+
ch := vm.mem[addr]
|
|
441
|
+
if ch == 0 {
|
|
442
|
+
break
|
|
443
|
+
}
|
|
444
|
+
sb.WriteByte(ch)
|
|
445
|
+
addr++
|
|
446
|
+
}
|
|
447
|
+
return sb.String()
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
func (vm *vmState) writeString(addr uint64, s string) string {
|
|
451
|
+
if e := vm.checkAddr(addr, len(s)+1); e != "" {
|
|
452
|
+
return e
|
|
453
|
+
}
|
|
454
|
+
copy(vm.mem[addr:addr+uint64(len(s))], s)
|
|
455
|
+
vm.mem[addr+uint64(len(s))] = 0
|
|
456
|
+
return ""
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// sysBuffer 轮转静态缓冲 (与 Python 一致: heap+2048+idx*64)
|
|
460
|
+
func (vm *vmState) sysBuffer() uint64 {
|
|
461
|
+
idx := vm.sysIdx % 8
|
|
462
|
+
vm.sysIdx++
|
|
463
|
+
return vm.heapPtr + 2048 + uint64(idx)*64
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// ---------------- 指令执行 ----------------
|
|
467
|
+
|
|
468
|
+
func (vm *vmState) execute(ins instruction) (bool, string) {
|
|
469
|
+
args := ins.args
|
|
470
|
+
switch ins.opcode {
|
|
471
|
+
case opMOV:
|
|
472
|
+
v, ok := vm.val(args[1])
|
|
473
|
+
if !ok {
|
|
474
|
+
return false, "bad MOV operand"
|
|
475
|
+
}
|
|
476
|
+
vm.setReg(int(args[0].value), v)
|
|
477
|
+
case opADD:
|
|
478
|
+
rd := int(args[0].value)
|
|
479
|
+
v, ok := vm.val(args[1])
|
|
480
|
+
if !ok {
|
|
481
|
+
return false, "bad ADD operand"
|
|
482
|
+
}
|
|
483
|
+
vm.setReg(rd, (vm.reg(rd)+v)&mask64)
|
|
484
|
+
case opSUB:
|
|
485
|
+
rd := int(args[0].value)
|
|
486
|
+
v, ok := vm.val(args[1])
|
|
487
|
+
if !ok {
|
|
488
|
+
return false, "bad SUB operand"
|
|
489
|
+
}
|
|
490
|
+
vm.setReg(rd, (vm.reg(rd)-v)&mask64)
|
|
491
|
+
case opMUL:
|
|
492
|
+
rd := int(args[0].value)
|
|
493
|
+
v, ok := vm.val(args[1])
|
|
494
|
+
if !ok {
|
|
495
|
+
return false, "bad MUL operand"
|
|
496
|
+
}
|
|
497
|
+
vm.setReg(rd, (vm.reg(rd)*v)&mask64)
|
|
498
|
+
case opDIV:
|
|
499
|
+
rd := int(args[0].value)
|
|
500
|
+
d, ok := vm.val(args[1])
|
|
501
|
+
if !ok {
|
|
502
|
+
return false, "bad DIV operand"
|
|
503
|
+
}
|
|
504
|
+
if d == 0 {
|
|
505
|
+
return false, "Division by zero"
|
|
506
|
+
}
|
|
507
|
+
vm.setReg(rd, sdiv(vm.reg(rd), d))
|
|
508
|
+
case opAND:
|
|
509
|
+
rd := int(args[0].value)
|
|
510
|
+
v, _ := vm.val(args[1])
|
|
511
|
+
vm.setReg(rd, vm.reg(rd)&v)
|
|
512
|
+
case opOR:
|
|
513
|
+
rd := int(args[0].value)
|
|
514
|
+
v, _ := vm.val(args[1])
|
|
515
|
+
vm.setReg(rd, vm.reg(rd)|v)
|
|
516
|
+
case opXOR:
|
|
517
|
+
rd := int(args[0].value)
|
|
518
|
+
v, _ := vm.val(args[1])
|
|
519
|
+
vm.setReg(rd, vm.reg(rd)^v)
|
|
520
|
+
case opSHL:
|
|
521
|
+
rd := int(args[0].value)
|
|
522
|
+
v, _ := vm.val(args[1])
|
|
523
|
+
vm.setReg(rd, (vm.reg(rd)<<(v&63))&mask64)
|
|
524
|
+
case opSHR:
|
|
525
|
+
rd := int(args[0].value)
|
|
526
|
+
v, _ := vm.val(args[1])
|
|
527
|
+
vm.setReg(rd, vm.reg(rd)>>(v&63))
|
|
528
|
+
case opINC:
|
|
529
|
+
rd := int(args[0].value)
|
|
530
|
+
vm.setReg(rd, (vm.reg(rd)+1)&mask64)
|
|
531
|
+
case opDEC:
|
|
532
|
+
rd := int(args[0].value)
|
|
533
|
+
vm.setReg(rd, (vm.reg(rd)-1)&mask64)
|
|
534
|
+
case opMVN:
|
|
535
|
+
rd := int(args[0].value)
|
|
536
|
+
v, _ := vm.val(args[1])
|
|
537
|
+
vm.setReg(rd, ^v&mask64)
|
|
538
|
+
case opCMP:
|
|
539
|
+
a, _ := vm.val(args[0])
|
|
540
|
+
b, _ := vm.val(args[1])
|
|
541
|
+
vm.setFlagsSub(a, b)
|
|
542
|
+
case opJMP:
|
|
543
|
+
t, _ := vm.val(args[0])
|
|
544
|
+
vm.pc = int(t)
|
|
545
|
+
case opJZ, opJE:
|
|
546
|
+
if vm.flags.Z {
|
|
547
|
+
t, _ := vm.val(args[0])
|
|
548
|
+
vm.pc = int(t)
|
|
549
|
+
}
|
|
550
|
+
case opJNZ:
|
|
551
|
+
if !vm.flags.Z {
|
|
552
|
+
t, _ := vm.val(args[0])
|
|
553
|
+
vm.pc = int(t)
|
|
554
|
+
}
|
|
555
|
+
case opJL:
|
|
556
|
+
if vm.flags.N != vm.flags.V {
|
|
557
|
+
t, _ := vm.val(args[0])
|
|
558
|
+
vm.pc = int(t)
|
|
559
|
+
}
|
|
560
|
+
case opJG:
|
|
561
|
+
if !vm.flags.Z && vm.flags.N == vm.flags.V {
|
|
562
|
+
t, _ := vm.val(args[0])
|
|
563
|
+
vm.pc = int(t)
|
|
564
|
+
}
|
|
565
|
+
case opPUSH:
|
|
566
|
+
v, _ := vm.val(args[0])
|
|
567
|
+
if e := vm.push(v); e != "" {
|
|
568
|
+
return false, e
|
|
569
|
+
}
|
|
570
|
+
case opPOP:
|
|
571
|
+
v, e := vm.pop()
|
|
572
|
+
if e != "" {
|
|
573
|
+
return false, e
|
|
574
|
+
}
|
|
575
|
+
vm.setReg(int(args[0].value), v)
|
|
576
|
+
case opCALL, opBL:
|
|
577
|
+
if e := vm.push(uint64(vm.pc)); e != "" {
|
|
578
|
+
return false, e
|
|
579
|
+
}
|
|
580
|
+
t, _ := vm.val(args[0])
|
|
581
|
+
vm.pc = int(t)
|
|
582
|
+
case opRET:
|
|
583
|
+
v, e := vm.pop()
|
|
584
|
+
if e != "" {
|
|
585
|
+
return false, e
|
|
586
|
+
}
|
|
587
|
+
vm.pc = int(v)
|
|
588
|
+
case opNOP:
|
|
589
|
+
// nothing
|
|
590
|
+
case opB:
|
|
591
|
+
cond := -1
|
|
592
|
+
target := uint64(0)
|
|
593
|
+
for _, a := range args {
|
|
594
|
+
if a.kind == kindCond {
|
|
595
|
+
cond = int(a.value)
|
|
596
|
+
} else {
|
|
597
|
+
t, ok := vm.val(a)
|
|
598
|
+
if ok {
|
|
599
|
+
target = t
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
if cond >= 0 && !vm.condition(uint8(cond)) {
|
|
604
|
+
break
|
|
605
|
+
}
|
|
606
|
+
vm.pc = int(target)
|
|
607
|
+
case opIN:
|
|
608
|
+
vm.setReg(int(args[0].value), vm.readLineInt())
|
|
609
|
+
case opOUT:
|
|
610
|
+
if e := vm.doOut(args[0]); e != "" {
|
|
611
|
+
return false, e
|
|
612
|
+
}
|
|
613
|
+
case opHALT:
|
|
614
|
+
return true, ""
|
|
615
|
+
// load/store
|
|
616
|
+
case opLOAD:
|
|
617
|
+
addr, e := vm.loadStoreAddr(args[1])
|
|
618
|
+
if e != "" {
|
|
619
|
+
return false, e
|
|
620
|
+
}
|
|
621
|
+
if e := vm.checkAddr(addr, 4); e != "" {
|
|
622
|
+
return false, e
|
|
623
|
+
}
|
|
624
|
+
v := uint64(binary.LittleEndian.Uint32(vm.mem[addr : addr+4]))
|
|
625
|
+
vm.setReg(int(args[0].value), v)
|
|
626
|
+
case opLW:
|
|
627
|
+
addr, e := vm.loadStoreAddr(args[1])
|
|
628
|
+
if e != "" {
|
|
629
|
+
return false, e
|
|
630
|
+
}
|
|
631
|
+
if e := vm.checkAddr(addr, 4); e != "" {
|
|
632
|
+
return false, e
|
|
633
|
+
}
|
|
634
|
+
v := int64(binary.LittleEndian.Uint32(vm.mem[addr : addr+4]))
|
|
635
|
+
if v&0x80000000 != 0 {
|
|
636
|
+
v -= 1 << 32
|
|
637
|
+
}
|
|
638
|
+
vm.setReg(int(args[0].value), uint64(v)&mask64)
|
|
639
|
+
case opSTORE, opSW:
|
|
640
|
+
addr, e := vm.loadStoreAddr(args[1])
|
|
641
|
+
if e != "" {
|
|
642
|
+
return false, e
|
|
643
|
+
}
|
|
644
|
+
if e := vm.checkAddr(addr, 4); e != "" {
|
|
645
|
+
return false, e
|
|
646
|
+
}
|
|
647
|
+
rs := vm.reg(int(args[0].value))
|
|
648
|
+
binary.LittleEndian.PutUint32(vm.mem[addr:addr+4], uint32(rs))
|
|
649
|
+
case opLD:
|
|
650
|
+
addr, e := vm.loadStoreAddr(args[1])
|
|
651
|
+
if e != "" {
|
|
652
|
+
return false, e
|
|
653
|
+
}
|
|
654
|
+
v, e := vm.readQ(addr)
|
|
655
|
+
if e != "" {
|
|
656
|
+
return false, e
|
|
657
|
+
}
|
|
658
|
+
vm.setReg(int(args[0].value), v)
|
|
659
|
+
case opSD:
|
|
660
|
+
addr, e := vm.loadStoreAddr(args[1])
|
|
661
|
+
if e != "" {
|
|
662
|
+
return false, e
|
|
663
|
+
}
|
|
664
|
+
rs := vm.reg(int(args[0].value))
|
|
665
|
+
if e := vm.writeQ(addr, rs); e != "" {
|
|
666
|
+
return false, e
|
|
667
|
+
}
|
|
668
|
+
case opLB:
|
|
669
|
+
addr, e := vm.loadStoreAddr(args[1])
|
|
670
|
+
if e != "" {
|
|
671
|
+
return false, e
|
|
672
|
+
}
|
|
673
|
+
if e := vm.checkAddr(addr, 1); e != "" {
|
|
674
|
+
return false, e
|
|
675
|
+
}
|
|
676
|
+
v := int64(vm.mem[addr])
|
|
677
|
+
if v&0x80 != 0 {
|
|
678
|
+
v -= 256
|
|
679
|
+
}
|
|
680
|
+
vm.setReg(int(args[0].value), uint64(v)&mask64)
|
|
681
|
+
case opLH:
|
|
682
|
+
addr, e := vm.loadStoreAddr(args[1])
|
|
683
|
+
if e != "" {
|
|
684
|
+
return false, e
|
|
685
|
+
}
|
|
686
|
+
if e := vm.checkAddr(addr, 2); e != "" {
|
|
687
|
+
return false, e
|
|
688
|
+
}
|
|
689
|
+
v := int64(binary.LittleEndian.Uint16(vm.mem[addr : addr+2]))
|
|
690
|
+
if v&0x8000 != 0 {
|
|
691
|
+
v -= 65536
|
|
692
|
+
}
|
|
693
|
+
vm.setReg(int(args[0].value), uint64(v)&mask64)
|
|
694
|
+
case opSB:
|
|
695
|
+
addr, e := vm.loadStoreAddr(args[1])
|
|
696
|
+
if e != "" {
|
|
697
|
+
return false, e
|
|
698
|
+
}
|
|
699
|
+
if e := vm.checkAddr(addr, 1); e != "" {
|
|
700
|
+
return false, e
|
|
701
|
+
}
|
|
702
|
+
vm.mem[addr] = byte(vm.reg(int(args[0].value)) & 0xFF)
|
|
703
|
+
case opSH:
|
|
704
|
+
addr, e := vm.loadStoreAddr(args[1])
|
|
705
|
+
if e != "" {
|
|
706
|
+
return false, e
|
|
707
|
+
}
|
|
708
|
+
if e := vm.checkAddr(addr, 2); e != "" {
|
|
709
|
+
return false, e
|
|
710
|
+
}
|
|
711
|
+
binary.LittleEndian.PutUint16(vm.mem[addr:addr+2], uint16(vm.reg(int(args[0].value))&0xFFFF))
|
|
712
|
+
// 立即数算术
|
|
713
|
+
case opADDI:
|
|
714
|
+
rd, rs := int(args[0].value), int(args[1].value)
|
|
715
|
+
v, _ := vm.val(args[2])
|
|
716
|
+
vm.setReg(rd, (vm.reg(rs)+v)&mask64)
|
|
717
|
+
case opXORI:
|
|
718
|
+
rd, rs := int(args[0].value), int(args[1].value)
|
|
719
|
+
v, _ := vm.val(args[2])
|
|
720
|
+
vm.setReg(rd, vm.reg(rs)^v)
|
|
721
|
+
case opORI:
|
|
722
|
+
rd, rs := int(args[0].value), int(args[1].value)
|
|
723
|
+
v, _ := vm.val(args[2])
|
|
724
|
+
vm.setReg(rd, vm.reg(rs)|v)
|
|
725
|
+
case opANDI:
|
|
726
|
+
rd, rs := int(args[0].value), int(args[1].value)
|
|
727
|
+
v, _ := vm.val(args[2])
|
|
728
|
+
vm.setReg(rd, vm.reg(rs)&v)
|
|
729
|
+
case opLSL:
|
|
730
|
+
rd, rn := int(args[0].value), int(args[1].value)
|
|
731
|
+
v, _ := vm.val(args[2])
|
|
732
|
+
vm.setReg(rd, (vm.reg(rn)<<(v&63))&mask64)
|
|
733
|
+
case opLSR:
|
|
734
|
+
rd, rn := int(args[0].value), int(args[1].value)
|
|
735
|
+
v, _ := vm.val(args[2])
|
|
736
|
+
vm.setReg(rd, vm.reg(rn)>>(v&63))
|
|
737
|
+
case opASR:
|
|
738
|
+
// 算术右移 (保留符号), 与 Python _op_asr 一致
|
|
739
|
+
rd, rn := int(args[0].value), int(args[1].value)
|
|
740
|
+
amt, _ := vm.val(args[2])
|
|
741
|
+
sv := int64(vm.reg(rn))
|
|
742
|
+
vm.setReg(rd, uint64(sv>>(amt&63))&mask64)
|
|
743
|
+
case opSYS:
|
|
744
|
+
if len(args) == 0 || args[0].kind != kindImm {
|
|
745
|
+
return false, "SYS requires an immediate call id"
|
|
746
|
+
}
|
|
747
|
+
if e := vm.doSyscall(uint64(args[0].value)); e != "" {
|
|
748
|
+
return false, e
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return false, ""
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
func (vm *vmState) loadStoreAddr(op operand) (uint64, string) {
|
|
755
|
+
if op.kind == kindMem {
|
|
756
|
+
addr, _ := vm.memAddr(op)
|
|
757
|
+
return addr, ""
|
|
758
|
+
}
|
|
759
|
+
v, ok := vm.val(op)
|
|
760
|
+
if !ok {
|
|
761
|
+
return 0, "bad memory operand"
|
|
762
|
+
}
|
|
763
|
+
return v, ""
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// sdiv: 有符号 64 位除法, 向零截断
|
|
767
|
+
func sdiv(a, b uint64) uint64 {
|
|
768
|
+
sa := int64(a)
|
|
769
|
+
sb := int64(b)
|
|
770
|
+
q := sa / sb // Go 整数除法即向零截断
|
|
771
|
+
return uint64(q) & mask64
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
func (vm *vmState) doOut(op operand) string {
|
|
775
|
+
if op.kind == kindStr {
|
|
776
|
+
vm.outWrite(vm.readCString(uint64(op.value)))
|
|
777
|
+
return ""
|
|
778
|
+
}
|
|
779
|
+
v, ok := vm.val(op)
|
|
780
|
+
if !ok {
|
|
781
|
+
return "bad OUT operand"
|
|
782
|
+
}
|
|
783
|
+
if op.kind == kindFloat || op.kind == kindVec || op.kind == kindVecLane {
|
|
784
|
+
vm.outWrite(formatFloat(bitsToF(v)))
|
|
785
|
+
return ""
|
|
786
|
+
}
|
|
787
|
+
if v == 10 {
|
|
788
|
+
vm.outByte('\n')
|
|
789
|
+
} else {
|
|
790
|
+
vm.outWrite(strconv.FormatUint(v, 10))
|
|
791
|
+
}
|
|
792
|
+
return ""
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
func (vm *vmState) readLineInt() uint64 {
|
|
796
|
+
for vm.inPos < len(vm.inData) {
|
|
797
|
+
end := vm.inPos
|
|
798
|
+
for end < len(vm.inData) && vm.inData[end] != '\n' {
|
|
799
|
+
end++
|
|
800
|
+
}
|
|
801
|
+
line := strings.TrimSpace(string(vm.inData[vm.inPos:end]))
|
|
802
|
+
if end < len(vm.inData) {
|
|
803
|
+
vm.inPos = end + 1
|
|
804
|
+
} else {
|
|
805
|
+
vm.inPos = end
|
|
806
|
+
}
|
|
807
|
+
n, err := strconv.ParseInt(line, 10, 64)
|
|
808
|
+
if err == nil {
|
|
809
|
+
return uint64(n) & mask64
|
|
810
|
+
}
|
|
811
|
+
return 0
|
|
812
|
+
}
|
|
813
|
+
return 0
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// ---------------- SYS ----------------
|
|
817
|
+
|
|
818
|
+
func (vm *vmState) doSyscall(id uint64) string {
|
|
819
|
+
x0 := vm.reg(0)
|
|
820
|
+
x1 := vm.reg(1)
|
|
821
|
+
x2 := vm.reg(2)
|
|
822
|
+
|
|
823
|
+
switch id {
|
|
824
|
+
case sysABS:
|
|
825
|
+
vm.setReg(0, uint64(abs64(toSigned(x0)))&mask64)
|
|
826
|
+
case sysSQRT:
|
|
827
|
+
vm.setReg(0, fToBits(math.Sqrt(bitsToF(x0))))
|
|
828
|
+
case sysPOW:
|
|
829
|
+
vm.setReg(0, fToBits(math.Pow(bitsToF(x0), bitsToF(x1))))
|
|
830
|
+
case sysSIN:
|
|
831
|
+
vm.setReg(0, fToBits(math.Sin(bitsToF(x0))))
|
|
832
|
+
case sysCOS:
|
|
833
|
+
vm.setReg(0, fToBits(math.Cos(bitsToF(x0))))
|
|
834
|
+
case sysTAN:
|
|
835
|
+
vm.setReg(0, fToBits(math.Tan(bitsToF(x0))))
|
|
836
|
+
case sysFADD:
|
|
837
|
+
vm.setReg(0, fToBits(bitsToF(x0)+bitsToF(x1)))
|
|
838
|
+
case sysFSUB:
|
|
839
|
+
vm.setReg(0, fToBits(bitsToF(x0)-bitsToF(x1)))
|
|
840
|
+
case sysFMUL:
|
|
841
|
+
vm.setReg(0, fToBits(bitsToF(x0)*bitsToF(x1)))
|
|
842
|
+
case sysFDIV:
|
|
843
|
+
b := bitsToF(x1)
|
|
844
|
+
if b == 0 {
|
|
845
|
+
return "Float division by zero (SYS)"
|
|
846
|
+
}
|
|
847
|
+
vm.setReg(0, fToBits(bitsToF(x0)/b))
|
|
848
|
+
case sysFCMP:
|
|
849
|
+
a, b := bitsToF(x0), bitsToF(x1)
|
|
850
|
+
r := uint64(0)
|
|
851
|
+
if a < b {
|
|
852
|
+
r = mask64 // -1 的无符号表示
|
|
853
|
+
} else if a > b {
|
|
854
|
+
r = 1
|
|
855
|
+
}
|
|
856
|
+
vm.setReg(0, r)
|
|
857
|
+
case sysFTOI:
|
|
858
|
+
vm.setReg(0, uint64(int64(bitsToF(x0)))&mask64)
|
|
859
|
+
case sysITOF:
|
|
860
|
+
vm.setReg(0, fToBits(float64(toSigned(x0))))
|
|
861
|
+
case sysRAND:
|
|
862
|
+
vm.setReg(0, uint64(vm.rng.Int63n(1<<31))&mask64)
|
|
863
|
+
case sysSRAND:
|
|
864
|
+
vm.rng.Seed(int64(x0))
|
|
865
|
+
case sysTIME:
|
|
866
|
+
vm.setReg(0, uint64(time.Now().Unix())&mask64)
|
|
867
|
+
case sysSTRLEN:
|
|
868
|
+
n := uint64(0)
|
|
869
|
+
for x0+n < uint64(len(vm.mem)) && vm.mem[x0+n] != 0 {
|
|
870
|
+
n++
|
|
871
|
+
}
|
|
872
|
+
vm.setReg(0, n)
|
|
873
|
+
case sysSTRCMP:
|
|
874
|
+
i := uint64(0)
|
|
875
|
+
for {
|
|
876
|
+
var ca, cb byte
|
|
877
|
+
if x0+i < uint64(len(vm.mem)) {
|
|
878
|
+
ca = vm.mem[x0+i]
|
|
879
|
+
}
|
|
880
|
+
if x1+i < uint64(len(vm.mem)) {
|
|
881
|
+
cb = vm.mem[x1+i]
|
|
882
|
+
}
|
|
883
|
+
if ca != cb || ca == 0 {
|
|
884
|
+
vm.setReg(0, uint64(int64(ca)-int64(cb))&mask64)
|
|
885
|
+
break
|
|
886
|
+
}
|
|
887
|
+
i++
|
|
888
|
+
}
|
|
889
|
+
case sysSTRCPY, sysSTRCAT:
|
|
890
|
+
dst := x0
|
|
891
|
+
if id == sysSTRCAT {
|
|
892
|
+
for dst < uint64(len(vm.mem)) && vm.mem[dst] != 0 {
|
|
893
|
+
dst++
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
src := x1
|
|
897
|
+
i := uint64(0)
|
|
898
|
+
for {
|
|
899
|
+
var ch byte
|
|
900
|
+
if src+i < uint64(len(vm.mem)) {
|
|
901
|
+
ch = vm.mem[src+i]
|
|
902
|
+
}
|
|
903
|
+
if e := vm.checkAddr(dst+i, 1); e != "" {
|
|
904
|
+
return e
|
|
905
|
+
}
|
|
906
|
+
vm.mem[dst+i] = ch
|
|
907
|
+
i++
|
|
908
|
+
if ch == 0 {
|
|
909
|
+
break
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
vm.setReg(0, x0)
|
|
913
|
+
case sysMALLOC:
|
|
914
|
+
size := (x0 + 15) &^ uint64(15)
|
|
915
|
+
ptr := vm.heapPtr
|
|
916
|
+
vm.heapPtr += size
|
|
917
|
+
if vm.heapPtr > vm.sp {
|
|
918
|
+
return "Heap exhausted"
|
|
919
|
+
}
|
|
920
|
+
vm.setReg(0, ptr)
|
|
921
|
+
case sysPRINTFLO:
|
|
922
|
+
vm.outWrite(formatFloat(bitsToF(x0)))
|
|
923
|
+
case sysITOA:
|
|
924
|
+
addr := vm.sysBuffer()
|
|
925
|
+
s := strconv.FormatInt(toSigned(x0), 10)
|
|
926
|
+
if e := vm.writeString(addr, s); e != "" {
|
|
927
|
+
return e
|
|
928
|
+
}
|
|
929
|
+
vm.setReg(0, addr)
|
|
930
|
+
case sysFTOA:
|
|
931
|
+
addr := vm.sysBuffer()
|
|
932
|
+
s := formatFloat(bitsToF(x0))
|
|
933
|
+
if e := vm.writeString(addr, s); e != "" {
|
|
934
|
+
return e
|
|
935
|
+
}
|
|
936
|
+
vm.setReg(0, addr)
|
|
937
|
+
case sysPRINTSTR:
|
|
938
|
+
vm.outWrite(vm.readCString(x0))
|
|
939
|
+
case sysSTRCONCAT:
|
|
940
|
+
sa := vm.readCString(x0)
|
|
941
|
+
sb := vm.readCString(x1)
|
|
942
|
+
data := []byte(sa + sb + "\x00")
|
|
943
|
+
size := uint64(len(data)+15) &^ uint64(15)
|
|
944
|
+
ptr := vm.heapPtr
|
|
945
|
+
vm.heapPtr += size
|
|
946
|
+
if vm.heapPtr > vm.sp {
|
|
947
|
+
return "Heap exhausted (string concat)"
|
|
948
|
+
}
|
|
949
|
+
if e := vm.checkAddr(ptr, len(data)); e != "" {
|
|
950
|
+
return e
|
|
951
|
+
}
|
|
952
|
+
copy(vm.mem[ptr:ptr+uint64(len(data))], data)
|
|
953
|
+
vm.setReg(0, ptr)
|
|
954
|
+
case sysBOOLSTR:
|
|
955
|
+
addr := vm.sysBuffer()
|
|
956
|
+
s := "false"
|
|
957
|
+
if x0 != 0 {
|
|
958
|
+
s = "true"
|
|
959
|
+
}
|
|
960
|
+
if e := vm.writeString(addr, s); e != "" {
|
|
961
|
+
return e
|
|
962
|
+
}
|
|
963
|
+
vm.setReg(0, addr)
|
|
964
|
+
case sysSUBSTR:
|
|
965
|
+
// substr(s, start, len): 按字符索引, 越界自动裁剪
|
|
966
|
+
runes := []rune(vm.readCString(x0))
|
|
967
|
+
n := int64(len(runes))
|
|
968
|
+
start := int64(0)
|
|
969
|
+
if int64(x1) > n {
|
|
970
|
+
start = n
|
|
971
|
+
} else if int64(x1) > 0 {
|
|
972
|
+
start = int64(x1)
|
|
973
|
+
}
|
|
974
|
+
length := int64(0)
|
|
975
|
+
if int64(x2) > 0 {
|
|
976
|
+
length = int64(x2)
|
|
977
|
+
}
|
|
978
|
+
end := start + length
|
|
979
|
+
if end > n {
|
|
980
|
+
end = n
|
|
981
|
+
}
|
|
982
|
+
p, e := vm.heapDupString(string(runes[start:end]))
|
|
983
|
+
if e != "" {
|
|
984
|
+
return e
|
|
985
|
+
}
|
|
986
|
+
vm.setReg(0, p)
|
|
987
|
+
case sysINDEXOF:
|
|
988
|
+
hay := vm.readCString(x0)
|
|
989
|
+
needle := vm.readCString(x1)
|
|
990
|
+
bi := strings.Index(hay, needle)
|
|
991
|
+
idx := int64(-1)
|
|
992
|
+
if bi >= 0 {
|
|
993
|
+
idx = int64(len([]rune(hay[:bi])))
|
|
994
|
+
}
|
|
995
|
+
vm.setReg(0, uint64(idx)&mask64)
|
|
996
|
+
case sysTOUPPER:
|
|
997
|
+
p, e := vm.heapDupString(strings.ToUpper(vm.readCString(x0)))
|
|
998
|
+
if e != "" {
|
|
999
|
+
return e
|
|
1000
|
+
}
|
|
1001
|
+
vm.setReg(0, p)
|
|
1002
|
+
case sysTOLOWER:
|
|
1003
|
+
p, e := vm.heapDupString(strings.ToLower(vm.readCString(x0)))
|
|
1004
|
+
if e != "" {
|
|
1005
|
+
return e
|
|
1006
|
+
}
|
|
1007
|
+
vm.setReg(0, p)
|
|
1008
|
+
case sysABORT:
|
|
1009
|
+
msg := vm.readCString(x0)
|
|
1010
|
+
if msg != "" {
|
|
1011
|
+
return "Runtime abort: " + msg
|
|
1012
|
+
}
|
|
1013
|
+
return "Runtime abort"
|
|
1014
|
+
case sysFLOOR:
|
|
1015
|
+
vm.setReg(0, fToBits(math.Floor(bitsToF(x0))))
|
|
1016
|
+
case sysCEIL:
|
|
1017
|
+
vm.setReg(0, fToBits(math.Ceil(bitsToF(x0))))
|
|
1018
|
+
case sysROUND:
|
|
1019
|
+
vm.setReg(0, fToBits(math.Floor(bitsToF(x0)+0.5)))
|
|
1020
|
+
case sysATOI:
|
|
1021
|
+
s := strings.TrimSpace(vm.readCString(x0))
|
|
1022
|
+
n, err := strconv.ParseInt(s, 10, 64)
|
|
1023
|
+
if err != nil {
|
|
1024
|
+
vm.setReg(0, 0)
|
|
1025
|
+
} else {
|
|
1026
|
+
vm.setReg(0, uint64(n)&mask64)
|
|
1027
|
+
}
|
|
1028
|
+
case sysTRIM:
|
|
1029
|
+
p, e := vm.heapDupString(strings.TrimSpace(vm.readCString(x0)))
|
|
1030
|
+
if e != "" {
|
|
1031
|
+
return e
|
|
1032
|
+
}
|
|
1033
|
+
vm.setReg(0, p)
|
|
1034
|
+
case sysLTRIM:
|
|
1035
|
+
p, e := vm.heapDupString(strings.TrimLeft(vm.readCString(x0), " \t\n\r\v\f"))
|
|
1036
|
+
if e != "" {
|
|
1037
|
+
return e
|
|
1038
|
+
}
|
|
1039
|
+
vm.setReg(0, p)
|
|
1040
|
+
case sysRTRIM:
|
|
1041
|
+
p, e := vm.heapDupString(strings.TrimRight(vm.readCString(x0), " \t\n\r\v\f"))
|
|
1042
|
+
if e != "" {
|
|
1043
|
+
return e
|
|
1044
|
+
}
|
|
1045
|
+
vm.setReg(0, p)
|
|
1046
|
+
case sysAUDIOPLAY:
|
|
1047
|
+
vm.setReg(0, vm.audioPlay(vm.readCString(x0)))
|
|
1048
|
+
case sysAUDIOSTOP:
|
|
1049
|
+
vm.audioStop()
|
|
1050
|
+
case sysAUDIOVOL:
|
|
1051
|
+
vm.audioVolume(x0)
|
|
1052
|
+
case sysAUDIOWAIT:
|
|
1053
|
+
vm.audioWait()
|
|
1054
|
+
case sysCANVASNEW:
|
|
1055
|
+
vm.canvasNew(x0, x1)
|
|
1056
|
+
case sysCANVASSET:
|
|
1057
|
+
vm.canvasSetColor(x0)
|
|
1058
|
+
case sysCANVASRECT:
|
|
1059
|
+
vm.canvasRect(x0, x1, vm.reg(2), vm.reg(3))
|
|
1060
|
+
case sysCANVASCIRC:
|
|
1061
|
+
vm.canvasCircle(x0, x1, vm.reg(2))
|
|
1062
|
+
case sysCANVASTEXT:
|
|
1063
|
+
vm.canvasText(x0, x1, vm.readCString(vm.reg(2)))
|
|
1064
|
+
case sysCANVASLINE:
|
|
1065
|
+
vm.canvasLine(x0, x1, vm.reg(2), vm.reg(3))
|
|
1066
|
+
case sysCANVASSAVE:
|
|
1067
|
+
vm.setReg(0, vm.canvasSave(vm.readCString(x0)))
|
|
1068
|
+
case sysCANVASSHOW:
|
|
1069
|
+
vm.setReg(0, vm.canvasShow())
|
|
1070
|
+
// 系统原生交互 (文件/进程/环境/系统信息)
|
|
1071
|
+
case sysFILEREAD:
|
|
1072
|
+
vm.setReg(0, vm.fileRead(vm.readCString(x0)))
|
|
1073
|
+
case sysFILEWRITE:
|
|
1074
|
+
vm.setReg(0, vm.fileWrite(vm.readCString(x0), vm.readCString(x1)))
|
|
1075
|
+
case sysFILEAPPEND:
|
|
1076
|
+
vm.setReg(0, vm.fileAppend(vm.readCString(x0), vm.readCString(x1)))
|
|
1077
|
+
case sysFILEEXISTS:
|
|
1078
|
+
vm.setReg(0, vm.fileExists(vm.readCString(x0)))
|
|
1079
|
+
case sysFILEDELETE:
|
|
1080
|
+
vm.setReg(0, vm.fileDelete(vm.readCString(x0)))
|
|
1081
|
+
case sysFILESIZE:
|
|
1082
|
+
vm.setReg(0, vm.fileSize(vm.readCString(x0)))
|
|
1083
|
+
case sysMKDIR:
|
|
1084
|
+
vm.setReg(0, vm.mkdir(vm.readCString(x0)))
|
|
1085
|
+
case sysDIRLIST:
|
|
1086
|
+
vm.setReg(0, vm.dirList(vm.readCString(x0)))
|
|
1087
|
+
case sysEXEC:
|
|
1088
|
+
vm.setReg(0, vm.execCmd(vm.readCString(x0)))
|
|
1089
|
+
case sysEXECOUTPUT:
|
|
1090
|
+
vm.setReg(0, vm.execOutput(vm.readCString(x0)))
|
|
1091
|
+
case sysGETENV:
|
|
1092
|
+
vm.setReg(0, vm.getenv(vm.readCString(x0)))
|
|
1093
|
+
case sysSETENV:
|
|
1094
|
+
vm.setReg(0, vm.setenv(vm.readCString(x0), vm.readCString(x1)))
|
|
1095
|
+
case sysOSNAME:
|
|
1096
|
+
vm.setReg(0, vm.osName())
|
|
1097
|
+
case sysHOSTNAME:
|
|
1098
|
+
vm.setReg(0, vm.hostname())
|
|
1099
|
+
case sysUSERNAME:
|
|
1100
|
+
vm.setReg(0, vm.username())
|
|
1101
|
+
case sysCWD:
|
|
1102
|
+
vm.setReg(0, vm.cwd())
|
|
1103
|
+
case sysHOMEDIR:
|
|
1104
|
+
vm.setReg(0, vm.homeDir())
|
|
1105
|
+
// Termux API
|
|
1106
|
+
case sysTERMUXAVAIL:
|
|
1107
|
+
vm.setReg(0, vm.termuxAvailable())
|
|
1108
|
+
case sysTERMUXNOTIFY:
|
|
1109
|
+
vm.setReg(0, vm.termuxNotify(vm.readCString(x0), vm.readCString(x1)))
|
|
1110
|
+
case sysTERMUXTOAST:
|
|
1111
|
+
vm.setReg(0, vm.termuxToast(vm.readCString(x0)))
|
|
1112
|
+
case sysTERMUXCLIPGET:
|
|
1113
|
+
vm.setReg(0, vm.termuxClipboardGet())
|
|
1114
|
+
case sysTERMUXCLIPSET:
|
|
1115
|
+
vm.setReg(0, vm.termuxClipboardSet(vm.readCString(x0)))
|
|
1116
|
+
case sysTERMUXBATTERY:
|
|
1117
|
+
vm.setReg(0, vm.termuxBattery())
|
|
1118
|
+
case sysTERMUXVIBRATE:
|
|
1119
|
+
vm.setReg(0, vm.termuxVibrate(x0))
|
|
1120
|
+
case sysTERMUXTTS:
|
|
1121
|
+
vm.setReg(0, vm.termuxTTS(vm.readCString(x0)))
|
|
1122
|
+
case sysTERMUXLOCATION:
|
|
1123
|
+
vm.setReg(0, vm.termuxLocation())
|
|
1124
|
+
case sysTERMUXWIFI:
|
|
1125
|
+
vm.setReg(0, vm.termuxWifiInfo())
|
|
1126
|
+
case sysTERMUXDIALOG:
|
|
1127
|
+
vm.setReg(0, vm.termuxDialog(vm.readCString(x0)))
|
|
1128
|
+
case sysTERMUXSMS:
|
|
1129
|
+
vm.setReg(0, vm.termuxSmsSend(vm.readCString(x0), vm.readCString(x1)))
|
|
1130
|
+
default:
|
|
1131
|
+
return "Unknown SYS call id"
|
|
1132
|
+
}
|
|
1133
|
+
return ""
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// heapDupString 在堆上分配 NUL 结尾字符串副本, 返回 (指针, 错误)。
|
|
1137
|
+
func (vm *vmState) heapDupString(s string) (uint64, string) {
|
|
1138
|
+
data := []byte(s + "\x00")
|
|
1139
|
+
size := (uint64(len(data)) + 15) &^ uint64(15)
|
|
1140
|
+
ptr := vm.heapPtr
|
|
1141
|
+
vm.heapPtr += size
|
|
1142
|
+
if vm.heapPtr > vm.sp {
|
|
1143
|
+
return 0, "Heap exhausted (string operation)"
|
|
1144
|
+
}
|
|
1145
|
+
if e := vm.checkAddr(ptr, len(data)); e != "" {
|
|
1146
|
+
return 0, e
|
|
1147
|
+
}
|
|
1148
|
+
copy(vm.mem[ptr:ptr+uint64(len(data))], data)
|
|
1149
|
+
return ptr, ""
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
func abs64(v int64) int64 {
|
|
1153
|
+
if v < 0 {
|
|
1154
|
+
return -v
|
|
1155
|
+
}
|
|
1156
|
+
return v
|
|
1157
|
+
}
|