/*
DingusPPC - The Experimental PowerPC Macintosh emulator
Copyright (C) 2018-20 divingkatae and maximum
                      (theweirdo)     spatium

(Contact divingkatae#1017 or powermax#2286 on Discord for more info)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

// The Power-specific opcodes for the processor - ppcopcodes.cpp
// Any shared opcodes are in ppcopcodes.cpp

#include "ppcemu.h"
#include "ppcmmu.h"
#include <cmath>
#include <iostream>
#include <limits>
#include <stdio.h>
#include <thirdparty/loguru/loguru.hpp>

void power_abs() {
    ppc_grab_regsda();
    if (ppc_result_a == 0x80000000) {
        ppc_result_d = ppc_result_a;

    } else {
        ppc_result_d = ppc_result_a & 0x7FFFFFFF;
    }
    ppc_store_result_regd();
}


void power_absdot() {
    ppc_grab_regsda();
    if (ppc_result_a == 0x80000000) {
        ppc_result_d = ppc_result_a;

    } else {
        ppc_result_d = ppc_result_a & 0x7FFFFFFF;
    }
    ppc_changecrf0(ppc_result_d);
    ppc_store_result_regd();
}

void power_abso() {
    ppc_grab_regsda();
    if (ppc_result_a == 0x80000000) {
        ppc_result_d = ppc_result_a;
        ppc_state.spr[SPR::XER] |= 0x40000000;

    } else {
        ppc_result_d = ppc_result_a & 0x7FFFFFFF;
    }
    ppc_store_result_regd();
}

void power_absodot() {
    ppc_grab_regsda();
    if (ppc_result_a == 0x80000000) {
        ppc_result_d = ppc_result_a;
        ppc_state.spr[SPR::XER] |= 0x40000000;

    } else {
        ppc_result_d = ppc_result_a & 0x7FFFFFFF;
    }
    ppc_changecrf0(ppc_result_d);
    ppc_store_result_regd();
}

void power_clcs() {
    ppc_grab_regsda();
    switch (reg_a) {
    case 12:
    case 13:
    case 14:
    case 15:
        ppc_result_d = 65535;
        break;
    default:
        ppc_result_d = 0;
    }
    ppc_store_result_regd();
}

void power_clcsdot() {
    switch (reg_a) {
    case 12:
    case 13:
    case 14:
    case 15:
        ppc_result_d = 65535;
        break;
    default:
        ppc_result_d = 0;
    }
    ppc_changecrf0(ppc_result_d);
    printf("Does RC do anything here? (TODO) \n");
    ppc_store_result_regd();
}

void power_div() {
    ppc_grab_regsdab();
    ppc_result_d           = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
    ppc_state.spr[SPR::MQ] = (ppc_result_a | ppc_state.spr[SPR::MQ]) % ppc_result_b;
    ppc_store_result_regd();
}

void power_divdot() {
    ppc_result_d           = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
    ppc_state.spr[SPR::MQ] = (ppc_result_a | ppc_state.spr[SPR::MQ]) % ppc_result_b;
}

void power_divo() {
    ppc_result_d           = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
    ppc_state.spr[SPR::MQ] = (ppc_result_a | ppc_state.spr[SPR::MQ]) % ppc_result_b;
}

void power_divodot() {
    ppc_result_d           = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
    ppc_state.spr[SPR::MQ] = (ppc_result_a | ppc_state.spr[SPR::MQ]) % ppc_result_b;
}

void power_divs() {
    ppc_grab_regsdab();
    ppc_result_d           = ppc_result_a / ppc_result_b;
    ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b);
    ppc_store_result_regd();
}

void power_divsdot() {
    ppc_result_d           = ppc_result_a / ppc_result_b;
    ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b);
}

void power_divso() {
    ppc_result_d           = ppc_result_a / ppc_result_b;
    ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b);
}

void power_divsodot() {
    ppc_result_d           = ppc_result_a / ppc_result_b;
    ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b);
}

void power_doz() {
    ppc_grab_regsdab();
    if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
        ppc_result_d = 0;
    } else {
        ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
    }
    ppc_store_result_rega();
}

void power_dozdot() {
    ppc_grab_regsdab();
    if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
        ppc_result_d = 0;
    } else {
        ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
    }
    ppc_changecrf0(ppc_result_d);
    ppc_store_result_rega();
}

void power_dozo() {
    if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
        ppc_result_d = 0;
    } else {
        ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
    }
}

void power_dozodot() {
    if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
        ppc_result_d = 0;
    } else {
        ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
    }
}

void power_dozi() {
    ppc_grab_regsdab();
    if (((int32_t)ppc_result_a) > simm) {
        ppc_result_d = 0;
    } else {
        ppc_result_d = ~ppc_result_a + simm + 1;
    }
    ppc_store_result_rega();
}

void power_lscbx() {
    ppc_grab_regsdab();
    uint32_t bytes_copied = 0;
    bool match_found      = false;
    uint32_t shift_amount = 0;
    uint8_t return_value;
    uint8_t byte_compared = (uint8_t)((ppc_state.spr[SPR::XER] & 0xFF00) >> 8);
    if ((ppc_state.spr[SPR::XER] & 0x7f) == 0) {
        return;
    }
    uint32_t bytes_to_load = (ppc_state.spr[SPR::XER] & 0x7f) + 1;
    ppc_effective_address  = (reg_a == 0) ? ppc_result_b : ppc_result_a + ppc_result_b;
    do {
        ppc_effective_address++;
        bytes_to_load--;
        if (match_found == false) {
            switch (shift_amount) {
            case 0:
                return_value = mem_grab_byte(ppc_effective_address);
                ppc_result_d = (ppc_result_d & 0x00FFFFFF) | (return_value << 24);
                ppc_store_result_regd();
                break;
            case 1:
                return_value = mem_grab_byte(ppc_effective_address);
                ppc_result_d = (ppc_result_d & 0xFF00FFFF) | (return_value << 16);
                ppc_store_result_regd();
                break;
            case 2:
                return_value = mem_grab_byte(ppc_effective_address);
                ppc_result_d = (ppc_result_d & 0xFFFF00FF) | (return_value << 8);
                ppc_store_result_regd();
                break;
            case 3:
                return_value = mem_grab_byte(ppc_effective_address);
                ppc_result_d = (ppc_result_d & 0xFFFFFF00) | return_value;
                ppc_store_result_regd();
                break;
            }

            bytes_copied++;
        }
        if (return_value == byte_compared) {
            break;
        }

        if (shift_amount == 3) {
            shift_amount = 0;
            reg_d        = (reg_d + 1) & 0x1F;
        } else {
            shift_amount++;
        }
    } while (bytes_to_load > 0);
    ppc_state.spr[SPR::XER] = (ppc_state.spr[SPR::XER] & 0xFFFFFF80) | bytes_copied;
    ppc_store_result_regd();
}

void power_lscbxdot() {
    printf("OOPS! Placeholder!!! \n");
}

void power_maskg() {
    ppc_grab_regssab();
    uint32_t mask_start  = ppc_result_d & 31;
    uint32_t mask_end    = ppc_result_b & 31;
    uint32_t insert_mask = 0;

    if (mask_start < (mask_end + 1)) {
        for (uint32_t i = mask_start; i < mask_end; i++) {
            insert_mask |= (0x80000000 >> i);
        }
    } else if (mask_start == (mask_end + 1)) {
        insert_mask = 0xFFFFFFFF;
    } else {
        insert_mask = 0xFFFFFFFF;
        for (uint32_t i = (mask_end + 1); i < (mask_start - 1); i++) {
            insert_mask &= (~(0x80000000 >> i));
        }
    }

    ppc_result_a = insert_mask;
    ppc_store_result_rega();
}

void power_maskgdot() {
    ppc_grab_regssab();
    uint32_t mask_start  = ppc_result_d & 31;
    uint32_t mask_end    = ppc_result_b & 31;
    uint32_t insert_mask = 0;

    if (mask_start < (mask_end + 1)) {
        for (uint32_t i = mask_start; i < mask_end; i++) {
            insert_mask |= (0x80000000 >> i);
        }
    } else if (mask_start == (mask_end + 1)) {
        insert_mask = 0xFFFFFFFF;
    } else {
        insert_mask = 0xFFFFFFFF;
        for (uint32_t i = (mask_end + 1); i < (mask_start - 1); i++) {
            insert_mask &= (~(0x80000000 >> i));
        }
    }

    ppc_result_a = insert_mask;
    ppc_store_result_rega();
}

void power_maskir() {
    ppc_grab_regssab();
    uint32_t mask_insert = ppc_result_a;
    uint32_t insert_rot  = 0x80000000;
    do {
        if (ppc_result_b & insert_rot) {
            mask_insert &= ~insert_rot;
            mask_insert |= (ppc_result_d & insert_rot);
        }
        insert_rot = insert_rot >> 1;
    } while (insert_rot > 0);

    ppc_result_a = (ppc_result_d & ppc_result_b);
    ppc_store_result_rega();
}

void power_maskirdot() {
    ppc_grab_regssab();
    uint32_t mask_insert = ppc_result_a;
    uint32_t insert_rot  = 0x80000000;
    do {
        if (ppc_result_b & insert_rot) {
            mask_insert &= ~insert_rot;
            mask_insert |= (ppc_result_d & insert_rot);
        }
        insert_rot = insert_rot >> 1;
    } while (insert_rot > 0);

    ppc_result_a = (ppc_result_d & ppc_result_b);
    ppc_changecrf0(ppc_result_a);
    ppc_store_result_rega();
}

void power_mul() {
    ppc_grab_regsdab();
    uint64_t product;

    product                = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
    ppc_result_d           = ((uint32_t)(product >> 32));
    ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
    ppc_store_result_regd();
}

void power_muldot() {
    ppc_grab_regsdab();
    uint64_t product;

    product                = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
    ppc_result_d           = ((uint32_t)(product >> 32));
    ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
    ppc_changecrf0(ppc_result_d);
    ppc_store_result_regd();
}

void power_mulo() {
    uint64_t product;

    product                = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
    ppc_result_d           = ((uint32_t)(product >> 32));
    ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
}

void power_mulodot() {
    uint64_t product;

    product                = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
    ppc_result_d           = ((uint32_t)(product >> 32));
    ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
}

void power_nabs() {
    ppc_grab_regsda();
    ppc_result_d = (0x80000000 | ppc_result_a);
    ppc_store_result_regd();
}

void power_nabsdot() {
    ppc_result_d = (0x80000000 | ppc_result_a);
}

void power_nabso() {
    ppc_result_d = (0x80000000 | ppc_result_a);
}

void power_nabsodot() {
    ppc_result_d = (0x80000000 | ppc_result_a);
}

void power_rlmi() {
    ppc_grab_regssab();
    unsigned rot_mb      = (ppc_cur_instruction >> 6) & 31;
    unsigned rot_me      = (ppc_cur_instruction >> 1) & 31;
    uint32_t rot_amt     = ppc_result_b & 31;
    uint32_t insert_mask = 0;

    if (rot_mb < (rot_me + 1)) {
        for (uint32_t i = rot_mb; i < rot_me; i++) {
            insert_mask |= (0x80000000 >> i);
        }
    } else if (rot_mb == (rot_me + 1)) {
        insert_mask = 0xFFFFFFFF;
    } else {
        insert_mask = 0xFFFFFFFF;
        for (uint32_t i = (rot_me + 1); i < (rot_mb - 1); i++) {
            insert_mask &= (~(0x80000000 >> i));
        }
    }

    uint32_t step2 = (ppc_result_d << rot_amt) | (ppc_result_d >> rot_amt);
    ppc_result_a   = step2 & insert_mask;
    ppc_store_result_rega();
}

void power_rrib() {
    ppc_grab_regssab();
    if (ppc_result_d & 0x80000000) {
        ppc_result_a |= (0x80000000 >> ppc_result_b);
    } else {
        ppc_result_a &= ~(0x80000000 >> ppc_result_b);
    }
    ppc_store_result_rega();
}

void power_rribdot() {
    ppc_grab_regssab();
    if (ppc_result_d & 0x80000000) {
        ppc_result_a |= (0x80000000 >> ppc_result_b);
    } else {
        ppc_result_a &= ~(0x80000000 >> ppc_result_b);
    }
    ppc_changecrf0(ppc_result_a);
    ppc_store_result_rega();
}

void power_sle() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    uint32_t rot_amt     = ppc_result_b & 31;
    for (uint32_t i = 31; i > rot_amt; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_final  = ((ppc_result_d << rot_amt) | (ppc_result_d >> (32 - rot_amt)));
    ppc_state.spr[SPR::MQ] = insert_final & insert_mask;
    ppc_result_a           = insert_final & insert_mask;
    ppc_store_result_rega();
}

void power_sledot() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    uint32_t rot_amt     = ppc_result_b & 31;
    for (uint32_t i = 31; i > rot_amt; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_final  = ((ppc_result_d << rot_amt) | (ppc_result_d >> (32 - rot_amt)));
    ppc_state.spr[SPR::MQ] = insert_final & insert_mask;
    ppc_result_a           = insert_final & insert_mask;
    ppc_changecrf0(ppc_result_a);
    ppc_store_result_rega();
}

void power_sleq() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    uint32_t rot_amt     = ppc_result_b & 31;
    for (uint32_t i = 31; i > rot_amt; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d << rot_amt) | (ppc_result_d >> (rot_amt - 31)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_store_result_rega();
}

void power_sleqdot() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    uint32_t rot_amt     = ppc_result_b & 31;
    for (uint32_t i = 31; i > rot_amt; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d << rot_amt) | (ppc_result_d >> (rot_amt - 31)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_changecrf0(ppc_result_a);
    ppc_store_result_rega();
}

void power_sliq() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    unsigned rot_sh      = (ppc_cur_instruction >> 11) & 31;
    for (uint32_t i = 31; i > rot_sh; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d << rot_sh) | (ppc_result_d >> (rot_sh - 31)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end & insert_mask;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_store_result_rega();
}

void power_sliqdot() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    unsigned rot_sh      = (ppc_cur_instruction >> 11) & 31;
    for (uint32_t i = 31; i > rot_sh; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d << rot_sh) | (ppc_result_d >> (rot_sh - 31)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end & insert_mask;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_changecrf0(ppc_result_a);
    ppc_store_result_rega();
}

void power_slliq() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    unsigned rot_sh      = (ppc_cur_instruction >> 11) & 31;
    for (uint32_t i = 31; i > rot_sh; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_store_result_rega();
}

void power_slliqdot() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    unsigned rot_sh      = (ppc_cur_instruction >> 11) & 31;
    for (uint32_t i = 31; i > rot_sh; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_changecrf0(ppc_result_a);
    ppc_store_result_rega();
}

void power_sllq() {
    LOG_F(WARNING, "OOPS! Placeholder for sllq!!! \n");
}

void power_sllqdot() {
    LOG_F(WARNING, "OOPS! Placeholder for sllq.!!! \n");
}

void power_slq() {
    LOG_F(WARNING, "OOPS! Placeholder for slq!!! \n");
}

void power_slqdot() {
    LOG_F(WARNING, "OOPS! Placeholder for slq.!!! \n");
}

void power_sraiq() {
    LOG_F(WARNING, "OOPS! Placeholder for sraiq!!! \n");
}

void power_sraiqdot() {
    LOG_F(WARNING, "OOPS! Placeholder for sraiq.!!! \n");
}

void power_sraq() {
    LOG_F(WARNING, "OOPS! Placeholder for sraq!!! \n");
}

void power_sraqdot() {
    LOG_F(WARNING, "OOPS! Placeholder for sraq.!!! \n");
}

void power_sre() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    uint32_t rot_amt     = ppc_result_b & 31;
    for (uint32_t i = 31; i > rot_amt; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_final  = ((ppc_result_d >> rot_amt) | (ppc_result_d << (32 - rot_amt)));
    ppc_state.spr[SPR::MQ] = insert_final & insert_mask;
    ppc_result_a           = insert_final;
    ppc_store_result_rega();
}

void power_sredot() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    uint32_t rot_amt     = ppc_result_b & 31;
    for (uint32_t i = 31; i > rot_amt; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_final  = ((ppc_result_d >> rot_amt) | (ppc_result_d << (32 - rot_amt)));
    ppc_state.spr[SPR::MQ] = insert_final & insert_mask;
    ppc_result_a           = insert_final;
    ppc_changecrf0(ppc_result_a);
    ppc_store_result_rega();
}

void power_srea() {
    LOG_F(WARNING, "OOPS! Placeholder for srea!!! \n");
}

void power_sreadot() {
    LOG_F(WARNING, "OOPS! Placeholder for srea.!!! \n");
}

void power_sreq() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    unsigned rot_sh      = ppc_result_b & 31;
    for (uint32_t i = 31; i > rot_sh; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_store_result_rega();
}

void power_sreqdot() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    unsigned rot_sh      = ppc_result_b & 31;
    for (uint32_t i = 31; i > rot_sh; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_changecrf0(ppc_result_a);
    ppc_store_result_rega();
}

void power_sriq() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    unsigned rot_sh      = (ppc_cur_instruction >> 11) & 31;
    for (uint32_t i = 31; i > rot_sh; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_store_result_rega();
}

void power_sriqdot() {
    ppc_grab_regssa();
    uint32_t insert_mask = 0;
    unsigned rot_sh      = (ppc_cur_instruction >> 11) & 31;
    for (uint32_t i = 31; i > rot_sh; i--) {
        insert_mask |= (1 << i);
    }
    uint32_t insert_start = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
    uint32_t insert_end   = ppc_state.spr[SPR::MQ];

    for (int i = 0; i < 32; i++) {
        if (insert_mask & (1 << i)) {
            insert_end &= ~(1 << i);
            insert_end |= (insert_start & (1 << i));
        }
    }

    ppc_result_a           = insert_end;
    ppc_state.spr[SPR::MQ] = insert_start;
    ppc_changecrf0(ppc_result_a);
    ppc_store_result_rega();
}

void power_srliq() {
    LOG_F(WARNING, "OOPS! Placeholder for slriq!!! \n");
}

void power_srliqdot() {
    LOG_F(WARNING, "OOPS! Placeholder for slriq.!!! \n");
}

void power_srlq() {
    LOG_F(WARNING, "OOPS! Placeholder for slrq!!! \n");
}

void power_srlqdot() {
    LOG_F(WARNING, "OOPS! Placeholder for slrq.!!! \n");
}

void power_srq() {
    LOG_F(WARNING, "OOPS! Placeholder for srq!!! \n");
}

void power_srqdot() {
    LOG_F(WARNING, "OOPS! Placeholder for srq.!!! \n");
}
