阶段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:
+2
-1
@@ -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
@@ -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<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
@@ -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 取 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<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 取 off32(47..16 = 字节 2..5,JMP 形态,有符号)。
|
||||
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 取 off32(55..24 = 字节 3..6,JC 形态,有符号)。
|
||||
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_id32(47..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_id16(31..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 的 off32(87..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 取 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<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') {
|
||||
// 11:bit7..6 = 11;10:bit7..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 编码 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<uint8_t>(Op::RET));
|
||||
set_func(out, 0);
|
||||
return instr_len(out);
|
||||
}
|
||||
}
|
||||
|
||||
+100
-127
@@ -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 <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(前缀 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<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
@@ -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<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 返回 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 <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
@@ -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 → 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<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
@@ -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
@@ -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};
|
||||
// RR(MOVE 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);
|
||||
// RRR(ADD 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);
|
||||
// SLOT(LOAD 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);
|
||||
// IMM(LOADK)
|
||||
enc_imm(buf, "010000", static_cast<uint8_t>(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<uint8_t>(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<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);
|
||||
// RR:MOVE
|
||||
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);
|
||||
// SLOT:LOAD.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);
|
||||
// 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<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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user