Files
Interpreter/Doc/isa/指令集优化.md
T

357 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 指令集优化(V2 规格,型号 STATOR2)
> 状态:**规格冻结中**。核心决策已全部定案(§2),本文为 V2 规格草案;
> §4 列出**尚未确定的细节项**,全部闭合后进入实现阶段。
> 与现状(V1)的关系:V1 编码冻结不可改(opcode 0..33、32bit 指令、8 字节定宽槽),
> 本优化为**全新 V2 架构**,.stb 格式 / 指令字 / 数据模型全部重设计,型号 bump 为 STATOR2。
## 1. 背景与动机
| # | 现状问题 | 优化方向 |
|---|---|---|
| 1 | opcode 定义草率:34 条按语义乱序编号,无位域结构 | format/宽度**编码进 opcode**,位掩码机械推导 |
| 2 | 8 字节定宽槽浪费:BOOL 只用 1/8 空间 | **变宽紧凑值区**1/2/4/8 字节按类型) |
| 3 | 变量区利用率低 | 值区按类型紧凑布局 + 地址 u32(4GB) |
| 4 | 类型只有 BOOL/INT/TIME | 扩展 IEC 全基础类型(19 种) |
| 5 | 结构体无法支持 | 槽表引用 + LOAD 16B 变体(基槽+偏移,预留) |
| 6 | 指令 32bit 固定 | 变长指令(长度编码在 opcode);寄存器编号维持 8 位 |
| 7 | 槽(变量)与初值(数据)耦合在同一格 | **槽表(引用)与值区(数据)解耦** |
## 2. 已定案设计
### 2.1 变长指令,前缀编码 + 形态分区
- 指令长度**不固定**:4 / 8 / 16 字节(32 字节预留);**长度与形态由前缀分区一体表达**(见 [`指令编码.md`](指令编码.md)
- **前缀分区**`11`=RR、`10`=NONE4B);`011`=RRR、`010 000/001/010/011/100/101`=IMM/SLOT/JMP/JC/CALL/CAL8B);`0010`=SLOT+off、`0011`=IMM6416B);`0001`=预留(32B
- **fmt 位段已取消**(用户定案):形态全部由前缀分区表达(含 010 区内部分区,零查表)
```text
字节 0 字节 1 字节 2..n(按长度组)
[前缀+形态分区 | op] [func:4 | 空:4] 操作数区
```
| 位段 | 位号 | 内容 |
|---|---|---|
| 前缀+分区 | 4B: bit7..6 / 8B: bit7..5 / 16B: bit7..4 / 32B: bit7..4 | 长度与形态分区 |
| op | 4B: bit5..0 / 8B: bit4..0 / 16B: bit3..0 / 32B: bit3..0 | 分区内独立编号 |
| func | bit15..12 | 数据语义(宽度×符号/浮点),语义随 op |
| 空 | bit11..8 | 待全部编码完后定用途 |
| 长度组 | 指令长度 | 形态分区 | 操作数区 |
|---|---|---|---|
| `11`/`10` | 4 字节 | RR / NONE | rd + rs1(各 1B/ 无 |
| `011`/`010` | 8 字节 | RRR / 010 区六形态(分区直推) | rd+rs1+rs2 / 见指令编码.md §5 |
| `0010`/`0011` | 16 字节 | SLOT+off / IMM64 | rd + slot32 + off32 / rd + imm64 |
| `0001` | 32 字节 | 预留 | 超大立即数/未来扩展 |
- 取指:读字节 0 → 前缀定总长 → 搬 4/8/16 字节
- **推导**(编码在头两字节):
- 指令长度 + 形态 ← 前缀分区(010 区查表)
- uses_rd/uses_ra/uses_rb ← 形态:全部前缀直推(指令编码.md §6)
- 数据宽度/符号 ← `func` 位段(查 constexpr 宽度/符号表)
- **字段访问统一为 LOAD/STORE 16B 变体**`LOAD rd, slot, off32`(基槽 + 偏移,编译期算死)——结构体字段与 FB 共享体字段**同一指令**,无单独 LOADF
- **跳转偏移字节化**:off32(字节,相对下一条);pc/code_offset/code_len 全字节单位;code 段 16 字节对齐
### 2.2 寄存器模型与调用栈(U10 定案)
- **寄存器编号 = 1 字节(8 位)→ 256 个为寻址上限**(8 位字段能编的最大寄存器号),**不是每帧分配数**
- **每帧按函数头 nregs 动态分配**(编译器按该函数变量+临时峰值算):帧大小 = nregs × 8B(百字节级),栈深 64 上限
- 编号容量恒定关系:`8bit×256 == 16bit×128 == 32bit×64 == 64bit×32`(指编号位宽 × 数量反比,编号空间,非帧大小)
- 寄存器值仍 8 字节(int64);codegen `register overflow (>256)` 检查保留
- 调用约定不变:r0 结果、r1..r7 参数(≤7)、r8+ 变量/临时;CALL/RET 帧复制 = **r0..r7 全宽(64B**,类型解释是下游指令按 func 的事
#### 调用栈(方案 C:预分配栈区,U10 定案)
- **无递归**:链接层检测调用图环(FUNCTION 自调用/循环调用)→ **编译期报错**`link error: recursive call`);无环 → 最坏调用路径编译期可算
- **帧结构(每帧 12B 帧头 + nregs×8B 寄存器区)**:帧头 = { fn_id:u32, ret_pc:u32, ret_fn_id:u32 };寄存器区 = 本函数 nregs 个 int64
- **max_stack 编译期计算(写入映像头 @116**`max_stack = MAIN 帧需求 + 最坏 FUNCTION 调用路径 Σ(帧需求)`,帧需求 = 12 + nregs×8;调用图为 DAG(无递归),最坏路径 = 按字节权重的最长路径;MAIN 帧计入(常驻栈底)
- **预分配栈区**:Machine 构造时一次性分配 max_stack 字节连续内存,运行期零分配
- **压帧**:从栈顶取 帧需求(12 + nregs×8),sp += 帧需求;**弹帧**sp -= 帧需求
- **溢出检查双口径**:剩余栈 < 帧需求 → `StackOverflow`(字节主检查)+ 深度 ≤64(双保险)
- **MAIN 帧常驻栈底**(跨周期保留),周期结束回退 sp 到 MAIN 帧顶
### 2.3 数据模型:槽表(引用)→ 值区(数据)
```text
槽表段(静态引用表,8B/条) 值段(初值,紧凑变宽)
┌─────────────────────────┐ ┌──────────────────────────┐
│ { addr:u32, 预留:u32 } │ ──地址──▶ │ BOOL 1B / INT 2B(对齐) │
│ 槽 0..n_slots-1 │ │ DINT·REAL 4B / TIME 8B │
└─────────────────────────┘ │ 结构体 = 连续字段块(预留) │
└──────────────────────────┘
```
- 访问:`LOAD rd, slot``addr = 槽表[slot].addr` → 值区按 `type` 位段读 1/2/4/8 字节;字段访问 `LOAD rd, slot, off32``addr + off`
- **两级间接**:每次访问多一次内存读(PLC 规模无感)
- **宽度编码进 opcode**`type` 位段携带宽度 + 符号,VM 无歧义读写(V1 因"变宽布局无法从槽号推断宽度"而改定宽,V2 用 type 位段化解)
- 对齐规则:1/2/4/8 字节,编译器布局保证
- 初值**整合在 .stb 内分段**(ELF 式):槽表段 / 值段 / 元数据段并列,单文件 SHA-256 校验
- 寻址规模:**全 32 位**——槽号 u32(2^32 引用)、值区地址 u324GB)
### 2.4 类型系统:IEC 全基础类型(19 种,type:5
`type` 位段 **type:532 种)**19 个 IEC 基础类型 + 13 预留;结构体/字符串/数组不占位段(组合类型走元数据段)。
| type | 类型 | 宽度 | 符号 | C 对应 | type | 类型 | 宽度 | 符号 | C 对应 |
|---|---|---|---|---|---|---|---|---|---|
| 0 | BOOL | 1B | — | bool | 10 | UINT | 2B | 无 | uint16_t |
| 1 | BYTE | 1B | 无 | uint8_t | 11 | UDINT | 4B | 无 | uint32_t |
| 2 | WORD | 2B | 无 | uint16_t | 12 | ULINT | 8B | 无 | uint64_t |
| 3 | DWORD | 4B | 无 | uint32_t | 13 | TIME | 8B | 有(ms) | int64_t |
| 4 | LWORD | 8B | 无 | uint64_t | 14 | **REAL** | 4B | IEEE754 | **float** |
| 5 | SINT | 1B | 有 | int8_t | 15 | **LREAL** | 8B | IEEE754 | **double** |
| 6 | INT | 2B | 有 | int16_t | 16 | **DATE** | 4B | 无 | uint32_t(天) |
| 7 | DINT | 4B | 有 | int32_t | 17 | **TOD** | 4B | 无 | uint32_t(当日 ms) |
| 8 | LINT | 8B | 有 | int64_t | 18 | **DT** | 8B | 无 | uint64_t |
| 9 | USINT | 1B | 无 | uint8_t | 19..31 | 预留 | | | |
- **type 位段红利**:CMP/算术按类型自动语义——无符号类型无符号比较、整数饱和到类型宽度(模板化)、浮点走 IEEE 754(无饱和,溢出→±inf)、读取按宽度+符号/零扩展
- **整数除法语义(A 定案)**:除零 → **返回被除数**(结果保持,Fail-safe);MIN/-1 溢出 → **饱和夹界**(各宽度模板化);截断除法(向零,C 风格);**MOD 符号随被除数**(-7 MOD 3 = -1,与除法一致),除零同 DIV
- **DATE/TOD/DTU13 定案)**DATE=uint32(天数)、TOD=uint32(当日 ms)、DT=uint64 **{date:32 \| tod:32} 拼接**(高 32 位日期);DT→DATE 取高 32 位、DT→TOD 取低 32 位(CONV/移位展开);v1 无日期运算仅存取/比较
- **浮点表示**REAL 4B / LREAL 8B,值区 4/8 字节对齐;寄存器 int64 位模式搬运(REAL 低 4 字节),运算时按 type 重解释
- **常量表契约(A2 定案)**:条目 = **8 字节原始值(无 tag**,按位模式去重;
`LOADK rd, const_id`8B IMM 形态)**用指令 type 位段**解释(读 width 字节、按符号扩展),
与 LOAD 语义统一;同一常量可被不同 type 的 LOADK 复用(字面量按上下文适配的落地)。
V1 的 {tag, value} 契约废弃。IMM64 形态(16B 内嵌 64 位值)**保留编码、v1 不发射**。
- **ST 层**:19 类型名全量进关键字;**进制前缀** `2#`/`8#`/`16#` 支持(浮点无前缀);浮点十进制字面量(`1.5``-2.5e3`
- **类型转换**:**禁止隐式变量转换**(赋值/比较/算术要求类型严格一致,Typecheck 阶段报错);**字面量按上下文适配**(`5` 可赋 INT/REAL/DINT 等,编译期解释,非运行时转换);显式转换函数(`INT_TO_REAL()`v1 不做
### 2.5 映像格式(头 128 字节,16 对齐)——U7 已定案
```text
0..3 magicSTSC,不变)
4..7 version = 2V2 格式;V1 = 1
8..71 原 15 字段(cycle_limit/dt_ms/project_hash/entry_fn_id/
n_globals/n_i/n_q/n_m/n_consts/n_funcs + offset_const/funcs/code/fb/data
64 offset_slots ← 槽表段(原 offset_fb 改义,FB 并入值区)
68 offset_values ← 值段(原 offset_data 改义,起点 16 对齐)
72..103 型号标识(STATOR2
104 n_slots ← 槽表条目数(= n_globals + FB 实例/结构体字段槽数)
108 values_size ← 值段字节数(原 n_values,命名修正)
112 offset_meta ← 元数据段偏移(v1 恒 0 = 空段;结构体/字符串类型表预留)
116 max_stack ← 栈区字节数(编译期按调用图算,U10 方案 C)
120..127 预留 8 字节
```
段序:头 → 常量表 → 函数表 → 字节码 → 槽表段 → 值段 → 元数据段(v1 空) → SHA-256 尾
**U7 修正注记(2026-08-24**
- 「原 15 字段」修正为**原 17 字段(72 字节)**
- `n_values` 改名 **`values_size`**(值段字节数,避免与"数量"混淆)
- 预留区固定 **`offset_meta` @112**(v1 填 0 = 元数据段不存在,将来启用不改头)
- **n_i/n_q/n_m 保留恒 0**V1 遗产字段:兼容 + sidecar 校验/将来 I/Q/M 分区语义预留,不删)
- **n_slots = n_globals + FB 实例/结构体字段槽数**(明确关系)
- **offset_values 16 对齐**TIME/LREAL 8B 对齐的上界;编译器保证)
### 2.6 其他定案
- **型号 bump**STATOR1 → **STATOR2**
- **I/Q/M 六条 LOAD/STORE 合并为 LOAD/STORE 两条**(单一值区,语义标签交给 sidecar)
- **LOADF 取消**:结构体/FB 字段访问统一用 LOAD/STORE 16B 变体(基槽 + 偏移)
- **FB 共享体实施**:16B 变体即基址寻址指令,FB 体编译一次消除内联膨胀
- 结构体语法 v1 **不实现**,只留编码路径(16B 变体 + 元数据段)
- **FB 编码定案(B1/B2****1 条 CAL**SLOT 形态,8B:头 2 + fb_id:16 + slot32+ **fb_id 16 位**(查 machine.toml `[[fb]]` 表);新增内建 FB 只改配置 + VM 实现,指令格式零变化。V1 的 CAL_TON..CAL_F_TRIG 8 个 opcode 作废
- **领域指令不进指令集(B4 定案)**:运动控制 / 通信等**全部走 FB 库**ST 层 FB + CALL + 共享体),V2 **不设 EXT 服务指令**——op 位段只承载基础指令
### 2.7 调用与内联策略(V1 现状 + V2 方向)
**V1 现状**
| 对象 | V1 处理 | 原因 |
|---|---|---|
| 用户 FBFUNCTION_BLOCK | **调用点内联展开**(字节码随调用点数膨胀) | 12.8 定案:FB 体访问**绝对字段地址**,不同实例基址不同,共享体无法复用 |
| FUNCTIONFC | 独立函数 + `CALL fn_id` 帧栈 | FC 无状态,寄存器约定(r1..r7 / r0),无地址冲突;递归在前层被拒 |
| 内建 FBTON/CTU/…) | `CAL_*` 指令(VM 运行时原语 `do_cal`) | 定时器/计数器是 VM 侧状态机,天然共享 |
**V2 定案**16B 变体 `LOAD/STORE rd, slot, off` = 基址寻址——FB 体编译一次,运行时按实例槽定位字段,**消除内联膨胀**。FUNCTION 仍走 CALL 帧栈;内建 FB 仍走 CAL(SLOT 形态,实例号即槽号)。
## 3. 与 V1 的差异对照
| 项 | V1(现状) | V2(定案) |
|---|---|---|
| 指令长度 | 固定 32bit | **变长 4/8/16B**,长度在 opcode |
| opcode | 0..33 乱序,无位域 | `[前缀+形态分区\|op]` + `[func:4\|空:4]` |
| 格式 | 9 种(RR/RRR/IMM/SLOT/JMP/JC/CALL/CAL/NONE | **形态由前缀分区表达**11/10/011/010查表/0010/0011),fmt 位段取消 |
| 寄存器编号 | 8 位(256/帧) | 8 位(256/帧,不变) |
| 变量访问 | 立即数槽号直接寻址 | **槽表引用 → 值区**(两级间接) |
| 槽 | 8B 定宽 | 8B 引用表({addr:u32} |
| 值区 | 定宽 8B/变量 | **变宽紧凑**1/2/4/8B |
| 宽度信息 | 无(定宽) | **type 位段**RISC-V 式) |
| 类型 | BOOL/INT/TIME | **19 IEC 基础类型 + 13 预留** |
| 字段访问 | 无(FB 内联) | **LOAD/STORE rd, slot, off**(结构体/FB 共用) |
| FB 调用 | 用户 FB **内联展开** | **基址寻址共享体**(消除膨胀) |
| 寻址空间 | 槽 65535512KB | 槽 2^32、值区 4GB |
| 初值 | 槽内 | 值段(逻辑分段,同文件) |
| 跳转/pc | 条数单位 | **字节单位** |
| 型号 | STATOR1 | STATOR2 |
## 4. 尚未确定项(细节,待逐项闭合)
核心决策已全部定案,以下为进入实现前需闭合的设计细节:
| # | 项 | 状态 |
|---|---|---|
| ~~A1~~ | ~~元数据段格式~~ | **已定案(U12**v1 0 长度占位(offset_meta=0),schema 延后 |
| ~~A2~~ | ~~常量内嵌 vs 常量表~~ | **已定案**:常量表(8B LOADK 查表);LOADK 用 type 位段解释;条目 8B 无 tagIMM64 预留不发射 |
| A3 | 内建 FB 字段类型化 | **已定案**:字段类型化(TON: in/pt/q/et = BOOL/TIME/BOOL/TIMER_TRIG: clk/q = BOOL/BOOL);计数器单/双字(INT/DINT**编码形式 = fb 表拆条**CTU/DCTU/CTD/DCTD/CTUD/DCTUD 6 条,名字即宽度)——U5 已定案 |
| A4 | DATE/TOD/DT 字面量 | **已定案(V2 修订)****V2 支持** IEC 格式 `D#2026-8-24`/`TOD#12:30:00`/`DT#2026-8-24-12:30:00`;纪元 1970-01-01=0 天;TOD 无小数秒;年 1..9999(详见阶段3-语言层V2.md L10 |
| A5 | 算术语义细化 | **已定案**:饱和模板化到各宽度(SINT/DINT/LINT);TIME+TIME / TIME-TIME / TIME 比较;浮点 IEEE 常规(溢出→±inf、0 除→±inf、NaN 传播,无特判);DATE/TOD/DT **不做运算**(仅存取/比较) |
| A6 | sidecar/I/O 绑定 | **已定案**:与现状一致——绑定粒度仍 `slot = 槽号`(指向槽表条目),channel/bit 语义不变 |
| A7 | disasm 文本格式 | **已定案****类型后缀**形式:`LOAD.I16 r5, s3``STORE.U32 s1, r7``ADD.F64 r1, r2, r3` |
| A8 | machine.toml V2 schema | **已定案**type 表 = **编译器内建基元别名**bit/int8/int16/int32/int64/uint8/uint16/uint32/uint64/float32/float64):REAL→base float32=C float)、LREAL→base float64=C double),其余按位宽/符号映射;op 表 {name, op(0..63), fmt} + fmt/type 位段互锁校验 |
| ~~A9~~ | ~~字面量类型推断~~ | **已定案**:按上下文适配;默认 DINT 仅作兜底语义(上下文恒存在,正常程序不触发) |
| ~~A10~~ | ~~FB 编码~~ | **已定案(B1/B2**1 CAL + fb_id **16 位**(查 [[fb]] 表);新增 FB 只改配置 + VM 实现 |
另:CALL 的 V2 确认(随 A10)——ret_pc 字节化(随跳转已定);CALL(IMM 形态)rd 恒 0;帧/寄存器约定不变(r0..r7 复制)。
### 未定 / 待细化(C1..C6
| # | 项 | 说明 |
|---|---|---|
| ~~C1~~ | ~~元数据段格式(原 A1~~ | **已定案(U12**v1 0 长度占位(offset_meta=0),schema 延后 |
| ~~C2~~ | ~~头 128B 布局终稿~~ | **已定案(U7 修正版)**:见 §2.5offset_meta/max_stack/values_size 等) |
| C3 | machine.toml `[[fb]]` 表 schema | **字段/布局已定案**(指令集清单 §8.1);`[[fb]]` **配置格式**并入 N5machine.toml V2 schema,阶段 1 |
| ~~C4~~ | ~~CALL/CAL 的 rd 恒 0 成文~~ | **已定案(U14**:已写入指令编码.md §5 |
| C5 | line1 推演重算 | 实施阶段(阶段 5)才需要 |
| ~~C6~~ | ~~计数器字段表终稿~~ | **已定案**:指令集清单 §8.1CTU 8B / DCTU 16B / CTUD 10B / DCTUD 16B |
## 8. 待讨论(用户反问)
### A9:什么情况下会没有上下文?(已定案)
ST 中字面量只能出现在表达式/赋值里(`x := 5``y + 5``IF 16#FF > t THEN`),
目标类型或运算操作数类型恒在,v1 无"裸字面量"位置——**上下文恒存在**。
因此"默认 DINT"只是防御性兜底(编译器内部缺类型时的报错路径),
正常程序不触发。结论:按上下文适配即可,默认 DINT 保留为兜底语义。**已确认(2026-08-24**。
### A10:FB 为什么会有 8 种?(已定案)
V1 的 CAL_TON..CAL_F_TRIG 是 8 个 opcode24..31),因为 V1 opcode 充足、无位段压力。
V2 的 op 位段仅 6 位(64 个),FB 占 8 个不划算,且 machine.toml 已有 `[[fb]]`
(8 条,含 opcode 字段)——**可收敛为 1 个 CAL(SLOT 形态)+ FB 类型 id(立即数/查 fb 表)**:
- 收益:op 位段省 7 个;新增 FB(如自定义内建)不加 opcode、只加配置
- 代价:VM 按 id 分派(一次查表,可接受);disasm 需查 fb 表打印名称
- 关联:A3 的单字/双字计数变体编码也随此定(fb 表加 width/type 列即可)
**已定案(B1/B2**1 CAL + fb_id 16 位。
后续扩展讨论(B4/B5):领域指令(运动控制/通信)**不进指令集**——PLCopen 运动控制本
是 FB 库;V2 不设 EXT 服务指令,一切领域功能走 FB 库(CALL + 共享体)。op 位段预算见 B5。
## 5. 影响面清单
| 模块 | 改动 |
|---|---|
| isa | Op.h 重排(位域)、Instr.h 变长 pack/拆、Encode disasm 表驱动、Types 宽度/符号表 + 饱和模板化 |
| compiler | machine.toml V2type 表 19 条 + fmt/type 位段互锁)、MachineConfig 校验、Codec 变长、Codegen(槽表+值区布局、初值写值段、E_* 变长发射、字节化回填)、Stb 新头/段 |
| vm | Image 新头/段校验、Machine 取指变长 + 两级访问(槽表→值区)+ 按 func 读写 + **预分配栈区**max_stack,替代动态 vector frames |
| executor | slot_bool 按 BOOL 读 1 字节(小改) |
| tests | isa/vm/machine/codegen/compiler 全部重写;cases 20 个重新生成产物 |
| docs | 指令与映像、指令配置、stb文件格式、寄存器码、指令执行(line1 推演重算)、扫描周期、初步计划、README |
## 6. 实施阶段(每阶段独立可验证 + 提交)
1. **规格冻结**:本文 §4 全部闭合后,重写指令与映像.md / 指令配置.md / stb文件格式.md
2. **isa 重构**:变长 Instr + 位域 Op + Encode + isa_test
3. **compiler 侧**machine.toml V2 + MachineConfig + Codec + Codegen + Stb + 对应测试
4. **vm 侧**Image + Machine(两级访问)+ vm_test
5. **executor + 全链路**cases 20 个 + cli 测试 + line1 产物重生成
6. **文档收尾**:指令执行推演、扫描周期、初步计划、README
## 7. 决策历史(讨论纪要)
- 动机源起:用户质疑 opcode 定义草率;探索 format 位前缀编码(方案 A)与 uses_rd 位掩码推导
- 数据模型演进:8B 定宽槽 →(用户提出槽表引用 + 初值分离)→ 槽表/值区两级模型
- 宽度信息:用户选「宽度编码进 opcode」(RISC-V 式,对应「槽表条目带类型」被否)
- 初值组织:用户选「整合 .stb 内分段」(ELF 式)
- 寻址规模:用户选「全 32 位」(槽号 u32 + 地址 u32
- 指令长度:用户定「变长指令,长度编码在 opcode」;此前 128bit 固定长度方案被否
- 寄存器:用户定「编号 8 位(256/帧)维持现状」,容量恒定式 8bit×256=16bit×128=32bit×64=64bit×32
- 类型扩展:IEC 整数族 12 种 + REAL/LREAL= C float/double+ DATE/TOD/DT → **19 种,type:532 种)**
- 格式合并:用户确认原子类型固定后选位段方案;数位得出 type:5CALL→IMM、CAL→SLOT 形态合并,fmt 3 位
- 调用策略:V1 用户 FB 内联 / FC CALL / 内建 CAL_*V2 用 16B 变体(基槽+偏移)实现 FB 共享体
- LOADF 取消:用户指出 LOADF 与 LOAD 无本质区别(仅数据搬运)→ 字段访问统一 LOAD/STORE 16B 变体
- 类型转换:用户定「禁止隐式变换,编译阶段检查」+ 字面量按上下文适配
- 字面量:用户定支持 IEC 进制前缀(2#/8#/16#
- A2 定案:LOADK 用 type 位段解释常量值(与 LOAD 语义统一);常量表条目 8B 无 tag;IMM64 预留不发射
- A3..A8 定案(2026-08-24):计数器单/双字两种;DATE 字面量不支持;TIME/浮点运算按推荐;sidecar 一致;disasm 类型后缀;type 表=基元别名(REAL→float32、LREAL→float64
- A9 定案:按上下文适配、默认 DINT 兜底(用户确认)
- U5 定案:内建 FB 15 条全部 v1 实现(6 计数拆条 + TON/TOF/TP/R/F_TRIG + SR/RS、PWM、RTC
- U6 定案:op 预算按指令集清单/指令编码文档方案(前缀分区)
- U7 定案:头 128B 修正版(offset_meta 占位、values_size 命名、n_i/n_q/n_m 保留恒 0、n_slots 关系、16 对齐)
- U8 定案:槽表条目 {addr:u32, 预留:u32} 8B
- U9 定案:值段 1/2/4/8B 对齐编译器保证
- U10 定案:寄存器/调用约定维持现状、帧按 nregs 动态分配;栈方案 C(预分配栈区 + max_stack@116 编译期算 + 字节/深度双检查);递归 = 链接层环检测编译期报错
- U12 定案:元数据段 v1 0 长度占位(offset_meta=0),schema 延后
- U13 定案:DATE/TOD/DT 表示(DT={date:32|tod:32} 拼接,转换取高/低 32 位)
- U14 定案:CALL/CAL rd 字段恒 0(按指令编码/指令集清单文档)——**全部 U 项闭合,V2 规格冻结**
- 版本线确认:当前设计 = **V2**(V1 为已实现简化版);头 version = 2,型号 STATOR2
- 帧头 12B 成文(fn_id/ret_pc/ret_fn_id+ max_stack 计算细则(MAIN 计入、DAG 最长路径)
- 整数除法语义 A 定案:除零返回被除数、MIN/-1 饱和、截断除法、MOD 符号随被除数(延续 V1 饱和算术家族)
- A10 定案(B1/B2):1 CAL + fb_id 16 位(查 [[fb]] 表);V1 的 8 个 CAL_* opcode 作废
- B4 定案:领域指令(运动控制/通信)不进指令集,一律 FB 库;无 EXT 服务指令
- B3/B5 说明中待确认:单/双字计数编码、op 位段预算(均已随 U5/U6 定案)
- 未定项记录:C1..C6(均已闭合:C1=U12、C2=U7、C3=字段表已定+配置格式入 N5、C4=U14、C5=实施阶段、C6=§8.1 字段表终稿)
## 9. 确认核验清单(2026-08-24 核对)
> 原则:**未明确回答 ≠ 同意**。本清单逐项记录「用户明确回答」与「待确认」,
> 待确认项由用户逐项表态后闭合。
### 9.1 已确认(用户明确回答)
| # | 项 | 用户回答 |
|---|---|---|
| K1 | 变长指令(长度编码在 opcode) | 「变长指令,指令长度编码再opcode里面」 |
| K2 | 寄存器 8 位编号 256/帧(容量恒定式) | 「寄存器大小不变,8bit*256 == 16bit*128 == ...」 |
| K3 | 宽度编码进 opcode(非槽表带类型) | question 选「宽度编码进 opcode」 |
| K4 | 初值整合 .stb 内分段(ELF 式) | question 选「整合在 .stb 内分段」 |
| K5 | 全 32 位寻址(槽号 u32 + 地址 u32 | question 选「全 32 位寻址」 |
| K6 | type:532 种,含 DATE/TOD/DT 19 基础类型) | 「B」 |
| K7 | 跳转偏移字节化 | 「接受」 |
| K8 | I/Q/M 六条合并为 LOAD/STORE 两条 | 「合并」 |
| K9 | LOADF 取消(LOAD/STORE 16B 变体=字段访问) | 「LOADF和普通的LOAD应该没有区别吧」 |
| K10 | ST 层类型全量(19 类型名进关键字) | 「全量」 |
| K11 | 禁止隐式变量转换(编译期检查) | 「禁止隐式变换,只需要编译阶段检查」 |
| K12 | 进制前缀(2#/8#/16# | 「进制前缀」 |
| K13 | A2 常量表(LOADK type 解释、条目 8B 无 tag、IMM64 预留) | 「使用常量表吧」+ 讨论 |
| K14 | A3 计数单字/双字两种都要 | 「需要两种,单字的和双字的计数指令都要有」 |
| K15 | A4 DATE/TOD/DT 字面量 v1 不支持 | 「先不支持」 |
| K16 | A5 算术语义(饱和模板/TIME±/浮点 IEEE/DATE 不运算) | 「先做吧」 |
| K17 | A6 sidecar 绑定粒度一致(slot=槽号) | 「应该可以保持一致」 |
| K18 | A7 disasm 类型后缀(LOAD.I16 r5, s3 | 「类型后缀」 |
| K19 | A8 type 表=基元别名(REAL→float32、LREAL→float64 | 「类型:编译器内建基元...float32-floatfloat64-double」 |
| K20 | A9 字面量按上下文适配、默认 DINT 兜底 | 「就这么做」 |
| K21 | B1 fb_id 16 位 | 「16位」 |
| K22 | B2 1 CAL + fb_id(查 [[fb]] 表) | 「cal + fb_id」 |
| K23 | B4 领域指令不进指令集(运动/通信走 FB 库) | 「不进指令集」 |
| K24 | 前缀分区形态:`011`=RRR、`010`=其他 | 「那就011前缀的是RRR类型指令,010前缀的是其他指令」 |
| K25 | fmt 位段取消,形态全前缀分区(零查表) | 「010区也换成前缀编码,这样所有指令都统一了」 |
| K26 | MOVE 只搬宽度,不管符号/浮点;类型不匹配编译期报错 | 「move指令只管宽度和搬运...类型不匹配,编译时就报错」 |
### 9.2 待确认(用户未明确回答)——已全部闭合(2026-08-24)
| # | 事项 | 当前文档写法 | 待表态 |
|---|---|---|---|
| ~~U1~~ | ~~格式合并 9→7~~ | **作废**:fmt 位段已取消,形态由前缀分区表达,无合并问题 |
| ~~U2~~ | ~~长度组映射~~ | **已被前缀编码取代**11/10/011/010xxx/0010/0011/0001,见指令编码.md §3 |
| ~~U3~~ | ~~字节布局~~ | **已被取代**`[前缀+形态分区\|op] + [func:4\|空:4]`(指令编码.md §2 |
| ~~U4~~ | ~~结构体 v1 只留编码不实现语法~~ | **已定案(预留)**:只留编码路径(LOAD/STORE 16B 变体 + 元数据段),语法 v1 不实现 |
| ~~U5~~ | ~~B3 计数拆条~~ | **已定案**fb 表拆条 11 条(CTU/DCTU/CTD/DCTD/CTUD/DCTUD 6 计数 + TON/TOF/TP/R_TRIG/F_TRIG),名字即宽度;**清单内建 FB 全部 15 条(含 SR/RS、PWM、RTCv1 实现** |
| ~~U6~~ | ~~op 预算~~ | **已定案**:按指令集清单.md §12 / 指令编码.md §3 方案(前缀分区预算:RR 21/64、NONE 2/64、RRR 26/32、010 区 8/24、SLOT+off 8/16、IMM64 1/16、0001 预留 6/16 |
| ~~U7~~ | ~~头 128 字节布局~~ | **已定案(修正版)**17 字段表述、values_size 命名、offset_meta @112v1=0)、n_i/n_q/n_m 保留恒 0、n_slots 关系定义、16 对齐(见 §2.5 注记) |
| ~~U8~~ | ~~槽表条目格式~~ | **已定案**{addr:u32, 预留:u32} 8B/条(引用表,地址指向值段) |
| ~~U9~~ | ~~值段对齐~~ | **已定案**:1/2/4/8B 对齐由编译器布局保证(值段起点 16 对齐,见 U7) |
| ~~U10~~ | ~~寄存器与调用栈~~ | **已定案**:寄存器 int64 不变;调用约定不变;CALL/RET 全宽复制;帧按 nregs 动态分配(§2.2 表述修正);栈方案 C(预分配 + max_stack@116 + 字节/深度双检查 + 递归编译器报错) |
| ~~U11~~ | ~~CAL 编码布局~~ | **已定案**010 101 分区,操作数区 fb_id16=31..16 + slot32=63..32 |
| ~~U12~~ | ~~元数据段占位~~ | **已定案**v1 定 0 长度占位(offset_meta=0 = 空段,接口预留),字段表 schema 延后(有使用方时再定) |
| ~~U13~~ | ~~DATE/TOD/DT 表示~~ | **已定案**DATE=uint32(天数)、TOD=uint32(当日 ms)、DT=uint64 **{date:32 \| tod:32} 拼接**(高 32 位日期,取高/低即转换,比较天然有序);v1 无日期运算(A5);将来转换编译展开 |
| ~~U14~~ | ~~CALL/CAL 的 rd 恒 0~~ | **已定案**CALL010 100 区)/ CAL010 101 区)的 rd 字节恒 0(未使用),按指令编码/指令集清单文档编码 |
| ~~U15~~ | ~~无类型指令 type=NONE~~ | **已被 func=0 取代**(func 位段,无类型指令编码 0 不使用) |
| ~~U16~~ | ~~off32 相对下一条公式~~ | **已确认**(随 K7 跳转字节化接受) |
## 10. 全功能指令集清单
全功能目标下的完整指令清单(10 类 ~55 条,含 op 预算核对)已拆分为独立文档:
[`指令集清单.md`](指令集清单.md)。状态列:`核心` = v1 实现;`扩展` = v1 后实现;`预留` = 仅留编码/未来。