#pragma once

#include <spider/SpiderRuntime.hpp>
#include <spider/runtime/cpu/Register.hpp>

namespace spider {

    class CPU {
    public: // Flag Register Constants //
        static constexpr const u64 FLAG_ENABLE            = 0b0000000000000000000000000000000000000000000000000000000000000001;
        static constexpr const u64 FLAG_INTERRUPT_SIGNAL  = 0b0000000000000000000000000000000000000000000000000000000000000010;
        static constexpr const u64 FLAG_INTERRUPT_REQUEST = 0b0000000000000000000000000000000000000000000000000000000000000100;
        static constexpr const u64 FLAG_EXCEPTION         = 0b0000000000000000000000000000000000000000000000000000000000001000;
        static constexpr const u64 FLAG_MEMORY_MODE       = 0b0000000000000000000000000000000000000000000000000000000000110000;

    public: // General Purpose Registers
        union {
            register_t GPR[16];
            struct {
                register_t RA, RB, RC, RD,
                           RX, RY, R0, R1,
                           R2, R3, R4, R5,
                           R6, R7, R8, R9;
            };
        };

    public: // System Registers
        u64 RF;
        u64 RI;
        u64 RS;
        u64 RZ;
        u64 RE;
        u64 RN; // Epsilo(n)
        u64 RV;
        u64 RM;

    public:

        /**
         * These are private registers, which are only used
         * whenever constant things are used.
         * This way we don't "write" into constant values, rather
         * we write into a writeable var which is "hidden"
         */
        register_t ALU0, ALU1;

    private:

        /**
         * Pointer to the current RAM hooked into
         * the CPU.
         * 
         * It is unproved whether having the RAM directly
         * into the CPU is better than not, or whether a
         * virtual BUS is better.
         * 
         * Alas, this way we can have a CPU state switch
         * between memory and instruction banks.
         */
        RAM* _ram;

        /**
         * Pointer to the current Instruction Reel
         * hooked into the CPU.
         * 
         * Ditto as RAM.
         */
        InstrReel* _reel;

        register_t* _next;
        u8 _addrm : 6;
        u8 _size : 2;

    public:

        CPU();

        CPU(const CPU& other) = default;

        CPU(CPU&& other) noexcept = default;

        ~CPU();

    public:
        
        CPU& operator=(const CPU& other) = default;

        CPU& operator=(CPU&& other) noexcept = default;

    public:

        void hookRAM(RAM* ram);

        void hookInstrReel(InstrReel* reel);

        constexpr u64 getFlag(u64 mask);

    public: // Addressing Modes

        /**
         * Implied Addressing Mode
         */
        void imp();

        /**
         * Immediate Addressing Mode
         */
        void imm();

        /**
         * Absolute Addressing Mode
         */
        void abs();
        
        /**
         * Register Addressing Mode
         */
        void reg();
        
        /**
         * Indrect Addressing Mode
         */
        void ind();
        
        /**
         * Pointer Addressing Mode
         */
        void ptr();
        
        /**
         * Indexed Addressing Mode
         */
        void idx();
        
        /**
         * Scaled Addressing Mode
         */
        void sca();
        
        /**
         * Displaced Addressing Mode
         */
        void dis();

    public:

        // <pygen-target name=cpu-instructions> //
        // [System] 0x000 — NOP: No Operation
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Nothing
        void NOP();

        // [System] 0x001 — SPDR: Will place the Spider version of the interpreter in RA
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (Spider Version) -> RA
        void SPDR();

        // [System] 0x002 — MMODE: Set Memory Mode
        //   Params: 1 | AddrMask1: 05 AddrMask2: 00 | TypeMask: 01
        //   Operation: Dst -> Memory Mode Bits
        void MMODE();

        // [System] 0x003 — INT: Interrupt
        //   Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 0F
        //   Operation: Performs system interrupt no. (Dst) (See table)
        void INT();

        // [System] 0x004 — LRV: Load Interrupt Vector Register
        //   Params: 1 | AddrMask1: 1F AddrMask2: 00 | TypeMask: 0C
        //   Operation: Dst -> RV
        void LRV();

        // [System] 0x005 — FSR: Fetch System Register
        //   Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F
        //   Operation: System Register at Dst -> Dst
        void FSR();

        // [System] 0x006 — FIR: Fetch Instruction Register
        //   Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F
        //   Operation: Instruction Register -> Dst
        void FIR();

        // [System] 0x007 — FZR: Fetch Stack Base Register
        //   Params: 1 | AddrMask1: 1E AddrMask2: 00 | TypeMask: 0F
        //   Operation: Stack Base Register -> Dst
        void FZR();

        // [System] 0x008 — LSR: Load System Register
        //   Params: 2 | AddrMask1: 1E AddrMask2: 1F | TypeMask: 0F
        //   Operation: Src -> System Register at Dst
        void LSR();

        // [System] 0x009 — FVR: Fetch Interrupt Vector Register
        //   Params: 1 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Interrupt Vector Register -> Dst
        void FVR();

        // [Memory] 0x00A — MOV: Moves values
        //   Params: 2 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Src -> Dst
        void MOV();

        // [Memory] 0x00B — MOR: Moves registers
        //   Params: 2 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: R Scr -> R Dst
        void MOR();

        // [Memory] 0x00C — AMOV: Array Move, uses X and Y as ptrs, A as amount
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Array from X to Y, by A amount
        void AMOV();

        // [Memory] 0x00D — SWP: Swap registers
        //   Params: 2 | AddrMask1: 04 AddrMask2: 04 | TypeMask: 00
        //   Operation: Src <-> Dst
        void SWP();

        // [Memory] 0x00E — AHM: Ask Host for Memory
        //   Params: 1 | AddrMask1: 04 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Asks the host for a specific size of memory. Responds with 0 or 1
        void AHM();

        // [Integer] 0x010 — COM: One's complement
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: ~ Dst -> Dst
        void COM();

        // [Integer] 0x011 — NEG: Two's complement
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: - Dst -> Dst
        void NEG();

        // [Integer] 0x012 — EXS: Extend Sign
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Last bit is copied and expanded for the next int size
        void EXS();

        // [Integer] 0x013 — INC: Increment
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst + 1 -> Dst
        void INC();

        // [Integer] 0x014 — DEC: Decrement
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst - 1 -> Dst
        void DEC();

        // [Integer] 0x015 — ADD: Addition
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst + Src -> Dst
        void ADD();

        // [Integer] 0x016 — SUB: Subtraction
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst - Src-> Dst
        void SUB();

        // [Integer] 0x017 — MUL: Multiplication
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Signed Dst * Src -> Dst
        void MUL();

        // [Integer] 0x018 — UMUL: Unsigned Multiplication
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Unsigned Dst * Src -> Dst
        void UMUL();

        // [Integer] 0x019 — DIV: Division
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Signed Dst / Src -> Dst
        void DIV();

        // [Integer] 0x01A — UDIV: Unsigned Division
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Unsigned Dst / Src -> Dst
        void UDIV();

        // [Integer] 0x01B — MOD: Modulus
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Signed Dst % Src -> Dst
        void MOD();

        // [Integer] 0x01C — UMOD: Unsigned Modulus
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Unsigned Dst % Src -> Dst
        void UMOD();

        // [Integer] 0x01D — DMOD: Division and Modulus
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Signed Dst / Src -> X, Dst % Src -> Y
        void DMOD();

        // [Integer] 0x01E — UDMD: Unsigned Division and Modulus
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Unsigned Dst / Src -> X, Dst % Src -> Y
        void UDMD();

        // [System] 0x01F — FBT: Test and update Flag Register (Integer) Bits
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Flags of Dst -
        void FBT();

        // [Bit Wise] 0x020 — STB: Set Bit
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Src# bit is set on Dst
        void STB();

        // [Bit Wise] 0x021 — CRB: Clear Bit
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Src# bit is cleared on Dst
        void CRB();

        // [Bit Wise] 0x022 — TSB: Test Bit
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Src# bit is tested against Dst, updates Equal Flag
        void TSB();

        // [Bit Wise] 0x023 — BOOL: Sets the booleaness of a value
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Tests Dst != 0, updates Equal Flag
        void BOOL();

        // [Bit Wise] 0x024 — NOT: Sets the inverse booleaness of a value (! BOOL)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Tests Dst == 0, updates Equal Flag
        void NOT();

        // [Bit Wise] 0x025 — AND: Boolean AND operation
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst AND Src into Dst
        void AND();

        // [Bit Wise] 0x026 — OR: Boolean OR operation
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst OR Src into Dst
        void OR();

        // [Bit Wise] 0x027 — XOR: Boolean XOR operation
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst XOR Src into Dst
        void XOR();

        // [Bit Wise] 0x028 — SHL: Arithmetic Shift Left
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst << Src into Dst
        void SHL();

        // [Bit Wise] 0x029 — SHR: Arithmetic Shift Right
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst >> Src into Dst
        void SHR();

        // [Bit Wise] 0x02A — SSR: Signed Shift Right
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst >>> Src into Dst
        void SSR();

        // [Bit Wise] 0x02B — ROL: Rotate Left
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst ROL Src into Dst
        void ROL();

        // [Bit Wise] 0x02C — ROR: Rotate Right
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst ROR Src into Dst
        void ROR();

        // [Bit Wise] 0x02D — CNT: Counts bits
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: # of 1's into Dst
        void CNT();

        // [Boolean] 0x030 — EQ: Equal
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst == Src into Dst
        void EQ();

        // [Boolean] 0x031 — NE: Not Equal
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst != Src into Dst
        void NE();

        // [Boolean] 0x032 — GT: Greater Than
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst > Src into Dst
        void GT();

        // [Boolean] 0x033 — GE: Greater or Equal Than
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst >= Src into Dst
        void GE();

        // [Boolean] 0x034 — LT: Lower Than
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst < Src into Dst
        void LT();

        // [Boolean] 0x035 — LE: Lower or Equal Than
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst <= Src into Dst
        void LE();

        // [Branch] 0x038 — JMP: Jump to absolute position
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst -> Instruction Register
        void JMP();

        // [Branch] 0x039 — JEQ: Jumps to position if EQ flag is set
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst -> Instruction Register IF Flags.EQ
        void JEQ();

        // [Branch] 0x03A — JNE: Jumps to position if EQ flag is cleared
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst -> Instruction Register IF NOT Flags.EQ
        void JNE();

        // [Branch] 0x03B — JIF: Jumps if value provided is booleanly true
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst -> Instruction Register IF Src
        void JIF();

        // [Branch] 0x03C — JMR: Jump Relative
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst + Instruction Register -> Instruction Register
        void JMR();

        // [Branch] 0x03D — JER: Jumps to relative position if EQ flag is set
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst + Instruction Register -> Instruction Register IF Flags.EQ
        void JER();

        // [Branch] 0x03E — JNR: Jumps to relative position if EQ flag is cleared
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst + Instruction Register -> Instruction Register IF NOT Flags.EQ
        void JNR();

        // [Branch] 0x03F — JIR: Jumps to relative position if value provided is booleanly true
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst + Instruction Register -> Instruction Register IF Src
        void JIR();

        // [System] 0x040 — SFB: Store (User) Flag Bit
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: 
        void SFB();

        // [System] 0x041 — LFB: Load (User) Flag Bit
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: 
        void LFB();

        // [Branch] 0x042 — JUF: Jump to absolute position, if user flag is true
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: 
        void JUF();

        // [Branch] 0x043 — JUR: Jump to relative position, if user flag is true
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: 
        void JUR();

        // [Memory] 0x044 — PUSH: Push to stack
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst -> pushed into stack
        void PUSH();

        // [Memory] 0x045 — POP: Pop from stack
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: popped from stack -> Dst
        void POP();

        // [Memory] 0x046 — ALLOC: Allocate to heap
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Dst -> heap ptr of size Dst
        void ALLOC();

        // [Memory] 0x047 — HFREE: Delete from heap
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Frees heap ptr in Dst
        void HFREE();

        // [Branch] 0x04A — CALL: Call function at instruction index
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Performs a function call, step XX
        void CALL();

        // [Branch] 0x04B — RET: Return from a function
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: Undoes a function call, step XX
        void RET();

        // [System] 0x04C — EDI: Enable/Disable External Interrupts
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: bool( Dst ) -> Enable External Interrupts Bit
        void EDI();

        // [System] 0x04D — SHSS: Set Hotswap Signal Bit
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 0F
        //   Operation: bool( Dst ) -> Hot Swap Signal Bit
        void SHSS();

        // [Floating Point] 0x050 — FLI: Float Load Immediate
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void FLI();

        // [Floating Point] 0x051 — FNEG: Float negate
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: - Dst -> Dst
        void FNEG();

        // [Floating Point] 0x052 — FADD: Float add
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst + Src -> Dst
        void FADD();

        // [Floating Point] 0x053 — FSUB: Float subtract
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst - Src-> Dst
        void FSUB();

        // [Floating Point] 0x054 — FMUL: Float multiplication
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst * Src -> Dst
        void FMUL();

        // [Floating Point] 0x055 — FDIV: Float division
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst / Src -> Dst
        void FDIV();

        // [Floating Point] 0x056 — FMOD: Float modulus
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst % Src -> Dst
        void FMOD();

        // [Floating Point] 0x057 — FDMOD: Float division and modulus
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst / Src -> X, Dst % Src -> Y
        void FDMOD();

        // [Floating Point] 0x058 — FEPS: Sets the float epsilon value, for comparison
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst -> Epsilon Register
        void FEPS();

        // [Floating Point] 0x059 — FEEP: Float Enable/Disable Epsilon
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: bool( Dst ) -> Epsilon Enable Bit
        void FEEP();

        // [Boolean] 0x05A — FEQ: Float Equal
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst == Src into Dst
        void FEQ();

        // [Boolean] 0x05B — FNE: Float Not Equal
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst != Src into Dst
        void FNE();

        // [Boolean] 0x05C — FGT: Float Greater Than
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst > Src into Dst
        void FGT();

        // [Boolean] 0x05D — FGE: Float Greater or Equal Than
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst >= Src into Dst
        void FGE();

        // [Boolean] 0x05E — FLT: Float Lower Than
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst < Src into Dst
        void FLT();

        // [Boolean] 0x05F — FLE: Float Lower or Equal Than
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst <= Src into Dst
        void FLE();

        // [Casts] 0x060 — F2D: F32 (Float) to F64 (Double)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void F2D();

        // [Casts] 0x061 — D2F: F64 (Double) to F32 (Float)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void D2F();

        // [Casts] 0x062 — I2F: I32 (Integer) to F32 (Float)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void I2F();

        // [Casts] 0x063 — I2D: I32 (Integer) to F64 (Double)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void I2D();

        // [Casts] 0x064 — L2F: I64 (Long) to F32 (Float)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void L2F();

        // [Casts] 0x065 — L2D: I64 (Long) to F64 (Double)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void L2D();

        // [Casts] 0x066 — F2I: F32 (Float) to I32 (Integer)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void F2I();

        // [Casts] 0x067 — F2L: F32 (Float) to I64 (Long)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void F2L();

        // [Casts] 0x068 — D2I: F64 (Double) to I32 (Integer)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void D2I();

        // [Casts] 0x069 — D2L: F64 (Double) to I64 (Long)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: (cast) Dst -> Dst
        void D2L();

        // [Trigonometric] 0x06C — SIN: Sine Function
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: sin( Dst ) -> Dst
        void SIN();

        // [Trigonometric] 0x06D — COS: Cosine Function
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: cos( Dst ) -> Dst
        void COS();

        // [Trigonometric] 0x06E — TAN: Tangent Function
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: tan( Dst ) -> Dst
        void TAN();

        // [Trigonometric] 0x06F — ASIN: Arc Sine Function
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: asin( Dst ) -> Dst
        void ASIN();

        // [Trigonometric] 0x070 — ACOS: Arc Cosine Function
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: acos( Dst ) -> Dst
        void ACOS();

        // [Trigonometric] 0x071 — ATAN: Arc Tangent Function
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: atan( Dst ) -> Dst
        void ATAN();

        // [Trigonometric] 0x072 — ATAN2: Arc Tangent Function with 2 Arguments
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: atan( Dst, Src ) -> Dst
        void ATAN2();

        // [Exponential] 0x074 — EXP: Exponential Function
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: exp( Dst ) -> Dst
        void EXP();

        // [Exponential] 0x075 — LOG: Natural Logarithm
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: ln( Dst ) -> Dst
        void LOG();

        // [Exponential] 0x076 — LOGAB: Logarithm A of B
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: log( Dst, Src ) -> Dst
        void LOGAB();

        // [Exponential] 0x077 — POW: Power Function
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: pow( Dst, Src ) -> Dst
        void POW();

        // [Exponential] 0x078 — SQRT: Square Root
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: sqrt( Dst ) -> Dst
        void SQRT();

        // [Exponential] 0x079 — ROOT: General Root
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: pow( Dst, 1 / Src ) -> Dst
        void ROOT();

        // [Integer] 0x07C — ADC: Add with Carry
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst + Src + Flags.Carry -> Dst, Flags.Carry
        void ADC();

        // [Integer] 0x07D — SWC: Subtract with Carry (Borrow)
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Dst - Src - Flags.Carry -> Dst, Flags.Carry
        void SWC();

        // [Integer] 0x07E — MWO: Multiply with Overflow
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Signed Dst * Src -> Dst, Flags.Carry
        void MWO();

        // [Integer] 0x07F — UMO: Unsigned Multiply with Overflow
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: Unsigned Dst * Src -> Dst, Flags.Carry
        void UMO();

        // [Matrix] 0x080 — MADD: Matrix Addition
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void MADD();

        // [Matrix] 0x081 — MSUB: Matrix Subtraction
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void MSUB();

        // [Matrix] 0x082 — MMUL: Matrix Multiply
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void MMUL();

        // [Matrix] 0x083 — MINV: Matrix Inverse
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void MINV();

        // [Matrix] 0x084 — MTRA: Matrix Transpose
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void MTRA();

        // [Matrix] 0x085 — MDET: Matrix Determinant
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void MDET();

        // [SIMD] 0x08A — XADD: SIMD Addition
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void XADD();

        // [SIMD] 0x08B — XSUB: SIMD Subtract
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void XSUB();

        // [SIMD] 0x08C — XAMA: SIMD Alternate Multiply-Add
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void XAMA();

        // [SIMD] 0x08D — XMUL: SIMD Multiply
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void XMUL();

        // [SIMD] 0x08E — XDIV: SIMD Divide
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void XDIV();

        // [Easter Eggs] 0x0F0 — UPY: Will place "YUPI" in memory
        //   Params: 0 | AddrMask1: 00 AddrMask2: 00 | TypeMask: 00
        //   Operation: 
        void UPY();

        // </pygen-target> //

    };

}