阶段4-1:isa 重构 V2 完成(Types/Op/Instr/Encode + isa_test 91 checks)

- 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 同步
This commit is contained in:
2026-08-26 09:56:43 +08:00
parent 384e681ef3
commit 4f3da55ed7
8 changed files with 968 additions and 466 deletions
+2 -1
View File
@@ -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)
+28 -22
View File
@@ -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; ///< rd23..16
uint8_t rs1 = 0; ///< rs131..24
uint8_t rs2 = 0; ///< rs239..32
uint32_t imm32 = 0; ///< imm/slot/fn_id(按形态)
int32_t off_hi = 0; ///< SLOT_OFF 的 off3287..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<w>`。
* @details 按形态表驱动输出(类型后缀:full/float/dst 类显示 .U8/.I16/.F32 等;
* CAL 显示 fb 名如 `CAL.TON s5`);未知 (prefix,op) 输出 `??? 0x<hex>`。
*/
void disasm(Instr w, char* out, size_t cap);
void disasm(const uint8_t* code, size_t len, char* out, size_t cap);
}
+258 -129
View File
@@ -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<uint32_t>(static_cast<uint8_t>(op))
| (static_cast<uint32_t>(rd) << 8)
| (static_cast<uint32_t>(a) << 16)
| (static_cast<uint32_t>(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<Op>(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<uint8_t>((w >> 8) & 0xFFu);
/// @brief 取 func 位段(字节 1 高 4 位)。
inline uint8_t func_of(const uint8_t* code) {
return static_cast<uint8_t>((code[1] >> 4) & 0x0F);
}
/**
* @brief 取 a 字段。
* @param w 指令字
* @return a(第 16..23 位)
*/
inline uint8_t a(Instr w) {
return static_cast<uint8_t>((w >> 16) & 0xFFu);
/// @brief 取 rd23..16 = 字节 2)。
inline uint8_t rd_of(const uint8_t* code) { return code[2]; }
/// @brief 取 rs131..24 = 字节 3)。
inline uint8_t rs1_of(const uint8_t* code) { return code[3]; }
/// @brief 取 rs239..32 = 字节 4)。
inline uint8_t rs2_of(const uint8_t* code) { return code[4]; }
/// @brief 取 imm3255..24 = 字节 3..6,小端)。
inline uint32_t imm32_of(const uint8_t* code) {
return static_cast<uint32_t>(code[3])
| (static_cast<uint32_t>(code[4]) << 8)
| (static_cast<uint32_t>(code[5]) << 16)
| (static_cast<uint32_t>(code[6]) << 24);
}
/**
* @brief 取 b 字段。
* @param w 指令字
* @return b(第 24..31 位)
*/
inline uint8_t b(Instr w) {
return static_cast<uint8_t>((w >> 24) & 0xFFu);
/// @brief 取 slot32(同 imm32 位号)。
inline uint32_t slot32_of(const uint8_t* code) { return imm32_of(code); }
/// @brief 取 off3247..16 = 字节 2..5JMP 形态,有符号)。
inline int32_t off32_of(const uint8_t* code) {
return static_cast<int32_t>(static_cast<uint32_t>(code[2])
| (static_cast<uint32_t>(code[3]) << 8)
| (static_cast<uint32_t>(code[4]) << 16)
| (static_cast<uint32_t>(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<uint16_t>(a(w) | (static_cast<uint16_t>(b(w)) << 8));
/// @brief 取 off3255..24 = 字节 3..6JC 形态,有符号)。
inline int32_t off32_jc_of(const uint8_t* code) {
return static_cast<int32_t>(static_cast<uint32_t>(code[3])
| (static_cast<uint32_t>(code[4]) << 8)
| (static_cast<uint32_t>(code[5]) << 16)
| (static_cast<uint32_t>(code[6]) << 24));
}
/**
* @brief 组合视图:a|b 为有符号相对偏移。
* @param w 指令字
* @return 偏移量,单位是指令条数(跳转目标 = 下一条指令 + off)
*/
inline int16_t off16(Instr w) {
return static_cast<int16_t>(imm16(w));
/// @brief 取 fn_id3247..16 = 字节 2..5)。
inline uint32_t fn_id32_of(const uint8_t* code) {
return static_cast<uint32_t>(code[2])
| (static_cast<uint32_t>(code[3]) << 8)
| (static_cast<uint32_t>(code[4]) << 16)
| (static_cast<uint32_t>(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_id1631..16 = 字节 2..3)。
inline uint16_t fb_id16_of(const uint8_t* code) {
return static_cast<uint16_t>(code[2] | (static_cast<uint16_t>(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<uint32_t>(code[4])
| (static_cast<uint32_t>(code[5]) << 8)
| (static_cast<uint32_t>(code[6]) << 16)
| (static_cast<uint32_t>(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<uint8_t>(imm & 0xFFu),
static_cast<uint8_t>((imm >> 8) & 0xFFu));
/// @brief 取 SLOT_OFF 的 off3287..56 = 字节 7..10,有符号)。
inline int32_t off32_hi_of(const uint8_t* code) {
return static_cast<int32_t>(static_cast<uint32_t>(code[7])
| (static_cast<uint32_t>(code[8]) << 8)
| (static_cast<uint32_t>(code[9]) << 16)
| (static_cast<uint32_t>(code[10]) << 24));
}
/**
* @brief 按 JMP 形态编码。
* @param off 有符号相对偏移(条数),拆成 a|b 存放
* @return 指令字
*/
inline Instr enc_jmp(int16_t off) {
return pack(Op::JMP, 0,
static_cast<uint8_t>(static_cast<uint16_t>(off) & 0xFFu),
static_cast<uint8_t>((static_cast<uint16_t>(off) >> 8) & 0xFFu));
/// @brief 取 imm6487..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<uint64_t>(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<uint8_t>(static_cast<uint16_t>(off) & 0xFFu),
static_cast<uint8_t>((static_cast<uint16_t>(off) >> 8) & 0xFFu));
// ---- 发射器(写字节,调用方提供 ≥16 字节缓冲;返回指令长度)----
/// @brief 写字节 0(前缀 + 分区内 op)。
inline void set_byte0(uint8_t* out, const char* prefix, uint8_t op) {
if (prefix[0] == '1') {
// 11bit7..6 = 1110bit7..6 = 10
out[0] = static_cast<uint8_t>((prefix[1] == '1' ? 0xC0 : 0x80) | (op & 0x3F));
} else if (prefix[0] == '0') {
if (prefix[1] == '1' && prefix[2] == '1') {
out[0] = static_cast<uint8_t>(0x60 | (op & 0x1F)); // 011
} else if (prefix[1] == '1') {
// 010xxx:形态位 3 位 + 子 op 2 位
const uint8_t shape = static_cast<uint8_t>(
(prefix[3] - '0') * 4 + (prefix[4] - '0') * 2 + (prefix[5] - '0'));
out[0] = static_cast<uint8_t>(0x40 | (shape << 2) | (op & 0x03));
} else if (prefix[2] == '1') {
out[0] = static_cast<uint8_t>(0x20 | (op & 0x0F)); // 0010/0011
} else {
out[0] = static_cast<uint8_t>(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<uint8_t>((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<uint8_t>(v & 0xFF);
out[4] = static_cast<uint8_t>((v >> 8) & 0xFF);
out[5] = static_cast<uint8_t>((v >> 16) & 0xFF);
out[6] = static_cast<uint8_t>((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<uint32_t>(v);
out[2] = static_cast<uint8_t>(u & 0xFF);
out[3] = static_cast<uint8_t>((u >> 8) & 0xFF);
out[4] = static_cast<uint8_t>((u >> 16) & 0xFF);
out[5] = static_cast<uint8_t>((u >> 24) & 0xFF);
}
inline void set_off32_jc(uint8_t* out, int32_t v) { // JC:字节 3..6
const uint32_t u = static_cast<uint32_t>(v);
out[3] = static_cast<uint8_t>(u & 0xFF);
out[4] = static_cast<uint8_t>((u >> 8) & 0xFF);
out[5] = static_cast<uint8_t>((u >> 16) & 0xFF);
out[6] = static_cast<uint8_t>((u >> 24) & 0xFF);
}
inline void set_fn_id32(uint8_t* out, uint32_t v) { set_off32(out, static_cast<int32_t>(v)); }
inline void set_fb_id16(uint8_t* out, uint16_t v) {
out[2] = static_cast<uint8_t>(v & 0xFF);
out[3] = static_cast<uint8_t>((v >> 8) & 0xFF);
}
inline void set_cal_slot32(uint8_t* out, uint32_t v) {
out[4] = static_cast<uint8_t>(v & 0xFF);
out[5] = static_cast<uint8_t>((v >> 8) & 0xFF);
out[6] = static_cast<uint8_t>((v >> 16) & 0xFF);
out[7] = static_cast<uint8_t>((v >> 24) & 0xFF);
}
inline void set_off32_hi(uint8_t* out, int32_t v) { // SLOT_OFF:字节 7..10
const uint32_t u = static_cast<uint32_t>(v);
out[7] = static_cast<uint8_t>(u & 0xFF);
out[8] = static_cast<uint8_t>((u >> 8) & 0xFF);
out[9] = static_cast<uint8_t>((u >> 16) & 0xFF);
out[10] = static_cast<uint8_t>((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<uint8_t>((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 编码 JMP010010 区),返回指令长度。
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/JF010011 区),返回指令长度。
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 编码 CALL010100 区),返回指令长度。
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 编码 CAL010101 区),返回指令长度。
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_OFFLOAD_OFF/STORE_OFF0010 区),返回指令长度。
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 编码 RET10 区),返回指令长度。
inline size_t enc_ret(uint8_t* out) {
set_byte0(out, "10", static_cast<uint8_t>(Op::RET));
set_func(out, 0);
return instr_len(out);
}
}
+100 -127
View File
@@ -1,8 +1,13 @@
/**
* @file Op.h
* @brief 操作码枚举、操作数形态与编译期指令表
* @details 操作码数值即 .stb 指令编码。执行器(vm)只依赖本表;
* 编译器侧的登记见 Doc/isa/指令配置.mdcompiler/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 <cstdint>
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(前缀 11op 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(前缀 10op 6 位)
NOP = 0, RET = 1,
// 8B RRR(前缀 011op 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/0011op 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 预留(前缀 0001op 4 位)
JTBL = 0, STR_CONCAT = 1, STR_FIND = 2, STR_REPLACE = 3,
ARR_LOAD = 4, ARR_STORE = 5,
};
/// 操作码总数(= 最大 opcode + 1kOpDefs 的下标上界)。
static const int kOpCount = 34;
/**
* @brief 操作数形态(三层分类第二层,见 Doc/isa/指令配置.md)。
* @details 决定操作数 a|b 的解释方式与反汇编文本格式。
* @brief 操作数形态(前缀分区的语义标签)。
*/
enum class OpFormat : uint8_t {
RR, // 两寄存器:rd rsMOVE / NOT
RRR, // 三寄存器:rd ra rb(逻辑 / 算术 / 比较
IMM, // 常量:rd const_idLOADK
SLOT, // 槽:rd slotLOAD_* / STORE_*
JMP, // 偏移:off
JC, // 条件跳转:r offJT / JF
CALL, // 调用:fn_id
CAL, // 实例:instanceCAL_*
NONE, // 无操作数(RET
RR, ///< rd, rs4B
NONE, ///< 无操作数(4B
RRR, ///< rd, ra, rb8B
IMM, ///< rd, imm328B
SLOT, ///< rd, slot328B
JMP, ///< off328B
JC, ///< rd, off328B
CALL, ///< fn_id328B
CAL, ///< fb_id16, slot328B
SLOT_OFF, ///< rd, slot32, off3216B
IMM64, ///< rd, imm6416B
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/算术/CMPfunc 0..9 全矩阵
Float, ///< 浮点单目/舍入:func 8/9
Dst, ///< CONVfunc = 目标类型
};
/// 前缀字符串。
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<int>(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<int>(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<int>(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];
}
+62 -50
View File
@@ -1,8 +1,12 @@
/**
* @file Types.h
* @brief 定宽类型与饱和算术
* @brief 定宽类型、func 表与饱和算术V2
* @details 虚拟机字长与类型契约的唯一来源。compiler 与 vm 共用同一套规则,
* 详见 Doc/isa/指令与映像.md。
* 详见 Doc/isa/指令与映像.mdV2
* - 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 无 tagLOADK 按 func 解释)
* @author
* @date 2026-08-18
*/
@@ -14,93 +18,101 @@
namespace isa {
namespace types {
/**
* @brief 布尔值:8 位,只允许 0/10=FALSE1=TRUE)。
*/
/// 布尔值:8 位,只允许 0/10=FALSE1=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..71B无/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<int32_t>(a) + static_cast<int32_t>(b);
return static_cast<INT>(sum < std::numeric_limits<INT>::min() ? std::numeric_limits<INT>::min()
: sum > std::numeric_limits<INT>::max() ? std::numeric_limits<INT>::max()
: sum);
template <typename T>
T sat_add(T a, T b) {
const __int128 sum = static_cast<__int128>(a) + static_cast<__int128>(b);
return static_cast<T>(sum < std::numeric_limits<T>::min()
? std::numeric_limits<T>::min()
: sum > std::numeric_limits<T>::max()
? std::numeric_limits<T>::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<int32_t>(a) - static_cast<int32_t>(b);
return static_cast<INT>(diff < std::numeric_limits<INT>::min() ? std::numeric_limits<INT>::min()
: diff > std::numeric_limits<INT>::max() ? std::numeric_limits<INT>::max()
: diff);
template <typename T>
T sat_sub(T a, T b) {
const __int128 diff = static_cast<__int128>(a) - static_cast<__int128>(b);
return static_cast<T>(diff < std::numeric_limits<T>::min()
? std::numeric_limits<T>::min()
: diff > std::numeric_limits<T>::max()
? std::numeric_limits<T>::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<int32_t>(a) * static_cast<int32_t>(b);
return static_cast<INT>(prod < std::numeric_limits<INT>::min() ? std::numeric_limits<INT>::min()
: prod > std::numeric_limits<INT>::max() ? std::numeric_limits<INT>::max()
: prod);
template <typename T>
T sat_mul(T a, T b) {
const __int128 prod = static_cast<__int128>(a) * static_cast<__int128>(b);
return static_cast<T>(prod < std::numeric_limits<T>::min()
? std::numeric_limits<T>::min()
: prod > std::numeric_limits<T>::max()
? std::numeric_limits<T>::max()
: prod);
}
/**
* @brief 饱和除法。
* @brief 饱和除法(除法 A 定案)
* @param a 被除数
* @param b 除数
* @return a/b;b==0 视为除以 1 返回 aINT_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 <typename T>
T sat_div(T a, T b) {
if (b == 0) {
return a;
return a; // 除零返回被除数(Fail-safe
}
if (a == std::numeric_limits<INT>::min() && b == -1) {
return std::numeric_limits<INT>::max();
if (a == std::numeric_limits<T>::min() && b == T(-1)) {
return std::numeric_limits<T>::max(); // MIN/-1 溢出饱和
}
return static_cast<INT>(a / b);
return static_cast<T>(a / b);
}
}
}
+144 -46
View File
@@ -1,6 +1,6 @@
/**
* @file Encode.cpp
* @brief 指令编解码与反汇编实现
* @brief 指令编解码与反汇编实现V2
* @author
* @date 2026-08-19
*/
@@ -8,83 +8,181 @@
#include "isa/Encode.h"
#include <cstdio>
#include <cstring>
#include <string>
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 → imm32JMP/JC → offCALL → 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<uint32_t>(off32_of(code));
} else if (f == OpFormat::JC) {
d.imm32 = static_cast<uint32_t>(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<w>`。
* @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<int32_t>(d.imm32));
} else if (f == OpFormat::JC) {
set_off32_jc(out, static_cast<int32_t>(d.imm32));
} else if (f == OpFormat::CALL) {
set_fn_id32(out, d.imm32);
} else if (f == OpFormat::CAL) {
set_fb_id16(out, static_cast<uint16_t>(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<int>(o);
if (idx < 0 || idx >= kOpCount) {
snprintf(out, cap, "??? 0x%08x", static_cast<unsigned>(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<unsigned>(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<unsigned>(rd(w)), static_cast<unsigned>(a(w)));
snprintf(out, cap, "%s%s r%u, r%u", od.name, suffix.c_str(),
static_cast<unsigned>(d.rd), static_cast<unsigned>(d.rs1));
break;
case OpFormat::RRR:
snprintf(out, cap, "%s r%u, r%u, r%u", m,
static_cast<unsigned>(rd(w)), static_cast<unsigned>(a(w)),
static_cast<unsigned>(b(w)));
snprintf(out, cap, "%s%s r%u, r%u, r%u", od.name, suffix.c_str(),
static_cast<unsigned>(d.rd), static_cast<unsigned>(d.rs1),
static_cast<unsigned>(d.rs2));
break;
case OpFormat::IMM:
snprintf(out, cap, "%s%s r%u, %u", od.name, suffix.c_str(),
static_cast<unsigned>(d.rd), static_cast<unsigned>(d.imm32));
break;
case OpFormat::SLOT:
snprintf(out, cap, "%s r%u, %u", m,
static_cast<unsigned>(rd(w)), static_cast<unsigned>(imm16(w)));
snprintf(out, cap, "%s%s r%u, s%u", od.name, suffix.c_str(),
static_cast<unsigned>(d.rd), static_cast<unsigned>(d.imm32));
break;
case OpFormat::JMP:
snprintf(out, cap, "%s %+d", m, static_cast<int>(off16(w)));
snprintf(out, cap, "%s %+d", od.name, static_cast<int>(d.imm32));
break;
case OpFormat::JC:
snprintf(out, cap, "%s r%u, %+d", m,
static_cast<unsigned>(rd(w)), static_cast<int>(off16(w)));
snprintf(out, cap, "%s r%u, %+d", od.name, static_cast<unsigned>(d.rd),
static_cast<int>(d.imm32));
break;
case OpFormat::CALL:
case OpFormat::CAL:
snprintf(out, cap, "%s %u", m, static_cast<unsigned>(imm16(w)));
snprintf(out, cap, "%s %u", od.name, static_cast<unsigned>(d.imm32));
break;
case OpFormat::CAL: {
const uint16_t fb = static_cast<uint16_t>(d.imm32 & 0xFFFF);
const char* fbname = (fb < 15) ? kFbNames[fb] : "?";
snprintf(out, cap, "CAL.%s s%u", fbname, static_cast<unsigned>(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<unsigned>(d.rd), static_cast<unsigned>(d.imm32),
static_cast<int>(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;
}
}
+162
View File
@@ -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<uint8_t>(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",
};
}
+212 -91
View File
@@ -1,15 +1,12 @@
/**
* @file isa_test.cpp
* @brief isa 合同测试:饱和、编解码、disasm、哈希、映像、sidecar
* @brief isa V2 测试:饱和模板 / func 表 / 前缀定长 / 位号往返 / 编解码 / disasm / uses_*
* @author
* @date 2026-08-19
*/
#include <cassert>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#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<int>(TypeTag::Bool) == 0);
CHECK(static_cast<int>(TypeTag::Int) == 1);
CHECK(static_cast<int>(TypeTag::Time) == 2);
// int8
CHECK(sat_add<int8_t>(100, 100) == 127);
CHECK(sat_add<int8_t>(-100, -100) == -128);
CHECK(sat_sub<int8_t>(-128, 1) == -128);
CHECK(sat_mul<int8_t>(20, 20) == 127);
CHECK(sat_div<int8_t>(-128, -1) == 127); // MIN/-1 饱和
CHECK(sat_div<int8_t>(7, 0) == 7); // 除零返回被除数
CHECK(sat_div<int8_t>(-7, 3) == -2); // 截断
// int16
CHECK(sat_add<int16_t>(30000, 30000) == 32767);
CHECK(sat_add<int16_t>(-30000, -30000) == -32768);
CHECK(sat_div<int16_t>(-32768, -1) == 32767);
CHECK(sat_div<int16_t>(10, 3) == 3);
CHECK(sat_div<int16_t>(7, 0) == 7);
// int32 / int64 边界
CHECK(sat_add<int32_t>(2147483000, 1000) == 2147483647);
CHECK(sat_div<int64_t>(INT64_MIN, -1) == INT64_MAX);
CHECK(sat_add<int64_t>(INT64_MAX, 1) == INT64_MAX);
return true;
}
// ---- 2. 操作码与助记符 ----
// ---- 2. func 表 ----
static bool test_op() {
using namespace isa;
CHECK(static_cast<int>(Op::MOVE) == 0);
CHECK(static_cast<int>(Op::CAL_TON) == 24);
CHECK(static_cast<int>(Op::CAL_F_TRIG) == 31); // 8 个 CAL_* 连续 24..31
CHECK(static_cast<int>(Op::CALL) == 32);
CHECK(static_cast<int>(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<Op>(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};
// RRMOVE 11 区)
enc_rr(buf, "11", static_cast<uint8_t>(isa::Op::MOVE), 0, 5, 3);
CHECK(op_of(buf) == static_cast<uint8_t>(isa::Op::MOVE));
CHECK(rd_of(buf) == 5);
CHECK(rs1_of(buf) == 3);
// RRRADD 011 区,func=3
enc_rrr(buf, "011", static_cast<uint8_t>(isa::Op::ADD), 3, 1, 2, 4);
CHECK(op_of(buf) == static_cast<uint8_t>(isa::Op::ADD));
CHECK(func_of(buf) == 3);
CHECK(rd_of(buf) == 1 && rs1_of(buf) == 2 && rs2_of(buf) == 4);
// SLOTLOAD 010001 区)
enc_slot(buf, "010001", static_cast<uint8_t>(isa::Op::LOAD), 0, 7, 300);
CHECK(rd_of(buf) == 7);
CHECK(slot32_of(buf) == 300);
// IMMLOADK
enc_imm(buf, "010000", static_cast<uint8_t>(isa::Op::LOADK), 3, 0, 0x12345678);
CHECK(imm32_of(buf) == 0x12345678);
// JMP010010
enc_jmp(buf, -3);
CHECK(off32_of(buf) == -3);
// JC010011off@55..24 不覆盖 rd
enc_jc(buf, static_cast<uint8_t>(isa::Op::JT), 2, -3);
CHECK(rd_of(buf) == 2);
CHECK(off32_jc_of(buf) == -3);
// CALL010100
enc_call(buf, 7);
CHECK(fn_id32_of(buf) == 7);
// CAL010101fb_id16 + slot32
enc_cal(buf, 3, 42);
CHECK(fb_id16_of(buf) == 3);
CHECK(cal_slot32_of(buf) == 42);
// SLOT_OFF0010off@87..56
enc_slot_off(buf, static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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);
// RRMOVE
enc_rr(buf, "11", static_cast<uint8_t>(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<uint8_t>(isa::Op::ADD), 8, 1, 2, 3);
isa::disasm(buf, 8, out, sizeof out);
CHECK(std::strcmp(out, "ADD.F32 r1, r2, r3") == 0);
// SLOTLOAD.I16
enc_slot(buf, "010001", static_cast<uint8_t>(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<uint8_t>(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);
// CALfb 名
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<uint8_t>(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<uint8_t>(Op::MOVE)) == 0);
CHECK(find_op("011", static_cast<uint8_t>(Op::ADD)) >= 0);
CHECK(find_op("010001", static_cast<uint8_t>(Op::LOAD)) >= 0);
CHECK(find_op("010101", static_cast<uint8_t>(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<uint8_t>(Op::MOVE)), "MOVE") == 0);
CHECK(std::strcmp(mnemonic("011", static_cast<uint8_t>(Op::ADD)), "ADD") == 0);
CHECK(std::strcmp(mnemonic("99", 0), "???") == 0);
CHECK(format_of("010101", static_cast<uint8_t>(Op::CAL)) == OpFormat::CAL);
CHECK(func_mode_of("11", static_cast<uint8_t>(Op::MOVE)) == FuncMode::Width);
CHECK(func_mode_of("010001", static_cast<uint8_t>(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;
}