阶段 C 步骤 7:isa 拆出 Image,vm 依赖收窄。
- 删 isa/Image.h + Image.cpp(ImageView/FNV/写文件/sidecar 不再属于 isa) - vm 自实现只读视图 vm/Image.h/cpp:头 104(12.13)/段校验/缺 SHA 尾报错 (型号匹配与 SHA 校验留步骤 8);Machine 改用 vm::Image + vm::ImageHeader - executor:本地读文件(替换 isa::read_stb_file) - 测试:isa_test 删映像/FNV 部分;codegen_test/vm_test 改用 compiler::StbView / vm::ConstEntry;vm_test 手拼映像适配新格式(头 104 + 尾 32 占位) - 验证:line1 编译 288 字节 → BytecodeExecutor 回放 Q 正确;ctest 12/12
This commit is contained in:
+2
-1
@@ -7,7 +7,8 @@ project(VM
|
||||
DESCRIPTION "寄存器虚拟机")
|
||||
|
||||
add_library(vm STATIC
|
||||
./src/Machine.cpp)
|
||||
./src/Machine.cpp
|
||||
./src/Image.cpp)
|
||||
|
||||
target_include_directories(vm PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
target_link_libraries(vm PUBLIC isa)
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @file Image.h
|
||||
* @brief vm 自带的 .stb 只读视图(执行器侧;compiler 各有实现)
|
||||
* @author
|
||||
* @date 2026-08-21
|
||||
*
|
||||
* @details 格式契约见 Doc/isa/指令与映像.md(12.13 修订:头 104 = 72 + 型号标识[32],
|
||||
* 文件尾 SHA-256[32])。步骤 7:解析头与段;步骤 8:补型号匹配与 SHA-256 校验。
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace vm {
|
||||
|
||||
// 映像头(字段与 Doc/isa/指令与映像.md 一致)
|
||||
struct ImageHeader {
|
||||
uint32_t cycle_limit = 0;
|
||||
uint32_t dt_ms = 0;
|
||||
uint64_t project_hash = 0;
|
||||
uint32_t entry_fn_id = 0;
|
||||
uint32_t n_globals = 0;
|
||||
uint32_t n_i = 0;
|
||||
uint32_t n_q = 0;
|
||||
uint32_t n_m = 0;
|
||||
uint32_t n_consts = 0;
|
||||
uint32_t n_funcs = 0;
|
||||
uint32_t offset_const = 0;
|
||||
uint32_t offset_funcs = 0;
|
||||
uint32_t offset_code = 0;
|
||||
uint32_t offset_fb = 0;
|
||||
uint32_t offset_data = 0;
|
||||
};
|
||||
|
||||
struct FuncRow {
|
||||
uint32_t nregs = 0;
|
||||
uint32_t code_offset = 0; // 相对字节码段起点(字节)
|
||||
uint32_t code_len = 0; // 指令条数
|
||||
};
|
||||
|
||||
struct ConstEntry {
|
||||
uint32_t tag = 0;
|
||||
uint64_t value = 0;
|
||||
};
|
||||
|
||||
// 只读视图:校验过的映像(指向外部缓冲)
|
||||
class Image {
|
||||
public:
|
||||
static Image from(const uint8_t* buf, size_t len);
|
||||
static Image from(const std::vector<uint8_t>& buf);
|
||||
|
||||
bool ok() const { return ok_; }
|
||||
const std::string& error() const { return err_; }
|
||||
const ImageHeader& header() const { return hdr_; }
|
||||
|
||||
FuncRow func_row(size_t i) const;
|
||||
ConstEntry const_entry(size_t i) const;
|
||||
|
||||
const uint8_t* code_bytes() const; // 字节码段起点
|
||||
const uint8_t* data_bytes() const; // 数据段起点
|
||||
size_t data_len() const; // 字节数
|
||||
|
||||
public:
|
||||
// 默认构造为无效态(ok() == false)
|
||||
Image() : buf_(nullptr), len_(0) {}
|
||||
|
||||
private:
|
||||
const uint8_t* buf_;
|
||||
size_t len_;
|
||||
bool ok_ = false;
|
||||
std::string err_;
|
||||
ImageHeader hdr_;
|
||||
};
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "isa/Image.h"
|
||||
#include "vm/Image.h"
|
||||
#include "isa/Instr.h"
|
||||
|
||||
namespace vm {
|
||||
@@ -67,7 +67,7 @@ namespace vm {
|
||||
bool ended() const;
|
||||
|
||||
/** @brief 映像头(dt_ms / cycle_limit 等) */
|
||||
const isa::ImageHeader& header() const;
|
||||
const vm::ImageHeader& header() const;
|
||||
|
||||
/** @brief 当前指令下标(相对当前函数字节码段) */
|
||||
uint32_t pc() const;
|
||||
@@ -105,7 +105,7 @@ namespace vm {
|
||||
uint32_t ret_fn_id = 0; // 返回目标函数
|
||||
};
|
||||
|
||||
isa::ImageView image_; // 映像只读视图
|
||||
vm::Image image_; // 映像只读视图(vm 自实现)
|
||||
std::vector<uint8_t> data_; // 数据区工作副本(8 字节定宽槽)
|
||||
std::vector<Frame> frames_; // 调用栈([0] = MAIN,跨周期保留)
|
||||
// 边沿检测上次输入(每槽 2 字节:[slot*2] 第一边沿、[slot*2+1] 第二边沿;
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @file Image.cpp
|
||||
* @brief vm 自带的 .stb 只读视图(执行器侧)
|
||||
* @author
|
||||
* @date 2026-08-21
|
||||
*/
|
||||
|
||||
#include "vm/Image.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
namespace {
|
||||
|
||||
const uint32_t kMagic = 0x43545353u; // "STSC" 小端
|
||||
const uint32_t kVersion = 1;
|
||||
const size_t kHeaderSize = 104;
|
||||
const size_t kConstEntrySize = 12;
|
||||
const size_t kFuncRowSize = 12;
|
||||
const size_t kSha256Size = 32; // 文件尾(步骤 8 校验)
|
||||
|
||||
uint32_t get_le32(const uint8_t* p) {
|
||||
return static_cast<uint32_t>(p[0])
|
||||
| (static_cast<uint32_t>(p[1]) << 8)
|
||||
| (static_cast<uint32_t>(p[2]) << 16)
|
||||
| (static_cast<uint32_t>(p[3]) << 24);
|
||||
}
|
||||
|
||||
uint64_t get_le64(const uint8_t* p) {
|
||||
uint64_t v = 0;
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
v |= static_cast<uint64_t>(p[i]) << (8 * i);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Image Image::from(const uint8_t* buf, size_t len) {
|
||||
Image v;
|
||||
v.buf_ = buf;
|
||||
v.len_ = len;
|
||||
if (buf == nullptr) {
|
||||
v.err_ = "null buffer";
|
||||
return v;
|
||||
}
|
||||
if (len < kHeaderSize) {
|
||||
v.err_ = "image too short";
|
||||
return v;
|
||||
}
|
||||
if (get_le32(buf + 0) != kMagic) {
|
||||
v.err_ = "bad magic";
|
||||
return v;
|
||||
}
|
||||
if (get_le32(buf + 4) != kVersion) {
|
||||
v.err_ = "bad version";
|
||||
return v;
|
||||
}
|
||||
ImageHeader& h = v.hdr_;
|
||||
h.cycle_limit = get_le32(buf + 8);
|
||||
h.dt_ms = get_le32(buf + 12);
|
||||
h.project_hash = get_le64(buf + 16);
|
||||
h.entry_fn_id = get_le32(buf + 24);
|
||||
h.n_globals = get_le32(buf + 28);
|
||||
h.n_i = get_le32(buf + 32);
|
||||
h.n_q = get_le32(buf + 36);
|
||||
h.n_m = get_le32(buf + 40);
|
||||
h.n_consts = get_le32(buf + 44);
|
||||
h.n_funcs = get_le32(buf + 48);
|
||||
h.offset_const = get_le32(buf + 52);
|
||||
h.offset_funcs = get_le32(buf + 56);
|
||||
h.offset_code = get_le32(buf + 60);
|
||||
h.offset_fb = get_le32(buf + 64);
|
||||
h.offset_data = get_le32(buf + 68);
|
||||
|
||||
// 段校验(数据段之后是 SHA-256 文件尾;步骤 8 做校验,这里仅保证有尾)
|
||||
if (len < static_cast<size_t>(h.offset_data) + kSha256Size) {
|
||||
v.err_ = "missing sha256 tail";
|
||||
return v;
|
||||
}
|
||||
const uint64_t offs[5] = {h.offset_const, h.offset_funcs, h.offset_code, h.offset_fb,
|
||||
h.offset_data};
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
if (offs[i] < kHeaderSize || offs[i] > len - kSha256Size) {
|
||||
v.err_ = "segment offset out of range";
|
||||
return v;
|
||||
}
|
||||
if (i > 0 && offs[i] < offs[i - 1]) {
|
||||
v.err_ = "segment offsets not monotonic";
|
||||
return v;
|
||||
}
|
||||
}
|
||||
if (offs[1] - offs[0] != static_cast<uint64_t>(h.n_consts) * kConstEntrySize) {
|
||||
v.err_ = "const table size mismatch";
|
||||
return v;
|
||||
}
|
||||
if (offs[2] - offs[1] != static_cast<uint64_t>(h.n_funcs) * kFuncRowSize) {
|
||||
v.err_ = "function table size mismatch";
|
||||
return v;
|
||||
}
|
||||
if ((h.offset_fb - h.offset_code) % 4 != 0) {
|
||||
v.err_ = "code segment not 4-byte aligned";
|
||||
return v;
|
||||
}
|
||||
if (h.entry_fn_id >= h.n_funcs && h.n_funcs != 0) {
|
||||
v.err_ = "entry fn_id out of range";
|
||||
return v;
|
||||
}
|
||||
v.ok_ = true;
|
||||
v.err_.clear();
|
||||
return v;
|
||||
}
|
||||
|
||||
Image Image::from(const std::vector<uint8_t>& buf) {
|
||||
return from(buf.data(), buf.size());
|
||||
}
|
||||
|
||||
FuncRow Image::func_row(size_t i) const {
|
||||
FuncRow r;
|
||||
if (ok_ && i < hdr_.n_funcs) {
|
||||
const uint8_t* p = buf_ + hdr_.offset_funcs + i * kFuncRowSize;
|
||||
r.nregs = get_le32(p + 0);
|
||||
r.code_offset = get_le32(p + 4);
|
||||
r.code_len = get_le32(p + 8);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
ConstEntry Image::const_entry(size_t i) const {
|
||||
ConstEntry e;
|
||||
if (ok_ && i < hdr_.n_consts) {
|
||||
const uint8_t* p = buf_ + hdr_.offset_const + i * kConstEntrySize;
|
||||
e.tag = get_le32(p);
|
||||
e.value = get_le64(p + 4);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
const uint8_t* Image::code_bytes() const {
|
||||
return ok_ ? buf_ + hdr_.offset_code : nullptr;
|
||||
}
|
||||
|
||||
const uint8_t* Image::data_bytes() const {
|
||||
return ok_ ? buf_ + hdr_.offset_data : nullptr;
|
||||
}
|
||||
|
||||
size_t Image::data_len() const {
|
||||
// 步骤 7:含 SHA 尾(步骤 8 收紧并校验)
|
||||
return ok_ ? len_ - hdr_.offset_data : 0;
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
+7
-7
@@ -25,7 +25,7 @@ namespace vm {
|
||||
|
||||
bool Machine::create(const std::vector<uint8_t>& image, Machine* out,
|
||||
std::string* err) {
|
||||
out->image_ = isa::ImageView::from(image);
|
||||
out->image_ = vm::Image::from(image);
|
||||
if (!out->image_.ok()) {
|
||||
if (err) {
|
||||
*err = out->image_.error();
|
||||
@@ -39,7 +39,7 @@ bool Machine::create(const std::vector<uint8_t>& image, Machine* out,
|
||||
|
||||
// MAIN 帧(跨周期保留)
|
||||
const uint32_t entry = out->image_.header().entry_fn_id;
|
||||
const isa::FuncRow main = out->image_.func_row(entry);
|
||||
const vm::FuncRow main = out->image_.func_row(entry);
|
||||
out->frames_.clear();
|
||||
Frame f;
|
||||
f.fn_id = entry;
|
||||
@@ -79,7 +79,7 @@ bool Machine::step() {
|
||||
|
||||
Fault Machine::fault() const { return fault_; }
|
||||
bool Machine::ended() const { return ended_; }
|
||||
const isa::ImageHeader& Machine::header() const { return image_.header(); }
|
||||
const vm::ImageHeader& Machine::header() const { return image_.header(); }
|
||||
uint32_t Machine::pc() const { return pc_; }
|
||||
uint32_t Machine::fn_id() const { return cur_frame().fn_id; }
|
||||
uint32_t Machine::cycle_count() const { return cycle_count_; }
|
||||
@@ -94,7 +94,7 @@ uint32_t Machine::nregs() const {
|
||||
}
|
||||
|
||||
isa::Instr Machine::cur_instr() const {
|
||||
const isa::FuncRow row = image_.func_row(cur_frame().fn_id);
|
||||
const vm::FuncRow row = image_.func_row(cur_frame().fn_id);
|
||||
const uint8_t* base = image_.code_bytes() + row.code_offset;
|
||||
if (pc_ >= row.code_len) {
|
||||
return isa::pack(isa::Op::RET, 0, 0, 0);
|
||||
@@ -107,7 +107,7 @@ const Machine::Frame& Machine::cur_frame() const { return frames_.back(); }
|
||||
|
||||
bool Machine::exec_one() {
|
||||
// ---- 取指 ----
|
||||
const isa::FuncRow row = image_.func_row(cur_frame().fn_id);
|
||||
const vm::FuncRow row = image_.func_row(cur_frame().fn_id);
|
||||
if (pc_ >= row.code_len) {
|
||||
fault_ = Fault::BadOp;
|
||||
return false;
|
||||
@@ -165,7 +165,7 @@ bool Machine::exec_one() {
|
||||
fault_ = Fault::BadConst;
|
||||
return false;
|
||||
}
|
||||
const isa::ConstEntry c = image_.const_entry(cid);
|
||||
const vm::ConstEntry c = image_.const_entry(cid);
|
||||
if (c.tag == isa::types::Bool) {
|
||||
regs[rd] = c.value ? 1 : 0;
|
||||
} else if (c.tag == isa::types::Int) {
|
||||
@@ -310,7 +310,7 @@ Fault Machine::do_call(uint32_t fn_id) {
|
||||
if (frames_.size() >= 64) {
|
||||
return Fault::StackOverflow;
|
||||
}
|
||||
const isa::FuncRow row = image_.func_row(fn_id);
|
||||
const vm::FuncRow row = image_.func_row(fn_id);
|
||||
Frame f;
|
||||
f.fn_id = fn_id;
|
||||
f.regs.assign(row.nregs, 0);
|
||||
|
||||
Reference in New Issue
Block a user