落地 isa 合同:饱和类型、操作码枚举、32-bit 指令编解码。

- Types.h:TIME 改 int64_t(毫秒),补 sat_add/sub/mul/div,除零与 INT_MIN/-1 规则
- Op.h:29 条操作码枚举 + mnemonic 助记符,数值即编码
- Instr.h:pack/拆字段 + 按形态 enc_rr/rrr/imm/jmp/jc/slot/call/ret
This commit is contained in:
2026-08-19 13:59:48 +08:00
parent 9a35a881d1
commit 94accd52c3
3 changed files with 199 additions and 3 deletions
+93
View File
@@ -0,0 +1,93 @@
/**
* @file Instr.h
* @brief 32-bit 指令打包 / 拆字段
* @author
* @date 2026-08-19
*/
#pragma once
#include <cstdint>
#include "isa/Op.h"
namespace isa {
// 指令字:[ op:8 | rd:8 | a:8 | b:8 ],整体是一个小端 uint32_t。
// 字段含义按操作码形态解释,见 Doc/isa/指令与映像.md。
typedef uint32_t Instr;
// 打包 / 拆字段
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 Op op(Instr w) {
return static_cast<Op>(w & 0xFFu);
}
inline uint8_t rd(Instr w) {
return static_cast<uint8_t>((w >> 8) & 0xFFu);
}
inline uint8_t a(Instr w) {
return static_cast<uint8_t>((w >> 16) & 0xFFu);
}
inline uint8_t b(Instr w) {
return static_cast<uint8_t>((w >> 24) & 0xFFu);
}
// 组合视图:a|b 拼成 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));
}
// 组合视图:a|b 为有符号相对偏移,单位是指令条数
inline int16_t off16(Instr w) {
return static_cast<int16_t>(imm16(w));
}
// 按形态的便捷编码
inline Instr enc_rr(Op op, uint8_t rd, uint8_t rs) {
return pack(op, rd, rs, 0); // MOVE / NOTa = rs
}
inline Instr enc_rrr(Op op, uint8_t rd, uint8_t ra, uint8_t rb) {
return pack(op, rd, ra, rb); // AND/OR/ADD/.../CMP_xx
}
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)); // LOADK
}
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));
}
inline Instr enc_jc(Op op, uint8_t r, int16_t off) {
// JT / JF:条件寄存器在 rd,偏移在 a|b
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));
}
inline Instr enc_slot(Op op, uint8_t rd, uint16_t slot) {
// LOAD_I / STORE_Q / LOAD_M / STORE_M / LOAD_GLOBAL / STORE_GLOBAL / CAL_*
// 槽号 / 实例号在 a|b
return enc_imm(op, rd, slot);
}
inline Instr enc_call(uint16_t fn_id) {
return enc_imm(Op::CALL, 0, fn_id);
}
inline Instr enc_ret() {
return pack(Op::RET, 0, 0, 0);
}
}
+65
View File
@@ -0,0 +1,65 @@
/**
* @file Op.h
* @brief 操作码枚举 + 助记符
* @author
* @date 2026-08-19
*/
#pragma once
#include <cstdint>
namespace isa {
// 操作码一次列全。数值即编码:冻结后不得改顺序、不得插值,
// 增加指令只能追加到末尾,并同步 Doc/isa/指令与映像.md 与测试。
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 slot, rs
LOAD_M = 20, // LOAD_M rd, slot
STORE_M = 21, // STORE_M slot, rs
LOAD_GLOBAL = 22, // LOAD_GLOBAL rd, slot
STORE_GLOBAL = 23, // STORE_GLOBAL slot, rs
CAL_TON = 24, // CAL_TON instance_slot
CAL_TOF = 25, // CAL_TOF instance_slot
CAL_CTU = 26, // CAL_CTU instance_slot
CALL = 27, // CALL fn_id
RET = 28, // RET
};
// 操作码总数
static const int kOpCount = 29;
// 助记符:下标与 Op 数值一一对应
inline const char* mnemonic(Op op) {
static const char* const kMnemonic[kOpCount] = {
"MOVE", "LOADK", "NOT", "AND", "OR",
"ADD", "SUB", "MUL", "DIV",
"CMP_EQ", "CMP_NE", "CMP_LT", "CMP_LE", "CMP_GT", "CMP_GE",
"JMP", "JT", "JF",
"LOAD_I", "STORE_Q", "LOAD_M", "STORE_M",
"LOAD_GLOBAL", "STORE_GLOBAL",
"CAL_TON", "CAL_TOF", "CAL_CTU",
"CALL", "RET",
};
const int idx = static_cast<int>(op);
return (idx >= 0 && idx < kOpCount) ? kMnemonic[idx] : "???";
}
}
+41 -3
View File
@@ -8,13 +8,51 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <limits>
namespace isa { namespace isa {
namespace types { namespace types {
// 定宽类型。整数溢出规则:饱和(夹到 INT 最小/最大), // 定宽类型。整数溢出规则:饱和(夹到 INT 最小/最大),
// 由 compiler 与 vm 按同一规则实现,见 Doc/isa/指令与映像.md。 // 由 compiler 与 vm 按同一规则实现,见 Doc/isa/指令与映像.md。
using BOOL = uint8_t; using BOOL = uint8_t; // 只允许 0/1
using INT = int16_t; using INT = int16_t; // IEC INT
using TIME = uint64_t; // 毫秒,有符号。64 位理由见 Doc/isa/指令与映像.md
// 差值可负、为 DATE_AND_TIME 与 64 位定时器预留。槽位按 8 字节对齐。
using TIME = int64_t;
// 饱和算术:夹到 INT 最小/最大,编译期与 VM 共用同一规则。
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);
}
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);
}
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);
}
inline INT sat_div(INT a, INT b) {
// b == 0 视为除以 1,避免未定义行为;除零的语义由 compiler/VM 层报错
if (b == 0) {
return a;
}
// INT_MIN / -1 溢出:饱和到 INT_MAX
if (a == std::numeric_limits<INT>::min() && b == -1) {
return std::numeric_limits<INT>::max();
}
return static_cast<INT>(a / b);
}
} }
} }