12.9 步骤 0:数据段改 8 字节定宽槽(方案 a)。

- 指令与映像.md / 寄存器码.md:slot 语义 = 槽号(数据偏移 = 槽号 × 8),取消变宽对齐与 global_offset 映射
- Codegen.cpp:删除 width_of/align_up/global_offsets_;layout_data/layout_fb_instances 按槽号布局(字段 = 槽序号)
- stb文件格式.md:line1 真实字节更新(224B、56B 数据段、starter 槽 4/5/6)
- codegen_test:断言更新(槽号化 + 数据区字节数),189 断言 9/9 全绿
This commit is contained in:
2026-08-21 20:01:21 +08:00
parent cd417cd27b
commit ce948451e0
5 changed files with 78 additions and 117 deletions
+3 -3
View File
@@ -25,9 +25,9 @@ compiler 模块的代码生成。输入:`Project` + `Unit`AST+ `LinkResu
| FB 实例(任意 POU 内声明) | **数据区实例块**(绝对地址) | 状态跨周期持久 | | FB 实例(任意 POU 内声明) | **数据区实例块**(绝对地址) | 状态跨周期持久 |
| 全局(含 I/Q/M) | 数据区(声明序) | 12.6 已定槽号 | | 全局(含 I/Q/M) | 数据区(声明序) | 12.6 已定槽号 |
- **数据区** = 全局块(声明序,按对齐规则:BOOL 1B / INT 2B / TIME 8B,起点对齐自身宽度)→ FB 实例块(按实例声明序,各块按类型布局大小、8 字节对齐 - **数据区** = 全局块(声明序,**每槽 8 字节定宽**,见 [`指令与映像.md`](../isa/指令与映像.md))→ FB 实例块(按实例声明序,每字段一槽
- **指令 slot = 数据区字节偏移**u16);符号表 `address` 保持逻辑槽号(12.6 冻结),编译时做 槽号 → 偏移 映射 - **指令 slot = 槽号**u160..65535);数据偏移 = 槽号 × 8;符号表 `address` 即指令 slot,无映射
- 字段访问 `fb.Q``LOAD_GLOBAL rd, <实例基+字段偏移>`(编译期算死);I/Q/M 用 `LOAD_I` / `STORE_Q` / `LOAD_M` / `STORE_M` 同槽号 - 字段访问 `fb.Q``LOAD_GLOBAL rd, <实例基+字段序号>`(编译期算死);I/Q/M 用 `LOAD_I` / `STORE_Q` / `LOAD_M` / `STORE_M` 同槽号
- 函数帧寄存器:`FUNCTION` 结果固定 **r0**`VAR_INPUT` 从 r1 起按声明序,`VAR` 续后;PROGRAM / FB 变量从 r0 起按声明序 - 函数帧寄存器:`FUNCTION` 结果固定 **r0**`VAR_INPUT` 从 r1 起按声明序,`VAR` 续后;PROGRAM / FB 变量从 r0 起按声明序
### 调用约定(v1 冻结,VM 12.9 按此实现) ### 调用约定(v1 冻结,VM 12.9 按此实现)
+19 -16
View File
@@ -1,6 +1,6 @@
# .stb 映像文件结构 # .stb 映像文件结构
编译产物 `.stb` 的**面向使用者**的结构说明。规范以 [`指令与映像.md`](指令与映像.md) 为准,本文用 `line1.stb`184 字节)做真实拆解。 编译产物 `.stb` 的**面向使用者**的结构说明。规范以 [`指令与映像.md`](指令与映像.md) 为准,本文用 `line1.stb`224 字节)做真实拆解。
## 概览 ## 概览
@@ -74,15 +74,15 @@ line12 行):
- `CALL``fn_id` = 函数表行下标 - `CALL``fn_id` = 函数表行下标
- 调用约定:结果 r0、参数 r1..r7、变量与临时 r8 起 - 调用约定:结果 r0、参数 r1..r7、变量与临时 r8 起
line1 `MAIN` 前 5 条(`0x60` 起): line1 `MAIN` 前 5 条(`0x60`slot 为 8 字节定宽槽号):
| 偏移 | 字节 | 反汇编 | 含义 | | 偏移 | 字节 | 反汇编 | 含义 |
|---|---|---|---| |---|---|---|---|
| 0x60 | `12 08 01 00` | `LOAD_I r8, 1` | I0_0io.input 绑定 → LOAD_I | | 0x64 | `12 08 01 00` | `LOAD_I r8, 1` | I0_0io.input 绑定 → LOAD_I,槽 1 |
| 0x64 | `17 08 08 00` | `STORE_GLOBAL r8, 8` | starter.start ← I0_0 | | 0x68 | `17 08 04 00` | `STORE_GLOBAL r8, 4` | starter.start(槽 4← I0_0 |
| 0x68 | `16 09 02 00` | `LOAD_GLOBAL r9, 2` | I0_1 | | 0x6C | `16 09 02 00` | `LOAD_GLOBAL r9, 2` | I0_1(槽 2 |
| 0x6C | `17 09 09 00` | `STORE_GLOBAL r9, 9` | starter.stop ← I0_1 | | 0x70 | `17 09 05 00` | `STORE_GLOBAL r9, 5` | starter.stop(槽 5← I0_1 |
| 0x70 | `16 08 08 00` | `LOAD_GLOBAL r8, 8` | 内联体:读 starter.start | | 0x74 | `16 08 04 00` | `LOAD_GLOBAL r8, 4` | 内联体:读 starter.start(槽 4 |
## FB 布局段(`offset_fb` 起) ## FB 布局段(`offset_fb` 起)
@@ -90,18 +90,21 @@ v1 为空(用户 FB 内联展开,字段偏移已算进数据段;内建 TON
## 数据段(`offset_data` 起) ## 数据段(`offset_data` 起)
**全局块**`n_globals` 个,声明序)→ **FB 实例块**(按 POU 收集序、实例声明序,块间 8 字节对齐) **每槽 8 字节定宽**12.9 方案 a):`BOOL` 用低 1 字节、`INT` 用低 2 字节(小端)、`TIME` 全 8 字节。指令 `slot` 操作数即**槽号**,数据偏移 = 槽号 × 8
宽与对齐:`BOOL` 1 字节 / `INT` 2 字节 / `TIME` 8 字节,每个槽起点对齐自身宽度 序:**全局块**`n_globals` 个,声明序)→ **FB 实例块**(POU 收集序、实例声明序,每字段一槽)
line1 数据段(16 字节,`0xA8` 起): line1 数据段(56 字节 = 7 槽 × 8B`0xA8` 起):
| 偏移 | 内容 | | 槽号 | 偏移 | 内容 |
|---|---| |---|---|---|
| 0xA8..0xAB | 全局:EmergencyStop、I0_0、I0_1、Q0_0BOOL,初值 0 | | 0 | 0xA8 | EmergencyStopBOOL,初值 0 |
| 0xAC..0xAF | 填充(实例块 8 对齐 | | 1 | 0xB0 | I0_0BOOL |
| 0xB0..0xB2 | starter 实例:start、stop、qBOOL | | 2 | 0xB8 | I0_1BOOL |
| 0xB3..0xB7 | 填充 | | 3 | 0xC0 | Q0_0BOOL |
| 4 | 0xC8 | starter.startBOOL |
| 5 | 0xD0 | starter.stopBOOL |
| 6 | 0xD8 | starter.qBOOL |
## 用工具验证 ## 用工具验证
+2 -2
View File
@@ -76,7 +76,7 @@ C++20 定宽:
- 有符号:`TOF` 剩余时间、两个时间点相减会出负值,免去无符号边界处理 - 有符号:`TOF` 剩余时间、两个时间点相减会出负值,免去无符号边界处理
- 64 位:为将来 `DATE_AND_TIME`(毫秒时间戳)与 `TON` / `TOF` / `TP` 的 64 位定时器预留;毫秒量程约 2.9 亿年,扫描周期场景永不溢出 - 64 位:为将来 `DATE_AND_TIME`(毫秒时间戳)与 `TON` / `TOF` / `TP` 的 64 位定时器预留;毫秒量程约 2.9 亿年,扫描周期场景永不溢出
- 代价:槽位 8 字节对齐。**槽位对齐规则**`BOOL` 1 字节、`INT` 2 字节、`TIME` 8 字节;连续排列按类型对齐,需要时插 padding,偏移以本规则为准 - 代价:槽位 8 字节对齐。**槽位规则**(12.9 方案 a):每槽 8 字节定宽,`BOOL` 用低 1 字节、`INT` 用低 2 字节(小端)`TIME` 8 字节;槽号 × 8 = 数据偏移,无 padding
--- ---
@@ -180,7 +180,7 @@ FB 实例固定布局,字段偏移编译期算死。
### 数据段 ### 数据段
槽初值按序排:全局(`n_globals`)→ I → Q → M。槽宽与对齐`BOOL` 1 字节 / `INT` 2 字节 / `TIME` 8 字节,每个槽起点对齐到自身宽度(需要时插 padding) 槽初值按序排:全局(`n_globals`v1 不拆 I/Q/M)→ FB 实例块(每字段一槽)。**每槽 8 字节定宽**(12.9 方案 a)`BOOL` 用低 1 字节`INT` 用低 2 字节(小端)、`TIME` 8 字节。指令 `slot` 操作数即**槽号**,数据偏移 = 槽号 × 8;符号表 `address` 与指令 slot 一致,无映射
工程哈希:收录源文件路径排序后对内容做 **FNV-1a 64**,只保证回放槽位一致,不是密码学哈希。FNV-1a 64basis `0xcbf29ce484222325`prime `0x100000001b3` 工程哈希:收录源文件路径排序后对内容做 **FNV-1a 64**,只保证回放槽位一致,不是密码学哈希。FNV-1a 64basis `0xcbf29ce484222325`prime `0x100000001b3`
+37 -79
View File
@@ -7,15 +7,14 @@
* @details 设计说明(详见 Doc/compiler/寄存器码.md): * @details 设计说明(详见 Doc/compiler/寄存器码.md):
* - 切片 1~6:帧/字面量/MOVE/RET;全局数据区;短路 AND/ORCMP 与 IFWHILE 与四则; * - 切片 1~6:帧/字面量/MOVE/RET;全局数据区;短路 AND/ORCMP 与 IFWHILE 与四则;
* FUNCTION 与 CALL(调用约定 r0/r1..r7/r8+)。 * FUNCTION 与 CALL(调用约定 r0/r1..r7/r8+)。
* - 切片 7:FB 实例 → 数据区实例块(跨周期持久);字段地址 = 实例基 + 字段偏移 * - 切片 7:FB 实例 → 数据区实例块(跨周期持久);字段槽号 = 实例基 + 字段序号
* (编译期算死);字段读写走 LOAD_GLOBAL / STORE_GLOBAL * (编译期算死);字段读写走 LOAD_GLOBAL / STORE_GLOBAL
* 内建 TON/TOF/CTU → 实参写字段后 CAL_* <实例偏移> * 内建 TON/TOF/CTU → 实参写字段后 CAL_* <实例基槽>
* 用户 FB → 调用点内联展开(实参写字段 → FB 体以实例字段为变量编译) * 用户 FB → 调用点内联展开(实参写字段 → FB 体以实例字段为变量编译)
* - 其余构造报 codegen error * - 方案 a(12.9 前置):数据段**每槽 8 字节定宽**,指令 slot = 槽号(无映射)
* *
* 函数清单: * 函数清单:
* - put_le32 / put_le64 小端写入映像缓冲 * - put_le32 / put_le64 小端写入映像缓冲
* - align_up / width_of 对齐与槽宽
* - Builder::Builder (构造)存工程/源文件/链接结果/输出,收集 io 绑定分类 * - Builder::Builder (构造)存工程/源文件/链接结果/输出,收集 io 绑定分类
* - Builder::run 布局数据区(全局 + 实例)→ 逐 POU 建函数 → 拼映像 * - Builder::run 布局数据区(全局 + 实例)→ 逐 POU 建函数 → 拼映像
* - Builder::fail 组装 "codegen error: <msg>" 返回 false * - Builder::fail 组装 "codegen error: <msg>" 返回 false
@@ -29,9 +28,10 @@
* - store_target 赋值左值:STORE_* 到全局槽(或内联模式实例字段) * - store_target 赋值左值:STORE_* 到全局槽(或内联模式实例字段)
* - compile_expr 表达式编译到寄存器(含 Field 字段读) * - compile_expr 表达式编译到寄存器(含 Field 字段读)
* - cmp_op / arith_op / load_op / store_op 操作码选择 * - cmp_op / arith_op / load_op / store_op 操作码选择
* - global_offset / instance_of 槽号 → 偏移 / 实例 → 字段地址 * - global_offset 槽号恒等(方案 a 无映射)
* - instance_of 实例 → 字段槽号表
* - patch_jump 回填跳转偏移(相对下一条指令) * - patch_jump 回填跳转偏移(相对下一条指令)
* - layout_data / layout_fb_instances / init_of 数据区布局 * - layout_data / layout_fb_instances / init_of 数据区布局8 字节定宽槽)
* - const_id 取常量表 id(无则追加) * - const_id 取常量表 id(无则追加)
* - assemble_image 拼头 + 常量表 + 函数表 + 字节码 + 数据段 * - assemble_image 拼头 + 常量表 + 函数表 + 字节码 + 数据段
* - codegen_project 对外入口 * - codegen_project 对外入口
@@ -68,38 +68,6 @@ namespace {
} }
} }
/**
* @brief 按 2 的幂宽度向上对齐
* @param v 当前偏移
* @param w 对齐宽度(1/2/8
* @return 对齐后的偏移
*/
uint32_t align_up(uint32_t v, uint32_t w) {
return (v + w - 1) & ~(w - 1);
}
/**
* @brief 类型名 → 槽宽(对齐规则见 Doc/isa/指令与映像.md
* @param name "bool" / "int" / "time"
* @return 1 / 2 / 8;未知返回 1
*/
uint32_t width_of(const std::string& name) {
if (name == "int") return 2;
if (name == "time") return 8;
return 1; // bool 及未知
}
/**
* @brief TypeKind → 槽宽(FB 字段布局用)
* @param k 类型种类
* @return 1 / 2 / 8;未知返回 1
*/
uint32_t width_of(TypeKind k) {
if (k == TypeKind::Int) return 2;
if (k == TypeKind::Time) return 8;
return 1;
}
/** /**
* @brief 代码生成器(切片 1) * @brief 代码生成器(切片 1)
*/ */
@@ -715,58 +683,56 @@ namespace {
} }
/** /**
* @brief 逻辑槽号 → 数据区字节偏移(layout_data 先行 * @brief 逻辑槽号(符号表 address)即指令 slot(方案 a:8 字节定宽,无映射
* @param slot 全局逻辑槽号(符号表 address * @param slot 全局逻辑槽号
* @return 数据区字节偏移(u16 可容 * @return 同值(u16 可容,layout_data 已校验
*/ */
uint16_t global_offset(uint32_t slot) const { uint16_t global_offset(uint32_t slot) const {
return static_cast<uint16_t>(global_offsets_[slot]); return static_cast<uint16_t>(slot);
} }
/** /**
* @brief 布局全局数据区:对齐 + 初值字节 * @brief 布局全局数据区:每槽 8 字节定宽(方案 a
* @details 槽 = 声明序12.6);对齐规则 BOOL 1B / INT 2B / TIME 8B * @details 槽 = 符号表 address声明序12.6);
* 起点对齐自身宽度;初值取自 GVL 声明的 has_init(无则 0 * BOOL 用低 1 字节、INT 用低 2 字节(小端)、TIME 全 8 字节;
* @return true 成功;false(槽溢出等,err 已写 * 初值取自 GVL 声明的 has_init(无则 0
* @return true 成功;false(槽号越界,err 已写)
*/ */
bool layout_data() { bool layout_data() {
uint32_t cur = 0;
for (const Symbol& s : link_.globals) { for (const Symbol& s : link_.globals) {
const uint32_t w = width_of(s.type_name); if (s.address > 0xFFFF) {
cur = align_up(cur, w);
if (cur + w > 0xFFFF) {
return fail("data area exceeds slot range"); return fail("data area exceeds slot range");
} }
global_offsets_.push_back(cur);
bool has_init = false; bool has_init = false;
int64_t init = 0; int64_t init = 0;
init_of(s.name, &has_init, &init); init_of(s.name, &has_init, &init);
data_.resize(cur + w, 0); const int64_t v = has_init ? init : 0;
if (s.type_name == "bool") { const size_t off = static_cast<size_t>(s.address) * 8;
data_[cur] = static_cast<uint8_t>(has_init ? init : 0); data_.resize(off + 8, 0);
} else if (s.type_name == "int") { if (s.type_name == "int") {
const uint16_t v = static_cast<uint16_t>(has_init ? init : 0); const uint16_t iv = static_cast<uint16_t>(v);
data_[cur] = static_cast<uint8_t>(v & 0xFFu); data_[off] = static_cast<uint8_t>(iv & 0xFFu);
data_[cur + 1] = static_cast<uint8_t>((v >> 8) & 0xFFu); data_[off + 1] = static_cast<uint8_t>((iv >> 8) & 0xFFu);
} else if (s.type_name == "time") { } else if (s.type_name == "time") {
const uint64_t v = static_cast<uint64_t>(has_init ? init : 0); const uint64_t tv = static_cast<uint64_t>(v);
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
data_[cur + i] = static_cast<uint8_t>((v >> (8 * i)) & 0xFFu); data_[off + i] = static_cast<uint8_t>((tv >> (8 * i)) & 0xFFu);
} }
} else { // bool
data_[off] = v ? 1 : 0;
} }
cur += w;
} }
return true; return true;
} }
/** /**
* @brief 布局 FB 实例块:数据区全局之后,按 POU 收集序 / 实例声明序 * @brief 布局 FB 实例块:数据区全局之后,按 POU 收集序 / 实例声明序
* @details 每实例:字段按布局段序对齐排布(BOOL 1 / INT 2 / TIME 8), * @details 每实例:字段按布局段序各占一槽(8 字节定宽),
* 字段地址 = 实例基 + 字段偏移;实例块间 8 字节对齐,块内容初值 0 * 字段地址 = 实例基 + 字段序号;实例基槽 = 累计槽数
* @return true 成功;falseerr 已写) * @return true 成功;falseerr 已写)
*/ */
bool layout_fb_instances() { bool layout_fb_instances() {
uint32_t cur = align_up(static_cast<uint32_t>(data_.size()), 8); uint32_t cur = static_cast<uint32_t>(data_.size() / 8); // 槽号起点
bool any = false; bool any = false;
for (const LinkResult::PouScope& sc : link_.scopes) { for (const LinkResult::PouScope& sc : link_.scopes) {
for (const Symbol& s : sc.syms) { for (const Symbol& s : sc.syms) {
@@ -777,27 +743,20 @@ namespace {
if (lay == sc.fb_instances.end()) { if (lay == sc.fb_instances.end()) {
return fail("no layout for instance '" + s.name + "'"); return fail("no layout for instance '" + s.name + "'");
} }
cur = align_up(cur, 8);
InstFields inst; InstFields inst;
inst.base = cur; inst.base = cur; // 实例基槽(CAL_* 操作数)
inst.type_name = s.type_name; inst.type_name = s.type_name;
uint32_t off = 0; for (size_t i = 0; i < lay->second.fields.size(); ++i) {
for (const FbField& fd : lay->second.fields) { inst.field_addr[lay->second.fields[i].name] = cur + i;
const uint32_t w = width_of(fd.type);
off = align_up(off, w);
inst.field_addr[fd.name] = cur + off;
off += w;
} }
cur += align_up(off, 8); cur += static_cast<uint32_t>(lay->second.fields.size());
instances_[sc.name + "/" + s.name] = inst; instances_[sc.name + "/" + s.name] = inst;
any = true; any = true;
} }
} }
// 仅在有实例时把数据区补到实例区终点(无实例则保持全局区原样) // 仅在有实例时把数据区补到实例区终点(无实例则保持全局区原样)
if (any) { if (any) {
while (data_.size() < cur) { data_.resize(static_cast<size_t>(cur) * 8, 0);
data_.push_back(0);
}
} }
return true; return true;
} }
@@ -945,9 +904,8 @@ namespace {
std::vector<isa::ConstEntry> consts_; std::vector<isa::ConstEntry> consts_;
std::map<std::string, bool> io_input_; // io.input 绑定名(小写) std::map<std::string, bool> io_input_; // io.input 绑定名(小写)
std::map<std::string, bool> io_output_; // io.output 绑定名(小写) std::map<std::string, bool> io_output_; // io.output 绑定名(小写)
std::vector<uint32_t> global_offsets_; // 逻辑槽号 → 数据区字节偏移 std::vector<uint8_t> data_; // 数据区(8 字节定宽槽:全局 + FB 实例块)
std::vector<uint8_t> data_; // 数据区(全局初值 + FB 实例块) std::map<std::string, InstFields> instances_; // "POU/实例名" → 字段槽号
std::map<std::string, InstFields> instances_; // "POU/实例名" → 字段地址
const InstFields* inline_fields_ = nullptr; // 内联 FB 体字段上下文(可空) const InstFields* inline_fields_ = nullptr; // 内联 FB 体字段上下文(可空)
}; };
+17 -17
View File
@@ -174,7 +174,7 @@ static bool test_case09() {
const isa::ImageView v = isa::ImageView::from(img); const isa::ImageView v = isa::ImageView::from(img);
CHECK(v.ok()); CHECK(v.ok());
CHECK(v.header().n_globals == 1); CHECK(v.header().n_globals == 1);
CHECK(v.data_len() == 2); // INT 2 字节 CHECK(v.data_len() == 8); // 8 字节定宽槽
CHECK(v.data_bytes()[0] == 5); // G1 初值 5(小端低位) CHECK(v.data_bytes()[0] == 5); // G1 初值 5(小端低位)
CHECK(v.data_bytes()[1] == 0); CHECK(v.data_bytes()[1] == 0);
@@ -248,14 +248,14 @@ static bool test_layout() {
const isa::ImageView v = isa::ImageView::from(img); const isa::ImageView v = isa::ImageView::from(img);
CHECK(v.ok()); CHECK(v.ok());
CHECK(v.header().n_globals == 3); CHECK(v.header().n_globals == 3);
CHECK(v.data_len() == 16); // 0 + 2 + 8(对齐)= 16 CHECK(v.data_len() == 24); // 3 槽 × 8 字节定宽
CHECK(v.data_bytes()[0] == 0); // B 无初值 CHECK(v.data_bytes()[0] == 0); // B 无初值
CHECK(v.data_bytes()[2] == 0x2C && v.data_bytes()[3] == 0x01); // I = 300 CHECK(v.data_bytes()[8] == 0x2C && v.data_bytes()[9] == 0x01); // I = 300(槽 1
CHECK(v.data_bytes()[8] == 10); // T = 10ms CHECK(v.data_bytes()[16] == 10); // T = 10ms(槽 2
char buf[64]; char buf[64];
isa::disasm(reinterpret_cast<const uint32_t*>(v.code_bytes())[0], buf, sizeof buf); isa::disasm(reinterpret_cast<const uint32_t*>(v.code_bytes())[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 2") == 0); // x := IINT 偏移 2 CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 1") == 0); // x := I槽 1
return true; return true;
} }
@@ -552,7 +552,7 @@ static bool test_case15() {
CHECK(v.ok()); CHECK(v.ok());
CHECK(v.header().n_funcs == 2); // FB 占位 + MAIN CHECK(v.header().n_funcs == 2); // FB 占位 + MAIN
CHECK(v.header().entry_fn_id == 1); CHECK(v.header().entry_fn_id == 1);
CHECK(v.data_len() == 8); // 实例 3Bstart@0 stop@1 q@2),8 对齐 CHECK(v.data_len() == 24); // 实例 3× 8 字节定宽
const isa::FuncRow fm = v.func_row(1); const isa::FuncRow fm = v.func_row(1);
CHECK(fm.nregs == 12); CHECK(fm.nregs == 12);
@@ -602,11 +602,11 @@ static bool test_case17() {
isa::disasm(ins[2], buf, sizeof buf); isa::disasm(ins[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOADK r10, 1") == 0); CHECK(std::strcmp(buf, "LOADK r10, 1") == 0);
isa::disasm(ins[3], buf, sizeof buf); isa::disasm(ins[3], buf, sizeof buf);
CHECK(std::strcmp(buf, "STORE_GLOBAL r10, 8") == 0); // ptTIME 8 对齐 CHECK(std::strcmp(buf, "STORE_GLOBAL r10, 1") == 0); // pt槽 1
isa::disasm(ins[4], buf, sizeof buf); isa::disasm(ins[4], buf, sizeof buf);
CHECK(std::strcmp(buf, "CAL_TON 0") == 0); CHECK(std::strcmp(buf, "CAL_TON 0") == 0);
isa::disasm(ins[5], buf, sizeof buf); isa::disasm(ins[5], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 16") == 0); // t.Q CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 2") == 0); // t.Q(槽 2
return true; return true;
} }
@@ -619,7 +619,7 @@ static bool test_case18() {
const isa::ImageView v = isa::ImageView::from(img); const isa::ImageView v = isa::ImageView::from(img);
CHECK(v.ok()); CHECK(v.ok());
CHECK(v.data_len() == 40); // tf 块 0..31in@0 pt@8 q@16 et@24)、c 块 32.. CHECK(v.data_len() == 72); // tf 4 槽 + c 5 槽 = 9 槽 × 8
const isa::FuncRow r = v.func_row(0); const isa::FuncRow r = v.func_row(0);
CHECK(r.nregs == 14); CHECK(r.nregs == 14);
const uint32_t* ins = reinterpret_cast<const uint32_t*>(v.code_bytes()); const uint32_t* ins = reinterpret_cast<const uint32_t*>(v.code_bytes());
@@ -627,11 +627,11 @@ static bool test_case18() {
isa::disasm(ins[4], buf, sizeof buf); isa::disasm(ins[4], buf, sizeof buf);
CHECK(std::strcmp(buf, "CAL_TOF 0") == 0); CHECK(std::strcmp(buf, "CAL_TOF 0") == 0);
isa::disasm(ins[12], buf, sizeof buf); isa::disasm(ins[12], buf, sizeof buf);
CHECK(std::strcmp(buf, "CAL_CTU 32") == 0); CHECK(std::strcmp(buf, "CAL_CTU 4") == 0);
isa::disasm(ins[13], buf, sizeof buf); isa::disasm(ins[13], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_GLOBAL r9, 36") == 0); // c.Q CHECK(std::strcmp(buf, "LOAD_GLOBAL r9, 7") == 0); // c.Q(槽 7
isa::disasm(ins[14], buf, sizeof buf); isa::disasm(ins[14], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_GLOBAL r10, 38") == 0); // c.CVINT 2 对齐 CHECK(std::strcmp(buf, "LOAD_GLOBAL r10, 8") == 0); // c.CV槽 8
return true; return true;
} }
@@ -660,7 +660,7 @@ static bool test_line1() {
CHECK(v.header().n_globals == 4); CHECK(v.header().n_globals == 4);
CHECK(v.header().n_funcs == 2); CHECK(v.header().n_funcs == 2);
CHECK(v.header().entry_fn_id == 1); CHECK(v.header().entry_fn_id == 1);
CHECK(v.data_len() == 16); // 全局 4B + 实例块 8..10(8 对齐) CHECK(v.data_len() == 56); // 7 槽 × 8 字节定宽
const isa::FuncRow fm = v.func_row(1); const isa::FuncRow fm = v.func_row(1);
CHECK(fm.nregs == 13); CHECK(fm.nregs == 13);
@@ -670,15 +670,15 @@ static bool test_line1() {
isa::disasm(im[0], buf, sizeof buf); isa::disasm(im[0], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_I r8, 1") == 0); // I0_0io.input CHECK(std::strcmp(buf, "LOAD_I r8, 1") == 0); // I0_0io.input
isa::disasm(im[1], buf, sizeof buf); isa::disasm(im[1], buf, sizeof buf);
CHECK(std::strcmp(buf, "STORE_GLOBAL r8, 8") == 0); // starter.start CHECK(std::strcmp(buf, "STORE_GLOBAL r8, 4") == 0); // starter.start(槽 4
isa::disasm(im[2], buf, sizeof buf); isa::disasm(im[2], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_GLOBAL r9, 2") == 0); // I0_1 CHECK(std::strcmp(buf, "LOAD_GLOBAL r9, 2") == 0); // I0_1
isa::disasm(im[3], buf, sizeof buf); isa::disasm(im[3], buf, sizeof buf);
CHECK(std::strcmp(buf, "STORE_GLOBAL r9, 9") == 0); // starter.stop CHECK(std::strcmp(buf, "STORE_GLOBAL r9, 5") == 0); // starter.stop(槽 5
isa::disasm(im[13], buf, sizeof buf); isa::disasm(im[13], buf, sizeof buf);
CHECK(std::strcmp(buf, "STORE_GLOBAL r8, 10") == 0); // starter.Q CHECK(std::strcmp(buf, "STORE_GLOBAL r8, 6") == 0); // starter.Q(槽 6
isa::disasm(im[14], buf, sizeof buf); isa::disasm(im[14], buf, sizeof buf);
CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 10") == 0); // starter.Q 读回 CHECK(std::strcmp(buf, "LOAD_GLOBAL r8, 6") == 0); // starter.Q 读回
isa::disasm(im[15], buf, sizeof buf); isa::disasm(im[15], buf, sizeof buf);
CHECK(std::strcmp(buf, "STORE_Q r8, 3") == 0); // Q0_0io.output CHECK(std::strcmp(buf, "STORE_Q r8, 3") == 0); // Q0_0io.output
isa::disasm(im[16], buf, sizeof buf); isa::disasm(im[16], buf, sizeof buf);