mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-12-25 18:29:49 +00:00
2444 lines
72 KiB
C++
2444 lines
72 KiB
C++
//DingusPPC
|
|
//Written by divingkatae and maximum
|
|
//(c)2018-20 (theweirdo) spatium
|
|
//Please ask for permission
|
|
//if you want to distribute this.
|
|
//(divingkatae#1017 or powermax#2286 on Discord)
|
|
|
|
// General opcodes for the processor - ppcopcodes.cpp
|
|
|
|
#include <thirdparty/loguru.hpp>
|
|
#include <iostream>
|
|
#include <cstring>
|
|
#include <cinttypes>
|
|
#include <array>
|
|
#include <thread>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdexcept>
|
|
#include "ppcemu.h"
|
|
#include "ppcmmu.h"
|
|
|
|
uint32_t crf_d;
|
|
uint32_t crf_s;
|
|
uint32_t reg_s;
|
|
uint32_t reg_d;
|
|
uint32_t reg_a;
|
|
uint32_t reg_b;
|
|
uint32_t reg_c; //used only for floating point multiplication operations
|
|
uint32_t xercon;
|
|
uint32_t cmp_c;
|
|
uint32_t crm;
|
|
uint32_t uimm;
|
|
uint32_t grab_sr;
|
|
uint32_t grab_inb; //This is for grabbing the number of immediate bytes for loading and storing
|
|
uint32_t ppc_to;
|
|
int32_t simm;
|
|
int32_t adr_li;
|
|
|
|
//Used for GP calcs
|
|
uint32_t ppc_result_a = 0;
|
|
uint32_t ppc_result_b = 0;
|
|
uint32_t ppc_result_c = 0;
|
|
uint32_t ppc_result_d = 0;
|
|
|
|
uint32_t strwrd_replace_value;
|
|
|
|
/**
|
|
Extract the registers desired and the values of the registers
|
|
This also takes the MSR into account, mainly to determine
|
|
what endian the numbers are to be stored in.
|
|
**/
|
|
|
|
//Storage and register retrieval functions for the integer functions.
|
|
void ppc_store_result_regd() {
|
|
ppc_state.ppc_gpr[reg_d] = ppc_result_d;
|
|
}
|
|
|
|
void ppc_store_result_rega() {
|
|
ppc_state.ppc_gpr[reg_a] = ppc_result_a;
|
|
}
|
|
|
|
void ppc_grab_regsdasimm() {
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
reg_a = (ppc_cur_instruction >> 16) & 31;
|
|
simm = (int32_t)((int16_t)((ppc_cur_instruction) & 65535));
|
|
ppc_result_a = ppc_state.ppc_gpr[reg_a];
|
|
}
|
|
|
|
void ppc_grab_regsdauimm() {
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
reg_a = (ppc_cur_instruction >> 16) & 31;
|
|
uimm = (uint32_t)((uint16_t)((ppc_cur_instruction) & 65535));
|
|
ppc_result_a = ppc_state.ppc_gpr[reg_a];
|
|
}
|
|
|
|
void ppc_grab_regsasimm() {
|
|
reg_a = (ppc_cur_instruction >> 16) & 31;
|
|
simm = (int32_t)((int16_t)(ppc_cur_instruction & 65535));
|
|
ppc_result_a = ppc_state.ppc_gpr[reg_a];
|
|
}
|
|
|
|
void ppc_grab_regssauimm() {
|
|
reg_s = (ppc_cur_instruction >> 21) & 31;
|
|
reg_a = (ppc_cur_instruction >> 16) & 31;
|
|
uimm = (uint32_t)((uint16_t)((ppc_cur_instruction) & 65535));
|
|
ppc_result_d = ppc_state.ppc_gpr[reg_s];
|
|
ppc_result_a = ppc_state.ppc_gpr[reg_a];
|
|
}
|
|
|
|
void ppc_grab_regsdab() {
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
reg_a = (ppc_cur_instruction >> 16) & 31;
|
|
reg_b = (ppc_cur_instruction >> 11) & 31;
|
|
ppc_result_a = ppc_state.ppc_gpr[reg_a];
|
|
ppc_result_b = ppc_state.ppc_gpr[reg_b];
|
|
}
|
|
|
|
void ppc_grab_regssab() {
|
|
reg_s = (ppc_cur_instruction >> 21) & 31;
|
|
reg_a = (ppc_cur_instruction >> 16) & 31;
|
|
reg_b = (ppc_cur_instruction >> 11) & 31;
|
|
ppc_result_d = ppc_state.ppc_gpr[reg_s];
|
|
ppc_result_a = ppc_state.ppc_gpr[reg_a];
|
|
ppc_result_b = ppc_state.ppc_gpr[reg_b];
|
|
}
|
|
|
|
void ppc_grab_regssa() {
|
|
reg_s = (ppc_cur_instruction >> 21) & 31;
|
|
reg_a = (ppc_cur_instruction >> 16) & 31;
|
|
ppc_result_d = ppc_state.ppc_gpr[reg_s];
|
|
ppc_result_a = ppc_state.ppc_gpr[reg_a];
|
|
}
|
|
|
|
void ppc_grab_regssb() {
|
|
reg_s = (ppc_cur_instruction >> 21) & 31;
|
|
reg_b = (ppc_cur_instruction >> 11) & 31;
|
|
ppc_result_d = ppc_state.ppc_gpr[reg_s];
|
|
ppc_result_b = ppc_state.ppc_gpr[reg_b];
|
|
}
|
|
|
|
void ppc_grab_regsda() {
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
reg_a = (ppc_cur_instruction >> 16) & 31;
|
|
ppc_result_a = ppc_state.ppc_gpr[reg_a];
|
|
}
|
|
|
|
void ppc_grab_regsdb() {
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
reg_b = (ppc_cur_instruction >> 11) & 31;
|
|
ppc_result_b = ppc_state.ppc_gpr[reg_b];
|
|
}
|
|
|
|
|
|
//Affects CR Field 0 - For integer operations
|
|
void ppc_changecrf0(uint32_t set_result) {
|
|
ppc_state.ppc_cr &= 0x0FFFFFFFUL;
|
|
|
|
if (set_result == 0) {
|
|
ppc_state.ppc_cr |= 0x20000000UL;
|
|
}
|
|
else {
|
|
if (set_result & 0x80000000) {
|
|
ppc_state.ppc_cr |= 0x80000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr |= 0x40000000UL;
|
|
}
|
|
}
|
|
|
|
/* copy XER[SO] into CR0[SO]. */
|
|
ppc_state.ppc_cr |= (ppc_state.ppc_spr[SPR::XER] >> 3) & 0x10000000UL;
|
|
}
|
|
|
|
//Affects the XER register's Carry Bit
|
|
inline void ppc_carry(uint32_t a, uint32_t b) {
|
|
if (b < a) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
}
|
|
|
|
inline void ppc_carry_sub(uint32_t a, uint32_t b) {
|
|
if (b >= a) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
}
|
|
|
|
//Affects the XER register's SO and OV Bits
|
|
|
|
inline void ppc_setsoov(uint32_t a, uint32_t b, uint32_t d) {
|
|
if ((a ^ b) & (a ^ d) & 0x80000000UL) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xC0000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
The core functionality of this PPC emulation is within all of these void functions.
|
|
This is where the opcode tables in the ppcemumain.h come into play - reducing the number of comparisons needed.
|
|
This means loads of functions, but less CPU cycles needed to determine the function (theoretically).
|
|
**/
|
|
|
|
void ppc_addi() {
|
|
ppc_grab_regsdasimm();
|
|
ppc_result_d = (reg_a == 0) ? simm : (ppc_result_a + simm);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addic() {
|
|
ppc_grab_regsdasimm();
|
|
ppc_result_d = (ppc_result_a + simm);
|
|
ppc_carry(ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addicdot() {
|
|
ppc_grab_regsdasimm();
|
|
ppc_result_d = (ppc_result_a + simm);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_carry(ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addis() {
|
|
ppc_grab_regsdasimm();
|
|
ppc_result_d = (reg_a == 0) ? (simm << 16) : (ppc_result_a + (simm << 16));
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_add() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_a + ppc_result_b;
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_adddot() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_a + ppc_result_b;
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
//addo + addodot
|
|
void ppc_addo() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_a + ppc_result_b;
|
|
ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addodot() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_a + ppc_result_b;
|
|
ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addc() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_a + ppc_result_b;
|
|
ppc_carry(ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addcdot() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_a + ppc_result_b;
|
|
ppc_carry(ppc_result_a, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addco() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_a + ppc_result_b;
|
|
ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d);
|
|
ppc_carry(ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addcodot() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_a + ppc_result_b;
|
|
ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d);
|
|
ppc_carry(ppc_result_a, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_adde() {
|
|
ppc_grab_regsdab();
|
|
uint32_t xer_ca = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + ppc_result_b + xer_ca;
|
|
if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addedot() {
|
|
ppc_grab_regsdab();
|
|
uint32_t xer_ca = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + ppc_result_b + xer_ca;
|
|
if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addeo() {
|
|
ppc_grab_regsdab();
|
|
uint32_t xer_ca = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + ppc_result_b + xer_ca;
|
|
if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addeodot() {
|
|
ppc_grab_regsdab();
|
|
uint32_t xer_ca = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + ppc_result_b + xer_ca;
|
|
if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addme() {
|
|
ppc_grab_regsda();
|
|
uint32_t xer_ca = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + xer_ca - 1;
|
|
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addmedot() {
|
|
ppc_grab_regsda();
|
|
uint32_t xer_ca = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + xer_ca - 1;
|
|
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addmeo() {
|
|
ppc_grab_regsda();
|
|
uint32_t xer_ca = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + xer_ca - 1;
|
|
ppc_setsoov(ppc_result_a, 0, ppc_result_d);
|
|
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addmeodot() {
|
|
ppc_grab_regsda();
|
|
uint32_t xer_ca = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + xer_ca - 1;
|
|
ppc_setsoov(ppc_result_a, 0, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addze() {
|
|
ppc_grab_regsda();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + grab_xer;
|
|
if (ppc_result_d < ppc_result_a) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addzedot() {
|
|
ppc_grab_regsda();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + grab_xer;
|
|
if (ppc_result_d < ppc_result_a) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addzeo() {
|
|
ppc_grab_regsda();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + grab_xer;
|
|
ppc_setsoov(ppc_result_a, 0xFFFFFFFFUL, ppc_result_d);
|
|
if (ppc_result_d < ppc_result_a) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_addzeodot() {
|
|
ppc_grab_regsda();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ppc_result_a + grab_xer;
|
|
ppc_setsoov(ppc_result_a, 0xFFFFFFFFUL, ppc_result_d);
|
|
if (ppc_result_d < ppc_result_a) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subf() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_b - ppc_result_a;
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfdot() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_b - ppc_result_a;
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfo() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_b - ppc_result_a;
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfodot() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_b - ppc_result_a;
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfc() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_b - ppc_result_a;
|
|
ppc_carry_sub(ppc_result_a, ppc_result_b);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfcdot() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_b - ppc_result_a;
|
|
ppc_carry_sub(ppc_result_a, ppc_result_b);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfco() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_b - ppc_result_a;
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_carry_sub(ppc_result_a, ppc_result_b);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfcodot() {
|
|
ppc_grab_regsdab();
|
|
ppc_result_d = ppc_result_b - ppc_result_a;
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_carry_sub(ppc_result_a, ppc_result_b);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfic() {
|
|
ppc_grab_regsdasimm();
|
|
ppc_result_d = simm - ppc_result_a;
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfe() {
|
|
ppc_grab_regsdab();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ~ppc_result_a + ppc_result_b + grab_xer;
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfedot() {
|
|
ppc_grab_regsdab();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ~ppc_result_a + ppc_result_b + grab_xer;
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfeo() {
|
|
ppc_grab_regsdab();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ~ppc_result_a + ppc_result_b + grab_xer;
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfeodot() {
|
|
ppc_grab_regsdab();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ~ppc_result_a + ppc_result_b + grab_xer;
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfme() {
|
|
ppc_grab_regsda();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ~ppc_result_a + grab_xer - 1;
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfmedot() {
|
|
ppc_grab_regsda();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ~ppc_result_a + grab_xer - 1;
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfmeo() {
|
|
ppc_grab_regsda();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ~ppc_result_a + grab_xer - 1;
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfmeodot() {
|
|
ppc_grab_regsda();
|
|
uint32_t grab_xer = !!(ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_result_d = ~ppc_result_a + grab_xer - 1;
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfze() {
|
|
ppc_grab_regsda();
|
|
ppc_result_d = ~ppc_result_a + (ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfzedot() {
|
|
ppc_grab_regsda();
|
|
ppc_result_d = ~ppc_result_a + (ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfzeo() {
|
|
ppc_grab_regsda();
|
|
ppc_result_d = ~ppc_result_a + (ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_subfzeodot() {
|
|
ppc_grab_regsda();
|
|
ppc_result_d = ~ppc_result_a + (ppc_state.ppc_spr[SPR::XER] & 0x20000000);
|
|
ppc_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
|
|
ppc_carry(~ppc_result_a, ppc_result_d);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
|
|
void ppc_and() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d & ppc_result_b;
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_anddot() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d & ppc_result_b;
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_andc() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d & ~(ppc_result_b);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_andcdot() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d & ~(ppc_result_b);
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_andidot() {
|
|
ppc_grab_regssauimm();
|
|
ppc_result_a = ppc_result_d & uimm;
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_andisdot() {
|
|
ppc_grab_regssauimm();
|
|
ppc_result_a = ppc_result_d & (uimm << 16);
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_nand() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ~(ppc_result_d & ppc_result_b);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_nanddot() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ~(ppc_result_d & ppc_result_b);
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_or() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d | ppc_result_b;
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_ordot() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d | ppc_result_b;
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_orc() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d | ~(ppc_result_b);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_orcdot() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d | ~(ppc_result_b);
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_ori() {
|
|
ppc_grab_regssauimm();
|
|
ppc_result_a = ppc_result_d | uimm;
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_oris() {
|
|
ppc_grab_regssauimm();
|
|
ppc_result_a = (uimm << 16) | ppc_result_d;
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_eqv() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ~(ppc_result_d ^ ppc_result_b);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_eqvdot() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ~(ppc_result_d ^ ppc_result_b);
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_nor() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ~(ppc_result_d | ppc_result_b);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_nordot() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ~(ppc_result_d | ppc_result_b);
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_xor() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d ^ ppc_result_b;
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_xordot() {
|
|
ppc_grab_regssab();
|
|
ppc_result_a = ppc_result_d ^ ppc_result_b;
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_xori() {
|
|
ppc_grab_regssauimm();
|
|
ppc_result_a = ppc_result_d ^ uimm;
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_xoris() {
|
|
ppc_grab_regssauimm();
|
|
ppc_result_a = ppc_result_d ^ (uimm << 16);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_neg() {
|
|
ppc_grab_regsda();
|
|
ppc_result_d = ~(ppc_result_a)+1;
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_negdot() {
|
|
ppc_grab_regsda();
|
|
ppc_result_d = ~(ppc_result_a)+1;
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_nego() {
|
|
ppc_grab_regsda();
|
|
ppc_result_d = ~(ppc_result_a)+1;
|
|
if (ppc_result_a == 0x80000000)
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xc0000000;
|
|
else
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xBFFFFFFF;
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_negodot() {
|
|
ppc_grab_regsda();
|
|
ppc_result_d = ~(ppc_result_a)+1;
|
|
if (ppc_result_a == 0x80000000)
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xc0000000;
|
|
else
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xBFFFFFFF;
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_cntlzw() {
|
|
ppc_grab_regssa();
|
|
|
|
uint32_t lead = 0;
|
|
uint32_t bit_check = ppc_result_d;
|
|
|
|
#ifdef USE_GCC_BUILTINS
|
|
lead = __builtin_clz(bit_check);
|
|
#elif defined USE_VS_BUILTINS
|
|
lead = __lzcnt(bit_check);
|
|
#else
|
|
for (uint32_t mask = 0x80000000UL; mask; lead++, mask >>= 1) {
|
|
if (bit_check & mask)
|
|
break;
|
|
}
|
|
#endif
|
|
ppc_result_a = lead;
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_cntlzwdot() {
|
|
ppc_grab_regssa();
|
|
|
|
uint32_t lead = 0;
|
|
uint32_t bit_check = ppc_result_d;
|
|
|
|
#ifdef USE_GCC_BUILTINS
|
|
lead = __builtin_clz(bit_check);
|
|
#elif defined USE_VS_BUILTINS
|
|
lead = __lzcnt(bit_check);
|
|
#else
|
|
for (uint32_t mask = 0x80000000UL; mask; lead++, mask >>= 1) {
|
|
if (bit_check & mask)
|
|
break;
|
|
}
|
|
#endif
|
|
ppc_result_a = lead;
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_mulhwu() {
|
|
ppc_grab_regsdab();
|
|
uint64_t product = (uint64_t)ppc_result_a * (uint64_t)ppc_result_b;
|
|
ppc_result_d = (uint32_t)(product >> 32);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_mulhwudot() {
|
|
ppc_grab_regsdab();
|
|
uint64_t product = (uint64_t)ppc_result_a * (uint64_t)ppc_result_b;
|
|
ppc_result_d = (uint32_t)(product >> 32);
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_mulhw() {
|
|
ppc_grab_regsdab();
|
|
int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b;
|
|
ppc_result_d = product >> 32;
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_mulhwdot() {
|
|
ppc_grab_regsdab();
|
|
int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b;
|
|
ppc_result_d = product >> 32;
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_mullw() {
|
|
ppc_grab_regsdab();
|
|
int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b;
|
|
ppc_result_d = (uint32_t)product;
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_mullwdot() {
|
|
ppc_grab_regsdab();
|
|
int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b;
|
|
ppc_result_d = (uint32_t)product;
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_mullwo() {
|
|
ppc_grab_regsdab();
|
|
int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b;
|
|
if (product != (int64_t)(int32_t)product) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xC0000000;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
ppc_result_d = (uint32_t)product;
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_mullwodot() {
|
|
ppc_grab_regsdab();
|
|
int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b;
|
|
if (product != (int64_t)(int32_t)product) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xC0000000;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
ppc_result_d = (uint32_t)product;
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_mulli() {
|
|
ppc_grab_regsdasimm();
|
|
int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)simm;
|
|
ppc_result_d = (uint32_t)product;
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
|
|
void ppc_divw() {
|
|
ppc_grab_regsdab();
|
|
|
|
if (!ppc_result_b) { /* handle the "anything / 0" case */
|
|
ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
|
|
}
|
|
else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
|
|
ppc_result_d = 0xFFFFFFFF;
|
|
}
|
|
else { /* normal signed devision */
|
|
ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b;
|
|
}
|
|
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_divwdot() {
|
|
ppc_grab_regsdab();
|
|
|
|
if (!ppc_result_b) { /* handle the "anything / 0" case */
|
|
ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
|
|
}
|
|
else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
|
|
ppc_result_d = 0xFFFFFFFF;
|
|
}
|
|
else { /* normal signed devision */
|
|
ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b;
|
|
}
|
|
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_divwo() {
|
|
ppc_grab_regsdab();
|
|
|
|
if (!ppc_result_b) { /* handle the "anything / 0" case */
|
|
ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xC0000000;
|
|
}
|
|
else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
|
|
ppc_result_d = 0xFFFFFFFF;
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xC0000000;
|
|
}
|
|
else { /* normal signed devision */
|
|
ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b;
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_divwodot() {
|
|
ppc_grab_regsdab();
|
|
|
|
if (!ppc_result_b) { /* handle the "anything / 0" case */
|
|
ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xC0000000;
|
|
}
|
|
else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
|
|
ppc_result_d = 0xFFFFFFFF;
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xC0000000;
|
|
}
|
|
else { /* normal signed devision */
|
|
ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b;
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_divwu() {
|
|
ppc_grab_regsdab();
|
|
|
|
if (!ppc_result_b) { /* division by zero */
|
|
ppc_result_d = 0;
|
|
}
|
|
else {
|
|
ppc_result_d = ppc_result_a / ppc_result_b;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_divwudot() {
|
|
ppc_grab_regsdab();
|
|
|
|
if (!ppc_result_b) { /* division by zero */
|
|
ppc_result_d = 0;
|
|
ppc_state.ppc_cr |= 0x20000000;
|
|
}
|
|
else {
|
|
ppc_result_d = ppc_result_a / ppc_result_b;
|
|
ppc_changecrf0(ppc_result_d);
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_divwuo() {
|
|
ppc_grab_regsdab();
|
|
|
|
if (!ppc_result_b) { /* division by zero */
|
|
ppc_result_d = 0;
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xC0000000;
|
|
}
|
|
else {
|
|
ppc_result_d = ppc_result_a / ppc_result_b;
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_divwuodot() {
|
|
ppc_grab_regsdab();
|
|
|
|
if (!ppc_result_b) { /* division by zero */
|
|
ppc_result_d = 0;
|
|
ppc_state.ppc_spr[SPR::XER] |= 0xC0000000;
|
|
}
|
|
else {
|
|
ppc_result_d = ppc_result_a / ppc_result_b;
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xBFFFFFFFUL;
|
|
}
|
|
ppc_changecrf0(ppc_result_d);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
//Value shifting
|
|
|
|
void ppc_slw() {
|
|
ppc_grab_regssab();
|
|
if (ppc_result_b & 0x20) {
|
|
ppc_result_a = 0;
|
|
}
|
|
else {
|
|
ppc_result_a = ppc_result_d << (ppc_result_b & 0x1F);
|
|
}
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_slwdot() {
|
|
ppc_grab_regssab();
|
|
if (ppc_result_b & 0x20) {
|
|
ppc_result_a = 0;
|
|
}
|
|
else {
|
|
ppc_result_a = ppc_result_d << (ppc_result_b & 0x1F);
|
|
}
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_srw() {
|
|
ppc_grab_regssab();
|
|
if (ppc_result_b & 0x20) {
|
|
ppc_result_a = 0;
|
|
}
|
|
else {
|
|
ppc_result_a = ppc_result_d >> (ppc_result_b & 0x1F);
|
|
}
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_srwdot() {
|
|
ppc_grab_regssab();
|
|
if (ppc_result_b & 0x20) {
|
|
ppc_result_a = 0;
|
|
}
|
|
else {
|
|
ppc_result_a = ppc_result_d >> (ppc_result_b & 0x1F);
|
|
}
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_sraw() {
|
|
ppc_grab_regssab();
|
|
if (ppc_result_b & 0x20) {
|
|
ppc_result_a = (int32_t)ppc_result_d >> 31;
|
|
ppc_state.ppc_spr[SPR::XER] |= (ppc_result_a & 1) << 29;
|
|
}
|
|
else {
|
|
uint32_t shift = ppc_result_b & 0x1F;
|
|
uint32_t mask = (1 << shift) - 1;
|
|
ppc_result_a = (int32_t)ppc_result_d >> shift;
|
|
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
}
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_srawdot() {
|
|
ppc_grab_regssab();
|
|
if (ppc_result_b & 0x20) {
|
|
ppc_result_a = (int32_t)ppc_result_d >> 31;
|
|
ppc_state.ppc_spr[SPR::XER] |= (ppc_result_a & 1) << 29;
|
|
}
|
|
else {
|
|
uint32_t shift = ppc_result_b & 0x1F;
|
|
uint32_t mask = (1 << shift) - 1;
|
|
ppc_result_a = (int32_t)ppc_result_d >> shift;
|
|
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
}
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_srawi() {
|
|
ppc_grab_regssa();
|
|
unsigned shift = (ppc_cur_instruction >> 11) & 0x1F;
|
|
uint32_t mask = (1 << shift) - 1;
|
|
ppc_result_a = (int32_t)ppc_result_d >> shift;
|
|
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_srawidot() {
|
|
ppc_grab_regssa();
|
|
unsigned shift = (ppc_cur_instruction >> 11) & 0x1F;
|
|
uint32_t mask = (1 << shift) - 1;
|
|
ppc_result_a = (int32_t)ppc_result_d >> shift;
|
|
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
|
|
ppc_state.ppc_spr[SPR::XER] |= 0x20000000UL;
|
|
}
|
|
else {
|
|
ppc_state.ppc_spr[SPR::XER] &= 0xDFFFFFFFUL;
|
|
}
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
/** mask generator for rotate and shift instructions (§ 4.2.1.4 PowerpC PEM) */
|
|
static inline uint32_t rot_mask(unsigned rot_mb, unsigned rot_me)
|
|
{
|
|
uint32_t m1 = 0xFFFFFFFFUL >> rot_mb;
|
|
uint32_t m2 = 0xFFFFFFFFUL << (31 - rot_me);
|
|
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
|
|
}
|
|
|
|
void ppc_rlwimi() {
|
|
ppc_grab_regssa();
|
|
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
|
unsigned rot_mb = (ppc_cur_instruction >> 6) & 31;
|
|
unsigned rot_me = (ppc_cur_instruction >> 1) & 31;
|
|
uint32_t mask = rot_mask(rot_mb, rot_me);
|
|
uint32_t r = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
|
ppc_result_a = (ppc_result_a & ~mask) | (r & mask);
|
|
if ((ppc_cur_instruction & 0x01) == 1) {
|
|
ppc_changecrf0(ppc_result_a);
|
|
}
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_rlwinm() {
|
|
ppc_grab_regssa();
|
|
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
|
unsigned rot_mb = (ppc_cur_instruction >> 6) & 31;
|
|
unsigned rot_me = (ppc_cur_instruction >> 1) & 31;
|
|
uint32_t mask = rot_mask(rot_mb, rot_me);
|
|
uint32_t r = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
|
ppc_result_a = r & mask;
|
|
if ((ppc_cur_instruction & 0x01) == 1) {
|
|
ppc_changecrf0(ppc_result_a);
|
|
}
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_rlwnm() {
|
|
ppc_grab_regssab();
|
|
unsigned rot_mb = (ppc_cur_instruction >> 6) & 31;
|
|
unsigned rot_me = (ppc_cur_instruction >> 1) & 31;
|
|
uint32_t mask = rot_mask(rot_mb, rot_me);
|
|
uint32_t r = ((ppc_result_d << ppc_result_b) | (ppc_result_d >> (32 - ppc_result_b)));
|
|
ppc_result_a = r & mask;
|
|
if ((ppc_cur_instruction & 0x01) == 1) {
|
|
ppc_changecrf0(ppc_result_a);
|
|
}
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_mfcr() {
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
ppc_state.ppc_gpr[reg_d] = ppc_state.ppc_cr;
|
|
}
|
|
|
|
void ppc_mtsr() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
if ((ppc_state.ppc_msr & 0x4000) == 0) {
|
|
reg_s = (ppc_cur_instruction >> 21) & 31;
|
|
grab_sr = (ppc_cur_instruction >> 16) & 15;
|
|
ppc_state.ppc_sr[grab_sr] = ppc_state.ppc_gpr[reg_s];
|
|
}
|
|
}
|
|
|
|
void ppc_mtsrin() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
if ((ppc_state.ppc_msr & 0x4000) == 0) {
|
|
ppc_grab_regssb();
|
|
grab_sr = ppc_result_b >> 28;
|
|
ppc_state.ppc_sr[grab_sr] = ppc_result_d;
|
|
}
|
|
}
|
|
|
|
void ppc_mfsr() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
if ((ppc_state.ppc_msr & 0x4000) == 0) {
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
grab_sr = (ppc_cur_instruction >> 16) & 15;
|
|
ppc_state.ppc_gpr[reg_d] = ppc_state.ppc_sr[grab_sr];
|
|
}
|
|
}
|
|
|
|
void ppc_mfsrin() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
if ((ppc_state.ppc_msr & 0x4000) == 0) {
|
|
ppc_grab_regsdb();
|
|
grab_sr = ppc_result_b >> 28;
|
|
ppc_state.ppc_gpr[reg_d] = ppc_state.ppc_sr[grab_sr];
|
|
}
|
|
}
|
|
|
|
void ppc_mfmsr() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
if (ppc_state.ppc_msr & 0x4000) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x00040000);
|
|
}
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
ppc_state.ppc_gpr[reg_d] = ppc_state.ppc_msr;
|
|
}
|
|
|
|
void ppc_mtmsr() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
if (ppc_state.ppc_msr & 0x4000) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x00040000);
|
|
}
|
|
reg_s = (ppc_cur_instruction >> 21) & 31;
|
|
ppc_state.ppc_msr = ppc_state.ppc_gpr[reg_s];
|
|
}
|
|
|
|
void ppc_mfspr() {
|
|
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 31) << 5) | ((ppc_cur_instruction >> 16) & 31);
|
|
|
|
#ifdef PROFILER
|
|
if (ref_spr > 31) {
|
|
supervisor_inst_num++;
|
|
}
|
|
#endif
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
ppc_state.ppc_gpr[reg_d] = ppc_state.ppc_spr[ref_spr];
|
|
}
|
|
|
|
void ppc_mtspr() {
|
|
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 31) << 5) | ((ppc_cur_instruction >> 16) & 31);
|
|
reg_s = (ppc_cur_instruction >> 21) & 31;
|
|
|
|
#ifdef PROFILER
|
|
if (ref_spr > 31) {
|
|
supervisor_inst_num++;
|
|
}
|
|
#endif
|
|
|
|
if (ref_spr != 287) {
|
|
ppc_state.ppc_spr[ref_spr] = ppc_state.ppc_gpr[reg_s];
|
|
}
|
|
|
|
switch (ref_spr) {
|
|
//Mirror the TBRs in the SPR range to the user-mode TBRs.
|
|
case 284:
|
|
ppc_state.ppc_spr[284] = (uint32_t)timebase_counter;
|
|
ppc_state.ppc_tbr[TBR::TBL] = (uint32_t)timebase_counter;
|
|
break;
|
|
case 285:
|
|
ppc_state.ppc_spr[285] = (uint32_t)(timebase_counter >> 32);
|
|
ppc_state.ppc_tbr[TBR::TBU] = (uint32_t)(timebase_counter >> 32);
|
|
break;
|
|
case 528:
|
|
case 529:
|
|
case 530:
|
|
case 531:
|
|
case 532:
|
|
case 533:
|
|
case 534:
|
|
case 535:
|
|
ibat_update(ref_spr);
|
|
break;
|
|
case 536:
|
|
case 537:
|
|
case 538:
|
|
case 539:
|
|
case 540:
|
|
case 541:
|
|
case 542:
|
|
case 543:
|
|
dbat_update(ref_spr);
|
|
}
|
|
}
|
|
|
|
void ppc_mftb() {
|
|
uint32_t ref_spr = (((ppc_cur_instruction >> 11) & 31) << 5) | ((ppc_cur_instruction >> 16) & 31);
|
|
reg_d = (ppc_cur_instruction >> 21) & 31;
|
|
switch (ref_spr) {
|
|
case 268:
|
|
ppc_state.ppc_gpr[reg_d] = ppc_state.ppc_tbr[TBR::TBL];
|
|
break;
|
|
case 269:
|
|
ppc_state.ppc_gpr[reg_d] = ppc_state.ppc_tbr[TBR::TBU];
|
|
break;
|
|
default:
|
|
std::cout << "Invalid TBR access attempted!" << std::endl;
|
|
}
|
|
}
|
|
|
|
void ppc_mtcrf() {
|
|
uint32_t cr_mask = 0;
|
|
ppc_grab_regssa();
|
|
crm = ((ppc_cur_instruction >> 12) & 255);
|
|
//check this
|
|
cr_mask += (crm & 128) ? 0xF0000000 : 0x00000000;
|
|
cr_mask += (crm & 64) ? 0x0F000000 : 0x00000000;
|
|
cr_mask += (crm & 32) ? 0x00F00000 : 0x00000000;
|
|
cr_mask += (crm & 16) ? 0x000F0000 : 0x00000000;
|
|
cr_mask += (crm & 8) ? 0x0000F000 : 0x00000000;
|
|
cr_mask += (crm & 4) ? 0x00000F00 : 0x00000000;
|
|
cr_mask += (crm & 2) ? 0x000000F0 : 0x00000000;
|
|
cr_mask += (crm & 1) ? 0x0000000F : 0x00000000;
|
|
ppc_state.ppc_cr = (ppc_result_d & cr_mask) | (ppc_state.ppc_cr & ~(cr_mask));
|
|
}
|
|
|
|
void ppc_mcrxr() {
|
|
crf_d = (ppc_cur_instruction >> 23) & 7;
|
|
crf_d = crf_d << 2;
|
|
ppc_state.ppc_cr = (ppc_state.ppc_cr & ~(0xF0000000UL >> crf_d)) | ((ppc_state.ppc_spr[SPR::XER] & 0xF0000000UL) >> crf_d);
|
|
ppc_state.ppc_spr[SPR::XER] &= 0x0FFFFFFF;
|
|
}
|
|
|
|
void ppc_extsb() {
|
|
ppc_grab_regssa();
|
|
ppc_result_d = ppc_result_d & 0xFF;
|
|
ppc_result_a = (ppc_result_d < 0x80) ? (ppc_result_d & 0x000000FF) : (0xFFFFFF00UL | (ppc_result_d & 0x000000FF));
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_extsbdot() {
|
|
ppc_grab_regssa();
|
|
ppc_result_d = ppc_result_d & 0xFF;
|
|
ppc_result_a = (ppc_result_d < 0x80) ? (ppc_result_d & 0x000000FF) : (0xFFFFFF00UL | (ppc_result_d & 0x000000FF));
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_extsh() {
|
|
ppc_grab_regssa();
|
|
ppc_result_d = ppc_result_d & 0xFFFF;
|
|
ppc_result_a = (ppc_result_d < 0x8000) ? (ppc_result_d & 0x0000FFFF) : (0xFFFF0000UL | (ppc_result_d & 0x0000FFFF));
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_extshdot() {
|
|
ppc_grab_regssa();
|
|
ppc_result_d = ppc_result_d & 0xFFFF;
|
|
ppc_result_a = (ppc_result_d < 0x8000) ? (ppc_result_d & 0x0000FFFF) : (0xFFFF0000UL | (ppc_result_d & 0x0000FFFF));
|
|
ppc_changecrf0(ppc_result_a);
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
//Branching Instructions
|
|
|
|
//The last two bytes of the instruction are used for determining how the branch happens.
|
|
//The middle 24 bytes are the 24-bit address to use for branching to.
|
|
|
|
|
|
void ppc_b() {
|
|
uint32_t quick_test = (ppc_cur_instruction & 0x03FFFFFC);
|
|
adr_li = (quick_test < 0x2000000) ? quick_test : (0xFC000000UL + quick_test);
|
|
ppc_next_instruction_address = (uint32_t)(ppc_state.ppc_pc + adr_li);
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
|
|
void ppc_bl() {
|
|
uint32_t quick_test = (ppc_cur_instruction & 0x03FFFFFC);
|
|
adr_li = (quick_test < 0x2000000) ? quick_test : (0xFC000000UL + quick_test);
|
|
ppc_next_instruction_address = (uint32_t)(ppc_state.ppc_pc + adr_li);
|
|
ppc_state.ppc_spr[SPR::LR] = (uint32_t)(ppc_state.ppc_pc + 4);
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
|
|
void ppc_ba() {
|
|
uint32_t quick_test = (ppc_cur_instruction & 0x03FFFFFC);
|
|
adr_li = (quick_test < 0x2000000) ? quick_test : (0xFC000000UL + quick_test);
|
|
ppc_next_instruction_address = adr_li;
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
|
|
void ppc_bla() {
|
|
uint32_t quick_test = (ppc_cur_instruction & 0x03FFFFFC);
|
|
adr_li = (quick_test < 0x2000000) ? quick_test : (0xFC000000UL + quick_test);
|
|
ppc_next_instruction_address = adr_li;
|
|
ppc_state.ppc_spr[SPR::LR] = ppc_state.ppc_pc + 4;
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
|
|
void ppc_bc()
|
|
{
|
|
uint32_t ctr_ok;
|
|
uint32_t cnd_ok;
|
|
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
|
|
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
|
|
int32_t br_bd = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFC));
|
|
|
|
if (!(br_bo & 0x04)) {
|
|
(ppc_state.ppc_spr[SPR::CTR])--; /* decrement CTR */
|
|
}
|
|
ctr_ok = (br_bo & 0x04) || ((ppc_state.ppc_spr[SPR::CTR] != 0) == !(br_bo & 0x02));
|
|
cnd_ok = (br_bo & 0x10) || (!(ppc_state.ppc_cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
|
|
|
|
if (ctr_ok && cnd_ok) {
|
|
ppc_next_instruction_address = (ppc_state.ppc_pc + br_bd);
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
}
|
|
|
|
void ppc_bca()
|
|
{
|
|
uint32_t ctr_ok;
|
|
uint32_t cnd_ok;
|
|
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
|
|
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
|
|
int32_t br_bd = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFC));
|
|
|
|
if (!(br_bo & 0x04)) {
|
|
(ppc_state.ppc_spr[SPR::CTR])--; /* decrement CTR */
|
|
}
|
|
ctr_ok = (br_bo & 0x04) || ((ppc_state.ppc_spr[SPR::CTR] != 0) == !(br_bo & 0x02));
|
|
cnd_ok = (br_bo & 0x10) || (!(ppc_state.ppc_cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
|
|
|
|
if (ctr_ok && cnd_ok) {
|
|
ppc_next_instruction_address = br_bd;
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
}
|
|
|
|
void ppc_bcl()
|
|
{
|
|
uint32_t ctr_ok;
|
|
uint32_t cnd_ok;
|
|
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
|
|
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
|
|
int32_t br_bd = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFC));
|
|
|
|
if (!(br_bo & 0x04)) {
|
|
(ppc_state.ppc_spr[SPR::CTR])--; /* decrement CTR */
|
|
}
|
|
ctr_ok = (br_bo & 0x04) || ((ppc_state.ppc_spr[SPR::CTR] != 0) == !(br_bo & 0x02));
|
|
cnd_ok = (br_bo & 0x10) || (!(ppc_state.ppc_cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
|
|
|
|
if (ctr_ok && cnd_ok) {
|
|
ppc_next_instruction_address = (ppc_state.ppc_pc + br_bd);
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
ppc_state.ppc_spr[SPR::LR] = ppc_state.ppc_pc + 4;
|
|
}
|
|
|
|
void ppc_bcla()
|
|
{
|
|
uint32_t ctr_ok;
|
|
uint32_t cnd_ok;
|
|
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
|
|
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
|
|
int32_t br_bd = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFC));
|
|
|
|
if (!(br_bo & 0x04)) {
|
|
(ppc_state.ppc_spr[SPR::CTR])--; /* decrement CTR */
|
|
}
|
|
ctr_ok = (br_bo & 0x04) || ((ppc_state.ppc_spr[SPR::CTR] != 0) == !(br_bo & 0x02));
|
|
cnd_ok = (br_bo & 0x10) || (!(ppc_state.ppc_cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
|
|
|
|
if (ctr_ok && cnd_ok) {
|
|
ppc_next_instruction_address = br_bd;
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
ppc_state.ppc_spr[SPR::LR] = ppc_state.ppc_pc + 4;
|
|
}
|
|
|
|
void ppc_bcctr()
|
|
{
|
|
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
|
|
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
|
|
|
|
uint32_t cnd_ok = (br_bo & 0x10) || (!(ppc_state.ppc_cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
|
|
|
|
if (cnd_ok) {
|
|
ppc_next_instruction_address = (ppc_state.ppc_spr[SPR::CTR] & 0xFFFFFFFCUL);
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
}
|
|
|
|
void ppc_bcctrl()
|
|
{
|
|
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
|
|
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
|
|
|
|
uint32_t cnd_ok = (br_bo & 0x10) || (!(ppc_state.ppc_cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
|
|
|
|
if (cnd_ok) {
|
|
ppc_next_instruction_address = (ppc_state.ppc_spr[SPR::CTR] & 0xFFFFFFFCUL);
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
ppc_state.ppc_spr[SPR::LR] = ppc_state.ppc_pc + 4;
|
|
}
|
|
|
|
void ppc_bclr()
|
|
{
|
|
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
|
|
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
|
|
uint32_t ctr_ok;
|
|
uint32_t cnd_ok;
|
|
|
|
if (!(br_bo & 0x04)) {
|
|
(ppc_state.ppc_spr[SPR::CTR])--; /* decrement CTR */
|
|
}
|
|
ctr_ok = (br_bo & 0x04) || ((ppc_state.ppc_spr[SPR::CTR] != 0) == !(br_bo & 0x02));
|
|
cnd_ok = (br_bo & 0x10) || (!(ppc_state.ppc_cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
|
|
|
|
if (ctr_ok && cnd_ok) {
|
|
ppc_next_instruction_address = (ppc_state.ppc_spr[SPR::LR] & 0xFFFFFFFCUL);
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
}
|
|
|
|
void ppc_bclrl()
|
|
{
|
|
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
|
|
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
|
|
uint32_t ctr_ok;
|
|
uint32_t cnd_ok;
|
|
|
|
if (!(br_bo & 0x04)) {
|
|
(ppc_state.ppc_spr[SPR::CTR])--; /* decrement CTR */
|
|
}
|
|
ctr_ok = (br_bo & 0x04) || ((ppc_state.ppc_spr[SPR::CTR] != 0) == !(br_bo & 0x02));
|
|
cnd_ok = (br_bo & 0x10) || (!(ppc_state.ppc_cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
|
|
|
|
if (ctr_ok && cnd_ok) {
|
|
ppc_next_instruction_address = (ppc_state.ppc_spr[SPR::LR] & 0xFFFFFFFCUL);
|
|
grab_branch = 1;
|
|
bb_kind = BB_end_kind::BB_BRANCH;
|
|
}
|
|
ppc_state.ppc_spr[SPR::LR] = ppc_state.ppc_pc + 4;
|
|
}
|
|
//Compare Instructions
|
|
|
|
void ppc_cmp() {
|
|
#ifdef CHECK_INVALID
|
|
if (ppc_cur_instruction & 0x200000) {
|
|
LOG_F(WARNING, "Invalid CMP instruction form (L=1)!\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
crf_d = (ppc_cur_instruction >> 23) & 7;
|
|
crf_d = crf_d << 2;
|
|
ppc_grab_regssab();
|
|
xercon = (ppc_state.ppc_spr[SPR::XER] & 0x80000000UL) >> 3;
|
|
cmp_c = (((int32_t)ppc_result_a) == ((int32_t)ppc_result_b)) ? 0x20000000UL : (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) ? 0x40000000UL : 0x80000000UL;
|
|
ppc_state.ppc_cr = ((ppc_state.ppc_cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d));
|
|
}
|
|
|
|
void ppc_cmpi() {
|
|
#ifdef CHECK_INVALID
|
|
if (ppc_cur_instruction & 0x200000) {
|
|
LOG_F(WARNING, "Invalid CMPI instruction form (L=1)!\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
crf_d = (ppc_cur_instruction >> 23) & 7;
|
|
crf_d = crf_d << 2;
|
|
ppc_grab_regsasimm();
|
|
xercon = (ppc_state.ppc_spr[SPR::XER] & 0x80000000UL) >> 3;
|
|
cmp_c = (((int32_t)ppc_result_a) == simm) ? 0x20000000UL : (((int32_t)ppc_result_a) > simm) ? 0x40000000UL : 0x80000000UL;
|
|
ppc_state.ppc_cr = ((ppc_state.ppc_cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d));
|
|
}
|
|
|
|
void ppc_cmpl() {
|
|
#ifdef CHECK_INVALID
|
|
if (ppc_cur_instruction & 0x200000) {
|
|
LOG_F(WARNING, "Invalid CMPL instruction form (L=1)!\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
crf_d = (ppc_cur_instruction >> 23) & 7;
|
|
crf_d = crf_d << 2;
|
|
ppc_grab_regssab();
|
|
xercon = (ppc_state.ppc_spr[SPR::XER] & 0x80000000UL) >> 3;
|
|
cmp_c = (ppc_result_a == ppc_result_b) ? 0x20000000UL : (ppc_result_a > ppc_result_b) ? 0x40000000UL : 0x80000000UL;
|
|
ppc_state.ppc_cr = ((ppc_state.ppc_cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d));
|
|
}
|
|
|
|
void ppc_cmpli() {
|
|
#ifdef CHECK_INVALID
|
|
if (ppc_cur_instruction & 0x200000) {
|
|
LOG_F(WARNING, "Invalid CMPLI instruction form (L=1)!\n");
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
crf_d = (ppc_cur_instruction >> 23) & 7;
|
|
crf_d = crf_d << 2;
|
|
ppc_grab_regssauimm();
|
|
xercon = (ppc_state.ppc_spr[SPR::XER] & 0x80000000UL) >> 3;
|
|
cmp_c = (ppc_result_a == uimm) ? 0x20000000UL : (ppc_result_a > uimm) ? 0x40000000UL : 0x80000000UL;
|
|
ppc_state.ppc_cr = ((ppc_state.ppc_cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d));
|
|
}
|
|
|
|
//Condition Register Changes
|
|
|
|
void ppc_crand() {
|
|
ppc_grab_regsdab();
|
|
if ((ppc_state.ppc_cr & (0x80000000UL >> reg_a)) && (ppc_state.ppc_cr & (0x80000000UL >> reg_b))) {
|
|
ppc_state.ppc_cr |= (0x80000000UL >> reg_d);
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr &= ~(0x80000000UL >> reg_d);
|
|
}
|
|
}
|
|
void ppc_crandc() {
|
|
ppc_grab_regsdab();
|
|
if ((ppc_state.ppc_cr & (0x80000000UL >> reg_a)) && !(ppc_state.ppc_cr & (0x80000000UL >> reg_b))) {
|
|
ppc_state.ppc_cr |= (0x80000000UL >> reg_d);
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr &= ~(0x80000000UL >> reg_d);
|
|
}
|
|
}
|
|
void ppc_creqv() {
|
|
ppc_grab_regsdab();
|
|
if (!((ppc_state.ppc_cr & (0x80000000UL >> reg_a)) ^ (ppc_state.ppc_cr & (0x80000000UL >> reg_b)))) {
|
|
ppc_state.ppc_cr |= (0x80000000UL >> reg_d);
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr &= ~(0x80000000UL >> reg_d);
|
|
}
|
|
}
|
|
void ppc_crnand() {
|
|
ppc_grab_regsdab();
|
|
if (!((ppc_state.ppc_cr & (0x80000000UL >> reg_a)) && (ppc_state.ppc_cr & (0x80000000UL >> reg_b)))) {
|
|
ppc_state.ppc_cr |= (0x80000000UL >> reg_d);
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr &= ~(0x80000000UL >> reg_d);
|
|
}
|
|
}
|
|
void ppc_crnor() {
|
|
ppc_grab_regsdab();
|
|
if (!((ppc_state.ppc_cr & (0x80000000UL >> reg_a)) || (ppc_state.ppc_cr & (0x80000000UL >> reg_b)))) {
|
|
ppc_state.ppc_cr |= (0x80000000UL >> reg_d);
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr &= ~(0x80000000UL >> reg_d);
|
|
}
|
|
}
|
|
|
|
void ppc_cror() {
|
|
ppc_grab_regsdab();
|
|
if ((ppc_state.ppc_cr & (0x80000000UL >> reg_a)) || (ppc_state.ppc_cr & (0x80000000UL >> reg_b))) {
|
|
ppc_state.ppc_cr |= (0x80000000UL >> reg_d);
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr &= ~(0x80000000UL >> reg_d);
|
|
}
|
|
}
|
|
void ppc_crorc() {
|
|
ppc_grab_regsdab();
|
|
if ((ppc_state.ppc_cr & (0x80000000UL >> reg_a)) || !(ppc_state.ppc_cr & (0x80000000UL >> reg_b))) {
|
|
ppc_state.ppc_cr |= (0x80000000UL >> reg_d);
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr &= ~(0x80000000UL >> reg_d);
|
|
}
|
|
}
|
|
void ppc_crxor() {
|
|
ppc_grab_regsdab();
|
|
if ((ppc_state.ppc_cr & (0x80000000UL >> reg_a)) ^ (ppc_state.ppc_cr & (0x80000000UL >> reg_b))) {
|
|
ppc_state.ppc_cr |= (0x80000000UL >> reg_d);
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr &= ~(0x80000000UL >> reg_d);
|
|
}
|
|
}
|
|
|
|
//Processor MGMT Fns.
|
|
|
|
void ppc_rfi() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
uint32_t new_srr1_val = (ppc_state.ppc_spr[SPR::SRR1] & 0x87C0FF73UL);
|
|
uint32_t new_msr_val = (ppc_state.ppc_msr & ~(0x87C0FF73UL));
|
|
ppc_state.ppc_msr = (new_msr_val | new_srr1_val) & 0xFFFBFFFFUL;
|
|
ppc_next_instruction_address = ppc_state.ppc_spr[SPR::SRR0] & 0xFFFFFFFCUL;
|
|
|
|
grab_return = true;
|
|
bb_kind = BB_end_kind::BB_RFI;
|
|
}
|
|
|
|
void ppc_sc() {
|
|
ppc_exception_handler(Except_Type::EXC_SYSCALL, 0x20000);
|
|
}
|
|
|
|
void ppc_tw() {
|
|
reg_a = (ppc_cur_instruction >> 11) & 31;
|
|
reg_b = (ppc_cur_instruction >> 16) & 31;
|
|
ppc_to = (ppc_cur_instruction >> 21) & 31;
|
|
if ((((int32_t)ppc_state.ppc_gpr[reg_a] < (int32_t)ppc_state.ppc_gpr[reg_b]) & (ppc_to & 0x10)) || \
|
|
(((int32_t)ppc_state.ppc_gpr[reg_a] > (int32_t)ppc_state.ppc_gpr[reg_b])& (ppc_to & 0x08)) || \
|
|
(((int32_t)ppc_state.ppc_gpr[reg_a] == (int32_t)ppc_state.ppc_gpr[reg_b]) & (ppc_to & 0x04)) || \
|
|
((ppc_state.ppc_gpr[reg_a] < ppc_state.ppc_gpr[reg_b]) & (ppc_to & 0x02)) || \
|
|
((ppc_state.ppc_gpr[reg_a] > ppc_state.ppc_gpr[reg_b])& (ppc_to & 0x01))) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_twi() {
|
|
simm = (int32_t)((int16_t)((ppc_cur_instruction) & 65535));
|
|
reg_b = (ppc_cur_instruction >> 16) & 31;
|
|
ppc_to = (ppc_cur_instruction >> 21) & 31;
|
|
if ((((int32_t)ppc_state.ppc_gpr[reg_a] < simm) & (ppc_to & 0x10)) || \
|
|
(((int32_t)ppc_state.ppc_gpr[reg_a] > simm)& (ppc_to & 0x08)) || \
|
|
(((int32_t)ppc_state.ppc_gpr[reg_a] == simm) & (ppc_to & 0x04)) || \
|
|
((ppc_state.ppc_gpr[reg_a] < (uint32_t)simm) & (ppc_to & 0x02)) || \
|
|
((ppc_state.ppc_gpr[reg_a] > (uint32_t)simm)& (ppc_to & 0x01))) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_eieio() {
|
|
//std::cout << "Oops. Placeholder for eieio." << std::endl;
|
|
}
|
|
|
|
void ppc_isync() {
|
|
//std::cout << "Oops. Placeholder for isync." << std::endl;
|
|
}
|
|
|
|
void ppc_sync() {
|
|
//std::cout << "Oops. Placeholder for sync." << std::endl;
|
|
}
|
|
|
|
void ppc_icbi() {
|
|
LOG_F(WARNING, "Placeholder for icbi. \n");
|
|
}
|
|
|
|
void ppc_dcbf() {
|
|
LOG_F(WARNING, "Placeholder for dcbf. \n");
|
|
}
|
|
|
|
void ppc_dcbi() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
LOG_F(WARNING, "Placeholder for dcbi. \n");
|
|
}
|
|
|
|
void ppc_dcbst() {
|
|
LOG_F(WARNING, "Placeholder for dcbst. \n");
|
|
}
|
|
|
|
void ppc_dcbt() {
|
|
//Not needed, the HDI reg is touched to no-op this instruction.
|
|
return;
|
|
}
|
|
|
|
void ppc_dcbtst() {
|
|
//Not needed, the HDI reg is touched to no-op this instruction.
|
|
return;
|
|
}
|
|
|
|
void ppc_dcbz() {
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
if (!(ppc_state.ppc_pc & 32) && (ppc_state.ppc_pc < 0xFFFFFFE0UL)) {
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
mem_write_qword(ppc_effective_address, 0);
|
|
mem_write_qword((ppc_effective_address + 8), 0);
|
|
mem_write_qword((ppc_effective_address + 16), 0);
|
|
mem_write_qword((ppc_effective_address + 24), 0);
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x00000);
|
|
}
|
|
}
|
|
|
|
|
|
//Integer Load and Store Functions
|
|
|
|
void ppc_stb() {
|
|
ppc_grab_regssa();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
|
mem_write_byte(ppc_effective_address, ppc_result_d);
|
|
}
|
|
|
|
void ppc_stbx() {
|
|
ppc_grab_regssab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
mem_write_byte(ppc_effective_address, ppc_result_d);
|
|
}
|
|
|
|
void ppc_stbu() {
|
|
ppc_grab_regssa();
|
|
if (reg_a != 0) {
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += ppc_result_a;
|
|
mem_write_byte(ppc_effective_address, ppc_result_d);
|
|
ppc_state.ppc_gpr[reg_a] = ppc_effective_address;
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_stbux() {
|
|
ppc_grab_regssab();
|
|
if (reg_a != 0) {
|
|
ppc_effective_address = ppc_result_a + ppc_result_b;
|
|
mem_write_byte(ppc_effective_address, ppc_result_d);
|
|
ppc_state.ppc_gpr[reg_a] = ppc_effective_address;
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_sth() {
|
|
ppc_grab_regssa();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
|
mem_write_word(ppc_effective_address, ppc_result_d);
|
|
}
|
|
|
|
void ppc_sthu() {
|
|
ppc_grab_regssa();
|
|
if (reg_a != 0) {
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += ppc_result_a;
|
|
mem_write_word(ppc_effective_address, ppc_result_d);
|
|
ppc_state.ppc_gpr[reg_a] = ppc_effective_address;
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_sthux() {
|
|
ppc_grab_regssab();
|
|
if (reg_a != 0) {
|
|
ppc_effective_address = ppc_result_a + ppc_result_b;
|
|
mem_write_word(ppc_effective_address, ppc_result_d);
|
|
ppc_state.ppc_gpr[reg_a] = ppc_effective_address;
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_sthx() {
|
|
ppc_grab_regssab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
mem_write_word(ppc_effective_address, ppc_result_d);
|
|
}
|
|
|
|
void ppc_sthbrx() {
|
|
ppc_grab_regssab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
ppc_result_d = (uint32_t)(BYTESWAP_16((uint16_t)ppc_result_d));
|
|
mem_write_word(ppc_effective_address, ppc_result_d);
|
|
|
|
}
|
|
void ppc_stw() {
|
|
ppc_grab_regssa();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
|
mem_write_dword(ppc_effective_address, ppc_result_d);
|
|
}
|
|
|
|
void ppc_stwx() {
|
|
ppc_grab_regssab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
mem_write_dword(ppc_effective_address, ppc_result_d);
|
|
}
|
|
|
|
void ppc_stwcx() {
|
|
//PLACEHOLDER CODE FOR STWCX - We need to check for reserve memory
|
|
ppc_grab_regssab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
if (ppc_state.ppc_reserve) {
|
|
mem_write_dword(ppc_effective_address, ppc_result_d);
|
|
ppc_state.ppc_cr |= (ppc_state.ppc_spr[SPR::XER] & 0x80000000) ? 0x30000000 : 0x20000000;
|
|
ppc_state.ppc_reserve = false;
|
|
}
|
|
else {
|
|
ppc_state.ppc_cr |= (ppc_state.ppc_spr[SPR::XER] & 0x80000000) ? 0x10000000 : 0;
|
|
}
|
|
}
|
|
|
|
void ppc_stwu() {
|
|
ppc_grab_regssa();
|
|
if (reg_a != 0) {
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += ppc_result_a;
|
|
mem_write_dword(ppc_effective_address, ppc_result_d);
|
|
ppc_state.ppc_gpr[reg_a] = ppc_effective_address;
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_stwux() {
|
|
ppc_grab_regssab();
|
|
if (reg_a != 0) {
|
|
ppc_effective_address = ppc_result_a + ppc_result_b;
|
|
mem_write_dword(ppc_effective_address, ppc_result_d);
|
|
ppc_state.ppc_gpr[reg_a] = ppc_effective_address;
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_stwbrx() {
|
|
ppc_grab_regssab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
ppc_result_d = BYTESWAP_32(ppc_result_d);
|
|
mem_write_dword(ppc_effective_address, ppc_result_d);
|
|
}
|
|
|
|
void ppc_stmw() {
|
|
ppc_grab_regssa();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
|
//How many words to store in memory - using a do-while for this
|
|
do {
|
|
mem_write_dword(ppc_effective_address, ppc_result_d);
|
|
ppc_effective_address += 4;
|
|
reg_d++;
|
|
} while (reg_d < 32);
|
|
}
|
|
|
|
void ppc_lbz() {
|
|
ppc_grab_regsda();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
|
ppc_result_d = mem_grab_byte(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lbzu() {
|
|
ppc_grab_regsda();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
if ((reg_a != reg_d) || reg_a != 0) {
|
|
ppc_effective_address += ppc_result_a;
|
|
ppc_result_d = mem_grab_byte(ppc_effective_address);
|
|
ppc_result_a = ppc_effective_address;
|
|
ppc_store_result_regd();
|
|
ppc_store_result_rega();
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_lbzx() {
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
ppc_result_d = mem_grab_byte(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lbzux() {
|
|
ppc_grab_regsdab();
|
|
if ((reg_a != reg_d) || reg_a != 0) {
|
|
ppc_effective_address = ppc_result_a + ppc_result_b;
|
|
ppc_result_d = mem_grab_byte(ppc_effective_address);
|
|
ppc_result_a = ppc_effective_address;
|
|
ppc_store_result_regd();
|
|
ppc_store_result_rega();
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
|
|
void ppc_lhz() {
|
|
ppc_grab_regsda();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
|
ppc_result_d = mem_grab_word(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lhzu() {
|
|
ppc_grab_regsda();
|
|
if ((reg_a != reg_d) || reg_a != 0) {
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += ppc_result_a;
|
|
ppc_result_d = mem_grab_word(ppc_effective_address);
|
|
ppc_result_a = ppc_effective_address;
|
|
ppc_store_result_regd();
|
|
ppc_store_result_rega();
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_lhzx() {
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
ppc_result_d = mem_grab_word(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lhzux() {
|
|
ppc_grab_regsdab();
|
|
if ((reg_a != reg_d) || reg_a != 0) {
|
|
ppc_effective_address = ppc_result_a + ppc_result_b;
|
|
ppc_result_d = mem_grab_word(ppc_effective_address);
|
|
ppc_result_a = ppc_effective_address;
|
|
ppc_store_result_regd();
|
|
ppc_store_result_rega();
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_lha() {
|
|
ppc_grab_regsda();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
|
uint16_t val = mem_grab_word(ppc_effective_address);
|
|
if (val & 0x8000) {
|
|
ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
|
|
}
|
|
else {
|
|
ppc_result_d = (uint32_t)val;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lhau() {
|
|
ppc_grab_regsda();
|
|
if ((reg_a != reg_d) || reg_a != 0) {
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += ppc_result_a;
|
|
uint16_t val = mem_grab_word(ppc_effective_address);
|
|
if (val & 0x8000) {
|
|
ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
|
|
}
|
|
else {
|
|
ppc_result_d = (uint32_t)val;
|
|
}
|
|
ppc_store_result_regd();
|
|
ppc_result_a = ppc_effective_address;
|
|
ppc_store_result_rega();
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_lhaux() {
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
uint16_t val = mem_grab_word(ppc_effective_address);
|
|
if (val & 0x8000) {
|
|
ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
|
|
}
|
|
else {
|
|
ppc_result_d = (uint32_t)val;
|
|
}
|
|
ppc_store_result_regd();
|
|
ppc_result_a = ppc_effective_address;
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_lhax() {
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
uint16_t val = mem_grab_word(ppc_effective_address);
|
|
if (val & 0x8000) {
|
|
ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
|
|
}
|
|
else {
|
|
ppc_result_d = (uint32_t)val;
|
|
}
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lhbrx() {
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
ppc_result_d = (uint32_t)(BYTESWAP_16(mem_grab_word(ppc_effective_address)));
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lwz() {
|
|
ppc_grab_regsda();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
|
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lwbrx() {
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
ppc_result_d = BYTESWAP_32(mem_grab_dword(ppc_effective_address));
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lwzu() {
|
|
ppc_grab_regsda();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
if ((reg_a != reg_d) || reg_a != 0) {
|
|
ppc_effective_address += ppc_result_a;
|
|
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
ppc_result_a = ppc_effective_address;
|
|
ppc_store_result_rega();
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
}
|
|
|
|
void ppc_lwzx() {
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lwzux() {
|
|
ppc_grab_regsdab();
|
|
if ((reg_a != reg_d) || reg_a != 0) {
|
|
ppc_effective_address = ppc_result_a + ppc_result_b;
|
|
}
|
|
else {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
|
}
|
|
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
|
ppc_result_a = ppc_effective_address;
|
|
ppc_store_result_regd();
|
|
ppc_store_result_rega();
|
|
}
|
|
|
|
void ppc_lwarx() {
|
|
//Placeholder - Get the reservation of memory implemented!
|
|
ppc_grab_regsdab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
ppc_state.ppc_reserve = true;
|
|
ppc_result_d = mem_grab_dword(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
}
|
|
|
|
void ppc_lmw() {
|
|
ppc_grab_regsda();
|
|
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
|
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
|
//How many words to load in memory - using a do-while for this
|
|
do {
|
|
ppc_state.ppc_gpr[reg_d] = mem_grab_dword(ppc_effective_address);
|
|
ppc_effective_address += 4;
|
|
reg_d++;
|
|
} while (reg_d < 32);
|
|
}
|
|
|
|
void ppc_lswi() {
|
|
ppc_grab_regsda();
|
|
ppc_effective_address = ppc_result_a;
|
|
grab_inb = (ppc_cur_instruction >> 11) & 31;
|
|
grab_inb = (grab_inb & 32) == 0 ? 32 : grab_inb;
|
|
|
|
uint32_t shift_times = 0;
|
|
|
|
while (grab_inb > 0) {
|
|
switch (shift_times) {
|
|
case 0:
|
|
ppc_state.ppc_gpr[reg_d] = (ppc_result_d & 0x00FFFFFFUL) |
|
|
(mem_grab_byte(ppc_effective_address) << 24);
|
|
ppc_store_result_regd();
|
|
break;
|
|
case 1:
|
|
ppc_result_d = (ppc_result_d & 0xFF00FFFFUL) |
|
|
(mem_grab_byte(ppc_effective_address) << 16);
|
|
ppc_store_result_regd();
|
|
break;
|
|
case 2:
|
|
ppc_result_d = (ppc_result_d & 0xFFFF00FFUL) |
|
|
(mem_grab_byte(ppc_effective_address) << 8);
|
|
ppc_store_result_regd();
|
|
break;
|
|
case 3:
|
|
ppc_result_d = (ppc_result_d & 0xFFFFFF00UL) |
|
|
mem_grab_byte(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
break;
|
|
default:
|
|
LOG_F(ERROR, "Something really horrible happened with lswi. \n");
|
|
}
|
|
if (shift_times == 3) {
|
|
shift_times = 0;
|
|
reg_d = (reg_d + 1) & 0x1F;
|
|
}
|
|
else {
|
|
shift_times++;
|
|
}
|
|
ppc_effective_address++;
|
|
grab_inb--;
|
|
}
|
|
}
|
|
|
|
void ppc_lswx() {
|
|
ppc_grab_regsdab();
|
|
//Invalid instruction forms
|
|
if ((ppc_result_d == 0) && (ppc_result_a == 0)) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x100000);
|
|
}
|
|
if ((ppc_result_d == ppc_result_a) || (ppc_result_a == ppc_result_b)) {
|
|
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x100000);
|
|
}
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
grab_inb = ppc_state.ppc_spr[SPR::XER] & 127;
|
|
uint32_t shift_times = 0;
|
|
while (grab_inb > 0) {
|
|
switch (shift_times) {
|
|
case 0:
|
|
ppc_result_d = (ppc_result_d & 0x00FFFFFFUL) |
|
|
(mem_grab_byte(ppc_effective_address) << 24);
|
|
ppc_store_result_regd();
|
|
break;
|
|
case 1:
|
|
ppc_result_d = (ppc_result_d & 0xFF00FFFFUL) |
|
|
(mem_grab_byte(ppc_effective_address) << 16);
|
|
ppc_store_result_regd();
|
|
break;
|
|
case 2:
|
|
ppc_result_d = (ppc_result_d & 0xFFFF00FFUL) |
|
|
(mem_grab_byte(ppc_effective_address) << 8);
|
|
ppc_store_result_regd();
|
|
break;
|
|
case 3:
|
|
ppc_result_d = (ppc_result_d & 0xFFFFFF00UL) |
|
|
mem_grab_byte(ppc_effective_address);
|
|
ppc_store_result_regd();
|
|
break;
|
|
default:
|
|
LOG_F(ERROR, "Something really horrible happened with lswx. \n");
|
|
}
|
|
if (shift_times == 3) {
|
|
shift_times = 0;
|
|
reg_d = (reg_d + 1) & 0x1F;
|
|
}
|
|
else {
|
|
shift_times++;
|
|
}
|
|
ppc_effective_address++;
|
|
grab_inb--;
|
|
}
|
|
|
|
}
|
|
|
|
void ppc_stswi() {
|
|
ppc_grab_regssa();
|
|
ppc_effective_address = (reg_a == 0) ? 0 : ppc_result_a;
|
|
grab_inb = (ppc_cur_instruction >> 11) & 31;
|
|
grab_inb = (grab_inb & 32) == 0 ? 32 : grab_inb;
|
|
uint32_t shift_times = 0;
|
|
while (grab_inb > 0) {
|
|
switch (shift_times) {
|
|
case 0:
|
|
strwrd_replace_value = (ppc_result_d >> 24);
|
|
mem_write_byte(ppc_effective_address, strwrd_replace_value);
|
|
break;
|
|
case 1:
|
|
strwrd_replace_value = (ppc_result_d >> 16);
|
|
mem_write_byte(ppc_effective_address, strwrd_replace_value);
|
|
break;
|
|
case 2:
|
|
strwrd_replace_value = (ppc_result_d >> 8);
|
|
mem_write_byte(ppc_effective_address, strwrd_replace_value);
|
|
break;
|
|
case 3:
|
|
strwrd_replace_value = (ppc_result_d);
|
|
mem_write_byte(ppc_effective_address, strwrd_replace_value);
|
|
break;
|
|
default:
|
|
LOG_F(ERROR, "Something really horrible happened with stswi. \n");
|
|
}
|
|
if (shift_times == 3) {
|
|
shift_times = 0;
|
|
reg_s = (reg_s + 1) & 0x1F;
|
|
}
|
|
else {
|
|
shift_times++;
|
|
}
|
|
ppc_effective_address++;
|
|
grab_inb--;
|
|
}
|
|
}
|
|
|
|
void ppc_stswx() {
|
|
ppc_grab_regssab();
|
|
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
|
|
grab_inb = ppc_state.ppc_spr[SPR::XER] & 127;
|
|
uint32_t shift_times = 0;
|
|
while (grab_inb > 0) {
|
|
switch (shift_times) {
|
|
case 0:
|
|
strwrd_replace_value = (ppc_result_d >> 24);
|
|
mem_write_byte(ppc_effective_address, strwrd_replace_value);
|
|
break;
|
|
case 1:
|
|
strwrd_replace_value = (ppc_result_d >> 16);
|
|
mem_write_byte(ppc_effective_address, strwrd_replace_value);
|
|
break;
|
|
case 2:
|
|
strwrd_replace_value = (ppc_result_d >> 8);
|
|
mem_write_byte(ppc_effective_address, strwrd_replace_value);
|
|
break;
|
|
case 3:
|
|
strwrd_replace_value = (ppc_result_d);
|
|
mem_write_byte(ppc_effective_address, strwrd_replace_value);
|
|
break;
|
|
default:
|
|
LOG_F(ERROR, "Something really horrible happened with stswx. \n");
|
|
}
|
|
if (shift_times == 3) {
|
|
shift_times = 0;
|
|
reg_s = (reg_s + 1) & 0x1F;
|
|
}
|
|
else {
|
|
shift_times++;
|
|
}
|
|
ppc_effective_address++;
|
|
grab_inb--;
|
|
}
|
|
}
|
|
|
|
//TLB Instructions
|
|
|
|
void ppc_tlbie() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
/**
|
|
reg_b = (ppc_cur_instruction >> 11) & 31;
|
|
uint32_t vps = ppc_state.ppc_gpr[reg_b] & 0xFFFF000;
|
|
**/
|
|
LOG_F(WARNING, "Placeholder for tlbie \n");
|
|
}
|
|
|
|
void ppc_tlbia() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
LOG_F(WARNING, "Placeholder for tlbia \n");
|
|
}
|
|
|
|
void ppc_tlbld() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
LOG_F(WARNING, "Placeholder for tlbld - 603 only \n");
|
|
}
|
|
|
|
void ppc_tlbli() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
LOG_F(WARNING, "Placeholder for tlbli - 603 only \n");
|
|
}
|
|
|
|
void ppc_tlbsync() {
|
|
#ifdef PROFILER
|
|
supervisor_inst_num++;
|
|
#endif
|
|
LOG_F(WARNING, "Placeholder for tlbsync \n");
|
|
} |