阶段2-3:Codec V2 化(变长指令字编解码 + 配置驱动 disasm 类型后缀)
- instr_len 前缀定长(1/01/001/0001 → 4/8/16/32B) - prefix_of/op_of/func_of + 全部位号 get/set(rd/rs1/rs2/imm32/slot32/off32/ fn_id32/fb_id16/cal_slot32/off32_hi/imm64) - set_byte0 按前缀写(11/10/011/010xxx 形态位/0010/0011/0001) - disasm:find_op_by_key 查配置;full/float/dst 类显示 .TYPE 后缀 (U8/I8/.../F64);CAL 打印 fb 名(CAL.TON s5);未知输出 ??? 0x hex - main.cpp --disasm 调用适配(TODO V2 待 Stb 重写) - 状态:编译仅剩 Codegen.cpp(84 处 V1 残留,下一步阶段2-5 重写)
This commit is contained in:
@@ -1,59 +1,123 @@
|
||||
/**
|
||||
* @file Codec.h
|
||||
* @brief 指令字编解码 + 配置驱动反汇编(编译器侧)
|
||||
* @brief 指令字编解码 + 配置驱动反汇编(编译器侧,V2)
|
||||
* @author
|
||||
* @date 2026-08-21
|
||||
*
|
||||
* @details 编译器不依赖 isa:指令字布局([op:8|rd:8|a:8|b:8] 小端)与
|
||||
* 反汇编输出(按 machine.toml 的 format/参数名)全部由本模块 + MachineConfig 提供,
|
||||
* 保证与执行器(isa)产生的字节一致。
|
||||
* @details 编译器不依赖 isa:变长指令字(前缀分区编码,4/8/16/32B)与
|
||||
* 反汇编输出(按 machine.toml 的 prefix/op/func/fmt)全部由本模块 + MachineConfig
|
||||
* 提供,保证与执行器(isa V2)产生的字节一致。位号见 Doc/isa/指令编码.md。
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "compiler/MachineConfig.h"
|
||||
|
||||
namespace compiler {
|
||||
|
||||
/// 指令字:`[ op:8 | rd:8 | a:8 | b:8 ]`,小端 u32。
|
||||
typedef uint32_t Instr;
|
||||
/// 指令字最大长度(字节)。
|
||||
static constexpr size_t kMaxInstrLen = 16;
|
||||
|
||||
/**
|
||||
* @brief 打包:opcode + 三个 8 位字段拼成一条指令字。
|
||||
* @param opcode 操作码(低 8 位)
|
||||
* @param rd 目标寄存器 / 条件寄存器(第 8..15 位)
|
||||
* @param a 源寄存器 / 立即数低 8 位 / 偏移低 8 位(第 16..23 位)
|
||||
* @param b 源寄存器 / 立即数高 8 位 / 偏移高 8 位(第 24..31 位)
|
||||
* @return 打包后的指令字(小端 u32)
|
||||
* @details 布局与执行器 isa 一致,保证编译器产出的字节可被执行。
|
||||
* @brief 前缀定长:读字节 0 判指令长度。
|
||||
* @param code 指令字节(至少 1 字节)
|
||||
* @return 4/8/16/32(前缀 `1`/`01`/`001`/`0001`)
|
||||
*/
|
||||
Instr pack(uint8_t opcode, uint8_t rd, uint8_t a, uint8_t b);
|
||||
|
||||
/// @brief 取操作码(低 8 位)。
|
||||
uint8_t op_of(Instr w);
|
||||
/// @brief 取 rd 字段(第 8..15 位)。
|
||||
uint8_t rd_of(Instr w);
|
||||
/// @brief 取 a 字段(第 16..23 位)。
|
||||
uint8_t a_of(Instr w);
|
||||
/// @brief 取 b 字段(第 24..31 位)。
|
||||
uint8_t b_of(Instr w);
|
||||
/// @brief a|b 拼 16 位无符号数(const_id / slot / fn_id)。
|
||||
uint16_t imm16_of(Instr w);
|
||||
/// @brief a|b 为有符号相对偏移(单位:指令条数,相对下一条指令)。
|
||||
int16_t off16_of(Instr w);
|
||||
size_t instr_len(const uint8_t* code);
|
||||
|
||||
/**
|
||||
* @brief 配置驱动反汇编:按 machine.toml 的 format 输出一行文本。
|
||||
* @param cfg 机器配置(opcode 名 / format / 参数名来源)
|
||||
* @param w 指令字
|
||||
* @brief 推导形态前缀字符串。
|
||||
* @param code 指令字节
|
||||
* @return "11"/"10"/"011"/"010000".."010101"/"0010"/"0011"/"0001"
|
||||
*/
|
||||
std::string prefix_of(const uint8_t* code);
|
||||
|
||||
/**
|
||||
* @brief 取分区内操作码。
|
||||
* @param code 指令字节
|
||||
* @return op(4B 6 位 / 8B 5 位或 2 位 / 16B·32B 4 位)
|
||||
*/
|
||||
uint8_t op_of(const uint8_t* code);
|
||||
|
||||
/**
|
||||
* @brief 取 func 位段(字节 1 高 4 位)。
|
||||
* @param code 指令字节
|
||||
* @return 0..15(0..9 有效)
|
||||
*/
|
||||
uint8_t func_of(const uint8_t* code);
|
||||
|
||||
/// @brief 取 rd(23..16)。
|
||||
uint8_t rd_of(const uint8_t* code);
|
||||
/// @brief 取 rs1(31..24)。
|
||||
uint8_t rs1_of(const uint8_t* code);
|
||||
/// @brief 取 rs2(39..32)。
|
||||
uint8_t rs2_of(const uint8_t* code);
|
||||
/// @brief 取 imm32(55..24,IMM 形态)。
|
||||
uint32_t imm32_of(const uint8_t* code);
|
||||
/// @brief 取 slot32(55..24,SLOT 形态)。
|
||||
uint32_t slot32_of(const uint8_t* code);
|
||||
/// @brief 取 off32(47..16,JMP/JC 形态,有符号字节偏移)。
|
||||
int32_t off32_of(const uint8_t* code);
|
||||
/// @brief 取 fn_id32(47..16,CALL 形态)。
|
||||
uint32_t fn_id32_of(const uint8_t* code);
|
||||
/// @brief 取 fb_id16(31..16,CAL 形态)。
|
||||
uint16_t fb_id16_of(const uint8_t* code);
|
||||
/// @brief 取 CAL 的实例槽号(63..32)。
|
||||
uint32_t cal_slot32_of(const uint8_t* code);
|
||||
/// @brief 取 16B 形态的 off32(87..56)。
|
||||
int32_t off32_hi_of(const uint8_t* code);
|
||||
/// @brief 取 imm64(87..24,IMM64 形态)。
|
||||
uint64_t imm64_of(const uint8_t* code);
|
||||
|
||||
/**
|
||||
* @brief 写字节 0(前缀 + 操作码)。
|
||||
* @param out 指令缓冲(≥16B,写入后高位补 0 由调用方保证)
|
||||
* @param prefix 形态前缀(11/10/011/010000..010101/0010/0011/0001)
|
||||
* @param op 分区内编号
|
||||
*/
|
||||
void set_byte0(uint8_t* out, const std::string& prefix, uint32_t op);
|
||||
|
||||
/// @brief 写字节 1 的 func(高 4 位)。
|
||||
void set_func(uint8_t* out, uint8_t func);
|
||||
/// @brief 写 rd(23..16)。
|
||||
void set_rd(uint8_t* out, uint8_t rd);
|
||||
/// @brief 写 rs1(31..24)。
|
||||
void set_rs1(uint8_t* out, uint8_t rs1);
|
||||
/// @brief 写 rs2(39..32)。
|
||||
void set_rs2(uint8_t* out, uint8_t rs2);
|
||||
/// @brief 写 imm32(55..24)。
|
||||
void set_imm32(uint8_t* out, uint32_t v);
|
||||
/// @brief 写 slot32(55..24)。
|
||||
void set_slot32(uint8_t* out, uint32_t v);
|
||||
/// @brief 写 off32(47..16)。
|
||||
void set_off32(uint8_t* out, int32_t v);
|
||||
/// @brief 写 fn_id32(47..16)。
|
||||
void set_fn_id32(uint8_t* out, uint32_t v);
|
||||
/// @brief 写 fb_id16(31..16)。
|
||||
void set_fb_id16(uint8_t* out, uint16_t v);
|
||||
/// @brief 写 CAL 实例槽号(63..32)。
|
||||
void set_cal_slot32(uint8_t* out, uint32_t v);
|
||||
/// @brief 写 16B 形态的 off32(87..56)。
|
||||
void set_off32_hi(uint8_t* out, int32_t v);
|
||||
/// @brief 写 imm64(87..24)。
|
||||
void set_imm64(uint8_t* out, uint64_t v);
|
||||
|
||||
/**
|
||||
* @brief 配置驱动反汇编:按 machine.toml 的 prefix/op/func/fmt 输出一行文本。
|
||||
* @param cfg 机器配置(指令名 / fmt / func 类别 / fb 名来源)
|
||||
* @param code 指令字节
|
||||
* @param len 指令长度(instr_len 定)
|
||||
* @param out 输出缓冲
|
||||
* @param cap 缓冲容量(含 '\0');cap==0 时直接返回、不写 out
|
||||
* @details 文本格式与 Doc/isa/指令与映像.md 一致(如 `MOVE r1, r2`、
|
||||
* `LOADK r0, 3`、`JMP +4`、`JT r0, -1`、`CALL 1`、`CAL_TON 0`、`RET`);
|
||||
* 未知操作码输出 `??? 0x<hex>`。
|
||||
* @details 文本格式与 Doc/isa/指令与映像.md §10 一致:
|
||||
* `MOVE r1, r2`、`LOAD.I16 r5, s3`(full/float/dst 类显示类型后缀)、
|
||||
* `JMP +4`、`JT r0, -1`、`CALL 1`、`CAL.TON s5`、`RET`;
|
||||
* 未知 (prefix, op) 输出 `??? 0x<hex dump>`。
|
||||
*/
|
||||
void disasm(const MachineConfig& cfg, Instr w, char* out, size_t cap);
|
||||
void disasm(const MachineConfig& cfg, const uint8_t* code, size_t len,
|
||||
char* out, size_t cap);
|
||||
}
|
||||
|
||||
+284
-57
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
* @file Codec.cpp
|
||||
* @brief 指令字编解码 + 配置驱动反汇编(编译器侧)
|
||||
* @brief 指令字编解码 + 配置驱动反汇编(编译器侧,V2)
|
||||
* @author
|
||||
* @date 2026-08-21
|
||||
*
|
||||
* @details pack / op_of / imm16_of / off16_of 与执行器 isa 字节布局一致;
|
||||
* disasm 由 MachineConfig 驱动(opcode 名 / format / 参数名来自配置)。
|
||||
* @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"
|
||||
@@ -14,84 +15,310 @@
|
||||
|
||||
namespace compiler {
|
||||
|
||||
/**
|
||||
* @brief 打包:四个字段拼成一条指令字。
|
||||
* @param opcode 操作码(低 8 位)
|
||||
* @param rd 目标寄存器 / 条件寄存器(第 8..15 位)
|
||||
* @param a 源寄存器 / 立即数低 8 位 / 偏移低 8 位(第 16..23 位)
|
||||
* @param b 源寄存器 / 立即数高 8 位 / 偏移高 8 位(第 24..31 位)
|
||||
* @return 打包后的指令字(小端 u32)
|
||||
*/
|
||||
Instr pack(uint8_t opcode, uint8_t rd, uint8_t a, uint8_t b) {
|
||||
return static_cast<uint32_t>(opcode)
|
||||
| (static_cast<uint32_t>(rd) << 8)
|
||||
| (static_cast<uint32_t>(a) << 16)
|
||||
| (static_cast<uint32_t>(b) << 24);
|
||||
}
|
||||
namespace {
|
||||
|
||||
/// @brief 取操作码(低 8 位)。
|
||||
uint8_t op_of(Instr w) { return static_cast<uint8_t>(w & 0xFFu); }
|
||||
/// @brief 取 rd 字段(第 8..15 位)。
|
||||
uint8_t rd_of(Instr w) { return static_cast<uint8_t>((w >> 8) & 0xFFu); }
|
||||
/// @brief 取 a 字段(第 16..23 位)。
|
||||
uint8_t a_of(Instr w) { return static_cast<uint8_t>((w >> 16) & 0xFFu); }
|
||||
/// @brief 取 b 字段(第 24..31 位)。
|
||||
uint8_t b_of(Instr w) { return static_cast<uint8_t>((w >> 24) & 0xFFu); }
|
||||
/**
|
||||
* @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 a|b 拼成 16 位无符号数。
|
||||
* @param w 指令字
|
||||
* @return 小端拼出的 16 位值(const_id / slot / fn_id)
|
||||
* @brief 前缀定长:读字节 0 判指令长度。
|
||||
* @param code 指令字节(至少 1 字节)
|
||||
* @return 4/8/16/32(前缀 `1`/`01`/`001`/`0001`)
|
||||
*/
|
||||
uint16_t imm16_of(Instr w) {
|
||||
return static_cast<uint16_t>(a_of(w) | (static_cast<uint16_t>(b_of(w)) << 8));
|
||||
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 a|b 为有符号相对偏移。
|
||||
* @param w 指令字
|
||||
* @return 偏移量(单位:指令条数,相对下一条指令)
|
||||
* @brief 推导形态前缀字符串。
|
||||
* @param code 指令字节
|
||||
* @return "11"/"10"/"011"/"010000".."010101"/"0010"/"0011"/"0001"
|
||||
*/
|
||||
int16_t off16_of(Instr w) { return static_cast<int16_t>(imm16_of(w)); }
|
||||
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 配置驱动反汇编:按 machine.toml 的 format 输出一行文本。
|
||||
* @param cfg 机器配置(opcode 名 / format / 参数名来源)
|
||||
* @param w 指令字
|
||||
* @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,小端 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));
|
||||
}
|
||||
|
||||
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>(0x80 | (op & 0x3F));
|
||||
} else if (prefix == "10") {
|
||||
out[0] = static_cast<uint8_t>(0x80 | 0x40 | (op & 0x3F));
|
||||
} else if (prefix == "011") {
|
||||
out[0] = static_cast<uint8_t>(0x40 | (op & 0x1F));
|
||||
} 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_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
|
||||
* @details 未知操作码输出 `??? 0x%08x`;format 分支 RR/RRR/IMM/SLOT/JMP/JC/CALL/CAL/NONE
|
||||
* 输出文本与 Doc/isa/指令与映像.md 一致。
|
||||
*/
|
||||
void disasm(const MachineConfig& cfg, Instr w, char* out, size_t cap) {
|
||||
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 ConfigOp* op = cfg.find_op_by_code(op_of(w));
|
||||
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%08x", static_cast<unsigned>(w));
|
||||
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 rd = rd_of(w);
|
||||
const std::string& f = op->format;
|
||||
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 r%u, r%u", op->name.c_str(), static_cast<unsigned>(rd),
|
||||
static_cast<unsigned>(a_of(w)));
|
||||
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 r%u, r%u, r%u", op->name.c_str(), static_cast<unsigned>(rd),
|
||||
static_cast<unsigned>(a_of(w)), static_cast<unsigned>(b_of(w)));
|
||||
} else if (f == "IMM" || f == "SLOT") {
|
||||
snprintf(out, cap, "%s r%u, %u", op->name.c_str(), static_cast<unsigned>(rd),
|
||||
static_cast<unsigned>(imm16_of(w)));
|
||||
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>(off16_of(w)));
|
||||
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),
|
||||
static_cast<int>(off16_of(w)));
|
||||
} else if (f == "CALL" || f == "CAL") {
|
||||
snprintf(out, cap, "%s %u", op->name.c_str(), static_cast<unsigned>(imm16_of(w)));
|
||||
} else { // NONE
|
||||
snprintf(out, cap, "%s r%u, %+d", op->name.c_str(),
|
||||
static_cast<unsigned>(rd_of(code)), static_cast<int>(off32_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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +84,8 @@ namespace {
|
||||
const uint8_t* base = v.code_bytes() + r.code_offset;
|
||||
for (uint32_t j = 0; j < r.code_len; ++j) {
|
||||
char buf[64];
|
||||
compiler::disasm(cfg, reinterpret_cast<const uint32_t*>(base)[j], buf,
|
||||
sizeof buf);
|
||||
// TODO(V2): Stb 重写(阶段2-4)后 code_len 为字节、instr_len 定长
|
||||
compiler::disasm(cfg, base + j * 4, 4, buf, sizeof buf);
|
||||
std::printf(" 0x%04x %s\n",
|
||||
v.offset_code() + r.code_offset + j * 4, buf);
|
||||
}
|
||||
|
||||
@@ -31,16 +31,16 @@ static int g_checks = 0;
|
||||
|
||||
// ---- 写临时 toml ----
|
||||
|
||||
static std::string write_tmp(const char* name, const char* content) {
|
||||
static std::string write_tmp(const char* name, const std::string& content) {
|
||||
const std::filesystem::path dir = std::filesystem::temp_directory_path();
|
||||
const std::filesystem::path path = dir / name;
|
||||
std::FILE* f = std::fopen(path.string().c_str(), "w");
|
||||
std::fputs(content, f);
|
||||
std::fputs(content.c_str(), f);
|
||||
std::fclose(f);
|
||||
return path.string();
|
||||
}
|
||||
|
||||
static bool expect_load_err(const char* name, const char* content, const char* keyword) {
|
||||
static bool expect_load_err(const char* name, const std::string& content, const char* keyword) {
|
||||
const std::string path = write_tmp(name, content);
|
||||
compiler::MachineConfig cfg;
|
||||
std::string err;
|
||||
|
||||
Reference in New Issue
Block a user