# .stb 映像文件结构(V2,STATOR2) 编译产物 `.stb` 的**面向使用者**的结构说明。规范以 [`指令与映像.md`](指令与映像.md) 为准,本文给结构与示例。 真实 `line1.stb` 字节拆解在**阶段 5**(`line1` 推演重算,C5)补充;本文示例为概念性布局。 ## 概览 - 魔数 `STSC`,**版本 `2`**,型号标识 `STATOR2`,全部整数小端 - 文件 = 头 + 七个段,段序:**常量表 → 函数表 → 字节码 → 槽表段 → 值段 → 元数据段 → SHA-256 尾** - 段偏移记在头里,单调:`offset_const ≤ offset_funcs ≤ offset_code ≤ offset_slots ≤ offset_values ≤ 文件长度` ``` ┌──────────────────────────────────────────────────┐ │ 头(128 字节,偏移 0,含型号标识[32]) │ ├──────────────────────────────────────────────────┤ │ 常量表段 offset_const .. offset_funcs │ ├──────────────────────────────────────────────────┤ │ 函数表段 offset_funcs .. offset_code │ ├──────────────────────────────────────────────────┤ │ 字节码段 offset_code .. offset_slots(16 对齐)│ ├──────────────────────────────────────────────────┤ │ 槽表段 offset_slots .. offset_values │ ├──────────────────────────────────────────────────┤ │ 值段 offset_values .. offset_meta(或文件尾)│ ├──────────────────────────────────────────────────┤ │ 元数据段 offset_meta (v1 = 0,空段) │ ├──────────────────────────────────────────────────┤ │ SHA-256 文件尾(32 字节,对文件尾之前全部内容) │ └──────────────────────────────────────────────────┘ ``` ## 头(128 字节,16 对齐) | 偏移 | 宽 | 字段 | 说明 | |---|---|---|---| | 0 | 4 | 魔数 `STSC` | 不变(V1 沿用) | | 4 | 4 | 版本 `2` | V1 = 1 | | 8 | 4 | `cycle_limit` | 每周期指令数上限 | | 12 | 4 | `dt_ms` | 周期时长(毫秒,定时器推进步长) | | 16 | 8 | 工程哈希(FNV-1a 64) | 源文件路径排序后对内容计算 | | 24 | 4 | 入口 `entry_fn_id` | MAIN 函数表行下标 | | 28 | 4 | 全局槽数 `n_globals` | 槽表内全局块条目数 | | 32/36/40 | 4×3 | `n_i` / `n_q` / `n_m` | **保留恒 0**(V1 遗产,兼容 + 将来语义) | | 44 | 4 | 常量数 `n_consts` | 常量表条目数 | | 48 | 4 | 函数数 `n_funcs` | 函数表行数 | | 52/56/60 | 4×3 | `offset_const` / `offset_funcs` / `offset_code` | 段偏移 | | 64 | 4 | `offset_slots` | 槽表段偏移 | | 68 | 4 | `offset_values` | 值段偏移(**16 对齐**) | | 72 | 32 | **型号标识**(定长 ASCII 含版本,补 `'\0'`) | `"STATOR2"`(name + version=2) | | 104 | 4 | `n_slots` | 槽表条目数(= n_globals + FB 实例/结构体字段槽数) | | 108 | 4 | `values_size` | 值段字节数 | | 112 | 4 | `offset_meta` | 元数据段偏移(**v1 = 0** = 空段) | | 116 | 4 | `max_stack` | 栈区字节数(编译期调用图最坏路径) | | 120 | 8 | 预留 | 未来扩展 | ## 常量表段(`offset_const` 起) 一行 **8 字节**:`[value:u64]`(原始位模式,**无 tag**——类型由 LOADK 指令的 func 位段解释)。 - 按位模式去重(同值多类型复用:`5` 可被 func=INT 与 func=REAL 的 LOADK 引用) - `const_id` = 行下标(u32,IMM 形态 imm32 字段) ## 函数表段(`offset_funcs` 起) 一行 12 字节:`[nregs:u32][code_offset:u32][code_len:u32]` - **行下标即 `fn_id`**;`code_offset` 相对字节码段起点(**字节**);`code_len` 为**字节数**(变长指令,字节单位) - 入口 = 头 `entry_fn_id` 指向的行 - `nregs` = 本函数帧寄存器数(帧分配 = nregs×8 + 帧头 12B;max_stack 由编译期按调用图算) ## 字节码段(`offset_code` 起) **变长指令 4/8/16/32B**,段起点 16 对齐。指令字: ```text 字节 0 字节 1 [长度前缀+形态分区 | op] [func:4 | 空:4] ``` - 形态(前缀直推):`11`=RR、`10`=NONE、`011`=RRR、`010 000..101`=IMM/SLOT/JMP/JC/CALL/CAL、`0010`=SLOT+off、`0011`=IMM64、`0001`=预留 - 编码明细(位号/操作数区/uses_*)见 [`指令编码.md`](指令编码.md)、清单见 [`指令集清单.md`](指令集清单.md) - 跳转偏移 off32 **字节单位,相对下一条**(目标 = 当前指令地址 + 指令长 + off) - 调用约定:结果 r0、参数 r1..r7、变量与临时 r8 起;CALL/RET 复制 r0..r7 全宽 ## 槽表段(`offset_slots` 起) 一行 **8 字节**:`[addr:u32][预留:u32]`(addr = 值段内字节偏移,指向变量/FB 实例起始)。 - **行下标即槽号**(slot u32);`n_slots` 行 - 槽序:全局块(声明序,`n_globals` 个)→ FB 实例块(POU 收集序、实例声明序) ## 值段(`offset_values` 起) **变宽紧凑布局**(对齐 1/2/4/8B,编译器保证;段起点 16 对齐): - 变量按类型占宽:BOOL 1B、INT 2B、DINT/REAL 4B、TIME/LREAL 8B…(func 宽度表) - 变量初值、FB 实例字段初值(0)写于此;运行时拷入工作副本,文件只读 - 字段访问:`LOAD/STORE rd, slot, off32`——addr = 槽表[slot].addr + off(结构体/FB 共享体统一) FB 实例布局(字段偏移/大小,对齐规则)见 [`指令集清单.md`](指令集清单.md) §8.1,例: | FB | 布局(偏移) | 大小 | |---|---|---| | TON | in=0、pt=8、q=16、et=24 | 32B | | CTU | cu=0、r=1、pv=2、q=4、cv=6 | 8B | | DCTU | cu=0、r=1、pad 2..3、pv=4、q=8、pad 9..11、cv=12 | 16B | ## 元数据段(`offset_meta` 起) v1 为空段(`offset_meta = 0`)。将来承载结构体/字符串/数组的类型描述表(字段表),schema 延后(U12)。 ## SHA-256 文件尾(32 字节) 文件尾追加 32 字节 SHA-256:**对文件尾之前全部内容计算**。compiler 写侧与 vm 读侧**各自实现**一份。执行器校验不通过 → 直接拒绝。 ## 读取校验链(vm 读侧) 1. **结构校验**:魔数/版本/头大小/段偏移单调且在 SHA 前/常量表·函数表尺寸一致/代码段 16 对齐/入口 fn_id 范围 2. **SHA-256**:完整性(防篡改) 3. **型号匹配**:头内 32 字节与 `"STATOR2"` 补零逐字节比对 任一不符 → `Machine::create` 拒绝,不创建机器。 ## 与 sidecar / 执行器的关系 - `.stb` + `.runtime.toml`(sidecar:`[[io.input]]`/`[[io.output]]`,var → 槽号 → channel/bit) - I/O 绑定**不进映像**;绑定粒度 `slot = 槽号`(指向槽表条目),channel/bit 语义不变 - executor 按 sidecar 采样 I / 写回 Q;`dt_ms`/`cycle_limit` 从映像头取;`max_stack` 供 VM 预分配栈区 ## 用工具验证 - `ctest`:`isa_roundtrip`(编解码)、`vm_cycles`(型号/SHA 拒绝)、`machine_config`(V2 schema 强校验) - `STCompiler x.stb --disasm --machine machine.toml`:显示 `model=STATOR2` 与 `sha=ok|BAD` - 阶段 5 后:`xxd line1.stb` 对照本文逐段核对(C5 line1 推演重算)