#include "CPU.hpp"

#include <spider/runtime/native/machine.hpp>

#include <spider/runtime/memory/RAM.hpp>

#include <spider/runtime/reel/InstrReel.hpp>

#if __cplusplus >= 202002L
#include <bit>
#endif

namespace spider {

    CPU::CPU()
        : RA{}, RB{}, RC{}, RD{},
        RX{}, RY{}, R0{}, R1{},
        R2{}, R3{}, R4{}, R5{},
        R6{}, R7{}, R8{}, R9{},
        RF{}, RI{}, RS{}, RZ{},
        RE{}, RN{}, RV{}, RM{},
        ALU0{}, ALU1{},
        _ram(nullptr), _reel(nullptr) {
    }

    CPU::~CPU() {}

    // Setup & Configuration //

    void CPU::hookRAM(RAM* ram) {
        this->_ram = ram;
    }

    void CPU::hookInstrReel(InstrReel* reel) {
        this->_reel = reel;
    }

    constexpr u64 CPU::getFlag(u64 mask) {
        if (!mask) return 0;
#if __cplusplus >= 202002L
        return (RF & mask) >> std::countr_zero(mask);
#elif defined(SPIDER_COMPILER_GCC_LIKE)
        return (RF & mask) >> __builtin_ctzll(mask);
#elif defined(SPIDER_COMPILER_MSVC)
        return (RF & mask) >> _BitScanForward64(mask);
#else
        // If you have reached this part,
        // please come up with a better alternative.
        u64 bits = RF & mask;
        while (mask && (mask >>= 1)) bits >>= 1;
        return bits;
#endif
    }

    // Addressing Modes //

    /**
     * Implied Addressing Mode
     */
    void CPU::imp() {
        // Nothing //
    }

    /**
     * Immediate Addressing Mode
     */
    void CPU::imm() {
        u8 size = 2 << _size;
        _next = &ALU0;
    }

    /**
     * Absolute Addressing Mode
     */
    void CPU::abs() {
        u8 size = 2 << getFlag(CPU::FLAG_MEMORY_MODE);
    }

    /**
     * Register Addressing Mode
     */
    void CPU::reg() {
        sizeof(CPU);
    }

    /**
     * Indrect Addressing Mode
     */
    void CPU::ind() {}

    /**
     * Pointer Addressing Mode
     */
    void CPU::ptr() {}

    /**
     * Indexed Addressing Mode
     */
    void CPU::idx() {}

    /**
     * Scaled Addressing Mode
     */
    void CPU::sca() {}

    /**
     * Displaced Addressing Mode
     */
    void CPU::dis() {}

}
