先挂 Encode.cpp 和定宽类型别名,规范仍以 Doc 为准。 Co-authored-by: Cursor <cursoragent@cursor.com>
isa
指令集 + 映像 + 定宽类型。CMake 目标:isa(STATIC),无依赖。
compiler 写映像、vm 读映像,两边只依赖本目录,不互链。
host → compiler → isa
host → vm → isa
类型、操作码、指令字、映像布局以 doc/isa/指令与映像.md 为准。 头文件实现该文,本 README 不另当规范。全工程阶段见 doc/初步计划.md 12.0~12.1。
公开头:isa/include/isa/。
做 / 不做
做: 操作码与 32-bit 指令、映像头与段、BOOL/INT/TIME 宽度与饱和、编解码、工程哈希、一条指令的文本转储。
不做: toml、关键字、符号表、AST、VM switch、扫描周期、I/O 采样。AND/OR 只组合已算好的值;短路由 compiler 编成跳转。
实现步骤
原则:先冻合同,再头文件,再 .cpp,再最小测试。每步能编过再进下一步。改编码或映像字段时,先改规范文和本模块,再动 compiler / vm。
目标目录(与规范一致):
isa/
CMakeLists.txt
README.md
include/isa/
Types.hpp # 宽度、饱和、槽值
Op.hpp # 操作码枚举 + 助记符声明
Instr.hpp # 32-bit 打包/拆字段(inline)
Encode.hpp # encode / decode / disasm
Image.hpp # 头、段、FNV、读写缓冲
src/
Encode.cpp
Image.cpp
add_library(isa STATIC src/Encode.cpp src/Image.cpp)
target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
compiler / vm:target_link_libraries(... PUBLIC isa)。
0. CMake 骨架
根 CMakeLists.txt 已 add_subdirectory 了 compiler / vm / host。这三个目录若没有 CMakeLists.txt,顶层 configure 失败,isa 也编不过。
本步只让工程能配置、能链,不写业务。
- 写本目录
CMakeLists.txt(上面那段即可) compiler/vm:空.cpp+PUBLIC链isahost:main打印Stator 0.1,链compiler、vm- 根 CMake:
enable_testing()(测试文件下一步再加)
完成:cmake --build 过。
1. 冻合同(先改规范文)
指令与映像.md 已有助记符和 [ op:8 | rd:8 | a:8 | b:8 ],还缺数值和映像字节。头文件不得自己发明一份表。
把下面这些写进规范文,再写代码(细则以该文最终落笔为准):
- 指令字:小端
uint32_t;op/rd/a/b各 8 bit;imm16 = a | (b << 8);off16为有符号、单位是指令条数 - 操作码 0..28 连续赋值,以后只追加不插队
- 各指令操作数字面(
LOADK/JMP/CALL/LOAD_*/STORE_*/CAL_*/RET) INT饱和、INT_MIN / -1、除零、BOOL只允许 0/1- FNV-1a 64 的 basis/prime;路径只当排序键,对文件内容 update;空集合 = basis
- 映像魔数
STSC、版本 1、头字段偏移与长度、常量表/函数表/FB 表一行的字节 - 第一版可写映像:空槽、空常量表/FB、
MAIN(fn_id=0)、一条RET
完成:规范文能当唯一合同;本 README 仍只指向它。
2. Types.hpp
include/isa/Types.hpp,inline,无对应 .cpp。命名空间 isa。C++11,不用 designated initializer。
Bool=uint8_t,Int=int16_t,Time=int32_t(毫秒)TypeTag:Bool/Int/Timesat_add/sat_sub/sat_mul/sat_div(规则见规范文)pack_bool/pack_int/pack_time→ 4 字节 cell;对应 unpack
完成:单独包含该头能编译。
3. Op.hpp + Instr.hpp
Op.hpp:enum Op : uint8_t,取值与规范文一致;声明op_mnemonic(Op)(表可放Encode.cpp)Instr.hpp:typedef uint32_t Instr;pack、取op/rd/a/b、imm16/off16;按形态enc_rr/enc_rrr/enc_imm/enc_jmp/enc_jc
完成:能打包/拆开一条 32-bit 指令,不依赖 .cpp。
4. Encode.hpp + Encode.cpp
给 host 打印和测试往返:
Decoded { Op op; uint8_t rd, a, b; }Instr encode(Decoded)/Decoded decode(Instr)disasm(Instr, char* out, size_t cap)
disasm 格式冻在规范文,例如:RET、MOVE r1, r2、LOADK r0, 3、ADD r1, r2, r3、JMP +4、JT r0, -1、CALL 1、LOAD_I r0, 2、CAL_TON 0。
完成:一条指令能编、能解、能打出一行文本。
5. Image.hpp + Image.cpp
fnv1a64/fnv1a64_updateImageView:只读视图,指向外部缓冲read_image:校验魔数、版本、头大小、各段不越界、entry_fn_id落在函数表内write_ret_main(cycle_limit, dt_ms, hash)→std::vector<uint8_t>:空槽 +MAIN+ 一条RET
小端 put_* / get_* 只放 .cpp,不把 packed struct 当 ABI。本阶段不写完整 ImageBuilder(等 codegen)。
完成:能写出并读回「空映像 + 一条 RET」。
6. 最小测试
在 tests/ 加一个只链 isa 的 CTest 可执行文件(不是第 12.2 节那 20 个用例):
RET/ADD/LOADK/JMP -1:encode 后再 decode,字段一致;disasm非空write_ret_main再read_image:魔数、version=1、n_funcs=1、入口是RETfnv1a64空输入等于 basis
完成:ctest 过上述用例。
验收
cmake --build过;ctest过 isa 往返compiler/vm只#include <isa/...>,不互相包含- 操作码或映像有变:先改
指令与映像.md+ 本目录 + 本测试,再改两端