clang-format everything

This commit is contained in:
Waqar Ahmed 2020-05-12 23:55:45 +05:00
parent a5c63c1b09
commit 0ab9380be3
49 changed files with 2718 additions and 3104 deletions

78
.clang-format Normal file
View File

@ -0,0 +1,78 @@
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: true
AlignConsecutiveDeclarations: false
#AlignConsecutiveMacros: false
AlignEscapedNewlines: Right
AlignOperands: false
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
#AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
#BreakInheritanceList: BeforeComma
BreakStringLiterals: true
ColumnLimit: 100
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: false
IndentPPDirectives: AfterHash
IndentWidth: 4
IndentWrappedFunctionNames: true
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 2
NamespaceIndentation: None
PenaltyBreakAssignment: 50
PenaltyBreakBeforeFirstCallParameter: 0
PenaltyBreakComment: 100
PenaltyBreakFirstLessLess: 200
PenaltyBreakString: 100
#PenaltyBreakTemplateDeclaration: 0
PenaltyExcessCharacter: 10
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
#SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
#SpaceBeforeCpp11BracedList: true
#SpaceBeforeCtorInitializerColon: false
#SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatements
#SpaceBeforeRangeBasedForLoopColon: false
#SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 4
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
#Standard: c++17
TabWidth: 4
UseTab: Never

View File

@ -22,23 +22,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
// The Power-specific opcodes for the processor - ppcopcodes.cpp // The Power-specific opcodes for the processor - ppcopcodes.cpp
// Any shared opcodes are in ppcopcodes.cpp // Any shared opcodes are in ppcopcodes.cpp
#include <thirdparty/loguru/loguru.hpp>
#include <iostream>
#include <array>
#include <stdio.h>
#include <stdexcept>
#include "ppcemu.h" #include "ppcemu.h"
#include "ppcmmu.h" #include "ppcmmu.h"
#include <array>
#include <cmath> #include <cmath>
#include <iostream>
#include <limits> #include <limits>
#include <stdexcept>
#include <stdio.h>
#include <thirdparty/loguru/loguru.hpp>
void power_abs() { void power_abs() {
ppc_grab_regsda(); ppc_grab_regsda();
if (ppc_result_a == 0x80000000) { if (ppc_result_a == 0x80000000) {
ppc_result_d = ppc_result_a; ppc_result_d = ppc_result_a;
} } else {
else {
ppc_result_d = ppc_result_a & 0x7FFFFFFF; ppc_result_d = ppc_result_a & 0x7FFFFFFF;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -50,8 +49,7 @@ void power_absdot() {
if (ppc_result_a == 0x80000000) { if (ppc_result_a == 0x80000000) {
ppc_result_d = ppc_result_a; ppc_result_d = ppc_result_a;
} } else {
else {
ppc_result_d = ppc_result_a & 0x7FFFFFFF; ppc_result_d = ppc_result_a & 0x7FFFFFFF;
} }
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
@ -64,8 +62,7 @@ void power_abso() {
ppc_result_d = ppc_result_a; ppc_result_d = ppc_result_a;
ppc_state.spr[SPR::XER] |= 0x40000000; ppc_state.spr[SPR::XER] |= 0x40000000;
} } else {
else {
ppc_result_d = ppc_result_a & 0x7FFFFFFF; ppc_result_d = ppc_result_a & 0x7FFFFFFF;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -77,8 +74,7 @@ void power_absodot() {
ppc_result_d = ppc_result_a; ppc_result_d = ppc_result_a;
ppc_state.spr[SPR::XER] |= 0x40000000; ppc_state.spr[SPR::XER] |= 0x40000000;
} } else {
else {
ppc_result_d = ppc_result_a & 0x7FFFFFFF; ppc_result_d = ppc_result_a & 0x7FFFFFFF;
} }
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
@ -164,8 +160,7 @@ void power_doz() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) { if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
ppc_result_d = 0; ppc_result_d = 0;
} } else {
else {
ppc_result_d = ~ppc_result_a + ppc_result_b + 1; ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
} }
ppc_store_result_rega(); ppc_store_result_rega();
@ -175,8 +170,7 @@ void power_dozdot() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) { if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
ppc_result_d = 0; ppc_result_d = 0;
} } else {
else {
ppc_result_d = ~ppc_result_a + ppc_result_b + 1; ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
} }
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
@ -186,8 +180,7 @@ void power_dozdot() {
void power_dozo() { void power_dozo() {
if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) { if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
ppc_result_d = 0; ppc_result_d = 0;
} } else {
else {
ppc_result_d = ~ppc_result_a + ppc_result_b + 1; ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
} }
} }
@ -195,8 +188,7 @@ void power_dozo() {
void power_dozodot() { void power_dozodot() {
if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) { if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
ppc_result_d = 0; ppc_result_d = 0;
} } else {
else {
ppc_result_d = ~ppc_result_a + ppc_result_b + 1; ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
} }
} }
@ -205,8 +197,7 @@ void power_dozi() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if (((int32_t)ppc_result_a) > simm) { if (((int32_t)ppc_result_a) > simm) {
ppc_result_d = 0; ppc_result_d = 0;
} } else {
else {
ppc_result_d = ~ppc_result_a + simm + 1; ppc_result_d = ~ppc_result_a + simm + 1;
} }
ppc_store_result_rega(); ppc_store_result_rega();
@ -260,8 +251,7 @@ void power_lscbx() {
if (shift_amount == 3) { if (shift_amount == 3) {
shift_amount = 0; shift_amount = 0;
reg_d = (reg_d + 1) & 0x1F; reg_d = (reg_d + 1) & 0x1F;
} } else {
else {
shift_amount++; shift_amount++;
} }
} while (bytes_to_load > 0); } while (bytes_to_load > 0);
@ -283,11 +273,9 @@ void power_maskg() {
for (uint32_t i = mask_start; i < mask_end; i++) { for (uint32_t i = mask_start; i < mask_end; i++) {
insert_mask |= (0x80000000 >> i); insert_mask |= (0x80000000 >> i);
} }
} } else if (mask_start == (mask_end + 1)) {
else if (mask_start == (mask_end + 1)) {
insert_mask = 0xFFFFFFFF; insert_mask = 0xFFFFFFFF;
} } else {
else {
insert_mask = 0xFFFFFFFF; insert_mask = 0xFFFFFFFF;
for (uint32_t i = (mask_end + 1); i < (mask_start - 1); i++) { for (uint32_t i = (mask_end + 1); i < (mask_start - 1); i++) {
insert_mask &= (~(0x80000000 >> i)); insert_mask &= (~(0x80000000 >> i));
@ -308,11 +296,9 @@ void power_maskgdot() {
for (uint32_t i = mask_start; i < mask_end; i++) { for (uint32_t i = mask_start; i < mask_end; i++) {
insert_mask |= (0x80000000 >> i); insert_mask |= (0x80000000 >> i);
} }
} } else if (mask_start == (mask_end + 1)) {
else if (mask_start == (mask_end + 1)) {
insert_mask = 0xFFFFFFFF; insert_mask = 0xFFFFFFFF;
} } else {
else {
insert_mask = 0xFFFFFFFF; insert_mask = 0xFFFFFFFF;
for (uint32_t i = (mask_end + 1); i < (mask_start - 1); i++) { for (uint32_t i = (mask_end + 1); i < (mask_start - 1); i++) {
insert_mask &= (~(0x80000000 >> i)); insert_mask &= (~(0x80000000 >> i));
@ -364,7 +350,6 @@ void power_mul() {
ppc_result_d = ((uint32_t)(product >> 32)); ppc_result_d = ((uint32_t)(product >> 32));
ppc_state.spr[SPR::MQ] = ((uint32_t)(product)); ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
ppc_store_result_regd(); ppc_store_result_regd();
} }
void power_muldot() { void power_muldot() {
@ -376,7 +361,6 @@ void power_muldot() {
ppc_state.spr[SPR::MQ] = ((uint32_t)(product)); ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
ppc_store_result_regd(); ppc_store_result_regd();
} }
void power_mulo() { void power_mulo() {
@ -385,7 +369,6 @@ void power_mulo() {
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b); product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
ppc_result_d = ((uint32_t)(product >> 32)); ppc_result_d = ((uint32_t)(product >> 32));
ppc_state.spr[SPR::MQ] = ((uint32_t)(product)); ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
} }
void power_mulodot() { void power_mulodot() {
@ -394,7 +377,6 @@ void power_mulodot() {
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b); product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
ppc_result_d = ((uint32_t)(product >> 32)); ppc_result_d = ((uint32_t)(product >> 32));
ppc_state.spr[SPR::MQ] = ((uint32_t)(product)); ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
} }
void power_nabs() { void power_nabs() {
@ -426,11 +408,9 @@ void power_rlmi() {
for (uint32_t i = rot_mb; i < rot_me; i++) { for (uint32_t i = rot_mb; i < rot_me; i++) {
insert_mask |= (0x80000000 >> i); insert_mask |= (0x80000000 >> i);
} }
} } else if (rot_mb == (rot_me + 1)) {
else if (rot_mb == (rot_me + 1)) {
insert_mask = 0xFFFFFFFF; insert_mask = 0xFFFFFFFF;
} } else {
else {
insert_mask = 0xFFFFFFFF; insert_mask = 0xFFFFFFFF;
for (uint32_t i = (rot_me + 1); i < (rot_mb - 1); i++) { for (uint32_t i = (rot_me + 1); i < (rot_mb - 1); i++) {
insert_mask &= (~(0x80000000 >> i)); insert_mask &= (~(0x80000000 >> i));
@ -446,8 +426,7 @@ void power_rrib() {
ppc_grab_regssab(); ppc_grab_regssab();
if (ppc_result_d & 0x80000000) { if (ppc_result_d & 0x80000000) {
ppc_result_a |= (0x80000000 >> ppc_result_b); ppc_result_a |= (0x80000000 >> ppc_result_b);
} } else {
else {
ppc_result_a &= ~(0x80000000 >> ppc_result_b); ppc_result_a &= ~(0x80000000 >> ppc_result_b);
} }
ppc_store_result_rega(); ppc_store_result_rega();
@ -457,8 +436,7 @@ void power_rribdot() {
ppc_grab_regssab(); ppc_grab_regssab();
if (ppc_result_d & 0x80000000) { if (ppc_result_d & 0x80000000) {
ppc_result_a |= (0x80000000 >> ppc_result_b); ppc_result_a |= (0x80000000 >> ppc_result_b);
} } else {
else {
ppc_result_a &= ~(0x80000000 >> ppc_result_b); ppc_result_a &= ~(0x80000000 >> ppc_result_b);
} }
ppc_changecrf0(ppc_result_a); ppc_changecrf0(ppc_result_a);

File diff suppressed because it is too large Load Diff

View File

@ -22,11 +22,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCEMU_H #ifndef PPCEMU_H
#define PPCEMU_H #define PPCEMU_H
#include <cinttypes>
#include <string>
#include <setjmp.h>
#include "endianswap.h"
#include "devices/memctrlbase.h" #include "devices/memctrlbase.h"
#include "endianswap.h"
#include <cinttypes>
#include <setjmp.h>
#include <string>
// Uncomment this to help debug the emulator further // Uncomment this to help debug the emulator further
//#define EXHAUSTIVE_DEBUG 1 //#define EXHAUSTIVE_DEBUG 1
@ -94,10 +94,7 @@ enum SPR : int {
}; };
/** symbolic names for frequently used SPRs */ /** symbolic names for frequently used SPRs */
enum TBR : int { enum TBR : int { TBL = 0, TBU = 1 };
TBL = 0,
TBU = 1
};
/** symbolic names for common PPC processors */ /** symbolic names for common PPC processors */
enum PPC_VER : uint32_t { enum PPC_VER : uint32_t {
@ -293,10 +290,8 @@ void ppc_fp_changecrf1();
void ppc_tbr_update(); void ppc_tbr_update();
/* Exception handlers. */ /* Exception handlers. */
[[noreturn]] void ppc_exception_handler(Except_Type exception_type, [[noreturn]] void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits);
uint32_t srr1_bits); [[noreturn]] void dbg_exception_handler(Except_Type exception_type, uint32_t srr1_bits);
[[noreturn]] void dbg_exception_handler(Except_Type exception_type,
uint32_t srr1_bits);
// MEMORY DECLARATIONS // MEMORY DECLARATIONS
extern MemCtrlBase* mem_ctrl_instance; extern MemCtrlBase* mem_ctrl_instance;

View File

@ -21,16 +21,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
/** @file Handling of low-level PPC exceptions. */ /** @file Handling of low-level PPC exceptions. */
#include <setjmp.h>
#include <string>
#include <stdexcept>
#include "ppcemu.h" #include "ppcemu.h"
#include <setjmp.h>
#include <stdexcept>
#include <string>
jmp_buf exc_env; /* Global exception environment. */ jmp_buf exc_env; /* Global exception environment. */
[[noreturn]] void ppc_exception_handler(Except_Type exception_type, [[noreturn]] void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) {
uint32_t srr1_bits)
{
grab_exception = true; grab_exception = true;
#ifdef PROFILER #ifdef PROFILER
exceptions_performed++; exceptions_performed++;
@ -105,8 +103,7 @@ jmp_buf exc_env; /* Global exception environment. */
ppc_state.spr[SPR::SRR1] = (ppc_state.msr & 0x0000FF73) | srr1_bits; ppc_state.spr[SPR::SRR1] = (ppc_state.msr & 0x0000FF73) | srr1_bits;
ppc_state.msr &= 0xFFFB1041; ppc_state.msr &= 0xFFFB1041;
/* copy MSR[ILE] to MSR[LE] */ /* copy MSR[ILE] to MSR[LE] */
ppc_state.msr = (ppc_state.msr & 0xFFFFFFFE) | ppc_state.msr = (ppc_state.msr & 0xFFFFFFFE) | ((ppc_state.msr >> 16) & 1);
((ppc_state.msr >> 16) & 1);
if (ppc_state.msr & 0x40) { if (ppc_state.msr & 0x40) {
ppc_next_instruction_address |= 0xFFF00000; ppc_next_instruction_address |= 0xFFF00000;
@ -116,9 +113,7 @@ jmp_buf exc_env; /* Global exception environment. */
} }
[[noreturn]] void dbg_exception_handler(Except_Type exception_type, [[noreturn]] void dbg_exception_handler(Except_Type exception_type, uint32_t srr1_bits) {
uint32_t srr1_bits)
{
std::string exc_descriptor; std::string exc_descriptor;
switch (exception_type) { switch (exception_type) {

View File

@ -19,16 +19,16 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <thirdparty/loguru/loguru.hpp> #include <algorithm>
#include <chrono>
#include <iostream>
#include <map>
#include <setjmp.h>
#include <stdexcept>
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <iostream> #include <thirdparty/loguru/loguru.hpp>
#include <stdexcept>
#include <algorithm>
#include <map>
#include <unordered_map> #include <unordered_map>
#include <chrono>
#include <setjmp.h>
#include "ppcemu.h" #include "ppcemu.h"
#include "ppcmmu.h" #include "ppcmmu.h"
@ -60,371 +60,344 @@ clock_t clock_test_begin; //Used to make sure the TBR does not increment so quic
/** Primary opcode (bits 0...5) lookup table. */ /** Primary opcode (bits 0...5) lookup table. */
static PPCOpcode OpcodeGrabber[] = { static PPCOpcode OpcodeGrabber[] = {
ppc_illegalop, ppc_illegalop, ppc_illegalop, ppc_twi, ppc_opcode4, ppc_illegalop, ppc_illegalop, ppc_illegalop, ppc_twi, ppc_opcode4, ppc_illegalop,
ppc_illegalop, ppc_illegalop, ppc_mulli, ppc_subfic, power_dozi, ppc_illegalop, ppc_mulli, ppc_subfic, power_dozi, ppc_cmpli, ppc_cmpi,
ppc_cmpli, ppc_cmpi, ppc_addic, ppc_addicdot, ppc_addi, ppc_addic, ppc_addicdot, ppc_addi, ppc_addis, ppc_opcode16, ppc_sc,
ppc_addis, ppc_opcode16, ppc_sc, ppc_opcode18, ppc_opcode19, ppc_opcode18, ppc_opcode19, ppc_rlwimi, ppc_rlwinm, power_rlmi, ppc_rlwnm,
ppc_rlwimi, ppc_rlwinm, power_rlmi, ppc_rlwnm, ppc_ori, ppc_ori, ppc_oris, ppc_xori, ppc_xoris, ppc_andidot, ppc_andisdot,
ppc_oris, ppc_xori, ppc_xoris, ppc_andidot, ppc_andisdot, ppc_illegalop, ppc_opcode31, ppc_lwz, ppc_lwzu, ppc_lbz, ppc_lbzu,
ppc_illegalop, ppc_opcode31, ppc_lwz, ppc_lwzu, ppc_lbz, ppc_stw, ppc_stwu, ppc_stb, ppc_stbu, ppc_lhz, ppc_lhzu,
ppc_lbzu, ppc_stw, ppc_stwu, ppc_stb, ppc_stbu, ppc_lha, ppc_lhau, ppc_sth, ppc_sthu, ppc_lmw, ppc_stmw,
ppc_lhz, ppc_lhzu, ppc_lha, ppc_lhau, ppc_sth, ppc_lfs, ppc_lfsu, ppc_lfd, ppc_lfdu, ppc_stfs, ppc_stfsu,
ppc_sthu, ppc_lmw, ppc_stmw, ppc_lfs, ppc_lfsu, ppc_stfd, ppc_stfdu, ppc_psq_l, ppc_psq_lu, ppc_illegalop, ppc_illegalop,
ppc_lfd, ppc_lfdu, ppc_stfs, ppc_stfsu, ppc_stfd, ppc_psq_st, ppc_psq_stu, ppc_illegalop, ppc_opcode63};
ppc_stfdu, ppc_psq_l, ppc_psq_lu, ppc_illegalop, ppc_illegalop,
ppc_psq_st, ppc_psq_stu, ppc_illegalop, ppc_opcode63
};
/** Lookup tables for branch instructions. */ /** Lookup tables for branch instructions. */
static PPCOpcode SubOpcode16Grabber[] = { static PPCOpcode SubOpcode16Grabber[] = {ppc_bc, ppc_bcl, ppc_bca, ppc_bcla};
ppc_bc, ppc_bcl, ppc_bca, ppc_bcla
};
static PPCOpcode SubOpcode18Grabber[] = { static PPCOpcode SubOpcode18Grabber[] = {ppc_b, ppc_bl, ppc_ba, ppc_bla};
ppc_b, ppc_bl, ppc_ba, ppc_bla
};
/** General conditional register instructions decoding table. */ /** General conditional register instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode19Grabber = { static std::unordered_map<uint16_t, PPCOpcode> SubOpcode19Grabber = {
{ 32, &ppc_bclr}, { 33, &ppc_bclrl}, { 66, &ppc_crnor}, {100, &ppc_rfi}, {32, &ppc_bclr},
{ 258, &ppc_crandc}, { 300, &ppc_isync}, {386, &ppc_crxor}, {450, &ppc_crnand}, {33, &ppc_bclrl},
{ 514, &ppc_crand}, { 578, &ppc_creqv}, {834, &ppc_crorc}, {898, &ppc_cror}, {66, &ppc_crnor},
{1056, &ppc_bcctr}, {1057, &ppc_bcctrl} {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}};
/** General integer instructions decoding table. */ /** General integer instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode31Grabber = { static std::unordered_map<uint16_t, PPCOpcode> SubOpcode31Grabber = {
{ 0, &ppc_cmp}, { 8, &ppc_tw}, { 16, &ppc_subfc}, {0, &ppc_cmp}, {8, &ppc_tw},
{ 17, &ppc_subfcdot}, { 20, &ppc_addc}, { 21, &ppc_addcdot}, {16, &ppc_subfc}, {17, &ppc_subfcdot},
{ 22, &ppc_mulhwu}, { 23, &ppc_mulhwudot}, { 38, &ppc_mfcr}, {20, &ppc_addc}, {21, &ppc_addcdot},
{ 40, &ppc_lwarx}, { 46, &ppc_lwzx}, { 48, &ppc_slw}, {22, &ppc_mulhwu}, {23, &ppc_mulhwudot},
{ 49, &ppc_slwdot}, { 52, &ppc_cntlzw}, { 53, &ppc_cntlzwdot}, {38, &ppc_mfcr}, {40, &ppc_lwarx},
{ 56, &ppc_and}, { 57, &ppc_anddot}, { 58, &power_maskg}, {46, &ppc_lwzx}, {48, &ppc_slw},
{ 59, &power_maskgdot}, { 64, &ppc_cmpl}, { 80, &ppc_subf}, {49, &ppc_slwdot}, {52, &ppc_cntlzw},
{ 81, &ppc_subfdot}, { 108, &ppc_dcbst}, { 110, &ppc_lwzux}, {53, &ppc_cntlzwdot}, {56, &ppc_and},
{ 120, &ppc_andc}, { 121, &ppc_andcdot}, { 150, &ppc_mulhw}, {57, &ppc_anddot}, {58, &power_maskg},
{ 151, &ppc_mulhwdot}, { 166, &ppc_mfmsr}, { 172, &ppc_dcbf}, {59, &power_maskgdot}, {64, &ppc_cmpl},
{ 174, &ppc_lbzx}, { 208, &ppc_neg}, { 209, &ppc_negdot}, {80, &ppc_subf}, {81, &ppc_subfdot},
{ 214, &power_mul}, { 215, &power_muldot}, { 238, &ppc_lbzux}, {108, &ppc_dcbst}, {110, &ppc_lwzux},
{ 248, &ppc_nor}, { 249, &ppc_nordot}, { 272, &ppc_subfe}, {120, &ppc_andc}, {121, &ppc_andcdot},
{ 273, &ppc_subfedot}, { 276, &ppc_adde}, { 277, &ppc_addedot}, {150, &ppc_mulhw}, {151, &ppc_mulhwdot},
{ 288, &ppc_mtcrf}, { 292, &ppc_mtmsr}, { 301, &ppc_stwcx}, {166, &ppc_mfmsr}, {172, &ppc_dcbf},
{ 302, &ppc_stwx}, { 304, &power_slq}, { 305, &power_slqdot}, {174, &ppc_lbzx}, {208, &ppc_neg},
{ 306, &power_sle}, { 307, &power_sledot}, { 366, &ppc_stwux}, {209, &ppc_negdot}, {214, &power_mul},
{ 368, &power_sliq}, { 400, &ppc_subfze}, { 401, &ppc_subfzedot}, {215, &power_muldot}, {238, &ppc_lbzux},
{ 404, &ppc_addze}, { 405, &ppc_addzedot}, { 420, &ppc_mtsr}, {248, &ppc_nor}, {249, &ppc_nordot},
{ 430, &ppc_stbx}, { 432, &power_sllq}, { 433, &power_sllqdot}, {272, &ppc_subfe}, {273, &ppc_subfedot},
{ 434, &power_sleq}, { 436, &power_sleqdot}, { 464, &ppc_subfme}, {276, &ppc_adde}, {277, &ppc_addedot},
{ 465, &ppc_subfmedot}, { 468, &ppc_addme}, { 469, &ppc_addmedot}, {288, &ppc_mtcrf}, {292, &ppc_mtmsr},
{ 470, &ppc_mullw}, { 471, &ppc_mullwdot}, { 484, &ppc_mtsrin}, {301, &ppc_stwcx}, {302, &ppc_stwx},
{ 492, &ppc_dcbtst}, { 494, &ppc_stbux}, { 496, &power_slliq}, {304, &power_slq}, {305, &power_slqdot},
{ 497, &power_slliqdot}, { 528, &power_doz}, { 529, &power_dozdot}, {306, &power_sle}, {307, &power_sledot},
{ 532, &ppc_add}, { 533, &ppc_adddot}, { 554, &power_lscbx}, {366, &ppc_stwux}, {368, &power_sliq},
{ 555, &power_lscbxdot}, { 556, &ppc_dcbt}, { 558, &ppc_lhzx}, {400, &ppc_subfze}, {401, &ppc_subfzedot},
{ 568, &ppc_eqv}, { 569, &ppc_eqvdot}, { 612, &ppc_tlbie}, {404, &ppc_addze}, {405, &ppc_addzedot},
{ 622, &ppc_lhzux}, { 632, &ppc_xor}, { 633, &ppc_xordot}, {420, &ppc_mtsr}, {430, &ppc_stbx},
{ 662, &power_div}, { 663, &power_divdot}, { 678, &ppc_mfspr}, {432, &power_sllq}, {433, &power_sllqdot},
{ 686, &ppc_lhax}, { 720, &power_abs}, { 721, &power_absdot}, {434, &power_sleq}, {436, &power_sleqdot},
{ 726, &power_divs}, { 727, &power_divsdot}, { 740, &ppc_tlbia}, {464, &ppc_subfme}, {465, &ppc_subfmedot},
{ 742, &ppc_mftb}, { 750, &ppc_lhaux}, { 814, &ppc_sthx}, {468, &ppc_addme}, {469, &ppc_addmedot},
{ 824, &ppc_orc}, { 825, &ppc_orcdot}, { 878, &ppc_sthx}, {470, &ppc_mullw}, {471, &ppc_mullwdot},
{ 888, &ppc_or}, { 889, &ppc_ordot}, { 918, &ppc_divwu}, {484, &ppc_mtsrin}, {492, &ppc_dcbtst},
{ 919, &ppc_divwudot}, { 934, &ppc_mtspr}, { 940, &ppc_dcbi}, {494, &ppc_stbux}, {496, &power_slliq},
{ 952, &ppc_nand}, { 953, &ppc_nanddot}, { 976, &power_nabs}, {497, &power_slliqdot}, {528, &power_doz},
{ 977, &power_nabsdot}, { 982, &ppc_divw}, { 983, &ppc_divwdot}, {529, &power_dozdot}, {532, &ppc_add},
{1024, &ppc_mcrxr}, {1040, &ppc_subfco}, {1041, &ppc_subfcodot}, {533, &ppc_adddot}, {554, &power_lscbx},
{1044, &ppc_addco}, {1045, &ppc_addcodot}, {1062, &power_clcs}, {555, &power_lscbxdot}, {556, &ppc_dcbt},
{1063, &power_clcsdot}, {1066, &ppc_lswx}, {1068, &ppc_lwbrx}, {558, &ppc_lhzx}, {568, &ppc_eqv},
{1070, &ppc_lfsx}, {1072, &ppc_srw}, {1073, &ppc_srwdot}, {569, &ppc_eqvdot}, {612, &ppc_tlbie},
{1074, &power_rrib}, {1075, &power_rribdot}, {1082, &power_maskir}, {622, &ppc_lhzux}, {632, &ppc_xor},
{1083, &power_maskirdot}, {1104, &ppc_subfo}, {1105, &ppc_subfodot}, {633, &ppc_xordot}, {662, &power_div},
{1132, &ppc_tlbsync}, {1134, &ppc_lfsux}, {1190, &ppc_mfsr}, {663, &power_divdot}, {678, &ppc_mfspr},
{1194, &ppc_lswi}, {1196, &ppc_sync}, {1198, &ppc_lfdx}, {686, &ppc_lhax}, {720, &power_abs},
{1232, &ppc_nego}, {1233, &ppc_negodot}, {1238, &power_mulo}, {721, &power_absdot}, {726, &power_divs},
{1239, &power_mulodot}, {1262, &ppc_lfdux}, {1296, &ppc_subfeo}, {727, &power_divsdot}, {740, &ppc_tlbia},
{1297, &ppc_subfeodot}, {1300, &ppc_addeo}, {1301, &ppc_addeodot}, {742, &ppc_mftb}, {750, &ppc_lhaux},
{1318, &ppc_mfsrin}, {1322, &ppc_stswx}, {1324, &ppc_stwbrx}, {814, &ppc_sthx}, {824, &ppc_orc},
{1326, &ppc_stfsx}, {1328, &power_srq}, {1329, &power_srqdot}, {825, &ppc_orcdot}, {878, &ppc_sthx},
{1330, &power_sre}, {1331, &power_sredot}, {1390, &ppc_stfsux}, {888, &ppc_or}, {889, &ppc_ordot},
{1392, &power_sriq}, {1393, &power_sriqdot}, {1424, &ppc_subfzeo}, {918, &ppc_divwu}, {919, &ppc_divwudot},
{1425, &ppc_subfzeodot}, {1428, &ppc_addzeo}, {1429, &ppc_addzeodot}, {934, &ppc_mtspr}, {940, &ppc_dcbi},
{1450, &ppc_stswi}, {1454, &ppc_stfdx}, {1456, &power_srlq}, {952, &ppc_nand}, {953, &ppc_nanddot},
{1457, &power_srlqdot}, {1458, &power_sreq}, {1459, &power_sreqdot}, {976, &power_nabs}, {977, &power_nabsdot},
{1488, &ppc_subfmeo}, {1489, &ppc_subfmeodot}, {1492, &ppc_addmeo}, {982, &ppc_divw}, {983, &ppc_divwdot},
{1493, &ppc_addmeodot}, {1494, &ppc_mullwo}, {1495, &ppc_mullwodot}, {1024, &ppc_mcrxr}, {1040, &ppc_subfco},
{1518, &ppc_stfdux}, {1520, &power_srliq}, {1521, &power_srliqdot}, {1041, &ppc_subfcodot}, {1044, &ppc_addco},
{1552, &power_dozo}, {1553, &power_dozodot}, {1556, &ppc_addo}, {1045, &ppc_addcodot}, {1062, &power_clcs},
{1557, &ppc_addodot}, {1580, &ppc_lhbrx}, {1584, &ppc_sraw}, {1063, &power_clcsdot}, {1066, &ppc_lswx},
{1585, &ppc_srawdot}, {1648, &ppc_srawi}, {1649, &ppc_srawidot}, {1068, &ppc_lwbrx}, {1070, &ppc_lfsx},
{1686, &power_divo}, {1687, &power_divodot}, {1708, &ppc_eieio}, {1072, &ppc_srw}, {1073, &ppc_srwdot},
{1744, &power_abso}, {1745, &power_absodot}, {1750, &power_divso}, {1074, &power_rrib}, {1075, &power_rribdot},
{1751, &power_divsodot}, {1836, &ppc_sthbrx}, {1840, &power_sraq}, {1082, &power_maskir}, {1083, &power_maskirdot},
{1841, &power_sraqdot}, {1842, &power_srea}, {1843, &power_sreadot}, {1104, &ppc_subfo}, {1105, &ppc_subfodot},
{1844, &ppc_extsh}, {1845, &ppc_extshdot}, {1904, &power_sraiq}, {1132, &ppc_tlbsync}, {1134, &ppc_lfsux},
{1905, &power_sraiqdot}, {1908, &ppc_extsb}, {1909, &ppc_extsbdot}, {1190, &ppc_mfsr}, {1194, &ppc_lswi},
{1942, &ppc_divwuo}, {1943, &ppc_divwuodot}, {1956, &ppc_tlbld}, {1196, &ppc_sync}, {1198, &ppc_lfdx},
{1964, &ppc_icbi}, {1966, &ppc_stfiwx}, {2000, &power_nabso}, {1232, &ppc_nego}, {1233, &ppc_negodot},
{2001, &power_nabsodot}, {2006, &ppc_divwo}, {2007, &ppc_divwodot}, {1238, &power_mulo}, {1239, &power_mulodot},
{2020, &ppc_tlbli}, {2028, &ppc_dcbz} {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. */ /** Single-precision floating-point instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode59Grabber = { static std::unordered_map<uint16_t, PPCOpcode> SubOpcode59Grabber = {
{ 36, &ppc_fdivs}, { 37, &ppc_fdivsdot}, { 40, &ppc_fsubs}, {36, &ppc_fdivs}, {37, &ppc_fdivsdot}, {40, &ppc_fsubs}, {41, &ppc_fsubsdot},
{ 41, &ppc_fsubsdot}, { 42, &ppc_fadds}, { 43, &ppc_faddsdot}, {42, &ppc_fadds}, {43, &ppc_faddsdot}, {44, &ppc_fsqrts}, {45, &ppc_fsqrtsdot},
{ 44, &ppc_fsqrts}, { 45, &ppc_fsqrtsdot}, { 48, &ppc_fres}, {48, &ppc_fres}, {49, &ppc_fresdot}, {50, &ppc_fmults}, {51, &ppc_fmultsdot},
{ 49, &ppc_fresdot}, { 50, &ppc_fmults}, { 51, &ppc_fmultsdot}, {56, &ppc_fmsubs}, {57, &ppc_fmsubsdot}, {58, &ppc_fmadds}, {59, &ppc_fmaddsdot},
{ 56, &ppc_fmsubs}, { 57, &ppc_fmsubsdot}, { 58, &ppc_fmadds}, {60, &ppc_fnmsubs}, {61, &ppc_fnmsubsdot}, {62, &ppc_fnmadds}, {63, &ppc_fnmaddsdot},
{ 59, &ppc_fmaddsdot}, { 60, &ppc_fnmsubs}, { 61, &ppc_fnmsubsdot}, {114, &ppc_fmults}, {115, &ppc_fmultsdot}, {120, &ppc_fmsubs}, {121, &ppc_fmsubsdot},
{ 62, &ppc_fnmadds}, { 63, &ppc_fnmaddsdot}, { 114, &ppc_fmults}, {122, &ppc_fmadds}, {123, &ppc_fmadds}, {124, &ppc_fnmsubs}, {125, &ppc_fnmsubsdot},
{ 115, &ppc_fmultsdot}, { 120, &ppc_fmsubs}, { 121, &ppc_fmsubsdot}, {126, &ppc_fnmadds}, {127, &ppc_fnmaddsdot}, {178, &ppc_fmults}, {179, &ppc_fmultsdot},
{ 122, &ppc_fmadds}, { 123, &ppc_fmadds}, { 124, &ppc_fnmsubs}, {184, &ppc_fmsubs}, {185, &ppc_fmsubsdot}, {186, &ppc_fmadds}, {187, &ppc_fmaddsdot},
{ 125, &ppc_fnmsubsdot}, { 126, &ppc_fnmadds}, { 127, &ppc_fnmaddsdot}, {188, &ppc_fnmsubs}, {189, &ppc_fnmsubsdot}, {190, &ppc_fnmadds}, {191, &ppc_fnmaddsdot},
{ 178, &ppc_fmults}, { 179, &ppc_fmultsdot}, { 184, &ppc_fmsubs}, {242, &ppc_fmults}, {243, &ppc_fmultsdot}, {248, &ppc_fmsubs}, {249, &ppc_fmsubsdot},
{ 185, &ppc_fmsubsdot}, { 186, &ppc_fmadds}, { 187, &ppc_fmaddsdot}, {250, &ppc_fmadds}, {251, &ppc_fmaddsdot}, {252, &ppc_fnmsubs}, {253, &ppc_fnmsubsdot},
{ 188, &ppc_fnmsubs}, { 189, &ppc_fnmsubsdot}, { 190, &ppc_fnmadds}, {254, &ppc_fnmadds}, {255, &ppc_fnmaddsdot}, {306, &ppc_fmults}, {307, &ppc_fmultsdot},
{ 191, &ppc_fnmaddsdot}, { 242, &ppc_fmults}, { 243, &ppc_fmultsdot}, {312, &ppc_fmsubs}, {313, &ppc_fmsubsdot}, {314, &ppc_fmadds}, {315, &ppc_fmaddsdot},
{ 248, &ppc_fmsubs}, { 249, &ppc_fmsubsdot}, { 250, &ppc_fmadds}, {316, &ppc_fnmsubs}, {317, &ppc_fnmsubsdot}, {318, &ppc_fnmadds}, {319, &ppc_fnmaddsdot},
{ 251, &ppc_fmaddsdot}, { 252, &ppc_fnmsubs}, { 253, &ppc_fnmsubsdot}, {370, &ppc_fmults}, {371, &ppc_fmultsdot}, {376, &ppc_fmsubs}, {377, &ppc_fmsubsdot},
{ 254, &ppc_fnmadds}, { 255, &ppc_fnmaddsdot}, { 306, &ppc_fmults}, {378, &ppc_fmadds}, {379, &ppc_fmaddsdot}, {380, &ppc_fnmsubs}, {381, &ppc_fnmsubsdot},
{ 307, &ppc_fmultsdot}, { 312, &ppc_fmsubs}, { 313, &ppc_fmsubsdot}, {382, &ppc_fnmadds}, {383, &ppc_fnmaddsdot}, {434, &ppc_fmults}, {435, &ppc_fmultsdot},
{ 314, &ppc_fmadds}, { 315, &ppc_fmaddsdot}, { 316, &ppc_fnmsubs}, {440, &ppc_fmsubs}, {441, &ppc_fmsubsdot}, {442, &ppc_fmadds}, {443, &ppc_fmaddsdot},
{ 317, &ppc_fnmsubsdot}, { 318, &ppc_fnmadds}, { 319, &ppc_fnmaddsdot}, {444, &ppc_fnmsubs}, {445, &ppc_fnmsubsdot}, {446, &ppc_fnmadds}, {447, &ppc_fnmaddsdot},
{ 370, &ppc_fmults}, { 371, &ppc_fmultsdot}, { 376, &ppc_fmsubs}, {498, &ppc_fmults}, {499, &ppc_fmultsdot}, {504, &ppc_fmsubs}, {505, &ppc_fmsubsdot},
{ 377, &ppc_fmsubsdot}, { 378, &ppc_fmadds}, { 379, &ppc_fmaddsdot}, {506, &ppc_fmadds}, {507, &ppc_fmaddsdot}, {508, &ppc_fnmsubs}, {509, &ppc_fnmsubsdot},
{ 380, &ppc_fnmsubs}, { 381, &ppc_fnmsubsdot}, { 382, &ppc_fnmadds}, {510, &ppc_fnmadds}, {511, &ppc_fnmaddsdot}, {562, &ppc_fmults}, {563, &ppc_fmultsdot},
{ 383, &ppc_fnmaddsdot}, { 434, &ppc_fmults}, { 435, &ppc_fmultsdot}, {568, &ppc_fmsubs}, {569, &ppc_fmsubsdot}, {570, &ppc_fmadds}, {571, &ppc_fmaddsdot},
{ 440, &ppc_fmsubs}, { 441, &ppc_fmsubsdot}, { 442, &ppc_fmadds}, {572, &ppc_fnmsubs}, {573, &ppc_fnmsubsdot}, {574, &ppc_fnmadds}, {575, &ppc_fnmaddsdot},
{ 443, &ppc_fmaddsdot}, { 444, &ppc_fnmsubs}, { 445, &ppc_fnmsubsdot}, {626, &ppc_fmults}, {627, &ppc_fmultsdot}, {632, &ppc_fmsubs}, {633, &ppc_fmsubsdot},
{ 446, &ppc_fnmadds}, { 447, &ppc_fnmaddsdot}, { 498, &ppc_fmults}, {634, &ppc_fmadds}, {635, &ppc_fmaddsdot}, {636, &ppc_fnmsubs}, {637, &ppc_fnmsubsdot},
{ 499, &ppc_fmultsdot}, { 504, &ppc_fmsubs}, { 505, &ppc_fmsubsdot}, {638, &ppc_fnmadds}, {639, &ppc_fnmaddsdot}, {690, &ppc_fmults}, {691, &ppc_fmultsdot},
{ 506, &ppc_fmadds}, { 507, &ppc_fmaddsdot}, { 508, &ppc_fnmsubs}, {696, &ppc_fmsubs}, {697, &ppc_fmsubsdot}, {698, &ppc_fmadds}, {699, &ppc_fmaddsdot},
{ 509, &ppc_fnmsubsdot}, { 510, &ppc_fnmadds}, { 511, &ppc_fnmaddsdot}, {700, &ppc_fnmsubs}, {701, &ppc_fnmsubsdot}, {702, &ppc_fnmadds}, {703, &ppc_fnmaddsdot},
{ 562, &ppc_fmults}, { 563, &ppc_fmultsdot}, { 568, &ppc_fmsubs}, {754, &ppc_fmults}, {755, &ppc_fmultsdot}, {760, &ppc_fmsubs}, {761, &ppc_fmsubsdot},
{ 569, &ppc_fmsubsdot}, { 570, &ppc_fmadds}, { 571, &ppc_fmaddsdot}, {762, &ppc_fmadds}, {763, &ppc_fmaddsdot}, {764, &ppc_fnmsubs}, {765, &ppc_fnmsubsdot},
{ 572, &ppc_fnmsubs}, { 573, &ppc_fnmsubsdot}, { 574, &ppc_fnmadds}, {766, &ppc_fnmadds}, {767, &ppc_fnmaddsdot}, {818, &ppc_fmults}, {819, &ppc_fmultsdot},
{ 575, &ppc_fnmaddsdot}, { 626, &ppc_fmults}, { 627, &ppc_fmultsdot}, {824, &ppc_fmsubs}, {825, &ppc_fmsubsdot}, {826, &ppc_fmadds}, {827, &ppc_fmaddsdot},
{ 632, &ppc_fmsubs}, { 633, &ppc_fmsubsdot}, { 634, &ppc_fmadds}, {828, &ppc_fnmsubs}, {829, &ppc_fnmsubsdot}, {830, &ppc_fnmadds}, {831, &ppc_fnmaddsdot},
{ 635, &ppc_fmaddsdot}, { 636, &ppc_fnmsubs}, { 637, &ppc_fnmsubsdot}, {882, &ppc_fmults}, {883, &ppc_fmultsdot}, {888, &ppc_fmsubs}, {889, &ppc_fmsubsdot},
{ 638, &ppc_fnmadds}, { 639, &ppc_fnmaddsdot}, { 690, &ppc_fmults}, {890, &ppc_fmadds}, {891, &ppc_fmaddsdot}, {892, &ppc_fnmsubs}, {893, &ppc_fnmsubsdot},
{ 691, &ppc_fmultsdot}, { 696, &ppc_fmsubs}, { 697, &ppc_fmsubsdot}, {894, &ppc_fnmadds}, {895, &ppc_fnmaddsdot}, {946, &ppc_fmults}, {947, &ppc_fmultsdot},
{ 698, &ppc_fmadds}, { 699, &ppc_fmaddsdot}, { 700, &ppc_fnmsubs}, {952, &ppc_fmsubs}, {953, &ppc_fmsubsdot}, {954, &ppc_fmadds}, {955, &ppc_fmaddsdot},
{ 701, &ppc_fnmsubsdot}, { 702, &ppc_fnmadds}, { 703, &ppc_fnmaddsdot}, {957, &ppc_fnmsubs}, {958, &ppc_fnmsubsdot}, {958, &ppc_fnmadds}, {959, &ppc_fnmaddsdot},
{ 754, &ppc_fmults}, { 755, &ppc_fmultsdot}, { 760, &ppc_fmsubs}, {1010, &ppc_fmults}, {1011, &ppc_fmultsdot}, {1016, &ppc_fmsubs}, {1017, &ppc_fmsubsdot},
{ 761, &ppc_fmsubsdot}, { 762, &ppc_fmadds}, { 763, &ppc_fmaddsdot}, {1018, &ppc_fmadds}, {1019, &ppc_fmaddsdot}, {1020, &ppc_fnmsubs}, {1021, &ppc_fnmsubsdot},
{ 764, &ppc_fnmsubs}, { 765, &ppc_fnmsubsdot}, { 766, &ppc_fnmadds}, {1022, &ppc_fnmadds}, {1023, &ppc_fnmaddsdot}, {1074, &ppc_fmults}, {1075, &ppc_fmultsdot},
{ 767, &ppc_fnmaddsdot}, { 818, &ppc_fmults}, { 819, &ppc_fmultsdot}, {1080, &ppc_fmsubs}, {1081, &ppc_fmsubsdot}, {1082, &ppc_fmadds}, {1083, &ppc_fmaddsdot},
{ 824, &ppc_fmsubs}, { 825, &ppc_fmsubsdot}, { 826, &ppc_fmadds}, {1084, &ppc_fnmsubs}, {1085, &ppc_fnmsubsdot}, {1086, &ppc_fnmadds}, {1087, &ppc_fnmaddsdot},
{ 827, &ppc_fmaddsdot}, { 828, &ppc_fnmsubs}, { 829, &ppc_fnmsubsdot}, {1138, &ppc_fmults}, {1139, &ppc_fmultsdot}, {1144, &ppc_fmsubs}, {1145, &ppc_fmsubsdot},
{ 830, &ppc_fnmadds}, { 831, &ppc_fnmaddsdot}, { 882, &ppc_fmults}, {1146, &ppc_fmadds}, {1147, &ppc_fmaddsdot}, {1148, &ppc_fnmsubs}, {1149, &ppc_fnmsubsdot},
{ 883, &ppc_fmultsdot}, { 888, &ppc_fmsubs}, { 889, &ppc_fmsubsdot}, {1150, &ppc_fnmadds}, {1151, &ppc_fnmaddsdot}, {1202, &ppc_fmults}, {1203, &ppc_fmultsdot},
{ 890, &ppc_fmadds}, { 891, &ppc_fmaddsdot}, { 892, &ppc_fnmsubs}, {1208, &ppc_fmsubs}, {1209, &ppc_fmsubsdot}, {1210, &ppc_fmadds}, {1211, &ppc_fmaddsdot},
{ 893, &ppc_fnmsubsdot}, { 894, &ppc_fnmadds}, { 895, &ppc_fnmaddsdot}, {1212, &ppc_fnmsubs}, {1213, &ppc_fnmsubsdot}, {1214, &ppc_fnmadds}, {1215, &ppc_fnmaddsdot},
{ 946, &ppc_fmults}, { 947, &ppc_fmultsdot}, { 952, &ppc_fmsubs}, {1266, &ppc_fmults}, {1267, &ppc_fmultsdot}, {1272, &ppc_fmsubs}, {1273, &ppc_fmsubsdot},
{ 953, &ppc_fmsubsdot}, { 954, &ppc_fmadds}, { 955, &ppc_fmaddsdot}, {1274, &ppc_fmadds}, {1275, &ppc_fmaddsdot}, {1276, &ppc_fnmsubs}, {1277, &ppc_fnmsubsdot},
{ 957, &ppc_fnmsubs}, { 958, &ppc_fnmsubsdot}, { 958, &ppc_fnmadds}, {1278, &ppc_fnmadds}, {1279, &ppc_fnmaddsdot}, {1330, &ppc_fmults}, {1331, &ppc_fmultsdot},
{ 959, &ppc_fnmaddsdot}, {1010, &ppc_fmults}, {1011, &ppc_fmultsdot}, {1336, &ppc_fmsubs}, {1337, &ppc_fmsubsdot}, {1338, &ppc_fmadds}, {1339, &ppc_fmaddsdot},
{1016, &ppc_fmsubs}, {1017, &ppc_fmsubsdot}, {1018, &ppc_fmadds}, {1340, &ppc_fnmsubs}, {1341, &ppc_fnmsubsdot}, {1342, &ppc_fnmadds}, {1343, &ppc_fnmaddsdot},
{1019, &ppc_fmaddsdot}, {1020, &ppc_fnmsubs}, {1021, &ppc_fnmsubsdot}, {1394, &ppc_fmults}, {1395, &ppc_fmultsdot}, {1400, &ppc_fmsubs}, {1401, &ppc_fmsubsdot},
{1022, &ppc_fnmadds}, {1023, &ppc_fnmaddsdot}, {1074, &ppc_fmults}, {1402, &ppc_fmadds}, {1403, &ppc_fmaddsdot}, {1404, &ppc_fnmsubs}, {1405, &ppc_fnmsubsdot},
{1075, &ppc_fmultsdot}, {1080, &ppc_fmsubs}, {1081, &ppc_fmsubsdot}, {1406, &ppc_fnmadds}, {1407, &ppc_fnmaddsdot}, {1458, &ppc_fmults}, {1459, &ppc_fmultsdot},
{1082, &ppc_fmadds}, {1083, &ppc_fmaddsdot}, {1084, &ppc_fnmsubs}, {1464, &ppc_fmsubs}, {1465, &ppc_fmsubsdot}, {1466, &ppc_fmadds}, {1467, &ppc_fmaddsdot},
{1085, &ppc_fnmsubsdot}, {1086, &ppc_fnmadds}, {1087, &ppc_fnmaddsdot}, {1468, &ppc_fnmsubs}, {1469, &ppc_fnmsubsdot}, {1470, &ppc_fnmadds}, {1471, &ppc_fnmaddsdot},
{1138, &ppc_fmults}, {1139, &ppc_fmultsdot}, {1144, &ppc_fmsubs}, {1522, &ppc_fmults}, {1523, &ppc_fmultsdot}, {1528, &ppc_fmsubs}, {1529, &ppc_fmsubsdot},
{1145, &ppc_fmsubsdot}, {1146, &ppc_fmadds}, {1147, &ppc_fmaddsdot}, {1530, &ppc_fmadds}, {1531, &ppc_fmaddsdot}, {1532, &ppc_fnmsubs}, {1533, &ppc_fnmsubsdot},
{1148, &ppc_fnmsubs}, {1149, &ppc_fnmsubsdot}, {1150, &ppc_fnmadds}, {1534, &ppc_fnmadds}, {1535, &ppc_fnmaddsdot}, {1586, &ppc_fmults}, {1587, &ppc_fmultsdot},
{1151, &ppc_fnmaddsdot}, {1202, &ppc_fmults}, {1203, &ppc_fmultsdot}, {1592, &ppc_fmsubs}, {1593, &ppc_fmsubsdot}, {1594, &ppc_fmadds}, {1595, &ppc_fmaddsdot},
{1208, &ppc_fmsubs}, {1209, &ppc_fmsubsdot}, {1210, &ppc_fmadds}, {1596, &ppc_fnmsubs}, {1597, &ppc_fnmsubsdot}, {1598, &ppc_fnmadds}, {1599, &ppc_fnmaddsdot},
{1211, &ppc_fmaddsdot}, {1212, &ppc_fnmsubs}, {1213, &ppc_fnmsubsdot}, {1650, &ppc_fmults}, {1651, &ppc_fmultsdot}, {1656, &ppc_fmsubs}, {1657, &ppc_fmsubsdot},
{1214, &ppc_fnmadds}, {1215, &ppc_fnmaddsdot}, {1266, &ppc_fmults}, {1658, &ppc_fmadds}, {1659, &ppc_fmaddsdot}, {1660, &ppc_fnmsubs}, {1661, &ppc_fnmsubsdot},
{1267, &ppc_fmultsdot}, {1272, &ppc_fmsubs}, {1273, &ppc_fmsubsdot}, {1662, &ppc_fnmadds}, {1663, &ppc_fnmaddsdot}, {1714, &ppc_fmults}, {1715, &ppc_fmultsdot},
{1274, &ppc_fmadds}, {1275, &ppc_fmaddsdot}, {1276, &ppc_fnmsubs}, {1720, &ppc_fmsubs}, {1721, &ppc_fmsubsdot}, {1722, &ppc_fmadds}, {1723, &ppc_fmaddsdot},
{1277, &ppc_fnmsubsdot}, {1278, &ppc_fnmadds}, {1279, &ppc_fnmaddsdot}, {1724, &ppc_fnmsubs}, {1725, &ppc_fnmsubsdot}, {1726, &ppc_fnmadds}, {1727, &ppc_fnmaddsdot},
{1330, &ppc_fmults}, {1331, &ppc_fmultsdot}, {1336, &ppc_fmsubs}, {1778, &ppc_fmults}, {1779, &ppc_fmultsdot}, {1784, &ppc_fmsubs}, {1785, &ppc_fmsubsdot},
{1337, &ppc_fmsubsdot}, {1338, &ppc_fmadds}, {1339, &ppc_fmaddsdot}, {1786, &ppc_fmadds}, {1787, &ppc_fmaddsdot}, {1788, &ppc_fnmsubs}, {1789, &ppc_fnmsubsdot},
{1340, &ppc_fnmsubs}, {1341, &ppc_fnmsubsdot}, {1342, &ppc_fnmadds}, {1790, &ppc_fnmadds}, {1791, &ppc_fnmaddsdot}, {1842, &ppc_fmults}, {1843, &ppc_fmultsdot},
{1343, &ppc_fnmaddsdot}, {1394, &ppc_fmults}, {1395, &ppc_fmultsdot}, {1848, &ppc_fmsubs}, {1849, &ppc_fmsubsdot}, {1850, &ppc_fmadds}, {1851, &ppc_fmaddsdot},
{1400, &ppc_fmsubs}, {1401, &ppc_fmsubsdot}, {1402, &ppc_fmadds}, {1852, &ppc_fnmsubs}, {1853, &ppc_fnmsubsdot}, {1854, &ppc_fnmadds}, {1855, &ppc_fnmaddsdot},
{1403, &ppc_fmaddsdot}, {1404, &ppc_fnmsubs}, {1405, &ppc_fnmsubsdot}, {1906, &ppc_fmults}, {1907, &ppc_fmultsdot}, {1912, &ppc_fmsubs}, {1913, &ppc_fmsubsdot},
{1406, &ppc_fnmadds}, {1407, &ppc_fnmaddsdot}, {1458, &ppc_fmults}, {1914, &ppc_fmadds}, {1915, &ppc_fmaddsdot}, {1916, &ppc_fnmsubs}, {1917, &ppc_fnmsubsdot},
{1459, &ppc_fmultsdot}, {1464, &ppc_fmsubs}, {1465, &ppc_fmsubsdot}, {1918, &ppc_fnmadds}, {1919, &ppc_fnmaddsdot}, {1970, &ppc_fmults}, {1971, &ppc_fmultsdot},
{1466, &ppc_fmadds}, {1467, &ppc_fmaddsdot}, {1468, &ppc_fnmsubs}, {1976, &ppc_fmsubs}, {1977, &ppc_fmsubsdot}, {1978, &ppc_fmadds}, {1979, &ppc_fmaddsdot},
{1469, &ppc_fnmsubsdot}, {1470, &ppc_fnmadds}, {1471, &ppc_fnmaddsdot}, {1980, &ppc_fnmsubs}, {1981, &ppc_fnmsubsdot}, {1982, &ppc_fnmadds}, {1983, &ppc_fnmaddsdot},
{1522, &ppc_fmults}, {1523, &ppc_fmultsdot}, {1528, &ppc_fmsubs}, {2034, &ppc_fmults}, {2035, &ppc_fmultsdot}, {2040, &ppc_fmsubs}, {2041, &ppc_fmsubsdot},
{1529, &ppc_fmsubsdot}, {1530, &ppc_fmadds}, {1531, &ppc_fmaddsdot}, {2042, &ppc_fmadds}, {2043, &ppc_fmaddsdot}, {2044, &ppc_fnmsubs}, {2045, &ppc_fnmsubsdot},
{1532, &ppc_fnmsubs}, {1533, &ppc_fnmsubsdot}, {1534, &ppc_fnmadds}, {2046, &ppc_fnmadds}, {2047, &ppc_fnmaddsdot}};
{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. */ /** Double-precision floating-point instructions decoding table. */
static std::unordered_map<uint16_t, PPCOpcode> SubOpcode63Grabber = { static std::unordered_map<uint16_t, PPCOpcode> SubOpcode63Grabber = {
{ 0, &ppc_fcmpu}, { 24, &ppc_frsp}, { 25, &ppc_frspdot}, {0, &ppc_fcmpu}, {24, &ppc_frsp}, {25, &ppc_frspdot}, {28, &ppc_fctiw},
{ 28, &ppc_fctiw}, { 29, &ppc_fctiwdot}, { 30, &ppc_fctiwz}, {29, &ppc_fctiwdot}, {30, &ppc_fctiwz}, {31, &ppc_fctiwzdot}, {36, &ppc_fdiv},
{ 31, &ppc_fctiwzdot}, { 36, &ppc_fdiv}, { 37, &ppc_fdivdot}, {37, &ppc_fdivdot}, {40, &ppc_fsub}, {41, &ppc_fsubdot}, {42, &ppc_fadd},
{ 40, &ppc_fsub}, { 41, &ppc_fsubdot}, { 42, &ppc_fadd}, {43, &ppc_fadddot}, {44, &ppc_fsqrt}, {45, &ppc_fsqrtdot}, {46, &ppc_fsel},
{ 43, &ppc_fadddot}, { 44, &ppc_fsqrt}, { 45, &ppc_fsqrtdot}, {47, &ppc_fseldot}, {50, &ppc_fmult}, {51, &ppc_fmultdot}, {52, &ppc_frsqrte},
{ 46, &ppc_fsel}, { 47, &ppc_fseldot}, { 50, &ppc_fmult}, {53, &ppc_frsqrtedot}, {56, &ppc_fmsub}, {57, &ppc_fmsubdot}, {58, &ppc_fmadd},
{ 51, &ppc_fmultdot}, { 52, &ppc_frsqrte}, { 53, &ppc_frsqrtedot}, {59, &ppc_fmadddot}, {60, &ppc_fnmsub}, {61, &ppc_fnmsubdot}, {62, &ppc_fnmadd},
{ 56, &ppc_fmsub}, { 57, &ppc_fmsubdot}, { 58, &ppc_fmadd}, {63, &ppc_fnmadddot}, {64, &ppc_fcmpo}, {76, &ppc_mtfsb1}, {77, &ppc_mtfsb1dot},
{ 59, &ppc_fmadddot}, { 60, &ppc_fnmsub}, { 61, &ppc_fnmsubdot}, {80, &ppc_fneg}, {81, &ppc_fnegdot}, {110, &ppc_fsel}, {111, &ppc_fseldot},
{ 62, &ppc_fnmadd}, { 63, &ppc_fnmadddot}, { 64, &ppc_fcmpo}, {114, &ppc_fmult}, {115, &ppc_fmultdot}, {120, &ppc_fmsub}, {121, &ppc_fmsubdot},
{ 76, &ppc_mtfsb1}, { 77, &ppc_mtfsb1dot}, { 80, &ppc_fneg}, {122, &ppc_fmadd}, {123, &ppc_fmadd}, {124, &ppc_fnmsub}, {125, &ppc_fnmsubdot},
{ 81, &ppc_fnegdot}, { 110, &ppc_fsel}, { 111, &ppc_fseldot}, {126, &ppc_fnmadd}, {127, &ppc_fnmadddot}, {128, &ppc_mcrfs}, {140, &ppc_mtfsb0},
{ 114, &ppc_fmult}, { 115, &ppc_fmultdot}, { 120, &ppc_fmsub}, {141, &ppc_mtfsb0dot}, {144, &ppc_fmr}, {174, &ppc_fsel}, {175, &ppc_fseldot},
{ 121, &ppc_fmsubdot}, { 122, &ppc_fmadd}, { 123, &ppc_fmadd}, {178, &ppc_fmult}, {179, &ppc_fmultdot}, {184, &ppc_fmsub}, {185, &ppc_fmsubdot},
{ 124, &ppc_fnmsub}, { 125, &ppc_fnmsubdot}, { 126, &ppc_fnmadd}, {186, &ppc_fmadd}, {187, &ppc_fmadddot}, {188, &ppc_fnmsub}, {189, &ppc_fnmsubdot},
{ 127, &ppc_fnmadddot}, { 128, &ppc_mcrfs}, { 140, &ppc_mtfsb0}, {190, &ppc_fnmadd}, {191, &ppc_fnmadddot}, {238, &ppc_fsel}, {239, &ppc_fseldot},
{ 141, &ppc_mtfsb0dot}, { 144, &ppc_fmr}, { 174, &ppc_fsel}, {242, &ppc_fmult}, {243, &ppc_fmultdot}, {248, &ppc_fmsub}, {249, &ppc_fmsubdot},
{ 175, &ppc_fseldot}, { 178, &ppc_fmult}, { 179, &ppc_fmultdot}, {250, &ppc_fmadd}, {251, &ppc_fmadddot}, {252, &ppc_fnmsub}, {253, &ppc_fnmsubdot},
{ 184, &ppc_fmsub}, { 185, &ppc_fmsubdot}, { 186, &ppc_fmadd}, {254, &ppc_fnmadd}, {255, &ppc_fnmadddot}, {268, &ppc_mtfsfi}, {272, &ppc_fnabs},
{ 187, &ppc_fmadddot}, { 188, &ppc_fnmsub}, { 189, &ppc_fnmsubdot}, {273, &ppc_fnabsdot}, {302, &ppc_fsel}, {303, &ppc_fseldot}, {306, &ppc_fmult},
{ 190, &ppc_fnmadd}, { 191, &ppc_fnmadddot}, { 238, &ppc_fsel}, {307, &ppc_fmultdot}, {312, &ppc_fmsub}, {313, &ppc_fmsubdot}, {314, &ppc_fmadd},
{ 239, &ppc_fseldot}, { 242, &ppc_fmult}, { 243, &ppc_fmultdot}, {315, &ppc_fmadddot}, {316, &ppc_fnmsub}, {317, &ppc_fnmsubdot}, {318, &ppc_fnmadd},
{ 248, &ppc_fmsub}, { 249, &ppc_fmsubdot}, { 250, &ppc_fmadd}, {319, &ppc_fnmadddot}, {366, &ppc_fsel}, {367, &ppc_fseldot}, {370, &ppc_fmult},
{ 251, &ppc_fmadddot}, { 252, &ppc_fnmsub}, { 253, &ppc_fnmsubdot}, {371, &ppc_fmultdot}, {376, &ppc_fmsub}, {377, &ppc_fmsubdot}, {378, &ppc_fmadd},
{ 254, &ppc_fnmadd}, { 255, &ppc_fnmadddot}, { 268, &ppc_mtfsfi}, {379, &ppc_fmadddot}, {380, &ppc_fnmsub}, {381, &ppc_fnmsubdot}, {382, &ppc_fnmadd},
{ 272, &ppc_fnabs}, { 273, &ppc_fnabsdot}, { 302, &ppc_fsel}, {383, &ppc_fnmadddot}, {430, &ppc_fsel}, {431, &ppc_fseldot}, {434, &ppc_fmult},
{ 303, &ppc_fseldot}, { 306, &ppc_fmult}, { 307, &ppc_fmultdot}, {435, &ppc_fmultdot}, {440, &ppc_fmsub}, {441, &ppc_fmsubdot}, {442, &ppc_fmadd},
{ 312, &ppc_fmsub}, { 313, &ppc_fmsubdot}, { 314, &ppc_fmadd}, {443, &ppc_fmadddot}, {444, &ppc_fnmsub}, {445, &ppc_fnmsubdot}, {446, &ppc_fnmadd},
{ 315, &ppc_fmadddot}, { 316, &ppc_fnmsub}, { 317, &ppc_fnmsubdot}, {447, &ppc_fnmadddot}, {494, &ppc_fsel}, {495, &ppc_fseldot}, {498, &ppc_fmult},
{ 318, &ppc_fnmadd}, { 319, &ppc_fnmadddot}, { 366, &ppc_fsel}, {499, &ppc_fmultdot}, {504, &ppc_fmsub}, {505, &ppc_fmsubdot}, {506, &ppc_fmadd},
{ 367, &ppc_fseldot}, { 370, &ppc_fmult}, { 371, &ppc_fmultdot}, {507, &ppc_fmadddot}, {508, &ppc_fnmsub}, {509, &ppc_fnmsubdot}, {510, &ppc_fnmadd},
{ 376, &ppc_fmsub}, { 377, &ppc_fmsubdot}, { 378, &ppc_fmadd}, {511, &ppc_fnmadddot}, {528, &ppc_fabs}, {529, &ppc_fabsdot}, {536, &ppc_mtfsfidot},
{ 379, &ppc_fmadddot}, { 380, &ppc_fnmsub}, { 381, &ppc_fnmsubdot}, {558, &ppc_fsel}, {559, &ppc_fseldot}, {562, &ppc_fmult}, {563, &ppc_fmultdot},
{ 382, &ppc_fnmadd}, { 383, &ppc_fnmadddot}, { 430, &ppc_fsel}, {568, &ppc_fmsub}, {569, &ppc_fmsubdot}, {570, &ppc_fmadd}, {571, &ppc_fmadddot},
{ 431, &ppc_fseldot}, { 434, &ppc_fmult}, { 435, &ppc_fmultdot}, {572, &ppc_fnmsub}, {573, &ppc_fnmsubdot}, {574, &ppc_fnmadd}, {575, &ppc_fnmadddot},
{ 440, &ppc_fmsub}, { 441, &ppc_fmsubdot}, { 442, &ppc_fmadd}, {622, &ppc_fsel}, {623, &ppc_fseldot}, {626, &ppc_fmult}, {627, &ppc_fmultdot},
{ 443, &ppc_fmadddot}, { 444, &ppc_fnmsub}, { 445, &ppc_fnmsubdot}, {632, &ppc_fmsub}, {633, &ppc_fmsubdot}, {634, &ppc_fmadd}, {635, &ppc_fmadddot},
{ 446, &ppc_fnmadd}, { 447, &ppc_fnmadddot}, { 494, &ppc_fsel}, {636, &ppc_fnmsub}, {637, &ppc_fnmsubdot}, {638, &ppc_fnmadd}, {639, &ppc_fnmadddot},
{ 495, &ppc_fseldot}, { 498, &ppc_fmult}, { 499, &ppc_fmultdot}, {686, &ppc_fsel}, {687, &ppc_fseldot}, {690, &ppc_fmult}, {691, &ppc_fmultdot},
{ 504, &ppc_fmsub}, { 505, &ppc_fmsubdot}, { 506, &ppc_fmadd}, {696, &ppc_fmsub}, {697, &ppc_fmsubdot}, {698, &ppc_fmadd}, {699, &ppc_fmadddot},
{ 507, &ppc_fmadddot}, { 508, &ppc_fnmsub}, { 509, &ppc_fnmsubdot}, {700, &ppc_fnmsub}, {701, &ppc_fnmsubdot}, {702, &ppc_fnmadd}, {703, &ppc_fnmadddot},
{ 510, &ppc_fnmadd}, { 511, &ppc_fnmadddot}, { 528, &ppc_fabs}, {750, &ppc_fsel}, {751, &ppc_fseldot}, {754, &ppc_fmult}, {755, &ppc_fmultdot},
{ 529, &ppc_fabsdot}, { 536, &ppc_mtfsfidot}, { 558, &ppc_fsel}, {760, &ppc_fmsub}, {761, &ppc_fmsubdot}, {762, &ppc_fmadd}, {763, &ppc_fmadddot},
{ 559, &ppc_fseldot}, { 562, &ppc_fmult}, { 563, &ppc_fmultdot}, {764, &ppc_fnmsub}, {765, &ppc_fnmsubdot}, {766, &ppc_fnmadd}, {767, &ppc_fnmadddot},
{ 568, &ppc_fmsub}, { 569, &ppc_fmsubdot}, { 570, &ppc_fmadd}, {814, &ppc_fsel}, {815, &ppc_fseldot}, {818, &ppc_fmult}, {819, &ppc_fmultdot},
{ 571, &ppc_fmadddot}, { 572, &ppc_fnmsub}, { 573, &ppc_fnmsubdot}, {824, &ppc_fmsub}, {825, &ppc_fmsubdot}, {826, &ppc_fmadd}, {827, &ppc_fmadddot},
{ 574, &ppc_fnmadd}, { 575, &ppc_fnmadddot}, { 622, &ppc_fsel}, {828, &ppc_fnmsub}, {829, &ppc_fnmsubdot}, {830, &ppc_fnmadd}, {831, &ppc_fnmadddot},
{ 623, &ppc_fseldot}, { 626, &ppc_fmult}, { 627, &ppc_fmultdot}, {878, &ppc_fsel}, {879, &ppc_fseldot}, {882, &ppc_fmult}, {883, &ppc_fmultdot},
{ 632, &ppc_fmsub}, { 633, &ppc_fmsubdot}, { 634, &ppc_fmadd}, {888, &ppc_fmsub}, {889, &ppc_fmsubdot}, {890, &ppc_fmadd}, {891, &ppc_fmadddot},
{ 635, &ppc_fmadddot}, { 636, &ppc_fnmsub}, { 637, &ppc_fnmsubdot}, {892, &ppc_fnmsub}, {893, &ppc_fnmsubdot}, {894, &ppc_fnmadd}, {895, &ppc_fnmadddot},
{ 638, &ppc_fnmadd}, { 639, &ppc_fnmadddot}, { 686, &ppc_fsel}, {942, &ppc_fsel}, {943, &ppc_fseldot}, {946, &ppc_fmult}, {947, &ppc_fmultdot},
{ 687, &ppc_fseldot}, { 690, &ppc_fmult}, { 691, &ppc_fmultdot}, {952, &ppc_fmsub}, {953, &ppc_fmsubdot}, {954, &ppc_fmadd}, {955, &ppc_fmadddot},
{ 696, &ppc_fmsub}, { 697, &ppc_fmsubdot}, { 698, &ppc_fmadd}, {957, &ppc_fnmsub}, {958, &ppc_fnmsubdot}, {958, &ppc_fnmadd}, {959, &ppc_fnmadddot},
{ 699, &ppc_fmadddot}, { 700, &ppc_fnmsub}, { 701, &ppc_fnmsubdot}, {1006, &ppc_fsel}, {1007, &ppc_fseldot}, {1010, &ppc_fmult}, {1011, &ppc_fmultdot},
{ 702, &ppc_fnmadd}, { 703, &ppc_fnmadddot}, { 750, &ppc_fsel}, {1016, &ppc_fmsub}, {1017, &ppc_fmsubdot}, {1018, &ppc_fmadd}, {1019, &ppc_fmadddot},
{ 751, &ppc_fseldot}, { 754, &ppc_fmult}, { 755, &ppc_fmultdot}, {1020, &ppc_fnmsub}, {1021, &ppc_fnmsubdot}, {1022, &ppc_fnmadd}, {1023, &ppc_fnmadddot},
{ 760, &ppc_fmsub}, { 761, &ppc_fmsubdot}, { 762, &ppc_fmadd}, {1070, &ppc_fsel}, {1071, &ppc_fseldot}, {1074, &ppc_fmult}, {1075, &ppc_fmultdot},
{ 763, &ppc_fmadddot}, { 764, &ppc_fnmsub}, { 765, &ppc_fnmsubdot}, {1080, &ppc_fmsub}, {1081, &ppc_fmsubdot}, {1082, &ppc_fmadd}, {1083, &ppc_fmadddot},
{ 766, &ppc_fnmadd}, { 767, &ppc_fnmadddot}, { 814, &ppc_fsel}, {1084, &ppc_fnmsub}, {1085, &ppc_fnmsubdot}, {1086, &ppc_fnmadd}, {1087, &ppc_fnmadddot},
{ 815, &ppc_fseldot}, { 818, &ppc_fmult}, { 819, &ppc_fmultdot}, {1134, &ppc_fsel}, {1135, &ppc_fseldot}, {1138, &ppc_fmult}, {1139, &ppc_fmultdot},
{ 824, &ppc_fmsub}, { 825, &ppc_fmsubdot}, { 826, &ppc_fmadd}, {1144, &ppc_fmsub}, {1145, &ppc_fmsubdot}, {1146, &ppc_fmadd}, {1147, &ppc_fmadddot},
{ 827, &ppc_fmadddot}, { 828, &ppc_fnmsub}, { 829, &ppc_fnmsubdot}, {1148, &ppc_fnmsub}, {1149, &ppc_fnmsubdot}, {1150, &ppc_fnmadd}, {1151, &ppc_fnmadddot},
{ 830, &ppc_fnmadd}, { 831, &ppc_fnmadddot}, { 878, &ppc_fsel}, {1166, &ppc_mffs}, {1167, &ppc_mffsdot}, {1198, &ppc_fsel}, {1199, &ppc_fseldot},
{ 879, &ppc_fseldot}, { 882, &ppc_fmult}, { 883, &ppc_fmultdot}, {1202, &ppc_fmult}, {1203, &ppc_fmultdot}, {1208, &ppc_fmsub}, {1209, &ppc_fmsubdot},
{ 888, &ppc_fmsub}, { 889, &ppc_fmsubdot}, { 890, &ppc_fmadd}, {1210, &ppc_fmadd}, {1211, &ppc_fmadddot}, {1212, &ppc_fnmsub}, {1213, &ppc_fnmsubdot},
{ 891, &ppc_fmadddot}, { 892, &ppc_fnmsub}, { 893, &ppc_fnmsubdot}, {1214, &ppc_fnmadd}, {1215, &ppc_fnmadddot}, {1262, &ppc_fsel}, {1263, &ppc_fseldot},
{ 894, &ppc_fnmadd}, { 895, &ppc_fnmadddot}, { 942, &ppc_fsel}, {1266, &ppc_fmult}, {1267, &ppc_fmultdot}, {1272, &ppc_fmsub}, {1273, &ppc_fmsubdot},
{ 943, &ppc_fseldot}, { 946, &ppc_fmult}, { 947, &ppc_fmultdot}, {1274, &ppc_fmadd}, {1275, &ppc_fmadddot}, {1276, &ppc_fnmsub}, {1277, &ppc_fnmsubdot},
{ 952, &ppc_fmsub}, { 953, &ppc_fmsubdot}, { 954, &ppc_fmadd}, {1278, &ppc_fnmadd}, {1279, &ppc_fnmadddot}, {1326, &ppc_fsel}, {1327, &ppc_fseldot},
{ 955, &ppc_fmadddot}, { 957, &ppc_fnmsub}, { 958, &ppc_fnmsubdot}, {1330, &ppc_fmult}, {1331, &ppc_fmultdot}, {1336, &ppc_fmsub}, {1337, &ppc_fmsubdot},
{ 958, &ppc_fnmadd}, { 959, &ppc_fnmadddot}, {1006, &ppc_fsel}, {1338, &ppc_fmadd}, {1339, &ppc_fmadddot}, {1340, &ppc_fnmsub}, {1341, &ppc_fnmsubdot},
{1007, &ppc_fseldot}, {1010, &ppc_fmult}, {1011, &ppc_fmultdot}, {1342, &ppc_fnmadd}, {1343, &ppc_fnmadddot}, {1390, &ppc_fsel}, {1391, &ppc_fseldot},
{1016, &ppc_fmsub}, {1017, &ppc_fmsubdot}, {1018, &ppc_fmadd}, {1394, &ppc_fmult}, {1395, &ppc_fmultdot}, {1400, &ppc_fmsub}, {1401, &ppc_fmsubdot},
{1019, &ppc_fmadddot}, {1020, &ppc_fnmsub}, {1021, &ppc_fnmsubdot}, {1402, &ppc_fmadd}, {1403, &ppc_fmadddot}, {1404, &ppc_fnmsub}, {1405, &ppc_fnmsubdot},
{1022, &ppc_fnmadd}, {1023, &ppc_fnmadddot}, {1070, &ppc_fsel}, {1406, &ppc_fnmadd}, {1407, &ppc_fnmadddot}, {1422, &ppc_mtfsf}, {1423, &ppc_mtfsfdot},
{1071, &ppc_fseldot}, {1074, &ppc_fmult}, {1075, &ppc_fmultdot}, {1454, &ppc_fsel}, {1455, &ppc_fseldot}, {1458, &ppc_fmult}, {1459, &ppc_fmultdot},
{1080, &ppc_fmsub}, {1081, &ppc_fmsubdot}, {1082, &ppc_fmadd}, {1464, &ppc_fmsub}, {1465, &ppc_fmsubdot}, {1466, &ppc_fmadd}, {1467, &ppc_fmadddot},
{1083, &ppc_fmadddot}, {1084, &ppc_fnmsub}, {1085, &ppc_fnmsubdot}, {1468, &ppc_fnmsub}, {1469, &ppc_fnmsubdot}, {1470, &ppc_fnmadd}, {1471, &ppc_fnmadddot},
{1086, &ppc_fnmadd}, {1087, &ppc_fnmadddot}, {1134, &ppc_fsel}, {1518, &ppc_fsel}, {1519, &ppc_fseldot}, {1522, &ppc_fmult}, {1523, &ppc_fmultdot},
{1135, &ppc_fseldot}, {1138, &ppc_fmult}, {1139, &ppc_fmultdot}, {1528, &ppc_fmsub}, {1529, &ppc_fmsubdot}, {1530, &ppc_fmadd}, {1531, &ppc_fmadddot},
{1144, &ppc_fmsub}, {1145, &ppc_fmsubdot}, {1146, &ppc_fmadd}, {1532, &ppc_fnmsub}, {1533, &ppc_fnmsubdot}, {1534, &ppc_fnmadd}, {1535, &ppc_fnmadddot},
{1147, &ppc_fmadddot}, {1148, &ppc_fnmsub}, {1149, &ppc_fnmsubdot}, {1582, &ppc_fsel}, {1583, &ppc_fseldot}, {1586, &ppc_fmult}, {1587, &ppc_fmultdot},
{1150, &ppc_fnmadd}, {1151, &ppc_fnmadddot}, {1166, &ppc_mffs}, {1592, &ppc_fmsub}, {1593, &ppc_fmsubdot}, {1594, &ppc_fmadd}, {1595, &ppc_fmadddot},
{1167, &ppc_mffsdot}, {1198, &ppc_fsel}, {1199, &ppc_fseldot}, {1596, &ppc_fnmsub}, {1597, &ppc_fnmsubdot}, {1598, &ppc_fnmadd}, {1599, &ppc_fnmadddot},
{1202, &ppc_fmult}, {1203, &ppc_fmultdot}, {1208, &ppc_fmsub}, {1646, &ppc_fsel}, {1647, &ppc_fseldot}, {1650, &ppc_fmult}, {1651, &ppc_fmultdot},
{1209, &ppc_fmsubdot}, {1210, &ppc_fmadd}, {1211, &ppc_fmadddot}, {1656, &ppc_fmsub}, {1657, &ppc_fmsubdot}, {1658, &ppc_fmadd}, {1659, &ppc_fmadddot},
{1212, &ppc_fnmsub}, {1213, &ppc_fnmsubdot}, {1214, &ppc_fnmadd}, {1660, &ppc_fnmsub}, {1661, &ppc_fnmsubdot}, {1662, &ppc_fnmadd}, {1663, &ppc_fnmadddot},
{1215, &ppc_fnmadddot}, {1262, &ppc_fsel}, {1263, &ppc_fseldot}, {1710, &ppc_fsel}, {1711, &ppc_fseldot}, {1714, &ppc_fmult}, {1715, &ppc_fmultdot},
{1266, &ppc_fmult}, {1267, &ppc_fmultdot}, {1272, &ppc_fmsub}, {1720, &ppc_fmsub}, {1721, &ppc_fmsubdot}, {1722, &ppc_fmadd}, {1723, &ppc_fmadddot},
{1273, &ppc_fmsubdot}, {1274, &ppc_fmadd}, {1275, &ppc_fmadddot}, {1724, &ppc_fnmsub}, {1725, &ppc_fnmsubdot}, {1726, &ppc_fnmadd}, {1727, &ppc_fnmadddot},
{1276, &ppc_fnmsub}, {1277, &ppc_fnmsubdot}, {1278, &ppc_fnmadd}, {1774, &ppc_fsel}, {1775, &ppc_fseldot}, {1778, &ppc_fmult}, {1779, &ppc_fmultdot},
{1279, &ppc_fnmadddot}, {1326, &ppc_fsel}, {1327, &ppc_fseldot}, {1784, &ppc_fmsub}, {1785, &ppc_fmsubdot}, {1786, &ppc_fmadd}, {1787, &ppc_fmadddot},
{1330, &ppc_fmult}, {1331, &ppc_fmultdot}, {1336, &ppc_fmsub}, {1788, &ppc_fnmsub}, {1789, &ppc_fnmsubdot}, {1790, &ppc_fnmadd}, {1791, &ppc_fnmadddot},
{1337, &ppc_fmsubdot}, {1338, &ppc_fmadd}, {1339, &ppc_fmadddot}, {1838, &ppc_fsel}, {1839, &ppc_fseldot}, {1842, &ppc_fmult}, {1843, &ppc_fmultdot},
{1340, &ppc_fnmsub}, {1341, &ppc_fnmsubdot}, {1342, &ppc_fnmadd}, {1848, &ppc_fmsub}, {1849, &ppc_fmsubdot}, {1850, &ppc_fmadd}, {1851, &ppc_fmadddot},
{1343, &ppc_fnmadddot}, {1390, &ppc_fsel}, {1391, &ppc_fseldot}, {1852, &ppc_fnmsub}, {1853, &ppc_fnmsubdot}, {1854, &ppc_fnmadd}, {1855, &ppc_fnmadddot},
{1394, &ppc_fmult}, {1395, &ppc_fmultdot}, {1400, &ppc_fmsub}, {1902, &ppc_fsel}, {1903, &ppc_fseldot}, {1906, &ppc_fmult}, {1907, &ppc_fmultdot},
{1401, &ppc_fmsubdot}, {1402, &ppc_fmadd}, {1403, &ppc_fmadddot}, {1912, &ppc_fmsub}, {1913, &ppc_fmsubdot}, {1914, &ppc_fmadd}, {1915, &ppc_fmadddot},
{1404, &ppc_fnmsub}, {1405, &ppc_fnmsubdot}, {1406, &ppc_fnmadd}, {1916, &ppc_fnmsub}, {1917, &ppc_fnmsubdot}, {1918, &ppc_fnmadd}, {1919, &ppc_fnmadddot},
{1407, &ppc_fnmadddot}, {1422, &ppc_mtfsf}, {1423, &ppc_mtfsfdot}, {1966, &ppc_fsel}, {1967, &ppc_fseldot}, {1970, &ppc_fmult}, {1971, &ppc_fmultdot},
{1454, &ppc_fsel}, {1455, &ppc_fseldot}, {1458, &ppc_fmult}, {1976, &ppc_fmsub}, {1977, &ppc_fmsubdot}, {1978, &ppc_fmadd}, {1979, &ppc_fmadddot},
{1459, &ppc_fmultdot}, {1464, &ppc_fmsub}, {1465, &ppc_fmsubdot}, {1980, &ppc_fnmsub}, {1981, &ppc_fnmsubdot}, {1982, &ppc_fnmadd}, {1983, &ppc_fnmadddot},
{1466, &ppc_fmadd}, {1467, &ppc_fmadddot}, {1468, &ppc_fnmsub}, {2030, &ppc_fsel}, {2031, &ppc_fseldot}, {2034, &ppc_fmult}, {2035, &ppc_fmultdot},
{1469, &ppc_fnmsubdot}, {1470, &ppc_fnmadd}, {1471, &ppc_fnmadddot}, {2040, &ppc_fmsub}, {2041, &ppc_fmsubdot}, {2042, &ppc_fmadd}, {2043, &ppc_fmadddot},
{1518, &ppc_fsel}, {1519, &ppc_fseldot}, {1522, &ppc_fmult}, {2044, &ppc_fnmsub}, {2045, &ppc_fnmsubdot}, {2046, &ppc_fnmadd}, {2047, &ppc_fnmadddot}};
{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}
};
/** Opcode decoding functions. */ /** Opcode decoding functions. */
@ -445,8 +418,11 @@ void ppc_opcode4() {
LOG_F(INFO, "Reading from Opcode 4 table \n"); LOG_F(INFO, "Reading from Opcode 4 table \n");
uint8_t subop_grab = ppc_cur_instruction & 3; uint8_t subop_grab = ppc_cur_instruction & 3;
uint32_t regrab = (uint32_t)subop_grab; uint32_t regrab = (uint32_t)subop_grab;
LOG_F(ERROR, "Executing subopcode entry %d \n" LOG_F(
".. or would if I bothered to implement it. SORRY!", regrab); ERROR,
"Executing subopcode entry %d \n"
".. or would if I bothered to implement it. SORRY!",
regrab);
exit(0); exit(0);
} }
@ -465,8 +441,7 @@ void ppc_opcode19() {
LOG_F(INFO, "Executing Opcode 19 table subopcode entry \n", regrab); LOG_F(INFO, "Executing Opcode 19 table subopcode entry \n", regrab);
if (SubOpcode19Grabber.count(subop_grab) == 1) { if (SubOpcode19Grabber.count(subop_grab) == 1) {
SubOpcode19Grabber[subop_grab](); SubOpcode19Grabber[subop_grab]();
} } else {
else {
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab); LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
} }
@ -482,8 +457,7 @@ void ppc_opcode31() {
LOG_F(INFO, "Executing Opcode 31 table subopcode entry \n", regrab); LOG_F(INFO, "Executing Opcode 31 table subopcode entry \n", regrab);
if (SubOpcode31Grabber.count(subop_grab) == 1) { if (SubOpcode31Grabber.count(subop_grab) == 1) {
SubOpcode31Grabber[subop_grab](); SubOpcode31Grabber[subop_grab]();
} } else {
else {
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab); LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
} }
@ -499,8 +473,7 @@ void ppc_opcode59() {
LOG_F(INFO, "Executing Opcode 59 table subopcode entry \n", regrab); LOG_F(INFO, "Executing Opcode 59 table subopcode entry \n", regrab);
if (SubOpcode59Grabber.count(subop_grab) == 1) { if (SubOpcode59Grabber.count(subop_grab) == 1) {
SubOpcode59Grabber[subop_grab](); SubOpcode59Grabber[subop_grab]();
} } else {
else {
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab); LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
} }
@ -516,8 +489,7 @@ void ppc_opcode63() {
LOG_F(INFO, "Executing Opcode 63 table subopcode entry \n", regrab); LOG_F(INFO, "Executing Opcode 63 table subopcode entry \n", regrab);
if (SubOpcode63Grabber.count(subop_grab) == 1) { if (SubOpcode63Grabber.count(subop_grab) == 1) {
SubOpcode63Grabber[subop_grab](); SubOpcode63Grabber[subop_grab]();
} } else {
else {
LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab); LOG_F(ERROR, "ILLEGAL SUBOPCODE: %d \n", subop_grab);
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x80000);
} }
@ -533,20 +505,17 @@ void ppc_main_opcode() {
} }
/** Old time base register (TBR) update code. */ /** Old time base register (TBR) update code. */
void tbr_update() void tbr_update() {
{
clock_t clock_test_current = clock(); clock_t clock_test_current = clock();
uint32_t test_clock = ((uint32_t)(clock_test_current - clock_test_begin)) / CLOCKS_PER_SEC; uint32_t test_clock = ((uint32_t)(clock_test_current - clock_test_begin)) / CLOCKS_PER_SEC;
if (test_clock) { if (test_clock) {
if (ppc_state.tbr[0] != 0xFFFFFFFF) { if (ppc_state.tbr[0] != 0xFFFFFFFF) {
ppc_state.tbr[0]++; ppc_state.tbr[0]++;
} } else {
else {
ppc_state.tbr[0] = 0; ppc_state.tbr[0] = 0;
if (ppc_state.tbr[1] != 0xFFFFFFFF) { if (ppc_state.tbr[1] != 0xFFFFFFFF) {
ppc_state.tbr[1]++; ppc_state.tbr[1]++;
} } else {
else {
ppc_state.tbr[1] = 0; ppc_state.tbr[1] = 0;
} }
} }
@ -584,8 +553,7 @@ void ppc_exec()
} }
} }
#else #else
void ppc_exec() void ppc_exec() {
{
uint32_t bb_start_la, page_start; uint32_t bb_start_la, page_start;
uint8_t* pc_real; uint8_t* pc_real;
@ -619,15 +587,13 @@ again:
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) { if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
page_start = bb_start_la & 0xFFFFF000; page_start = bb_start_la & 0xFFFFF000;
pc_real = quickinstruction_translate(bb_start_la); pc_real = quickinstruction_translate(bb_start_la);
} } else {
else {
pc_real += (int)bb_start_la - (int)ppc_state.pc; pc_real += (int)bb_start_la - (int)ppc_state.pc;
ppc_set_cur_instruction(pc_real); ppc_set_cur_instruction(pc_real);
} }
ppc_state.pc = bb_start_la; ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE; bb_kind = BB_end_kind::BB_NONE;
} } else {
else {
ppc_state.pc += 4; ppc_state.pc += 4;
pc_real += 4; pc_real += 4;
ppc_set_cur_instruction(pc_real); ppc_set_cur_instruction(pc_real);
@ -659,8 +625,7 @@ void ppc_exec_single()
} }
} }
#else #else
void ppc_exec_single() void ppc_exec_single() {
{
if (setjmp(exc_env)) { if (setjmp(exc_env)) {
/* reaching here means we got a low-level exception */ /* reaching here means we got a low-level exception */
timebase_counter += 1; timebase_counter += 1;
@ -674,8 +639,7 @@ void ppc_exec_single()
if (bb_kind != BB_end_kind::BB_NONE) { if (bb_kind != BB_end_kind::BB_NONE) {
ppc_state.pc = ppc_next_instruction_address; ppc_state.pc = ppc_next_instruction_address;
bb_kind = BB_end_kind::BB_NONE; bb_kind = BB_end_kind::BB_NONE;
} } else {
else {
ppc_state.pc += 4; ppc_state.pc += 4;
} }
timebase_counter += 1; timebase_counter += 1;
@ -708,8 +672,7 @@ void ppc_exec_until(uint32_t goal_addr)
} }
} }
#else #else
void ppc_exec_until(uint32_t goal_addr) void ppc_exec_until(uint32_t goal_addr) {
{
uint32_t bb_start_la, page_start; uint32_t bb_start_la, page_start;
uint8_t* pc_real; uint8_t* pc_real;
@ -743,15 +706,13 @@ again:
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) { if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
page_start = bb_start_la & 0xFFFFF000; page_start = bb_start_la & 0xFFFFF000;
pc_real = quickinstruction_translate(bb_start_la); pc_real = quickinstruction_translate(bb_start_la);
} } else {
else {
pc_real += (int)bb_start_la - (int)ppc_state.pc; pc_real += (int)bb_start_la - (int)ppc_state.pc;
ppc_set_cur_instruction(pc_real); ppc_set_cur_instruction(pc_real);
} }
ppc_state.pc = bb_start_la; ppc_state.pc = bb_start_la;
bb_kind = BB_end_kind::BB_NONE; bb_kind = BB_end_kind::BB_NONE;
} } else {
else {
ppc_state.pc += 4; ppc_state.pc += 4;
pc_real += 4; pc_real += 4;
ppc_set_cur_instruction(pc_real); ppc_set_cur_instruction(pc_real);
@ -760,8 +721,7 @@ again:
} }
#endif #endif
void ppc_cpu_init(MemCtrlBase *mem_ctrl, uint32_t proc_version) void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t proc_version) {
{
int i; int i;
mem_ctrl_instance = mem_ctrl; mem_ctrl_instance = mem_ctrl;
@ -816,11 +776,9 @@ void ppc_cpu_init(MemCtrlBase *mem_ctrl, uint32_t proc_version)
ppc_state.pc = 0xFFF00100; ppc_state.pc = 0xFFF00100;
} }
void print_gprs() void print_gprs() {
{
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
cout << "GPR " << dec << i << " : " << uppercase << hex cout << "GPR " << dec << i << " : " << uppercase << hex << ppc_state.gpr[i] << endl;
<< ppc_state.gpr[i] << endl;
cout << "PC: " << uppercase << hex << ppc_state.pc << endl; cout << "PC: " << uppercase << hex << ppc_state.pc << endl;
cout << "LR: " << uppercase << hex << ppc_state.spr[SPR::LR] << endl; cout << "LR: " << uppercase << hex << ppc_state.spr[SPR::LR] << endl;
@ -830,19 +788,15 @@ void print_gprs()
cout << "MSR: " << uppercase << hex << ppc_state.msr << endl; cout << "MSR: " << uppercase << hex << ppc_state.msr << endl;
} }
void print_fprs() void print_fprs() {
{
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
cout << "FPR " << dec << i << " : " << ppc_state.fpr[i].dbl64_r << endl; cout << "FPR " << dec << i << " : " << ppc_state.fpr[i].dbl64_r << endl;
} }
static map<string, int> SPRName2Num = { static map<string, int> SPRName2Num = {
{"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR}, {"DEC", SPR::DEC}, {"XER", SPR::XER}, {"LR", SPR::LR}, {"CTR", SPR::CTR}, {"DEC", SPR::DEC}, {"PVR", SPR::PVR}};
{"PVR", SPR::PVR}
};
uint64_t reg_op(string &reg_name, uint64_t val, bool is_write) uint64_t reg_op(string& reg_name, uint64_t val, bool is_write) {
{
string reg_name_u, reg_num_str; string reg_name_u, reg_num_str;
unsigned reg_num; unsigned reg_num;
map<string, int>::iterator spr; map<string, int>::iterator spr;
@ -853,9 +807,7 @@ uint64_t reg_op(string &reg_name, uint64_t val, bool is_write)
reg_name_u = reg_name; reg_name_u = reg_name;
/* convert reg_name string to uppercase */ /* convert reg_name string to uppercase */
std::for_each(reg_name_u.begin(), reg_name_u.end(), [](char & c) { std::for_each(reg_name_u.begin(), reg_name_u.end(), [](char& c) { c = ::toupper(c); });
c = ::toupper(c);
});
try { try {
if (reg_name_u == "PC") { if (reg_name_u == "PC") {
@ -925,20 +877,17 @@ uint64_t reg_op(string &reg_name, uint64_t val, bool is_write)
ppc_state.spr[spr->second] = val; ppc_state.spr[spr->second] = val;
return ppc_state.spr[spr->second]; return ppc_state.spr[spr->second];
} }
} } catch (...) {
catch (...) {
} }
bail_out: bail_out:
throw std::invalid_argument(string("Unknown register ") + reg_name); throw std::invalid_argument(string("Unknown register ") + reg_name);
} }
uint64_t get_reg(string &reg_name) uint64_t get_reg(string& reg_name) {
{
return reg_op(reg_name, 0, false); return reg_op(reg_name, 0, false);
} }
void set_reg(string &reg_name, uint64_t val) void set_reg(string& reg_name, uint64_t val) {
{
reg_op(reg_name, val, true); reg_op(reg_name, val, true);
} }

View File

@ -21,18 +21,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
// The opcodes for the processor - ppcopcodes.cpp // The opcodes for the processor - ppcopcodes.cpp
#include <iostream>
#include <map>
#include <unordered_map>
#include <cinttypes>
#include <array>
#include <stdio.h>
#include <stdexcept>
#include "ppcemu.h" #include "ppcemu.h"
#include "ppcmmu.h" #include "ppcmmu.h"
#include <array>
#include <cfenv> #include <cfenv>
#include <cinttypes>
#include <cmath> #include <cmath>
#include <iostream>
#include <limits> #include <limits>
#include <map>
#include <stdexcept>
#include <stdio.h>
#include <unordered_map>
// Used for FP calcs // Used for FP calcs
uint64_t ppc_result64_a; uint64_t ppc_result64_a;
@ -62,8 +62,7 @@ void ppc_store_sfpresult(bool int_rep) {
if (int_rep) { if (int_rep) {
ppc_state.fpr[reg_d].int64_r = ppc_result64_d; ppc_state.fpr[reg_d].int64_r = ppc_result64_d;
ppc_state.fpr[reg_d].dbl64_r = *(double*)&ppc_result64_d; ppc_state.fpr[reg_d].dbl64_r = *(double*)&ppc_result64_d;
} } else {
else {
ppc_state.fpr[reg_d].dbl64_r = ppc_dblresult64_d; ppc_state.fpr[reg_d].dbl64_r = ppc_dblresult64_d;
ppc_state.fpr[reg_d].int64_r = *(uint64_t*)&ppc_dblresult64_d; ppc_state.fpr[reg_d].int64_r = *(uint64_t*)&ppc_dblresult64_d;
} }
@ -73,8 +72,7 @@ void ppc_store_dfpresult(bool int_rep) {
if (int_rep) { if (int_rep) {
ppc_state.fpr[reg_d].int64_r = ppc_result64_d; ppc_state.fpr[reg_d].int64_r = ppc_result64_d;
ppc_state.fpr[reg_d].dbl64_r = *(double*)&ppc_result64_d; ppc_state.fpr[reg_d].dbl64_r = *(double*)&ppc_result64_d;
} } else {
else {
ppc_state.fpr[reg_d].dbl64_r = ppc_dblresult64_d; ppc_state.fpr[reg_d].dbl64_r = ppc_dblresult64_d;
ppc_state.fpr[reg_d].int64_r = *(uint64_t*)&ppc_dblresult64_d; ppc_state.fpr[reg_d].int64_r = *(uint64_t*)&ppc_dblresult64_d;
} }
@ -85,8 +83,7 @@ void ppc_grab_regsfpdb(bool int_rep) {
reg_b = (ppc_cur_instruction >> 11) & 31; reg_b = (ppc_cur_instruction >> 11) & 31;
if (int_rep) { if (int_rep) {
ppc_result64_b = ppc_state.fpr[reg_b].int64_r; ppc_result64_b = ppc_state.fpr[reg_b].int64_r;
} } else {
else {
ppc_dblresult64_b = ppc_state.fpr[reg_b].dbl64_r; ppc_dblresult64_b = ppc_state.fpr[reg_b].dbl64_r;
} }
} }
@ -96,7 +93,6 @@ void ppc_grab_regsfpdiab(bool int_rep) {
reg_a = (ppc_cur_instruction >> 16) & 31; reg_a = (ppc_cur_instruction >> 16) & 31;
reg_b = (ppc_cur_instruction >> 11) & 31; reg_b = (ppc_cur_instruction >> 11) & 31;
if (int_rep == true) { if (int_rep == true) {
} }
ppc_result_a = ppc_state.gpr[reg_a]; ppc_result_a = ppc_state.gpr[reg_a];
ppc_result_b = ppc_state.gpr[reg_b]; ppc_result_b = ppc_state.gpr[reg_b];
@ -132,8 +128,7 @@ void ppc_grab_regsfpsab(bool int_rep) {
ppc_result64_d = ppc_state.fpr[reg_s].int64_r; ppc_result64_d = ppc_state.fpr[reg_s].int64_r;
ppc_result64_a = ppc_state.fpr[reg_a].int64_r; ppc_result64_a = ppc_state.fpr[reg_a].int64_r;
ppc_result64_b = ppc_state.fpr[reg_b].int64_r; ppc_result64_b = ppc_state.fpr[reg_b].int64_r;
} } else {
else {
ppc_dblresult64_d = fp_return_double(reg_s); ppc_dblresult64_d = fp_return_double(reg_s);
ppc_dblresult64_a = fp_return_double(reg_a); ppc_dblresult64_a = fp_return_double(reg_a);
ppc_dblresult64_c = fp_return_double(reg_c); ppc_dblresult64_c = fp_return_double(reg_c);
@ -147,8 +142,7 @@ void ppc_grab_regsfpdab(bool int_rep) {
if (int_rep) { if (int_rep) {
ppc_result64_a = fp_return_uint64(reg_a); ppc_result64_a = fp_return_uint64(reg_a);
ppc_result64_b = fp_return_uint64(reg_b); ppc_result64_b = fp_return_uint64(reg_b);
} } else {
else {
ppc_dblresult64_a = fp_return_double(reg_a); ppc_dblresult64_a = fp_return_double(reg_a);
ppc_dblresult64_b = fp_return_double(reg_b); ppc_dblresult64_b = fp_return_double(reg_b);
} }
@ -161,8 +155,7 @@ void ppc_grab_regsfpdac(bool int_rep) {
if (int_rep) { if (int_rep) {
ppc_result64_a = fp_return_uint64(reg_a); ppc_result64_a = fp_return_uint64(reg_a);
ppc_result64_c = fp_return_uint64(reg_c); ppc_result64_c = fp_return_uint64(reg_c);
} } else {
else {
ppc_dblresult64_a = fp_return_double(reg_a); ppc_dblresult64_a = fp_return_double(reg_a);
ppc_dblresult64_c = fp_return_double(reg_c); ppc_dblresult64_c = fp_return_double(reg_c);
} }
@ -177,8 +170,7 @@ void ppc_grab_regsfpdabc(bool int_rep) {
ppc_result64_a = fp_return_uint64(reg_a); ppc_result64_a = fp_return_uint64(reg_a);
ppc_result64_b = fp_return_uint64(reg_b); ppc_result64_b = fp_return_uint64(reg_b);
ppc_result64_c = fp_return_uint64(reg_c); ppc_result64_c = fp_return_uint64(reg_c);
} } else {
else {
ppc_dblresult64_a = fp_return_double(reg_a); ppc_dblresult64_a = fp_return_double(reg_a);
ppc_dblresult64_b = fp_return_double(reg_b); ppc_dblresult64_b = fp_return_double(reg_b);
ppc_dblresult64_c = fp_return_double(reg_c); ppc_dblresult64_c = fp_return_double(reg_c);
@ -203,7 +195,6 @@ void fp_save_uint64(uint64_t entry) {
void fp_save_uint32(uint32_t entry) { void fp_save_uint32(uint32_t entry) {
ppc_state.fpr[reg_d].int64_r = entry; ppc_state.fpr[reg_d].int64_r = entry;
ppc_state.fpr[reg_d].dbl64_r = (double)entry; ppc_state.fpr[reg_d].dbl64_r = (double)entry;
} }
void ppc_fp_changecrf1() { void ppc_fp_changecrf1() {
@ -222,8 +213,7 @@ void ppc_divbyzero(uint64_t input_a, uint64_t input_b, bool is_single) {
int64_t round_to_nearest(double f) { int64_t round_to_nearest(double f) {
if (f >= 0.0) { if (f >= 0.0) {
return (int32_t)(int64_t)(f + 0.5); return (int32_t)(int64_t)(f + 0.5);
} } else {
else {
return (int32_t)(-(int64_t)(-f + 0.5)); return (int32_t)(-(int64_t)(-f + 0.5));
} }
} }
@ -265,8 +255,7 @@ bool ppc_confirm_inf_nan(uint32_t chosen_reg_1, uint32_t chosen_reg_2, bool is_s
ppc_state.fpscr |= 0x80400000; ppc_state.fpscr |= 0x80400000;
ppc_toggle_fpscr_fex(); ppc_toggle_fpscr_fex();
return true; return true;
} } else if ((input_a == 0) & (input_b == 0)) {
else if ((input_a == 0) & (input_b == 0)) {
ppc_state.fpscr |= 0x80200000; ppc_state.fpscr |= 0x80200000;
ppc_toggle_fpscr_fex(); ppc_toggle_fpscr_fex();
return true; return true;
@ -297,8 +286,7 @@ bool ppc_confirm_inf_nan(uint32_t chosen_reg_1, uint32_t chosen_reg_2, bool is_s
default: default:
return false; return false;
} }
} } else {
else {
uint32_t exp_a = (input_a >> 52) & 0x7ff; uint32_t exp_a = (input_a >> 52) & 0x7ff;
uint32_t exp_b = (input_b >> 52) & 0x7ff; uint32_t exp_b = (input_b >> 52) & 0x7ff;
@ -310,8 +298,7 @@ bool ppc_confirm_inf_nan(uint32_t chosen_reg_1, uint32_t chosen_reg_2, bool is_s
ppc_state.fpscr |= 0x80400000; ppc_state.fpscr |= 0x80400000;
ppc_toggle_fpscr_fex(); ppc_toggle_fpscr_fex();
return true; return true;
} } else if ((input_a == 0) & (input_b == 0)) {
else if ((input_a == 0) & (input_b == 0)) {
ppc_state.fpscr |= 0x80200000; ppc_state.fpscr |= 0x80200000;
ppc_toggle_fpscr_fex(); ppc_toggle_fpscr_fex();
return true; return true;
@ -348,7 +335,6 @@ bool ppc_confirm_inf_nan(uint32_t chosen_reg_1, uint32_t chosen_reg_2, bool is_s
} }
void fpresult_update(uint64_t set_result, bool confirm_arc) { void fpresult_update(uint64_t set_result, bool confirm_arc) {
bool confirm_ov = (bool)std::fetestexcept(FE_OVERFLOW); bool confirm_ov = (bool)std::fetestexcept(FE_OVERFLOW);
if (confirm_ov) { if (confirm_ov) {
@ -362,15 +348,12 @@ void fpresult_update(uint64_t set_result, bool confirm_arc) {
if (set_result == 0) { if (set_result == 0) {
ppc_state.fpscr |= 0x2000; ppc_state.fpscr |= 0x2000;
} } else {
else {
if (set_result < 0) { if (set_result < 0) {
ppc_state.fpscr |= 0x8000; ppc_state.fpscr |= 0x8000;
} } else if (set_result > 0) {
else if (set_result > 0) {
ppc_state.fpscr |= 0x4000; ppc_state.fpscr |= 0x4000;
} } else {
else {
ppc_state.fpscr |= 0x1000; ppc_state.fpscr |= 0x1000;
} }
} }
@ -378,9 +361,7 @@ void fpresult_update(uint64_t set_result, bool confirm_arc) {
} }
void ppc_frsqrte_result() { void ppc_frsqrte_result() {
if (ppc_result64_d & 0x007FF000000000000UL) { if (ppc_result64_d & 0x007FF000000000000UL) {
} }
} }
@ -638,7 +619,6 @@ void ppc_fmultsdot() {
ppc_grab_regsfpdac(false); ppc_grab_regsfpdac(false);
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 50)) { if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 50)) {
float intermediate = (float)ppc_dblresult64_a * (float)ppc_dblresult64_b; float intermediate = (float)ppc_dblresult64_a * (float)ppc_dblresult64_b;
ppc_dblresult64_d = static_cast<double>(intermediate); ppc_dblresult64_d = static_cast<double>(intermediate);
ppc_store_dfpresult(false); ppc_store_dfpresult(false);
@ -682,7 +662,6 @@ void ppc_fmadds() {
ppc_store_dfpresult(false); ppc_store_dfpresult(false);
} }
} }
} }
void ppc_fmaddsdot() { void ppc_fmaddsdot() {
@ -717,8 +696,6 @@ void ppc_fmsubs() {
ppc_store_dfpresult(false); ppc_store_dfpresult(false);
} }
} }
} }
void ppc_fmsubsdot() { void ppc_fmsubsdot() {
@ -793,7 +770,6 @@ void ppc_fnmsubs() {
ppc_store_dfpresult(false); ppc_store_dfpresult(false);
} }
} }
} }
void ppc_fnmsubsdot() { void ppc_fnmsubsdot() {
@ -873,8 +849,7 @@ void ppc_fsel() {
if (ppc_dblresult64_a >= 0.0) { if (ppc_dblresult64_a >= 0.0) {
ppc_dblresult64_d = ppc_dblresult64_c; ppc_dblresult64_d = ppc_dblresult64_c;
} } else {
else {
ppc_dblresult64_d = ppc_dblresult64_b; ppc_dblresult64_d = ppc_dblresult64_b;
} }
@ -886,8 +861,7 @@ void ppc_fseldot() {
if (ppc_dblresult64_a >= 0.0) { if (ppc_dblresult64_a >= 0.0) {
ppc_dblresult64_d = ppc_dblresult64_c; ppc_dblresult64_d = ppc_dblresult64_c;
} } else {
else {
ppc_dblresult64_d = ppc_dblresult64_b; ppc_dblresult64_d = ppc_dblresult64_b;
} }
@ -1001,7 +975,6 @@ void ppc_fctiw() {
} }
ppc_store_dfpresult(true); ppc_store_dfpresult(true);
} }
void ppc_fctiwdot() { void ppc_fctiwdot() {
@ -1057,8 +1030,7 @@ void ppc_lfsu() {
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_dfpresult(true); ppc_store_dfpresult(true);
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1078,8 +1050,7 @@ void ppc_lfsux() {
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_dfpresult(true); ppc_store_dfpresult(true);
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1101,8 +1072,7 @@ void ppc_lfdu() {
ppc_store_dfpresult(true); ppc_store_dfpresult(true);
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1122,8 +1092,7 @@ void ppc_lfdux() {
ppc_store_dfpresult(true); ppc_store_dfpresult(true);
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1143,8 +1112,7 @@ void ppc_stfsu() {
mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r)); mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1162,8 +1130,7 @@ void ppc_stfsux() {
mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r)); mem_write_dword(ppc_effective_address, uint32_t(ppc_state.fpr[reg_s].int64_r));
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1183,8 +1150,7 @@ void ppc_stfdu() {
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r); mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1202,8 +1168,7 @@ void ppc_stfdux() {
mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r); mem_write_qword(ppc_effective_address, ppc_state.fpr[reg_s].int64_r);
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1275,14 +1240,16 @@ void ppc_mtfsfi() {
ppc_result_b = (ppc_cur_instruction >> 11) & 15; ppc_result_b = (ppc_cur_instruction >> 11) & 15;
crf_d = (ppc_cur_instruction >> 23) & 7; crf_d = (ppc_cur_instruction >> 23) & 7;
crf_d = crf_d << 2; crf_d = crf_d << 2;
ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) | ((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d); ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) |
((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
} }
void ppc_mtfsfidot() { void ppc_mtfsfidot() {
ppc_result_b = (ppc_cur_instruction >> 11) & 15; ppc_result_b = (ppc_cur_instruction >> 11) & 15;
crf_d = (ppc_cur_instruction >> 23) & 7; crf_d = (ppc_cur_instruction >> 23) & 7;
crf_d = crf_d << 2; crf_d = crf_d << 2;
ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) | ((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d); ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) |
((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
ppc_fp_changecrf1(); ppc_fp_changecrf1();
} }
@ -1321,7 +1288,8 @@ void ppc_mcrfs() {
crf_d = crf_d << 2; crf_d = crf_d << 2;
crf_s = (ppc_cur_instruction >> 18) & 7; crf_s = (ppc_cur_instruction >> 18) & 7;
crf_s = crf_d << 2; crf_s = crf_d << 2;
ppc_state.cr = ~(ppc_state.cr & ((15 << (28 - crf_d)))) & (ppc_state.fpscr & (15 << (28 - crf_s))); ppc_state.cr = ~(ppc_state.cr & ((15 << (28 - crf_d)))) &
(ppc_state.fpscr & (15 << (28 - crf_s)));
} }
// Floating Point Comparisons // Floating Point Comparisons
@ -1339,14 +1307,11 @@ void ppc_fcmpo() {
if (std::isnan(db_test_a) || std::isnan(db_test_b)) { if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
cmp_c |= 0x01; cmp_c |= 0x01;
} } else if (db_test_a < db_test_b) {
else if (db_test_a < db_test_b) {
cmp_c |= 0x08; cmp_c |= 0x08;
} } else if (db_test_a > db_test_b) {
else if (db_test_a > db_test_b) {
cmp_c |= 0x04; cmp_c |= 0x04;
} } else {
else {
cmp_c |= 0x02; cmp_c |= 0x02;
} }
@ -1358,11 +1323,9 @@ void ppc_fcmpo() {
if (ppc_state.fpscr & 0x80) { if (ppc_state.fpscr & 0x80) {
ppc_state.fpscr |= 0x80000; ppc_state.fpscr |= 0x80000;
} }
} } else if ((db_test_a == qnan) || (db_test_b == qnan)) {
else if ((db_test_a == qnan) || (db_test_b == qnan)) {
ppc_state.fpscr |= 0x80000; ppc_state.fpscr |= 0x80000;
} }
} }
void ppc_fcmpu() { void ppc_fcmpu() {
@ -1378,14 +1341,11 @@ void ppc_fcmpu() {
if (std::isnan(db_test_a) || std::isnan(db_test_b)) { if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
cmp_c |= 0x01; cmp_c |= 0x01;
} } else if (db_test_a < db_test_b) {
else if (db_test_a < db_test_b) {
cmp_c |= 0x08; cmp_c |= 0x08;
} } else if (db_test_a > db_test_b) {
else if (db_test_a > db_test_b) {
cmp_c |= 0x04; cmp_c |= 0x04;
} } else {
else {
cmp_c |= 0x02; cmp_c |= 0x02;
} }

View File

@ -21,9 +21,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
// The uniquely Gekko opcodes for the processor - ppcgekkoopcodes.cpp // The uniquely Gekko opcodes for the processor - ppcgekkoopcodes.cpp
#include "ppcemu.h"
#include <iostream> #include <iostream>
#include <stdio.h> #include <stdio.h>
#include "ppcemu.h"
void ppc_psq_l() { void ppc_psq_l() {
printf("Hello. There's no GameCube emulation...yet. Goodbye."); printf("Hello. There's no GameCube emulation...yet. Goodbye.");

View File

@ -28,17 +28,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
- clarify what to do in the case of unaligned memory accesses - clarify what to do in the case of unaligned memory accesses
*/ */
#include <thirdparty/loguru/loguru.hpp>
#include <iostream>
#include <cstdint>
#include <cinttypes>
#include <string>
#include <stdexcept>
#include <array>
#include "memreadwrite.h"
#include "ppcemu.h"
#include "ppcmmu.h" #include "ppcmmu.h"
#include "devices/memctrlbase.h" #include "devices/memctrlbase.h"
#include "memreadwrite.h"
#include "ppcemu.h"
#include <array>
#include <cinttypes>
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <string>
#include <thirdparty/loguru/loguru.hpp>
/* pointer to exception handler to be called when a MMU exception is occured. */ /* pointer to exception handler to be called when a MMU exception is occured. */
void (*mmu_exception_handler)(Except_Type exception_type, uint32_t srr1_bits); void (*mmu_exception_handler)(Except_Type exception_type, uint32_t srr1_bits);
@ -68,17 +68,13 @@ AddressMapEntry last_dma_area = { 0 };
(ENTRY).end = entry->end; \ (ENTRY).end = entry->end; \
(ENTRY).mem_ptr = entry->mem_ptr; \ (ENTRY).mem_ptr = entry->mem_ptr; \
ret = OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start)); \ ret = OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start)); \
} \ } else if (entry->type & RT_MMIO) { \
else if (entry->type & RT_MMIO) { \ ret = entry->devobj->read(entry->start, (ADDR)-entry->start, (SIZE)); \
ret = entry->devobj->read(entry->start, (ADDR) - entry->start, \ } else { \
(SIZE)); \
} \
else { \
LOG_F(ERROR, "Please check your address map! \n"); \ LOG_F(ERROR, "Please check your address map! \n"); \
ret = (UNVAL); \ ret = (UNVAL); \
} \ } \
} \ } else { \
else { \
LOG_F(WARNING, "Read from unmapped memory at 0x%08X!\n", (ADDR)); \ LOG_F(WARNING, "Read from unmapped memory at 0x%08X!\n", (ADDR)); \
ret = (UNVAL); \ ret = (UNVAL); \
} \ } \
@ -98,48 +94,39 @@ AddressMapEntry last_dma_area = { 0 };
(ENTRY).end = entry->end; \ (ENTRY).end = entry->end; \
(ENTRY).mem_ptr = entry->mem_ptr; \ (ENTRY).mem_ptr = entry->mem_ptr; \
OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start), (VAL)); \ OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start), (VAL)); \
} \ } else if (entry->type & RT_MMIO) { \
else if (entry->type & RT_MMIO) { \ entry->devobj->write(entry->start, (ADDR)-entry->start, (VAL), (SIZE)); \
entry->devobj->write(entry->start, (ADDR) - entry->start, \ } else { \
(VAL), (SIZE)); \
} \
else { \
LOG_F(ERROR, "Please check your address map!\n"); \ LOG_F(ERROR, "Please check your address map!\n"); \
} \ } \
} \ } else { \
else { \
LOG_F(WARNING, "Write to unmapped memory at 0x%08X!\n", (ADDR)); \ LOG_F(WARNING, "Write to unmapped memory at 0x%08X!\n", (ADDR)); \
} \ } \
} \ } \
} }
uint8_t *mmu_get_dma_mem(uint32_t addr, uint32_t size) uint8_t* mmu_get_dma_mem(uint32_t addr, uint32_t size) {
{
if (addr >= last_dma_area.start && (addr + size) <= last_dma_area.end) { if (addr >= last_dma_area.start && (addr + size) <= last_dma_area.end) {
return last_dma_area.mem_ptr + (addr - last_dma_area.start); return last_dma_area.mem_ptr + (addr - last_dma_area.start);
} } else {
else {
AddressMapEntry* entry = mem_ctrl_instance->find_range(addr); AddressMapEntry* entry = mem_ctrl_instance->find_range(addr);
if (entry && entry->type & (RT_ROM | RT_RAM)) { if (entry && entry->type & (RT_ROM | RT_RAM)) {
last_dma_area.start = entry->start; last_dma_area.start = entry->start;
last_dma_area.end = entry->end; last_dma_area.end = entry->end;
last_dma_area.mem_ptr = entry->mem_ptr; last_dma_area.mem_ptr = entry->mem_ptr;
return last_dma_area.mem_ptr + (addr - last_dma_area.start); return last_dma_area.mem_ptr + (addr - last_dma_area.start);
} } else {
else {
LOG_F(ERROR, "SOS: DMA access to unmapped memory %08X!\n", addr); LOG_F(ERROR, "SOS: DMA access to unmapped memory %08X!\n", addr);
exit(-1); // FIXME: ugly error handling, must be the proper exception! exit(-1); // FIXME: ugly error handling, must be the proper exception!
} }
} }
} }
void ppc_set_cur_instruction(const uint8_t* ptr) void ppc_set_cur_instruction(const uint8_t* ptr) {
{
ppc_cur_instruction = READ_DWORD_BE_A(ptr); ppc_cur_instruction = READ_DWORD_BE_A(ptr);
} }
void ibat_update(uint32_t bat_reg) void ibat_update(uint32_t bat_reg) {
{
int upper_reg_num; int upper_reg_num;
uint32_t bl, lo_mask; uint32_t bl, lo_mask;
PPC_BAT_entry* bat_entry; PPC_BAT_entry* bat_entry;
@ -159,8 +146,7 @@ void ibat_update(uint32_t bat_reg)
} }
} }
void dbat_update(uint32_t bat_reg) void dbat_update(uint32_t bat_reg) {
{
int upper_reg_num; int upper_reg_num;
uint32_t bl, lo_mask; uint32_t bl, lo_mask;
PPC_BAT_entry* bat_entry; PPC_BAT_entry* bat_entry;
@ -180,41 +166,35 @@ void dbat_update(uint32_t bat_reg)
} }
} }
static inline uint8_t* calc_pteg_addr(uint32_t hash) static inline uint8_t* calc_pteg_addr(uint32_t hash) {
{
uint32_t sdr1_val, pteg_addr; uint32_t sdr1_val, pteg_addr;
sdr1_val = ppc_state.spr[SPR::SDR1]; sdr1_val = ppc_state.spr[SPR::SDR1];
pteg_addr = sdr1_val & 0xFE000000; pteg_addr = sdr1_val & 0xFE000000;
pteg_addr |= (sdr1_val & 0x01FF0000) | pteg_addr |= (sdr1_val & 0x01FF0000) | (((sdr1_val & 0x1FF) << 16) & ((hash & 0x7FC00) << 6));
(((sdr1_val & 0x1FF) << 16) & ((hash & 0x7FC00) << 6));
pteg_addr |= (hash & 0x3FF) << 6; pteg_addr |= (hash & 0x3FF) << 6;
if (pteg_addr >= last_ptab_area.start && pteg_addr <= last_ptab_area.end) { if (pteg_addr >= last_ptab_area.start && pteg_addr <= last_ptab_area.end) {
return last_ptab_area.mem_ptr + (pteg_addr - last_ptab_area.start); return last_ptab_area.mem_ptr + (pteg_addr - last_ptab_area.start);
} } else {
else {
AddressMapEntry* entry = mem_ctrl_instance->find_range(pteg_addr); AddressMapEntry* entry = mem_ctrl_instance->find_range(pteg_addr);
if (entry && entry->type & (RT_ROM | RT_RAM)) { if (entry && entry->type & (RT_ROM | RT_RAM)) {
last_ptab_area.start = entry->start; last_ptab_area.start = entry->start;
last_ptab_area.end = entry->end; last_ptab_area.end = entry->end;
last_ptab_area.mem_ptr = entry->mem_ptr; last_ptab_area.mem_ptr = entry->mem_ptr;
return last_ptab_area.mem_ptr + (pteg_addr - last_ptab_area.start); return last_ptab_area.mem_ptr + (pteg_addr - last_ptab_area.start);
} } else {
else {
LOG_F(ERROR, "SOS: no page table region was found at %08X!\n", pteg_addr); LOG_F(ERROR, "SOS: no page table region was found at %08X!\n", pteg_addr);
exit(-1); // FIXME: ugly error handling, must be the proper exception! exit(-1); // FIXME: ugly error handling, must be the proper exception!
} }
} }
} }
static bool search_pteg(uint8_t* pteg_addr, uint8_t** ret_pte_addr, static bool search_pteg(
uint32_t vsid, uint16_t page_index, uint8_t pteg_num) uint8_t* pteg_addr, uint8_t** ret_pte_addr, uint32_t vsid, uint16_t page_index, uint8_t pteg_num) {
{
/* construct PTE matching word */ /* construct PTE matching word */
uint32_t pte_check = 0x80000000 | (vsid << 7) | (pteg_num << 6) | uint32_t pte_check = 0x80000000 | (vsid << 7) | (pteg_num << 6) | (page_index >> 10);
(page_index >> 10);
#ifdef MMU_INTEGRITY_CHECKS #ifdef MMU_INTEGRITY_CHECKS
/* PTEG integrity check that ensures that all matching PTEs have /* PTEG integrity check that ensures that all matching PTEs have
@ -229,8 +209,7 @@ static bool search_pteg(uint8_t* pteg_addr, uint8_t** ret_pte_addr,
LOG_F(ERROR, "Multiple PTEs with different RPN/WIMG/PP found!\n"); LOG_F(ERROR, "Multiple PTEs with different RPN/WIMG/PP found!\n");
exit(-1); exit(-1);
} }
} } else {
else {
/* isolate RPN, WIMG and PP fields */ /* isolate RPN, WIMG and PP fields */
pte_word2_check = READ_DWORD_BE_A(pteg_addr) & 0xFFFFF07B; pte_word2_check = READ_DWORD_BE_A(pteg_addr) & 0xFFFFF07B;
*ret_pte_addr = pteg_addr; *ret_pte_addr = pteg_addr;
@ -249,9 +228,7 @@ static bool search_pteg(uint8_t* pteg_addr, uint8_t** ret_pte_addr,
return false; return false;
} }
static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch, static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch, unsigned msr_pr, int is_write) {
unsigned msr_pr, int is_write)
{
uint32_t sr_val, page_index, pteg_hash1, vsid, pte_word2; uint32_t sr_val, page_index, pteg_hash1, vsid, pte_word2;
unsigned key, pp; unsigned key, pp;
uint8_t* pte_addr; uint8_t* pte_addr;
@ -275,8 +252,7 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch,
if (!search_pteg(calc_pteg_addr(~pteg_hash1), &pte_addr, vsid, page_index, 1)) { if (!search_pteg(calc_pteg_addr(~pteg_hash1), &pte_addr, vsid, page_index, 1)) {
if (is_instr_fetch) { if (is_instr_fetch) {
mmu_exception_handler(Except_Type::EXC_ISI, 0x40000000); mmu_exception_handler(Except_Type::EXC_ISI, 0x40000000);
} } else {
else {
ppc_state.spr[SPR::DSISR] = 0x40000000 | (is_write << 25); ppc_state.spr[SPR::DSISR] = 0x40000000 | (is_write << 25);
ppc_state.spr[SPR::DAR] = la; ppc_state.spr[SPR::DAR] = la;
mmu_exception_handler(Except_Type::EXC_DSI, 0); mmu_exception_handler(Except_Type::EXC_DSI, 0);
@ -298,8 +274,7 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch,
if ((key && (!pp || (pp == 1 && is_write))) || (pp == 3 && is_write)) { if ((key && (!pp || (pp == 1 && is_write))) || (pp == 3 && is_write)) {
if (is_instr_fetch) { if (is_instr_fetch) {
mmu_exception_handler(Except_Type::EXC_ISI, 0x08000000); mmu_exception_handler(Except_Type::EXC_ISI, 0x08000000);
} } else {
else {
ppc_state.spr[SPR::DSISR] = 0x08000000 | (is_write << 25); ppc_state.spr[SPR::DSISR] = 0x08000000 | (is_write << 25);
ppc_state.spr[SPR::DAR] = la; ppc_state.spr[SPR::DAR] = la;
mmu_exception_handler(Except_Type::EXC_DSI, 0); mmu_exception_handler(Except_Type::EXC_DSI, 0);
@ -318,8 +293,7 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch,
} }
/** PowerPC-style MMU instruction address translation. */ /** PowerPC-style MMU instruction address translation. */
static uint32_t ppc_mmu_instr_translate(uint32_t la) static uint32_t ppc_mmu_instr_translate(uint32_t la) {
{
uint32_t pa; /* translated physical address */ uint32_t pa; /* translated physical address */
bool bat_hit = false; bool bat_hit = false;
@ -333,8 +307,7 @@ static uint32_t ppc_mmu_instr_translate(uint32_t la)
for (int bat_index = 0; bat_index < 4; bat_index++) { for (int bat_index = 0; bat_index < 4; bat_index++) {
PPC_BAT_entry* bat_entry = &ibat_array[bat_index]; PPC_BAT_entry* bat_entry = &ibat_array[bat_index];
if ((bat_entry->access & access_bits) && if ((bat_entry->access & access_bits) && ((la & ~bat_entry->lo_mask) == bat_entry->bepi)) {
((la & ~bat_entry->lo_mask) == bat_entry->bepi)) {
bat_hit = true; bat_hit = true;
if (!bat_entry->prot) { if (!bat_entry->prot) {
@ -356,8 +329,7 @@ static uint32_t ppc_mmu_instr_translate(uint32_t la)
} }
/** PowerPC-style MMU data address translation. */ /** PowerPC-style MMU data address translation. */
static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write) static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write) {
{
#ifdef PROFILER #ifdef PROFILER
mmu_translations_num++; mmu_translations_num++;
#endif #endif
@ -375,8 +347,7 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write)
for (int bat_index = 0; bat_index < 4; bat_index++) { for (int bat_index = 0; bat_index < 4; bat_index++) {
PPC_BAT_entry* bat_entry = &dbat_array[bat_index]; PPC_BAT_entry* bat_entry = &dbat_array[bat_index];
if ((bat_entry->access & access_bits) && if ((bat_entry->access & access_bits) && ((la & ~bat_entry->lo_mask) == bat_entry->bepi)) {
((la & ~bat_entry->lo_mask) == bat_entry->bepi)) {
bat_hit = true; bat_hit = true;
if (!bat_entry->prot || ((bat_entry->prot & 1) && is_write)) { if (!bat_entry->prot || ((bat_entry->prot & 1) && is_write)) {
@ -399,8 +370,7 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write)
return pa; return pa;
} }
static void mem_write_unaligned(uint32_t addr, uint32_t value, uint32_t size) static void mem_write_unaligned(uint32_t addr, uint32_t value, uint32_t size) {
{
LOG_F(WARNING, "Attempt to write unaligned %d bytes to 0x%08X\n", size, addr); LOG_F(WARNING, "Attempt to write unaligned %d bytes to 0x%08X\n", size, addr);
if (((addr & 0xFFF) + size) > 0x1000) { if (((addr & 0xFFF) + size) > 0x1000) {
@ -420,8 +390,7 @@ static void mem_write_unaligned(uint32_t addr, uint32_t value, uint32_t size)
} }
} }
void mem_write_byte(uint32_t addr, uint8_t value) void mem_write_byte(uint32_t addr, uint8_t value) {
{
/* data address translation if enabled */ /* data address translation if enabled */
if (ppc_state.msr & 0x10) { if (ppc_state.msr & 0x10) {
addr = ppc_mmu_addr_translate(addr, 1); addr = ppc_mmu_addr_translate(addr, 1);
@ -432,8 +401,7 @@ void mem_write_byte(uint32_t addr, uint8_t value)
WRITE_PHYS_MEM(last_write_area, addr, WRITE_BYTE, value, 1); WRITE_PHYS_MEM(last_write_area, addr, WRITE_BYTE, value, 1);
} }
void mem_write_word(uint32_t addr, uint16_t value) void mem_write_word(uint32_t addr, uint16_t value) {
{
if (addr & 1) { if (addr & 1) {
mem_write_unaligned(addr, value, 2); mem_write_unaligned(addr, value, 2);
} }
@ -446,8 +414,7 @@ void mem_write_word(uint32_t addr, uint16_t value)
WRITE_PHYS_MEM(last_write_area, addr, WRITE_WORD_BE_A, value, 2); WRITE_PHYS_MEM(last_write_area, addr, WRITE_WORD_BE_A, value, 2);
} }
void mem_write_dword(uint32_t addr, uint32_t value) void mem_write_dword(uint32_t addr, uint32_t value) {
{
if (addr & 3) { if (addr & 3) {
mem_write_unaligned(addr, value, 4); mem_write_unaligned(addr, value, 4);
} }
@ -460,8 +427,7 @@ void mem_write_dword(uint32_t addr, uint32_t value)
WRITE_PHYS_MEM(last_write_area, addr, WRITE_DWORD_BE_A, value, 4); WRITE_PHYS_MEM(last_write_area, addr, WRITE_DWORD_BE_A, value, 4);
} }
void mem_write_qword(uint32_t addr, uint64_t value) void mem_write_qword(uint32_t addr, uint64_t value) {
{
if (addr & 7) { if (addr & 7) {
LOG_F(ERROR, "SOS! Attempt to write unaligned QWORD to 0x%08X\n", addr); LOG_F(ERROR, "SOS! Attempt to write unaligned QWORD to 0x%08X\n", addr);
exit(-1); // FIXME! exit(-1); // FIXME!
@ -475,8 +441,7 @@ void mem_write_qword(uint32_t addr, uint64_t value)
WRITE_PHYS_MEM(last_write_area, addr, WRITE_QWORD_BE_A, value, 8); WRITE_PHYS_MEM(last_write_area, addr, WRITE_QWORD_BE_A, value, 8);
} }
static uint32_t mem_grab_unaligned(uint32_t addr, uint32_t size) static uint32_t mem_grab_unaligned(uint32_t addr, uint32_t size) {
{
uint32_t ret = 0; uint32_t ret = 0;
LOG_F(WARNING, "Attempt to read unaligned %d bytes from 0x%08X\n", size, addr); LOG_F(WARNING, "Attempt to read unaligned %d bytes from 0x%08X\n", size, addr);
@ -501,8 +466,7 @@ static uint32_t mem_grab_unaligned(uint32_t addr, uint32_t size)
} }
/** Grab a value from memory into a register */ /** Grab a value from memory into a register */
uint8_t mem_grab_byte(uint32_t addr) uint8_t mem_grab_byte(uint32_t addr) {
{
uint8_t ret; uint8_t ret;
/* data address translation if enabled */ /* data address translation if enabled */
@ -514,8 +478,7 @@ uint8_t mem_grab_byte(uint32_t addr)
return ret; return ret;
} }
uint16_t mem_grab_word(uint32_t addr) uint16_t mem_grab_word(uint32_t addr) {
{
uint16_t ret; uint16_t ret;
if (addr & 1) { if (addr & 1) {
@ -531,8 +494,7 @@ uint16_t mem_grab_word(uint32_t addr)
return ret; return ret;
} }
uint32_t mem_grab_dword(uint32_t addr) uint32_t mem_grab_dword(uint32_t addr) {
{
uint32_t ret; uint32_t ret;
if (addr & 3) { if (addr & 3) {
@ -548,8 +510,7 @@ uint32_t mem_grab_dword(uint32_t addr)
return ret; return ret;
} }
uint64_t mem_grab_qword(uint32_t addr) uint64_t mem_grab_qword(uint32_t addr) {
{
uint64_t ret; uint64_t ret;
if (addr & 7) { if (addr & 7) {
@ -566,8 +527,7 @@ uint64_t mem_grab_qword(uint32_t addr)
return ret; return ret;
} }
uint8_t* quickinstruction_translate(uint32_t addr) uint8_t* quickinstruction_translate(uint32_t addr) {
{
uint8_t* real_addr; uint8_t* real_addr;
/* perform instruction address translation if enabled */ /* perform instruction address translation if enabled */
@ -578,8 +538,7 @@ uint8_t* quickinstruction_translate(uint32_t addr)
if (addr >= last_exec_area.start && addr <= last_exec_area.end) { if (addr >= last_exec_area.start && addr <= last_exec_area.end) {
real_addr = last_exec_area.mem_ptr + (addr - last_exec_area.start); real_addr = last_exec_area.mem_ptr + (addr - last_exec_area.start);
ppc_set_cur_instruction(real_addr); ppc_set_cur_instruction(real_addr);
} } else {
else {
AddressMapEntry* entry = mem_ctrl_instance->find_range(addr); AddressMapEntry* entry = mem_ctrl_instance->find_range(addr);
if (entry && entry->type & (RT_ROM | RT_RAM)) { if (entry && entry->type & (RT_ROM | RT_RAM)) {
last_exec_area.start = entry->start; last_exec_area.start = entry->start;
@ -587,8 +546,7 @@ uint8_t* quickinstruction_translate(uint32_t addr)
last_exec_area.mem_ptr = entry->mem_ptr; last_exec_area.mem_ptr = entry->mem_ptr;
real_addr = last_exec_area.mem_ptr + (addr - last_exec_area.start); real_addr = last_exec_area.mem_ptr + (addr - last_exec_area.start);
ppc_set_cur_instruction(real_addr); ppc_set_cur_instruction(real_addr);
} } else {
else {
LOG_F(WARNING, "attempt to execute code at %08X!\n", addr); LOG_F(WARNING, "attempt to execute code at %08X!\n", addr);
exit(-1); // FIXME: ugly error handling, must be the proper exception! exit(-1); // FIXME: ugly error handling, must be the proper exception!
} }
@ -597,8 +555,7 @@ uint8_t* quickinstruction_translate(uint32_t addr)
return real_addr; return real_addr;
} }
uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size) uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size) {
{
uint32_t save_dsisr, save_dar; uint32_t save_dsisr, save_dar;
uint64_t ret_val; uint64_t ret_val;
@ -624,8 +581,7 @@ uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size)
default: default:
ret_val = mem_grab_byte(virt_addr); ret_val = mem_grab_byte(virt_addr);
} }
} } catch (std::invalid_argument& exc) {
catch (std::invalid_argument& exc) {
/* restore MMU-related CPU state */ /* restore MMU-related CPU state */
mmu_exception_handler = ppc_exception_handler; mmu_exception_handler = ppc_exception_handler;
ppc_state.spr[SPR::DSISR] = save_dsisr; ppc_state.spr[SPR::DSISR] = save_dsisr;
@ -643,7 +599,6 @@ uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size)
return ret_val; return ret_val;
} }
void ppc_mmu_init() void ppc_mmu_init() {
{
mmu_exception_handler = ppc_exception_handler; mmu_exception_handler = ppc_exception_handler;
} }

View File

@ -24,9 +24,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PPCMEMORY_H #ifndef PPCMEMORY_H
#define PPCMEMORY_H #define PPCMEMORY_H
#include <array>
#include <cinttypes> #include <cinttypes>
#include <vector> #include <vector>
#include <array>
/* Uncomment this to exhaustive MMU integrity checks. */ /* Uncomment this to exhaustive MMU integrity checks. */
//#define MMU_INTEGRITY_CHECKS //#define MMU_INTEGRITY_CHECKS

View File

@ -21,17 +21,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
// General opcodes for the processor - ppcopcodes.cpp // General opcodes for the processor - ppcopcodes.cpp
#include <thirdparty/loguru/loguru.hpp>
#include <iostream>
#include <cstring>
#include <cinttypes>
#include <array>
#include <thread>
#include <stdio.h>
#include <stdlib.h>
#include <stdexcept>
#include "ppcemu.h" #include "ppcemu.h"
#include "ppcmmu.h" #include "ppcmmu.h"
#include <array>
#include <cinttypes>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <stdio.h>
#include <stdlib.h>
#include <thirdparty/loguru/loguru.hpp>
#include <thread>
uint32_t crf_d; uint32_t crf_d;
uint32_t crf_s; uint32_t crf_s;
@ -151,12 +151,10 @@ void ppc_changecrf0(uint32_t set_result) {
if (set_result == 0) { if (set_result == 0) {
ppc_state.cr |= 0x20000000UL; ppc_state.cr |= 0x20000000UL;
} } else {
else {
if (set_result & 0x80000000) { if (set_result & 0x80000000) {
ppc_state.cr |= 0x80000000UL; ppc_state.cr |= 0x80000000UL;
} } else {
else {
ppc_state.cr |= 0x40000000UL; ppc_state.cr |= 0x40000000UL;
} }
} }
@ -169,8 +167,7 @@ void ppc_changecrf0(uint32_t set_result) {
inline void ppc_carry(uint32_t a, uint32_t b) { inline void ppc_carry(uint32_t a, uint32_t b) {
if (b < a) { if (b < a) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
} }
@ -178,8 +175,7 @@ inline void ppc_carry(uint32_t a, uint32_t b) {
inline void ppc_carry_sub(uint32_t a, uint32_t b) { inline void ppc_carry_sub(uint32_t a, uint32_t b) {
if (b >= a) { if (b >= a) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
} }
@ -189,16 +185,16 @@ inline void ppc_carry_sub(uint32_t a, uint32_t b) {
inline void ppc_setsoov(uint32_t a, uint32_t b, uint32_t d) { inline void ppc_setsoov(uint32_t a, uint32_t b, uint32_t d) {
if ((a ^ b) & (a ^ d) & 0x80000000UL) { if ((a ^ b) & (a ^ d) & 0x80000000UL) {
ppc_state.spr[SPR::XER] |= 0xC0000000UL; ppc_state.spr[SPR::XER] |= 0xC0000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
} }
} }
/** /**
The core functionality of this PPC emulation is within all of these void functions. The core functionality of this PPC emulation is within all of these void functions.
This is where the opcode tables in the ppcemumain.h come into play - reducing the number of comparisons needed. This is where the opcode tables in the ppcemumain.h come into play - reducing the number of
This means loads of functions, but less CPU cycles needed to determine the function (theoretically). comparisons needed. This means loads of functions, but less CPU cycles needed to determine the
function (theoretically).
**/ **/
void ppc_addi() { void ppc_addi() {
@ -295,8 +291,7 @@ void ppc_adde() {
ppc_result_d = ppc_result_a + ppc_result_b + xer_ca; ppc_result_d = ppc_result_a + ppc_result_b + xer_ca;
if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) { if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -308,8 +303,7 @@ void ppc_addedot() {
ppc_result_d = ppc_result_a + ppc_result_b + xer_ca; ppc_result_d = ppc_result_a + ppc_result_b + xer_ca;
if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) { if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
@ -322,8 +316,7 @@ void ppc_addeo() {
ppc_result_d = ppc_result_a + ppc_result_b + xer_ca; ppc_result_d = ppc_result_a + ppc_result_b + xer_ca;
if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) { if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d); ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d);
@ -336,8 +329,7 @@ void ppc_addeodot() {
ppc_result_d = ppc_result_a + ppc_result_b + xer_ca; ppc_result_d = ppc_result_a + ppc_result_b + xer_ca;
if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) { if ((ppc_result_d < ppc_result_a) || (xer_ca && (ppc_result_d == ppc_result_a))) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d); ppc_setsoov(ppc_result_a, ~ppc_result_b, ppc_result_d);
@ -351,8 +343,7 @@ void ppc_addme() {
ppc_result_d = ppc_result_a + xer_ca - 1; ppc_result_d = ppc_result_a + xer_ca - 1;
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) { if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -364,8 +355,7 @@ void ppc_addmedot() {
ppc_result_d = ppc_result_a + xer_ca - 1; ppc_result_d = ppc_result_a + xer_ca - 1;
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) { if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
@ -379,8 +369,7 @@ void ppc_addmeo() {
ppc_setsoov(ppc_result_a, 0, ppc_result_d); ppc_setsoov(ppc_result_a, 0, ppc_result_d);
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) { if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -394,8 +383,7 @@ void ppc_addmeodot() {
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) { if (((xer_ca - 1) < 0xFFFFFFFFUL) | (ppc_result_d < ppc_result_a)) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -407,8 +395,7 @@ void ppc_addze() {
ppc_result_d = ppc_result_a + grab_xer; ppc_result_d = ppc_result_a + grab_xer;
if (ppc_result_d < ppc_result_a) { if (ppc_result_d < ppc_result_a) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -420,8 +407,7 @@ void ppc_addzedot() {
ppc_result_d = ppc_result_a + grab_xer; ppc_result_d = ppc_result_a + grab_xer;
if (ppc_result_d < ppc_result_a) { if (ppc_result_d < ppc_result_a) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
@ -435,8 +421,7 @@ void ppc_addzeo() {
ppc_setsoov(ppc_result_a, 0xFFFFFFFFUL, ppc_result_d); ppc_setsoov(ppc_result_a, 0xFFFFFFFFUL, ppc_result_d);
if (ppc_result_d < ppc_result_a) { if (ppc_result_d < ppc_result_a) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -449,8 +434,7 @@ void ppc_addzeodot() {
ppc_setsoov(ppc_result_a, 0xFFFFFFFFUL, ppc_result_d); ppc_setsoov(ppc_result_a, 0xFFFFFFFFUL, ppc_result_d);
if (ppc_result_d < ppc_result_a) { if (ppc_result_d < ppc_result_a) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
@ -896,8 +880,7 @@ void ppc_mullwo() {
int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b; int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b;
if (product != (int64_t)(int32_t)product) { if (product != (int64_t)(int32_t)product) {
ppc_state.spr[SPR::XER] |= 0xC0000000; ppc_state.spr[SPR::XER] |= 0xC0000000;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
} }
ppc_result_d = (uint32_t)product; ppc_result_d = (uint32_t)product;
@ -909,8 +892,7 @@ void ppc_mullwodot() {
int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b; int64_t product = (int64_t)(int32_t)ppc_result_a * (int64_t)(int32_t)ppc_result_b;
if (product != (int64_t)(int32_t)product) { if (product != (int64_t)(int32_t)product) {
ppc_state.spr[SPR::XER] |= 0xC0000000; ppc_state.spr[SPR::XER] |= 0xC0000000;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
} }
ppc_result_d = (uint32_t)product; ppc_result_d = (uint32_t)product;
@ -931,11 +913,9 @@ void ppc_divw() {
if (!ppc_result_b) { /* handle the "anything / 0" case */ if (!ppc_result_b) { /* handle the "anything / 0" case */
ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */ ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
} } else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
ppc_result_d = 0xFFFFFFFF; ppc_result_d = 0xFFFFFFFF;
} } else { /* normal signed devision */
else { /* normal signed devision */
ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b; ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b;
} }
@ -947,11 +927,9 @@ void ppc_divwdot() {
if (!ppc_result_b) { /* handle the "anything / 0" case */ if (!ppc_result_b) { /* handle the "anything / 0" case */
ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */ ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
} } else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
ppc_result_d = 0xFFFFFFFF; ppc_result_d = 0xFFFFFFFF;
} } else { /* normal signed devision */
else { /* normal signed devision */
ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b; ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b;
} }
@ -965,12 +943,10 @@ void ppc_divwo() {
if (!ppc_result_b) { /* handle the "anything / 0" case */ if (!ppc_result_b) { /* handle the "anything / 0" case */
ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */ ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
ppc_state.spr[SPR::XER] |= 0xC0000000; ppc_state.spr[SPR::XER] |= 0xC0000000;
} } else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
ppc_result_d = 0xFFFFFFFF; ppc_result_d = 0xFFFFFFFF;
ppc_state.spr[SPR::XER] |= 0xC0000000; ppc_state.spr[SPR::XER] |= 0xC0000000;
} } else { /* normal signed devision */
else { /* normal signed devision */
ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b; ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b;
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
} }
@ -984,12 +960,10 @@ void ppc_divwodot() {
if (!ppc_result_b) { /* handle the "anything / 0" case */ if (!ppc_result_b) { /* handle the "anything / 0" case */
ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */ ppc_result_d = (ppc_result_a & 0x80000000) ? -1 : 0; /* UNDOCUMENTED! */
ppc_state.spr[SPR::XER] |= 0xC0000000; ppc_state.spr[SPR::XER] |= 0xC0000000;
} } else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
else if (ppc_result_a == 0x80000000UL && ppc_result_b == 0xFFFFFFFFUL) {
ppc_result_d = 0xFFFFFFFF; ppc_result_d = 0xFFFFFFFF;
ppc_state.spr[SPR::XER] |= 0xC0000000; ppc_state.spr[SPR::XER] |= 0xC0000000;
} } else { /* normal signed devision */
else { /* normal signed devision */
ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b; ppc_result_d = (int32_t)ppc_result_a / (int32_t)ppc_result_b;
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
} }
@ -1003,8 +977,7 @@ void ppc_divwu() {
if (!ppc_result_b) { /* division by zero */ if (!ppc_result_b) { /* division by zero */
ppc_result_d = 0; ppc_result_d = 0;
} } else {
else {
ppc_result_d = ppc_result_a / ppc_result_b; ppc_result_d = ppc_result_a / ppc_result_b;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -1016,8 +989,7 @@ void ppc_divwudot() {
if (!ppc_result_b) { /* division by zero */ if (!ppc_result_b) { /* division by zero */
ppc_result_d = 0; ppc_result_d = 0;
ppc_state.cr |= 0x20000000; ppc_state.cr |= 0x20000000;
} } else {
else {
ppc_result_d = ppc_result_a / ppc_result_b; ppc_result_d = ppc_result_a / ppc_result_b;
ppc_changecrf0(ppc_result_d); ppc_changecrf0(ppc_result_d);
} }
@ -1030,8 +1002,7 @@ void ppc_divwuo() {
if (!ppc_result_b) { /* division by zero */ if (!ppc_result_b) { /* division by zero */
ppc_result_d = 0; ppc_result_d = 0;
ppc_state.spr[SPR::XER] |= 0xC0000000; ppc_state.spr[SPR::XER] |= 0xC0000000;
} } else {
else {
ppc_result_d = ppc_result_a / ppc_result_b; ppc_result_d = ppc_result_a / ppc_result_b;
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
} }
@ -1044,8 +1015,7 @@ void ppc_divwuodot() {
if (!ppc_result_b) { /* division by zero */ if (!ppc_result_b) { /* division by zero */
ppc_result_d = 0; ppc_result_d = 0;
ppc_state.spr[SPR::XER] |= 0xC0000000; ppc_state.spr[SPR::XER] |= 0xC0000000;
} } else {
else {
ppc_result_d = ppc_result_a / ppc_result_b; ppc_result_d = ppc_result_a / ppc_result_b;
ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xBFFFFFFFUL;
} }
@ -1059,8 +1029,7 @@ void ppc_slw() {
ppc_grab_regssab(); ppc_grab_regssab();
if (ppc_result_b & 0x20) { if (ppc_result_b & 0x20) {
ppc_result_a = 0; ppc_result_a = 0;
} } else {
else {
ppc_result_a = ppc_result_d << (ppc_result_b & 0x1F); ppc_result_a = ppc_result_d << (ppc_result_b & 0x1F);
} }
ppc_store_result_rega(); ppc_store_result_rega();
@ -1070,8 +1039,7 @@ void ppc_slwdot() {
ppc_grab_regssab(); ppc_grab_regssab();
if (ppc_result_b & 0x20) { if (ppc_result_b & 0x20) {
ppc_result_a = 0; ppc_result_a = 0;
} } else {
else {
ppc_result_a = ppc_result_d << (ppc_result_b & 0x1F); ppc_result_a = ppc_result_d << (ppc_result_b & 0x1F);
} }
ppc_changecrf0(ppc_result_a); ppc_changecrf0(ppc_result_a);
@ -1082,8 +1050,7 @@ void ppc_srw() {
ppc_grab_regssab(); ppc_grab_regssab();
if (ppc_result_b & 0x20) { if (ppc_result_b & 0x20) {
ppc_result_a = 0; ppc_result_a = 0;
} } else {
else {
ppc_result_a = ppc_result_d >> (ppc_result_b & 0x1F); ppc_result_a = ppc_result_d >> (ppc_result_b & 0x1F);
} }
ppc_store_result_rega(); ppc_store_result_rega();
@ -1093,8 +1060,7 @@ void ppc_srwdot() {
ppc_grab_regssab(); ppc_grab_regssab();
if (ppc_result_b & 0x20) { if (ppc_result_b & 0x20) {
ppc_result_a = 0; ppc_result_a = 0;
} } else {
else {
ppc_result_a = ppc_result_d >> (ppc_result_b & 0x1F); ppc_result_a = ppc_result_d >> (ppc_result_b & 0x1F);
} }
ppc_changecrf0(ppc_result_a); ppc_changecrf0(ppc_result_a);
@ -1106,15 +1072,13 @@ void ppc_sraw() {
if (ppc_result_b & 0x20) { if (ppc_result_b & 0x20) {
ppc_result_a = (int32_t)ppc_result_d >> 31; ppc_result_a = (int32_t)ppc_result_d >> 31;
ppc_state.spr[SPR::XER] |= (ppc_result_a & 1) << 29; ppc_state.spr[SPR::XER] |= (ppc_result_a & 1) << 29;
} } else {
else {
uint32_t shift = ppc_result_b & 0x1F; uint32_t shift = ppc_result_b & 0x1F;
uint32_t mask = (1 << shift) - 1; uint32_t mask = (1 << shift) - 1;
ppc_result_a = (int32_t)ppc_result_d >> shift; ppc_result_a = (int32_t)ppc_result_d >> shift;
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) { if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
} }
@ -1126,15 +1090,13 @@ void ppc_srawdot() {
if (ppc_result_b & 0x20) { if (ppc_result_b & 0x20) {
ppc_result_a = (int32_t)ppc_result_d >> 31; ppc_result_a = (int32_t)ppc_result_d >> 31;
ppc_state.spr[SPR::XER] |= (ppc_result_a & 1) << 29; ppc_state.spr[SPR::XER] |= (ppc_result_a & 1) << 29;
} } else {
else {
uint32_t shift = ppc_result_b & 0x1F; uint32_t shift = ppc_result_b & 0x1F;
uint32_t mask = (1 << shift) - 1; uint32_t mask = (1 << shift) - 1;
ppc_result_a = (int32_t)ppc_result_d >> shift; ppc_result_a = (int32_t)ppc_result_d >> shift;
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) { if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
} }
@ -1149,8 +1111,7 @@ void ppc_srawi() {
ppc_result_a = (int32_t)ppc_result_d >> shift; ppc_result_a = (int32_t)ppc_result_d >> shift;
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) { if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_store_result_rega(); ppc_store_result_rega();
@ -1163,8 +1124,7 @@ void ppc_srawidot() {
ppc_result_a = (int32_t)ppc_result_d >> shift; ppc_result_a = (int32_t)ppc_result_d >> shift;
if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) { if ((ppc_result_d & 0x80000000UL) && (ppc_result_d & mask)) {
ppc_state.spr[SPR::XER] |= 0x20000000UL; ppc_state.spr[SPR::XER] |= 0x20000000UL;
} } else {
else {
ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL; ppc_state.spr[SPR::XER] &= 0xDFFFFFFFUL;
} }
ppc_changecrf0(ppc_result_a); ppc_changecrf0(ppc_result_a);
@ -1172,8 +1132,7 @@ void ppc_srawidot() {
} }
/** mask generator for rotate and shift instructions (§ 4.2.1.4 PowerpC PEM) */ /** mask generator for rotate and shift instructions (§ 4.2.1.4 PowerpC PEM) */
static inline uint32_t rot_mask(unsigned rot_mb, unsigned rot_me) static inline uint32_t rot_mask(unsigned rot_mb, unsigned rot_me) {
{
uint32_t m1 = 0xFFFFFFFFUL >> rot_mb; uint32_t m1 = 0xFFFFFFFFUL >> rot_mb;
uint32_t m2 = 0xFFFFFFFFUL << (31 - rot_me); uint32_t m2 = 0xFFFFFFFFUL << (31 - rot_me);
return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2); return ((rot_mb <= rot_me) ? m2 & m1 : m1 | m2);
@ -1320,8 +1279,7 @@ void ppc_mtspr() {
switch (ref_spr) { switch (ref_spr) {
// Mirror the TBRs in the SPR range to the user-mode TBRs. // Mirror the TBRs in the SPR range to the user-mode TBRs.
case 284: case 284:
timebase_counter = (timebase_counter & 0xFFFFFFFF00000000ULL) + timebase_counter = (timebase_counter & 0xFFFFFFFF00000000ULL) + ppc_state.gpr[reg_s];
ppc_state.gpr[reg_s];
break; break;
case 285: case 285:
timebase_counter = (timebase_counter & 0x00000000FFFFFFFFULL) + timebase_counter = (timebase_counter & 0x00000000FFFFFFFFULL) +
@ -1383,21 +1341,24 @@ void ppc_mtcrf() {
void ppc_mcrxr() { void ppc_mcrxr() {
crf_d = (ppc_cur_instruction >> 23) & 7; crf_d = (ppc_cur_instruction >> 23) & 7;
crf_d = crf_d << 2; crf_d = crf_d << 2;
ppc_state.cr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) | ((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d); ppc_state.cr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) |
((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
ppc_state.spr[SPR::XER] &= 0x0FFFFFFF; ppc_state.spr[SPR::XER] &= 0x0FFFFFFF;
} }
void ppc_extsb() { void ppc_extsb() {
ppc_grab_regssa(); ppc_grab_regssa();
ppc_result_d = ppc_result_d & 0xFF; ppc_result_d = ppc_result_d & 0xFF;
ppc_result_a = (ppc_result_d < 0x80) ? (ppc_result_d & 0x000000FF) : (0xFFFFFF00UL | (ppc_result_d & 0x000000FF)); ppc_result_a = (ppc_result_d < 0x80) ? (ppc_result_d & 0x000000FF)
: (0xFFFFFF00UL | (ppc_result_d & 0x000000FF));
ppc_store_result_rega(); ppc_store_result_rega();
} }
void ppc_extsbdot() { void ppc_extsbdot() {
ppc_grab_regssa(); ppc_grab_regssa();
ppc_result_d = ppc_result_d & 0xFF; ppc_result_d = ppc_result_d & 0xFF;
ppc_result_a = (ppc_result_d < 0x80) ? (ppc_result_d & 0x000000FF) : (0xFFFFFF00UL | (ppc_result_d & 0x000000FF)); ppc_result_a = (ppc_result_d < 0x80) ? (ppc_result_d & 0x000000FF)
: (0xFFFFFF00UL | (ppc_result_d & 0x000000FF));
ppc_changecrf0(ppc_result_a); ppc_changecrf0(ppc_result_a);
ppc_store_result_rega(); ppc_store_result_rega();
} }
@ -1405,14 +1366,16 @@ void ppc_extsbdot() {
void ppc_extsh() { void ppc_extsh() {
ppc_grab_regssa(); ppc_grab_regssa();
ppc_result_d = ppc_result_d & 0xFFFF; ppc_result_d = ppc_result_d & 0xFFFF;
ppc_result_a = (ppc_result_d < 0x8000) ? (ppc_result_d & 0x0000FFFF) : (0xFFFF0000UL | (ppc_result_d & 0x0000FFFF)); ppc_result_a = (ppc_result_d < 0x8000) ? (ppc_result_d & 0x0000FFFF)
: (0xFFFF0000UL | (ppc_result_d & 0x0000FFFF));
ppc_store_result_rega(); ppc_store_result_rega();
} }
void ppc_extshdot() { void ppc_extshdot() {
ppc_grab_regssa(); ppc_grab_regssa();
ppc_result_d = ppc_result_d & 0xFFFF; ppc_result_d = ppc_result_d & 0xFFFF;
ppc_result_a = (ppc_result_d < 0x8000) ? (ppc_result_d & 0x0000FFFF) : (0xFFFF0000UL | (ppc_result_d & 0x0000FFFF)); ppc_result_a = (ppc_result_d < 0x8000) ? (ppc_result_d & 0x0000FFFF)
: (0xFFFF0000UL | (ppc_result_d & 0x0000FFFF));
ppc_changecrf0(ppc_result_a); ppc_changecrf0(ppc_result_a);
ppc_store_result_rega(); ppc_store_result_rega();
} }
@ -1457,8 +1420,7 @@ void ppc_bla() {
bb_kind = BB_end_kind::BB_BRANCH; bb_kind = BB_end_kind::BB_BRANCH;
} }
void ppc_bc() void ppc_bc() {
{
uint32_t ctr_ok; uint32_t ctr_ok;
uint32_t cnd_ok; uint32_t cnd_ok;
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31; uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
@ -1478,8 +1440,7 @@ void ppc_bc()
} }
} }
void ppc_bca() void ppc_bca() {
{
uint32_t ctr_ok; uint32_t ctr_ok;
uint32_t cnd_ok; uint32_t cnd_ok;
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31; uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
@ -1499,8 +1460,7 @@ void ppc_bca()
} }
} }
void ppc_bcl() void ppc_bcl() {
{
uint32_t ctr_ok; uint32_t ctr_ok;
uint32_t cnd_ok; uint32_t cnd_ok;
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31; uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
@ -1521,8 +1481,7 @@ void ppc_bcl()
ppc_state.spr[SPR::LR] = ppc_state.pc + 4; ppc_state.spr[SPR::LR] = ppc_state.pc + 4;
} }
void ppc_bcla() void ppc_bcla() {
{
uint32_t ctr_ok; uint32_t ctr_ok;
uint32_t cnd_ok; uint32_t cnd_ok;
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31; uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
@ -1543,12 +1502,12 @@ void ppc_bcla()
ppc_state.spr[SPR::LR] = ppc_state.pc + 4; ppc_state.spr[SPR::LR] = ppc_state.pc + 4;
} }
void ppc_bcctr() void ppc_bcctr() {
{
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31; uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31; uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
uint32_t cnd_ok = (br_bo & 0x10) || (!(ppc_state.cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08)); uint32_t cnd_ok = (br_bo & 0x10) ||
(!(ppc_state.cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
if (cnd_ok) { if (cnd_ok) {
ppc_next_instruction_address = (ppc_state.spr[SPR::CTR] & 0xFFFFFFFCUL); ppc_next_instruction_address = (ppc_state.spr[SPR::CTR] & 0xFFFFFFFCUL);
@ -1557,12 +1516,12 @@ void ppc_bcctr()
} }
} }
void ppc_bcctrl() void ppc_bcctrl() {
{
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31; uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31; uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
uint32_t cnd_ok = (br_bo & 0x10) || (!(ppc_state.cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08)); uint32_t cnd_ok = (br_bo & 0x10) ||
(!(ppc_state.cr & (0x80000000UL >> br_bi)) == !(br_bo & 0x08));
if (cnd_ok) { if (cnd_ok) {
ppc_next_instruction_address = (ppc_state.spr[SPR::CTR] & 0xFFFFFFFCUL); ppc_next_instruction_address = (ppc_state.spr[SPR::CTR] & 0xFFFFFFFCUL);
@ -1572,8 +1531,7 @@ void ppc_bcctrl()
ppc_state.spr[SPR::LR] = ppc_state.pc + 4; ppc_state.spr[SPR::LR] = ppc_state.pc + 4;
} }
void ppc_bclr() void ppc_bclr() {
{
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31; uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31; uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
uint32_t ctr_ok; uint32_t ctr_ok;
@ -1592,8 +1550,7 @@ void ppc_bclr()
} }
} }
void ppc_bclrl() void ppc_bclrl() {
{
uint32_t br_bo = (ppc_cur_instruction >> 21) & 31; uint32_t br_bo = (ppc_cur_instruction >> 21) & 31;
uint32_t br_bi = (ppc_cur_instruction >> 16) & 31; uint32_t br_bi = (ppc_cur_instruction >> 16) & 31;
uint32_t ctr_ok; uint32_t ctr_ok;
@ -1626,7 +1583,9 @@ void ppc_cmp() {
crf_d = crf_d << 2; crf_d = crf_d << 2;
ppc_grab_regssab(); ppc_grab_regssab();
xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3; xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3;
cmp_c = (((int32_t)ppc_result_a) == ((int32_t)ppc_result_b)) ? 0x20000000UL : (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) ? 0x40000000UL : 0x80000000UL; cmp_c = (((int32_t)ppc_result_a) == ((int32_t)ppc_result_b))
? 0x20000000UL
: (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) ? 0x40000000UL : 0x80000000UL;
ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d)); ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d));
} }
@ -1642,7 +1601,9 @@ void ppc_cmpi() {
crf_d = crf_d << 2; crf_d = crf_d << 2;
ppc_grab_regsasimm(); ppc_grab_regsasimm();
xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3; xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3;
cmp_c = (((int32_t)ppc_result_a) == simm) ? 0x20000000UL : (((int32_t)ppc_result_a) > simm) ? 0x40000000UL : 0x80000000UL; cmp_c = (((int32_t)ppc_result_a) == simm)
? 0x20000000UL
: (((int32_t)ppc_result_a) > simm) ? 0x40000000UL : 0x80000000UL;
ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d)); ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d));
} }
@ -1658,7 +1619,9 @@ void ppc_cmpl() {
crf_d = crf_d << 2; crf_d = crf_d << 2;
ppc_grab_regssab(); ppc_grab_regssab();
xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3; xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3;
cmp_c = (ppc_result_a == ppc_result_b) ? 0x20000000UL : (ppc_result_a > ppc_result_b) ? 0x40000000UL : 0x80000000UL; cmp_c = (ppc_result_a == ppc_result_b)
? 0x20000000UL
: (ppc_result_a > ppc_result_b) ? 0x40000000UL : 0x80000000UL;
ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d)); ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d));
} }
@ -1674,7 +1637,8 @@ void ppc_cmpli() {
crf_d = crf_d << 2; crf_d = crf_d << 2;
ppc_grab_regssauimm(); ppc_grab_regssauimm();
xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3; xercon = (ppc_state.spr[SPR::XER] & 0x80000000UL) >> 3;
cmp_c = (ppc_result_a == uimm) ? 0x20000000UL : (ppc_result_a > uimm) ? 0x40000000UL : 0x80000000UL; cmp_c = (ppc_result_a == uimm) ? 0x20000000UL
: (ppc_result_a > uimm) ? 0x40000000UL : 0x80000000UL;
ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d)); ppc_state.cr = ((ppc_state.cr & ~(0xf0000000UL >> crf_d)) | ((cmp_c + xercon) >> crf_d));
} }
@ -1684,8 +1648,7 @@ void ppc_crand() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if ((ppc_state.cr & (0x80000000UL >> reg_a)) && (ppc_state.cr & (0x80000000UL >> reg_b))) { if ((ppc_state.cr & (0x80000000UL >> reg_a)) && (ppc_state.cr & (0x80000000UL >> reg_b))) {
ppc_state.cr |= (0x80000000UL >> reg_d); ppc_state.cr |= (0x80000000UL >> reg_d);
} } else {
else {
ppc_state.cr &= ~(0x80000000UL >> reg_d); ppc_state.cr &= ~(0x80000000UL >> reg_d);
} }
} }
@ -1693,8 +1656,7 @@ void ppc_crandc() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if ((ppc_state.cr & (0x80000000UL >> reg_a)) && !(ppc_state.cr & (0x80000000UL >> reg_b))) { if ((ppc_state.cr & (0x80000000UL >> reg_a)) && !(ppc_state.cr & (0x80000000UL >> reg_b))) {
ppc_state.cr |= (0x80000000UL >> reg_d); ppc_state.cr |= (0x80000000UL >> reg_d);
} } else {
else {
ppc_state.cr &= ~(0x80000000UL >> reg_d); ppc_state.cr &= ~(0x80000000UL >> reg_d);
} }
} }
@ -1702,8 +1664,7 @@ void ppc_creqv() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if (!((ppc_state.cr & (0x80000000UL >> reg_a)) ^ (ppc_state.cr & (0x80000000UL >> reg_b)))) { if (!((ppc_state.cr & (0x80000000UL >> reg_a)) ^ (ppc_state.cr & (0x80000000UL >> reg_b)))) {
ppc_state.cr |= (0x80000000UL >> reg_d); ppc_state.cr |= (0x80000000UL >> reg_d);
} } else {
else {
ppc_state.cr &= ~(0x80000000UL >> reg_d); ppc_state.cr &= ~(0x80000000UL >> reg_d);
} }
} }
@ -1711,8 +1672,7 @@ void ppc_crnand() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if (!((ppc_state.cr & (0x80000000UL >> reg_a)) && (ppc_state.cr & (0x80000000UL >> reg_b)))) { if (!((ppc_state.cr & (0x80000000UL >> reg_a)) && (ppc_state.cr & (0x80000000UL >> reg_b)))) {
ppc_state.cr |= (0x80000000UL >> reg_d); ppc_state.cr |= (0x80000000UL >> reg_d);
} } else {
else {
ppc_state.cr &= ~(0x80000000UL >> reg_d); ppc_state.cr &= ~(0x80000000UL >> reg_d);
} }
} }
@ -1720,8 +1680,7 @@ void ppc_crnor() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if (!((ppc_state.cr & (0x80000000UL >> reg_a)) || (ppc_state.cr & (0x80000000UL >> reg_b)))) { if (!((ppc_state.cr & (0x80000000UL >> reg_a)) || (ppc_state.cr & (0x80000000UL >> reg_b)))) {
ppc_state.cr |= (0x80000000UL >> reg_d); ppc_state.cr |= (0x80000000UL >> reg_d);
} } else {
else {
ppc_state.cr &= ~(0x80000000UL >> reg_d); ppc_state.cr &= ~(0x80000000UL >> reg_d);
} }
} }
@ -1730,8 +1689,7 @@ void ppc_cror() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if ((ppc_state.cr & (0x80000000UL >> reg_a)) || (ppc_state.cr & (0x80000000UL >> reg_b))) { if ((ppc_state.cr & (0x80000000UL >> reg_a)) || (ppc_state.cr & (0x80000000UL >> reg_b))) {
ppc_state.cr |= (0x80000000UL >> reg_d); ppc_state.cr |= (0x80000000UL >> reg_d);
} } else {
else {
ppc_state.cr &= ~(0x80000000UL >> reg_d); ppc_state.cr &= ~(0x80000000UL >> reg_d);
} }
} }
@ -1739,8 +1697,7 @@ void ppc_crorc() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if ((ppc_state.cr & (0x80000000UL >> reg_a)) || !(ppc_state.cr & (0x80000000UL >> reg_b))) { if ((ppc_state.cr & (0x80000000UL >> reg_a)) || !(ppc_state.cr & (0x80000000UL >> reg_b))) {
ppc_state.cr |= (0x80000000UL >> reg_d); ppc_state.cr |= (0x80000000UL >> reg_d);
} } else {
else {
ppc_state.cr &= ~(0x80000000UL >> reg_d); ppc_state.cr &= ~(0x80000000UL >> reg_d);
} }
} }
@ -1748,8 +1705,7 @@ void ppc_crxor() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if ((ppc_state.cr & (0x80000000UL >> reg_a)) ^ (ppc_state.cr & (0x80000000UL >> reg_b))) { if ((ppc_state.cr & (0x80000000UL >> reg_a)) ^ (ppc_state.cr & (0x80000000UL >> reg_b))) {
ppc_state.cr |= (0x80000000UL >> reg_d); ppc_state.cr |= (0x80000000UL >> reg_d);
} } else {
else {
ppc_state.cr &= ~(0x80000000UL >> reg_d); ppc_state.cr &= ~(0x80000000UL >> reg_d);
} }
} }
@ -1777,17 +1733,16 @@ void ppc_tw() {
reg_a = (ppc_cur_instruction >> 11) & 31; reg_a = (ppc_cur_instruction >> 11) & 31;
reg_b = (ppc_cur_instruction >> 16) & 31; reg_b = (ppc_cur_instruction >> 16) & 31;
ppc_to = (ppc_cur_instruction >> 21) & 31; ppc_to = (ppc_cur_instruction >> 21) & 31;
if ((((int32_t)ppc_state.gpr[reg_a] < (int32_t)ppc_state.gpr[reg_b]) & (ppc_to & 0x10)) || \ if ((((int32_t)ppc_state.gpr[reg_a] < (int32_t)ppc_state.gpr[reg_b]) & (ppc_to & 0x10)) ||
(((int32_t)ppc_state.gpr[reg_a] > (int32_t)ppc_state.gpr[reg_b])& (ppc_to & 0x08)) || \ (((int32_t)ppc_state.gpr[reg_a] > (int32_t)ppc_state.gpr[reg_b]) & (ppc_to & 0x08)) ||
(((int32_t)ppc_state.gpr[reg_a] == (int32_t)ppc_state.gpr[reg_b]) & (ppc_to & 0x04)) || \ (((int32_t)ppc_state.gpr[reg_a] == (int32_t)ppc_state.gpr[reg_b]) & (ppc_to & 0x04)) ||
((ppc_state.gpr[reg_a] < ppc_state.gpr[reg_b]) & (ppc_to & 0x02)) || \ ((ppc_state.gpr[reg_a] < ppc_state.gpr[reg_b]) & (ppc_to & 0x02)) ||
((ppc_state.gpr[reg_a] > ppc_state.gpr[reg_b]) & (ppc_to & 0x01))) { ((ppc_state.gpr[reg_a] > ppc_state.gpr[reg_b]) & (ppc_to & 0x01))) {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
void ppc_twi() void ppc_twi() {
{
simm = (int32_t)((int16_t)((ppc_cur_instruction)&0xFFFF)); simm = (int32_t)((int16_t)((ppc_cur_instruction)&0xFFFF));
reg_a = (ppc_cur_instruction >> 16) & 0x1F; reg_a = (ppc_cur_instruction >> 16) & 0x1F;
ppc_to = (ppc_cur_instruction >> 21) & 0x1F; ppc_to = (ppc_cur_instruction >> 21) & 0x1F;
@ -1851,8 +1806,7 @@ void ppc_dcbz() {
mem_write_qword((ppc_effective_address + 8), 0); mem_write_qword((ppc_effective_address + 8), 0);
mem_write_qword((ppc_effective_address + 16), 0); mem_write_qword((ppc_effective_address + 16), 0);
mem_write_qword((ppc_effective_address + 24), 0); mem_write_qword((ppc_effective_address + 24), 0);
} } else {
else {
ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x00000); ppc_exception_handler(Except_Type::EXC_ALIGNMENT, 0x00000);
} }
} }
@ -1880,8 +1834,7 @@ void ppc_stbu() {
ppc_effective_address += ppc_result_a; ppc_effective_address += ppc_result_a;
mem_write_byte(ppc_effective_address, ppc_result_d); mem_write_byte(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address; ppc_state.gpr[reg_a] = ppc_effective_address;
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1892,8 +1845,7 @@ void ppc_stbux() {
ppc_effective_address = ppc_result_a + ppc_result_b; ppc_effective_address = ppc_result_a + ppc_result_b;
mem_write_byte(ppc_effective_address, ppc_result_d); mem_write_byte(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address; ppc_state.gpr[reg_a] = ppc_effective_address;
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1912,8 +1864,7 @@ void ppc_sthu() {
ppc_effective_address += ppc_result_a; ppc_effective_address += ppc_result_a;
mem_write_word(ppc_effective_address, ppc_result_d); mem_write_word(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address; ppc_state.gpr[reg_a] = ppc_effective_address;
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1924,8 +1875,7 @@ void ppc_sthux() {
ppc_effective_address = ppc_result_a + ppc_result_b; ppc_effective_address = ppc_result_a + ppc_result_b;
mem_write_word(ppc_effective_address, ppc_result_d); mem_write_word(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address; ppc_state.gpr[reg_a] = ppc_effective_address;
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1941,7 +1891,6 @@ void ppc_sthbrx() {
ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b); ppc_effective_address = (reg_a == 0) ? ppc_result_b : (ppc_result_a + ppc_result_b);
ppc_result_d = (uint32_t)(BYTESWAP_16((uint16_t)ppc_result_d)); ppc_result_d = (uint32_t)(BYTESWAP_16((uint16_t)ppc_result_d));
mem_write_word(ppc_effective_address, ppc_result_d); mem_write_word(ppc_effective_address, ppc_result_d);
} }
void ppc_stw() { void ppc_stw() {
ppc_grab_regssa(); ppc_grab_regssa();
@ -1964,8 +1913,7 @@ void ppc_stwcx() {
mem_write_dword(ppc_effective_address, ppc_result_d); mem_write_dword(ppc_effective_address, ppc_result_d);
ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x30000000 : 0x20000000; ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x30000000 : 0x20000000;
ppc_state.reserve = false; ppc_state.reserve = false;
} } else {
else {
ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x10000000 : 0; ppc_state.cr |= (ppc_state.spr[SPR::XER] & 0x80000000) ? 0x10000000 : 0;
} }
} }
@ -1977,8 +1925,7 @@ void ppc_stwu() {
ppc_effective_address += ppc_result_a; ppc_effective_address += ppc_result_a;
mem_write_dword(ppc_effective_address, ppc_result_d); mem_write_dword(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address; ppc_state.gpr[reg_a] = ppc_effective_address;
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -1989,8 +1936,7 @@ void ppc_stwux() {
ppc_effective_address = ppc_result_a + ppc_result_b; ppc_effective_address = ppc_result_a + ppc_result_b;
mem_write_dword(ppc_effective_address, ppc_result_d); mem_write_dword(ppc_effective_address, ppc_result_d);
ppc_state.gpr[reg_a] = ppc_effective_address; ppc_state.gpr[reg_a] = ppc_effective_address;
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -2002,8 +1948,7 @@ void ppc_stwbrx() {
mem_write_dword(ppc_effective_address, ppc_result_d); mem_write_dword(ppc_effective_address, ppc_result_d);
} }
void ppc_stmw() void ppc_stmw() {
{
ppc_grab_regssa(); ppc_grab_regssa();
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF)); ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0; ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
@ -2036,8 +1981,7 @@ void ppc_lbzu() {
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_regd(); ppc_store_result_regd();
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -2057,8 +2001,7 @@ void ppc_lbzux() {
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_regd(); ppc_store_result_regd();
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -2081,8 +2024,7 @@ void ppc_lhzu() {
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_regd(); ppc_store_result_regd();
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -2102,8 +2044,7 @@ void ppc_lhzux() {
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_regd(); ppc_store_result_regd();
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -2115,8 +2056,7 @@ void ppc_lha() {
uint16_t val = mem_grab_word(ppc_effective_address); uint16_t val = mem_grab_word(ppc_effective_address);
if (val & 0x8000) { if (val & 0x8000) {
ppc_result_d = 0xFFFF0000UL | (uint32_t)val; ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
} } else {
else {
ppc_result_d = (uint32_t)val; ppc_result_d = (uint32_t)val;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -2130,15 +2070,13 @@ void ppc_lhau() {
uint16_t val = mem_grab_word(ppc_effective_address); uint16_t val = mem_grab_word(ppc_effective_address);
if (val & 0x8000) { if (val & 0x8000) {
ppc_result_d = 0xFFFF0000UL | (uint32_t)val; ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
} } else {
else {
ppc_result_d = (uint32_t)val; ppc_result_d = (uint32_t)val;
} }
ppc_store_result_regd(); ppc_store_result_regd();
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -2149,8 +2087,7 @@ void ppc_lhaux() {
uint16_t val = mem_grab_word(ppc_effective_address); uint16_t val = mem_grab_word(ppc_effective_address);
if (val & 0x8000) { if (val & 0x8000) {
ppc_result_d = 0xFFFF0000UL | (uint32_t)val; ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
} } else {
else {
ppc_result_d = (uint32_t)val; ppc_result_d = (uint32_t)val;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -2164,8 +2101,7 @@ void ppc_lhax() {
uint16_t val = mem_grab_word(ppc_effective_address); uint16_t val = mem_grab_word(ppc_effective_address);
if (val & 0x8000) { if (val & 0x8000) {
ppc_result_d = 0xFFFF0000UL | (uint32_t)val; ppc_result_d = 0xFFFF0000UL | (uint32_t)val;
} } else {
else {
ppc_result_d = (uint32_t)val; ppc_result_d = (uint32_t)val;
} }
ppc_store_result_regd(); ppc_store_result_regd();
@ -2202,8 +2138,7 @@ void ppc_lwzu() {
ppc_store_result_regd(); ppc_store_result_regd();
ppc_result_a = ppc_effective_address; ppc_result_a = ppc_effective_address;
ppc_store_result_rega(); ppc_store_result_rega();
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
} }
@ -2219,8 +2154,7 @@ void ppc_lwzux() {
ppc_grab_regsdab(); ppc_grab_regsdab();
if ((reg_a != reg_d) || reg_a != 0) { if ((reg_a != reg_d) || reg_a != 0) {
ppc_effective_address = ppc_result_a + ppc_result_b; ppc_effective_address = ppc_result_a + ppc_result_b;
} } else {
else {
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000); ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
} }
ppc_result_d = mem_grab_dword(ppc_effective_address); ppc_result_d = mem_grab_dword(ppc_effective_address);
@ -2276,8 +2210,7 @@ void ppc_lswi() {
ppc_store_result_regd(); ppc_store_result_regd();
break; break;
case 3: case 3:
ppc_result_d = (ppc_result_d & 0xFFFFFF00UL) | ppc_result_d = (ppc_result_d & 0xFFFFFF00UL) | mem_grab_byte(ppc_effective_address);
mem_grab_byte(ppc_effective_address);
ppc_store_result_regd(); ppc_store_result_regd();
break; break;
default: default:
@ -2286,8 +2219,7 @@ void ppc_lswi() {
if (shift_times == 3) { if (shift_times == 3) {
shift_times = 0; shift_times = 0;
reg_d = (reg_d + 1) & 0x1F; reg_d = (reg_d + 1) & 0x1F;
} } else {
else {
shift_times++; shift_times++;
} }
ppc_effective_address++; ppc_effective_address++;
@ -2325,8 +2257,7 @@ void ppc_lswx() {
ppc_store_result_regd(); ppc_store_result_regd();
break; break;
case 3: case 3:
ppc_result_d = (ppc_result_d & 0xFFFFFF00UL) | ppc_result_d = (ppc_result_d & 0xFFFFFF00UL) | mem_grab_byte(ppc_effective_address);
mem_grab_byte(ppc_effective_address);
ppc_store_result_regd(); ppc_store_result_regd();
break; break;
default: default:
@ -2335,14 +2266,12 @@ void ppc_lswx() {
if (shift_times == 3) { if (shift_times == 3) {
shift_times = 0; shift_times = 0;
reg_d = (reg_d + 1) & 0x1F; reg_d = (reg_d + 1) & 0x1F;
} } else {
else {
shift_times++; shift_times++;
} }
ppc_effective_address++; ppc_effective_address++;
grab_inb--; grab_inb--;
} }
} }
void ppc_stswi() { void ppc_stswi() {
@ -2375,8 +2304,7 @@ void ppc_stswi() {
if (shift_times == 3) { if (shift_times == 3) {
shift_times = 0; shift_times = 0;
reg_s = (reg_s + 1) & 0x1F; reg_s = (reg_s + 1) & 0x1F;
} } else {
else {
shift_times++; shift_times++;
} }
ppc_effective_address++; ppc_effective_address++;
@ -2413,8 +2341,7 @@ void ppc_stswx() {
if (shift_times == 3) { if (shift_times == 3) {
shift_times = 0; shift_times = 0;
reg_s = (reg_s + 1) & 0x1F; reg_s = (reg_s + 1) & 0x1F;
} } else {
else {
shift_times++; shift_times++;
} }
ppc_effective_address++; ppc_effective_address++;

View File

@ -1,34 +1,31 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <string>
#include "../ppcemu.h"
#include "../ppcdisasm.h" #include "../ppcdisasm.h"
#include "../ppcemu.h"
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std; using namespace std;
int ntested; /* number of tested instructions */ int ntested; /* number of tested instructions */
int nfailed; /* number of failed instructions */ int nfailed; /* number of failed instructions */
void xer_ov_test(string mnem, uint32_t opcode) void xer_ov_test(string mnem, uint32_t opcode) {
{
ppc_state.gpr[3] = 2; ppc_state.gpr[3] = 2;
ppc_state.gpr[4] = 2; ppc_state.gpr[4] = 2;
ppc_state.spr[SPR::XER] = 0xFFFFFFFF; ppc_state.spr[SPR::XER] = 0xFFFFFFFF;
ppc_cur_instruction = opcode; ppc_cur_instruction = opcode;
ppc_main_opcode(); ppc_main_opcode();
if (ppc_state.spr[SPR::XER] & 0x40000000UL) { if (ppc_state.spr[SPR::XER] & 0x40000000UL) {
cout << "Invalid " << mnem << " emulation! XER[OV] should not be set." cout << "Invalid " << mnem << " emulation! XER[OV] should not be set." << endl;
<< endl;
nfailed++; nfailed++;
} }
ntested++; ntested++;
} }
void xer_update_test() void xer_update_test() {
{
xer_ov_test("ADDCO", 0x7C632414); xer_ov_test("ADDCO", 0x7C632414);
xer_ov_test("ADDCO.", 0x7C632415); xer_ov_test("ADDCO.", 0x7C632415);
xer_ov_test("ADDO", 0x7C632614); xer_ov_test("ADDO", 0x7C632614);
@ -60,8 +57,7 @@ void xer_update_test()
} }
/** testing vehicle */ /** testing vehicle */
static void read_test_data() static void read_test_data() {
{
string line, token; string line, token;
int i, lineno; int i, lineno;
uint32_t opcode, dest, src1, src2, check_xer, check_cr; uint32_t opcode, dest, src1, src2, check_xer, check_cr;
@ -113,8 +109,8 @@ static void read_test_data()
} else if (tokens[i].rfind("CR=", 0) == 0) { } else if (tokens[i].rfind("CR=", 0) == 0) {
check_cr = stoul(tokens[i].substr(3), NULL, 16); check_cr = stoul(tokens[i].substr(3), NULL, 16);
} else { } else {
cout << "Unknown parameter " << tokens[i] << " in line " << lineno << cout << "Unknown parameter " << tokens[i] << " in line " << lineno << ". Exiting..."
". Exiting..." << endl; << endl;
exit(0); exit(0);
} }
} }
@ -131,15 +127,13 @@ static void read_test_data()
ntested++; ntested++;
if ((tokens[0].rfind("CMP") && (ppc_state.gpr[3] != dest)) || if ((tokens[0].rfind("CMP") && (ppc_state.gpr[3] != dest)) ||
(ppc_state.spr[SPR::XER] != check_xer) || (ppc_state.spr[SPR::XER] != check_xer) || (ppc_state.cr != check_cr)) {
(ppc_state.cr != check_cr)) { cout << "Mismatch: instr=" << tokens[0] << ", src1=0x" << hex << src1 << ", src2=0x"
cout << "Mismatch: instr=" << tokens[0] << ", src1=0x" << hex << src1 << hex << src2 << endl;
<< ", src2=0x" << hex << src2 << endl; cout << "expected: dest=0x" << hex << dest << ", XER=0x" << hex << check_xer
cout << "expected: dest=0x" << hex << dest << ", XER=0x" << hex << ", CR=0x" << hex << check_cr << endl;
<< check_xer << ", CR=0x" << hex << check_cr << endl; cout << "got: dest=0x" << hex << ppc_state.gpr[3] << ", XER=0x" << hex
cout << "got: dest=0x" << hex << ppc_state.gpr[3] << ", XER=0x" << ppc_state.spr[SPR::XER] << ", CR=0x" << hex << ppc_state.cr << endl;
<< hex << ppc_state.spr[SPR::XER] << ", CR=0x" << hex
<< ppc_state.cr << endl;
cout << "Test file line #: " << dec << lineno << endl << endl; cout << "Test file line #: " << dec << lineno << endl << endl;
nfailed++; nfailed++;
@ -147,9 +141,7 @@ static void read_test_data()
} }
} }
int main() int main() {
{
cout << "Running DingusPPC emulator tests..." << endl << endl; cout << "Running DingusPPC emulator tests..." << endl << endl;
ntested = 0; ntested = 0;

View File

@ -1,16 +1,15 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <string>
#include "../ppcdisasm.h" #include "../ppcdisasm.h"
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std; using namespace std;
/** testing vehicle */ /** testing vehicle */
static vector<PPCDisasmContext> read_test_data() static vector<PPCDisasmContext> read_test_data() {
{
string line, token; string line, token;
int i, lineno; int i, lineno;
PPCDisasmContext ctx; PPCDisasmContext ctx;
@ -72,8 +71,7 @@ static vector<PPCDisasmContext> read_test_data()
return tstvec; return tstvec;
} }
int test_ppc_disasm() int test_ppc_disasm() {
{
int i, nfailed; int i, nfailed;
PPCDisasmContext ctx; PPCDisasmContext ctx;
@ -92,14 +90,13 @@ int test_ppc_disasm()
std::string disas = disassemble_single(&ctx); std::string disas = disassemble_single(&ctx);
if (disas != testdata[i].instr_str) { if (disas != testdata[i].instr_str) {
cout << "Mismatch found, expected={" << testdata[i].instr_str << cout << "Mismatch found, expected={" << testdata[i].instr_str << "}, got={" << disas
"}, got={" << disas << "}" << endl; << "}" << endl;
nfailed++; nfailed++;
} }
} }
cout << "Tested " << testdata.size() << " instructions. Failed: " << cout << "Tested " << testdata.size() << " instructions. Failed: " << nfailed << "." << endl;
nfailed << "." << endl;
return 0; return 0;
} }

View File

@ -19,43 +19,38 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <stdio.h> #include "../cpu/ppc/ppcdisasm.h"
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <map>
#include "../cpu/ppc/ppcemu.h" #include "../cpu/ppc/ppcemu.h"
#include "../cpu/ppc/ppcmmu.h" #include "../cpu/ppc/ppcmmu.h"
#include "../cpu/ppc/ppcdisasm.h" #include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <sstream>
#include <stdio.h>
#include <string>
#include <thirdparty/loguru/loguru.hpp> #include <thirdparty/loguru/loguru.hpp>
using namespace std; using namespace std;
static uint32_t str2addr(string& addr_str) static uint32_t str2addr(string& addr_str) {
{
try { try {
return stoul(addr_str, NULL, 0); return stoul(addr_str, NULL, 0);
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
throw invalid_argument(string("Cannot convert ") + addr_str); throw invalid_argument(string("Cannot convert ") + addr_str);
} }
} }
static uint32_t str2num(string& num_str) static uint32_t str2num(string& num_str) {
{
try { try {
return stol(num_str, NULL, 0); return stol(num_str, NULL, 0);
} } catch (invalid_argument& exc) {
catch (invalid_argument & exc) {
throw invalid_argument(string("Cannot convert ") + num_str); throw invalid_argument(string("Cannot convert ") + num_str);
} }
} }
static void show_help() static void show_help() {
{
cout << "Debugger commands:" << endl; cout << "Debugger commands:" << endl;
cout << " step -- execute single instruction" << endl; cout << " step -- execute single instruction" << endl;
cout << " si -- shortcut for step" << endl; cout << " si -- shortcut for step" << endl;
@ -80,8 +75,7 @@ static void show_help()
cout << "Pressing ENTER will repeat last command." << endl; cout << "Pressing ENTER will repeat last command." << endl;
} }
static void disasm(uint32_t count, uint32_t address) static void disasm(uint32_t count, uint32_t address) {
{
PPCDisasmContext ctx; PPCDisasmContext ctx;
ctx.instr_addr = address; ctx.instr_addr = address;
@ -94,8 +88,7 @@ static void disasm(uint32_t count, uint32_t address)
} }
} }
static void dump_mem(string& params) static void dump_mem(string& params) {
{
int cell_size, chars_per_line; int cell_size, chars_per_line;
bool is_char; bool is_char;
uint32_t count, addr; uint32_t count, addr;
@ -144,21 +137,18 @@ static void dump_mem(string& params)
try { try {
num_type_str = num_type_str.substr(0, num_type_str.length() - 1); num_type_str = num_type_str.substr(0, num_type_str.length() - 1);
count = str2addr(num_type_str); count = str2addr(num_type_str);
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
cout << exc.what() << endl; cout << exc.what() << endl;
return; return;
} }
try { try {
addr = str2addr(addr_str); addr = str2addr(addr_str);
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
try { try {
/* number conversion failed, trying reg name */ /* number conversion failed, trying reg name */
addr = get_reg(addr_str); addr = get_reg(addr_str);
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
cout << exc.what() << endl; cout << exc.what() << endl;
return; return;
} }
@ -179,13 +169,11 @@ static void dump_mem(string& params)
cout << (char)val; cout << (char)val;
chars_per_line += cell_size; chars_per_line += cell_size;
} else { } else {
cout << setw(cell_size * 2) << setfill('0') << uppercase << cout << setw(cell_size * 2) << setfill('0') << uppercase << hex << val << " ";
hex << val << " ";
chars_per_line += cell_size * 2 + 2; chars_per_line += cell_size * 2 + 2;
} }
} }
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
cout << exc.what() << endl; cout << exc.what() << endl;
return; return;
} }
@ -193,10 +181,8 @@ static void dump_mem(string& params)
cout << endl << endl; cout << endl << endl;
} }
void enter_debugger() void enter_debugger() {
{ string inp, cmd, addr_str, expr_str, reg_expr, last_cmd, reg_value_str, inst_string, inst_num_str;
string inp, cmd, addr_str, expr_str, reg_expr, last_cmd, reg_value_str,
inst_string, inst_num_str;
uint32_t addr, inst_grab; uint32_t addr, inst_grab;
std::stringstream ss; std::stringstream ss;
int log_level; int log_level;
@ -223,8 +209,7 @@ void enter_debugger()
} }
if (cmd == "help") { if (cmd == "help") {
show_help(); show_help();
} } else if (cmd == "quit") {
else if (cmd == "quit") {
break; break;
} }
#ifdef PROFILER #ifdef PROFILER
@ -236,8 +221,7 @@ void enter_debugger()
#endif #endif
else if (cmd == "regs") { else if (cmd == "regs") {
print_gprs(); print_gprs();
} } else if (cmd == "set") {
else if (cmd == "set") {
ss >> expr_str; ss >> expr_str;
separator_pos = expr_str.find_first_of("="); separator_pos = expr_str.find_first_of("=");
@ -256,35 +240,28 @@ void enter_debugger()
continue; continue;
} }
loguru::g_stderr_verbosity = log_level; loguru::g_stderr_verbosity = log_level;
} } else {
else {
addr = str2addr(addr_str); addr = str2addr(addr_str);
set_reg(reg_expr, addr); set_reg(reg_expr, addr);
} }
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
cout << exc.what() << endl; cout << exc.what() << endl;
} }
} } else if (cmd == "step" || cmd == "si") {
else if (cmd == "step" || cmd == "si") {
ppc_exec_single(); ppc_exec_single();
} } else if (cmd == "next" || cmd == "ni") {
else if (cmd == "next" || cmd == "ni") {
addr_str = "PC"; addr_str = "PC";
addr = get_reg(addr_str) + 4; addr = get_reg(addr_str) + 4;
ppc_exec_until(addr); ppc_exec_until(addr);
} } else if (cmd == "until") {
else if (cmd == "until") {
ss >> addr_str; ss >> addr_str;
try { try {
addr = str2addr(addr_str); addr = str2addr(addr_str);
ppc_exec_until(addr); ppc_exec_until(addr);
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
cout << exc.what() << endl; cout << exc.what() << endl;
} }
} } else if (cmd == "disas") {
else if (cmd == "disas") {
expr_str = ""; expr_str = "";
ss >> expr_str; ss >> expr_str;
if (expr_str.length() > 0) { if (expr_str.length() > 0) {
@ -298,37 +275,31 @@ void enter_debugger()
addr_str = expr_str.substr(expr_str.find_first_of(",") + 1); addr_str = expr_str.substr(expr_str.find_first_of(",") + 1);
try { try {
addr = str2addr(addr_str); addr = str2addr(addr_str);
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
try { try {
/* number conversion failed, trying reg name */ /* number conversion failed, trying reg name */
addr = get_reg(addr_str); addr = get_reg(addr_str);
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
cout << exc.what() << endl; cout << exc.what() << endl;
continue; continue;
} }
} }
try { try {
disasm(inst_grab, addr); disasm(inst_grab, addr);
} } catch (invalid_argument& exc) {
catch (invalid_argument& exc) {
cout << exc.what() << endl; cout << exc.what() << endl;
} }
} } else {
else {
/* disas without arguments defaults to disas 1,pc */ /* disas without arguments defaults to disas 1,pc */
addr_str = "PC"; addr_str = "PC";
addr = get_reg(addr_str); addr = get_reg(addr_str);
disasm(1, addr); disasm(1, addr);
} }
} } else if (cmd == "dump") {
else if (cmd == "dump") {
expr_str = ""; expr_str = "";
ss >> expr_str; ss >> expr_str;
dump_mem(expr_str); dump_mem(expr_str);
} } else {
else {
cout << "Unknown command: " << cmd << endl; cout << "Unknown command: " << cmd << endl;
continue; continue;
} }

View File

@ -25,9 +25,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include "devices/adb.h"
#include <cinttypes> #include <cinttypes>
#include <cstring> #include <cstring>
#include "devices/adb.h"
#include <thirdparty/SDL2/include/SDL.h> #include <thirdparty/SDL2/include/SDL.h>
#include <thirdparty/SDL2/include/SDL_events.h> #include <thirdparty/SDL2/include/SDL_events.h>
@ -53,29 +53,22 @@ ADB_Bus::ADB_Bus() {
mouse_access_no = adb_relative; mouse_access_no = adb_relative;
} }
ADB_Bus::~ADB_Bus() { ADB_Bus::~ADB_Bus() {}
}
bool ADB_Bus::listen(int device, int reg) { bool ADB_Bus::listen(int device, int reg) {
if (device == keyboard_access_no) { if (device == keyboard_access_no) {
if (adb_keybd_listen(reg)) { if (adb_keybd_listen(reg)) {
return true; return true;
} } else {
else {
return false; return false;
} }
} } else if (device == mouse_access_no) {
else if (device == mouse_access_no) {
if (adb_mouse_listen(reg)) { if (adb_mouse_listen(reg)) {
return true; return true;
} } else {
else {
return false; return false;
} }
} } else {
else {
return false; return false;
} }
} }
@ -363,8 +356,7 @@ bool ADB_Bus::adb_keybd_listen(int reg) {
adb_keybd_register0 &= (ask_key_pressed << 8); adb_keybd_register0 &= (ask_key_pressed << 8);
output_data_stream[0] = (adb_keybd_register0 >> 8); output_data_stream[0] = (adb_keybd_register0 >> 8);
output_data_stream[1] = (adb_keybd_register0 & 0xff); output_data_stream[1] = (adb_keybd_register0 & 0xff);
} } else if (adb_keybd_register0 & 0x80) {
else if (adb_keybd_register0 & 0x80) {
adb_keybd_register0 &= 0xFF7F; adb_keybd_register0 &= 0xFF7F;
adb_keybd_register0 &= (ask_key_pressed); adb_keybd_register0 &= (ask_key_pressed);
output_data_stream[0] = (adb_keybd_register0 >> 8); output_data_stream[0] = (adb_keybd_register0 >> 8);
@ -386,8 +378,7 @@ bool ADB_Bus::adb_keybd_listen(int reg) {
adb_keybd_register0 |= 0x8000; adb_keybd_register0 |= 0x8000;
output_data_stream[0] = (adb_keybd_register0 >> 8); output_data_stream[0] = (adb_keybd_register0 >> 8);
output_data_stream[1] = (adb_keybd_register0 & 0xff); output_data_stream[1] = (adb_keybd_register0 & 0xff);
} } else if (adb_keybd_register0 & 0x80)
else if (adb_keybd_register0 & 0x80)
adb_keybd_register0 |= 0x0080; adb_keybd_register0 |= 0x0080;
output_data_stream[0] = (adb_keybd_register0 >> 8); output_data_stream[0] = (adb_keybd_register0 >> 8);
output_data_stream[1] = (adb_keybd_register0 & 0xff); output_data_stream[1] = (adb_keybd_register0 & 0xff);
@ -403,8 +394,7 @@ bool ADB_Bus::adb_keybd_listen(int reg) {
if ((reg != 1)) { if ((reg != 1)) {
return true; return true;
} } else {
else {
return false; return false;
} }
} }
@ -421,11 +411,9 @@ bool ADB_Bus::adb_mouse_listen(int reg) {
if (adb_mouse_evt.motion.xrel < 0) { if (adb_mouse_evt.motion.xrel < 0) {
if (adb_mouse_evt.motion.xrel <= -64) { if (adb_mouse_evt.motion.xrel <= -64) {
this->adb_mouse_register0 |= 0x7F; this->adb_mouse_register0 |= 0x7F;
} } else if (adb_mouse_evt.motion.xrel >= 63) {
else if (adb_mouse_evt.motion.xrel >= 63) {
this->adb_mouse_register0 |= 0x3F; this->adb_mouse_register0 |= 0x3F;
} } else {
else {
this->adb_mouse_register0 |= adb_mouse_evt.motion.xrel; this->adb_mouse_register0 |= adb_mouse_evt.motion.xrel;
} }
} }
@ -436,15 +424,12 @@ bool ADB_Bus::adb_mouse_listen(int reg) {
if (adb_mouse_evt.motion.yrel < 0) { if (adb_mouse_evt.motion.yrel < 0) {
if (adb_mouse_evt.motion.yrel <= -64) { if (adb_mouse_evt.motion.yrel <= -64) {
this->adb_mouse_register0 |= 0x7F00; this->adb_mouse_register0 |= 0x7F00;
} } else if (adb_mouse_evt.motion.yrel >= 63) {
else if (adb_mouse_evt.motion.yrel >= 63) {
this->adb_mouse_register0 |= 0x3F00; this->adb_mouse_register0 |= 0x3F00;
} } else {
else {
this->adb_mouse_register0 |= (adb_mouse_evt.motion.yrel << 8); this->adb_mouse_register0 |= (adb_mouse_evt.motion.yrel << 8);
} }
} }
} }
switch (adb_mouse_evt.type) { switch (adb_mouse_evt.type) {
@ -458,13 +443,11 @@ bool ADB_Bus::adb_mouse_listen(int reg) {
if (reg == 0) { if (reg == 0) {
output_data_stream[0] = (adb_mouse_register0 >> 8); output_data_stream[0] = (adb_mouse_register0 >> 8);
output_data_stream[1] = (adb_mouse_register0 & 0xff); output_data_stream[1] = (adb_mouse_register0 & 0xff);
} } else if (reg == 3) {
else if (reg == 3) {
output_data_stream[0] = (adb_mouse_register3 >> 8); output_data_stream[0] = (adb_mouse_register3 >> 8);
output_data_stream[1] = (adb_mouse_register3 & 0xff); output_data_stream[1] = (adb_mouse_register3 & 0xff);
} }
return true; return true;
} }

View File

@ -27,14 +27,25 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <thirdparty/SDL2/include/SDL_events.h> #include <thirdparty/SDL2/include/SDL_events.h>
enum adb_default_values { enum adb_default_values {
adb_reserved0, adb_reserved1, adb_encoded, adb_relative, adb_reserved0,
adb_absolute, adb_reserved5, adb_reserved6, adb_reserved7, adb_reserved1,
adb_other8, adb_other9, adb_other10, adb_other11, adb_encoded,
adb_other12, adb_other13, adb_other14, adb_other15 adb_relative,
adb_absolute,
adb_reserved5,
adb_reserved6,
adb_reserved7,
adb_other8,
adb_other9,
adb_other10,
adb_other11,
adb_other12,
adb_other13,
adb_other14,
adb_other15
}; };
class ADB_Bus class ADB_Bus {
{
public: public:
ADB_Bus(); ADB_Bus();
~ADB_Bus(); ~ADB_Bus();

View File

@ -19,17 +19,16 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <atirage.h> #include "displayid.h"
#include <cstdint>
#include <thirdparty/loguru/loguru.hpp>
#include "endianswap.h" #include "endianswap.h"
#include "memreadwrite.h" #include "memreadwrite.h"
#include "pcidevice.h" #include "pcidevice.h"
#include "displayid.h" #include <atirage.h>
#include <cstdint>
#include <thirdparty/loguru/loguru.hpp>
ATIRage::ATIRage(uint16_t dev_id) : PCIDevice("ati-rage") ATIRage::ATIRage(uint16_t dev_id) : PCIDevice("ati-rage") {
{
WRITE_DWORD_BE_A(&this->pci_cfg[0], (dev_id << 16) | ATI_PCI_VENDOR_ID); WRITE_DWORD_BE_A(&this->pci_cfg[0], (dev_id << 16) | ATI_PCI_VENDOR_ID);
WRITE_DWORD_BE_A(&this->pci_cfg[8], 0x0300005C); WRITE_DWORD_BE_A(&this->pci_cfg[8], 0x0300005C);
WRITE_DWORD_BE_A(&this->pci_cfg[0x3C], 0x00080100); WRITE_DWORD_BE_A(&this->pci_cfg[0x3C], 0x00080100);
@ -37,13 +36,11 @@ ATIRage::ATIRage(uint16_t dev_id) : PCIDevice("ati-rage")
this->disp_id = new DisplayID(); this->disp_id = new DisplayID();
} }
ATIRage::~ATIRage() ATIRage::~ATIRage() {
{
delete (this->disp_id); delete (this->disp_id);
} }
uint32_t ATIRage::size_dep_read(uint8_t *buf, uint32_t size) uint32_t ATIRage::size_dep_read(uint8_t* buf, uint32_t size) {
{
switch (size) { switch (size) {
case 4: case 4:
return READ_DWORD_LE_A(buf); return READ_DWORD_LE_A(buf);
@ -60,8 +57,7 @@ uint32_t ATIRage::size_dep_read(uint8_t *buf, uint32_t size)
} }
} }
void ATIRage::size_dep_write(uint8_t *buf, uint32_t value, uint32_t size) void ATIRage::size_dep_write(uint8_t* buf, uint32_t value, uint32_t size) {
{
switch (size) { switch (size) {
case 4: case 4:
WRITE_DWORD_BE_A(buf, value); WRITE_DWORD_BE_A(buf, value);
@ -74,8 +70,7 @@ void ATIRage::size_dep_write(uint8_t *buf, uint32_t value, uint32_t size)
} }
} }
const char* ATIRage::get_reg_name(uint32_t reg_offset) const char* ATIRage::get_reg_name(uint32_t reg_offset) {
{
const char* reg_name; const char* reg_name;
switch (reg_offset & ~3) { switch (reg_offset & ~3) {
@ -152,16 +147,19 @@ const char* ATIRage::get_reg_name(uint32_t reg_offset)
return reg_name; return reg_name;
} }
uint32_t ATIRage::read_reg(uint32_t offset, uint32_t size) uint32_t ATIRage::read_reg(uint32_t offset, uint32_t size) {
{
uint32_t res; uint32_t res;
switch (offset & ~3) { switch (offset & ~3) {
case ATI_GP_IO: case ATI_GP_IO:
break; break;
default: default:
LOG_F(INFO, "ATI Rage: read I/O reg %s at 0x%X, size=%d, val=0x%X", LOG_F(
get_reg_name(offset), offset, size, INFO,
"ATI Rage: read I/O reg %s at 0x%X, size=%d, val=0x%X",
get_reg_name(offset),
offset,
size,
size_dep_read(&this->block_io_regs[offset], size)); size_dep_read(&this->block_io_regs[offset], size));
} }
@ -170,8 +168,7 @@ uint32_t ATIRage::read_reg(uint32_t offset, uint32_t size)
return res; return res;
} }
void ATIRage::write_reg(uint32_t offset, uint32_t value, uint32_t size) void ATIRage::write_reg(uint32_t offset, uint32_t value, uint32_t size) {
{
uint32_t gpio_val; uint32_t gpio_val;
uint16_t gpio_dir; uint16_t gpio_dir;
@ -183,20 +180,23 @@ void ATIRage::write_reg(uint32_t offset, uint32_t value, uint32_t size)
if (offset < (ATI_GP_IO + 2)) { if (offset < (ATI_GP_IO + 2)) {
gpio_val = READ_DWORD_LE_A(&this->block_io_regs[ATI_GP_IO]); gpio_val = READ_DWORD_LE_A(&this->block_io_regs[ATI_GP_IO]);
gpio_dir = (gpio_val >> 16) & 0x3FFF; gpio_dir = (gpio_val >> 16) & 0x3FFF;
WRITE_WORD_LE_A(&this->block_io_regs[ATI_GP_IO], WRITE_WORD_LE_A(
&this->block_io_regs[ATI_GP_IO],
this->disp_id->read_monitor_sense(gpio_val, gpio_dir)); this->disp_id->read_monitor_sense(gpio_val, gpio_dir));
} }
break; break;
default: default:
LOG_F(INFO, "ATI Rage: %s register at 0x%X set to 0x%X", LOG_F(
get_reg_name(offset), offset & ~3, INFO,
"ATI Rage: %s register at 0x%X set to 0x%X",
get_reg_name(offset),
offset & ~3,
READ_DWORD_LE_A(&this->block_io_regs[offset & ~3])); READ_DWORD_LE_A(&this->block_io_regs[offset & ~3]));
} }
} }
uint32_t ATIRage::pci_cfg_read(uint32_t reg_offs, uint32_t size) uint32_t ATIRage::pci_cfg_read(uint32_t reg_offs, uint32_t size) {
{
uint32_t res = 0; uint32_t res = 0;
LOG_F(INFO, "Reading ATI Rage config space, offset = 0x%X, size=%d", reg_offs, size); LOG_F(INFO, "Reading ATI Rage config space, offset = 0x%X, size=%d", reg_offs, size);
@ -207,32 +207,32 @@ uint32_t ATIRage::pci_cfg_read(uint32_t reg_offs, uint32_t size)
return res; return res;
} }
void ATIRage::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) void ATIRage::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) {
{ LOG_F(
LOG_F(INFO, "Writing into ATI Rage PCI config space, offset = 0x%X, val=0x%X size=%d", INFO,
reg_offs, BYTESWAP_32(value), size); "Writing into ATI Rage PCI config space, offset = 0x%X, val=0x%X size=%d",
reg_offs,
BYTESWAP_32(value),
size);
switch (reg_offs) { switch (reg_offs) {
case 0x10: /* BAR 0 */ case 0x10: /* BAR 0 */
if (value == 0xFFFFFFFFUL) { if (value == 0xFFFFFFFFUL) {
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR0], 0xFF000008); WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR0], 0xFF000008);
} } else {
else {
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR0], value); WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR0], value);
} }
break; break;
case 0x14: /* BAR 1: I/O space base, 256 bytes wide */ case 0x14: /* BAR 1: I/O space base, 256 bytes wide */
if (value == 0xFFFFFFFFUL) { if (value == 0xFFFFFFFFUL) {
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR1], 0x0000FFF1); WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR1], 0x0000FFF1);
} } else {
else {
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR1], value); WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR1], value);
} }
case 0x18: /* BAR 2 */ case 0x18: /* BAR 2 */
if (value == 0xFFFFFFFFUL) { if (value == 0xFFFFFFFFUL) {
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR2], 0xFFFFF000); WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR2], 0xFFFFF000);
} } else {
else {
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR2], value); WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR2], value);
} }
break; break;
@ -248,8 +248,7 @@ void ATIRage::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
} }
bool ATIRage::io_access_allowed(uint32_t offset, uint32_t *p_io_base) bool ATIRage::io_access_allowed(uint32_t offset, uint32_t* p_io_base) {
{
if (!(this->pci_cfg[CFG_REG_CMD] & 1)) { if (!(this->pci_cfg[CFG_REG_CMD] & 1)) {
LOG_F(WARNING, "ATI I/O space disabled in the command reg"); LOG_F(WARNING, "ATI I/O space disabled in the command reg");
return false; return false;
@ -268,8 +267,7 @@ bool ATIRage::io_access_allowed(uint32_t offset, uint32_t *p_io_base)
} }
bool ATIRage::pci_io_read(uint32_t offset, uint32_t size, uint32_t *res) bool ATIRage::pci_io_read(uint32_t offset, uint32_t size, uint32_t* res) {
{
uint32_t io_base; uint32_t io_base;
if (!this->io_access_allowed(offset, &io_base)) { if (!this->io_access_allowed(offset, &io_base)) {
@ -281,8 +279,7 @@ bool ATIRage::pci_io_read(uint32_t offset, uint32_t size, uint32_t *res)
} }
bool ATIRage::pci_io_write(uint32_t offset, uint32_t value, uint32_t size) bool ATIRage::pci_io_write(uint32_t offset, uint32_t value, uint32_t size) {
{
uint32_t io_base; uint32_t io_base;
if (!this->io_access_allowed(offset, &io_base)) { if (!this->io_access_allowed(offset, &io_base)) {
@ -294,13 +291,11 @@ bool ATIRage::pci_io_write(uint32_t offset, uint32_t value, uint32_t size)
} }
uint32_t ATIRage::read(uint32_t reg_start, uint32_t offset, int size) uint32_t ATIRage::read(uint32_t reg_start, uint32_t offset, int size) {
{
LOG_F(INFO, "Reading reg=%X, size %d", offset, size); LOG_F(INFO, "Reading reg=%X, size %d", offset, size);
return 0; return 0;
} }
void ATIRage::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) void ATIRage::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) {
{
LOG_F(INFO, "Writing reg=%X, value=%X, size %d", offset, value, size); LOG_F(INFO, "Writing reg=%X, value=%X, size %d", offset, value, size);
} }

View File

@ -22,9 +22,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef ATI_RAGE_H #ifndef ATI_RAGE_H
#define ATI_RAGE_H #define ATI_RAGE_H
#include <cinttypes>
#include "pcidevice.h"
#include "displayid.h" #include "displayid.h"
#include "pcidevice.h"
#include <cinttypes>
using namespace std; using namespace std;
@ -102,8 +102,7 @@ enum {
ATI_TVO_CNTL = 0x0500, ATI_TVO_CNTL = 0x0500,
}; };
class ATIRage : public PCIDevice class ATIRage : public PCIDevice {
{
public: public:
ATIRage(uint16_t dev_id); ATIRage(uint16_t dev_id);
~ATIRage(); ~ATIRage();
@ -112,10 +111,14 @@ public:
uint32_t read(uint32_t reg_start, uint32_t offset, int size); uint32_t read(uint32_t reg_start, uint32_t offset, int size);
void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size); void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size);
bool supports_type(HWCompType type) { return type == HWCompType::MMIO_DEV; }; bool supports_type(HWCompType type) {
return type == HWCompType::MMIO_DEV;
};
/* PCI device methods */ /* PCI device methods */
bool supports_io_space(void) { return true; }; bool supports_io_space(void) {
return true;
};
uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size);
void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size);

View File

@ -24,17 +24,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
Author: Max Poliakovski 2019-20 Author: Max Poliakovski 2019-20
*/ */
#include <thirdparty/loguru/loguru.hpp>
#include "endianswap.h"
#include "awacs.h" #include "awacs.h"
#include "dbdma.h" #include "dbdma.h"
#include "endianswap.h"
#include "machines/machinebase.h" #include "machines/machinebase.h"
#include <thirdparty/SDL2/include/SDL.h> #include <thirdparty/SDL2/include/SDL.h>
#include <thirdparty/loguru/loguru.hpp>
static int awac_freqs[8] = {44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350}; static int awac_freqs[8] = {44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350};
AWACDevice::AWACDevice() AWACDevice::AWACDevice() {
{
this->audio_proc = new AudioProcessor(); this->audio_proc = new AudioProcessor();
/* register audio processor chip with the I2C bus */ /* register audio processor chip with the I2C bus */
@ -42,8 +41,7 @@ AWACDevice::AWACDevice()
i2c_bus->register_device(0x45, this->audio_proc); i2c_bus->register_device(0x45, this->audio_proc);
} }
AWACDevice::~AWACDevice() AWACDevice::~AWACDevice() {
{
delete this->audio_proc; delete this->audio_proc;
if (this->snd_buf) if (this->snd_buf)
@ -53,21 +51,18 @@ AWACDevice::~AWACDevice()
SDL_CloseAudioDevice(snd_out_dev); SDL_CloseAudioDevice(snd_out_dev);
} }
void AWACDevice::set_dma_out(DMAChannel *dma_out_ch) void AWACDevice::set_dma_out(DMAChannel* dma_out_ch) {
{
this->dma_out_ch = dma_out_ch; this->dma_out_ch = dma_out_ch;
} }
uint32_t AWACDevice::snd_ctrl_read(uint32_t offset, int size) uint32_t AWACDevice::snd_ctrl_read(uint32_t offset, int size) {
{
switch (offset) { switch (offset) {
case AWAC_SOUND_CTRL_REG: case AWAC_SOUND_CTRL_REG:
return this->snd_ctrl_reg; return this->snd_ctrl_reg;
case AWAC_CODEC_CTRL_REG: case AWAC_CODEC_CTRL_REG:
return this->is_busy; return this->is_busy;
case AWAC_CODEC_STATUS_REG: case AWAC_CODEC_STATUS_REG:
return (AWAC_AVAILABLE << 8) | (AWAC_MAKER_CRYSTAL << 16) | return (AWAC_AVAILABLE << 8) | (AWAC_MAKER_CRYSTAL << 16) | (AWAC_REV_SCREAMER << 20);
(AWAC_REV_SCREAMER << 20);
break; break;
default: default:
LOG_F(ERROR, "AWAC: unsupported register at offset 0x%X", offset); LOG_F(ERROR, "AWAC: unsupported register at offset 0x%X", offset);
@ -76,8 +71,7 @@ uint32_t AWACDevice::snd_ctrl_read(uint32_t offset, int size)
return 0; return 0;
} }
void AWACDevice::snd_ctrl_write(uint32_t offset, uint32_t value, int size) void AWACDevice::snd_ctrl_write(uint32_t offset, uint32_t value, int size) {
{
int subframe, reg_num; int subframe, reg_num;
uint16_t data; uint16_t data;
@ -99,8 +93,7 @@ void AWACDevice::snd_ctrl_write(uint32_t offset, uint32_t value, int size)
} }
} }
static void convert_data(const uint8_t *in, uint8_t *out, uint32_t len) static void convert_data(const uint8_t* in, uint8_t* out, uint32_t len) {
{
uint16_t *p_in, *p_out; uint16_t *p_in, *p_out;
if (len & 7) { if (len & 7) {
@ -120,8 +113,7 @@ static void convert_data(const uint8_t *in, uint8_t *out, uint32_t len)
} }
} }
static void audio_out_callback(void *user_data, uint8_t *buf, int buf_len) static void audio_out_callback(void* user_data, uint8_t* buf, int buf_len) {
{
uint8_t* p_in; uint8_t* p_in;
uint32_t rem_len, got_len; uint32_t rem_len, got_len;
@ -139,8 +131,7 @@ static void audio_out_callback(void *user_data, uint8_t *buf, int buf_len)
} }
} }
uint32_t AWACDevice::convert_data(const uint8_t *data, int len) uint32_t AWACDevice::convert_data(const uint8_t* data, int len) {
{
int i; int i;
uint16_t *p_in, *p_out; uint16_t *p_in, *p_out;
@ -164,8 +155,7 @@ uint32_t AWACDevice::convert_data(const uint8_t *data, int len)
return i; return i;
} }
void AWACDevice::dma_start() void AWACDevice::dma_start() {
{
SDL_AudioSpec snd_spec, snd_settings; SDL_AudioSpec snd_spec, snd_settings;
SDL_zero(snd_spec); SDL_zero(snd_spec);
@ -188,16 +178,14 @@ void AWACDevice::dma_start()
SDL_PauseAudioDevice(this->snd_out_dev, 0); /* start audio playing */ SDL_PauseAudioDevice(this->snd_out_dev, 0); /* start audio playing */
} }
void AWACDevice::dma_end() void AWACDevice::dma_end() {
{
if (this->snd_out_dev) { if (this->snd_out_dev) {
SDL_CloseAudioDevice(this->snd_out_dev); SDL_CloseAudioDevice(this->snd_out_dev);
this->snd_out_dev = 0; this->snd_out_dev = 0;
} }
} }
void AWACDevice::dma_push(uint8_t *buf, int size) void AWACDevice::dma_push(uint8_t* buf, int size) {
{
uint32_t dst_len; uint32_t dst_len;
dst_len = this->convert_data(buf, size); dst_len = this->convert_data(buf, size);
@ -213,6 +201,4 @@ void AWACDevice::dma_push(uint8_t *buf, int size)
} }
} }
void AWACDevice::dma_pull(uint8_t *buf, int size) void AWACDevice::dma_pull(uint8_t* buf, int size) {}
{
}

View File

@ -28,9 +28,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef AWAC_H #ifndef AWAC_H
#define AWAC_H #define AWAC_H
#include <cinttypes>
#include "i2c.h"
#include "dbdma.h" #include "dbdma.h"
#include "i2c.h"
#include <cinttypes>
#include <thirdparty/SDL2/include/SDL.h> #include <thirdparty/SDL2/include/SDL.h>
/** AWAC registers offsets. */ /** AWAC registers offsets. */
@ -57,7 +57,9 @@ public:
AudioProcessor() = default; AudioProcessor() = default;
~AudioProcessor() = default; ~AudioProcessor() = default;
void start_transaction() { this->pos = 0; }; void start_transaction() {
this->pos = 0;
};
bool send_subaddress(uint8_t sub_addr) { bool send_subaddress(uint8_t sub_addr) {
if ((sub_addr & 0xF) > 6) if ((sub_addr & 0xF) > 6)
@ -65,8 +67,7 @@ public:
this->sub_addr = sub_addr & 0xF; this->sub_addr = sub_addr & 0xF;
this->auto_inc = !!(sub_addr & 0x10); this->auto_inc = !!(sub_addr & 0x10);
LOG_F(INFO, "TDA7433 subaddress = 0x%X, auto increment = %d", LOG_F(INFO, "TDA7433 subaddress = 0x%X, auto increment = %d", this->sub_addr, this->auto_inc);
this->sub_addr, this->auto_inc);
this->pos++; this->pos++;
return true; return true;
}; };

View File

@ -21,20 +21,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
/** @file Descriptor-based direct memory access emulation. */ /** @file Descriptor-based direct memory access emulation. */
#include "dbdma.h"
#include "cpu/ppc/ppcmmu.h"
#include "endianswap.h"
#include <cinttypes> #include <cinttypes>
#include <thirdparty/loguru/loguru.hpp> #include <thirdparty/loguru/loguru.hpp>
#include "dbdma.h"
#include "endianswap.h"
#include "cpu/ppc/ppcmmu.h"
void DMAChannel::get_next_cmd(uint32_t cmd_addr, DMACmd *p_cmd) void DMAChannel::get_next_cmd(uint32_t cmd_addr, DMACmd* p_cmd) {
{
/* load DMACmd from physical memory */ /* load DMACmd from physical memory */
memcpy((uint8_t*)p_cmd, mmu_get_dma_mem(cmd_addr, 16), 16); memcpy((uint8_t*)p_cmd, mmu_get_dma_mem(cmd_addr, 16), 16);
} }
uint8_t DMAChannel::interpret_cmd() uint8_t DMAChannel::interpret_cmd() {
{
DMACmd cmd_struct; DMACmd cmd_struct;
get_next_cmd(this->cmd_ptr, &cmd_struct); get_next_cmd(this->cmd_ptr, &cmd_struct);
@ -105,8 +103,7 @@ uint8_t DMAChannel::interpret_cmd()
} }
uint32_t DMAChannel::reg_read(uint32_t offset, int size) uint32_t DMAChannel::reg_read(uint32_t offset, int size) {
{
uint32_t res = 0; uint32_t res = 0;
if (size != 4) { if (size != 4) {
@ -128,8 +125,7 @@ uint32_t DMAChannel::reg_read(uint32_t offset, int size)
return res; return res;
} }
void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size) void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size) {
{
uint16_t mask, old_stat, new_stat; uint16_t mask, old_stat, new_stat;
if (size != 4) { if (size != 4) {
@ -187,8 +183,7 @@ void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size)
} }
} }
int DMAChannel::get_data(uint32_t req_len, uint32_t *avail_len, uint8_t **p_data) int DMAChannel::get_data(uint32_t req_len, uint32_t* avail_len, uint8_t** p_data) {
{
if (this->ch_stat & CH_STAT_DEAD || !(this->ch_stat & CH_STAT_ACTIVE)) { if (this->ch_stat & CH_STAT_DEAD || !(this->ch_stat & CH_STAT_ACTIVE)) {
LOG_F(WARNING, "Dead/idle channel -> no more data"); LOG_F(WARNING, "Dead/idle channel -> no more data");
*avail_len = 0; *avail_len = 0;
@ -220,8 +215,7 @@ int DMAChannel::get_data(uint32_t req_len, uint32_t *avail_len, uint8_t **p_data
return -1; /* tell the caller there is no more data */ return -1; /* tell the caller there is no more data */
} }
void DMAChannel::start() void DMAChannel::start() {
{
if (this->ch_stat & CH_STAT_PAUSE) { if (this->ch_stat & CH_STAT_PAUSE) {
LOG_F(WARNING, "Cannot start DMA channel, PAUSE bit is set"); LOG_F(WARNING, "Cannot start DMA channel, PAUSE bit is set");
return; return;
@ -237,8 +231,7 @@ void DMAChannel::start()
//} //}
} }
void DMAChannel::resume() void DMAChannel::resume() {
{
if (this->ch_stat & CH_STAT_PAUSE) { if (this->ch_stat & CH_STAT_PAUSE) {
LOG_F(WARNING, "Cannot resume DMA channel, PAUSE bit is set"); LOG_F(WARNING, "Cannot resume DMA channel, PAUSE bit is set");
return; return;
@ -247,13 +240,11 @@ void DMAChannel::resume()
LOG_F(INFO, "Resuming DMA channel"); LOG_F(INFO, "Resuming DMA channel");
} }
void DMAChannel::abort() void DMAChannel::abort() {
{
LOG_F(INFO, "Aborting DMA channel"); LOG_F(INFO, "Aborting DMA channel");
} }
void DMAChannel::pause() void DMAChannel::pause() {
{
LOG_F(INFO, "Pausing DMA channel"); LOG_F(INFO, "Pausing DMA channel");
this->dma_cb->dma_end(); this->dma_cb->dma_end();
} }

View File

@ -69,7 +69,9 @@ public:
class DMAChannel { class DMAChannel {
public: public:
DMAChannel(DMACallback *cb) { this->dma_cb = cb; }; DMAChannel(DMACallback* cb) {
this->dma_cb = cb;
};
~DMAChannel() = default; ~DMAChannel() = default;
uint32_t reg_read(uint32_t offset, int size); uint32_t reg_read(uint32_t offset, int size);

View File

@ -19,11 +19,10 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <thirdparty/loguru/loguru.hpp>
#include "displayid.h" #include "displayid.h"
#include <thirdparty/loguru/loguru.hpp>
DisplayID::DisplayID() DisplayID::DisplayID() {
{
/* Initialize Apple monitor codes */ /* Initialize Apple monitor codes */
this->std_sense_code = 6; this->std_sense_code = 6;
this->ext_sense_code = 0x2B; this->ext_sense_code = 0x2B;
@ -41,22 +40,19 @@ DisplayID::DisplayID()
} }
uint16_t DisplayID::set_result(uint8_t sda, uint8_t scl) uint16_t DisplayID::set_result(uint8_t sda, uint8_t scl) {
{
this->last_sda = sda; this->last_sda = sda;
this->last_scl = scl; this->last_scl = scl;
if (scl) { if (scl) {
this->data_out |= 0x1000; this->data_out |= 0x1000;
} } else {
else {
this->data_out &= ~0x1000U; this->data_out &= ~0x1000U;
} }
if (sda) { if (sda) {
this->data_out |= 0x2000; this->data_out |= 0x2000;
} } else {
else {
this->data_out &= ~0x2000U; this->data_out &= ~0x2000U;
} }
@ -64,8 +60,7 @@ uint16_t DisplayID::set_result(uint8_t sda, uint8_t scl)
} }
uint16_t DisplayID::read_monitor_sense(uint16_t data, uint16_t dirs) uint16_t DisplayID::read_monitor_sense(uint16_t data, uint16_t dirs) {
{
uint8_t scl, sda; uint8_t scl, sda;
uint16_t result; uint16_t result;
@ -81,24 +76,19 @@ uint16_t DisplayID::read_monitor_sense(uint16_t data, uint16_t dirs)
sda = (dirs & 0x2000) ? !!(data & 0x2000) : 1; sda = (dirs & 0x2000) ? !!(data & 0x2000) : 1;
return update_ddc_i2c(sda, scl); return update_ddc_i2c(sda, scl);
} } else { /* Apple legacy monitor codes (see Technical Note HW30) */
else { /* Apple legacy monitor codes (see Technical Note HW30) */
switch (dirs & 0x3100) { switch (dirs & 0x3100) {
case 0: case 0:
result = ((this->std_sense_code & 6) << 11) | result = ((this->std_sense_code & 6) << 11) | ((this->std_sense_code & 1) << 8);
((this->std_sense_code & 1) << 8);
break; break;
case 0x2000: /* Sense line 2 is low */ case 0x2000: /* Sense line 2 is low */
result = ((this->ext_sense_code & 0x20) << 7) | result = ((this->ext_sense_code & 0x20) << 7) | ((this->ext_sense_code & 0x10) << 4);
((this->ext_sense_code & 0x10) << 4);
break; break;
case 0x1000: /* Sense line 1 is low */ case 0x1000: /* Sense line 1 is low */
result = ((this->ext_sense_code & 8) << 10) | result = ((this->ext_sense_code & 8) << 10) | ((this->ext_sense_code & 4) << 6);
((this->ext_sense_code & 4) << 6);
break; break;
case 0x100: /* Sense line 0 is low */ case 0x100: /* Sense line 0 is low */
result = ((this->ext_sense_code & 2) << 12) | result = ((this->ext_sense_code & 2) << 12) | ((this->ext_sense_code & 1) << 12);
((this->ext_sense_code & 1) << 12);
break; break;
default: default:
result = 0x3100U; result = 0x3100U;
@ -128,8 +118,7 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
LOG_F(9, "DDC-I2C: START condition detected!"); LOG_F(9, "DDC-I2C: START condition detected!");
this->next_state = I2CState::DEV_ADDR; this->next_state = I2CState::DEV_ADDR;
this->bit_count = 0; this->bit_count = 0;
} } else {
else {
LOG_F(9, "DDC-I2C: STOP condition detected!"); LOG_F(9, "DDC-I2C: STOP condition detected!");
this->next_state = I2CState::STOP; this->next_state = I2CState::STOP;
} }
@ -152,8 +141,7 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
case I2CState::DEV_ADDR: case I2CState::DEV_ADDR:
if ((dev_addr & 0xFE) == 0xA0) { if ((dev_addr & 0xFE) == 0xA0) {
sda = 0; /* send ACK */ sda = 0; /* send ACK */
} } else {
else {
LOG_F(ERROR, "DDC-I2C: unknown device address 0x%X", this->dev_addr); LOG_F(ERROR, "DDC-I2C: unknown device address 0x%X", this->dev_addr);
sda = 1; /* send NACK */ sda = 1; /* send NACK */
} }
@ -161,8 +149,7 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
this->next_state = I2CState::DATA; this->next_state = I2CState::DATA;
this->data_ptr = this->edid; this->data_ptr = this->edid;
this->byte = *(this->data_ptr++); this->byte = *(this->data_ptr++);
} } else {
else {
this->next_state = I2CState::REG_ADDR; this->next_state = I2CState::REG_ADDR;
} }
break; break;
@ -170,8 +157,7 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
this->next_state = I2CState::DATA; this->next_state = I2CState::DATA;
if (!this->reg_addr) { if (!this->reg_addr) {
sda = 0; /* send ACK */ sda = 0; /* send ACK */
} } else {
else {
LOG_F(ERROR, "DDC-I2C: unknown register address 0x%X", this->reg_addr); LOG_F(ERROR, "DDC-I2C: unknown register address 0x%X", this->reg_addr);
sda = 1; /* send NACK */ sda = 1; /* send NACK */
} }
@ -182,12 +168,10 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
if (!sda) { if (!sda) {
/* load next data byte */ /* load next data byte */
this->byte = *(this->data_ptr++); this->byte = *(this->data_ptr++);
} } else {
else {
LOG_F(ERROR, "DDC-I2C: Oops! NACK received"); LOG_F(ERROR, "DDC-I2C: Oops! NACK received");
} }
} } else {
else {
sda = 0; /* send ACK */ sda = 0; /* send ACK */
} }
break; break;
@ -204,8 +188,7 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
if (this->prev_state == I2CState::DEV_ADDR) { if (this->prev_state == I2CState::DEV_ADDR) {
LOG_F(9, "DDC-I2C: device address received, addr=0x%X", this->byte); LOG_F(9, "DDC-I2C: device address received, addr=0x%X", this->byte);
this->dev_addr = this->byte; this->dev_addr = this->byte;
} } else {
else {
LOG_F(9, "DDC-I2C: register address received, addr=0x%X", this->byte); LOG_F(9, "DDC-I2C: register address received, addr=0x%X", this->byte);
this->reg_addr = this->byte; this->reg_addr = this->byte;
} }

View File

@ -77,23 +77,15 @@ private:
uint8_t* data_ptr; /* ptr to data byte to be transferred next */ uint8_t* data_ptr; /* ptr to data byte to be transferred next */
uint8_t edid[128] = { uint8_t edid[128] = {
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x06, 0x10, 0x02, 0x9d, 0x01, 0x01, 0x01,
0x06, 0x10, 0x02, 0x9d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x09, 0x01, 0x01, 0x68, 0x20, 0x18, 0x28, 0xe8, 0x04, 0x89, 0xa0, 0x57, 0x4a,
0x08, 0x09, 0x01, 0x01, 0x68, 0x20, 0x18, 0x28, 0x9b, 0x26, 0x12, 0x48, 0x4c, 0x31, 0x2b, 0x80, 0x31, 0x59, 0x45, 0x59, 0x61, 0x59, 0xa9,
0xe8, 0x04, 0x89, 0xa0, 0x57, 0x4a, 0x9b, 0x26, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x60, 0x16, 0x40, 0x40, 0x31, 0x70,
0x12, 0x48, 0x4c, 0x31, 0x2b, 0x80, 0x31, 0x59, 0x2b, 0x20, 0x20, 0x40, 0x23, 0x00, 0x38, 0xea, 0x10, 0x00, 0x00, 0x18, 0x48, 0x3f, 0x40,
0x45, 0x59, 0x61, 0x59, 0xa9, 0x40, 0x01, 0x01, 0x32, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc2, 0x13, 0x00, 0x38, 0xea, 0x10, 0x00, 0x00, 0x18,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x60, 0x16, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x30, 0xa0, 0x1e, 0x55, 0x10, 0x00, 0x0a, 0x20, 0x20, 0x20,
0x40, 0x40, 0x31, 0x70, 0x2b, 0x20, 0x20, 0x40, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x74, 0x75, 0x64, 0x69, 0x6f, 0x44,
0x23, 0x00, 0x38, 0xea, 0x10, 0x00, 0x00, 0x18, 0x73, 0x70, 0x6c, 0x79, 0x31, 0x37, 0x00, 0x19};
0x48, 0x3f, 0x40, 0x32, 0x62, 0xb0, 0x32, 0x40,
0x40, 0xc2, 0x13, 0x00, 0x38, 0xea, 0x10, 0x00,
0x00, 0x18, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x30,
0xa0, 0x1e, 0x55, 0x10, 0x00, 0x0a, 0x20, 0x20,
0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
0x00, 0x53, 0x74, 0x75, 0x64, 0x69, 0x6f, 0x44,
0x73, 0x70, 0x6c, 0x79, 0x31, 0x37, 0x00, 0x19
};
/* More EDID: /* More EDID:
00ff ffff ffff ff00 5a63 5151 0341 0000 00ff ffff ffff ff00 5a63 5151 0341 0000

View File

@ -19,14 +19,14 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <thirdparty/loguru/loguru.hpp>
#include <cinttypes>
#include <iostream>
#include "macio.h"
#include "viacuda.h"
#include "awacs.h" #include "awacs.h"
#include "dbdma.h" #include "dbdma.h"
#include "machines/machinebase.h" #include "machines/machinebase.h"
#include "macio.h"
#include "viacuda.h"
#include <cinttypes>
#include <iostream>
#include <thirdparty/loguru/loguru.hpp>
/** Heathrow Mac I/O device emulation. /** Heathrow Mac I/O device emulation.
@ -35,8 +35,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
using namespace std; using namespace std;
HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow") HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow") {
{
this->nvram = new NVram(); this->nvram = new NVram();
this->viacuda = new ViaCuda(); this->viacuda = new ViaCuda();
@ -47,8 +46,7 @@ HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow")
this->screamer->set_dma_out(this->snd_out_dma); this->screamer->set_dma_out(this->snd_out_dma);
} }
HeathrowIC::~HeathrowIC() HeathrowIC::~HeathrowIC() {
{
if (this->nvram) if (this->nvram)
delete (this->nvram); delete (this->nvram);
@ -57,27 +55,25 @@ HeathrowIC::~HeathrowIC()
} }
uint32_t HeathrowIC::pci_cfg_read(uint32_t reg_offs, uint32_t size) uint32_t HeathrowIC::pci_cfg_read(uint32_t reg_offs, uint32_t size) {
{
return this->pci_cfg_hdr[reg_offs & 0xFF]; return this->pci_cfg_hdr[reg_offs & 0xFF];
} }
void HeathrowIC::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) void HeathrowIC::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) {
{
switch (reg_offs) { switch (reg_offs) {
case CFG_REG_BAR0: // base address register case CFG_REG_BAR0: // base address register
value = LE2BE(value); value = LE2BE(value);
if (value == 0xFFFFFFFF) { if (value == 0xFFFFFFFF) {
LOG_F(ERROR, "%s err: BAR0 block size determination not \ LOG_F(
implemented yet \n", this->name.c_str()); ERROR,
} "%s err: BAR0 block size determination not \
else if (value & 1) { implemented yet \n",
this->name.c_str());
} else if (value & 1) {
LOG_F(ERROR, "%s err: BAR0 I/O space not supported! \n", this->name.c_str()); LOG_F(ERROR, "%s err: BAR0 I/O space not supported! \n", this->name.c_str());
} } else if (value & 0x06) {
else if (value & 0x06) {
LOG_F(ERROR, "%s err: BAR0 64-bit I/O space not supported! \n", this->name.c_str()); LOG_F(ERROR, "%s err: BAR0 64-bit I/O space not supported! \n", this->name.c_str());
} } else {
else {
this->base_addr = value & 0xFFF80000; this->base_addr = value & 0xFFF80000;
this->host_instance->pci_register_mmio_region(this->base_addr, 0x80000, this); this->host_instance->pci_register_mmio_region(this->base_addr, 0x80000, this);
LOG_F(INFO, "%s base address set to %x \n", this->name.c_str(), this->base_addr); LOG_F(INFO, "%s base address set to %x \n", this->name.c_str(), this->base_addr);
@ -86,8 +82,7 @@ void HeathrowIC::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
} }
} }
uint32_t HeathrowIC::dma_read(uint32_t offset, int size) uint32_t HeathrowIC::dma_read(uint32_t offset, int size) {
{
uint32_t res = 0; uint32_t res = 0;
switch (offset >> 8) { switch (offset >> 8) {
@ -101,8 +96,7 @@ uint32_t HeathrowIC::dma_read(uint32_t offset, int size)
return res; return res;
} }
void HeathrowIC::dma_write(uint32_t offset, uint32_t value, int size) void HeathrowIC::dma_write(uint32_t offset, uint32_t value, int size) {
{
switch (offset >> 8) { switch (offset >> 8) {
case 8: case 8:
this->snd_out_dma->reg_write(offset & 0xFF, value, size); this->snd_out_dma->reg_write(offset & 0xFF, value, size);
@ -113,8 +107,7 @@ void HeathrowIC::dma_write(uint32_t offset, uint32_t value, int size)
} }
uint32_t HeathrowIC::read(uint32_t reg_start, uint32_t offset, int size) uint32_t HeathrowIC::read(uint32_t reg_start, uint32_t offset, int size) {
{
uint32_t res = 0; uint32_t res = 0;
LOG_F(9, "%s: reading from offset %x \n", this->name.c_str(), offset); LOG_F(9, "%s: reading from offset %x \n", this->name.c_str(), offset);
@ -138,8 +131,7 @@ uint32_t HeathrowIC::read(uint32_t reg_start, uint32_t offset, int size)
default: default:
if (sub_addr >= 0x60) { if (sub_addr >= 0x60) {
res = this->nvram->read_byte((offset - 0x60000) >> 4); res = this->nvram->read_byte((offset - 0x60000) >> 4);
} } else {
else {
LOG_F(WARNING, "Attempting to read unmapped I/O space: %x \n", offset); LOG_F(WARNING, "Attempting to read unmapped I/O space: %x \n", offset);
} }
} }
@ -147,8 +139,7 @@ uint32_t HeathrowIC::read(uint32_t reg_start, uint32_t offset, int size)
return res; return res;
} }
void HeathrowIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) void HeathrowIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) {
{
LOG_F(9, "%s: writing to offset %x \n", this->name.c_str(), offset); LOG_F(9, "%s: writing to offset %x \n", this->name.c_str(), offset);
unsigned sub_addr = (offset >> 12) & 0x7F; unsigned sub_addr = (offset >> 12) & 0x7F;
@ -170,15 +161,13 @@ void HeathrowIC::write(uint32_t reg_start, uint32_t offset, uint32_t value, int
default: default:
if (sub_addr >= 0x60) { if (sub_addr >= 0x60) {
this->nvram->write_byte((offset - 0x60000) >> 4, value); this->nvram->write_byte((offset - 0x60000) >> 4, value);
} } else {
else {
LOG_F(WARNING, "Attempting to write to unmapped I/O space: %x \n", offset); LOG_F(WARNING, "Attempting to write to unmapped I/O space: %x \n", offset);
} }
} }
} }
uint32_t HeathrowIC::mio_ctrl_read(uint32_t offset, int size) uint32_t HeathrowIC::mio_ctrl_read(uint32_t offset, int size) {
{
uint32_t res = 0; uint32_t res = 0;
switch (offset & 0xFF) { switch (offset & 0xFF) {
@ -221,8 +210,7 @@ uint32_t HeathrowIC::mio_ctrl_read(uint32_t offset, int size)
return res; return res;
} }
void HeathrowIC::mio_ctrl_write(uint32_t offset, uint32_t value, int size) void HeathrowIC::mio_ctrl_write(uint32_t offset, uint32_t value, int size) {
{
switch (offset & 0xFF) { switch (offset & 0xFF) {
case 0x14: case 0x14:
LOG_F(9, "read from MIO:Int_Mask2 register \n"); LOG_F(9, "read from MIO:Int_Mask2 register \n");

View File

@ -45,8 +45,12 @@ class HWComponent {
public: public:
virtual ~HWComponent() = default; virtual ~HWComponent() = default;
virtual std::string get_name(void) { return this->name; }; virtual std::string get_name(void) {
virtual void set_name(std::string name) { this->name = name; }; return this->name;
};
virtual void set_name(std::string name) {
this->name = name;
};
virtual bool supports_type(HWCompType type) = 0; virtual bool supports_type(HWCompType type) = 0;

View File

@ -27,9 +27,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef I2C_H #ifndef I2C_H
#define I2C_H #define I2C_H
#include <thirdparty/loguru/loguru.hpp>
#include <string>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <thirdparty/loguru/loguru.hpp>
/** Base class for I2C devices */ /** Base class for I2C devices */
class I2CDevice { class I2CDevice {
@ -43,8 +43,12 @@ public:
/** Base class for I2C hosts */ /** Base class for I2C hosts */
class I2CBus { class I2CBus {
public: public:
I2CBus() { std::memset(this->dev_list, 0, sizeof(this->dev_list)); }; I2CBus() {
~I2CBus() { std::memset(this->dev_list, 0, sizeof(this->dev_list)); }; std::memset(this->dev_list, 0, sizeof(this->dev_list));
};
~I2CBus() {
std::memset(this->dev_list, 0, sizeof(this->dev_list));
};
virtual void register_device(uint8_t dev_addr, I2CDevice* dev_obj) { virtual void register_device(uint8_t dev_addr, I2CDevice* dev_obj) {
if (this->dev_list[dev_addr]) { if (this->dev_list[dev_addr]) {

View File

@ -22,9 +22,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef MACHINE_ID_H #ifndef MACHINE_ID_H
#define MACHINE_ID_H #define MACHINE_ID_H
#include <cinttypes>
#include "hwcomponent.h" #include "hwcomponent.h"
#include "mmiodevice.h" #include "mmiodevice.h"
#include <cinttypes>
/** /**
@file Contains definitions for PowerMacintosh machine ID registers. @file Contains definitions for PowerMacintosh machine ID registers.
@ -44,7 +44,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
class GossamerID : public MMIODevice { class GossamerID : public MMIODevice {
public: public:
GossamerID(const uint16_t id) { this->id = id, this->name = "Machine-id"; }; GossamerID(const uint16_t id) {
this->id = id, this->name = "Machine-id";
};
~GossamerID() = default; ~GossamerID() = default;
bool supports_type(HWCompType type) { bool supports_type(HWCompType type) {
@ -52,10 +54,10 @@ public:
}; };
uint32_t read(uint32_t reg_start, uint32_t offset, int size) { uint32_t read(uint32_t reg_start, uint32_t offset, int size) {
return ((!offset && size == 2) ? this->id : 0); }; return ((!offset && size == 2) ? this->id : 0);
};
void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size){}; /* not writable */
{}; /* not writable */
private: private:
uint16_t id; uint16_t id;

View File

@ -51,16 +51,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef MACIO_H #ifndef MACIO_H
#define MACIO_H #define MACIO_H
#include <cinttypes>
#include "hwcomponent.h"
#include "pcidevice.h"
#include "memctrlbase.h"
#include "mmiodevice.h"
#include "pcihost.h"
#include "viacuda.h"
#include "nvram.h"
#include "awacs.h" #include "awacs.h"
#include "dbdma.h" #include "dbdma.h"
#include "hwcomponent.h"
#include "memctrlbase.h"
#include "mmiodevice.h"
#include "nvram.h"
#include "pcidevice.h"
#include "pcihost.h"
#include "viacuda.h"
#include <cinttypes>
/** /**
Heathrow ASIC emulation Heathrow ASIC emulation
@ -86,16 +86,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
VIA-CUDA register space: 0x00016000, size: 0x00002000 VIA-CUDA register space: 0x00016000, size: 0x00002000
*/ */
class HeathrowIC : public PCIDevice class HeathrowIC : public PCIDevice {
{
public: public:
HeathrowIC(); HeathrowIC();
~HeathrowIC(); ~HeathrowIC();
bool supports_type(HWCompType type) { return type == HWCompType::MMIO_DEV; }; bool supports_type(HWCompType type) {
return type == HWCompType::MMIO_DEV;
};
/* PCI device methods */ /* PCI device methods */
bool supports_io_space(void) { return false; }; bool supports_io_space(void) {
return false;
};
uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size);
void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size);
@ -113,17 +116,23 @@ protected:
private: private:
uint8_t pci_cfg_hdr[256] = { uint8_t pci_cfg_hdr[256] = {
0x6B, 0x10, // vendor ID: Apple Computer Inc. 0x6B,
0x10, 0x00, // device ID: Heathrow Mac I/O 0x10, // vendor ID: Apple Computer Inc.
0x00, 0x00, // PCI command (set to 0 at power-up?) 0x10,
0x00, 0x00, // PCI status (set to 0 at power-up?) 0x00, // device ID: Heathrow Mac I/O
0x00,
0x00, // PCI command (set to 0 at power-up?)
0x00,
0x00, // PCI status (set to 0 at power-up?)
0x01, // revision ID 0x01, // revision ID
// class code is reported in OF property "class-code" as 0xff0000 // class code is reported in OF property "class-code" as 0xff0000
0x00, // standard programming 0x00, // standard programming
0x00, // subclass code 0x00, // subclass code
0xFF, // class code: unassigned 0xFF, // class code: unassigned
0x00, 0x00, // unknown defaults 0x00,
0x00, 0x00 // unknown defaults 0x00, // unknown defaults
0x00,
0x00 // unknown defaults
}; };
uint32_t int_mask2; uint32_t int_mask2;

View File

@ -19,16 +19,15 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <string>
#include <cstring>
#include <vector>
#include <algorithm> // to shut up MSVC errors (: #include <algorithm> // to shut up MSVC errors (:
#include <cstring>
#include <string>
#include <vector>
#include "memctrlbase.h" #include "memctrlbase.h"
MemCtrlBase::~MemCtrlBase() MemCtrlBase::~MemCtrlBase() {
{
for (auto& reg : mem_regions) { for (auto& reg : mem_regions) {
if (reg) if (reg)
delete (reg); delete (reg);
@ -38,8 +37,7 @@ MemCtrlBase::~MemCtrlBase()
} }
AddressMapEntry *MemCtrlBase::find_range(uint32_t addr) AddressMapEntry* MemCtrlBase::find_range(uint32_t addr) {
{
for (auto& entry : address_map) { for (auto& entry : address_map) {
if (addr >= entry.start && addr <= entry.end) if (addr >= entry.start && addr <= entry.end)
return &entry; return &entry;
@ -49,9 +47,8 @@ AddressMapEntry *MemCtrlBase::find_range(uint32_t addr)
} }
bool MemCtrlBase::add_mem_region(uint32_t start_addr, uint32_t size, bool MemCtrlBase::add_mem_region(
uint32_t dest_addr, uint32_t type, uint8_t init_val = 0) uint32_t start_addr, uint32_t size, uint32_t dest_addr, uint32_t type, uint8_t init_val = 0) {
{
AddressMapEntry entry; AddressMapEntry entry;
/* error if a memory region for the given range already exists */ /* error if a memory region for the given range already exists */
@ -75,20 +72,17 @@ bool MemCtrlBase::add_mem_region(uint32_t start_addr, uint32_t size,
} }
bool MemCtrlBase::add_rom_region(uint32_t start_addr, uint32_t size) bool MemCtrlBase::add_rom_region(uint32_t start_addr, uint32_t size) {
{
return add_mem_region(start_addr, size, 0, RT_ROM); return add_mem_region(start_addr, size, 0, RT_ROM);
} }
bool MemCtrlBase::add_ram_region(uint32_t start_addr, uint32_t size) bool MemCtrlBase::add_ram_region(uint32_t start_addr, uint32_t size) {
{
return add_mem_region(start_addr, size, 0, RT_RAM); return add_mem_region(start_addr, size, 0, RT_RAM);
} }
bool MemCtrlBase::add_mem_mirror(uint32_t start_addr, uint32_t dest_addr) bool MemCtrlBase::add_mem_mirror(uint32_t start_addr, uint32_t dest_addr) {
{
AddressMapEntry entry, *ref_entry; AddressMapEntry entry, *ref_entry;
ref_entry = find_range(dest_addr); ref_entry = find_range(dest_addr);
@ -108,8 +102,7 @@ bool MemCtrlBase::add_mem_mirror(uint32_t start_addr, uint32_t dest_addr)
} }
bool MemCtrlBase::set_data(uint32_t reg_addr, const uint8_t *data, uint32_t size) bool MemCtrlBase::set_data(uint32_t reg_addr, const uint8_t* data, uint32_t size) {
{
AddressMapEntry* ref_entry; AddressMapEntry* ref_entry;
uint32_t cpy_size; uint32_t cpy_size;
@ -124,9 +117,7 @@ bool MemCtrlBase::set_data(uint32_t reg_addr, const uint8_t *data, uint32_t size
} }
bool MemCtrlBase::add_mmio_region(uint32_t start_addr, uint32_t size, bool MemCtrlBase::add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice* dev_instance) {
MMIODevice *dev_instance)
{
AddressMapEntry entry; AddressMapEntry entry;
/* error if another region for the given range already exists */ /* error if another region for the given range already exists */

View File

@ -22,10 +22,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef MEMORY_CONTROLLER_BASE_H #ifndef MEMORY_CONTROLLER_BASE_H
#define MEMORY_CONTROLLER_BASE_H #define MEMORY_CONTROLLER_BASE_H
#include "mmiodevice.h"
#include <cinttypes> #include <cinttypes>
#include <string> #include <string>
#include <vector> #include <vector>
#include "mmiodevice.h"
enum RangeType { enum RangeType {
RT_ROM = 1, /* read-only memory */ RT_ROM = 1, /* read-only memory */
@ -62,8 +62,8 @@ public:
AddressMapEntry* find_range(uint32_t addr); AddressMapEntry* find_range(uint32_t addr);
protected: protected:
bool add_mem_region(uint32_t start_addr, uint32_t size, uint32_t dest_addr, bool add_mem_region(
uint32_t type, uint8_t init_val); uint32_t start_addr, uint32_t size, uint32_t dest_addr, uint32_t type, uint8_t init_val);
private: private:
std::vector<uint8_t*> mem_regions; std::vector<uint8_t*> mem_regions;

View File

@ -22,9 +22,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef MMIO_DEVICE_H #ifndef MMIO_DEVICE_H
#define MMIO_DEVICE_H #define MMIO_DEVICE_H
#include "hwcomponent.h"
#include <cinttypes> #include <cinttypes>
#include <string> #include <string>
#include "hwcomponent.h"
/** Abstract class representing a simple, memory-mapped I/O device */ /** Abstract class representing a simple, memory-mapped I/O device */
class MMIODevice : public HWComponent { class MMIODevice : public HWComponent {

View File

@ -24,20 +24,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
Author: Max Poliakovski Author: Max Poliakovski
*/ */
#include <thirdparty/loguru/loguru.hpp>
#include <iostream>
#include <cstring>
#include <cinttypes> #include <cinttypes>
#include <cstring>
#include <iostream>
#include <thirdparty/loguru/loguru.hpp>
#include "memreadwrite.h"
#include "memctrlbase.h"
#include "mmiodevice.h"
#include "hwcomponent.h" #include "hwcomponent.h"
#include "memctrlbase.h"
#include "memreadwrite.h"
#include "mmiodevice.h"
#include "mpc106.h" #include "mpc106.h"
MPC106::MPC106() : MemCtrlBase(), PCIDevice("Grackle PCI host bridge") MPC106::MPC106() : MemCtrlBase(), PCIDevice("Grackle PCI host bridge") {
{
this->name = "Grackle"; this->name = "Grackle";
/* add PCI/ISA I/O space, 64K for now */ /* add PCI/ISA I/O space, 64K for now */
@ -50,13 +49,11 @@ MPC106::MPC106() : MemCtrlBase(), PCIDevice("Grackle PCI host bridge")
this->io_space_devs.clear(); this->io_space_devs.clear();
} }
MPC106::~MPC106() MPC106::~MPC106() {
{
this->pci_0_bus.clear(); this->pci_0_bus.clear();
} }
bool MPC106::supports_type(HWCompType type) bool MPC106::supports_type(HWCompType type) {
{
if (type == HWCompType::MEM_CTRL || type == HWCompType::MMIO_DEV || if (type == HWCompType::MEM_CTRL || type == HWCompType::MMIO_DEV ||
type == HWCompType::PCI_HOST || type == HWCompType::PCI_DEV) { type == HWCompType::PCI_HOST || type == HWCompType::PCI_DEV) {
return true; return true;
@ -65,8 +62,7 @@ bool MPC106::supports_type(HWCompType type)
} }
} }
uint32_t MPC106::read(uint32_t reg_start, uint32_t offset, int size) uint32_t MPC106::read(uint32_t reg_start, uint32_t offset, int size) {
{
uint32_t result; uint32_t result;
if (reg_start == 0xFE000000) { if (reg_start == 0xFE000000) {
@ -78,8 +74,7 @@ uint32_t MPC106::read(uint32_t reg_start, uint32_t offset, int size)
} }
} }
LOG_F(ERROR, "Attempt to read from unmapped PCI I/O space, offset=0x%X", offset); LOG_F(ERROR, "Attempt to read from unmapped PCI I/O space, offset=0x%X", offset);
} } else {
else {
if (offset >= 0x200000) { if (offset >= 0x200000) {
if (this->config_addr & 0x80) // process only if bit E (enable) is set if (this->config_addr & 0x80) // process only if bit E (enable) is set
return pci_read(size); return pci_read(size);
@ -91,8 +86,7 @@ uint32_t MPC106::read(uint32_t reg_start, uint32_t offset, int size)
return 0; return 0;
} }
void MPC106::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) void MPC106::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) {
{
if (reg_start == 0xFE000000) { if (reg_start == 0xFE000000) {
/* broadcast I/O request to devices that support I/O space /* broadcast I/O request to devices that support I/O space
until a device returns true that means "request accepted" */ until a device returns true that means "request accepted" */
@ -102,26 +96,26 @@ void MPC106::write(uint32_t reg_start, uint32_t offset, uint32_t value, int size
} }
} }
LOG_F(ERROR, "Attempt to write to unmapped PCI I/O space, offset=0x%X", offset); LOG_F(ERROR, "Attempt to write to unmapped PCI I/O space, offset=0x%X", offset);
} } else {
else {
if (offset < 0x200000) { if (offset < 0x200000) {
this->config_addr = value; this->config_addr = value;
} } else {
else {
if (this->config_addr & 0x80) // process only if bit E (enable) is set if (this->config_addr & 0x80) // process only if bit E (enable) is set
return pci_write(value, size); return pci_write(value, size);
} }
} }
} }
uint32_t MPC106::pci_read(uint32_t size) uint32_t MPC106::pci_read(uint32_t size) {
{
int bus_num, dev_num, fun_num, reg_offs; int bus_num, dev_num, fun_num, reg_offs;
bus_num = (this->config_addr >> 8) & 0xFF; bus_num = (this->config_addr >> 8) & 0xFF;
if (bus_num) { if (bus_num) {
LOG_F(ERROR, "%s err: read attempt from non-local PCI bus, config_addr = %x \n", \ LOG_F(
this->name.c_str(), this->config_addr); ERROR,
"%s err: read attempt from non-local PCI bus, config_addr = %x \n",
this->name.c_str(),
this->config_addr);
return 0; return 0;
} }
@ -135,7 +129,11 @@ uint32_t MPC106::pci_read(uint32_t size)
if (this->pci_0_bus.count(dev_num)) { if (this->pci_0_bus.count(dev_num)) {
return this->pci_0_bus[dev_num]->pci_cfg_read(reg_offs, size); return this->pci_0_bus[dev_num]->pci_cfg_read(reg_offs, size);
} else { } else {
LOG_F(ERROR, "%s err: read attempt from non-existing PCI device %d \n", this->name.c_str(), dev_num); LOG_F(
ERROR,
"%s err: read attempt from non-existing PCI device %d \n",
this->name.c_str(),
dev_num);
return 0; return 0;
} }
} }
@ -143,14 +141,16 @@ uint32_t MPC106::pci_read(uint32_t size)
return 0; return 0;
} }
void MPC106::pci_write(uint32_t value, uint32_t size) void MPC106::pci_write(uint32_t value, uint32_t size) {
{
int bus_num, dev_num, fun_num, reg_offs; int bus_num, dev_num, fun_num, reg_offs;
bus_num = (this->config_addr >> 8) & 0xFF; bus_num = (this->config_addr >> 8) & 0xFF;
if (bus_num) { if (bus_num) {
LOG_F(ERROR, "%s err: write attempt to non-local PCI bus, config_addr = %x \n", LOG_F(
this->name.c_str(), this->config_addr); ERROR,
"%s err: write attempt to non-local PCI bus, config_addr = %x \n",
this->name.c_str(),
this->config_addr);
return; return;
} }
@ -164,14 +164,16 @@ void MPC106::pci_write(uint32_t value, uint32_t size)
if (this->pci_0_bus.count(dev_num)) { if (this->pci_0_bus.count(dev_num)) {
this->pci_0_bus[dev_num]->pci_cfg_write(reg_offs, value, size); this->pci_0_bus[dev_num]->pci_cfg_write(reg_offs, value, size);
} else { } else {
LOG_F(ERROR, "%s err: write attempt to non-existing PCI device %d \n", \ LOG_F(
this->name.c_str(), dev_num); ERROR,
"%s err: write attempt to non-existing PCI device %d \n",
this->name.c_str(),
dev_num);
} }
} }
} }
uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size) uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size) {
{
#ifdef MPC106_DEBUG #ifdef MPC106_DEBUG
LOG_F(9, "read from Grackle register %08X\n", reg_offs); LOG_F(9, "read from Grackle register %08X\n", reg_offs);
#endif #endif
@ -193,8 +195,7 @@ uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size)
return 0; return 0;
} }
void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) {
{
#ifdef MPC106_DEBUG #ifdef MPC106_DEBUG
LOG_F(9, "write %08X to Grackle register %08X\n", value, reg_offs); LOG_F(9, "write %08X to Grackle register %08X\n", value, reg_offs);
#endif #endif
@ -226,8 +227,7 @@ void MPC106::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
} }
} }
bool MPC106::pci_register_device(int dev_num, PCIDevice *dev_instance) bool MPC106::pci_register_device(int dev_num, PCIDevice* dev_instance) {
{
if (this->pci_0_bus.count(dev_num)) // is dev_num already registered? if (this->pci_0_bus.count(dev_num)) // is dev_num already registered?
return false; return false;
@ -242,14 +242,12 @@ bool MPC106::pci_register_device(int dev_num, PCIDevice *dev_instance)
return true; return true;
} }
bool MPC106::pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice *obj) bool MPC106::pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice* obj) {
{
// FIXME: add sanity checks! // FIXME: add sanity checks!
return this->add_mmio_region(start_addr, size, obj); return this->add_mmio_region(start_addr, size, obj);
} }
void MPC106::setup_ram() void MPC106::setup_ram() {
{
uint32_t mem_start, mem_end, ext_mem_start, ext_mem_end, bank_start, bank_end; uint32_t mem_start, mem_end, ext_mem_start, ext_mem_end, bank_start, bank_end;
uint32_t ram_size = 0; uint32_t ram_size = 0;

View File

@ -35,17 +35,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef MPC106_H_ #ifndef MPC106_H_
#define MPC106_H_ #define MPC106_H_
#include <cinttypes>
#include <unordered_map>
#include "hwcomponent.h" #include "hwcomponent.h"
#include "memctrlbase.h" #include "memctrlbase.h"
#include "mmiodevice.h" #include "mmiodevice.h"
#include "pcidevice.h" #include "pcidevice.h"
#include "pcihost.h" #include "pcihost.h"
#include <cinttypes>
#include <unordered_map>
class MPC106 : public MemCtrlBase, public PCIDevice, public PCIHost class MPC106 : public MemCtrlBase, public PCIDevice, public PCIHost {
{
public: public:
MPC106(); MPC106();
~MPC106(); ~MPC106();
@ -67,7 +66,9 @@ protected:
uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size); uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size);
void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size); void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size);
bool supports_io_space(void) { return true; }; bool supports_io_space(void) {
return true;
};
bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice* obj); bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice* obj);
@ -87,12 +88,9 @@ private:
0x00, // latency timer 0x00, // latency timer
0x00, // header type 0x00, // header type
0x00, // BIST Control 0x00, // BIST Control
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0x00, // Interrupt line 0x00, // Interrupt line
0x00, // Interrupt pin 0x00, // Interrupt pin
0x00, // MIN GNT 0x00, // MIN GNT
@ -100,8 +98,7 @@ private:
0x00, // Bus number 0x00, // Bus number
0x00, // Subordinate bus number 0x00, // Subordinate bus number
0x00, // Discount counter 0x00, // Discount counter
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // Performance monitor command
0x00, 0x00, 0x00, 0x00, //Performance monitor command
0x00, 0x00, // Performance monitor mode control 0x00, 0x00, // Performance monitor mode control
0xFF, 0xFF, 0xFF, 0xFF,
@ -110,17 +107,14 @@ private:
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 2 0x00, 0x00, 0x00, 0x00, // Performance monitor counter 2
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 3 0x00, 0x00, 0x00, 0x00, // Performance monitor counter 3
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, // Power mgt config 1 0x00, 0x00, // Power mgt config 1
0x00, // Power mgt config 2 0x00, // Power mgt config 2
0xCD, // default value for ODCR 0xCD, // default value for ODCR
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, // Memory Starting Address
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Memory Starting Address
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Extended Memory Starting Address 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Extended Memory Starting Address
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Memory Ending Address 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Memory Ending Address
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Extended Memory Ending Address 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Extended Memory Ending Address
@ -132,8 +126,7 @@ private:
0x10, 0x00, 0x00, 0xFF, // PICR1 0x10, 0x00, 0x00, 0xFF, // PICR1
0x0C, 0x06, 0x0C, 0x00, // PICR2 0x0C, 0x06, 0x0C, 0x00, // PICR2
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0x00, // ECC single-bit error counter 0x00, // ECC single-bit error counter
0x00, // ECC single-bit error trigger 0x00, // ECC single-bit error trigger
0x04, // Alternate OS visible paramaters 1 0x04, // Alternate OS visible paramaters 1
@ -153,10 +146,8 @@ private:
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0x42, 0x00, 0xFF, 0x0F, // Emulation support config 1 0x42, 0x00, 0xFF, 0x0F, // Emulation support config 1
0x00, 0x00, 0x00, 0x00, // Modified memory status (no clear) 0x00, 0x00, 0x00, 0x00, // Modified memory status (no clear)

View File

@ -19,12 +19,12 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <thirdparty/loguru/loguru.hpp>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cinttypes>
#include "nvram.h" #include "nvram.h"
#include <cinttypes>
#include <cstring>
#include <fstream>
#include <iostream>
#include <thirdparty/loguru/loguru.hpp>
/** @file Non-volatile RAM implementation. /** @file Non-volatile RAM implementation.
*/ */
@ -34,8 +34,7 @@ using namespace std;
/** the signature for NVRAM backing file identification. */ /** the signature for NVRAM backing file identification. */
static char NVRAM_FILE_ID[] = "DINGUSPPCNVRAM"; static char NVRAM_FILE_ID[] = "DINGUSPPCNVRAM";
NVram::NVram(std::string file_name, uint32_t ram_size) NVram::NVram(std::string file_name, uint32_t ram_size) {
{
this->file_name = file_name; this->file_name = file_name;
this->ram_size = ram_size; this->ram_size = ram_size;
@ -44,20 +43,17 @@ NVram::NVram(std::string file_name, uint32_t ram_size)
this->init(); this->init();
} }
NVram::~NVram() NVram::~NVram() {
{
this->save(); this->save();
if (this->storage) if (this->storage)
delete this->storage; delete this->storage;
} }
uint8_t NVram::read_byte(uint32_t offset) uint8_t NVram::read_byte(uint32_t offset) {
{
return (this->storage[offset]); return (this->storage[offset]);
} }
void NVram::write_byte(uint32_t offset, uint8_t val) void NVram::write_byte(uint32_t offset, uint8_t val) {
{
this->storage[offset] = val; this->storage[offset] = val;
} }
@ -67,12 +63,10 @@ void NVram::init() {
ifstream f(this->file_name, ios::in | ios::binary); ifstream f(this->file_name, ios::in | ios::binary);
if (f.fail() || !f.read(sig, sizeof(NVRAM_FILE_ID)) || \ if (f.fail() || !f.read(sig, sizeof(NVRAM_FILE_ID)) ||
!f.read((char *)&data_size, sizeof(data_size)) || \ !f.read((char*)&data_size, sizeof(data_size)) ||
memcmp(sig, NVRAM_FILE_ID, sizeof(NVRAM_FILE_ID)) || \ memcmp(sig, NVRAM_FILE_ID, sizeof(NVRAM_FILE_ID)) || data_size != this->ram_size ||
data_size != this->ram_size || \ !f.read((char*)this->storage, this->ram_size)) {
!f.read((char *)this->storage, this->ram_size))
{
LOG_F(WARNING, "Could not restore NVRAM content from the given file. \n"); LOG_F(WARNING, "Could not restore NVRAM content from the given file. \n");
memset(this->storage, 0, sizeof(this->ram_size)); memset(this->storage, 0, sizeof(this->ram_size));
} }
@ -80,8 +74,7 @@ void NVram::init() {
f.close(); f.close();
} }
void NVram::save() void NVram::save() {
{
ofstream f(this->file_name, ios::out | ios::binary); ofstream f(this->file_name, ios::out | ios::binary);
/* write file identification */ /* write file identification */

View File

@ -22,8 +22,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef NVRAM_H #ifndef NVRAM_H
#define NVRAM_H #define NVRAM_H
#include <string>
#include <cinttypes> #include <cinttypes>
#include <string>
/** @file Non-volatile RAM emulation. /** @file Non-volatile RAM emulation.
@ -31,8 +31,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
automatically saved to and restored from the dedicated file. automatically saved to and restored from the dedicated file.
*/ */
class NVram class NVram {
{
public: public:
NVram(std::string file_name = "nvram.bin", uint32_t ram_size = 8192); NVram(std::string file_name = "nvram.bin", uint32_t ram_size = 8192);
~NVram(); ~NVram();

View File

@ -22,10 +22,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef PCI_DEVICE_H #ifndef PCI_DEVICE_H
#define PCI_DEVICE_H #define PCI_DEVICE_H
#include <cinttypes>
#include <string>
#include "mmiodevice.h" #include "mmiodevice.h"
#include "pcihost.h" #include "pcihost.h"
#include <cinttypes>
#include <string>
/* convert little-endian DWORD to big-endian DWORD */ /* convert little-endian DWORD to big-endian DWORD */
#define LE2BE(x) (x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24) #define LE2BE(x) (x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24)
@ -45,23 +45,29 @@ enum {
class PCIDevice : public MMIODevice { class PCIDevice : public MMIODevice {
public: public:
PCIDevice(std::string name) { this->pci_name = name; }; PCIDevice(std::string name) {
this->pci_name = name;
};
virtual ~PCIDevice() = default; virtual ~PCIDevice() = default;
virtual bool supports_io_space(void) = 0; virtual bool supports_io_space(void) = 0;
/* I/O space access methods */ /* I/O space access methods */
virtual bool pci_io_read(uint32_t offset, uint32_t size, uint32_t* res) virtual bool pci_io_read(uint32_t offset, uint32_t size, uint32_t* res) {
{ return false; }; return false;
};
virtual bool pci_io_write(uint32_t offset, uint32_t value, uint32_t size) virtual bool pci_io_write(uint32_t offset, uint32_t value, uint32_t size) {
{ return false; }; return false;
};
/* configuration space access methods */ /* configuration space access methods */
virtual uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size) = 0; virtual uint32_t pci_cfg_read(uint32_t reg_offs, uint32_t size) = 0;
virtual void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) = 0; virtual void pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) = 0;
virtual void set_host(PCIHost* host_instance) { this->host_instance = host_instance; }; virtual void set_host(PCIHost* host_instance) {
this->host_instance = host_instance;
};
protected: protected:
std::string pci_name; // human-readable device name std::string pci_name; // human-readable device name

View File

@ -8,8 +8,7 @@ class PCIDevice; // forward declaration to prevent errors
class PCIHost { class PCIHost {
public: public:
virtual bool pci_register_device(int dev_num, PCIDevice* dev_instance) = 0; virtual bool pci_register_device(int dev_num, PCIDevice* dev_instance) = 0;
virtual bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, virtual bool pci_register_mmio_region(uint32_t start_addr, uint32_t size, PCIDevice* obj) = 0;
PCIDevice *obj) = 0;
}; };
#endif /* PCI_HOST_H */ #endif /* PCI_HOST_H */

View File

@ -47,16 +47,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef SPD_EEPROM_H #ifndef SPD_EEPROM_H
#define SPD_EEPROM_H #define SPD_EEPROM_H
#include <cinttypes>
#include <string>
#include <stdexcept>
#include <thirdparty/loguru/loguru.hpp>
#include "i2c.h"
#include "hwcomponent.h" #include "hwcomponent.h"
#include "i2c.h"
#include <cinttypes>
#include <stdexcept>
#include <string>
#include <thirdparty/loguru/loguru.hpp>
enum RAMType : int { enum RAMType : int { SDRAM = 4 };
SDRAM = 4
};
class SpdSdram168 : public HWComponent, public I2CDevice { class SpdSdram168 : public HWComponent, public I2CDevice {
@ -68,7 +66,9 @@ public:
~SpdSdram168() = default; ~SpdSdram168() = default;
bool supports_type(HWCompType type) { return type == HWCompType::RAM; }; bool supports_type(HWCompType type) {
return type == HWCompType::RAM;
};
void set_capacity(int capacity_megs) { void set_capacity(int capacity_megs) {
switch (capacity_megs) { switch (capacity_megs) {
@ -95,11 +95,12 @@ public:
default: default:
throw std::invalid_argument(std::string("Unsupported capacity!")); throw std::invalid_argument(std::string("Unsupported capacity!"));
} }
LOG_F(INFO, "SDRAM capacity set to %dMB, I2C addr = 0x%X", LOG_F(INFO, "SDRAM capacity set to %dMB, I2C addr = 0x%X", capacity_megs, this->dev_addr);
capacity_megs, this->dev_addr);
}; };
void start_transaction() { this->pos = 0; }; void start_transaction() {
this->pos = 0;
};
bool send_subaddress(uint8_t sub_addr) { bool send_subaddress(uint8_t sub_addr) {
this->pos = sub_addr; this->pos = sub_addr;

View File

@ -24,15 +24,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
Author: Max Poliakovski 2019 Author: Max Poliakovski 2019
*/ */
#include <thirdparty/loguru/loguru.hpp>
#include <cinttypes>
#include "viacuda.h" #include "viacuda.h"
#include "adb.h" #include "adb.h"
#include <cinttypes>
#include <thirdparty/loguru/loguru.hpp>
using namespace std; using namespace std;
ViaCuda::ViaCuda() ViaCuda::ViaCuda() {
{
this->name = "ViaCuda"; this->name = "ViaCuda";
/* FIXME: is this the correct /* FIXME: is this the correct
@ -52,14 +51,12 @@ ViaCuda::ViaCuda()
this->init(); this->init();
} }
ViaCuda::~ViaCuda() ViaCuda::~ViaCuda() {
{
if (this->pram_obj) if (this->pram_obj)
delete (this->pram_obj); delete (this->pram_obj);
} }
void ViaCuda::init() void ViaCuda::init() {
{
this->old_tip = 0; this->old_tip = 0;
this->old_byteack = 0; this->old_byteack = 0;
this->treq = 1; this->treq = 1;
@ -68,8 +65,7 @@ void ViaCuda::init()
this->poll_rate = 11; this->poll_rate = 11;
} }
uint8_t ViaCuda::read(int reg) uint8_t ViaCuda::read(int reg) {
{
uint8_t res; uint8_t res;
LOG_F(9, "Read VIA reg %x \n", (uint32_t)reg); LOG_F(9, "Read VIA reg %x \n", (uint32_t)reg);
@ -92,8 +88,7 @@ uint8_t ViaCuda::read(int reg)
return res; return res;
} }
void ViaCuda::write(int reg, uint8_t value) void ViaCuda::write(int reg, uint8_t value) {
{
switch (reg & 0xF) { switch (reg & 0xF) {
case VIA_B: case VIA_B:
this->via_regs[VIA_B] = value; this->via_regs[VIA_B] = value;
@ -120,8 +115,7 @@ void ViaCuda::write(int reg, uint8_t value)
this->via_regs[VIA_ACR] = value; this->via_regs[VIA_ACR] = value;
break; break;
case VIA_IER: case VIA_IER:
this->via_regs[VIA_IER] = (value & 0x80) ? value & 0x7F this->via_regs[VIA_IER] = (value & 0x80) ? value & 0x7F : this->via_regs[VIA_IER] & ~value;
: this->via_regs[VIA_IER] & ~value;
LOG_F(INFO, "VIA_IER updated to %d \n", (uint32_t)this->via_regs[VIA_IER]); LOG_F(INFO, "VIA_IER updated to %d \n", (uint32_t)this->via_regs[VIA_IER]);
print_enabled_ints(); print_enabled_ints();
break; break;
@ -130,8 +124,7 @@ void ViaCuda::write(int reg, uint8_t value)
} }
} }
void ViaCuda::print_enabled_ints() void ViaCuda::print_enabled_ints() {
{
const char* via_int_src[] = {"CA2", "CA1", "SR", "CB2", "CB1", "T2", "T1"}; const char* via_int_src[] = {"CA2", "CA1", "SR", "CB2", "CB1", "T2", "T1"};
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
@ -140,18 +133,15 @@ void ViaCuda::print_enabled_ints()
} }
} }
inline bool ViaCuda::ready() inline bool ViaCuda::ready() {
{
return ((this->via_regs[VIA_DIRB] & 0x38) == 0x30); return ((this->via_regs[VIA_DIRB] & 0x38) == 0x30);
} }
inline void ViaCuda::assert_sr_int() inline void ViaCuda::assert_sr_int() {
{
this->via_regs[VIA_IFR] |= 0x84; this->via_regs[VIA_IFR] |= 0x84;
} }
void ViaCuda::write(uint8_t new_state) void ViaCuda::write(uint8_t new_state) {
{
if (!ready()) { if (!ready()) {
LOG_F(WARNING, "Cuda not ready! \n"); LOG_F(WARNING, "Cuda not ready! \n");
return; return;
@ -183,8 +173,7 @@ void ViaCuda::write(uint8_t new_state)
} }
this->in_count = 0; this->in_count = 0;
} } else {
else {
LOG_F(9, "Cuda: enter sync state \n"); LOG_F(9, "Cuda: enter sync state \n");
this->via_regs[VIA_B] &= ~CUDA_TREQ; /* assert TREQ */ this->via_regs[VIA_B] &= ~CUDA_TREQ; /* assert TREQ */
this->treq = 0; this->treq = 0;
@ -193,18 +182,15 @@ void ViaCuda::write(uint8_t new_state)
} }
assert_sr_int(); /* send dummy byte as idle acknowledge or attention */ assert_sr_int(); /* send dummy byte as idle acknowledge or attention */
} } else {
else {
if (this->via_regs[VIA_ACR] & 0x10) { /* data transfer: Host --> Cuda */ if (this->via_regs[VIA_ACR] & 0x10) { /* data transfer: Host --> Cuda */
if (this->in_count < 16) { if (this->in_count < 16) {
this->in_buf[this->in_count++] = this->via_regs[VIA_SR]; this->in_buf[this->in_count++] = this->via_regs[VIA_SR];
assert_sr_int(); /* tell the system we've read the data */ assert_sr_int(); /* tell the system we've read the data */
} } else {
else {
LOG_F(WARNING, "Cuda input buffer exhausted! \n"); LOG_F(WARNING, "Cuda input buffer exhausted! \n");
} }
} } else { /* data transfer: Cuda --> Host */
else { /* data transfer: Cuda --> Host */
(this->*out_handler)(); (this->*out_handler)();
assert_sr_int(); /* tell the system we've written the data */ assert_sr_int(); /* tell the system we've written the data */
} }
@ -212,25 +198,21 @@ void ViaCuda::write(uint8_t new_state)
} }
/* sends zeros to host at infinitum */ /* sends zeros to host at infinitum */
void ViaCuda::null_out_handler() void ViaCuda::null_out_handler() {
{
this->via_regs[VIA_SR] = 0; this->via_regs[VIA_SR] = 0;
} }
/* sends data from out_buf until exhausted, then switches to next_out_handler */ /* sends data from out_buf until exhausted, then switches to next_out_handler */
void ViaCuda::out_buf_handler() void ViaCuda::out_buf_handler() {
{
if (this->out_pos < this->out_count) { if (this->out_pos < this->out_count) {
LOG_F(9, "OutBufHandler: sending next byte 0x%X", this->out_buf[this->out_pos]); LOG_F(9, "OutBufHandler: sending next byte 0x%X", this->out_buf[this->out_pos]);
this->via_regs[VIA_SR] = this->out_buf[this->out_pos++]; this->via_regs[VIA_SR] = this->out_buf[this->out_pos++];
} } else if (this->is_open_ended) {
else if (this->is_open_ended) {
LOG_F(9, "OutBufHandler: switching to next handler"); LOG_F(9, "OutBufHandler: switching to next handler");
this->out_handler = this->next_out_handler; this->out_handler = this->next_out_handler;
this->next_out_handler = &ViaCuda::null_out_handler; this->next_out_handler = &ViaCuda::null_out_handler;
(this->*out_handler)(); (this->*out_handler)();
} } else {
else {
LOG_F(9, "Sending last byte"); LOG_F(9, "Sending last byte");
this->out_count = 0; this->out_count = 0;
this->via_regs[VIA_B] |= CUDA_TREQ; /* negate TREQ */ this->via_regs[VIA_B] |= CUDA_TREQ; /* negate TREQ */
@ -238,8 +220,7 @@ void ViaCuda::out_buf_handler()
} }
} }
void ViaCuda::response_header(uint32_t pkt_type, uint32_t pkt_flag) void ViaCuda::response_header(uint32_t pkt_type, uint32_t pkt_flag) {
{
this->out_buf[0] = pkt_type; this->out_buf[0] = pkt_type;
this->out_buf[1] = pkt_flag; this->out_buf[1] = pkt_flag;
this->out_buf[2] = this->in_buf[1]; /* copy original cmd */ this->out_buf[2] = this->in_buf[1]; /* copy original cmd */
@ -250,8 +231,7 @@ void ViaCuda::response_header(uint32_t pkt_type, uint32_t pkt_flag)
this->is_open_ended = false; this->is_open_ended = false;
} }
void ViaCuda::error_response(uint32_t error) void ViaCuda::error_response(uint32_t error) {
{
this->out_buf[0] = CUDA_PKT_ERROR; this->out_buf[0] = CUDA_PKT_ERROR;
this->out_buf[1] = error; this->out_buf[1] = error;
this->out_buf[2] = this->in_buf[0]; this->out_buf[2] = this->in_buf[0];
@ -263,8 +243,7 @@ void ViaCuda::error_response(uint32_t error)
this->is_open_ended = false; this->is_open_ended = false;
} }
void ViaCuda::process_packet() void ViaCuda::process_packet() {
{
if (this->in_count < 2) { if (this->in_count < 2) {
LOG_F(ERROR, "Cuda: invalid packet (too few data)!\n"); LOG_F(ERROR, "Cuda: invalid packet (too few data)!\n");
error_response(CUDA_ERR_BAD_SIZE); error_response(CUDA_ERR_BAD_SIZE);
@ -291,20 +270,17 @@ void ViaCuda::process_packet()
} }
} }
void ViaCuda::process_adb_command(uint8_t cmd_byte, int data_count) void ViaCuda::process_adb_command(uint8_t cmd_byte, int data_count) {
{
int adb_dev = cmd_byte >> 4; // 2 for keyboard, 3 for mouse int adb_dev = cmd_byte >> 4; // 2 for keyboard, 3 for mouse
int cmd = cmd_byte & 0xF; int cmd = cmd_byte & 0xF;
if (!cmd) { if (!cmd) {
LOG_F(9, "Cuda: ADB SendReset command requested\n"); LOG_F(9, "Cuda: ADB SendReset command requested\n");
response_header(CUDA_PKT_ADB, 0); response_header(CUDA_PKT_ADB, 0);
} } else if (cmd == 1) {
else if (cmd == 1) {
LOG_F(9, "Cuda: ADB Flush command requested\n"); LOG_F(9, "Cuda: ADB Flush command requested\n");
response_header(CUDA_PKT_ADB, 0); response_header(CUDA_PKT_ADB, 0);
} } else if ((cmd & 0xC) == 8) {
else if ((cmd & 0xC) == 8) {
LOG_F(9, "Cuda: ADB Listen command requested\n"); LOG_F(9, "Cuda: ADB Listen command requested\n");
int adb_reg = cmd_byte & 0x3; int adb_reg = cmd_byte & 0x3;
if (adb_obj->listen(adb_dev, adb_reg)) { if (adb_obj->listen(adb_dev, adb_reg)) {
@ -312,36 +288,30 @@ void ViaCuda::process_adb_command(uint8_t cmd_byte, int data_count)
for (int data_ptr = 0; data_ptr < adb_obj->get_output_len(); data_ptr++) { for (int data_ptr = 0; data_ptr < adb_obj->get_output_len(); data_ptr++) {
this->in_buf[(2 + data_ptr)] = adb_obj->get_output_byte(data_ptr); this->in_buf[(2 + data_ptr)] = adb_obj->get_output_byte(data_ptr);
} }
} } else {
else {
response_header(CUDA_PKT_ADB, 2); response_header(CUDA_PKT_ADB, 2);
} }
} } else if ((cmd & 0xC) == 0xC) {
else if ((cmd & 0xC) == 0xC) {
LOG_F(9, "Cuda: ADB Talk command requested\n"); LOG_F(9, "Cuda: ADB Talk command requested\n");
response_header(CUDA_PKT_ADB, 0); response_header(CUDA_PKT_ADB, 0);
int adb_reg = cmd_byte & 0x3; int adb_reg = cmd_byte & 0x3;
if (adb_obj->talk(adb_dev, adb_reg, this->in_buf[2])) { if (adb_obj->talk(adb_dev, adb_reg, this->in_buf[2])) {
response_header(CUDA_PKT_ADB, 0); response_header(CUDA_PKT_ADB, 0);
} } else {
else {
response_header(CUDA_PKT_ADB, 2); response_header(CUDA_PKT_ADB, 2);
} }
} } else {
else {
LOG_F(ERROR, "Cuda: unsupported ADB command 0x%x \n", cmd); LOG_F(ERROR, "Cuda: unsupported ADB command 0x%x \n", cmd);
error_response(CUDA_ERR_BAD_CMD); error_response(CUDA_ERR_BAD_CMD);
} }
} }
void ViaCuda::pseudo_command(int cmd, int data_count) void ViaCuda::pseudo_command(int cmd, int data_count) {
{
switch (cmd) { switch (cmd) {
case CUDA_START_STOP_AUTOPOLL: case CUDA_START_STOP_AUTOPOLL:
if (this->in_buf[2]) { if (this->in_buf[2]) {
LOG_F(INFO, "Cuda: autopoll started, rate: %dms", this->poll_rate); LOG_F(INFO, "Cuda: autopoll started, rate: %dms", this->poll_rate);
} } else {
else {
LOG_F(INFO, "Cuda: autopoll stopped"); LOG_F(INFO, "Cuda: autopoll stopped");
} }
response_header(CUDA_PKT_PSEUDO, 0); response_header(CUDA_PKT_PSEUDO, 0);
@ -371,8 +341,8 @@ void ViaCuda::pseudo_command(int cmd, int data_count)
case CUDA_COMB_FMT_I2C: case CUDA_COMB_FMT_I2C:
response_header(CUDA_PKT_PSEUDO, 0); response_header(CUDA_PKT_PSEUDO, 0);
if (this->in_count >= 5) { if (this->in_count >= 5) {
i2c_comb_transaction(this->in_buf[2], this->in_buf[3], this->in_buf[4], i2c_comb_transaction(
&this->in_buf[5], this->in_count - 5); this->in_buf[2], this->in_buf[3], this->in_buf[4], &this->in_buf[5], this->in_count - 5);
} }
break; break;
case CUDA_OUT_PB0: /* undocumented call! */ case CUDA_OUT_PB0: /* undocumented call! */
@ -386,14 +356,11 @@ void ViaCuda::pseudo_command(int cmd, int data_count)
} }
/* sends data from the current I2C to host ad infinitum */ /* sends data from the current I2C to host ad infinitum */
void ViaCuda::i2c_handler() void ViaCuda::i2c_handler() {
{
this->receive_byte(this->curr_i2c_addr, &this->via_regs[VIA_SR]); this->receive_byte(this->curr_i2c_addr, &this->via_regs[VIA_SR]);
} }
void ViaCuda::i2c_simple_transaction(uint8_t dev_addr, const uint8_t* in_buf, void ViaCuda::i2c_simple_transaction(uint8_t dev_addr, const uint8_t* in_buf, int in_bytes) {
int in_bytes)
{
int op_type = dev_addr & 1; /* 0 - write to device, 1 - read from device */ int op_type = dev_addr & 1; /* 0 - write to device, 1 - read from device */
dev_addr >>= 1; /* strip RD/WR bit */ dev_addr >>= 1; /* strip RD/WR bit */
@ -422,9 +389,8 @@ void ViaCuda::i2c_simple_transaction(uint8_t dev_addr, const uint8_t* in_buf,
} }
} }
void ViaCuda::i2c_comb_transaction(uint8_t dev_addr, uint8_t sub_addr, void ViaCuda::i2c_comb_transaction(
uint8_t dev_addr1, const uint8_t* in_buf, int in_bytes) uint8_t dev_addr, uint8_t sub_addr, uint8_t dev_addr1, const uint8_t* in_buf, int in_bytes) {
{
int op_type = dev_addr1 & 1; /* 0 - write to device, 1 - read from device */ int op_type = dev_addr1 & 1; /* 0 - write to device, 1 - read from device */
if ((dev_addr & 0xFE) != (dev_addr1 & 0xFE)) { if ((dev_addr & 0xFE) != (dev_addr1 & 0xFE)) {

View File

@ -45,10 +45,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef VIACUDA_H #ifndef VIACUDA_H
#define VIACUDA_H #define VIACUDA_H
#include "hwcomponent.h"
#include "nvram.h"
#include "adb.h" #include "adb.h"
#include "hwcomponent.h"
#include "i2c.h" #include "i2c.h"
#include "nvram.h"
/** VIA register offsets. */ /** VIA register offsets. */
enum { enum {
@ -107,8 +107,7 @@ enum {
}; };
class ViaCuda : public HWComponent, public I2CBus class ViaCuda : public HWComponent, public I2CBus {
{
public: public:
ViaCuda(); ViaCuda();
~ViaCuda(); ~ViaCuda();
@ -162,8 +161,8 @@ private:
/* I2C related methods */ /* I2C related methods */
void i2c_simple_transaction(uint8_t dev_addr, const uint8_t* in_buf, int in_bytes); void i2c_simple_transaction(uint8_t dev_addr, const uint8_t* in_buf, int in_bytes);
void i2c_comb_transaction(uint8_t dev_addr, uint8_t sub_addr, uint8_t dev_addr1, void i2c_comb_transaction(
const uint8_t* in_buf, int in_bytes); uint8_t dev_addr, uint8_t sub_addr, uint8_t dev_addr1, const uint8_t* in_buf, int in_bytes);
}; };
#endif /* VIACUDA_H */ #endif /* VIACUDA_H */

View File

@ -1,14 +1,13 @@
#include "machinebase.h"
#include "devices/hwcomponent.h"
#include <memory> #include <memory>
#include <string> #include <string>
#include <thirdparty/loguru/loguru.hpp> #include <thirdparty/loguru/loguru.hpp>
#include "machinebase.h"
#include "devices/hwcomponent.h"
std::unique_ptr<MachineBase> gMachineObj = 0; std::unique_ptr<MachineBase> gMachineObj = 0;
MachineBase::MachineBase(std::string name) MachineBase::MachineBase(std::string name) {
{
this->name = name; this->name = name;
/* initialize internal maps */ /* initialize internal maps */
@ -17,8 +16,7 @@ MachineBase::MachineBase(std::string name)
this->aliases.clear(); this->aliases.clear();
} }
MachineBase::~MachineBase() MachineBase::~MachineBase() {
{
for (auto it = this->comp_map.begin(); it != this->comp_map.end(); it++) { for (auto it = this->comp_map.begin(); it != this->comp_map.end(); it++) {
delete it->second; delete it->second;
} }
@ -27,8 +25,7 @@ MachineBase::~MachineBase()
this->subdev_map.clear(); this->subdev_map.clear();
} }
bool MachineBase::add_component(std::string name, HWComponent *dev_obj) bool MachineBase::add_component(std::string name, HWComponent* dev_obj) {
{
if (this->comp_map.count(name)) { if (this->comp_map.count(name)) {
LOG_F(ERROR, "Component %s already exists!", name.c_str()); LOG_F(ERROR, "Component %s already exists!", name.c_str());
return false; return false;
@ -39,8 +36,7 @@ bool MachineBase::add_component(std::string name, HWComponent *dev_obj)
return true; return true;
} }
bool MachineBase::add_subdevice(std::string name, HWComponent *dev_obj) bool MachineBase::add_subdevice(std::string name, HWComponent* dev_obj) {
{
if (this->subdev_map.count(name)) { if (this->subdev_map.count(name)) {
LOG_F(ERROR, "Subdevice %s already exists!", name.c_str()); LOG_F(ERROR, "Subdevice %s already exists!", name.c_str());
return false; return false;
@ -51,13 +47,11 @@ bool MachineBase::add_subdevice(std::string name, HWComponent *dev_obj)
return true; return true;
} }
void MachineBase::add_alias(std::string name, std::string alias) void MachineBase::add_alias(std::string name, std::string alias) {
{
this->aliases[alias] = name; this->aliases[alias] = name;
} }
HWComponent *MachineBase::get_comp_by_name(std::string name) HWComponent* MachineBase::get_comp_by_name(std::string name) {
{
if (this->aliases.count(name)) { if (this->aliases.count(name)) {
name = this->aliases[name]; name = this->aliases[name];
} }
@ -73,8 +67,7 @@ HWComponent *MachineBase::get_comp_by_name(std::string name)
} }
} }
HWComponent *MachineBase::get_comp_by_type(HWCompType type) HWComponent* MachineBase::get_comp_by_type(HWCompType type) {
{
std::string comp_name; std::string comp_name;
bool found = false; bool found = false;

View File

@ -27,13 +27,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
#ifndef MACHINE_BASE_H #ifndef MACHINE_BASE_H
#define MACHINE_BASE_H #define MACHINE_BASE_H
#include "devices/hwcomponent.h"
#include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <map>
#include "devices/hwcomponent.h"
class MachineBase class MachineBase {
{
public: public:
MachineBase(std::string name); MachineBase(std::string name);
~MachineBase(); ~MachineBase();

View File

@ -24,15 +24,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
Author: Max Poliakovski Author: Max Poliakovski
*/ */
#include <map>
#include <cinttypes>
#include <cstring>
#include <iostream>
#include <fstream>
#include <thirdparty/loguru/loguru.hpp>
#include "memreadwrite.h"
#include "machinefactory.h" #include "machinefactory.h"
#include "devices/memctrlbase.h" #include "devices/memctrlbase.h"
#include "memreadwrite.h"
#include <cinttypes>
#include <cstring>
#include <fstream>
#include <iostream>
#include <map>
#include <thirdparty/loguru/loguru.hpp>
using namespace std; using namespace std;
@ -61,8 +61,7 @@ static const map<uint32_t, string> rom_identity = {
}; };
int create_machine_for_id(uint32_t id) int create_machine_for_id(uint32_t id) {
{
switch (id) { switch (id) {
case 0x476F7373: case 0x476F7373:
create_gossamer(); create_gossamer();
@ -76,23 +75,21 @@ int create_machine_for_id(uint32_t id)
/* Read ROM file content and transfer it to the dedicated ROM region */ /* Read ROM file content and transfer it to the dedicated ROM region */
void load_rom(ifstream& rom_file, uint32_t file_size) void load_rom(ifstream& rom_file, uint32_t file_size) {
{
unsigned char* sysrom_mem = new unsigned char[file_size]; unsigned char* sysrom_mem = new unsigned char[file_size];
rom_file.seekg(0, ios::beg); rom_file.seekg(0, ios::beg);
rom_file.read((char*)sysrom_mem, file_size); rom_file.read((char*)sysrom_mem, file_size);
MemCtrlBase *mem_ctrl = dynamic_cast<MemCtrlBase *> MemCtrlBase* mem_ctrl = dynamic_cast<MemCtrlBase*>(
(gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL)); gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
mem_ctrl->set_data(0xFFC00000, sysrom_mem, file_size); mem_ctrl->set_data(0xFFC00000, sysrom_mem, file_size);
delete[] sysrom_mem; delete[] sysrom_mem;
} }
int create_machine_for_rom(const char* rom_filepath) int create_machine_for_rom(const char* rom_filepath) {
{
ifstream rom_file; ifstream rom_file;
uint32_t file_size, config_info_offset, rom_id; uint32_t file_size, config_info_offset, rom_id;
char rom_id_str[17]; char rom_id_str[17];
@ -135,8 +132,7 @@ int create_machine_for_rom(const char* rom_filepath)
} }
/* convert BootstrapVersion string to ROM ID */ /* convert BootstrapVersion string to ROM ID */
rom_id = (rom_id_str[5] << 24) | (rom_id_str[6] << 16) | rom_id = (rom_id_str[5] << 24) | (rom_id_str[6] << 16) | (rom_id_str[7] << 8) | rom_id_str[8];
(rom_id_str[7] << 8) | rom_id_str[8];
LOG_F(INFO, "The machine is identified as... %s\n", rom_identity.at(rom_id).c_str()); LOG_F(INFO, "The machine is identified as... %s\n", rom_identity.at(rom_id).c_str());

View File

@ -24,18 +24,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
Author: Max Poliakovski Author: Max Poliakovski
*/ */
#include <thirdparty/loguru/loguru.hpp>
#include "machinebase.h"
#include "cpu/ppc/ppcemu.h" #include "cpu/ppc/ppcemu.h"
#include "devices/mpc106.h" #include "devices/atirage.h"
#include "devices/machineid.h" #include "devices/machineid.h"
#include "devices/macio.h" #include "devices/macio.h"
#include "devices/viacuda.h" #include "devices/mpc106.h"
#include "devices/spdram.h" #include "devices/spdram.h"
#include "devices/atirage.h" #include "devices/viacuda.h"
#include "machinebase.h"
#include <thirdparty/loguru/loguru.hpp>
static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs) static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs) {
{
if (!capacity_megs) if (!capacity_megs)
return; return;
@ -49,8 +48,7 @@ static void setup_ram_slot(std::string name, int i2c_addr, int capacity_megs)
} }
int create_gossamer() int create_gossamer() {
{
if (gMachineObj) { if (gMachineObj) {
LOG_F(ERROR, "Global machine object not empty!"); LOG_F(ERROR, "Global machine object not empty!");
return -1; return -1;
@ -70,13 +68,13 @@ int create_gossamer()
/* add the machine ID register */ /* add the machine ID register */
gMachineObj->add_component("MachineID", new GossamerID(0x3d8c)); gMachineObj->add_component("MachineID", new GossamerID(0x3d8c));
grackle_obj->add_mmio_region(0xFF000004, 4096, grackle_obj->add_mmio_region(
dynamic_cast<MMIODevice *>(gMachineObj->get_comp_by_name("MachineID"))); 0xFF000004, 4096, dynamic_cast<MMIODevice*>(gMachineObj->get_comp_by_name("MachineID")));
/* add the Heathrow I/O controller */ /* add the Heathrow I/O controller */
gMachineObj->add_component("Heathrow", new HeathrowIC); gMachineObj->add_component("Heathrow", new HeathrowIC);
grackle_obj->pci_register_device(16, grackle_obj->pci_register_device(
dynamic_cast<PCIDevice *>(gMachineObj->get_comp_by_name("Heathrow"))); 16, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("Heathrow")));
/* allocate ROM region */ /* allocate ROM region */
if (!grackle_obj->add_rom_region(0xFFC00000, 0x400000)) { if (!grackle_obj->add_rom_region(0xFFC00000, 0x400000)) {
@ -91,8 +89,8 @@ int create_gossamer()
/* register ATI 3D Rage Pro video card with the PCI host bridge */ /* register ATI 3D Rage Pro video card with the PCI host bridge */
gMachineObj->add_component("ATIRage", new ATIRage(ATI_RAGE_PRO_DEV_ID)); gMachineObj->add_component("ATIRage", new ATIRage(ATI_RAGE_PRO_DEV_ID));
grackle_obj->pci_register_device(18, grackle_obj->pci_register_device(
dynamic_cast<PCIDevice *>(gMachineObj->get_comp_by_name("ATIRage"))); 18, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("ATIRage")));
/* Init virtual CPU and request MPC750 CPU aka G3 */ /* Init virtual CPU and request MPC750 CPU aka G3 */
ppc_cpu_init(grackle_obj, PPC_VER::MPC750); ppc_cpu_init(grackle_obj, PPC_VER::MPC750);

View File

@ -22,23 +22,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
// The main runfile - main.cpp // The main runfile - main.cpp
// This is where the magic begins // This is where the magic begins
#include <thirdparty/loguru/loguru.hpp>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>
#include <cinttypes>
#include <stdio.h>
#include "ppcemu.h"
#include "debugger/debugger.h" #include "debugger/debugger.h"
#include "machines/machinefactory.h" #include "machines/machinefactory.h"
#include "ppcemu.h"
#include <cinttypes>
#include <cstring>
#include <fstream>
#include <iostream>
#include <sstream>
#include <stdio.h>
#include <thirdparty/SDL2/include/SDL.h> #include <thirdparty/SDL2/include/SDL.h>
#include <thirdparty/loguru/loguru.hpp>
using namespace std; using namespace std;
int main(int argc, char **argv) int main(int argc, char** argv) {
{
std::cout << "DingusPPC - Prototype 5bf4 (7/14/2019) " << endl; std::cout << "DingusPPC - Prototype 5bf4 (7/14/2019) " << endl;
std::cout << "Written by divingkatae, (c) 2019. " << endl; std::cout << "Written by divingkatae, (c) 2019. " << endl;
std::cout << "This is not intended for general use. " << endl; std::cout << "This is not intended for general use. " << endl;
@ -48,8 +46,8 @@ int main(int argc, char **argv)
string checker = argv[1]; string checker = argv[1];
cout << checker << endl; cout << checker << endl;
if ((checker == "1") || (checker == "realtime") || \ if ((checker == "1") || (checker == "realtime") || (checker == "-realtime") ||
(checker == "-realtime") || (checker == "/realtime")) { (checker == "/realtime")) {
loguru::g_stderr_verbosity = loguru::Verbosity_OFF; loguru::g_stderr_verbosity = loguru::Verbosity_OFF;
loguru::g_preamble_date = false; loguru::g_preamble_date = false;
loguru::g_preamble_time = false; loguru::g_preamble_time = false;
@ -58,9 +56,7 @@ int main(int argc, char **argv)
loguru::add_file("dingusppc.log", loguru::Append, 0); loguru::add_file("dingusppc.log", loguru::Append, 0);
// Replace the above line with this for maximum debugging detail: // Replace the above line with this for maximum debugging detail:
// loguru::add_file("dingusppc.log", loguru::Append, loguru::Verbosity_MAX); // loguru::add_file("dingusppc.log", loguru::Append, loguru::Verbosity_MAX);
} } else if ((checker == "debugger") || (checker == "/debugger") || (checker == "-debugger")) {
else if ((checker == "debugger") || (checker == "/debugger") ||
(checker == "-debugger")) {
loguru::g_stderr_verbosity = 0; loguru::g_stderr_verbosity = 0;
loguru::g_preamble_date = false; loguru::g_preamble_date = false;
loguru::g_preamble_time = false; loguru::g_preamble_time = false;
@ -87,26 +83,20 @@ int main(int argc, char **argv)
config_output.write("video_card=0x4750\n", 19); config_output.write("video_card=0x4750\n", 19);
config_output.close(); config_output.close();
} } else {
else {
while (std::getline(config_input, line)) { while (std::getline(config_input, line)) {
sin.str(line.substr(line.find("=") + 1)); sin.str(line.substr(line.find("=") + 1));
if (line.find("rompath") != std::string::npos) { if (line.find("rompath") != std::string::npos) {
sin >> rom_file; sin >> rom_file;
} } else if (line.find("diskpath") != std::string::npos) {
else if (line.find("diskpath") != std::string::npos) {
sin >> disk_file; sin >> disk_file;
} } else if (line.find("ramsize") != std::string::npos) {
else if (line.find("ramsize") != std::string::npos) {
sin >> ram_size; sin >> ram_size;
} } else if (line.find("machine_gestalt") != std::string::npos) {
else if (line.find("machine_gestalt") != std::string::npos) {
sin >> machine_gestalt; sin >> machine_gestalt;
} } else if (line.find("video_vendor") != std::string::npos) {
else if (line.find("video_vendor") != std::string::npos) {
sin >> video_card_vendor; sin >> video_card_vendor;
} } else if (line.find("video_card") != std::string::npos) {
else if (line.find("video_card") != std::string::npos) {
sin >> video_card_id; sin >> video_card_id;
} }
sin.clear(); sin.clear();
@ -122,15 +112,13 @@ int main(int argc, char **argv)
goto bail; goto bail;
} }
if ((checker == "1") || (checker == "realtime") || \ if ((checker == "1") || (checker == "realtime") || (checker == "-realtime") ||
(checker == "-realtime") || (checker == "/realtime")) { (checker == "/realtime")) {
ppc_exec(); ppc_exec();
} else if ((checker == "debugger") || (checker == "/debugger") || } else if ((checker == "debugger") || (checker == "/debugger") || (checker == "-debugger")) {
(checker == "-debugger")) {
enter_debugger(); enter_debugger();
} }
} } else {
else {
std::cout << " " << endl; std::cout << " " << endl;
std::cout << "Please enter one of the following commands when " << endl; std::cout << "Please enter one of the following commands when " << endl;
std::cout << "booting up DingusPPC... " << endl; std::cout << "booting up DingusPPC... " << endl;

View File

@ -5,8 +5,8 @@
#ifndef MEM_READ_WRITE_H #ifndef MEM_READ_WRITE_H
#define MEM_READ_WRITE_H #define MEM_READ_WRITE_H
#include <cinttypes>
#include "endianswap.h" #include "endianswap.h"
#include <cinttypes>
/* read an aligned big-endian WORD (16bit) */ /* read an aligned big-endian WORD (16bit) */
#define READ_WORD_BE_A(addr) (BYTESWAP_16(*((uint16_t*)((addr))))) #define READ_WORD_BE_A(addr) (BYTESWAP_16(*((uint16_t*)((addr)))))
@ -30,27 +30,23 @@
#define READ_WORD_BE_U(addr) (((addr)[0] << 8) | (addr)[1]) #define READ_WORD_BE_U(addr) (((addr)[0] << 8) | (addr)[1])
/* read an unaligned big-endian DWORD (32bit) */ /* read an unaligned big-endian DWORD (32bit) */
#define READ_DWORD_BE_U(addr) (((addr)[0] << 24) | ((addr)[1] << 16) | \ #define READ_DWORD_BE_U(addr) (((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
((addr)[2] << 8) | (addr)[3])
/* read an unaligned big-endian QWORD (32bit) */ /* read an unaligned big-endian QWORD (32bit) */
#define READ_QWORD_BE_U(addr) (((addr)[0] << 56) | ((addr)[1] << 48) | \ #define READ_QWORD_BE_U(addr) \
((addr)[2] << 40) | ((addr)[3] << 32) | \ (((addr)[0] << 56) | ((addr)[1] << 48) | ((addr)[2] << 40) | ((addr)[3] << 32) | \
((addr)[4] << 24) | ((addr)[5] << 16) | \ ((addr)[4] << 24) | ((addr)[5] << 16) | ((addr)[6] << 8) | (addr)[7])
((addr)[6] << 8) | (addr)[7])
/* read an unaligned little-endian WORD (16bit) */ /* read an unaligned little-endian WORD (16bit) */
#define READ_WORD_LE_U(addr) (((addr)[1] << 8) | (addr)[0]) #define READ_WORD_LE_U(addr) (((addr)[1] << 8) | (addr)[0])
/* read an unaligned little-endian DWORD (32bit) */ /* read an unaligned little-endian DWORD (32bit) */
#define READ_DWORD_LE_U(addr) (((addr)[3] << 24) | ((addr)[2] << 16) | \ #define READ_DWORD_LE_U(addr) (((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
((addr)[1] << 8) | (addr)[0])
/* read an unaligned little-endian DWORD (32bit) */ /* read an unaligned little-endian DWORD (32bit) */
#define READ_QWORD_LE_U(addr) (((addr)[7] << 56) | ((addr)[6] << 48) | \ #define READ_QWORD_LE_U(addr) \
((addr)[5] << 40) | ((addr)[4] << 32) | \ (((addr)[7] << 56) | ((addr)[6] << 48) | ((addr)[5] << 40) | ((addr)[4] << 32) | \
((addr)[3] << 24) | ((addr)[2] << 16) | \ ((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
((addr)[1] << 8) | (addr)[0])
/* write an aligned big-endian WORD (16bit) */ /* write an aligned big-endian WORD (16bit) */