From 4f3da55ed7b58132b9eb4e9efd27d1a1f49f6c61 Mon Sep 17 00:00:00 2001 From: chentianya Date: Wed, 26 Aug 2026 09:56:43 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=B6=E6=AE=B54-1=EF=BC=9Aisa=20=E9=87=8D?= =?UTF-8?q?=E6=9E=84=20V2=20=E5=AE=8C=E6=88=90=EF=BC=88Types/Op/Instr/Enco?= =?UTF-8?q?de=20+=20isa=5Ftest=2091=20checks=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Types.h:func 宽度/符号表(kFuncWidth/kFuncSigned)、饱和模板(各宽度 __int128 中间量 + 除法 A:除零返回被除数/MIN/-1 夹界/截断)、删 TypeTag - Op.h/.cpp:前缀分区 + 72 条指令表(与 machine.toml 强校验一致)、 uses_rd/rs1/rs2 直推、kFbNames(15 内建 FB) - Instr.h:变长 instr_len、位号 get/set(含 JC off@55..24、SLOT_OFF off@87..56)、 enc_* 发射器 - Encode.h/.cpp:decode/encode 往返、disasm(类型后缀 + CAL fb 名 + 未知 0x dump) - isa_test V2:饱和边界/func 表/前缀定长/位号往返/编解码/disasm/uses_*/指令表 修复的实现 bug:find_op 字符串比较(指针==)、set_byte0 11/10 与 010xxx 分支、 CAL 字段约定((slot<<16)|fb_id)、disasm 未知前缀 used 长度 状态:vm/executor 编译暂破(V1 代码引用旧 isa 接口),4-2 同步 --- isa/CMakeLists.txt | 3 +- isa/include/isa/Encode.h | 50 ++--- isa/include/isa/Instr.h | 387 ++++++++++++++++++++++++++------------- isa/include/isa/Op.h | 227 ++++++++++------------- isa/include/isa/Types.h | 112 ++++++----- isa/src/Encode.cpp | 190 ++++++++++++++----- isa/src/Op.cpp | 162 ++++++++++++++++ tests/src/isa_test.cpp | 303 +++++++++++++++++++++--------- 8 files changed, 968 insertions(+), 466 deletions(-) create mode 100644 isa/src/Op.cpp diff --git a/isa/CMakeLists.txt b/isa/CMakeLists.txt index 9df22ef..aa32c1f 100644 --- a/isa/CMakeLists.txt +++ b/isa/CMakeLists.txt @@ -7,6 +7,7 @@ project(ISA DESCRIPTION "指令集架构") add_library(isa STATIC - ./src/Encode.cpp) + ./src/Encode.cpp + ./src/Op.cpp) target_include_directories(isa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) \ No newline at end of file diff --git a/isa/include/isa/Encode.h b/isa/include/isa/Encode.h index b4dfcfa..a14d29b 100644 --- a/isa/include/isa/Encode.h +++ b/isa/include/isa/Encode.h @@ -1,7 +1,7 @@ /** * @file Encode.h - * @brief 指令编解码与反汇编 - * @details 给 STCompiler --disasm 与测试往返使用;文本格式见 Doc/isa/指令与映像.md。 + * @brief 指令编解码与反汇编(V2) + * @details 给 VM/测试/STCompiler --disasm 使用;文本格式见 Doc/isa/指令与映像.md。 * @author * @date 2026-08-19 */ @@ -15,40 +15,46 @@ #include "isa/Op.h" namespace isa { + /** - * @brief 解码后的字段视图。 - * @details 各字段是 8 位原始值,含义按操作数形态(OpFormat)解释, - * a|b 可用 imm16 / off16 组合成 16 位视图。 + * @brief 解码后的字段视图(通用字段;具体形态语义由调用方按 OpFormat 解释)。 */ struct Decoded { - Op op; ///< 操作码 - uint8_t rd; ///< 目标寄存器 / 条件寄存器 - uint8_t a; ///< 源寄存器 / 立即数低 8 位 / 偏移低 8 位 - uint8_t b; ///< 源寄存器 / 立即数高 8 位 / 偏移高 8 位 + const char* prefix = "?"; ///< 形态前缀("11"/"010001" 等) + uint8_t op = 0; ///< 分区内编号 + uint8_t func = 0; ///< func 位段 + uint8_t rd = 0; ///< rd(23..16) + uint8_t rs1 = 0; ///< rs1(31..24) + uint8_t rs2 = 0; ///< rs2(39..32) + uint32_t imm32 = 0; ///< imm/slot/fn_id(按形态) + int32_t off_hi = 0; ///< SLOT_OFF 的 off32(87..56) }; /** - * @brief 编码:字段视图打包成一条 32 位指令字。 - * @param d 解码后的字段视图 - * @return 打包后的指令字;满足 encode(decode(w)) == w + * @brief 解码:指令字节 → 字段视图。 + * @param code 指令字节 + * @param len 指令长度(instr_len 定) + * @return 字段视图(含 prefix/op/func/寄存器与 32 位数值字段) */ - Instr encode(Decoded d); + Decoded decode(const uint8_t* code, size_t len); /** - * @brief 解码:指令字拆成字段视图。 - * @param w 32 位指令字 - * @return 各字段视图 + * @brief 编码:字段视图 → 指令字节。 + * @param d 字段视图 + * @param out 输出缓冲(≥16 字节) + * @return 指令长度 + * @details 满足 decode(encode(d)) 字段一致(encode 填 prefix/op/func/rd/rs1/rs2/imm32/off_hi)。 */ - Decoded decode(Instr w); + size_t encode(const Decoded& d, uint8_t* out); /** * @brief 反汇编一条指令为一行文本。 - * @param w 指令字 + * @param code 指令字节 + * @param len 指令长度 * @param out 输出缓冲 * @param cap 缓冲容量(含 '\0');cap==0 时直接返回、不写 out - * @details 按操作数形态表驱动输出(如 `RET`、`MOVE r1, r2`、`LOADK r0, 3`、 - * `ADD r1, r2, r3`、`JMP +4`、`JT r0, -1`、`CALL 1`、`CAL_TON 0`); - * 未知操作码输出 `??? 0x`。 + * @details 按形态表驱动输出(类型后缀:full/float/dst 类显示 .U8/.I16/.F32 等; + * CAL 显示 fb 名如 `CAL.TON s5`);未知 (prefix,op) 输出 `??? 0x`。 */ - void disasm(Instr w, char* out, size_t cap); + void disasm(const uint8_t* code, size_t len, char* out, size_t cap); } diff --git a/isa/include/isa/Instr.h b/isa/include/isa/Instr.h index f9e4a6d..0a36410 100644 --- a/isa/include/isa/Instr.h +++ b/isa/include/isa/Instr.h @@ -1,8 +1,13 @@ /** * @file Instr.h - * @brief 32-bit 指令字打包 / 拆字段 - * @details 指令字布局:`[ op:8 | rd:8 | a:8 | b:8 ]`,整体是一个小端 uint32_t。 - * 字段含义按操作码形态解释,见 Doc/isa/指令与映像.md。 + * @brief 变长指令字:前缀定长 + 位号读写 + 发射器(V2) + * @details 执行器侧实现(compiler 侧 Codec 各自一份,位号一致)。 + * - 字节 0 = [长度前缀+形态分区 | op];字节 1 = [func:4 | 空:4] + * - 前缀定长:`1`→4B、`01`→8B、`001`→16B、`0001`→32B + * - 操作数区位号(bit16 起):rd=23..16、imm32/slot32=55..24(字节 3..6)、 + * off32(JMP)=47..16(字节 2..5)、off32_jc(JC)=55..24(字节 3..6)、 + * fn_id32=47..16、fb_id16=31..16、CAL slot32=63..32、 + * SLOT_OFF off32=87..56(字节 7..10)、imm64=87..24 * @author * @date 2026-08-19 */ @@ -14,162 +19,286 @@ #include "isa/Op.h" namespace isa { - /// 指令字:`[ op:8 | rd:8 | a:8 | b:8 ]`,小端 uint32_t。 - typedef uint32_t Instr; /** - * @brief 打包:四个字段拼成一条指令字。 - * @param op 操作码(低 8 位) - * @param rd 目标寄存器 / 条件寄存器(第 8..15 位) - * @param a 源寄存器 / 立即数低 8 位 / 偏移低 8 位(第 16..23 位) - * @param b 源寄存器 / 立即数高 8 位 / 偏移高 8 位(第 24..31 位) - * @return 打包后的指令字 + * @brief 前缀定长:读字节 0 判指令长度。 + * @param code 指令字节(至少 1 字节) + * @return 4/8/16/32 */ - inline Instr pack(Op op, uint8_t rd, uint8_t a, uint8_t b) { - return static_cast(static_cast(op)) - | (static_cast(rd) << 8) - | (static_cast(a) << 16) - | (static_cast(b) << 24); + inline size_t instr_len(const uint8_t* code) { + const uint8_t b = code[0]; + if (b & 0x80) return 4; // 1xxxxxxx + if ((b & 0xC0) == 0x40) return 8; // 01xxxxxx + if ((b & 0xE0) == 0x20) return 16; // 001xxxxx + return 32; // 0001xxxx } - /** - * @brief 取操作码。 - * @param w 指令字 - * @return 低 8 位解释为 Op - */ - inline Op op(Instr w) { - return static_cast(w & 0xFFu); + /// @brief 取分区内操作码(4B 6 位 / 8B 5 位或 2 位 / 16B·32B 4 位)。 + inline uint8_t op_of(const uint8_t* code) { + const uint8_t b = code[0]; + if (b & 0x80) return b & 0x3F; + if ((b & 0xC0) == 0x40) { + return (b & 0x20) ? (b & 0x1F) : (b & 0x03); + } + return b & 0x0F; } - /** - * @brief 取目标寄存器字段。 - * @param w 指令字 - * @return rd(第 8..15 位) - */ - inline uint8_t rd(Instr w) { - return static_cast((w >> 8) & 0xFFu); + /// @brief 取 func 位段(字节 1 高 4 位)。 + inline uint8_t func_of(const uint8_t* code) { + return static_cast((code[1] >> 4) & 0x0F); } - /** - * @brief 取 a 字段。 - * @param w 指令字 - * @return a(第 16..23 位) - */ - inline uint8_t a(Instr w) { - return static_cast((w >> 16) & 0xFFu); + /// @brief 取 rd(23..16 = 字节 2)。 + inline uint8_t rd_of(const uint8_t* code) { return code[2]; } + /// @brief 取 rs1(31..24 = 字节 3)。 + inline uint8_t rs1_of(const uint8_t* code) { return code[3]; } + /// @brief 取 rs2(39..32 = 字节 4)。 + inline uint8_t rs2_of(const uint8_t* code) { return code[4]; } + + /// @brief 取 imm32(55..24 = 字节 3..6,小端)。 + inline uint32_t imm32_of(const uint8_t* code) { + return static_cast(code[3]) + | (static_cast(code[4]) << 8) + | (static_cast(code[5]) << 16) + | (static_cast(code[6]) << 24); } - /** - * @brief 取 b 字段。 - * @param w 指令字 - * @return b(第 24..31 位) - */ - inline uint8_t b(Instr w) { - return static_cast((w >> 24) & 0xFFu); + /// @brief 取 slot32(同 imm32 位号)。 + inline uint32_t slot32_of(const uint8_t* code) { return imm32_of(code); } + + /// @brief 取 off32(47..16 = 字节 2..5,JMP 形态,有符号)。 + inline int32_t off32_of(const uint8_t* code) { + return static_cast(static_cast(code[2]) + | (static_cast(code[3]) << 8) + | (static_cast(code[4]) << 16) + | (static_cast(code[5]) << 24)); } - /** - * @brief 组合视图:a|b 拼成 16 位无符号数。 - * @param w 指令字 - * @return 小端拼出的 16 位值,用作 const_id / fn_id / slot 号 - */ - inline uint16_t imm16(Instr w) { - return static_cast(a(w) | (static_cast(b(w)) << 8)); + /// @brief 取 off32(55..24 = 字节 3..6,JC 形态,有符号)。 + inline int32_t off32_jc_of(const uint8_t* code) { + return static_cast(static_cast(code[3]) + | (static_cast(code[4]) << 8) + | (static_cast(code[5]) << 16) + | (static_cast(code[6]) << 24)); } - /** - * @brief 组合视图:a|b 为有符号相对偏移。 - * @param w 指令字 - * @return 偏移量,单位是指令条数(跳转目标 = 下一条指令 + off) - */ - inline int16_t off16(Instr w) { - return static_cast(imm16(w)); + /// @brief 取 fn_id32(47..16 = 字节 2..5)。 + inline uint32_t fn_id32_of(const uint8_t* code) { + return static_cast(code[2]) + | (static_cast(code[3]) << 8) + | (static_cast(code[4]) << 16) + | (static_cast(code[5]) << 24); } - /** - * @brief 按 RR 形态编码。 - * @param op 操作码(MOVE / NOT) - * @param rd 目标寄存器 - * @param rs 源寄存器(放进 a) - * @return 指令字 - */ - inline Instr enc_rr(Op op, uint8_t rd, uint8_t rs) { - return pack(op, rd, rs, 0); + /// @brief 取 fb_id16(31..16 = 字节 2..3)。 + inline uint16_t fb_id16_of(const uint8_t* code) { + return static_cast(code[2] | (static_cast(code[3]) << 8)); } - /** - * @brief 按 RRR 形态编码。 - * @param op 操作码(AND/OR/ADD/.../CMP_xx) - * @param rd 目标寄存器 - * @param ra 第一源寄存器 - * @param rb 第二源寄存器 - * @return 指令字 - */ - inline Instr enc_rrr(Op op, uint8_t rd, uint8_t ra, uint8_t rb) { - return pack(op, rd, ra, rb); + /// @brief 取 CAL 实例槽号(63..32 = 字节 4..7)。 + inline uint32_t cal_slot32_of(const uint8_t* code) { + return static_cast(code[4]) + | (static_cast(code[5]) << 8) + | (static_cast(code[6]) << 16) + | (static_cast(code[7]) << 24); } - /** - * @brief 按 IMM 形态编码。 - * @param op 操作码(LOADK) - * @param rd 目标寄存器 - * @param imm 16 位立即数(const_id),拆成 a|b 存放 - * @return 指令字 - */ - inline Instr enc_imm(Op op, uint8_t rd, uint16_t imm) { - return pack(op, rd, static_cast(imm & 0xFFu), - static_cast((imm >> 8) & 0xFFu)); + /// @brief 取 SLOT_OFF 的 off32(87..56 = 字节 7..10,有符号)。 + inline int32_t off32_hi_of(const uint8_t* code) { + return static_cast(static_cast(code[7]) + | (static_cast(code[8]) << 8) + | (static_cast(code[9]) << 16) + | (static_cast(code[10]) << 24)); } - /** - * @brief 按 JMP 形态编码。 - * @param off 有符号相对偏移(条数),拆成 a|b 存放 - * @return 指令字 - */ - inline Instr enc_jmp(int16_t off) { - return pack(Op::JMP, 0, - static_cast(static_cast(off) & 0xFFu), - static_cast((static_cast(off) >> 8) & 0xFFu)); + /// @brief 取 imm64(87..24 = 字节 3..10)。 + inline uint64_t imm64_of(const uint8_t* code) { + uint64_t v = 0; + for (int i = 0; i < 8; ++i) { + v |= static_cast(code[3 + i]) << (8 * i); + } + return v; } - /** - * @brief 按 JC 形态编码(条件跳转)。 - * @param op 操作码(JT / JF) - * @param r 条件寄存器(放进 rd) - * @param off 有符号相对偏移(条数),放进 a|b - * @return 指令字 - */ - inline Instr enc_jc(Op op, uint8_t r, int16_t off) { - return pack(op, r, - static_cast(static_cast(off) & 0xFFu), - static_cast((static_cast(off) >> 8) & 0xFFu)); + // ---- 发射器(写字节,调用方提供 ≥16 字节缓冲;返回指令长度)---- + + /// @brief 写字节 0(前缀 + 分区内 op)。 + inline void set_byte0(uint8_t* out, const char* prefix, uint8_t op) { + if (prefix[0] == '1') { + // 11:bit7..6 = 11;10:bit7..6 = 10 + out[0] = static_cast((prefix[1] == '1' ? 0xC0 : 0x80) | (op & 0x3F)); + } else if (prefix[0] == '0') { + if (prefix[1] == '1' && prefix[2] == '1') { + out[0] = static_cast(0x60 | (op & 0x1F)); // 011 + } else if (prefix[1] == '1') { + // 010xxx:形态位 3 位 + 子 op 2 位 + const uint8_t shape = static_cast( + (prefix[3] - '0') * 4 + (prefix[4] - '0') * 2 + (prefix[5] - '0')); + out[0] = static_cast(0x40 | (shape << 2) | (op & 0x03)); + } else if (prefix[2] == '1') { + out[0] = static_cast(0x20 | (op & 0x0F)); // 0010/0011 + } else { + out[0] = static_cast(0x10 | (op & 0x0F)); // 0001 + } + } else { + out[0] = 0; + } } - /** - * @brief 按 SLOT 形态编码。 - * @param op 操作码(LOAD_I / STORE_Q / LOAD_M / STORE_M / LOAD_GLOBAL / STORE_GLOBAL / CAL_*) - * @param rd 目标寄存器(CAL_* 时置 0) - * @param slot 槽号 / 实例号,放进 a|b - * @return 指令字 - */ - inline Instr enc_slot(Op op, uint8_t rd, uint16_t slot) { - return enc_imm(op, rd, slot); + /// @brief 写 func(字节 1 高 4 位)。 + inline void set_func(uint8_t* out, uint8_t func) { + out[1] = static_cast((out[1] & 0x0F) | ((func & 0x0F) << 4)); } - /** - * @brief 按 CALL 形态编码。 - * @param fn_id 函数表下标,放进 a|b - * @return 指令字 - */ - inline Instr enc_call(uint16_t fn_id) { - return enc_imm(Op::CALL, 0, fn_id); + inline void set_rd(uint8_t* out, uint8_t rd) { out[2] = rd; } + inline void set_rs1(uint8_t* out, uint8_t rs1) { out[3] = rs1; } + inline void set_rs2(uint8_t* out, uint8_t rs2) { out[4] = rs2; } + + inline void set_imm32(uint8_t* out, uint32_t v) { + out[3] = static_cast(v & 0xFF); + out[4] = static_cast((v >> 8) & 0xFF); + out[5] = static_cast((v >> 16) & 0xFF); + out[6] = static_cast((v >> 24) & 0xFF); } - /** - * @brief 按 NONE 形态编码(RET)。 - * @return 指令字 - */ - inline Instr enc_ret() { - return pack(Op::RET, 0, 0, 0); + inline void set_slot32(uint8_t* out, uint32_t v) { set_imm32(out, v); } + + inline void set_off32(uint8_t* out, int32_t v) { // JMP:字节 2..5 + const uint32_t u = static_cast(v); + out[2] = static_cast(u & 0xFF); + out[3] = static_cast((u >> 8) & 0xFF); + out[4] = static_cast((u >> 16) & 0xFF); + out[5] = static_cast((u >> 24) & 0xFF); + } + + inline void set_off32_jc(uint8_t* out, int32_t v) { // JC:字节 3..6 + const uint32_t u = static_cast(v); + out[3] = static_cast(u & 0xFF); + out[4] = static_cast((u >> 8) & 0xFF); + out[5] = static_cast((u >> 16) & 0xFF); + out[6] = static_cast((u >> 24) & 0xFF); + } + + inline void set_fn_id32(uint8_t* out, uint32_t v) { set_off32(out, static_cast(v)); } + + inline void set_fb_id16(uint8_t* out, uint16_t v) { + out[2] = static_cast(v & 0xFF); + out[3] = static_cast((v >> 8) & 0xFF); + } + + inline void set_cal_slot32(uint8_t* out, uint32_t v) { + out[4] = static_cast(v & 0xFF); + out[5] = static_cast((v >> 8) & 0xFF); + out[6] = static_cast((v >> 16) & 0xFF); + out[7] = static_cast((v >> 24) & 0xFF); + } + + inline void set_off32_hi(uint8_t* out, int32_t v) { // SLOT_OFF:字节 7..10 + const uint32_t u = static_cast(v); + out[7] = static_cast(u & 0xFF); + out[8] = static_cast((u >> 8) & 0xFF); + out[9] = static_cast((u >> 16) & 0xFF); + out[10] = static_cast((u >> 24) & 0xFF); + } + + inline void set_imm64(uint8_t* out, uint64_t v) { + for (int i = 0; i < 8; ++i) { + out[3 + i] = static_cast((v >> (8 * i)) & 0xFF); + } + } + + // ---- 便捷编码(vm_test 手拼映像用;输出 ≥16 字节缓冲)---- + + /// @brief 编码 RR 形态(MOVE/NOT/NEG 等),返回指令长度。 + inline size_t enc_rr(uint8_t* out, const char* prefix, uint8_t op, uint8_t func, + uint8_t rd, uint8_t rs) { + set_byte0(out, prefix, op); + set_func(out, func); + set_rd(out, rd); + set_rs1(out, rs); + return instr_len(out); + } + + /// @brief 编码 RRR 形态,返回指令长度。 + inline size_t enc_rrr(uint8_t* out, const char* prefix, uint8_t op, uint8_t func, + uint8_t rd, uint8_t ra, uint8_t rb) { + set_byte0(out, prefix, op); + set_func(out, func); + set_rd(out, rd); + set_rs1(out, ra); + set_rs2(out, rb); + return instr_len(out); + } + + /// @brief 编码 SLOT 形态(LOAD/STORE),返回指令长度。 + inline size_t enc_slot(uint8_t* out, const char* prefix, uint8_t op, uint8_t func, + uint8_t rd, uint32_t slot) { + set_byte0(out, prefix, op); + set_func(out, func); + set_rd(out, rd); + set_slot32(out, slot); + return instr_len(out); + } + + /// @brief 编码 IMM 形态(LOADK),返回指令长度。 + inline size_t enc_imm(uint8_t* out, const char* prefix, uint8_t op, uint8_t func, + uint8_t rd, uint32_t imm) { + set_byte0(out, prefix, op); + set_func(out, func); + set_rd(out, rd); + set_imm32(out, imm); + return instr_len(out); + } + + /// @brief 编码 JMP(010010 区),返回指令长度。 + inline size_t enc_jmp(uint8_t* out, int32_t off) { + set_byte0(out, "010010", 0); + set_func(out, 0); + set_off32(out, off); + return instr_len(out); + } + + /// @brief 编码 JC 形态(JT/JF,010011 区),返回指令长度。 + inline size_t enc_jc(uint8_t* out, uint8_t op, uint8_t rd, int32_t off) { + set_byte0(out, "010011", op); + set_func(out, 0); + set_rd(out, rd); + set_off32_jc(out, off); + return instr_len(out); + } + + /// @brief 编码 CALL(010100 区),返回指令长度。 + inline size_t enc_call(uint8_t* out, uint32_t fn_id) { + set_byte0(out, "010100", 0); + set_func(out, 0); + set_fn_id32(out, fn_id); + return instr_len(out); + } + + /// @brief 编码 CAL(010101 区),返回指令长度。 + inline size_t enc_cal(uint8_t* out, uint16_t fb_id, uint32_t slot) { + set_byte0(out, "010101", 0); + set_func(out, 0); + set_fb_id16(out, fb_id); + set_cal_slot32(out, slot); + return instr_len(out); + } + + /// @brief 编码 SLOT_OFF(LOAD_OFF/STORE_OFF,0010 区),返回指令长度。 + inline size_t enc_slot_off(uint8_t* out, uint8_t op, uint8_t func, + uint8_t rd, uint32_t slot, int32_t off) { + set_byte0(out, "0010", op); + set_func(out, func); + set_rd(out, rd); + set_slot32(out, slot); + set_off32_hi(out, off); + return instr_len(out); + } + + /// @brief 编码 RET(10 区),返回指令长度。 + inline size_t enc_ret(uint8_t* out) { + set_byte0(out, "10", static_cast(Op::RET)); + set_func(out, 0); + return instr_len(out); } } diff --git a/isa/include/isa/Op.h b/isa/include/isa/Op.h index a3684ac..8ebbf18 100644 --- a/isa/include/isa/Op.h +++ b/isa/include/isa/Op.h @@ -1,8 +1,13 @@ /** * @file Op.h - * @brief 操作码枚举、操作数形态与编译期指令表 - * @details 操作码数值即 .stb 指令编码。执行器(vm)只依赖本表; - * 编译器侧的登记见 Doc/isa/指令配置.md(compiler/machine.toml,与之强校验)。 + * @brief 操作码、前缀分区、形态与指令表(V2) + * @details 执行器侧指令定义(vm 依赖本表;compiler 不链 isa,其登记在 + * compiler/machine.toml,与本表强校验一致)。 + * - 前缀分区(长度+形态一体):`11`=RR、`10`=NONE、`011`=RRR、 + * `010 000..101`=IMM/SLOT/JMP/JC/CALL/CAL、`0010`=SLOT+off、 + * `0011`=IMM64、`0001`=预留(32B) + * - uses_rd/uses_ra/uses_rb:形态 → 哪些字段是寄存器(前缀直推,零查表) + * - 指令表 kOps:与 machine.toml 72 条 op 行对应(prefix/op/fmt/func_mode) * @author * @date 2026-08-19 */ @@ -12,154 +17,122 @@ #include namespace isa { + + /// 指令最大长度(字节)。 + static constexpr int kMaxInstrLen = 16; + /** - * @brief 操作码枚举。 - * @details 数值即编码:冻结后不得改顺序、不得插值,增加指令只能追加到末尾, - * 并同步 Doc/isa/指令与映像.md、compiler/machine.toml 与测试。 + * @brief 操作码(分区内独立编号:MOVE=0、ADD=0、LOADK=0 等不冲突,靠前缀区分)。 + * @details 每个分区的 op 从 0 起;查表用 (prefix, op) 键。 */ enum class Op : uint8_t { - MOVE = 0, // MOVE rd, rs - LOADK = 1, // LOADK rd, const_id - NOT = 2, // NOT rd, rs - AND = 3, // AND rd, ra, rb - OR = 4, // OR rd, ra, rb - ADD = 5, // ADD rd, ra, rb - SUB = 6, // SUB rd, ra, rb - MUL = 7, // MUL rd, ra, rb - DIV = 8, // DIV rd, ra, rb - CMP_EQ = 9, // CMP_EQ rd, ra, rb - CMP_NE = 10, // CMP_NE rd, ra, rb - CMP_LT = 11, // CMP_LT rd, ra, rb - CMP_LE = 12, // CMP_LE rd, ra, rb - CMP_GT = 13, // CMP_GT rd, ra, rb - CMP_GE = 14, // CMP_GE rd, ra, rb - JMP = 15, // JMP offset - JT = 16, // JT r, offset - JF = 17, // JF r, offset - LOAD_I = 18, // LOAD_I rd, slot - STORE_Q = 19, // STORE_Q rs, slot - LOAD_M = 20, // LOAD_M rd, slot - STORE_M = 21, // STORE_M rs, slot - LOAD_GLOBAL = 22, // LOAD_GLOBAL rd, slot - STORE_GLOBAL = 23, // STORE_GLOBAL rs, slot - // 内置功能块(8 个连续,12.11 扩充:TON/TOF/TP/CTU/CTD/CTUD/R_TRIG/F_TRIG) - CAL_TON = 24, // CAL_TON instance_slot - CAL_TOF = 25, // CAL_TOF instance_slot - CAL_TP = 26, // CAL_TP instance_slot - CAL_CTU = 27, // CAL_CTU instance_slot - CAL_CTD = 28, // CAL_CTD instance_slot - CAL_CTUD = 29, // CAL_CTUD instance_slot - CAL_R_TRIG = 30, // CAL_R_TRIG instance_slot - CAL_F_TRIG = 31, // CAL_F_TRIG instance_slot - CALL = 32, // CALL fn_id - RET = 33, // RET + // 4B RR(前缀 11,op 6 位) + MOVE = 0, NOT = 1, NEG = 2, ABS = 3, INC = 4, DEC = 5, + SQRT = 6, SIN = 7, COS = 8, TAN = 9, ASIN = 10, ACOS = 11, + ATAN = 12, LN = 13, LOG = 14, EXP = 15, ROUND = 16, TRUNC = 17, + FLOOR = 18, CEIL = 19, CONV = 20, + // 4B NONE(前缀 10,op 6 位) + NOP = 0, RET = 1, + // 8B RRR(前缀 011,op 5 位) + ADD = 0, SUB = 1, MUL = 2, DIV = 3, MOD = 4, EXPT = 5, + AND = 6, OR = 7, XOR = 8, NAND = 9, NOR = 10, XNOR = 11, + SHL = 12, SHR = 13, ROL = 14, ROR = 15, + CMP_EQ = 16, CMP_NE = 17, CMP_LT = 18, CMP_LE = 19, + CMP_GT = 20, CMP_GE = 21, + GETBIT = 22, SETBIT = 23, CLRBIT = 24, TOGBIT = 25, + // 8B 010 区(形态位 3 + 子 op 2 位) + LOADK = 0, LOAD = 0, STORE = 1, JMP = 0, JT = 0, JF = 1, + CALL = 0, CAL = 0, + // 16B(前缀 0010/0011,op 4 位) + LOAD_OFF = 0, STORE_OFF = 1, STR_LEN = 2, STR_CMP = 3, + STR_EQ = 4, STR_MID = 5, STR_LEFT = 6, STR_RIGHT = 7, + LOADK64 = 0, + // 32B 预留(前缀 0001,op 4 位) + JTBL = 0, STR_CONCAT = 1, STR_FIND = 2, STR_REPLACE = 3, + ARR_LOAD = 4, ARR_STORE = 5, }; - /// 操作码总数(= 最大 opcode + 1,kOpDefs 的下标上界)。 - static const int kOpCount = 34; - /** - * @brief 操作数形态(三层分类第二层,见 Doc/isa/指令配置.md)。 - * @details 决定操作数 a|b 的解释方式与反汇编文本格式。 + * @brief 操作数形态(前缀分区的语义标签)。 */ enum class OpFormat : uint8_t { - RR, // 两寄存器:rd rs(MOVE / NOT) - RRR, // 三寄存器:rd ra rb(逻辑 / 算术 / 比较) - IMM, // 常量:rd const_id(LOADK) - SLOT, // 槽:rd slot(LOAD_* / STORE_*) - JMP, // 偏移:off - JC, // 条件跳转:r off(JT / JF) - CALL, // 调用:fn_id - CAL, // 实例:instance(CAL_*) - NONE, // 无操作数(RET) + RR, ///< rd, rs(4B) + NONE, ///< 无操作数(4B) + RRR, ///< rd, ra, rb(8B) + IMM, ///< rd, imm32(8B) + SLOT, ///< rd, slot32(8B) + JMP, ///< off32(8B) + JC, ///< rd, off32(8B) + CALL, ///< fn_id32(8B) + CAL, ///< fb_id16, slot32(8B) + SLOT_OFF, ///< rd, slot32, off32(16B) + IMM64, ///< rd, imm64(16B) + RESERVED, ///< 32B 预留 }; /** - * @brief 操作对象大类(三层分类第一层)。 + * @brief func 语义类别(与 machine.toml op 表一致)。 */ - enum class OpClass : uint8_t { - Plain, // 无实例:寄存器 / 立即数 / 槽 / 分支 / 调用 - Instance, // 有实例:操作数据区实例块(内建 FB) + enum class FuncMode : uint8_t { + None, ///< 无类型(func 恒 0) + Width, ///< MOVE 类:func 0..3 = 1/2/4/8B 宽度 + Uint, ///< 逻辑/位串类:func 0/2/4/6(无符号宽度) + Full, ///< LOAD/STORE/算术/CMP:func 0..9 全矩阵 + Float, ///< 浮点单目/舍入:func 8/9 + Dst, ///< CONV:func = 目标类型 }; + /// 前缀字符串。 + extern const char* kPrefixNames[12]; + /** - * @brief 编译期指令表条目。 - * @details 一条指令的名称、操作数形态与大类;下标与 Op 数值一一对应。 + * @brief 指令定义(与 machine.toml [[op]] 行对应)。 */ struct OpDef { - const char* name; ///< 助记符(与 .stb / machine.toml 一致) - OpFormat format; ///< 操作数形态 - OpClass cls; ///< 操作对象大类 + const char* name; ///< 助记符(大写,与配置一致) + const char* prefix; ///< 形态前缀("11"/"010001" 等) + Op op; ///< 分区内编号 + OpFormat format; ///< 操作数形态 + FuncMode func_mode; ///< func 语义类别 }; - /** - * @brief 编译期指令表:下标与 Op 数值一一对应(machine.toml 强校验的基准)。 - * @details 表与 Op 枚举同步维护;查询入口见 mnemonic / format / op_class。 - */ - static const OpDef kOpDefs[kOpCount] = { - {"MOVE", OpFormat::RR, OpClass::Plain}, // 0 - {"LOADK", OpFormat::IMM, OpClass::Plain}, // 1 - {"NOT", OpFormat::RR, OpClass::Plain}, // 2 - {"AND", OpFormat::RRR, OpClass::Plain}, // 3 - {"OR", OpFormat::RRR, OpClass::Plain}, // 4 - {"ADD", OpFormat::RRR, OpClass::Plain}, // 5 - {"SUB", OpFormat::RRR, OpClass::Plain}, // 6 - {"MUL", OpFormat::RRR, OpClass::Plain}, // 7 - {"DIV", OpFormat::RRR, OpClass::Plain}, // 8 - {"CMP_EQ", OpFormat::RRR, OpClass::Plain}, // 9 - {"CMP_NE", OpFormat::RRR, OpClass::Plain}, // 10 - {"CMP_LT", OpFormat::RRR, OpClass::Plain}, // 11 - {"CMP_LE", OpFormat::RRR, OpClass::Plain}, // 12 - {"CMP_GT", OpFormat::RRR, OpClass::Plain}, // 13 - {"CMP_GE", OpFormat::RRR, OpClass::Plain}, // 14 - {"JMP", OpFormat::JMP, OpClass::Plain}, // 15 - {"JT", OpFormat::JC, OpClass::Plain}, // 16 - {"JF", OpFormat::JC, OpClass::Plain}, // 17 - {"LOAD_I", OpFormat::SLOT, OpClass::Plain}, // 18 - {"STORE_Q", OpFormat::SLOT, OpClass::Plain}, // 19 - {"LOAD_M", OpFormat::SLOT, OpClass::Plain}, // 20 - {"STORE_M", OpFormat::SLOT, OpClass::Plain}, // 21 - {"LOAD_GLOBAL", OpFormat::SLOT, OpClass::Plain}, // 22 - {"STORE_GLOBAL", OpFormat::SLOT, OpClass::Plain},// 23 - {"CAL_TON", OpFormat::CAL, OpClass::Instance}, // 24 - {"CAL_TOF", OpFormat::CAL, OpClass::Instance}, // 25 - {"CAL_TP", OpFormat::CAL, OpClass::Instance}, // 26 - {"CAL_CTU", OpFormat::CAL, OpClass::Instance}, // 27 - {"CAL_CTD", OpFormat::CAL, OpClass::Instance}, // 28 - {"CAL_CTUD", OpFormat::CAL, OpClass::Instance}, // 29 - {"CAL_R_TRIG", OpFormat::CAL, OpClass::Instance},// 30 - {"CAL_F_TRIG", OpFormat::CAL, OpClass::Instance},// 31 - {"CALL", OpFormat::CALL, OpClass::Plain}, // 32 - {"RET", OpFormat::NONE, OpClass::Plain}, // 33 - }; + /// 指令表(72 条,与 machine.toml 强校验一致)。 + extern const OpDef kOps[]; + + /// 指令表条数(= 72)。 + static const int kOpCount = 72; /** - * @brief 查助记符。 - * @param op 操作码 - * @return 对应助记符;越界返回哨兵 "???" + * @brief 按 (prefix, op) 查指令。 + * @param prefix 形态前缀 + * @param op 分区内编号 + * @return 命中下标;未找到返回 -1 */ - inline const char* mnemonic(Op op) { - const int idx = static_cast(op); - return (idx >= 0 && idx < kOpCount) ? kOpDefs[idx].name : "???"; - } + int find_op(const char* prefix, uint8_t op); /** - * @brief 查操作数形态。 - * @param op 操作码 - * @return 对应 OpFormat;越界返回 OpFormat::NONE + * @brief 按助记符查指令。 + * @param name 助记符(如 "MOVE") + * @return 命中下标;未找到返回 -1 */ - inline OpFormat format(Op op) { - const int idx = static_cast(op); - return (idx >= 0 && idx < kOpCount) ? kOpDefs[idx].format : OpFormat::NONE; - } + int find_op_by_name(const char* name); - /** - * @brief 查操作对象大类。 - * @param op 操作码 - * @return 对应 OpClass;越界返回 OpClass::Plain - */ - inline OpClass op_class(Op op) { - const int idx = static_cast(op); - return (idx >= 0 && idx < kOpCount) ? kOpDefs[idx].cls : OpClass::Plain; - } + /// @brief 指令名(助记符);未知返回 "???"。 + const char* mnemonic(const char* prefix, uint8_t op); + + /// @brief 指令形态;未知返回 OpFormat::RESERVED。 + OpFormat format_of(const char* prefix, uint8_t op); + + /// @brief func 语义类别;未知返回 FuncMode::None。 + FuncMode func_mode_of(const char* prefix, uint8_t op); + + /// @brief 该形态 rd 字段是否为寄存器。 + bool uses_rd(OpFormat f); + /// @brief 该形态 rs1 字段是否为寄存器。 + bool uses_rs1(OpFormat f); + /// @brief 该形态 rs2 字段是否为寄存器。 + bool uses_rs2(OpFormat f); + + /// 内建 FB 名表(fb_id → 名;15 条,与 machine.toml [[fb]] 一致)。 + extern const char* kFbNames[15]; } diff --git a/isa/include/isa/Types.h b/isa/include/isa/Types.h index 104e783..6fde318 100644 --- a/isa/include/isa/Types.h +++ b/isa/include/isa/Types.h @@ -1,8 +1,12 @@ /** * @file Types.h - * @brief 定宽类型与饱和算术 + * @brief 定宽类型、func 表与饱和算术(V2) * @details 虚拟机字长与类型契约的唯一来源。compiler 与 vm 共用同一套规则, - * 详见 Doc/isa/指令与映像.md。 + * 详见 Doc/isa/指令与映像.md(V2)。 + * - func 0..9:宽度×符号(1B无/1B有/2B无/2B有/4B无/4B有/8B无/8B有)+ F32 + F64 + * - 饱和模板:T ∈ {int8_t, int16_t, int32_t, int64_t},除法 A 边界 + * (除零返回被除数、MIN/-1 饱和夹界、截断除法) + * - TypeTag 已删除(V2 常量表 8B 无 tag,LOADK 按 func 解释) * @author * @date 2026-08-18 */ @@ -14,93 +18,101 @@ namespace isa { namespace types { - /** - * @brief 布尔值:8 位,只允许 0/1(0=FALSE,1=TRUE)。 - */ + /// 布尔值:8 位,只允许 0/1(0=FALSE,1=TRUE)。 using BOOL = uint8_t; - /** - * @brief IEC INT:16 位有符号整数,溢出按饱和规则处理。 - */ + /// IEC INT:16 位有符号整数,溢出按饱和规则处理。 using INT = int16_t; - /** - * @brief 时间:64 位有符号整数,单位毫秒。 - * @details 取 64 位的理由见 Doc/isa/指令与映像.md:差值可负、 - * 为 DATE_AND_TIME 与 64 位定时器预留。槽位按 8 字节对齐。 - */ + /// 时间:64 位有符号整数,单位毫秒。 using TIME = int64_t; /** - * @brief 槽 / 常量表类型标记。 - * @details 数值冻结并写入 .stb 常量表:0=BOOL、1=INT、2=TIME(见映像规范), - * 不得改顺序、不得插值。 + * @brief func 位段 → 数据宽度(字节)。 + * @details 下标 0..9 有效(0..7 = 1/2/4/8B × 有/无符号,8=F32、9=F64); + * 10..15 预留返回 0。 */ - enum TypeTag : uint8_t { - Bool = 0, - Int = 1, - Time = 2, + inline constexpr int kFuncWidth[16] = { + 1, 1, 2, 2, 4, 4, 8, 8, // 0..7:1B无/1B有/2B无/2B有/4B无/4B有/8B无/8B有 + 4, 8, // 8=F32、9=F64 + 0, 0, 0, 0, 0, 0, // 10..15 预留 }; - // 饱和算术:夹到 INT 最小/最大,编译期与 VM 共用同一规则。 + /** + * @brief func 位段 → 是否有符号(读取扩展方向)。 + * @details 浮点(8/9)按 true(位模式原样搬运,扩展无实际作用)。 + */ + inline constexpr bool kFuncSigned[16] = { + false, true, false, true, false, true, false, true, + true, true, // 浮点位模式 + false, false, false, false, false, false, + }; /** * @brief 饱和加法。 * @param a 加数 * @param b 加数 - * @return a+b,超出 INT 范围时夹到最小/最大值 - * @details 中间量用 int32 计算,避免 int16 溢出未定义行为。 + * @return a+b,超出 T 范围时夹到最小/最大值 + * @details 中间量用 int64 计算,避免窄类型溢出未定义行为。 */ - inline INT sat_add(INT a, INT b) { - const int32_t sum = static_cast(a) + static_cast(b); - return static_cast(sum < std::numeric_limits::min() ? std::numeric_limits::min() - : sum > std::numeric_limits::max() ? std::numeric_limits::max() - : sum); + template + T sat_add(T a, T b) { + const __int128 sum = static_cast<__int128>(a) + static_cast<__int128>(b); + return static_cast(sum < std::numeric_limits::min() + ? std::numeric_limits::min() + : sum > std::numeric_limits::max() + ? std::numeric_limits::max() + : sum); } /** * @brief 饱和减法。 * @param a 被减数 * @param b 减数 - * @return a-b,超出 INT 范围时夹到最小/最大值 - * @details 中间量用 int32 计算,避免 int16 溢出未定义行为。 + * @return a-b,超出 T 范围时夹到最小/最大值 */ - inline INT sat_sub(INT a, INT b) { - const int32_t diff = static_cast(a) - static_cast(b); - return static_cast(diff < std::numeric_limits::min() ? std::numeric_limits::min() - : diff > std::numeric_limits::max() ? std::numeric_limits::max() - : diff); + template + T sat_sub(T a, T b) { + const __int128 diff = static_cast<__int128>(a) - static_cast<__int128>(b); + return static_cast(diff < std::numeric_limits::min() + ? std::numeric_limits::min() + : diff > std::numeric_limits::max() + ? std::numeric_limits::max() + : diff); } /** * @brief 饱和乘法。 * @param a 乘数 * @param b 乘数 - * @return a*b,超出 INT 范围时夹到最小/最大值 - * @details 中间量用 int32 计算,避免 int16 溢出未定义行为。 + * @return a*b,超出 T 范围时夹到最小/最大值 */ - inline INT sat_mul(INT a, INT b) { - const int32_t prod = static_cast(a) * static_cast(b); - return static_cast(prod < std::numeric_limits::min() ? std::numeric_limits::min() - : prod > std::numeric_limits::max() ? std::numeric_limits::max() - : prod); + template + T sat_mul(T a, T b) { + const __int128 prod = static_cast<__int128>(a) * static_cast<__int128>(b); + return static_cast(prod < std::numeric_limits::min() + ? std::numeric_limits::min() + : prod > std::numeric_limits::max() + ? std::numeric_limits::max() + : prod); } /** - * @brief 饱和除法。 + * @brief 饱和除法(除法 A 定案)。 * @param a 被除数 * @param b 除数 - * @return a/b;b==0 视为除以 1 返回 a;INT_MIN / -1 溢出饱和到 INT_MAX - * @details b==0 返回 a 是为避免未定义行为;除零的语义由 compiler/VM 层报错。 + * @return a/b(截断除法,向零);b==0 → 返回 a(结果保持); + * MIN/-1 → 饱和夹到 MAX */ - inline INT sat_div(INT a, INT b) { + template + T sat_div(T a, T b) { if (b == 0) { - return a; + return a; // 除零返回被除数(Fail-safe) } - if (a == std::numeric_limits::min() && b == -1) { - return std::numeric_limits::max(); + if (a == std::numeric_limits::min() && b == T(-1)) { + return std::numeric_limits::max(); // MIN/-1 溢出饱和 } - return static_cast(a / b); + return static_cast(a / b); } } } diff --git a/isa/src/Encode.cpp b/isa/src/Encode.cpp index db74a9a..6a34fe1 100644 --- a/isa/src/Encode.cpp +++ b/isa/src/Encode.cpp @@ -1,6 +1,6 @@ /** * @file Encode.cpp - * @brief 指令编解码与反汇编实现 + * @brief 指令编解码与反汇编实现(V2) * @author * @date 2026-08-19 */ @@ -8,83 +8,181 @@ #include "isa/Encode.h" #include +#include +#include namespace isa { -/** - * @brief 编码:字段视图打包成一条 32 位指令字。 - * @param d 解码后的字段视图 - * @return 打包后的指令字;满足 encode(decode(w)) == w - */ -Instr encode(Decoded d) { - return pack(d.op, d.rd, d.a, d.b); -} +namespace { + + /** + * @brief func → 类型后缀(disasm 用)。 + * @param func func 值(0..9) + * @return 后缀("U8"/"I8"/.../"F64");越界返回 "?" + */ + const char* type_suffix(uint8_t func) { + static const char* kSuffix[16] = { + "U8", "I8", "U16", "I16", "U32", "I32", "U64", "I64", + "F32", "F64", "?", "?", "?", "?", "?", "?", + }; + return kSuffix[func & 0x0F]; + } + + /// 形态是否显示类型后缀(full/float/dst 类)。 + bool shows_type_suffix(FuncMode m) { + return m == FuncMode::Full || m == FuncMode::Float || m == FuncMode::Dst; + } + +} // namespace /** - * @brief 解码:指令字拆成字段视图。 - * @param w 32 位指令字 - * @return 各字段视图 + * @brief 解码:指令字节 → 字段视图。 */ -Decoded decode(Instr w) { +Decoded decode(const uint8_t* code, size_t len) { Decoded d; - d.op = op(w); - d.rd = rd(w); - d.a = a(w); - d.b = b(w); + (void)len; + // 前缀推导(按字节 0 位模式) + const uint8_t b = code[0]; + if (b & 0x80) { + d.prefix = (b & 0x40) ? "11" : "10"; + d.op = b & 0x3F; + } else if ((b & 0xC0) == 0x40) { + if (b & 0x20) { + d.prefix = "011"; + d.op = b & 0x1F; + } else { + static const char* kShapes[8] = { + "010000", "010001", "010010", "010011", + "010100", "010101", "010110", "010111", + }; + d.prefix = kShapes[(b >> 2) & 0x07]; + d.op = b & 0x03; + } + } else if ((b & 0xE0) == 0x20) { + d.prefix = (b & 0x10) ? "0011" : "0010"; + d.op = b & 0x0F; + } else { + d.prefix = "0001"; + d.op = b & 0x0F; + } + d.func = func_of(code); + d.rd = rd_of(code); + d.rs1 = rs1_of(code); + d.rs2 = rs2_of(code); + // 数值字段(按形态解释):IMM/SLOT → imm32;JMP/JC → off;CALL → fn_id + const OpFormat f = format_of(d.prefix, d.op); + if (f == OpFormat::IMM || f == OpFormat::SLOT) { + d.imm32 = imm32_of(code); + } else if (f == OpFormat::JMP) { + d.imm32 = static_cast(off32_of(code)); + } else if (f == OpFormat::JC) { + d.imm32 = static_cast(off32_jc_of(code)); + } else if (f == OpFormat::CALL) { + d.imm32 = fn_id32_of(code); + } else if (f == OpFormat::CAL) { + d.imm32 = (cal_slot32_of(code) << 16) | fb_id16_of(code); // (slot<<16)|fb_id + } else if (f == OpFormat::SLOT_OFF) { + d.imm32 = slot32_of(code); + d.off_hi = off32_hi_of(code); + } return d; } /** - * @brief 反汇编一条指令为一行文本。 - * @param w 指令字 - * @param out 输出缓冲 - * @param cap 缓冲容量(含 '\0');cap==0 时直接返回、不写 out - * @details 按操作数形态表驱动输出,文本与 Doc/isa/指令与映像.md 一致; - * 未知操作码输出 `??? 0x`。 + * @brief 编码:字段视图 → 指令字节。 */ -void disasm(Instr w, char* out, size_t cap) { +size_t encode(const Decoded& d, uint8_t* out) { + set_byte0(out, d.prefix, d.op); + set_func(out, d.func); + set_rd(out, d.rd); + set_rs1(out, d.rs1); + set_rs2(out, d.rs2); + const OpFormat f = format_of(d.prefix, d.op); + if (f == OpFormat::IMM || f == OpFormat::SLOT) { + set_imm32(out, d.imm32); + } else if (f == OpFormat::JMP) { + set_off32(out, static_cast(d.imm32)); + } else if (f == OpFormat::JC) { + set_off32_jc(out, static_cast(d.imm32)); + } else if (f == OpFormat::CALL) { + set_fn_id32(out, d.imm32); + } else if (f == OpFormat::CAL) { + set_fb_id16(out, static_cast(d.imm32 & 0xFFFF)); + set_cal_slot32(out, d.imm32); + } else if (f == OpFormat::SLOT_OFF) { + set_slot32(out, d.imm32); + set_off32_hi(out, d.off_hi); + } + return instr_len(out); +} + +/** + * @brief 反汇编一条指令为一行文本。 + */ +void disasm(const uint8_t* code, size_t len, char* out, size_t cap) { if (cap == 0) { return; } out[0] = '\0'; - - const Op o = op(w); - const int idx = static_cast(o); - if (idx < 0 || idx >= kOpCount) { - snprintf(out, cap, "??? 0x%08x", static_cast(w)); + const Decoded d = decode(code, len); + const int idx = find_op(d.prefix, d.op); + if (idx < 0) { + snprintf(out, cap, "??? 0x"); + size_t used = 6; // "??? 0x" 长度 + for (size_t i = 0; i < len && used + 2 < cap; ++i) { + snprintf(out + used, cap - used, "%02x", static_cast(code[i])); + used += 2; + } return; } - const char* m = mnemonic(o); - - // 表驱动:按操作数形态输出(文本与 Doc/isa/指令与映像.md 一致) - switch (format(o)) { + const OpDef& od = kOps[idx]; + const std::string suffix = + shows_type_suffix(od.func_mode) ? std::string(".") + type_suffix(d.func) : ""; + const OpFormat f = od.format; + switch (f) { case OpFormat::RR: - snprintf(out, cap, "%s r%u, r%u", m, - static_cast(rd(w)), static_cast(a(w))); + snprintf(out, cap, "%s%s r%u, r%u", od.name, suffix.c_str(), + static_cast(d.rd), static_cast(d.rs1)); break; case OpFormat::RRR: - snprintf(out, cap, "%s r%u, r%u, r%u", m, - static_cast(rd(w)), static_cast(a(w)), - static_cast(b(w))); + snprintf(out, cap, "%s%s r%u, r%u, r%u", od.name, suffix.c_str(), + static_cast(d.rd), static_cast(d.rs1), + static_cast(d.rs2)); break; case OpFormat::IMM: + snprintf(out, cap, "%s%s r%u, %u", od.name, suffix.c_str(), + static_cast(d.rd), static_cast(d.imm32)); + break; case OpFormat::SLOT: - snprintf(out, cap, "%s r%u, %u", m, - static_cast(rd(w)), static_cast(imm16(w))); + snprintf(out, cap, "%s%s r%u, s%u", od.name, suffix.c_str(), + static_cast(d.rd), static_cast(d.imm32)); break; case OpFormat::JMP: - snprintf(out, cap, "%s %+d", m, static_cast(off16(w))); + snprintf(out, cap, "%s %+d", od.name, static_cast(d.imm32)); break; case OpFormat::JC: - snprintf(out, cap, "%s r%u, %+d", m, - static_cast(rd(w)), static_cast(off16(w))); + snprintf(out, cap, "%s r%u, %+d", od.name, static_cast(d.rd), + static_cast(d.imm32)); break; case OpFormat::CALL: - case OpFormat::CAL: - snprintf(out, cap, "%s %u", m, static_cast(imm16(w))); + snprintf(out, cap, "%s %u", od.name, static_cast(d.imm32)); break; + case OpFormat::CAL: { + const uint16_t fb = static_cast(d.imm32 & 0xFFFF); + const char* fbname = (fb < 15) ? kFbNames[fb] : "?"; + snprintf(out, cap, "CAL.%s s%u", fbname, static_cast(d.imm32 >> 16)); + break; + } + case OpFormat::SLOT_OFF: + snprintf(out, cap, "%s%s r%u, s%u, %d", od.name, suffix.c_str(), + static_cast(d.rd), static_cast(d.imm32), + static_cast(d.off_hi)); + break; + case OpFormat::IMM64: case OpFormat::NONE: - snprintf(out, cap, "%s", m); + case OpFormat::RESERVED: + default: + snprintf(out, cap, "%s", od.name); break; } } diff --git a/isa/src/Op.cpp b/isa/src/Op.cpp new file mode 100644 index 0000000..a937849 --- /dev/null +++ b/isa/src/Op.cpp @@ -0,0 +1,162 @@ +/** + * @file Op.cpp + * @brief 操作码表与查询实现(V2) + * @details 指令表与 compiler/machine.toml 的 72 条 op 行强校验一致; + * uses_* 由形态直推(前缀分区表达,零查表)。 + * @author + * @date 2026-08-19 + */ + +#include "isa/Op.h" + +namespace isa { + + const char* kPrefixNames[12] = { + "11", "10", "011", "010000", "010001", "010010", + "010011", "010100", "010101", "0010", "0011", "0001", + }; + + // 指令表(72 条;顺序与 machine.toml [[op]] 一致) + const OpDef kOps[] = { + // 4B RR(前缀 11) + {"MOVE", "11", Op::MOVE, OpFormat::RR, FuncMode::Width}, + {"NOT", "11", Op::NOT, OpFormat::RR, FuncMode::Uint}, + {"NEG", "11", Op::NEG, OpFormat::RR, FuncMode::Full}, + {"ABS", "11", Op::ABS, OpFormat::RR, FuncMode::Full}, + {"INC", "11", Op::INC, OpFormat::RR, FuncMode::Full}, + {"DEC", "11", Op::DEC, OpFormat::RR, FuncMode::Full}, + {"SQRT", "11", Op::SQRT, OpFormat::RR, FuncMode::Float}, + {"SIN", "11", Op::SIN, OpFormat::RR, FuncMode::Float}, + {"COS", "11", Op::COS, OpFormat::RR, FuncMode::Float}, + {"TAN", "11", Op::TAN, OpFormat::RR, FuncMode::Float}, + {"ASIN", "11", Op::ASIN, OpFormat::RR, FuncMode::Float}, + {"ACOS", "11", Op::ACOS, OpFormat::RR, FuncMode::Float}, + {"ATAN", "11", Op::ATAN, OpFormat::RR, FuncMode::Float}, + {"LN", "11", Op::LN, OpFormat::RR, FuncMode::Float}, + {"LOG", "11", Op::LOG, OpFormat::RR, FuncMode::Float}, + {"EXP", "11", Op::EXP, OpFormat::RR, FuncMode::Float}, + {"ROUND", "11", Op::ROUND, OpFormat::RR, FuncMode::Float}, + {"TRUNC", "11", Op::TRUNC, OpFormat::RR, FuncMode::Float}, + {"FLOOR", "11", Op::FLOOR, OpFormat::RR, FuncMode::Float}, + {"CEIL", "11", Op::CEIL, OpFormat::RR, FuncMode::Float}, + {"CONV", "11", Op::CONV, OpFormat::RR, FuncMode::Dst}, + // 4B NONE(前缀 10) + {"NOP", "10", Op::NOP, OpFormat::NONE, FuncMode::None}, + {"RET", "10", Op::RET, OpFormat::NONE, FuncMode::None}, + // 8B RRR(前缀 011) + {"ADD", "011", Op::ADD, OpFormat::RRR, FuncMode::Full}, + {"SUB", "011", Op::SUB, OpFormat::RRR, FuncMode::Full}, + {"MUL", "011", Op::MUL, OpFormat::RRR, FuncMode::Full}, + {"DIV", "011", Op::DIV, OpFormat::RRR, FuncMode::Full}, + {"MOD", "011", Op::MOD, OpFormat::RRR, FuncMode::Full}, + {"EXPT", "011", Op::EXPT, OpFormat::RRR, FuncMode::Full}, + {"AND", "011", Op::AND, OpFormat::RRR, FuncMode::Uint}, + {"OR", "011", Op::OR, OpFormat::RRR, FuncMode::Uint}, + {"XOR", "011", Op::XOR, OpFormat::RRR, FuncMode::Uint}, + {"NAND", "011", Op::NAND, OpFormat::RRR, FuncMode::Uint}, + {"NOR", "011", Op::NOR, OpFormat::RRR, FuncMode::Uint}, + {"XNOR", "011", Op::XNOR, OpFormat::RRR, FuncMode::Uint}, + {"SHL", "011", Op::SHL, OpFormat::RRR, FuncMode::Uint}, + {"SHR", "011", Op::SHR, OpFormat::RRR, FuncMode::Full}, + {"ROL", "011", Op::ROL, OpFormat::RRR, FuncMode::Uint}, + {"ROR", "011", Op::ROR, OpFormat::RRR, FuncMode::Uint}, + {"CMP_EQ", "011", Op::CMP_EQ, OpFormat::RRR, FuncMode::Full}, + {"CMP_NE", "011", Op::CMP_NE, OpFormat::RRR, FuncMode::Full}, + {"CMP_LT", "011", Op::CMP_LT, OpFormat::RRR, FuncMode::Full}, + {"CMP_LE", "011", Op::CMP_LE, OpFormat::RRR, FuncMode::Full}, + {"CMP_GT", "011", Op::CMP_GT, OpFormat::RRR, FuncMode::Full}, + {"CMP_GE", "011", Op::CMP_GE, OpFormat::RRR, FuncMode::Full}, + {"GETBIT", "011", Op::GETBIT, OpFormat::RRR, FuncMode::None}, + {"SETBIT", "011", Op::SETBIT, OpFormat::RRR, FuncMode::None}, + {"CLRBIT", "011", Op::CLRBIT, OpFormat::RRR, FuncMode::None}, + {"TOGBIT", "011", Op::TOGBIT, OpFormat::RRR, FuncMode::None}, + // 8B 010 区 + {"LOADK", "010000", Op::LOADK, OpFormat::IMM, FuncMode::Full}, + {"LOAD", "010001", Op::LOAD, OpFormat::SLOT, FuncMode::Full}, + {"STORE", "010001", Op::STORE, OpFormat::SLOT, FuncMode::Full}, + {"JMP", "010010", Op::JMP, OpFormat::JMP, FuncMode::None}, + {"JT", "010011", Op::JT, OpFormat::JC, FuncMode::None}, + {"JF", "010011", Op::JF, OpFormat::JC, FuncMode::None}, + {"CALL", "010100", Op::CALL, OpFormat::CALL, FuncMode::None}, + {"CAL", "010101", Op::CAL, OpFormat::CAL, FuncMode::None}, + // 16B + {"LOAD_OFF", "0010", Op::LOAD_OFF, OpFormat::SLOT_OFF, FuncMode::Full}, + {"STORE_OFF", "0010", Op::STORE_OFF, OpFormat::SLOT_OFF, FuncMode::Full}, + {"STR_LEN", "0010", Op::STR_LEN, OpFormat::SLOT_OFF, FuncMode::None}, + {"STR_CMP", "0010", Op::STR_CMP, OpFormat::SLOT_OFF, FuncMode::None}, + {"STR_EQ", "0010", Op::STR_EQ, OpFormat::SLOT_OFF, FuncMode::None}, + {"STR_MID", "0010", Op::STR_MID, OpFormat::SLOT_OFF, FuncMode::None}, + {"STR_LEFT", "0010", Op::STR_LEFT, OpFormat::SLOT_OFF, FuncMode::None}, + {"STR_RIGHT", "0010", Op::STR_RIGHT, OpFormat::SLOT_OFF, FuncMode::None}, + {"LOADK64", "0011", Op::LOADK64, OpFormat::IMM64, FuncMode::Full}, + // 32B 预留 + {"JTBL", "0001", Op::JTBL, OpFormat::RESERVED, FuncMode::None}, + {"STR_CONCAT", "0001", Op::STR_CONCAT, OpFormat::RESERVED, FuncMode::None}, + {"STR_FIND", "0001", Op::STR_FIND, OpFormat::RESERVED, FuncMode::None}, + {"STR_REPLACE", "0001", Op::STR_REPLACE, OpFormat::RESERVED, FuncMode::None}, + {"ARR_LOAD", "0001", Op::ARR_LOAD, OpFormat::RESERVED, FuncMode::None}, + {"ARR_STORE", "0001", Op::ARR_STORE, OpFormat::RESERVED, FuncMode::None}, + }; + + int find_op(const char* prefix, uint8_t op) { + for (int i = 0; i < kOpCount; ++i) { + const char* p = kOps[i].prefix; + const char* q = prefix; + bool eq = true; + while (*p && *q) { + if (*p != *q) { eq = false; break; } + ++p; ++q; + } + if (eq && *p == *q && static_cast(kOps[i].op) == op) { + return i; + } + } + return -1; + } + + int find_op_by_name(const char* name) { + for (int i = 0; i < kOpCount; ++i) { + const char* p = kOps[i].name; + const char* q = name; + while (*p && *q && *p == *q) { ++p; ++q; } + if (*p == '\0' && *q == '\0') { + return i; + } + } + return -1; + } + + const char* mnemonic(const char* prefix, uint8_t op) { + const int i = find_op(prefix, op); + return i >= 0 ? kOps[i].name : "???"; + } + + OpFormat format_of(const char* prefix, uint8_t op) { + const int i = find_op(prefix, op); + return i >= 0 ? kOps[i].format : OpFormat::RESERVED; + } + + FuncMode func_mode_of(const char* prefix, uint8_t op) { + const int i = find_op(prefix, op); + return i >= 0 ? kOps[i].func_mode : FuncMode::None; + } + + bool uses_rd(OpFormat f) { + return f == OpFormat::RR || f == OpFormat::RRR || f == OpFormat::IMM || + f == OpFormat::SLOT || f == OpFormat::JC || f == OpFormat::SLOT_OFF || + f == OpFormat::IMM64; + } + + bool uses_rs1(OpFormat f) { + return f == OpFormat::RR || f == OpFormat::RRR; + } + + bool uses_rs2(OpFormat f) { + return f == OpFormat::RRR; + } + + const char* kFbNames[15] = { + "TON", "TOF", "TP", "CTU", "DCTU", "CTD", "DCTD", "CTUD", + "DCTUD", "R_TRIG", "F_TRIG", "SR", "RS", "PWM", "RTC", + }; +} diff --git a/tests/src/isa_test.cpp b/tests/src/isa_test.cpp index 5583c14..2424a28 100644 --- a/tests/src/isa_test.cpp +++ b/tests/src/isa_test.cpp @@ -1,15 +1,12 @@ /** * @file isa_test.cpp - * @brief isa 合同测试:饱和、编解码、disasm、哈希、映像、sidecar + * @brief isa V2 测试:饱和模板 / func 表 / 前缀定长 / 位号往返 / 编解码 / disasm / uses_* * @author * @date 2026-08-19 */ -#include #include #include -#include -#include #include "isa/Encode.h" #include "isa/Instr.h" @@ -18,119 +15,243 @@ static int g_checks = 0; -#define CHECK(cond) \ - do { \ - if (!(cond)) { \ +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ std::printf("FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \ - return false; \ - } \ - ++g_checks; \ + return false; \ + } \ + ++g_checks; \ } while (0) -// ---- 1. 饱和算术 ---- +// ---- 1. 饱和模板(各宽度 + 除法 A)---- static bool test_sat() { using namespace isa::types; - CHECK(sat_add(30000, 30000) == 32767); - CHECK(sat_add(-30000, -30000) == -32768); - CHECK(sat_add(10, 20) == 30); - CHECK(sat_sub(-30000, 30000) == -32768); - CHECK(sat_sub(5, 3) == 2); - CHECK(sat_mul(300, 200) == 32767); - CHECK(sat_mul(-300, 200) == -32768); - CHECK(sat_mul(6, 7) == 42); - CHECK(sat_div(10, 3) == 3); - CHECK(sat_div(-32768, -1) == 32767); // INT_MIN / -1 饱和 - CHECK(sat_div(7, 0) == 7); // 除零返回被除数 - CHECK(static_cast(TypeTag::Bool) == 0); - CHECK(static_cast(TypeTag::Int) == 1); - CHECK(static_cast(TypeTag::Time) == 2); + // int8 + CHECK(sat_add(100, 100) == 127); + CHECK(sat_add(-100, -100) == -128); + CHECK(sat_sub(-128, 1) == -128); + CHECK(sat_mul(20, 20) == 127); + CHECK(sat_div(-128, -1) == 127); // MIN/-1 饱和 + CHECK(sat_div(7, 0) == 7); // 除零返回被除数 + CHECK(sat_div(-7, 3) == -2); // 截断 + // int16 + CHECK(sat_add(30000, 30000) == 32767); + CHECK(sat_add(-30000, -30000) == -32768); + CHECK(sat_div(-32768, -1) == 32767); + CHECK(sat_div(10, 3) == 3); + CHECK(sat_div(7, 0) == 7); + // int32 / int64 边界 + CHECK(sat_add(2147483000, 1000) == 2147483647); + CHECK(sat_div(INT64_MIN, -1) == INT64_MAX); + CHECK(sat_add(INT64_MAX, 1) == INT64_MAX); return true; } -// ---- 2. 操作码与助记符 ---- +// ---- 2. func 表 ---- -static bool test_op() { - using namespace isa; - CHECK(static_cast(Op::MOVE) == 0); - CHECK(static_cast(Op::CAL_TON) == 24); - CHECK(static_cast(Op::CAL_F_TRIG) == 31); // 8 个 CAL_* 连续 24..31 - CHECK(static_cast(Op::CALL) == 32); - CHECK(static_cast(Op::RET) == 33); - CHECK(kOpCount == 34); - CHECK(std::strcmp(mnemonic(Op::CAL_CTUD), "CAL_CTUD") == 0); - CHECK(std::strcmp(mnemonic(Op::CAL_F_TRIG), "CAL_F_TRIG") == 0); - CHECK(std::strcmp(mnemonic(static_cast(255)), "???") == 0); +static bool test_func_table() { + using namespace isa::types; + CHECK(kFuncWidth[0] == 1 && !kFuncSigned[0]); // 1B 无 + CHECK(kFuncWidth[1] == 1 && kFuncSigned[1]); // 1B 有 + CHECK(kFuncWidth[3] == 2 && kFuncSigned[3]); // 2B 有(INT) + CHECK(kFuncWidth[4] == 4 && !kFuncSigned[4]); // 4B 无 + CHECK(kFuncWidth[6] == 8 && !kFuncSigned[6]); // 8B 无 + CHECK(kFuncWidth[7] == 8 && kFuncSigned[7]); // 8B 有 + CHECK(kFuncWidth[8] == 4); // F32 + CHECK(kFuncWidth[9] == 8); // F64 + CHECK(kFuncWidth[10] == 0); // 预留 return true; } -// ---- 3. 指令打包 / 拆字段 ---- +// ---- 3. 前缀定长 ---- -static bool test_instr() { +static bool test_instr_len() { using namespace isa; - const Instr w = pack(Op::ADD, 5, 3, 4); - CHECK(op(w) == Op::ADD); - CHECK(rd(w) == 5); - CHECK(a(w) == 3); - CHECK(b(w) == 4); - CHECK(imm16(enc_imm(Op::LOADK, 0, 0x1234)) == 0x1234); - CHECK(off16(enc_jmp(-1)) == -1); - CHECK(off16(enc_jmp(4)) == 4); - CHECK(rd(enc_jc(Op::JT, 2, -3)) == 2); - CHECK(off16(enc_jc(Op::JT, 2, -3)) == -3); - CHECK(imm16(enc_call(0xABCD)) == 0xABCD); - CHECK(imm16(enc_slot(Op::LOAD_I, 7, 300)) == 300); - CHECK(rd(enc_slot(Op::LOAD_I, 7, 300)) == 7); - CHECK(rd(enc_rr(Op::MOVE, 1, 2)) == 1); - CHECK(a(enc_rr(Op::MOVE, 1, 2)) == 2); - CHECK(op(enc_ret()) == Op::RET); + uint8_t buf[16] = {0}; + // 各前缀编码 → 长度 + set_byte0(buf, "11", 0); + CHECK(instr_len(buf) == 4); + set_byte0(buf, "10", 1); + CHECK(instr_len(buf) == 4); + set_byte0(buf, "011", 0); + CHECK(instr_len(buf) == 8); + set_byte0(buf, "010001", 0); + CHECK(instr_len(buf) == 8); + set_byte0(buf, "0010", 0); + CHECK(instr_len(buf) == 16); + set_byte0(buf, "0011", 0); + CHECK(instr_len(buf) == 16); + set_byte0(buf, "0001", 0); + CHECK(instr_len(buf) == 32); return true; } -// ---- 4. encode / decode / disasm ---- +// ---- 4. 位号往返 ---- -static bool test_encode() { +static bool test_fields() { using namespace isa; - const Instr w = enc_rrr(Op::ADD, 5, 3, 4); - CHECK(encode(decode(w)) == w); - CHECK(decode(w).op == Op::ADD); - CHECK(decode(w).rd == 5); - CHECK(decode(w).a == 3); - CHECK(decode(w).b == 4); + uint8_t buf[16] = {0}; + // RR(MOVE 11 区) + enc_rr(buf, "11", static_cast(isa::Op::MOVE), 0, 5, 3); + CHECK(op_of(buf) == static_cast(isa::Op::MOVE)); + CHECK(rd_of(buf) == 5); + CHECK(rs1_of(buf) == 3); + // RRR(ADD 011 区,func=3) + enc_rrr(buf, "011", static_cast(isa::Op::ADD), 3, 1, 2, 4); + CHECK(op_of(buf) == static_cast(isa::Op::ADD)); + CHECK(func_of(buf) == 3); + CHECK(rd_of(buf) == 1 && rs1_of(buf) == 2 && rs2_of(buf) == 4); + // SLOT(LOAD 010001 区) + enc_slot(buf, "010001", static_cast(isa::Op::LOAD), 0, 7, 300); + CHECK(rd_of(buf) == 7); + CHECK(slot32_of(buf) == 300); + // IMM(LOADK) + enc_imm(buf, "010000", static_cast(isa::Op::LOADK), 3, 0, 0x12345678); + CHECK(imm32_of(buf) == 0x12345678); + // JMP(010010) + enc_jmp(buf, -3); + CHECK(off32_of(buf) == -3); + // JC(010011,off@55..24 不覆盖 rd) + enc_jc(buf, static_cast(isa::Op::JT), 2, -3); + CHECK(rd_of(buf) == 2); + CHECK(off32_jc_of(buf) == -3); + // CALL(010100) + enc_call(buf, 7); + CHECK(fn_id32_of(buf) == 7); + // CAL(010101:fb_id16 + slot32) + enc_cal(buf, 3, 42); + CHECK(fb_id16_of(buf) == 3); + CHECK(cal_slot32_of(buf) == 42); + // SLOT_OFF(0010:off@87..56) + enc_slot_off(buf, static_cast(isa::Op::LOAD_OFF), 3, 1, 9, -12); + CHECK(slot32_of(buf) == 9); + CHECK(off32_hi_of(buf) == -12); + // RET + enc_ret(buf); + CHECK(op_of(buf) == static_cast(isa::Op::RET)); + return true; +} - char buf[64]; - disasm(w, buf, sizeof buf); - CHECK(std::strcmp(buf, "ADD r5, r3, r4") == 0); - disasm(enc_rr(Op::MOVE, 1, 2), buf, sizeof buf); - CHECK(std::strcmp(buf, "MOVE r1, r2") == 0); - disasm(enc_imm(Op::LOADK, 0, 3), buf, sizeof buf); - CHECK(std::strcmp(buf, "LOADK r0, 3") == 0); - disasm(enc_jmp(4), buf, sizeof buf); - CHECK(std::strcmp(buf, "JMP +4") == 0); - disasm(enc_jmp(-1), buf, sizeof buf); - CHECK(std::strcmp(buf, "JMP -1") == 0); - disasm(enc_jc(Op::JT, 0, -1), buf, sizeof buf); - CHECK(std::strcmp(buf, "JT r0, -1") == 0); - disasm(enc_call(1), buf, sizeof buf); - CHECK(std::strcmp(buf, "CALL 1") == 0); - disasm(enc_slot(Op::LOAD_I, 0, 2), buf, sizeof buf); - CHECK(std::strcmp(buf, "LOAD_I r0, 2") == 0); - disasm(enc_slot(Op::STORE_Q, 4, 0), buf, sizeof buf); - CHECK(std::strcmp(buf, "STORE_Q r4, 0") == 0); - disasm(enc_ret(), buf, sizeof buf); - CHECK(std::strcmp(buf, "RET") == 0); - disasm(enc_imm(Op::CAL_TON, 0, 0), buf, sizeof buf); - CHECK(std::strcmp(buf, "CAL_TON 0") == 0); - disasm(0xFFu, buf, sizeof buf); // 未知操作码 - CHECK(std::strcmp(buf, "??? 0x000000ff") == 0); +// ---- 5. decode/encode 往返 ---- + +static bool test_roundtrip() { + using namespace isa; + uint8_t buf[16] = {0}; + enc_rrr(buf, "011", static_cast(isa::Op::ADD), 5, 3, 7, 9); + const isa::Decoded d = isa::decode(buf, 8); + CHECK(std::strcmp(d.prefix, "011") == 0); + CHECK(d.op == static_cast(isa::Op::ADD)); + CHECK(d.func == 5); + CHECK(d.rd == 3 && d.rs1 == 7 && d.rs2 == 9); + uint8_t buf2[16] = {0}; + const size_t len = isa::encode(d, buf2); + CHECK(len == 8); + CHECK(std::memcmp(buf, buf2, 8) == 0); + return true; +} + +// ---- 6. disasm 文本 ---- + +static bool test_disasm() { + using namespace isa; + uint8_t buf[16] = {0}; + char out[64]; + // 无类型:RET + enc_ret(buf); + isa::disasm(buf, 4, out, sizeof out); + CHECK(std::strcmp(out, "RET") == 0); + // RR:MOVE + enc_rr(buf, "11", static_cast(isa::Op::MOVE), 0, 1, 2); + isa::disasm(buf, 4, out, sizeof out); + CHECK(std::strcmp(out, "MOVE r1, r2") == 0); + // RRR 类型后缀:ADD.F32 + enc_rrr(buf, "011", static_cast(isa::Op::ADD), 8, 1, 2, 3); + isa::disasm(buf, 8, out, sizeof out); + CHECK(std::strcmp(out, "ADD.F32 r1, r2, r3") == 0); + // SLOT:LOAD.I16 + enc_slot(buf, "010001", static_cast(isa::Op::LOAD), 3, 5, 4); + isa::disasm(buf, 8, out, sizeof out); + CHECK(std::strcmp(out, "LOAD.I16 r5, s4") == 0); + // JMP + enc_jmp(buf, 12); + isa::disasm(buf, 8, out, sizeof out); + CHECK(std::strcmp(out, "JMP +12") == 0); + // JC + enc_jc(buf, static_cast(isa::Op::JT), 0, -1); + isa::disasm(buf, 8, out, sizeof out); + CHECK(std::strcmp(out, "JT r0, -1") == 0); + // CALL + enc_call(buf, 3); + isa::disasm(buf, 8, out, sizeof out); + CHECK(std::strcmp(out, "CALL 3") == 0); + // CAL:fb 名 + enc_cal(buf, 0, 5); + isa::disasm(buf, 8, out, sizeof out); + CHECK(std::strcmp(out, "CAL.TON s5") == 0); + enc_cal(buf, 4, 9); + isa::disasm(buf, 8, out, sizeof out); + CHECK(std::strcmp(out, "CAL.DCTU s9") == 0); + // SLOT_OFF + enc_slot_off(buf, static_cast(isa::Op::LOAD_OFF), 3, 2, 8, 16); + isa::disasm(buf, 16, out, sizeof out); + CHECK(std::strcmp(out, "LOAD_OFF.I16 r2, s8, 16") == 0); + // 未知(010110 预留区) + buf[0] = 0x58; + isa::disasm(buf, 8, out, sizeof out); + CHECK(std::strncmp(out, "??? 0x", 6) == 0); + return true; +} + +// ---- 7. uses_* 直推 ---- + +static bool test_uses() { + using namespace isa; + CHECK(uses_rd(OpFormat::RR) && uses_rs1(OpFormat::RR) && !uses_rs2(OpFormat::RR)); + CHECK(uses_rd(OpFormat::RRR) && uses_rs1(OpFormat::RRR) && uses_rs2(OpFormat::RRR)); + CHECK(uses_rd(OpFormat::IMM) && !uses_rs1(OpFormat::IMM)); + CHECK(uses_rd(OpFormat::SLOT) && !uses_rs1(OpFormat::SLOT)); + CHECK(uses_rd(OpFormat::JC) && !uses_rs1(OpFormat::JC)); + CHECK(!uses_rd(OpFormat::JMP) && !uses_rd(OpFormat::CALL)); + CHECK(!uses_rd(OpFormat::CAL) && !uses_rd(OpFormat::NONE)); + CHECK(uses_rd(OpFormat::SLOT_OFF) && uses_rd(OpFormat::IMM64)); + return true; +} + +// ---- 8. 指令表查询 ---- + +static bool test_op_table() { + using namespace isa; + CHECK(find_op("11", static_cast(Op::MOVE)) == 0); + CHECK(find_op("011", static_cast(Op::ADD)) >= 0); + CHECK(find_op("010001", static_cast(Op::LOAD)) >= 0); + CHECK(find_op("010101", static_cast(Op::CAL)) >= 0); + CHECK(find_op("99", 0) == -1); + CHECK(find_op_by_name("MOVE") == 0); + CHECK(find_op_by_name("ADD") >= 0); + CHECK(find_op_by_name("CAL") >= 0); + CHECK(find_op_by_name("NOPE") == -1); + CHECK(std::strcmp(mnemonic("11", static_cast(Op::MOVE)), "MOVE") == 0); + CHECK(std::strcmp(mnemonic("011", static_cast(Op::ADD)), "ADD") == 0); + CHECK(std::strcmp(mnemonic("99", 0), "???") == 0); + CHECK(format_of("010101", static_cast(Op::CAL)) == OpFormat::CAL); + CHECK(func_mode_of("11", static_cast(Op::MOVE)) == FuncMode::Width); + CHECK(func_mode_of("010001", static_cast(Op::LOAD)) == FuncMode::Full); + CHECK(std::strcmp(kFbNames[0], "TON") == 0); + CHECK(std::strcmp(kFbNames[14], "RTC") == 0); return true; } int main() { if (!test_sat()) return 1; - if (!test_op()) return 1; - if (!test_instr()) return 1; - if (!test_encode()) return 1; + if (!test_func_table()) return 1; + if (!test_instr_len()) return 1; + if (!test_fields()) return 1; + if (!test_roundtrip()) return 1; + if (!test_disasm()) return 1; + if (!test_uses()) return 1; + if (!test_op_table()) return 1; std::printf("isa_test: %d checks passed\n", g_checks); return 0; }