- Doc/isa/stb文件格式.md:段布局图、17 字段头表、常量/函数/字节码/FB/数据各段 - 用 line1.stb(184 字节)逐段核对实际值:函数表 2 行、MAIN 指令字节、数据段全局+实例块 - 标注与执行器的关系(sidecar 不含在映像);索引与 isa README 登记
5.5 KiB
5.5 KiB
.stb 映像文件结构
编译产物 .stb 的面向使用者的结构说明。规范以 指令与映像.md 为准,本文用 line1.stb(184 字节)做真实拆解。
概览
- 魔数
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_data(v1 为空)│
├──────────────────────────────────────────────────┤
│ 数据段 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 |
1(MAIN) |
| 28 | 4 | 全局槽数 n_globals |
4 |
| 32 | 4 | I 槽数 n_i |
0(v1 不拆) |
| 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];tag:0=BOOL、1=INT、2=TIME。
line1 无字面量常量 → 段为空(offset_const == offset_funcs)。
函数表段(offset_funcs 起)
一行 12 字节:[nregs:u32][code_offset:u32][code_len:u32]
- 行下标即
fn_id;code_offset相对字节码段起点(字节);code_len为指令条数 - 入口 = 头的
entry_fn_id指向的行
line1(2 行):
| 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)CALL的fn_id= 函数表行下标- 调用约定:结果 r0、参数 r1..r7、变量与临时 r8 起
line1 MAIN 前 5 条(0x60 起):
| 偏移 | 字节 | 反汇编 | 含义 |
|---|---|---|---|
| 0x60 | 12 08 01 00 |
LOAD_I r8, 1 |
I0_0(io.input 绑定 → LOAD_I) |
| 0x64 | 17 08 08 00 |
STORE_GLOBAL r8, 8 |
starter.start ← I0_0 |
| 0x68 | 16 09 02 00 |
LOAD_GLOBAL r9, 2 |
I0_1 |
| 0x6C | 17 09 09 00 |
STORE_GLOBAL r9, 9 |
starter.stop ← I0_1 |
| 0x70 | 16 08 08 00 |
LOAD_GLOBAL r8, 8 |
内联体:读 starter.start |
FB 布局段(offset_fb 起)
v1 为空(用户 FB 内联展开,字段偏移已算进数据段;内建 TON/TOF/CTU 布局冻结在编译器中)。行格式约定:[field_count:u32][field_count × (tag:u32, offset:u32)],offset 相对实例基址。
数据段(offset_data 起)
全局块(n_globals 个,声明序)→ FB 实例块(按 POU 收集序、实例声明序,块间 8 字节对齐)。
槽宽与对齐:BOOL 1 字节 / INT 2 字节 / TIME 8 字节,每个槽起点对齐自身宽度。
line1 数据段(16 字节,0xA8 起):
| 偏移 | 内容 |
|---|---|
| 0xA8..0xAB | 全局:EmergencyStop、I0_0、I0_1、Q0_0(BOOL,初值 0) |
| 0xAC..0xAF | 填充(实例块 8 对齐) |
| 0xB0..0xB2 | starter 实例:start、stop、q(BOOL) |
| 0xB3..0xB7 | 填充 |
用工具验证
ctest的isa_roundtrip/codegen_slice1覆盖编解码往返与映像校验isa::ImageView提供只读视图(校验魔数/版本/段边界/入口 fn_id)- 手工检查:
xxd line1.stb对照上表逐段核对
与执行器的关系
BytecodeExecutor(12.9/12.10 实现)只读本格式:头(cycle_limit/dt_ms)、函数表(帧 nregs + 代码定位)、数据段(全局 + FB 实例状态)。I/O 绑定不在映像里,在 sidecar <name>.runtime.toml(var → 槽号 → channel/bit)。