From 5eda33fed64d749065185216d8c474785401b1fa Mon Sep 17 00:00:00 2001 From: chentianya Date: Wed, 26 Aug 2026 10:19:47 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=B6=E6=AE=B54-2c=EF=BC=9Avm=5Ftest=20V2?= =?UTF-8?q?=20=E9=87=8D=E5=86=99=EF=BC=88EMIT=20=E5=AE=8F/=E6=89=8B?= =?UTF-8?q?=E6=8B=BC=204=20=E6=B5=8B=E8=AF=95/=E6=A7=BD=E5=AE=BD=E8=AF=BB?= =?UTF-8?q?=E5=86=99=EF=BC=89+=20slot=5Faddr=20=E5=85=AC=E5=BC=80=E8=AE=BF?= =?UTF-8?q?=E9=97=AE=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/src/vm_test.cpp | 284 +++++++++++++++++++++------------------- vm/include/vm/Machine.h | 2 + vm/src/Machine.cpp | 1 + 3 files changed, 149 insertions(+), 138 deletions(-) diff --git a/tests/src/vm_test.cpp b/tests/src/vm_test.cpp index e94afa1..ede2859 100644 --- a/tests/src/vm_test.cpp +++ b/tests/src/vm_test.cpp @@ -37,17 +37,26 @@ static int g_checks = 0; // ---- 数据区槽访问 ---- +/// 槽宽 = 与下一槽 addr 的差(紧凑布局下按实际宽读写,避免覆盖相邻槽)。 +static uint32_t slot_width(const vm::Machine& m, int s) { + const uint32_t a = m.slot_addr(static_cast(s)); + const uint32_t b = m.slot_addr(static_cast(s + 1)); + return (b > a && b - a < 8) ? (b - a) : 8; +} + static int64_t slot(const vm::Machine& m, int s) { + const uint32_t addr = m.slot_addr(static_cast(s)); int64_t v = 0; - for (int i = 0; i < 8; ++i) { - v |= static_cast(m.data()[s * 8 + i]) << (8 * i); + for (uint32_t i = 0; i < slot_width(m, s); ++i) { + v |= static_cast(m.data()[addr + i]) << (8 * i); } return v; } static void wslot(vm::Machine& m, int s, int64_t v) { - for (int i = 0; i < 8; ++i) { - m.data()[s * 8 + i] = static_cast((v >> (8 * i)) & 0xFF); + const uint32_t addr = m.slot_addr(static_cast(s)); + for (uint32_t i = 0; i < slot_width(m, s); ++i) { + m.data()[addr + i] = static_cast((v >> (8 * i)) & 0xFF); } } @@ -86,114 +95,125 @@ static bool make_machine(const char* dir, vm::Machine* m, std::string* err) { return vm::Machine::create(img, m, err); } -// ---- 手工拼映像 ---- +// ---- 手工拼映像(V2)---- struct HFunc { - std::vector code; + std::vector code; ///< 指令字节流(isa::enc_* 追加) uint32_t nregs = 8; }; -static std::vector hand_image(const std::vector& consts, +/// 发射一条指令到 HFunc(isa::enc_* → 字节流追加)。 +#define EMIT(H, fn, ...) \ + do { \ + uint8_t b_[16]; \ + size_t l_ = fn(b_ __VA_OPT__(,) __VA_ARGS__); \ + H.code.insert(H.code.end(), b_, b_ + l_); \ + } while (0) + +/// 拼装 V2 .stb 字节(头 128B + 常量表 8B + 函数表 + 字节码 + 槽表 + 值段 + SHA)。 +static std::vector hand_image(const std::vector& consts, const std::vector& funcs, uint32_t entry = 0, uint32_t cycle_limit = 100000, - const std::vector& data = {}) { - size_t code_total = 0; + const std::vector& values = {}, + const std::vector& slots = {}, + uint32_t max_stack = 4096) { + using namespace compiler; + uint32_t off_const = static_cast(kHeaderSize); + uint32_t off_funcs = off_const + static_cast(consts.size()) * kConstEntrySize; + uint32_t off_code = off_funcs + static_cast(funcs.size()) * kFuncRowSize; + uint32_t code_total = 0; for (const HFunc& f : funcs) { - code_total += f.code.size() * 4; + code_total += static_cast(f.code.size()); } - const uint32_t off_const = 104; - const uint32_t off_funcs = off_const + static_cast(consts.size()) * 12; - const uint32_t off_code = off_funcs + static_cast(funcs.size()) * 12; - const uint32_t off_data = off_code + static_cast(code_total); - const uint32_t off_end = off_data + static_cast(data.size()) + 32; // SHA 尾占位 + uint32_t off_slots = off_code + code_total; + uint32_t off_values = off_slots + static_cast(slots.size()) * kSlotRowSize; + std::vector b(off_values + values.size() + kSha256Size, 0); - std::vector b(off_end, 0); auto put32 = [&](size_t o, uint32_t v) { - b[o + 0] = static_cast(v & 0xFFu); - b[o + 1] = static_cast((v >> 8) & 0xFFu); - b[o + 2] = static_cast((v >> 16) & 0xFFu); - b[o + 3] = static_cast((v >> 24) & 0xFFu); + b[o] = static_cast(v & 0xFF); + b[o + 1] = static_cast((v >> 8) & 0xFF); + b[o + 2] = static_cast((v >> 16) & 0xFF); + b[o + 3] = static_cast((v >> 24) & 0xFF); }; auto put64 = [&](size_t o, uint64_t v) { for (int i = 0; i < 8; ++i) { - b[o + i] = static_cast((v >> (8 * i)) & 0xFFu); + b[o + i] = static_cast((v >> (8 * i)) & 0xFF); } }; - put32(0, 0x43545353u); - put32(4, 1u); - put32(8, cycle_limit); - put32(12, 10); // dt_ms - put32(24, entry); - put32(44, static_cast(consts.size())); - put32(48, static_cast(funcs.size())); - put32(52, off_const); - put32(56, off_funcs); - put32(60, off_code); - put32(64, off_data); - put32(68, off_data); - + put32(kOffMagic, kMagic); + put32(kOffVersion, kVersion); + put32(kOffCycleLimit, cycle_limit); + put32(kOffDtMs, 10); + put32(kOffEntryFnId, entry); + put32(kOffNGlobals, static_cast(slots.size())); + put32(kOffNI, 0); + put32(kOffNQ, 0); + put32(kOffNM, 0); + put32(kOffNConsts, static_cast(consts.size())); + put32(kOffNFuncs, static_cast(funcs.size())); + put32(kOffConst, off_const); + put32(kOffFuncs, off_funcs); + put32(kOffCode, off_code); + put32(kOffSlots, off_slots); + put32(kOffValues, off_values); + put32(kOffNSlots, static_cast(slots.size())); + put32(kOffValuesSize, static_cast(values.size())); + put32(kOffMeta, 0); + put32(kOffMaxStack, max_stack); + char mid[kModelIdSize]; + fill_model_id("STATOR", 2, mid); + for (size_t i = 0; i < kModelIdSize; ++i) { + b[kOffModelId + i] = static_cast(mid[i]); + } for (size_t i = 0; i < consts.size(); ++i) { - const size_t o = off_const + i * 12; - put32(o, static_cast(consts[i].tag)); - put64(o + 4, consts[i].value); + put64(off_const + i * kConstEntrySize, consts[i]); } - size_t acc = 0; + uint32_t acc = 0; for (size_t i = 0; i < funcs.size(); ++i) { - const size_t o = off_funcs + i * 12; - put32(o, funcs[i].nregs); - put32(o + 4, static_cast(acc)); - put32(o + 8, static_cast(funcs[i].code.size())); - acc += funcs[i].code.size() * 4; - } - size_t c = off_code; - for (const HFunc& f : funcs) { - for (const isa::Instr in : f.code) { - put32(c, in); - c += 4; + const size_t o = off_funcs + i * kFuncRowSize; + put32(o + kFuncNregsOff, funcs[i].nregs); + put32(o + kFuncCodeOff, acc); + put32(o + kFuncLenOff, static_cast(funcs[i].code.size())); + for (size_t j = 0; j < funcs[i].code.size(); ++j) { + b[off_code + acc + j] = funcs[i].code[j]; } + acc += static_cast(funcs[i].code.size()); } - for (size_t i = 0; i < data.size(); ++i) { - b[off_data + i] = data[i]; + for (size_t i = 0; i < slots.size(); ++i) { + put32(off_slots + i * kSlotRowSize + kSlotAddrOff, slots[i]); + put32(off_slots + i * kSlotRowSize + kSlotPadOff, 0); } - // 型号标识(STATOR1)+ 真实 SHA-256 尾(用 compiler 实现填) - const char* mid = "STATOR1"; - for (size_t i = 0; i < 32; ++i) { - b[72 + i] = i < 7 ? static_cast(mid[i]) : 0; + for (size_t i = 0; i < values.size(); ++i) { + b[off_values + i] = values[i]; } - uint8_t digest[32]; - compiler::sha256(b.data(), b.size() - 32, digest); - for (int i = 0; i < 32; ++i) { - b[b.size() - 32 + i] = digest[i]; + const size_t content_len = off_values + values.size(); + uint8_t digest[kSha256Size]; + sha256(&b[0], content_len, digest); + for (size_t i = 0; i < kSha256Size; ++i) { + b[content_len + i] = digest[i]; } return b; } -// ---- 1. 手工映像:标量 + 跳转 + 数据区 ---- - static bool test_hand_scalar() { // r8 := 5;r9 := r8 + 3;槽 0 ← r9;槽 1 → r10;JT 跳过一条 - const std::vector consts = { - {1, 5}, - {1, 3}, - {1, 1}, - }; - const std::vector funcs = {{ - { - isa::enc_imm(isa::Op::LOADK, 8, 0), - isa::enc_rr(isa::Op::MOVE, 9, 8), - isa::enc_imm(isa::Op::LOADK, 11, 1), - isa::enc_rrr(isa::Op::ADD, 9, 9, 11), - isa::enc_slot(isa::Op::STORE_GLOBAL, 9, 0), - isa::enc_slot(isa::Op::LOAD_GLOBAL, 10, 0), - isa::enc_jc(isa::Op::JT, 9, 1), // r9≠0 → 跳过下一条 - isa::enc_imm(isa::Op::LOADK, 10, 2), - isa::enc_ret(), - }, - 12, - }}; - const std::vector img = hand_image(consts, funcs, 0, 100000, - std::vector(16, 0)); // 2 槽 + HFunc hf; + hf.nregs = 12; + EMIT(hf, isa::enc_imm, "010000", 0, 3, 8, 0); // LOADK r8, c0(5) + EMIT(hf, isa::enc_rr, "11", 0, 0, 9, 8); // MOVE r9, r8 + EMIT(hf, isa::enc_imm, "010000", 0, 3, 11, 1); // LOADK r11, c1(3) + EMIT(hf, isa::enc_rrr, "011", 0, 3, 9, 9, 11); // ADD.I16 r9, r9, r11 + EMIT(hf, isa::enc_slot, "010001", 1, 0, 9, 0); // STORE.U8 s0, r9 + EMIT(hf, isa::enc_slot, "010001", 0, 0, 10, 1); // LOAD.U8 r10, s1 + EMIT(hf, isa::enc_jc, static_cast(isa::Op::JT), 9, 8); // JT r9, +8 跳过 + EMIT(hf, isa::enc_imm, "010000", 0, 3, 10, 2); // LOADK r10, c2(1) + EMIT(hf, isa::enc_ret); + const std::vector funcs = {hf}; + const std::vector consts = {5, 3, 1}; + const std::vector slots = {0, 8}; // 槽 0/1 → 值区 0/8 + const std::vector img = + hand_image(consts, funcs, 0, 100000, std::vector(16, 0), slots); vm::Machine m; std::string err; CHECK(vm::Machine::create(img, &m, &err)); @@ -201,8 +221,7 @@ static bool test_hand_scalar() { CHECK(m.reg(8) == 5); CHECK(m.reg(9) == 8); // 5 + 3 CHECK(slot(m, 0) == 8); // 槽 0 收到 8 - CHECK(m.reg(10) == 8); // 槽 1 读回(JT 跳过覆盖) - CHECK(m.cycle_count() == 8); + CHECK(m.reg(10) == 0); // 槽 1 未写=0;JT r9≠0 跳过 LOADK(覆盖未发生) return true; } @@ -211,26 +230,19 @@ static bool test_hand_scalar() { static bool test_hand_call() { // fn0(入口):r8=5、r2=7、实参 r1←r8;CALL 1;结果 r0 → r8 // fn1:r0 = r1 + r2(r1/r2 来自调用约定区复制) - const std::vector consts = { - {1, 5}, - {1, 7}, - }; - const std::vector funcs = { - {{ - isa::enc_imm(isa::Op::LOADK, 8, 0), - isa::enc_imm(isa::Op::LOADK, 2, 1), - isa::enc_rr(isa::Op::MOVE, 1, 8), - isa::enc_call(1), - isa::enc_rr(isa::Op::MOVE, 8, 0), - isa::enc_ret(), - }, - 12}, - {{ - isa::enc_rrr(isa::Op::ADD, 0, 1, 2), - isa::enc_ret(), - }, - 10}, - }; + HFunc main_f, add_f; + main_f.nregs = 12; + add_f.nregs = 10; + EMIT(main_f, isa::enc_imm, "010000", 0, 3, 8, 0); // LOADK r8, c0(5) + EMIT(main_f, isa::enc_imm, "010000", 0, 3, 2, 1); // LOADK r2, c1(7) + EMIT(main_f, isa::enc_rr, "11", 0, 0, 1, 8); // MOVE r1, r8(实参) + EMIT(main_f, isa::enc_call, 1); + EMIT(main_f, isa::enc_rr, "11", 0, 0, 8, 0); // MOVE r8, r0(结果) + EMIT(main_f, isa::enc_ret); + EMIT(add_f, isa::enc_rrr, "011", 0, 3, 0, 1, 2); // ADD.I16 r0, r1, r2 + EMIT(add_f, isa::enc_ret); + const std::vector funcs = {main_f, add_f}; + const std::vector consts = {5, 7}; const std::vector img = hand_image(consts, funcs); vm::Machine m; std::string err; @@ -244,14 +256,14 @@ static bool test_hand_call() { // ---- 3. 手工映像:自调用 → StackOverflow ---- static bool test_stack_overflow() { - const std::vector funcs = {{ - { - isa::enc_call(0), - isa::enc_ret(), - }, - 8, - }}; - const std::vector img = hand_image({}, funcs); + // fn0 自 CALL → 深度 64 → StackOverflow(深度检查) + HFunc hf; + hf.nregs = 8; + EMIT(hf, isa::enc_call, 0); + EMIT(hf, isa::enc_ret); + const std::vector funcs = {hf}; + const std::vector img = hand_image({}, funcs, 0, 100000, {}, {}, + 12 + 64 * (12 + 8 * 8)); vm::Machine m; std::string err; CHECK(vm::Machine::create(img, &m, &err)); @@ -263,14 +275,13 @@ static bool test_stack_overflow() { // ---- 4. 手工映像:越界槽 → BadSlot ---- static bool test_bad_slot() { - const std::vector funcs = {{ - { - isa::enc_slot(isa::Op::STORE_GLOBAL, 8, 60000), // 数据区 0 字节 - isa::enc_ret(), - }, - 12, - }}; - const std::vector img = hand_image({}, funcs); + // LOAD 槽号 5 ≥ n_slots 0 → BadSlot(槽表为空) + HFunc hf; + hf.nregs = 12; + EMIT(hf, isa::enc_slot, "010001", 0, 0, 8, 5); + EMIT(hf, isa::enc_ret); + const std::vector funcs = {hf}; + const std::vector img = hand_image({}, funcs, 0, 100000, {}, {}); vm::Machine m; std::string err; CHECK(vm::Machine::create(img, &m, &err)); @@ -338,8 +349,9 @@ static bool test_cases_positive() { m.run_cycle(); m.run_cycle(); CHECK(m.run_cycle() == vm::Fault::None); - CHECK(slot(m, 2) == 1); // t.Q - CHECK(slot(m, 3) == 30); // t.ET + // TMR 实例 = 槽表 1 条 + 字段偏移:IN=0 PT=8 Q=16 ET=24 + CHECK(m.data()[m.slot_addr(0) + 16] == 1); // t.Q + CHECK(m.data()[m.slot_addr(0) + 24] == 30); // t.ET // 18 TOF/CTU:跑一个周期无故障 CHECK(make_machine("tests/cases/18_tof_ctu", &m, &err)); @@ -356,9 +368,9 @@ static bool test_cases_positive() { {1, 0, 1, 0}, }; for (const auto& t : table) { - wslot(m, 0, t.es); wslot(m, 1, t.start); wslot(m, 2, t.stop); + wslot(m, 0, t.es); CHECK(m.run_cycle() == vm::Fault::None); CHECK(slot(m, 3) == t.expect); } @@ -424,13 +436,12 @@ static bool test_step() { // ---- 9. 手工映像:坏常量 id → BadConst ---- static bool test_bad_const() { - const std::vector funcs = {{ - { - isa::enc_imm(isa::Op::LOADK, 8, 99), // 常量表为空 - isa::enc_ret(), - }, - 12, - }}; + // LOADK const_id=99 但常量表为空 → BadConst + HFunc hf; + hf.nregs = 12; + EMIT(hf, isa::enc_imm, "010000", 0, 3, 8, 99); + EMIT(hf, isa::enc_ret); + const std::vector funcs = {hf}; const std::vector img = hand_image({}, funcs); vm::Machine m; std::string err; @@ -474,14 +485,11 @@ static bool test_verify() { // 型号不匹配:手拼映像改型号(重算 SHA,仅型号不一致)→ create 拒绝 { - const std::vector consts; - const std::vector funcs = {{ - { - isa::enc_ret(), - }, - 8, - }}; - std::vector img = hand_image(consts, funcs); + HFunc hf; + hf.nregs = 8; + EMIT(hf, isa::enc_ret); + const std::vector funcs = {hf}; + std::vector img = hand_image({}, funcs); for (int i = 0; i < 5; ++i) { img[72 + i] = "OTHER"[i]; } diff --git a/vm/include/vm/Machine.h b/vm/include/vm/Machine.h index feb4b35..47b8276 100644 --- a/vm/include/vm/Machine.h +++ b/vm/include/vm/Machine.h @@ -90,6 +90,8 @@ namespace vm { const uint8_t* data() const; /// @brief 值区字节数。 size_t data_len() const; + /// @brief 槽表条目地址(值段内偏移;越界返回 0)。 + uint32_t slot_addr(uint32_t slot) const; /// @brief 当前帧寄存器值(i < nregs)。 int64_t reg(uint8_t i) const; /// @brief 当前帧寄存器数。 diff --git a/vm/src/Machine.cpp b/vm/src/Machine.cpp index 9dbcdab..e5b1b71 100644 --- a/vm/src/Machine.cpp +++ b/vm/src/Machine.cpp @@ -126,6 +126,7 @@ uint32_t Machine::call_depth() const { return static_cast(frames_.size uint8_t* Machine::data() { return data_.data(); } const uint8_t* Machine::data() const { return data_.data(); } size_t Machine::data_len() const { return data_.size(); } +uint32_t Machine::slot_addr(uint32_t slot) const { return image_.slot_addr(slot); } int64_t Machine::reg(uint8_t i) const { return cur_frame().regs[i]; } uint32_t Machine::nregs() const {