357 lines
29 KiB
Markdown
357 lines
29 KiB
Markdown
# 指令集优化(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`=NONE(4B);`011`=RRR、`010 000/001/010/011/100/101`=IMM/SLOT/JMP/JC/CALL/CAL(8B);`0010`=SLOT+off、`0011`=IMM64(16B);`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 引用)、值区地址 u32(4GB)
|
||
|
||
### 2.4 类型系统:IEC 全基础类型(19 种,type:5)
|
||
|
||
`type` 位段 **type:5(32 种)**: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/DT(U13 定案)**: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 magic(STSC,不变)
|
||
4..7 version = 2(V2 格式;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 处理 | 原因 |
|
||
|---|---|---|
|
||
| 用户 FB(FUNCTION_BLOCK) | **调用点内联展开**(字节码随调用点数膨胀) | 12.8 定案:FB 体访问**绝对字段地址**,不同实例基址不同,共享体无法复用 |
|
||
| FUNCTION(FC) | 独立函数 + `CALL fn_id` 帧栈 | FC 无状态,寄存器约定(r1..r7 / r0),无地址冲突;递归在前层被拒 |
|
||
| 内建 FB(TON/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 **内联展开** | **基址寻址共享体**(消除膨胀) |
|
||
| 寻址空间 | 槽 65535(512KB) | 槽 2^32、值区 4GB |
|
||
| 初值 | 槽内 | 值段(逻辑分段,同文件) |
|
||
| 跳转/pc | 条数单位 | **字节单位** |
|
||
| 型号 | STATOR1 | STATOR2 |
|
||
|
||
## 4. 尚未确定项(细节,待逐项闭合)
|
||
|
||
核心决策已全部定案,以下为进入实现前需闭合的设计细节:
|
||
|
||
| # | 项 | 状态 |
|
||
|---|---|---|
|
||
| ~~A1~~ | ~~元数据段格式~~ | **已定案(U12)**:v1 0 长度占位(offset_meta=0),schema 延后 |
|
||
| ~~A2~~ | ~~常量内嵌 vs 常量表~~ | **已定案**:常量表(8B LOADK 查表);LOADK 用 type 位段解释;条目 8B 无 tag;IMM64 预留不发射 |
|
||
| A3 | 内建 FB 字段类型化 | **已定案**:字段类型化(TON: in/pt/q/et = BOOL/TIME/BOOL/TIME;R_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.5(offset_meta/max_stack/values_size 等) |
|
||
| C3 | machine.toml `[[fb]]` 表 schema | **字段/布局已定案**(指令集清单 §8.1);`[[fb]]` **配置格式**并入 N5(machine.toml V2 schema,阶段 1) |
|
||
| ~~C4~~ | ~~CALL/CAL 的 rd 恒 0 成文~~ | **已定案(U14)**:已写入指令编码.md §5 |
|
||
| C5 | line1 推演重算 | 实施阶段(阶段 5)才需要 |
|
||
| ~~C6~~ | ~~计数器字段表终稿~~ | **已定案**:指令集清单 §8.1(CTU 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 个 opcode(24..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 V2(type 表 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:5(32 种)**
|
||
- 格式合并:用户确认原子类型固定后选位段方案;数位得出 type:5;CALL→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:5(32 种,含 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-float,float64-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、RTC)v1 实现** |
|
||
| ~~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 @112(v1=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~~ | **已定案**:CALL(010 100 区)/ CAL(010 101 区)的 rd 字节恒 0(未使用),按指令编码/指令集清单文档编码 |
|
||
| ~~U15~~ | ~~无类型指令 type=NONE~~ | **已被 func=0 取代**(func 位段,无类型指令编码 0 不使用) |
|
||
| ~~U16~~ | ~~off32 相对下一条公式~~ | **已确认**(随 K7 跳转字节化接受) |
|
||
|
||
|
||
## 10. 全功能指令集清单
|
||
|
||
全功能目标下的完整指令清单(10 类 ~55 条,含 op 预算核对)已拆分为独立文档:
|
||
[`指令集清单.md`](指令集清单.md)。状态列:`核心` = v1 实现;`扩展` = v1 后实现;`预留` = 仅留编码/未来。
|