阶段1-1:指令与映像.md 重写为 V2 规格(STATOR2)

- §2 特性总表(变长指令/前缀分区/func/栈方案C/除法A)
- §3 指令编码(前缀分区表 + func 位段 + 操作数区位号 + uses_* 直推)
- §4 寄存器与调用栈(帧按 nregs、max_stack、递归编译期报错)
- §5 类型系统(19 类型→func 映射、BOOL 强制、日期表示)
- §6 指令语义(除法 A、浮点 IEEE、跳转字节化、内建 FB 14 条)
- §7 数据模型(槽表→值区)、§8 映像格式(头 128B/段序/校验)
- §9 sidecar、§10 反汇编(类型后缀)、§11 目录、§12 实现约定
This commit is contained in:
2026-08-25 11:29:15 +08:00
parent 53df69f4be
commit 59d7ff3159
+279 -184
View File
@@ -1,10 +1,14 @@
# 指令与映像 # 指令与映像V2 规格,STATOR2
isa 模块规范:指令集 + 映像 + 定宽类型。不是编译器,不把 `.st` 编成映像。 > 状态:**V2 规格(阶段 1 重写)**。本文件为指令编码、类型、数据模型、映像格式的
> **规范**,头文件与代码实现本文,不另当规范。
> 定案依据:[`阶段1规格总览.md`](阶段1规格总览.md)(主参考)、[`指令编码.md`](指令编码.md)、
> [`指令集清单.md`](指令集清单.md)、[`指令集优化.md`](指令集优化.md)。
> 与 V1 关系:V1(32bit 指令、8 字节定宽槽、STATOR1)已实现并冻结;本文为**全新 V2**,
> 头 `version = 2`、型号 `STATOR2`,老映像被版本/型号校验拒绝。
`compiler``.stb``vm``.stb`,两边**各自实现**读写;`isa` 归执行器侧只管指令定义。指令 opcode / 类型 / FB 布局的登记见 [`指令配置.md`](指令配置.md)`compiler/machine.toml`,与代码强校验)。 `compiler``.stb``vm``.stb`,两边**各自实现**读写;`isa` 归执行器侧只管指令定义。
指令 opcode / 类型 / FB 布局的登记见 [`指令配置.md`](指令配置.md)`compiler/machine.toml`,与代码强校验)。
全工程定案见 [`初步计划.md`](../初步计划.md)。**类型、指令编码、映像布局以本文为准**,不要另写一份互相打架的表。头文件实现本文,不另当规范。
```text ```text
STCompiler → compiler (编码查 machine.toml;自带 .stb 写) STCompiler → compiler (编码查 machine.toml;自带 .stb 写)
@@ -15,13 +19,13 @@ CMake 目标:`isa``STATIC`),无依赖;`vm` PUBLIC 链 `isa`。公开
--- ---
## 做 / 不做 ## 1. 做 / 不做
**做** **做**
- 操作码与 32 位指令布局 - 操作码(前缀分区)与**变长指令**布局(4/8/16/32B
- 映像头与段(函数字节码、全局 / FB 槽、工程哈希 - 映像头 128B 与段(常量表 / 函数表 / 字节码 / 槽表段 / 值段 / 元数据段
- `BOOL` / `INT` / `TIME` 宽度与溢出规则 - 19 种 IEC 类型 → 10 种 func 的宽度/符号表、饱和与除法边界
- 编解码、工程哈希、一条指令的文本转储(反汇编,给 STCompiler `--disasm` 与测试打印) - 编解码、工程哈希、一条指令的文本转储(反汇编,给 STCompiler `--disasm` 与测试打印)
**不做** **不做**
@@ -34,209 +38,304 @@ CMake 目标:`isa``STATIC`),无依赖;`vm` PUBLIC 链 `isa`。公开
--- ---
## 特性 ## 2. 特性总表(V2
| 项 | 第一版 | | 项 | V2 定案 |
|---|---| |---|---|
| `BOOL` | `uint8_t`,只允许 0/1 | | 指令宽度 | **变长 4/8/16/32B**,长度与形态由**前缀分区**表达 |
| `INT` | `int16_t`IEC `INT` | | 前缀 | `11`=RR、`10`=NONE、`011`=RRR、`010 000..101`=IMM/SLOT/JMP/JC/CALL/CAL、`0010`=SLOT+off、`0011`=IMM64、`0001`=预留(32B) |
| `TIME` | `int64_t` 毫秒(有符号);与 `INT` 不混用 | | 头部 | 字节 0 = `[前缀+分区\|op]`;字节 1 = `[func:4\|空:4]`(空位延后定) |
| 整数溢出 | **饱和**(夹到 `INT` 最小/最大) | | func | 4 位:0..7 = 宽度×符号(1/2/4/8B×有/无)、8=F32、9=F64;无类型指令 = 0 |
| 寄存器 | 编号 8 位(**256 = 寻址上限**),值 int64;**每帧按函数头 nregs 动态分配** |
| 调用约定 | r0 结果、r1..r7 参数(≤7)、r8+ 变量/临时;CALL/RET 复制 r0..r7 全宽(64B |
| 调用栈 | 预分配栈区(max_stack 编译期算)、帧头 12B、溢出双检查(字节+深度 64);**递归 = 编译期报错** |
| 跳转 | **字节单位**,相对下一条(目标 = 当前 + off32) |
| 类型 | 19 IEC 类型 → 10 种 func 编译期映射;禁隐式变量转换 |
| 整数溢出 | **饱和**(各宽度模板);除零返回被除数;MIN/-1 饱和;截断除法;MOD 符号随被除数 |
| 浮点 | IEEE 754(溢出/零除 → ±inf、NaN 传播) |
| 变量访问 | **槽表(引用)→ 值区(变宽紧凑)**两级间接;全 32 位寻址 |
| 字节序 | 小端 | | 字节序 | 小端 |
| 指令宽度 | 32 bit,一种主布局 | | 映像 | 魔数 `STSC`、**version = 2**、型号 `STATOR2` |
| 寄存器 | 下标 0..255;每函数实际个数写在函数头 `nregs` |
| 跳转 | 相对 offset,单位是**指令条数**,不是字节 |
| `CALL` | 立即数 `fn_id`u16),无函数指针 |
### 调用约定(冻结,compiler 12.8 与 VM 12.9 共同遵守)
- 结果寄存器 **r0**;参数寄存器 **r1..r7**(最多 7 个输入,按声明序)
- 变量与表达式临时**全部从 r8 起**(调用约定区 r0..r7 不受用户数据占用)
- `CALL`:VM 复制当前帧 r0..r7 到新帧 r0..r7
- `RET`:VM 复制当前帧 r0..r7 回调用方帧 r0..r7r0 = 结果;r1..r7 原样返回)
- 函数输入在函数体内只读(compiler 拒绝写入)
| 映像魔数 | `STSC`,版本 `1` |
| 工程哈希 | 源文件路径排序后对内容做 FNV-1a 64(非密码学) | | 工程哈希 | 源文件路径排序后对内容做 FNV-1a 64(非密码学) |
| I/O 绑定 | **不进映像**;编译期把 `var` 收成槽号,channel/bit 由 STCompiler 写进 sidecar`.runtime.toml`),BytecodeExecutor 读 sidecar 采样 | | 完整性 | 文件尾 SHA-256[32];型号标识[32]@72 |
| 不做 | `REAL`、隐式宽化 | | I/O 绑定 | **不进映像**sidecar`.runtime.toml`)绑定 var→槽号→channel/bit,粒度不变 |
| 内建 FB | 14 条(CAL + fb_id 16 位);字段布局见 [`指令集清单.md`](指令集清单.md) §8.1 |
--- ---
## 类型 ## 3. 指令编码(详见指令编码.md
C++20 定宽:
- `BOOL``uint8_t`0/1
- `INT``int16_t`;加减乘除溢出饱和
- `TIME``int64_t` 毫秒,有符号
`compiler``vm` 都按同一规则,不再另选溢出策略。
`TIME``int64_t` 的理由(冻结,不再反复问):
- 有符号:`TOF` 剩余时间、两个时间点相减会出负值,免去无符号边界处理
- 64 位:为将来 `DATE_AND_TIME`(毫秒时间戳)与 `TON` / `TOF` / `TP` 的 64 位定时器预留;毫秒量程约 2.9 亿年,扫描周期场景永不溢出
- 代价:槽位 8 字节对齐。**槽位规则**(12.9 方案 a):每槽 8 字节定宽,`BOOL` 用低 1 字节、`INT` 用低 2 字节(小端)、`TIME` 全 8 字节;槽号 × 8 = 数据偏移,无 padding。
---
## 指令
定宽 32 bit
```text ```text
[ op:8 | rd:8 | a:8 | b:8 ] 指令 = 字节0 + 字节1 + 操作数区(按形态)
字节 0 字节 1
[长度前缀+形态分区 | op] [func:4 | 空:4]
``` ```
- 三寄存器:`a`/`b``ra`/`rb``MOVE`/`NOT` 只用 `rd`+`a` ### 3.1 前缀分区与 op 空间
- `LOADK``a|b``const_id`u16
- `JMP` / `JT` / `JF``a|b` 为有符号相对 offset(指令条数),**相对下一条指令**:目标下标 = 当前下标 + 1 + off
- `CALL``a|b``fn_id`u16
操作码一次列全(`CMP_xx` 冻下面六种): | 前缀 | 长度 | 形态 | op 位宽 | op 空间 | 识别 |
|---|---|---|---|---|---|
| `11` | 4B | RR | 6 位 | 64 | 前缀直推 |
| `10` | 4B | NONE | 6 位 | 64 | 前缀直推 |
| `011` | 8B | RRR | 5 位 | 32 | 前缀直推 |
| `010 000` | 8B | IMM | 2 位 | 4 | 前缀直推 |
| `010 001` | 8B | SLOT | 2 位 | 4 | 前缀直推 |
| `010 010` | 8B | JMP | 2 位 | 4 | 前缀直推 |
| `010 011` | 8B | JC | 2 位 | 4 | 前缀直推 |
| `010 100` | 8B | CALL | 2 位 | 4 | 前缀直推 |
| `010 101` | 8B | CAL | 2 位 | 4 | 前缀直推 |
| `010 110/111` | 8B | 预留 | 2 位 | 8 | — |
| `0010` | 16B | SLOT+off | 4 位 | 16 | 前缀直推 |
| `0011` | 16B | IMM64 | 4 位 | 16 | 前缀直推 |
| `0001` | 32B | 预留(N2 | 4 位 | 16 | — |
- op 按分区独立编号(0 起);取指:读字节 0 → 前缀定长 → 搬整条
- **uses_rd/uses_ra/uses_rb 全部前缀直推**(零查表):RRR 三寄存器全真;RR 的 rd/rsIMM/SLOT/JC/SLOT+off/IMM64 仅 rdJMP/CALL/CAL/NONE 无
### 3.2 func 位段(字节 1 高 4 位)
| func | 语义 | 覆盖类型 |
|---|---|---|
| 0 | 1B 无符号 | BOOL、BYTE、USINT |
| 1 | 1B 有符号 | SINT |
| 2 | 2B 无符号 | WORD、UINT |
| 3 | 2B 有符号 | INT |
| 4 | 4B 无符号 | DWORD、UDINT、DATE |
| 5 | 4B 有符号 | DINT |
| 6 | 8B 无符号 | LWORD、ULINT、DT、TOD |
| 7 | 8B 有符号 | LINT、TIME |
| 8 | F32 | REAL |
| 9 | F64 | LREAL |
| 10..15 | 预留 | |
- **func 语义随 op**MOVE=宽度;LOAD/STORE=宽度×符号;ADD..=宽度×符号+浮点;逻辑=宽度;无类型指令=0
- 字节 1 低 4 位暂空(N1,延后定)
### 3.3 操作数区位号(bit16 起;pad = 对齐填充,编码固定 0)
| 形态 | 操作数区 |
|---|---|
| RR | rd=23..16、rs=31..24 |
| NONE | pad=31..16 |
| RRR | rd=23..16、rs1=31..24、rs2=39..32、pad=63..40 |
| IMM | rd=23..16、imm32=55..24、pad=63..56 |
| SLOT | rd=23..16、slot32=55..24、pad=63..56 |
| JMP | off32=47..16、pad=63..48 |
| JC | rd=23..16、off32=55..24、pad=63..56 |
| CALL | fn_id32=47..16、pad=63..48**rd 恒 0** |
| CAL | fb_id16=31..16、slot32=63..32**rd 恒 0** |
| SLOT+off | rd=23..16、slot32=55..24、off32=87..56、pad=127..88 |
| IMM64 | rd=23..16、imm64=87..24、pad=127..88 |
---
## 4. 寄存器与调用栈
- **寄存器编号 8 位**:256 为寻址上限(不是每帧分配数);**每帧按函数头 nregs 动态分配**(nregs×8B,百字节级)
- 寄存器值 int64codegen `register overflow (>256)` 检查
- **调用约定**:r0 结果、r1..r7 参数(≤7)、r8+ 变量/临时;CALL/RET 复制 r0..r7 全宽(64B);函数输入只读(compiler 拒绝写入)
### 调用栈(方案 C
- **递归禁止**:链接层调用图环检测(自调用/循环调用)→ 编译期报错 `link error: recursive call`
- **max_stack**MAIN 帧 + DAG 最坏调用路径 Σ(帧需求),帧需求 = 帧头 12B + nregs×8;写入映像头 @116
- **预分配栈区**:Machine 构造时一次性分配 max_stack 连续内存,运行期零分配
- 帧结构:帧头 `{ fn_id:u32, ret_pc:u32, ret_fn_id:u32 }`12B+ 寄存器区 nregs×8
- 压帧:栈顶取帧需求,sp += 需求;弹帧:sp -= 需求
- **溢出双检查**:剩余栈 < 帧需求 → `StackOverflow`(字节主检查)+ 深度 ≤64(双保险)
- MAIN 帧常驻栈底(跨周期保留),周期结束回退 sp 到 MAIN 帧顶
---
## 5. 类型系统
### 5.1 19 种 IEC 基础类型(编译期概念 → func 映射)
| 类型 | 宽度 | 符号 | func | 类型 | 宽度 | 符号 | func |
|---|---|---|---|---|---|---|---|
| BOOL | 1B | — | 0 | LINT | 8B | 有 | 7 |
| BYTE | 1B | 无 | 0 | USINT | 1B | 无 | 0 |
| WORD | 2B | 无 | 2 | UINT | 2B | 无 | 2 |
| DWORD | 4B | 无 | 4 | UDINT | 4B | 无 | 4 |
| LWORD | 8B | 无 | 6 | ULINT | 8B | 无 | 6 |
| SINT | 1B | 有 | 1 | TIME | 8B | 有(ms) | 7 |
| INT | 2B | 有 | 3 | REAL | 4B | IEEE754 | 8 |
| DINT | 4B | 有 | 5 | LREAL | 8B | IEEE754 | 9 |
| | | | | DATE | 4B | 无(天) | 4 |
| | | | | TOD | 4B | 无(ms) | 6 |
| | | | | DT | 8B | 无 | 6 |
- 编译器类型检查**严格比对**(不匹配编译期报错);**BOOL 编译器强制 0/1**(越界报错)
- **禁隐式变量转换**;**字面量按上下文适配**(`5` 可赋 INT/REAL/DINT…,编译期解释),默认 DINT 兜底
- 进制前缀 `2#`/`8#`/`16#` 字面量(浮点无前缀)
- **DATE/TOD/DT**v1 不运算(仅存取/比较);DT = u64 `{date:32 | tod:32}` 拼接(高 32 位日期)
### 5.2 值表示(寄存器 / 槽统一约定)
| 类型 | 寄存器(int64 位模式) |
|---|---|
| BOOL | 低 1 字节(0/1 |
| 有符号整数 | 按 func 宽度符号扩展 |
| 无符号/位串 | 按 func 宽度零扩展 |
| TIME/LREAL/DT | 全 64 位 |
| REAL | 低 4 字节(float 位模式) |
全宽 int64 比较等价于各类型自身比较(编译层保证类型语义)。
---
## 6. 指令语义(清单见指令集清单.md)
### 6.1 数据搬运
- `MOVE rd, rs`RR,func=宽度 0..3):寄存器间按宽度搬运(高位清 0),不管符号/浮点
- `LOAD rd, slot` / `STORE slot, rs`SLOTfunc 全矩阵):槽表[slot].addr → 值区按 func 读/写宽度
- `LOADK rd, const_id`(IMM,func 全矩阵):常量表条目 8B 原始值,按 func 解释
- `LOAD_OFF rd, slot, off` / `STORE_OFF slot, off, rs`(SLOT+off):字段访问(结构体/FB 共享体统一)
### 6.2 逻辑与位运算
- `NOT`RR)、`AND/OR/XOR`(RRR):按 func 宽度逐位(BOOL 由编译器保证 0/1)
### 6.3 算术
- `ADD/SUB/MUL/DIV`(RRR,func 全矩阵):整数饱和到 func 宽度 / 浮点 IEEE
- **整数除法边界(A 定案)**:除零 → 返回被除数;MIN/-1 → 饱和夹界;截断除法(向零)
- `MOD`:符号随被除数(-7 MOD 3 = -1);除零同 DIV
- `NEG/ABS/INC/DEC`(RR);浮点单目/舍入(RR,func 8/9);`CONV`RRfunc = 目标类型)
### 6.4 比较
- `CMP_EQ..GE`RRRfunc 全矩阵):按 func 有/无符号、浮点 IEEENaN 传播)
### 6.5 控制流
- `JMP off32`:pc += off(字节,相对下一条);`JT/JF rd, off`:条件跳转
- `CALL fn_id`(rd 恒 0):压帧(复制 r0..r7 全宽);`RET`:弹帧 / MAIN 周期结束
- `CAL fb_id, slot`(rd 恒 0):内建 FB 调用,fb_id 查 [[fb]] 表
- 周期指令计数:每条 +1,超 `cycle_limit``CycleLimit` 故障
### 6.6 内建 FB14 条)
| fb_id | FB | fb_id | FB |
|---|---|---|---|
| 0 | TON | 7 | CTUD |
| 1 | TOF | 8 | DCTUD |
| 2 | TP | 9 | R_TRIG |
| 3 | CTU | 10 | F_TRIG |
| 4 | DCTU | 11 | SR |
| 5 | CTD | 12 | RS |
| 6 | DCTD | 13 | PWM |
| | | 14 | RTC |
字段布局(类型化 + 对齐 1/2/4/8 + 偏移)见 [`指令集清单.md`](指令集清单.md) §8.1。
RTC 时钟源 = **虚拟时钟**(周期计数 × dt_ms,确定性,不读系统时钟)。
---
## 7. 数据模型:槽表 → 值区
```text ```text
MOVE rd, rs 槽表段(静态引用表,8B/条) 值段(初值,紧凑变宽)
LOADK rd, const_id { addr:u32, 预留:u32 } ──地址──▶ BOOL 1B / INT 2B / DINT·REAL 4B / TIME·LREAL 8B
NOT rd, rs 槽 0..n_slots-1 结构体 = 连续字段块(v1 预留)
AND/OR rd, ra, rb (* 已算好的值;短路用跳转 *)
ADD/SUB/MUL/DIV rd, ra, rb
CMP_EQ/NE/LT/LE/GT/GE rd, ra, rb
JMP offset
JT/JF r, offset
LOAD_I / STORE_Q / LOAD_M / STORE_M
LOAD_GLOBAL / STORE_GLOBAL
CAL_TON / CAL_TOF / CAL_TP / CAL_CTU / CAL_CTD / CAL_CTUD / CAL_R_TRIG / CAL_F_TRIG
CALL fn_id
RET
``` ```
> 12.11 修订:内置功能块扩为 8 个(TON/TOF/TP/CTU/CTD/CTUD/R_TRIG/F_TRIG), - **访问**`LOAD rd, slot``addr = 槽表[slot].addr` → 值区按 func 读宽度;字段访问 `LOAD rd, slot, off``addr + off`
> `CAL_*` 操作码**连续占 24..31**(原 CALL=27、RET=28 后移为 32、33)。 - **两级间接**:每次访问多一次内存读(PLC 规模无感)
> 操作码数值即编码,本表为准。 - **对齐**:1/2/4/8B,编译器布局保证;值段起点 16 对齐
- **初值**:编译期写值段(变量初值、FB 实例字段 0);运行时拷贝工作副本,文件只读
局部 / `VAR` = 固定寄存器;表达式临时值往后编号;`nregs` 写进函数头。 - **寻址**:槽号 u32(2^32 引用)、值区地址 u324GB)
`I`/`Q`/`M` 走映像指令,不是通用寄存器。 - 槽表分配:n_slots = n_globals(全局声明序)+ FB 实例/字段槽数
FB 实例固定布局,字段偏移编译期算死。
### 反汇编格式(disasm
`disasm` 输出一条指令的一行文本,格式冻结:
| 形态 | 格式 | 示例 |
|---|---|---|
| 二寄存器 | `MOVE rd, rs` / `NOT rd, rs` | `MOVE r1, r2` |
| 三寄存器 | `OP rd, ra, rb`(逻辑 / 算术 / 比较) | `ADD r1, r2, r3` |
| 常量 | `LOADK rd, imm` | `LOADK r0, 3` |
| 无条件跳转 | `JMP off` | `JMP +4` |
| 条件跳转 | `JT rd, off` / `JF rd, off` | `JT r0, -1` |
| I/Q/M/全局 | `LOAD_I rd, slot` 等;STORE 同形 `STORE_Q rs, slot` | `LOAD_I r0, 2` |
| FB 内置 | `CAL_TON instance` 等 | `CAL_TON 0` |
| 调用 | `CALL fn_id` | `CALL 1` |
| 返回 | `RET` | `RET` |
| 未知操作码 | `??? 0x<hex>` | — |
跳转偏移带符号、恒显正负号(`%+d`);寄存器一律 `r<n>`;常量/槽号/`fn_id` 无符号十进制。
--- ---
## 映像 ## 8. 映像格式
魔数 `STSC`,版本 `1`。全部整数小端。文件 = 头 + 五个段 + **文件尾校验**,段序:常量表 → 函数表 → 字节码 → FB 布局 → 数据。偏移记在头里,段必须连续、偏移单调不减,末段终点不超过文件长度(文件尾在数据段之后)。 ### 8.1 头(128 字节,16 对齐)
> 12.13 修订:头新增 **型号标识[32]**(原头 72 字节 → 104 字节,段偏移基准同步后移); | 偏移 | 字段 | 说明 |
> 文件尾新增 **SHA-256[32]**(对文件尾之前全部内容计算,compiler 写侧 / vm 读侧各自实现)。
> 执行器读取时:型号标识与自身支持型号不匹配 → 报错;SHA-256 不匹配 → 报错(损坏/篡改)。
### 头(104 字节)
| 偏移 | 宽 | 字段 |
|---|---|---| |---|---|---|
| 0 | 4 | 魔数 `STSC` | | 0 | magic | `STSC`(不变) |
| 4 | 4 | 版本 `1` | | 4 | version | **= 2**V1 = 1 |
| 8 | 4 | `cycle_limit` | | 8 | cycle_limit | 每周期指令数上限 |
| 12 | 4 | `dt_ms` | | 12 | dt_ms | 周期时长(毫秒) |
| 16 | 8 | 工程哈希(FNV-1a 64 | | 16 | project_hash | FNV-1a 64 |
| 24 | 4 | 入口 `entry_fn_id` | | 24 | entry_fn_id | 入口函数(MAIN |
| 28 | 4 | 全局槽数 `n_globals` | | 28 | n_globals | 全局槽数 |
| 32 | 4 | I 槽数 `n_i` | | 32/36/40 | n_i / n_q / n_m | **保留恒 0**V1 遗产,兼容/将来语义) |
| 36 | 4 | Q 槽数 `n_q` | | 44 | n_consts | 常量表条目数 |
| 40 | 4 | M 槽数 `n_m` | | 48 | n_funcs | 函数表行数 |
| 44 | 4 | 常量数 `n_consts` | | 52/56/60 | offset_const / funcs / code | 段偏移 |
| 48 | 4 | 函数数 `n_funcs` | | 64 | offset_slots | 槽表段偏移 |
| 52 | 4 | `offset_const` | | 68 | offset_values | 值段偏移(16 对齐) |
| 56 | 4 | `offset_funcs` | | 72..103 | 型号标识[32] | `STATOR2`name+version 补零) |
| 60 | 4 | `offset_code` | | 104 | n_slots | 槽表条目数(= n_globals + 实例/字段槽数) |
| 64 | 4 | `offset_fb` | | 108 | values_size | 值段字节数 |
| 68 | 4 | `offset_data` | | 112 | offset_meta | 元数据段偏移(v1 = 0 空段) |
| 72 | 32 | **型号标识**(定长 ASCII,含版本,如 `"STATOR" + "1"` 拼 32 字节补 `'\0'` | | 116 | max_stack | 栈区字节数(编译期算 |
| 120..127 | 预留 | 8 字节 |
### 文件尾(SHA-256 ### 8.2 段序
数据段之后追加 **32 字节 SHA-256**:对文件尾之前全部内容计算。执行器必须校验通过才运行;compiler 写入。 ```text
头(128) → 常量表(8B/条) → 函数表(12B/行) → 字节码(16 对齐) →
### 常量表一行(12 字节) 槽表段(8B/条) → 值段 → 元数据段(v1 空) → SHA-256[32]
`[tag:u32][value:u64]``tag`0=BOOL、1=INT、2=TIME。`value` 按 tag 解释,未用高位为 0。
### 函数表一行(12 字节)
`[nregs:u32][code_offset:u32][code_len:u32]`;行下标即 `fn_id``code_offset` 相对字节码段起点,`code_len` 为指令条数。
### 字节码段
指令按 `u32` 连续排;`CALL``fn_id` 是函数表行下标。
### FB 布局段
第一版为空;每类型一行 `[field_count:u32][field_count × (tag:u32, offset:u32)]`offset 相对实例基址,12.8 落地 codegen 时冻精确表。
### 数据段
槽初值按序排:全局(`n_globals`v1 不拆 I/Q/M)→ FB 实例块(每字段一槽)。**每槽 8 字节定宽**(12.9 方案 a):`BOOL` 用低 1 字节、`INT` 用低 2 字节(小端)、`TIME` 全 8 字节。指令 `slot` 操作数即**槽号**,数据偏移 = 槽号 × 8;符号表 `address` 与指令 slot 一致,无映射。
工程哈希:收录源文件路径排序后对内容做 **FNV-1a 64**,只保证回放槽位一致,不是密码学哈希。FNV-1a 64basis `0xcbf29ce484222325`prime `0x100000001b3`
`[[io.input]]` / `[[io.output]]` 不进映像。
---
## 映像文件(`.stb`)与 sidecar
编译产物是单文件 `<name>.stb`:映像头 + 各段按本文布局连续排,魔数 `STSC`、版本 `1`、小端。`STCompiler` 写,`BytecodeExecutor` 读。
- `dt_ms` / `cycle_limit` 在映像头,执行器只认映像,不重复配置。
- I/O 绑定不进映像:`STCompiler` 另写 sidecar `<name>.runtime.toml``BytecodeExecutor` 读 sidecar 做采样与写回,不创造变量。
sidecar 格式(TOML 子集,冻结):
```toml
[[io.input]] # 或 [[io.output]]
var = "I0_0" # 已在 GVL 声明的名字
slot = 1 # 全局槽号(编译期已解析)
channel = 0
bit = 0
``` ```
每行一个绑定;`var` 顺序不要求与映像槽序一致(`slot` 为准)。 ### 8.3 段细节
- **常量表行(8B)**:原始 64 位值(无 tag),LOADK 按 func 解释,按位模式去重
- **函数表行(12B**`{ nregs:u32, code_offset:u32(字节), code_len:u32(字节) }`
- **槽表行(8B**`{ addr:u32, 预留:u32 }`
- **值段**:全局块 + FB 实例块(1/2/4/8 对齐,编译器布局)
- **元数据段**v1 0 长度(offset_meta = 0
- **文件尾**SHA-256[32](对去掉尾的内容计算)
### 8.4 校验(vm 读侧)
1. 结构校验:魔数/版本/段偏移单调且在 SHA 前/常量表·函数表尺寸一致/代码段对齐/入口 fn_id 范围
2. **SHA-256**:完整性(防篡改)
3. **型号匹配**`STATOR2`name + version=2 补零 32 字节逐字节比对)
--- ---
## 目录与 CMake ## 9. `.stb` 与 sidecar
- `<name>.stb`(映像)+ `<name>.runtime.toml`sidecar`[[io.input]]`/`[[io.output]]`var→slot→channel/bit
- I/O 绑定**不进映像**;绑定粒度 `slot = 槽号`(指向槽表条目),channel/bit 语义不变
- executor 按 sidecar 采样 I / 写回 Q`dt_ms`/`cycle_limit` 从映像头取
---
## 10. 反汇编格式(A7 定案)
按 func 显示**类型后缀**
```text
LOAD.I16 r5, s3 STORE.U32 s1, r7 ADD.F64 r1, r2, r3
MOVE r1, r2 LOAD_OFF.I8 r4, s2, 8
JMP +4 JT r0, -1 CALL 1 CAL.TON s5
```
前缀分区决定打印模板;010 区/16B 区按形态直推。
---
## 11. 目录与 CMake
```text ```text
isa/ isa/
CMakeLists.txt CMakeLists.txt
README.md # 代码目录入口,指向本文 README.md
include/isa/ include/isa/
Types.h # 宽度、饱和、槽值表示 Types.h # 宽度/符号/饱和、除零边界
Op.h # 操作码枚举 + 助记符 Op.h # 前缀分区 + 操作码 + 形态
Instr.h # 32-bit 打包/拆字段(inline Instr.h # 变长 pack/拆字段(inline
Image.h # 头、段、函数表/常量表/FB 布局 Encode.h # encode / decode / disasm
Encode.h # 编解码、哈希、反汇编一行
src/ src/
Encode.cpp Encode.cpp
Image.cpp
``` ```
```cmake ```cmake
@@ -248,12 +347,8 @@ target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
--- ---
## 实现顺序(对齐初步计划 12.0~12.1) ## 12. 实现约定
1. `Types.h`:三类型 + `sat_add` 等饱和函数(inline 即可 - machine.tomlV2 schema)与代码**强校验**:前缀分区/op/func 互锁(见指令配置.md,阶段 1 重写
2. `Op.h` + `Instr.h`:枚举与 32-bit 编解码 - 操作码有变:先改 machine.toml + 本目录 + 测试,再动两端
3. `Encode.cpp``encode` / `decode` / `disasm` 一条指令 - 错误类别:`isa` 层无错误前缀(编解码纯函数);vm/compiler 各自带前缀
4. `Image.h` + `Image.cpp`:头布局、FNV-1a、读写缓冲(先能写空映像 + 一条 `RET`
5. 测试随后在 `tests/` 加编解码往返;本阶段以头文件和库能链为准
不在本模块做:VM `switch`、toml、关键字、符号表。