#include "InstrReel.hpp"

#include <spider/runtime/cpu/CPU.hpp>

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

namespace spider {

    // Public Interface //

    InstrReel::InstrReel() : _mem(nullptr), _size(0), _offset(0), _total_size(0) {}

    InstrReel::~InstrReel() {}

    // Instruction abstraction //

    u8 InstrReel::atU8(u64 ip) {
        // guard against access
        u64 ip_p = ip - _offset;
        if(ip_p + 1 > _size) return 0;

        // send byte
        return _mem[ip];
    }

    u16 InstrReel::atU16(u64 ip) {
        // guard against access
        u64 ip_p = ip - _offset;
        if(ip_p + 2 > _size) return 0;

        // build a 16-bit big endian number
        u16 dat;
        spider::loadLE(&dat, _mem + ip_p);
        return dat;
    }

    u32 InstrReel::atU32(u64 ip) {
        // guard against access
        u64 ip_p = ip - _offset;
        if(ip_p + 4 > _size) return 0;

        // build a 32-bit big endian number
        u32 dat;
        spider::loadLE(&dat, _mem + ip_p);
        return dat;
    }

    u64 InstrReel::atU64(u64 ip) {
        // guard against access
        u64 ip_p = ip - _offset;
        if(ip_p + 8 > _size) return 0;

        // build a 64-bit big endian number
        u64 dat;
        spider::loadLE(&dat, _mem + ip_p);
        return dat;
    }

    u64 InstrReel::size() {
        return _total_size;
    }

    // Static Utils //

    u16 InstrReel::unpackInstr(u16 bcode) {
        return (bcode >> 5) & 0x1FF;
    }

    u8 InstrReel::unpackAddrMode(u16 bcode) {
        return (bcode >> 2) & 0x1F;
    }

    u8 InstrReel::unpackTypeSize(u16 bcode) {
        return bcode & 0x3;
    }

}
