# 扫描周期 vm 模块:寄存器虚拟机(V2:变长指令 / 槽表两级 / 栈方案 C)。CMake 目标:`vm`(`STATIC`),只依赖 [`指令与映像.md`](../isa/指令与映像.md)。 运行时是 **一台 VM、一个入口、一份映像**。不链接 `compiler`。扫描周期与确定性见 [`初步计划.md`](../初步计划.md) 第 2、8 节。 ## 扫描周期 ```text 1. 按 sidecar 的 io 绑定,采样 → I / 输入全局(executor 写值区槽) 2. 从 PROGRAM MAIN 的 pc=0 执行到 RET 3. 写回 Q / 输出全局(executor 读值区槽) 4. 用本周期 Δt(映像头 dt_ms)推进内置 FB(不用 wall clock);RTC 用累计周期数 ``` ## 边界 - 只认 `.stb` 映像(`vm` 自带读实现);读取时**型号标识匹配(STATOR2)+ SHA-256 校验**,不符/篡改 → 拒绝 - 类型与溢出按 [`指令与映像.md`](../isa/指令与映像.md)(整数饱和 / 除法 A / 浮点 IEEE);指令定义归 `isa` - 局部 / `VAR` = 固定寄存器;`nregs` 在函数头;栈区预分配(`max_stack`,编译期 DAG 最坏路径) - `CALL` 目标是立即数 `fn_id`,有界调用栈(深度 64 双检查) - 无 GC、无堆、无线程;每周期受 `cycle_limit` 限制 - I/O 从哪来、Δt 谁给、回放怎么喂,属于 `BytecodeExecutor`(读 `.stb` + sidecar) --- ## 可观察性接口(v1 预留) TUI 是执行器(`BytecodeExecutor`)的界面,用途是方便观察 VM 运行状态。**v1 不做 TUI**,只预留接口,避免后续改 VM 的观察面。原则: - **数据与展示分离**:`vm` 只提供只读观察 API(数据);TUI 渲染与文本输出属于 `executor`(展示)。vm 不画任何界面。 - **只读轮询**:TUI 通过快照轮询,绝不写 VM 状态;"继续 / 单步"是 executor 侧命令,不改变确定性。 - **快照 POD 化**:快照保持简单数据(将来跨进程 TUI 可序列化)。 已落地的观察面(`Machine` 公共接口): ```cpp bool step(); // 精确执行一条指令,停在指令边界 Fault fault() const; // 最近一次故障 bool ended() const; // 周期是否已结束 uint32_t pc() const; // 当前 pc(字节,相对本帧函数) uint32_t fn_id() const; // 当前函数 uint32_t cycle_count() const; // 本周期已执行指令数 uint32_t call_depth() const; // 调用栈深度 uint8_t* data(); // 值区(I 采样 / Q 读回由外部做) uint32_t slot_addr(uint32_t slot) const; // 槽 → 值区偏移(槽表两级) int64_t reg(uint8_t i) const; // 当前帧寄存器 const uint8_t* cur_instr_bytes() const; // 当前指令首字节(单步反汇编用) uint32_t cur_instr_len() const; // 当前指令长度(变长) ``` - 寄存器 ≤256、映像很小,快照拷贝成本可忽略。 - 单步、回放、dump 都建立在同一套观察 API 上。 --- ## V2 落地状态 | 项 | 状态 | |---|---| | 变长取指(4/8/16/32B,前缀分区)+ 字节 pc | ✅ `Machine.cpp` exec_one | | 槽表两级(slot → addr → 值区变宽紧凑)+ LOAD_OFF/STORE_OFF | ✅ | | 栈方案 C(预分配 max_stack、帧头 12B、r0..r7 复制、深度 64 双检查) | ✅ do_call/do_ret | | 19 类型 func 驱动(整数饱和 / 无符号 / F32 / F64 IEEE) | ✅ exec_arith/exec_cmp | | CAL 15 条(TON/TOF/TP/CTU/DCTU/CTD/DCTD/CTUD/DCTUD/R_TRIG/F_TRIG/SR/RS/PWM/RTC) | ✅ do_cal | | 故障(None/CycleLimit/StackOverflow/BadOp/BadSlot/BadConst) | ✅ | | 边沿缓冲 edge_prev_(每槽 2 字节,跨周期) | ✅ | | 确定性:同一 I 序列跑两遍,数据区完全一致 | ✅ vm_test | 指令执行语义(帧/调用栈、指令表、定时器、故障、line1 推演)见 [`指令执行.md`](指令执行.md)。