# stvm **Repository Path**: galaxy_0/stvm ## Basic Information - **Project Name**: stvm - **Description**: STVM(Structured Text Virtual Machine)是一款专为工业物联网与边缘计算场景设计的轻量级 IEC 61131-3 结构化文本(ST)语言虚拟机。 - **Primary Language**: C++ - **License**: GPL-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-10 - **Last Updated**: 2026-09-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # STVM — ST 虚拟机 面向嵌入式设备的 ST(Structured Text)语言字节码虚拟机。 ## 开源版本特性 - **双语法前端**: - 旧 ST 语法子集(Flex + Bison) - **IEC 61131-3 ST 语法**(手写词法/语法分析器):`FUNCTION` / `FUNCTION_BLOCK` / `PROGRAM` / `TYPE` / `STRUCT` / `ARRAY` / `ENUM` 等 - **40 条指令 ISA**:栈式字节码指令集,基础 28 条(数据搬运、算术、逻辑比较、流程控制、系统调用)+ IEC 扩展 12 条(函数调用、结构/数组寻址、类型转换、栈帧管理) - **确定性 PLC 扫描执行器**:指令配额限制 + 标准 PLC 顺序扫描,符合 IEC 61131-3 循环执行模型 - **CPU 亲和性绑定**:将调度器绑定到指定 CPU 核心,消除缓存抖动和时序不确定性,保证 PLC 程序的确定性执行 - **系统调用表**:TON / TOF / CTU / CTD / SR / RS / R_TRIG / F_TRIG / TP / CTUD 十个内建功能块(多输出 + 持久化状态,支持 IEC 61131-3 实例语义) - **IEC 内建函数库**:~30 个已实现(数学 12 + 位操作 4 + 选择 3 + 字符串 9 + 时间 4 + 比较 6),通过 `CALLB` 指令调用 - **AT %* 地址定位**:支持 `%I`/`%Q`/`%M` 三大 I/O 区域的位/字节/字/双字访问 - **调试支持**:VM 错误报告自动附加源码行号(`[line N]`);`STVM_TRACE=1` 启用指令级执行追踪 - **CRC32 校验**:字节码文件带校验和,防止传输损坏 - **C/C++ 双 API**:提供 C 一站式接口与 C++ 完整 API - **跨平台构建**:Linux / WSL / macOS(Flex+Bison)与 Windows / MSVC(win_flex+win_bison 或预生成文件) ## 商业版特性 - **单步执行** - **查看调用栈** - **查看数据** - **载入源码自动编译成字节码** - **断点功能** - **观察点功能** - **自动编译成字节码** - **CLI 命令行调试器** - **websocket远程调试器** - **openplc runtime v4兼容 ws调试协议** ## 支持的 ST 语法 项目同时支持两套语法前端,编译器按输入文件扩展名自动选择(`.st` → 旧 ST,`.iec`/`.stc`/`.iecst` → IEC),也可用 `--iec` 强制 IEC 模式。 ### 旧 ST 语法子集(`*.st`) | 类别 | 语法 | | :--- | :--- | | 数据类型 | `BOOL` `INT` `REAL` `TIME` `ARRAY[N] OF` | | 语句 | `IF-ELSIF-ELSE` `FOR-TO-BY-DO` `WHILE-DO` `CASE` 赋值 | | 功能块 | `TON(IN,PT)` `TOF(IN,PT)` `CTU(CU,PV)` `CTD(CD,PV)` `SR(S1,R)` `RS(S,R1)` `R_TRIG(CLK)` `F_TRIG(CLK)` `TP(IN,PT)` `CTUD(CU,CD,PV)` | | 运算符 | `+ - * / MOD **` `= <> > < >= <=` `AND OR NOT XOR` | | 字面量 | 整型 `42`、实型 `3.14`、布尔 `TRUE/FALSE`、时间 `T#1ms` `T#100us` `T#2s` | | 注释 | `(* 块注释 *)` 和 `// 行注释` | ### IEC 61131-3 ST 语法(`*.iec`) | 类别 | 语法 | | :--- | :--- | | POU | `PROGRAM` `FUNCTION` `FUNCTION_BLOCK`(含 `END_*` 终结) | | 变量声明 | `VAR` `VAR_INPUT` `VAR_OUTPUT` `VAR_TEMP` `END_VAR` | | 数据类型 | `BOOL` `BYTE` `WORD` `DWORD` `LWORD` `SINT` `INT` `DINT` `LINT` `USINT` `UINT` `UDINT` `ULINT` `REAL` `LREAL` `TIME` `STRING` `WSTRING` | | 派生类型 | `TYPE ... : ARRAY[...] OF ...;` `STRUCT ... END_STRUCT` `ENUM` `SUBRANGE` `ALIAS` | | 语句 | `IF-ELSIF-ELSE` `FOR-TO-BY-DO` `WHILE-DO` `REPEAT-UNTIL` `CASE-OF-ELSE` 赋值 `;` | | 运算符 | `+ - * / MOD **` `= <> > < >= <=` `AND OR NOT XOR` | | 函数调用 | 用户自定义 `FUNCTION` 递归调用 + ~20 个已实现内建函数(`ABS` `MAX` `MIN` `LIMIT` `SQRT` `SHL` `SHR` `ROL` `ROR` ...),字符串/时间函数占位 | | 功能块实例 | 10 个标准 FB:`TON` `TOF` `CTU` `CTD` `SR` `RS` `R_TRIG` `F_TRIG` `TP` `CTUD`,支持 IEC 61131-3 实例模式:`VAR trig : R_TRIG; END_VAR` → `trig(CLK := x);` → `q := trig.Q;` | | 字面量 | 整型、实型、布尔、时间 `T#1ms`、字符串 `'abc'` | | 注释 | `(* 块注释 *)`、`/* 块注释 */` 和 `// 行注释` | ## 快速开始 ### 环境要求 - **C++17** 编译器(g++ 9+, clang 10+, MSVC 2019+) - **CMake 3.15+** - **Flex 2.6+** 和 **Bison 3.5+**(Linux/WSL/macOS 用 `flex`/`bison`;Windows 用 `win_flex`/`win_bison`) - 若环境中没有 Flex/Bison,可使用源码树中 `src/parser/generated/` 的预生成文件回退(需曾用 Flex/Bison 构建过一次以生成该目录) - 可选:**cpp-misc-lib**(wheels,用于日志/定时器/锁等) ### 构建(Linux / WSL / macOS) ```bash # 安装依赖 sudo apt install flex bison cmake g++ # Debian/Ubuntu # sudo yum install flex bison cmake gcc-c++ # RHEL/CentOS # 配置 cmake -S . -B build # 构建 cmake --build build -j$(nproc) # 运行测试 ctest --test-dir build --output-on-failure ``` ### 构建(Windows / MSVC) 仓库附带 `build.ps1` 脚本,使用 NMake Makefiles + VS DevShell: ```powershell # 需先安装 win_flex / win_bison 并加入 PATH,或使用预生成文件 ./build.ps1 ``` 也可手动调用 CMake(需在 VS Developer 命令行中): ```powershell cmake -S . -B build -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release cmake --build build --parallel ``` ### 构建选项(CMake) | 选项 | 默认 | 说明 | | :--- | :--- | :--- | | `STVM_BUILD_TOOLS` | `ON` | 构建 CLI 工具(stvmc / stvm-run / stvm-disasm) | | `STVM_BUILD_TESTS` | `ON` | 构建单元/集成测试 | | `STVM_USE_CPP_MISC` | `OFF` | 启用 cpp-misc-lib 集成 | | `STVM_BUILD_SHARED` | `OFF` | 构建动态库(默认静态库) | | `CPP_MISC_LIB_DIR` | - | cpp-misc-lib 根目录路径 | ### 启用可选依赖 ```bash # 启用 cpp-misc-lib cmake -S . -B build -DSTVM_USE_CPP_MISC=ON -DCPP_MISC_LIB_DIR=/mnt/e/work/wheels/C++ ``` ## 使用示例 ### 编译 ST / IEC 源码 ```bash # 编译旧 ST 语法 ./build/stvmc tests/integration/samples/assign_for.st -o output.bytecode # 编译 IEC 61131-3 语法(按 .iec 扩展名自动识别) ./build/stvmc tests/integration/samples/simple_iec.iec -o output.bytecode # 编译并查看反汇编 ./build/stvmc tests/integration/samples/assign_for.st -o output.bytecode -v # 强制 IEC 模式(不论扩展名) ./build/stvmc program.txt --iec -o output.bytecode ``` `stvmc` 选项:`-o ` 输出路径、`-v` 编译后打印反汇编、`--iec` 强制 IEC 模式、`-h/--help` 帮助。 ### 运行字节码 ```bash # 单任务运行,运行后打印所有变量 ./build/stvm-run output.bytecode --dump # 运行前先打印反汇编 ./build/stvm-run output.bytecode --disasm # 多任务调度(标准 PLC 顺序扫描,按任务列表逐周期轮询执行) ./build/stvm-run output.bytecode --task main=1ms:100 --task bg=10ms:50 # 限制最大调度轮数 ./build/stvm-run output.bytecode --max-cycles 1000 --dump ``` `stvm-run` 选项:`--task NAME=PERIOD:QUOTA`(周期支持 `1ms`/`100us`/`0`一次性)、`--max-cycles N`、`--dump` 打印变量、`--disasm` 运行前反汇编、`--affinity N` 绑定 CPU 核心(可选)、`-h/--help`。 ### 反汇编 ```bash ./build/stvm-disasm output.bytecode ``` ### ST 源码示例 ```iecst PROGRAM assign_for VAR i : INT; sum : INT; END_VAR sum := 0; FOR i := 1 TO 10 DO sum := sum + i; END_FOR; END_PROGRAM ``` 运行结果:`sum = 55` ### IEC 61131-3 源码示例 ```iecst (* 嵌套函数调用 + 内建函数 *) FUNCTION Square : INT VAR_INPUT x : INT; END_VAR Square := x * x; END_FUNCTION FUNCTION SumOfSquares : INT VAR_INPUT a : INT; b : INT; END_VAR SumOfSquares := Square(a) + Square(b); END_FUNCTION PROGRAM functions VAR result : INT; abs_val : INT; big : INT; clamped : INT; END_VAR result := SumOfSquares(3, 4); (* 9 + 16 = 25 *) abs_val := ABS(-7); (* 7 *) big := MAX(10, 20); (* 20 *) clamped := LIMIT(0, 100, 50); (* 50 *) END_PROGRAM ``` ### IEC 61131-3 功能块实例化示例 ```iecst (* LD/FBD 工程导出 ST 示例:多功能块实例 *) PROGRAM fb_demo VAR button : BOOL; timer : BOOL; up_btn : BOOL; down_btn: BOOL; (* FB 实例声明 *) rise : R_TRIG; (* 上升沿检测 *) fall : F_TRIG; (* 下降沿检测 *) ton_dly : TON; (* 延时接通 *) counter : CTUD; (* 双向计数 *) (* 输出变量 *) rise_q : BOOL; fall_q : BOOL; ton_q : BOOL; ton_et : TIME; ctud_qu : BOOL; ctud_qd : BOOL; ctud_cv : INT; END_VAR (* FB 实例调用:输入按名赋值 *) rise(CLK := button); fall(CLK := button); ton_dly(IN := timer, PT := T#100ms); counter(CU := up_btn, CD := down_btn, PV := 10); (* 读取 FB 输出成员 *) rise_q := rise.Q; fall_q := fall.Q; ton_q := ton_dly.Q; ton_et := ton_dly.ET; ctud_qu := counter.QU; ctud_qd := counter.QD; ctud_cv := counter.CV; END_PROGRAM ``` > **注意**:功能块为实例化设计,每个变量声明独立的持久化状态。在 PLC 循环扫描中,每个周期执行一次 FB 调用即可正确更新状态。状态跨周期保持(上升沿/下降沿检测、计时器、计数器均按 IEC 61131-3 标准行为工作)。 ### C++ API 集成 ```cpp #include "stvm.h" #include "stvm/platform/cpu_affinity.hpp" // 编译(旧 ST 模式) stvm::StCompiler compiler; stvm::BytecodeProgram prog; std::string err; compiler.compileToProgram("task.st", prog, err); // 编译 IEC 模式 stvm::BytecodeProgram iec_prog; compiler.compileIecToProgram("task.iec", iec_prog, err); // 或从字符串编译 compiler.compileIecString("PROGRAM main VAR x : INT; END_VAR x := 1; END_PROGRAM", iec_prog, err); // 运行(标准 PLC 顺序扫描) stvm::SyscallTable syscalls; stvm::Scheduler sched; sched.setSyscallTable(&syscalls); // 配置 CPU 亲和性(可选,绑定到指定核心保证确定性执行) // 仅在实时 PLC 部署环境中需要,桌面开发可省略 sched.config().cpu_affinity = 2; // 绑定到第 3 个逻辑核心(0-based) // 添加任务:周期 1ms,每周期执行 100 条指令 sched.addTask("main", prog, 1000, 100); sched.runUntilDone(); ``` > **CPU 亲和性说明**:`cpu_affinity` 仅在首次调用 `runOnce()` 时生效,将调度器绑定到指定 CPU 核心。析构时自动恢复系统默认亲和性。设置为 `-1`(默认)则不绑定,使用系统默认调度。这可以消除操作系统调度器在核心间迁移线程导致的缓存失效和时序抖动,保证 PLC 程序的确定性执行。 ### C API 一站式调用 ```c #include "stvm.h" /* 编译 + 运行(旧 ST 语法) */ stvm_compile_file("task.st", "task.bytecode", NULL, 0); /* 编译 IEC 61131-3 语法 */ stvm_compile_iec_file("task.iec", "task.bytecode", NULL, 0); /* 加载并单次运行 */ stvm_run_file("task.bytecode", 0, NULL, 0); /* 反汇编到 stdout */ stvm_disassemble_file("task.bytecode"); /* 版本号 */ printf("STVM %s\n", stvm_version()); ``` ## 项目结构 ``` stvm/ ├── CMakeLists.txt # 顶层构建脚本 ├── build.ps1 # Windows / MSVC 构建脚本 ├── cmake/FindLibco.cmake # libco 查找模块(可选,已弃用) ├── third_party/ # 第三方依赖 ├── include/ │ ├── stvm.h # 公共 C/C++ API │ └── stvm/ # 内部头文件 │ ├── types.hpp # 基础类型、错误码 │ ├── bytecode.hpp # 指令集、栈值、文件头 │ ├── program.hpp # 字节码程序序列化 │ ├── compiler.hpp # 编译器入口(双模式) │ ├── loader.hpp # 加载器 │ ├── disassembler.hpp # 反汇编 │ ├── bytecodeGen.hpp # 旧 ST 字节码生成器 │ ├── symbolTable.hpp # 旧 ST 符号表 │ ├── TypeChecker.hpp # 旧 ST 类型检查 │ ├── IecCodegen.hpp # IEC 代码生成器 │ ├── IecSymbolTable.hpp # IEC 符号表 │ ├── IecTypeChecker.hpp # IEC 类型检查 │ ├── iecTypes.hpp # IEC 类型系统 + 内建函数表 │ ├── ast/ # AST 节点(ASTNode / ASTNodeExt) │ ├── iec/ # IEC 词法/语法分析器(IecLexer / IecParser) │ ├── vm/ # 虚拟机(vm.hpp / context.hpp) │ ├── scheduler/ # 调度器(scheduler.hpp / task.hpp) │ ├── platform/ # 平台抽象(cpu_affinity.hpp) │ └── syscall/ # 系统调用(syscall.hpp) ├── src/ # 实现文件 │ ├── ast/ # AST │ ├── compiler/ # 编译器入口 │ ├── lexer/ # 词法分析器(st_flex.l / IecLexer) │ ├── parser/ # 语法分析器(st_bison.y / IecParser / generated/) │ ├── semantics/ # 符号表与类型检查(旧 ST + IEC) │ ├── generator/ # 字节码生成器(BytecodeGen / IecCodegen) │ ├── loader/ # 加载器 │ ├── vm/ # VM 执行器 │ ├── scheduler/ # 调度器 │ ├── platform/ # 平台实现(cpu_affinity.cpp) │ ├── syscall/ # 系统调用实现 │ ├── program.cpp # 字节码程序序列化 │ ├── disassembler.cpp # 反汇编 │ └── stvm_api.cpp # 公共 C API 实现 ├── tools/ # CLI 工具 │ ├── stvmc/ # 编译器(.st/.iec → .bytecode) │ ├── stvm-run/ # 运行器 │ └── disassembler/ # 反汇编器 ├── tests/ # 测试 │ ├── unit/ # 单元测试(test_bytecode / test_vm / test_cpu_affinity) │ ├── bench/ # 基准测试(bench_perf.cpp / test_fb_cycles.cpp) │ └── integration/ # 集成测试 + samples/*.st / *.iec ├── gram/ # IEC 参考语法(iec_ref_flex.ll / iec_ref_bision.yy,仅作蓝图) └── doc/technical.md # 技术设计文档 ``` ## 指令集(ISA) 指令格式:`1B opcode + 1B flags + 4B operand = 6B` ### 基础指令(28 条) | 编码 | 助记符 | 说明 | | :--- | :--- | :--- | | 0x00 | `NOP` | 空操作 | | 0x01-0x06 | `LDC LDV STV LDVP POP DUP` | 数据搬运 | | 0x10-0x16 | `ADD SUB MUL DIV MOD NEG POW` | 算术运算 | | 0x20-0x28 | `EQ NE GT LT GE LE AND OR XOR` | 逻辑/比较 | | 0x30-0x33 | `JMP JMPT JMPF RET` | 流程控制 | | 0xF0 | `SVC` | 系统调用 | ### IEC 扩展指令(12 条) | 编码 | 助记符 | 说明 | | :--- | :--- | :--- | | 0x40 | `CALLB` | 调用内建函数(operand = BuiltinFunc ID) | | 0x41 | `CALLP` | 调用用户 POU(operand = POU 索引) | | 0x42 | `RETV` | 带返回值返回 | | 0x43 | `LDA` | 加载数组元素地址 | | 0x44 | `LDF` | 加载结构字段 | | 0x45 | `STF` | 存储结构字段 | | 0x46 | `LDX` | 加载数组元素 | | 0x47 | `STX` | 存储数组元素 | | 0x49 | `CATS` | 字符串拼接 | | 0x4A | `CAST` | 类型转换(operand = 目标 IecType) | | 0x4B | `PUSHFrame` | 压入栈帧(operand = 局部变量区大小) | | 0x4C | `POPFrame` | 弹出栈帧 | > 另有 `HALT`(0xFE) 为 VM 内部停机指令,非 ISA 正式成员。 ## 字节码文件格式 文件头 `BytecodeHeader`(26 字节,紧凑布局): | 字段 | 大小 | 说明 | | :--- | :--- | :--- | | magic | 4B | 魔数 `STVM`(0x5354564D) | | version | 2B | 版本号 | | global_size | 4B | 全局变量区大小 | | const_count | 4B | 常量个数 | | code_size | 4B | 字节码段大小(字节) | | entry_point | 4B | 入口地址(字节偏移) | | checksum | 4B | CRC32 校验和(覆盖常量池+代码段) | ## 性能 详细测试报告见 [doc/test-report-2026-08-12.md](doc/test-report-2026-08-12.md)(最新)| [doc/test-report-2026-08-11.md](doc/test-report-2026-08-11.md)。基准测试源码:`tests/bench/bench_perf.cpp`,构建:`-DSTVM_BUILD_TESTS=ON`,运行:`ctest -R bench_perf`。 ### 测试环境 | 项 | x86_64 平台 | ARM64 真机平台 | | :--- | :--- | :--- | | CPU | Intel i7-14700HX(WSL Ubuntu 24.04) | **Cortex-A55 @ 2.4 GHz** | | 编译器 | g++ 13.3.0 (-O3) | Linaro GCC 9.2.1 (-O3) | | 执行模式 | 单任务直接,quota=1e8,1 轮 warmup + 20 轮迭代 | 3 次独立运行取平均 | ### 编译吞吐 | 场景 | 吞吐 | 说明 | | :--- | :--- | :--- | | 进程内编译(C API `compileIecString`) | ~2.3M 行/秒 | 无进程启动开销,适合嵌入式集成 | | stvmc CLI(含启动) | ~1.5M 行/秒(大文件) | 小文件受 ~0.8ms 进程启动主导 | ### 字节码密度 | 程序 | 指令数 | 代码段 | 密度 | | :--- | :--- | :--- | :--- | | loop_sum(FOR 循环求和) | 19 | 114 B | **6 B/指令** | | nested_mul(双重循环) | 32 | 192 B | **6 B/指令** | | branchy(IF/ELSE 分支密集) | 32 | 192 B | **6 B/指令** | 每条指令固定 6 字节(1B opcode + 1B flags + 4B operand),无变长编码,解码零开销。 ### VM 执行吞吐(核心指标) #### x86_64(g++ 13 -O3,i7-14700HX @ 2.3 GHz 基频) | 工作负载 | 指令数/轮 | avg(ms) | **avg MIPS** | best MIPS | | :--- | :--- | :--- | :--- | :--- | | loop_sum(纯循环 + ADD) | 13,000,009 | 37.55 | **346** | 352 | | nested_mul(双层循环 + MUL) | 1,515,009 | 4.41 | **343** | 353 | | branchy(IF/ELSE 分支密集) | 17,500,011 | 49.97 | **350** | 355 | **结论:x86 稳定吞吐 ~343-350 MIPS,峰值 ~355 MIPS,单指令 ~2.8 ns(@ 2.3 GHz 基频)。** > 性能受 CPU 频率调度影响显著。turbo boost 启用时可达 ~500 MIPS。详见测试报告 §5.6。 #### ARM64(Cortex-A55 2.4GHz,真机实测) | 工作负载 | avg MIPS (3 次) | 波动 | 单指令延迟 | | :--- | :--- | :--- | :--- | | loop_sum | 133.79 / 133.73 / 133.67 | ±0.09% | ~7.5 ns | | nested_mul | 131.79 / 131.77 / 131.69 | ±0.05% | ~7.6 ns | | branchy | 137.33 / 137.29 / 137.22 | ±0.05% | ~7.3 ns | **结论:Cortex-A55 真机稳定吞吐 ~131–137 MIPS,波动 ±0.10%,高度稳定。** #### 跨平台对比 | 平台 | loop_sum | nested_mul | branchy | 单指令延迟 | | :--- | :--- | :--- | :--- | :--- | | x86_64 (g++ 13 -O3, @2.3GHz) | 346 MIPS | 343 MIPS | 350 MIPS | ~2.8 ns | | **Cortex-A55 2.4GHz(真机)** | **134 MIPS** | **132 MIPS** | **137 MIPS** | **~7.5 ns** | | qemu 模拟 ARM64(仅功能验证) | 47 MIPS | 48 MIPS | 47 MIPS | ~21 ns | #### 工业控制周期余量 | 控制周期 | x86 可执行指令 | **Cortex-A55 可执行指令** | | :--- | :--- | :--- | | 1 ms | ~350,000 | ~**134,000** | | 10 ms | ~3,500,000 | ~**1,340,000** | 典型 PLC 任务(几千~几万条指令/周期)余量充裕。 #### 内存测试 ```bash root@xxx:/home/stvm# clear && valgrind --leak-check=full ./bench_perf ==11721== Memcheck, a memory error detector ==11721== Copyright (C) 2002-2017, and GNU GPL\`d, by Julian Seward et al. ==11721== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info ==11721== Command: ./bench_perf ==11721== ============================================================ STVM 性能基准测试 iterations : 20 (warmup=1) mode : 单任务直接模式, quota=1e8 ============================================================ ===== [A] 编译性能 (compileIecString, 20 次) ===== workload lines instrs avg(ms) min(ms) KL/s loop_sum 10 19 0.695 0.626 14.4 nested_mul 13 32 0.783 0.760 16.6 branchy 18 32 0.950 0.918 19.0 ===== [B] VM 执行吞吐 (quota=1e8, 单任务直接模式) ===== workload instrs/run min med avg p99 max | best MIPS avg MIPS loop_sum 13000009 4490.27 4501.25 4501.42 4519.20 4519.20 | 2.90 2.89 [CHECK] sum = 500000500000 -> OK nested_mul 1515009 525.78 528.21 528.30 531.36 531.36 | 2.88 2.87 [CHECK] sum = 2527525000 -> OK branchy 17500011 6024.59 6040.87 6040.40 6057.95 6057.95 | 2.90 2.90 [CHECK] acc = -500000 -> OK ============================================================ RESULT: ALL PASSED (0 failures) ============================================================ ==11721== ==11721== HEAP SUMMARY: ==11721== in use at exit: 0 bytes in 0 blocks ==11721== total heap usage: 10,599 allocs, 10,599 frees, 1,195,505 bytes allocated ==11721== ==11721== All heap blocks were freed -- no leaks are possible ==11721== ==11721== For lists of detected and suppressed errors, rerun with: -s ==11721== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) ``` ### 功能块多周期测试 功能块(R_TRIG / F_TRIG / TON / CTUD)的状态持久性与多周期行为由 `tests/bench/test_fb_cycles.cpp` 验证。测试在 9 个扫描周期内注入不同输入序列,使用软重置(仅重置 IP/SP,保留 `global_mem` + `svc_states`)模拟 PLC 循环扫描,校验每个周期的输出是否符合 IEC 61131-3 标准行为。 ```bash # 构建并运行功能块多周期测试 ctest -R test_fb_cycles # 或直接运行 ./build/tests/test_fb_cycles ``` **测试覆盖**: - **R_TRIG**:上升沿检测(clk FALSE→TRUE 时 Q 输出单周期 TRUE) - **F_TRIG**:下降沿检测(clk TRUE→FALSE 时 Q 输出单周期 TRUE) - **TON**:延时接通(IN=TRUE 后延时 PT 微秒 Q 置位,ET 递增) - **CTUD**:双向计数(CU 上升沿递增、CD 上升沿递减、QU/QD 标志位) ## 许可证(双授权 / Dual License) STVM 采用 **GPL v2.0 开源协议 + 商业授权** 的双许可证模式,您可根据自身使用场景自行选择适用条款(二者不可叠加适用)。 ### 一、GPL v2.0(免费开源) 本项目在 GNU General Public License v2.0 下开放源代码,您可自由地使用、修改、分发,**前提是衍生作品(包括将 STVM 作为库链接的程序)也必须以 GPL v2.0 方式公开源代码**。 - 许可文本:[LICENSE](LICENSE) - 适用场景: - 个人学习、研究 - 开源项目(本身也使用 GPL v2.0 或兼容协议) - 企业内部工具、非对外分发的原型验证 - 闭源商业产品发行(禁止,需转商业授权) - 嵌入硬件/软件对外销售且源代码不开放(禁止,需转商业授权) - SaaS / 云服务且服务端代码不公开(禁止,需转商业授权) ### 二、商业授权(付费,闭源友好) 如果您需要将 STVM 集成到闭源商业产品、OEM 硬件、SaaS 云服务中,且不愿向社会公开衍生作品的源代码,应购买商业授权。一旦选择商业授权,您对 STVM 的对应使用行为**不再受 GPL v2.0 开源义务约束**。 - 中文协议文本:[LICENSE.COMMERCIAL.zh-CN.md](LICENSE.COMMERCIAL.zh-CN.md) - English Agreement: [LICENSE.COMMERCIAL.en.md](LICENSE.COMMERCIAL.en.md) **核心权利**: - 永久、全球范围内使用 STVM 源代码与二进制 - 任意修改、适配、二次开发,**修改部分无需开源** - 以闭源形式分发包含 STVM 的最终产品(二进制/源代码任选其一) - 用于 SaaS、云服务、API 网关等网络服务场景 - 包含标准技术支持(一年邮件支持,可续) **授权档次(参考价,最终以双方书面约定为准)**: | 档次 | 适用场景 | 参考费用(人民币) | 说明 | |------|---------|------------------|------| | 评估授权 / Evaluation | 原型验证、内部测试 | 免费或协商 | 不得用于商业发行的产品 | | OEM 授权 / OEM | 嵌入第三方硬件批量销售 | 按台抽成或年费 | 需另行签订 OEM 协议 | ### 三、如何选择? | 您的使用场景 | 推荐许可证 | |-------------|-----------| | 个人学习、开源项目 | GPL v2.0(免费) | | 内部工具、非商业用途 | GPL v2.0(免费) | | 闭源商业产品发行 | 商业授权 | | 嵌入硬件销售(OEM) | 商业授权(OEM 档次) | | SaaS / 云服务(服务端代码不公开) | 商业授权 | | 修改后不愿公开源代码 | 商业授权 | > **简言之**:愿意开源用 GPL v2.0;需要闭源用商业授权。 ### 四、商业授权联系方式 - 版权持有人:宋炜 - 咨询方式 : 17367073@qq.com --- *Copyright © 宋炜. STVM dual-licensed: GPL v2.0 or Commercial.*