阶段4-2b:vm/Machine V2(变长取指/槽表两级/栈方案 C/CAL 15 条)
- 变长取指(instr_len 前缀定长)、译码(前缀分区+func+uses_* 直推) - 槽表两级访问:slot→slot_addr→值区按 func 读宽/扩展、写宽(含 F32/F64 位模式) - 栈方案 C:预分配 max_stack、帧头 12B(fn_id/ret_pc/ret_fn_id)+ regs 指向栈区、 r0..r7 全宽复制、字节+深度 64 双检查、MAIN 帧常驻、周期结束回退 sp - 指令语义:MOVE(func 宽度高位清 0)、LOADK(常量 8B 按 func)、NOT 逻辑非、 AND/OR/XOR 逐位、算术(各宽度饱和模板+无符号+浮点 IEEE)、CMP(按 func 符号)、 跳转(off 字节相对下一条)、CALL/RET 帧 - CAL 15 条 fb_id 分派:TON/TOF/TP/CTU/DCTU/CTD/DCTD/CTUD/DCTUD/R_TRIG/F_TRIG/ SR/RS/PWM(duty×pt 高电平)/RTC(虚拟时钟:周期×dt_ms,1970 纪元) - 边沿检测 edge_prev_(每槽 2 字节) - 验证:line1 全链路(I 采样→FB→短路→Q=1 真值表一致)、急停 Q=0、 13_call x=7、07 算术 42/10/32/eq、05 while n=10 - 状态:vm_test(48 处)/executor(1 处)待 4-2c/4-3
This commit is contained in:
+67
-81
@@ -1,17 +1,19 @@
|
||||
/**
|
||||
* @file Machine.h
|
||||
* @brief 寄存器虚拟机(12.9)
|
||||
* @brief 寄存器虚拟机(V2:变长指令 / 槽表两级访问 / 栈方案 C / CAL 15 条)
|
||||
* @author
|
||||
* @date 2026-08-21
|
||||
*
|
||||
* @details 设计说明(详见 Doc/vm/扫描周期.md 与 Doc/vm/指令执行.md):
|
||||
* - 只认 .stb 映像(vm 自带读实现;Machine::create 做型号/SHA-256 校验);
|
||||
* 无 GC、无堆、无线程
|
||||
* - 扫描周期:MAIN pc=0 → RET;MAIN 帧跨周期保留,调用栈深度上限 64
|
||||
* - 帧:{ fn_id, regs[nregs], ret_pc, ret_fn_id };CALL 压帧复制 r0..r7,
|
||||
* RET 复制回调用方(r0=结果)
|
||||
* - 数据区:8 字节定宽槽(方案 a),指令 slot = 槽号,偏移 = slot × 8
|
||||
* - 可观察性(v1 预留):step / pc / fn_id / cycle_count / call_depth / reg
|
||||
* @details 设计说明(详见 Doc/vm/扫描周期.md 与 Doc/isa/阶段4-执行侧V2.md):
|
||||
* - 只认 V2 .stb(vm::Image);create 做结构 + SHA-256 + 型号(STATOR2)校验
|
||||
* - 变长取指:instr_len 前缀定长;译码按前缀分区 + func + uses_* 直推
|
||||
* - 数据访问两级:slot → 槽表[slot].addr → 值区按 func 读宽/扩展、写宽
|
||||
* - 栈方案 C:create 一次性预分配 max_stack;帧头 12B(fn_id/ret_pc/ret_fn_id)
|
||||
* + regs(nregs×8,int64);压帧复制 r0..r7 全宽;字节 + 深度 64 双检查;
|
||||
* MAIN 帧常驻栈底,周期结束回退 sp 到 MAIN 帧顶
|
||||
* - CAL 15 条(fb_id 分派):字段布局见 Doc/isa/指令集清单.md §8.1;
|
||||
* RTC 用虚拟时钟(累计周期 × dt_ms,1970 纪元)
|
||||
* - 可观察性:step / pc(字节)/ fn_id / cycle_count / call_depth / reg
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -22,6 +24,8 @@
|
||||
|
||||
#include "vm/Image.h"
|
||||
#include "isa/Instr.h"
|
||||
#include "isa/Op.h"
|
||||
#include "isa/Types.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
@@ -30,30 +34,29 @@ namespace vm {
|
||||
*/
|
||||
enum class Fault {
|
||||
None, ///< 正常
|
||||
CycleLimit, ///< 本周期指令数超过映像头 cycle_limit(用例 6)
|
||||
StackOverflow, ///< 调用栈深度超过 64
|
||||
BadOp, ///< 非法操作码 / 寄存器越界 / CALL 目标越出函数表
|
||||
BadSlot, ///< slot × 8 + 8 越出数据区
|
||||
CycleLimit, ///< 本周期指令数超过映像头 cycle_limit
|
||||
StackOverflow, ///< 调用栈字节越界或深度 > 64
|
||||
BadOp, ///< 非法操作码 / 寄存器越界 / CALL 目标越界
|
||||
BadSlot, ///< 槽号越界或值区访问越界
|
||||
BadConst, ///< const_id 越出常量表
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 寄存器虚拟机:按扫描周期执行 .stb 映像。
|
||||
* @details 一个实例 = 一台机器:持有映像只读视图 + 数据区工作副本 + 调用栈。
|
||||
* MAIN 帧跨周期保留(PROGRAM 变量状态持久);每周期从 pc=0 执行到
|
||||
* MAIN 的 RET,期间调用栈可进可出(上限 64 帧)。
|
||||
* I 采样写入 / Q 读回由外部(executor)经 data() 完成,VM 只管数据区。
|
||||
* @brief 寄存器虚拟机(V2)。
|
||||
* @details 一个实例 = 一台机器:值区工作副本 + 预分配栈区 + 调用栈。
|
||||
* MAIN 帧常驻栈底(跨周期保留,PROGRAM 变量状态持久);
|
||||
* 每周期从 pc=0 执行到 MAIN 的 RET。
|
||||
*/
|
||||
class Machine {
|
||||
public:
|
||||
/**
|
||||
* @brief 从映像字节构建机器(校验 + 拷贝数据段 + 建 MAIN 帧)。
|
||||
* @brief 从映像字节构建机器。
|
||||
* @param image .stb 映像字节
|
||||
* @param out 输出 Machine(未初始化)
|
||||
* @param err 错误输出;可为 nullptr(静默)
|
||||
* @return true 成功;false(映像非法,err 已写)
|
||||
* @details 校验顺序:解析 .stb(Image::from)→ SHA-256 → 型号标识匹配
|
||||
* (内建 kModelName + kModelVersion),任一不符直接拒绝。
|
||||
* @return true 成功;false(结构/SHA/型号任一不符,err 已写)
|
||||
* @details 校验顺序:Image::from 结构 → SHA-256 → 型号 STATOR2;
|
||||
* 通过后拷贝值区、预分配 max_stack 栈区、建 MAIN 帧。
|
||||
*/
|
||||
static bool create(const std::vector<uint8_t>& image, Machine* out,
|
||||
std::string* err);
|
||||
@@ -64,96 +67,79 @@ namespace vm {
|
||||
*/
|
||||
Fault run_cycle();
|
||||
|
||||
// ---- 可观察性(v1 预留,12.11 供单步/回放/TUI)----
|
||||
// ---- 可观察性 ----
|
||||
|
||||
/**
|
||||
* @brief 执行一条指令,停在指令边界。
|
||||
* @return true 继续;false 周期结束(MAIN 的 RET)或发生故障
|
||||
*/
|
||||
/// @brief 执行一条指令,停在指令边界;false = 周期结束或故障。
|
||||
bool step();
|
||||
|
||||
/// @brief 最近一次故障(step 返回 false 后查询)。
|
||||
Fault fault() const;
|
||||
|
||||
/// @brief 周期是否已结束(MAIN 的 RET 后为 true)。
|
||||
bool ended() const;
|
||||
|
||||
/// @brief 映像头(dt_ms / cycle_limit 等)。
|
||||
/// @brief 映像头(dt_ms / cycle_limit / max_stack 等)。
|
||||
const vm::ImageHeader& header() const;
|
||||
|
||||
/// @brief 当前指令下标(相对当前函数字节码段)。
|
||||
/// @brief 当前 pc(字节偏移,相对当前函数字节码段)。
|
||||
uint32_t pc() const;
|
||||
|
||||
/// @brief 当前函数 fn_id。
|
||||
uint32_t fn_id() const;
|
||||
|
||||
/// @brief 本周期已执行指令数。
|
||||
uint32_t cycle_count() const;
|
||||
|
||||
/// @brief 调用栈深度(MAIN 帧 = 1)。
|
||||
uint32_t call_depth() const;
|
||||
|
||||
/// @brief 数据区(I 采样写入 / Q 读回由外部做;8 字节定宽槽)。
|
||||
/// @brief 值区工作副本(I 采样写入 / Q 读回由外部做)。
|
||||
uint8_t* data();
|
||||
const uint8_t* data() const;
|
||||
|
||||
/// @brief 数据区字节数。
|
||||
/// @brief 值区字节数。
|
||||
size_t data_len() const;
|
||||
|
||||
/// @brief 当前帧寄存器值(i < nregs)。
|
||||
int64_t reg(uint8_t i) const;
|
||||
|
||||
/// @brief 当前帧寄存器数(函数头 nregs)。
|
||||
/// @brief 当前帧寄存器数。
|
||||
uint32_t nregs() const;
|
||||
|
||||
/// @brief 当前指令(pc_ 处;单步/观察用;pc 越界时返回 RET 哨兵)。
|
||||
isa::Instr cur_instr() const;
|
||||
/// @brief 当前指令字节(pc 处;单步/观察用)。
|
||||
const uint8_t* cur_instr_bytes() const;
|
||||
/// @brief 当前指令长度。
|
||||
uint32_t cur_instr_len() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 调用帧。
|
||||
*/
|
||||
/// 调用帧(regs 指向预分配栈区子块)。
|
||||
struct Frame {
|
||||
uint32_t fn_id = 0; ///< 本帧函数
|
||||
std::vector<int64_t> regs; ///< 寄存器文件(大小 = 函数头 nregs)
|
||||
uint32_t ret_pc = 0; ///< CALL 的下一条(非 MAIN 帧有意义)
|
||||
uint32_t ret_fn_id = 0; ///< 返回目标函数
|
||||
uint32_t fn_id = 0; ///< 本帧函数
|
||||
uint32_t nregs = 0; ///< 寄存器数
|
||||
int64_t* regs = nullptr;///< 寄存器文件(栈区内)
|
||||
uint32_t ret_pc = 0; ///< CALL 的下一条(字节;非 MAIN 帧有意义)
|
||||
uint32_t ret_fn_id = 0; ///< 返回目标函数
|
||||
};
|
||||
|
||||
vm::Image image_; ///< 映像只读视图(vm 自实现,指向外部缓冲)
|
||||
std::vector<uint8_t> data_; ///< 数据区工作副本(8 字节定宽槽)
|
||||
std::vector<Frame> frames_; ///< 调用栈([0] = MAIN,跨周期保留)
|
||||
/**
|
||||
* @brief 边沿检测上次输入(每槽 2 字节:[slot*2] 第一边沿、[slot*2+1] 第二边沿;
|
||||
* CTU/CTD/R_TRIG/F_TRIG 用第一、CTUD 用两个),跨周期保留。
|
||||
*/
|
||||
std::vector<uint8_t> edge_prev_;
|
||||
uint32_t pc_ = 0; ///< 当前 pc(相对本帧函数字节码段)
|
||||
uint32_t cycle_count_ = 0; ///< 本周期指令数
|
||||
Fault fault_ = Fault::None;///< 最近一次故障
|
||||
bool ended_ = false; ///< step 后周期是否已结束
|
||||
|
||||
/// @brief 当前(栈顶)帧引用。
|
||||
Frame& cur_frame();
|
||||
/// @brief 当前(栈顶)帧常量引用。
|
||||
const Frame& cur_frame() const;
|
||||
|
||||
/// @brief 译码执行一条;false = 故障或周期结束。
|
||||
bool exec_one();
|
||||
|
||||
/// @brief 压帧(复制 r0..r7);fn_id 越界以 BadOp 表示。
|
||||
Fault do_call(uint32_t fn_id);
|
||||
|
||||
/// @brief 弹帧 / 周期结束(复制 r0..r7 回调用方)。
|
||||
Fault do_ret();
|
||||
Fault do_cal(uint16_t fb_id, uint32_t slot);
|
||||
|
||||
/// @brief 执行内置 FB(TON/TOF/TP/CTU/CTD/CTUD/R_TRIG/F_TRIG)。
|
||||
Fault do_cal(uint8_t op, uint16_t slot);
|
||||
/// 值区字段读写(实例 addr + 偏移,按 func 宽度)。
|
||||
bool read_value(uint32_t addr, uint8_t func, int64_t* out);
|
||||
bool write_value(uint32_t addr, uint8_t func, int64_t v);
|
||||
/// 算术(按 func:整数饱和 / 无符号 / 浮点 IEEE)。
|
||||
int64_t exec_arith(const char* name, uint8_t func, int64_t a, int64_t b);
|
||||
/// 比较(按 func:有/无符号、浮点)。
|
||||
int64_t exec_cmp(const char* name, uint8_t func, int64_t a, int64_t b);
|
||||
/// 比较结果(模板:有符号/无符号/浮点共用)。
|
||||
template <typename T>
|
||||
static int64_t cmp_result(const char* name, T a, T b);
|
||||
/// 实例字段读写(slot → addr + off)。
|
||||
bool read_field(uint32_t slot, int32_t off, uint8_t func, int64_t* out);
|
||||
bool write_field(uint32_t slot, int32_t off, uint8_t func, int64_t v);
|
||||
|
||||
/// @brief 读数据区槽(8 字节定宽;越界返回 false)。
|
||||
bool slot_get(uint16_t slot, int64_t* out) const;
|
||||
|
||||
/// @brief 写数据区槽(8 字节定宽;越界返回 false)。
|
||||
bool slot_set(uint16_t slot, int64_t v);
|
||||
vm::Image image_; ///< 映像只读视图
|
||||
std::vector<uint8_t> data_; ///< 值区工作副本
|
||||
std::vector<uint8_t> stack_; ///< 预分配栈区(max_stack 字节)
|
||||
size_t sp_ = 0; ///< 栈顶(MAIN 帧之后)
|
||||
std::vector<Frame> frames_; ///< 调用栈([0] = MAIN,跨周期保留)
|
||||
std::vector<uint8_t> edge_prev_; ///< 边沿检测(每槽 2 字节,跨周期保留)
|
||||
uint32_t pc_ = 0; ///< 当前 pc(字节,相对本帧函数字节码段)
|
||||
uint32_t cycle_count_ = 0; ///< 本周期指令数
|
||||
uint64_t cycles_total_ = 0; ///< 累计周期数(RTC 虚拟时钟用)
|
||||
Fault fault_ = Fault::None; ///< 最近一次故障
|
||||
bool ended_ = false; ///< step 后周期是否已结束
|
||||
};
|
||||
}
|
||||
|
||||
+598
-363
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user