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

215 lines
15 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 变长指令,长度编码在 opcode
- 指令长度**不固定**:4 / 8 / 16 字节(32 字节预留)
- **长度组 = opcode 高 2 位**`[len:2 | op:6]`;长度组 = 操作数形态(fmt)的自然覆盖
```text
字节 0 字节 1 字节 2..n(按长度组)
[len:2 | op:6] [type:5 | fmt:3] 操作数区
```
| 位段 | 宽度 | 内容 |
|---|---|---|
| len | 2 | 4 / 8 / 16B + 32B 预留 |
| op | 6 | 主操作码(64 空间,实际约 30 个) |
| type | 5 | **32 种:19 IEC 基础类型 + 13 预留** |
| fmt | 3 | 8 种形态:**RR、RRR、IMM、SLOT、JMP、JC、NONE、预留** |
**格式合并(9 → 7 种形态)**`CALL` 并入 **IMM**fn_id 即 32 位立即数,rd 未用)、`CAL` 并入 **SLOT**(实例号即槽号,rd 未用)——形态相同,指令身份由 op 位段区分。
| 长度组 | 指令长度 | 覆盖形态 | 操作数区 |
|---|---|---|---|
| `00` | 4 字节 | NONE / RR | rd + rs1(各 1B |
| `01` | 8 字节 | RRR / IMM / SLOT / JMP / JC | + rs2 + slot32/fn_id32/const_id32/off32 |
| `10` | 16 字节 | **SLOT+off**(字段访问)/ IMM64 | + slot32 + off32/imm64 |
| `11` | 32 字节 | 预留 | 超大立即数/未来扩展 |
- 取指:读字节 0 → `len` 位段定总长 → 搬 4/8/16 字节
- **位掩码推导**(全部编码在头 2 字节):
- 指令长度 ← `len`
- 操作数形态 ← `fmt``uses_rd = fmt∈{RR,RRR,IMM,SLOT,JC}``uses_ra = fmt∈{RR,RRR}``uses_rb = {RRR}`CALL/CAL 的 rd 恒 0,按 fmt 检查无害)
- 数据宽度/符号 ← `type`(查 constexpr 宽度/符号表)
- **字段访问统一为 LOAD/STORE 16B 变体**`LOAD rd, slot, off32`(基槽 + 偏移,编译期算死)——结构体字段与 FB 共享体字段**同一指令**,无单独 LOADF
- **跳转偏移字节化**:off32(字节,相对下一条);pc/code_offset/code_len 全字节单位;code 段 16 字节对齐
### 2.2 寄存器模型(维持现状)
- **寄存器编号 = 1 字节(8 位)→ 256 个/帧**(定长)
- 编号容量恒定关系:`8bit×256 == 16bit×128 == 32bit×64 == 64bit×32`(编号位宽 × 数量反比,总容量恒定)
- 寄存器值仍 8 字节(int64);codegen `register overflow (>256)` 检查保留
- 调用约定不变:r0 结果、r1..r7 参数、r8+ 变量/临时
### 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)、读取按宽度+符号/零扩展
- **浮点表示**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 对齐)
```text
0..71 原 15 字段(magic/版本/cycle_limit/dt_ms/hash/entry/n_globals/n_i/n_q/n_m/
n_consts/n_funcs + offset_const/funcs/code
64 offset_slots ← 槽表段(原 offset_fb 改义,FB 并入值区)
68 offset_values ← 值段(原 offset_data 改义)
72..103 型号标识(STATOR2
104 n_slots ← 新增
108 n_values ← 新增(值段字节数)
112..127 预留
```
段序:头 → 常量表 → 函数表 → 字节码 → 槽表段 → 值段 → 元数据段(预留) → SHA-256 尾
### 2.6 其他定案
- **型号 bump**STATOR1 → **STATOR2**
- **I/Q/M 六条 LOAD/STORE 合并为 LOAD/STORE 两条**(单一值区,语义标签交给 sidecar)
- **LOADF 取消**:结构体/FB 字段访问统一用 LOAD/STORE 16B 变体(基槽 + 偏移)
- **FB 共享体实施**:16B 变体即基址寻址指令,FB 体编译一次消除内联膨胀
- 结构体语法 v1 **不实现**,只留编码路径(16B 变体 + 元数据段)
### 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 乱序,无位域 | `[len:2\|op:6]` + `[type:5\|fmt:3]` 位域 |
| 格式 | 9 种(RR/RRR/IMM/SLOT/JMP/JC/CALL/CAL/NONE | **7 种形态**CALL→IMM、CAL→SLOT 合并)+ 1 预留 |
| 寄存器编号 | 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 | 元数据段格式 | 结构体/字符串的表 schema(类型描述、字段表条目)——v1 预留但格式未定 |
| ~~A2~~ | ~~常量内嵌 vs 常量表~~ | **已定案**:常量表(8B LOADK 查表);LOADK 用 type 位段解释;条目 8B 无 tagIMM64 预留不发射 |
| A3 | 内建 FB 字段类型化 | CAL_* 的实例字段在 V2 值区是类型化布局(TON.et=TIME、q=BOOL 等),字段宽度/偏移怎么定 |
| A4 | DATE/TOD/DT 字面量 | IEC 语法 `D#2026-8-24``TOD#12:30:00``DT#2026-8-24-12:30:00` 是否 v1 支持 |
| A5 | 算术语义细化 | 各宽度饱和规则(SINT/DINT/LINT 模板)、TIME/DATE 运算(TIME+TIME、TIME 比较)、浮点比较(NaN/±inf 语义) |
| A6 | sidecar/I/O 绑定 | V2 下绑定粒度(槽号不变?绑定到槽表引用)、channel/bit 语义 |
| A7 | disasm 文本格式 | V2 指令文本(含 type/off 的打印形式) |
| A8 | machine.toml V2 schema | type 表 19 条字段(base/width/signed/tag)、op 表字段(fmt/type 位段互锁) |
| A9 | 字面量类型推断细则 | 进制字面量默认类型归属(`16#FF` 是 BYTE/WORD/DINT?)、赋不同目标类型的适配规则 |
| A10 | CALL 在 V2 的确认 | 帧/寄存器约定不变(r0..r7 复制),但变长指令下 ret_pc 字节化;CALL 的 IMM 形态 rd 字段约定 |
## 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 取指变长 + 两级访问(槽表→值区)+ 按 type 读写 |
| 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 预留不发射