neptools

Modding tools to Neptunia games
git clone https://git.neptards.moe/neptards/neptools.git
Log | Files | Refs | Submodules | README | LICENSE

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