Merge branch 'cpu-refactor'

This commit is contained in:
dingusdev 2020-12-04 11:01:34 -07:00
commit 5cba9c1dae
18 changed files with 1599 additions and 2210 deletions

4
.gitmodules vendored
View File

@ -1,3 +1,7 @@
[submodule "thirdparty/cubeb"]
path = thirdparty/cubeb
url = https://github.com/DingusDevOrg/cubeb.git
[submodule "thirdparty/capstone"]
path = thirdparty/capstone
url = https://github.com/maximumspatium/capstone.git
branch = next

View File

@ -16,9 +16,45 @@ if (UNIX AND NOT APPLE)
endif()
endif()
option(ENABLE_68K_DEBUGGER "Enable 68k debugging" OFF)
if (ENABLE_68K_DEBUGGER)
# Build capstone as static library.
set(CAPSTONE_BUILD_STATIC ON CACHE BOOL "")
# Turn off anything unnecessary.
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "")
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "")
set(CAPSTONE_BUILD_CSTOOL OFF CACHE BOOL "")
set(CAPSTONE_BUILD_DIET OFF CACHE BOOL "")
set(CAPSTONE_OSXKERNEL_SUPPORT OFF CACHE BOOL "")
# Disable unused Capstone architectures.
set(CAPSTONE_ARM_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_ARM64_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_MIPS_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_PPC_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_SPARC_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_SYSZ_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_XCORE_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_X86_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_TMS320C64X_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_M680X_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_EVM_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_MOS65XX_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_WASM_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_BPF_SUPPORT OFF CACHE BOOL "")
set(CAPSTONE_RISCV_SUPPORT OFF CACHE BOOL "")
ADD_DEFINITIONS(-DENABLE_68K_DEBUGGER)
add_subdirectory(thirdparty/capstone EXCLUDE_FROM_ALL)
endif()
add_subdirectory("${PROJECT_SOURCE_DIR}/cpu/ppc/")
add_subdirectory("${PROJECT_SOURCE_DIR}/debugger/")
add_subdirectory("${PROJECT_SOURCE_DIR}/devices/")
add_subdirectory("${PROJECT_SOURCE_DIR}/execution")
add_subdirectory("${PROJECT_SOURCE_DIR}/machines/")
add_subdirectory("${PROJECT_SOURCE_DIR}/thirdparty/loguru/")
@ -57,6 +93,7 @@ file(GLOB TEST_SOURCES "${PROJECT_SOURCE_DIR}/cpu/ppc/test/*.cpp")
add_executable(dingusppc ${SOURCES} $<TARGET_OBJECTS:debugger>
$<TARGET_OBJECTS:cpu_ppc>
$<TARGET_OBJECTS:devices>
$<TARGET_OBJECTS:execution>
$<TARGET_OBJECTS:machines>
$<TARGET_OBJECTS:loguru>)
@ -70,10 +107,15 @@ target_link_libraries(dingusppc cubeb ${SDL2_LIBRARIES} ${CMAKE_DL_LIBS} ${CMAKE
target_include_directories(dingusppc PRIVATE ${CLI11_ROOT})
endif()
if (ENABLE_68K_DEBUGGER)
target_link_libraries(dingusppc capstone-static)
endif()
add_executable(testppc ${TEST_SOURCES} $<TARGET_OBJECTS:debugger>
$<TARGET_OBJECTS:cpu_ppc>
$<TARGET_OBJECTS:devices>
$<TARGET_OBJECTS:execution>
$<TARGET_OBJECTS:machines>
$<TARGET_OBJECTS:loguru>)
@ -86,6 +128,24 @@ else()
target_link_libraries(testppc cubeb ${SDL2_LIBRARIES} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
endif()
if (ENABLE_68K_DEBUGGER)
target_link_libraries(testppc capstone-static)
endif()
file(GLOB BENCH_SOURCES "${PROJECT_SOURCE_DIR}/benchmark/*.cpp")
add_executable(bench1 ${BENCH_SOURCES} $<TARGET_OBJECTS:debugger>
$<TARGET_OBJECTS:cpu_ppc>
$<TARGET_OBJECTS:devices>
$<TARGET_OBJECTS:execution>
$<TARGET_OBJECTS:machines>
$<TARGET_OBJECTS:loguru>)
target_link_libraries(bench1 cubeb ${SDL2_LIBRARIES} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
if (ENABLE_68K_DEBUGGER)
target_link_libraries(bench1 capstone-static)
endif()
add_custom_command(
TARGET testppc POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy

91
benchmark/bench1.cpp Normal file
View File

@ -0,0 +1,91 @@
#include <stdlib.h>
#include <chrono>
#include "cpu/ppc/ppcemu.h"
#include "cpu/ppc/ppcmmu.h"
#include "devices/mpc106.h"
#include <thirdparty/loguru/loguru.hpp>
uint32_t cs_code[] = {
0x3863FFFC, 0x7C861671, 0x41820090, 0x70600002, 0x41E2001C, 0xA0030004,
0x3884FFFE, 0x38630002, 0x5486F0BF, 0x7CA50114, 0x41820070, 0x70C60003,
0x41820014, 0x7CC903A6, 0x84030004, 0x7CA50114, 0x4200FFF8, 0x5486E13F,
0x41820050, 0x80030004, 0x7CC903A6, 0x80C30008, 0x7CA50114, 0x80E3000C,
0x7CA53114, 0x85030010, 0x7CA53914, 0x42400028, 0x80030004, 0x7CA54114,
0x80C30008, 0x7CA50114, 0x80E3000C, 0x7CA53114, 0x85030010, 0x7CA53914,
0x4200FFE0, 0x7CA54114, 0x70800002, 0x41E20010, 0xA0030004, 0x38630002,
0x7CA50114, 0x70800001, 0x41E20010, 0x88030004, 0x5400402E, 0x7CA50114,
0x7C650194, 0x4E800020
};
int main(int argc, char** argv) {
int i;
/* initialize logging */
loguru::g_preamble_date = false;
loguru::g_preamble_time = false;
loguru::g_preamble_thread = false;
loguru::g_stderr_verbosity = 0;
loguru::init(argc, argv);
MPC106* grackle_obj = new MPC106;
/* we need some RAM */
if (!grackle_obj->add_ram_region(0, 0x9000)) {
LOG_F(ERROR, "Could not create RAM region");
delete(grackle_obj);
return -1;
}
ppc_cpu_init(grackle_obj, PPC_VER::MPC750);
/* load executable code into RAM at address 0 */
for (i = 0; i < sizeof(cs_code); i++) {
mem_write_dword(i*4, cs_code[i]);
}
srand(0xCAFEBABE);
for (i = 0; i < 32768; i++) {
mem_write_byte(0x1000+i, rand() % 256);
}
/* prepare benchmark code execution */
ppc_state.pc = 0;
ppc_state.gpr[3] = 0x1000; // buf
ppc_state.gpr[4] = 0x8000; // len
ppc_state.gpr[5] = 0; // sum
ppc_exec_until(0xC4);
LOG_F(INFO, "Checksum: 0x%08X", ppc_state.gpr[3]);
// run the clock once for cache fill etc.
auto start_time = std::chrono::steady_clock::now();
auto end_time = std::chrono::steady_clock::now();
auto time_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
LOG_F(INFO, "Time elapsed (dry run): %lld ns", time_elapsed.count());
for (i = 0; i < 5; i++) {
ppc_state.pc = 0;
ppc_state.gpr[3] = 0x1000; // buf
ppc_state.gpr[4] = 0x8000; // len
ppc_state.gpr[5] = 0; // sum
auto start_time = std::chrono::steady_clock::now();
ppc_exec_until(0xC4);
auto end_time = std::chrono::steady_clock::now();
LOG_F(INFO, "Checksum: 0x%08X", ppc_state.gpr[3]);
auto time_elapsed = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time);
LOG_F(INFO, "Time elapsed (run #%d): %lld ns", i, time_elapsed.count());
}
delete(grackle_obj);
return 0;
}

View File

@ -24,62 +24,42 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "ppcemu.h"
#include "ppcmmu.h"
#include <array>
#include <cmath>
#include <iostream>
#include <limits>
#include <stdexcept>
#include <stdio.h>
#include <thirdparty/loguru/loguru.hpp>
void power_abs() {
// Affects the XER register's SO and OV Bits
inline void power_setsoov(uint32_t a, uint32_t b, uint32_t d) {
if ((a ^ b) & (a ^ d) & 0x80000000UL) {
ppc_state.spr[SPR::XER] |= 0xC0000000UL;
} else {
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
}
}
void dppc_interpreter::power_abs() {
ppc_grab_regsda();
if (ppc_result_a == 0x80000000) {
ppc_result_d = ppc_result_a;
if (oe_flag)
ppc_state.spr[SPR::XER] |= 0x40000000;
} else {
ppc_result_d = ppc_result_a & 0x7FFFFFFF;
}
if (rc_flag)
ppc_changecrf0(ppc_result_d);
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() {
void dppc_interpreter::power_clcs() {
ppc_grab_regsda();
switch (reg_a) {
case 12:
@ -91,107 +71,56 @@ void power_clcs() {
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;
if (rc_flag) {
ppc_changecrf0(ppc_result_d);
printf("Does RC do anything here? (TODO) \n");
}
ppc_changecrf0(ppc_result_d);
printf("Does RC do anything here? (TODO) \n");
ppc_store_result_regd();
}
void power_div() {
void dppc_interpreter::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;
if (oe_flag)
power_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
if (rc_flag)
ppc_changecrf0(ppc_result_d);
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() {
void dppc_interpreter::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);
if (oe_flag)
power_setsoov(ppc_result_b, ppc_result_a, ppc_result_d);
if (rc_flag)
ppc_changecrf0(ppc_result_d);
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() {
void dppc_interpreter::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;
}
if (rc_flag)
ppc_changecrf0(ppc_result_d);
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() {
void dppc_interpreter::power_dozi() {
ppc_grab_regsdab();
if (((int32_t)ppc_result_a) > simm) {
ppc_result_d = 0;
@ -201,7 +130,7 @@ void power_dozi() {
ppc_store_result_rega();
}
void power_lscbx() {
void dppc_interpreter::power_lscbx() {
ppc_grab_regsdab();
uint32_t bytes_copied = 0;
bool match_found = false;
@ -254,14 +183,15 @@ void power_lscbx() {
}
} while (bytes_to_load > 0);
ppc_state.spr[SPR::XER] = (ppc_state.spr[SPR::XER] & 0xFFFFFF80) | bytes_copied;
if (rc_flag)
ppc_changecrf0(ppc_result_d);
ppc_store_result_regd();
}
void power_lscbxdot() {
printf("OOPS! Placeholder!!! \n");
}
void power_maskg() {
void dppc_interpreter::power_maskg() {
ppc_grab_regssab();
uint32_t mask_start = ppc_result_d & 31;
uint32_t mask_end = ppc_result_b & 31;
@ -281,33 +211,14 @@ void power_maskg() {
}
ppc_result_a = insert_mask;
if (rc_flag)
ppc_changecrf0(ppc_result_d);
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() {
void dppc_interpreter::power_maskir() {
ppc_grab_regssab();
uint32_t mask_insert = ppc_result_a;
uint32_t insert_rot = 0x80000000;
@ -320,82 +231,38 @@ void power_maskir() {
} while (insert_rot > 0);
ppc_result_a = (ppc_result_d & ppc_result_b);
if (rc_flag)
ppc_changecrf0(ppc_result_a);
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() {
void dppc_interpreter::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));
if (rc_flag)
ppc_changecrf0(ppc_result_d);
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() {
void dppc_interpreter::power_nabs() {
ppc_grab_regsda();
ppc_result_d = (0x80000000 | ppc_result_a);
if (rc_flag)
ppc_changecrf0(ppc_result_d);
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() {
void dppc_interpreter::power_rlmi() {
ppc_grab_regssab();
unsigned rot_mb = (ppc_cur_instruction >> 6) & 31;
unsigned rot_me = (ppc_cur_instruction >> 1) & 31;
@ -420,28 +287,22 @@ void power_rlmi() {
ppc_store_result_rega();
}
void power_rrib() {
void dppc_interpreter::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);
}
if (rc_flag)
ppc_changecrf0(ppc_result_a);
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() {
void dppc_interpreter::power_sle() {
ppc_grab_regssa();
uint32_t insert_mask = 0;
uint32_t rot_amt = ppc_result_b & 31;
@ -451,24 +312,14 @@ void power_sle() {
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;
if (rc_flag)
ppc_changecrf0(ppc_result_a);
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() {
void dppc_interpreter::power_sleq() {
ppc_grab_regssa();
uint32_t insert_mask = 0;
uint32_t rot_amt = ppc_result_b & 31;
@ -487,33 +338,14 @@ void power_sleq() {
ppc_result_a = insert_end;
ppc_state.spr[SPR::MQ] = insert_start;
if (rc_flag)
ppc_changecrf0(ppc_result_a);
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() {
void dppc_interpreter::power_sliq() {
ppc_grab_regssa();
uint32_t insert_mask = 0;
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
@ -532,33 +364,14 @@ void power_sliq() {
ppc_result_a = insert_end & insert_mask;
ppc_state.spr[SPR::MQ] = insert_start;
if (rc_flag)
ppc_changecrf0(ppc_result_a);
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() {
void dppc_interpreter::power_slliq() {
ppc_grab_regssa();
uint32_t insert_mask = 0;
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
@ -577,65 +390,30 @@ void power_slliq() {
ppc_result_a = insert_end;
ppc_state.spr[SPR::MQ] = insert_start;
if (rc_flag)
ppc_changecrf0(ppc_result_a);
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() {
void dppc_interpreter::power_sllq() {
LOG_F(WARNING, "OOPS! Placeholder for sllq!!! \n");
}
void power_sllqdot() {
LOG_F(WARNING, "OOPS! Placeholder for sllq.!!! \n");
}
void power_slq() {
void dppc_interpreter::power_slq() {
LOG_F(WARNING, "OOPS! Placeholder for slq!!! \n");
}
void power_slqdot() {
LOG_F(WARNING, "OOPS! Placeholder for slq.!!! \n");
}
void power_sraiq() {
void dppc_interpreter::power_sraiq() {
LOG_F(WARNING, "OOPS! Placeholder for sraiq!!! \n");
}
void power_sraiqdot() {
LOG_F(WARNING, "OOPS! Placeholder for sraiq.!!! \n");
}
void power_sraq() {
void dppc_interpreter::power_sraq() {
LOG_F(WARNING, "OOPS! Placeholder for sraq!!! \n");
}
void power_sraqdot() {
LOG_F(WARNING, "OOPS! Placeholder for sraq.!!! \n");
}
void power_sre() {
void dppc_interpreter::power_sre() {
ppc_grab_regssa();
uint32_t insert_mask = 0;
uint32_t rot_amt = ppc_result_b & 31;
@ -645,32 +423,16 @@ void power_sre() {
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;
if (rc_flag)
ppc_changecrf0(ppc_result_a);
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() {
void dppc_interpreter::power_srea() {
LOG_F(WARNING, "OOPS! Placeholder for srea!!! \n");
}
void power_sreadot() {
LOG_F(WARNING, "OOPS! Placeholder for srea.!!! \n");
}
void power_sreq() {
void dppc_interpreter::power_sreq() {
ppc_grab_regssa();
uint32_t insert_mask = 0;
unsigned rot_sh = ppc_result_b & 31;
@ -689,33 +451,14 @@ void power_sreq() {
ppc_result_a = insert_end;
ppc_state.spr[SPR::MQ] = insert_start;
if (rc_flag)
ppc_changecrf0(ppc_result_a);
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() {
void dppc_interpreter::power_sriq() {
ppc_grab_regssa();
uint32_t insert_mask = 0;
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
@ -734,52 +477,21 @@ void power_sriq() {
ppc_result_a = insert_end;
ppc_state.spr[SPR::MQ] = insert_start;
if (rc_flag)
ppc_changecrf0(ppc_result_a);
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() {
void dppc_interpreter::power_srliq() {
LOG_F(WARNING, "OOPS! Placeholder for slriq!!! \n");
}
void power_srliqdot() {
LOG_F(WARNING, "OOPS! Placeholder for slriq.!!! \n");
}
void power_srlq() {
void dppc_interpreter::power_srlq() {
LOG_F(WARNING, "OOPS! Placeholder for slrq!!! \n");
}
void power_srlqdot() {
LOG_F(WARNING, "OOPS! Placeholder for slrq.!!! \n");
}
void power_srq() {
void dppc_interpreter::power_srq() {
LOG_F(WARNING, "OOPS! Placeholder for srq!!! \n");
}
void power_srqdot() {
LOG_F(WARNING, "OOPS! Placeholder for srq.!!! \n");
}
}

View File

@ -215,6 +215,14 @@ enum class Except_Type {
EXC_TRACE = 13
};
/** Programm Exception subclasses. */
enum Exc_Cause : uint32_t {
FPU_OFF = 1 << (31 - 11),
ILLEGAL_OP = 1 << (31 - 12),
NOT_ALLOWED = 1 << (31 - 13),
TRAP = 1 << (31 - 14),
};
// extern bool bb_end;
extern BB_end_kind bb_kind;
@ -226,10 +234,12 @@ extern bool grab_return;
extern bool power_on;
extern bool is_601; // For PowerPC 601 Emulation
extern bool is_gekko; // For GameCube Emulation
extern bool is_altivec; // For Altivec Emulation
extern bool is_64bit; // For PowerPC G5 Emulation
extern bool rc_flag; // Record flag
extern bool oe_flag; // Overflow flag
// Important Addressing Integers
extern uint32_t ppc_cur_instruction;
extern uint32_t ppc_effective_address;
@ -244,7 +254,13 @@ extern uint32_t supervisor_inst_num;
extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t proc_version);
extern void ppc_mmu_init();
void ppc_illegalop();
[[noreturn]] void ppc_illegalop();
[[noreturn]] void ppc_fpu_off();
void ppc_illegalsubop19();
void ppc_illegalsubop31();
void ppc_illegalsubop59();
void ppc_illegalsubop63();
void ppc_opcode4();
void ppc_opcode16();
void ppc_opcode18();
@ -253,6 +269,8 @@ void ppc_opcode31();
void ppc_opcode59();
void ppc_opcode63();
void initialize_ppc_opcode_tables();
extern bool ppc_confirm_inf_nan(uint64_t input_a, uint64_t input_b, bool is_single, uint32_t op);
extern double fp_return_double(uint32_t reg);
extern uint64_t fp_return_uint64(uint32_t reg);
@ -286,8 +304,6 @@ extern void ppc_store_dfpresult(bool int_rep);
void ppc_changecrf0(uint32_t set_result);
void ppc_fp_changecrf1();
void ppc_tbr_update();
/* Exception handlers. */
[[noreturn]] void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits);
[[noreturn]] void dbg_exception_handler(Except_Type exception_type, uint32_t srr1_bits);
@ -296,6 +312,7 @@ void ppc_tbr_update();
extern MemCtrlBase* mem_ctrl_instance;
// The functions used by the PowerPC processor
namespace dppc_interpreter {
extern void ppc_bcctr();
extern void ppc_bcctrl();
extern void ppc_bclr();
@ -311,33 +328,15 @@ extern void ppc_crxor();
extern void ppc_isync();
extern void ppc_add();
extern void ppc_adddot();
extern void ppc_addo();
extern void ppc_addodot();
extern void ppc_addc();
extern void ppc_addcdot();
extern void ppc_addco();
extern void ppc_addcodot();
extern void ppc_adde();
extern void ppc_addedot();
extern void ppc_addeo();
extern void ppc_addeodot();
extern void ppc_addme();
extern void ppc_addmedot();
extern void ppc_addmeo();
extern void ppc_addmeodot();
extern void ppc_addze();
extern void ppc_addzedot();
extern void ppc_addzeo();
extern void ppc_addzeodot();
extern void ppc_and();
extern void ppc_anddot();
extern void ppc_andc();
extern void ppc_andcdot();
extern void ppc_cmp();
extern void ppc_cmpl();
extern void ppc_cntlzw();
extern void ppc_cntlzwdot();
extern void ppc_dcbf();
extern void ppc_dcbi();
extern void ppc_dcbst();
@ -345,20 +344,11 @@ extern void ppc_dcbt();
extern void ppc_dcbtst();
extern void ppc_dcbz();
extern void ppc_divw();
extern void ppc_divwdot();
extern void ppc_divwo();
extern void ppc_divwodot();
extern void ppc_divwu();
extern void ppc_divwudot();
extern void ppc_divwuo();
extern void ppc_divwuodot();
extern void ppc_eieio();
extern void ppc_eqv();
extern void ppc_eqvdot();
extern void ppc_extsb();
extern void ppc_extsbdot();
extern void ppc_extsh();
extern void ppc_extshdot();
extern void ppc_icbi();
extern void ppc_mftb();
extern void ppc_lhzux();
@ -375,33 +365,17 @@ extern void ppc_lwzx();
extern void ppc_mcrxr();
extern void ppc_mfcr();
extern void ppc_mulhwu();
extern void ppc_mulhwudot();
extern void ppc_mulhw();
extern void ppc_mulhwdot();
extern void ppc_mullw();
extern void ppc_mullwdot();
extern void ppc_mullwo();
extern void ppc_mullwodot();
extern void ppc_nand();
extern void ppc_nanddot();
extern void ppc_neg();
extern void ppc_negdot();
extern void ppc_nego();
extern void ppc_negodot();
extern void ppc_nor();
extern void ppc_nordot();
extern void ppc_or();
extern void ppc_ordot();
extern void ppc_orc();
extern void ppc_orcdot();
extern void ppc_slw();
extern void ppc_slwdot();
extern void ppc_srw();
extern void ppc_srwdot();
extern void ppc_sraw();
extern void ppc_srawdot();
extern void ppc_srawi();
extern void ppc_srawidot();
extern void ppc_stbx();
extern void ppc_stbux();
extern void ppc_stfiwx();
@ -413,25 +387,10 @@ extern void ppc_stwcx();
extern void ppc_stwux();
extern void ppc_stwbrx();
extern void ppc_subf();
extern void ppc_subfdot();
extern void ppc_subfo();
extern void ppc_subfodot();
extern void ppc_subfc();
extern void ppc_subfcdot();
extern void ppc_subfco();
extern void ppc_subfcodot();
extern void ppc_subfe();
extern void ppc_subfedot();
extern void ppc_subfeo();
extern void ppc_subfeodot();
extern void ppc_subfme();
extern void ppc_subfmedot();
extern void ppc_subfmeo();
extern void ppc_subfmeodot();
extern void ppc_subfze();
extern void ppc_subfzedot();
extern void ppc_subfzeo();
extern void ppc_subfzeodot();
extern void ppc_sync();
extern void ppc_tlbia();
extern void ppc_tlbie();
@ -440,7 +399,6 @@ extern void ppc_tlbld();
extern void ppc_tlbsync();
extern void ppc_tw();
extern void ppc_xor();
extern void ppc_xordot();
extern void ppc_lswi();
extern void ppc_lswx();
@ -561,111 +519,39 @@ extern void ppc_frsp();
extern void ppc_fctiw();
extern void ppc_fctiwz();
extern void ppc_fadddot();
extern void ppc_fsubdot();
extern void ppc_fmultdot();
extern void ppc_fdivdot();
extern void ppc_fmadddot();
extern void ppc_fmsubdot();
extern void ppc_fnmadddot();
extern void ppc_fnmsubdot();
extern void ppc_fabsdot();
extern void ppc_fnabsdot();
extern void ppc_fnegdot();
extern void ppc_fseldot();
extern void ppc_fsqrtdot();
extern void ppc_frsqrtedot();
extern void ppc_frspdot();
extern void ppc_fctiwdot();
extern void ppc_fctiwzdot();
extern void ppc_fresdot();
extern void ppc_faddsdot();
extern void ppc_fsubsdot();
extern void ppc_fmultsdot();
extern void ppc_fdivsdot();
extern void ppc_fmaddsdot();
extern void ppc_fmsubsdot();
extern void ppc_fnmaddsdot();
extern void ppc_fnmsubsdot();
extern void ppc_fsqrtsdot();
extern void ppc_fcmpo();
extern void ppc_fcmpu();
// Power-specific instructions
extern void power_abs();
extern void power_absdot();
extern void power_abso();
extern void power_absodot();
extern void power_clcs();
extern void power_clcsdot();
extern void power_div();
extern void power_divdot();
extern void power_divo();
extern void power_divodot();
extern void power_divs();
extern void power_divsdot();
extern void power_divso();
extern void power_divsodot();
extern void power_doz();
extern void power_dozdot();
extern void power_dozo();
extern void power_dozodot();
extern void power_dozi();
extern void power_lscbx();
extern void power_lscbxdot();
extern void power_maskg();
extern void power_maskgdot();
extern void power_maskir();
extern void power_maskirdot();
extern void power_mul();
extern void power_muldot();
extern void power_mulo();
extern void power_mulodot();
extern void power_nabs();
extern void power_nabsdot();
extern void power_nabso();
extern void power_nabsodot();
extern void power_rlmi();
extern void power_rrib();
extern void power_rribdot();
extern void power_sle();
extern void power_sledot();
extern void power_sleq();
extern void power_sleqdot();
extern void power_sliq();
extern void power_sliqdot();
extern void power_slliq();
extern void power_slliqdot();
extern void power_sllq();
extern void power_sllqdot();
extern void power_slq();
extern void power_slqdot();
extern void power_sraiq();
extern void power_sraiqdot();
extern void power_sraq();
extern void power_sraqdot();
extern void power_sre();
extern void power_sredot();
extern void power_srea();
extern void power_sreadot();
extern void power_sreq();
extern void power_sreqdot();
extern void power_sriq();
extern void power_sriqdot();
extern void power_srliq();
extern void power_srliqdot();
extern void power_srlq();
extern void power_srlqdot();
extern void power_srq();
extern void power_srqdot();
// Gekko instructions
extern void ppc_psq_l();
extern void ppc_psq_lu();
extern void ppc_psq_st();
extern void ppc_psq_stu();
} // namespace dppc_interpreter
// AltiVec instructions
@ -677,6 +563,7 @@ extern void ppc_main_opcode(void);
extern void ppc_exec(void);
extern void ppc_exec_single(void);
extern void ppc_exec_until(uint32_t goal_addr);
extern void ppc_exec_dbg(uint32_t start_addr, uint32_t size);
/* debugging support API */
void print_gprs(void); /* print content of the general purpose registers */

View File

@ -35,6 +35,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#define NEW_TBR_UPDATE_ALGO
using namespace std;
using namespace dppc_interpreter;
MemCtrlBase* mem_ctrl_instance = 0;
@ -42,6 +43,9 @@ bool power_on = 1;
SetPRS ppc_state;
bool rc_flag = 0; // Record flag
bool oe_flag = 0; // Overflow flag
bool grab_exception;
bool grab_return;
bool grab_breakpoint;
@ -69,344 +73,37 @@ uint8_t tbr_factor; /* cycles_count to TBR freq ratio in 2^x units */
/** Primary opcode (bits 0...5) lookup table. */
static PPCOpcode OpcodeGrabber[] = {
ppc_illegalop, ppc_illegalop, ppc_illegalop, ppc_twi, ppc_opcode4, ppc_illegalop,
ppc_illegalop, ppc_mulli, ppc_subfic, power_dozi, ppc_cmpli, ppc_cmpi,
ppc_addic, ppc_addicdot, ppc_addi, ppc_addis, ppc_opcode16, ppc_sc,
ppc_opcode18, ppc_opcode19, ppc_rlwimi, ppc_rlwinm, power_rlmi, ppc_rlwnm,
ppc_ori, ppc_oris, ppc_xori, ppc_xoris, ppc_andidot, ppc_andisdot,
ppc_illegalop, ppc_opcode31, ppc_lwz, ppc_lwzu, ppc_lbz, ppc_lbzu,
ppc_stw, ppc_stwu, ppc_stb, ppc_stbu, ppc_lhz, ppc_lhzu,
ppc_lha, ppc_lhau, ppc_sth, ppc_sthu, ppc_lmw, ppc_stmw,
ppc_lfs, ppc_lfsu, ppc_lfd, ppc_lfdu, ppc_stfs, ppc_stfsu,
ppc_stfd, ppc_stfdu, ppc_psq_l, ppc_psq_lu, ppc_illegalop, ppc_illegalop,
ppc_psq_st, ppc_psq_stu, ppc_illegalop, ppc_opcode63};
ppc_illegalop, ppc_illegalop, ppc_illegalop, ppc_twi, ppc_illegalop, ppc_illegalop,
ppc_illegalop, ppc_mulli, ppc_subfic, power_dozi, ppc_cmpli, ppc_cmpi,
ppc_addic, ppc_addicdot, ppc_addi, ppc_addis, ppc_opcode16, ppc_sc,
ppc_opcode18, ppc_opcode19, ppc_rlwimi, ppc_rlwinm, power_rlmi, ppc_rlwnm,
ppc_ori, ppc_oris, ppc_xori, ppc_xoris, ppc_andidot, ppc_andisdot,
ppc_illegalop, ppc_opcode31, ppc_lwz, ppc_lwzu, ppc_lbz, ppc_lbzu,
ppc_stw, ppc_stwu, ppc_stb, ppc_stbu, ppc_lhz, ppc_lhzu,
ppc_lha, ppc_lhau, ppc_sth, ppc_sthu, ppc_lmw, ppc_stmw,
ppc_lfs, ppc_lfsu, ppc_lfd, ppc_lfdu, ppc_stfs, ppc_stfsu,
ppc_stfd, ppc_stfdu, ppc_illegalop, ppc_illegalop, ppc_illegalop, ppc_illegalop,
ppc_illegalop, ppc_illegalop, ppc_illegalop, ppc_opcode63};
/** Lookup tables for branch instructions. */
static PPCOpcode SubOpcode16Grabber[] = {ppc_bc, ppc_bcl, ppc_bca, ppc_bcla};
static PPCOpcode SubOpcode16Grabber[] = {
dppc_interpreter::ppc_bc,
dppc_interpreter::ppc_bcl,
dppc_interpreter::ppc_bca,
dppc_interpreter::ppc_bcla};
static PPCOpcode SubOpcode18Grabber[] = {ppc_b, ppc_bl, ppc_ba, ppc_bla};
static PPCOpcode SubOpcode18Grabber[] = {
dppc_interpreter::ppc_b,
dppc_interpreter::ppc_bl,
dppc_interpreter::ppc_ba,
dppc_interpreter::ppc_bla};
/** General conditional register instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode19Grabber = {
{32, &ppc_bclr},
{33, &ppc_bclrl},
{66, &ppc_crnor},
{100, &ppc_rfi},
{258, &ppc_crandc},
{300, &ppc_isync},
{386, &ppc_crxor},
{450, &ppc_crnand},
{514, &ppc_crand},
{578, &ppc_creqv},
{834, &ppc_crorc},
{898, &ppc_cror},
{1056, &ppc_bcctr},
{1057, &ppc_bcctrl}};
/** Instructions decoding tables for integer,
single floating-point, and double-floating point ops respectively */
/** General integer instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode31Grabber = {
{0, &ppc_cmp}, {8, &ppc_tw},
{16, &ppc_subfc}, {17, &ppc_subfcdot},
{20, &ppc_addc}, {21, &ppc_addcdot},
{22, &ppc_mulhwu}, {23, &ppc_mulhwudot},
{38, &ppc_mfcr}, {40, &ppc_lwarx},
{46, &ppc_lwzx}, {48, &ppc_slw},
{49, &ppc_slwdot}, {52, &ppc_cntlzw},
{53, &ppc_cntlzwdot}, {56, &ppc_and},
{57, &ppc_anddot}, {58, &power_maskg},
{59, &power_maskgdot}, {64, &ppc_cmpl},
{80, &ppc_subf}, {81, &ppc_subfdot},
{108, &ppc_dcbst}, {110, &ppc_lwzux},
{120, &ppc_andc}, {121, &ppc_andcdot},
{150, &ppc_mulhw}, {151, &ppc_mulhwdot},
{166, &ppc_mfmsr}, {172, &ppc_dcbf},
{174, &ppc_lbzx}, {208, &ppc_neg},
{209, &ppc_negdot}, {214, &power_mul},
{215, &power_muldot}, {238, &ppc_lbzux},
{248, &ppc_nor}, {249, &ppc_nordot},
{272, &ppc_subfe}, {273, &ppc_subfedot},
{276, &ppc_adde}, {277, &ppc_addedot},
{288, &ppc_mtcrf}, {292, &ppc_mtmsr},
{301, &ppc_stwcx}, {302, &ppc_stwx},
{304, &power_slq}, {305, &power_slqdot},
{306, &power_sle}, {307, &power_sledot},
{366, &ppc_stwux}, {368, &power_sliq},
{400, &ppc_subfze}, {401, &ppc_subfzedot},
{404, &ppc_addze}, {405, &ppc_addzedot},
{420, &ppc_mtsr}, {430, &ppc_stbx},
{432, &power_sllq}, {433, &power_sllqdot},
{434, &power_sleq}, {436, &power_sleqdot},
{464, &ppc_subfme}, {465, &ppc_subfmedot},
{468, &ppc_addme}, {469, &ppc_addmedot},
{470, &ppc_mullw}, {471, &ppc_mullwdot},
{484, &ppc_mtsrin}, {492, &ppc_dcbtst},
{494, &ppc_stbux}, {496, &power_slliq},
{497, &power_slliqdot}, {528, &power_doz},
{529, &power_dozdot}, {532, &ppc_add},
{533, &ppc_adddot}, {554, &power_lscbx},
{555, &power_lscbxdot}, {556, &ppc_dcbt},
{558, &ppc_lhzx}, {568, &ppc_eqv},
{569, &ppc_eqvdot}, {612, &ppc_tlbie},
{622, &ppc_lhzux}, {632, &ppc_xor},
{633, &ppc_xordot}, {662, &power_div},
{663, &power_divdot}, {678, &ppc_mfspr},
{686, &ppc_lhax}, {720, &power_abs},
{721, &power_absdot}, {726, &power_divs},
{727, &power_divsdot}, {740, &ppc_tlbia},
{742, &ppc_mftb}, {750, &ppc_lhaux},
{814, &ppc_sthx}, {824, &ppc_orc},
{825, &ppc_orcdot}, {878, &ppc_sthx},
{888, &ppc_or}, {889, &ppc_ordot},
{918, &ppc_divwu}, {919, &ppc_divwudot},
{934, &ppc_mtspr}, {940, &ppc_dcbi},
{952, &ppc_nand}, {953, &ppc_nanddot},
{976, &power_nabs}, {977, &power_nabsdot},
{982, &ppc_divw}, {983, &ppc_divwdot},
{1024, &ppc_mcrxr}, {1040, &ppc_subfco},
{1041, &ppc_subfcodot}, {1044, &ppc_addco},
{1045, &ppc_addcodot}, {1062, &power_clcs},
{1063, &power_clcsdot}, {1066, &ppc_lswx},
{1068, &ppc_lwbrx}, {1070, &ppc_lfsx},
{1072, &ppc_srw}, {1073, &ppc_srwdot},
{1074, &power_rrib}, {1075, &power_rribdot},
{1082, &power_maskir}, {1083, &power_maskirdot},
{1104, &ppc_subfo}, {1105, &ppc_subfodot},
{1132, &ppc_tlbsync}, {1134, &ppc_lfsux},
{1190, &ppc_mfsr}, {1194, &ppc_lswi},
{1196, &ppc_sync}, {1198, &ppc_lfdx},
{1232, &ppc_nego}, {1233, &ppc_negodot},
{1238, &power_mulo}, {1239, &power_mulodot},
{1262, &ppc_lfdux}, {1296, &ppc_subfeo},
{1297, &ppc_subfeodot}, {1300, &ppc_addeo},
{1301, &ppc_addeodot}, {1318, &ppc_mfsrin},
{1322, &ppc_stswx}, {1324, &ppc_stwbrx},
{1326, &ppc_stfsx}, {1328, &power_srq},
{1329, &power_srqdot}, {1330, &power_sre},
{1331, &power_sredot}, {1390, &ppc_stfsux},
{1392, &power_sriq}, {1393, &power_sriqdot},
{1424, &ppc_subfzeo}, {1425, &ppc_subfzeodot},
{1428, &ppc_addzeo}, {1429, &ppc_addzeodot},
{1450, &ppc_stswi}, {1454, &ppc_stfdx},
{1456, &power_srlq}, {1457, &power_srlqdot},
{1458, &power_sreq}, {1459, &power_sreqdot},
{1488, &ppc_subfmeo}, {1489, &ppc_subfmeodot},
{1492, &ppc_addmeo}, {1493, &ppc_addmeodot},
{1494, &ppc_mullwo}, {1495, &ppc_mullwodot},
{1518, &ppc_stfdux}, {1520, &power_srliq},
{1521, &power_srliqdot}, {1552, &power_dozo},
{1553, &power_dozodot}, {1556, &ppc_addo},
{1557, &ppc_addodot}, {1580, &ppc_lhbrx},
{1584, &ppc_sraw}, {1585, &ppc_srawdot},
{1648, &ppc_srawi}, {1649, &ppc_srawidot},
{1686, &power_divo}, {1687, &power_divodot},
{1708, &ppc_eieio}, {1744, &power_abso},
{1745, &power_absodot}, {1750, &power_divso},
{1751, &power_divsodot}, {1836, &ppc_sthbrx},
{1840, &power_sraq}, {1841, &power_sraqdot},
{1842, &power_srea}, {1843, &power_sreadot},
{1844, &ppc_extsh}, {1845, &ppc_extshdot},
{1904, &power_sraiq}, {1905, &power_sraiqdot},
{1908, &ppc_extsb}, {1909, &ppc_extsbdot},
{1942, &ppc_divwuo}, {1943, &ppc_divwuodot},
{1956, &ppc_tlbld}, {1964, &ppc_icbi},
{1966, &ppc_stfiwx}, {2000, &power_nabso},
{2001, &power_nabsodot}, {2006, &ppc_divwo},
{2007, &ppc_divwodot}, {2020, &ppc_tlbli},
{2028, &ppc_dcbz}};
/** Single-precision floating-point instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode59Grabber = {
{36, &ppc_fdivs}, {37, &ppc_fdivsdot}, {40, &ppc_fsubs}, {41, &ppc_fsubsdot},
{42, &ppc_fadds}, {43, &ppc_faddsdot}, {44, &ppc_fsqrts}, {45, &ppc_fsqrtsdot},
{48, &ppc_fres}, {49, &ppc_fresdot}, {50, &ppc_fmults}, {51, &ppc_fmultsdot},
{56, &ppc_fmsubs}, {57, &ppc_fmsubsdot}, {58, &ppc_fmadds}, {59, &ppc_fmaddsdot},
{60, &ppc_fnmsubs}, {61, &ppc_fnmsubsdot}, {62, &ppc_fnmadds}, {63, &ppc_fnmaddsdot},
{114, &ppc_fmults}, {115, &ppc_fmultsdot}, {120, &ppc_fmsubs}, {121, &ppc_fmsubsdot},
{122, &ppc_fmadds}, {123, &ppc_fmadds}, {124, &ppc_fnmsubs}, {125, &ppc_fnmsubsdot},
{126, &ppc_fnmadds}, {127, &ppc_fnmaddsdot}, {178, &ppc_fmults}, {179, &ppc_fmultsdot},
{184, &ppc_fmsubs}, {185, &ppc_fmsubsdot}, {186, &ppc_fmadds}, {187, &ppc_fmaddsdot},
{188, &ppc_fnmsubs}, {189, &ppc_fnmsubsdot}, {190, &ppc_fnmadds}, {191, &ppc_fnmaddsdot},
{242, &ppc_fmults}, {243, &ppc_fmultsdot}, {248, &ppc_fmsubs}, {249, &ppc_fmsubsdot},
{250, &ppc_fmadds}, {251, &ppc_fmaddsdot}, {252, &ppc_fnmsubs}, {253, &ppc_fnmsubsdot},
{254, &ppc_fnmadds}, {255, &ppc_fnmaddsdot}, {306, &ppc_fmults}, {307, &ppc_fmultsdot},
{312, &ppc_fmsubs}, {313, &ppc_fmsubsdot}, {314, &ppc_fmadds}, {315, &ppc_fmaddsdot},
{316, &ppc_fnmsubs}, {317, &ppc_fnmsubsdot}, {318, &ppc_fnmadds}, {319, &ppc_fnmaddsdot},
{370, &ppc_fmults}, {371, &ppc_fmultsdot}, {376, &ppc_fmsubs}, {377, &ppc_fmsubsdot},
{378, &ppc_fmadds}, {379, &ppc_fmaddsdot}, {380, &ppc_fnmsubs}, {381, &ppc_fnmsubsdot},
{382, &ppc_fnmadds}, {383, &ppc_fnmaddsdot}, {434, &ppc_fmults}, {435, &ppc_fmultsdot},
{440, &ppc_fmsubs}, {441, &ppc_fmsubsdot}, {442, &ppc_fmadds}, {443, &ppc_fmaddsdot},
{444, &ppc_fnmsubs}, {445, &ppc_fnmsubsdot}, {446, &ppc_fnmadds}, {447, &ppc_fnmaddsdot},
{498, &ppc_fmults}, {499, &ppc_fmultsdot}, {504, &ppc_fmsubs}, {505, &ppc_fmsubsdot},
{506, &ppc_fmadds}, {507, &ppc_fmaddsdot}, {508, &ppc_fnmsubs}, {509, &ppc_fnmsubsdot},
{510, &ppc_fnmadds}, {511, &ppc_fnmaddsdot}, {562, &ppc_fmults}, {563, &ppc_fmultsdot},
{568, &ppc_fmsubs}, {569, &ppc_fmsubsdot}, {570, &ppc_fmadds}, {571, &ppc_fmaddsdot},
{572, &ppc_fnmsubs}, {573, &ppc_fnmsubsdot}, {574, &ppc_fnmadds}, {575, &ppc_fnmaddsdot},
{626, &ppc_fmults}, {627, &ppc_fmultsdot}, {632, &ppc_fmsubs}, {633, &ppc_fmsubsdot},
{634, &ppc_fmadds}, {635, &ppc_fmaddsdot}, {636, &ppc_fnmsubs}, {637, &ppc_fnmsubsdot},
{638, &ppc_fnmadds}, {639, &ppc_fnmaddsdot}, {690, &ppc_fmults}, {691, &ppc_fmultsdot},
{696, &ppc_fmsubs}, {697, &ppc_fmsubsdot}, {698, &ppc_fmadds}, {699, &ppc_fmaddsdot},
{700, &ppc_fnmsubs}, {701, &ppc_fnmsubsdot}, {702, &ppc_fnmadds}, {703, &ppc_fnmaddsdot},
{754, &ppc_fmults}, {755, &ppc_fmultsdot}, {760, &ppc_fmsubs}, {761, &ppc_fmsubsdot},
{762, &ppc_fmadds}, {763, &ppc_fmaddsdot}, {764, &ppc_fnmsubs}, {765, &ppc_fnmsubsdot},
{766, &ppc_fnmadds}, {767, &ppc_fnmaddsdot}, {818, &ppc_fmults}, {819, &ppc_fmultsdot},
{824, &ppc_fmsubs}, {825, &ppc_fmsubsdot}, {826, &ppc_fmadds}, {827, &ppc_fmaddsdot},
{828, &ppc_fnmsubs}, {829, &ppc_fnmsubsdot}, {830, &ppc_fnmadds}, {831, &ppc_fnmaddsdot},
{882, &ppc_fmults}, {883, &ppc_fmultsdot}, {888, &ppc_fmsubs}, {889, &ppc_fmsubsdot},
{890, &ppc_fmadds}, {891, &ppc_fmaddsdot}, {892, &ppc_fnmsubs}, {893, &ppc_fnmsubsdot},
{894, &ppc_fnmadds}, {895, &ppc_fnmaddsdot}, {946, &ppc_fmults}, {947, &ppc_fmultsdot},
{952, &ppc_fmsubs}, {953, &ppc_fmsubsdot}, {954, &ppc_fmadds}, {955, &ppc_fmaddsdot},
{957, &ppc_fnmsubs}, {958, &ppc_fnmsubsdot}, {958, &ppc_fnmadds}, {959, &ppc_fnmaddsdot},
{1010, &ppc_fmults}, {1011, &ppc_fmultsdot}, {1016, &ppc_fmsubs}, {1017, &ppc_fmsubsdot},
{1018, &ppc_fmadds}, {1019, &ppc_fmaddsdot}, {1020, &ppc_fnmsubs}, {1021, &ppc_fnmsubsdot},
{1022, &ppc_fnmadds}, {1023, &ppc_fnmaddsdot}, {1074, &ppc_fmults}, {1075, &ppc_fmultsdot},
{1080, &ppc_fmsubs}, {1081, &ppc_fmsubsdot}, {1082, &ppc_fmadds}, {1083, &ppc_fmaddsdot},
{1084, &ppc_fnmsubs}, {1085, &ppc_fnmsubsdot}, {1086, &ppc_fnmadds}, {1087, &ppc_fnmaddsdot},
{1138, &ppc_fmults}, {1139, &ppc_fmultsdot}, {1144, &ppc_fmsubs}, {1145, &ppc_fmsubsdot},
{1146, &ppc_fmadds}, {1147, &ppc_fmaddsdot}, {1148, &ppc_fnmsubs}, {1149, &ppc_fnmsubsdot},
{1150, &ppc_fnmadds}, {1151, &ppc_fnmaddsdot}, {1202, &ppc_fmults}, {1203, &ppc_fmultsdot},
{1208, &ppc_fmsubs}, {1209, &ppc_fmsubsdot}, {1210, &ppc_fmadds}, {1211, &ppc_fmaddsdot},
{1212, &ppc_fnmsubs}, {1213, &ppc_fnmsubsdot}, {1214, &ppc_fnmadds}, {1215, &ppc_fnmaddsdot},
{1266, &ppc_fmults}, {1267, &ppc_fmultsdot}, {1272, &ppc_fmsubs}, {1273, &ppc_fmsubsdot},
{1274, &ppc_fmadds}, {1275, &ppc_fmaddsdot}, {1276, &ppc_fnmsubs}, {1277, &ppc_fnmsubsdot},
{1278, &ppc_fnmadds}, {1279, &ppc_fnmaddsdot}, {1330, &ppc_fmults}, {1331, &ppc_fmultsdot},
{1336, &ppc_fmsubs}, {1337, &ppc_fmsubsdot}, {1338, &ppc_fmadds}, {1339, &ppc_fmaddsdot},
{1340, &ppc_fnmsubs}, {1341, &ppc_fnmsubsdot}, {1342, &ppc_fnmadds}, {1343, &ppc_fnmaddsdot},
{1394, &ppc_fmults}, {1395, &ppc_fmultsdot}, {1400, &ppc_fmsubs}, {1401, &ppc_fmsubsdot},
{1402, &ppc_fmadds}, {1403, &ppc_fmaddsdot}, {1404, &ppc_fnmsubs}, {1405, &ppc_fnmsubsdot},
{1406, &ppc_fnmadds}, {1407, &ppc_fnmaddsdot}, {1458, &ppc_fmults}, {1459, &ppc_fmultsdot},
{1464, &ppc_fmsubs}, {1465, &ppc_fmsubsdot}, {1466, &ppc_fmadds}, {1467, &ppc_fmaddsdot},
{1468, &ppc_fnmsubs}, {1469, &ppc_fnmsubsdot}, {1470, &ppc_fnmadds}, {1471, &ppc_fnmaddsdot},
{1522, &ppc_fmults}, {1523, &ppc_fmultsdot}, {1528, &ppc_fmsubs}, {1529, &ppc_fmsubsdot},
{1530, &ppc_fmadds}, {1531, &ppc_fmaddsdot}, {1532, &ppc_fnmsubs}, {1533, &ppc_fnmsubsdot},
{1534, &ppc_fnmadds}, {1535, &ppc_fnmaddsdot}, {1586, &ppc_fmults}, {1587, &ppc_fmultsdot},
{1592, &ppc_fmsubs}, {1593, &ppc_fmsubsdot}, {1594, &ppc_fmadds}, {1595, &ppc_fmaddsdot},
{1596, &ppc_fnmsubs}, {1597, &ppc_fnmsubsdot}, {1598, &ppc_fnmadds}, {1599, &ppc_fnmaddsdot},
{1650, &ppc_fmults}, {1651, &ppc_fmultsdot}, {1656, &ppc_fmsubs}, {1657, &ppc_fmsubsdot},
{1658, &ppc_fmadds}, {1659, &ppc_fmaddsdot}, {1660, &ppc_fnmsubs}, {1661, &ppc_fnmsubsdot},
{1662, &ppc_fnmadds}, {1663, &ppc_fnmaddsdot}, {1714, &ppc_fmults}, {1715, &ppc_fmultsdot},
{1720, &ppc_fmsubs}, {1721, &ppc_fmsubsdot}, {1722, &ppc_fmadds}, {1723, &ppc_fmaddsdot},
{1724, &ppc_fnmsubs}, {1725, &ppc_fnmsubsdot}, {1726, &ppc_fnmadds}, {1727, &ppc_fnmaddsdot},
{1778, &ppc_fmults}, {1779, &ppc_fmultsdot}, {1784, &ppc_fmsubs}, {1785, &ppc_fmsubsdot},
{1786, &ppc_fmadds}, {1787, &ppc_fmaddsdot}, {1788, &ppc_fnmsubs}, {1789, &ppc_fnmsubsdot},
{1790, &ppc_fnmadds}, {1791, &ppc_fnmaddsdot}, {1842, &ppc_fmults}, {1843, &ppc_fmultsdot},
{1848, &ppc_fmsubs}, {1849, &ppc_fmsubsdot}, {1850, &ppc_fmadds}, {1851, &ppc_fmaddsdot},
{1852, &ppc_fnmsubs}, {1853, &ppc_fnmsubsdot}, {1854, &ppc_fnmadds}, {1855, &ppc_fnmaddsdot},
{1906, &ppc_fmults}, {1907, &ppc_fmultsdot}, {1912, &ppc_fmsubs}, {1913, &ppc_fmsubsdot},
{1914, &ppc_fmadds}, {1915, &ppc_fmaddsdot}, {1916, &ppc_fnmsubs}, {1917, &ppc_fnmsubsdot},
{1918, &ppc_fnmadds}, {1919, &ppc_fnmaddsdot}, {1970, &ppc_fmults}, {1971, &ppc_fmultsdot},
{1976, &ppc_fmsubs}, {1977, &ppc_fmsubsdot}, {1978, &ppc_fmadds}, {1979, &ppc_fmaddsdot},
{1980, &ppc_fnmsubs}, {1981, &ppc_fnmsubsdot}, {1982, &ppc_fnmadds}, {1983, &ppc_fnmaddsdot},
{2034, &ppc_fmults}, {2035, &ppc_fmultsdot}, {2040, &ppc_fmsubs}, {2041, &ppc_fmsubsdot},
{2042, &ppc_fmadds}, {2043, &ppc_fmaddsdot}, {2044, &ppc_fnmsubs}, {2045, &ppc_fnmsubsdot},
{2046, &ppc_fnmadds}, {2047, &ppc_fnmaddsdot}};
/** Double-precision floating-point instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode63Grabber = {
{0, &ppc_fcmpu}, {24, &ppc_frsp}, {25, &ppc_frspdot}, {28, &ppc_fctiw},
{29, &ppc_fctiwdot}, {30, &ppc_fctiwz}, {31, &ppc_fctiwzdot}, {36, &ppc_fdiv},
{37, &ppc_fdivdot}, {40, &ppc_fsub}, {41, &ppc_fsubdot}, {42, &ppc_fadd},
{43, &ppc_fadddot}, {44, &ppc_fsqrt}, {45, &ppc_fsqrtdot}, {46, &ppc_fsel},
{47, &ppc_fseldot}, {50, &ppc_fmult}, {51, &ppc_fmultdot}, {52, &ppc_frsqrte},
{53, &ppc_frsqrtedot}, {56, &ppc_fmsub}, {57, &ppc_fmsubdot}, {58, &ppc_fmadd},
{59, &ppc_fmadddot}, {60, &ppc_fnmsub}, {61, &ppc_fnmsubdot}, {62, &ppc_fnmadd},
{63, &ppc_fnmadddot}, {64, &ppc_fcmpo}, {76, &ppc_mtfsb1}, {77, &ppc_mtfsb1dot},
{80, &ppc_fneg}, {81, &ppc_fnegdot}, {110, &ppc_fsel}, {111, &ppc_fseldot},
{114, &ppc_fmult}, {115, &ppc_fmultdot}, {120, &ppc_fmsub}, {121, &ppc_fmsubdot},
{122, &ppc_fmadd}, {123, &ppc_fmadd}, {124, &ppc_fnmsub}, {125, &ppc_fnmsubdot},
{126, &ppc_fnmadd}, {127, &ppc_fnmadddot}, {128, &ppc_mcrfs}, {140, &ppc_mtfsb0},
{141, &ppc_mtfsb0dot}, {144, &ppc_fmr}, {174, &ppc_fsel}, {175, &ppc_fseldot},
{178, &ppc_fmult}, {179, &ppc_fmultdot}, {184, &ppc_fmsub}, {185, &ppc_fmsubdot},
{186, &ppc_fmadd}, {187, &ppc_fmadddot}, {188, &ppc_fnmsub}, {189, &ppc_fnmsubdot},
{190, &ppc_fnmadd}, {191, &ppc_fnmadddot}, {238, &ppc_fsel}, {239, &ppc_fseldot},
{242, &ppc_fmult}, {243, &ppc_fmultdot}, {248, &ppc_fmsub}, {249, &ppc_fmsubdot},
{250, &ppc_fmadd}, {251, &ppc_fmadddot}, {252, &ppc_fnmsub}, {253, &ppc_fnmsubdot},
{254, &ppc_fnmadd}, {255, &ppc_fnmadddot}, {268, &ppc_mtfsfi}, {272, &ppc_fnabs},
{273, &ppc_fnabsdot}, {302, &ppc_fsel}, {303, &ppc_fseldot}, {306, &ppc_fmult},
{307, &ppc_fmultdot}, {312, &ppc_fmsub}, {313, &ppc_fmsubdot}, {314, &ppc_fmadd},
{315, &ppc_fmadddot}, {316, &ppc_fnmsub}, {317, &ppc_fnmsubdot}, {318, &ppc_fnmadd},
{319, &ppc_fnmadddot}, {366, &ppc_fsel}, {367, &ppc_fseldot}, {370, &ppc_fmult},
{371, &ppc_fmultdot}, {376, &ppc_fmsub}, {377, &ppc_fmsubdot}, {378, &ppc_fmadd},
{379, &ppc_fmadddot}, {380, &ppc_fnmsub}, {381, &ppc_fnmsubdot}, {382, &ppc_fnmadd},
{383, &ppc_fnmadddot}, {430, &ppc_fsel}, {431, &ppc_fseldot}, {434, &ppc_fmult},
{435, &ppc_fmultdot}, {440, &ppc_fmsub}, {441, &ppc_fmsubdot}, {442, &ppc_fmadd},
{443, &ppc_fmadddot}, {444, &ppc_fnmsub}, {445, &ppc_fnmsubdot}, {446, &ppc_fnmadd},
{447, &ppc_fnmadddot}, {494, &ppc_fsel}, {495, &ppc_fseldot}, {498, &ppc_fmult},
{499, &ppc_fmultdot}, {504, &ppc_fmsub}, {505, &ppc_fmsubdot}, {506, &ppc_fmadd},
{507, &ppc_fmadddot}, {508, &ppc_fnmsub}, {509, &ppc_fnmsubdot}, {510, &ppc_fnmadd},
{511, &ppc_fnmadddot}, {528, &ppc_fabs}, {529, &ppc_fabsdot}, {536, &ppc_mtfsfidot},
{558, &ppc_fsel}, {559, &ppc_fseldot}, {562, &ppc_fmult}, {563, &ppc_fmultdot},
{568, &ppc_fmsub}, {569, &ppc_fmsubdot}, {570, &ppc_fmadd}, {571, &ppc_fmadddot},
{572, &ppc_fnmsub}, {573, &ppc_fnmsubdot}, {574, &ppc_fnmadd}, {575, &ppc_fnmadddot},
{622, &ppc_fsel}, {623, &ppc_fseldot}, {626, &ppc_fmult}, {627, &ppc_fmultdot},
{632, &ppc_fmsub}, {633, &ppc_fmsubdot}, {634, &ppc_fmadd}, {635, &ppc_fmadddot},
{636, &ppc_fnmsub}, {637, &ppc_fnmsubdot}, {638, &ppc_fnmadd}, {639, &ppc_fnmadddot},
{686, &ppc_fsel}, {687, &ppc_fseldot}, {690, &ppc_fmult}, {691, &ppc_fmultdot},
{696, &ppc_fmsub}, {697, &ppc_fmsubdot}, {698, &ppc_fmadd}, {699, &ppc_fmadddot},
{700, &ppc_fnmsub}, {701, &ppc_fnmsubdot}, {702, &ppc_fnmadd}, {703, &ppc_fnmadddot},
{750, &ppc_fsel}, {751, &ppc_fseldot}, {754, &ppc_fmult}, {755, &ppc_fmultdot},
{760, &ppc_fmsub}, {761, &ppc_fmsubdot}, {762, &ppc_fmadd}, {763, &ppc_fmadddot},
{764, &ppc_fnmsub}, {765, &ppc_fnmsubdot}, {766, &ppc_fnmadd}, {767, &ppc_fnmadddot},
{814, &ppc_fsel}, {815, &ppc_fseldot}, {818, &ppc_fmult}, {819, &ppc_fmultdot},
{824, &ppc_fmsub}, {825, &ppc_fmsubdot}, {826, &ppc_fmadd}, {827, &ppc_fmadddot},
{828, &ppc_fnmsub}, {829, &ppc_fnmsubdot}, {830, &ppc_fnmadd}, {831, &ppc_fnmadddot},
{878, &ppc_fsel}, {879, &ppc_fseldot}, {882, &ppc_fmult}, {883, &ppc_fmultdot},
{888, &ppc_fmsub}, {889, &ppc_fmsubdot}, {890, &ppc_fmadd}, {891, &ppc_fmadddot},
{892, &ppc_fnmsub}, {893, &ppc_fnmsubdot}, {894, &ppc_fnmadd}, {895, &ppc_fnmadddot},
{942, &ppc_fsel}, {943, &ppc_fseldot}, {946, &ppc_fmult}, {947, &ppc_fmultdot},
{952, &ppc_fmsub}, {953, &ppc_fmsubdot}, {954, &ppc_fmadd}, {955, &ppc_fmadddot},
{957, &ppc_fnmsub}, {958, &ppc_fnmsubdot}, {958, &ppc_fnmadd}, {959, &ppc_fnmadddot},
{1006, &ppc_fsel}, {1007, &ppc_fseldot}, {1010, &ppc_fmult}, {1011, &ppc_fmultdot},
{1016, &ppc_fmsub}, {1017, &ppc_fmsubdot}, {1018, &ppc_fmadd}, {1019, &ppc_fmadddot},
{1020, &ppc_fnmsub}, {1021, &ppc_fnmsubdot}, {1022, &ppc_fnmadd}, {1023, &ppc_fnmadddot},
{1070, &ppc_fsel}, {1071, &ppc_fseldot}, {1074, &ppc_fmult}, {1075, &ppc_fmultdot},
{1080, &ppc_fmsub}, {1081, &ppc_fmsubdot}, {1082, &ppc_fmadd}, {1083, &ppc_fmadddot},
{1084, &ppc_fnmsub}, {1085, &ppc_fnmsubdot}, {1086, &ppc_fnmadd}, {1087, &ppc_fnmadddot},
{1134, &ppc_fsel}, {1135, &ppc_fseldot}, {1138, &ppc_fmult}, {1139, &ppc_fmultdot},
{1144, &ppc_fmsub}, {1145, &ppc_fmsubdot}, {1146, &ppc_fmadd}, {1147, &ppc_fmadddot},
{1148, &ppc_fnmsub}, {1149, &ppc_fnmsubdot}, {1150, &ppc_fnmadd}, {1151, &ppc_fnmadddot},
{1166, &ppc_mffs}, {1167, &ppc_mffsdot}, {1198, &ppc_fsel}, {1199, &ppc_fseldot},
{1202, &ppc_fmult}, {1203, &ppc_fmultdot}, {1208, &ppc_fmsub}, {1209, &ppc_fmsubdot},
{1210, &ppc_fmadd}, {1211, &ppc_fmadddot}, {1212, &ppc_fnmsub}, {1213, &ppc_fnmsubdot},
{1214, &ppc_fnmadd}, {1215, &ppc_fnmadddot}, {1262, &ppc_fsel}, {1263, &ppc_fseldot},
{1266, &ppc_fmult}, {1267, &ppc_fmultdot}, {1272, &ppc_fmsub}, {1273, &ppc_fmsubdot},
{1274, &ppc_fmadd}, {1275, &ppc_fmadddot}, {1276, &ppc_fnmsub}, {1277, &ppc_fnmsubdot},
{1278, &ppc_fnmadd}, {1279, &ppc_fnmadddot}, {1326, &ppc_fsel}, {1327, &ppc_fseldot},
{1330, &ppc_fmult}, {1331, &ppc_fmultdot}, {1336, &ppc_fmsub}, {1337, &ppc_fmsubdot},
{1338, &ppc_fmadd}, {1339, &ppc_fmadddot}, {1340, &ppc_fnmsub}, {1341, &ppc_fnmsubdot},
{1342, &ppc_fnmadd}, {1343, &ppc_fnmadddot}, {1390, &ppc_fsel}, {1391, &ppc_fseldot},
{1394, &ppc_fmult}, {1395, &ppc_fmultdot}, {1400, &ppc_fmsub}, {1401, &ppc_fmsubdot},
{1402, &ppc_fmadd}, {1403, &ppc_fmadddot}, {1404, &ppc_fnmsub}, {1405, &ppc_fnmsubdot},
{1406, &ppc_fnmadd}, {1407, &ppc_fnmadddot}, {1422, &ppc_mtfsf}, {1423, &ppc_mtfsfdot},
{1454, &ppc_fsel}, {1455, &ppc_fseldot}, {1458, &ppc_fmult}, {1459, &ppc_fmultdot},
{1464, &ppc_fmsub}, {1465, &ppc_fmsubdot}, {1466, &ppc_fmadd}, {1467, &ppc_fmadddot},
{1468, &ppc_fnmsub}, {1469, &ppc_fnmsubdot}, {1470, &ppc_fnmadd}, {1471, &ppc_fnmadddot},
{1518, &ppc_fsel}, {1519, &ppc_fseldot}, {1522, &ppc_fmult}, {1523, &ppc_fmultdot},
{1528, &ppc_fmsub}, {1529, &ppc_fmsubdot}, {1530, &ppc_fmadd}, {1531, &ppc_fmadddot},
{1532, &ppc_fnmsub}, {1533, &ppc_fnmsubdot}, {1534, &ppc_fnmadd}, {1535, &ppc_fnmadddot},
{1582, &ppc_fsel}, {1583, &ppc_fseldot}, {1586, &ppc_fmult}, {1587, &ppc_fmultdot},
{1592, &ppc_fmsub}, {1593, &ppc_fmsubdot}, {1594, &ppc_fmadd}, {1595, &ppc_fmadddot},
{1596, &ppc_fnmsub}, {1597, &ppc_fnmsubdot}, {1598, &ppc_fnmadd}, {1599, &ppc_fnmadddot},
{1646, &ppc_fsel}, {1647, &ppc_fseldot}, {1650, &ppc_fmult}, {1651, &ppc_fmultdot},
{1656, &ppc_fmsub}, {1657, &ppc_fmsubdot}, {1658, &ppc_fmadd}, {1659, &ppc_fmadddot},
{1660, &ppc_fnmsub}, {1661, &ppc_fnmsubdot}, {1662, &ppc_fnmadd}, {1663, &ppc_fnmadddot},
{1710, &ppc_fsel}, {1711, &ppc_fseldot}, {1714, &ppc_fmult}, {1715, &ppc_fmultdot},
{1720, &ppc_fmsub}, {1721, &ppc_fmsubdot}, {1722, &ppc_fmadd}, {1723, &ppc_fmadddot},
{1724, &ppc_fnmsub}, {1725, &ppc_fnmsubdot}, {1726, &ppc_fnmadd}, {1727, &ppc_fnmadddot},
{1774, &ppc_fsel}, {1775, &ppc_fseldot}, {1778, &ppc_fmult}, {1779, &ppc_fmultdot},
{1784, &ppc_fmsub}, {1785, &ppc_fmsubdot}, {1786, &ppc_fmadd}, {1787, &ppc_fmadddot},
{1788, &ppc_fnmsub}, {1789, &ppc_fnmsubdot}, {1790, &ppc_fnmadd}, {1791, &ppc_fnmadddot},
{1838, &ppc_fsel}, {1839, &ppc_fseldot}, {1842, &ppc_fmult}, {1843, &ppc_fmultdot},
{1848, &ppc_fmsub}, {1849, &ppc_fmsubdot}, {1850, &ppc_fmadd}, {1851, &ppc_fmadddot},
{1852, &ppc_fnmsub}, {1853, &ppc_fnmsubdot}, {1854, &ppc_fnmadd}, {1855, &ppc_fnmadddot},
{1902, &ppc_fsel}, {1903, &ppc_fseldot}, {1906, &ppc_fmult}, {1907, &ppc_fmultdot},
{1912, &ppc_fmsub}, {1913, &ppc_fmsubdot}, {1914, &ppc_fmadd}, {1915, &ppc_fmadddot},
{1916, &ppc_fnmsub}, {1917, &ppc_fnmsubdot}, {1918, &ppc_fnmadd}, {1919, &ppc_fnmadddot},
{1966, &ppc_fsel}, {1967, &ppc_fseldot}, {1970, &ppc_fmult}, {1971, &ppc_fmultdot},
{1976, &ppc_fmsub}, {1977, &ppc_fmsubdot}, {1978, &ppc_fmadd}, {1979, &ppc_fmadddot},
{1980, &ppc_fnmsub}, {1981, &ppc_fnmsubdot}, {1982, &ppc_fnmadd}, {1983, &ppc_fnmadddot},
{2030, &ppc_fsel}, {2031, &ppc_fseldot}, {2034, &ppc_fmult}, {2035, &ppc_fmultdot},
{2040, &ppc_fmsub}, {2041, &ppc_fmsubdot}, {2042, &ppc_fmadd}, {2043, &ppc_fmadddot},
{2044, &ppc_fnmsub}, {2045, &ppc_fnmsubdot}, {2046, &ppc_fnmadd}, {2047, &ppc_fnmadddot}};
PPCOpcode SubOpcode31Grabber[1024] = { ppc_illegalop };
PPCOpcode SubOpcode59Grabber[1024] = { ppc_fpu_off };
PPCOpcode SubOpcode63Grabber[1024] = { ppc_fpu_off };
#define UPDATE_TBR_DEC \
@ -420,22 +117,18 @@ static std::unordered_map<uint16_t, PPCOpcode> SubOpcode63Grabber = {
old_cycles_count += delta << tbr_factor; \
}
/** Exception helpers. */
[[noreturn]] void ppc_illegalop() {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
[[noreturn]] void ppc_fpu_off() {
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::FPU_OFF);
}
/** Opcode decoding functions. */
void ppc_illegalop() {
LOG_F(ERROR, "Illegal opcode reported: 0x%X Report this! \n", ppc_cur_instruction);
exit(-1);
}
void ppc_opcode4() {
LOG_F(INFO, "Reading from Opcode 4 table \n");
uint8_t subop_grab = ppc_cur_instruction & 3;
uint32_t regrab = (uint32_t)subop_grab;
LOG_F(ERROR, "Executing subopcode entry %d \n"
".. or would if I bothered to implement it. SORRY!", regrab);
exit(-1);
}
void ppc_opcode16() {
SubOpcode16Grabber[ppc_cur_instruction & 3]();
}
@ -445,67 +138,92 @@ void ppc_opcode18() {
}
void ppc_opcode19() {
uint16_t subop_grab = ppc_cur_instruction & 2047;
uint16_t subop_grab = ppc_cur_instruction & 0x7FF;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
LOG_F(INFO, "Executing Opcode 19 table subopcode entry \n", regrab);
if (SubOpcode19Grabber.count(subop_grab) == 1) {
SubOpcode19Grabber[subop_grab]();
} else {
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
}
#else
SubOpcode19Grabber[subop_grab]();
#endif // EXHAUSTIVE_DEBUG
if (subop_grab == 32) {
ppc_bclr();
} else if (subop_grab == 33) {
ppc_bclrl();
} else if (subop_grab == 1056) {
ppc_bcctr();
} else if (subop_grab == 1057) {
ppc_bcctrl();
} else {
switch (subop_grab) {
case 66:
ppc_crnor();
break;
case 100:
ppc_rfi();
break;
case 258:
ppc_crandc();
break;
case 300:
ppc_isync();
break;
case 386:
ppc_crxor();
break;
case 450:
ppc_crnand();
break;
case 514:
ppc_crand();
break;
case 578:
ppc_creqv();
break;
case 834:
ppc_crorc();
break;
case 898:
ppc_cror();
break;
default:
ppc_illegalop();
}
}
}
void ppc_opcode31() {
uint16_t subop_grab = ppc_cur_instruction & 2047;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
LOG_F(INFO, "Executing Opcode 31 table subopcode entry \n", regrab);
if (SubOpcode31Grabber.count(subop_grab) == 1) {
SubOpcode31Grabber[subop_grab]();
} else {
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
}
#else
SubOpcode31Grabber[subop_grab]();
#endif // EXHAUSTIVE_DEBUG
}
uint16_t subop_grab = (ppc_cur_instruction & 0x7FF) >> 1;
void ppc_opcode59() {
uint16_t subop_grab = ppc_cur_instruction & 2047;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
LOG_F(INFO, "Executing Opcode 59 table subopcode entry \n", regrab);
if (SubOpcode59Grabber.count(subop_grab) == 1) {
SubOpcode59Grabber[subop_grab]();
} else {
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
}
#else
SubOpcode59Grabber[subop_grab]();
#endif // EXHAUSTIVE_DEBUG
}
rc_flag = ppc_cur_instruction & 0x1;
oe_flag = ppc_cur_instruction & 0x400;
void ppc_opcode63() {
uint16_t subop_grab = ppc_cur_instruction & 2047;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
LOG_F(INFO, "Executing Opcode 63 table subopcode entry \n", regrab);
if (SubOpcode63Grabber.count(subop_grab) == 1) {
SubOpcode63Grabber[subop_grab]();
} else {
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
}
#else
SubOpcode63Grabber[subop_grab]();
#endif // EXHAUSTIVE_DEBUG
SubOpcode31Grabber[subop_grab]();
}
void ppc_opcode59() {
uint16_t subop_grab = (ppc_cur_instruction & 0x7FF) >> 1;
rc_flag = subop_grab & 1;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
LOG_F(INFO, "Executing Opcode 59 table subopcode entry \n", regrab);
#endif // EXHAUSTIVE_DEBUG
SubOpcode59Grabber[subop_grab]();
}
void ppc_opcode63() {
uint16_t subop_grab = (ppc_cur_instruction & 0x7FF) >> 1;
rc_flag = subop_grab & 1;
#ifdef EXHAUSTIVE_DEBUG
uint32_t regrab = (uint32_t)subop_grab;
LOG_F(INFO, "Executing Opcode 63 table subopcode entry \n", regrab);
#endif // EXHAUSTIVE_DEBUG
SubOpcode63Grabber[subop_grab]();
}
/* Dispatch using main opcode */
@ -610,7 +328,7 @@ void ppc_exec_single()
}
/** Execute PPC code until goal_addr is reached. */
void ppc_exec_until(uint32_t goal_addr)
void ppc_exec_until(volatile uint32_t goal_addr)
{
uint32_t bb_start_la, page_start, delta;
uint8_t* pc_real;
@ -669,6 +387,68 @@ again:
}
}
/** Execute PPC code until control is reached the specified region. */
void ppc_exec_dbg(volatile uint32_t start_addr, volatile uint32_t size)
{
uint32_t bb_start_la, page_start, delta;
uint8_t* pc_real;
/* start new basic block */
glob_bb_start_la = bb_start_la = ppc_state.pc;
bb_kind = BB_end_kind::BB_NONE;
if (setjmp(exc_env)) {
/* reaching here means we got a low-level exception */
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
UPDATE_TBR_DEC
#else
timebase_counter += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
#endif
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
pc_real = quickinstruction_translate(bb_start_la);
page_start = bb_start_la & 0xFFFFF000;
ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE;
//printf("DBG Exec: got exception, continue at %X\n", ppc_state.pc);
goto again;
}
/* initial MMU translation for the current code page. */
pc_real = quickinstruction_translate(bb_start_la);
/* set current code page limits */
page_start = bb_start_la & 0xFFFFF000;
again:
while (ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size) {
ppc_main_opcode();
if (bb_kind != BB_end_kind::BB_NONE) {
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count += ((ppc_state.pc - bb_start_la) >> 2) + 1;
UPDATE_TBR_DEC
#else
timebase_counter += ((ppc_state.pc - bb_start_la) >> 2) + 1;
#endif
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
page_start = bb_start_la & 0xFFFFF000;
pc_real = quickinstruction_translate(bb_start_la);
} else {
pc_real += (int)bb_start_la - (int)ppc_state.pc;
ppc_set_cur_instruction(pc_real);
}
ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE;
//printf("DBG Exec: new basic block at %X, start_addr=%X\n", ppc_state.pc, start_addr);
} else {
ppc_state.pc += 4;
pc_real += 4;
ppc_set_cur_instruction(pc_real);
}
}
}
uint64_t instr_count, old_instr_count;
@ -704,6 +484,209 @@ void test_timebase_update()
}
void initialize_ppc_opcode_tables() {
SubOpcode31Grabber[0] = ppc_cmp;
SubOpcode31Grabber[4] = ppc_tw;
SubOpcode31Grabber[32] = ppc_cmpl;
SubOpcode31Grabber[8] = SubOpcode31Grabber[520] = ppc_subfc;
SubOpcode31Grabber[40] = SubOpcode31Grabber[552] = ppc_subf;
SubOpcode31Grabber[104] = SubOpcode31Grabber[616] = ppc_neg;
SubOpcode31Grabber[136] = SubOpcode31Grabber[648] = ppc_subfe;
SubOpcode31Grabber[200] = SubOpcode31Grabber[712] = ppc_subfze;
SubOpcode31Grabber[232] = SubOpcode31Grabber[744] = ppc_subfme;
SubOpcode31Grabber[10] = SubOpcode31Grabber[522] = ppc_addc;
SubOpcode31Grabber[138] = SubOpcode31Grabber[650] = ppc_adde;
SubOpcode31Grabber[202] = SubOpcode31Grabber[714] = ppc_addze;
SubOpcode31Grabber[234] = SubOpcode31Grabber[746] = ppc_addme;
SubOpcode31Grabber[266] = SubOpcode31Grabber[778] = ppc_add;
SubOpcode31Grabber[11] = ppc_mulhwu;
SubOpcode31Grabber[75] = ppc_mulhw;
SubOpcode31Grabber[235] = SubOpcode31Grabber[747] = ppc_mullw;
SubOpcode31Grabber[459] = SubOpcode31Grabber[971] = ppc_divwu;
SubOpcode31Grabber[491] = SubOpcode31Grabber[1003] = ppc_divw;
SubOpcode31Grabber[20] = ppc_lwarx;
SubOpcode31Grabber[23] = ppc_lwzx;
SubOpcode31Grabber[55] = ppc_lwzux;
SubOpcode31Grabber[87] = ppc_lbzx;
SubOpcode31Grabber[119] = ppc_lbzux;
SubOpcode31Grabber[279] = ppc_lhzx;
SubOpcode31Grabber[311] = ppc_lhzux;
SubOpcode31Grabber[343] = ppc_lhax;
SubOpcode31Grabber[375] = ppc_lhaux;
SubOpcode31Grabber[533] = ppc_lswx;
SubOpcode31Grabber[534] = ppc_lwbrx;
SubOpcode31Grabber[535] = ppc_lfsx;
SubOpcode31Grabber[567] = ppc_lfsux;
SubOpcode31Grabber[597] = ppc_lswi;
SubOpcode31Grabber[599] = ppc_lfdx;
SubOpcode31Grabber[631] = ppc_lfdux;
SubOpcode31Grabber[790] = ppc_lhbrx;
SubOpcode31Grabber[150] = ppc_stwcx;
SubOpcode31Grabber[151] = ppc_stwx;
SubOpcode31Grabber[183] = ppc_stwux;
SubOpcode31Grabber[215] = ppc_stbx;
SubOpcode31Grabber[247] = ppc_stbux;
SubOpcode31Grabber[407] = ppc_sthx;
SubOpcode31Grabber[439] = ppc_sthux;
SubOpcode31Grabber[661] = ppc_stswx;
SubOpcode31Grabber[662] = ppc_stwbrx;
SubOpcode31Grabber[663] = ppc_stfsx;
SubOpcode31Grabber[695] = ppc_stfsux;
SubOpcode31Grabber[725] = ppc_stswi;
SubOpcode31Grabber[727] = ppc_stfdx;
SubOpcode31Grabber[759] = ppc_stfdux;
SubOpcode31Grabber[918] = ppc_sthbrx;
SubOpcode31Grabber[983] = ppc_stfiwx;
SubOpcode31Grabber[24] = ppc_slw;
SubOpcode31Grabber[28] = ppc_and;
SubOpcode31Grabber[60] = ppc_andc;
SubOpcode31Grabber[124] = ppc_nor;
SubOpcode31Grabber[284] = ppc_eqv;
SubOpcode31Grabber[316] = ppc_xor;
SubOpcode31Grabber[412] = ppc_orc;
SubOpcode31Grabber[444] = ppc_or;
SubOpcode31Grabber[476] = ppc_nand;
SubOpcode31Grabber[536] = ppc_srw;
SubOpcode31Grabber[792] = ppc_sraw;
SubOpcode31Grabber[824] = ppc_srawi;
SubOpcode31Grabber[922] = ppc_extsh;
SubOpcode31Grabber[954] = ppc_extsb;
SubOpcode31Grabber[26] = ppc_cntlzw;
SubOpcode31Grabber[19] = ppc_mfcr;
SubOpcode31Grabber[83] = ppc_mfmsr;
SubOpcode31Grabber[144] = ppc_mtcrf;
SubOpcode31Grabber[146] = ppc_mtmsr;
SubOpcode31Grabber[210] = ppc_mtsr;
SubOpcode31Grabber[242] = ppc_mtsrin;
SubOpcode31Grabber[339] = ppc_mfspr;
SubOpcode31Grabber[371] = ppc_mftb;
SubOpcode31Grabber[467] = ppc_mtspr;
SubOpcode31Grabber[512] = ppc_mcrxr;
SubOpcode31Grabber[595] = ppc_mfsr;
SubOpcode31Grabber[659] = ppc_mfsrin;
SubOpcode31Grabber[54] = ppc_dcbst;
SubOpcode31Grabber[86] = ppc_dcbf;
SubOpcode31Grabber[246] = ppc_dcbtst;
SubOpcode31Grabber[278] = ppc_dcbt;
SubOpcode31Grabber[598] = ppc_sync;
SubOpcode31Grabber[470] = ppc_dcbi;
SubOpcode31Grabber[1014] = ppc_dcbz;
SubOpcode31Grabber[29] = power_maskg;
SubOpcode31Grabber[107] = SubOpcode31Grabber[619] = power_mul;
SubOpcode31Grabber[152] = power_slq;
SubOpcode31Grabber[153] = power_sle;
SubOpcode31Grabber[184] = power_sliq;
SubOpcode31Grabber[216] = power_sllq;
SubOpcode31Grabber[217] = power_sleq;
SubOpcode31Grabber[248] = power_slliq;
SubOpcode31Grabber[264] = SubOpcode31Grabber[776] = power_doz;
SubOpcode31Grabber[277] = power_lscbx;
SubOpcode31Grabber[331] = SubOpcode31Grabber[843] = power_div;
SubOpcode31Grabber[360] = SubOpcode31Grabber[872] = power_abs;
SubOpcode31Grabber[363] = SubOpcode31Grabber[875] = power_divs;
SubOpcode31Grabber[488] = SubOpcode31Grabber[1000] = power_nabs;
SubOpcode31Grabber[531] = power_clcs;
SubOpcode31Grabber[537] = power_rrib;
SubOpcode31Grabber[541] = power_maskir;
SubOpcode31Grabber[664] = power_srq;
SubOpcode31Grabber[665] = power_sre;
SubOpcode31Grabber[696] = power_sriq;
SubOpcode31Grabber[728] = power_srlq;
SubOpcode31Grabber[729] = power_sreq;
SubOpcode31Grabber[760] = power_srliq;
SubOpcode31Grabber[920] = power_sraq;
SubOpcode31Grabber[921] = power_srea;
SubOpcode31Grabber[952] = power_sraiq;
SubOpcode31Grabber[306] = ppc_tlbie;
SubOpcode31Grabber[370] = ppc_tlbia;
SubOpcode31Grabber[566] = ppc_tlbsync;
SubOpcode31Grabber[854] = ppc_eieio;
SubOpcode31Grabber[982] = ppc_icbi;
SubOpcode31Grabber[978] = ppc_tlbld;
SubOpcode31Grabber[1010] = ppc_tlbli;
SubOpcode59Grabber[18] = ppc_fdivs;
SubOpcode59Grabber[20] = ppc_fsubs;
SubOpcode59Grabber[22] = ppc_fsqrts;
SubOpcode59Grabber[24] = ppc_fres;
for (int i = 25; i < 1024; i += 32) {
SubOpcode59Grabber[i] = ppc_fmults;
}
for (int i = 28; i < 1024; i += 32) {
SubOpcode59Grabber[i] = ppc_fmsubs;
}
for (int i = 29; i < 1024; i += 32) {
SubOpcode59Grabber[i] = ppc_fmadds;
}
for (int i = 30; i < 1024; i += 32) {
SubOpcode59Grabber[i] = ppc_fnmsubs;
}
for (int i = 31; i < 1024; i += 32) {
SubOpcode59Grabber[i] = ppc_fnmadds;
}
SubOpcode63Grabber[0] = ppc_fcmpu;
SubOpcode63Grabber[12] = ppc_frsp;
SubOpcode63Grabber[14] = ppc_fctiw;
SubOpcode63Grabber[15] = ppc_fctiwz;
SubOpcode63Grabber[18] = ppc_fdiv;
SubOpcode63Grabber[20] = ppc_fsub;
SubOpcode63Grabber[21] = ppc_fadd;
SubOpcode63Grabber[22] = ppc_fsqrt;
SubOpcode63Grabber[26] = ppc_frsqrte;
SubOpcode63Grabber[32] = ppc_fcmpo;
SubOpcode63Grabber[38] = ppc_mtfsb1;
SubOpcode63Grabber[40] = ppc_fneg;
SubOpcode63Grabber[64] = ppc_mcrfs;
SubOpcode63Grabber[70] = ppc_mtfsb0;
SubOpcode63Grabber[72] = ppc_fmr;
SubOpcode63Grabber[134] = ppc_mtfsfi;
SubOpcode63Grabber[136] = ppc_fnabs;
SubOpcode63Grabber[264] = ppc_fabs;
SubOpcode63Grabber[583] = ppc_mffs;
SubOpcode63Grabber[711] = ppc_mtfsf;
for (int i = 23; i < 1024; i += 32) {
SubOpcode63Grabber[i] = ppc_fsel;
}
for (int i = 25; i < 1024; i += 32) {
SubOpcode63Grabber[i] = ppc_fmult;
}
for (int i = 28; i < 1024; i += 32) {
SubOpcode63Grabber[i] = ppc_fmsub;
}
for (int i = 29; i < 1024; i += 32) {
SubOpcode63Grabber[i] = ppc_fmadd;
}
for (int i = 30; i < 1024; i += 32) {
SubOpcode63Grabber[i] = ppc_fnmsub;
}
for (int i = 31; i < 1024; i += 32) {
SubOpcode63Grabber[i] = ppc_fnmadd;
}
}
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t proc_version) {
int i;
@ -711,6 +694,8 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t proc_version) {
//test_timebase_update();
initialize_ppc_opcode_tables();
/* initialize timer variables */
#ifdef NEW_TBR_UPDATE_ALGO
cycles_count = 0;

View File

@ -371,73 +371,43 @@ void ppc_changecrf1() {
}
// Floating Point Arithmetic
void ppc_fadd() {
void dppc_interpreter::ppc_fadd() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 58)) {
ppc_dblresult64_d = ppc_dblresult64_a + ppc_dblresult64_b;
ppc_store_dfpresult(false);
}
if (rc_flag)
ppc_changecrf1();
}
void ppc_fadddot() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 58)) {
ppc_dblresult64_d = ppc_dblresult64_a + ppc_dblresult64_b;
ppc_store_dfpresult(false);
}
ppc_changecrf1();
}
void ppc_fsub() {
void dppc_interpreter::ppc_fsub() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 56)) {
ppc_dblresult64_d = ppc_dblresult64_a - ppc_dblresult64_b;
ppc_store_dfpresult(false);
}
if (rc_flag)
ppc_changecrf1();
}
void ppc_fsubdot() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 56)) {
ppc_dblresult64_d = ppc_dblresult64_a - ppc_dblresult64_b;
ppc_store_dfpresult(false);
}
ppc_changecrf1();
}
void ppc_fdiv() {
void dppc_interpreter::ppc_fdiv() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 36)) {
ppc_dblresult64_d = ppc_dblresult64_a / ppc_dblresult64_b;
ppc_store_dfpresult(false);
}
if (rc_flag)
ppc_changecrf1();
}
void ppc_fdivdot() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 36)) {
ppc_dblresult64_d = ppc_dblresult64_a / ppc_dblresult64_b;
ppc_store_dfpresult(false);
}
ppc_changecrf1();
}
void ppc_fmult() {
ppc_grab_regsfpdac(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 50)) {
ppc_dblresult64_d = ppc_dblresult64_a * ppc_dblresult64_b;
ppc_store_dfpresult(false);
}
}
void ppc_fmultdot() {
void dppc_interpreter::ppc_fmult() {
ppc_grab_regsfpdac(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 50)) {
@ -445,10 +415,11 @@ void ppc_fmultdot() {
ppc_store_dfpresult(false);
}
ppc_changecrf1();
if (rc_flag)
ppc_changecrf1();
}
void ppc_fmadd() {
void dppc_interpreter::ppc_fmadd() {
ppc_grab_regsfpdabc(false);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
@ -459,23 +430,12 @@ void ppc_fmadd() {
}
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fmadddot() {
ppc_grab_regsfpdabc(false);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
ppc_dblresult64_d = (ppc_dblresult64_a * ppc_dblresult64_c);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 58)) {
ppc_dblresult64_d += ppc_dblresult64_b;
}
}
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fmsub() {
void dppc_interpreter::ppc_fmsub() {
ppc_grab_regsfpdabc(false);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
@ -486,23 +446,12 @@ void ppc_fmsub() {
}
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fmsubdot() {
ppc_grab_regsfpdabc(false);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
ppc_dblresult64_d = (ppc_dblresult64_a * ppc_dblresult64_c);
if (!ppc_confirm_inf_nan(reg_d, reg_b, false, 56)) {
ppc_dblresult64_d -= ppc_dblresult64_b;
}
}
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fnmadd() {
void dppc_interpreter::ppc_fnmadd() {
ppc_grab_regsfpdabc(false);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
@ -514,25 +463,12 @@ void ppc_fnmadd() {
ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fnmadddot() {
ppc_grab_regsfpdabc(false);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
ppc_dblresult64_d = (ppc_dblresult64_a * ppc_dblresult64_c);
if (!ppc_confirm_inf_nan(reg_a, reg_b, false, 58)) {
ppc_dblresult64_d += ppc_dblresult64_b;
}
}
ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fnmsub() {
void dppc_interpreter::ppc_fnmsub() {
ppc_grab_regsfpdabc(false);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
@ -544,34 +480,12 @@ void ppc_fnmsub() {
ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fnmsubdot() {
ppc_grab_regsfpdabc(false);
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
ppc_dblresult64_d = (ppc_dblresult64_a * ppc_dblresult64_c);
if (!ppc_confirm_inf_nan(reg_d, reg_b, false, 56)) {
ppc_dblresult64_d -= ppc_dblresult64_b;
}
}
ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fadds() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) {
float intermediate = (float)ppc_dblresult64_a + (float)ppc_dblresult64_b;
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_dfpresult(false);
}
}
void ppc_faddsdot() {
void dppc_interpreter::ppc_fadds() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) {
@ -580,20 +494,11 @@ void ppc_faddsdot() {
ppc_store_dfpresult(false);
}
ppc_changecrf1();
if (rc_flag)
ppc_changecrf1();
}
void ppc_fsubs() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 56)) {
float intermediate = (float)ppc_dblresult64_a - (float)ppc_dblresult64_b;
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_dfpresult(false);
}
}
void ppc_fsubsdot() {
void dppc_interpreter::ppc_fsubs() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 56)) {
@ -602,10 +507,11 @@ void ppc_fsubsdot() {
ppc_store_dfpresult(false);
}
ppc_changecrf1();
if (rc_flag)
ppc_changecrf1();
}
void ppc_fmults() {
void dppc_interpreter::ppc_fmults() {
ppc_grab_regsfpdac(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 50)) {
@ -613,30 +519,12 @@ void ppc_fmults() {
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_dfpresult(false);
}
if (rc_flag)
ppc_changecrf1();
}
void ppc_fmultsdot() {
ppc_grab_regsfpdac(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 50)) {
float intermediate = (float)ppc_dblresult64_a * (float)ppc_dblresult64_b;
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_dfpresult(false);
}
ppc_changecrf1();
}
void ppc_fdivs() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 36)) {
float intermediate = (float)ppc_dblresult64_a / (float)ppc_dblresult64_b;
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_dfpresult(false);
}
}
void ppc_fdivsdot() {
void dppc_interpreter::ppc_fdivs() {
ppc_grab_regsfpdab(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 36)) {
@ -645,26 +533,11 @@ void ppc_fdivsdot() {
ppc_store_dfpresult(false);
}
ppc_changecrf1();
if (rc_flag)
ppc_changecrf1();
}
void ppc_fmadds() {
ppc_grab_regsfpdabc(false);
float intermediate;
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) {
intermediate = (float)ppc_dblresult64_a * (float)ppc_dblresult64_c;
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) {
intermediate += (float)ppc_dblresult64_b;
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_dfpresult(false);
}
}
}
void ppc_fmaddsdot() {
void dppc_interpreter::ppc_fmadds() {
ppc_grab_regsfpdabc(false);
float intermediate;
@ -679,26 +552,11 @@ void ppc_fmaddsdot() {
}
}
ppc_changecrf1();
if (rc_flag)
ppc_changecrf1();
}
void ppc_fmsubs() {
ppc_grab_regsfpdabc(false);
float intermediate;
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
intermediate = (float)ppc_dblresult64_a * (float)ppc_dblresult64_c;
if (!ppc_confirm_inf_nan(reg_d, reg_b, false, 56)) {
intermediate -= (float)ppc_dblresult64_b;
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_dfpresult(false);
}
}
}
void ppc_fmsubsdot() {
void dppc_interpreter::ppc_fmsubs() {
ppc_grab_regsfpdabc(false);
float intermediate;
@ -713,28 +571,11 @@ void ppc_fmsubsdot() {
}
}
ppc_changecrf1();
if (rc_flag)
ppc_changecrf1();
}
void ppc_fnmadds() {
ppc_grab_regsfpdabc(false);
float intermediate;
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) {
intermediate = (float)ppc_dblresult64_a * (float)ppc_dblresult64_c;
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) {
intermediate += (float)ppc_dblresult64_b;
intermediate = -intermediate;
ppc_dblresult64_d = static_cast<double>(intermediate);
}
}
ppc_store_dfpresult(false);
}
void ppc_fnmaddsdot() {
void dppc_interpreter::ppc_fnmadds() {
ppc_grab_regsfpdabc(false);
float intermediate;
@ -751,10 +592,11 @@ void ppc_fnmaddsdot() {
}
}
ppc_changecrf1();
if (rc_flag)
ppc_changecrf1();
}
void ppc_fnmsubs() {
void dppc_interpreter::ppc_fnmsubs() {
ppc_grab_regsfpdabc(false);
float intermediate;
@ -770,81 +612,46 @@ void ppc_fnmsubs() {
ppc_store_dfpresult(false);
}
}
if (rc_flag)
ppc_changecrf1();
}
void ppc_fnmsubsdot() {
ppc_grab_regsfpdabc(false);
float intermediate;
if (!ppc_confirm_inf_nan(reg_a, reg_c, false, 50)) {
intermediate = (float)ppc_dblresult64_a * (float)ppc_dblresult64_c;
if (!ppc_confirm_inf_nan(reg_d, reg_b, false, 56)) {
intermediate -= (float)ppc_dblresult64_b;
intermediate = -intermediate;
ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_dfpresult(false);
}
}
ppc_changecrf1();
}
void ppc_fabs() {
void dppc_interpreter::ppc_fabs() {
ppc_grab_regsfpdb(false);
ppc_dblresult64_d = abs(ppc_dblresult64_b);
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fabsdot() {
ppc_grab_regsfpdb(false);
ppc_dblresult64_d = abs(ppc_dblresult64_b);
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fnabs() {
void dppc_interpreter::ppc_fnabs() {
ppc_grab_regsfpdb(false);
ppc_dblresult64_d = abs(ppc_dblresult64_b);
ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fnabsdot() {
ppc_grab_regsfpdb(false);
ppc_dblresult64_d = abs(ppc_dblresult64_b);
ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fneg() {
void dppc_interpreter::ppc_fneg() {
ppc_grab_regsfpdb(false);
ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fnegdot() {
ppc_grab_regsfpdb(false);
ppc_dblresult64_d = -ppc_dblresult64_d;
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fsel() {
void dppc_interpreter::ppc_fsel() {
ppc_grab_regsfpdabc(false);
if (ppc_dblresult64_a >= 0.0) {
@ -854,35 +661,21 @@ void ppc_fsel() {
}
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fseldot() {
ppc_grab_regsfpdabc(false);
if (ppc_dblresult64_a >= 0.0) {
ppc_dblresult64_d = ppc_dblresult64_c;
} else {
ppc_dblresult64_d = ppc_dblresult64_b;
}
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fsqrt() {
void dppc_interpreter::ppc_fsqrt() {
ppc_grab_regsfpdb(false);
ppc_dblresult64_d = std::sqrt(ppc_dblresult64_b);
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fsqrtdot() {
ppc_grab_regsfpdb(false);
ppc_dblresult64_d = std::sqrt(ppc_dblresult64_b);
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fsqrts() {
void dppc_interpreter::ppc_fsqrts() {
ppc_grab_regsfpdb(true);
uint32_t test = (uint32_t)ppc_result64_b;
test += 127 << 23;
@ -890,20 +683,12 @@ void ppc_fsqrts() {
uint64_t* pre_final = (uint64_t*)&test;
ppc_result64_d = *pre_final;
ppc_store_dfpresult(true);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fsqrtsdot() {
ppc_grab_regsfpdb(true);
uint32_t test = (uint32_t)ppc_result64_b;
test += 127 << 23;
test >>= 1;
uint64_t* pre_final = (uint64_t*)&test;
ppc_result64_d = *pre_final;
ppc_store_dfpresult(true);
ppc_changecrf1();
}
void ppc_frsqrte() {
void dppc_interpreter::ppc_frsqrte() {
ppc_grab_regsfpdb(false);
double testd2 = (double)ppc_result64_b;
for (int i = 0; i < 10; i++) {
@ -912,55 +697,34 @@ void ppc_frsqrte() {
ppc_dblresult64_d = testd2;
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_frsqrtedot() {
ppc_grab_regsfpdb(false);
double testd2 = (double)ppc_result64_b;
for (int i = 0; i < 10; i++) {
testd2 = testd2 * (1.5 - (testd2 * .5) * testd2 * testd2);
}
ppc_dblresult64_d = testd2;
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_frsp() {
void dppc_interpreter::ppc_frsp() {
ppc_grab_regsfpdb(false);
double testd2 = (double)ppc_result64_b;
float testf2 = (float)testd2;
ppc_dblresult64_d = (double)testf2;
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_frspdot() {
ppc_grab_regsfpdb(false);
double testd2 = (double)ppc_result64_b;
float testf2 = (float)testd2;
ppc_dblresult64_d = (double)testf2;
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fres() {
void dppc_interpreter::ppc_fres() {
ppc_grab_regsfpdb(false);
float testf2 = (float)ppc_dblresult64_b;
testf2 = 1 / testf2;
ppc_dblresult64_d = (double)testf2;
ppc_store_dfpresult(false);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fresdot() {
ppc_grab_regsfpdb(false);
float testf2 = (float)ppc_dblresult64_b;
testf2 = 1 / testf2;
ppc_dblresult64_d = (double)testf2;
ppc_store_dfpresult(false);
ppc_changecrf1();
}
void ppc_fctiw() {
void dppc_interpreter::ppc_fctiw() {
ppc_grab_regsfpdb(false);
switch (ppc_state.fpscr & 0x3) {
@ -975,44 +739,24 @@ void ppc_fctiw() {
}
ppc_store_dfpresult(true);
if (rc_flag)
ppc_changecrf1();
}
void ppc_fctiwdot() {
ppc_grab_regsfpdb(false);
switch (ppc_state.fpscr & 0x3) {
case 0:
ppc_result64_d = round_to_nearest(ppc_dblresult64_b);
case 1:
ppc_result64_d = round_to_zero(ppc_dblresult64_b);
case 2:
ppc_result64_d = round_to_pos_inf(ppc_dblresult64_b);
case 3:
ppc_result64_d = round_to_neg_inf(ppc_dblresult64_b);
}
ppc_store_dfpresult(true);
ppc_changecrf1();
}
void ppc_fctiwz() {
void dppc_interpreter::ppc_fctiwz() {
ppc_grab_regsfpdb(false);
ppc_result64_d = round_to_zero(ppc_dblresult64_b);
ppc_store_result_regd();
}
void ppc_fctiwzdot() {
ppc_grab_regsfpdb(false);
ppc_result64_d = round_to_zero(ppc_dblresult64_b);
ppc_store_result_regd();
ppc_changecrf1();
if (rc_flag)
ppc_changecrf1();
}
// Floating Point Store and Load
void ppc_lfs() {
void dppc_interpreter::ppc_lfs() {
ppc_grab_regsfpdia(true);
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
@ -1021,9 +765,9 @@ void ppc_lfs() {
}
void ppc_lfsu() {
void dppc_interpreter::ppc_lfsu() {
ppc_grab_regsfpdia(true);
if (reg_a == 0) {
if (reg_a != 0) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
@ -1031,31 +775,31 @@ void ppc_lfsu() {
ppc_store_dfpresult(true);
ppc_store_result_rega();
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void ppc_lfsx() {
void dppc_interpreter::ppc_lfsx() {
ppc_grab_regsfpdiab(true);
ppc_effective_address = (reg_a == 0) ? ppc_result_b : ppc_result_a + ppc_result_b;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_store_dfpresult(true);
}
void ppc_lfsux() {
void dppc_interpreter::ppc_lfsux() {
ppc_grab_regsfpdiab(true);
if (reg_a == 0) {
if (reg_a != 0) {
ppc_effective_address = ppc_result_a + ppc_result_b;
ppc_result64_d = mem_grab_dword(ppc_effective_address);
ppc_result_a = ppc_effective_address;
ppc_store_dfpresult(true);
ppc_store_result_rega();
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void ppc_lfd() {
void dppc_interpreter::ppc_lfd() {
ppc_grab_regsfpdia(true);
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
@ -1063,9 +807,9 @@ void ppc_lfd() {
ppc_store_dfpresult(true);
}
void ppc_lfdu() {
void dppc_interpreter::ppc_lfdu() {
ppc_grab_regsfpdia(true);
if (reg_a == 0) {
if (reg_a != 0) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += ppc_result_a;
ppc_result64_d = mem_grab_qword(ppc_effective_address);
@ -1073,107 +817,107 @@ void ppc_lfdu() {
ppc_result_a = ppc_effective_address;
ppc_store_result_rega();
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void ppc_lfdx() {
void dppc_interpreter::ppc_lfdx() {
ppc_grab_regsfpdia(true);
ppc_effective_address += (reg_a > 0) ? ppc_result_a + ppc_result_b : ppc_result_b;
ppc_effective_address = (reg_a > 0) ? ppc_result_a + ppc_result_b : ppc_result_b;
ppc_result64_d = mem_grab_qword(ppc_effective_address);
ppc_store_dfpresult(true);
}
void ppc_lfdux() {
void dppc_interpreter::ppc_lfdux() {
ppc_grab_regsfpdiab(true);
if (reg_a == 0) {
if (reg_a != 0) {
ppc_effective_address = ppc_result_a + ppc_result_b;
ppc_result64_d = mem_grab_qword(ppc_effective_address);
ppc_store_dfpresult(true);
ppc_result_a = ppc_effective_address;
ppc_store_result_rega();
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void ppc_stfs() {
void dppc_interpreter::ppc_stfs() {
ppc_grab_regsfpsia(true);
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, uint32_t(ppc_state.fpr[reg_s].int64_r));
}
void ppc_stfsu() {
void dppc_interpreter::ppc_stfsu() {
ppc_grab_regsfpsia(true);
if (reg_a == 0) {
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, uint32_t(ppc_state.fpr[reg_s].int64_r));
ppc_result_a = ppc_effective_address;
ppc_store_result_rega();
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void ppc_stfsx() {
void dppc_interpreter::ppc_stfsx() {
ppc_grab_regsfpsiab(true);
ppc_effective_address = (reg_a == 0) ? ppc_result_b : ppc_result_a + ppc_result_b;
mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
}
void ppc_stfsux() {
void dppc_interpreter::ppc_stfsux() {
ppc_grab_regsfpsiab(true);
if (reg_a == 0) {
if (reg_a != 0) {
ppc_effective_address = ppc_result_a + ppc_result_b;
mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
ppc_result_a = ppc_effective_address;
ppc_store_result_rega();
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void ppc_stfd() {
void dppc_interpreter::ppc_stfd() {
ppc_grab_regsfpsia(true);
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
}
void ppc_stfdu() {
void dppc_interpreter::ppc_stfdu() {
ppc_grab_regsfpsia(true);
if (reg_a == 0) {
if (reg_a != 0) {
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += ppc_result_a;
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
ppc_result_a = ppc_effective_address;
ppc_store_result_rega();
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void ppc_stfdx() {
void dppc_interpreter::ppc_stfdx() {
ppc_grab_regsfpsiab(true);
ppc_effective_address = (reg_a == 0) ? ppc_result_b : ppc_result_a + ppc_result_b;
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
}
void ppc_stfdux() {
void dppc_interpreter::ppc_stfdux() {
ppc_grab_regsfpsiab(true);
if (reg_a == 0) {
if (reg_a != 0) {
ppc_effective_address = ppc_result_a + ppc_result_b;
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
ppc_result_a = ppc_effective_address;
ppc_store_result_rega();
} else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
ppc_exception_handler(Except_Type::EXC_PROGRAM, Exc_Cause::ILLEGAL_OP);
}
}
void ppc_stfiwx() {
void dppc_interpreter::ppc_stfiwx() {
ppc_grab_regsfpsiab(true);
ppc_effective_address = (reg_a == 0) ? ppc_result_b : ppc_result_a + ppc_result_b;
mem_write_dword(ppc_effective_address, (uint32_t)(ppc_state.fpr[reg_s].int64_r));
@ -1181,14 +925,14 @@ void ppc_stfiwx() {
// Floating Point Register Transfer
void ppc_fmr() {
void dppc_interpreter::ppc_fmr() {
ppc_grab_regsfpdb(true);
ppc_state.fpr[reg_d] = ppc_state.fpr[reg_b];
ppc_store_dfpresult(true);
}
void ppc_mffs() {
void dppc_interpreter::ppc_mffs() {
ppc_grab_regsda();
uint64_t fpstore1 = ppc_state.fpr[reg_d].int64_r & 0xFFFFFFFF00000000;
uint64_t fpstore2 = ppc_state.fpscr & 0x00000000FFFFFFFF;
@ -1196,7 +940,7 @@ void ppc_mffs() {
fp_save_uint64(fpstore1);
}
void ppc_mffsdot() {
void dppc_interpreter::ppc_mffsdot() {
ppc_grab_regsda();
uint64_t fpstore1 = ppc_state.fpr[reg_d].int64_r & 0xFFFFFFFF00000000;
uint64_t fpstore2 = ppc_state.fpscr & 0x00000000FFFFFFFF;
@ -1205,7 +949,7 @@ void ppc_mffsdot() {
ppc_fp_changecrf1();
}
void ppc_mtfsf() {
void dppc_interpreter::ppc_mtfsf() {
reg_b = (ppc_cur_instruction >> 11) & 31;
uint32_t fm_mask = (ppc_cur_instruction >> 17) & 255;
crm += ((fm_mask & 1) == 1) ? 0xF0000000 : 0x00000000;
@ -1220,7 +964,7 @@ void ppc_mtfsf() {
ppc_state.fpscr = (quickfprval & crm) | (quickfprval & ~(crm));
}
void ppc_mtfsfdot() {
void dppc_interpreter::ppc_mtfsfdot() {
reg_b = (ppc_cur_instruction >> 11) & 31;
uint32_t fm_mask = (ppc_cur_instruction >> 17) & 255;
crm += ((fm_mask & 1) == 1) ? 0xF0000000 : 0x00000000;
@ -1236,7 +980,7 @@ void ppc_mtfsfdot() {
ppc_fp_changecrf1();
}
void ppc_mtfsfi() {
void dppc_interpreter::ppc_mtfsfi() {
ppc_result_b = (ppc_cur_instruction >> 11) & 15;
crf_d = (ppc_cur_instruction >> 23) & 7;
crf_d = crf_d << 2;
@ -1244,7 +988,7 @@ void ppc_mtfsfi() {
((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
}
void ppc_mtfsfidot() {
void dppc_interpreter::ppc_mtfsfidot() {
ppc_result_b = (ppc_cur_instruction >> 11) & 15;
crf_d = (ppc_cur_instruction >> 23) & 7;
crf_d = crf_d << 2;
@ -1253,14 +997,14 @@ void ppc_mtfsfidot() {
ppc_fp_changecrf1();
}
void ppc_mtfsb0() {
void dppc_interpreter::ppc_mtfsb0() {
crf_d = (ppc_cur_instruction >> 21) & 0x31;
if ((crf_d == 0) || (crf_d > 2)) {
ppc_state.fpscr &= ~(1 << (31 - crf_d));
}
}
void ppc_mtfsb0dot() {
void dppc_interpreter::ppc_mtfsb0dot() {
crf_d = (ppc_cur_instruction >> 21) & 0x31;
if ((crf_d == 0) || (crf_d > 2)) {
ppc_state.fpscr &= ~(1 << crf_d);
@ -1268,14 +1012,14 @@ void ppc_mtfsb0dot() {
ppc_fp_changecrf1();
}
void ppc_mtfsb1() {
void dppc_interpreter::ppc_mtfsb1() {
crf_d = (ppc_cur_instruction >> 21) & 0x31;
if ((crf_d == 0) || (crf_d > 2)) {
ppc_state.fpscr |= (1 << crf_d);
}
}
void ppc_mtfsb1dot() {
void dppc_interpreter::ppc_mtfsb1dot() {
crf_d = ~(ppc_cur_instruction >> 21) & 0x31;
if ((crf_d == 0) || (crf_d > 2)) {
ppc_state.fpscr |= (1 << crf_d);
@ -1283,7 +1027,7 @@ void ppc_mtfsb1dot() {
ppc_fp_changecrf1();
}
void ppc_mcrfs() {
void dppc_interpreter::ppc_mcrfs() {
crf_d = (ppc_cur_instruction >> 23) & 7;
crf_d = crf_d << 2;
crf_s = (ppc_cur_instruction >> 18) & 7;
@ -1294,7 +1038,7 @@ void ppc_mcrfs() {
// Floating Point Comparisons
void ppc_fcmpo() {
void dppc_interpreter::ppc_fcmpo() {
ppc_grab_regsfpsab(true);
crf_d = (ppc_cur_instruction >> 23) & 7;
@ -1328,7 +1072,7 @@ void ppc_fcmpo() {
}
}
void ppc_fcmpu() {
void dppc_interpreter::ppc_fcmpu() {
ppc_grab_regsfpsab(true);
crf_d = (ppc_cur_instruction >> 23) & 7;

View File

@ -48,13 +48,15 @@ PPC_BAT_entry ibat_array[4] = {{0}};
PPC_BAT_entry dbat_array[4] = {{0}};
/** remember recently used physical memory regions for quicker translation. */
AddressMapEntry last_read_area = {0};
AddressMapEntry last_write_area = {0};
AddressMapEntry last_exec_area = {0};
AddressMapEntry last_ptab_area = {0};
AddressMapEntry last_dma_area = {0};
AddressMapEntry last_read_area = {0xFFFFFFFF, 0xFFFFFFFF};
AddressMapEntry last_write_area = {0xFFFFFFFF, 0xFFFFFFFF};
AddressMapEntry last_exec_area = {0xFFFFFFFF, 0xFFFFFFFF};
AddressMapEntry last_ptab_area = {0xFFFFFFFF, 0xFFFFFFFF};
AddressMapEntry last_dma_area = {0xFFFFFFFF, 0xFFFFFFFF};
#define WRITE_BYTE(addr, val) (*(addr) = val)
/* macro for generating code reading from physical memory */
#define READ_PHYS_MEM(ENTRY, ADDR, OP, SIZE, UNVAL) \
{ \
@ -371,13 +373,32 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write) {
}
static void mem_write_unaligned(uint32_t addr, uint32_t value, uint32_t size) {
#ifdef MMU_DEBUG
LOG_F(WARNING, "Attempt to write unaligned %d bytes to 0x%08X\n", size, addr);
#endif
if (((addr & 0xFFF) + size) > 0x1000) {
LOG_F(ERROR, "SOS! Cross-page unaligned write, addr=%08X, size=%d\n", addr, size);
exit(-1); // FIXME!
// Special case: unaligned cross-page writes
LOG_F(WARNING, "Cross-page unaligned write, addr=%08X, size=%d\n",
addr, size);
uint32_t phys_addr;
uint32_t shift = (size - 1) * 8;
// Break misaligned memory accesses into multiple, smaller accesses
// and retranslate on page boundary.
// Because such accesses suffer a performance penalty, they will be
// presumably very rare so don't care much about performance.
for (int i = 0; i < size; shift -= 8, addr++, phys_addr++, i++) {
if ((ppc_state.msr & 0x10) && (!i || !(addr & 0xFFF))) {
phys_addr = ppc_mmu_addr_translate(addr, 0);
}
WRITE_PHYS_MEM(last_write_area, phys_addr, WRITE_BYTE,
(value >> shift) & 0xFF, 1);
}
} else {
/* data address translation if enabled */
// data address translation if enabled
if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 0);
}
@ -396,8 +417,6 @@ void mem_write_byte(uint32_t addr, uint8_t value) {
addr = ppc_mmu_addr_translate(addr, 1);
}
#define WRITE_BYTE(addr, val) (*(addr) = val)
WRITE_PHYS_MEM(last_write_area, addr, WRITE_BYTE, value, 1);
}
@ -444,11 +463,32 @@ void mem_write_qword(uint32_t addr, uint64_t value) {
static uint32_t mem_grab_unaligned(uint32_t addr, uint32_t size) {
uint32_t ret = 0;
#ifdef MMU_DEBUG
LOG_F(WARNING, "Attempt to read unaligned %d bytes from 0x%08X\n", size, addr);
#endif
if (((addr & 0xFFF) + size) > 0x1000) {
LOG_F(ERROR, "SOS! Cross-page unaligned read, addr=%08X, size=%d\n", addr, size);
exit(-1); // FIXME!
// Special case: misaligned cross-page reads
LOG_F(WARNING, "Cross-page unaligned read, addr=%08X, size=%d\n",
addr, size);
uint32_t phys_addr;
uint32_t res = 0;
// Break misaligned memory accesses into multiple, smaller accesses
// and retranslate on page boundary.
// Because such accesses suffer a performance penalty, they will be
// presumably very rare so don't care much about performance.
for (int i = 0; i < size; addr++, phys_addr++, i++) {
if ((ppc_state.msr & 0x10) && (!i || !(addr & 0xFFF))) {
phys_addr = ppc_mmu_addr_translate(addr, 0);
}
READ_PHYS_MEM(last_read_area, phys_addr, *, 1, 0xFFU);
res = (res << 8) | ret;
}
return res;
} else {
/* data address translation if enabled */
if (ppc_state.msr & 0x10) {

File diff suppressed because it is too large Load Diff

View File

@ -142,6 +142,8 @@ static void read_test_data() {
}
int main() {
initialize_ppc_opcode_tables(); //kludge
cout << "Running DingusPPC emulator tests..." << endl << endl;
ntested = 0;

View File

@ -1,5 +1,6 @@
include_directories("${PROJECT_SOURCE_DIR}")
include_directories("${PROJECT_SOURCE_DIR}"
"${PROJECT_SOURCE_DIR}/thirdparty/capstone/include")
file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_library(debugger OBJECT ${SOURCES})
add_library(debugger OBJECT ${SOURCES})

View File

@ -19,9 +19,6 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "../cpu/ppc/ppcdisasm.h"
#include "../cpu/ppc/ppcemu.h"
#include "../cpu/ppc/ppcmmu.h"
#include <fstream>
#include <iomanip>
#include <iostream>
@ -30,7 +27,13 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <stdio.h>
#include <string>
#include <thirdparty/loguru/loguru.hpp>
#include "../cpu/ppc/ppcdisasm.h"
#include "../cpu/ppc/ppcemu.h"
#include "../cpu/ppc/ppcmmu.h"
#ifdef ENABLE_68K_DEBUGGER // optionally defined in CMakeLists.txt
#include <capstone/capstone.h>
#endif
using namespace std;
@ -71,23 +74,153 @@ static void show_help() {
cout << " disas N,X -- disassemble N instructions starting at address X" << endl;
cout << " X can be any number or a known register name" << endl;
cout << " disas with no arguments defaults to disas 1,pc" << endl;
#ifdef ENABLE_68K_DEBUGGER
cout << " context X -- switch to the debugging context X." << endl;
cout << " X can be either 'ppc' (default) or '68k'" << endl;
cout << " Use 68k for debugging emulated 68k code only." << endl;
#endif
cout << " quit -- quit the debugger" << endl << endl;
cout << "Pressing ENTER will repeat last command." << endl;
}
static void disasm(uint32_t count, uint32_t address) {
PPCDisasmContext ctx;
#ifdef ENABLE_68K_DEBUGGER
ctx.instr_addr = address;
ctx.simplified = true;
static void disasm_68k(uint32_t count, uint32_t address) {
csh cs_handle;
uint8_t code[10];
size_t code_size;
uint64_t dis_addr;
for (int i = 0; i < count; i++) {
ctx.instr_code = mem_read_dbg(ctx.instr_addr, 4);
cout << uppercase << hex << ctx.instr_addr;
cout << " " << disassemble_single(&ctx) << endl;
if (cs_open(CS_ARCH_M68K, CS_MODE_M68K_040, &cs_handle) != CS_ERR_OK) {
cout << "Capstone initialization error" << endl;
return;
}
cs_insn* insn = cs_malloc(cs_handle);
for (; count > 0; count--) {
/* prefetch opcode bytes (a 68k instruction can occupy 2...10 bytes) */
for (int i = 0; i < sizeof(code); i++) {
code[i] = mem_read_dbg(address + i, 1);
}
const uint8_t *code_ptr = code;
code_size = sizeof(code);
dis_addr = address;
if (cs_disasm_iter(cs_handle, &code_ptr, &code_size, &dis_addr, insn)) {
cout << uppercase << hex << insn->address << " ";
cout << setfill(' ');
cout << setw(10) << left << insn->mnemonic << insn->op_str << endl;
address = dis_addr;
} else {
cout << "DS.W " << hex << ((code[0] << 8) | code[1]) << endl;
address += 2;
}
}
cs_free(insn, 1);
cs_close(&cs_handle);
}
/* emulator opcode table size --> 512 KB */
#define EMU_68K_TABLE_SIZE 0x80000
/** Execute one emulated 68k instruction. */
void exec_single_68k()
{
string reg;
uint32_t emu_table_virt, cur_68k_pc, cur_instr_tab_entry, ppc_pc;
/* PPC r24 contains 68k PC advanced by two bytes
as part of instruction prefetching */
reg = "R24";
cur_68k_pc = get_reg(reg) - 2;
/* PPC r29 contains base address of the emulator opcode table */
reg = "R29";
emu_table_virt = get_reg(reg) & 0xFFF80000;
/* calculate address of the current opcode table entry as follows:
get_word(68k_PC) * entry_size + table_base */
cur_instr_tab_entry = mem_grab_word(cur_68k_pc) * 8 + emu_table_virt;
/* grab the PPC PC too */
reg = "PC";
ppc_pc = get_reg(reg);
//printf("cur_instr_tab_entry = %X\n", cur_instr_tab_entry);
/* because the first two PPC instructions for each emulated 68k once
are resided in the emulator opcode table, we need to execute them
one by one until the execution goes outside the opcode table. */
while (ppc_pc >= cur_instr_tab_entry && ppc_pc < cur_instr_tab_entry + 8) {
ppc_exec_single();
reg = "PC";
ppc_pc = get_reg(reg);
LOG_F(9, "Tracing within emulator table, PC = %X\n", ppc_pc);
}
/* Getting here means we're outside the emualtor opcode table.
Execute PPC code until we hit the opcode table again. */
LOG_F(9, "Tracing outside the emulator table, PC = %X\n", ppc_pc);
ppc_exec_dbg(emu_table_virt, EMU_68K_TABLE_SIZE - 1);
}
/** Execute emulated 68k code until target_addr is reached. */
void exec_until_68k(uint32_t target_addr)
{
string reg;
uint32_t emu_table_virt, ppc_pc;
reg = "R29";
emu_table_virt = get_reg(reg) & 0xFFF80000;
reg = "R24";
while (target_addr != (get_reg(reg) - 2)) {
reg = "PC";
ppc_pc = get_reg(reg);
if (ppc_pc >= emu_table_virt && ppc_pc < (emu_table_virt + EMU_68K_TABLE_SIZE - 1)) {
LOG_F(9, "Tracing within emulator table, PC = %X\n", ppc_pc);
ppc_exec_single();
} else {
LOG_F(9, "Tracing outside the emulator table, PC = %X\n", ppc_pc);
ppc_exec_dbg(emu_table_virt, EMU_68K_TABLE_SIZE - 1);
}
reg = "R24";
}
}
void print_68k_regs()
{
int i;
string reg;
for (i = 0; i < 8; i++) {
reg = "R" + to_string(i + 8);
cout << "D" << dec << i << " : " << uppercase << hex << get_reg(reg) << endl;
}
for (i = 0; i < 7; i++) {
reg = "R" + to_string(i + 16);
cout << "A" << dec << i << " : " << uppercase << hex << get_reg(reg) << endl;
}
reg = "R1";
cout << "A7 : " << uppercase << hex << get_reg(reg) << endl;
reg = "R24";
cout << "PC: " << uppercase << hex << get_reg(reg) - 2 << endl;
reg = "R25";
cout << "SR: " << uppercase << hex << ((get_reg(reg) & 0xFF) << 8) << endl;
reg = "R26";
cout << "CCR: " << uppercase << hex << get_reg(reg) << endl;
}
#endif // ENABLE_68K_DEBUGGER
static void dump_mem(string& params) {
int cell_size, chars_per_line;
bool is_char;
@ -169,7 +302,8 @@ static void dump_mem(string& params) {
cout << (char)val;
chars_per_line += cell_size;
} else {
cout << setw(cell_size * 2) << setfill('0') << uppercase << hex << val << " ";
cout << setw(cell_size * 2) << setfill('0') << right;
cout << uppercase << hex << val << " ";
chars_per_line += cell_size * 2 + 2;
}
}
@ -181,18 +315,33 @@ static void dump_mem(string& params) {
cout << endl << endl;
}
static void disasm(uint32_t count, uint32_t address) {
PPCDisasmContext ctx;
ctx.instr_addr = address;
ctx.simplified = true;
for (int i = 0; i < count; i++) {
ctx.instr_code = mem_read_dbg(ctx.instr_addr, 4);
cout << uppercase << hex << ctx.instr_addr;
cout << " " << disassemble_single(&ctx) << endl;
}
}
void enter_debugger() {
string inp, cmd, addr_str, expr_str, reg_expr, last_cmd, reg_value_str, inst_string, inst_num_str;
uint32_t addr, inst_grab;
std::stringstream ss;
int log_level;
int log_level, context;
size_t separator_pos;
context = 1; /* start with the PowerPC context */
cout << "Welcome to the DingusPPC command line debugger." << endl;
cout << "Please enter a command or 'help'." << endl << endl;
while (1) {
cout << "ppcdbg> ";
cout << "dingusdbg> ";
/* reset string stream */
ss.str("");
@ -220,7 +369,13 @@ void enter_debugger() {
}
#endif
else if (cmd == "regs") {
print_gprs();
if (context == 2) {
#ifdef ENABLE_68K_DEBUGGER
print_68k_regs();
#endif
} else {
print_gprs();
}
} else if (cmd == "set") {
ss >> expr_str;
@ -248,7 +403,13 @@ void enter_debugger() {
cout << exc.what() << endl;
}
} else if (cmd == "step" || cmd == "si") {
ppc_exec_single();
if (context == 2) {
#ifdef ENABLE_68K_DEBUGGER
exec_single_68k();
#endif
} else {
ppc_exec_single();
}
} else if (cmd == "next" || cmd == "ni") {
addr_str = "PC";
addr = get_reg(addr_str) + 4;
@ -257,7 +418,13 @@ void enter_debugger() {
ss >> addr_str;
try {
addr = str2addr(addr_str);
ppc_exec_until(addr);
if (context == 2) {
#ifdef ENABLE_68K_DEBUGGER
exec_until_68k(addr);
#endif
} else {
ppc_exec_until(addr);
}
} catch (invalid_argument& exc) {
cout << exc.what() << endl;
}
@ -278,27 +445,58 @@ void enter_debugger() {
} catch (invalid_argument& exc) {
try {
/* number conversion failed, trying reg name */
addr = get_reg(addr_str);
if (context == 2 && (addr_str == "pc" || addr_str == "PC")) {
addr_str = "R24";
addr = get_reg(addr_str) - 2;
} else {
addr = get_reg(addr_str);
}
} catch (invalid_argument& exc) {
cout << exc.what() << endl;
continue;
}
}
try {
disasm(inst_grab, addr);
if (context == 2) {
#ifdef ENABLE_68K_DEBUGGER
disasm_68k(inst_grab, addr);
#endif
} else {
disasm(inst_grab, addr);
}
} catch (invalid_argument& exc) {
cout << exc.what() << endl;
}
} else {
/* disas without arguments defaults to disas 1,pc */
addr_str = "PC";
addr = get_reg(addr_str);
disasm(1, addr);
if (context == 2) {
#ifdef ENABLE_68K_DEBUGGER
addr_str = "R24";
addr = get_reg(addr_str);
disasm_68k(1, addr - 2);
#endif
} else {
addr_str = "PC";
addr = get_reg(addr_str);
disasm(1, addr);
}
}
} else if (cmd == "dump") {
expr_str = "";
ss >> expr_str;
dump_mem(expr_str);
#ifdef ENABLE_68K_DEBUGGER
} else if (cmd == "context") {
expr_str = "";
ss >> expr_str;
if (expr_str == "ppc" || expr_str == "PPC") {
context = 1;
} else if (expr_str == "68k" || expr_str == "68K") {
context = 2;
} else {
cout << "Unknown debugging context: " << expr_str << endl;
}
#endif
} else {
cout << "Unknown command: " << cmd << endl;
continue;

View File

@ -135,13 +135,13 @@ private:
0x00 // unknown defaults
};
uint32_t int_mask2;
uint32_t int_clear2;
uint32_t int_levels2;
uint32_t int_mask1;
uint32_t int_clear1;
uint32_t int_levels1;
uint32_t feat_ctrl; // features control register
uint32_t int_mask2 = 0;
uint32_t int_clear2 = 0;
uint32_t int_levels2 = 0;
uint32_t int_mask1 = 0;
uint32_t int_clear1 = 0;
uint32_t int_levels1 = 0;
uint32_t feat_ctrl = 0; // features control register
/* device cells */
ViaCuda* viacuda; /* VIA cell with Cuda MCU attached to it */

6
execution/CMakeLists.txt Normal file
View File

@ -0,0 +1,6 @@
include_directories("${PROJECT_SOURCE_DIR}")
file(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
add_library(execution OBJECT ${SOURCES})
target_link_libraries(execution PRIVATE cubeb)

View File

@ -0,0 +1,111 @@
/*
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/>.
*/
#include <chrono>
#include <cinttypes>
#include <ctime>
#include <iostream>
#include <interpreter_loop.h>
#include <thirdparty/loguru/loguru.hpp>
#include <cpu/ppc/ppcemu.h>
std::chrono::high_resolution_clock::time_point global; // global timer
std::chrono::high_resolution_clock::time_point cuda_timer; // updates every 11 ms
std::chrono::high_resolution_clock::time_point disp_timer; // updates every 16 ms
using namespace std;
const uint64_t cuda_update = 11000;
const uint64_t display_update = 16667;
bool cuda_priority = 0;
bool disp_priority = 0;
uint64_t elapsed_times[3] = {0}; // Elapsed time to reach a cycle (for display)
uint64_t routine_bench[3] = {0}; // Estimated time (in microseconds) to cycle through functions
uint64_t routine_runtime[3] = {0, cuda_update, display_update}; // Time to elapse before execution
enum general_routine_timepoint { OVERALL_UPDATE_TIME, CUDA_UPDATE_TIME, DISPLAY_UPDATE_TIME };
void round_robin_bench() {
// Benchmark how much time elapses during a minimal CPU block
std::chrono::high_resolution_clock::time_point dummy = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 4096; i++) {
dppc_interpreter::ppc_ori(); //execute NOPs as a basic test
}
std::chrono::high_resolution_clock::time_point dummy2 = std::chrono::high_resolution_clock::now();
routine_bench[OVERALL_UPDATE_TIME] =
std::chrono::duration_cast<std::chrono::microseconds>(dummy2 - dummy).count();
std::cout << "Initial test: " << routine_bench[OVERALL_UPDATE_TIME] << endl;
}
void interpreter_update_counters() {
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
elapsed_times[OVERALL_UPDATE_TIME] =
std::chrono::duration_cast<std::chrono::microseconds>(end - global).count();
elapsed_times[CUDA_UPDATE_TIME] =
std::chrono::duration_cast<std::chrono::microseconds>(end - cuda_timer).count();
elapsed_times[DISPLAY_UPDATE_TIME] =
std::chrono::duration_cast<std::chrono::microseconds>(end - disp_timer).count();
// Calculate if the threshold for updating a time-critical section has reached or is about to be reached
if ((elapsed_times[CUDA_UPDATE_TIME] + routine_bench[OVERALL_UPDATE_TIME]) >=
routine_runtime[CUDA_UPDATE_TIME]) {
cuda_priority = true;
elapsed_times[CUDA_UPDATE_TIME] = 0;
cuda_timer = end;
}
if ((elapsed_times[DISPLAY_UPDATE_TIME] + routine_bench[OVERALL_UPDATE_TIME]) >=
routine_runtime[DISPLAY_UPDATE_TIME]) {
disp_priority = true;
elapsed_times[DISPLAY_UPDATE_TIME] = 0;
disp_timer = end;
}
}
void interpreter_main_loop() {
// Round robin algorithm goes here
round_robin_bench();
global = std::chrono::high_resolution_clock::now();
cuda_timer = global;
disp_timer = global;
for (;;) {
if (cuda_priority) {
LOG_F(9, "Placeholder for Cuda Update function!\n");
cuda_priority = false;
}
if (disp_priority) {
LOG_F(9, "Placeholder for Display Update function! \n");
disp_priority = false;
}
ppc_exec();
interpreter_update_counters();
}
}

View File

@ -1,46 +1,23 @@
/*
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 uniquely Gekko opcodes for the processor - ppcgekkoopcodes.cpp
#include "ppcemu.h"
#include <iostream>
#include <stdio.h>
void ppc_psq_l() {
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
exit(0);
}
void ppc_psq_lu() {
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
exit(0);
}
void ppc_psq_st() {
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
exit(0);
}
void ppc_psq_stu() {
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
exit(0);
}
/*
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/>.
*/
void interpreter_update_counters();
void interpreter_main_loop();

View File

@ -23,6 +23,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
// This is where the magic begins
#include "debugger/debugger.h"
#include "execution/interpreter_loop.h"
#include "machines/machinefactory.h"
#include "machines/machineproperties.h"
#include "ppcemu.h"
@ -165,9 +166,7 @@ int main(int argc, char** argv) {
switch (execution_mode) {
case 0:
for (;;) {
ppc_exec();
}
interpreter_main_loop();
break;
case 1:
enter_debugger();

1
thirdparty/capstone vendored Submodule

@ -0,0 +1 @@
Subproject commit bfb2e45d76dd3dda08b40dfad6da94db01bd27ad