Compare commits
2
Commits
9a35a881d1
...
7c855b1618
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c855b1618 | ||
|
|
94accd52c3 |
@@ -1,8 +1,8 @@
|
||||
# 编译管线
|
||||
|
||||
compiler 模块:ST / toml 编译器。CMake 目标:`compiler`(`STATIC`),依赖 [`指令与映像.md`](../isa/指令与映像.md)。
|
||||
compiler 模块:ST / toml 编译器。CMake 目标:`compiler`(`STATIC`),依赖 [`指令与映像.md`](../isa/指令与映像.md)。可执行入口 `STCompiler`(本模块 `src/main.cpp`,链 `compiler` + `isa`)。
|
||||
|
||||
读齐工程后走直通 pass,产出单一映像,不上 LLVM。词法、语法、符号表、检查、codegen、链接都留在本库,不再拆 CMake 子库。
|
||||
读齐工程后走直通 pass,产出单一映像文件,不上 LLVM。词法、语法、符号表、检查、codegen、链接都留在本库,不再拆 CMake 子库。
|
||||
|
||||
语言规则、toml 字段、链接与第 12 节阶段见 [`初步计划.md`](../初步计划.md)。指令和映像只认 [`指令与映像.md`](../isa/指令与映像.md)。
|
||||
|
||||
@@ -16,6 +16,7 @@ compiler 模块:ST / toml 编译器。CMake 目标:`compiler`(`STATIC`)
|
||||
→ 类型检查
|
||||
→ 按 PROGRAM / FUNCTION / FB 编寄存器码
|
||||
→ 回填跳转、写映像头与工程哈希
|
||||
→ 写 <name>.stb(映像)与 <name>.runtime.toml(sidecar:io 绑定)
|
||||
```
|
||||
|
||||
## 边界
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# 执行器入口
|
||||
|
||||
BytecodeExecutor 模块:可执行入口。CMake 目标:`BytecodeExecutor`(`EXECUTABLE`),链接 `vm` 和 `isa`,**不链 `compiler`**。源码目录 `executor/`。
|
||||
|
||||
第一版两个可执行:`STCompiler` 编译出 `<name>.stb` 与 `<name>.runtime.toml`;`BytecodeExecutor` 加载映像按扫描周期跑。总顺序见 [`初步计划.md`](../初步计划.md) 第 12.10 节。
|
||||
|
||||
## 职责
|
||||
|
||||
- 加载 `.stb` 映像与 `<name>.runtime.toml` sidecar(I/O 绑定 var → 槽号 → channel/bit)
|
||||
- 按 sidecar 采样 I、写回 Q(不创造变量)
|
||||
- `dt_ms` / `cycle_limit` 从映像头取,推进 `TON` / `TOF` / `CTU`
|
||||
- 单步、看寄存器和映像、按录制的 `I` 回放
|
||||
|
||||
## 边界
|
||||
|
||||
- 指令与映像编码见 [`指令与映像.md`](../isa/指令与映像.md)
|
||||
- ST 解析与链接见 [`编译管线.md`](../compiler/编译管线.md),本模块不碰 `.st`
|
||||
- 寄存器执行循环见 [`扫描周期.md`](../vm/扫描周期.md)
|
||||
@@ -1,18 +0,0 @@
|
||||
# 宿主入口
|
||||
|
||||
host 模块:可执行入口。CMake 目标:`host`(`EXECUTABLE`),链接 `compiler` 和 `vm`。
|
||||
|
||||
第一版一条命令:读工程 → 编译映像 → 按扫描周期跑。不拆独立的编译器可执行文件。总顺序见 [`初步计划.md`](../初步计划.md) 第 12.10 节。
|
||||
|
||||
## 职责
|
||||
|
||||
- 读 `project.toml` 和其中的 `.st`,交给 `compiler`
|
||||
- 按 `[[io.input]]` / `[[io.output]]` 采样 I、写回 Q(不创造变量)
|
||||
- 把 `dt_ms` 交给 VM,推进 `TON` / `TOF` / `CTU`
|
||||
- 单步、看寄存器和映像、按录制的 `I` 回放
|
||||
|
||||
## 边界
|
||||
|
||||
- 指令编码见 [`指令与映像.md`](../isa/指令与映像.md)
|
||||
- ST 解析与链接见 [`编译管线.md`](../compiler/编译管线.md)
|
||||
- 寄存器执行循环见 [`扫描周期.md`](../vm/扫描周期.md)
|
||||
+30
-15
@@ -7,8 +7,8 @@ isa 模块规范:指令集 + 映像 + 定宽类型。不是编译器,不把
|
||||
全工程定案见 [`初步计划.md`](../初步计划.md)。**类型、指令编码、映像布局以本文为准**,不要另写一份互相打架的表。头文件实现本文,不另当规范。
|
||||
|
||||
```text
|
||||
host → compiler → isa
|
||||
host → vm → isa
|
||||
STCompiler → compiler → isa
|
||||
BytecodeExecutor → vm → isa
|
||||
```
|
||||
|
||||
CMake 目标:`isa`(`STATIC`),无依赖。公开头:`isa/include/isa/`。
|
||||
@@ -22,7 +22,7 @@ CMake 目标:`isa`(`STATIC`),无依赖。公开头:`isa/include/isa/`
|
||||
- 操作码与 32 位指令布局
|
||||
- 映像头与段(函数字节码、全局 / FB 槽、工程哈希)
|
||||
- `BOOL` / `INT` / `TIME` 宽度与溢出规则
|
||||
- 编解码、工程哈希、一条指令的文本转储(给 host 打印)
|
||||
- 编解码、工程哈希、一条指令的文本转储(反汇编,给 STCompiler `--disasm` 与测试打印)
|
||||
|
||||
**不做**
|
||||
|
||||
@@ -40,7 +40,7 @@ CMake 目标:`isa`(`STATIC`),无依赖。公开头:`isa/include/isa/`
|
||||
|---|---|
|
||||
| `BOOL` | `uint8_t`,只允许 0/1 |
|
||||
| `INT` | `int16_t`(IEC `INT`) |
|
||||
| `TIME` | `int32_t` 毫秒;与 `INT` 不混用 |
|
||||
| `TIME` | `int64_t` 毫秒(有符号);与 `INT` 不混用 |
|
||||
| 整数溢出 | **饱和**(夹到 `INT` 最小/最大) |
|
||||
| 字节序 | 小端 |
|
||||
| 指令宽度 | 32 bit,一种主布局 |
|
||||
@@ -49,8 +49,8 @@ CMake 目标:`isa`(`STATIC`),无依赖。公开头:`isa/include/isa/`
|
||||
| `CALL` | 立即数 `fn_id`(u16),无函数指针 |
|
||||
| 映像魔数 | `STSC`,版本 `1` |
|
||||
| 工程哈希 | 源文件路径排序后对内容做 FNV-1a 64(非密码学) |
|
||||
| I/O 绑定 | **不进映像**;编译期把 `var` 收成槽号,channel/bit 留在 host 读 toml |
|
||||
| 不做 | `REAL`、隐式宽化、独立 `stc.exe` |
|
||||
| I/O 绑定 | **不进映像**;编译期把 `var` 收成槽号,channel/bit 由 STCompiler 写进 sidecar(`.runtime.toml`),BytecodeExecutor 读 sidecar 采样 |
|
||||
| 不做 | `REAL`、隐式宽化 |
|
||||
|
||||
---
|
||||
|
||||
@@ -60,10 +60,16 @@ C++11 定宽:
|
||||
|
||||
- `BOOL`:`uint8_t`,0/1
|
||||
- `INT`:`int16_t`;加减乘除溢出饱和
|
||||
- `TIME`:`int32_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,偏移以本规则为准。
|
||||
|
||||
---
|
||||
|
||||
## 指令
|
||||
@@ -123,6 +129,15 @@ FB 实例固定布局,字段偏移编译期算死。
|
||||
|
||||
---
|
||||
|
||||
## 映像文件(`.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
|
||||
@@ -130,11 +145,11 @@ isa/
|
||||
CMakeLists.txt
|
||||
README.md # 代码目录入口,指向本文
|
||||
include/isa/
|
||||
Types.hpp # 宽度、饱和、槽值表示
|
||||
Op.hpp # 操作码枚举 + 助记符
|
||||
Instr.hpp # 32-bit 打包/拆字段(inline)
|
||||
Image.hpp # 头、段、函数表/常量表/FB 布局
|
||||
Encode.hpp # 编解码、哈希、反汇编一行
|
||||
Types.h # 宽度、饱和、槽值表示
|
||||
Op.h # 操作码枚举 + 助记符
|
||||
Instr.h # 32-bit 打包/拆字段(inline)
|
||||
Image.h # 头、段、函数表/常量表/FB 布局
|
||||
Encode.h # 编解码、哈希、反汇编一行
|
||||
src/
|
||||
Encode.cpp
|
||||
Image.cpp
|
||||
@@ -151,10 +166,10 @@ target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
## 实现顺序(对齐初步计划 12.0~12.1)
|
||||
|
||||
1. `Types.hpp`:三类型 + `sat_add` 等饱和函数(inline 即可)
|
||||
2. `Op.hpp` + `Instr.hpp`:枚举与 32-bit 编解码
|
||||
1. `Types.h`:三类型 + `sat_add` 等饱和函数(inline 即可)
|
||||
2. `Op.h` + `Instr.h`:枚举与 32-bit 编解码
|
||||
3. `Encode.cpp`:`encode` / `decode` / `disasm` 一条指令
|
||||
4. `Image.hpp` + `Image.cpp`:头布局、FNV-1a、读写缓冲(先能写空映像 + 一条 `RET`)
|
||||
4. `Image.h` + `Image.cpp`:头布局、FNV-1a、读写缓冲(先能写空映像 + 一条 `RET`)
|
||||
5. 测试随后在 `tests/` 加编解码往返;本阶段以头文件和库能链为准
|
||||
|
||||
不在本模块做:VM `switch`、toml、关键字、符号表。
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ vm 模块:寄存器虚拟机。CMake 目标:`vm`(`STATIC`),只依赖 [
|
||||
## 扫描周期
|
||||
|
||||
```text
|
||||
1. 按 toml 的 io 绑定,采样 → I / 输入全局
|
||||
1. 按 sidecar 的 io 绑定,采样 → I / 输入全局
|
||||
2. 从 PROGRAM MAIN 的 pc=0 执行到 RET
|
||||
3. 写回 Q / 输出全局
|
||||
4. 用本周期 Δt 推进 TON / TOF / CTU(不用 wall clock)
|
||||
@@ -19,4 +19,4 @@ vm 模块:寄存器虚拟机。CMake 目标:`vm`(`STATIC`),只依赖 [
|
||||
- 局部 / `VAR` = 固定寄存器;`nregs` 在函数头
|
||||
- `CALL` 目标是立即数 `fn_id`,有界调用栈
|
||||
- 无 GC、无堆、无线程;每周期受 `cycle_limit` 限制
|
||||
- I/O 从哪来、Δt 谁给、回放怎么喂,属于 `host`
|
||||
- I/O 从哪来、Δt 谁给、回放怎么喂,属于 `BytecodeExecutor`(读 `.stb` + sidecar)
|
||||
|
||||
+21
-15
@@ -271,13 +271,13 @@ RET
|
||||
|
||||
## 10. 目录
|
||||
|
||||
仓库布局见根目录 `README.md`。实现时按四个 CMake 目标拆,样例不放仓库根:
|
||||
仓库布局见根目录 `README.md`。实现时按模块拆 CMake 目标(三个库 + 两个可执行),样例不放仓库根:
|
||||
|
||||
```text
|
||||
isa/ # 指令编码、映像头、定宽类型(compiler 与 vm 的合同)
|
||||
compiler/ # lexer parser symbols checker codegen linker
|
||||
vm/ # 扫描周期、寄存器、映像、FB
|
||||
host/ # 喂 I、收 Q、Δt、回放
|
||||
compiler/ # lexer parser symbols checker codegen linker;STCompiler 入口在 src/main.cpp
|
||||
vm/ # 扫描周期、寄存器、映像、FB(库)
|
||||
executor/ # BytecodeExecutor:加载 .stb + sidecar,喂 I、收 Q、Δt、回放
|
||||
examples/line1/ # 第 11 节最小样例(给人看)
|
||||
tests/ # 冻规则用的正例 / 负例
|
||||
```
|
||||
@@ -327,13 +327,13 @@ END_PROGRAM
|
||||
|
||||
原则:**先冻合同,再解析,再链接,最后写 VM**。`compiler` 与 `vm` 不互链,合同只进 `isa`。每一阶段先有可运行的测试,再进入下一阶段。一人约 4~8 周做到第 11 节 `line1`。
|
||||
|
||||
第一版不做:图染色、SSA、WHILE 有界证明、异常表、闭包、优化、`REAL`、独立 `stc.exe`。
|
||||
第一版不做:图染色、SSA、WHILE 有界证明、异常表、闭包、优化、`REAL`。
|
||||
|
||||
---
|
||||
|
||||
### 12.0 骨架(约 1 天)
|
||||
|
||||
CMake 四个目标能空编译:`isa`、`compiler`、`vm`、`host`。`host` 先打印版本即可。
|
||||
CMake 三个库能空编译:`isa`、`compiler`、`vm`;两个可执行 `STCompiler`、`BytecodeExecutor` 先打印版本即可。
|
||||
|
||||
- 落下 `examples/line1/`:第 3 节 toml + 第 11 节三个 `.st`。
|
||||
- `tests/` 接上 CTest,先放一个必过的空测试。
|
||||
@@ -524,16 +524,22 @@ CMake 四个目标能空编译:`isa`、`compiler`、`vm`、`host`。`host` 先
|
||||
|
||||
---
|
||||
|
||||
### 12.10 host(约 2~3 天)
|
||||
### 12.10 双可执行:STCompiler 与 BytecodeExecutor(约 2~3 天)
|
||||
|
||||
一条命令:读 toml → `compiler` → `vm` 跑 N 个周期。不拆第二个可执行文件。
|
||||
编译与执行拆成两个可执行,映像 `.stb` 是中间产物:
|
||||
|
||||
- 按 `[[io.*]]` 从宿主缓冲采样 / 写回,不创造变量。
|
||||
- 把 `dt_ms` 每周期传给 VM。
|
||||
- 最小可观测:打印本周期 I/Q,或把寄存器/映像 dump 出来。
|
||||
```text
|
||||
STCompiler <project.toml> -o <name>.stb # 编译:读 toml + .st → 映像 + sidecar
|
||||
BytecodeExecutor <name>.stb [--cycles N] # 执行:加载 .stb + sidecar,跑 N 周期
|
||||
```
|
||||
|
||||
- `STCompiler` 链 `compiler` + `isa`;`BytecodeExecutor` 链 `vm` + `isa`,**不链 `compiler`**。
|
||||
- 产物两个文件:`<name>.stb`(映像,魔数 `STSC`)+ `<name>.runtime.toml`(sidecar:I/O 绑定 var → 槽号 → channel/bit)。`[[io.*]]` 不进映像,sidecar 由 STCompiler 生成,不创造变量。
|
||||
- `dt_ms` / `cycle_limit` 从映像头取,sidecar 不重复配置。
|
||||
- 最小可观测:BytecodeExecutor 打印本周期 I/Q,或把寄存器/映像 dump 出来。
|
||||
- 回放:读预先录制的 I 序列(文本即可),不接真实硬件。
|
||||
|
||||
完成:`host examples/line1/project.toml` 能编译并跑若干周期。
|
||||
完成:`STCompiler examples/line1/project.toml -o line1.stb` 产出两个文件;`BytecodeExecutor line1.stb` 能跑若干周期。
|
||||
|
||||
---
|
||||
|
||||
@@ -556,7 +562,7 @@ CMake 四个目标能空编译:`isa`、`compiler`、`vm`、`host`。`host` 先
|
||||
| 2 | 12.5:AST,能 parse `line1`,拒绝多余特性 |
|
||||
| 3 | 12.6~12.7:链接、定址、类型、io 校验 |
|
||||
| 4 | 12.8 前半 + 12.9 前半:赋值/短路/IF 出映像,VM 能跑 |
|
||||
| 5 | 12.8 后半 + 12.10:CALL、FB、host 跑起来 |
|
||||
| 5 | 12.8 后半 + 12.10:CALL、FB、两个可执行跑起来 |
|
||||
| 6 | 定时器/计数器、io、Δt、`line1` 语义 |
|
||||
| 7~8 | 20 用例、回放、单步、补漏 |
|
||||
|
||||
@@ -567,8 +573,8 @@ CMake 四个目标能空编译:`isa`、`compiler`、`vm`、`host`。`host` 先
|
||||
### 12.13 依赖方向(全程遵守)
|
||||
|
||||
```text
|
||||
host → compiler → isa
|
||||
host → vm → isa
|
||||
STCompiler → compiler → isa
|
||||
BytecodeExecutor → vm → isa
|
||||
```
|
||||
|
||||
- 指令或映像布局有变:先改 `isa` 和编解码测试,再改两端。
|
||||
|
||||
@@ -9,7 +9,7 @@ doc/
|
||||
isa/指令与映像.md
|
||||
compiler/编译管线.md
|
||||
vm/扫描周期.md
|
||||
host/宿主入口.md
|
||||
executor/执行器入口.md
|
||||
```
|
||||
|
||||
| 路径 | 内容 |
|
||||
@@ -18,6 +18,6 @@ doc/
|
||||
| [`isa/指令与映像.md`](isa/指令与映像.md) | 指令、映像、定宽类型、饱和;**规范以此为准** |
|
||||
| [`compiler/编译管线.md`](compiler/编译管线.md) | 编译器边界与管线 |
|
||||
| [`vm/扫描周期.md`](vm/扫描周期.md) | 扫描周期与 VM 边界 |
|
||||
| [`host/宿主入口.md`](host/宿主入口.md) | 可执行入口:编译 + 跑周期 |
|
||||
| [`executor/执行器入口.md`](executor/执行器入口.md) | 可执行入口:加载 `.stb` + sidecar,跑扫描周期 |
|
||||
|
||||
代码目录里的 README 只作入口;类型、指令、映像以 `isa/指令与映像.md` 为准。
|
||||
|
||||
@@ -8,23 +8,23 @@
|
||||
多个 .st
|
||||
↑ project.toml 列出
|
||||
↓
|
||||
compiler(词法 / 语法 → 符号表 → 类型检查 → 寄存器码 → 链接)
|
||||
STCompiler(compiler 库:词法 / 语法 → 符号表 → 类型检查 → 寄存器码 → 链接)
|
||||
↓
|
||||
单一映像(函数字节码 + 全局 / FB 数据槽 + 工程哈希)
|
||||
<name>.stb 映像 + <name>.runtime.toml sidecar
|
||||
↓
|
||||
vm 按扫描周期执行;host 喂 I、收 Q、给 Δt、回放
|
||||
BytecodeExecutor(vm 库按扫描周期执行;喂 I、收 Q、给 Δt、回放)
|
||||
```
|
||||
|
||||
## 目录
|
||||
|
||||
```text
|
||||
.
|
||||
├── CMakeLists.txt # 顶层工程:加入四个目标,并启用测试
|
||||
├── CMakeLists.txt # 顶层工程:加入各目标,并启用测试
|
||||
├── cmake/ # CMake 辅助(警告、C++ 标准等),不是业务模块
|
||||
├── isa/ # 共享契约:指令、映像、定宽类型
|
||||
├── compiler/ # ST / toml 编译器
|
||||
├── vm/ # 寄存器虚拟机
|
||||
├── host/ # 可执行入口:编译并跑扫描周期
|
||||
├── compiler/ # ST / toml 编译器(库)+ STCompiler 可执行入口
|
||||
├── vm/ # 寄存器虚拟机(库)
|
||||
├── executor/ # BytecodeExecutor:加载 .stb + sidecar 并执行
|
||||
├── examples/ # 样例工程(给人看、跑通最小闭环)
|
||||
│ └── line1/ # MAIN + Motor FB + I/O
|
||||
│ ├── project.toml
|
||||
@@ -40,14 +40,15 @@ vm 按扫描周期执行;host 喂 I、收 Q、给 Δt、回放
|
||||
|
||||
## 模块与 CMake 目标
|
||||
|
||||
四个链接目标,与目录一一对应。`compiler` 与 `vm` 不互相链接,合同放在 `isa`。
|
||||
三个静态库与两个可执行,与目录一一对应。`compiler` 与 `vm` 不互相链接,合同放在 `isa`。依赖方向:`STCompiler → compiler → isa`、`BytecodeExecutor → vm → isa`。
|
||||
|
||||
| 目录 | 目标 | 类型 | 依赖 | 职责 |
|
||||
|---|---|---|---|---|
|
||||
| `isa/` | `isa` | `STATIC` 或 `INTERFACE` | 无 | 约 20 条指令编码、映像头、工程哈希、`BOOL` / `INT` / `TIME` 宽度 |
|
||||
| `isa/` | `isa` | `STATIC` | 无 | 约 20 条指令编码、映像头、工程哈希、`BOOL` / `INT` / `TIME` 宽度 |
|
||||
| `compiler/` | `compiler` | `STATIC` | `isa` | 读 toml、收齐 `.st`、解析、链接、定址、类型检查、编寄存器码、写映像 |
|
||||
| `vm/` | `vm` | `STATIC` | `isa` | 一台 VM、一个入口、一份映像;扫描周期、寄存器、FB、有界 `CALL` / `RET` |
|
||||
| `host/` | `host` | `EXECUTABLE` | `compiler`、`vm` | 读工程、编译、按 toml 的 io 采样 I、执行 `PROGRAM MAIN`、写回 Q、用 Δt 推进定时器 / 计数器、回放 |
|
||||
| `compiler/` | `STCompiler` | `EXECUTABLE` | `compiler`、`isa` | `STCompiler <project.toml> -o <name>.stb`:编译并写映像 + sidecar;`--disasm` 可反汇编 |
|
||||
| `executor/` | `BytecodeExecutor` | `EXECUTABLE` | `vm`、`isa` | `BytecodeExecutor <name>.stb`:加载映像 + sidecar,采样 I、执行 `PROGRAM MAIN`、写回 Q、用 Δt 推进定时器 / 计数器、回放 |
|
||||
|
||||
词法、语法、符号表、检查、codegen、链接都留在 `compiler` 一个库里,不再拆 CMake 子库。
|
||||
|
||||
@@ -63,9 +64,9 @@ toml **不声明变量**,只列出源文件、指定唯一 GVL、可选地把
|
||||
|
||||
每个扫描周期:采样 I → 从 `PROGRAM MAIN` 的 `pc=0` 执行到 `RET` → 写回 Q → 用本周期 Δt 推进 `TON` / `TOF` / `CTU`。无 GC、无堆、无线程;变量编译期分配。
|
||||
|
||||
### `host`
|
||||
### `executor`(BytecodeExecutor)
|
||||
|
||||
第一版做成一条命令:编译 + 跑周期。不必再拆独立的编译器可执行文件。
|
||||
第一版两个可执行:`STCompiler` 编译出 `<name>.stb`(映像)+ `<name>.runtime.toml`(sidecar:I/O 绑定);`BytecodeExecutor` 加载后按扫描周期跑。不再有"一条命令编译 + 跑"。`dt_ms` / `cycle_limit` 从映像头取。
|
||||
|
||||
### `examples/` 与 `tests/`
|
||||
|
||||
@@ -74,4 +75,4 @@ toml **不声明变量**,只列出源文件、指定唯一 GVL、可选地把
|
||||
| `examples/line1/` | 计划中的最小样例:全局、`MotorStarter` FB、`PROGRAM MAIN` |
|
||||
| `tests/` | 冻关键字、指令、符号表、链接错误(重复 `VAR_GLOBAL`、`io.var` 未声明等) |
|
||||
|
||||
`tests/` 通过 `add_test` 调用 `host` 或直接链接 `compiler` + `vm`。
|
||||
`tests/` 通过 `add_test` 调 `STCompiler` / `BytecodeExecutor`,或直接链接 `compiler` + `vm`。样例工程数据按「一份 toml + 若干 `.st`」分子目录存放,不做成 library。
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
给人看的样例工程,**不是** CMake 库。每个子目录是一份完整工程:`project.toml` + 若干 `.st`。
|
||||
|
||||
供 `host` 直接打开,用来跑通最小闭环。自动化断言放 `tests/`。
|
||||
供 `STCompiler` 编译、`BytecodeExecutor` 执行,用来跑通最小闭环。自动化断言放 `tests/`。
|
||||
|
||||
## line1
|
||||
|
||||
|
||||
+19
-18
@@ -5,8 +5,8 @@
|
||||
`compiler` 写映像、`vm` 读映像,两边只依赖本目录,不互链。
|
||||
|
||||
```text
|
||||
host → compiler → isa
|
||||
host → vm → isa
|
||||
STCompiler → compiler → isa
|
||||
BytecodeExecutor → vm → isa
|
||||
```
|
||||
|
||||
**类型、操作码、指令字、映像布局以** [`doc/isa/指令与映像.md`](../doc/isa/指令与映像.md) **为准。** 头文件实现该文,本 README 不另当规范。全工程阶段见 [`doc/初步计划.md`](../doc/初步计划.md) 12.0~12.1。
|
||||
@@ -34,11 +34,11 @@ isa/
|
||||
CMakeLists.txt
|
||||
README.md
|
||||
include/isa/
|
||||
Types.hpp # 宽度、饱和、槽值
|
||||
Op.hpp # 操作码枚举 + 助记符声明
|
||||
Instr.hpp # 32-bit 打包/拆字段(inline)
|
||||
Encode.hpp # encode / decode / disasm
|
||||
Image.hpp # 头、段、FNV、读写缓冲
|
||||
Types.h # 宽度、饱和、槽值
|
||||
Op.h # 操作码枚举 + 助记符
|
||||
Instr.h # 32-bit 打包/拆字段(inline)
|
||||
Encode.h # encode / decode / disasm
|
||||
Image.h # 头、段、FNV、读写缓冲
|
||||
src/
|
||||
Encode.cpp
|
||||
Image.cpp
|
||||
@@ -55,13 +55,13 @@ target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
### 0. CMake 骨架
|
||||
|
||||
根 `CMakeLists.txt` 已 `add_subdirectory` 了 `compiler` / `vm` / `host`。这三个目录若没有 `CMakeLists.txt`,顶层 configure 失败,`isa` 也编不过。
|
||||
根 `CMakeLists.txt` 已 `add_subdirectory` 了 `compiler` / `vm` / `executor`。这三个目录若没有 `CMakeLists.txt`,顶层 configure 失败,`isa` 也编不过。
|
||||
|
||||
本步只让工程能配置、能链,不写业务。
|
||||
|
||||
- 写本目录 `CMakeLists.txt`(上面那段即可)
|
||||
- `compiler` / `vm`:空 `.cpp` + `PUBLIC` 链 `isa`
|
||||
- `host`:`main` 打印 `Stator 0.1`,链 `compiler`、`vm`
|
||||
- `executor`:`BytecodeExecutor`,`main` 打印版本,链 `vm`、`isa`;`STCompiler` 入口在 `compiler/src/main.cpp`,链 `compiler`、`isa`
|
||||
- 根 CMake:`enable_testing()`(测试文件下一步再加)
|
||||
|
||||
完成:`cmake --build` 过。
|
||||
@@ -86,11 +86,11 @@ target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
---
|
||||
|
||||
### 2. `Types.hpp`
|
||||
### 2. `Types.h`
|
||||
|
||||
`include/isa/Types.hpp`,inline,无对应 `.cpp`。命名空间 `isa`。C++11,不用 designated initializer。
|
||||
`include/isa/Types.h`,inline,无对应 `.cpp`。命名空间 `isa`。C++11,不用 designated initializer。
|
||||
|
||||
- `Bool` = `uint8_t`,`Int` = `int16_t`,`Time` = `int32_t`(毫秒)
|
||||
- `Bool` = `uint8_t`,`Int` = `int16_t`,`Time` = `int64_t`(毫秒;理由见规范文)
|
||||
- `TypeTag`:`Bool` / `Int` / `Time`
|
||||
- `sat_add` / `sat_sub` / `sat_mul` / `sat_div`(规则见规范文)
|
||||
- `pack_bool` / `pack_int` / `pack_time` → 4 字节 cell;对应 unpack
|
||||
@@ -99,18 +99,18 @@ target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
---
|
||||
|
||||
### 3. `Op.hpp` + `Instr.hpp`
|
||||
### 3. `Op.h` + `Instr.h`
|
||||
|
||||
- `Op.hpp`:`enum Op : uint8_t`,取值与规范文一致;声明 `op_mnemonic(Op)`(表可放 `Encode.cpp`)
|
||||
- `Instr.hpp`:`typedef uint32_t Instr`;`pack`、取 `op`/`rd`/`a`/`b`、`imm16`/`off16`;按形态 `enc_rr` / `enc_rrr` / `enc_imm` / `enc_jmp` / `enc_jc`
|
||||
- `Op.h`:`enum Op : uint8_t`,取值与规范文一致;`mnemonic(Op)` 助记符(已在头内落地)
|
||||
- `Instr.h`:`typedef uint32_t Instr`;`pack`、取 `op`/`rd`/`a`/`b`、`imm16`/`off16`;按形态 `enc_rr` / `enc_rrr` / `enc_imm` / `enc_jmp` / `enc_jc`
|
||||
|
||||
完成:能打包/拆开一条 32-bit 指令,不依赖 `.cpp`。
|
||||
|
||||
---
|
||||
|
||||
### 4. `Encode.hpp` + `Encode.cpp`
|
||||
### 4. `Encode.h` + `Encode.cpp`
|
||||
|
||||
给 host 打印和测试往返:
|
||||
给 `STCompiler --disasm` 和测试往返打印:
|
||||
|
||||
- `Decoded { Op op; uint8_t rd, a, b; }`
|
||||
- `Instr encode(Decoded)` / `Decoded decode(Instr)`
|
||||
@@ -122,12 +122,13 @@ target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
---
|
||||
|
||||
### 5. `Image.hpp` + `Image.cpp`
|
||||
### 5. `Image.h` + `Image.cpp`
|
||||
|
||||
- `fnv1a64` / `fnv1a64_update`
|
||||
- `ImageView`:只读视图,指向外部缓冲
|
||||
- `read_image`:校验魔数、版本、头大小、各段不越界、`entry_fn_id` 落在函数表内
|
||||
- `write_ret_main(cycle_limit, dt_ms, hash)` → `std::vector<uint8_t>`:空槽 + `MAIN` + 一条 `RET`
|
||||
- `.stb` 文件读写与 `<name>.runtime.toml` sidecar(I/O 绑定 var → 槽号 → channel/bit)
|
||||
|
||||
小端 `put_*` / `get_*` 只放 `.cpp`,不把 packed struct 当 ABI。本阶段不写完整 `ImageBuilder`(等 codegen)。
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @file Instr.h
|
||||
* @brief 32-bit 指令打包 / 拆字段
|
||||
* @author
|
||||
* @date 2026-08-19
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "isa/Op.h"
|
||||
|
||||
namespace isa {
|
||||
// 指令字:[ op:8 | rd:8 | a:8 | b:8 ],整体是一个小端 uint32_t。
|
||||
// 字段含义按操作码形态解释,见 Doc/isa/指令与映像.md。
|
||||
typedef uint32_t Instr;
|
||||
|
||||
// 打包 / 拆字段
|
||||
inline Instr pack(Op op, uint8_t rd, uint8_t a, uint8_t b) {
|
||||
return static_cast<uint32_t>(static_cast<uint8_t>(op))
|
||||
| (static_cast<uint32_t>(rd) << 8)
|
||||
| (static_cast<uint32_t>(a) << 16)
|
||||
| (static_cast<uint32_t>(b) << 24);
|
||||
}
|
||||
|
||||
inline Op op(Instr w) {
|
||||
return static_cast<Op>(w & 0xFFu);
|
||||
}
|
||||
|
||||
inline uint8_t rd(Instr w) {
|
||||
return static_cast<uint8_t>((w >> 8) & 0xFFu);
|
||||
}
|
||||
|
||||
inline uint8_t a(Instr w) {
|
||||
return static_cast<uint8_t>((w >> 16) & 0xFFu);
|
||||
}
|
||||
|
||||
inline uint8_t b(Instr w) {
|
||||
return static_cast<uint8_t>((w >> 24) & 0xFFu);
|
||||
}
|
||||
|
||||
// 组合视图:a|b 拼成 16 位(const_id / fn_id / slot)
|
||||
inline uint16_t imm16(Instr w) {
|
||||
return static_cast<uint16_t>(a(w) | (static_cast<uint16_t>(b(w)) << 8));
|
||||
}
|
||||
|
||||
// 组合视图:a|b 为有符号相对偏移,单位是指令条数
|
||||
inline int16_t off16(Instr w) {
|
||||
return static_cast<int16_t>(imm16(w));
|
||||
}
|
||||
|
||||
// 按形态的便捷编码
|
||||
inline Instr enc_rr(Op op, uint8_t rd, uint8_t rs) {
|
||||
return pack(op, rd, rs, 0); // MOVE / NOT:a = rs
|
||||
}
|
||||
|
||||
inline Instr enc_rrr(Op op, uint8_t rd, uint8_t ra, uint8_t rb) {
|
||||
return pack(op, rd, ra, rb); // AND/OR/ADD/.../CMP_xx
|
||||
}
|
||||
|
||||
inline Instr enc_imm(Op op, uint8_t rd, uint16_t imm) {
|
||||
return pack(op, rd, static_cast<uint8_t>(imm & 0xFFu),
|
||||
static_cast<uint8_t>((imm >> 8) & 0xFFu)); // LOADK
|
||||
}
|
||||
|
||||
inline Instr enc_jmp(int16_t off) {
|
||||
return pack(Op::JMP, 0,
|
||||
static_cast<uint8_t>(static_cast<uint16_t>(off) & 0xFFu),
|
||||
static_cast<uint8_t>((static_cast<uint16_t>(off) >> 8) & 0xFFu));
|
||||
}
|
||||
|
||||
inline Instr enc_jc(Op op, uint8_t r, int16_t off) {
|
||||
// JT / JF:条件寄存器在 rd,偏移在 a|b
|
||||
return pack(op, r,
|
||||
static_cast<uint8_t>(static_cast<uint16_t>(off) & 0xFFu),
|
||||
static_cast<uint8_t>((static_cast<uint16_t>(off) >> 8) & 0xFFu));
|
||||
}
|
||||
|
||||
inline Instr enc_slot(Op op, uint8_t rd, uint16_t slot) {
|
||||
// LOAD_I / STORE_Q / LOAD_M / STORE_M / LOAD_GLOBAL / STORE_GLOBAL / CAL_*
|
||||
// 槽号 / 实例号在 a|b
|
||||
return enc_imm(op, rd, slot);
|
||||
}
|
||||
|
||||
inline Instr enc_call(uint16_t fn_id) {
|
||||
return enc_imm(Op::CALL, 0, fn_id);
|
||||
}
|
||||
|
||||
inline Instr enc_ret() {
|
||||
return pack(Op::RET, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @file Op.h
|
||||
* @brief 操作码枚举 + 助记符
|
||||
* @author
|
||||
* @date 2026-08-19
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace isa {
|
||||
// 操作码一次列全。数值即编码:冻结后不得改顺序、不得插值,
|
||||
// 增加指令只能追加到末尾,并同步 Doc/isa/指令与映像.md 与测试。
|
||||
enum class Op : uint8_t {
|
||||
MOVE = 0, // MOVE rd, rs
|
||||
LOADK = 1, // LOADK rd, const_id
|
||||
NOT = 2, // NOT rd, rs
|
||||
AND = 3, // AND rd, ra, rb
|
||||
OR = 4, // OR rd, ra, rb
|
||||
ADD = 5, // ADD rd, ra, rb
|
||||
SUB = 6, // SUB rd, ra, rb
|
||||
MUL = 7, // MUL rd, ra, rb
|
||||
DIV = 8, // DIV rd, ra, rb
|
||||
CMP_EQ = 9, // CMP_EQ rd, ra, rb
|
||||
CMP_NE = 10, // CMP_NE rd, ra, rb
|
||||
CMP_LT = 11, // CMP_LT rd, ra, rb
|
||||
CMP_LE = 12, // CMP_LE rd, ra, rb
|
||||
CMP_GT = 13, // CMP_GT rd, ra, rb
|
||||
CMP_GE = 14, // CMP_GE rd, ra, rb
|
||||
JMP = 15, // JMP offset
|
||||
JT = 16, // JT r, offset
|
||||
JF = 17, // JF r, offset
|
||||
LOAD_I = 18, // LOAD_I rd, slot
|
||||
STORE_Q = 19, // STORE_Q slot, rs
|
||||
LOAD_M = 20, // LOAD_M rd, slot
|
||||
STORE_M = 21, // STORE_M slot, rs
|
||||
LOAD_GLOBAL = 22, // LOAD_GLOBAL rd, slot
|
||||
STORE_GLOBAL = 23, // STORE_GLOBAL slot, rs
|
||||
CAL_TON = 24, // CAL_TON instance_slot
|
||||
CAL_TOF = 25, // CAL_TOF instance_slot
|
||||
CAL_CTU = 26, // CAL_CTU instance_slot
|
||||
CALL = 27, // CALL fn_id
|
||||
RET = 28, // RET
|
||||
};
|
||||
|
||||
// 操作码总数
|
||||
static const int kOpCount = 29;
|
||||
|
||||
// 助记符:下标与 Op 数值一一对应
|
||||
inline const char* mnemonic(Op op) {
|
||||
static const char* const kMnemonic[kOpCount] = {
|
||||
"MOVE", "LOADK", "NOT", "AND", "OR",
|
||||
"ADD", "SUB", "MUL", "DIV",
|
||||
"CMP_EQ", "CMP_NE", "CMP_LT", "CMP_LE", "CMP_GT", "CMP_GE",
|
||||
"JMP", "JT", "JF",
|
||||
"LOAD_I", "STORE_Q", "LOAD_M", "STORE_M",
|
||||
"LOAD_GLOBAL", "STORE_GLOBAL",
|
||||
"CAL_TON", "CAL_TOF", "CAL_CTU",
|
||||
"CALL", "RET",
|
||||
};
|
||||
const int idx = static_cast<int>(op);
|
||||
return (idx >= 0 && idx < kOpCount) ? kMnemonic[idx] : "???";
|
||||
}
|
||||
}
|
||||
+41
-3
@@ -8,13 +8,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
namespace isa {
|
||||
namespace types {
|
||||
// 定宽类型。整数溢出规则:饱和(夹到 INT 最小/最大),
|
||||
// 由 compiler 与 vm 按同一规则实现,见 Doc/isa/指令与映像.md。
|
||||
using BOOL = uint8_t;
|
||||
using INT = int16_t;
|
||||
using TIME = uint64_t;
|
||||
using BOOL = uint8_t; // 只允许 0/1
|
||||
using INT = int16_t; // IEC INT
|
||||
// 毫秒,有符号。64 位理由见 Doc/isa/指令与映像.md:
|
||||
// 差值可负、为 DATE_AND_TIME 与 64 位定时器预留。槽位按 8 字节对齐。
|
||||
using TIME = int64_t;
|
||||
|
||||
// 饱和算术:夹到 INT 最小/最大,编译期与 VM 共用同一规则。
|
||||
|
||||
inline INT sat_add(INT a, INT b) {
|
||||
const int32_t sum = static_cast<int32_t>(a) + static_cast<int32_t>(b);
|
||||
return static_cast<INT>(sum < std::numeric_limits<INT>::min() ? std::numeric_limits<INT>::min()
|
||||
: sum > std::numeric_limits<INT>::max() ? std::numeric_limits<INT>::max()
|
||||
: sum);
|
||||
}
|
||||
|
||||
inline INT sat_sub(INT a, INT b) {
|
||||
const int32_t diff = static_cast<int32_t>(a) - static_cast<int32_t>(b);
|
||||
return static_cast<INT>(diff < std::numeric_limits<INT>::min() ? std::numeric_limits<INT>::min()
|
||||
: diff > std::numeric_limits<INT>::max() ? std::numeric_limits<INT>::max()
|
||||
: diff);
|
||||
}
|
||||
|
||||
inline INT sat_mul(INT a, INT b) {
|
||||
const int32_t prod = static_cast<int32_t>(a) * static_cast<int32_t>(b);
|
||||
return static_cast<INT>(prod < std::numeric_limits<INT>::min() ? std::numeric_limits<INT>::min()
|
||||
: prod > std::numeric_limits<INT>::max() ? std::numeric_limits<INT>::max()
|
||||
: prod);
|
||||
}
|
||||
|
||||
inline INT sat_div(INT a, INT b) {
|
||||
// b == 0 视为除以 1,避免未定义行为;除零的语义由 compiler/VM 层报错
|
||||
if (b == 0) {
|
||||
return a;
|
||||
}
|
||||
// INT_MIN / -1 溢出:饱和到 INT_MAX
|
||||
if (a == std::numeric_limits<INT>::min() && b == -1) {
|
||||
return std::numeric_limits<INT>::max();
|
||||
}
|
||||
return static_cast<INT>(a / b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
自动化用例,由顶层 `enable_testing()` 接入 CTest。
|
||||
|
||||
可以 `add_test` 调用 `host`,或直接链接 `compiler` + `vm`。样例工程数据按「一份 toml + 若干 `.st`」分子目录存放,不要做成 library。
|
||||
可以 `add_test` 调 `STCompiler` / `BytecodeExecutor`(编译→执行管线),或直接链接 `compiler` + `vm` 做单元断言。样例工程数据按「一份 toml + 若干 `.st`」分子目录存放,不要做成 library。
|
||||
|
||||
## 第一版要冻的
|
||||
|
||||
|
||||
Reference in New Issue
Block a user