12.11 闭环:二十用例点亮 + 单步观察。
- cases_test:tests/cases/01..20 逐一跑完整管线(解析→链接→类型→码→VM 周期), 按 EXPECTED.md 期望断言:13 正例运行通过(含双周期可重复)、06 CycleLimit、6 负例报错类别 - BytecodeExecutor --step:采样 I → 逐指令打印 pc/fn/反汇编 + 执行后非零寄存器 → I/Q - Machine 补 header()/ended()/nregs()/cur_instr() 观察接口 - ctest 11/11(cases_all 20 用例点亮);line1 回放 0/1 组合 Q 正确、单步 I=[0 1]→Q=[1]
This commit is contained in:
+98
-40
@@ -20,16 +20,18 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "isa/Encode.h"
|
||||
#include "isa/Image.h"
|
||||
#include "vm/Machine.h"
|
||||
|
||||
namespace {
|
||||
|
||||
void usage() {
|
||||
std::printf("usage: BytecodeExecutor <name>.stb [--cycles N] [--replay <file>]\n"
|
||||
std::printf("usage: BytecodeExecutor <name>.stb [--cycles N] [--replay <file>] [--step]\n"
|
||||
" 加载 .stb + <name>.runtime.toml,按扫描周期执行\n"
|
||||
" --cycles N 跑 N 个周期(缺省 10)\n"
|
||||
" --replay <file> 读录制的 I 序列(每行按 io.input 顺序的 0/1)\n"
|
||||
" --step 单步:逐指令打印 pc/fn/反汇编/寄存器(跑 1 个周期)\n"
|
||||
" --help 打印本帮助\n");
|
||||
}
|
||||
|
||||
@@ -116,6 +118,58 @@ namespace {
|
||||
m.data()[static_cast<size_t>(slot) * 8] = v ? 1 : 0;
|
||||
}
|
||||
|
||||
// 采样:回放行按 io.input 顺序填,无回放则全 0;文件读尽后保持最后一行
|
||||
void sample_inputs(vm::Machine& m, const std::vector<Binding>& bindings,
|
||||
std::ifstream& replay_in, std::vector<int>& replay_line) {
|
||||
if (replay_in.is_open()) {
|
||||
std::string line;
|
||||
if (std::getline(replay_in, line)) {
|
||||
replay_line.clear();
|
||||
size_t pos = 0;
|
||||
while (pos < line.size()) {
|
||||
while (pos < line.size() &&
|
||||
std::isspace(static_cast<unsigned char>(line[pos]))) {
|
||||
++pos;
|
||||
}
|
||||
if (pos >= line.size()) break;
|
||||
const size_t s = pos;
|
||||
while (pos < line.size() &&
|
||||
!std::isspace(static_cast<unsigned char>(line[pos]))) {
|
||||
++pos;
|
||||
}
|
||||
replay_line.push_back(std::stoi(line.substr(s, pos - s)));
|
||||
}
|
||||
}
|
||||
size_t idx = 0;
|
||||
for (const Binding& b : bindings) {
|
||||
if (!b.is_input) continue;
|
||||
put_bool(m, b.slot, idx < replay_line.size() ? replay_line[idx] : 0);
|
||||
++idx;
|
||||
}
|
||||
} else {
|
||||
for (const Binding& b : bindings) {
|
||||
if (b.is_input) {
|
||||
put_bool(m, b.slot, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按 sidecar 绑定顺序打印 I/Q
|
||||
std::string iq_string(vm::Machine& m, const std::vector<Binding>& bindings,
|
||||
std::string* is, std::string* qs) {
|
||||
for (const Binding& b : bindings) {
|
||||
if (b.is_input) {
|
||||
if (!is->empty()) *is += " ";
|
||||
*is += std::to_string(slot_bool(m, b.slot));
|
||||
} else {
|
||||
if (!qs->empty()) *qs += " ";
|
||||
*qs += std::to_string(slot_bool(m, b.slot));
|
||||
}
|
||||
}
|
||||
return *is;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
@@ -131,12 +185,15 @@ int main(int argc, char** argv) {
|
||||
|
||||
const std::string stb_path = argv[1];
|
||||
uint32_t cycles = 10;
|
||||
bool step_mode = false;
|
||||
std::string replay;
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
if (std::strcmp(argv[i], "--cycles") == 0 && i + 1 < argc) {
|
||||
cycles = static_cast<uint32_t>(std::stoul(argv[i + 1]));
|
||||
} else if (std::strcmp(argv[i], "--replay") == 0 && i + 1 < argc) {
|
||||
replay = argv[i + 1];
|
||||
} else if (std::strcmp(argv[i], "--step") == 0) {
|
||||
step_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,54 +237,55 @@ int main(int argc, char** argv) {
|
||||
std::printf("image: %s (%zu bytes, dt_ms=%u, cycle_limit=%u)\n", stb_path.c_str(),
|
||||
bytes.size(), h.dt_ms, h.cycle_limit);
|
||||
|
||||
for (uint32_t c = 1; c <= cycles; ++c) {
|
||||
// 采样:回放行按 io.input 顺序填,无回放则全 0
|
||||
if (replay_in.is_open()) {
|
||||
std::string line;
|
||||
if (std::getline(replay_in, line)) {
|
||||
replay_line.clear();
|
||||
size_t pos = 0;
|
||||
while (pos < line.size()) {
|
||||
while (pos < line.size() &&
|
||||
std::isspace(static_cast<unsigned char>(line[pos]))) {
|
||||
++pos;
|
||||
}
|
||||
if (pos >= line.size()) break;
|
||||
const size_t s = pos;
|
||||
while (pos < line.size() &&
|
||||
!std::isspace(static_cast<unsigned char>(line[pos]))) {
|
||||
++pos;
|
||||
}
|
||||
replay_line.push_back(std::stoi(line.substr(s, pos - s)));
|
||||
// 单步模式:采样 I → 逐指令打印(指令 + 执行后寄存器)→ I/Q
|
||||
if (step_mode) {
|
||||
std::printf("-- single step (cycle 1) --\n");
|
||||
sample_inputs(machine, bindings, replay_in, replay_line);
|
||||
uint32_t guard = 0;
|
||||
while (machine.fault() == vm::Fault::None && !machine.ended()) {
|
||||
char buf[64];
|
||||
isa::disasm(machine.cur_instr(), buf, sizeof buf);
|
||||
const uint32_t pc = machine.pc();
|
||||
const uint32_t fn = machine.fn_id();
|
||||
if (!machine.step()) {
|
||||
break;
|
||||
}
|
||||
// 执行后状态:指令 + 非零寄存器
|
||||
std::printf(" pc=%u fn=%u %s", pc, fn, buf);
|
||||
std::string regs;
|
||||
const uint32_t n = machine.nregs() < 32 ? machine.nregs() : 32;
|
||||
for (uint32_t i = 0; i < n; ++i) {
|
||||
const int64_t v = machine.reg(static_cast<uint8_t>(i));
|
||||
if (v != 0) {
|
||||
if (!regs.empty()) regs += " ";
|
||||
regs += "r" + std::to_string(i) + "=" + std::to_string(v);
|
||||
}
|
||||
}
|
||||
size_t idx = 0;
|
||||
for (const Binding& b : bindings) {
|
||||
if (!b.is_input) continue;
|
||||
put_bool(machine, b.slot, idx < replay_line.size() ? replay_line[idx] : 0);
|
||||
++idx;
|
||||
}
|
||||
} else {
|
||||
for (const Binding& b : bindings) {
|
||||
if (b.is_input) {
|
||||
put_bool(machine, b.slot, 0);
|
||||
}
|
||||
std::printf(" [%s]\n", regs.c_str());
|
||||
if (++guard > 1000000) {
|
||||
std::printf(" ...step limit\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (machine.fault() != vm::Fault::None) {
|
||||
std::printf(" FAULT(%d)\n", static_cast<int>(machine.fault()));
|
||||
return 1;
|
||||
}
|
||||
std::string is, qs;
|
||||
iq_string(machine, bindings, &is, &qs);
|
||||
std::printf("cycle 1: I=[%s] Q=[%s]\n", is.c_str(), qs.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint32_t c = 1; c <= cycles; ++c) {
|
||||
// 采样:回放行按 io.input 顺序填,无回放则全 0
|
||||
sample_inputs(machine, bindings, replay_in, replay_line);
|
||||
|
||||
const vm::Fault f = machine.run_cycle();
|
||||
|
||||
// 打印 I/Q(按 sidecar 绑定顺序)
|
||||
std::string is, qs;
|
||||
for (const Binding& b : bindings) {
|
||||
if (b.is_input) {
|
||||
if (!is.empty()) is += " ";
|
||||
is += std::to_string(slot_bool(machine, b.slot));
|
||||
} else {
|
||||
if (!qs.empty()) qs += " ";
|
||||
qs += std::to_string(slot_bool(machine, b.slot));
|
||||
}
|
||||
}
|
||||
iq_string(machine, bindings, &is, &qs);
|
||||
std::printf("cycle %u: I=[%s] Q=[%s]", c, is.c_str(), qs.c_str());
|
||||
if (f != vm::Fault::None) {
|
||||
std::printf(" FAULT(%d)", static_cast<int>(f));
|
||||
|
||||
Reference in New Issue
Block a user