阶段5-2:文档收尾——vm 指令执行/扫描周期、compiler 寄存器码/符号表/STCompiler说明、executor 入口全部更新为 V2

This commit is contained in:
2026-08-26 10:40:20 +08:00
parent 98d2e86dca
commit 84de006665
6 changed files with 242 additions and 275 deletions
+41 -48
View File
@@ -1,33 +1,33 @@
# 寄存器码(12.8
# 寄存器码(V2
compiler 模块的代码生成。输入:`Project` + `Unit`AST+ `LinkResult`;输出:`.stb` 映像字节(`std::vector<uint8_t>`)。全工程定案见 [`初步计划.md`](../初步计划.md) 12.8,指令/映像布局见 [`指令与映像.md`](../isa/指令与映像.md)。
compiler 模块的代码生成。输入:`Project` + `Unit`AST+ `LinkResult`;输出:`.stb` 映像字节(`std::vector<uint8_t>`)。全工程定案见 [`初步计划.md`](../初步计划.md) 12.8,指令/映像布局见 [`指令与映像.md`](../isa/指令与映像.md),槽表/值段格式见 [`stb文件格式.md`](../isa/stb文件格式.md)
## 做 / 不做
**做**
- 寄存器分配:局部/变量固定寄存器,表达式临时值往后编号,`nregs` 写进函数头
- 跳转先留洞、后回填;`AND` / `OR` **必须编成跳转**(短路),禁止两边都算
- 常量表(`LOADK`)、全局/实例槽(`LOAD_GLOBAL` / `STORE_GLOBAL`
- `CALL fn_id` 有界帧;用户 FB 调用**内联展开**;内建 `CAL_TON` / `CAL_TOF` / `CAL_CTU`
- 拼装映像:函数表 / 常量表 / 数据段 / 头(`cycle_limit``dt_ms`、工程哈希、入口)
- 跳转先留洞、后回填(字节单位,相对下一条)`AND` / `OR` **必须编成跳转**(短路),禁止两边都算
- 常量表(`LOADK`8B 原始值无 tag,按 func 解释)、全局/实例槽(`LOAD` / `STORE` / `LOAD_OFF` / `STORE_OFF`
- `CALL fn_id` 有界帧;用户 FB 调用**内联展开**;内建 `CAL fb_id, 实例槽`
- 拼装映像:V2 头 128B / 函数表 / 常量表 / 字节码 / 槽表 / 值段 + SHA-256 尾部
- `max_stack`MAIN + FUNCTION 调用图 DAG 最坏路径 Σ(12 + nregs×8);递归 = 编译期报错
**不做(第一版)**
- 图染色、SSA、生命周期分析、优化、异常表、闭包
- 函数指针、间接跳转、`REAL`
- 函数指针、间接跳转、动态实例
## 存储布局(v1 定案)
## 存储布局(V2 定案)
| 数据 | 放哪 | 说明 |
|---|---|---|
| PROGRAM / FUNCTION 标量变量与临时 | **寄存器**(函数帧) | 每周期帧保留由 VM 负责(12.9) |
| FB 实例(任意 POU 内声明) | **数据区实例块**(绝对地址) | 状态跨周期持久 |
| 全局(含 I/Q/M) | 数据区(声明序) | 12.6 已定槽号 |
| 全局(含 I/Q/M)与 FB 实例 | **值区**(紧凑变宽,1/2/4/8 对齐) | 槽表条目(8Baddr:u32 + 预留)指到值区偏移;状态跨周期持久 |
- **数据区** = 全局块(声明序,**每槽 8 字节定宽**,见 [`指令与映像.md`](../isa/指令与映像.md))→ FB 实例块(按实例声明序,每字段一槽)
- **指令 slot = 槽号**u160..65535);数据偏移 = 槽号 × 8;符号表 `address` 即指令 slot,无映射
- 字段访问 `fb.Q``LOAD_GLOBAL rd, <实例基槽+字段序号>`(编译期算死);I/Q/M 用 `LOAD_I` / `STORE_Q` / `LOAD_M` / `STORE_M` 同槽号
- **槽表两级**:指令操作数 = **槽号**(u32)→ 槽表条目 → 值区字节偏移;`slot_addr(slot)` 由 VM/Image 提供
- 全局按 GVL 声明序编槽;**FB 实例 = 1 个槽表条目**,字段在实例基址上按偏移访问(字段偏移编译期按 1/2/4/8 对齐计算,字段类型 = machine.toml `[[fb]]` 表)
- 字段访问 `fb.Q``LOAD_OFF rd, <实例槽>, <偏移>` / `STORE_OFF <实例槽>, <偏移>, rs`16B SLOT+off 指令);I/Q/M 同普通槽(`LOAD` / `STORE`
- 函数帧寄存器:`FUNCTION` 结果固定 **r0**`VAR_INPUT` 从 r1 起按声明序,`VAR` 续后;PROGRAM / FB 变量从 r0 起按声明序
### 调用约定(v1 冻结,VM 12.9 按此实现)
@@ -37,7 +37,7 @@ compiler 模块的代码生成。输入:`Project` + `Unit`AST+ `LinkResu
| 结果寄存器 | **r0**FUNCTION 结果写入处) |
| 参数寄存器 | **r1..r7**(最多 7 个输入,按声明序) |
| 变量 / 临时 | **全部从 r8 起**(调用约定区不受覆盖) |
| `CALL` | VM 复制当前帧 **r0..r7 → 新帧 r0..r7** |
| `CALL` | VM 复制当前帧 **r0..r7 → 新帧 r0..r7**(全宽) |
| `RET` | VM 复制当前帧 **r0..r7 → 调用方帧 r0..r7**(r0=结果,r1..r7 原样返回) |
| 函数输入 | 函数体内**只读**(写输入 → codegen error |
@@ -53,9 +53,9 @@ compiler 模块的代码生成。输入:`Project` + `Unit`AST+ `LinkResu
## 表达式与语句的指令模式
```text
字面量 LOADK rd, const_id
变量读 LOAD_GLOBAL/LOAD_I/LOAD_M rd, slot (或帧内 MOVE
字段读 LOAD_GLOBAL rd, <基址+偏移>
字面量 LOADK rd, const_id func = 语言类型;REAL/LREAL 位模式按目标类型装载)
变量读 LOAD rd, slot (帧内直接 MOVE
字段读 LOAD_OFF rd, <实例槽>, <偏移>
函数调用 <实参求值 → 参数寄存器> CALL fn_id MOVE rd, r0
NOT <operand → t> NOT rd, t
@@ -65,7 +65,7 @@ AND/OR 短路(必须跳转):
L_end:
比较 <l→t1> <r→t2> CMP_xx rd, t1, t2
算术 <l→t1> <r→t2> ADD/SUB/MUL/DIV rd, t1, t2
负号 <operand → t> SUB rd, r0, t 0 - tr0 恒 0
负号 <operand → t> NEG rd, t
IF <cond → t> JF t, L_else
<then body> JMP L_end
@@ -74,13 +74,13 @@ IF <cond → t> JF t, L_else
WHILE L_loop: <cond → t> JF t, L_end <body> JMP L_loop L_end:
FB 调用(用户,内联展开):
<每个实参求值 → 临时> STORE_GLOBAL <实例基址+字段偏移>, 临时
<内联体:读输入字段、算输出、写输出字段>
内建 实参同左 → CAL_TON/CAL_TOF/CAL_CTU <实例偏移>
<每个实参求值 → 临时> STORE_OFF <实例槽>, <字段偏移>, 临时
<内联体:LOAD_OFF 读输入字段、算输出、STORE_OFF 写输出字段>
内建 实参同左 → CAL <fb_id>, <实例>
```
- 常量统一进常量表(BOOL / INT / TIME),`const_id` = 首次出现序
- 空条件寄存器约定:`r0` 恒 0`enc_jmp` 用),`SUB rd, r0, t` 实现取负
- 常量统一进常量表(8B 原始值,位模式去重;BOOL / 整数 / 时间 / 浮点 / 日期),`const_id` = 首次出现序;`LOADK` 按 func 解释位模式
- 指令 func 位段 = 语言类型对应`func_of_name`:宽度 × 符号 + F32/F64
## 用户 FB 调用内联(v1 定案)
@@ -90,17 +90,23 @@ FB 体共享会与「绝对字段地址」冲突(不同实例基址不同)
- 代价:字节码随调用点数膨胀;v1 规模可接受;以后可升级为「基址寄存器寻址」指令
- FB 无递归、无动态实例,内联安全
## 映像拼装
## 映像拼装V2
```text
头 128Bmagic / version=2 / model=STATOR2 / cycle_limit / dt_ms / 工程哈希 /
entry_fn_id / n_globals / n_consts / n_funcs / 各段偏移 /
n_slots / values_size / meta / max_stack
函数表:收集序 fn_id → { nregs, code_offset(相对字节码段), code_len }
常量表:const_id → { tag, value }
数据段:全局 + 实例块(见上)
头:cycle_limit / dt_ms / 工程哈希(12.3/ entry=MAIN fn_id / n_globals / n_i=n_q=n_m=0
常量表:const_id → { value:u64 }(无 tag
字节码:各函数指令连续
槽表:每条目 8Baddr:u32 + 预留:u32
值段:全局 + FB 实例紧凑变宽
尾部:SHA-256(覆盖头部到值段末尾)
```
-`isa``enc_*` 编码指令`ImageView` 校验回读
- 工程哈希用 12.3 的 `compute_project_hash`
-`isa``enc_*` 编码指令(变长 4/8/16/32B,前缀分区)
- 工程哈希用 12.3 的 `compute_project_hash`FNV-1a 64
- `--dump-map` 可打印变量/槽映射(对照源码 ↔ 反汇编)
## 错误
@@ -109,27 +115,14 @@ FB 体共享会与「绝对字段地址」冲突(不同实例基址不同)
```text
codegen error: register overflow (>256) in function 'f'
codegen error: constant table overflow
codegen error: slot out of range
codegen error: no storage for 'x'
codegen error: no instance 't' in 'MAIN'
codegen error: recursive CALL/FB nesting too deep
```
## 完成标准
1. `line1` 能写出映像(函数字节码 + 全局/FB 槽 + 工程哈希),`ImageView` 校验通过
2. 跳转回填无悬空(disasm 抽查)
1. `line1` 能写出映像(函数字节码 + 槽表/值段 + 工程哈希 + SHA-256),`StbView` 校验通过
2. 跳转回填无悬空(`--disasm` 抽查)
3. 用例 19、13、15、17、18、20 编译出映像;负例(10/11/12/14/16/19)仍在前层被拒
4. 全部构建 + `ctest` 无回归
---
## 执行计划(8 片,每片验证编译产物)
1. **`Codegen.h`(新建)+ `Codegen.cpp` 骨架**:帧/槽/常量表/指令缓冲/回填基础设施;`MOVE` `LOADK` `RET` → 用例 1、2 出映像
2. **全局与 I/Q/M**`LOAD_I` / `STORE_Q` / `LOAD_M` / `STORE_M` / `LOAD_GLOBAL` / `STORE_GLOBAL`(用例 9
3. **`NOT` + 短路 `AND` / `OR`**(用例 3,断言产物含跳转)
4. **`CMP_*` + `JMP` / `JT` / `JF``IF`**(用例 4
5. **`WHILE`**(用例 5`cycle_limit` 进映像头)
6. **`ADD/SUB/MUL/DIV` + TIME 常量**(用例 7、8
7. **`CALL fn_id` + 有界帧**(用例 13
8. **FB 实例块 + 字段偏移;内联用户 FB`CAL_TON` / `CAL_TOF` / `CAL_CTU`**(用例 15、17、18、20 line1 全链路)
每片配 `codegen_test` 断言(nregs / 指令序列 disasm / 回填 / 常量表 / 数据区);最终 `ctest` 9/9。
4. 全部构建 + `ctest` 无回归14/14