Files
Interpreter/Doc/isa/指令与映像.md
T
Admin 7c855b1618 文档同步双可执行架构:STCompiler + BytecodeExecutor。
- 12.10 重写为两条命令:STCompiler 编译出 .stb + sidecar,BytecodeExecutor 加载执行
- 12.0 删独立 stc.exe,12.13 依赖方向改为 STCompiler/BytecodeExecutor
- 指令与映像.md 新增「映像文件(.stb)与 sidecar」节,I/O 绑定不进映像
- host/ 改名 executor/,宿主入口.md 重写为执行器入口.md
- README / tests / examples / isa README 同步
2026-08-19 13:59:50 +08:00

176 lines
5.7 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.
# 指令与映像
isa 模块规范:指令集 + 映像 + 定宽类型。不是编译器,不把 `.st` 编成映像。
`compiler` 按本文件写出字节,`vm` 只认这些字节。两边不互链。
全工程定案见 [`初步计划.md`](../初步计划.md)。**类型、指令编码、映像布局以本文为准**,不要另写一份互相打架的表。头文件实现本文,不另当规范。
```text
STCompiler → compiler → isa
BytecodeExecutor → vm → isa
```
CMake 目标:`isa``STATIC`),无依赖。公开头:`isa/include/isa/`
---
## 做 / 不做
**做**
- 操作码与 32 位指令布局
- 映像头与段(函数字节码、全局 / FB 槽、工程哈希)
- `BOOL` / `INT` / `TIME` 宽度与溢出规则
- 编解码、工程哈希、一条指令的文本转储(反汇编,给 STCompiler `--disasm` 与测试打印)
**不做**
- toml 字段、关键字表、符号表、AST
- 扫描周期循环、I/O 采样
- 短路语义(`AND`/`OR` 指令只组合已算好的值;短路由 `compiler` 编成跳转)
指令表可作为内部 IR 的文本形态,不必当主语言。
---
## 特性
| 项 | 第一版 |
|---|---|
| `BOOL` | `uint8_t`,只允许 0/1 |
| `INT` | `int16_t`IEC `INT` |
| `TIME` | `int64_t` 毫秒(有符号);与 `INT` 不混用 |
| 整数溢出 | **饱和**(夹到 `INT` 最小/最大) |
| 字节序 | 小端 |
| 指令宽度 | 32 bit,一种主布局 |
| 寄存器 | 下标 0..255;每函数实际个数写在函数头 `nregs` |
| 跳转 | 相对 offset,单位是**指令条数**,不是字节 |
| `CALL` | 立即数 `fn_id`u16),无函数指针 |
| 映像魔数 | `STSC`,版本 `1` |
| 工程哈希 | 源文件路径排序后对内容做 FNV-1a 64(非密码学) |
| I/O 绑定 | **不进映像**;编译期把 `var` 收成槽号,channel/bit 由 STCompiler 写进 sidecar`.runtime.toml`),BytecodeExecutor 读 sidecar 采样 |
| 不做 | `REAL`、隐式宽化 |
---
## 类型
C++11 定宽:
- `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 字节对齐。**槽位对齐规则**:`BOOL` 1 字节、`INT` 2 字节、`TIME` 8 字节;连续排列按类型对齐,需要时插 padding,偏移以本规则为准。
---
## 指令
定宽 32 bit
```text
[ op:8 | rd:8 | a:8 | b:8 ]
```
- 三寄存器:`a`/`b``ra`/`rb``MOVE`/`NOT` 只用 `rd`+`a`
- `LOADK``a|b``const_id`u16
- `JMP` / `JT` / `JF``a|b` 为有符号相对 offset(指令条数)
- `CALL``a|b``fn_id`u16
操作码一次列全(`CMP_xx` 冻下面六种):
```text
MOVE rd, rs
LOADK rd, const_id
NOT rd, rs
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_CTU
CALL fn_id
RET
```
局部 / `VAR` = 固定寄存器;表达式临时值往后编号;`nregs` 写进函数头。
`I`/`Q`/`M` 走映像指令,不是通用寄存器。
FB 实例固定布局,字段偏移编译期算死。
---
## 映像
魔数 `STSC`,版本 `1`
头:
- `cycle_limit``dt_ms`
- 工程哈希
- 全局槽数、I/Q/M 槽数
- 常量表 / 函数表 / 字节码 / FB 布局的偏移
- 入口 `MAIN``fn_id`
函数表一行:`fn_id``nregs`、字节码偏移与长度。
工程哈希:收录源文件路径排序后对内容做 **FNV-1a 64**,只保证回放槽位一致,不是密码学哈希。
`[[io.input]]` / `[[io.output]]` 不进映像。
---
## 映像文件(`.stb`)与 sidecar
编译产物是单文件 `<name>.stb`:映像头 + 各段按本文布局连续排,魔数 `STSC`、版本 `1`、小端。`STCompiler` 写,`BytecodeExecutor` 读。
- `dt_ms` / `cycle_limit` 在映像头,执行器只认映像,不重复配置。
- I/O 绑定不进映像:`STCompiler` 另写 sidecar `<name>.runtime.toml`,内容是 `var`(已解析槽号)→ `channel` / `bit``BytecodeExecutor` 读 sidecar 做采样与写回,不创造变量。
---
## 目录与 CMake
```text
isa/
CMakeLists.txt
README.md # 代码目录入口,指向本文
include/isa/
Types.h # 宽度、饱和、槽值表示
Op.h # 操作码枚举 + 助记符
Instr.h # 32-bit 打包/拆字段(inline
Image.h # 头、段、函数表/常量表/FB 布局
Encode.h # 编解码、哈希、反汇编一行
src/
Encode.cpp
Image.cpp
```
```cmake
add_library(isa STATIC src/Encode.cpp src/Image.cpp)
target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
```
`compiler` / `vm``target_link_libraries(... PUBLIC isa)`
---
## 实现顺序(对齐初步计划 12.0~12.1)
1. `Types.h`:三类型 + `sat_add` 等饱和函数(inline 即可)
2. `Op.h` + `Instr.h`:枚举与 32-bit 编解码
3. `Encode.cpp``encode` / `decode` / `disasm` 一条指令
4. `Image.h` + `Image.cpp`:头布局、FNV-1a、读写缓冲(先能写空映像 + 一条 `RET`
5. 测试随后在 `tests/` 加编解码往返;本阶段以头文件和库能链为准
不在本模块做:VM `switch`、toml、关键字、符号表。