#include <cpu.h>
#include <stdio.h>
#include <instructions/instructions.h>

/* mov.l @(disp,PC),Rn */
void instruction_movl_disp_pc_r(cpu_status_t* status) {
    uint32_t disp = (0x000000FF & cpu_read8(status,status->pc+1));
    status->r[LO_NIBBLE(cpu_read8(status,status->pc))] = cpu_read32(status,(status->pc & 0xFFFFFFFC) + 4 + (disp << 2));
    status->pc += 2;
}

void instruction_movl_ar_r(cpu_status_t* status) {
    status->r[LO_NIBBLE(cpu_read8(status,status->pc))] = cpu_read32(status, status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))]);
    status->pc += 2;
}

void instruction_movl_r_ar(cpu_status_t* status) {
    cpu_write32(status, status->r[LO_NIBBLE(cpu_read8(status,status->pc))], status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))]);
    //printf("@%8x <- %8x\n", LO_NIBBLE(cpu_read8(status,status->pc)),HI_NIBBLE(cpu_read8(status,status->pc+1)));
    status->pc += 2;
}

void instruction_movl_arp_r(cpu_status_t* status){
    status->r[LO_NIBBLE(cpu_read8(status,status->pc))] = cpu_read32(status, status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))]);

    //if (status->r[LO_NIBBLE(cpu_read8(status,status->pc))] != status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))])
    if (LO_NIBBLE(cpu_read8(status,status->pc)) != HI_NIBBLE(cpu_read8(status,status->pc+1)))
        status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))] += 4;
    status->pc += 2;
}

void instruction_movl_r_amr(cpu_status_t* status){
    cpu_write32(status, status->r[LO_NIBBLE(cpu_read8(status,status->pc))]-4, status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))]);
    status->r[LO_NIBBLE(cpu_read8(status,status->pc))] -= 4;
    status->pc += 2;
}

void instruction_movl_disp_r_r(cpu_status_t* status){
    long disp = (0x0000000F & (long)LO_NIBBLE(cpu_read8(status,status->pc+1)));
    status->r[LO_NIBBLE(cpu_read8(status,status->pc))] = cpu_read32(status, status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))] + (disp << 2));
    status->pc += 2;
}

void instruction_movl_r_disp_r(cpu_status_t* status){
    long disp = (0x0000000F & (long)LO_NIBBLE(cpu_read8(status,status->pc+1)));
    cpu_write32(status, status->r[LO_NIBBLE(cpu_read8(status,status->pc))] + (disp << 2), status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))]);
    status->pc += 2;
}

void instruction_movl_r0_r_r(cpu_status_t* status){
    status->r[LO_NIBBLE(cpu_read8(status,status->pc))] = cpu_read32(status, status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))] + status->r[0]);
    status->pc += 2;
}

void instruction_movl_r_r0_r(cpu_status_t* status){
    cpu_write32(status, status->r[LO_NIBBLE(cpu_read8(status,status->pc))] + status->r[0], status->r[HI_NIBBLE(cpu_read8(status,status->pc+1))]);
    status->pc += 2;
}

void instruction_movl_disp_gbr_r0(cpu_status_t* status){
    unsigned int disp = (0x000000FF & cpu_read8(status,status->pc+1));
    status->r[0] = cpu_read32(status, status->gbr + (disp << 2));
    status->pc += 2;
}