clang-format everything
This commit is contained in:
parent
a5c63c1b09
commit
0ab9380be3
|
@ -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
|
|
@ -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
|
@ -32,11 +32,11 @@ typedef struct PPCDisasmContext {
|
||||||
bool simplified; /* true if we should output simplified mnemonics */
|
bool simplified; /* true if we should output simplified mnemonics */
|
||||||
} PPCDisasmContext;
|
} PPCDisasmContext;
|
||||||
|
|
||||||
std::string disassemble_single(PPCDisasmContext *ctx);
|
std::string disassemble_single(PPCDisasmContext* ctx);
|
||||||
|
|
||||||
int test_ppc_disasm(void);
|
int test_ppc_disasm(void);
|
||||||
|
|
||||||
/** sign-extend an integer. */
|
/** sign-extend an integer. */
|
||||||
#define SIGNEXT(x, sb) ((x) | (((x) & (1 << (sb))) ? ~((1 << (sb))-1) : 0))
|
#define SIGNEXT(x, sb) ((x) | (((x) & (1 << (sb))) ? ~((1 << (sb)) - 1) : 0))
|
||||||
|
|
||||||
#endif /* PPCDISASM_H */
|
#endif /* PPCDISASM_H */
|
||||||
|
|
|
@ -22,22 +22,22 @@ 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
|
||||||
|
|
||||||
//Uncomment this to have a more graceful approach to illegal opcodes
|
// Uncomment this to have a more graceful approach to illegal opcodes
|
||||||
//#define ILLEGAL_OP_SAFE 1
|
//#define ILLEGAL_OP_SAFE 1
|
||||||
|
|
||||||
//Uncomment this to use GCC built-in functions.
|
// Uncomment this to use GCC built-in functions.
|
||||||
//#define USE_GCC_BUILTINS 1
|
//#define USE_GCC_BUILTINS 1
|
||||||
|
|
||||||
//Uncomment this to use Visual Studio built-in functions.
|
// Uncomment this to use Visual Studio built-in functions.
|
||||||
//#define USE_VS_BUILTINS 1
|
//#define USE_VS_BUILTINS 1
|
||||||
|
|
||||||
enum endian_switch { big_end = 0, little_end = 1 };
|
enum endian_switch { big_end = 0, little_end = 1 };
|
||||||
|
@ -65,7 +65,7 @@ fpscr = FP Status and Condition Register
|
||||||
|
|
||||||
typedef struct struct_ppc_state {
|
typedef struct struct_ppc_state {
|
||||||
FPR_storage fpr[32];
|
FPR_storage fpr[32];
|
||||||
uint32_t pc; //Referred as the CIA in the PPC manual
|
uint32_t pc; // Referred as the CIA in the PPC manual
|
||||||
uint32_t gpr[32];
|
uint32_t gpr[32];
|
||||||
uint32_t cr;
|
uint32_t cr;
|
||||||
uint32_t fpscr;
|
uint32_t fpscr;
|
||||||
|
@ -73,7 +73,7 @@ typedef struct struct_ppc_state {
|
||||||
uint32_t spr[1024];
|
uint32_t spr[1024];
|
||||||
uint32_t msr;
|
uint32_t msr;
|
||||||
uint32_t sr[16];
|
uint32_t sr[16];
|
||||||
bool reserve; //reserve bit used for lwarx and stcwx
|
bool reserve; // reserve bit used for lwarx and stcwx
|
||||||
} SetPRS;
|
} SetPRS;
|
||||||
|
|
||||||
extern SetPRS ppc_state;
|
extern SetPRS ppc_state;
|
||||||
|
@ -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 {
|
||||||
|
@ -147,10 +144,10 @@ SUPERVISOR MODEL
|
||||||
536 - 543 are the Data BAT registers
|
536 - 543 are the Data BAT registers
|
||||||
**/
|
**/
|
||||||
|
|
||||||
extern uint32_t opcode_value; //used for interpreting opcodes
|
extern uint32_t opcode_value; // used for interpreting opcodes
|
||||||
extern uint64_t timebase_counter; //used for storing time base value
|
extern uint64_t timebase_counter; // used for storing time base value
|
||||||
|
|
||||||
//Additional steps to prevent overflow?
|
// Additional steps to prevent overflow?
|
||||||
extern int32_t add_result;
|
extern int32_t add_result;
|
||||||
extern int32_t simult_result;
|
extern int32_t simult_result;
|
||||||
extern uint32_t uiadd_result;
|
extern uint32_t uiadd_result;
|
||||||
|
@ -176,19 +173,19 @@ extern uint32_t rot_mb;
|
||||||
extern uint32_t rot_me;
|
extern uint32_t rot_me;
|
||||||
extern uint32_t uimm;
|
extern uint32_t uimm;
|
||||||
extern uint32_t grab_sr;
|
extern uint32_t grab_sr;
|
||||||
extern uint32_t grab_inb; //This is for grabbing the number of immediate bytes for loading and storing
|
extern uint32_t grab_inb; // This is for grabbing the number of immediate bytes for loading and storing
|
||||||
extern uint32_t ppc_to;
|
extern uint32_t ppc_to;
|
||||||
extern int32_t simm;
|
extern int32_t simm;
|
||||||
extern int32_t adr_li;
|
extern int32_t adr_li;
|
||||||
extern int32_t br_bd;
|
extern int32_t br_bd;
|
||||||
|
|
||||||
//Used for GP calcs
|
// Used for GP calcs
|
||||||
extern uint32_t ppc_result_a;
|
extern uint32_t ppc_result_a;
|
||||||
extern uint32_t ppc_result_b;
|
extern uint32_t ppc_result_b;
|
||||||
extern uint32_t ppc_result_c;
|
extern uint32_t ppc_result_c;
|
||||||
extern uint32_t ppc_result_d;
|
extern uint32_t ppc_result_d;
|
||||||
|
|
||||||
//Used for FP calcs
|
// Used for FP calcs
|
||||||
extern uint64_t ppc_result64_a;
|
extern uint64_t ppc_result64_a;
|
||||||
extern uint64_t ppc_result64_b;
|
extern uint64_t ppc_result64_b;
|
||||||
extern uint64_t ppc_result64_c;
|
extern uint64_t ppc_result64_c;
|
||||||
|
@ -218,7 +215,7 @@ enum class Except_Type {
|
||||||
EXC_TRACE = 13
|
EXC_TRACE = 13
|
||||||
};
|
};
|
||||||
|
|
||||||
//extern bool bb_end;
|
// extern bool bb_end;
|
||||||
extern BB_end_kind bb_kind;
|
extern BB_end_kind bb_kind;
|
||||||
|
|
||||||
extern jmp_buf exc_env;
|
extern jmp_buf exc_env;
|
||||||
|
@ -229,23 +226,23 @@ extern bool grab_return;
|
||||||
|
|
||||||
extern bool power_on;
|
extern bool power_on;
|
||||||
|
|
||||||
extern bool is_601; //For PowerPC 601 Emulation
|
extern bool is_601; // For PowerPC 601 Emulation
|
||||||
extern bool is_gekko; //For GameCube Emulation
|
extern bool is_gekko; // For GameCube Emulation
|
||||||
extern bool is_altivec; //For Altivec Emulation
|
extern bool is_altivec; // For Altivec Emulation
|
||||||
extern bool is_64bit; //For PowerPC G5 Emulation
|
extern bool is_64bit; // For PowerPC G5 Emulation
|
||||||
|
|
||||||
//Important Addressing Integers
|
// Important Addressing Integers
|
||||||
extern uint32_t ppc_cur_instruction;
|
extern uint32_t ppc_cur_instruction;
|
||||||
extern uint32_t ppc_effective_address;
|
extern uint32_t ppc_effective_address;
|
||||||
extern uint32_t ppc_next_instruction_address;
|
extern uint32_t ppc_next_instruction_address;
|
||||||
|
|
||||||
//Profiling Stats
|
// Profiling Stats
|
||||||
extern uint32_t mmu_translations_num;
|
extern uint32_t mmu_translations_num;
|
||||||
extern uint32_t exceptions_performed;
|
extern uint32_t exceptions_performed;
|
||||||
extern uint32_t supervisor_inst_num;
|
extern uint32_t supervisor_inst_num;
|
||||||
|
|
||||||
//Function prototypes
|
// Function prototypes
|
||||||
extern void ppc_cpu_init(MemCtrlBase *mem_ctrl, uint32_t proc_version);
|
extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t proc_version);
|
||||||
extern void ppc_mmu_init();
|
extern void ppc_mmu_init();
|
||||||
|
|
||||||
void ppc_illegalop();
|
void ppc_illegalop();
|
||||||
|
@ -293,15 +290,13 @@ 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;
|
||||||
|
|
||||||
//The functions used by the PowerPC processor
|
// The functions used by the PowerPC processor
|
||||||
extern void ppc_bcctr();
|
extern void ppc_bcctr();
|
||||||
extern void ppc_bcctrl();
|
extern void ppc_bcctrl();
|
||||||
extern void ppc_bclr();
|
extern void ppc_bclr();
|
||||||
|
@ -599,7 +594,7 @@ extern void ppc_fsqrtsdot();
|
||||||
extern void ppc_fcmpo();
|
extern void ppc_fcmpo();
|
||||||
extern void ppc_fcmpu();
|
extern void ppc_fcmpu();
|
||||||
|
|
||||||
//Power-specific instructions
|
// Power-specific instructions
|
||||||
extern void power_abs();
|
extern void power_abs();
|
||||||
extern void power_absdot();
|
extern void power_absdot();
|
||||||
extern void power_abso();
|
extern void power_abso();
|
||||||
|
@ -667,17 +662,17 @@ extern void power_srlqdot();
|
||||||
extern void power_srq();
|
extern void power_srq();
|
||||||
extern void power_srqdot();
|
extern void power_srqdot();
|
||||||
|
|
||||||
//Gekko instructions
|
// Gekko instructions
|
||||||
extern void ppc_psq_l();
|
extern void ppc_psq_l();
|
||||||
extern void ppc_psq_lu();
|
extern void ppc_psq_lu();
|
||||||
extern void ppc_psq_st();
|
extern void ppc_psq_st();
|
||||||
extern void ppc_psq_stu();
|
extern void ppc_psq_stu();
|
||||||
|
|
||||||
//AltiVec instructions
|
// AltiVec instructions
|
||||||
|
|
||||||
//64-bit instructions
|
// 64-bit instructions
|
||||||
|
|
||||||
//G5+ instructions
|
// G5+ instructions
|
||||||
|
|
||||||
extern void ppc_main_opcode(void);
|
extern void ppc_main_opcode(void);
|
||||||
extern void ppc_exec(void);
|
extern void ppc_exec(void);
|
||||||
|
@ -687,7 +682,7 @@ extern void ppc_exec_until(uint32_t goal_addr);
|
||||||
/* debugging support API */
|
/* debugging support API */
|
||||||
void print_gprs(void); /* print content of the general purpose registers */
|
void print_gprs(void); /* print content of the general purpose registers */
|
||||||
void print_fprs(void); /* print content of the floating-point registers */
|
void print_fprs(void); /* print content of the floating-point registers */
|
||||||
uint64_t get_reg(std::string ®_name); /* get content of the register reg_name */
|
uint64_t get_reg(std::string& reg_name); /* get content of the register reg_name */
|
||||||
void set_reg(std::string ®_name, uint64_t val); /* set reg_name to val */
|
void set_reg(std::string& reg_name, uint64_t val); /* set reg_name to val */
|
||||||
|
|
||||||
#endif /* PPCEMU_H */
|
#endif /* PPCEMU_H */
|
||||||
|
|
|
@ -21,23 +21,21 @@ 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++;
|
||||||
#endif
|
#endif
|
||||||
bb_kind = BB_end_kind::BB_EXCEPTION;
|
bb_kind = BB_end_kind::BB_EXCEPTION;
|
||||||
|
|
||||||
switch(exception_type) {
|
switch (exception_type) {
|
||||||
case Except_Type::EXC_SYSTEM_RESET:
|
case Except_Type::EXC_SYSTEM_RESET:
|
||||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||||
ppc_next_instruction_address = 0x0100;
|
ppc_next_instruction_address = 0x0100;
|
||||||
|
@ -97,16 +95,15 @@ jmp_buf exc_env; /* Global exception environment. */
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//printf("Unknown exception occured: %X\n", exception_type);
|
// printf("Unknown exception occured: %X\n", exception_type);
|
||||||
//exit(-1);
|
// exit(-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
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,12 +113,10 @@ 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) {
|
||||||
case Except_Type::EXC_SYSTEM_RESET:
|
case Except_Type::EXC_SYSTEM_RESET:
|
||||||
exc_descriptor = "System reset exception occured";
|
exc_descriptor = "System reset exception occured";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -19,23 +19,23 @@ 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"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
MemCtrlBase *mem_ctrl_instance = 0;
|
MemCtrlBase* mem_ctrl_instance = 0;
|
||||||
|
|
||||||
bool power_on = 1;
|
bool power_on = 1;
|
||||||
|
|
||||||
|
@ -46,385 +46,358 @@ bool grab_exception;
|
||||||
bool grab_return;
|
bool grab_return;
|
||||||
bool grab_breakpoint;
|
bool grab_breakpoint;
|
||||||
|
|
||||||
uint32_t ppc_cur_instruction; //Current instruction for the PPC
|
uint32_t ppc_cur_instruction; // Current instruction for the PPC
|
||||||
uint32_t ppc_effective_address;
|
uint32_t ppc_effective_address;
|
||||||
uint32_t ppc_next_instruction_address; //Used for branching, setting up the NIA
|
uint32_t ppc_next_instruction_address; // Used for branching, setting up the NIA
|
||||||
|
|
||||||
BB_end_kind bb_kind; /* basic block end */
|
BB_end_kind bb_kind; /* basic block end */
|
||||||
|
|
||||||
uint64_t timebase_counter; /* internal timebase counter */
|
uint64_t timebase_counter; /* internal timebase counter */
|
||||||
|
|
||||||
clock_t clock_test_begin; //Used to make sure the TBR does not increment so quickly.
|
clock_t clock_test_begin; // Used to make sure the TBR does not increment so quickly.
|
||||||
|
|
||||||
/** Opcode lookup tables. */
|
/** Opcode lookup tables. */
|
||||||
|
|
||||||
/** 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);
|
||||||
}
|
}
|
||||||
|
@ -527,31 +499,28 @@ void ppc_opcode63() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppc_main_opcode() {
|
void ppc_main_opcode() {
|
||||||
//Grab the main opcode
|
// Grab the main opcode
|
||||||
uint8_t ppc_mainop = (ppc_cur_instruction >> 26) & 63;
|
uint8_t ppc_mainop = (ppc_cur_instruction >> 26) & 63;
|
||||||
OpcodeGrabber[ppc_mainop]();
|
OpcodeGrabber[ppc_mainop]();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
clock_test_begin = clock();
|
clock_test_begin = clock();
|
||||||
//Placeholder Decrementing Code
|
// Placeholder Decrementing Code
|
||||||
if (ppc_state.spr[22] > 0) {
|
if (ppc_state.spr[22] > 0) {
|
||||||
ppc_state.spr[22]--;
|
ppc_state.spr[22]--;
|
||||||
}
|
}
|
||||||
|
@ -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 ®_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 ®_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 ®_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 ®_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 ®_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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,20 +21,20 @@ 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;
|
||||||
uint64_t ppc_result64_b;
|
uint64_t ppc_result64_b;
|
||||||
uint64_t ppc_result64_c;
|
uint64_t ppc_result64_c;
|
||||||
|
@ -48,7 +48,7 @@ double ppc_dblresult64_d;
|
||||||
double snan = std::numeric_limits<double>::signaling_NaN();
|
double snan = std::numeric_limits<double>::signaling_NaN();
|
||||||
double qnan = std::numeric_limits<double>::quiet_NaN();
|
double qnan = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
|
||||||
//Storage and register retrieval functions for the floating point functions.
|
// Storage and register retrieval functions for the floating point functions.
|
||||||
|
|
||||||
double fp_return_double(uint32_t reg) {
|
double fp_return_double(uint32_t reg) {
|
||||||
return ppc_state.fpr[reg].dbl64_r;
|
return ppc_state.fpr[reg].dbl64_r;
|
||||||
|
@ -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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +370,7 @@ void ppc_changecrf1() {
|
||||||
ppc_state.cr |= (ppc_state.fpscr & 0xF0000000) >> 4;
|
ppc_state.cr |= (ppc_state.fpscr & 0xF0000000) >> 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Floating Point Arithmetic
|
// Floating Point Arithmetic
|
||||||
void ppc_fadd() {
|
void ppc_fadd() {
|
||||||
ppc_grab_regsfpdab(false);
|
ppc_grab_regsfpdab(false);
|
||||||
|
|
||||||
|
@ -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() {
|
||||||
|
@ -1037,7 +1010,7 @@ void ppc_fctiwzdot() {
|
||||||
ppc_changecrf1();
|
ppc_changecrf1();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Floating Point Store and Load
|
// Floating Point Store and Load
|
||||||
|
|
||||||
void ppc_lfs() {
|
void ppc_lfs() {
|
||||||
ppc_grab_regsfpdia(true);
|
ppc_grab_regsfpdia(true);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1214,7 +1179,7 @@ void ppc_stfiwx() {
|
||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Floating Point Register Transfer
|
// Floating Point Register Transfer
|
||||||
|
|
||||||
void ppc_fmr() {
|
void ppc_fmr() {
|
||||||
ppc_grab_regsfpdb(true);
|
ppc_grab_regsfpdb(true);
|
||||||
|
@ -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,10 +1288,11 @@ 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
|
||||||
|
|
||||||
void ppc_fcmpo() {
|
void ppc_fcmpo() {
|
||||||
ppc_grab_regsfpsab(true);
|
ppc_grab_regsfpsab(true);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,26 +21,26 @@ 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.");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppc_psq_lu(){
|
void ppc_psq_lu() {
|
||||||
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppc_psq_st(){
|
void ppc_psq_st() {
|
||||||
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ppc_psq_stu(){
|
void ppc_psq_stu() {
|
||||||
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,36 +28,36 @@ 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);
|
||||||
|
|
||||||
/** PowerPC-style MMU BAT arrays (NULL initialization isn't prescribed). */
|
/** PowerPC-style MMU BAT arrays (NULL initialization isn't prescribed). */
|
||||||
PPC_BAT_entry ibat_array[4] = { {0} };
|
PPC_BAT_entry ibat_array[4] = {{0}};
|
||||||
PPC_BAT_entry dbat_array[4] = { {0} };
|
PPC_BAT_entry dbat_array[4] = {{0}};
|
||||||
|
|
||||||
/** remember recently used physical memory regions for quicker translation. */
|
/** remember recently used physical memory regions for quicker translation. */
|
||||||
AddressMapEntry last_read_area = { 0 };
|
AddressMapEntry last_read_area = {0};
|
||||||
AddressMapEntry last_write_area = { 0 };
|
AddressMapEntry last_write_area = {0};
|
||||||
AddressMapEntry last_exec_area = { 0 };
|
AddressMapEntry last_exec_area = {0};
|
||||||
AddressMapEntry last_ptab_area = { 0 };
|
AddressMapEntry last_ptab_area = {0};
|
||||||
AddressMapEntry last_dma_area = { 0 };
|
AddressMapEntry last_dma_area = {0};
|
||||||
|
|
||||||
|
|
||||||
/* macro for generating code reading from physical memory */
|
/* macro for generating code reading from physical memory */
|
||||||
#define READ_PHYS_MEM(ENTRY, ADDR, OP, SIZE, UNVAL) \
|
#define READ_PHYS_MEM(ENTRY, ADDR, OP, SIZE, UNVAL) \
|
||||||
{ \
|
{ \
|
||||||
if ((ADDR) >= (ENTRY).start && ((ADDR) + (SIZE)) <= (ENTRY).end) { \
|
if ((ADDR) >= (ENTRY).start && ((ADDR) + (SIZE)) <= (ENTRY).end) { \
|
||||||
ret = OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start)); \
|
ret = OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start)); \
|
||||||
} else { \
|
} else { \
|
||||||
|
@ -68,26 +68,22 @@ 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); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* macro for generating code writing to physical memory */
|
/* macro for generating code writing to physical memory */
|
||||||
#define WRITE_PHYS_MEM(ENTRY, ADDR, OP, VAL, SIZE) \
|
#define WRITE_PHYS_MEM(ENTRY, ADDR, OP, VAL, SIZE) \
|
||||||
{ \
|
{ \
|
||||||
if ((ADDR) >= (ENTRY).start && ((ADDR) + (SIZE)) <= (ENTRY).end) { \
|
if ((ADDR) >= (ENTRY).start && ((ADDR) + (SIZE)) <= (ENTRY).end) { \
|
||||||
OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start), (VAL)); \
|
OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start), (VAL)); \
|
||||||
} else { \
|
} else { \
|
||||||
|
@ -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);
|
||||||
|
@ -286,7 +262,7 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch,
|
||||||
|
|
||||||
pte_word2 = READ_DWORD_BE_A(pte_addr + 4);
|
pte_word2 = READ_DWORD_BE_A(pte_addr + 4);
|
||||||
|
|
||||||
key = (((sr_val >> 29) & 1)& msr_pr) | (((sr_val >> 30) & 1)& (msr_pr ^ 1));
|
key = (((sr_val >> 29) & 1) & msr_pr) | (((sr_val >> 30) & 1) & (msr_pr ^ 1));
|
||||||
|
|
||||||
/* check page access */
|
/* check page access */
|
||||||
pp = pte_word2 & 3;
|
pp = pte_word2 & 3;
|
||||||
|
@ -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,13 +370,12 @@ 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) {
|
||||||
LOG_F(ERROR, "SOS! Cross-page unaligned write, addr=%08X, size=%d\n", addr, size);
|
LOG_F(ERROR, "SOS! Cross-page unaligned write, addr=%08X, size=%d\n", addr, size);
|
||||||
exit(-1); //FIXME!
|
exit(-1); // FIXME!
|
||||||
} else {
|
} else {
|
||||||
/* data address translation if enabled */
|
/* data address translation if enabled */
|
||||||
if (ppc_state.msr & 0x10) {
|
if (ppc_state.msr & 0x10) {
|
||||||
|
@ -420,20 +390,18 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define WRITE_BYTE(addr, val) (*(addr) = val)
|
#define WRITE_BYTE(addr, val) (*(addr) = val)
|
||||||
|
|
||||||
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,11 +427,10 @@ 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!
|
||||||
}
|
}
|
||||||
|
|
||||||
/* data address translation if enabled */
|
/* data address translation if enabled */
|
||||||
|
@ -475,15 +441,14 @@ 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);
|
||||||
|
|
||||||
if (((addr & 0xFFF) + size) > 0x1000) {
|
if (((addr & 0xFFF) + size) > 0x1000) {
|
||||||
LOG_F(ERROR, "SOS! Cross-page unaligned read, addr=%08X, size=%d\n", addr, size);
|
LOG_F(ERROR, "SOS! Cross-page unaligned read, addr=%08X, size=%d\n", addr, size);
|
||||||
exit(-1); //FIXME!
|
exit(-1); // FIXME!
|
||||||
} else {
|
} else {
|
||||||
/* data address translation if enabled */
|
/* data address translation if enabled */
|
||||||
if (ppc_state.msr & 0x10) {
|
if (ppc_state.msr & 0x10) {
|
||||||
|
@ -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,13 +510,12 @@ 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) {
|
||||||
LOG_F(ERROR, "SOS! Attempt to read unaligned QWORD at 0x%08X\n", addr);
|
LOG_F(ERROR, "SOS! Attempt to read unaligned QWORD at 0x%08X\n", addr);
|
||||||
exit(-1); //FIXME!
|
exit(-1); // FIXME!
|
||||||
}
|
}
|
||||||
|
|
||||||
/* data address translation if enabled */
|
/* data address translation if enabled */
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -608,7 +565,7 @@ uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size)
|
||||||
mmu_exception_handler = dbg_exception_handler;
|
mmu_exception_handler = dbg_exception_handler;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch(size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
ret_val = mem_grab_byte(virt_addr);
|
ret_val = mem_grab_byte(virt_addr);
|
||||||
break;
|
break;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
@ -44,7 +44,7 @@ typedef struct PPC_BAT_entry {
|
||||||
extern void ibat_update(uint32_t bat_reg);
|
extern void ibat_update(uint32_t bat_reg);
|
||||||
extern void dbat_update(uint32_t bat_reg);
|
extern void dbat_update(uint32_t bat_reg);
|
||||||
|
|
||||||
extern uint8_t *mmu_get_dma_mem(uint32_t addr, uint32_t size);
|
extern uint8_t* mmu_get_dma_mem(uint32_t addr, uint32_t size);
|
||||||
|
|
||||||
extern void ppc_set_cur_instruction(const uint8_t* ptr);
|
extern void ppc_set_cur_instruction(const uint8_t* ptr);
|
||||||
extern void mem_write_byte(uint32_t addr, uint8_t value);
|
extern void mem_write_byte(uint32_t addr, uint8_t value);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||||
|
@ -74,7 +70,7 @@ static void read_test_data()
|
||||||
|
|
||||||
lineno = 0;
|
lineno = 0;
|
||||||
|
|
||||||
while(getline(tfstream, line)) {
|
while (getline(tfstream, line)) {
|
||||||
lineno++;
|
lineno++;
|
||||||
|
|
||||||
if (line.empty() || !line.rfind("#", 0))
|
if (line.empty() || !line.rfind("#", 0))
|
||||||
|
@ -84,7 +80,7 @@ static void read_test_data()
|
||||||
|
|
||||||
vector<string> tokens;
|
vector<string> tokens;
|
||||||
|
|
||||||
while(getline(lnstream, token, ',' )) {
|
while (getline(lnstream, token, ',')) {
|
||||||
tokens.push_back(token);
|
tokens.push_back(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -24,7 +23,7 @@ static vector<PPCDisasmContext> read_test_data()
|
||||||
|
|
||||||
lineno = 0;
|
lineno = 0;
|
||||||
|
|
||||||
while(getline(tfstream, line)) {
|
while (getline(tfstream, line)) {
|
||||||
lineno++;
|
lineno++;
|
||||||
|
|
||||||
if (line.empty() || !line.rfind("#", 0))
|
if (line.empty() || !line.rfind("#", 0))
|
||||||
|
@ -34,8 +33,8 @@ static vector<PPCDisasmContext> read_test_data()
|
||||||
|
|
||||||
vector<string> tokens;
|
vector<string> tokens;
|
||||||
|
|
||||||
while(getline(lnstream, token, ',' )) {
|
while (getline(lnstream, token, ',')) {
|
||||||
//cout << "Token: " << token << endl;
|
// cout << "Token: " << token << endl;
|
||||||
tokens.push_back(token);
|
tokens.push_back(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +63,7 @@ static vector<PPCDisasmContext> read_test_data()
|
||||||
|
|
||||||
ctx.instr_str = idisasm.str();
|
ctx.instr_str = idisasm.str();
|
||||||
|
|
||||||
//cout << idisasm.str() << endl;
|
// cout << idisasm.str() << endl;
|
||||||
|
|
||||||
tstvec.push_back(ctx);
|
tstvec.push_back(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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -114,7 +107,7 @@ static void dump_mem(string& params)
|
||||||
|
|
||||||
is_char = false;
|
is_char = false;
|
||||||
|
|
||||||
switch(num_type_str.back()) {
|
switch (num_type_str.back()) {
|
||||||
case 'b':
|
case 'b':
|
||||||
case 'B':
|
case 'B':
|
||||||
cell_size = 1;
|
cell_size = 1;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
@ -40,7 +40,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
ADB_Bus::ADB_Bus() {
|
ADB_Bus::ADB_Bus() {
|
||||||
//set data streams as clear
|
// set data streams as clear
|
||||||
this->adb_mouse_register0 = 0x8080;
|
this->adb_mouse_register0 = 0x8080;
|
||||||
|
|
||||||
input_stream_len = 0;
|
input_stream_len = 0;
|
||||||
|
@ -53,50 +53,43 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ADB_Bus::talk(int device, int reg, uint16_t value) {
|
bool ADB_Bus::talk(int device, int reg, uint16_t value) {
|
||||||
//temp code
|
// temp code
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ADB_Bus::bus_reset() {
|
bool ADB_Bus::bus_reset() {
|
||||||
//temp code
|
// temp code
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ADB_Bus::set_addr(int dev_addr, int new_addr) {
|
bool ADB_Bus::set_addr(int dev_addr, int new_addr) {
|
||||||
//temp code
|
// temp code
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ADB_Bus::flush(int dev_addr) {
|
bool ADB_Bus::flush(int dev_addr) {
|
||||||
//temp code
|
// temp code
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +101,7 @@ bool ADB_Bus::adb_keybd_listen(int reg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (SDL_PollEvent(&adb_keybd_evt)) {
|
while (SDL_PollEvent(&adb_keybd_evt)) {
|
||||||
//Poll our SDL key event for any keystrokes.
|
// Poll our SDL key event for any keystrokes.
|
||||||
switch (adb_keybd_evt.type) {
|
switch (adb_keybd_evt.type) {
|
||||||
case SDL_KEYDOWN:
|
case SDL_KEYDOWN:
|
||||||
switch (adb_keybd_evt.key.keysym.sym) {
|
switch (adb_keybd_evt.key.keysym.sym) {
|
||||||
|
@ -323,34 +316,34 @@ bool ADB_Bus::adb_keybd_listen(int reg) {
|
||||||
ask_key_pressed = 0x5C;
|
ask_key_pressed = 0x5C;
|
||||||
break;
|
break;
|
||||||
case SDLK_BACKSPACE:
|
case SDLK_BACKSPACE:
|
||||||
//ask_key_pressed = 0x33;
|
// ask_key_pressed = 0x33;
|
||||||
confirm_ask_reg_2 = true;
|
confirm_ask_reg_2 = true;
|
||||||
mod_key_pressed = 0x40;
|
mod_key_pressed = 0x40;
|
||||||
break;
|
break;
|
||||||
case SDLK_CAPSLOCK:
|
case SDLK_CAPSLOCK:
|
||||||
//ask_key_pressed = 0x39;
|
// ask_key_pressed = 0x39;
|
||||||
confirm_ask_reg_2 = true;
|
confirm_ask_reg_2 = true;
|
||||||
mod_key_pressed = 0x20;
|
mod_key_pressed = 0x20;
|
||||||
break;
|
break;
|
||||||
case SDLK_RALT:
|
case SDLK_RALT:
|
||||||
case SDLK_RCTRL: //Temp key for Control key
|
case SDLK_RCTRL: // Temp key for Control key
|
||||||
//ask_key_pressed = 0x36;
|
// ask_key_pressed = 0x36;
|
||||||
confirm_ask_reg_2 = true;
|
confirm_ask_reg_2 = true;
|
||||||
mod_key_pressed = 0x8;
|
mod_key_pressed = 0x8;
|
||||||
break;
|
break;
|
||||||
case SDLK_LSHIFT:
|
case SDLK_LSHIFT:
|
||||||
case SDLK_RSHIFT:
|
case SDLK_RSHIFT:
|
||||||
//ask_key_pressed = 0x38;
|
// ask_key_pressed = 0x38;
|
||||||
confirm_ask_reg_2 = true;
|
confirm_ask_reg_2 = true;
|
||||||
mod_key_pressed = 0x4;
|
mod_key_pressed = 0x4;
|
||||||
break;
|
break;
|
||||||
case SDLK_LALT:
|
case SDLK_LALT:
|
||||||
//ask_key_pressed = 0x3A;
|
// ask_key_pressed = 0x3A;
|
||||||
confirm_ask_reg_2 = true;
|
confirm_ask_reg_2 = true;
|
||||||
mod_key_pressed = 0x2;
|
mod_key_pressed = 0x2;
|
||||||
break;
|
break;
|
||||||
case SDLK_LCTRL: //Temp key for the Command/Apple key
|
case SDLK_LCTRL: // Temp key for the Command/Apple key
|
||||||
//ask_key_pressed = 0x37;
|
// ask_key_pressed = 0x37;
|
||||||
confirm_ask_reg_2 = true;
|
confirm_ask_reg_2 = true;
|
||||||
mod_key_pressed = 0x1;
|
mod_key_pressed = 0x1;
|
||||||
break;
|
break;
|
||||||
|
@ -363,15 +356,14 @@ 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);
|
||||||
output_data_stream[1] = (adb_keybd_register0 & 0xff);
|
output_data_stream[1] = (adb_keybd_register0 & 0xff);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if mod keys are being pressed
|
// check if mod keys are being pressed
|
||||||
|
|
||||||
if (confirm_ask_reg_2) {
|
if (confirm_ask_reg_2) {
|
||||||
adb_keybd_register0 |= (mod_key_pressed << 8);
|
adb_keybd_register0 |= (mod_key_pressed << 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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -58,7 +69,7 @@ private:
|
||||||
int keyboard_access_no;
|
int keyboard_access_no;
|
||||||
int mouse_access_no;
|
int mouse_access_no;
|
||||||
|
|
||||||
//Keyboard Variables
|
// Keyboard Variables
|
||||||
|
|
||||||
uint16_t adb_keybd_register0;
|
uint16_t adb_keybd_register0;
|
||||||
uint16_t adb_keybd_register2;
|
uint16_t adb_keybd_register2;
|
||||||
|
@ -71,15 +82,15 @@ private:
|
||||||
|
|
||||||
bool confirm_ask_reg_2;
|
bool confirm_ask_reg_2;
|
||||||
|
|
||||||
//Mouse Variables
|
// Mouse Variables
|
||||||
SDL_Event adb_mouse_evt;
|
SDL_Event adb_mouse_evt;
|
||||||
|
|
||||||
uint16_t adb_mouse_register0;
|
uint16_t adb_mouse_register0;
|
||||||
uint16_t adb_mouse_register3;
|
uint16_t adb_mouse_register3;
|
||||||
|
|
||||||
uint8_t input_data_stream[16]; //temp buffer
|
uint8_t input_data_stream[16]; // temp buffer
|
||||||
int input_stream_len;
|
int input_stream_len;
|
||||||
uint8_t output_data_stream[16]; //temp buffer
|
uint8_t output_data_stream[16]; // temp buffer
|
||||||
int output_stream_len;
|
int output_stream_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,17 +111,21 @@ 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);
|
||||||
|
|
||||||
/* I/O space access methods */
|
/* I/O space access methods */
|
||||||
bool pci_io_read(uint32_t offset, uint32_t size, uint32_t *res);
|
bool pci_io_read(uint32_t offset, uint32_t size, uint32_t* res);
|
||||||
bool pci_io_write(uint32_t offset, uint32_t value, uint32_t size) ;
|
bool pci_io_write(uint32_t offset, uint32_t value, uint32_t size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t size_dep_read(uint8_t* buf, uint32_t size);
|
uint32_t size_dep_read(uint8_t* buf, uint32_t size);
|
||||||
|
@ -133,14 +136,14 @@ protected:
|
||||||
void write_reg(uint32_t offset, uint32_t value, uint32_t size);
|
void write_reg(uint32_t offset, uint32_t value, uint32_t size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//uint32_t atirage_membuf_regs[9]; /* ATI Rage Memory Buffer Registers */
|
// uint32_t atirage_membuf_regs[9]; /* ATI Rage Memory Buffer Registers */
|
||||||
//uint32_t atirage_scratch_regs[4]; /* ATI Rage Scratch Registers */
|
// uint32_t atirage_scratch_regs[4]; /* ATI Rage Scratch Registers */
|
||||||
//uint32_t atirage_cmdfifo_regs[3]; /* ATI Rage Command FIFO Registers */
|
// uint32_t atirage_cmdfifo_regs[3]; /* ATI Rage Command FIFO Registers */
|
||||||
//uint32_t atirage_datapath_regs[12]; /* ATI Rage Data Path Registers*/
|
// uint32_t atirage_datapath_regs[12]; /* ATI Rage Data Path Registers*/
|
||||||
|
|
||||||
uint8_t block_io_regs[256] = { 0 };
|
uint8_t block_io_regs[256] = {0};
|
||||||
|
|
||||||
uint8_t pci_cfg[256] = { 0 }; /* PCI configuration space */
|
uint8_t pci_cfg[256] = {0}; /* PCI configuration space */
|
||||||
|
|
||||||
DisplayID* disp_id;
|
DisplayID* disp_id;
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,26 +24,24 @@ 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 */
|
||||||
I2CBus *i2c_bus = dynamic_cast<I2CBus *>(gMachineObj->get_comp_by_type(HWCompType::I2C_HOST));
|
I2CBus* i2c_bus = dynamic_cast<I2CBus*>(gMachineObj->get_comp_by_type(HWCompType::I2C_HOST));
|
||||||
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,12 +71,11 @@ 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;
|
||||||
|
|
||||||
switch(offset) {
|
switch (offset) {
|
||||||
case AWAC_SOUND_CTRL_REG:
|
case AWAC_SOUND_CTRL_REG:
|
||||||
this->snd_ctrl_reg = BYTESWAP_32(value);
|
this->snd_ctrl_reg = BYTESWAP_32(value);
|
||||||
LOG_F(INFO, "New sound control value = 0x%X", this->snd_ctrl_reg);
|
LOG_F(INFO, "New sound control value = 0x%X", this->snd_ctrl_reg);
|
||||||
|
@ -99,48 +93,45 @@ 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) {
|
||||||
LOG_F(WARNING, "AWAC sound buffer len not a multiply of 8, %d", len);
|
LOG_F(WARNING, "AWAC sound buffer len not a multiply of 8, %d", len);
|
||||||
}
|
}
|
||||||
|
|
||||||
p_in = (uint16_t *)in;
|
p_in = (uint16_t*)in;
|
||||||
p_out = (uint16_t *)out;
|
p_out = (uint16_t*)out;
|
||||||
len >>= 1;
|
len >>= 1;
|
||||||
|
|
||||||
/* AWAC data comes as LLRR -> convert it to LRLR */
|
/* AWAC data comes as LLRR -> convert it to LRLR */
|
||||||
for (int i = 0; i < len; i += 8) {
|
for (int i = 0; i < len; i += 8) {
|
||||||
p_out[i] = p_in[i];
|
p_out[i] = p_in[i];
|
||||||
p_out[i+1] = p_in[i+2];
|
p_out[i + 1] = p_in[i + 2];
|
||||||
p_out[i+2] = p_in[i+1];
|
p_out[i + 2] = p_in[i + 1];
|
||||||
p_out[i+3] = p_in[i+3];
|
p_out[i + 3] = p_in[i + 3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
DMAChannel *dma_ch = (DMAChannel *)user_data; /* C API baby! */
|
DMAChannel* dma_ch = (DMAChannel*)user_data; /* C API baby! */
|
||||||
|
|
||||||
for (rem_len = buf_len; rem_len > 0; rem_len -= got_len, buf += got_len) {
|
for (rem_len = buf_len; rem_len > 0; rem_len -= got_len, buf += got_len) {
|
||||||
if (!dma_ch->get_data(rem_len, &got_len, &p_in)) {
|
if (!dma_ch->get_data(rem_len, &got_len, &p_in)) {
|
||||||
convert_data(p_in, buf, got_len);
|
convert_data(p_in, buf, got_len);
|
||||||
//LOG_F(9, "Converted sound data, len = %d", got_len);
|
// LOG_F(9, "Converted sound data, len = %d", got_len);
|
||||||
} else { /* no more data */
|
} else { /* no more data */
|
||||||
memset(buf, 0, rem_len); /* fill the buffer with silence */
|
memset(buf, 0, rem_len); /* fill the buffer with silence */
|
||||||
//LOG_F(9, "Inserted silence, len = %d", rem_len);
|
// LOG_F(9, "Inserted silence, len = %d", rem_len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -151,21 +142,20 @@ uint32_t AWACDevice::convert_data(const uint8_t *data, int len)
|
||||||
this->buf_len = len;
|
this->buf_len = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
p_in = (uint16_t *)data;
|
p_in = (uint16_t*)data;
|
||||||
p_out = (uint16_t *)this->snd_buf;
|
p_out = (uint16_t*)this->snd_buf;
|
||||||
|
|
||||||
for (i = 0; i < len; i += 8) {
|
for (i = 0; i < len; i += 8) {
|
||||||
p_out[i] = p_in[i];
|
p_out[i] = p_in[i];
|
||||||
p_out[i+1] = p_in[i+2];
|
p_out[i + 1] = p_in[i + 2];
|
||||||
p_out[i+2] = p_in[i+1];
|
p_out[i + 2] = p_in[i + 1];
|
||||||
p_out[i+3] = p_in[i+3];
|
p_out[i + 3] = p_in[i + 3];
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
@ -174,7 +164,7 @@ void AWACDevice::dma_start()
|
||||||
snd_spec.channels = 2;
|
snd_spec.channels = 2;
|
||||||
snd_spec.samples = 4096; /* buffer size, chosen empirically */
|
snd_spec.samples = 4096; /* buffer size, chosen empirically */
|
||||||
snd_spec.callback = audio_out_callback;
|
snd_spec.callback = audio_out_callback;
|
||||||
snd_spec.userdata = (void *)this->dma_out_ch;
|
snd_spec.userdata = (void*)this->dma_out_ch;
|
||||||
|
|
||||||
|
|
||||||
this->snd_out_dev = SDL_OpenAudioDevice(NULL, 0, &snd_spec, &snd_settings, 0);
|
this->snd_out_dev = SDL_OpenAudioDevice(NULL, 0, &snd_spec, &snd_settings, 0);
|
||||||
|
@ -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) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -86,7 +87,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool receive_byte(uint8_t *p_data) {
|
bool receive_byte(uint8_t* p_data) {
|
||||||
*p_data = this->regs[this->sub_addr];
|
*p_data = this->regs[this->sub_addr];
|
||||||
LOG_F(INFO, "TDA7433 byte 0x%X sent", *p_data);
|
LOG_F(INFO, "TDA7433 byte 0x%X sent", *p_data);
|
||||||
return true;
|
return true;
|
||||||
|
@ -105,7 +106,7 @@ public:
|
||||||
AWACDevice();
|
AWACDevice();
|
||||||
~AWACDevice();
|
~AWACDevice();
|
||||||
|
|
||||||
void set_dma_out(DMAChannel *dma_out_ch);
|
void set_dma_out(DMAChannel* dma_out_ch);
|
||||||
|
|
||||||
uint32_t snd_ctrl_read(uint32_t offset, int size);
|
uint32_t snd_ctrl_read(uint32_t offset, int size);
|
||||||
void snd_ctrl_write(uint32_t offset, uint32_t value, int size);
|
void snd_ctrl_write(uint32_t offset, uint32_t value, int size);
|
||||||
|
@ -113,22 +114,22 @@ public:
|
||||||
/* DMACallback methods */
|
/* DMACallback methods */
|
||||||
void dma_start();
|
void dma_start();
|
||||||
void dma_end();
|
void dma_end();
|
||||||
void dma_push(uint8_t *buf, int size);
|
void dma_push(uint8_t* buf, int size);
|
||||||
void dma_pull(uint8_t *buf, int size);
|
void dma_pull(uint8_t* buf, int size);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
uint32_t convert_data(const uint8_t *data, int len);
|
uint32_t convert_data(const uint8_t* data, int len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t snd_ctrl_reg = {0};
|
uint32_t snd_ctrl_reg = {0};
|
||||||
uint16_t control_regs[8] = {0}; /* control registers, each 12-bits wide */
|
uint16_t control_regs[8] = {0}; /* control registers, each 12-bits wide */
|
||||||
uint8_t is_busy = 0;
|
uint8_t is_busy = 0;
|
||||||
AudioProcessor *audio_proc;
|
AudioProcessor* audio_proc;
|
||||||
|
|
||||||
SDL_AudioDeviceID snd_out_dev = 0;
|
SDL_AudioDeviceID snd_out_dev = 0;
|
||||||
bool wake_up = false;
|
bool wake_up = false;
|
||||||
|
|
||||||
DMAChannel *dma_out_ch;
|
DMAChannel* dma_out_ch;
|
||||||
|
|
||||||
uint8_t* snd_buf = 0;
|
uint8_t* snd_buf = 0;
|
||||||
uint32_t buf_len = 0;
|
uint32_t buf_len = 0;
|
||||||
|
|
|
@ -21,27 +21,25 @@ 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);
|
||||||
|
|
||||||
this->ch_stat &= ~CH_STAT_WAKE; /* clear wake bit (DMA spec, 5.5.3.4) */
|
this->ch_stat &= ~CH_STAT_WAKE; /* clear wake bit (DMA spec, 5.5.3.4) */
|
||||||
|
|
||||||
switch(cmd_struct.cmd_key >> 4) {
|
switch (cmd_struct.cmd_key >> 4) {
|
||||||
case 0:
|
case 0:
|
||||||
LOG_F(9, "Executing DMA Command OUTPUT_MORE");
|
LOG_F(9, "Executing DMA Command OUTPUT_MORE");
|
||||||
if (cmd_struct.cmd_key & 7) {
|
if (cmd_struct.cmd_key & 7) {
|
||||||
|
@ -52,7 +50,7 @@ uint8_t DMAChannel::interpret_cmd()
|
||||||
LOG_F(ERROR, "non-zero i/b/w not implemented");
|
LOG_F(ERROR, "non-zero i/b/w not implemented");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//this->dma_cb->dma_push(
|
// this->dma_cb->dma_push(
|
||||||
// mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count),
|
// mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count),
|
||||||
// cmd_struct.req_count);
|
// cmd_struct.req_count);
|
||||||
this->queue_data = mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count);
|
this->queue_data = mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count);
|
||||||
|
@ -69,7 +67,7 @@ uint8_t DMAChannel::interpret_cmd()
|
||||||
LOG_F(ERROR, "non-zero i/b/w not implemented");
|
LOG_F(ERROR, "non-zero i/b/w not implemented");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//this->dma_cb->dma_push(
|
// this->dma_cb->dma_push(
|
||||||
// mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count),
|
// mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count),
|
||||||
// cmd_struct.req_count);
|
// cmd_struct.req_count);
|
||||||
this->queue_data = mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count);
|
this->queue_data = mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count);
|
||||||
|
@ -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) {
|
||||||
|
@ -114,7 +111,7 @@ uint32_t DMAChannel::reg_read(uint32_t offset, int size)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(offset) {
|
switch (offset) {
|
||||||
case DMAReg::CH_CTRL:
|
case DMAReg::CH_CTRL:
|
||||||
res = 0; /* ChannelControl reads as 0 (DBDMA spec 5.5.1, table 74) */
|
res = 0; /* ChannelControl reads as 0 (DBDMA spec 5.5.1, table 74) */
|
||||||
break;
|
break;
|
||||||
|
@ -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) {
|
||||||
|
@ -140,7 +136,7 @@ void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size)
|
||||||
value = BYTESWAP_32(value);
|
value = BYTESWAP_32(value);
|
||||||
old_stat = this->ch_stat;
|
old_stat = this->ch_stat;
|
||||||
|
|
||||||
switch(offset) {
|
switch (offset) {
|
||||||
case DMAReg::CH_CTRL:
|
case DMAReg::CH_CTRL:
|
||||||
mask = value >> 16;
|
mask = value >> 16;
|
||||||
new_stat = (value & mask & 0xF0FFU) | (old_stat & ~mask);
|
new_stat = (value & mask & 0xF0FFU) | (old_stat & ~mask);
|
||||||
|
@ -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;
|
||||||
|
@ -233,12 +227,11 @@ void DMAChannel::start()
|
||||||
|
|
||||||
this->dma_cb->dma_start();
|
this->dma_cb->dma_start();
|
||||||
|
|
||||||
//while (this->interpret_cmd() != 7) {
|
// while (this->interpret_cmd() != 7) {
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,22 +63,24 @@ class DMACallback {
|
||||||
public:
|
public:
|
||||||
virtual void dma_start(void) = 0;
|
virtual void dma_start(void) = 0;
|
||||||
virtual void dma_end(void) = 0;
|
virtual void dma_end(void) = 0;
|
||||||
virtual void dma_push(uint8_t *buf, int size) = 0;
|
virtual void dma_push(uint8_t* buf, int size) = 0;
|
||||||
virtual void dma_pull(uint8_t *buf, int size) = 0;
|
virtual void dma_pull(uint8_t* buf, int size) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
void reg_write(uint32_t offset, uint32_t value, int size);
|
void reg_write(uint32_t offset, uint32_t value, int size);
|
||||||
|
|
||||||
int get_data(uint32_t req_len, uint32_t *avail_len, uint8_t **p_data);
|
int get_data(uint32_t req_len, uint32_t* avail_len, uint8_t** p_data);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void get_next_cmd(uint32_t cmd_addr, DMACmd *p_cmd);
|
void get_next_cmd(uint32_t cmd_addr, DMACmd* p_cmd);
|
||||||
uint8_t interpret_cmd(void);
|
uint8_t interpret_cmd(void);
|
||||||
|
|
||||||
void start(void);
|
void start(void);
|
||||||
|
@ -87,7 +89,7 @@ protected:
|
||||||
void pause(void);
|
void pause(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DMACallback *dma_cb = 0;
|
DMACallback* dma_cb = 0;
|
||||||
uint16_t ch_stat = 0;
|
uint16_t ch_stat = 0;
|
||||||
uint32_t cmd_ptr = 0;
|
uint32_t cmd_ptr = 0;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -109,7 +99,7 @@ uint16_t DisplayID::read_monitor_sense(uint16_t data, uint16_t dirs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, uint16_t dirs)
|
uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl) //(uint16_t data, uint16_t dirs)
|
||||||
{
|
{
|
||||||
bool clk_gone_high = false;
|
bool clk_gone_high = false;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,26 +74,18 @@ private:
|
||||||
uint8_t byte; /* byte value being currently transferred */
|
uint8_t byte; /* byte value being currently transferred */
|
||||||
uint8_t dev_addr; /* current device address */
|
uint8_t dev_addr; /* current device address */
|
||||||
uint8_t reg_addr; /* current register address */
|
uint8_t reg_addr; /* current register address */
|
||||||
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
|
||||||
|
|
|
@ -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,37 +46,34 @@ 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);
|
||||||
|
|
||||||
if (this->viacuda)
|
if (this->viacuda)
|
||||||
delete(this->viacuda);
|
delete (this->viacuda);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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,11 +82,10 @@ 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) {
|
||||||
case 8:
|
case 8:
|
||||||
res = this->snd_out_dma->reg_read(offset & 0xFF, size);
|
res = this->snd_out_dma->reg_read(offset & 0xFF, size);
|
||||||
break;
|
break;
|
||||||
|
@ -101,9 +96,8 @@ 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);
|
||||||
break;
|
break;
|
||||||
|
@ -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");
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
@ -37,16 +37,20 @@ public:
|
||||||
virtual void start_transaction() = 0;
|
virtual void start_transaction() = 0;
|
||||||
virtual bool send_subaddress(uint8_t sub_addr) = 0;
|
virtual bool send_subaddress(uint8_t sub_addr) = 0;
|
||||||
virtual bool send_byte(uint8_t data) = 0;
|
virtual bool send_byte(uint8_t data) = 0;
|
||||||
virtual bool receive_byte(uint8_t *p_data) = 0;
|
virtual bool receive_byte(uint8_t* p_data) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** 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]) {
|
||||||
throw std::invalid_argument(std::string("I2C address already taken!"));
|
throw std::invalid_argument(std::string("I2C address already taken!"));
|
||||||
}
|
}
|
||||||
|
@ -77,7 +81,7 @@ public:
|
||||||
return this->dev_list[dev_addr]->send_byte(data);
|
return this->dev_list[dev_addr]->send_byte(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual bool receive_byte(uint8_t dev_addr, uint8_t *p_data) {
|
virtual bool receive_byte(uint8_t dev_addr, uint8_t* p_data) {
|
||||||
if (!this->dev_list[dev_addr]) {
|
if (!this->dev_list[dev_addr]) {
|
||||||
return false; /* no device -> no acknowledge */
|
return false; /* no device -> no acknowledge */
|
||||||
}
|
}
|
||||||
|
@ -85,7 +89,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
I2CDevice *dev_list[128]; /* list of registered I2C devices */
|
I2CDevice* dev_list[128]; /* list of registered I2C devices */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* I2C_H */
|
#endif /* I2C_H */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -135,11 +144,11 @@ private:
|
||||||
uint32_t feat_ctrl; // features control register
|
uint32_t feat_ctrl; // features control register
|
||||||
|
|
||||||
/* device cells */
|
/* device cells */
|
||||||
ViaCuda *viacuda; /* VIA cell with Cuda MCU attached to it */
|
ViaCuda* viacuda; /* VIA cell with Cuda MCU attached to it */
|
||||||
NVram *nvram; /* NVRAM cell */
|
NVram* nvram; /* NVRAM cell */
|
||||||
AWACDevice *screamer; /* Screamer audio codec instance */
|
AWACDevice* screamer; /* Screamer audio codec instance */
|
||||||
|
|
||||||
DMAChannel *snd_out_dma;
|
DMAChannel* snd_out_dma;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MACIO_H */
|
#endif /* MACIO_H */
|
||||||
|
|
|
@ -19,28 +19,26 @@ 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 ® : mem_regions) {
|
|
||||||
if (reg)
|
if (reg)
|
||||||
delete(reg);
|
delete (reg);
|
||||||
}
|
}
|
||||||
this->mem_regions.clear();
|
this->mem_regions.clear();
|
||||||
this->address_map.clear();
|
this->address_map.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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,16 +47,15 @@ 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 */
|
||||||
if (find_range(start_addr) || find_range(start_addr + size))
|
if (find_range(start_addr) || find_range(start_addr + size))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint8_t *reg_content = new uint8_t[size];
|
uint8_t* reg_content = new uint8_t[size];
|
||||||
|
|
||||||
this->mem_regions.push_back(reg_content);
|
this->mem_regions.push_back(reg_content);
|
||||||
|
|
||||||
|
@ -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,9 +102,8 @@ 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;
|
||||||
|
|
||||||
ref_entry = find_range(reg_addr);
|
ref_entry = find_range(reg_addr);
|
||||||
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
@ -55,18 +55,18 @@ public:
|
||||||
virtual bool add_ram_region(uint32_t start_addr, uint32_t size);
|
virtual bool add_ram_region(uint32_t start_addr, uint32_t size);
|
||||||
virtual bool add_mem_mirror(uint32_t start_addr, uint32_t dest_addr);
|
virtual bool add_mem_mirror(uint32_t start_addr, uint32_t dest_addr);
|
||||||
|
|
||||||
virtual bool add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice *dev_instance);
|
virtual bool add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice* dev_instance);
|
||||||
|
|
||||||
virtual bool set_data(uint32_t reg_addr, const uint8_t *data, uint32_t size);
|
virtual bool set_data(uint32_t reg_addr, const uint8_t* data, uint32_t size);
|
||||||
|
|
||||||
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;
|
||||||
std::vector<AddressMapEntry> address_map;
|
std::vector<AddressMapEntry> address_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,19 +164,21 @@ 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
|
||||||
|
|
||||||
switch(size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
return this->my_pci_cfg_hdr[reg_offs];
|
return this->my_pci_cfg_hdr[reg_offs];
|
||||||
break;
|
break;
|
||||||
|
@ -193,26 +195,25 @@ 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
|
||||||
|
|
||||||
// FIXME: implement write-protection for read-only registers
|
// FIXME: implement write-protection for read-only registers
|
||||||
switch(size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
this->my_pci_cfg_hdr[reg_offs] = value & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs] = value & 0xFF;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
this->my_pci_cfg_hdr[reg_offs] = (value >> 8) & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs] = (value >> 8) & 0xFF;
|
||||||
this->my_pci_cfg_hdr[reg_offs+1] = value & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs + 1] = value & 0xFF;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
this->my_pci_cfg_hdr[reg_offs] = (value >> 24) & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs] = (value >> 24) & 0xFF;
|
||||||
this->my_pci_cfg_hdr[reg_offs+1] = (value >> 16) & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs + 1] = (value >> 16) & 0xFF;
|
||||||
this->my_pci_cfg_hdr[reg_offs+2] = (value >> 8) & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs + 2] = (value >> 8) & 0xFF;
|
||||||
this->my_pci_cfg_hdr[reg_offs+3] = value & 0xFF;
|
this->my_pci_cfg_hdr[reg_offs + 3] = value & 0xFF;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_F(ERROR, "MPC106 read error: invalid size parameter %d \n", size);
|
LOG_F(ERROR, "MPC106 read error: invalid size parameter %d \n", size);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
127
devices/mpc106.h
127
devices/mpc106.h
|
@ -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();
|
||||||
|
@ -56,7 +55,7 @@ public:
|
||||||
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);
|
||||||
|
|
||||||
/* PCI host bridge API */
|
/* PCI host bridge API */
|
||||||
bool pci_register_device(int dev_num, PCIDevice *dev_instance);
|
bool pci_register_device(int dev_num, PCIDevice* dev_instance);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* PCI access */
|
/* PCI access */
|
||||||
|
@ -67,9 +66,11 @@ 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);
|
||||||
|
|
||||||
void setup_ram(void);
|
void setup_ram(void);
|
||||||
|
|
||||||
|
@ -87,90 +88,80 @@ 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,
|
0x00, // Interrupt line
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
0x00, // Interrupt pin
|
||||||
0xFF, 0xFF, 0xFF, 0xFF,
|
0x00, // MIN GNT
|
||||||
0x00, //Interrupt line
|
0x00, // MAX LAT
|
||||||
0x00, //Interrupt pin
|
0x00, // Bus number
|
||||||
0x00, //MIN GNT
|
0x00, // Subordinate bus number
|
||||||
0x00, //MAX LAT
|
0x00, // Discount counter
|
||||||
0x00, //Bus number
|
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // Performance monitor command
|
||||||
0x00, //Subordinate bus number
|
0x00, 0x00, // Performance monitor mode control
|
||||||
0x00, //Discount counter
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
||||||
0x00, 0x00, 0x00, 0x00, //Performance monitor command
|
|
||||||
0x00, 0x00, //Performance monitor mode control
|
|
||||||
0xFF, 0xFF,
|
0xFF, 0xFF,
|
||||||
|
|
||||||
0x00, 0x00, 0x00, 0x00, //Performance monitor counter 0
|
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 0
|
||||||
0x00, 0x00, 0x00, 0x00, //Performance monitor counter 1
|
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 1
|
||||||
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
|
|
||||||
|
|
||||||
0x00, //Memory bank enable
|
0x00, // Memory bank enable
|
||||||
0xFF, 0xFF,
|
0xFF, 0xFF,
|
||||||
0x00, //Memory page mode
|
0x00, // Memory page mode
|
||||||
0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
|
||||||
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
|
0x01, // Alternate OS visible paramaters 2
|
||||||
0x01, //Alternate OS visible paramaters 2
|
|
||||||
|
|
||||||
0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
|
|
||||||
0x01, //Error enabling 1
|
0x01, // Error enabling 1
|
||||||
0x00, //Error detection 1
|
0x00, // Error detection 1
|
||||||
0xFF,
|
0xFF,
|
||||||
0x00, //60x bus error status
|
0x00, // 60x bus error status
|
||||||
0x00, //Error enabling 2
|
0x00, // Error enabling 2
|
||||||
0x00, //Error detection 2
|
0x00, // Error detection 2
|
||||||
0xFF,
|
0xFF,
|
||||||
0x00, //PCI bus error status
|
0x00, // PCI bus error status
|
||||||
0x00, 0x00, 0x00, 0x00, //60x/PCI ERROR address
|
0x00, 0x00, 0x00, 0x00, // 60x/PCI ERROR address
|
||||||
|
|
||||||
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)
|
||||||
0x20, 0x00, 0x00, 0x00, //Emulation support config 2
|
0x20, 0x00, 0x00, 0x00, // Emulation support config 2
|
||||||
0x00, 0x00, 0x00, 0x00, //Modified memory status (clear)
|
0x00, 0x00, 0x00, 0x00, // Modified memory status (clear)
|
||||||
|
|
||||||
0x00, 0x00, 0x02, 0xFF, //Memory ctrl config 1
|
0x00, 0x00, 0x02, 0xFF, // Memory ctrl config 1
|
||||||
0x03, 0x00, 0x00, 0x00, //Memory ctrl config 2
|
0x03, 0x00, 0x00, 0x00, // Memory ctrl config 2
|
||||||
0x00, 0x00, 0x00, 0x00, //Memory ctrl config 3
|
0x00, 0x00, 0x00, 0x00, // Memory ctrl config 3
|
||||||
0x00, 0x00, 0x10, 0x00 //Memory ctrl config 4
|
0x00, 0x00, 0x10, 0x00 // Memory ctrl config 4
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t config_addr;
|
uint32_t config_addr;
|
||||||
//uint32_t config_data;
|
// uint32_t config_data;
|
||||||
|
|
||||||
std::unordered_map<int, PCIDevice*> pci_0_bus;
|
std::unordered_map<int, PCIDevice*> pci_0_bus;
|
||||||
std::vector<PCIDevice*> io_space_devs;
|
std::vector<PCIDevice*> io_space_devs;
|
||||||
|
|
|
@ -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,16 +74,15 @@ 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 */
|
||||||
f.write(NVRAM_FILE_ID, sizeof(NVRAM_FILE_ID));
|
f.write(NVRAM_FILE_ID, sizeof(NVRAM_FILE_ID));
|
||||||
f.write((char *)&this->ram_size, sizeof(this->ram_size));
|
f.write((char*)&this->ram_size, sizeof(this->ram_size));
|
||||||
|
|
||||||
/* write NVRAM content */
|
/* write NVRAM content */
|
||||||
f.write((char *)this->storage, this->ram_size);
|
f.write((char*)this->storage, this->ram_size);
|
||||||
|
|
||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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,27 +45,33 @@ 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
|
||||||
PCIHost *host_instance; // host bridge instance to call back
|
PCIHost* host_instance; // host bridge instance to call back
|
||||||
uint32_t base_addr; // base address register 0
|
uint32_t base_addr; // base address register 0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,8 @@ 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 */
|
||||||
|
|
|
@ -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,10 +66,12 @@ 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) {
|
||||||
case 32:
|
case 32:
|
||||||
this->eeprom_data[3] = 0xC; /* 12 rows */
|
this->eeprom_data[3] = 0xC; /* 12 rows */
|
||||||
this->eeprom_data[4] = 0x8; /* 8 columns */
|
this->eeprom_data[4] = 0x8; /* 8 columns */
|
||||||
|
@ -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;
|
||||||
|
@ -112,7 +113,7 @@ public:
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool receive_byte(uint8_t *p_data) {
|
bool receive_byte(uint8_t* p_data) {
|
||||||
if (this->pos >= this->eeprom_data[0]) {
|
if (this->pos >= this->eeprom_data[0]) {
|
||||||
this->pos = 0; /* attempt to read past SPD data should wrap around */
|
this->pos = 0; /* attempt to read past SPD data should wrap around */
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
@ -44,7 +43,7 @@ ViaCuda::ViaCuda()
|
||||||
this->via_regs[VIA_T1LH] = 0xFF;
|
this->via_regs[VIA_T1LH] = 0xFF;
|
||||||
this->via_regs[VIA_IER] = 0x7F;
|
this->via_regs[VIA_IER] = 0x7F;
|
||||||
|
|
||||||
//PRAM Pre-Initialization
|
// PRAM Pre-Initialization
|
||||||
this->pram_obj = new NVram("pram.bin", 256);
|
this->pram_obj = new NVram("pram.bin", 256);
|
||||||
|
|
||||||
this->adb_obj = new ADB_Bus();
|
this->adb_obj = new ADB_Bus();
|
||||||
|
@ -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,9 +124,8 @@ 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++) {
|
||||||
if (this->via_regs[VIA_IER] & (1 << i))
|
if (this->via_regs[VIA_IER] & (1 << 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,57 +270,48 @@ 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)) {
|
||||||
response_header(CUDA_PKT_ADB, 0);
|
response_header(CUDA_PKT_ADB, 0);
|
||||||
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)) {
|
||||||
|
|
|
@ -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();
|
||||||
|
@ -150,7 +149,7 @@ private:
|
||||||
void assert_sr_int();
|
void assert_sr_int();
|
||||||
void write(uint8_t new_state);
|
void write(uint8_t new_state);
|
||||||
void response_header(uint32_t pkt_type, uint32_t pkt_flag);
|
void response_header(uint32_t pkt_type, uint32_t pkt_flag);
|
||||||
//void cuda_response_packet();
|
// void cuda_response_packet();
|
||||||
void error_response(uint32_t error);
|
void error_response(uint32_t error);
|
||||||
void process_packet();
|
void process_packet();
|
||||||
void process_adb_command(uint8_t cmd_byte, int data_count);
|
void process_adb_command(uint8_t cmd_byte, int data_count);
|
||||||
|
@ -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 */
|
||||||
|
|
|
@ -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,9 +16,8 @@ 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;
|
||||||
}
|
}
|
||||||
this->comp_map.clear();
|
this->comp_map.clear();
|
||||||
|
@ -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,12 +67,11 @@ 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;
|
||||||
|
|
||||||
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++) {
|
||||||
if (it->second->supports_type(type)) {
|
if (it->second->supports_type(type)) {
|
||||||
comp_name = it->first;
|
comp_name = it->first;
|
||||||
found = true;
|
found = true;
|
||||||
|
@ -90,7 +83,7 @@ HWComponent *MachineBase::get_comp_by_type(HWCompType type)
|
||||||
return this->get_comp_by_name(comp_name);
|
return this->get_comp_by_name(comp_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto it = this->subdev_map.begin(); it != this->subdev_map.end(); it++) {
|
for (auto it = this->subdev_map.begin(); it != this->subdev_map.end(); it++) {
|
||||||
if (it->second->supports_type(type)) {
|
if (it->second->supports_type(type)) {
|
||||||
comp_name = it->first;
|
comp_name = it->first;
|
||||||
found = true;
|
found = true;
|
||||||
|
|
|
@ -27,27 +27,26 @@ 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();
|
||||||
|
|
||||||
bool add_component(std::string name, HWComponent *dev_obj);
|
bool add_component(std::string name, HWComponent* dev_obj);
|
||||||
bool add_subdevice(std::string name, HWComponent *dev_obj);
|
bool add_subdevice(std::string name, HWComponent* dev_obj);
|
||||||
void add_alias(std::string name, std::string alias);
|
void add_alias(std::string name, std::string alias);
|
||||||
HWComponent *get_comp_by_name(std::string name);
|
HWComponent* get_comp_by_name(std::string name);
|
||||||
HWComponent *get_comp_by_type(HWCompType type);
|
HWComponent* get_comp_by_type(HWCompType type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
std::map<std::string, HWComponent *>comp_map;
|
std::map<std::string, HWComponent*> comp_map;
|
||||||
std::map<std::string, HWComponent *>subdev_map;
|
std::map<std::string, HWComponent*> subdev_map;
|
||||||
std::map<std::string, std::string> aliases;
|
std::map<std::string, std::string> aliases;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -43,27 +43,26 @@ using namespace std;
|
||||||
or 0x30C064 (Nubus Macs).
|
or 0x30C064 (Nubus Macs).
|
||||||
*/
|
*/
|
||||||
static const map<uint32_t, string> rom_identity = {
|
static const map<uint32_t, string> rom_identity = {
|
||||||
{0x416C6368, "Performa 6400"}, //Alchemy
|
{0x416C6368, "Performa 6400"}, // Alchemy
|
||||||
//{"Come", "PowerBook 2400"}, //Comet
|
//{"Come", "PowerBook 2400"}, //Comet
|
||||||
{0x436F7264, "Power Mac 5200/6200 series"}, //Cordyceps
|
{0x436F7264, "Power Mac 5200/6200 series"}, // Cordyceps
|
||||||
{0x47617A65, "Power Mac 6500"}, //Gazelle
|
{0x47617A65, "Power Mac 6500"}, // Gazelle
|
||||||
{0x476F7373, "Power Mac G3 Beige"}, //Gossamer
|
{0x476F7373, "Power Mac G3 Beige"}, // Gossamer
|
||||||
{0x47525820, "PowerBook G3 Wallstreet"},
|
{0x47525820, "PowerBook G3 Wallstreet"},
|
||||||
//{"Hoop", "PowerBook 3400"}, //Hooper
|
//{"Hoop", "PowerBook 3400"}, //Hooper
|
||||||
{0x50425820, "PowerBook Pre-G3"},
|
{0x50425820, "PowerBook Pre-G3"},
|
||||||
{0x50444D20, "Nubus Power Mac or WGS"}, //Piltdown Man (6100/7100/8100)
|
{0x50444D20, "Nubus Power Mac or WGS"}, // Piltdown Man (6100/7100/8100)
|
||||||
{0x50697020, "Bandai Pippin"}, //Pippin
|
{0x50697020, "Bandai Pippin"}, // Pippin
|
||||||
//{"Powe", "Generic Power Mac"}, //PowerMac?
|
//{"Powe", "Generic Power Mac"}, //PowerMac?
|
||||||
//{"Spar", "20th Anniversay Mac"}, //Spartacus
|
//{"Spar", "20th Anniversay Mac"}, //Spartacus
|
||||||
{0x544E5420, "Power Mac 7xxxx/8xxx series"}, //Trinitrotoluene :-)
|
{0x544E5420, "Power Mac 7xxxx/8xxx series"}, // Trinitrotoluene :-)
|
||||||
{0x5A616E7A, "Power Mac 4400/7220"}, //Zanzibar
|
{0x5A616E7A, "Power Mac 4400/7220"}, // Zanzibar
|
||||||
//{"????", "A clone, perhaps?"} //N/A (Placeholder ID)
|
//{"????", "A clone, perhaps?"} //N/A (Placeholder ID)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
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();
|
||||||
break;
|
break;
|
||||||
|
@ -76,28 +75,26 @@ 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];
|
||||||
|
|
||||||
rom_file.open(rom_filepath, ios::in|ios::binary);
|
rom_file.open(rom_filepath, ios::in | ios::binary);
|
||||||
if (rom_file.fail()) {
|
if (rom_file.fail()) {
|
||||||
LOG_F(ERROR, "Cound not open the specified ROM file.");
|
LOG_F(ERROR, "Cound not open the specified ROM file.");
|
||||||
rom_file.close();
|
rom_file.close();
|
||||||
|
@ -108,7 +105,7 @@ int create_machine_for_rom(const char* rom_filepath)
|
||||||
file_size = rom_file.tellg();
|
file_size = rom_file.tellg();
|
||||||
rom_file.seekg(0, rom_file.beg);
|
rom_file.seekg(0, rom_file.beg);
|
||||||
|
|
||||||
if (file_size != 0x400000UL){
|
if (file_size != 0x400000UL) {
|
||||||
LOG_F(ERROR, "Unxpected ROM File size. Expected size is 4 megabytes.");
|
LOG_F(ERROR, "Unxpected ROM File size. Expected size is 4 megabytes.");
|
||||||
rom_file.close();
|
rom_file.close();
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -117,7 +114,7 @@ int create_machine_for_rom(const char* rom_filepath)
|
||||||
/* read config info offset from file */
|
/* read config info offset from file */
|
||||||
config_info_offset = 0;
|
config_info_offset = 0;
|
||||||
rom_file.seekg(0x300080, ios::beg);
|
rom_file.seekg(0x300080, ios::beg);
|
||||||
rom_file.read((char *)&config_info_offset, 4);
|
rom_file.read((char*)&config_info_offset, 4);
|
||||||
config_info_offset = READ_DWORD_BE_A(&config_info_offset);
|
config_info_offset = READ_DWORD_BE_A(&config_info_offset);
|
||||||
|
|
||||||
/* rewind to ConfigInfo.BootstrapVersion field */
|
/* rewind to ConfigInfo.BootstrapVersion field */
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
|
|
@ -24,33 +24,31 @@ 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;
|
||||||
|
|
||||||
gMachineObj->add_component(name, new SpdSdram168(i2c_addr));
|
gMachineObj->add_component(name, new SpdSdram168(i2c_addr));
|
||||||
SpdSdram168 *ram_dimm = dynamic_cast<SpdSdram168 *>(gMachineObj->get_comp_by_name(name));
|
SpdSdram168* ram_dimm = dynamic_cast<SpdSdram168*>(gMachineObj->get_comp_by_name(name));
|
||||||
ram_dimm->set_capacity(capacity_megs);
|
ram_dimm->set_capacity(capacity_megs);
|
||||||
|
|
||||||
/* register RAM DIMM with the I2C bus */
|
/* register RAM DIMM with the I2C bus */
|
||||||
I2CBus *i2c_bus = dynamic_cast<I2CBus *>(gMachineObj->get_comp_by_type(HWCompType::I2C_HOST));
|
I2CBus* i2c_bus = dynamic_cast<I2CBus*>(gMachineObj->get_comp_by_type(HWCompType::I2C_HOST));
|
||||||
i2c_bus->register_device(i2c_addr, ram_dimm);
|
i2c_bus->register_device(i2c_addr, ram_dimm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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;
|
||||||
|
@ -66,17 +64,17 @@ int create_gossamer()
|
||||||
gMachineObj->add_alias("Grackle", "PCI_Host");
|
gMachineObj->add_alias("Grackle", "PCI_Host");
|
||||||
|
|
||||||
/* get raw pointer to MPC106 object */
|
/* get raw pointer to MPC106 object */
|
||||||
MPC106 *grackle_obj = dynamic_cast<MPC106 *>(gMachineObj->get_comp_by_name("Grackle"));
|
MPC106* grackle_obj = dynamic_cast<MPC106*>(gMachineObj->get_comp_by_name("Grackle"));
|
||||||
|
|
||||||
/* 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);
|
||||||
|
|
66
main.cpp
66
main.cpp
|
@ -19,26 +19,24 @@ 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/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//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,19 +46,17 @@ 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;
|
||||||
loguru::g_preamble_thread = false;
|
loguru::g_preamble_thread = false;
|
||||||
loguru::init(argc, argv);
|
loguru::init(argc, 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();
|
||||||
|
@ -117,20 +107,18 @@ int main(int argc, char **argv)
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_Init(SDL_INIT_AUDIO)){
|
if (SDL_Init(SDL_INIT_AUDIO)) {
|
||||||
LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError());
|
LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError());
|
||||||
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;
|
||||||
|
|
|
@ -5,102 +5,98 @@
|
||||||
#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)))))
|
||||||
|
|
||||||
/* read an aligned big-endian DWORD (32bit) */
|
/* read an aligned big-endian DWORD (32bit) */
|
||||||
#define READ_DWORD_BE_A(addr) (BYTESWAP_32(*((uint32_t *)((addr)))))
|
#define READ_DWORD_BE_A(addr) (BYTESWAP_32(*((uint32_t*)((addr)))))
|
||||||
|
|
||||||
/* read an aligned big-endian QWORD (64bit) */
|
/* read an aligned big-endian QWORD (64bit) */
|
||||||
#define READ_QWORD_BE_A(addr) (BYTESWAP_64(*((uint64_t *)((addr)))))
|
#define READ_QWORD_BE_A(addr) (BYTESWAP_64(*((uint64_t*)((addr)))))
|
||||||
|
|
||||||
/* read an aligned little-endian WORD (16bit) */
|
/* read an aligned little-endian WORD (16bit) */
|
||||||
#define READ_WORD_LE_A(addr) (*(uint16_t *)((addr)))
|
#define READ_WORD_LE_A(addr) (*(uint16_t*)((addr)))
|
||||||
|
|
||||||
/* read an aligned little-endian DWORD (32bit) */
|
/* read an aligned little-endian DWORD (32bit) */
|
||||||
#define READ_DWORD_LE_A(addr) (*(uint32_t *)((addr)))
|
#define READ_DWORD_LE_A(addr) (*(uint32_t*)((addr)))
|
||||||
|
|
||||||
/* read an aligned little-endian QWORD (64bit) */
|
/* read an aligned little-endian QWORD (64bit) */
|
||||||
#define READ_QWORD_LE_A(addr) (*(uint64_t *)((addr)))
|
#define READ_QWORD_LE_A(addr) (*(uint64_t*)((addr)))
|
||||||
|
|
||||||
/* read an unaligned big-endian WORD (16bit) */
|
/* read an unaligned big-endian WORD (16bit) */
|
||||||
#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) */
|
||||||
#define WRITE_WORD_BE_A(addr,val) (*((uint16_t *)((addr))) = BYTESWAP_16(val))
|
#define WRITE_WORD_BE_A(addr, val) (*((uint16_t*)((addr))) = BYTESWAP_16(val))
|
||||||
|
|
||||||
/* write an aligned big-endian DWORD (32bit) */
|
/* write an aligned big-endian DWORD (32bit) */
|
||||||
#define WRITE_DWORD_BE_A(addr,val) (*((uint32_t *)((addr))) = BYTESWAP_32(val))
|
#define WRITE_DWORD_BE_A(addr, val) (*((uint32_t*)((addr))) = BYTESWAP_32(val))
|
||||||
|
|
||||||
/* write an aligned big-endian QWORD (64bit) */
|
/* write an aligned big-endian QWORD (64bit) */
|
||||||
#define WRITE_QWORD_BE_A(addr,val) (*((uint64_t *)((addr))) = BYTESWAP_64(val))
|
#define WRITE_QWORD_BE_A(addr, val) (*((uint64_t*)((addr))) = BYTESWAP_64(val))
|
||||||
|
|
||||||
/* write an unaligned big-endian WORD (16bit) */
|
/* write an unaligned big-endian WORD (16bit) */
|
||||||
#define WRITE_WORD_BE_U(addr, val) \
|
#define WRITE_WORD_BE_U(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
(addr)[0] = ((val) >> 8) & 0xFF; \
|
(addr)[0] = ((val) >> 8) & 0xFF; \
|
||||||
(addr)[1] = (val) & 0xFF; \
|
(addr)[1] = (val)&0xFF; \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
/* write an unaligned big-endian DWORD (32bit) */
|
/* write an unaligned big-endian DWORD (32bit) */
|
||||||
#define WRITE_DWORD_BE_U(addr, val) \
|
#define WRITE_DWORD_BE_U(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
(addr)[0] = ((val) >> 24) & 0xFF; \
|
(addr)[0] = ((val) >> 24) & 0xFF; \
|
||||||
(addr)[1] = ((val) >> 16) & 0xFF; \
|
(addr)[1] = ((val) >> 16) & 0xFF; \
|
||||||
(addr)[2] = ((val) >> 8) & 0xFF; \
|
(addr)[2] = ((val) >> 8) & 0xFF; \
|
||||||
(addr)[3] = (val) & 0xFF; \
|
(addr)[3] = (val)&0xFF; \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
/* write an aligned little-endian WORD (16bit) */
|
/* write an aligned little-endian WORD (16bit) */
|
||||||
#define WRITE_WORD_LE_A(addr,val) (*((uint16_t *)((addr))) = (val))
|
#define WRITE_WORD_LE_A(addr, val) (*((uint16_t*)((addr))) = (val))
|
||||||
|
|
||||||
/* write an aligned little-endian DWORD (32bit) */
|
/* write an aligned little-endian DWORD (32bit) */
|
||||||
#define WRITE_DWORD_LE_A(addr,val) (*((uint32_t *)((addr))) = (val))
|
#define WRITE_DWORD_LE_A(addr, val) (*((uint32_t*)((addr))) = (val))
|
||||||
|
|
||||||
/* write an aligned little-endian QWORD (64bit) */
|
/* write an aligned little-endian QWORD (64bit) */
|
||||||
#define WRITE_QWORD_LE_A(addr,val) (*((uint64_t *)((addr))) = (val))
|
#define WRITE_QWORD_LE_A(addr, val) (*((uint64_t*)((addr))) = (val))
|
||||||
|
|
||||||
/* write an unaligned little-endian WORD (16bit) */
|
/* write an unaligned little-endian WORD (16bit) */
|
||||||
#define WRITE_WORD_LE_U(addr, val) \
|
#define WRITE_WORD_LE_U(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
(addr)[0] = (val) & 0xFF; \
|
(addr)[0] = (val)&0xFF; \
|
||||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
/* write an unaligned little-endian DWORD (32bit) */
|
/* write an unaligned little-endian DWORD (32bit) */
|
||||||
#define WRITE_DWORD_LE_U(addr, val) \
|
#define WRITE_DWORD_LE_U(addr, val) \
|
||||||
do { \
|
do { \
|
||||||
(addr)[0] = (val) & 0xFF; \
|
(addr)[0] = (val)&0xFF; \
|
||||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||||
(addr)[2] = ((val) >> 16) & 0xFF; \
|
(addr)[2] = ((val) >> 16) & 0xFF; \
|
||||||
(addr)[3] = ((val) >> 24) & 0xFF; \
|
(addr)[3] = ((val) >> 24) & 0xFF; \
|
||||||
} while(0)
|
} while (0)
|
||||||
|
|
||||||
#endif /* MEM_READ_WRITE_H */
|
#endif /* MEM_READ_WRITE_H */
|
||||||
|
|
Loading…
Reference in New Issue