阶段 D 步骤 11:文档同步 + 提交(指令配置全流程收尾)。
- stb文件格式.md:288 字节真实拆解(头 104 含型号标识 STATOR1@0x48、函数表 0x68、 代码 0x80 fn0 RET=0x21、数据段 0xC8 7 槽、SHA-256 尾 0x100);工具验证与执行器关系更新 - STCompiler使用说明.md:--machine 参数(编译/disasm 必填、打印模式不需要)、 .stb 加固说明、288 字节示例、当前状态(可编译+可执行+配置驱动) - 执行器入口.md:读取时型号/SHA 校验拒绝 - ctest 14/14 全绿
This commit is contained in:
@@ -15,45 +15,52 @@ ctest --test-dir build/gcc-debug # 测试(当前 9 个用例)
|
|||||||
## 用法
|
## 用法
|
||||||
|
|
||||||
```text
|
```text
|
||||||
STCompiler <project.toml> [-o <name>.stb]
|
STCompiler <project.toml> [-o <name>.stb] --machine <machine.toml>
|
||||||
STCompiler <name>.stb --disasm
|
STCompiler <name>.stb --disasm --machine <machine.toml>
|
||||||
```
|
```
|
||||||
|
|
||||||
| 参数 | 作用 |
|
| 参数 | 作用 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `<project.toml>` | 工程文件(必填) |
|
| `<project.toml>` | 工程文件(必填) |
|
||||||
| `-o <name>.stb` | 编译并写出映像文件;**缺省时只打印文件集合与工程哈希**(12.3 阶段行为) |
|
| `-o <name>.stb` | 编译并写出映像文件(+ sidecar);**缺省时只打印文件集合与工程哈希**(不需 `--machine`) |
|
||||||
|
| `--machine <machine.toml>` | 机器定义(指令 opcode / 类型 / FB 布局,见 `Doc/isa/指令配置.md`);**编译与 `--disasm` 必填**,加载/校验失败报错退出 |
|
||||||
| `<name>.stb --disasm` | **反汇编一个已编译的映像**(不重新编译,见下) |
|
| `<name>.stb --disasm` | **反汇编一个已编译的映像**(不重新编译,见下) |
|
||||||
| `--help` | 打印帮助 |
|
| `--help` | 打印帮助 |
|
||||||
|
|
||||||
退出码:`0` 成功;`1` 编译失败(错误信息打到 stderr)。
|
退出码:`0` 成功;`1` 失败(错误信息打到 stderr)。
|
||||||
|
|
||||||
## 反汇编(--disasm)
|
## 反汇编(--disasm)
|
||||||
|
|
||||||
对已编译的 `.stb` 逐段查看:段摘要、函数表逐条指令(文件绝对偏移)、常量表、数据段 hex。
|
对已编译的 `.stb` 逐段查看:段摘要(含型号与 SHA 校验)、函数表逐条指令(文件绝对偏移)、常量表、数据段 hex。
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ STCompiler line1.stb --disasm
|
$ STCompiler line1.stb --disasm --machine machine.toml
|
||||||
image: line1.stb (184 bytes, 2 functions, 4 globals, entry fn 1)
|
image: line1.stb (288 bytes, 2 functions, 4 globals, entry fn 1)
|
||||||
dt_ms=10 cycle_limit=100000 hash=0xc3fe4ae74ad45900
|
dt_ms=10 cycle_limit=100000 hash=0xc3fe4ae74ad45900 model=STATOR1 sha=ok
|
||||||
functions:
|
functions:
|
||||||
fn 0: nregs=8, offset=0, len=1
|
fn 0: nregs=8, offset=0, len=1
|
||||||
0x0060 RET
|
0x0080 RET
|
||||||
fn 1: nregs=13, offset=4, len=17
|
fn 1: nregs=13, offset=4, len=17
|
||||||
0x0064 LOAD_I r8, 1
|
0x0084 LOAD_I r8, 1
|
||||||
0x0068 STORE_GLOBAL r8, 8
|
0x0088 STORE_GLOBAL r8, 4
|
||||||
0x006c LOAD_GLOBAL r9, 2
|
|
||||||
...
|
...
|
||||||
data (16 bytes):
|
data (56 bytes):
|
||||||
0x0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
0x0000: ...
|
||||||
```
|
```
|
||||||
|
|
||||||
说明:
|
说明:
|
||||||
|
|
||||||
- 指令偏移是**文件绝对字节偏移**,可直接对照 `xxd line1.stb`
|
- 指令偏移是**文件绝对字节偏移**,可直接对照 `xxd line1.stb`
|
||||||
- 映像里**没有符号名**(函数表只有 fn_id,数据段无名字映射),因此按 `fn 0` / `fn 1`、槽号显示
|
- 映像里**没有符号名**(函数表只有 fn_id,数据段无名字映射),因此按 `fn 0` / `fn 1`、槽号显示
|
||||||
|
- `model=` 显示型号标识(`machine.toml [meta]` 生成);`sha=ok|BAD` 显示文件尾 SHA-256 校验结果
|
||||||
- 文件损坏或打不开 → `error: ...` 退出码 1
|
- 文件损坏或打不开 → `error: ...` 退出码 1
|
||||||
|
|
||||||
|
## 编译产物(.stb 加固)
|
||||||
|
|
||||||
|
- **型号标识[32]**:`[meta] name + version` 拼成(如 `"STATOR1"`),写进头偏移 72
|
||||||
|
- **SHA-256 文件尾[32]**:对文件尾之前全部内容计算;compiler 写侧与 vm 读侧各实现一份
|
||||||
|
- 执行器读取时型号不匹配 / SHA 不符 → 直接拒绝(详见 `Doc/isa/指令与映像.md` 12.13 修订)
|
||||||
|
|
||||||
## 示例(line1)
|
## 示例(line1)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -65,11 +72,11 @@ files:
|
|||||||
main.st
|
main.st
|
||||||
hash: 0xc3fe4ae74ad45900
|
hash: 0xc3fe4ae74ad45900
|
||||||
|
|
||||||
$ STCompiler examples/line1/project.toml -o line1.stb
|
$ STCompiler examples/line1/project.toml -o line1.stb --machine compiler/machine.toml
|
||||||
compiled: line1.stb (184 bytes, 2 functions, 4 globals)
|
compiled: line1.stb (288 bytes, 2 functions, 4 globals)
|
||||||
```
|
```
|
||||||
|
|
||||||
产物 `line1.stb`:魔数 `STSC` + 版本 1 的单一映像(指令见 `Doc/isa/指令与映像.md`)。
|
产物:`line1.stb`(288 字节:头 104 含型号标识 + 各段 + SHA-256 文件尾)+ `line1.runtime.toml`(sidecar)。指令见 `Doc/isa/指令与映像.md`,结构拆解见 `Doc/isa/stb文件格式.md`。
|
||||||
|
|
||||||
## 工程文件(project.toml)
|
## 工程文件(project.toml)
|
||||||
|
|
||||||
@@ -142,10 +149,10 @@ project.toml + .st
|
|||||||
|
|
||||||
- `examples/line1/`:最小闭环(MAIN + MotorStarter FB + I/O + 全局),给人看
|
- `examples/line1/`:最小闭环(MAIN + MotorStarter FB + I/O + 全局),给人看
|
||||||
- `tests/cases/01~20/`:20 个用例(每份 `project.toml` + `.st` + `EXPECTED.md`),编译结果按表
|
- `tests/cases/01~20/`:20 个用例(每份 `project.toml` + `.st` + `EXPECTED.md`),编译结果按表
|
||||||
- `tests/`:CTest(`isa_roundtrip` / `compiler_toml` / `lexer_tokens` / `parser_syntax` / `linker_links` / `typecheck_types` / `codegen_slice1`)
|
- `tests/`:CTest(`compiler_toml` / `lexer_tokens` / `parser_syntax` / `linker_links` / `typecheck_types` / `codegen_slice1` / `machine_config` / `vm_cycles` / `cases_all` / `cli_*`)
|
||||||
|
|
||||||
## 当前状态
|
## 当前状态
|
||||||
|
|
||||||
- ✅ 可编译:14 个正例用例全部产出 `.stb`;6 个负例按期望拒绝
|
- ✅ 可编译:14 个正例用例全部产出 `.stb`(含型号标识 + SHA-256);6 个负例按期望拒绝
|
||||||
- ⏳ 执行:`BytecodeExecutor`(加载 `.stb` 跑扫描周期)在 12.9/12.10
|
- ✅ 执行:`BytecodeExecutor` 加载 `.stb` 跑扫描周期(型号/SHA 校验、回放、单步)
|
||||||
- ⏳ sidecar(`<name>.runtime.toml`,I/O 绑定)在 12.10 随执行器一起接线
|
- ✅ 配置驱动:指令 opcode / 类型元数据 / FB 布局来自 `compiler/machine.toml`(`--machine`)
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ BytecodeExecutor <name>.stb [--cycles N] [--replay <file>] [--step]
|
|||||||
## 职责
|
## 职责
|
||||||
|
|
||||||
- 加载 `.stb` 映像与 `<name>.runtime.toml` sidecar(I/O 绑定 var → 槽号 → channel/bit)
|
- 加载 `.stb` 映像与 `<name>.runtime.toml` sidecar(I/O 绑定 var → 槽号 → channel/bit)
|
||||||
|
- 读取时**校验型号标识与 SHA-256**:型号不匹配 / 文件被篡改 → 直接报错拒绝(执行器只接受与自身内建型号一致的映像)
|
||||||
- 按 sidecar 采样 I、写回 Q(不创造变量)
|
- 按 sidecar 采样 I、写回 Q(不创造变量)
|
||||||
- `dt_ms` / `cycle_limit` 从映像头取,推进 `TON` / `TOF` / `CTU`
|
- `dt_ms` / `cycle_limit` 从映像头取,推进内置 FB(TON/TOF/TP/CTU/CTD/CTUD/R_TRIG/F_TRIG)
|
||||||
- 单步、看寄存器和映像、按录制的 `I` 回放
|
- 单步、看寄存器和映像、按录制的 `I` 回放
|
||||||
|
|
||||||
## 边界
|
## 边界
|
||||||
|
|||||||
+36
-28
@@ -1,8 +1,6 @@
|
|||||||
# .stb 映像文件结构
|
# .stb 映像文件结构
|
||||||
|
|
||||||
编译产物 `.stb` 的**面向使用者**的结构说明。规范以 [`指令与映像.md`](指令与映像.md) 为准,本文用 `line1.stb`(224 字节)做真实拆解。
|
编译产物 `.stb` 的**面向使用者**的结构说明。规范以 [`指令与映像.md`](指令与映像.md) 为准,本文用 `line1.stb`(288 字节,12.13 修订后)做真实拆解。
|
||||||
|
|
||||||
> **12.13 修订**(编译器写侧已落地,vm 读侧待步骤 8):头新增型号标识[32](头 72 → 104 字节,段偏移基准同步后移),文件尾新增 SHA-256[32](对文件尾之前全部内容计算)。line1 产物现为 288 字节。本文拆解仍为旧格式数字,需在 vm 侧落地后统一重新生成。
|
|
||||||
|
|
||||||
## 概览
|
## 概览
|
||||||
|
|
||||||
@@ -12,7 +10,7 @@
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌──────────────────────────────────────────────────┐
|
┌──────────────────────────────────────────────────┐
|
||||||
│ 头(72 字节,偏移 0) │
|
│ 头(104 字节,偏移 0,含型号标识[32]) │
|
||||||
├──────────────────────────────────────────────────┤
|
├──────────────────────────────────────────────────┤
|
||||||
│ 常量表段 offset_const .. offset_funcs │
|
│ 常量表段 offset_const .. offset_funcs │
|
||||||
├──────────────────────────────────────────────────┤
|
├──────────────────────────────────────────────────┤
|
||||||
@@ -22,11 +20,13 @@
|
|||||||
├──────────────────────────────────────────────────┤
|
├──────────────────────────────────────────────────┤
|
||||||
│ FB 布局段 offset_fb .. offset_data(v1 为空)│
|
│ FB 布局段 offset_fb .. offset_data(v1 为空)│
|
||||||
├──────────────────────────────────────────────────┤
|
├──────────────────────────────────────────────────┤
|
||||||
│ 数据段 offset_data .. 文件末尾 │
|
│ 数据段 offset_data .. offset_data+len │
|
||||||
|
├──────────────────────────────────────────────────┤
|
||||||
|
│ SHA-256 文件尾(32 字节,对文件尾之前全部内容) │
|
||||||
└──────────────────────────────────────────────────┘
|
└──────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
## 头(72 字节)
|
## 头(104 字节)
|
||||||
|
|
||||||
| 偏移 | 宽 | 字段 | line1 实际值 |
|
| 偏移 | 宽 | 字段 | line1 实际值 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
@@ -42,11 +42,15 @@
|
|||||||
| 40 | 4 | M 槽数 `n_m` | 0 |
|
| 40 | 4 | M 槽数 `n_m` | 0 |
|
||||||
| 44 | 4 | 常量数 `n_consts` | 0 |
|
| 44 | 4 | 常量数 `n_consts` | 0 |
|
||||||
| 48 | 4 | 函数数 `n_funcs` | 2 |
|
| 48 | 4 | 函数数 `n_funcs` | 2 |
|
||||||
| 52 | 4 | `offset_const` | 72 |
|
| 52 | 4 | `offset_const` | 104(`0x68`) |
|
||||||
| 56 | 4 | `offset_funcs` | 72 |
|
| 56 | 4 | `offset_funcs` | 104 |
|
||||||
| 60 | 4 | `offset_code` | 96 |
|
| 60 | 4 | `offset_code` | 128(`0x80`) |
|
||||||
| 64 | 4 | `offset_fb` | 168 |
|
| 64 | 4 | `offset_fb` | 200(`0xC8`) |
|
||||||
| 68 | 4 | `offset_data` | 168 |
|
| 68 | 4 | `offset_data` | 200 |
|
||||||
|
| 72 | 32 | **型号标识**(定长 ASCII 含版本,补 `'\0'`) | `"STATOR1"`(`0x48..0x67`) |
|
||||||
|
|
||||||
|
> 12.13 修订:型号标识由 `machine.toml [meta] name + version` 拼成(如 `STATOR + 1` → `"STATOR1"`);
|
||||||
|
> 执行器读取时型号不匹配 → 直接报错。
|
||||||
|
|
||||||
## 常量表段(`offset_const` 起)
|
## 常量表段(`offset_const` 起)
|
||||||
|
|
||||||
@@ -76,15 +80,15 @@ line1(2 行):
|
|||||||
- `CALL` 的 `fn_id` = 函数表行下标
|
- `CALL` 的 `fn_id` = 函数表行下标
|
||||||
- 调用约定:结果 r0、参数 r1..r7、变量与临时 r8 起
|
- 调用约定:结果 r0、参数 r1..r7、变量与临时 r8 起
|
||||||
|
|
||||||
line1 `MAIN` 前 5 条(`0x60` 起,slot 为 8 字节定宽槽号):
|
line1 `MAIN` 前 5 条(`0x84` 起;`0x80` 是 `fn 0` 的占位 `RET`,slot 为 8 字节定宽槽号):
|
||||||
|
|
||||||
| 偏移 | 字节 | 反汇编 | 含义 |
|
| 偏移 | 字节 | 反汇编 | 含义 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| 0x64 | `12 08 01 00` | `LOAD_I r8, 1` | I0_0(io.input 绑定 → LOAD_I,槽 1) |
|
| 0x84 | `12 08 01 00` | `LOAD_I r8, 1` | I0_0(io.input 绑定 → LOAD_I,槽 1) |
|
||||||
| 0x68 | `17 08 04 00` | `STORE_GLOBAL r8, 4` | starter.start(槽 4)← I0_0 |
|
| 0x88 | `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) |
|
| 0x8C | `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 |
|
| 0x90 | `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) |
|
| 0x94 | `16 08 04 00` | `LOAD_GLOBAL r8, 4` | 内联体:读 starter.start(槽 4) |
|
||||||
|
|
||||||
## FB 布局段(`offset_fb` 起)
|
## FB 布局段(`offset_fb` 起)
|
||||||
|
|
||||||
@@ -96,24 +100,28 @@ v1 为空(用户 FB 内联展开,字段偏移已算进数据段;内建 8
|
|||||||
|
|
||||||
槽序:**全局块**(`n_globals` 个,声明序)→ **FB 实例块**(POU 收集序、实例声明序,每字段一槽)。
|
槽序:**全局块**(`n_globals` 个,声明序)→ **FB 实例块**(POU 收集序、实例声明序,每字段一槽)。
|
||||||
|
|
||||||
line1 数据段(56 字节 = 7 槽 × 8B,`0xA8` 起):
|
line1 数据段(56 字节 = 7 槽 × 8B,`0xC8` 起):
|
||||||
|
|
||||||
| 槽号 | 偏移 | 内容 |
|
| 槽号 | 偏移 | 内容 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 0 | 0xA8 | EmergencyStop(BOOL,初值 0) |
|
| 0 | 0xC8 | EmergencyStop(BOOL,初值 0) |
|
||||||
| 1 | 0xB0 | I0_0(BOOL) |
|
| 1 | 0xD0 | I0_0(BOOL) |
|
||||||
| 2 | 0xB8 | I0_1(BOOL) |
|
| 2 | 0xD8 | I0_1(BOOL) |
|
||||||
| 3 | 0xC0 | Q0_0(BOOL) |
|
| 3 | 0xE0 | Q0_0(BOOL) |
|
||||||
| 4 | 0xC8 | starter.start(BOOL) |
|
| 4 | 0xE8 | starter.start(BOOL) |
|
||||||
| 5 | 0xD0 | starter.stop(BOOL) |
|
| 5 | 0xF0 | starter.stop(BOOL) |
|
||||||
| 6 | 0xD8 | starter.q(BOOL) |
|
| 6 | 0xF8 | starter.q(BOOL) |
|
||||||
|
|
||||||
|
## SHA-256 文件尾(32 字节)
|
||||||
|
|
||||||
|
数据段之后追加 32 字节 SHA-256:**对文件尾之前全部内容计算**(`0x100..0x11F`)。执行器必须校验通过才运行;任一字节被篡改 → 直接拒绝。compiler 写侧与 vm 读侧**各自实现**一份 SHA-256。
|
||||||
|
|
||||||
## 用工具验证
|
## 用工具验证
|
||||||
|
|
||||||
- `ctest` 的 `isa_roundtrip` / `codegen_slice1` 覆盖编解码往返与映像校验
|
- `ctest`:`codegen_slice1`(写侧 model/sha 自检)、`vm_cycles`(读侧型号/SHA 拒绝)、`machine_config`
|
||||||
- `isa::ImageView` 提供只读视图(校验魔数/版本/段边界/入口 fn_id)
|
- `STCompiler x.stb --disasm --machine machine.toml`:显示 `model=` 与 `sha=ok|BAD`
|
||||||
- 手工检查:`xxd line1.stb` 对照上表逐段核对
|
- 手工检查:`xxd line1.stb` 对照上表逐段核对
|
||||||
|
|
||||||
## 与执行器的关系
|
## 与执行器的关系
|
||||||
|
|
||||||
`BytecodeExecutor`(12.9/12.10 实现)只读本格式:头(`cycle_limit`/`dt_ms`)、函数表(帧 `nregs` + 代码定位)、数据段(全局 + FB 实例状态)。I/O 绑定**不在**映像里,在 sidecar `<name>.runtime.toml`(var → 槽号 → channel/bit)。
|
`BytecodeExecutor` 只读本格式:头(`cycle_limit`/`dt_ms`/型号标识)、函数表(帧 `nregs` + 代码定位)、数据段(全局 + FB 实例状态)。读取时**型号匹配 + SHA-256 校验**,任一不符 → 报错拒绝。I/O 绑定**不在**映像里,在 sidecar `<name>.runtime.toml`(var → 槽号 → channel/bit)。
|
||||||
|
|||||||
Reference in New Issue
Block a user