阶段4-2c:vm_test V2 重写(EMIT 宏/手拼 4 测试/槽宽读写)+ slot_addr 公开访问器
This commit is contained in:
+146
-138
@@ -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<uint32_t>(s));
|
||||
const uint32_t b = m.slot_addr(static_cast<uint32_t>(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<uint32_t>(s));
|
||||
int64_t v = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
v |= static_cast<int64_t>(m.data()[s * 8 + i]) << (8 * i);
|
||||
for (uint32_t i = 0; i < slot_width(m, s); ++i) {
|
||||
v |= static_cast<int64_t>(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<uint8_t>((v >> (8 * i)) & 0xFF);
|
||||
const uint32_t addr = m.slot_addr(static_cast<uint32_t>(s));
|
||||
for (uint32_t i = 0; i < slot_width(m, s); ++i) {
|
||||
m.data()[addr + i] = static_cast<uint8_t>((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<isa::Instr> code;
|
||||
std::vector<uint8_t> code; ///< 指令字节流(isa::enc_* 追加)
|
||||
uint32_t nregs = 8;
|
||||
};
|
||||
|
||||
static std::vector<uint8_t> hand_image(const std::vector<vm::ConstEntry>& 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<uint8_t> hand_image(const std::vector<uint64_t>& consts,
|
||||
const std::vector<HFunc>& funcs,
|
||||
uint32_t entry = 0,
|
||||
uint32_t cycle_limit = 100000,
|
||||
const std::vector<uint8_t>& data = {}) {
|
||||
size_t code_total = 0;
|
||||
const std::vector<uint8_t>& values = {},
|
||||
const std::vector<uint32_t>& slots = {},
|
||||
uint32_t max_stack = 4096) {
|
||||
using namespace compiler;
|
||||
uint32_t off_const = static_cast<uint32_t>(kHeaderSize);
|
||||
uint32_t off_funcs = off_const + static_cast<uint32_t>(consts.size()) * kConstEntrySize;
|
||||
uint32_t off_code = off_funcs + static_cast<uint32_t>(funcs.size()) * kFuncRowSize;
|
||||
uint32_t code_total = 0;
|
||||
for (const HFunc& f : funcs) {
|
||||
code_total += f.code.size() * 4;
|
||||
code_total += static_cast<uint32_t>(f.code.size());
|
||||
}
|
||||
const uint32_t off_const = 104;
|
||||
const uint32_t off_funcs = off_const + static_cast<uint32_t>(consts.size()) * 12;
|
||||
const uint32_t off_code = off_funcs + static_cast<uint32_t>(funcs.size()) * 12;
|
||||
const uint32_t off_data = off_code + static_cast<uint32_t>(code_total);
|
||||
const uint32_t off_end = off_data + static_cast<uint32_t>(data.size()) + 32; // SHA 尾占位
|
||||
uint32_t off_slots = off_code + code_total;
|
||||
uint32_t off_values = off_slots + static_cast<uint32_t>(slots.size()) * kSlotRowSize;
|
||||
std::vector<uint8_t> b(off_values + values.size() + kSha256Size, 0);
|
||||
|
||||
std::vector<uint8_t> b(off_end, 0);
|
||||
auto put32 = [&](size_t o, uint32_t v) {
|
||||
b[o + 0] = static_cast<uint8_t>(v & 0xFFu);
|
||||
b[o + 1] = static_cast<uint8_t>((v >> 8) & 0xFFu);
|
||||
b[o + 2] = static_cast<uint8_t>((v >> 16) & 0xFFu);
|
||||
b[o + 3] = static_cast<uint8_t>((v >> 24) & 0xFFu);
|
||||
b[o] = static_cast<uint8_t>(v & 0xFF);
|
||||
b[o + 1] = static_cast<uint8_t>((v >> 8) & 0xFF);
|
||||
b[o + 2] = static_cast<uint8_t>((v >> 16) & 0xFF);
|
||||
b[o + 3] = static_cast<uint8_t>((v >> 24) & 0xFF);
|
||||
};
|
||||
auto put64 = [&](size_t o, uint64_t v) {
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
b[o + i] = static_cast<uint8_t>((v >> (8 * i)) & 0xFFu);
|
||||
b[o + i] = static_cast<uint8_t>((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<uint32_t>(consts.size()));
|
||||
put32(48, static_cast<uint32_t>(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<uint32_t>(slots.size()));
|
||||
put32(kOffNI, 0);
|
||||
put32(kOffNQ, 0);
|
||||
put32(kOffNM, 0);
|
||||
put32(kOffNConsts, static_cast<uint32_t>(consts.size()));
|
||||
put32(kOffNFuncs, static_cast<uint32_t>(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<uint32_t>(slots.size()));
|
||||
put32(kOffValuesSize, static_cast<uint32_t>(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<uint8_t>(mid[i]);
|
||||
}
|
||||
for (size_t i = 0; i < consts.size(); ++i) {
|
||||
const size_t o = off_const + i * 12;
|
||||
put32(o, static_cast<uint32_t>(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<uint32_t>(acc));
|
||||
put32(o + 8, static_cast<uint32_t>(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<uint32_t>(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<uint32_t>(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<uint8_t>(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<vm::ConstEntry> consts = {
|
||||
{1, 5},
|
||||
{1, 3},
|
||||
{1, 1},
|
||||
};
|
||||
const std::vector<HFunc> 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<uint8_t> img = hand_image(consts, funcs, 0, 100000,
|
||||
std::vector<uint8_t>(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<uint8_t>(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<HFunc> funcs = {hf};
|
||||
const std::vector<uint64_t> consts = {5, 3, 1};
|
||||
const std::vector<uint32_t> slots = {0, 8}; // 槽 0/1 → 值区 0/8
|
||||
const std::vector<uint8_t> img =
|
||||
hand_image(consts, funcs, 0, 100000, std::vector<uint8_t>(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<vm::ConstEntry> consts = {
|
||||
{1, 5},
|
||||
{1, 7},
|
||||
};
|
||||
const std::vector<HFunc> 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<HFunc> funcs = {main_f, add_f};
|
||||
const std::vector<uint64_t> consts = {5, 7};
|
||||
const std::vector<uint8_t> 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<HFunc> funcs = {{
|
||||
{
|
||||
isa::enc_call(0),
|
||||
isa::enc_ret(),
|
||||
},
|
||||
8,
|
||||
}};
|
||||
const std::vector<uint8_t> 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<HFunc> funcs = {hf};
|
||||
const std::vector<uint8_t> 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<HFunc> funcs = {{
|
||||
{
|
||||
isa::enc_slot(isa::Op::STORE_GLOBAL, 8, 60000), // 数据区 0 字节
|
||||
isa::enc_ret(),
|
||||
},
|
||||
12,
|
||||
}};
|
||||
const std::vector<uint8_t> 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<HFunc> funcs = {hf};
|
||||
const std::vector<uint8_t> 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<HFunc> 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<HFunc> funcs = {hf};
|
||||
const std::vector<uint8_t> img = hand_image({}, funcs);
|
||||
vm::Machine m;
|
||||
std::string err;
|
||||
@@ -474,14 +485,11 @@ static bool test_verify() {
|
||||
|
||||
// 型号不匹配:手拼映像改型号(重算 SHA,仅型号不一致)→ create 拒绝
|
||||
{
|
||||
const std::vector<vm::ConstEntry> consts;
|
||||
const std::vector<HFunc> funcs = {{
|
||||
{
|
||||
isa::enc_ret(),
|
||||
},
|
||||
8,
|
||||
}};
|
||||
std::vector<uint8_t> img = hand_image(consts, funcs);
|
||||
HFunc hf;
|
||||
hf.nregs = 8;
|
||||
EMIT(hf, isa::enc_ret);
|
||||
const std::vector<HFunc> funcs = {hf};
|
||||
std::vector<uint8_t> img = hand_image({}, funcs);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
img[72 + i] = "OTHER"[i];
|
||||
}
|
||||
|
||||
@@ -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 当前帧寄存器数。
|
||||
|
||||
@@ -126,6 +126,7 @@ uint32_t Machine::call_depth() const { return static_cast<uint32_t>(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 {
|
||||
|
||||
Reference in New Issue
Block a user