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:
+37
-79
@@ -7,15 +7,14 @@
|
||||
* @details 设计说明(详见 Doc/compiler/寄存器码.md):
|
||||
* - 切片 1~6:帧/字面量/MOVE/RET;全局数据区;短路 AND/OR;CMP 与 IF;WHILE 与四则;
|
||||
* FUNCTION 与 CALL(调用约定 r0/r1..r7/r8+)。
|
||||
* - 切片 7:FB 实例 → 数据区实例块(跨周期持久);字段地址 = 实例基址 + 字段偏移
|
||||
* - 切片 7:FB 实例 → 数据区实例块(跨周期持久);字段槽号 = 实例基槽 + 字段序号
|
||||
* (编译期算死);字段读写走 LOAD_GLOBAL / STORE_GLOBAL;
|
||||
* 内建 TON/TOF/CTU → 实参写字段后 CAL_* <实例偏移>;
|
||||
* 内建 TON/TOF/CTU → 实参写字段后 CAL_* <实例基槽>;
|
||||
* 用户 FB → 调用点内联展开(实参写字段 → FB 体以实例字段为变量编译)
|
||||
* - 其余构造报 codegen error
|
||||
* - 方案 a(12.9 前置):数据段**每槽 8 字节定宽**,指令 slot = 槽号(无映射)
|
||||
*
|
||||
* 函数清单:
|
||||
* - put_le32 / put_le64 小端写入映像缓冲
|
||||
* - align_up / width_of 对齐与槽宽
|
||||
* - Builder::Builder (构造)存工程/源文件/链接结果/输出,收集 io 绑定分类
|
||||
* - Builder::run 布局数据区(全局 + 实例)→ 逐 POU 建函数 → 拼映像
|
||||
* - Builder::fail 组装 "codegen error: <msg>" 返回 false
|
||||
@@ -29,9 +28,10 @@
|
||||
* - store_target 赋值左值:STORE_* 到全局槽(或内联模式实例字段)
|
||||
* - compile_expr 表达式编译到寄存器(含 Field 字段读)
|
||||
* - cmp_op / arith_op / load_op / store_op 操作码选择
|
||||
* - global_offset / instance_of 槽号 → 偏移 / 实例 → 字段地址
|
||||
* - global_offset 槽号恒等(方案 a 无映射)
|
||||
* - instance_of 实例 → 字段槽号表
|
||||
* - patch_jump 回填跳转偏移(相对下一条指令)
|
||||
* - layout_data / layout_fb_instances / init_of 数据区布局
|
||||
* - layout_data / layout_fb_instances / init_of 数据区布局(8 字节定宽槽)
|
||||
* - const_id 取常量表 id(无则追加)
|
||||
* - assemble_image 拼头 + 常量表 + 函数表 + 字节码 + 数据段
|
||||
* - 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)
|
||||
*/
|
||||
@@ -715,58 +683,56 @@ namespace {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 逻辑槽号 → 数据区字节偏移(layout_data 先行)
|
||||
* @param slot 全局逻辑槽号(符号表 address)
|
||||
* @return 数据区字节偏移(u16 可容)
|
||||
* @brief 逻辑槽号(符号表 address)即指令 slot(方案 a:8 字节定宽,无映射)
|
||||
* @param slot 全局逻辑槽号
|
||||
* @return 同值(u16 可容,layout_data 已校验)
|
||||
*/
|
||||
uint16_t global_offset(uint32_t slot) const {
|
||||
return static_cast<uint16_t>(global_offsets_[slot]);
|
||||
return static_cast<uint16_t>(slot);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 布局全局数据区:对齐 + 初值字节
|
||||
* @details 槽序 = 声明序(12.6);对齐规则 BOOL 1B / INT 2B / TIME 8B,
|
||||
* 起点对齐自身宽度;初值取自 GVL 声明的 has_init(无则 0)
|
||||
* @return true 成功;false(槽溢出等,err 已写)
|
||||
* @brief 布局全局数据区:每槽 8 字节定宽(方案 a)
|
||||
* @details 槽号 = 符号表 address(声明序,12.6);
|
||||
* BOOL 用低 1 字节、INT 用低 2 字节(小端)、TIME 全 8 字节;
|
||||
* 初值取自 GVL 声明的 has_init(无则 0)
|
||||
* @return true 成功;false(槽号越界,err 已写)
|
||||
*/
|
||||
bool layout_data() {
|
||||
uint32_t cur = 0;
|
||||
for (const Symbol& s : link_.globals) {
|
||||
const uint32_t w = width_of(s.type_name);
|
||||
cur = align_up(cur, w);
|
||||
if (cur + w > 0xFFFF) {
|
||||
if (s.address > 0xFFFF) {
|
||||
return fail("data area exceeds slot range");
|
||||
}
|
||||
global_offsets_.push_back(cur);
|
||||
bool has_init = false;
|
||||
int64_t init = 0;
|
||||
init_of(s.name, &has_init, &init);
|
||||
data_.resize(cur + w, 0);
|
||||
if (s.type_name == "bool") {
|
||||
data_[cur] = static_cast<uint8_t>(has_init ? init : 0);
|
||||
} else if (s.type_name == "int") {
|
||||
const uint16_t v = static_cast<uint16_t>(has_init ? init : 0);
|
||||
data_[cur] = static_cast<uint8_t>(v & 0xFFu);
|
||||
data_[cur + 1] = static_cast<uint8_t>((v >> 8) & 0xFFu);
|
||||
const int64_t v = has_init ? init : 0;
|
||||
const size_t off = static_cast<size_t>(s.address) * 8;
|
||||
data_.resize(off + 8, 0);
|
||||
if (s.type_name == "int") {
|
||||
const uint16_t iv = static_cast<uint16_t>(v);
|
||||
data_[off] = static_cast<uint8_t>(iv & 0xFFu);
|
||||
data_[off + 1] = static_cast<uint8_t>((iv >> 8) & 0xFFu);
|
||||
} 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 布局 FB 实例块:数据区全局之后,按 POU 收集序 / 实例声明序
|
||||
* @details 每实例:字段按布局段序对齐排布(BOOL 1 / INT 2 / TIME 8),
|
||||
* 字段地址 = 实例基址 + 字段偏移;实例块间 8 字节对齐,块内容初值 0
|
||||
* @details 每实例:字段按布局段序各占一槽(8 字节定宽),
|
||||
* 字段地址 = 实例基槽 + 字段序号;实例基槽 = 累计槽数
|
||||
* @return true 成功;false(err 已写)
|
||||
*/
|
||||
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;
|
||||
for (const LinkResult::PouScope& sc : link_.scopes) {
|
||||
for (const Symbol& s : sc.syms) {
|
||||
@@ -777,27 +743,20 @@ namespace {
|
||||
if (lay == sc.fb_instances.end()) {
|
||||
return fail("no layout for instance '" + s.name + "'");
|
||||
}
|
||||
cur = align_up(cur, 8);
|
||||
InstFields inst;
|
||||
inst.base = cur;
|
||||
inst.base = cur; // 实例基槽(CAL_* 操作数)
|
||||
inst.type_name = s.type_name;
|
||||
uint32_t off = 0;
|
||||
for (const FbField& fd : lay->second.fields) {
|
||||
const uint32_t w = width_of(fd.type);
|
||||
off = align_up(off, w);
|
||||
inst.field_addr[fd.name] = cur + off;
|
||||
off += w;
|
||||
for (size_t i = 0; i < lay->second.fields.size(); ++i) {
|
||||
inst.field_addr[lay->second.fields[i].name] = cur + i;
|
||||
}
|
||||
cur += align_up(off, 8);
|
||||
cur += static_cast<uint32_t>(lay->second.fields.size());
|
||||
instances_[sc.name + "/" + s.name] = inst;
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
// 仅在有实例时把数据区补到实例区终点(无实例则保持全局区原样)
|
||||
if (any) {
|
||||
while (data_.size() < cur) {
|
||||
data_.push_back(0);
|
||||
}
|
||||
data_.resize(static_cast<size_t>(cur) * 8, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -945,9 +904,8 @@ namespace {
|
||||
std::vector<isa::ConstEntry> consts_;
|
||||
std::map<std::string, bool> io_input_; // io.input 绑定名(小写)
|
||||
std::map<std::string, bool> io_output_; // io.output 绑定名(小写)
|
||||
std::vector<uint32_t> global_offsets_; // 逻辑槽号 → 数据区字节偏移
|
||||
std::vector<uint8_t> data_; // 数据区(全局初值 + FB 实例块)
|
||||
std::map<std::string, InstFields> instances_; // "POU/实例名" → 字段地址
|
||||
std::vector<uint8_t> data_; // 数据区(8 字节定宽槽:全局 + FB 实例块)
|
||||
std::map<std::string, InstFields> instances_; // "POU/实例名" → 字段槽号
|
||||
const InstFields* inline_fields_ = nullptr; // 内联 FB 体字段上下文(可空)
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user