From ada9e5f99ea2aa6fa5f4e59a6a86217854b7fcde Mon Sep 17 00:00:00 2001 From: chentianya Date: Fri, 21 Aug 2026 20:20:26 +0800 Subject: [PATCH] =?UTF-8?q?12.9=20=E6=AD=A5=E9=AA=A4=204=EF=BC=9A=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E5=99=A8=20CAL=5FTON/CAL=5FTOF/CAL=5FCTU=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - do_cal:内建布局冻结(TON/TOF: in/pt/q/et、CTU: cu/r/pv/q/cv,字段=槽序号×8) - TON:in 真 → et+=dt(到 pt 停)、q=et≥pt;假 → 清零 - TOF:in 真 → q=1/et=0;掉电 → et+=dt、et≥pt → q=0 - CTU:cu 上升沿(ctu_prev_ 跨周期)→ cv+1;r 复位;q=cv≥pv - 抽 slot_get/slot_set 复用(exec_one 的 LOAD/STORE 同步重构) - 验证:TON 3 周期到 q=1、TOF 掉电延时 2 周期、CTU 交替上升沿到 cv=3、复位;line1 三组 I 组合 Q 正确 + 确定性两遍一致 --- vm/include/vm/Machine.h | 4 ++ vm/src/Machine.cpp | 119 +++++++++++++++++++++++++++++++++++----- 2 files changed, 109 insertions(+), 14 deletions(-) diff --git a/vm/include/vm/Machine.h b/vm/include/vm/Machine.h index ee3a238..263ea2b 100644 --- a/vm/include/vm/Machine.h +++ b/vm/include/vm/Machine.h @@ -107,5 +107,9 @@ namespace vm { Fault do_call(uint32_t fn_id); // 压帧;BadFn 用 BadOp 表示 Fault do_ret(); // 弹帧 / 周期结束 Fault do_cal(uint8_t op, uint16_t slot); // TON/TOF/CTU(12.9 步骤 4) + + // 数据区槽读写(8 字节定宽;越界返回 false) + bool slot_get(uint16_t slot, int64_t* out) const; + bool slot_set(uint16_t slot, int64_t v); }; } diff --git a/vm/src/Machine.cpp b/vm/src/Machine.cpp index 8dd0167..216b072 100644 --- a/vm/src/Machine.cpp +++ b/vm/src/Machine.cpp @@ -223,31 +223,20 @@ bool Machine::exec_one() { case isa::Op::LOAD_M: case isa::Op::LOAD_GLOBAL: { const uint16_t slot = isa::imm16(w); - const size_t off = static_cast(slot) * 8; - if (off + 8 > data_.size()) { + if (!slot_get(slot, ®s[rd])) { fault_ = Fault::BadSlot; return false; } - int64_t v = 0; - for (int i = 0; i < 8; ++i) { - v |= static_cast(data_[off + i]) << (8 * i); - } - regs[rd] = v; return true; } case isa::Op::STORE_Q: case isa::Op::STORE_M: case isa::Op::STORE_GLOBAL: { const uint16_t slot = isa::imm16(w); - const size_t off = static_cast(slot) * 8; - if (off + 8 > data_.size()) { + if (!slot_set(slot, regs[rd])) { fault_ = Fault::BadSlot; return false; } - const int64_t v = regs[rd]; - for (int i = 0; i < 8; ++i) { - data_[off + i] = static_cast((v >> (8 * i)) & 0xFFu); - } return true; } case isa::Op::CALL: @@ -259,13 +248,41 @@ bool Machine::exec_one() { return false; } return !ended_; // MAIN 的 RET → 周期结束(返回 false) + case isa::Op::CAL_TON: + case isa::Op::CAL_TOF: + case isa::Op::CAL_CTU: + fault_ = do_cal(static_cast(op), isa::imm16(w)); + return fault_ == Fault::None; default: - // CAL_TON / CAL_TOF / CAL_CTU(步骤 4 实现) fault_ = Fault::BadOp; return false; } } +bool Machine::slot_get(uint16_t slot, int64_t* out) const { + const size_t off = static_cast(slot) * 8; + if (off + 8 > data_.size()) { + return false; + } + int64_t v = 0; + for (int i = 0; i < 8; ++i) { + v |= static_cast(data_[off + i]) << (8 * i); + } + *out = v; + return true; +} + +bool Machine::slot_set(uint16_t slot, int64_t v) { + const size_t off = static_cast(slot) * 8; + if (off + 8 > data_.size()) { + return false; + } + for (int i = 0; i < 8; ++i) { + data_[off + i] = static_cast((v >> (8 * i)) & 0xFFu); + } + return true; +} + Fault Machine::do_call(uint32_t fn_id) { if (fn_id >= image_.header().n_funcs) { return Fault::BadOp; @@ -306,4 +323,78 @@ Fault Machine::do_ret() { return Fault::None; } +Fault Machine::do_cal(uint8_t op, uint16_t slot) { + // 内建 FB 布局冻结(Doc/compiler/符号表与链接.md): + // TON/TOF:in/pt/q/et(字段 0/1/2/3) + // CTU:cu/r/pv/q/cv(字段 0/1/2/3/4) + // 实例槽号从 slot(基槽)起;字段偏移 = 字段序号 × 8(8 字节定宽) + const int64_t dt = image_.header().dt_ms; + int64_t v = 0; + + if (op == static_cast(isa::Op::CAL_TON) || + op == static_cast(isa::Op::CAL_TOF)) { + // 字段:in=0 pt=1 q=2 et=3 + if (!slot_get(static_cast(slot + 0), &v)) return Fault::BadSlot; + const bool in = v != 0; + if (!slot_get(static_cast(slot + 1), &v)) return Fault::BadSlot; + const int64_t pt = v; + int64_t et = 0; + if (!slot_get(static_cast(slot + 3), &et)) return Fault::BadSlot; + int64_t q = 0; + if (op == static_cast(isa::Op::CAL_TON)) { + // TON:in 真 → et += dt(到 pt 停)、q = et ≥ pt;in 假 → et = 0、q = 0 + if (in) { + et += dt; + if (pt > 0 && et >= pt) { + et = pt; + } + q = (et >= pt) ? 1 : 0; + } else { + et = 0; + q = 0; + } + } else { + // TOF:in 真 → q = 1、et = 0;掉电 → et += dt、et ≥ pt → q = 0 + if (in) { + et = 0; + q = 1; + } else { + et += dt; + q = (pt > 0 && et >= pt) ? 0 : 1; + } + } + if (!slot_set(static_cast(slot + 3), et)) return Fault::BadSlot; + if (!slot_set(static_cast(slot + 2), q)) return Fault::BadSlot; + return Fault::None; + } + + if (op == static_cast(isa::Op::CAL_CTU)) { + // 字段:cu=0 r=1 pv=2 q=3 cv=4 + if (slot >= ctu_prev_.size()) return Fault::BadSlot; + if (!slot_get(static_cast(slot + 0), &v)) return Fault::BadSlot; + const bool cu = v != 0; + if (!slot_get(static_cast(slot + 1), &v)) return Fault::BadSlot; + const bool r = v != 0; + if (!slot_get(static_cast(slot + 2), &v)) return Fault::BadSlot; + const int64_t pv = v; + int64_t cv = 0; + if (!slot_get(static_cast(slot + 4), &cv)) return Fault::BadSlot; + // 上升沿:本周期 cu 真且上次 cu 假 → cv + 1;r → 复位 + const bool prev = ctu_prev_[slot] != 0; + if (r) { + cv = 0; + } else if (cu && !prev) { + cv += 1; + } + ctu_prev_[slot] = cu ? 1 : 0; // 记录本次 cu(跨周期) + if (!slot_set(static_cast(slot + 4), cv)) return Fault::BadSlot; + if (!slot_set(static_cast(slot + 3), (cv >= pv) ? 1 : 0)) { + return Fault::BadSlot; + } + return Fault::None; + } + + return Fault::BadOp; +} + } // namespace vm