diff --git a/compiler/src/Codec.cpp b/compiler/src/Codec.cpp index d0ef983..6d862b1 100644 --- a/compiler/src/Codec.cpp +++ b/compiler/src/Codec.cpp @@ -338,6 +338,10 @@ void disasm(const MachineConfig& cfg, const uint8_t* code, size_t len, snprintf(out, cap, "%s%s r%u, s%u, %d", op->name.c_str(), suffix.c_str(), static_cast(rd_of(code)), static_cast(slot32_of(code)), static_cast(off32_hi_of(code))); + } else if (f == "RS+off") { + snprintf(out, cap, "%s%s r%u, r%u, %d", op->name.c_str(), suffix.c_str(), + static_cast(rd_of(code)), static_cast(rs1_of(code)), + static_cast(off32_hi_of(code))); } else { // NONE / 预留 snprintf(out, cap, "%s", op->name.c_str()); } diff --git a/compiler/src/Codegen.cpp b/compiler/src/Codegen.cpp index ba76c09..54742fd 100644 --- a/compiler/src/Codegen.cpp +++ b/compiler/src/Codegen.cpp @@ -120,8 +120,9 @@ namespace { std::vector code; ///< 字节码(变长指令,字节流) std::map regs; ///< 变量名 → 帧寄存器 std::map reg_func; ///< 变量名 → func(类型) - std::map fb_temp; ///< FB 内联 VAR_TEMP → 帧寄存器(当前内联层) - std::map fb_temp_func; ///< FB 内联 VAR_TEMP → func + bool is_fb = false; ///< 本函数是 FUNCTION_BLOCK(共享体,r1=实例指针) + std::map fb_field_off; ///< 本 FB 类型字段名 → 偏移 + std::map fb_field_func; ///< 本 FB 类型字段名 → func uint8_t nlocals = 0; ///< 变量区终点 = 临时寄存器起始 uint8_t nregs = 0; ///< 寄存器峰值 uint8_t temp_used = 0; ///< 本语句已用临时数 @@ -206,6 +207,15 @@ namespace { set_off32_hi(f.code.data() + s, off); return s; } + /// 基址寻址字段访问(rd, 基址寄存器rs, 偏移;16B RS+off)。 + size_t E_rs_off(FuncCtx& f, const char* name, uint8_t rd, uint8_t rs, + int32_t off) { + const size_t s = emit(f, opc(name)); + set_rd(f.code.data() + s, rd); + set_rs1(f.code.data() + s, rs); + set_off32_hi(f.code.data() + s, off); + return s; + } /// 内建 FB 调用(fb_id16 + 实例槽32)。 size_t E_cal(FuncCtx& f, uint16_t fb_id, uint32_t slot) { const size_t s = emit(f, opc("CAL")); @@ -242,6 +252,7 @@ namespace { std::map field_off; ///< 字段名 → 值区内偏移 std::map field_func; ///< 字段名 → func(类型) uint32_t slot = 0; ///< 实例槽号(槽表条目) + uint32_t addr = 0; ///< 实例基址(值区偏移,LOADK r1 用) std::string type_name; ///< 实例的 FB 类型名 }; @@ -295,10 +306,68 @@ namespace { } } + /// FB 类型字段偏移(类型级,对齐规则与 layout_slots_values 一致)。 + void fb_type_field_off(const FbLayout& lay, + std::map* off, + std::map* func) { + int32_t cur = 0; + for (const FbField& fd : lay.fields) { + const TypeMeta tm = type_meta(cfg_, fd.type_name); + cur = static_cast(align_up(static_cast(cur), tm.width())); + (*off)[fd.name] = cur; + (*func)[fd.name] = static_cast(tm.func()); + cur += static_cast(tm.width()); + } + } + bool build_function(const POU& pou, FuncCtx* f) { if (pou.kind == PouKind::FunctionBlock) { + // FB 共享体:编译为独立函数,r1 = 实例指针(值区地址,约定) + // 字段(输入/输出/内部 VAR)在实例存储 → LOAD_PTR/STORE_PTR r1+off; + // 局部寄存器 = VAR_TEMP + 表达式临时(r8 起),帧每周期重建 → 天然重置 + f->is_fb = true; f->nlocals = 8; f->nregs = 8; + const auto fl = link_.fb_types.find(pou.name); + if (fl == link_.fb_types.end()) { + return fail("no FB type layout for '" + pou.name + "'"); + } + fb_type_field_off(fl->second, &f->fb_field_off, &f->fb_field_func); + uint8_t r = 8; + for (const VarBlock& b : pou.blocks) { + if (b.section != VarSection::Temp) { + continue; + } + for (const VarDecl& d : b.vars) { + if (d.type.kind != TypeKind::Scalar) { + continue; + } + f->regs[d.name] = r; + f->reg_func[d.name] = func_of_name(type_name_of_var(pou, d.name)); + ++r; + } + } + f->nlocals = r; + f->nregs = r; + if (map_ != nullptr) { + std::map vars; + for (const auto& kv : f->regs) { + std::string tn = "int"; + const auto tf = f->reg_func.find(kv.first); + if (tf != f->reg_func.end()) { + tn = std::to_string(tf->second); + } + vars[kv.first] = "r" + std::to_string(kv.second) + " (func " + tn + ")"; + } + map_->funcs.emplace_back(f->name, vars); + } + emit_temp_init(*f, pou, f->regs, f->reg_func); + for (const Stmt& st : pou.body) { + begin_stmt(*f); + if (!compile_stmt(*f, st)) { + return false; + } + } E_ret(*f); return true; } @@ -373,38 +442,24 @@ namespace { if (st.kind != StmtKind::Assign) { return fail("statement not supported"); } - if (inline_fields_) { - const auto fit = inline_fields_->field_off.find(st.target); - if (fit != inline_fields_->field_off.end()) { + if (f.is_fb) { + // FB 共享体:本实例字段(裸名)→ STORE_PTR r1+off + const auto fit = f.fb_field_off.find(st.target); + if (fit != f.fb_field_off.end()) { const uint8_t t = alloc_temp(f); - const auto ff_ = inline_fields_->field_func.find(st.target); + const auto ff_ = f.fb_field_func.find(st.target); if (!compile_expr(f, *st.value, t, - ff_ != inline_fields_->field_func.end() - ? ff_->second - : 0)) { + ff_ != f.fb_field_func.end() ? ff_->second : 0)) { return false; } - const size_t so = E_slot_off(f, "STORE_OFF", t, inline_fields_->slot, - fit->second); - const auto ff = inline_fields_->field_func.find(st.target); - if (ff != inline_fields_->field_func.end()) { + const size_t so = E_rs_off(f, "STORE_PTR", t, 1, fit->second); + const auto ff = f.fb_field_func.find(st.target); + if (ff != f.fb_field_func.end()) { set_func(f.code.data() + so, ff->second); } return true; } } - const auto tit = f.fb_temp.find(st.target); - if (tit != f.fb_temp.end()) { - const uint8_t t = alloc_temp(f); - const uint8_t tf_ = f.fb_temp_func.count(st.target) - ? f.fb_temp_func.at(st.target) - : func_of_name("INT"); - if (!compile_expr(f, *st.value, t, tf_)) { - return false; - } - E_rr(f, "MOVE", tit->second, t); - return true; - } const auto it = f.regs.find(st.target); if (it == f.regs.end()) { return store_target(f, st.target, *st.value); @@ -449,7 +504,25 @@ namespace { if (user_fb == nullptr) { return fail("no FB type '" + inst->type_name + "'"); } - return compile_fb_inline(f, *user_fb, *inst); + // 用户 FB → CALL 共享体:r1 = 实例指针(值区地址)→ CALL + const int fb_fn = find_fn_id(user_fb->name); + if (fb_fn < 0) { + return fail("no fn_id for '" + user_fb->name + "'"); + } + f.calls.push_back(static_cast(fb_fn)); + uint8_t save_r = 0; + if (f.is_fb) { + // 嵌套(FB 函数体内再调 FB):保存本层 r1,调用后恢复 + save_r = alloc_temp(f); + E_rr(f, "MOVE", save_r, 1); + } + const size_t lk = E_imm(f, "LOADK", 1, const_id(inst->addr)); + set_func(f.code.data() + lk, func_of_name("UDINT")); + E_call(f, static_cast(fb_fn)); + if (f.is_fb) { + E_rr(f, "MOVE", 1, save_r); + } + return true; } static std::string uppercase_of(const std::string& s) { @@ -460,43 +533,6 @@ namespace { return out; } - bool compile_fb_inline(FuncCtx& f, const POU& fb, const InstFields& inst) { - const InstFields* saved = inline_fields_; - inline_fields_ = &inst; - // VAR_TEMP:本调用点分配独立固定寄存器(MAIN 帧,nregs 之后), - // 内联体开头装载初值 → 每次调用重新初始化;嵌套内联 save/restore - const std::map saved_temp = f.fb_temp; - const std::map saved_temp_func = f.fb_temp_func; - f.fb_temp.clear(); - f.fb_temp_func.clear(); - for (const VarBlock& b : fb.blocks) { - if (b.section != VarSection::Temp) { - continue; - } - for (const VarDecl& d : b.vars) { - if (d.type.kind != TypeKind::Scalar) { - continue; - } - const uint8_t r = f.nregs++; - f.fb_temp[d.name] = r; - f.fb_temp_func[d.name] = func_of_name(type_name_of_var(fb, d.name)); - } - } - // 临时寄存器起点提到 Temp 区之上,避免语句内 alloc_temp 撞上 Temp 寄存器 - f.nlocals = f.nregs; - emit_temp_init(f, fb, f.fb_temp, f.fb_temp_func); - for (const Stmt& s : fb.body) { - begin_stmt(f); - if (!compile_stmt(f, s)) { - return false; - } - } - f.fb_temp = saved_temp; - f.fb_temp_func = saved_temp_func; - inline_fields_ = saved; - return true; - } - bool compile_while(FuncCtx& f, const Stmt& st) { const size_t loop = f.code.size(); const uint8_t t = alloc_temp(f); @@ -609,27 +645,18 @@ namespace { return true; } if (e.kind == ExprKind::VarRef) { - if (inline_fields_) { - const auto fit = inline_fields_->field_off.find(e.name); - if (fit != inline_fields_->field_off.end()) { - const size_t lo = E_slot_off(f, "LOAD_OFF", rd, - inline_fields_->slot, fit->second); - const auto ff = inline_fields_->field_func.find(e.name); - if (ff != inline_fields_->field_func.end()) { + if (f.is_fb) { + // FB 共享体:本实例字段(裸名)→ LOAD_PTR r1+off + const auto fit = f.fb_field_off.find(e.name); + if (fit != f.fb_field_off.end()) { + const size_t lo = E_rs_off(f, "LOAD_PTR", rd, 1, fit->second); + const auto ff = f.fb_field_func.find(e.name); + if (ff != f.fb_field_func.end()) { set_func(f.code.data() + lo, ff->second); } return true; } } - const auto tit = f.fb_temp.find(e.name); - if (tit != f.fb_temp.end()) { - const size_t s = E_rr(f, "MOVE", rd, tit->second); - const auto tf = f.fb_temp_func.find(e.name); - set_func(f.code.data() + s, - tf != f.fb_temp_func.end() ? tf->second - : func_of_name("INT")); - return true; - } const auto sit = f.regs.find(e.name); if (sit != f.regs.end()) { const size_t s = E_rr(f, "MOVE", rd, sit->second); @@ -736,11 +763,20 @@ namespace { if (fn_id < 0) { return fail("no fn_id for '" + e.name + "'"); } + uint8_t save_r = 0; + if (f.is_fb) { + // FB 函数内调 FUNCTION:实参区 r1..r7 会覆盖 r1(实例指针)→ 保存恢复 + save_r = alloc_temp(f); + E_rr(f, "MOVE", save_r, 1); + } for (size_t i = 0; i < args.size(); ++i) { E_rr(f, "MOVE", static_cast(1 + i), args[i]); } f.calls.push_back(static_cast(fn_id)); E_call(f, static_cast(fn_id)); + if (f.is_fb) { + E_rr(f, "MOVE", 1, save_r); + } E_rr(f, "MOVE", rd, 0); return true; } @@ -896,6 +932,7 @@ namespace { max_align = max_align > tm.width() ? max_align : tm.width(); } cur_addr = align_up(cur_addr, max_align); + inst.addr = cur_addr; slots_.push_back(cur_addr); values_.resize(cur_addr + static_cast(off), 0); instances_[sc.name + "/" + s.name] = inst; @@ -1153,7 +1190,6 @@ namespace { std::vector values_; ///< 值段字节 std::map global_slot_; ///< 全局名 → 槽号 std::map instances_; ///< "POU名/实例名" → 实例布局 - const InstFields* inline_fields_ = nullptr; ///< 内联 FB 字段表 uint32_t max_stack_ = 0; ///< 栈区字节数 CodegenMap* map_ = nullptr; ///< 变量/槽映射输出(可空) }; diff --git a/tests/src/codegen_test.cpp b/tests/src/codegen_test.cpp index 3d1cb7b..2e2c5d6 100644 --- a/tests/src/codegen_test.cpp +++ b/tests/src/codegen_test.cpp @@ -237,14 +237,20 @@ static bool test_line1() { CHECK(v.n_globals() == 4); // EmergencyStop/I0_0/I0_1/Q0_0 CHECK(v.n_slots() == 5); // 4 全局 + 1 实例(字段走偏移,实例占 1 条) CHECK(v.values_size() == 7); // 全局 4×1B + starter 3×1B - CHECK(v.max_stack() >= 12 + 13 * 8); - // 指令序列:LOAD(I 读)、STORE_OFF(FB 输入写)、LOAD_OFF(FB 输出读)、STORE(Q 写) + CHECK(v.max_stack() >= (12 + 13 * 8) + (12 + 10 * 8)); // fn0 共享体 13 + MAIN 10 + // MAIN(fn 1):LOAD(I 读)、STORE_OFF(实参写)、LOADK r1 + CALL(共享体)、LOAD_OFF(输出读)、STORE(Q 写) const std::vector lines = disasm_lines(cfg_global(), v, 1); CHECK(has_line(lines, "LOAD.U8")); CHECK(has_line(lines, "STORE_OFF.U8")); CHECK(has_line(lines, "LOAD_OFF.U8")); CHECK(has_line(lines, "STORE.U8")); - CHECK(has_line(lines, "JF r")); + CHECK(has_line(lines, "LOADK.U32 r1")); + CHECK(has_line(lines, "CALL 0")); + // MotorStarter 共享体(fn 0):LOAD_PTR/STORE_PTR + 短路 JF + const std::vector fb = disasm_lines(cfg_global(), v, 0); + CHECK(has_line(fb, "LOAD_PTR.U8")); + CHECK(has_line(fb, "STORE_PTR.U8")); + CHECK(has_line(fb, "JF r")); return true; }