Files
Interpreter/Doc/isa/stb文件格式.md
T
Admin ce948451e0 12.9 步骤 0:数据段改 8 字节定宽槽(方案 a)。
- 指令与映像.md / 寄存器码.md:slot 语义 = 槽号(数据偏移 = 槽号 × 8),取消变宽对齐与 global_offset 映射
- Codegen.cpp:删除 width_of/align_up/global_offsets_;layout_data/layout_fb_instances 按槽号布局(字段 = 槽序号)
- stb文件格式.md:line1 真实字节更新(224B、56B 数据段、starter 槽 4/5/6)
- codegen_test:断言更新(槽号化 + 数据区字节数),189 断言 9/9 全绿
2026-08-21 20:01:21 +08:00

5.8 KiB
Raw Blame History

.stb 映像文件结构

编译产物 .stb面向使用者的结构说明。规范以 指令与映像.md 为准,本文用 line1.stb224 字节)做真实拆解。

概览

  • 魔数 STSC,版本 1全部整数小端
  • 文件 = 头 + 五个段,段序:常量表 → 函数表 → 字节码 → FB 布局 → 数据
  • 段偏移记在头里;offset_const ≤ offset_funcs ≤ offset_code ≤ offset_fb ≤ offset_data ≤ 文件长度
┌──────────────────────────────────────────────────┐
│ 头(72 字节,偏移 0)                             │
├──────────────────────────────────────────────────┤
│ 常量表段  offset_const .. offset_funcs           │
├──────────────────────────────────────────────────┤
│ 函数表段  offset_funcs .. offset_code            │
├──────────────────────────────────────────────────┤
│ 字节码段  offset_code  .. offset_fb              │
├──────────────────────────────────────────────────┤
│ FB 布局段 offset_fb     .. offset_datav1 为空)│
├──────────────────────────────────────────────────┤
│ 数据段    offset_data   .. 文件末尾              │
└──────────────────────────────────────────────────┘

头(72 字节)

偏移 字段 line1 实际值
0 4 魔数 STSC 53 53 54 43
4 4 版本 1 1
8 4 cycle_limit(每周期指令上限) 100000
12 4 dt_ms(本周期 Δt 10
16 8 工程哈希(FNV-1a 64 0xc3fe4ae74ad45900
24 4 入口 entry_fn_id 1MAIN
28 4 全局槽数 n_globals 4
32 4 I 槽数 n_i 0v1 不拆)
36 4 Q 槽数 n_q 0
40 4 M 槽数 n_m 0
44 4 常量数 n_consts 0
48 4 函数数 n_funcs 2
52 4 offset_const 72
56 4 offset_funcs 72
60 4 offset_code 96
64 4 offset_fb 168
68 4 offset_data 168

常量表段(offset_const 起)

一行 12 字节:[tag:u32][value:u64]tag0=BOOL、1=INT、2=TIME。

line1 无字面量常量 → 段为空(offset_const == offset_funcs)。

函数表段(offset_funcs 起)

一行 12 字节:[nregs:u32][code_offset:u32][code_len:u32]

  • 行下标即 fn_idcode_offset 相对字节码段起点(字节);code_len指令条数
  • 入口 = 头的 entry_fn_id 指向的行

line12 行):

fn_id nregs code_offset code_len 内容
0 8 0 1 MotorStarter 占位(内联展开,仅 RET
1 13 4 17 MAIN

字节码段(offset_code 起)

指令 4 字节一条:[op:8 | rd:8 | a:8 | b:8](小端 u32)。

  • rd 目的寄存器;a|b 视操作码为寄存器、槽号(u16)或跳转偏移(有符号 int16,相对下一条指令:目标 = 当前 + 1 + off
  • CALLfn_id = 函数表行下标
  • 调用约定:结果 r0、参数 r1..r7、变量与临时 r8 起

line1 MAIN 前 5 条(0x60 起,slot 为 8 字节定宽槽号):

偏移 字节 反汇编 含义
0x64 12 08 01 00 LOAD_I r8, 1 I0_0io.input 绑定 → LOAD_I,槽 1
0x68 17 08 04 00 STORE_GLOBAL r8, 4 starter.start(槽 4)← I0_0
0x6C 16 09 02 00 LOAD_GLOBAL r9, 2 I0_1(槽 2
0x70 17 09 05 00 STORE_GLOBAL r9, 5 starter.stop(槽 5)← I0_1
0x74 16 08 04 00 LOAD_GLOBAL r8, 4 内联体:读 starter.start(槽 4

FB 布局段(offset_fb 起)

v1 为空(用户 FB 内联展开,字段偏移已算进数据段;内建 TON/TOF/CTU 布局冻结在编译器中)。行格式约定:[field_count:u32][field_count × (tag:u32, offset:u32)]offset 相对实例基址。

数据段(offset_data 起)

每槽 8 字节定宽12.9 方案 a):BOOL 用低 1 字节、INT 用低 2 字节(小端)、TIME 全 8 字节。指令 slot 操作数即槽号,数据偏移 = 槽号 × 8。

槽序:全局块n_globals 个,声明序)→ FB 实例块(POU 收集序、实例声明序,每字段一槽)。

line1 数据段(56 字节 = 7 槽 × 8B,0xA8 起):

槽号 偏移 内容
0 0xA8 EmergencyStopBOOL,初值 0
1 0xB0 I0_0BOOL
2 0xB8 I0_1BOOL
3 0xC0 Q0_0BOOL
4 0xC8 starter.startBOOL
5 0xD0 starter.stopBOOL
6 0xD8 starter.qBOOL

用工具验证

  • ctestisa_roundtrip / codegen_slice1 覆盖编解码往返与映像校验
  • isa::ImageView 提供只读视图(校验魔数/版本/段边界/入口 fn_id)
  • 手工检查:xxd line1.stb 对照上表逐段核对

与执行器的关系

BytecodeExecutor12.9/12.10 实现)只读本格式:头(cycle_limit/dt_ms)、函数表(帧 nregs + 代码定位)、数据段(全局 + FB 实例状态)。I/O 绑定不在映像里,在 sidecar <name>.runtime.tomlvar → 槽号 → channel/bit)。