Files
Interpreter/Doc/isa/指令配置.md
T
Admin 5bcab6791f 指令配置定案:两大分类(PLAIN/INSTANCE)+ FB 注册并入 ops.txt。
- 三层分类:class(操作对象)→ format(操作数形态)→ 参数名(语义)
- op 行加 class 字段(PLAIN 26 条 / INSTANCE 8 条 CAL_*),类别-格式互锁校验
- fb 行登记内建 FB 布局(8 个),cal_opcode 与 op 行强校验一致
- 加 FB = 配置文件一行 + VM 语义 case,编译器免重建;执行计划更新为 7 步
2026-08-21 21:09:23 +08:00

146 lines
7.3 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.
# 指令配置文件(ops.txt
指令集的**唯一事实来源**name / opcode / class / format / 参数名 / enabled。代码实现与配置文件在启动时**强校验**一致,防止两处漂移。
## 目标
- 加指令/屏蔽指令的登记集中在一处(配置文件),不再散落在代码各处手改
- 执行器(VM):**语义实现必须在代码里**,不能纯从文件加载;配置文件用于**屏蔽**(`enabled=false` 的指令执行到 → 故障)
- 编译器(STCompiler):**启动时从文件加载**(校验 + 屏蔽传导)
- `.stb` ABI 不变:opcode 数值仍是冻结契约;屏蔽是编译期/运行期策略,不改数值
## 指令的三层分类(定案)
```text
class(操作对象) → format(操作数形态) → 参数名(操作数语义)
PLAIN/INSTANCE RR/RRR/IMM/SLOT/ rd/rs/const_id/
JMP/JC/CALL/CAL/NONE slot/off/fn_id/instance
```
| 层 | 回答的问题 | 谁需要它 |
|---|---|---|
| **class** | 操作对象:**值/搬运** 还是 **实例算法** | 语义归属、校验互锁(INSTANCE ↔ CAL |
| **format** | 操作数的**形态**:寄存器 / 常量 id / 槽号 / 带符号偏移 | disasm 渲染、编码助手 |
| **参数名** | 每个操作数的**语义命名** | 元数据、文档、校验 |
### 两个大类
| 大类 | 操作对象 | 现有指令 | 操作数形态 |
|---|---|---|---|
| **无实例**(PLAIN) | 寄存器 / 立即数 / 槽号 / 分支 / 调用 | MOVE/LOADK/NOT/AND/OR/算术/CMP_* / JMP/JT/JF / LOAD_*/STORE_* / CALL/RET26 条) | RR/RRR/IMM/SLOT/JMP/JC/CALL/NONE |
| **有实例**INSTANCE | **数据区实例块**(内建 FB | CAL_TON/TOF/TP/CTU/CTD/CTUD/R_TRIG/F_TRIG8 条) | CAL(一个实例基槽号) |
区别的本质:
```text
LOAD_GLOBAL(无实例):从槽读一个"值" → 地址是编译期槽号,纯搬运
CAL_TON(有实例) :对实例块执行"算法" → 基槽号 + 完整定时器语义(读字段/推进/写字段)
```
format 不可省:同是"第二个操作数是数字",`LOADK`/`LOAD_I`/`CALL` 渲染相同但语义不同(常量 id / 槽号 / fn_id,由参数名表达);"数字 vs 寄存器 vs 偏移"的**渲染差异**只有 format 能表达(`r%d` / `%u` / `%+d`)。
## 配置文件格式(`isa/ops.txt`
**全属性必填,不可省略**`#` 注释、空行忽略:
```text
# op <name> <opcode> <class> <format> <参数名...> <enabled>
# class: PLAIN(无实例)/ INSTANCE(有实例)
op MOVE 0 PLAIN RR rd rs enabled
op LOADK 1 PLAIN IMM rd const_id enabled
op NOT 2 PLAIN RR rd rs enabled
op AND 3 PLAIN RRR rd ra rb enabled
op ADD 5 PLAIN RRR rd ra rb enabled
op CMP_EQ 9 PLAIN RRR rd ra rb enabled
op JMP 15 PLAIN JMP off enabled
op JT 16 PLAIN JC r off enabled
op LOAD_I 18 PLAIN SLOT rd slot enabled
op CAL_TON 24 INSTANCE CAL instance enabled
op CALL 32 PLAIN CALL fn_id enabled
op RET 33 PLAIN NONE enabled
```
- 参数个数由 format 决定,解析时校验字段数:
| format | 参数 | 现有指令 |
|---|---|---|
| `RR` | 2rd rs | MOVE / NOT |
| `RRR` | 3rd ra rb | AND/OR/ADD/SUB/MUL/DIV/CMP_xx |
| `IMM` | 2rd const_id | LOADK |
| `SLOT` | 2rd slot | LOAD_I/STORE_Q/LOAD_M/STORE_M/LOAD_GLOBAL/STORE_GLOBAL |
| `JMP` | 1off | JMP |
| `JC` | 2r off | JT / JF |
| `CALL` | 1fn_id | CALL |
| `CAL` | 1instance | CAL_*8 个) |
| `NONE` | 0 | RET |
- **类别与格式互锁**`INSTANCE` 类的 format 必须是 `CAL`,反之亦然——配置错误启动期暴露
### 内建 FB 注册(定案:并入 ops.txt
`CAL_*` 已是 op 行(与 ADD 同机制:编码/译码/disasm/屏蔽);fb 行登记其**数据结构(布局)**——ST 语言层的登记处(Lexer/Parser/Linker/Codegen 查表):
```text
# fb <name> <cal_opcode> <字段:类型 ...>
fb ton 24 in:BOOL pt:TIME q:BOOL et:TIME
fb tof 25 in:BOOL pt:TIME q:BOOL et:TIME
fb tp 26 in:BOOL pt:TIME q:BOOL et:TIME
fb ctu 27 cu:BOOL r:BOOL pv:INT q:BOOL cv:INT
fb ctd 28 cd:BOOL ld:BOOL pv:INT q:BOOL cv:INT
fb ctud 29 cu:BOOL cd:BOOL r:BOOL lu:BOOL pv:INT qu:BOOL qd:BOOL cv:INT
fb r_trig 30 clk:BOOL q:BOOL
fb f_trig 31 clk:BOOL q:BOOL
```
- fb 行的 `cal_opcode` 与 op 行的 CAL_* 操作码**强校验一致**(防两处漂移)
- 字段类型名小写(`bool/int/time`),与语言关键字对齐
- **加 FB = fb 行 + VM 一个语义 case,编译器免重建**(关键字/布局/操作码映射全部从表读)
## isa 层:`OpTable`
```cpp
class OpTable {
bool load(const char* path, std::string* err); // 解析 + 强校验
bool enabled(uint8_t op) const;
// name / format / 参数名查询(后续 FB 注册也走这里)
};
```
**强校验(load 时)**
- 语法:字段数符合 format、enabled 必须出现
- 操作码唯一、0..255
- **与编译期枚举一致**:文件里每条指令的 name/opcode/format 必须与代码(`Op` 枚举 + 助记符 + `OpFormat`)逐条一致,任一不符 → 报错列出差异
- 任一失败 → `load` 返回 false,调用方报错退出
前置改造:**OpFormat 显式化**——现有隐式"形态"disasm 的 case)变成枚举 `RR/RRR/IMM/SLOT/JMP/JC/CALL/CAL/NONE``disasm` 改表驱动(输出文本不变,现有断言兼容)。
## 各端接线
| 端 | 参数 | 行为 |
|---|---|---|
| STCompiler | `STCompiler <project.toml> [-o out.stb] --ops <ops.txt>` | **仅 `-o` 编译路径要求**;加载/校验失败 → 报错退出;codegen 生成被屏蔽指令 → 编译错误(屏蔽传导) |
| BytecodeExecutor | `--ops <ops.txt>`(**可选**) | 不传 = 全部启用(兼容现有用法);传入 → 加载 + 校验,执行到 disabled 指令 → `Fault::Disabled`,周期中止退出码 1 |
| 语义实现 | — | 仍在 VM 代码里(每指令一个 case,不可省) |
## 加东西的流程(改造后)
```text
加普通指令:ops.txt 加一行 opname opcode class format 参数 enabled
+ Op.h 枚举加一项 + VM 一个语义 case → 重建 isa/VM
加内建 FBops.txt 加一行 fbname cal_opcode 字段:类型)
+ VM 一个语义 case → 重建 VM(编译器免重建)
屏蔽指令:ops.txt 把 enabled 改 disabled
→ 编译器拒绝生成、执行器运行时报 Disabled 故障(零代码改动)
```
## 执行计划(单步确认)
1. **OpFormat / OpClass 显式化**:新增 `OpFormat`RR/RRR/IMM/SLOT/JMP/JC/CALL/CAL/NONE)与 `OpClass`PLAIN/INSTANCE);`disasm` 改表驱动(输出不变,11 个 ctest 全绿)
2. **`ops.txt` 落地**34 条 op 行 + 8 条 fb 行,全属性必填
3. **`OpTable`**`isa/include/isa/OpTable.h` + `isa/src/OpTable.cpp`(解析 + 强校验:语法/重号/越界/类别-格式互锁/fb-opcode 一致/与编译期枚举一致)
4. **STCompiler `--ops`**:加载/校验/屏蔽传导(codegen 生成被屏蔽指令 → 编译错误)
5. **BytecodeExecutor `--ops`**:可选加载 / `Fault::Disabled`
6. **测试**`ops_test`(正例 + 缺属性/字段数错/重号/互锁破坏/与枚举不一致负例)、屏蔽传导用例、11 个 ctest 回归
7. **文档 + 提交**