3.8 KiB
3.8 KiB
扫描周期
vm 模块:寄存器虚拟机(V2:变长指令 / 槽表两级 / 栈方案 C)。CMake 目标:vm(STATIC),只依赖 指令与映像.md。
运行时是 一台 VM、一个入口、一份映像。不链接 compiler。扫描周期与确定性见 初步计划.md 第 2、8 节。
扫描周期
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(整数饱和 / 除法 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 公共接口):
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。