12.9 步骤 2:VM 译码 switch(标量/跳转/LOAD-STORE)。

- Machine.cpp:create(拷贝数据段+建 MAIN 帧)、run_cycle、step、exec_one
- 标量:MOVE/LOADK(常量表 tag 定值表示)/NOT/AND/OR/四则饱和/CMP 全宽比较
- 跳转:JMP/JT/JF(相对下一条);LOAD/STORE:slot×8 定宽槽,BadSlot 校验
- 寄存器越界检查按指令形态(a|b 作偏移/槽号/常量 id 时不查)
- 修:ImageView 默认构造公开(无效态)、Codegen 两个编译警告
- 冒烟:用例 02/04/07/05 跑通、06 触发 CycleLimit、step 单步
This commit is contained in:
2026-08-21 20:16:28 +08:00
parent 815eb87a46
commit efe4dd1a2c
3 changed files with 260 additions and 7 deletions
+1 -4
View File
@@ -242,9 +242,6 @@ namespace {
if (d.type.kind == TypeKind::FbUser || d.type.kind == TypeKind::FbBuiltin) {
continue;
}
if (r > 255) {
return fail("register overflow in function '" + pou.name + "'");
}
f->regs[d.name] = r++;
}
}
@@ -660,8 +657,8 @@ namespace {
case BinOp::Le: return isa::Op::CMP_LE;
case BinOp::Gt: return isa::Op::CMP_GT;
case BinOp::Ge: return isa::Op::CMP_GE;
default: return isa::Op::CMP_EQ; // Add/Sub/Mul/Div 不经此函数
}
return isa::Op::CMP_EQ;
}
/**
+3 -1
View File
@@ -77,6 +77,8 @@ namespace isa {
// 只读视图:校验过的映像
class ImageView {
public:
// 默认构造为无效态(ok() == falseerror() == "uninitialized"
ImageView();
static ImageView from(const uint8_t* buf, size_t len);
static ImageView from(const std::vector<uint8_t>& buf);
@@ -96,7 +98,7 @@ namespace isa {
size_t data_len() const; // 字节数
private:
ImageView();
// 私有成员与内部构造辅助(from 使用)
const uint8_t* buf_;
size_t len_;
+256 -2
View File
@@ -1,8 +1,262 @@
/**
* @file Machine.cpp
* @brief 寄存器虚拟机(12.9 实现
* @date 2026-08-19
* @brief 寄存器虚拟机(12.9,步骤 2:译码 switch
* @author
* @date 2026-08-21
*
* @details 设计说明(详见 Doc/vm/指令执行.md):
* - 步骤 2 范围:create / run_cycle / step + 标量指令(MOVE/LOADK/NOT/AND/OR/算术/CMP)、
* 跳转(JMP/JT/JF)、LOAD/STOREslot × 8);RET 仅处理 MAIN(周期结束)
* - 步骤 3 补 CALL/RET 帧栈与栈深/坏操作码故障;步骤 4 补 CAL_* 定时器
* - 取指:函数表 → code_offset(字节)→ u32;执行后 pc 先 +1,跳转再 pc += off
* - 数据区 8 字节定宽槽:偏移 = slot × 8
*/
#include "vm/Machine.h"
#include "isa/Encode.h"
#include "isa/Instr.h"
#include "isa/Op.h"
#include "isa/Types.h"
namespace vm {
bool Machine::create(const std::vector<uint8_t>& image, Machine* out,
std::string* err) {
out->image_ = isa::ImageView::from(image);
if (!out->image_.ok()) {
if (err) {
*err = out->image_.error();
}
return false;
}
// 数据区工作副本(8 字节定宽槽)
out->data_.assign(out->image_.data_bytes(),
out->image_.data_bytes() + out->image_.data_len());
out->ctu_prev_.assign(out->data_len() / 8, 0);
// MAIN 帧(跨周期保留)
const uint32_t entry = out->image_.header().entry_fn_id;
const isa::FuncRow main = out->image_.func_row(entry);
out->frames_.clear();
Frame f;
f.fn_id = entry;
f.regs.assign(main.nregs, 0);
out->frames_.push_back(std::move(f));
out->pc_ = 0;
out->cycle_count_ = 0;
out->fault_ = Fault::None;
out->ended_ = false;
return true;
}
Fault Machine::run_cycle() {
cycle_count_ = 0;
ended_ = false;
fault_ = Fault::None;
pc_ = 0;
while (!ended_ && fault_ == Fault::None) {
if (!exec_one()) {
break;
}
}
// 周期结束:清调用栈(保留 MAIN 帧,PROGRAM 变量状态跨周期)
while (frames_.size() > 1) {
frames_.pop_back();
}
return fault_;
}
bool Machine::step() {
if (ended_ || fault_ != Fault::None) {
return false;
}
return exec_one();
}
Fault Machine::fault() const { return fault_; }
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_; }
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(); }
int64_t Machine::reg(uint8_t i) const { return cur_frame().regs[i]; }
Machine::Frame& Machine::cur_frame() { return frames_.back(); }
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);
if (pc_ >= row.code_len) {
fault_ = Fault::BadOp;
return false;
}
const uint8_t* base = image_.code_bytes() + row.code_offset;
const isa::Instr w = reinterpret_cast<const uint32_t*>(base)[pc_];
// ---- 周期指令计数 ----
++cycle_count_;
if (cycle_count_ > image_.header().cycle_limit) {
fault_ = Fault::CycleLimit;
return false;
}
// 先指向下一条(跳转指令再按"相对下一条"语义叠加偏移)
++pc_;
const isa::Op op = isa::op(w);
const uint8_t rd = isa::rd(w);
const uint8_t ra = isa::a(w);
const uint8_t rb = isa::b(w);
std::vector<int64_t>& regs = cur_frame().regs;
// 寄存器越界检查(仅对把字段当寄存器的指令;a|b 作偏移/槽号/常量 id 时跳过)
const bool uses_rd = op == isa::Op::MOVE || op == isa::Op::NOT || op == isa::Op::AND ||
op == isa::Op::OR || op == isa::Op::ADD || op == isa::Op::SUB ||
op == isa::Op::MUL || op == isa::Op::DIV || op == isa::Op::CMP_EQ ||
op == isa::Op::CMP_NE || op == isa::Op::CMP_LT ||
op == isa::Op::CMP_LE || op == isa::Op::CMP_GT ||
op == isa::Op::CMP_GE || op == isa::Op::JT || op == isa::Op::JF ||
op == isa::Op::LOADK || op == isa::Op::LOAD_I ||
op == isa::Op::LOAD_M || op == isa::Op::LOAD_GLOBAL ||
op == isa::Op::STORE_Q || op == isa::Op::STORE_M ||
op == isa::Op::STORE_GLOBAL;
const bool uses_ra = op == isa::Op::MOVE || op == isa::Op::NOT || op == isa::Op::AND ||
op == isa::Op::OR || op == isa::Op::ADD || op == isa::Op::SUB ||
op == isa::Op::MUL || op == isa::Op::DIV || op == isa::Op::CMP_EQ ||
op == isa::Op::CMP_NE || op == isa::Op::CMP_LT ||
op == isa::Op::CMP_LE || op == isa::Op::CMP_GT ||
op == isa::Op::CMP_GE;
const bool uses_rb = uses_ra;
if ((uses_rd && rd >= regs.size()) || (uses_ra && ra >= regs.size()) ||
(uses_rb && rb >= regs.size())) {
fault_ = Fault::BadOp;
return false;
}
switch (op) {
case isa::Op::MOVE:
regs[rd] = regs[ra];
return true;
case isa::Op::LOADK: {
const uint16_t cid = isa::imm16(w);
if (cid >= image_.header().n_consts) {
fault_ = Fault::BadConst;
return false;
}
const isa::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) {
regs[rd] = static_cast<int16_t>(c.value); // 符号扩展
} else {
regs[rd] = static_cast<int64_t>(c.value);
}
return true;
}
case isa::Op::NOT:
regs[rd] = (regs[ra] == 0) ? 1 : 0;
return true;
case isa::Op::AND:
regs[rd] = (regs[ra] != 0 && regs[rb] != 0) ? 1 : 0;
return true;
case isa::Op::OR:
regs[rd] = (regs[ra] != 0 || regs[rb] != 0) ? 1 : 0;
return true;
case isa::Op::ADD:
regs[rd] = isa::types::sat_add(static_cast<int16_t>(regs[ra]),
static_cast<int16_t>(regs[rb]));
return true;
case isa::Op::SUB:
regs[rd] = isa::types::sat_sub(static_cast<int16_t>(regs[ra]),
static_cast<int16_t>(regs[rb]));
return true;
case isa::Op::MUL:
regs[rd] = isa::types::sat_mul(static_cast<int16_t>(regs[ra]),
static_cast<int16_t>(regs[rb]));
return true;
case isa::Op::DIV:
regs[rd] = isa::types::sat_div(static_cast<int16_t>(regs[ra]),
static_cast<int16_t>(regs[rb]));
return true;
case isa::Op::CMP_EQ:
case isa::Op::CMP_NE:
case isa::Op::CMP_LT:
case isa::Op::CMP_LE:
case isa::Op::CMP_GT:
case isa::Op::CMP_GE: {
const int64_t l = regs[ra];
const int64_t r = regs[rb];
bool res = false;
switch (op) {
case isa::Op::CMP_EQ: res = (l == r); break;
case isa::Op::CMP_NE: res = (l != r); break;
case isa::Op::CMP_LT: res = (l < r); break;
case isa::Op::CMP_LE: res = (l <= r); break;
case isa::Op::CMP_GT: res = (l > r); break;
case isa::Op::CMP_GE: res = (l >= r); break;
default: break;
}
regs[rd] = res ? 1 : 0;
return true;
}
case isa::Op::JMP:
pc_ += isa::off16(w);
return true;
case isa::Op::JT:
if (regs[rd] != 0) {
pc_ += isa::off16(w);
}
return true;
case isa::Op::JF:
if (regs[rd] == 0) {
pc_ += isa::off16(w);
}
return true;
case isa::Op::LOAD_I:
case isa::Op::LOAD_M:
case isa::Op::LOAD_GLOBAL: {
const uint16_t slot = isa::imm16(w);
const size_t off = static_cast<size_t>(slot) * 8;
if (off + 8 > data_.size()) {
fault_ = Fault::BadSlot;
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;
}
case isa::Op::STORE_Q:
case isa::Op::STORE_M:
case isa::Op::STORE_GLOBAL: {
const uint16_t slot = isa::imm16(w);
const size_t off = static_cast<size_t>(slot) * 8;
if (off + 8 > data_.size()) {
fault_ = Fault::BadSlot;
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;
}
case isa::Op::RET:
// MAIN 的 RET = 周期结束(步骤 3 处理非 MAIN 帧返回)
ended_ = true;
return false;
default:
// CALL / CAL_TON / CAL_TOF / CAL_CTU(步骤 3 / 4 实现)
fault_ = Fault::BadOp;
return false;
}
}
} // namespace vm