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.
Files changed (54) hide show
  1. codecin/__init__.py +27 -0
  2. codecin/aot.py +229 -0
  3. codecin/assembler.py +548 -0
  4. codecin/cache.py +71 -0
  5. codecin/cin.py +2558 -0
  6. codecin/cli.py +282 -0
  7. codecin/config.py +58 -0
  8. codecin/console.py +183 -0
  9. codecin/cpu.py +1654 -0
  10. codecin/crom.py +222 -0
  11. codecin/debugger.py +659 -0
  12. codecin/disasm.py +86 -0
  13. codecin/errors.py +58 -0
  14. codecin/isa.py +457 -0
  15. codecin/jit.py +270 -0
  16. codecin/libcodecin_native.so +0 -0
  17. codecin/logger.py +145 -0
  18. codecin/memory.py +348 -0
  19. codecin/native/aot/aot.go +70 -0
  20. codecin/native/aot/build.go +219 -0
  21. codecin/native/aot/stub_main.go.txt +22 -0
  22. codecin/native/build.ps1 +33 -0
  23. codecin/native/build.sh +48 -0
  24. codecin/native/cmd/codecin/main.go +287 -0
  25. codecin/native/compiler/codegen.go +1938 -0
  26. codecin/native/compiler/compile_test.go +164 -0
  27. codecin/native/compiler/parser.go +1071 -0
  28. codecin/native/compiler/syscalls.go +86 -0
  29. codecin/native/compiler/tokenizer.go +336 -0
  30. codecin/native/compiler/types.go +213 -0
  31. codecin/native/engine/audio.go +152 -0
  32. codecin/native/engine/audio_other.go +46 -0
  33. codecin/native/engine/audio_windows.go +43 -0
  34. codecin/native/engine/canvas.go +271 -0
  35. codecin/native/engine/crom.go +86 -0
  36. codecin/native/engine/encode.go +93 -0
  37. codecin/native/engine/engine_test.go +198 -0
  38. codecin/native/engine/isa_gen.go +445 -0
  39. codecin/native/engine/system.go +190 -0
  40. codecin/native/engine/termux.go +113 -0
  41. codecin/native/engine/version_gen.go +7 -0
  42. codecin/native/engine/vm.go +1157 -0
  43. codecin/native/go.mod +3 -0
  44. codecin/native/ir/ir.go +48 -0
  45. codecin/native/main.go +225 -0
  46. codecin/native.py +336 -0
  47. codecin/registers.py +130 -0
  48. codecin/stats.py +235 -0
  49. codecin-5.4.2.dist-info/METADATA +985 -0
  50. codecin-5.4.2.dist-info/RECORD +54 -0
  51. codecin-5.4.2.dist-info/WHEEL +5 -0
  52. codecin-5.4.2.dist-info/entry_points.txt +2 -0
  53. codecin-5.4.2.dist-info/licenses/LICENSE +7 -0
  54. codecin-5.4.2.dist-info/top_level.txt +1 -0
codecin/cpu.py ADDED
@@ -0,0 +1,1654 @@
1
+ import math
2
+ import os
3
+ import random
4
+ import struct
5
+ import sys
6
+ import time
7
+ from typing import Any, Dict, List, Optional, Tuple, Union
8
+
9
+ from .assembler import Assembler
10
+ from .cache import Cache
11
+ from .config import Config
12
+ from .console import Colors, Console, Panel
13
+ from .errors import CPUSimulatorError, ExecutionError
14
+ from .isa import Constants, Syscall
15
+ from .logger import Logger
16
+ from .memory import FastMemory
17
+ from .registers import RegisterFile, VectorRegisterFile
18
+ from .stats import Statistics
19
+
20
+ Operand = Tuple[Any, ...]
21
+ Instruction = Tuple[str, List[Operand]]
22
+
23
+ MASK64 = 0xFFFFFFFFFFFFFFFF
24
+ MASK32 = 0xFFFFFFFF
25
+
26
+
27
+ def _f_to_bits(f: float) -> int:
28
+ return struct.unpack('<Q', struct.pack('<d', f))[0]
29
+
30
+
31
+ def _bits_to_f(b: int) -> float:
32
+ return struct.unpack('<d', struct.pack('<Q', b & MASK64))[0]
33
+
34
+
35
+ def _format_float(v: float) -> str:
36
+ if math.isnan(v):
37
+ return "NaN"
38
+ if math.isinf(v):
39
+ return "+Inf" if v > 0 else "-Inf"
40
+ s = repr(v)
41
+ if 'e' not in s and 'E' not in s and '.' in s:
42
+ s = s.rstrip('0').rstrip('.')
43
+ return s or "0"
44
+
45
+
46
+ class CPU:
47
+ # 建议 7: 指令处理器自动注册 (方法名 _op_XXX -> 指令 XXX)。
48
+ # 别名: 无事件模型的 ARM64 等待/事件指令, 语义上等价 NOP (预留扩展点)。
49
+ _OP_HANDLER_PREFIX = '_op_'
50
+ _OP_ALIASES = {
51
+ 'WFE': '_op_nop', # Wait For Event: 无中断模型, 视作 NOP
52
+ 'WFI': '_op_nop', # Wait For Interrupt: 无中断模型, 视作 NOP
53
+ 'SEV': '_op_nop', # Send Event: 无多核事件模型, 视作 NOP
54
+ }
55
+
56
+ def __init__(self, config: Config, filename: Optional[str] = None,
57
+ crom_file: Optional[str] = None,
58
+ from_bin: bool = False,
59
+ console: Optional[Console] = None):
60
+
61
+ self.console = console or Console()
62
+ self.config = config
63
+ self.filename = filename
64
+
65
+ # debug 模式强制 DEBUG 级别 (超详细日志)
66
+ if config.debug_mode and config.log_level.upper() != 'DEBUG':
67
+ config.log_level = 'DEBUG'
68
+ self.logger = Logger(self.console, config.log_level)
69
+ if config.log_file:
70
+ self.logger.set_log_file(config.log_file)
71
+ # 逐指令超详细追踪开关 (DEBUG 级别启用)
72
+ self._trace = self.logger.is_debug
73
+
74
+ self.memory = FastMemory(config.mem_size)
75
+ if config.mmu:
76
+ from .memory import Mmu
77
+ self.memory.attach_mmu(Mmu(config.mem_size))
78
+ self.cache = Cache(config.cache_size, config.cache_assoc)
79
+ # 内存访问日志 (DEBUG 级别生效)
80
+ self.memory.attach_logger(self.logger)
81
+
82
+ self.regs = RegisterFile(self.console)
83
+ self.vec_regs = VectorRegisterFile()
84
+
85
+ self.pstate: Dict[str, bool] = {'N': False, 'Z': False, 'C': False, 'V': False}
86
+ self.pc = 0
87
+ self.sp = (config.mem_size - Constants.STACK_SLOT) & ~0x7
88
+ self.heap_ptr = config.mem_size // 2
89
+
90
+ self.logger.dump("CPU 初始化", {
91
+ 'memory': f"0x{config.mem_size:x} bytes",
92
+ 'cache': f"{config.cache_size} lines x {config.cache_assoc}-way",
93
+ 'sp_init': f"0x{self.sp:x}",
94
+ 'heap_base': f"0x{self.heap_ptr:x}",
95
+ 'native': config.use_native,
96
+ 'jit': config.enable_jit,
97
+ 'log_level': config.log_level,
98
+ })
99
+
100
+ self.instructions: List[Instruction] = []
101
+ self.labels: Dict[str, int] = {}
102
+ self.data_labels: Dict[str, int] = {}
103
+ self.entry_pc = 0
104
+
105
+ self.stats = Statistics()
106
+ self.jit = None
107
+ if config.enable_jit and not config.debug_mode and not config.step_mode:
108
+ try:
109
+ from .jit import JITCompiler
110
+ self.jit = JITCompiler(logger=self.logger)
111
+ self.logger.info("JIT compiler enabled")
112
+ except Exception as e:
113
+ self.logger.warning(f"JIT unavailable: {e}")
114
+ self.running = False
115
+ self.is_debugging = False
116
+ self.breakpoints: set = set()
117
+ self.debug_server = None
118
+ # 建议 5: 'continue' 后豁免一次当前 PC 的断点命中 (防止原地重入)
119
+ self._resume_bp_pc: Optional[int] = None
120
+
121
+ self.input_buffer: str = ""
122
+ self._input_pos = 0
123
+ self.output_buffer: List[str] = []
124
+ self._capture_output = False
125
+ self.native_engine = None
126
+ self.native_used = False
127
+ # 执行期是否发生过错误 (供 CLI 决定退出码; 旧实现任何运行时错误
128
+ # 都只记日志, 进程仍以 0 退出)
129
+ self.execution_failed = False
130
+
131
+ self._sys_buffers = [bytearray(64) for _ in range(8)]
132
+ self._sys_buf_idx = 0
133
+ self._rand = random.Random(
134
+ config.seed if config.seed is not None else None)
135
+
136
+ self._init_dispatch()
137
+
138
+ if filename:
139
+ self.load_program(filename, crom_file=crom_file, from_bin=from_bin)
140
+
141
+ def load_program(self, filename: str, crom_file: Optional[str] = None,
142
+ from_bin: bool = False) -> None:
143
+ if not os.path.exists(filename):
144
+ raise CPUSimulatorError(f"File '{filename}' not found")
145
+
146
+ ext = os.path.splitext(filename)[1].lower()
147
+
148
+ if ext == '.cin':
149
+ from .cin import CINCompiler
150
+ compiler = CINCompiler(self.console, logger=self.logger)
151
+ result = compiler.compile(filename,
152
+ bounds_check=self.config.bounds_check)
153
+ self.instructions = result.instructions
154
+ self.labels = result.labels
155
+ self.data_labels = result.data_labels
156
+ for addr, data in result.data_writes:
157
+ self.memory.write_block(addr, data)
158
+ # pc 0 为 bootstrap (CALL main; HALT), main 标签为函数体入口
159
+ self.entry_pc = 0
160
+ self.pc = 0
161
+ self.logger.info(f"CIN compiled: {len(self.instructions)} instructions")
162
+ return
163
+
164
+ if from_bin or ext == '.bin':
165
+ from . import crom as crom_mod
166
+ crom_mod.load_bin(self, filename)
167
+ self.logger.info(f"Binary loaded: {len(self.instructions)} instructions")
168
+ return
169
+
170
+ # .pl / .asm
171
+ if crom_file is None:
172
+ base = os.path.splitext(filename)[0]
173
+ candidate = base + '.crom'
174
+ if os.path.exists(candidate):
175
+ crom_file = candidate
176
+ if crom_file and os.path.exists(crom_file):
177
+ from . import crom as crom_mod
178
+ crom_mod.load_crom(self.memory, crom_file, self.logger,
179
+ enable_mmu=self.config.mmu)
180
+
181
+ asm = Assembler(self.memory, self.console, strict=self.config.strict_mode,
182
+ logger=self.logger)
183
+ self.instructions, self.labels, self.data_labels = asm.assemble_file(filename)
184
+ self.entry_pc = self.labels.get('main', 0)
185
+ self.pc = self.entry_pc
186
+ self.cache.warmup(self.instructions)
187
+ self.logger.info(f"Assembly successful: {len(self.instructions)} instructions")
188
+ if self.logger.is_debug:
189
+ self.logger.dump("汇编标签表", {name: f"0x{pc:x}"
190
+ for name, pc in
191
+ sorted(self.labels.items())})
192
+ def _init_dispatch(self) -> None:
193
+ """自动注册指令处理器 (建议 7)。
194
+
195
+ 约定: CPU 上任意名为 ``_op_XXX`` 的可调用方法即指令 ``XXX`` 的处理器,
196
+ 不再手工维护 112 行映射表; 别名 (WFE/WFI/SEV -> NOP 语义) 见 _OP_ALIASES。
197
+ dispatch 键集合由 test_dispatch_complete 与 Opcode 枚举逐一校验。
198
+ """
199
+ t: Dict[str, Any] = {}
200
+ prefix = self._OP_HANDLER_PREFIX
201
+ for name in dir(self):
202
+ if not name.startswith(prefix):
203
+ continue
204
+ opcode_name = name[len(prefix):].upper()
205
+ handler = getattr(self, name)
206
+ if opcode_name and callable(handler):
207
+ t.setdefault(opcode_name, handler)
208
+ for opcode_name, handler_name in self._OP_ALIASES.items():
209
+ t[opcode_name] = getattr(self, handler_name)
210
+ self._dispatch = t
211
+
212
+ # ==================== 操作数辅助 ====================
213
+
214
+ def _reg(self, n: int) -> int:
215
+ if n == Constants.SP_REG:
216
+ return self.sp & MASK64
217
+ return self.regs.read(n)
218
+
219
+ def _set_reg(self, n: int, v: int) -> None:
220
+ v &= MASK64
221
+ if self._trace:
222
+ old = self._reg(n)
223
+ if old != v:
224
+ sv = v if v < (1 << 63) else v - (1 << 64)
225
+ self.logger.trace(f" R[{n}] {self._fmt_reg(n, old)} -> "
226
+ f"0x{v:016x} ({sv})")
227
+ if n == Constants.SP_REG:
228
+ self.sp = v
229
+ else:
230
+ self.regs.write(n, v)
231
+
232
+ @staticmethod
233
+ def _fmt_reg(n: int, v: int) -> str:
234
+ return f"0x{v:016x}"
235
+
236
+ def _fmt_op_trace(self, op: Operand) -> str:
237
+ """格式化操作数并附带当前值 (超详细追踪)。"""
238
+ kind = op[0]
239
+ try:
240
+ if kind == 'reg':
241
+ n = op[1]
242
+ v = self._reg(n)
243
+ return f"X{n}=0x{v:x}({v if v < (1 << 63) else v - (1 << 64)})"
244
+ if kind == 'imm':
245
+ return f"#{op[1]}"
246
+ if kind == 'mem':
247
+ addr = self._mem_addr(op)
248
+ return (f"[{op[1] if op[1] >= 0 else 'abs'}"
249
+ f"{op[2]:+d}]@0x{addr:x}"
250
+ f"=0x{self.memory.read_qword(addr):x}")
251
+ if kind == 'cond':
252
+ return (f"{op[1]}="
253
+ f"{int(self._condition(op[1]))}"
254
+ f"{{N={int(self.pstate['N'])} Z={int(self.pstate['Z'])} "
255
+ f"C={int(self.pstate['C'])} V={int(self.pstate['V'])}}}")
256
+ if kind == 'label':
257
+ return f"{op[1]}->0x{self.labels.get(op[1], -1):x}"
258
+ if kind == 'str':
259
+ return f'"@{op[1]}"'
260
+ if kind == 'float':
261
+ return f"#{op[1]}f"
262
+ except Exception:
263
+ pass
264
+ return self._fmt_operand(op)
265
+
266
+ def _trace_flags(self) -> str:
267
+ p = self.pstate
268
+ return (f"N={int(p['N'])} Z={int(p['Z'])} "
269
+ f"C={int(p['C'])} V={int(p['V'])}")
270
+
271
+ def _trace_cache(self, addr: int, hit: bool, kind: str) -> None:
272
+ cs = self.cache.get_stats()
273
+ self.logger.trace(
274
+ f" CACHE {'HIT ' if hit else 'MISS'} {kind} @0x{addr:x} "
275
+ f"(hit_rate={cs['hit_rate'] * 100:.1f}%)")
276
+
277
+ def _val(self, op: Operand) -> Union[int, float]:
278
+ kind = op[0]
279
+ if kind == 'reg':
280
+ return self._reg(op[1])
281
+ if kind == 'imm':
282
+ return op[1] & MASK64
283
+ if kind == 'vec':
284
+ return int(self.vec_regs.read_scalar(op[1]))
285
+ if kind == 'veclane':
286
+ return int(self.vec_regs.read_scalar(op[1], op[2]))
287
+ if kind == 'float':
288
+ return op[1]
289
+ if kind == 'mem':
290
+ addr = self._mem_addr(op)
291
+ return self.memory.read_qword(addr)
292
+ if kind == 'cond':
293
+ return 1 if self._condition(op[1]) else 0
294
+ if kind == 'str':
295
+ return op[1]
296
+ if kind == 'label':
297
+ target = self.labels.get(op[1])
298
+ if target is None:
299
+ raise ExecutionError(f"Undefined label: {op[1]}")
300
+ return target
301
+ raise ExecutionError(f"Unsupported operand kind: {kind}")
302
+
303
+ def _mem_addr(self, op: Operand) -> int:
304
+ # ('mem', base, off): base == -1 表示绝对地址
305
+ base = op[1] if len(op) > 1 else -1
306
+ off = op[2] if len(op) > 2 else 0
307
+ if isinstance(off, tuple):
308
+ off = self._val(off)
309
+ if base >= 0:
310
+ return (self._reg(base) + off) & MASK64
311
+ return off & MASK64
312
+
313
+ def _condition(self, cond: str) -> bool:
314
+ n, z, c, v = (self.pstate['N'], self.pstate['Z'],
315
+ self.pstate['C'], self.pstate['V'])
316
+ table = {
317
+ 'EQ': z, 'NE': not z,
318
+ 'CS': c, 'CC': not c,
319
+ 'MI': n, 'PL': not n,
320
+ 'VS': v, 'VC': not v,
321
+ 'HI': c and not z, 'LS': not c or z,
322
+ 'GE': n == v, 'LT': n != v,
323
+ 'GT': not z and (n == v), 'LE': z or (n != v),
324
+ 'AL': True, 'NV': False,
325
+ }
326
+ return table.get(cond.upper(), False)
327
+
328
+ def _set_flags_sub(self, a: int, b: int, result: int) -> None:
329
+ a &= MASK64
330
+ b &= MASK64
331
+ result &= MASK64
332
+ sa = a if a < (1 << 63) else a - (1 << 64)
333
+ sb = b if b < (1 << 63) else b - (1 << 64)
334
+ sr = sa - sb
335
+ old = dict(self.pstate)
336
+ self.pstate['Z'] = (result == 0)
337
+ self.pstate['N'] = bool(result & (1 << 63))
338
+ self.pstate['C'] = a >= b # 无借位
339
+ self.pstate['V'] = (sr > (1 << 63) - 1) or (sr < -(1 << 63))
340
+ if self._trace and old != self.pstate:
341
+ self.logger.trace(f" FLAGS <- {self._trace_flags()} "
342
+ f"(a=0x{a:x} b=0x{b:x})")
343
+
344
+ def _set_flags_add(self, a: int, b: int, result: int) -> None:
345
+ a &= MASK64
346
+ b &= MASK64
347
+ result &= MASK64
348
+ sa = a if a < (1 << 63) else a - (1 << 64)
349
+ sb = b if b < (1 << 63) else b - (1 << 64)
350
+ ss = sa + sb
351
+ old = dict(self.pstate)
352
+ self.pstate['Z'] = (result == 0)
353
+ self.pstate['N'] = bool(result & (1 << 63))
354
+ self.pstate['C'] = (a + b) > MASK64
355
+ self.pstate['V'] = (ss > (1 << 63) - 1) or (ss < -(1 << 63))
356
+ if self._trace and old != self.pstate:
357
+ self.logger.trace(f" FLAGS <- {self._trace_flags()} "
358
+ f"(a=0x{a:x} b=0x{b:x})")
359
+
360
+ # ==================== 栈 ====================
361
+
362
+ def _push(self, value: int) -> None:
363
+ self.sp = (self.sp - Constants.STACK_SLOT) & MASK64
364
+ if self.sp < self.heap_ptr + 4096:
365
+ raise ExecutionError("Stack overflow (collides with heap)")
366
+ self.memory.write_qword(self.sp, value & MASK64)
367
+ if self._trace:
368
+ self.logger.trace(f" PUSH @0x{self.sp:x} <- "
369
+ f"0x{value & MASK64:016x}")
370
+
371
+ def _pop(self) -> int:
372
+ if self.sp >= len(self.memory) - Constants.STACK_SLOT:
373
+ raise ExecutionError("Stack underflow")
374
+ value = self.memory.read_qword(self.sp)
375
+ self.sp = (self.sp + Constants.STACK_SLOT) & MASK64
376
+ if self._trace:
377
+ self.logger.trace(f" POP @0x{self.sp - 8:x} -> "
378
+ f"0x{value:016x}")
379
+ return value
380
+
381
+ def _check_stack(self) -> None:
382
+ if self.sp < self.heap_ptr + 4096:
383
+ raise ExecutionError("Stack overflow (collides with heap)")
384
+
385
+ # ==================== I/O ====================
386
+
387
+ def _emit_text(self, text: str) -> None:
388
+ if self._capture_output:
389
+ self.output_buffer.append(text)
390
+ else:
391
+ sys.stdout.write(text)
392
+ sys.stdout.flush()
393
+
394
+ def _read_input_int(self) -> int:
395
+ if self._input_pos < len(self.input_buffer):
396
+ end = self.input_buffer.find('\n', self._input_pos)
397
+ if end < 0:
398
+ end = len(self.input_buffer)
399
+ line = self.input_buffer[self._input_pos:end].strip()
400
+ self._input_pos = end + 1
401
+ try:
402
+ return int(line)
403
+ except ValueError:
404
+ return 0
405
+ try:
406
+ return int(input())
407
+ except (ValueError, EOFError):
408
+ return 0
409
+
410
+ # ==================== 基础指令 ====================
411
+
412
+ def _op_mov(self, args):
413
+ self._set_reg(args[0][1], self._val(args[1]))
414
+ return True
415
+
416
+ def _op_load(self, args):
417
+ rd = args[0][1]
418
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
419
+ self.stats.record_memory_read()
420
+ hit = self.cache.read(addr)
421
+ self.stats.record_cache(hit)
422
+ if self._trace:
423
+ self._trace_cache(addr, hit, 'R')
424
+ self._set_reg(rd, self.memory.read_dword(addr))
425
+ return True
426
+
427
+ def _op_store(self, args):
428
+ rs = args[0][1]
429
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
430
+ self.stats.record_memory_write()
431
+ hit = self.cache.write(addr)
432
+ self.stats.record_cache(hit)
433
+ if self._trace:
434
+ self._trace_cache(addr, hit, 'W')
435
+ self.memory.write_dword(addr, self._reg(rs))
436
+ return True
437
+
438
+ def _op_add(self, args):
439
+ rd = args[0][1]
440
+ self._set_reg(rd, self._reg(rd) + self._val(args[1]))
441
+ return True
442
+
443
+ def _op_sub(self, args):
444
+ rd = args[0][1]
445
+ self._set_reg(rd, self._reg(rd) - self._val(args[1]))
446
+ return True
447
+
448
+ def _op_mul(self, args):
449
+ rd = args[0][1]
450
+ self._set_reg(rd, self._reg(rd) * self._val(args[1]))
451
+ return True
452
+
453
+ def _op_div(self, args):
454
+ rd = args[0][1]
455
+ d = self._val(args[1])
456
+ if d == 0:
457
+ raise ExecutionError("Division by zero")
458
+ a = self._reg(rd)
459
+ self._set_reg(rd, self._sdiv(a, d))
460
+ return True
461
+
462
+ @staticmethod
463
+ def _sdiv(a: int, b: int) -> int:
464
+ """有符号 64 位除法。"""
465
+ sa = a if a < (1 << 63) else a - (1 << 64)
466
+ sb = b if b < (1 << 63) else b - (1 << 64)
467
+ q = abs(sa) // abs(sb)
468
+ if (sa < 0) != (sb < 0):
469
+ q = -q
470
+ return q & MASK64
471
+
472
+ def _op_and(self, args):
473
+ rd = args[0][1]
474
+ self._set_reg(rd, self._reg(rd) & self._val(args[1]))
475
+ return True
476
+
477
+ def _op_or(self, args):
478
+ rd = args[0][1]
479
+ self._set_reg(rd, self._reg(rd) | self._val(args[1]))
480
+ return True
481
+
482
+ def _op_xor(self, args):
483
+ rd = args[0][1]
484
+ self._set_reg(rd, self._reg(rd) ^ self._val(args[1]))
485
+ return True
486
+
487
+ def _op_shl(self, args):
488
+ rd = args[0][1]
489
+ self._set_reg(rd, self._reg(rd) << (self._val(args[1]) & 63))
490
+ return True
491
+
492
+ def _op_shr(self, args):
493
+ rd = args[0][1]
494
+ self._set_reg(rd, (self._reg(rd) & MASK64) >> (self._val(args[1]) & 63))
495
+ return True
496
+
497
+ def _op_inc(self, args):
498
+ rd = args[0][1]
499
+ self._set_reg(rd, self._reg(rd) + 1)
500
+ return True
501
+
502
+ def _op_dec(self, args):
503
+ rd = args[0][1]
504
+ self._set_reg(rd, self._reg(rd) - 1)
505
+ return True
506
+
507
+ def _op_cmp(self, args):
508
+ a = self._val(args[0])
509
+ b = self._val(args[1])
510
+ self._set_flags_sub(a, b, (a - b) & MASK64)
511
+ return True
512
+
513
+ def _op_jmp(self, args):
514
+ self.pc = self._val(args[0])
515
+ return True
516
+
517
+ def _op_jz(self, args):
518
+ if self.pstate['Z']:
519
+ self.pc = self._val(args[0])
520
+ return True
521
+
522
+ def _op_jnz(self, args):
523
+ if not self.pstate['Z']:
524
+ self.pc = self._val(args[0])
525
+ return True
526
+
527
+ def _op_je(self, args):
528
+ if self.pstate['Z']:
529
+ self.pc = self._val(args[0])
530
+ return True
531
+
532
+ def _op_jl(self, args):
533
+ if self.pstate['N'] != self.pstate['V']:
534
+ self.pc = self._val(args[0])
535
+ return True
536
+
537
+ def _op_jg(self, args):
538
+ if not self.pstate['Z'] and self.pstate['N'] == self.pstate['V']:
539
+ self.pc = self._val(args[0])
540
+ return True
541
+
542
+ def _op_push(self, args):
543
+ self._check_stack()
544
+ self._push(self._val(args[0]))
545
+ return True
546
+
547
+ def _op_pop(self, args):
548
+ self._set_reg(args[0][1], self._pop())
549
+ return True
550
+
551
+ def _op_call(self, args):
552
+ self._check_stack()
553
+ self._push(self.pc)
554
+ self.pc = self._val(args[0])
555
+ return True
556
+
557
+ def _op_ret(self, args):
558
+ self.pc = self._pop()
559
+ return True
560
+
561
+ def _op_in(self, args):
562
+ if self.config.allow_io:
563
+ self._set_reg(args[0][1], self._read_input_int())
564
+ return True
565
+
566
+ def _op_out(self, args):
567
+ if not self.config.allow_io:
568
+ return True
569
+ op = args[0]
570
+ if op[0] == 'str':
571
+ text = self.memory.read_string(op[1])
572
+ else:
573
+ val = self._val(op)
574
+ if op[0] == 'float' or (op[0] == 'vec') or (op[0] == 'veclane'):
575
+ text = _format_float(float(val))
576
+ else:
577
+ iv = int(val)
578
+ text = '\n' if iv == 10 else str(iv)
579
+ if self._trace:
580
+ shown = text.replace('\n', '\\n')
581
+ self.logger.trace(f" OUT -> {shown!r}")
582
+ self._emit_text(text)
583
+ return True
584
+
585
+ def _op_halt(self, args):
586
+ return False
587
+
588
+ # ==================== ARM64 扩展 ====================
589
+
590
+ def _op_adds(self, args):
591
+ rd, rn = args[0][1], args[1][1]
592
+ a, b = self._reg(rn), self._val(args[2])
593
+ r = (a + b) & MASK64
594
+ self._set_flags_add(a, b, r)
595
+ self._set_reg(rd, r)
596
+ return True
597
+
598
+ def _op_subs(self, args):
599
+ rd, rn = args[0][1], args[1][1]
600
+ a, b = self._reg(rn), self._val(args[2])
601
+ r = (a - b) & MASK64
602
+ self._set_flags_sub(a, b, r)
603
+ self._set_reg(rd, r)
604
+ return True
605
+
606
+ def _op_addc(self, args):
607
+ rd, rn = args[0][1], args[1][1]
608
+ a, b = self._reg(rn), self._val(args[2])
609
+ r = (a + b + (1 if self.pstate['C'] else 0)) & MASK64
610
+ self._set_flags_add(a, b, r)
611
+ self._set_reg(rd, r)
612
+ return True
613
+
614
+ def _op_subc(self, args):
615
+ rd, rn = args[0][1], args[1][1]
616
+ a, b = self._reg(rn), self._val(args[2])
617
+ r = (a - b - (0 if self.pstate['C'] else 1)) & MASK64
618
+ self._set_flags_sub(a, b, r)
619
+ self._set_reg(rd, r)
620
+ return True
621
+
622
+ def _op_lsl(self, args):
623
+ rd, rn = args[0][1], args[1][1]
624
+ self._set_reg(rd, (self._reg(rn) << (self._val(args[2]) & 63)) & MASK64)
625
+ return True
626
+
627
+ def _op_lsr(self, args):
628
+ rd, rn = args[0][1], args[1][1]
629
+ self._set_reg(rd, (self._reg(rn) & MASK64) >> (self._val(args[2]) & 63))
630
+ return True
631
+
632
+ def _op_asr(self, args):
633
+ rd, rn = args[0][1], args[1][1]
634
+ v = self._reg(rn)
635
+ sv = v if v < (1 << 63) else v - (1 << 64)
636
+ r = sv >> (self._val(args[2]) & 63)
637
+ self._set_reg(rd, r & MASK64)
638
+ return True
639
+
640
+ def _op_ror(self, args):
641
+ rd, rn = args[0][1], args[1][1]
642
+ v = self._reg(rn) & MASK64
643
+ amt = self._val(args[2]) & 63
644
+ r = ((v >> amt) | (v << (64 - amt))) & MASK64 if amt else v
645
+ self._set_reg(rd, r)
646
+ return True
647
+
648
+ def _op_mvn(self, args):
649
+ self._set_reg(args[0][1], (~self._val(args[1])) & MASK64)
650
+ return True
651
+
652
+ def _op_eor(self, args):
653
+ rd, rn = args[0][1], args[1][1]
654
+ self._set_reg(rd, self._reg(rn) ^ self._val(args[2]))
655
+ return True
656
+
657
+ def _op_bic(self, args):
658
+ rd, rn = args[0][1], args[1][1]
659
+ self._set_reg(rd, self._reg(rn) & (~self._val(args[2]) & MASK64))
660
+ return True
661
+
662
+ def _op_orn(self, args):
663
+ rd, rn = args[0][1], args[1][1]
664
+ self._set_reg(rd, self._reg(rn) | (~self._val(args[2]) & MASK64))
665
+ return True
666
+
667
+ def _op_ldr(self, args):
668
+ rd = args[0][1]
669
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
670
+ self.stats.record_memory_read()
671
+ hit = self.cache.read(addr)
672
+ self.stats.record_cache(hit)
673
+ if self._trace:
674
+ self._trace_cache(addr, hit, 'R')
675
+ self._set_reg(rd, self.memory.read_dword(addr))
676
+ return True
677
+
678
+ def _op_str(self, args):
679
+ rs = args[0][1]
680
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
681
+ self.stats.record_memory_write()
682
+ hit = self.cache.write(addr)
683
+ self.stats.record_cache(hit)
684
+ if self._trace:
685
+ self._trace_cache(addr, hit, 'W')
686
+ self.memory.write_dword(addr, self._reg(rs))
687
+ return True
688
+
689
+ def _op_ldp(self, args):
690
+ rt, rt2 = args[0][1], args[1][1]
691
+ addr = self._mem_addr(args[2]) if args[2][0] == 'mem' else self._val(args[2])
692
+ self.stats.record_memory_read()
693
+ self._set_reg(rt, self.memory.read_qword(addr))
694
+ self._set_reg(rt2, self.memory.read_qword(addr + 8))
695
+ return True
696
+
697
+ def _op_stp(self, args):
698
+ rt, rt2 = args[0][1], args[1][1]
699
+ addr = self._mem_addr(args[2]) if args[2][0] == 'mem' else self._val(args[2])
700
+ self.stats.record_memory_write()
701
+ self.memory.write_qword(addr, self._reg(rt))
702
+ self.memory.write_qword(addr + 8, self._reg(rt2))
703
+ return True
704
+
705
+ def _op_cbz(self, args):
706
+ if self._reg(args[0][1]) == 0:
707
+ self.pc = self._val(args[1])
708
+ return True
709
+
710
+ def _op_cbnz(self, args):
711
+ if self._reg(args[0][1]) != 0:
712
+ self.pc = self._val(args[1])
713
+ return True
714
+
715
+ def _op_tbz(self, args):
716
+ rn, bit = self._reg(args[0][1]), self._val(args[1]) & 63
717
+ if not (rn & (1 << bit)):
718
+ self.pc = self._val(args[2])
719
+ return True
720
+
721
+ def _op_tbnz(self, args):
722
+ rn, bit = self._reg(args[0][1]), self._val(args[1]) & 63
723
+ if rn & (1 << bit):
724
+ self.pc = self._val(args[2])
725
+ return True
726
+
727
+ def _op_b(self, args):
728
+ # 可选条件操作数 ('cond', 'EQ'); 条件不满足则不跳转
729
+ cond_op = next((a for a in args if a[0] == 'cond'), None)
730
+ if cond_op is not None and not self._condition(cond_op[1]):
731
+ return True
732
+ for op in args:
733
+ if op[0] != 'cond':
734
+ self.pc = self._val(op)
735
+ return True
736
+
737
+ def _op_bl(self, args):
738
+ self._check_stack()
739
+ self._push(self.pc)
740
+ self.pc = self._val(args[0])
741
+ return True
742
+
743
+ def _op_br(self, args):
744
+ self.pc = self._reg(args[0][1])
745
+ return True
746
+
747
+ def _op_nop(self, args):
748
+ return True
749
+
750
+ def _op_csel(self, args):
751
+ rd, rn, rm = args[0][1], args[1][1], args[2]
752
+ cond = args[3][1] if args[3][0] == 'cond' else 'AL'
753
+ self._set_reg(rd, self._reg(rn) if self._condition(cond) else self._val(rm))
754
+ return True
755
+
756
+ def _op_csinc(self, args):
757
+ rd, rn, rm = args[0][1], args[1][1], args[2]
758
+ cond = args[3][1] if args[3][0] == 'cond' else 'AL'
759
+ if self._condition(cond):
760
+ self._set_reg(rd, self._reg(rn))
761
+ else:
762
+ self._set_reg(rd, self._val(rm) + 1)
763
+ return True
764
+
765
+ def _op_csinv(self, args):
766
+ rd, rn, rm = args[0][1], args[1][1], args[2]
767
+ cond = args[3][1] if args[3][0] == 'cond' else 'AL'
768
+ if self._condition(cond):
769
+ self._set_reg(rd, self._reg(rn))
770
+ else:
771
+ self._set_reg(rd, (~self._val(rm)) & MASK64)
772
+ return True
773
+
774
+ def _op_csneg(self, args):
775
+ rd, rn, rm = args[0][1], args[1][1], args[2]
776
+ cond = args[3][1] if args[3][0] == 'cond' else 'AL'
777
+ if self._condition(cond):
778
+ self._set_reg(rd, self._reg(rn))
779
+ else:
780
+ self._set_reg(rd, (-self._val(rm)) & MASK64)
781
+ return True
782
+
783
+ @staticmethod
784
+ def _sign_extend(v: int, bits: int) -> int:
785
+ sign = 1 << (bits - 1)
786
+ v &= (1 << bits) - 1
787
+ return (v ^ sign) - sign
788
+
789
+ def _op_sxtb(self, args):
790
+ self._set_reg(args[0][1], self._sign_extend(self._val(args[1]), 8) & MASK64)
791
+ return True
792
+
793
+ def _op_sxth(self, args):
794
+ self._set_reg(args[0][1], self._sign_extend(self._val(args[1]), 16) & MASK64)
795
+ return True
796
+
797
+ def _op_sxtw(self, args):
798
+ self._set_reg(args[0][1], self._sign_extend(self._val(args[1]), 32) & MASK64)
799
+ return True
800
+
801
+ def _op_uxtb(self, args):
802
+ self._set_reg(args[0][1], self._val(args[1]) & 0xFF)
803
+ return True
804
+
805
+ def _op_uxth(self, args):
806
+ self._set_reg(args[0][1], self._val(args[1]) & 0xFFFF)
807
+ return True
808
+
809
+ def _op_clz(self, args):
810
+ v = self._val(args[1]) & MASK64
811
+ self._set_reg(args[0][1], 64 - v.bit_length() if v else 64)
812
+ return True
813
+
814
+ def _op_cls(self, args):
815
+ v = self._val(args[1]) & MASK64
816
+ sv = v if v < (1 << 63) else v - (1 << 64)
817
+ if sv >= 0:
818
+ self._set_reg(args[0][1], 63 - sv.bit_length() if sv else 63)
819
+ else:
820
+ self._set_reg(args[0][1], 63 - (~sv & MASK64).bit_length() + 1)
821
+ return True
822
+
823
+ def _op_rbit(self, args):
824
+ v = self._val(args[1]) & MASK64
825
+ r = int(f'{v:064b}'[::-1], 2)
826
+ self._set_reg(args[0][1], r)
827
+ return True
828
+
829
+ def _op_rev(self, args):
830
+ v = self._val(args[1]) & MASK64
831
+ b = v.to_bytes(8, 'little')
832
+ self._set_reg(args[0][1], int.from_bytes(b[::-1], 'little'))
833
+ return True
834
+
835
+ # ==================== 浮点 / 向量 ====================
836
+
837
+ def _op_fadd(self, args):
838
+ rd, rn, rm = args[0][1], args[1][1], args[2][1]
839
+ self.vec_regs.write_scalar(rd, self.vec_regs.read_scalar(rn) + self.vec_regs.read_scalar(rm))
840
+ return True
841
+
842
+ def _op_fsub(self, args):
843
+ rd, rn, rm = args[0][1], args[1][1], args[2][1]
844
+ self.vec_regs.write_scalar(rd, self.vec_regs.read_scalar(rn) - self.vec_regs.read_scalar(rm))
845
+ return True
846
+
847
+ def _op_fmul(self, args):
848
+ rd, rn, rm = args[0][1], args[1][1], args[2][1]
849
+ self.vec_regs.write_scalar(rd, self.vec_regs.read_scalar(rn) * self.vec_regs.read_scalar(rm))
850
+ return True
851
+
852
+ def _op_fdiv(self, args):
853
+ rd, rn, rm = args[0][1], args[1][1], args[2][1]
854
+ b = self.vec_regs.read_scalar(rm)
855
+ if b == 0:
856
+ raise ExecutionError("Float division by zero")
857
+ self.vec_regs.write_scalar(rd, self.vec_regs.read_scalar(rn) / b)
858
+ return True
859
+
860
+ def _op_fcmp(self, args):
861
+ rn, rm = args[0][1], args[1][1]
862
+ a, b = self.vec_regs.read_scalar(rn), self.vec_regs.read_scalar(rm)
863
+ self.pstate['Z'] = (a == b)
864
+ self.pstate['N'] = (a < b)
865
+ self.pstate['C'] = (a >= b)
866
+ self.pstate['V'] = False
867
+ return True
868
+
869
+ def _op_fcvt(self, args):
870
+ rd, rs = args[0][1], args[1][1]
871
+ if args[1][0] in ('vec', 'veclane'):
872
+ # float -> int
873
+ self._set_reg(rd, int(self.vec_regs.read_scalar(rs)))
874
+ else:
875
+ # int -> float
876
+ self.vec_regs.write_scalar(rd, float(self._reg(rs)))
877
+ return True
878
+
879
+ def _op_fabs(self, args):
880
+ self.vec_regs.write_scalar(args[0][1], abs(self.vec_regs.read_scalar(args[1][1])))
881
+ return True
882
+
883
+ def _op_fneg(self, args):
884
+ self.vec_regs.write_scalar(args[0][1], -self.vec_regs.read_scalar(args[1][1]))
885
+ return True
886
+
887
+ def _op_ldrs(self, args):
888
+ rd = args[0][1]
889
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
890
+ self.stats.record_memory_read()
891
+ self.vec_regs.write_scalar(rd, self.memory.read_float(addr))
892
+ return True
893
+
894
+ def _op_strs(self, args):
895
+ rs = args[0][1]
896
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
897
+ self.stats.record_memory_write()
898
+ self.memory.write_float(addr, self.vec_regs.read_scalar(rs))
899
+ return True
900
+
901
+ def _vec_bin(self, args, fn):
902
+ rd, rn, rm = args[0][1], args[1][1], args[2][1]
903
+ v1 = self.vec_regs.read_vector(rn)
904
+ v2 = self.vec_regs.read_vector(rm)
905
+ self.vec_regs.write_vector(rd, [fn(v1[i], v2[i]) for i in range(Constants.VECTOR_LANES)])
906
+ return True
907
+
908
+ def _op_vadd(self, args):
909
+ return self._vec_bin(args, lambda a, b: a + b)
910
+
911
+ def _op_vsub(self, args):
912
+ return self._vec_bin(args, lambda a, b: a - b)
913
+
914
+ def _op_vmul(self, args):
915
+ return self._vec_bin(args, lambda a, b: a * b)
916
+
917
+ def _op_vdiv(self, args):
918
+ def f(a, b):
919
+ if b == 0:
920
+ raise ExecutionError("Vector division by zero")
921
+ return a / b
922
+ return self._vec_bin(args, f)
923
+
924
+ def _op_vld1(self, args):
925
+ rd = args[0][1]
926
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
927
+ self.stats.record_memory_read()
928
+ data = self.memory.read_block(addr, 16)
929
+ self.vec_regs.write_vector(rd, [float(x) for x in struct.unpack('<4f', data)])
930
+ return True
931
+
932
+ def _op_vst1(self, args):
933
+ rs = args[0][1]
934
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
935
+ self.stats.record_memory_write()
936
+ vec = self.vec_regs.read_vector(rs)
937
+ self.memory.write_block(addr, struct.pack('<4f', *[float(x) for x in vec]))
938
+ return True
939
+
940
+ # ==================== RISC-V 扩展 ====================
941
+
942
+ def _load_width(self, args, bits: int, signed: bool):
943
+ rd = args[0][1]
944
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
945
+ self.stats.record_memory_read()
946
+ hit = self.cache.read(addr)
947
+ self.stats.record_cache(hit)
948
+ if self._trace:
949
+ self._trace_cache(addr, hit, 'R')
950
+ if bits == 8:
951
+ v = self.memory.read_byte(addr)
952
+ if signed:
953
+ v = self._sign_extend(v, 8)
954
+ elif bits == 16:
955
+ v = self.memory.read_word(addr)
956
+ if signed:
957
+ v = self._sign_extend(v, 16)
958
+ elif bits == 32:
959
+ v = self.memory.read_dword(addr)
960
+ if signed:
961
+ v = self._sign_extend(v, 32)
962
+ else:
963
+ v = self.memory.read_qword(addr)
964
+ self._set_reg(rd, v & MASK64)
965
+ return True
966
+
967
+ def _store_width(self, args, bits: int):
968
+ rs = args[0][1]
969
+ addr = self._mem_addr(args[1]) if args[1][0] == 'mem' else self._val(args[1])
970
+ self.stats.record_memory_write()
971
+ hit = self.cache.write(addr)
972
+ self.stats.record_cache(hit)
973
+ if self._trace:
974
+ self._trace_cache(addr, hit, 'W')
975
+ v = self._reg(rs)
976
+ if bits == 8:
977
+ self.memory.write_byte(addr, v & 0xFF)
978
+ elif bits == 16:
979
+ self.memory.write_word(addr, v & 0xFFFF)
980
+ elif bits == 32:
981
+ self.memory.write_dword(addr, v & MASK32)
982
+ else:
983
+ self.memory.write_qword(addr, v & MASK64)
984
+ return True
985
+
986
+ def _op_lb(self, args):
987
+ return self._load_width(args, 8, True)
988
+
989
+ def _op_lh(self, args):
990
+ return self._load_width(args, 16, True)
991
+
992
+ def _op_lw(self, args):
993
+ return self._load_width(args, 32, True)
994
+
995
+ def _op_ld(self, args):
996
+ return self._load_width(args, 64, False)
997
+
998
+ def _op_sb(self, args):
999
+ return self._store_width(args, 8)
1000
+
1001
+ def _op_sh(self, args):
1002
+ return self._store_width(args, 16)
1003
+
1004
+ def _op_sw(self, args):
1005
+ return self._store_width(args, 32)
1006
+
1007
+ def _op_sd(self, args):
1008
+ return self._store_width(args, 64)
1009
+
1010
+ def _op_addi(self, args):
1011
+ rd, rs1 = args[0][1], args[1][1]
1012
+ self._set_reg(rd, self._reg(rs1) + self._val(args[2]))
1013
+ return True
1014
+
1015
+ def _op_slti(self, args):
1016
+ rd, rs1 = args[0][1], args[1][1]
1017
+ a = self._reg(rs1)
1018
+ b = self._val(args[2])
1019
+ sa = a if a < (1 << 63) else a - (1 << 64)
1020
+ sb = b if b < (1 << 63) else b - (1 << 64)
1021
+ self._set_reg(rd, 1 if sa < sb else 0)
1022
+ return True
1023
+
1024
+ def _op_sltiu(self, args):
1025
+ rd, rs1 = args[0][1], args[1][1]
1026
+ self._set_reg(rd, 1 if (self._reg(rs1) & MASK64) < (self._val(args[2]) & MASK64) else 0)
1027
+ return True
1028
+
1029
+ def _op_xori(self, args):
1030
+ rd, rs1 = args[0][1], args[1][1]
1031
+ self._set_reg(rd, self._reg(rs1) ^ self._val(args[2]))
1032
+ return True
1033
+
1034
+ def _op_ori(self, args):
1035
+ rd, rs1 = args[0][1], args[1][1]
1036
+ self._set_reg(rd, self._reg(rs1) | self._val(args[2]))
1037
+ return True
1038
+
1039
+ def _op_andi(self, args):
1040
+ rd, rs1 = args[0][1], args[1][1]
1041
+ self._set_reg(rd, self._reg(rs1) & self._val(args[2]))
1042
+ return True
1043
+
1044
+ def _op_slli(self, args):
1045
+ rd, rs1 = args[0][1], args[1][1]
1046
+ self._set_reg(rd, (self._reg(rs1) << (self._val(args[2]) & 63)) & MASK64)
1047
+ return True
1048
+
1049
+ def _op_srli(self, args):
1050
+ rd, rs1 = args[0][1], args[1][1]
1051
+ self._set_reg(rd, (self._reg(rs1) & MASK64) >> (self._val(args[2]) & 63))
1052
+ return True
1053
+
1054
+ def _op_srai(self, args):
1055
+ rd, rs1 = args[0][1], args[1][1]
1056
+ v = self._reg(rs1)
1057
+ sv = v if v < (1 << 63) else v - (1 << 64)
1058
+ self._set_reg(rd, (sv >> (self._val(args[2]) & 63)) & MASK64)
1059
+ return True
1060
+
1061
+ def _branch_rs(self, args, pred_taken: bool, predicted: bool):
1062
+ self.stats.record_branch(self.pc, pred_taken, predicted)
1063
+ if pred_taken:
1064
+ self.pc = self._val(args[2])
1065
+
1066
+ def _op_beq(self, args):
1067
+ predicted = self.stats.performance_counters.branch_predictor.predict(self.pc)
1068
+ taken = self._reg(args[0][1]) == self._reg(args[1][1])
1069
+ self._branch_rs(args, taken, predicted)
1070
+ return True
1071
+
1072
+ def _op_bne(self, args):
1073
+ predicted = self.stats.performance_counters.branch_predictor.predict(self.pc)
1074
+ taken = self._reg(args[0][1]) != self._reg(args[1][1])
1075
+ self._branch_rs(args, taken, predicted)
1076
+ return True
1077
+
1078
+ def _op_blt(self, args):
1079
+ predicted = self.stats.performance_counters.branch_predictor.predict(self.pc)
1080
+ a, b = self._reg(args[0][1]), self._reg(args[1][1])
1081
+ sa = a if a < (1 << 63) else a - (1 << 64)
1082
+ sb = b if b < (1 << 63) else b - (1 << 64)
1083
+ self._branch_rs(args, sa < sb, predicted)
1084
+ return True
1085
+
1086
+ def _op_bge(self, args):
1087
+ predicted = self.stats.performance_counters.branch_predictor.predict(self.pc)
1088
+ a, b = self._reg(args[0][1]), self._reg(args[1][1])
1089
+ sa = a if a < (1 << 63) else a - (1 << 64)
1090
+ sb = b if b < (1 << 63) else b - (1 << 64)
1091
+ self._branch_rs(args, sa >= sb, predicted)
1092
+ return True
1093
+
1094
+ def _op_bltu(self, args):
1095
+ predicted = self.stats.performance_counters.branch_predictor.predict(self.pc)
1096
+ taken = (self._reg(args[0][1]) & MASK64) < (self._reg(args[1][1]) & MASK64)
1097
+ self._branch_rs(args, taken, predicted)
1098
+ return True
1099
+
1100
+ def _op_bgeu(self, args):
1101
+ predicted = self.stats.performance_counters.branch_predictor.predict(self.pc)
1102
+ taken = (self._reg(args[0][1]) & MASK64) >= (self._reg(args[1][1]) & MASK64)
1103
+ self._branch_rs(args, taken, predicted)
1104
+ return True
1105
+
1106
+ def _op_jalr(self, args):
1107
+ # JALR rd, rs1, imm / jalr rs1 (单寄存器形式视为 ret, rd 丢弃)
1108
+ regs = [a[1] for a in args if a[0] == 'reg']
1109
+ imm = 0
1110
+ for a in args:
1111
+ if a[0] == 'imm':
1112
+ imm = a[1]
1113
+ elif a[0] == 'mem':
1114
+ imm = a[2]
1115
+ if a[1] >= 0 and len(regs) < 2:
1116
+ regs.append(a[1])
1117
+ if len(regs) >= 2:
1118
+ rd, rs1 = regs[0], regs[1]
1119
+ elif len(regs) == 1:
1120
+ rd, rs1 = 31, regs[0]
1121
+ else:
1122
+ rd, rs1 = 31, 31
1123
+ if rd != 31:
1124
+ self._set_reg(rd, self.pc)
1125
+ self.pc = (self._reg(rs1) + imm) & MASK64
1126
+ return True
1127
+
1128
+ def _op_jal(self, args):
1129
+ rd = args[0][1] if args[0][0] == 'reg' else 31
1130
+ if rd != 31:
1131
+ self._set_reg(rd, self.pc)
1132
+ target = args[1] if args[0][0] == 'reg' else args[0]
1133
+ self.pc = self._val(target)
1134
+ return True
1135
+
1136
+ def _op_lui(self, args):
1137
+ rd = args[0][1]
1138
+ imm = self._val(args[1]) if args[1][0] != 'imm' else args[1][1]
1139
+ self._set_reg(rd, (imm & 0xFFFFF) << 12)
1140
+ return True
1141
+
1142
+ def _op_auipc(self, args):
1143
+ rd = args[0][1]
1144
+ imm = self._val(args[1]) if args[1][0] != 'imm' else args[1][1]
1145
+ self._set_reg(rd, self.pc + ((imm & 0xFFFFF) << 12))
1146
+ return True
1147
+
1148
+ # ==================== SYS 宿主调用 ====================
1149
+
1150
+ def _heap_dup_string(self, data: bytes) -> int:
1151
+ """在堆上分配 NUL 结尾字符串副本, 返回指针。"""
1152
+ size = (len(data) + 15) & ~0xF
1153
+ ptr = self.heap_ptr
1154
+ self.heap_ptr += size
1155
+ if self.heap_ptr > self.sp:
1156
+ raise ExecutionError("Heap exhausted (string operation)")
1157
+ self.memory.write_block(ptr, data)
1158
+ return ptr
1159
+
1160
+ def _sys_buffer(self) -> int:
1161
+ idx = self._sys_buf_idx % len(self._sys_buffers)
1162
+ self._sys_buf_idx += 1
1163
+ # 缓冲放在内存高地址区下方 (heap 之后)
1164
+ addr = self.heap_ptr + 2048 + idx * 64
1165
+ return addr
1166
+
1167
+ def _op_sys(self, args):
1168
+ if not args or args[0][0] != 'imm':
1169
+ raise ExecutionError("SYS requires an immediate call id")
1170
+ call_id = args[0][1]
1171
+ x0 = self._reg(0)
1172
+ x1 = self._reg(1)
1173
+ x2 = self._reg(2)
1174
+ if self._trace:
1175
+ name = Syscall(call_id).name if call_id in Syscall._value2member_map_ \
1176
+ else f'UNKNOWN({call_id})'
1177
+ self.logger.trace(f" SYS #{call_id} ({name}) "
1178
+ f"x0=0x{x0:x} x1=0x{x1:x} x2=0x{x2:x}")
1179
+
1180
+ if call_id == Syscall.ABS:
1181
+ self._set_reg(0, abs(x0 if x0 < (1 << 63) else x0 - (1 << 64)))
1182
+ elif call_id in (Syscall.SQRT,):
1183
+ self._set_reg(0, _f_to_bits(math.sqrt(_bits_to_f(x0))))
1184
+ elif call_id == Syscall.POW:
1185
+ self._set_reg(0, _f_to_bits(math.pow(_bits_to_f(x0), _bits_to_f(x1))))
1186
+ elif call_id == Syscall.SIN:
1187
+ self._set_reg(0, _f_to_bits(math.sin(_bits_to_f(x0))))
1188
+ elif call_id == Syscall.COS:
1189
+ self._set_reg(0, _f_to_bits(math.cos(_bits_to_f(x0))))
1190
+ elif call_id == Syscall.TAN:
1191
+ self._set_reg(0, _f_to_bits(math.tan(_bits_to_f(x0))))
1192
+ elif call_id == Syscall.FADD:
1193
+ self._set_reg(0, _f_to_bits(_bits_to_f(x0) + _bits_to_f(x1)))
1194
+ elif call_id == Syscall.FSUB:
1195
+ self._set_reg(0, _f_to_bits(_bits_to_f(x0) - _bits_to_f(x1)))
1196
+ elif call_id == Syscall.FMUL:
1197
+ self._set_reg(0, _f_to_bits(_bits_to_f(x0) * _bits_to_f(x1)))
1198
+ elif call_id == Syscall.FDIV:
1199
+ b = _bits_to_f(x1)
1200
+ if b == 0:
1201
+ raise ExecutionError("Float division by zero (SYS)")
1202
+ self._set_reg(0, _f_to_bits(_bits_to_f(x0) / b))
1203
+ elif call_id == Syscall.FCMP:
1204
+ a, b = _bits_to_f(x0), _bits_to_f(x1)
1205
+ self._set_reg(0, -1 if a < b else (1 if a > b else 0))
1206
+ elif call_id == Syscall.FTOI:
1207
+ self._set_reg(0, int(_bits_to_f(x0)))
1208
+ elif call_id == Syscall.ITOF:
1209
+ self._set_reg(0, _f_to_bits(float(x0 if x0 < (1 << 63) else x0 - (1 << 64))))
1210
+ elif call_id == Syscall.RAND:
1211
+ self._set_reg(0, self._rand.randrange(1 << 31))
1212
+ elif call_id == Syscall.SRAND:
1213
+ self._rand.seed(x0)
1214
+ elif call_id == Syscall.TIME:
1215
+ self._set_reg(0, int(time.time()))
1216
+ elif call_id == Syscall.STRLEN:
1217
+ n = 0
1218
+ while self.memory.read_byte(x0 + n) != 0:
1219
+ n += 1
1220
+ self._set_reg(0, n)
1221
+ elif call_id == Syscall.STRCMP:
1222
+ i = 0
1223
+ while True:
1224
+ ca = self.memory.read_byte(x0 + i)
1225
+ cb = self.memory.read_byte(x1 + i)
1226
+ if ca != cb or ca == 0:
1227
+ self._set_reg(0, ca - cb)
1228
+ break
1229
+ i += 1
1230
+ elif call_id in (Syscall.STRCPY, Syscall.STRCAT):
1231
+ dst = x0
1232
+ if call_id == Syscall.STRCAT:
1233
+ while self.memory.read_byte(dst) != 0:
1234
+ dst += 1
1235
+ src = x1
1236
+ i = 0
1237
+ while True:
1238
+ ch = self.memory.read_byte(src + i)
1239
+ self.memory.write_byte(dst + i, ch)
1240
+ i += 1
1241
+ if ch == 0:
1242
+ break
1243
+ self._set_reg(0, x0)
1244
+ elif call_id == Syscall.MALLOC:
1245
+ size = (x0 + 15) & ~0xF
1246
+ ptr = self.heap_ptr
1247
+ self.heap_ptr += size
1248
+ if self.heap_ptr > self.sp:
1249
+ raise ExecutionError("Heap exhausted")
1250
+ self._set_reg(0, ptr)
1251
+ elif call_id == Syscall.PRINT_FLOAT:
1252
+ self._emit_text(_format_float(_bits_to_f(x0)))
1253
+ elif call_id == Syscall.ITOA:
1254
+ addr = self._sys_buffer()
1255
+ signed = x0 if x0 < (1 << 63) else x0 - (1 << 64)
1256
+ self.memory.write_string(addr, str(signed))
1257
+ self._set_reg(0, addr)
1258
+ elif call_id == Syscall.FTOA:
1259
+ addr = self._sys_buffer()
1260
+ self.memory.write_string(addr, _format_float(_bits_to_f(x0)))
1261
+ self._set_reg(0, addr)
1262
+ elif call_id == Syscall.PRINT_STR:
1263
+ self._emit_text(self.memory.read_string(x0))
1264
+ elif call_id == Syscall.STR_CONCAT:
1265
+ sa = self.memory.read_string(x0)
1266
+ sb = self.memory.read_string(x1)
1267
+ data = (sa + sb).encode('utf-8') + b'\x00'
1268
+ size = (len(data) + 15) & ~0xF
1269
+ ptr = self.heap_ptr
1270
+ self.heap_ptr += size
1271
+ if self.heap_ptr > self.sp:
1272
+ raise ExecutionError("Heap exhausted (string concat)")
1273
+ self.memory.write_block(ptr, data)
1274
+ self._set_reg(0, ptr)
1275
+ elif call_id == Syscall.BOOL_STR:
1276
+ addr = self._sys_buffer()
1277
+ self.memory.write_string(addr, "true" if x0 != 0 else "false")
1278
+ self._set_reg(0, addr)
1279
+ elif call_id == Syscall.ABORT:
1280
+ # 运行时中止 (assert / 边界检查): 消息指针位于 x0
1281
+ msg = self.memory.read_string(x0, 512)
1282
+ raise ExecutionError(f"Runtime abort: {msg}" if msg
1283
+ else "Runtime abort")
1284
+ elif call_id == Syscall.SUBSTR:
1285
+ # substr(s, start, len): 越界自动裁剪
1286
+ s = self.memory.read_string(x0)
1287
+ n = len(s)
1288
+ start = 0 if x1 < 0 else (n if x1 > n else x1)
1289
+ length = 0 if x2 < 0 else x2
1290
+ self._set_reg(0, self._heap_dup_string(
1291
+ s[start:start + length].encode('utf-8') + b'\x00'))
1292
+ elif call_id == Syscall.INDEXOF:
1293
+ hay = self.memory.read_string(x0)
1294
+ needle = self.memory.read_string(x1)
1295
+ idx = hay.find(needle)
1296
+ self._set_reg(0, idx)
1297
+ elif call_id == Syscall.TOUPPER:
1298
+ data = self.memory.read_string(x0)
1299
+ self._set_reg(0, self._heap_dup_string(
1300
+ data.upper().encode('utf-8') + b'\x00'))
1301
+ elif call_id == Syscall.TOLOWER:
1302
+ data = self.memory.read_string(x0)
1303
+ self._set_reg(0, self._heap_dup_string(
1304
+ data.lower().encode('utf-8') + b'\x00'))
1305
+ elif call_id == Syscall.FLOOR:
1306
+ self._set_reg(0, _f_to_bits(math.floor(_bits_to_f(x0))))
1307
+ elif call_id == Syscall.CEIL:
1308
+ self._set_reg(0, _f_to_bits(math.ceil(_bits_to_f(x0))))
1309
+ elif call_id == Syscall.ROUND:
1310
+ # 与 lib/math.cin f_round 一致: floor(x + 0.5) (半值向 +inf)
1311
+ self._set_reg(0, _f_to_bits(math.floor(_bits_to_f(x0) + 0.5)))
1312
+ elif call_id == Syscall.ATOI:
1313
+ s = self.memory.read_string(x0).strip()
1314
+ try:
1315
+ self._set_reg(0, int(s) & MASK64)
1316
+ except ValueError:
1317
+ self._set_reg(0, 0)
1318
+ elif call_id == Syscall.TRIM:
1319
+ self._set_reg(0, self._heap_dup_string(
1320
+ self.memory.read_string(x0).strip().encode('utf-8') + b'\x00'))
1321
+ elif call_id == Syscall.LTRIM:
1322
+ self._set_reg(0, self._heap_dup_string(
1323
+ self.memory.read_string(x0).lstrip().encode('utf-8') + b'\x00'))
1324
+ elif call_id == Syscall.RTRIM:
1325
+ self._set_reg(0, self._heap_dup_string(
1326
+ self.memory.read_string(x0).rstrip().encode('utf-8') + b'\x00'))
1327
+ elif Syscall.AUDIOPLAY <= call_id <= Syscall.TERMUXSMS:
1328
+ raise ExecutionError(
1329
+ "host builtins (GUI/audio/system/Termux) require the native "
1330
+ "Go runtime (run without --no-native)")
1331
+ else:
1332
+ raise ExecutionError(f"Unknown SYS call id: {call_id}")
1333
+ return True
1334
+
1335
+ # ==================== 执行引擎 ====================
1336
+
1337
+ def execute(self, opcode: str, args: List[Operand]) -> bool:
1338
+ if self._trace:
1339
+ ops = ' '.join(self._fmt_op_trace(a) for a in args)
1340
+ self.logger.trace(
1341
+ f"PC=0x{self.pc:04x} #{self.stats.instruction_count:08d} "
1342
+ f"{opcode} {ops} SP=0x{self.sp:x}")
1343
+ self.pc += 1
1344
+ handler = self._dispatch.get(opcode)
1345
+ if handler is None:
1346
+ raise ExecutionError(f"Unimplemented instruction: {opcode}")
1347
+ result = handler(args)
1348
+ self.stats.record_instruction(opcode)
1349
+ if self._trace:
1350
+ self.logger.trace(
1351
+ f" => pc=0x{self.pc:04x} {self._trace_flags()}")
1352
+ return result
1353
+
1354
+ def step(self) -> bool:
1355
+ if self.pc < 0 or self.pc >= len(self.instructions):
1356
+ return False
1357
+ opcode, args = self.instructions[self.pc]
1358
+ return self.execute(opcode, args)
1359
+
1360
+ def _try_native_run(self) -> Optional[bool]:
1361
+ """尝试使用 Go 原生库执行整个程序; 不可用/不支持时返回 None。"""
1362
+ if not self.config.use_native or self.config.debug_mode or self.config.step_mode:
1363
+ return None
1364
+ if self.config.enable_jit:
1365
+ return None
1366
+ try:
1367
+ from . import native
1368
+ except Exception:
1369
+ return None
1370
+ engine = native.get_engine(self.logger)
1371
+ if engine is None:
1372
+ return None
1373
+
1374
+ from .native import encode_program
1375
+ all_labels = dict(self.labels)
1376
+ all_labels.update(self.data_labels)
1377
+ bytecode = encode_program(self.instructions, self.entry_pc, all_labels)
1378
+ mem_image = self.memory.get_snapshot()
1379
+ self.logger.debug(
1380
+ f"Native run: bytecode={len(bytecode)}B mem={len(mem_image)}B "
1381
+ f"entry={self.entry_pc} sp=0x{self.sp:x} "
1382
+ f"heap=0x{self.heap_ptr:x} max_steps={self.config.max_instructions}")
1383
+ import time as _time
1384
+ t0 = _time.perf_counter()
1385
+ result = engine.run(
1386
+ bytecode=bytecode,
1387
+ mem=mem_image,
1388
+ entry=self.entry_pc,
1389
+ sp=self.sp,
1390
+ heap_base=self.heap_ptr,
1391
+ input_data=self.input_buffer.encode('utf-8'),
1392
+ max_steps=self.config.max_instructions,
1393
+ )
1394
+ elapsed = _time.perf_counter() - t0
1395
+ if result is None:
1396
+ self.logger.debug("Native run failed (result None)")
1397
+ return None
1398
+
1399
+ self.logger.debug(
1400
+ f"Native result: status={result.get('status')} "
1401
+ f"halted={result.get('halted')} steps={result.get('steps')} "
1402
+ f"pc={result.get('pc')} elapsed={elapsed * 1000:.2f}ms "
1403
+ f"error={result.get('error')}")
1404
+
1405
+ if result.get('error') == 'unsupported':
1406
+ # 原生库遇到不支持的指令: 同步状态后回退解释执行
1407
+ self._apply_native_state(result)
1408
+ self.logger.debug(
1409
+ f"Native engine hit unsupported opcode, falling back to "
1410
+ f"interpreter at PC=0x{result.get('pc', 0):x}")
1411
+ return None
1412
+
1413
+ if result.get('error'):
1414
+ # 原生运行时错误 (status=3): 同步状态并按解释器行为抛出
1415
+ self._apply_native_state(result)
1416
+ self.native_used = True
1417
+ raise ExecutionError(result.get('error') or 'native runtime error')
1418
+
1419
+ # 应用原生执行结果
1420
+ self._apply_native_state(result)
1421
+ self.native_used = True
1422
+ if result.get('output'):
1423
+ self._emit_text(result['output'])
1424
+ return not result.get('halted', False) or result.get('error') is None
1425
+
1426
+ def _apply_native_state(self, result: dict) -> None:
1427
+ if 'regs' in result:
1428
+ self.regs.set_all(list(result['regs'])[:32])
1429
+ if 'sp' in result:
1430
+ self.sp = result['sp'] & MASK64
1431
+ if 'pc' in result:
1432
+ self.pc = result['pc']
1433
+ if 'vec_regs' in result:
1434
+ self.vec_regs.set_all(result['vec_regs'])
1435
+ if 'mem' in result:
1436
+ mem = result['mem']
1437
+ self.memory.write_block(0, bytes(mem[:len(self.memory)]))
1438
+ if 'steps' in result:
1439
+ # 原生 VM 已整程序执行完毕: 统计改为一次性批量写入, 不再按指令数在
1440
+ # Python 里逐条调用 record_instruction (实测可让原生路径快约 7 倍,
1441
+ # 且原写法算出的 opcode 直方图随后就被 clear 掉, 纯属浪费)。
1442
+ steps = int(result.get('steps') or 0)
1443
+ counted = min(steps, self.config.max_instructions)
1444
+ self.stats.instruction_count = steps
1445
+ self.stats.opcode_count.clear()
1446
+ self.stats.hot_instructions['?'] += counted
1447
+ self.stats.inst_profiler.cycles['?'] += counted
1448
+ self.stats.performance_counters.counters['instructions'] += counted
1449
+ if 'heap_ptr' in result:
1450
+ self.heap_ptr = result['heap_ptr']
1451
+
1452
+ def run(self) -> None:
1453
+ if self.config.debug_server_port is not None:
1454
+ return self._run_remote(self.config.debug_server_port)
1455
+ self.running = True
1456
+ self.stats.start()
1457
+ self.logger.info("Starting program execution")
1458
+
1459
+ native_outcome = None
1460
+ if (self.config.use_native and not self.config.debug_mode
1461
+ and not self.config.step_mode
1462
+ and not self.config.bounds_check
1463
+ and not self.config.mmu):
1464
+ native_outcome = self._try_native_run()
1465
+
1466
+ try:
1467
+ if native_outcome is not None:
1468
+ # 原生执行完成
1469
+ if not native_outcome:
1470
+ self.logger.info("HALT (native)")
1471
+ elif self._can_use_fast_path():
1472
+ self._run_fast()
1473
+ else:
1474
+ self._run_interpreted()
1475
+ except KeyboardInterrupt:
1476
+ self.logger.info("User interrupt")
1477
+ self.console.print(f"\n{Colors.colorize('User interrupt', Colors.YELLOW)}")
1478
+ except Exception as e:
1479
+ self.execution_failed = True
1480
+ if self.config.debug_mode:
1481
+ # 超详细: rich 彩色完整堆栈
1482
+ self.logger.exception(f"Execution error: {e}")
1483
+ else:
1484
+ self.logger.error(f"Execution error: {e}")
1485
+ self.console.print(Panel(
1486
+ f"{e}", title="Execution Error", border_style='red'))
1487
+ finally:
1488
+ self.running = False
1489
+ self.stats.stop()
1490
+ self.cache.flush()
1491
+ self.logger.info("Program execution finished")
1492
+
1493
+ if self.config.profile or self.config.debug_mode:
1494
+ self.display_state("Execution Complete")
1495
+ cache_stats = self.cache.get_stats()
1496
+ self.stats.display_summary(self.console, cache_stats,
1497
+ native_used=self.native_used)
1498
+
1499
+ if self.config.auto_save_crom:
1500
+ from . import crom as crom_mod
1501
+ crom_file = os.path.splitext(self.filename)[0] + '.crom' if self.filename else 'program.crom'
1502
+ crom_mod.save_crom(self.memory, crom_file,
1503
+ compress=self.config.compress_crom,
1504
+ logger=self.logger)
1505
+
1506
+ def _run_remote(self, port: int) -> None:
1507
+ """A4: 远程驱动式调试 (单线程服务; 不启用原生/JIT/本地单步会话)。"""
1508
+ from .debugger import DebugServer
1509
+ self.running = False
1510
+ self.stats.start()
1511
+ self.logger.info(f"Remote debug server on port {port} "
1512
+ f"(waiting for client)")
1513
+ srv = DebugServer(self, port)
1514
+ self.debug_server = srv
1515
+ try:
1516
+ srv.drive()
1517
+ except KeyboardInterrupt:
1518
+ self.logger.info("User interrupt")
1519
+ finally:
1520
+ self.running = False
1521
+ self.stats.stop()
1522
+ self.cache.flush()
1523
+ self.logger.info("Remote debug session ended")
1524
+
1525
+ def _can_use_fast_path(self) -> bool:
1526
+ """无调试/断点/单步/JIT/追踪/节流时, 可走紧凑解释循环。"""
1527
+ return (not self.config.debug_mode
1528
+ and not self.config.step_mode
1529
+ and not self.config.interactive_mode
1530
+ and not self.breakpoints
1531
+ and self.debug_server is None
1532
+ and self.jit is None
1533
+ and not self._trace
1534
+ and self.config.execution_interval <= 0)
1535
+
1536
+ def _run_fast(self) -> None:
1537
+ """紧凑解释循环 (快路径)。
1538
+
1539
+ 与 _run_interpreted 的语义差异仅在"没有"哪些检查: 断点命中、远程
1540
+ 调试轮询、单步会话、JIT 尝试、逐指令追踪与执行节流。这些在快路径的
1541
+ 启用条件里都已确认不生效, 因此逐指令语义 (pc 先自增、统计记账、HALT
1542
+ 返回 False) 完全一致。
1543
+ """
1544
+ instructions = self.instructions
1545
+ execute = self.execute
1546
+ logger = self.logger
1547
+ limit = self.config.max_instructions
1548
+ n = len(instructions)
1549
+ while True:
1550
+ pc = self.pc
1551
+ if pc < 0 or pc >= n:
1552
+ logger.info("Program ended normally")
1553
+ return
1554
+ if self.stats.instruction_count >= limit:
1555
+ raise ExecutionError(
1556
+ f"instruction limit reached ({limit} steps)")
1557
+ opcode, args = instructions[pc]
1558
+ if not execute(opcode, args):
1559
+ logger.info("HALT instruction executed")
1560
+ return
1561
+
1562
+ def _run_interpreted(self) -> None:
1563
+ while self.running:
1564
+ if self.pc < 0 or self.pc >= len(self.instructions):
1565
+ self.logger.info("Program ended normally")
1566
+ break
1567
+
1568
+ if self.stats.instruction_count >= self.config.max_instructions:
1569
+ # 与 Go 原生 VM 保持一致的语义: 步数用尽不是"正常结束",
1570
+ # 而是失败 (旧行为只是 warning + break, 会让被截断的程序
1571
+ # 以退出码 0 报告成功)。
1572
+ raise ExecutionError(
1573
+ f"instruction limit reached "
1574
+ f"({self.config.max_instructions} steps)")
1575
+
1576
+ # 建议 5: 'continue' 后豁免一次当前 PC 的断点命中,
1577
+ # 确保至少执行一条指令 (与 GDB 语义一致, 避免死循环重入)
1578
+ resume_bp = self._resume_bp_pc is not None
1579
+ if resume_bp:
1580
+ self._resume_bp_pc = None
1581
+
1582
+ if not resume_bp:
1583
+ if self.debug_server and self.debug_server.check_conditional_breakpoints():
1584
+ self.is_debugging = True
1585
+ self.debug_command_loop()
1586
+ continue
1587
+
1588
+ if self.pc in self.breakpoints:
1589
+ self.console.print(
1590
+ f"{Colors.colorize(f'Breakpoint hit at PC={self.pc:#x}', Colors.YELLOW)}")
1591
+ self.is_debugging = True
1592
+ self.debug_command_loop()
1593
+ continue
1594
+
1595
+ # 建议 6: --step 与断点命中共用 DebugSession 命令集
1596
+ if self.config.step_mode and self.config.interactive_mode:
1597
+ from .debugger import DebugSession
1598
+ action = DebugSession(self).run_step_mode()
1599
+ if action in ('quit', 'halted'):
1600
+ if action == 'quit':
1601
+ self.running = False
1602
+ break
1603
+ if action == 'run':
1604
+ self.config.step_mode = False
1605
+ continue
1606
+
1607
+ if self.jit is not None:
1608
+ jit_result = self.jit.try_step(self)
1609
+ if jit_result is True:
1610
+ continue
1611
+ if jit_result is False:
1612
+ self.logger.info("Program ended (JIT)")
1613
+ break
1614
+ # None: 该指令不适合 JIT, 回退解释执行
1615
+
1616
+ opcode, args = self.instructions[self.pc]
1617
+ continue_exec = self.execute(opcode, args)
1618
+
1619
+ if not continue_exec:
1620
+ self.logger.info("HALT instruction executed")
1621
+ break
1622
+
1623
+ if self.config.execution_interval > 0:
1624
+ time.sleep(self.config.execution_interval)
1625
+
1626
+ # ==================== 状态显示 / 调试 ====================
1627
+
1628
+ def display_state(self, title: str = "CPU State", opcode: Optional[str] = None,
1629
+ args: Optional[List[Operand]] = None) -> None:
1630
+ # 建议 6: 渲染逻辑迁移至 codecin/debugger.py (状态显示与执行解耦)
1631
+ from .debugger import display_state as _render_state
1632
+ _render_state(self, title, opcode, args)
1633
+
1634
+ @staticmethod
1635
+ def _fmt_operand(op: Operand) -> str:
1636
+ # 建议 6: 操作数格式化迁移至 codecin/debugger.py
1637
+ from .debugger import fmt_operand
1638
+ return fmt_operand(op)
1639
+
1640
+ def add_breakpoint(self, addr: int) -> None:
1641
+ self.breakpoints.add(addr)
1642
+ self.logger.info(f"Breakpoint set at PC={addr:#x}")
1643
+
1644
+ def remove_breakpoint(self, addr: int) -> None:
1645
+ self.breakpoints.discard(addr)
1646
+ self.logger.info(f"Breakpoint removed at PC={addr:#x}")
1647
+
1648
+ def debug_command_loop(self) -> None:
1649
+ """断点命中后的交互调试入口 (建议 6: 逻辑已迁移至 codecin/debugger.DebugSession)。"""
1650
+ from .debugger import DebugSession
1651
+ action = DebugSession(self).run()
1652
+ if action == 'halted':
1653
+ self.running = False
1654
+