Files
Interpreter/Doc/isa/指令与映像.md
T

15 KiB
Raw Blame History

指令与映像(V2 规格,STATOR2)

状态:V2 规格(阶段 1 重写)。本文件为指令编码、类型、数据模型、映像格式的 规范,头文件与代码实现本文,不另当规范。 定案依据:阶段1规格总览.md(主参考)、指令编码.md指令集清单.md指令集优化.md。 与 V1 关系:V1(32bit 指令、8 字节定宽槽、STATOR1)已实现并冻结;本文为全新 V2version = 2、型号 STATOR2,老映像被版本/型号校验拒绝。

compiler.stbvm.stb,两边各自实现读写;isa 归执行器侧只管指令定义。 指令 opcode / 类型 / FB 布局的登记见 指令配置.mdcompiler/machine.toml,与代码强校验)。

STCompiler      → compiler        (编码查 machine.toml;自带 .stb 写)
BytecodeExecutor → vm → isa        isa 只管指令;vm 自带 .stb 读)

CMake 目标:isaSTATIC),无依赖;vm PUBLIC 链 isa。公开头:isa/include/isa/


1. 做 / 不做

  • 操作码(前缀分区)与变长指令布局(4/8/16/32B
  • 映像头 128B 与段(常量表 / 函数表 / 字节码 / 槽表段 / 值段 / 元数据段)
  • 19 种 IEC 类型 → 10 种 func 的宽度/符号表、饱和与除法边界
  • 编解码、工程哈希、一条指令的文本转储(反汇编,给 STCompiler --disasm 与测试打印)

不做

  • toml 字段、关键字表、符号表、AST
  • 扫描周期循环、I/O 采样
  • 短路语义(AND/OR 指令只组合已算好的值;短路由 compiler 编成跳转)

指令表可作为内部 IR 的文本形态,不必当主语言。


2. 特性总表(V2

V2 定案
指令宽度 变长 4/8/16/32B,长度与形态由前缀分区表达
前缀 11=RR、10=NONE、011=RRR、010 000..101=IMM/SLOT/JMP/JC/CALL/CAL、0010=SLOT+off / RS+off、0011=IMM64、0001=预留(32B)
头部 字节 0 = [前缀+分区|op];字节 1 = [func:4|空:4](空位延后定)
func 4 位:0..7 = 宽度×符号(1/2/4/8B×有/无)、8=F32、9=F64;无类型指令 = 0
寄存器 编号 8 位(256 = 寻址上限),值 int64每帧按函数头 nregs 动态分配
调用约定 r0 结果、r1..r7 参数(≤7)、r8+ 变量/临时;CALL/RET 复制 r0..r7 全宽(64B
调用栈 预分配栈区(max_stack 编译期算)、帧头 12B、溢出双检查(字节+深度 64);递归 = 编译期报错
跳转 字节单位,相对下一条(目标 = 当前 + off32)
类型 19 IEC 类型 → 10 种 func 编译期映射;禁隐式变量转换
整数溢出 饱和(各宽度模板);除零返回被除数;MIN/-1 饱和;截断除法;MOD 符号随被除数
浮点 IEEE 754(溢出/零除 → ±inf、NaN 传播)
变量访问 **槽表(引用)→ 值区(变宽紧凑)**两级间接;全 32 位寻址
字节序 小端
映像 魔数 STSCversion = 2、型号 STATOR2
工程哈希 源文件路径排序后对内容做 FNV-1a 64(非密码学)
完整性 文件尾 SHA-256[32];型号标识[32]@72
I/O 绑定 不进映像sidecar.runtime.toml)绑定 var→槽号→channel/bit,粒度不变
内建 FB 15 条(CAL + fb_id 16 位);字段布局见 指令集清单.md §8.1

3. 指令编码(详见指令编码.md

指令 = 字节0 + 字节1 + 操作数区(按形态)

字节 0                    字节 1
[长度前缀+形态分区 | op]  [func:4 | 空:4]

3.1 前缀分区与 op 空间

前缀 长度 形态 op 位宽 op 空间 识别
11 4B RR 6 位 64 前缀直推
10 4B NONE 6 位 64 前缀直推
011 8B RRR 5 位 32 前缀直推
010 000 8B IMM 2 位 4 前缀直推
010 001 8B SLOT 2 位 4 前缀直推
010 010 8B JMP 2 位 4 前缀直推
010 011 8B JC 2 位 4 前缀直推
010 100 8B CALL 2 位 4 前缀直推
010 101 8B CAL 2 位 4 前缀直推
010 110/111 8B 预留 2 位 8
0010 16B SLOT+off / RS+off 4 位 16 前缀直推
0011 16B IMM64 4 位 16 前缀直推
0001 32B 预留(N2 4 位 16
  • op 按分区独立编号(0 起);取指:读字节 0 → 前缀定长 → 搬整条
  • uses_rd/uses_ra/uses_rb 全部前缀直推(零查表):RRR 三寄存器全真;RR 的 rd/rsIMM/SLOT/JC/SLOT+off/RS+off/IMM64 的 rdRS+off 另含 rs(基址寄存器);JMP/CALL/CAL/NONE 无

3.2 func 位段(字节 1 高 4 位)

func 语义 覆盖类型
0 1B 无符号 BOOL、BYTE、USINT
1 1B 有符号 SINT
2 2B 无符号 WORD、UINT
3 2B 有符号 INT
4 4B 无符号 DWORD、UDINT、DATE
5 4B 有符号 DINT
6 8B 无符号 LWORD、ULINT、DT、TOD
7 8B 有符号 LINT、TIME
8 F32 REAL
9 F64 LREAL
10..15 预留
  • func 语义随 opMOVE=宽度;LOAD/STORE=宽度×符号;ADD..=宽度×符号+浮点;逻辑=宽度;无类型指令=0
  • 字节 1 低 4 位暂空(N1,延后定)

3.3 操作数区位号(bit16 起;pad = 对齐填充,编码固定 0)

形态 操作数区
RR rd=23..16、rs=31..24
NONE pad=31..16
RRR rd=23..16、rs1=31..24、rs2=39..32、pad=63..40
IMM rd=23..16、imm32=55..24、pad=63..56
SLOT rd=23..16、slot32=55..24、pad=63..56
JMP off32=47..16、pad=63..48
JC rd=23..16、off32=55..24、pad=63..56
CALL fn_id32=47..16、pad=63..48rd 恒 0
CAL fb_id16=31..16、slot32=63..32rd 恒 0
SLOT+off rd=23..16、slot32=55..24、off32=87..56、pad=127..88
RS+off rd=23..16、rs=31..24(基址寄存器)、off32=87..56、pad=127..88
IMM64 rd=23..16、imm64=87..24、pad=127..88

4. 寄存器与调用栈

  • 寄存器编号 8 位:256 为寻址上限(不是每帧分配数);每帧按函数头 nregs 动态分配nregs×8B,百字节级)
  • 寄存器值 int64codegen register overflow (>256) 检查
  • 调用约定:r0 结果、r1..r7 参数(≤7)、r8+ 变量/临时;CALL/RET 复制 r0..r7 全宽(64B);函数输入只读(compiler 拒绝写入)

调用栈(方案 C

  • 递归禁止:链接层调用图环检测(自调用/循环调用)→ 编译期报错 link error: recursive call
  • max_stack:MAIN 帧 + DAG 最坏调用路径 Σ(帧需求),帧需求 = 帧头 12B + nregs×8;写入映像头 @116
  • 预分配栈区:Machine 构造时一次性分配 max_stack 连续内存,运行期零分配
  • 帧结构:帧头 { fn_id:u32, ret_pc:u32, ret_fn_id:u32 }12B+ 寄存器区 nregs×8
  • 压帧:栈顶取帧需求,sp += 需求;弹帧:sp -= 需求
  • 溢出双检查:剩余栈 < 帧需求 → StackOverflow(字节主检查)+ 深度 ≤64(双保险)
  • MAIN 帧常驻栈底(跨周期保留),周期结束回退 sp 到 MAIN 帧顶

5. 类型系统

5.1 19 种 IEC 基础类型(编译期概念 → func 映射)

类型 宽度 符号 func 类型 宽度 符号 func
BOOL 1B 0 LINT 8B 7
BYTE 1B 0 USINT 1B 0
WORD 2B 2 UINT 2B 2
DWORD 4B 4 UDINT 4B 4
LWORD 8B 6 ULINT 8B 6
SINT 1B 1 TIME 8B 有(ms) 7
INT 2B 3 REAL 4B IEEE754 8
DINT 4B 5 LREAL 8B IEEE754 9
DATE 4B 无(天) 4
TOD 4B 无(ms) 4
DT 8B 6
  • 编译器类型检查严格比对(不匹配编译期报错);BOOL 编译器强制 0/1(越界报错)
  • 禁隐式变量转换字面量按上下文适配5 可赋 INT/REAL/DINT…,编译期解释),默认 DINT 兜底
  • 进制前缀 2#/8#/16# 字面量(浮点无前缀)
  • DATE/TOD/DT:v1 不运算(仅存取/比较);DT = u64 {date:32 | tod:32} 拼接(高 32 位日期)

5.2 值表示(寄存器 / 槽统一约定)

类型 寄存器(int64 位模式)
BOOL 低 1 字节(0/1
有符号整数 按 func 宽度符号扩展
无符号/位串 按 func 宽度零扩展
TIME/LREAL/DT 全 64 位
REAL 低 4 字节(float 位模式)

全宽 int64 比较等价于各类型自身比较(编译层保证类型语义)。


6. 指令语义(清单见指令集清单.md)

6.1 数据搬运

  • MOVE rd, rsRR,func=宽度 0..3):寄存器间按宽度搬运(高位清 0),不管符号/浮点
  • LOAD rd, slot / STORE slot, rsSLOTfunc 全矩阵):槽表[slot].addr → 值区按 func 读/写宽度
  • LOADK rd, const_id(IMM,func 全矩阵):常量表条目 8B 原始值,按 func 解释
  • LOAD_OFF rd, slot, off / STORE_OFF slot, off, rs(SLOT+off):字段访问(绝对实例槽,调用点/输出读用)
  • LOAD_PTR rd, rs, off / STORE_PTR rd, rs, offRS+off):基址寻址——rs 寄存器 = 值区地址(实例指针),addr+off 直读值区(FB 共享体函数体内字段访问)

6.2 逻辑与位运算

  • NOTRR)、AND/OR/XOR(RRR):按 func 宽度逐位(BOOL 由编译器保证 0/1)

6.3 算术

  • ADD/SUB/MUL/DIV(RRR,func 全矩阵):整数饱和到 func 宽度 / 浮点 IEEE
  • 整数除法边界(A 定案):除零 → 返回被除数;MIN/-1 → 饱和夹界;截断除法(向零)
  • MOD:符号随被除数(-7 MOD 3 = -1);除零同 DIV
  • NEG/ABS/INC/DEC(RR);浮点单目/舍入(RR,func 8/9);CONVRRfunc = 目标类型)

6.4 比较

  • CMP_EQ..GERRRfunc 全矩阵):按 func 有/无符号、浮点 IEEE(NaN 传播)

6.5 控制流

  • JMP off32:pc += off(字节,相对下一条);JT/JF rd, off:条件跳转
  • CALL fn_id(rd 恒 0):压帧(复制 r0..r7 全宽);RET:弹帧 / MAIN 周期结束
  • CAL fb_id, slot(rd 恒 0):内建 FB 调用,fb_id 查 fb
  • 周期指令计数:每条 +1,超 cycle_limitCycleLimit 故障

6.6 内建 FB15 条)

fb_id FB fb_id FB
0 TON 7 CTUD
1 TOF 8 DCTUD
2 TP 9 R_TRIG
3 CTU 10 F_TRIG
4 DCTU 11 SR
5 CTD 12 RS
6 DCTD 13 PWM
14 RTC

字段布局(类型化 + 对齐 1/2/4/8 + 偏移)见 指令集清单.md §8.1。 RTC 时钟源 = 虚拟时钟(周期计数 × dt_ms,确定性,不读系统时钟)。


7. 数据模型:槽表 → 值区

槽表段(静态引用表,8B/条)            值段(初值,紧凑变宽)
{ addr:u32, 预留:u32 }  ──地址──▶      BOOL 1B / INT 2B / DINT·REAL 4B / TIME·LREAL 8B
槽 0..n_slots-1                        结构体 = 连续字段块(v1 预留)
  • 访问LOAD rd, slotaddr = 槽表[slot].addr → 值区按 func 读宽度;字段访问 LOAD rd, slot, offaddr + off
  • 两级间接:每次访问多一次内存读(PLC 规模无感)
  • 对齐:1/2/4/8B,编译器布局保证;值段起点 16 对齐
  • 初值:编译期写值段(变量初值、FB 实例字段 0);运行时拷贝工作副本,文件只读
  • 寻址:槽号 u32(2^32 引用)、值区地址 u324GB)
  • 槽表分配:n_slots = n_globals(全局声明序)+ FB 实例/字段槽数

8. 映像格式

8.1 头(128 字节,16 对齐)

偏移 字段 说明
0 magic STSC(不变)
4 version = 2V1 = 1
8 cycle_limit 每周期指令数上限
12 dt_ms 周期时长(毫秒)
16 project_hash FNV-1a 64
24 entry_fn_id 入口函数(MAIN
28 n_globals 全局槽数
32/36/40 n_i / n_q / n_m 保留恒 0V1 遗产,兼容/将来语义)
44 n_consts 常量表条目数
48 n_funcs 函数表行数
52/56/60 offset_const / funcs / code 段偏移
64 offset_slots 槽表段偏移
68 offset_values 值段偏移(16 对齐)
72..103 型号标识[32] STATOR2name+version 补零)
104 n_slots 槽表条目数(= n_globals + 实例/字段槽数)
108 values_size 值段字节数
112 offset_meta 元数据段偏移(v1 = 0 空段)
116 max_stack 栈区字节数(编译期算)
120..127 预留 8 字节

8.2 段序

头(128) → 常量表(8B/条) → 函数表(12B/行) → 字节码(16 对齐) →
槽表段(8B/条) → 值段 → 元数据段(v1 空) → SHA-256[32]

8.3 段细节

  • 常量表行(8B:原始 64 位值(无 tag),LOADK 按 func 解释,按位模式去重
  • 函数表行(12B{ nregs:u32, code_offset:u32(字节), code_len:u32(字节) }
  • 槽表行(8B{ addr:u32, 预留:u32 }
  • 值段:全局块 + FB 实例块(1/2/4/8 对齐,编译器布局)
  • 元数据段v1 0 长度(offset_meta = 0
  • 文件尾SHA-256[32](对去掉尾的内容计算)

8.4 校验(vm 读侧)

  1. 结构校验:魔数/版本/段偏移单调且在 SHA 前/常量表·函数表尺寸一致/代码段对齐/入口 fn_id 范围
  2. SHA-256:完整性(防篡改)
  3. 型号匹配STATOR2name + version=2 补零 32 字节逐字节比对)

9. .stb 与 sidecar

  • <name>.stb(映像)+ <name>.runtime.tomlsidecar[[io.input]]/[[io.output]]var→slot→channel/bit
  • I/O 绑定不进映像;绑定粒度 slot = 槽号(指向槽表条目),channel/bit 语义不变
  • executor 按 sidecar 采样 I / 写回 Qdt_ms/cycle_limit 从映像头取

10. 反汇编格式(A7 定案)

按 func 显示类型后缀

LOAD.I16 r5, s3      STORE.U32 s1, r7     ADD.F64 r1, r2, r3
MOVE r1, r2          LOAD_OFF.I8 r4, s2, 8
JMP +4                JT r0, -1            CALL 1               CAL.TON s5

前缀分区决定打印模板;010 区/16B 区按形态直推。


11. 目录与 CMake

isa/
  CMakeLists.txt
  README.md
  include/isa/
    Types.h                 # 宽度/符号/饱和、除零边界
    Op.h                    # 前缀分区 + 操作码 + 形态
    Instr.h                 # 变长 pack/拆字段(inline
    Encode.h                # encode / decode / disasm
  src/
    Encode.cpp
add_library(isa STATIC src/Encode.cpp)
target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)

vmtarget_link_libraries(vm PUBLIC isa)compiler 不链 isa


12. 实现约定

  • machine.tomlV2 schema)与代码强校验:前缀分区/op/func 互锁(见指令配置.md,阶段 1 重写)
  • 操作码有变:先改 machine.toml + 本目录 + 测试,再动两端
  • 错误类别:isa 层无错误前缀(编解码纯函数);vm/compiler 各自带前缀