instruction.hpp (11186B)
1 #ifndef UUID_032F4E0D_CAAE_429A_9928_2ACC24EC51E1 2 #define UUID_032F4E0D_CAAE_429A_9928_2ACC24EC51E1 3 #pragma once 4 5 #include "../item.hpp" 6 #include "../../source.hpp" 7 8 #include <libshit/check.hpp> 9 #include <libshit/lua/auto_table.hpp> 10 11 #include <boost/endian/arithmetic.hpp> 12 #include <variant> 13 14 namespace Neptools { class RawItem; } 15 16 namespace Neptools::Stcm 17 { 18 19 class InstructionItem final : public ItemWithChildren 20 { 21 LIBSHIT_DYNAMIC_OBJECT; 22 public: 23 struct Header 24 { 25 boost::endian::little_uint32_t is_call; 26 boost::endian::little_uint32_t opcode; 27 boost::endian::little_uint32_t param_count; 28 boost::endian::little_uint32_t size; 29 30 enum Opcode : uint32_t 31 { 32 USER_OPCODES = 0x1000, 33 SYSTEM_OPCODES_BEGIN = 0xffffff00, 34 SYSTEM_OPCODES_END = 0xffffff14, 35 }; 36 37 void Validate(FilePosition file_size) const; 38 }; 39 static_assert(sizeof(Header) == 0x10); 40 41 struct Parameter 42 { 43 struct Type0 44 { 45 static constexpr uint32_t MEM_OFFSET = 0; 46 static constexpr uint32_t UNK = 1; 47 static constexpr uint32_t INDIRECT = 2; 48 static constexpr uint32_t SPECIAL = 3; 49 }; 50 51 struct Type0Special 52 { 53 static constexpr uint32_t READ_STACK_MIN = 0xffffff00; 54 static constexpr uint32_t READ_STACK_MAX = 0xffffff0f; 55 static constexpr uint32_t READ_4AC_MIN = 0xffffff20; 56 static constexpr uint32_t READ_4AC_MAX = 0xffffff27; 57 static constexpr uint32_t INSTR_PTR0 = 0xffffff40; 58 static constexpr uint32_t INSTR_PTR1 = 0xffffff41; 59 static constexpr uint32_t COLL_LINK = 0xffffff42; 60 static constexpr uint32_t EXPANSION = 0xffffff43; 61 }; 62 63 struct Type48 64 { 65 static constexpr uint32_t MEM_OFFSET = 0; 66 static constexpr uint32_t IMMEDIATE = 1; 67 static constexpr uint32_t INDIRECT = 2; 68 static constexpr uint32_t SPECIAL = 3; 69 }; 70 71 struct Type48Special 72 { 73 static constexpr uint32_t READ_STACK_MIN = 0xffffff00; 74 static constexpr uint32_t READ_STACK_MAX = 0xffffff0f; 75 static constexpr uint32_t READ_4AC_MIN = 0xffffff20; 76 static constexpr uint32_t READ_4AC_MAX = 0xffffff27; 77 }; 78 79 boost::endian::little_uint32_t param_0; 80 boost::endian::little_uint32_t param_4; 81 boost::endian::little_uint32_t param_8; 82 83 static constexpr inline uint32_t TypeTag(uint32_t x) { return x >> 30; } 84 static constexpr inline uint32_t Value(uint32_t x) { return x & 0x3fffffff; } 85 static constexpr inline uint32_t Tag(uint32_t tag, uint32_t val) 86 { return (tag << 30) | val; } 87 void Validate(FilePosition file_size) const; 88 }; 89 static_assert(sizeof(Parameter) == 0xc); 90 91 class Param; 92 InstructionItem(Key k, Context& ctx) : ItemWithChildren{k, ctx} {} 93 InstructionItem(Key k, Context& ctx, Source src); 94 InstructionItem(Key k, Context& ctx, Libshit::NotNull<LabelPtr> tgt) 95 : ItemWithChildren{k, ctx}, opcode_target{std::move(tgt)} {} 96 InstructionItem(Key k, Context& ctx, Libshit::NotNull<LabelPtr> tgt, 97 Libshit::AT<std::vector<Param>> params) 98 : ItemWithChildren{k, ctx}, params{std::move(params.Get())}, 99 opcode_target{std::move(tgt)} {} 100 101 InstructionItem(Key k, Context& ctx, uint32_t opcode) 102 : ItemWithChildren{k, ctx}, opcode_target{opcode} {} 103 InstructionItem(Key k, Context& ctx, uint32_t opcode, 104 Libshit::AT<std::vector<Param>> params) 105 : ItemWithChildren{k, ctx}, params{std::move(params.Get())}, 106 opcode_target{opcode} {} 107 static InstructionItem& CreateAndInsert(ItemPointer ptr); 108 109 FilePosition GetSize() const noexcept override; 110 void Fixup() override; 111 void Dispose() noexcept override; 112 113 bool IsCall() const noexcept 114 { return !std::holds_alternative<uint32_t>(opcode_target); } 115 116 uint32_t GetOpcode() const { return std::get<0>(opcode_target); } 117 118 void SetOpcode(uint32_t oc) noexcept { opcode_target = oc; } 119 Libshit::NotNull<LabelPtr> GetTarget() const 120 { return std::get<1>(opcode_target); } 121 122 void SetTarget(Libshit::NotNull<LabelPtr> label) noexcept 123 { opcode_target = label; } 124 125 class Param48 : public Libshit::Lua::ValueObject 126 { 127 LIBSHIT_LUA_CLASS; 128 public: 129 enum class LIBSHIT_LUAGEN() Type 130 { 131 #define NEPTOOLS_GEN_TYPES(x, ...) \ 132 x(MEM_OFFSET, __VA_ARGS__) \ 133 x(IMMEDIATE, __VA_ARGS__) \ 134 x(INDIRECT, __VA_ARGS__) \ 135 x(READ_STACK, __VA_ARGS__) \ 136 x(READ_4AC, __VA_ARGS__) 137 #define NEPTOOLS_GEN_ENUM(x,y) x, 138 NEPTOOLS_GEN_TYPES(NEPTOOLS_GEN_ENUM,) 139 }; 140 using Variant = std::variant< 141 Libshit::NotNull<LabelPtr>, uint32_t, uint32_t, uint32_t, uint32_t>; 142 143 Param48(Context& ctx, uint32_t val) : val{GetVariant(ctx, val)} {} 144 template <size_t type, typename T> LIBSHIT_NOLUA 145 Param48(std::in_place_index_t<type> x, T val) : val{x, std::move(val)} {} 146 147 uint32_t Dump() const noexcept; 148 149 Type GetType() const noexcept { return static_cast<Type>(val.index()); } 150 151 template <typename Visitor> LIBSHIT_NOLUA 152 auto Visit(Visitor&& v) const 153 { return std::visit(std::forward<Visitor>(v), val); } 154 155 #define NEPTOOLS_GEN_TMPL(x,xname) LIBSHIT_LUAGEN( \ 156 name: xname + #x.downcase, template_params: %w( \ 157 Neptools::Stcm::InstructionItem::Param48::Type::x)) 158 template <Type type> NEPTOOLS_GEN_TYPES(NEPTOOLS_GEN_TMPL, "get_") 159 auto Get() const { return std::get<static_cast<size_t>(type)>(val); } 160 template <Type type> LIBSHIT_NOLUA 161 void Set(std::variant_alternative_t< 162 static_cast<size_t>(type), Variant> nval) 163 { val.emplace(std::in_place_index<type>(std::move(nval))); } 164 165 template <Type type> NEPTOOLS_GEN_TYPES(NEPTOOLS_GEN_TMPL, "new_") 166 static Param48 New(std::variant_alternative_t< 167 static_cast<size_t>(type), Variant> nval) 168 { return {std::in_place_index<static_cast<size_t>(type)>, std::move(nval)}; } 169 #undef NEPTOOLS_GEN_TMPL 170 #undef NEPTOOLS_GEN_TYPES 171 172 173 // NEPTOOLS_GEN_INT(Immediate, IMMEDIATE, Param48, Parameter::TypeTag(val) == 0) 174 // NEPTOOLS_GEN_INT(Indirect, INDIRECT, Param48, Parameter::TypeTag(val) == 0) 175 // NEPTOOLS_GEN_INT(ReadStack, READ_STACK, Param48, val < 16) 176 // NEPTOOLS_GEN_INT(Read4ac, READ_4AC, Param48, val < 16) 177 178 private: 179 Variant val; 180 static Variant GetVariant(Context& ctx, uint32_t val); 181 } LIBSHIT_LUAGEN(post_register: "bld.TaggedNew();"); 182 183 class Param : public Libshit::Lua::ValueObject 184 { 185 LIBSHIT_LUA_CLASS; 186 public: 187 struct MemOffset : Libshit::Lua::ValueObject 188 { 189 Libshit::NotNull<LabelPtr> target; 190 Param48 param_4; 191 Param48 param_8; 192 193 MemOffset(Libshit::NotNull<LabelPtr> target, Param48 param_4, 194 Param48 param_8) 195 : target{std::move(target)}, param_4{std::move(param_4)}, 196 param_8{std::move(param_8)} {} 197 LIBSHIT_LUA_CLASS; 198 }; 199 struct Indirect : Libshit::Lua::ValueObject 200 { 201 uint32_t param_0; 202 Param48 param_8; 203 204 Indirect(uint32_t param_0, Param48 param_8) 205 : param_0{param_0}, param_8{std::move(param_8)} {} 206 LIBSHIT_LUA_CLASS; 207 }; 208 enum class LIBSHIT_LUAGEN() Type 209 { 210 #define NEPTOOLS_GEN_TYPES(x, ...) \ 211 x(MEM_OFFSET, __VA_ARGS__) \ 212 x(INDIRECT, __VA_ARGS__) \ 213 x(READ_STACK, __VA_ARGS__) \ 214 x(READ_4AC, __VA_ARGS__) \ 215 x(INSTR_PTR0, __VA_ARGS__) \ 216 x(INSTR_PTR1, __VA_ARGS__) \ 217 x(COLL_LINK, __VA_ARGS__) \ 218 x(EXPANSION, __VA_ARGS__) 219 NEPTOOLS_GEN_TYPES(NEPTOOLS_GEN_ENUM,) 220 #undef NEPTOOLS_GEN_ENUM 221 }; 222 using Variant = std::variant< 223 MemOffset, Indirect, uint32_t, uint32_t, Libshit::NotNull<LabelPtr>, 224 Libshit::NotNull<LabelPtr>, Libshit::NotNull<LabelPtr>, 225 Libshit::NotNull<LabelPtr>>; 226 227 LIBSHIT_NOLUA 228 Param(Context& ctx, const Parameter& p) : val{GetVariant(ctx, p)} {} 229 template <size_t type, typename T> LIBSHIT_NOLUA 230 Param(std::in_place_index_t<type> x, T val) : val{x, std::move(val)} {} 231 232 void Dump(Sink& sink) const; 233 LIBSHIT_NOLUA void Dump(Sink&& sink) const { Dump(sink); } 234 235 Type GetType() const noexcept { return static_cast<Type>(val.index()); } 236 237 template <typename Visitor> LIBSHIT_NOLUA 238 auto Visit(Visitor&& v) const 239 { return std::visit(std::forward<Visitor>(v), val); } 240 241 #define NEPTOOLS_GEN_TMPL(x,xname) LIBSHIT_LUAGEN( \ 242 name: xname + #x.downcase, template_params: %w( \ 243 Neptools::Stcm::InstructionItem::Param::Type::x)) 244 template <Type type> NEPTOOLS_GEN_TYPES(NEPTOOLS_GEN_TMPL, "get_") 245 auto Get() const { return std::get<static_cast<size_t>(type)>(val); } 246 template <Type type> LIBSHIT_NOLUA 247 void Set(std::variant_alternative_t< 248 static_cast<size_t>(type), Variant> nval) 249 { val.emplace(std::in_place_index<type>(std::move(nval))); } 250 251 template <Type type> NEPTOOLS_GEN_TYPES(NEPTOOLS_GEN_TMPL, "new_") 252 static Param New(std::variant_alternative_t< 253 static_cast<size_t>(type), Variant> nval) 254 { return {std::in_place_index<static_cast<size_t>(type)>, std::move(nval)}; } 255 256 static Param NewMemOffset( 257 Libshit::NotNull<LabelPtr> target, Libshit::AT<Param48> param_4, 258 Libshit::AT<Param48> param_8) 259 { 260 return New<Type::MEM_OFFSET>({ 261 std::move(target), std::move(param_4.Get()), 262 std::move(param_8.Get())}); 263 } 264 static Param NewIndirect(uint32_t param_0, Libshit::AT<Param48> param_8) 265 { return New<Type::INDIRECT>({param_0, std::move(param_8.Get())}); } 266 267 #undef NEPTOOLS_GEN_TYPES 268 #undef NEPTOOL_GEN_ENUM 269 #undef NEPTOOLS_GEN_TMPL 270 271 // NEPTOOLS_GEN_LABEL(MemOffset, MEM_OFFSET, Param) 272 // NEPTOOLS_GEN_INT (Indirect, INDIRECT, Param, Parameter::TypeTag(val) == 0) 273 // NEPTOOLS_GEN_INT (ReadStack, READ_STACK, Param, val < 16) 274 // NEPTOOLS_GEN_INT (Read4ac, READ_4AC, Param, val < 16) 275 // NEPTOOLS_GEN_LABEL(InstrPtr0, INSTR_PTR0, Param) 276 // NEPTOOLS_GEN_LABEL(InstrPtr1, INSTR_PTR1, Param) 277 // NEPTOOLS_GEN_LABEL(CollLink, COLL_LINK, Param) 278 279 private: 280 Variant val; 281 static Variant GetVariant(Context& ctx, const Parameter& in); 282 } LIBSHIT_LUAGEN(post_register: "bld.TaggedNew();"); 283 284 LIBSHIT_LUAGEN(get: "::Libshit::Lua::GetSmartOwnedMember") 285 std::vector<Param> params; 286 287 private: 288 std::variant<uint32_t, Libshit::NotNull<LabelPtr>> opcode_target; 289 290 void Dump_(Sink& sink) const override; 291 void Inspect_(std::ostream& os, unsigned indent) const override; 292 void Parse_(Context& ctx, Source& src); 293 }; 294 295 std::ostream& operator<<(std::ostream& os, const InstructionItem::Param48& p); 296 std::ostream& operator<<(std::ostream& os, const InstructionItem::Param& p); 297 298 } 299 300 LIBSHIT_ENUM(Neptools::Stcm::InstructionItem::Param48::Type); 301 LIBSHIT_ENUM(Neptools::Stcm::InstructionItem::Param::Type); 302 303 #endif