- 指令与映像.md 冻结:头字段表、常量表/函数表行、段序、数据段对齐、sidecar 格式 - Types.h 补 TypeTag;Image.h/cpp:ImageView 校验、write_ret_main、文件与 sidecar - isa CMake 改 target_include_directories PUBLIC
8.1 KiB
指令与映像
isa 模块规范:指令集 + 映像 + 定宽类型。不是编译器,不把 .st 编成映像。
compiler 按本文件写出字节,vm 只认这些字节。两边不互链。
全工程定案见 初步计划.md。类型、指令编码、映像布局以本文为准,不要另写一份互相打架的表。头文件实现本文,不另当规范。
STCompiler → compiler → isa
BytecodeExecutor → vm → isa
CMake 目标:isa(STATIC),无依赖。公开头:isa/include/isa/。
做 / 不做
做
- 操作码与 32 位指令布局
- 映像头与段(函数字节码、全局 / FB 槽、工程哈希)
BOOL/INT/TIME宽度与溢出规则- 编解码、工程哈希、一条指令的文本转储(反汇编,给 STCompiler
--disasm与测试打印)
不做
- toml 字段、关键字表、符号表、AST
- 扫描周期循环、I/O 采样
- 短路语义(
AND/OR指令只组合已算好的值;短路由compiler编成跳转)
指令表可作为内部 IR 的文本形态,不必当主语言。
特性
| 项 | 第一版 |
|---|---|
BOOL |
uint8_t,只允许 0/1 |
INT |
int16_t(IEC INT) |
TIME |
int64_t 毫秒(有符号);与 INT 不混用 |
| 整数溢出 | 饱和(夹到 INT 最小/最大) |
| 字节序 | 小端 |
| 指令宽度 | 32 bit,一种主布局 |
| 寄存器 | 下标 0..255;每函数实际个数写在函数头 nregs |
| 跳转 | 相对 offset,单位是指令条数,不是字节 |
CALL |
立即数 fn_id(u16),无函数指针 |
| 映像魔数 | STSC,版本 1 |
| 工程哈希 | 源文件路径排序后对内容做 FNV-1a 64(非密码学) |
| I/O 绑定 | 不进映像;编译期把 var 收成槽号,channel/bit 由 STCompiler 写进 sidecar(.runtime.toml),BytecodeExecutor 读 sidecar 采样 |
| 不做 | REAL、隐式宽化 |
类型
C++11 定宽:
BOOL:uint8_t,0/1INT:int16_t;加减乘除溢出饱和TIME:int64_t毫秒,有符号
compiler 与 vm 都按同一规则,不再另选溢出策略。
TIME 选 int64_t 的理由(冻结,不再反复问):
- 有符号:
TOF剩余时间、两个时间点相减会出负值,免去无符号边界处理 - 64 位:为将来
DATE_AND_TIME(毫秒时间戳)与TON/TOF/TP的 64 位定时器预留;毫秒量程约 2.9 亿年,扫描周期场景永不溢出 - 代价:槽位 8 字节对齐。槽位对齐规则:
BOOL1 字节、INT2 字节、TIME8 字节;连续排列按类型对齐,需要时插 padding,偏移以本规则为准。
指令
定宽 32 bit:
[ op:8 | rd:8 | a:8 | b:8 ]
- 三寄存器:
a/b为ra/rb(MOVE/NOT只用rd+a) LOADK:a|b为const_id(u16)JMP/JT/JF:a|b为有符号相对 offset(指令条数)CALL:a|b为fn_id(u16)
操作码一次列全(CMP_xx 冻下面六种):
MOVE rd, rs
LOADK rd, const_id
NOT rd, rs
AND/OR rd, ra, rb (* 已算好的值;短路用跳转 *)
ADD/SUB/MUL/DIV rd, ra, rb
CMP_EQ/NE/LT/LE/GT/GE rd, ra, rb
JMP offset
JT/JF r, offset
LOAD_I / STORE_Q / LOAD_M / STORE_M
LOAD_GLOBAL / STORE_GLOBAL
CAL_TON / CAL_TOF / CAL_CTU
CALL fn_id
RET
局部 / VAR = 固定寄存器;表达式临时值往后编号;nregs 写进函数头。
I/Q/M 走映像指令,不是通用寄存器。
FB 实例固定布局,字段偏移编译期算死。
反汇编格式(disasm)
disasm 输出一条指令的一行文本,格式冻结:
| 形态 | 格式 | 示例 |
|---|---|---|
| 二寄存器 | MOVE rd, rs / NOT rd, rs |
MOVE r1, r2 |
| 三寄存器 | OP rd, ra, rb(逻辑 / 算术 / 比较) |
ADD r1, r2, r3 |
| 常量 | LOADK rd, imm |
LOADK r0, 3 |
| 无条件跳转 | JMP off |
JMP +4 |
| 条件跳转 | JT rd, off / JF rd, off |
JT r0, -1 |
| I/Q/M/全局 | LOAD_I rd, slot 等;STORE 同形 STORE_Q rs, slot |
LOAD_I r0, 2 |
| FB 内置 | CAL_TON instance 等 |
CAL_TON 0 |
| 调用 | CALL fn_id |
CALL 1 |
| 返回 | RET |
RET |
| 未知操作码 | ??? 0x<hex> |
— |
跳转偏移带符号、恒显正负号(%+d);寄存器一律 r<n>;常量/槽号/fn_id 无符号十进制。
映像
魔数 STSC,版本 1。全部整数小端。文件 = 头 + 五个段,段序:常量表 → 函数表 → 字节码 → FB 布局 → 数据。偏移记在头里,段必须连续、偏移单调不减,末段终点不超过文件长度。
头(72 字节)
| 偏移 | 宽 | 字段 |
|---|---|---|
| 0 | 4 | 魔数 STSC |
| 4 | 4 | 版本 1 |
| 8 | 4 | cycle_limit |
| 12 | 4 | dt_ms |
| 16 | 8 | 工程哈希(FNV-1a 64) |
| 24 | 4 | 入口 entry_fn_id |
| 28 | 4 | 全局槽数 n_globals |
| 32 | 4 | I 槽数 n_i |
| 36 | 4 | Q 槽数 n_q |
| 40 | 4 | M 槽数 n_m |
| 44 | 4 | 常量数 n_consts |
| 48 | 4 | 函数数 n_funcs |
| 52 | 4 | offset_const |
| 56 | 4 | offset_funcs |
| 60 | 4 | offset_code |
| 64 | 4 | offset_fb |
| 68 | 4 | offset_data |
常量表一行(12 字节)
[tag:u32][value:u64];tag:0=BOOL、1=INT、2=TIME。value 按 tag 解释,未用高位为 0。
函数表一行(12 字节)
[nregs:u32][code_offset:u32][code_len:u32];行下标即 fn_id,code_offset 相对字节码段起点,code_len 为指令条数。
字节码段
指令按 u32 连续排;CALL 的 fn_id 是函数表行下标。
FB 布局段
第一版为空;每类型一行 [field_count:u32][field_count × (tag:u32, offset:u32)],offset 相对实例基址,12.8 落地 codegen 时冻精确表。
数据段
槽初值按序排:全局(n_globals)→ I → Q → M。槽宽与对齐:BOOL 1 字节 / INT 2 字节 / TIME 8 字节,每个槽起点对齐到自身宽度(需要时插 padding)。
工程哈希:收录源文件路径排序后对内容做 FNV-1a 64,只保证回放槽位一致,不是密码学哈希。FNV-1a 64:basis 0xcbf29ce484222325,prime 0x100000001b3。
[[io.input]] / [[io.output]] 不进映像。
映像文件(.stb)与 sidecar
编译产物是单文件 <name>.stb:映像头 + 各段按本文布局连续排,魔数 STSC、版本 1、小端。STCompiler 写,BytecodeExecutor 读。
dt_ms/cycle_limit在映像头,执行器只认映像,不重复配置。- I/O 绑定不进映像:
STCompiler另写 sidecar<name>.runtime.toml,BytecodeExecutor读 sidecar 做采样与写回,不创造变量。
sidecar 格式(TOML 子集,冻结):
[[io.input]] # 或 [[io.output]]
var = "I0_0" # 已在 GVL 声明的名字
slot = 1 # 全局槽号(编译期已解析)
channel = 0
bit = 0
每行一个绑定;var 顺序不要求与映像槽序一致(slot 为准)。
目录与 CMake
isa/
CMakeLists.txt
README.md # 代码目录入口,指向本文
include/isa/
Types.h # 宽度、饱和、槽值表示
Op.h # 操作码枚举 + 助记符
Instr.h # 32-bit 打包/拆字段(inline)
Image.h # 头、段、函数表/常量表/FB 布局
Encode.h # 编解码、哈希、反汇编一行
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)。
实现顺序(对齐初步计划 12.0~12.1)
Types.h:三类型 +sat_add等饱和函数(inline 即可)Op.h+Instr.h:枚举与 32-bit 编解码Encode.cpp:encode/decode/disasm一条指令Image.h+Image.cpp:头布局、FNV-1a、读写缓冲(先能写空映像 + 一条RET)- 测试随后在
tests/加编解码往返;本阶段以头文件和库能链为准
不在本模块做:VM switch、toml、关键字、符号表。