新类型运算验证(综合用例全部正确): - REAL 算术 ADD.F32、LREAL 算术 ADD.F64 - TIME+ ADD.I64、TIME 比较 CMP_GT.I64 - DATE/TOD/DT 比较 CMP_GT.U32/U32/U64 - DINT 算术 ADD.I32、UDINT 字面量装载+截断 - WORD 位串 AND(短路 JF+MOVE) - 负例:UINT 溢出拦截 修复的 bug: 1. set_byte0 '011' 分支 0x40→0x60(RRR 指令被误判为 010 区, ADD 等显示错乱)——阶段 2 遗留 2. Codegen func_of_name 大小写不敏感(符号表小写/type 表大写, 否则 REAL 等返回 func 0) 3. Typecheck AND/OR 支持位串(BOOL 逻辑或 bit 按宽度逐位) 已知缺陷(记录):LREAL 字面量装载按 REAL(LOADK.F32), ADD.F64 运算位模式错位——需 compile_expr 携带目标 func(TODO)。
347 lines
12 KiB
C++
347 lines
12 KiB
C++
/**
|
||
* @file Codec.cpp
|
||
* @brief 指令字编解码 + 配置驱动反汇编(编译器侧,V2)
|
||
* @author
|
||
* @date 2026-08-21
|
||
*
|
||
* @details 变长指令字(前缀分区)的位号读写与 disasm;位号见 Doc/isa/指令编码.md:
|
||
* - 字节 0 = [长度前缀+形态分区 | op];字节 1 = [func:4 | 空:4]
|
||
* - 操作数区 bit16 起(rd=23..16、imm32/slot32=55..24、off32/fn_id32=47..16 等)
|
||
*/
|
||
|
||
#include "compiler/Codec.h"
|
||
|
||
#include <cstdio>
|
||
|
||
namespace compiler {
|
||
|
||
namespace {
|
||
|
||
/**
|
||
* @brief func → 类型后缀(disasm 用,A7 定案)。
|
||
* @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];
|
||
}
|
||
|
||
/**
|
||
* @brief 形态前缀是否带类型后缀(disasm 显示 .TYPE)。
|
||
* @param mode func 类别(none/width/uint/full/float/dst)
|
||
* @return full/float/dst → true(显示类型后缀)
|
||
*/
|
||
bool shows_type_suffix(const std::string& mode) {
|
||
return mode == "full" || mode == "float" || mode == "dst";
|
||
}
|
||
|
||
} // namespace
|
||
|
||
/**
|
||
* @brief 前缀定长:读字节 0 判指令长度。
|
||
* @param code 指令字节(至少 1 字节)
|
||
* @return 4/8/16/32(前缀 `1`/`01`/`001`/`0001`)
|
||
*/
|
||
size_t instr_len(const uint8_t* code) {
|
||
const uint8_t b = code[0];
|
||
if (b & 0x80) return 4; // 1xxxxxxx → 4B
|
||
if ((b & 0xC0) == 0x40) return 8; // 01xxxxxx → 8B
|
||
if ((b & 0xE0) == 0x20) return 16; // 001xxxxx → 16B
|
||
return 32; // 0001xxxx → 32B
|
||
}
|
||
|
||
/**
|
||
* @brief 推导形态前缀字符串。
|
||
* @param code 指令字节
|
||
* @return "11"/"10"/"011"/"010000".."010101"/"0010"/"0011"/"0001"
|
||
*/
|
||
std::string prefix_of(const uint8_t* code) {
|
||
const uint8_t b = code[0];
|
||
if (b & 0x80) {
|
||
return (b & 0x40) ? "11" : "10"; // 4B:bit6 区分 11/10
|
||
}
|
||
if ((b & 0xC0) == 0x40) {
|
||
if (b & 0x20) {
|
||
return "011"; // 8B RRR
|
||
}
|
||
static const char* kShapes[8] = {
|
||
"010000", "010001", "010010", "010011", "010100", "010101", "010110", "010111",
|
||
};
|
||
return kShapes[(b >> 2) & 0x07]; // 8B 010:形态位 3 位
|
||
}
|
||
if ((b & 0xE0) == 0x20) {
|
||
return (b & 0x10) ? "0011" : "0010"; // 16B
|
||
}
|
||
return "0001"; // 32B
|
||
}
|
||
|
||
/**
|
||
* @brief 取分区内操作码。
|
||
* @param code 指令字节
|
||
* @return op(4B 6 位 / 8B 5 位或 2 位 / 16B·32B 4 位)
|
||
*/
|
||
uint8_t op_of(const uint8_t* code) {
|
||
const uint8_t b = code[0];
|
||
if (b & 0x80) return b & 0x3F; // 4B:6 位
|
||
if ((b & 0xC0) == 0x40) {
|
||
return (b & 0x20) ? (b & 0x1F) : (b & 0x03); // 8B:011 → 5 位;010 → 2 位
|
||
}
|
||
return b & 0x0F; // 16B/32B:4 位
|
||
}
|
||
|
||
/**
|
||
* @brief 取 func 位段(字节 1 高 4 位)。
|
||
* @param code 指令字节
|
||
* @return 0..15(0..9 有效)
|
||
*/
|
||
uint8_t func_of(const uint8_t* code) {
|
||
return static_cast<uint8_t>((code[1] >> 4) & 0x0F);
|
||
}
|
||
|
||
uint8_t rd_of(const uint8_t* code) { return code[2]; }
|
||
uint8_t rs1_of(const uint8_t* code) { return code[3]; }
|
||
uint8_t rs2_of(const uint8_t* code) { return code[4]; }
|
||
|
||
/**
|
||
* @brief 取 imm32(55..24,小端 4 字节)。
|
||
* @param code 指令字节
|
||
* @return 32 位立即数
|
||
*/
|
||
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);
|
||
}
|
||
|
||
uint32_t slot32_of(const uint8_t* code) { return imm32_of(code); }
|
||
|
||
/**
|
||
* @brief 取 off32(47..16,JMP 形态,小端 4 字节,有符号)。
|
||
* @param code 指令字节
|
||
* @return 字节偏移(相对下一条)
|
||
*/
|
||
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 取 off32(55..24,JC 形态,小端 4 字节,有符号)。
|
||
* @param code 指令字节
|
||
* @return 字节偏移(相对下一条)
|
||
*/
|
||
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));
|
||
}
|
||
|
||
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 取 fb_id16(31..16)。
|
||
* @param code 指令字节
|
||
* @return FB 类型 id
|
||
*/
|
||
uint16_t fb_id16_of(const uint8_t* code) {
|
||
return static_cast<uint16_t>(code[2] | (static_cast<uint16_t>(code[3]) << 8));
|
||
}
|
||
|
||
/**
|
||
* @brief 取 CAL 的实例槽号(63..32)。
|
||
* @param code 指令字节
|
||
* @return 槽号
|
||
*/
|
||
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 取 16B 形态的 off32(87..56)。
|
||
* @param code 指令字节
|
||
* @return 字段偏移(字节)
|
||
*/
|
||
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 取 imm64(87..24)。
|
||
* @param code 指令字节
|
||
* @return 64 位立即数
|
||
*/
|
||
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 写字节 0(前缀 + 操作码)。
|
||
* @param out 指令缓冲(≥16B)
|
||
* @param prefix 形态前缀
|
||
* @param op 分区内编号
|
||
*/
|
||
void set_byte0(uint8_t* out, const std::string& prefix, uint32_t op) {
|
||
if (prefix == "11") {
|
||
out[0] = static_cast<uint8_t>(0xC0 | (op & 0x3F)); // bit7..6 = 11
|
||
} else if (prefix == "10") {
|
||
out[0] = static_cast<uint8_t>(0x80 | (op & 0x3F)); // bit7..6 = 10
|
||
} else if (prefix == "011") {
|
||
out[0] = static_cast<uint8_t>(0x60 | (op & 0x1F)); // bit7..5 = 011
|
||
} else if (prefix.size() == 6 && prefix.compare(0, 3, "010") == 0) {
|
||
const uint32_t shape = static_cast<uint32_t>(prefix[3] - '0') * 4 +
|
||
static_cast<uint32_t>(prefix[4] - '0') * 2 +
|
||
static_cast<uint32_t>(prefix[5] - '0');
|
||
out[0] = static_cast<uint8_t>(0x40 | (shape << 2) | (op & 0x03));
|
||
} else if (prefix == "0010") {
|
||
out[0] = static_cast<uint8_t>(0x20 | (op & 0x0F));
|
||
} else if (prefix == "0011") {
|
||
out[0] = static_cast<uint8_t>(0x30 | (op & 0x0F));
|
||
} else { // "0001"
|
||
out[0] = static_cast<uint8_t>(0x10 | (op & 0x0F));
|
||
}
|
||
}
|
||
|
||
void set_func(uint8_t* out, uint8_t func) {
|
||
out[1] = static_cast<uint8_t>((out[1] & 0x0F) | ((func & 0x0F) << 4));
|
||
}
|
||
void set_rd(uint8_t* out, uint8_t rd) { out[2] = rd; }
|
||
void set_rs1(uint8_t* out, uint8_t rs1) { out[3] = rs1; }
|
||
void set_rs2(uint8_t* out, uint8_t rs2) { out[4] = rs2; }
|
||
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);
|
||
}
|
||
void set_slot32(uint8_t* out, uint32_t v) { set_imm32(out, v); }
|
||
void set_off32(uint8_t* out, int32_t v) {
|
||
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);
|
||
}
|
||
|
||
void set_off32_jc(uint8_t* out, int32_t v) {
|
||
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);
|
||
}
|
||
void set_fn_id32(uint8_t* out, uint32_t v) { set_off32(out, static_cast<int32_t>(v)); }
|
||
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);
|
||
}
|
||
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);
|
||
}
|
||
void set_off32_hi(uint8_t* out, int32_t v) {
|
||
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);
|
||
}
|
||
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);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 配置驱动反汇编:按 machine.toml 的 prefix/op/func/fmt 输出一行文本。
|
||
* @param cfg 机器配置
|
||
* @param code 指令字节
|
||
* @param len 指令长度
|
||
* @param out 输出缓冲
|
||
* @param cap 缓冲容量(含 '\0');cap==0 时直接返回、不写 out
|
||
*/
|
||
void disasm(const MachineConfig& cfg, const uint8_t* code, size_t len,
|
||
char* out, size_t cap) {
|
||
if (cap == 0) {
|
||
return;
|
||
}
|
||
out[0] = '\0';
|
||
const std::string prefix = prefix_of(code);
|
||
const ConfigOp* op = cfg.find_op_by_key(prefix, op_of(code));
|
||
if (op == nullptr) {
|
||
snprintf(out, cap, "??? 0x");
|
||
size_t used = 4;
|
||
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 uint8_t func = func_of(code);
|
||
const std::string suffix =
|
||
shows_type_suffix(op->func_mode) ? std::string(".") + type_suffix(func) : "";
|
||
const std::string& f = op->fmt;
|
||
if (f == "RR") {
|
||
snprintf(out, cap, "%s%s r%u, r%u", op->name.c_str(), suffix.c_str(),
|
||
static_cast<unsigned>(rd_of(code)), static_cast<unsigned>(rs1_of(code)));
|
||
} else if (f == "RRR") {
|
||
snprintf(out, cap, "%s%s r%u, r%u, r%u", op->name.c_str(), suffix.c_str(),
|
||
static_cast<unsigned>(rd_of(code)), static_cast<unsigned>(rs1_of(code)),
|
||
static_cast<unsigned>(rs2_of(code)));
|
||
} else if (f == "IMM") {
|
||
snprintf(out, cap, "%s%s r%u, %u", op->name.c_str(), suffix.c_str(),
|
||
static_cast<unsigned>(rd_of(code)), static_cast<unsigned>(imm32_of(code)));
|
||
} else if (f == "SLOT") {
|
||
snprintf(out, cap, "%s%s r%u, s%u", op->name.c_str(), suffix.c_str(),
|
||
static_cast<unsigned>(rd_of(code)), static_cast<unsigned>(slot32_of(code)));
|
||
} else if (f == "JMP") {
|
||
snprintf(out, cap, "%s %+d", op->name.c_str(), static_cast<int>(off32_of(code)));
|
||
} else if (f == "JC") {
|
||
snprintf(out, cap, "%s r%u, %+d", op->name.c_str(),
|
||
static_cast<unsigned>(rd_of(code)), static_cast<int>(off32_jc_of(code)));
|
||
} else if (f == "CALL") {
|
||
snprintf(out, cap, "%s %u", op->name.c_str(), static_cast<unsigned>(fn_id32_of(code)));
|
||
} else if (f == "CAL") {
|
||
const ConfigFb* fb = cfg.find_fb_by_id(fb_id16_of(code));
|
||
if (fb != nullptr) {
|
||
snprintf(out, cap, "CAL.%s s%u", fb->name.c_str(),
|
||
static_cast<unsigned>(cal_slot32_of(code)));
|
||
} else {
|
||
snprintf(out, cap, "CAL ?%u s%u", static_cast<unsigned>(fb_id16_of(code)),
|
||
static_cast<unsigned>(cal_slot32_of(code)));
|
||
}
|
||
} else if (f == "SLOT+off") {
|
||
snprintf(out, cap, "%s%s r%u, s%u, %d", op->name.c_str(), suffix.c_str(),
|
||
static_cast<unsigned>(rd_of(code)), static_cast<unsigned>(slot32_of(code)),
|
||
static_cast<int>(off32_hi_of(code)));
|
||
} else { // NONE / 预留
|
||
snprintf(out, cap, "%s", op->name.c_str());
|
||
}
|
||
}
|
||
|
||
} // namespace compiler
|