阶段 B 步骤 4:compiler 配置驱动化,去除 isa 依赖。

- Project.h 自带 IoBinding;Stb.h/cpp:compiler 侧 .stb 规范(常量/ConstEntry/FNV/StbView/读写/sidecar)
- Codec.h/cpp:指令字 pack/字段/配置驱动 disasm(format 表驱动)
- Codegen:opcode 全查 MachineConfig(E_* 发射器)、常量 tag 查配置类型、初值按基元宽度写、
  映像拼装用 Stb 常量;codegen_project 增加 cfg 参数
- main.cpp:--machine <path>(编译/反汇编必填),--disasm 用 StbView+Codec
- CMake:compiler 不再链接 isa(仅 toml++ 私有);测试补链 isa(自身断言用)
- 验证:20 用例字节不变(hash 0xc3fe4ae74ad45900 相同)、ctest 12/12、缺 --machine 报错退出
This commit is contained in:
2026-08-21 22:14:29 +08:00
parent 44b5ecd46d
commit 447a8d0119
15 changed files with 739 additions and 390 deletions
+36
View File
@@ -0,0 +1,36 @@
/**
* @file Codec.h
* @brief 指令字编解码 + 配置驱动反汇编(编译器侧)
* @author
* @date 2026-08-21
*
* @details 编译器不依赖 isa:指令字布局([op:8|rd:8|a:8|b:8] 小端)与
* 反汇编输出(按 machine.toml 的 format/参数名)全部由本模块 + MachineConfig 提供,
* 保证与执行器(isa)产生的字节一致。
*/
#pragma once
#include <cstddef>
#include <cstdint>
#include "compiler/MachineConfig.h"
namespace compiler {
// 指令字:[op:8 | rd:8 | a:8 | b:8],小端 u32
typedef uint32_t Instr;
Instr pack(uint8_t opcode, uint8_t rd, uint8_t a, uint8_t b);
uint8_t op_of(Instr w);
uint8_t rd_of(Instr w);
uint8_t a_of(Instr w);
uint8_t b_of(Instr w);
uint16_t imm16_of(Instr w); // a|b 拼 u16const_id / slot / fn_id
int16_t off16_of(Instr w); // a|b 有符号偏移(相对下一条)
// 配置驱动反汇编:按 machine.toml 的 format 输出一行文本。
// 未知操作码 → "??? 0x<hex>"。输出格式与 Doc/isa/指令与映像.md 一致。
void disasm(const MachineConfig& cfg, Instr w, char* out, size_t cap);
}
+4 -2
View File
@@ -12,14 +12,16 @@
#include <vector>
#include "compiler/Linker.h"
#include "compiler/MachineConfig.h"
#include "compiler/Parser.h"
#include "compiler/Project.h"
namespace compiler {
// 编译工程为 .stb 映像字节(在链接 + 类型检查成功后调用)。
// 指令 opcode / 类型 tag / FB 布局全部来自 machine.tomlcfg)。
// 失败返回 falseerr 前缀 "codegen error"。
bool codegen_project(const Project& proj, const std::vector<SourceUnit>& units,
const LinkResult& link, std::vector<uint8_t>* image,
std::string* err);
const LinkResult& link, const MachineConfig& cfg,
std::vector<uint8_t>* image, std::string* err);
}
+11 -4
View File
@@ -11,10 +11,17 @@
#include <string>
#include <vector>
#include "isa/Image.h"
namespace compiler {
// I/O 绑定(project.toml [[io.*]];不创造变量,slot 由链接结果解析)
struct IoBinding {
std::string var;
uint32_t slot = 0;
uint32_t channel = 0;
uint32_t bit = 0;
bool is_input = false; // true = [[io.input]]false = [[io.output]]
};
// 与 Doc/初步计划.md 12.1 的 toml 字段表一一对应。
// 字段白名单 / 必填 / io 完整性在 parse_project 内校验。
struct Project {
@@ -24,7 +31,7 @@ namespace compiler {
uint32_t dt_ms = 0; // 必填 > 0
std::vector<std::string> files_st; // [files] 必填非空
std::string gvl_file; // [gvl] 可选;无则空串
std::vector<isa::IoBinding> io; // [[io.*]] 可选;slot 12.6 才解析,此处填 0
std::vector<IoBinding> io; // [[io.*]] 可选;slot 12.6 才解析,此处填 0
std::string base_dir; // toml 所在目录(解析相对路径用)
};
@@ -37,6 +44,6 @@ namespace compiler {
std::vector<std::string> compile_files(const Project& p);
// 校验全部文件存在并计算工程哈希:集合按路径排序,对内容做 FNV-1a 64 增量;
// 空集合 = basisisa::kFnvBasis)。缺文件报错前缀 "file missing"。
// 空集合 = basisStb::kFnvBasis)。缺文件报错前缀 "file missing"。
bool compute_project_hash(const Project& p, uint64_t* hash, std::string* err);
}
+103
View File
@@ -0,0 +1,103 @@
/**
* @file Stb.h
* @brief 编译器自带的 .stb 映像规范(写侧)+ 只读视图 + FNV-1a
* @author
* @date 2026-08-21
*
* @details 执行器(vm)各有自己的读写实现;格式契约见 Doc/isa/指令与映像.md。
* 12.13 修订(型号标识[32] 头 104 字节 + SHA-256 文件尾)在后续步骤落地。
*/
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>
#include "compiler/Project.h"
namespace compiler {
// ---- .stb 格式常量(契约)----
static const uint32_t kMagic = 0x43545353u; // "STSC" 小端
static const uint32_t kVersion = 1;
static const size_t kHeaderSize = 72;
static const size_t kConstEntrySize = 12;
static const size_t kFuncRowSize = 12;
static const uint64_t kFnvBasis = 0xcbf29ce484222325ull;
static const uint64_t kFnvPrime = 0x100000001b3ull;
// 常量表一行(tag0=BOOL、1=INT、2=TIME,契约)
struct ConstEntry {
uint32_t tag = 0;
uint64_t value = 0;
};
// FNV-1a 64(工程哈希,非密码学)
uint64_t fnv1a64_update(uint64_t h, const uint8_t* data, size_t len);
uint64_t fnv1a64(const uint8_t* data, size_t len);
// 只读视图(--disasm 用;校验魔数/版本/段边界)
class StbView {
public:
struct FuncRow {
uint32_t nregs = 0;
uint32_t code_offset = 0;
uint32_t code_len = 0;
};
static StbView from(const uint8_t* buf, size_t len);
static StbView from(const std::vector<uint8_t>& buf);
bool ok() const { return ok_; }
const std::string& error() const { return err_; }
uint32_t cycle_limit() const { return cycle_limit_; }
uint32_t dt_ms() const { return dt_ms_; }
uint64_t project_hash() const { return project_hash_; }
uint32_t entry_fn_id() const { return entry_fn_id_; }
uint32_t n_globals() const { return n_globals_; }
uint32_t n_consts() const { return n_consts_; }
uint32_t n_funcs() const { return n_funcs_; }
uint32_t offset_code() const { return offset_code_; }
uint32_t offset_fb() const { return offset_fb_; }
uint32_t offset_data() const { return offset_data_; }
ConstEntry const_entry(size_t i) const;
FuncRow func_row(size_t i) const;
const uint8_t* code_bytes() const;
size_t code_len() const;
const uint8_t* data_bytes() const;
size_t data_len() const;
private:
StbView() : buf_(0), len_(0) {}
uint32_t offs_of_const() const; // offset_constfrom 已校验段起点)
const uint8_t* buf_;
size_t len_;
bool ok_ = false;
std::string err_;
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_consts_ = 0;
uint32_t n_funcs_ = 0;
uint32_t offset_code_ = 0;
uint32_t offset_fb_ = 0;
uint32_t offset_data_ = 0;
};
// 文件读写(纯字节;校验交给 StbView)
bool read_stb_file(const char* path, std::vector<uint8_t>* out, std::string* err);
bool write_stb_file(const char* path, const std::vector<uint8_t>& img, std::string* err);
// sidecar 生成与写文件(I/O 绑定 var → 槽号 → channel/bit
std::string make_sidecar(const std::vector<IoBinding>& bindings);
bool write_sidecar_file(const char* path, const std::vector<IoBinding>& bindings,
std::string* err);
}