12.9 步骤 4:定时器 CAL_TON/CAL_TOF/CAL_CTU。
- 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 正确 + 确定性两遍一致
This commit is contained in:
@@ -107,5 +107,9 @@ namespace vm {
|
|||||||
Fault do_call(uint32_t fn_id); // 压帧;BadFn 用 BadOp 表示
|
Fault do_call(uint32_t fn_id); // 压帧;BadFn 用 BadOp 表示
|
||||||
Fault do_ret(); // 弹帧 / 周期结束
|
Fault do_ret(); // 弹帧 / 周期结束
|
||||||
Fault do_cal(uint8_t op, uint16_t slot); // TON/TOF/CTU(12.9 步骤 4)
|
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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+105
-14
@@ -223,31 +223,20 @@ bool Machine::exec_one() {
|
|||||||
case isa::Op::LOAD_M:
|
case isa::Op::LOAD_M:
|
||||||
case isa::Op::LOAD_GLOBAL: {
|
case isa::Op::LOAD_GLOBAL: {
|
||||||
const uint16_t slot = isa::imm16(w);
|
const uint16_t slot = isa::imm16(w);
|
||||||
const size_t off = static_cast<size_t>(slot) * 8;
|
if (!slot_get(slot, ®s[rd])) {
|
||||||
if (off + 8 > data_.size()) {
|
|
||||||
fault_ = Fault::BadSlot;
|
fault_ = Fault::BadSlot;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int64_t v = 0;
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
v |= static_cast<int64_t>(data_[off + i]) << (8 * i);
|
|
||||||
}
|
|
||||||
regs[rd] = v;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case isa::Op::STORE_Q:
|
case isa::Op::STORE_Q:
|
||||||
case isa::Op::STORE_M:
|
case isa::Op::STORE_M:
|
||||||
case isa::Op::STORE_GLOBAL: {
|
case isa::Op::STORE_GLOBAL: {
|
||||||
const uint16_t slot = isa::imm16(w);
|
const uint16_t slot = isa::imm16(w);
|
||||||
const size_t off = static_cast<size_t>(slot) * 8;
|
if (!slot_set(slot, regs[rd])) {
|
||||||
if (off + 8 > data_.size()) {
|
|
||||||
fault_ = Fault::BadSlot;
|
fault_ = Fault::BadSlot;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const int64_t v = regs[rd];
|
|
||||||
for (int i = 0; i < 8; ++i) {
|
|
||||||
data_[off + i] = static_cast<uint8_t>((v >> (8 * i)) & 0xFFu);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case isa::Op::CALL:
|
case isa::Op::CALL:
|
||||||
@@ -259,13 +248,41 @@ bool Machine::exec_one() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !ended_; // MAIN 的 RET → 周期结束(返回 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<uint8_t>(op), isa::imm16(w));
|
||||||
|
return fault_ == Fault::None;
|
||||||
default:
|
default:
|
||||||
// CAL_TON / CAL_TOF / CAL_CTU(步骤 4 实现)
|
|
||||||
fault_ = Fault::BadOp;
|
fault_ = Fault::BadOp;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Machine::slot_get(uint16_t slot, int64_t* out) const {
|
||||||
|
const size_t off = static_cast<size_t>(slot) * 8;
|
||||||
|
if (off + 8 > data_.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int64_t v = 0;
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
v |= static_cast<int64_t>(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<size_t>(slot) * 8;
|
||||||
|
if (off + 8 > data_.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
data_[off + i] = static_cast<uint8_t>((v >> (8 * i)) & 0xFFu);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Fault Machine::do_call(uint32_t fn_id) {
|
Fault Machine::do_call(uint32_t fn_id) {
|
||||||
if (fn_id >= image_.header().n_funcs) {
|
if (fn_id >= image_.header().n_funcs) {
|
||||||
return Fault::BadOp;
|
return Fault::BadOp;
|
||||||
@@ -306,4 +323,78 @@ Fault Machine::do_ret() {
|
|||||||
return Fault::None;
|
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<uint8_t>(isa::Op::CAL_TON) ||
|
||||||
|
op == static_cast<uint8_t>(isa::Op::CAL_TOF)) {
|
||||||
|
// 字段:in=0 pt=1 q=2 et=3
|
||||||
|
if (!slot_get(static_cast<uint16_t>(slot + 0), &v)) return Fault::BadSlot;
|
||||||
|
const bool in = v != 0;
|
||||||
|
if (!slot_get(static_cast<uint16_t>(slot + 1), &v)) return Fault::BadSlot;
|
||||||
|
const int64_t pt = v;
|
||||||
|
int64_t et = 0;
|
||||||
|
if (!slot_get(static_cast<uint16_t>(slot + 3), &et)) return Fault::BadSlot;
|
||||||
|
int64_t q = 0;
|
||||||
|
if (op == static_cast<uint8_t>(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<uint16_t>(slot + 3), et)) return Fault::BadSlot;
|
||||||
|
if (!slot_set(static_cast<uint16_t>(slot + 2), q)) return Fault::BadSlot;
|
||||||
|
return Fault::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == static_cast<uint8_t>(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<uint16_t>(slot + 0), &v)) return Fault::BadSlot;
|
||||||
|
const bool cu = v != 0;
|
||||||
|
if (!slot_get(static_cast<uint16_t>(slot + 1), &v)) return Fault::BadSlot;
|
||||||
|
const bool r = v != 0;
|
||||||
|
if (!slot_get(static_cast<uint16_t>(slot + 2), &v)) return Fault::BadSlot;
|
||||||
|
const int64_t pv = v;
|
||||||
|
int64_t cv = 0;
|
||||||
|
if (!slot_get(static_cast<uint16_t>(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<uint16_t>(slot + 4), cv)) return Fault::BadSlot;
|
||||||
|
if (!slot_set(static_cast<uint16_t>(slot + 3), (cv >= pv) ? 1 : 0)) {
|
||||||
|
return Fault::BadSlot;
|
||||||
|
}
|
||||||
|
return Fault::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Fault::BadOp;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
|||||||
Reference in New Issue
Block a user