mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-27 01:31:21 +00:00
Merge pull request #14 from Waqar144/clang-format
clang-format everything
This commit is contained in:
commit
f8bde236b8
78
.clang-format
Normal file
78
.clang-format
Normal file
@ -0,0 +1,78 @@
|
||||
Language: Cpp
|
||||
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: false
|
||||
#AlignConsecutiveMacros: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
#AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
#BreakInheritanceList: BeforeComma
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 100
|
||||
CompactNamespaces: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
FixNamespaceComments: true
|
||||
IncludeBlocks: Preserve
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
PenaltyBreakAssignment: 50
|
||||
PenaltyBreakBeforeFirstCallParameter: 0
|
||||
PenaltyBreakComment: 100
|
||||
PenaltyBreakFirstLessLess: 200
|
||||
PenaltyBreakString: 100
|
||||
#PenaltyBreakTemplateDeclaration: 0
|
||||
PenaltyExcessCharacter: 10
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SpaceAfterCStyleCast: false
|
||||
#SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
#SpaceBeforeCpp11BracedList: true
|
||||
#SpaceBeforeCtorInitializerColon: false
|
||||
#SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
#SpaceBeforeRangeBasedForLoopColon: false
|
||||
#SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 4
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
#Standard: c++17
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
@ -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
|
||||
// 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 "ppcmmu.h"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
|
||||
void power_abs() {
|
||||
ppc_grab_regsda();
|
||||
if (ppc_result_a == 0x80000000) {
|
||||
ppc_result_d = ppc_result_a;
|
||||
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_d = ppc_result_a & 0x7FFFFFFF;
|
||||
}
|
||||
ppc_store_result_regd();
|
||||
@ -50,8 +49,7 @@ void power_absdot() {
|
||||
if (ppc_result_a == 0x80000000) {
|
||||
ppc_result_d = ppc_result_a;
|
||||
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_d = ppc_result_a & 0x7FFFFFFF;
|
||||
}
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
@ -64,8 +62,7 @@ void power_abso() {
|
||||
ppc_result_d = ppc_result_a;
|
||||
ppc_state.spr[SPR::XER] |= 0x40000000;
|
||||
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_d = ppc_result_a & 0x7FFFFFFF;
|
||||
}
|
||||
ppc_store_result_regd();
|
||||
@ -77,8 +74,7 @@ void power_absodot() {
|
||||
ppc_result_d = ppc_result_a;
|
||||
ppc_state.spr[SPR::XER] |= 0x40000000;
|
||||
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_d = ppc_result_a & 0x7FFFFFFF;
|
||||
}
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
@ -118,45 +114,45 @@ void power_clcsdot() {
|
||||
|
||||
void power_div() {
|
||||
ppc_grab_regsdab();
|
||||
ppc_result_d = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
|
||||
ppc_result_d = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
|
||||
ppc_state.spr[SPR::MQ] = (ppc_result_a | ppc_state.spr[SPR::MQ]) % ppc_result_b;
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
void power_divdot() {
|
||||
ppc_result_d = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
|
||||
ppc_result_d = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
|
||||
ppc_state.spr[SPR::MQ] = (ppc_result_a | ppc_state.spr[SPR::MQ]) % ppc_result_b;
|
||||
}
|
||||
|
||||
void power_divo() {
|
||||
ppc_result_d = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
|
||||
ppc_result_d = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
|
||||
ppc_state.spr[SPR::MQ] = (ppc_result_a | ppc_state.spr[SPR::MQ]) % ppc_result_b;
|
||||
}
|
||||
|
||||
void power_divodot() {
|
||||
ppc_result_d = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
|
||||
ppc_result_d = (ppc_result_a | ppc_state.spr[SPR::MQ]) / ppc_result_b;
|
||||
ppc_state.spr[SPR::MQ] = (ppc_result_a | ppc_state.spr[SPR::MQ]) % ppc_result_b;
|
||||
}
|
||||
|
||||
void power_divs() {
|
||||
ppc_grab_regsdab();
|
||||
ppc_result_d = ppc_result_a / ppc_result_b;
|
||||
ppc_result_d = ppc_result_a / ppc_result_b;
|
||||
ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b);
|
||||
ppc_store_result_regd();
|
||||
}
|
||||
|
||||
void power_divsdot() {
|
||||
ppc_result_d = ppc_result_a / ppc_result_b;
|
||||
ppc_result_d = ppc_result_a / ppc_result_b;
|
||||
ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b);
|
||||
}
|
||||
|
||||
void power_divso() {
|
||||
ppc_result_d = ppc_result_a / ppc_result_b;
|
||||
ppc_result_d = ppc_result_a / ppc_result_b;
|
||||
ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b);
|
||||
}
|
||||
|
||||
void power_divsodot() {
|
||||
ppc_result_d = ppc_result_a / ppc_result_b;
|
||||
ppc_result_d = ppc_result_a / ppc_result_b;
|
||||
ppc_state.spr[SPR::MQ] = (ppc_result_a % ppc_result_b);
|
||||
}
|
||||
|
||||
@ -164,8 +160,7 @@ void power_doz() {
|
||||
ppc_grab_regsdab();
|
||||
if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
|
||||
ppc_result_d = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
|
||||
}
|
||||
ppc_store_result_rega();
|
||||
@ -175,8 +170,7 @@ void power_dozdot() {
|
||||
ppc_grab_regsdab();
|
||||
if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
|
||||
ppc_result_d = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
|
||||
}
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
@ -186,8 +180,7 @@ void power_dozdot() {
|
||||
void power_dozo() {
|
||||
if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
|
||||
ppc_result_d = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
|
||||
}
|
||||
}
|
||||
@ -195,8 +188,7 @@ void power_dozo() {
|
||||
void power_dozodot() {
|
||||
if (((int32_t)ppc_result_a) > ((int32_t)ppc_result_b)) {
|
||||
ppc_result_d = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_d = ~ppc_result_a + ppc_result_b + 1;
|
||||
}
|
||||
}
|
||||
@ -205,8 +197,7 @@ void power_dozi() {
|
||||
ppc_grab_regsdab();
|
||||
if (((int32_t)ppc_result_a) > simm) {
|
||||
ppc_result_d = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_d = ~ppc_result_a + simm + 1;
|
||||
}
|
||||
ppc_store_result_rega();
|
||||
@ -215,7 +206,7 @@ void power_dozi() {
|
||||
void power_lscbx() {
|
||||
ppc_grab_regsdab();
|
||||
uint32_t bytes_copied = 0;
|
||||
bool match_found = false;
|
||||
bool match_found = false;
|
||||
uint32_t shift_amount = 0;
|
||||
uint8_t return_value;
|
||||
uint8_t byte_compared = (uint8_t)((ppc_state.spr[SPR::XER] & 0xFF00) >> 8);
|
||||
@ -223,7 +214,7 @@ void power_lscbx() {
|
||||
return;
|
||||
}
|
||||
uint32_t bytes_to_load = (ppc_state.spr[SPR::XER] & 0x7f) + 1;
|
||||
ppc_effective_address = (reg_a == 0) ? ppc_result_b : ppc_result_a + ppc_result_b;
|
||||
ppc_effective_address = (reg_a == 0) ? ppc_result_b : ppc_result_a + ppc_result_b;
|
||||
do {
|
||||
ppc_effective_address++;
|
||||
bytes_to_load--;
|
||||
@ -259,9 +250,8 @@ void power_lscbx() {
|
||||
|
||||
if (shift_amount == 3) {
|
||||
shift_amount = 0;
|
||||
reg_d = (reg_d + 1) & 0x1F;
|
||||
}
|
||||
else {
|
||||
reg_d = (reg_d + 1) & 0x1F;
|
||||
} else {
|
||||
shift_amount++;
|
||||
}
|
||||
} while (bytes_to_load > 0);
|
||||
@ -275,19 +265,17 @@ void power_lscbxdot() {
|
||||
|
||||
void power_maskg() {
|
||||
ppc_grab_regssab();
|
||||
uint32_t mask_start = ppc_result_d & 31;
|
||||
uint32_t mask_end = ppc_result_b & 31;
|
||||
uint32_t mask_start = ppc_result_d & 31;
|
||||
uint32_t mask_end = ppc_result_b & 31;
|
||||
uint32_t insert_mask = 0;
|
||||
|
||||
if (mask_start < (mask_end + 1)) {
|
||||
for (uint32_t i = mask_start; i < mask_end; i++) {
|
||||
insert_mask |= (0x80000000 >> i);
|
||||
}
|
||||
}
|
||||
else if (mask_start == (mask_end + 1)) {
|
||||
} else if (mask_start == (mask_end + 1)) {
|
||||
insert_mask = 0xFFFFFFFF;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
insert_mask = 0xFFFFFFFF;
|
||||
for (uint32_t i = (mask_end + 1); i < (mask_start - 1); i++) {
|
||||
insert_mask &= (~(0x80000000 >> i));
|
||||
@ -300,19 +288,17 @@ void power_maskg() {
|
||||
|
||||
void power_maskgdot() {
|
||||
ppc_grab_regssab();
|
||||
uint32_t mask_start = ppc_result_d & 31;
|
||||
uint32_t mask_end = ppc_result_b & 31;
|
||||
uint32_t mask_start = ppc_result_d & 31;
|
||||
uint32_t mask_end = ppc_result_b & 31;
|
||||
uint32_t insert_mask = 0;
|
||||
|
||||
if (mask_start < (mask_end + 1)) {
|
||||
for (uint32_t i = mask_start; i < mask_end; i++) {
|
||||
insert_mask |= (0x80000000 >> i);
|
||||
}
|
||||
}
|
||||
else if (mask_start == (mask_end + 1)) {
|
||||
} else if (mask_start == (mask_end + 1)) {
|
||||
insert_mask = 0xFFFFFFFF;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
insert_mask = 0xFFFFFFFF;
|
||||
for (uint32_t i = (mask_end + 1); i < (mask_start - 1); i++) {
|
||||
insert_mask &= (~(0x80000000 >> i));
|
||||
@ -326,7 +312,7 @@ void power_maskgdot() {
|
||||
void power_maskir() {
|
||||
ppc_grab_regssab();
|
||||
uint32_t mask_insert = ppc_result_a;
|
||||
uint32_t insert_rot = 0x80000000;
|
||||
uint32_t insert_rot = 0x80000000;
|
||||
do {
|
||||
if (ppc_result_b & insert_rot) {
|
||||
mask_insert &= ~insert_rot;
|
||||
@ -342,7 +328,7 @@ void power_maskir() {
|
||||
void power_maskirdot() {
|
||||
ppc_grab_regssab();
|
||||
uint32_t mask_insert = ppc_result_a;
|
||||
uint32_t insert_rot = 0x80000000;
|
||||
uint32_t insert_rot = 0x80000000;
|
||||
do {
|
||||
if (ppc_result_b & insert_rot) {
|
||||
mask_insert &= ~insert_rot;
|
||||
@ -360,41 +346,37 @@ void power_mul() {
|
||||
ppc_grab_regsdab();
|
||||
uint64_t product;
|
||||
|
||||
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
|
||||
ppc_result_d = ((uint32_t)(product >> 32));
|
||||
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
|
||||
ppc_result_d = ((uint32_t)(product >> 32));
|
||||
ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
|
||||
ppc_store_result_regd();
|
||||
|
||||
}
|
||||
|
||||
void power_muldot() {
|
||||
ppc_grab_regsdab();
|
||||
uint64_t product;
|
||||
|
||||
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
|
||||
ppc_result_d = ((uint32_t)(product >> 32));
|
||||
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
|
||||
ppc_result_d = ((uint32_t)(product >> 32));
|
||||
ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
|
||||
ppc_changecrf0(ppc_result_d);
|
||||
ppc_store_result_regd();
|
||||
|
||||
}
|
||||
|
||||
void power_mulo() {
|
||||
uint64_t product;
|
||||
|
||||
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
|
||||
ppc_result_d = ((uint32_t)(product >> 32));
|
||||
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
|
||||
ppc_result_d = ((uint32_t)(product >> 32));
|
||||
ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
|
||||
|
||||
}
|
||||
|
||||
void power_mulodot() {
|
||||
uint64_t product;
|
||||
|
||||
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
|
||||
ppc_result_d = ((uint32_t)(product >> 32));
|
||||
product = ((uint64_t)ppc_result_a) * ((uint64_t)ppc_result_b);
|
||||
ppc_result_d = ((uint32_t)(product >> 32));
|
||||
ppc_state.spr[SPR::MQ] = ((uint32_t)(product));
|
||||
|
||||
}
|
||||
|
||||
void power_nabs() {
|
||||
@ -417,20 +399,18 @@ void power_nabsodot() {
|
||||
|
||||
void power_rlmi() {
|
||||
ppc_grab_regssab();
|
||||
unsigned rot_mb = (ppc_cur_instruction >> 6) & 31;
|
||||
unsigned rot_me = (ppc_cur_instruction >> 1) & 31;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
unsigned rot_mb = (ppc_cur_instruction >> 6) & 31;
|
||||
unsigned rot_me = (ppc_cur_instruction >> 1) & 31;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
uint32_t insert_mask = 0;
|
||||
|
||||
if (rot_mb < (rot_me + 1)) {
|
||||
for (uint32_t i = rot_mb; i < rot_me; i++) {
|
||||
insert_mask |= (0x80000000 >> i);
|
||||
}
|
||||
}
|
||||
else if (rot_mb == (rot_me + 1)) {
|
||||
} else if (rot_mb == (rot_me + 1)) {
|
||||
insert_mask = 0xFFFFFFFF;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
insert_mask = 0xFFFFFFFF;
|
||||
for (uint32_t i = (rot_me + 1); i < (rot_mb - 1); i++) {
|
||||
insert_mask &= (~(0x80000000 >> i));
|
||||
@ -438,7 +418,7 @@ void power_rlmi() {
|
||||
}
|
||||
|
||||
uint32_t step2 = (ppc_result_d << rot_amt) | (ppc_result_d >> rot_amt);
|
||||
ppc_result_a = step2 & insert_mask;
|
||||
ppc_result_a = step2 & insert_mask;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
|
||||
@ -446,8 +426,7 @@ void power_rrib() {
|
||||
ppc_grab_regssab();
|
||||
if (ppc_result_d & 0x80000000) {
|
||||
ppc_result_a |= (0x80000000 >> ppc_result_b);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_a &= ~(0x80000000 >> ppc_result_b);
|
||||
}
|
||||
ppc_store_result_rega();
|
||||
@ -457,8 +436,7 @@ void power_rribdot() {
|
||||
ppc_grab_regssab();
|
||||
if (ppc_result_d & 0x80000000) {
|
||||
ppc_result_a |= (0x80000000 >> ppc_result_b);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_result_a &= ~(0x80000000 >> ppc_result_b);
|
||||
}
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
@ -468,26 +446,26 @@ void power_rribdot() {
|
||||
void power_sle() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
for (uint32_t i = 31; i > rot_amt; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_final = ((ppc_result_d << rot_amt) | (ppc_result_d >> (32 - rot_amt)));
|
||||
uint32_t insert_final = ((ppc_result_d << rot_amt) | (ppc_result_d >> (32 - rot_amt)));
|
||||
ppc_state.spr[SPR::MQ] = insert_final & insert_mask;
|
||||
ppc_result_a = insert_final & insert_mask;
|
||||
ppc_result_a = insert_final & insert_mask;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
|
||||
void power_sledot() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
for (uint32_t i = 31; i > rot_amt; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_final = ((ppc_result_d << rot_amt) | (ppc_result_d >> (32 - rot_amt)));
|
||||
uint32_t insert_final = ((ppc_result_d << rot_amt) | (ppc_result_d >> (32 - rot_amt)));
|
||||
ppc_state.spr[SPR::MQ] = insert_final & insert_mask;
|
||||
ppc_result_a = insert_final & insert_mask;
|
||||
ppc_result_a = insert_final & insert_mask;
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
@ -495,12 +473,12 @@ void power_sledot() {
|
||||
void power_sleq() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
for (uint32_t i = 31; i > rot_amt; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d << rot_amt) | (ppc_result_d >> (rot_amt - 31)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -509,7 +487,7 @@ void power_sleq() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end;
|
||||
ppc_result_a = insert_end;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
@ -517,12 +495,12 @@ void power_sleq() {
|
||||
void power_sleqdot() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
for (uint32_t i = 31; i > rot_amt; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d << rot_amt) | (ppc_result_d >> (rot_amt - 31)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -531,7 +509,7 @@ void power_sleqdot() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end;
|
||||
ppc_result_a = insert_end;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
ppc_store_result_rega();
|
||||
@ -540,12 +518,12 @@ void power_sleqdot() {
|
||||
void power_sliq() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
for (uint32_t i = 31; i > rot_sh; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d << rot_sh) | (ppc_result_d >> (rot_sh - 31)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -554,7 +532,7 @@ void power_sliq() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end & insert_mask;
|
||||
ppc_result_a = insert_end & insert_mask;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
@ -562,12 +540,12 @@ void power_sliq() {
|
||||
void power_sliqdot() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
for (uint32_t i = 31; i > rot_sh; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d << rot_sh) | (ppc_result_d >> (rot_sh - 31)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -576,7 +554,7 @@ void power_sliqdot() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end & insert_mask;
|
||||
ppc_result_a = insert_end & insert_mask;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
ppc_store_result_rega();
|
||||
@ -585,12 +563,12 @@ void power_sliqdot() {
|
||||
void power_slliq() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
for (uint32_t i = 31; i > rot_sh; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -599,7 +577,7 @@ void power_slliq() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end;
|
||||
ppc_result_a = insert_end;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
@ -607,12 +585,12 @@ void power_slliq() {
|
||||
void power_slliqdot() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
for (uint32_t i = 31; i > rot_sh; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d << rot_sh) | (ppc_result_d >> (32 - rot_sh)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -621,7 +599,7 @@ void power_slliqdot() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end;
|
||||
ppc_result_a = insert_end;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
ppc_store_result_rega();
|
||||
@ -662,26 +640,26 @@ void power_sraqdot() {
|
||||
void power_sre() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
for (uint32_t i = 31; i > rot_amt; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_final = ((ppc_result_d >> rot_amt) | (ppc_result_d << (32 - rot_amt)));
|
||||
uint32_t insert_final = ((ppc_result_d >> rot_amt) | (ppc_result_d << (32 - rot_amt)));
|
||||
ppc_state.spr[SPR::MQ] = insert_final & insert_mask;
|
||||
ppc_result_a = insert_final;
|
||||
ppc_result_a = insert_final;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
|
||||
void power_sredot() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
uint32_t rot_amt = ppc_result_b & 31;
|
||||
for (uint32_t i = 31; i > rot_amt; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_final = ((ppc_result_d >> rot_amt) | (ppc_result_d << (32 - rot_amt)));
|
||||
uint32_t insert_final = ((ppc_result_d >> rot_amt) | (ppc_result_d << (32 - rot_amt)));
|
||||
ppc_state.spr[SPR::MQ] = insert_final & insert_mask;
|
||||
ppc_result_a = insert_final;
|
||||
ppc_result_a = insert_final;
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
@ -697,12 +675,12 @@ void power_sreadot() {
|
||||
void power_sreq() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
unsigned rot_sh = ppc_result_b & 31;
|
||||
unsigned rot_sh = ppc_result_b & 31;
|
||||
for (uint32_t i = 31; i > rot_sh; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -711,7 +689,7 @@ void power_sreq() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end;
|
||||
ppc_result_a = insert_end;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
@ -719,12 +697,12 @@ void power_sreq() {
|
||||
void power_sreqdot() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
unsigned rot_sh = ppc_result_b & 31;
|
||||
unsigned rot_sh = ppc_result_b & 31;
|
||||
for (uint32_t i = 31; i > rot_sh; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -733,7 +711,7 @@ void power_sreqdot() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end;
|
||||
ppc_result_a = insert_end;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
ppc_store_result_rega();
|
||||
@ -742,12 +720,12 @@ void power_sreqdot() {
|
||||
void power_sriq() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
for (uint32_t i = 31; i > rot_sh; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -756,7 +734,7 @@ void power_sriq() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end;
|
||||
ppc_result_a = insert_end;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
@ -764,12 +742,12 @@ void power_sriq() {
|
||||
void power_sriqdot() {
|
||||
ppc_grab_regssa();
|
||||
uint32_t insert_mask = 0;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
unsigned rot_sh = (ppc_cur_instruction >> 11) & 31;
|
||||
for (uint32_t i = 31; i > rot_sh; i--) {
|
||||
insert_mask |= (1 << i);
|
||||
}
|
||||
uint32_t insert_start = ((ppc_result_d >> rot_sh) | (ppc_result_d << (32 - rot_sh)));
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
uint32_t insert_end = ppc_state.spr[SPR::MQ];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
if (insert_mask & (1 << i)) {
|
||||
@ -778,7 +756,7 @@ void power_sriqdot() {
|
||||
}
|
||||
}
|
||||
|
||||
ppc_result_a = insert_end;
|
||||
ppc_result_a = insert_end;
|
||||
ppc_state.spr[SPR::MQ] = insert_start;
|
||||
ppc_changecrf0(ppc_result_a);
|
||||
ppc_store_result_rega();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,17 +26,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include <string>
|
||||
|
||||
typedef struct PPCDisasmContext {
|
||||
uint32_t instr_addr;
|
||||
uint32_t instr_code;
|
||||
uint32_t instr_addr;
|
||||
uint32_t instr_code;
|
||||
std::string instr_str;
|
||||
bool simplified; /* true if we should output simplified mnemonics */
|
||||
bool simplified; /* true if we should output simplified mnemonics */
|
||||
} PPCDisasmContext;
|
||||
|
||||
std::string disassemble_single(PPCDisasmContext *ctx);
|
||||
std::string disassemble_single(PPCDisasmContext* ctx);
|
||||
|
||||
int test_ppc_disasm(void);
|
||||
|
||||
/** 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 */
|
||||
|
@ -22,22 +22,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef PPCEMU_H
|
||||
#define PPCEMU_H
|
||||
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
#include <setjmp.h>
|
||||
#include "endianswap.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
|
||||
|
||||
//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
|
||||
|
||||
//Uncomment this to use GCC built-in functions.
|
||||
// Uncomment this to use GCC built-in functions.
|
||||
//#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
|
||||
|
||||
enum endian_switch { big_end = 0, little_end = 1 };
|
||||
@ -45,8 +45,8 @@ enum endian_switch { big_end = 0, little_end = 1 };
|
||||
typedef void (*PPCOpcode)(void);
|
||||
|
||||
union FPR_storage {
|
||||
double dbl64_r; // double floating-point representation
|
||||
uint64_t int64_r; // double integer representation
|
||||
double dbl64_r; // double floating-point representation
|
||||
uint64_t int64_r; // double integer representation
|
||||
};
|
||||
|
||||
/**
|
||||
@ -65,7 +65,7 @@ fpscr = FP Status and Condition Register
|
||||
|
||||
typedef struct struct_ppc_state {
|
||||
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 cr;
|
||||
uint32_t fpscr;
|
||||
@ -73,7 +73,7 @@ typedef struct struct_ppc_state {
|
||||
uint32_t spr[1024];
|
||||
uint32_t msr;
|
||||
uint32_t sr[16];
|
||||
bool reserve; //reserve bit used for lwarx and stcwx
|
||||
bool reserve; // reserve bit used for lwarx and stcwx
|
||||
} SetPRS;
|
||||
|
||||
extern SetPRS ppc_state;
|
||||
@ -94,10 +94,7 @@ enum SPR : int {
|
||||
};
|
||||
|
||||
/** symbolic names for frequently used SPRs */
|
||||
enum TBR : int {
|
||||
TBL = 0,
|
||||
TBU = 1
|
||||
};
|
||||
enum TBR : int { TBL = 0, TBU = 1 };
|
||||
|
||||
/** symbolic names for common PPC processors */
|
||||
enum PPC_VER : uint32_t {
|
||||
@ -147,10 +144,10 @@ SUPERVISOR MODEL
|
||||
536 - 543 are the Data BAT registers
|
||||
**/
|
||||
|
||||
extern uint32_t opcode_value; //used for interpreting opcodes
|
||||
extern uint64_t timebase_counter; //used for storing time base value
|
||||
extern uint32_t opcode_value; // used for interpreting opcodes
|
||||
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 simult_result;
|
||||
extern uint32_t uiadd_result;
|
||||
@ -176,19 +173,19 @@ extern uint32_t rot_mb;
|
||||
extern uint32_t rot_me;
|
||||
extern uint32_t uimm;
|
||||
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 int32_t simm;
|
||||
extern int32_t adr_li;
|
||||
extern int32_t br_bd;
|
||||
|
||||
//Used for GP calcs
|
||||
// Used for GP calcs
|
||||
extern uint32_t ppc_result_a;
|
||||
extern uint32_t ppc_result_b;
|
||||
extern uint32_t ppc_result_c;
|
||||
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_b;
|
||||
extern uint64_t ppc_result64_c;
|
||||
@ -197,7 +194,7 @@ extern uint64_t ppc_result64_d;
|
||||
|
||||
/* The precise end of a basic block. */
|
||||
enum class BB_end_kind {
|
||||
BB_NONE = 0, /* no basic block end is reached */
|
||||
BB_NONE = 0, /* no basic block end is reached */
|
||||
BB_BRANCH = 1, /* a branch instruction is encountered */
|
||||
BB_EXCEPTION, /* an exception is occured */
|
||||
BB_RFI /* the rfi instruction is encountered */
|
||||
@ -215,10 +212,10 @@ enum class Except_Type {
|
||||
EXC_NO_FPU,
|
||||
EXC_DECR,
|
||||
EXC_SYSCALL = 12,
|
||||
EXC_TRACE = 13
|
||||
EXC_TRACE = 13
|
||||
};
|
||||
|
||||
//extern bool bb_end;
|
||||
// extern bool bb_end;
|
||||
extern BB_end_kind bb_kind;
|
||||
|
||||
extern jmp_buf exc_env;
|
||||
@ -229,23 +226,23 @@ extern bool grab_return;
|
||||
|
||||
extern bool power_on;
|
||||
|
||||
extern bool is_601; //For PowerPC 601 Emulation
|
||||
extern bool is_gekko; //For GameCube Emulation
|
||||
extern bool is_altivec; //For Altivec Emulation
|
||||
extern bool is_64bit; //For PowerPC G5 Emulation
|
||||
extern bool is_601; // For PowerPC 601 Emulation
|
||||
extern bool is_gekko; // For GameCube Emulation
|
||||
extern bool is_altivec; // For Altivec Emulation
|
||||
extern bool is_64bit; // For PowerPC G5 Emulation
|
||||
|
||||
//Important Addressing Integers
|
||||
// Important Addressing Integers
|
||||
extern uint32_t ppc_cur_instruction;
|
||||
extern uint32_t ppc_effective_address;
|
||||
extern uint32_t ppc_next_instruction_address;
|
||||
|
||||
//Profiling Stats
|
||||
// Profiling Stats
|
||||
extern uint32_t mmu_translations_num;
|
||||
extern uint32_t exceptions_performed;
|
||||
extern uint32_t supervisor_inst_num;
|
||||
|
||||
//Function prototypes
|
||||
extern void ppc_cpu_init(MemCtrlBase *mem_ctrl, uint32_t proc_version);
|
||||
// Function prototypes
|
||||
extern void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t proc_version);
|
||||
extern void ppc_mmu_init();
|
||||
|
||||
void ppc_illegalop();
|
||||
@ -293,15 +290,13 @@ void ppc_fp_changecrf1();
|
||||
void ppc_tbr_update();
|
||||
|
||||
/* Exception handlers. */
|
||||
[[noreturn]] void ppc_exception_handler(Except_Type exception_type,
|
||||
uint32_t srr1_bits);
|
||||
[[noreturn]] void dbg_exception_handler(Except_Type exception_type,
|
||||
uint32_t srr1_bits);
|
||||
[[noreturn]] void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits);
|
||||
[[noreturn]] void dbg_exception_handler(Except_Type exception_type, uint32_t srr1_bits);
|
||||
|
||||
//MEMORY DECLARATIONS
|
||||
// MEMORY DECLARATIONS
|
||||
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_bcctrl();
|
||||
extern void ppc_bclr();
|
||||
@ -599,7 +594,7 @@ extern void ppc_fsqrtsdot();
|
||||
extern void ppc_fcmpo();
|
||||
extern void ppc_fcmpu();
|
||||
|
||||
//Power-specific instructions
|
||||
// Power-specific instructions
|
||||
extern void power_abs();
|
||||
extern void power_absdot();
|
||||
extern void power_abso();
|
||||
@ -667,17 +662,17 @@ extern void power_srlqdot();
|
||||
extern void power_srq();
|
||||
extern void power_srqdot();
|
||||
|
||||
//Gekko instructions
|
||||
// Gekko instructions
|
||||
extern void ppc_psq_l();
|
||||
extern void ppc_psq_lu();
|
||||
extern void ppc_psq_st();
|
||||
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_exec(void);
|
||||
@ -685,9 +680,9 @@ extern void ppc_exec_single(void);
|
||||
extern void ppc_exec_until(uint32_t goal_addr);
|
||||
|
||||
/* debugging support API */
|
||||
void print_gprs(void); /* print content of the general purpose 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 */
|
||||
void set_reg(std::string ®_name, uint64_t val); /* set reg_name to val */
|
||||
void print_gprs(void); /* print content of the general purpose registers */
|
||||
void print_fprs(void); /* print content of the floating-point registers */
|
||||
uint64_t get_reg(std::string& reg_name); /* get content of the register reg_name */
|
||||
void set_reg(std::string& reg_name, uint64_t val); /* set reg_name to val */
|
||||
|
||||
#endif /* PPCEMU_H */
|
||||
|
@ -21,92 +21,89 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/** @file Handling of low-level PPC exceptions. */
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include "ppcemu.h"
|
||||
#include <setjmp.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
jmp_buf exc_env; /* Global exception environment. */
|
||||
|
||||
[[noreturn]] void ppc_exception_handler(Except_Type exception_type,
|
||||
uint32_t srr1_bits)
|
||||
{
|
||||
[[noreturn]] void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) {
|
||||
grab_exception = true;
|
||||
#ifdef PROFILER
|
||||
#ifdef PROFILER
|
||||
exceptions_performed++;
|
||||
#endif
|
||||
#endif
|
||||
bb_kind = BB_end_kind::BB_EXCEPTION;
|
||||
|
||||
switch(exception_type) {
|
||||
case Except_Type::EXC_SYSTEM_RESET:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0100;
|
||||
break;
|
||||
switch (exception_type) {
|
||||
case Except_Type::EXC_SYSTEM_RESET:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0100;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_MACHINE_CHECK:
|
||||
if (!(ppc_state.msr & 0x1000)) {
|
||||
/* TODO: handle internal checkstop */
|
||||
}
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0200;
|
||||
break;
|
||||
case Except_Type::EXC_MACHINE_CHECK:
|
||||
if (!(ppc_state.msr & 0x1000)) {
|
||||
/* TODO: handle internal checkstop */
|
||||
}
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0200;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_DSI:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0300;
|
||||
break;
|
||||
case Except_Type::EXC_DSI:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0300;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_ISI:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_next_instruction_address;
|
||||
ppc_next_instruction_address = 0x0400;
|
||||
break;
|
||||
case Except_Type::EXC_ISI:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_next_instruction_address;
|
||||
ppc_next_instruction_address = 0x0400;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_EXT_INT:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_next_instruction_address;
|
||||
ppc_next_instruction_address = 0x0500;
|
||||
break;
|
||||
case Except_Type::EXC_EXT_INT:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_next_instruction_address;
|
||||
ppc_next_instruction_address = 0x0500;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_ALIGNMENT:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0600;
|
||||
break;
|
||||
case Except_Type::EXC_ALIGNMENT:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0600;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_PROGRAM:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0700;
|
||||
break;
|
||||
case Except_Type::EXC_PROGRAM:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0700;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_NO_FPU:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0800;
|
||||
break;
|
||||
case Except_Type::EXC_NO_FPU:
|
||||
ppc_state.spr[SPR::SRR0] = ppc_state.pc & 0xFFFFFFFC;
|
||||
ppc_next_instruction_address = 0x0800;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_DECR:
|
||||
ppc_state.spr[SPR::SRR0] = (ppc_state.pc & 0xFFFFFFFC) + 4;
|
||||
ppc_next_instruction_address = 0x0900;
|
||||
break;
|
||||
case Except_Type::EXC_DECR:
|
||||
ppc_state.spr[SPR::SRR0] = (ppc_state.pc & 0xFFFFFFFC) + 4;
|
||||
ppc_next_instruction_address = 0x0900;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_SYSCALL:
|
||||
ppc_state.spr[SPR::SRR0] = (ppc_state.pc & 0xFFFFFFFC) + 4;
|
||||
ppc_next_instruction_address = 0x0C00;
|
||||
break;
|
||||
case Except_Type::EXC_SYSCALL:
|
||||
ppc_state.spr[SPR::SRR0] = (ppc_state.pc & 0xFFFFFFFC) + 4;
|
||||
ppc_next_instruction_address = 0x0C00;
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_TRACE:
|
||||
ppc_state.spr[SPR::SRR0] = (ppc_state.pc & 0xFFFFFFFC) + 4;
|
||||
ppc_next_instruction_address = 0x0D00;
|
||||
break;
|
||||
case Except_Type::EXC_TRACE:
|
||||
ppc_state.spr[SPR::SRR0] = (ppc_state.pc & 0xFFFFFFFC) + 4;
|
||||
ppc_next_instruction_address = 0x0D00;
|
||||
break;
|
||||
|
||||
default:
|
||||
//printf("Unknown exception occured: %X\n", exception_type);
|
||||
//exit(-1);
|
||||
break;
|
||||
default:
|
||||
// printf("Unknown exception occured: %X\n", exception_type);
|
||||
// exit(-1);
|
||||
break;
|
||||
}
|
||||
|
||||
ppc_state.spr[SPR::SRR1] = (ppc_state.msr & 0x0000FF73) | srr1_bits;
|
||||
ppc_state.msr &= 0xFFFB1041;
|
||||
/* copy MSR[ILE] to MSR[LE] */
|
||||
ppc_state.msr = (ppc_state.msr & 0xFFFFFFFE) |
|
||||
((ppc_state.msr >> 16) & 1);
|
||||
ppc_state.msr = (ppc_state.msr & 0xFFFFFFFE) | ((ppc_state.msr >> 16) & 1);
|
||||
|
||||
if (ppc_state.msr & 0x40) {
|
||||
ppc_next_instruction_address |= 0xFFF00000;
|
||||
@ -116,61 +113,59 @@ jmp_buf exc_env; /* Global exception environment. */
|
||||
}
|
||||
|
||||
|
||||
[[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) {
|
||||
std::string exc_descriptor;
|
||||
|
||||
switch(exception_type) {
|
||||
case Except_Type::EXC_SYSTEM_RESET:
|
||||
exc_descriptor = "System reset exception occured";
|
||||
break;
|
||||
switch (exception_type) {
|
||||
case Except_Type::EXC_SYSTEM_RESET:
|
||||
exc_descriptor = "System reset exception occured";
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_MACHINE_CHECK:
|
||||
exc_descriptor = "Machine check exception occured";
|
||||
break;
|
||||
case Except_Type::EXC_MACHINE_CHECK:
|
||||
exc_descriptor = "Machine check exception occured";
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_DSI:
|
||||
case Except_Type::EXC_ISI:
|
||||
if (ppc_state.spr[SPR::DSISR] & 0x40000000)
|
||||
exc_descriptor = "DSI/ISI exception: unmapped memory access";
|
||||
else if (ppc_state.spr[SPR::DSISR] & 0x08000000)
|
||||
exc_descriptor = "DSI/ISI exception: access protection violation";
|
||||
else {
|
||||
if (exception_type == Except_Type::EXC_DSI)
|
||||
exc_descriptor = "DSI exception";
|
||||
else
|
||||
exc_descriptor = "ISI exception";
|
||||
}
|
||||
break;
|
||||
case Except_Type::EXC_DSI:
|
||||
case Except_Type::EXC_ISI:
|
||||
if (ppc_state.spr[SPR::DSISR] & 0x40000000)
|
||||
exc_descriptor = "DSI/ISI exception: unmapped memory access";
|
||||
else if (ppc_state.spr[SPR::DSISR] & 0x08000000)
|
||||
exc_descriptor = "DSI/ISI exception: access protection violation";
|
||||
else {
|
||||
if (exception_type == Except_Type::EXC_DSI)
|
||||
exc_descriptor = "DSI exception";
|
||||
else
|
||||
exc_descriptor = "ISI exception";
|
||||
}
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_EXT_INT:
|
||||
exc_descriptor = "External interrupt exception occured";
|
||||
break;
|
||||
case Except_Type::EXC_EXT_INT:
|
||||
exc_descriptor = "External interrupt exception occured";
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_ALIGNMENT:
|
||||
exc_descriptor = "Alignment exception occured";
|
||||
break;
|
||||
case Except_Type::EXC_ALIGNMENT:
|
||||
exc_descriptor = "Alignment exception occured";
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_PROGRAM:
|
||||
exc_descriptor = "Program exception occured";
|
||||
break;
|
||||
case Except_Type::EXC_PROGRAM:
|
||||
exc_descriptor = "Program exception occured";
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_NO_FPU:
|
||||
exc_descriptor = "Floating-Point unavailable exception occured";
|
||||
break;
|
||||
case Except_Type::EXC_NO_FPU:
|
||||
exc_descriptor = "Floating-Point unavailable exception occured";
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_DECR:
|
||||
exc_descriptor = "Decrementer exception occured";
|
||||
break;
|
||||
case Except_Type::EXC_DECR:
|
||||
exc_descriptor = "Decrementer exception occured";
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_SYSCALL:
|
||||
exc_descriptor = "Syscall exception occured";
|
||||
break;
|
||||
case Except_Type::EXC_SYSCALL:
|
||||
exc_descriptor = "Syscall exception occured";
|
||||
break;
|
||||
|
||||
case Except_Type::EXC_TRACE:
|
||||
exc_descriptor = "Trace exception occured";
|
||||
break;
|
||||
case Except_Type::EXC_TRACE:
|
||||
exc_descriptor = "Trace exception occured";
|
||||
break;
|
||||
}
|
||||
|
||||
throw std::invalid_argument(exc_descriptor);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,20 +21,20 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// 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 "ppcmmu.h"
|
||||
#include <array>
|
||||
#include <cfenv>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#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_b;
|
||||
uint64_t ppc_result64_c;
|
||||
@ -48,7 +48,7 @@ double ppc_dblresult64_d;
|
||||
double snan = std::numeric_limits<double>::signaling_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) {
|
||||
return ppc_state.fpr[reg].dbl64_r;
|
||||
@ -62,8 +62,7 @@ void ppc_store_sfpresult(bool int_rep) {
|
||||
if (int_rep) {
|
||||
ppc_state.fpr[reg_d].int64_r = 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].int64_r = *(uint64_t*)&ppc_dblresult64_d;
|
||||
}
|
||||
@ -73,8 +72,7 @@ void ppc_store_dfpresult(bool int_rep) {
|
||||
if (int_rep) {
|
||||
ppc_state.fpr[reg_d].int64_r = 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].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;
|
||||
if (int_rep) {
|
||||
ppc_result64_b = ppc_state.fpr[reg_b].int64_r;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_dblresult64_b = ppc_state.fpr[reg_b].dbl64_r;
|
||||
}
|
||||
}
|
||||
@ -96,32 +93,31 @@ void ppc_grab_regsfpdiab(bool int_rep) {
|
||||
reg_a = (ppc_cur_instruction >> 16) & 31;
|
||||
reg_b = (ppc_cur_instruction >> 11) & 31;
|
||||
if (int_rep == true) {
|
||||
|
||||
}
|
||||
ppc_result_a = ppc_state.gpr[reg_a];
|
||||
ppc_result_b = ppc_state.gpr[reg_b];
|
||||
}
|
||||
|
||||
void ppc_grab_regsfpdia(bool int_rep) {
|
||||
reg_d = (ppc_cur_instruction >> 21) & 31;
|
||||
reg_a = (ppc_cur_instruction >> 16) & 31;
|
||||
reg_d = (ppc_cur_instruction >> 21) & 31;
|
||||
reg_a = (ppc_cur_instruction >> 16) & 31;
|
||||
ppc_result_a = ppc_state.gpr[reg_a];
|
||||
}
|
||||
|
||||
void ppc_grab_regsfpsia(bool int_rep) {
|
||||
reg_s = (ppc_cur_instruction >> 21) & 31;
|
||||
reg_a = (ppc_cur_instruction >> 16) & 31;
|
||||
reg_s = (ppc_cur_instruction >> 21) & 31;
|
||||
reg_a = (ppc_cur_instruction >> 16) & 31;
|
||||
ppc_result_d = ppc_state.gpr[reg_s];
|
||||
ppc_result_a = ppc_state.gpr[reg_a];
|
||||
}
|
||||
|
||||
void ppc_grab_regsfpsiab(bool int_rep) {
|
||||
reg_s = (ppc_cur_instruction >> 21) & 31;
|
||||
reg_a = (ppc_cur_instruction >> 16) & 31;
|
||||
reg_b = (ppc_cur_instruction >> 11) & 31;
|
||||
reg_s = (ppc_cur_instruction >> 21) & 31;
|
||||
reg_a = (ppc_cur_instruction >> 16) & 31;
|
||||
reg_b = (ppc_cur_instruction >> 11) & 31;
|
||||
ppc_result64_d = ppc_state.fpr[reg_s].int64_r;
|
||||
ppc_result_a = ppc_state.gpr[reg_a];
|
||||
ppc_result_b = ppc_state.gpr[reg_b];
|
||||
ppc_result_a = ppc_state.gpr[reg_a];
|
||||
ppc_result_b = ppc_state.gpr[reg_b];
|
||||
}
|
||||
|
||||
void ppc_grab_regsfpsab(bool int_rep) {
|
||||
@ -132,8 +128,7 @@ void ppc_grab_regsfpsab(bool int_rep) {
|
||||
ppc_result64_d = ppc_state.fpr[reg_s].int64_r;
|
||||
ppc_result64_a = ppc_state.fpr[reg_a].int64_r;
|
||||
ppc_result64_b = ppc_state.fpr[reg_b].int64_r;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_dblresult64_d = fp_return_double(reg_s);
|
||||
ppc_dblresult64_a = fp_return_double(reg_a);
|
||||
ppc_dblresult64_c = fp_return_double(reg_c);
|
||||
@ -147,8 +142,7 @@ void ppc_grab_regsfpdab(bool int_rep) {
|
||||
if (int_rep) {
|
||||
ppc_result64_a = fp_return_uint64(reg_a);
|
||||
ppc_result64_b = fp_return_uint64(reg_b);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_dblresult64_a = fp_return_double(reg_a);
|
||||
ppc_dblresult64_b = fp_return_double(reg_b);
|
||||
}
|
||||
@ -161,8 +155,7 @@ void ppc_grab_regsfpdac(bool int_rep) {
|
||||
if (int_rep) {
|
||||
ppc_result64_a = fp_return_uint64(reg_a);
|
||||
ppc_result64_c = fp_return_uint64(reg_c);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_dblresult64_a = fp_return_double(reg_a);
|
||||
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_b = fp_return_uint64(reg_b);
|
||||
ppc_result64_c = fp_return_uint64(reg_c);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_dblresult64_a = fp_return_double(reg_a);
|
||||
ppc_dblresult64_b = fp_return_double(reg_b);
|
||||
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) {
|
||||
ppc_state.fpr[reg_d].int64_r = entry;
|
||||
ppc_state.fpr[reg_d].dbl64_r = (double)entry;
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
if (f >= 0.0) {
|
||||
return (int32_t)(int64_t)(f + 0.5);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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_toggle_fpscr_fex();
|
||||
return true;
|
||||
}
|
||||
else if ((input_a == 0) & (input_b == 0)) {
|
||||
} else if ((input_a == 0) & (input_b == 0)) {
|
||||
ppc_state.fpscr |= 0x80200000;
|
||||
ppc_toggle_fpscr_fex();
|
||||
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:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
uint32_t exp_a = (input_a >> 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_toggle_fpscr_fex();
|
||||
return true;
|
||||
}
|
||||
else if ((input_a == 0) & (input_b == 0)) {
|
||||
} else if ((input_a == 0) & (input_b == 0)) {
|
||||
ppc_state.fpscr |= 0x80200000;
|
||||
ppc_toggle_fpscr_fex();
|
||||
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) {
|
||||
|
||||
bool confirm_ov = (bool)std::fetestexcept(FE_OVERFLOW);
|
||||
|
||||
if (confirm_ov) {
|
||||
@ -362,15 +348,12 @@ void fpresult_update(uint64_t set_result, bool confirm_arc) {
|
||||
|
||||
if (set_result == 0) {
|
||||
ppc_state.fpscr |= 0x2000;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (set_result < 0) {
|
||||
ppc_state.fpscr |= 0x8000;
|
||||
}
|
||||
else if (set_result > 0) {
|
||||
} else if (set_result > 0) {
|
||||
ppc_state.fpscr |= 0x4000;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_state.fpscr |= 0x1000;
|
||||
}
|
||||
}
|
||||
@ -378,9 +361,7 @@ void fpresult_update(uint64_t set_result, bool confirm_arc) {
|
||||
}
|
||||
|
||||
void ppc_frsqrte_result() {
|
||||
|
||||
if (ppc_result64_d & 0x007FF000000000000UL) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,7 +370,7 @@ void ppc_changecrf1() {
|
||||
ppc_state.cr |= (ppc_state.fpscr & 0xF0000000) >> 4;
|
||||
}
|
||||
|
||||
//Floating Point Arithmetic
|
||||
// Floating Point Arithmetic
|
||||
void ppc_fadd() {
|
||||
ppc_grab_regsfpdab(false);
|
||||
|
||||
@ -585,7 +566,7 @@ void ppc_fadds() {
|
||||
|
||||
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) {
|
||||
float intermediate = (float)ppc_dblresult64_a + (float)ppc_dblresult64_b;
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
}
|
||||
@ -595,7 +576,7 @@ void ppc_faddsdot() {
|
||||
|
||||
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 58)) {
|
||||
float intermediate = (float)ppc_dblresult64_a + (float)ppc_dblresult64_b;
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
|
||||
@ -607,7 +588,7 @@ void ppc_fsubs() {
|
||||
|
||||
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 56)) {
|
||||
float intermediate = (float)ppc_dblresult64_a - (float)ppc_dblresult64_b;
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
}
|
||||
@ -617,7 +598,7 @@ void ppc_fsubsdot() {
|
||||
|
||||
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 56)) {
|
||||
float intermediate = (float)ppc_dblresult64_a - (float)ppc_dblresult64_b;
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
|
||||
@ -629,7 +610,7 @@ void ppc_fmults() {
|
||||
|
||||
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 50)) {
|
||||
float intermediate = (float)ppc_dblresult64_a * (float)ppc_dblresult64_b;
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
}
|
||||
@ -638,9 +619,8 @@ void ppc_fmultsdot() {
|
||||
ppc_grab_regsfpdac(false);
|
||||
|
||||
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 50)) {
|
||||
|
||||
float intermediate = (float)ppc_dblresult64_a * (float)ppc_dblresult64_b;
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
ppc_changecrf1();
|
||||
@ -651,7 +631,7 @@ void ppc_fdivs() {
|
||||
|
||||
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 36)) {
|
||||
float intermediate = (float)ppc_dblresult64_a / (float)ppc_dblresult64_b;
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
}
|
||||
@ -661,7 +641,7 @@ void ppc_fdivsdot() {
|
||||
|
||||
if (!ppc_confirm_inf_nan(reg_a, reg_b, true, 36)) {
|
||||
float intermediate = (float)ppc_dblresult64_a / (float)ppc_dblresult64_b;
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_dblresult64_d = static_cast<double>(intermediate);
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
|
||||
@ -682,7 +662,6 @@ void ppc_fmadds() {
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ppc_fmaddsdot() {
|
||||
@ -717,8 +696,6 @@ void ppc_fmsubs() {
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ppc_fmsubsdot() {
|
||||
@ -793,7 +770,6 @@ void ppc_fnmsubs() {
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ppc_fnmsubsdot() {
|
||||
@ -873,8 +849,7 @@ void ppc_fsel() {
|
||||
|
||||
if (ppc_dblresult64_a >= 0.0) {
|
||||
ppc_dblresult64_d = ppc_dblresult64_c;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_dblresult64_d = ppc_dblresult64_b;
|
||||
}
|
||||
|
||||
@ -886,8 +861,7 @@ void ppc_fseldot() {
|
||||
|
||||
if (ppc_dblresult64_a >= 0.0) {
|
||||
ppc_dblresult64_d = ppc_dblresult64_c;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_dblresult64_d = ppc_dblresult64_b;
|
||||
}
|
||||
|
||||
@ -914,7 +888,7 @@ void ppc_fsqrts() {
|
||||
test += 127 << 23;
|
||||
test >>= 1;
|
||||
uint64_t* pre_final = (uint64_t*)&test;
|
||||
ppc_result64_d = *pre_final;
|
||||
ppc_result64_d = *pre_final;
|
||||
ppc_store_dfpresult(true);
|
||||
}
|
||||
|
||||
@ -924,7 +898,7 @@ void ppc_fsqrtsdot() {
|
||||
test += 127 << 23;
|
||||
test >>= 1;
|
||||
uint64_t* pre_final = (uint64_t*)&test;
|
||||
ppc_result64_d = *pre_final;
|
||||
ppc_result64_d = *pre_final;
|
||||
ppc_store_dfpresult(true);
|
||||
ppc_changecrf1();
|
||||
}
|
||||
@ -954,16 +928,16 @@ void ppc_frsqrtedot() {
|
||||
|
||||
void ppc_frsp() {
|
||||
ppc_grab_regsfpdb(false);
|
||||
double testd2 = (double)ppc_result64_b;
|
||||
float testf2 = (float)testd2;
|
||||
double testd2 = (double)ppc_result64_b;
|
||||
float testf2 = (float)testd2;
|
||||
ppc_dblresult64_d = (double)testf2;
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
|
||||
void ppc_frspdot() {
|
||||
ppc_grab_regsfpdb(false);
|
||||
double testd2 = (double)ppc_result64_b;
|
||||
float testf2 = (float)testd2;
|
||||
double testd2 = (double)ppc_result64_b;
|
||||
float testf2 = (float)testd2;
|
||||
ppc_dblresult64_d = (double)testf2;
|
||||
ppc_store_dfpresult(false);
|
||||
ppc_changecrf1();
|
||||
@ -971,16 +945,16 @@ void ppc_frspdot() {
|
||||
|
||||
void ppc_fres() {
|
||||
ppc_grab_regsfpdb(false);
|
||||
float testf2 = (float)ppc_dblresult64_b;
|
||||
testf2 = 1 / testf2;
|
||||
float testf2 = (float)ppc_dblresult64_b;
|
||||
testf2 = 1 / testf2;
|
||||
ppc_dblresult64_d = (double)testf2;
|
||||
ppc_store_dfpresult(false);
|
||||
}
|
||||
|
||||
void ppc_fresdot() {
|
||||
ppc_grab_regsfpdb(false);
|
||||
float testf2 = (float)ppc_dblresult64_b;
|
||||
testf2 = 1 / testf2;
|
||||
float testf2 = (float)ppc_dblresult64_b;
|
||||
testf2 = 1 / testf2;
|
||||
ppc_dblresult64_d = (double)testf2;
|
||||
ppc_store_dfpresult(false);
|
||||
ppc_changecrf1();
|
||||
@ -1001,7 +975,6 @@ void ppc_fctiw() {
|
||||
}
|
||||
|
||||
ppc_store_dfpresult(true);
|
||||
|
||||
}
|
||||
|
||||
void ppc_fctiwdot() {
|
||||
@ -1037,7 +1010,7 @@ void ppc_fctiwzdot() {
|
||||
ppc_changecrf1();
|
||||
}
|
||||
|
||||
//Floating Point Store and Load
|
||||
// Floating Point Store and Load
|
||||
|
||||
void ppc_lfs() {
|
||||
ppc_grab_regsfpdia(true);
|
||||
@ -1054,11 +1027,10 @@ void ppc_lfsu() {
|
||||
ppc_effective_address = (int32_t)((int16_t)(ppc_cur_instruction & 0xFFFF));
|
||||
ppc_effective_address += (reg_a > 0) ? ppc_result_a : 0;
|
||||
ppc_result64_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_dfpresult(true);
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
||||
}
|
||||
}
|
||||
@ -1066,7 +1038,7 @@ void ppc_lfsu() {
|
||||
void ppc_lfsx() {
|
||||
ppc_grab_regsfpdiab(true);
|
||||
ppc_effective_address = (reg_a == 0) ? ppc_result_b : ppc_result_a + ppc_result_b;
|
||||
ppc_result64_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_result64_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_store_dfpresult(true);
|
||||
}
|
||||
|
||||
@ -1074,12 +1046,11 @@ void ppc_lfsux() {
|
||||
ppc_grab_regsfpdiab(true);
|
||||
if (reg_a == 0) {
|
||||
ppc_effective_address = ppc_result_a + ppc_result_b;
|
||||
ppc_result64_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_result64_d = mem_grab_dword(ppc_effective_address);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_dfpresult(true);
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
||||
}
|
||||
}
|
||||
@ -1101,8 +1072,7 @@ void ppc_lfdu() {
|
||||
ppc_store_dfpresult(true);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ppc_exception_handler(Except_Type::EXC_PROGRAM, 0x20000);
|
||||
}
|
||||
}
|
||||
@ -1118,12 +1088,11 @@ void ppc_lfdux() {
|
||||
ppc_grab_regsfpdiab(true);
|
||||
if (reg_a == 0) {
|
||||
ppc_effective_address = ppc_result_a + ppc_result_b;
|
||||
ppc_result64_d = mem_grab_qword(ppc_effective_address);
|
||||
ppc_result64_d = mem_grab_qword(ppc_effective_address);
|
||||
ppc_store_dfpresult(true);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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));
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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));
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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);
|
||||
ppc_result_a = ppc_effective_address;
|
||||
ppc_store_result_rega();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
|
||||
//Floating Point Register Transfer
|
||||
// Floating Point Register Transfer
|
||||
|
||||
void ppc_fmr() {
|
||||
ppc_grab_regsfpdb(true);
|
||||
@ -1241,7 +1206,7 @@ void ppc_mffsdot() {
|
||||
}
|
||||
|
||||
void ppc_mtfsf() {
|
||||
reg_b = (ppc_cur_instruction >> 11) & 31;
|
||||
reg_b = (ppc_cur_instruction >> 11) & 31;
|
||||
uint32_t fm_mask = (ppc_cur_instruction >> 17) & 255;
|
||||
crm += ((fm_mask & 1) == 1) ? 0xF0000000 : 0x00000000;
|
||||
crm += (((fm_mask >> 1) & 1) == 1) ? 0x0F000000 : 0x00000000;
|
||||
@ -1252,11 +1217,11 @@ void ppc_mtfsf() {
|
||||
crm += (((fm_mask >> 6) & 1) == 1) ? 0x000000F0 : 0x00000000;
|
||||
crm += (((fm_mask >> 7) & 1) == 1) ? 0x0000000F : 0x00000000;
|
||||
uint32_t quickfprval = (uint32_t)ppc_state.fpr[reg_b].int64_r;
|
||||
ppc_state.fpscr = (quickfprval & crm) | (quickfprval & ~(crm));
|
||||
ppc_state.fpscr = (quickfprval & crm) | (quickfprval & ~(crm));
|
||||
}
|
||||
|
||||
void ppc_mtfsfdot() {
|
||||
reg_b = (ppc_cur_instruction >> 11) & 31;
|
||||
reg_b = (ppc_cur_instruction >> 11) & 31;
|
||||
uint32_t fm_mask = (ppc_cur_instruction >> 17) & 255;
|
||||
crm += ((fm_mask & 1) == 1) ? 0xF0000000 : 0x00000000;
|
||||
crm += (((fm_mask >> 1) & 1) == 1) ? 0x0F000000 : 0x00000000;
|
||||
@ -1267,22 +1232,24 @@ void ppc_mtfsfdot() {
|
||||
crm += (((fm_mask >> 6) & 1) == 1) ? 0x000000F0 : 0x00000000;
|
||||
crm += (((fm_mask >> 7) & 1) == 1) ? 0x0000000F : 0x00000000;
|
||||
uint32_t quickfprval = (uint32_t)ppc_state.fpr[reg_b].int64_r;
|
||||
ppc_state.fpscr = (quickfprval & crm) | (quickfprval & ~(crm));
|
||||
ppc_state.fpscr = (quickfprval & crm) | (quickfprval & ~(crm));
|
||||
ppc_fp_changecrf1();
|
||||
}
|
||||
|
||||
void ppc_mtfsfi() {
|
||||
ppc_result_b = (ppc_cur_instruction >> 11) & 15;
|
||||
crf_d = (ppc_cur_instruction >> 23) & 7;
|
||||
crf_d = crf_d << 2;
|
||||
ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) | ((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
|
||||
ppc_result_b = (ppc_cur_instruction >> 11) & 15;
|
||||
crf_d = (ppc_cur_instruction >> 23) & 7;
|
||||
crf_d = crf_d << 2;
|
||||
ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) |
|
||||
((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
|
||||
}
|
||||
|
||||
void ppc_mtfsfidot() {
|
||||
ppc_result_b = (ppc_cur_instruction >> 11) & 15;
|
||||
crf_d = (ppc_cur_instruction >> 23) & 7;
|
||||
crf_d = crf_d << 2;
|
||||
ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) | ((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
|
||||
ppc_result_b = (ppc_cur_instruction >> 11) & 15;
|
||||
crf_d = (ppc_cur_instruction >> 23) & 7;
|
||||
crf_d = crf_d << 2;
|
||||
ppc_state.fpscr = (ppc_state.cr & ~(0xF0000000UL >> crf_d)) |
|
||||
((ppc_state.spr[SPR::XER] & 0xF0000000UL) >> crf_d);
|
||||
ppc_fp_changecrf1();
|
||||
}
|
||||
|
||||
@ -1317,14 +1284,15 @@ void ppc_mtfsb1dot() {
|
||||
}
|
||||
|
||||
void ppc_mcrfs() {
|
||||
crf_d = (ppc_cur_instruction >> 23) & 7;
|
||||
crf_d = crf_d << 2;
|
||||
crf_s = (ppc_cur_instruction >> 18) & 7;
|
||||
crf_s = crf_d << 2;
|
||||
ppc_state.cr = ~(ppc_state.cr & ((15 << (28 - crf_d)))) & (ppc_state.fpscr & (15 << (28 - crf_s)));
|
||||
crf_d = (ppc_cur_instruction >> 23) & 7;
|
||||
crf_d = crf_d << 2;
|
||||
crf_s = (ppc_cur_instruction >> 18) & 7;
|
||||
crf_s = crf_d << 2;
|
||||
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() {
|
||||
ppc_grab_regsfpsab(true);
|
||||
@ -1339,14 +1307,11 @@ void ppc_fcmpo() {
|
||||
|
||||
if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
|
||||
cmp_c |= 0x01;
|
||||
}
|
||||
else if (db_test_a < db_test_b) {
|
||||
} else if (db_test_a < db_test_b) {
|
||||
cmp_c |= 0x08;
|
||||
}
|
||||
else if (db_test_a > db_test_b) {
|
||||
} else if (db_test_a > db_test_b) {
|
||||
cmp_c |= 0x04;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
cmp_c |= 0x02;
|
||||
}
|
||||
|
||||
@ -1358,11 +1323,9 @@ void ppc_fcmpo() {
|
||||
if (ppc_state.fpscr & 0x80) {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ppc_fcmpu() {
|
||||
@ -1378,14 +1341,11 @@ void ppc_fcmpu() {
|
||||
|
||||
if (std::isnan(db_test_a) || std::isnan(db_test_b)) {
|
||||
cmp_c |= 0x01;
|
||||
}
|
||||
else if (db_test_a < db_test_b) {
|
||||
} else if (db_test_a < db_test_b) {
|
||||
cmp_c |= 0x08;
|
||||
}
|
||||
else if (db_test_a > db_test_b) {
|
||||
} else if (db_test_a > db_test_b) {
|
||||
cmp_c |= 0x04;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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
|
||||
|
||||
#include "ppcemu.h"
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include "ppcemu.h"
|
||||
|
||||
void ppc_psq_l(){
|
||||
void ppc_psq_l() {
|
||||
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void ppc_psq_lu(){
|
||||
void ppc_psq_lu() {
|
||||
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void ppc_psq_st(){
|
||||
void ppc_psq_st() {
|
||||
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void ppc_psq_stu(){
|
||||
void ppc_psq_stu() {
|
||||
printf("Hello. There's no GameCube emulation...yet. Goodbye.");
|
||||
exit(0);
|
||||
}
|
||||
|
@ -28,193 +28,173 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
- 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 "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. */
|
||||
void (*mmu_exception_handler)(Except_Type exception_type, uint32_t srr1_bits);
|
||||
|
||||
/** PowerPC-style MMU BAT arrays (NULL initialization isn't prescribed). */
|
||||
PPC_BAT_entry ibat_array[4] = { {0} };
|
||||
PPC_BAT_entry dbat_array[4] = { {0} };
|
||||
PPC_BAT_entry ibat_array[4] = {{0}};
|
||||
PPC_BAT_entry dbat_array[4] = {{0}};
|
||||
|
||||
/** remember recently used physical memory regions for quicker translation. */
|
||||
AddressMapEntry last_read_area = { 0 };
|
||||
AddressMapEntry last_write_area = { 0 };
|
||||
AddressMapEntry last_exec_area = { 0 };
|
||||
AddressMapEntry last_ptab_area = { 0 };
|
||||
AddressMapEntry last_dma_area = { 0 };
|
||||
AddressMapEntry last_read_area = {0};
|
||||
AddressMapEntry last_write_area = {0};
|
||||
AddressMapEntry last_exec_area = {0};
|
||||
AddressMapEntry last_ptab_area = {0};
|
||||
AddressMapEntry last_dma_area = {0};
|
||||
|
||||
|
||||
/* macro for generating code reading from physical memory */
|
||||
#define READ_PHYS_MEM(ENTRY, ADDR, OP, SIZE, UNVAL) \
|
||||
{ \
|
||||
if ((ADDR) >= (ENTRY).start && ((ADDR) + (SIZE)) <= (ENTRY).end) { \
|
||||
ret = OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start)); \
|
||||
} else { \
|
||||
AddressMapEntry* entry = mem_ctrl_instance->find_range((ADDR)); \
|
||||
if (entry) { \
|
||||
if (entry->type & (RT_ROM | RT_RAM)) { \
|
||||
(ENTRY).start = entry->start; \
|
||||
(ENTRY).end = entry->end; \
|
||||
(ENTRY).mem_ptr = entry->mem_ptr; \
|
||||
ret = OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start)); \
|
||||
} \
|
||||
else if (entry->type & RT_MMIO) { \
|
||||
ret = entry->devobj->read(entry->start, (ADDR) - entry->start, \
|
||||
(SIZE)); \
|
||||
} \
|
||||
else { \
|
||||
LOG_F(ERROR, "Please check your address map! \n"); \
|
||||
ret = (UNVAL); \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
LOG_F(WARNING, "Read from unmapped memory at 0x%08X!\n", (ADDR)); \
|
||||
ret = (UNVAL); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#define READ_PHYS_MEM(ENTRY, ADDR, OP, SIZE, UNVAL) \
|
||||
{ \
|
||||
if ((ADDR) >= (ENTRY).start && ((ADDR) + (SIZE)) <= (ENTRY).end) { \
|
||||
ret = OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start)); \
|
||||
} else { \
|
||||
AddressMapEntry* entry = mem_ctrl_instance->find_range((ADDR)); \
|
||||
if (entry) { \
|
||||
if (entry->type & (RT_ROM | RT_RAM)) { \
|
||||
(ENTRY).start = entry->start; \
|
||||
(ENTRY).end = entry->end; \
|
||||
(ENTRY).mem_ptr = entry->mem_ptr; \
|
||||
ret = OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start)); \
|
||||
} else if (entry->type & RT_MMIO) { \
|
||||
ret = entry->devobj->read(entry->start, (ADDR)-entry->start, (SIZE)); \
|
||||
} else { \
|
||||
LOG_F(ERROR, "Please check your address map! \n"); \
|
||||
ret = (UNVAL); \
|
||||
} \
|
||||
} else { \
|
||||
LOG_F(WARNING, "Read from unmapped memory at 0x%08X!\n", (ADDR)); \
|
||||
ret = (UNVAL); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/* macro for generating code writing to physical memory */
|
||||
#define WRITE_PHYS_MEM(ENTRY, ADDR, OP, VAL, SIZE) \
|
||||
{ \
|
||||
if ((ADDR) >= (ENTRY).start && ((ADDR) + (SIZE)) <= (ENTRY).end) { \
|
||||
OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start), (VAL)); \
|
||||
} else { \
|
||||
AddressMapEntry* entry = mem_ctrl_instance->find_range((ADDR)); \
|
||||
if (entry) { \
|
||||
if (entry->type & RT_RAM) { \
|
||||
(ENTRY).start = entry->start; \
|
||||
(ENTRY).end = entry->end; \
|
||||
(ENTRY).mem_ptr = entry->mem_ptr; \
|
||||
OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start), (VAL)); \
|
||||
} \
|
||||
else if (entry->type & RT_MMIO) { \
|
||||
entry->devobj->write(entry->start, (ADDR) - entry->start, \
|
||||
(VAL), (SIZE)); \
|
||||
} \
|
||||
else { \
|
||||
LOG_F(ERROR, "Please check your address map!\n"); \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
LOG_F(WARNING, "Write to unmapped memory at 0x%08X!\n", (ADDR)); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#define WRITE_PHYS_MEM(ENTRY, ADDR, OP, VAL, SIZE) \
|
||||
{ \
|
||||
if ((ADDR) >= (ENTRY).start && ((ADDR) + (SIZE)) <= (ENTRY).end) { \
|
||||
OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start), (VAL)); \
|
||||
} else { \
|
||||
AddressMapEntry* entry = mem_ctrl_instance->find_range((ADDR)); \
|
||||
if (entry) { \
|
||||
if (entry->type & RT_RAM) { \
|
||||
(ENTRY).start = entry->start; \
|
||||
(ENTRY).end = entry->end; \
|
||||
(ENTRY).mem_ptr = entry->mem_ptr; \
|
||||
OP((ENTRY).mem_ptr + ((ADDR) - (ENTRY).start), (VAL)); \
|
||||
} else if (entry->type & RT_MMIO) { \
|
||||
entry->devobj->write(entry->start, (ADDR)-entry->start, (VAL), (SIZE)); \
|
||||
} else { \
|
||||
LOG_F(ERROR, "Please check your address map!\n"); \
|
||||
} \
|
||||
} else { \
|
||||
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) {
|
||||
return last_dma_area.mem_ptr + (addr - last_dma_area.start);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
AddressMapEntry* entry = mem_ctrl_instance->find_range(addr);
|
||||
if (entry && entry->type & (RT_ROM | RT_RAM)) {
|
||||
last_dma_area.start = entry->start;
|
||||
last_dma_area.end = entry->end;
|
||||
last_dma_area.mem_ptr = entry->mem_ptr;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
void ibat_update(uint32_t bat_reg)
|
||||
{
|
||||
void ibat_update(uint32_t bat_reg) {
|
||||
int upper_reg_num;
|
||||
uint32_t bl, lo_mask;
|
||||
PPC_BAT_entry* bat_entry;
|
||||
|
||||
upper_reg_num = bat_reg & 0xFFFFFFFE;
|
||||
|
||||
if (ppc_state.spr[upper_reg_num] & 3) { // is that BAT pair valid?
|
||||
if (ppc_state.spr[upper_reg_num] & 3) { // is that BAT pair valid?
|
||||
bat_entry = &ibat_array[(bat_reg - 528) >> 1];
|
||||
bl = (ppc_state.spr[upper_reg_num] >> 2) & 0x7FF;
|
||||
lo_mask = (bl << 17) | 0x1FFFF;
|
||||
bl = (ppc_state.spr[upper_reg_num] >> 2) & 0x7FF;
|
||||
lo_mask = (bl << 17) | 0x1FFFF;
|
||||
|
||||
bat_entry->access = ppc_state.spr[upper_reg_num] & 3;
|
||||
bat_entry->prot = ppc_state.spr[upper_reg_num + 1] & 3;
|
||||
bat_entry->access = ppc_state.spr[upper_reg_num] & 3;
|
||||
bat_entry->prot = ppc_state.spr[upper_reg_num + 1] & 3;
|
||||
bat_entry->lo_mask = lo_mask;
|
||||
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & ~lo_mask;
|
||||
bat_entry->bepi = ppc_state.spr[upper_reg_num] & ~lo_mask;
|
||||
bat_entry->bepi = ppc_state.spr[upper_reg_num] & ~lo_mask;
|
||||
}
|
||||
}
|
||||
|
||||
void dbat_update(uint32_t bat_reg)
|
||||
{
|
||||
void dbat_update(uint32_t bat_reg) {
|
||||
int upper_reg_num;
|
||||
uint32_t bl, lo_mask;
|
||||
PPC_BAT_entry* bat_entry;
|
||||
|
||||
upper_reg_num = bat_reg & 0xFFFFFFFE;
|
||||
|
||||
if (ppc_state.spr[upper_reg_num] & 3) { // is that BAT pair valid?
|
||||
if (ppc_state.spr[upper_reg_num] & 3) { // is that BAT pair valid?
|
||||
bat_entry = &dbat_array[(bat_reg - 536) >> 1];
|
||||
bl = (ppc_state.spr[upper_reg_num] >> 2) & 0x7FF;
|
||||
lo_mask = (bl << 17) | 0x1FFFF;
|
||||
bl = (ppc_state.spr[upper_reg_num] >> 2) & 0x7FF;
|
||||
lo_mask = (bl << 17) | 0x1FFFF;
|
||||
|
||||
bat_entry->access = ppc_state.spr[upper_reg_num] & 3;
|
||||
bat_entry->prot = ppc_state.spr[upper_reg_num + 1] & 3;
|
||||
bat_entry->access = ppc_state.spr[upper_reg_num] & 3;
|
||||
bat_entry->prot = ppc_state.spr[upper_reg_num + 1] & 3;
|
||||
bat_entry->lo_mask = lo_mask;
|
||||
bat_entry->phys_hi = ppc_state.spr[upper_reg_num + 1] & ~lo_mask;
|
||||
bat_entry->bepi = ppc_state.spr[upper_reg_num] & ~lo_mask;
|
||||
bat_entry->bepi = ppc_state.spr[upper_reg_num] & ~lo_mask;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
sdr1_val = ppc_state.spr[SPR::SDR1];
|
||||
|
||||
pteg_addr = sdr1_val & 0xFE000000;
|
||||
pteg_addr |= (sdr1_val & 0x01FF0000) |
|
||||
(((sdr1_val & 0x1FF) << 16) & ((hash & 0x7FC00) << 6));
|
||||
pteg_addr |= (sdr1_val & 0x01FF0000) | (((sdr1_val & 0x1FF) << 16) & ((hash & 0x7FC00) << 6));
|
||||
pteg_addr |= (hash & 0x3FF) << 6;
|
||||
|
||||
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);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
AddressMapEntry* entry = mem_ctrl_instance->find_range(pteg_addr);
|
||||
if (entry && entry->type & (RT_ROM | RT_RAM)) {
|
||||
last_ptab_area.start = entry->start;
|
||||
last_ptab_area.end = entry->end;
|
||||
last_ptab_area.mem_ptr = entry->mem_ptr;
|
||||
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);
|
||||
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,
|
||||
uint32_t vsid, uint16_t page_index, uint8_t pteg_num)
|
||||
{
|
||||
static bool search_pteg(
|
||||
uint8_t* pteg_addr, uint8_t** ret_pte_addr, uint32_t vsid, uint16_t page_index, uint8_t pteg_num) {
|
||||
/* construct PTE matching word */
|
||||
uint32_t pte_check = 0x80000000 | (vsid << 7) | (pteg_num << 6) |
|
||||
(page_index >> 10);
|
||||
uint32_t pte_check = 0x80000000 | (vsid << 7) | (pteg_num << 6) | (page_index >> 10);
|
||||
|
||||
#ifdef MMU_INTEGRITY_CHECKS
|
||||
/* PTEG integrity check that ensures that all matching PTEs have
|
||||
@ -229,11 +209,10 @@ 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");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* isolate RPN, WIMG and PP fields */
|
||||
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;
|
||||
}
|
||||
|
||||
static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch,
|
||||
unsigned msr_pr, int is_write)
|
||||
{
|
||||
static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch, unsigned msr_pr, int is_write) {
|
||||
uint32_t sr_val, page_index, pteg_hash1, vsid, pte_word2;
|
||||
unsigned key, pp;
|
||||
uint8_t* pte_addr;
|
||||
@ -259,7 +236,7 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch,
|
||||
sr_val = ppc_state.sr[(la >> 28) & 0x0F];
|
||||
if (sr_val & 0x80000000) {
|
||||
LOG_F(ERROR, "Direct-store segments not supported, LA=%0xX\n", la);
|
||||
exit(-1); // FIXME: ugly error handling, must be the proper exception!
|
||||
exit(-1); // FIXME: ugly error handling, must be the proper exception!
|
||||
}
|
||||
|
||||
/* instruction fetch from a no-execute segment will cause ISI exception */
|
||||
@ -269,16 +246,15 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch,
|
||||
|
||||
page_index = (la >> 12) & 0xFFFF;
|
||||
pteg_hash1 = (sr_val & 0x7FFFF) ^ page_index;
|
||||
vsid = sr_val & 0x0FFFFFF;
|
||||
vsid = sr_val & 0x0FFFFFF;
|
||||
|
||||
if (!search_pteg(calc_pteg_addr(pteg_hash1), &pte_addr, vsid, page_index, 0)) {
|
||||
if (!search_pteg(calc_pteg_addr(~pteg_hash1), &pte_addr, vsid, page_index, 1)) {
|
||||
if (is_instr_fetch) {
|
||||
mmu_exception_handler(Except_Type::EXC_ISI, 0x40000000);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
|
||||
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 */
|
||||
pp = pte_word2 & 3;
|
||||
@ -298,10 +274,9 @@ 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 (is_instr_fetch) {
|
||||
mmu_exception_handler(Except_Type::EXC_ISI, 0x08000000);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -318,11 +293,10 @@ static uint32_t page_address_translate(uint32_t la, bool is_instr_fetch,
|
||||
}
|
||||
|
||||
/** 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 */
|
||||
|
||||
bool bat_hit = false;
|
||||
bool bat_hit = false;
|
||||
unsigned msr_pr = !!(ppc_state.msr & 0x4000);
|
||||
|
||||
// Format: %XY
|
||||
@ -333,8 +307,7 @@ static uint32_t ppc_mmu_instr_translate(uint32_t la)
|
||||
for (int bat_index = 0; bat_index < 4; bat_index++) {
|
||||
PPC_BAT_entry* bat_entry = &ibat_array[bat_index];
|
||||
|
||||
if ((bat_entry->access & access_bits) &&
|
||||
((la & ~bat_entry->lo_mask) == bat_entry->bepi)) {
|
||||
if ((bat_entry->access & access_bits) && ((la & ~bat_entry->lo_mask) == bat_entry->bepi)) {
|
||||
bat_hit = true;
|
||||
|
||||
if (!bat_entry->prot) {
|
||||
@ -356,15 +329,14 @@ static uint32_t ppc_mmu_instr_translate(uint32_t la)
|
||||
}
|
||||
|
||||
/** 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
|
||||
mmu_translations_num++;
|
||||
#endif
|
||||
|
||||
uint32_t pa; /* translated physical address */
|
||||
|
||||
bool bat_hit = false;
|
||||
bool bat_hit = false;
|
||||
unsigned msr_pr = !!(ppc_state.msr & 0x4000);
|
||||
|
||||
// Format: %XY
|
||||
@ -375,13 +347,12 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write)
|
||||
for (int bat_index = 0; bat_index < 4; bat_index++) {
|
||||
PPC_BAT_entry* bat_entry = &dbat_array[bat_index];
|
||||
|
||||
if ((bat_entry->access & access_bits) &&
|
||||
((la & ~bat_entry->lo_mask) == bat_entry->bepi)) {
|
||||
if ((bat_entry->access & access_bits) && ((la & ~bat_entry->lo_mask) == bat_entry->bepi)) {
|
||||
bat_hit = true;
|
||||
|
||||
if (!bat_entry->prot || ((bat_entry->prot & 1) && is_write)) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -399,13 +370,12 @@ static uint32_t ppc_mmu_addr_translate(uint32_t la, int is_write)
|
||||
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);
|
||||
|
||||
if (((addr & 0xFFF) + size) > 0x1000) {
|
||||
LOG_F(ERROR, "SOS! Cross-page unaligned write, addr=%08X, size=%d\n", addr, size);
|
||||
exit(-1); //FIXME!
|
||||
exit(-1); // FIXME!
|
||||
} else {
|
||||
/* data address translation if enabled */
|
||||
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 */
|
||||
if (ppc_state.msr & 0x10) {
|
||||
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);
|
||||
}
|
||||
|
||||
void mem_write_word(uint32_t addr, uint16_t value)
|
||||
{
|
||||
void mem_write_word(uint32_t addr, uint16_t value) {
|
||||
if (addr & 1) {
|
||||
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);
|
||||
}
|
||||
|
||||
void mem_write_dword(uint32_t addr, uint32_t value)
|
||||
{
|
||||
void mem_write_dword(uint32_t addr, uint32_t value) {
|
||||
if (addr & 3) {
|
||||
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);
|
||||
}
|
||||
|
||||
void mem_write_qword(uint32_t addr, uint64_t value)
|
||||
{
|
||||
void mem_write_qword(uint32_t addr, uint64_t value) {
|
||||
if (addr & 7) {
|
||||
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 */
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
LOG_F(WARNING, "Attempt to read unaligned %d bytes from 0x%08X\n", size, addr);
|
||||
|
||||
if (((addr & 0xFFF) + size) > 0x1000) {
|
||||
LOG_F(ERROR, "SOS! Cross-page unaligned read, addr=%08X, size=%d\n", addr, size);
|
||||
exit(-1); //FIXME!
|
||||
exit(-1); // FIXME!
|
||||
} else {
|
||||
/* data address translation if enabled */
|
||||
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 */
|
||||
uint8_t mem_grab_byte(uint32_t addr)
|
||||
{
|
||||
uint8_t mem_grab_byte(uint32_t addr) {
|
||||
uint8_t ret;
|
||||
|
||||
/* data address translation if enabled */
|
||||
@ -514,8 +478,7 @@ uint8_t mem_grab_byte(uint32_t addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint16_t mem_grab_word(uint32_t addr)
|
||||
{
|
||||
uint16_t mem_grab_word(uint32_t addr) {
|
||||
uint16_t ret;
|
||||
|
||||
if (addr & 1) {
|
||||
@ -531,8 +494,7 @@ uint16_t mem_grab_word(uint32_t addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint32_t mem_grab_dword(uint32_t addr)
|
||||
{
|
||||
uint32_t mem_grab_dword(uint32_t addr) {
|
||||
uint32_t ret;
|
||||
|
||||
if (addr & 3) {
|
||||
@ -548,13 +510,12 @@ uint32_t mem_grab_dword(uint32_t addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t mem_grab_qword(uint32_t addr)
|
||||
{
|
||||
uint64_t mem_grab_qword(uint32_t addr) {
|
||||
uint64_t ret;
|
||||
|
||||
if (addr & 7) {
|
||||
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 */
|
||||
@ -566,8 +527,7 @@ uint64_t mem_grab_qword(uint32_t addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t* quickinstruction_translate(uint32_t addr)
|
||||
{
|
||||
uint8_t* quickinstruction_translate(uint32_t addr) {
|
||||
uint8_t* real_addr;
|
||||
|
||||
/* perform instruction address translation if enabled */
|
||||
@ -578,72 +538,67 @@ uint8_t* quickinstruction_translate(uint32_t addr)
|
||||
if (addr >= last_exec_area.start && addr <= last_exec_area.end) {
|
||||
real_addr = last_exec_area.mem_ptr + (addr - last_exec_area.start);
|
||||
ppc_set_cur_instruction(real_addr);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
AddressMapEntry* entry = mem_ctrl_instance->find_range(addr);
|
||||
if (entry && entry->type & (RT_ROM | RT_RAM)) {
|
||||
last_exec_area.start = entry->start;
|
||||
last_exec_area.end = entry->end;
|
||||
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);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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!
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
uint64_t ret_val;
|
||||
|
||||
/* save MMU-related CPU state */
|
||||
save_dsisr = ppc_state.spr[SPR::DSISR];
|
||||
save_dar = ppc_state.spr[SPR::DAR];
|
||||
save_dsisr = ppc_state.spr[SPR::DSISR];
|
||||
save_dar = ppc_state.spr[SPR::DAR];
|
||||
mmu_exception_handler = dbg_exception_handler;
|
||||
|
||||
try {
|
||||
switch(size) {
|
||||
case 1:
|
||||
ret_val = mem_grab_byte(virt_addr);
|
||||
break;
|
||||
case 2:
|
||||
ret_val = mem_grab_word(virt_addr);
|
||||
break;
|
||||
case 4:
|
||||
ret_val = mem_grab_dword(virt_addr);
|
||||
break;
|
||||
case 8:
|
||||
ret_val = mem_grab_qword(virt_addr);
|
||||
break;
|
||||
default:
|
||||
ret_val = mem_grab_byte(virt_addr);
|
||||
switch (size) {
|
||||
case 1:
|
||||
ret_val = mem_grab_byte(virt_addr);
|
||||
break;
|
||||
case 2:
|
||||
ret_val = mem_grab_word(virt_addr);
|
||||
break;
|
||||
case 4:
|
||||
ret_val = mem_grab_dword(virt_addr);
|
||||
break;
|
||||
case 8:
|
||||
ret_val = mem_grab_qword(virt_addr);
|
||||
break;
|
||||
default:
|
||||
ret_val = mem_grab_byte(virt_addr);
|
||||
}
|
||||
}
|
||||
catch (std::invalid_argument& exc) {
|
||||
} catch (std::invalid_argument& exc) {
|
||||
/* 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::DAR] = save_dar;
|
||||
ppc_state.spr[SPR::DAR] = save_dar;
|
||||
|
||||
/* rethrow MMU exception */
|
||||
throw exc;
|
||||
}
|
||||
|
||||
/* 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::DAR] = save_dar;
|
||||
ppc_state.spr[SPR::DAR] = save_dar;
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
void ppc_mmu_init()
|
||||
{
|
||||
void ppc_mmu_init() {
|
||||
mmu_exception_handler = ppc_exception_handler;
|
||||
}
|
||||
|
@ -24,38 +24,38 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef PPCMEMORY_H
|
||||
#define PPCMEMORY_H
|
||||
|
||||
#include <array>
|
||||
#include <cinttypes>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
/* Uncomment this to exhaustive MMU integrity checks. */
|
||||
//#define MMU_INTEGRITY_CHECKS
|
||||
|
||||
/** generic PowerPC BAT descriptor (MMU internal state) */
|
||||
typedef struct PPC_BAT_entry {
|
||||
uint8_t access; /* copy of Vs | Vp bits */
|
||||
uint8_t prot; /* copy of PP bits */
|
||||
uint32_t phys_hi; /* high-order bits for physical address generation */
|
||||
uint32_t lo_mask; /* mask for low-order logical address bits */
|
||||
uint32_t bepi; /* copy of Block effective page index */
|
||||
uint8_t access; /* copy of Vs | Vp bits */
|
||||
uint8_t prot; /* copy of PP bits */
|
||||
uint32_t phys_hi; /* high-order bits for physical address generation */
|
||||
uint32_t lo_mask; /* mask for low-order logical address bits */
|
||||
uint32_t bepi; /* copy of Block effective page index */
|
||||
} PPC_BAT_entry;
|
||||
|
||||
|
||||
extern void ibat_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 mem_write_byte(uint32_t addr, uint8_t value);
|
||||
extern void mem_write_word(uint32_t addr, uint16_t value);
|
||||
extern void mem_write_dword(uint32_t addr, uint32_t value);
|
||||
extern void mem_write_qword(uint32_t addr, uint64_t value);
|
||||
extern uint8_t mem_grab_byte(uint32_t addr);
|
||||
extern uint8_t mem_grab_byte(uint32_t addr);
|
||||
extern uint16_t mem_grab_word(uint32_t addr);
|
||||
extern uint32_t mem_grab_dword(uint32_t addr);
|
||||
extern uint64_t mem_grab_qword(uint32_t addr);
|
||||
extern uint64_t mem_read_dbg(uint32_t virt_addr, uint32_t size);
|
||||
extern uint8_t* quickinstruction_translate(uint32_t address_grab);
|
||||
|
||||
#endif // PPCMEMORY_H
|
||||
#endif // PPCMEMORY_H
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,72 +1,68 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../ppcemu.h"
|
||||
#include "../ppcdisasm.h"
|
||||
#include "../ppcemu.h"
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int ntested; /* number of tested instructions */
|
||||
int nfailed; /* number of failed instructions */
|
||||
|
||||
void xer_ov_test(string mnem, uint32_t opcode)
|
||||
{
|
||||
ppc_state.gpr[3] = 2;
|
||||
ppc_state.gpr[4] = 2;
|
||||
void xer_ov_test(string mnem, uint32_t opcode) {
|
||||
ppc_state.gpr[3] = 2;
|
||||
ppc_state.gpr[4] = 2;
|
||||
ppc_state.spr[SPR::XER] = 0xFFFFFFFF;
|
||||
ppc_cur_instruction = opcode;
|
||||
ppc_cur_instruction = opcode;
|
||||
ppc_main_opcode();
|
||||
if (ppc_state.spr[SPR::XER] & 0x40000000UL) {
|
||||
cout << "Invalid " << mnem << " emulation! XER[OV] should not be set."
|
||||
<< endl;
|
||||
cout << "Invalid " << mnem << " emulation! XER[OV] should not be set." << endl;
|
||||
nfailed++;
|
||||
}
|
||||
ntested++;
|
||||
}
|
||||
|
||||
void xer_update_test()
|
||||
{
|
||||
xer_ov_test("ADDCO", 0x7C632414);
|
||||
xer_ov_test("ADDCO.", 0x7C632415);
|
||||
xer_ov_test("ADDO", 0x7C632614);
|
||||
xer_ov_test("ADDO.", 0x7C632615);
|
||||
xer_ov_test("ADDEO", 0x7C632514);
|
||||
xer_ov_test("ADDEO.", 0x7C632515);
|
||||
xer_ov_test("ADDMEO", 0x7C6305D4);
|
||||
xer_ov_test("ADDMEO.", 0x7C6305D5);
|
||||
xer_ov_test("ADDZEO", 0x7C630594);
|
||||
xer_ov_test("ADDZEO.", 0x7C630595);
|
||||
xer_ov_test("DIVWO", 0x7C6327D6);
|
||||
xer_ov_test("DIVWO.", 0x7C6327D7);
|
||||
xer_ov_test("DIVWUO", 0x7C632796);
|
||||
xer_ov_test("DIVWUO.", 0x7C632797);
|
||||
xer_ov_test("MULLWO", 0x7C6325D6);
|
||||
xer_ov_test("MULLWO.", 0x7C6325D7);
|
||||
xer_ov_test("NEGO", 0x7C6304D0);
|
||||
xer_ov_test("NEGO.", 0x7C6304D1);
|
||||
xer_ov_test("SUBFO", 0x7C632450);
|
||||
xer_ov_test("SUBFO.", 0x7C632451);
|
||||
xer_ov_test("SUBFCO", 0x7C632410);
|
||||
xer_ov_test("SUBFCO.", 0x7C632411);
|
||||
xer_ov_test("SUBFEO", 0x7C632510);
|
||||
xer_ov_test("SUBFEO.", 0x7C632511);
|
||||
xer_ov_test("SUBFMEO", 0x7C6305D0);
|
||||
void xer_update_test() {
|
||||
xer_ov_test("ADDCO", 0x7C632414);
|
||||
xer_ov_test("ADDCO.", 0x7C632415);
|
||||
xer_ov_test("ADDO", 0x7C632614);
|
||||
xer_ov_test("ADDO.", 0x7C632615);
|
||||
xer_ov_test("ADDEO", 0x7C632514);
|
||||
xer_ov_test("ADDEO.", 0x7C632515);
|
||||
xer_ov_test("ADDMEO", 0x7C6305D4);
|
||||
xer_ov_test("ADDMEO.", 0x7C6305D5);
|
||||
xer_ov_test("ADDZEO", 0x7C630594);
|
||||
xer_ov_test("ADDZEO.", 0x7C630595);
|
||||
xer_ov_test("DIVWO", 0x7C6327D6);
|
||||
xer_ov_test("DIVWO.", 0x7C6327D7);
|
||||
xer_ov_test("DIVWUO", 0x7C632796);
|
||||
xer_ov_test("DIVWUO.", 0x7C632797);
|
||||
xer_ov_test("MULLWO", 0x7C6325D6);
|
||||
xer_ov_test("MULLWO.", 0x7C6325D7);
|
||||
xer_ov_test("NEGO", 0x7C6304D0);
|
||||
xer_ov_test("NEGO.", 0x7C6304D1);
|
||||
xer_ov_test("SUBFO", 0x7C632450);
|
||||
xer_ov_test("SUBFO.", 0x7C632451);
|
||||
xer_ov_test("SUBFCO", 0x7C632410);
|
||||
xer_ov_test("SUBFCO.", 0x7C632411);
|
||||
xer_ov_test("SUBFEO", 0x7C632510);
|
||||
xer_ov_test("SUBFEO.", 0x7C632511);
|
||||
xer_ov_test("SUBFMEO", 0x7C6305D0);
|
||||
xer_ov_test("SUBFMEO.", 0x7C6305D1);
|
||||
xer_ov_test("SUBFZEO", 0x7C630590);
|
||||
xer_ov_test("SUBFZEO", 0x7C630590);
|
||||
xer_ov_test("SUBFZEO.", 0x7C630591);
|
||||
}
|
||||
|
||||
/** testing vehicle */
|
||||
static void read_test_data()
|
||||
{
|
||||
string line, token;
|
||||
int i, lineno;
|
||||
static void read_test_data() {
|
||||
string line, token;
|
||||
int i, lineno;
|
||||
uint32_t opcode, dest, src1, src2, check_xer, check_cr;
|
||||
|
||||
ifstream tfstream("ppcinttests.csv");
|
||||
ifstream tfstream("ppcinttests.csv");
|
||||
if (!tfstream.is_open()) {
|
||||
cout << "Could not open tests CSV file. Exiting..." << endl;
|
||||
return;
|
||||
@ -74,7 +70,7 @@ static void read_test_data()
|
||||
|
||||
lineno = 0;
|
||||
|
||||
while(getline(tfstream, line)) {
|
||||
while (getline(tfstream, line)) {
|
||||
lineno++;
|
||||
|
||||
if (line.empty() || !line.rfind("#", 0))
|
||||
@ -84,7 +80,7 @@ static void read_test_data()
|
||||
|
||||
vector<string> tokens;
|
||||
|
||||
while(getline(lnstream, token, ',' )) {
|
||||
while (getline(lnstream, token, ',')) {
|
||||
tokens.push_back(token);
|
||||
}
|
||||
|
||||
@ -95,9 +91,9 @@ static void read_test_data()
|
||||
|
||||
opcode = stoul(tokens[1], NULL, 16);
|
||||
|
||||
dest = 0;
|
||||
src1 = 0;
|
||||
src2 = 0;
|
||||
dest = 0;
|
||||
src1 = 0;
|
||||
src2 = 0;
|
||||
check_xer = 0;
|
||||
check_cr = 0;
|
||||
|
||||
@ -113,16 +109,16 @@ static void read_test_data()
|
||||
} else if (tokens[i].rfind("CR=", 0) == 0) {
|
||||
check_cr = stoul(tokens[i].substr(3), NULL, 16);
|
||||
} else {
|
||||
cout << "Unknown parameter " << tokens[i] << " in line " << lineno <<
|
||||
". Exiting..." << endl;
|
||||
cout << "Unknown parameter " << tokens[i] << " in line " << lineno << ". Exiting..."
|
||||
<< endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
ppc_state.gpr[3] = src1;
|
||||
ppc_state.gpr[4] = src2;
|
||||
ppc_state.gpr[3] = src1;
|
||||
ppc_state.gpr[4] = src2;
|
||||
ppc_state.spr[SPR::XER] = 0;
|
||||
ppc_state.cr = 0;
|
||||
ppc_state.cr = 0;
|
||||
|
||||
ppc_cur_instruction = opcode;
|
||||
|
||||
@ -131,15 +127,13 @@ static void read_test_data()
|
||||
ntested++;
|
||||
|
||||
if ((tokens[0].rfind("CMP") && (ppc_state.gpr[3] != dest)) ||
|
||||
(ppc_state.spr[SPR::XER] != check_xer) ||
|
||||
(ppc_state.cr != check_cr)) {
|
||||
cout << "Mismatch: instr=" << tokens[0] << ", src1=0x" << hex << src1
|
||||
<< ", src2=0x" << hex << src2 << endl;
|
||||
cout << "expected: dest=0x" << hex << dest << ", XER=0x" << hex
|
||||
<< check_xer << ", CR=0x" << hex << check_cr << endl;
|
||||
cout << "got: dest=0x" << hex << ppc_state.gpr[3] << ", XER=0x"
|
||||
<< hex << ppc_state.spr[SPR::XER] << ", CR=0x" << hex
|
||||
<< ppc_state.cr << endl;
|
||||
(ppc_state.spr[SPR::XER] != check_xer) || (ppc_state.cr != check_cr)) {
|
||||
cout << "Mismatch: instr=" << tokens[0] << ", src1=0x" << hex << src1 << ", src2=0x"
|
||||
<< hex << src2 << endl;
|
||||
cout << "expected: dest=0x" << hex << dest << ", XER=0x" << hex << check_xer
|
||||
<< ", CR=0x" << hex << check_cr << endl;
|
||||
cout << "got: dest=0x" << hex << ppc_state.gpr[3] << ", XER=0x" << hex
|
||||
<< ppc_state.spr[SPR::XER] << ", CR=0x" << hex << ppc_state.cr << endl;
|
||||
cout << "Test file line #: " << dec << lineno << endl << endl;
|
||||
|
||||
nfailed++;
|
||||
@ -147,9 +141,7 @@ static void read_test_data()
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
int main() {
|
||||
cout << "Running DingusPPC emulator tests..." << endl << endl;
|
||||
|
||||
ntested = 0;
|
||||
|
@ -1,22 +1,21 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "../ppcdisasm.h"
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
/** testing vehicle */
|
||||
static vector<PPCDisasmContext> read_test_data()
|
||||
{
|
||||
string line, token;
|
||||
int i, lineno;
|
||||
static vector<PPCDisasmContext> read_test_data() {
|
||||
string line, token;
|
||||
int i, lineno;
|
||||
PPCDisasmContext ctx;
|
||||
vector<PPCDisasmContext> tstvec;
|
||||
|
||||
ifstream tfstream("ppcdisasmtest.csv");
|
||||
ifstream tfstream("ppcdisasmtest.csv");
|
||||
if (!tfstream.is_open()) {
|
||||
cout << "Could not open tests CSV file. Exiting..." << endl;
|
||||
return tstvec;
|
||||
@ -24,18 +23,18 @@ static vector<PPCDisasmContext> read_test_data()
|
||||
|
||||
lineno = 0;
|
||||
|
||||
while(getline(tfstream, line)) {
|
||||
while (getline(tfstream, line)) {
|
||||
lineno++;
|
||||
|
||||
if (line.empty() || !line.rfind("#", 0))
|
||||
continue; // skip empty/comment lines
|
||||
continue; // skip empty/comment lines
|
||||
|
||||
istringstream lnstream(line);
|
||||
|
||||
vector<string> tokens;
|
||||
|
||||
while(getline(lnstream, token, ',' )) {
|
||||
//cout << "Token: " << token << endl;
|
||||
while (getline(lnstream, token, ',')) {
|
||||
// cout << "Token: " << token << endl;
|
||||
tokens.push_back(token);
|
||||
}
|
||||
|
||||
@ -44,7 +43,7 @@ static vector<PPCDisasmContext> read_test_data()
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx = {0};
|
||||
ctx = {0};
|
||||
ctx.instr_addr = stoul(tokens[0], NULL, 16);
|
||||
ctx.instr_code = stoul(tokens[1], NULL, 16);
|
||||
|
||||
@ -64,7 +63,7 @@ static vector<PPCDisasmContext> read_test_data()
|
||||
|
||||
ctx.instr_str = idisasm.str();
|
||||
|
||||
//cout << idisasm.str() << endl;
|
||||
// cout << idisasm.str() << endl;
|
||||
|
||||
tstvec.push_back(ctx);
|
||||
}
|
||||
@ -72,8 +71,7 @@ static vector<PPCDisasmContext> read_test_data()
|
||||
return tstvec;
|
||||
}
|
||||
|
||||
int test_ppc_disasm()
|
||||
{
|
||||
int test_ppc_disasm() {
|
||||
int i, nfailed;
|
||||
PPCDisasmContext ctx;
|
||||
|
||||
@ -84,7 +82,7 @@ int test_ppc_disasm()
|
||||
nfailed = 0;
|
||||
|
||||
for (i = 0; i < testdata.size(); i++) {
|
||||
ctx = {0};
|
||||
ctx = {0};
|
||||
ctx.instr_addr = testdata[i].instr_addr;
|
||||
ctx.instr_code = testdata[i].instr_code;
|
||||
ctx.simplified = true;
|
||||
@ -92,14 +90,13 @@ int test_ppc_disasm()
|
||||
std::string disas = disassemble_single(&ctx);
|
||||
|
||||
if (disas != testdata[i].instr_str) {
|
||||
cout << "Mismatch found, expected={" << testdata[i].instr_str <<
|
||||
"}, got={" << disas << "}" << endl;
|
||||
cout << "Mismatch found, expected={" << testdata[i].instr_str << "}, got={" << disas
|
||||
<< "}" << endl;
|
||||
nfailed++;
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Tested " << testdata.size() << " instructions. Failed: " <<
|
||||
nfailed << "." << endl;
|
||||
cout << "Tested " << testdata.size() << " instructions. Failed: " << nfailed << "." << endl;
|
||||
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include "../cpu/ppc/ppcdisasm.h"
|
||||
#include "../cpu/ppc/ppcemu.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>
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
static uint32_t str2addr(string& addr_str)
|
||||
{
|
||||
static uint32_t str2addr(string& addr_str) {
|
||||
try {
|
||||
return stoul(addr_str, NULL, 0);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
} catch (invalid_argument& exc) {
|
||||
throw invalid_argument(string("Cannot convert ") + addr_str);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t str2num(string& num_str)
|
||||
{
|
||||
static uint32_t str2num(string& num_str) {
|
||||
try {
|
||||
return stol(num_str, NULL, 0);
|
||||
}
|
||||
catch (invalid_argument & exc) {
|
||||
} catch (invalid_argument& exc) {
|
||||
throw invalid_argument(string("Cannot convert ") + num_str);
|
||||
}
|
||||
}
|
||||
|
||||
static void show_help()
|
||||
{
|
||||
static void show_help() {
|
||||
cout << "Debugger commands:" << endl;
|
||||
cout << " step -- execute single instruction" << endl;
|
||||
cout << " si -- shortcut for step" << endl;
|
||||
@ -80,8 +75,7 @@ static void show_help()
|
||||
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;
|
||||
|
||||
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;
|
||||
bool is_char;
|
||||
uint32_t count, addr;
|
||||
@ -110,55 +103,52 @@ static void dump_mem(string& params)
|
||||
}
|
||||
|
||||
num_type_str = params.substr(0, params.find_first_of(","));
|
||||
addr_str = params.substr(params.find_first_of(",") + 1);
|
||||
addr_str = params.substr(params.find_first_of(",") + 1);
|
||||
|
||||
is_char = false;
|
||||
|
||||
switch(num_type_str.back()) {
|
||||
case 'b':
|
||||
case 'B':
|
||||
cell_size = 1;
|
||||
break;
|
||||
case 'w':
|
||||
case 'W':
|
||||
cell_size = 2;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
cell_size = 4;
|
||||
break;
|
||||
case 'q':
|
||||
case 'Q':
|
||||
cell_size = 8;
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
cell_size = 1;
|
||||
is_char = true;
|
||||
break;
|
||||
default:
|
||||
cout << "Invalid data type " << num_type_str << endl;
|
||||
return;
|
||||
switch (num_type_str.back()) {
|
||||
case 'b':
|
||||
case 'B':
|
||||
cell_size = 1;
|
||||
break;
|
||||
case 'w':
|
||||
case 'W':
|
||||
cell_size = 2;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
cell_size = 4;
|
||||
break;
|
||||
case 'q':
|
||||
case 'Q':
|
||||
cell_size = 8;
|
||||
break;
|
||||
case 'c':
|
||||
case 'C':
|
||||
cell_size = 1;
|
||||
is_char = true;
|
||||
break;
|
||||
default:
|
||||
cout << "Invalid data type " << num_type_str << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
num_type_str = num_type_str.substr(0, num_type_str.length() - 1);
|
||||
count = str2addr(num_type_str);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
count = str2addr(num_type_str);
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
addr = str2addr(addr_str);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
addr = str2addr(addr_str);
|
||||
} catch (invalid_argument& exc) {
|
||||
try {
|
||||
/* number conversion failed, trying reg name */
|
||||
addr = get_reg(addr_str);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
return;
|
||||
}
|
||||
@ -179,13 +169,11 @@ static void dump_mem(string& params)
|
||||
cout << (char)val;
|
||||
chars_per_line += cell_size;
|
||||
} else {
|
||||
cout << setw(cell_size * 2) << setfill('0') << uppercase <<
|
||||
hex << val << " ";
|
||||
cout << setw(cell_size * 2) << setfill('0') << uppercase << hex << val << " ";
|
||||
chars_per_line += cell_size * 2 + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
return;
|
||||
}
|
||||
@ -193,10 +181,8 @@ static void dump_mem(string& params)
|
||||
cout << endl << endl;
|
||||
}
|
||||
|
||||
void enter_debugger()
|
||||
{
|
||||
string inp, cmd, addr_str, expr_str, reg_expr, last_cmd, reg_value_str,
|
||||
inst_string, inst_num_str;
|
||||
void enter_debugger() {
|
||||
string inp, cmd, addr_str, expr_str, reg_expr, last_cmd, reg_value_str, inst_string, inst_num_str;
|
||||
uint32_t addr, inst_grab;
|
||||
std::stringstream ss;
|
||||
int log_level;
|
||||
@ -223,8 +209,7 @@ void enter_debugger()
|
||||
}
|
||||
if (cmd == "help") {
|
||||
show_help();
|
||||
}
|
||||
else if (cmd == "quit") {
|
||||
} else if (cmd == "quit") {
|
||||
break;
|
||||
}
|
||||
#ifdef PROFILER
|
||||
@ -236,8 +221,7 @@ void enter_debugger()
|
||||
#endif
|
||||
else if (cmd == "regs") {
|
||||
print_gprs();
|
||||
}
|
||||
else if (cmd == "set") {
|
||||
} else if (cmd == "set") {
|
||||
ss >> expr_str;
|
||||
|
||||
separator_pos = expr_str.find_first_of("=");
|
||||
@ -256,35 +240,28 @@ void enter_debugger()
|
||||
continue;
|
||||
}
|
||||
loguru::g_stderr_verbosity = log_level;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
addr = str2addr(addr_str);
|
||||
set_reg(reg_expr, addr);
|
||||
}
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
}
|
||||
}
|
||||
else if (cmd == "step" || cmd == "si") {
|
||||
} else if (cmd == "step" || cmd == "si") {
|
||||
ppc_exec_single();
|
||||
}
|
||||
else if (cmd == "next" || cmd == "ni") {
|
||||
} else if (cmd == "next" || cmd == "ni") {
|
||||
addr_str = "PC";
|
||||
addr = get_reg(addr_str) + 4;
|
||||
addr = get_reg(addr_str) + 4;
|
||||
ppc_exec_until(addr);
|
||||
}
|
||||
else if (cmd == "until") {
|
||||
} else if (cmd == "until") {
|
||||
ss >> addr_str;
|
||||
try {
|
||||
addr = str2addr(addr_str);
|
||||
ppc_exec_until(addr);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
}
|
||||
}
|
||||
else if (cmd == "disas") {
|
||||
} else if (cmd == "disas") {
|
||||
expr_str = "";
|
||||
ss >> expr_str;
|
||||
if (expr_str.length() > 0) {
|
||||
@ -294,41 +271,35 @@ void enter_debugger()
|
||||
continue;
|
||||
}
|
||||
inst_num_str = expr_str.substr(0, expr_str.find_first_of(","));
|
||||
inst_grab = stol(inst_num_str, NULL, 0);
|
||||
addr_str = expr_str.substr(expr_str.find_first_of(",") + 1);
|
||||
inst_grab = stol(inst_num_str, NULL, 0);
|
||||
addr_str = expr_str.substr(expr_str.find_first_of(",") + 1);
|
||||
try {
|
||||
addr = str2addr(addr_str);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
} catch (invalid_argument& exc) {
|
||||
try {
|
||||
/* number conversion failed, trying reg name */
|
||||
addr = get_reg(addr_str);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try {
|
||||
disasm(inst_grab, addr);
|
||||
}
|
||||
catch (invalid_argument& exc) {
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
/* disas without arguments defaults to disas 1,pc */
|
||||
addr_str = "PC";
|
||||
addr = get_reg(addr_str);
|
||||
addr = get_reg(addr_str);
|
||||
disasm(1, addr);
|
||||
}
|
||||
}
|
||||
else if (cmd == "dump") {
|
||||
} else if (cmd == "dump") {
|
||||
expr_str = "";
|
||||
ss >> expr_str;
|
||||
dump_mem(expr_str);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
cout << "Unknown command: " << cmd << endl;
|
||||
continue;
|
||||
}
|
||||
|
@ -3,4 +3,4 @@
|
||||
|
||||
void enter_debugger(void);
|
||||
|
||||
#endif // DEBUGGER_H_
|
||||
#endif // DEBUGGER_H_
|
||||
|
@ -25,9 +25,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include "devices/adb.h"
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include "devices/adb.h"
|
||||
|
||||
#include <thirdparty/SDL2/include/SDL.h>
|
||||
#include <thirdparty/SDL2/include/SDL_events.h>
|
||||
@ -40,63 +40,56 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
using namespace std;
|
||||
|
||||
ADB_Bus::ADB_Bus() {
|
||||
//set data streams as clear
|
||||
// set data streams as clear
|
||||
this->adb_mouse_register0 = 0x8080;
|
||||
|
||||
input_stream_len = 0;
|
||||
input_stream_len = 0;
|
||||
output_stream_len = 2;
|
||||
|
||||
adb_keybd_register3 = 0x6201;
|
||||
adb_mouse_register3 = 0x6302;
|
||||
|
||||
keyboard_access_no = adb_encoded;
|
||||
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) {
|
||||
if (device == keyboard_access_no) {
|
||||
if (adb_keybd_listen(reg)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (device == mouse_access_no) {
|
||||
} else if (device == mouse_access_no) {
|
||||
if (adb_mouse_listen(reg)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ADB_Bus::talk(int device, int reg, uint16_t value) {
|
||||
//temp code
|
||||
// temp code
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ADB_Bus::bus_reset() {
|
||||
//temp code
|
||||
// temp code
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADB_Bus::set_addr(int dev_addr, int new_addr) {
|
||||
//temp code
|
||||
// temp code
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ADB_Bus::flush(int dev_addr) {
|
||||
//temp code
|
||||
// temp code
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -108,7 +101,7 @@ bool ADB_Bus::adb_keybd_listen(int reg) {
|
||||
}
|
||||
|
||||
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) {
|
||||
case SDL_KEYDOWN:
|
||||
switch (adb_keybd_evt.key.keysym.sym) {
|
||||
@ -323,36 +316,36 @@ bool ADB_Bus::adb_keybd_listen(int reg) {
|
||||
ask_key_pressed = 0x5C;
|
||||
break;
|
||||
case SDLK_BACKSPACE:
|
||||
//ask_key_pressed = 0x33;
|
||||
// ask_key_pressed = 0x33;
|
||||
confirm_ask_reg_2 = true;
|
||||
mod_key_pressed = 0x40;
|
||||
mod_key_pressed = 0x40;
|
||||
break;
|
||||
case SDLK_CAPSLOCK:
|
||||
//ask_key_pressed = 0x39;
|
||||
// ask_key_pressed = 0x39;
|
||||
confirm_ask_reg_2 = true;
|
||||
mod_key_pressed = 0x20;
|
||||
mod_key_pressed = 0x20;
|
||||
break;
|
||||
case SDLK_RALT:
|
||||
case SDLK_RCTRL: //Temp key for Control key
|
||||
//ask_key_pressed = 0x36;
|
||||
case SDLK_RCTRL: // Temp key for Control key
|
||||
// ask_key_pressed = 0x36;
|
||||
confirm_ask_reg_2 = true;
|
||||
mod_key_pressed = 0x8;
|
||||
mod_key_pressed = 0x8;
|
||||
break;
|
||||
case SDLK_LSHIFT:
|
||||
case SDLK_RSHIFT:
|
||||
//ask_key_pressed = 0x38;
|
||||
// ask_key_pressed = 0x38;
|
||||
confirm_ask_reg_2 = true;
|
||||
mod_key_pressed = 0x4;
|
||||
mod_key_pressed = 0x4;
|
||||
break;
|
||||
case SDLK_LALT:
|
||||
//ask_key_pressed = 0x3A;
|
||||
// ask_key_pressed = 0x3A;
|
||||
confirm_ask_reg_2 = true;
|
||||
mod_key_pressed = 0x2;
|
||||
mod_key_pressed = 0x2;
|
||||
break;
|
||||
case SDLK_LCTRL: //Temp key for the Command/Apple key
|
||||
//ask_key_pressed = 0x37;
|
||||
case SDLK_LCTRL: // Temp key for the Command/Apple key
|
||||
// ask_key_pressed = 0x37;
|
||||
confirm_ask_reg_2 = true;
|
||||
mod_key_pressed = 0x1;
|
||||
mod_key_pressed = 0x1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -363,15 +356,14 @@ bool ADB_Bus::adb_keybd_listen(int reg) {
|
||||
adb_keybd_register0 &= (ask_key_pressed << 8);
|
||||
output_data_stream[0] = (adb_keybd_register0 >> 8);
|
||||
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 &= (ask_key_pressed);
|
||||
output_data_stream[0] = (adb_keybd_register0 >> 8);
|
||||
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) {
|
||||
adb_keybd_register0 |= (mod_key_pressed << 8);
|
||||
@ -386,25 +378,23 @@ bool ADB_Bus::adb_keybd_listen(int reg) {
|
||||
adb_keybd_register0 |= 0x8000;
|
||||
output_data_stream[0] = (adb_keybd_register0 >> 8);
|
||||
output_data_stream[1] = (adb_keybd_register0 & 0xff);
|
||||
}
|
||||
else if (adb_keybd_register0 & 0x80)
|
||||
} else if (adb_keybd_register0 & 0x80)
|
||||
adb_keybd_register0 |= 0x0080;
|
||||
output_data_stream[0] = (adb_keybd_register0 >> 8);
|
||||
output_data_stream[1] = (adb_keybd_register0 & 0xff);
|
||||
output_data_stream[0] = (adb_keybd_register0 >> 8);
|
||||
output_data_stream[1] = (adb_keybd_register0 & 0xff);
|
||||
|
||||
if (confirm_ask_reg_2) {
|
||||
adb_keybd_register2 &= (mod_key_pressed << 8);
|
||||
output_data_stream[0] = (adb_keybd_register2 >> 8);
|
||||
output_data_stream[1] = (adb_keybd_register2 & 0xff);
|
||||
confirm_ask_reg_2 = false;
|
||||
confirm_ask_reg_2 = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((reg != 1)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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 <= -64) {
|
||||
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;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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 <= -64) {
|
||||
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;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this->adb_mouse_register0 |= (adb_mouse_evt.motion.yrel << 8);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
switch (adb_mouse_evt.type) {
|
||||
@ -458,13 +443,11 @@ bool ADB_Bus::adb_mouse_listen(int reg) {
|
||||
if (reg == 0) {
|
||||
output_data_stream[0] = (adb_mouse_register0 >> 8);
|
||||
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[1] = (adb_mouse_register3 & 0xff);
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,15 +26,26 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include <thirdparty/SDL2/include/SDL.h>
|
||||
#include <thirdparty/SDL2/include/SDL_events.h>
|
||||
|
||||
enum adb_default_values {
|
||||
adb_reserved0, adb_reserved1, adb_encoded, 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
|
||||
enum adb_default_values {
|
||||
adb_reserved0,
|
||||
adb_reserved1,
|
||||
adb_encoded,
|
||||
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:
|
||||
ADB_Bus();
|
||||
~ADB_Bus();
|
||||
@ -58,7 +69,7 @@ private:
|
||||
int keyboard_access_no;
|
||||
int mouse_access_no;
|
||||
|
||||
//Keyboard Variables
|
||||
// Keyboard Variables
|
||||
|
||||
uint16_t adb_keybd_register0;
|
||||
uint16_t adb_keybd_register2;
|
||||
@ -71,15 +82,15 @@ private:
|
||||
|
||||
bool confirm_ask_reg_2;
|
||||
|
||||
//Mouse Variables
|
||||
// Mouse Variables
|
||||
SDL_Event adb_mouse_evt;
|
||||
|
||||
uint16_t adb_mouse_register0;
|
||||
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;
|
||||
uint8_t output_data_stream[16]; //temp buffer
|
||||
uint8_t output_data_stream[16]; // temp buffer
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <atirage.h>
|
||||
#include <cstdint>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include "displayid.h"
|
||||
#include "endianswap.h"
|
||||
#include "memreadwrite.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[8], 0x0300005C);
|
||||
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();
|
||||
}
|
||||
|
||||
ATIRage::~ATIRage()
|
||||
{
|
||||
ATIRage::~ATIRage() {
|
||||
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) {
|
||||
case 4:
|
||||
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) {
|
||||
case 4:
|
||||
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;
|
||||
|
||||
switch (reg_offset & ~3) {
|
||||
@ -152,16 +147,19 @@ const char* ATIRage::get_reg_name(uint32_t reg_offset)
|
||||
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;
|
||||
|
||||
switch (offset & ~3) {
|
||||
case ATI_GP_IO:
|
||||
break;
|
||||
default:
|
||||
LOG_F(INFO, "ATI Rage: read I/O reg %s at 0x%X, size=%d, val=0x%X",
|
||||
get_reg_name(offset), offset, size,
|
||||
LOG_F(
|
||||
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));
|
||||
}
|
||||
|
||||
@ -170,8 +168,7 @@ uint32_t ATIRage::read_reg(uint32_t offset, uint32_t size)
|
||||
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;
|
||||
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)) {
|
||||
gpio_val = READ_DWORD_LE_A(&this->block_io_regs[ATI_GP_IO]);
|
||||
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));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_F(INFO, "ATI Rage: %s register at 0x%X set to 0x%X",
|
||||
get_reg_name(offset), offset & ~3,
|
||||
LOG_F(
|
||||
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]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void ATIRage::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size)
|
||||
{
|
||||
LOG_F(INFO, "Writing into ATI Rage PCI config space, offset = 0x%X, val=0x%X size=%d",
|
||||
reg_offs, BYTESWAP_32(value), size);
|
||||
void ATIRage::pci_cfg_write(uint32_t reg_offs, uint32_t value, uint32_t size) {
|
||||
LOG_F(
|
||||
INFO,
|
||||
"Writing into ATI Rage PCI config space, offset = 0x%X, val=0x%X size=%d",
|
||||
reg_offs,
|
||||
BYTESWAP_32(value),
|
||||
size);
|
||||
|
||||
switch (reg_offs) {
|
||||
case 0x10: /* BAR 0 */
|
||||
if (value == 0xFFFFFFFFUL) {
|
||||
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR0], 0xFF000008);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR0], value);
|
||||
}
|
||||
break;
|
||||
case 0x14: /* BAR 1: I/O space base, 256 bytes wide */
|
||||
if (value == 0xFFFFFFFFUL) {
|
||||
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR1], 0x0000FFF1);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR1], value);
|
||||
}
|
||||
case 0x18: /* BAR 2 */
|
||||
if (value == 0xFFFFFFFFUL) {
|
||||
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR2], 0xFFFFF000);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
WRITE_DWORD_BE_A(&this->pci_cfg[CFG_REG_BAR2], value);
|
||||
}
|
||||
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)) {
|
||||
LOG_F(WARNING, "ATI I/O space disabled in the command reg");
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
@ -22,9 +22,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef ATI_RAGE_H
|
||||
#define ATI_RAGE_H
|
||||
|
||||
#include <cinttypes>
|
||||
#include "pcidevice.h"
|
||||
#include "displayid.h"
|
||||
#include "pcidevice.h"
|
||||
#include <cinttypes>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@ -37,73 +37,72 @@ enum {
|
||||
|
||||
/** Mach registers offsets. */
|
||||
enum {
|
||||
ATI_CRTC_H_TOTAL_DISP = 0x0000,
|
||||
ATI_CRTC_H_SYNC_STRT_WID = 0x0004,
|
||||
ATI_CRTC_V_TOTAL_DISP = 0x0008,
|
||||
ATI_CRTC_V_SYNC_STRT_WID = 0x000C,
|
||||
ATI_CRTC_OFF_PITCH = 0x0014,
|
||||
ATI_CRTC_INT_CNTL = 0x0018,
|
||||
ATI_CRTC_GEN_CNTL = 0x001C,
|
||||
ATI_DSP_CONFIG = 0x0020,
|
||||
ATI_DSP_ON_OFF = 0x0024,
|
||||
ATI_TIMER_CFG = 0x0028,
|
||||
ATI_MEM_BUF_CNTL = 0x002C,
|
||||
ATI_MEM_ADDR_CFG = 0x0034,
|
||||
ATI_CRT_TRAP = 0x0038,
|
||||
ATI_I2C_CNTL_0 = 0x003C,
|
||||
ATI_OVR_CLR = 0x0040,
|
||||
ATI_OVR_WID_LEFT_RIGHT = 0x0044,
|
||||
ATI_OVR_WID_TOP_BOTTOM = 0x0048,
|
||||
ATI_VGA_DSP_CFG = 0x004C,
|
||||
ATI_VGA_DSP_TGL = 0x0050,
|
||||
ATI_DSP2_CONFIG = 0x0054,
|
||||
ATI_DSP2_TOGGLE = 0x0058,
|
||||
ATI_CRTC2_OFF_PITCH = 0x005C,
|
||||
ATI_CUR_CLR0 = 0x0060,
|
||||
ATI_CUR_CLR1 = 0x0064,
|
||||
ATI_CUR_OFFSET = 0x0068,
|
||||
ATI_CUR_HORZ_VERT_POSN = 0x006C,
|
||||
ATI_CUR_HORZ_VERT_OFF = 0x0070,
|
||||
ATI_GP_IO = 0x0078,
|
||||
ATI_HW_DEBUG = 0x007C,
|
||||
ATI_SCRATCH_REG0 = 0x0080,
|
||||
ATI_SCRATCH_REG1 = 0x0084,
|
||||
ATI_SCRATCH_REG2 = 0x0088,
|
||||
ATI_SCRATCH_REG3 = 0x008C,
|
||||
ATI_CLOCK_CNTL = 0x0090,
|
||||
ATI_CLONFIG_STAT1 = 0x0094,
|
||||
ATI_CLONFIG_STAT2 = 0x0098,
|
||||
ATI_BUS_CNTL = 0x00A0,
|
||||
ATI_EXT_MEM_CNTL = 0x00AC,
|
||||
ATI_MEM_CNTL = 0x00B0,
|
||||
ATI_VGA_WP_SEL = 0x00B4,
|
||||
ATI_VGA_RP_SEL = 0x00B8,
|
||||
ATI_I2C_CNTL_1 = 0x00BC,
|
||||
ATI_DAC_REGS = 0x00C0,
|
||||
ATI_DAC_CNTL = 0x00C4,
|
||||
ATI_GEN_TEST_CNTL = 0x00D0,
|
||||
ATI_CUSTOM_MACRO_CNTL = 0x00D4,
|
||||
ATI_CONFIG_CNTL = 0x00DC,
|
||||
ATI_CFG_CHIP_ID = 0x00E0,
|
||||
ATI_CFG_STAT0 = 0x00E4,
|
||||
ATI_CRC_SIG = 0x00E8,
|
||||
ATI_DST_OFF_PITCH = 0x0100,
|
||||
ATI_SRC_OFF_PITCH = 0x0180,
|
||||
ATI_HOST_CNTL = 0x0240,
|
||||
ATI_DP_WRITE_MSK = 0x02C8,
|
||||
ATI_DP_PIX_WIDTH = 0x02D0,
|
||||
ATI_DST_X_Y = 0x02E8,
|
||||
ATI_DST_WIDTH_HEIGHT = 0x02EC,
|
||||
ATI_CONTEXT_MASK = 0x0320,
|
||||
ATI_MPP_CONFIG = 0x04C0,
|
||||
ATI_MPP_STROBE_SEQ = 0x04C4,
|
||||
ATI_MPP_ADDR = 0x04C8,
|
||||
ATI_MPP_DATA = 0x04CC,
|
||||
ATI_TVO_CNTL = 0x0500,
|
||||
ATI_CRTC_H_TOTAL_DISP = 0x0000,
|
||||
ATI_CRTC_H_SYNC_STRT_WID = 0x0004,
|
||||
ATI_CRTC_V_TOTAL_DISP = 0x0008,
|
||||
ATI_CRTC_V_SYNC_STRT_WID = 0x000C,
|
||||
ATI_CRTC_OFF_PITCH = 0x0014,
|
||||
ATI_CRTC_INT_CNTL = 0x0018,
|
||||
ATI_CRTC_GEN_CNTL = 0x001C,
|
||||
ATI_DSP_CONFIG = 0x0020,
|
||||
ATI_DSP_ON_OFF = 0x0024,
|
||||
ATI_TIMER_CFG = 0x0028,
|
||||
ATI_MEM_BUF_CNTL = 0x002C,
|
||||
ATI_MEM_ADDR_CFG = 0x0034,
|
||||
ATI_CRT_TRAP = 0x0038,
|
||||
ATI_I2C_CNTL_0 = 0x003C,
|
||||
ATI_OVR_CLR = 0x0040,
|
||||
ATI_OVR_WID_LEFT_RIGHT = 0x0044,
|
||||
ATI_OVR_WID_TOP_BOTTOM = 0x0048,
|
||||
ATI_VGA_DSP_CFG = 0x004C,
|
||||
ATI_VGA_DSP_TGL = 0x0050,
|
||||
ATI_DSP2_CONFIG = 0x0054,
|
||||
ATI_DSP2_TOGGLE = 0x0058,
|
||||
ATI_CRTC2_OFF_PITCH = 0x005C,
|
||||
ATI_CUR_CLR0 = 0x0060,
|
||||
ATI_CUR_CLR1 = 0x0064,
|
||||
ATI_CUR_OFFSET = 0x0068,
|
||||
ATI_CUR_HORZ_VERT_POSN = 0x006C,
|
||||
ATI_CUR_HORZ_VERT_OFF = 0x0070,
|
||||
ATI_GP_IO = 0x0078,
|
||||
ATI_HW_DEBUG = 0x007C,
|
||||
ATI_SCRATCH_REG0 = 0x0080,
|
||||
ATI_SCRATCH_REG1 = 0x0084,
|
||||
ATI_SCRATCH_REG2 = 0x0088,
|
||||
ATI_SCRATCH_REG3 = 0x008C,
|
||||
ATI_CLOCK_CNTL = 0x0090,
|
||||
ATI_CLONFIG_STAT1 = 0x0094,
|
||||
ATI_CLONFIG_STAT2 = 0x0098,
|
||||
ATI_BUS_CNTL = 0x00A0,
|
||||
ATI_EXT_MEM_CNTL = 0x00AC,
|
||||
ATI_MEM_CNTL = 0x00B0,
|
||||
ATI_VGA_WP_SEL = 0x00B4,
|
||||
ATI_VGA_RP_SEL = 0x00B8,
|
||||
ATI_I2C_CNTL_1 = 0x00BC,
|
||||
ATI_DAC_REGS = 0x00C0,
|
||||
ATI_DAC_CNTL = 0x00C4,
|
||||
ATI_GEN_TEST_CNTL = 0x00D0,
|
||||
ATI_CUSTOM_MACRO_CNTL = 0x00D4,
|
||||
ATI_CONFIG_CNTL = 0x00DC,
|
||||
ATI_CFG_CHIP_ID = 0x00E0,
|
||||
ATI_CFG_STAT0 = 0x00E4,
|
||||
ATI_CRC_SIG = 0x00E8,
|
||||
ATI_DST_OFF_PITCH = 0x0100,
|
||||
ATI_SRC_OFF_PITCH = 0x0180,
|
||||
ATI_HOST_CNTL = 0x0240,
|
||||
ATI_DP_WRITE_MSK = 0x02C8,
|
||||
ATI_DP_PIX_WIDTH = 0x02D0,
|
||||
ATI_DST_X_Y = 0x02E8,
|
||||
ATI_DST_WIDTH_HEIGHT = 0x02EC,
|
||||
ATI_CONTEXT_MASK = 0x0320,
|
||||
ATI_MPP_CONFIG = 0x04C0,
|
||||
ATI_MPP_STROBE_SEQ = 0x04C4,
|
||||
ATI_MPP_ADDR = 0x04C8,
|
||||
ATI_MPP_DATA = 0x04CC,
|
||||
ATI_TVO_CNTL = 0x0500,
|
||||
};
|
||||
|
||||
class ATIRage : public PCIDevice
|
||||
{
|
||||
class ATIRage : public PCIDevice {
|
||||
public:
|
||||
ATIRage(uint16_t dev_id);
|
||||
~ATIRage();
|
||||
@ -112,17 +111,21 @@ public:
|
||||
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);
|
||||
|
||||
bool supports_type(HWCompType type) { return type == HWCompType::MMIO_DEV; };
|
||||
bool supports_type(HWCompType type) {
|
||||
return type == HWCompType::MMIO_DEV;
|
||||
};
|
||||
|
||||
/* 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);
|
||||
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 */
|
||||
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_read(uint32_t offset, uint32_t size, uint32_t* res);
|
||||
bool pci_io_write(uint32_t offset, uint32_t value, uint32_t size);
|
||||
|
||||
protected:
|
||||
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);
|
||||
|
||||
private:
|
||||
//uint32_t atirage_membuf_regs[9]; /* ATI Rage Memory Buffer 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_datapath_regs[12]; /* ATI Rage Data Path 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_cmdfifo_regs[3]; /* ATI Rage Command FIFO 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;
|
||||
};
|
||||
|
@ -24,26 +24,24 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
Author: Max Poliakovski 2019-20
|
||||
*/
|
||||
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include "endianswap.h"
|
||||
#include "awacs.h"
|
||||
#include "dbdma.h"
|
||||
#include "endianswap.h"
|
||||
#include "machines/machinebase.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};
|
||||
|
||||
AWACDevice::AWACDevice()
|
||||
{
|
||||
AWACDevice::AWACDevice() {
|
||||
this->audio_proc = new AudioProcessor();
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
AWACDevice::~AWACDevice()
|
||||
{
|
||||
AWACDevice::~AWACDevice() {
|
||||
delete this->audio_proc;
|
||||
|
||||
if (this->snd_buf)
|
||||
@ -53,21 +51,18 @@ AWACDevice::~AWACDevice()
|
||||
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;
|
||||
}
|
||||
|
||||
uint32_t AWACDevice::snd_ctrl_read(uint32_t offset, int size)
|
||||
{
|
||||
switch(offset) {
|
||||
uint32_t AWACDevice::snd_ctrl_read(uint32_t offset, int size) {
|
||||
switch (offset) {
|
||||
case AWAC_SOUND_CTRL_REG:
|
||||
return this->snd_ctrl_reg;
|
||||
case AWAC_CODEC_CTRL_REG:
|
||||
return this->is_busy;
|
||||
case AWAC_CODEC_STATUS_REG:
|
||||
return (AWAC_AVAILABLE << 8) | (AWAC_MAKER_CRYSTAL << 16) |
|
||||
(AWAC_REV_SCREAMER << 20);
|
||||
return (AWAC_AVAILABLE << 8) | (AWAC_MAKER_CRYSTAL << 16) | (AWAC_REV_SCREAMER << 20);
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
uint16_t data;
|
||||
|
||||
switch(offset) {
|
||||
switch (offset) {
|
||||
case AWAC_SOUND_CTRL_REG:
|
||||
this->snd_ctrl_reg = BYTESWAP_32(value);
|
||||
LOG_F(INFO, "New sound control value = 0x%X", this->snd_ctrl_reg);
|
||||
@ -89,7 +83,7 @@ void AWACDevice::snd_ctrl_write(uint32_t offset, uint32_t value, int size)
|
||||
case AWAC_CODEC_CTRL_REG:
|
||||
subframe = (value >> 14) & 3;
|
||||
reg_num = (value >> 20) & 7;
|
||||
data = ((value >> 8) & 0xF00) | ((value >> 24) & 0xFF);
|
||||
data = ((value >> 8) & 0xF00) | ((value >> 24) & 0xFF);
|
||||
LOG_F(INFO, "AWAC subframe = %d, reg = %d, data = %08X\n", subframe, reg_num, data);
|
||||
if (!subframe)
|
||||
this->control_regs[reg_num] = data;
|
||||
@ -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;
|
||||
|
||||
if (len & 7) {
|
||||
LOG_F(WARNING, "AWAC sound buffer len not a multiply of 8, %d", len);
|
||||
}
|
||||
|
||||
p_in = (uint16_t *)in;
|
||||
p_out = (uint16_t *)out;
|
||||
p_in = (uint16_t*)in;
|
||||
p_out = (uint16_t*)out;
|
||||
len >>= 1;
|
||||
|
||||
/* AWAC data comes as LLRR -> convert it to LRLR */
|
||||
for (int i = 0; i < len; i += 8) {
|
||||
p_out[i] = p_in[i];
|
||||
p_out[i+1] = p_in[i+2];
|
||||
p_out[i+2] = p_in[i+1];
|
||||
p_out[i+3] = p_in[i+3];
|
||||
p_out[i] = p_in[i];
|
||||
p_out[i + 1] = p_in[i + 2];
|
||||
p_out[i + 2] = p_in[i + 1];
|
||||
p_out[i + 3] = p_in[i + 3];
|
||||
}
|
||||
}
|
||||
|
||||
static void audio_out_callback(void *user_data, uint8_t *buf, int buf_len)
|
||||
{
|
||||
uint8_t *p_in;
|
||||
static void audio_out_callback(void* user_data, uint8_t* buf, int buf_len) {
|
||||
uint8_t* p_in;
|
||||
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) {
|
||||
if (!dma_ch->get_data(rem_len, &got_len, &p_in)) {
|
||||
convert_data(p_in, buf, got_len);
|
||||
//LOG_F(9, "Converted sound data, len = %d", got_len);
|
||||
} else { /* no more data */
|
||||
// LOG_F(9, "Converted sound data, len = %d", got_len);
|
||||
} else { /* no more data */
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AWACDevice::convert_data(const uint8_t *data, int len)
|
||||
{
|
||||
uint32_t AWACDevice::convert_data(const uint8_t* data, int len) {
|
||||
int i;
|
||||
uint16_t *p_in, *p_out;
|
||||
|
||||
@ -151,30 +142,29 @@ uint32_t AWACDevice::convert_data(const uint8_t *data, int len)
|
||||
this->buf_len = len;
|
||||
}
|
||||
|
||||
p_in = (uint16_t *)data;
|
||||
p_out = (uint16_t *)this->snd_buf;
|
||||
p_in = (uint16_t*)data;
|
||||
p_out = (uint16_t*)this->snd_buf;
|
||||
|
||||
for (i = 0; i < len; i += 8) {
|
||||
p_out[i] = p_in[i];
|
||||
p_out[i+1] = p_in[i+2];
|
||||
p_out[i+2] = p_in[i+1];
|
||||
p_out[i+3] = p_in[i+3];
|
||||
p_out[i] = p_in[i];
|
||||
p_out[i + 1] = p_in[i + 2];
|
||||
p_out[i + 2] = p_in[i + 1];
|
||||
p_out[i + 3] = p_in[i + 3];
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void AWACDevice::dma_start()
|
||||
{
|
||||
void AWACDevice::dma_start() {
|
||||
SDL_AudioSpec snd_spec, snd_settings;
|
||||
|
||||
SDL_zero(snd_spec);
|
||||
snd_spec.freq = awac_freqs[(this->snd_ctrl_reg >> 8) & 7];
|
||||
snd_spec.format = AUDIO_S16MSB; /* yes, AWAC accepts big-endian data */
|
||||
snd_spec.freq = awac_freqs[(this->snd_ctrl_reg >> 8) & 7];
|
||||
snd_spec.format = AUDIO_S16MSB; /* yes, AWAC accepts big-endian data */
|
||||
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.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);
|
||||
@ -188,16 +178,14 @@ void AWACDevice::dma_start()
|
||||
SDL_PauseAudioDevice(this->snd_out_dev, 0); /* start audio playing */
|
||||
}
|
||||
|
||||
void AWACDevice::dma_end()
|
||||
{
|
||||
void AWACDevice::dma_end() {
|
||||
if (this->snd_out_dev) {
|
||||
SDL_CloseAudioDevice(this->snd_out_dev);
|
||||
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;
|
||||
|
||||
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
|
||||
#define AWAC_H
|
||||
|
||||
#include <cinttypes>
|
||||
#include "i2c.h"
|
||||
#include "dbdma.h"
|
||||
#include "i2c.h"
|
||||
#include <cinttypes>
|
||||
#include <thirdparty/SDL2/include/SDL.h>
|
||||
|
||||
/** AWAC registers offsets. */
|
||||
@ -42,7 +42,7 @@ enum {
|
||||
|
||||
/** AWAC manufacturer and revision. */
|
||||
#define AWAC_MAKER_CRYSTAL 1
|
||||
#define AWAC_REV_SCREAMER 3
|
||||
#define AWAC_REV_SCREAMER 3
|
||||
|
||||
/** Apple source calls this kValidData but doesn't explain
|
||||
what it actually means. It seems like it's used to check
|
||||
@ -57,7 +57,9 @@ public:
|
||||
AudioProcessor() = default;
|
||||
~AudioProcessor() = default;
|
||||
|
||||
void start_transaction() { this->pos = 0; };
|
||||
void start_transaction() {
|
||||
this->pos = 0;
|
||||
};
|
||||
|
||||
bool send_subaddress(uint8_t sub_addr) {
|
||||
if ((sub_addr & 0xF) > 6)
|
||||
@ -65,8 +67,7 @@ public:
|
||||
|
||||
this->sub_addr = sub_addr & 0xF;
|
||||
this->auto_inc = !!(sub_addr & 0x10);
|
||||
LOG_F(INFO, "TDA7433 subaddress = 0x%X, auto increment = %d",
|
||||
this->sub_addr, this->auto_inc);
|
||||
LOG_F(INFO, "TDA7433 subaddress = 0x%X, auto increment = %d", this->sub_addr, this->auto_inc);
|
||||
this->pos++;
|
||||
return true;
|
||||
};
|
||||
@ -76,7 +77,7 @@ public:
|
||||
return send_subaddress(data);
|
||||
} else if (this->sub_addr <= 6) {
|
||||
LOG_F(INFO, "TDA7433 byte 0x%X received", data);
|
||||
this->regs[this->sub_addr] = data;
|
||||
this->regs[this->sub_addr] = data;
|
||||
if (this->auto_inc) {
|
||||
this->sub_addr++;
|
||||
}
|
||||
@ -86,17 +87,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
bool receive_byte(uint8_t *p_data) {
|
||||
bool receive_byte(uint8_t* p_data) {
|
||||
*p_data = this->regs[this->sub_addr];
|
||||
LOG_F(INFO, "TDA7433 byte 0x%X sent", *p_data);
|
||||
return true;
|
||||
};
|
||||
|
||||
private:
|
||||
uint8_t regs[7]; /* control registers, see TDA7433 datasheet */
|
||||
uint8_t regs[7]; /* control registers, see TDA7433 datasheet */
|
||||
uint8_t sub_addr;
|
||||
int pos;
|
||||
int auto_inc;
|
||||
int pos;
|
||||
int auto_inc;
|
||||
};
|
||||
|
||||
|
||||
@ -105,33 +106,33 @@ public:
|
||||
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);
|
||||
void snd_ctrl_write(uint32_t offset, uint32_t value, int size);
|
||||
void snd_ctrl_write(uint32_t offset, uint32_t value, int size);
|
||||
|
||||
/* DMACallback methods */
|
||||
void dma_start();
|
||||
void dma_end();
|
||||
void dma_push(uint8_t *buf, int size);
|
||||
void dma_pull(uint8_t *buf, int size);
|
||||
void dma_push(uint8_t* buf, int size);
|
||||
void dma_pull(uint8_t* buf, int size);
|
||||
|
||||
protected:
|
||||
uint32_t convert_data(const uint8_t *data, int len);
|
||||
uint32_t convert_data(const uint8_t* data, int len);
|
||||
|
||||
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 */
|
||||
uint8_t is_busy = 0;
|
||||
AudioProcessor *audio_proc;
|
||||
uint8_t is_busy = 0;
|
||||
AudioProcessor* audio_proc;
|
||||
|
||||
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;
|
||||
uint32_t buf_len = 0;
|
||||
uint8_t* snd_buf = 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. */
|
||||
|
||||
#include "dbdma.h"
|
||||
#include "cpu/ppc/ppcmmu.h"
|
||||
#include "endianswap.h"
|
||||
#include <cinttypes>
|
||||
#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 */
|
||||
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;
|
||||
|
||||
get_next_cmd(this->cmd_ptr, &cmd_struct);
|
||||
|
||||
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:
|
||||
LOG_F(9, "Executing DMA Command OUTPUT_MORE");
|
||||
if (cmd_struct.cmd_key & 7) {
|
||||
@ -52,11 +50,11 @@ uint8_t DMAChannel::interpret_cmd()
|
||||
LOG_F(ERROR, "non-zero i/b/w not implemented");
|
||||
break;
|
||||
}
|
||||
//this->dma_cb->dma_push(
|
||||
// this->dma_cb->dma_push(
|
||||
// mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count),
|
||||
// cmd_struct.req_count);
|
||||
this->queue_data = mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count);
|
||||
this->queue_len = cmd_struct.req_count;
|
||||
this->queue_len = cmd_struct.req_count;
|
||||
this->cmd_ptr += 16;
|
||||
break;
|
||||
case 1:
|
||||
@ -69,11 +67,11 @@ uint8_t DMAChannel::interpret_cmd()
|
||||
LOG_F(ERROR, "non-zero i/b/w not implemented");
|
||||
break;
|
||||
}
|
||||
//this->dma_cb->dma_push(
|
||||
// this->dma_cb->dma_push(
|
||||
// mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count),
|
||||
// cmd_struct.req_count);
|
||||
this->queue_data = mmu_get_dma_mem(cmd_struct.address, cmd_struct.req_count);
|
||||
this->queue_len = cmd_struct.req_count;
|
||||
this->queue_len = cmd_struct.req_count;
|
||||
this->cmd_ptr += 16;
|
||||
break;
|
||||
case 2:
|
||||
@ -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;
|
||||
|
||||
if (size != 4) {
|
||||
@ -114,7 +111,7 @@ uint32_t DMAChannel::reg_read(uint32_t offset, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(offset) {
|
||||
switch (offset) {
|
||||
case DMAReg::CH_CTRL:
|
||||
res = 0; /* ChannelControl reads as 0 (DBDMA spec 5.5.1, table 74) */
|
||||
break;
|
||||
@ -128,8 +125,7 @@ uint32_t DMAChannel::reg_read(uint32_t offset, int size)
|
||||
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;
|
||||
|
||||
if (size != 4) {
|
||||
@ -137,12 +133,12 @@ void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size)
|
||||
return;
|
||||
}
|
||||
|
||||
value = BYTESWAP_32(value);
|
||||
value = BYTESWAP_32(value);
|
||||
old_stat = this->ch_stat;
|
||||
|
||||
switch(offset) {
|
||||
switch (offset) {
|
||||
case DMAReg::CH_CTRL:
|
||||
mask = value >> 16;
|
||||
mask = value >> 16;
|
||||
new_stat = (value & mask & 0xF0FFU) | (old_stat & ~mask);
|
||||
LOG_F(INFO, "New ChannelStatus value = 0x%X", new_stat);
|
||||
|
||||
@ -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)) {
|
||||
LOG_F(WARNING, "Dead/idle channel -> no more data");
|
||||
*avail_len = 0;
|
||||
@ -204,14 +199,14 @@ int DMAChannel::get_data(uint32_t req_len, uint32_t *avail_len, uint8_t **p_data
|
||||
if (this->queue_len) {
|
||||
if (this->queue_len >= req_len) {
|
||||
LOG_F(9, "Return req_len = %d data", req_len);
|
||||
*p_data = this->queue_data;
|
||||
*p_data = this->queue_data;
|
||||
*avail_len = req_len;
|
||||
this->queue_len -= req_len;
|
||||
this->queue_len -= req_len;
|
||||
this->queue_data += req_len;
|
||||
} else { /* return less data than req_len */
|
||||
LOG_F(9, "Return queue_len = %d data", this->queue_len);
|
||||
*p_data = this->queue_data;
|
||||
*avail_len = this->queue_len;
|
||||
*p_data = this->queue_data;
|
||||
*avail_len = this->queue_len;
|
||||
this->queue_len = 0;
|
||||
}
|
||||
return 0; /* tell the caller there is more data */
|
||||
@ -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 */
|
||||
}
|
||||
|
||||
void DMAChannel::start()
|
||||
{
|
||||
void DMAChannel::start() {
|
||||
if (this->ch_stat & CH_STAT_PAUSE) {
|
||||
LOG_F(WARNING, "Cannot start DMA channel, PAUSE bit is set");
|
||||
return;
|
||||
@ -233,12 +227,11 @@ void DMAChannel::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) {
|
||||
LOG_F(WARNING, "Cannot resume DMA channel, PAUSE bit is set");
|
||||
return;
|
||||
@ -247,13 +240,11 @@ void DMAChannel::resume()
|
||||
LOG_F(INFO, "Resuming DMA channel");
|
||||
}
|
||||
|
||||
void DMAChannel::abort()
|
||||
{
|
||||
void DMAChannel::abort() {
|
||||
LOG_F(INFO, "Aborting DMA channel");
|
||||
}
|
||||
|
||||
void DMAChannel::pause()
|
||||
{
|
||||
void DMAChannel::pause() {
|
||||
LOG_F(INFO, "Pausing DMA channel");
|
||||
this->dma_cb->dma_end();
|
||||
}
|
||||
|
@ -33,52 +33,54 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/** DBDMA Channel registers offsets */
|
||||
enum DMAReg : uint32_t {
|
||||
CH_CTRL = 0,
|
||||
CH_STAT = 4,
|
||||
CMD_PTR_LO = 12,
|
||||
CH_CTRL = 0,
|
||||
CH_STAT = 4,
|
||||
CMD_PTR_LO = 12,
|
||||
};
|
||||
|
||||
/** Channel Status bits (DBDMA spec, 5.5.3) */
|
||||
enum {
|
||||
CH_STAT_ACTIVE = 0x400,
|
||||
CH_STAT_DEAD = 0x800,
|
||||
CH_STAT_WAKE = 0x1000,
|
||||
CH_STAT_FLUSH = 0x2000,
|
||||
CH_STAT_PAUSE = 0x4000,
|
||||
CH_STAT_RUN = 0x8000
|
||||
CH_STAT_ACTIVE = 0x400,
|
||||
CH_STAT_DEAD = 0x800,
|
||||
CH_STAT_WAKE = 0x1000,
|
||||
CH_STAT_FLUSH = 0x2000,
|
||||
CH_STAT_PAUSE = 0x4000,
|
||||
CH_STAT_RUN = 0x8000
|
||||
};
|
||||
|
||||
/** DBDMA command (DBDMA spec, 5.6.1) - all fields are little-endian! */
|
||||
typedef struct DMACmd {
|
||||
uint16_t req_count;
|
||||
uint8_t cmd_bits;
|
||||
uint8_t cmd_key;
|
||||
uint32_t address;
|
||||
uint32_t cmd_arg;
|
||||
uint16_t res_count;
|
||||
uint16_t xfer_stat;
|
||||
uint16_t req_count;
|
||||
uint8_t cmd_bits;
|
||||
uint8_t cmd_key;
|
||||
uint32_t address;
|
||||
uint32_t cmd_arg;
|
||||
uint16_t res_count;
|
||||
uint16_t xfer_stat;
|
||||
} DMACmd;
|
||||
|
||||
class DMACallback {
|
||||
public:
|
||||
virtual void dma_start(void) = 0;
|
||||
virtual void dma_end(void) = 0;
|
||||
virtual void dma_push(uint8_t *buf, int size) = 0;
|
||||
virtual void dma_pull(uint8_t *buf, int size) = 0;
|
||||
virtual void dma_start(void) = 0;
|
||||
virtual void dma_end(void) = 0;
|
||||
virtual void dma_push(uint8_t* buf, int size) = 0;
|
||||
virtual void dma_pull(uint8_t* buf, int size) = 0;
|
||||
};
|
||||
|
||||
class DMAChannel {
|
||||
public:
|
||||
DMAChannel(DMACallback *cb) { this->dma_cb = cb; };
|
||||
DMAChannel(DMACallback* cb) {
|
||||
this->dma_cb = cb;
|
||||
};
|
||||
~DMAChannel() = default;
|
||||
|
||||
uint32_t reg_read(uint32_t offset, 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:
|
||||
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);
|
||||
|
||||
void start(void);
|
||||
@ -87,12 +89,12 @@ protected:
|
||||
void pause(void);
|
||||
|
||||
private:
|
||||
DMACallback *dma_cb = 0;
|
||||
uint16_t ch_stat = 0;
|
||||
uint32_t cmd_ptr = 0;
|
||||
DMACallback* dma_cb = 0;
|
||||
uint16_t ch_stat = 0;
|
||||
uint32_t cmd_ptr = 0;
|
||||
|
||||
uint32_t queue_len;
|
||||
uint8_t* queue_data;
|
||||
uint32_t queue_len;
|
||||
uint8_t* queue_data;
|
||||
};
|
||||
|
||||
#endif /* DB_DMA_H */
|
||||
|
@ -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/>.
|
||||
*/
|
||||
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include "displayid.h"
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
|
||||
DisplayID::DisplayID()
|
||||
{
|
||||
DisplayID::DisplayID() {
|
||||
/* Initialize Apple monitor codes */
|
||||
this->std_sense_code = 6;
|
||||
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_scl = scl;
|
||||
|
||||
if (scl) {
|
||||
this->data_out |= 0x1000;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this->data_out &= ~0x1000U;
|
||||
}
|
||||
|
||||
if (sda) {
|
||||
this->data_out |= 0x2000;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this->data_out &= ~0x2000U;
|
||||
}
|
||||
|
||||
@ -64,9 +60,8 @@ uint16_t DisplayID::set_result(uint8_t sda, uint8_t scl)
|
||||
}
|
||||
|
||||
|
||||
uint16_t DisplayID::read_monitor_sense(uint16_t data, uint16_t dirs)
|
||||
{
|
||||
uint8_t scl, sda;
|
||||
uint16_t DisplayID::read_monitor_sense(uint16_t data, uint16_t dirs) {
|
||||
uint8_t scl, sda;
|
||||
uint16_t result;
|
||||
|
||||
if ((dirs & 0x3100) == 0 && (data & 0x3100) == 0x3100) {
|
||||
@ -81,24 +76,19 @@ uint16_t DisplayID::read_monitor_sense(uint16_t data, uint16_t dirs)
|
||||
sda = (dirs & 0x2000) ? !!(data & 0x2000) : 1;
|
||||
|
||||
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) {
|
||||
case 0:
|
||||
result = ((this->std_sense_code & 6) << 11) |
|
||||
((this->std_sense_code & 1) << 8);
|
||||
result = ((this->std_sense_code & 6) << 11) | ((this->std_sense_code & 1) << 8);
|
||||
break;
|
||||
case 0x2000: /* Sense line 2 is low */
|
||||
result = ((this->ext_sense_code & 0x20) << 7) |
|
||||
((this->ext_sense_code & 0x10) << 4);
|
||||
result = ((this->ext_sense_code & 0x20) << 7) | ((this->ext_sense_code & 0x10) << 4);
|
||||
break;
|
||||
case 0x1000: /* Sense line 1 is low */
|
||||
result = ((this->ext_sense_code & 8) << 10) |
|
||||
((this->ext_sense_code & 4) << 6);
|
||||
result = ((this->ext_sense_code & 8) << 10) | ((this->ext_sense_code & 4) << 6);
|
||||
break;
|
||||
case 0x100: /* Sense line 0 is low */
|
||||
result = ((this->ext_sense_code & 2) << 12) |
|
||||
((this->ext_sense_code & 1) << 12);
|
||||
result = ((this->ext_sense_code & 2) << 12) | ((this->ext_sense_code & 1) << 12);
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
|
||||
@ -127,9 +117,8 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
|
||||
if (!sda) {
|
||||
LOG_F(9, "DDC-I2C: START condition detected!");
|
||||
this->next_state = I2CState::DEV_ADDR;
|
||||
this->bit_count = 0;
|
||||
}
|
||||
else {
|
||||
this->bit_count = 0;
|
||||
} else {
|
||||
LOG_F(9, "DDC-I2C: STOP condition detected!");
|
||||
this->next_state = I2CState::STOP;
|
||||
}
|
||||
@ -147,22 +136,20 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
|
||||
|
||||
case I2CState::ACK:
|
||||
this->bit_count = 0;
|
||||
this->byte = 0;
|
||||
this->byte = 0;
|
||||
switch (this->prev_state) {
|
||||
case I2CState::DEV_ADDR:
|
||||
if ((dev_addr & 0xFE) == 0xA0) {
|
||||
sda = 0; /* send ACK */
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_F(ERROR, "DDC-I2C: unknown device address 0x%X", this->dev_addr);
|
||||
sda = 1; /* send NACK */
|
||||
}
|
||||
if (this->dev_addr & 1) {
|
||||
this->next_state = I2CState::DATA;
|
||||
this->data_ptr = this->edid;
|
||||
this->byte = *(this->data_ptr++);
|
||||
}
|
||||
else {
|
||||
this->data_ptr = this->edid;
|
||||
this->byte = *(this->data_ptr++);
|
||||
} else {
|
||||
this->next_state = I2CState::REG_ADDR;
|
||||
}
|
||||
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;
|
||||
if (!this->reg_addr) {
|
||||
sda = 0; /* send ACK */
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_F(ERROR, "DDC-I2C: unknown register address 0x%X", this->reg_addr);
|
||||
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) {
|
||||
/* load next data byte */
|
||||
this->byte = *(this->data_ptr++);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_F(ERROR, "DDC-I2C: Oops! NACK received");
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
sda = 0; /* send ACK */
|
||||
}
|
||||
break;
|
||||
@ -198,14 +182,13 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
|
||||
case I2CState::REG_ADDR:
|
||||
this->byte = (this->byte << 1) | this->last_sda;
|
||||
if (this->bit_count++ >= 7) {
|
||||
this->bit_count = 0;
|
||||
this->bit_count = 0;
|
||||
this->prev_state = this->next_state;
|
||||
this->next_state = I2CState::ACK;
|
||||
if (this->prev_state == I2CState::DEV_ADDR) {
|
||||
LOG_F(9, "DDC-I2C: device address received, addr=0x%X", this->byte);
|
||||
this->dev_addr = this->byte;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_F(9, "DDC-I2C: register address received, addr=0x%X", this->byte);
|
||||
this->reg_addr = this->byte;
|
||||
}
|
||||
@ -215,7 +198,7 @@ uint16_t DisplayID::update_ddc_i2c(uint8_t sda, uint8_t scl)//(uint16_t data, ui
|
||||
case I2CState::DATA:
|
||||
sda = (this->byte >> (7 - this->bit_count)) & 1;
|
||||
if (this->bit_count++ >= 7) {
|
||||
this->bit_count = 0;
|
||||
this->bit_count = 0;
|
||||
this->prev_state = this->next_state;
|
||||
this->next_state = I2CState::ACK;
|
||||
}
|
||||
|
@ -61,39 +61,31 @@ protected:
|
||||
private:
|
||||
bool i2c_on;
|
||||
|
||||
uint8_t std_sense_code;
|
||||
uint8_t ext_sense_code;
|
||||
uint8_t std_sense_code;
|
||||
uint8_t ext_sense_code;
|
||||
|
||||
/* DDC I2C variables. */
|
||||
uint8_t next_state;
|
||||
uint8_t prev_state;
|
||||
uint8_t last_sda;
|
||||
uint8_t last_scl;
|
||||
uint8_t next_state;
|
||||
uint8_t prev_state;
|
||||
uint8_t last_sda;
|
||||
uint8_t last_scl;
|
||||
uint16_t data_out;
|
||||
int bit_count; /* number of bits processed so far */
|
||||
uint8_t byte; /* byte value being currently transferred */
|
||||
uint8_t dev_addr; /* current device address */
|
||||
uint8_t reg_addr; /* current register address */
|
||||
uint8_t *data_ptr; /* ptr to data byte to be transferred next */
|
||||
int bit_count; /* number of bits processed so far */
|
||||
uint8_t byte; /* byte value being currently transferred */
|
||||
uint8_t dev_addr; /* current device address */
|
||||
uint8_t reg_addr; /* current register address */
|
||||
uint8_t* data_ptr; /* ptr to data byte to be transferred next */
|
||||
|
||||
uint8_t edid[128] = {
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
|
||||
0x06, 0x10, 0x02, 0x9d, 0x01, 0x01, 0x01, 0x01,
|
||||
0x08, 0x09, 0x01, 0x01, 0x68, 0x20, 0x18, 0x28,
|
||||
0xe8, 0x04, 0x89, 0xa0, 0x57, 0x4a, 0x9b, 0x26,
|
||||
0x12, 0x48, 0x4c, 0x31, 0x2b, 0x80, 0x31, 0x59,
|
||||
0x45, 0x59, 0x61, 0x59, 0xa9, 0x40, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x60, 0x16,
|
||||
0x40, 0x40, 0x31, 0x70, 0x2b, 0x20, 0x20, 0x40,
|
||||
0x23, 0x00, 0x38, 0xea, 0x10, 0x00, 0x00, 0x18,
|
||||
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
|
||||
};
|
||||
uint8_t edid[128] = {
|
||||
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x06, 0x10, 0x02, 0x9d, 0x01, 0x01, 0x01,
|
||||
0x01, 0x08, 0x09, 0x01, 0x01, 0x68, 0x20, 0x18, 0x28, 0xe8, 0x04, 0x89, 0xa0, 0x57, 0x4a,
|
||||
0x9b, 0x26, 0x12, 0x48, 0x4c, 0x31, 0x2b, 0x80, 0x31, 0x59, 0x45, 0x59, 0x61, 0x59, 0xa9,
|
||||
0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x60, 0x16, 0x40, 0x40, 0x31, 0x70,
|
||||
0x2b, 0x20, 0x20, 0x40, 0x23, 0x00, 0x38, 0xea, 0x10, 0x00, 0x00, 0x18, 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:
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include <cinttypes>
|
||||
#include <iostream>
|
||||
#include "macio.h"
|
||||
#include "viacuda.h"
|
||||
#include "awacs.h"
|
||||
#include "dbdma.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.
|
||||
|
||||
@ -35,49 +35,45 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using namespace std;
|
||||
|
||||
HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow")
|
||||
{
|
||||
this->nvram = new NVram();
|
||||
HeathrowIC::HeathrowIC() : PCIDevice("mac-io/heathrow") {
|
||||
this->nvram = new NVram();
|
||||
|
||||
this->viacuda = new ViaCuda();
|
||||
this->viacuda = new ViaCuda();
|
||||
gMachineObj->add_subdevice("ViaCuda", this->viacuda);
|
||||
|
||||
this->screamer = new AWACDevice();
|
||||
this->screamer = new AWACDevice();
|
||||
this->snd_out_dma = new DMAChannel(this->screamer);
|
||||
this->screamer->set_dma_out(this->snd_out_dma);
|
||||
}
|
||||
|
||||
HeathrowIC::~HeathrowIC()
|
||||
{
|
||||
HeathrowIC::~HeathrowIC() {
|
||||
if (this->nvram)
|
||||
delete(this->nvram);
|
||||
delete (this->nvram);
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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) {
|
||||
case CFG_REG_BAR0: // base address register
|
||||
case CFG_REG_BAR0: // base address register
|
||||
value = LE2BE(value);
|
||||
if (value == 0xFFFFFFFF) {
|
||||
LOG_F(ERROR, "%s err: BAR0 block size determination not \
|
||||
implemented yet \n", this->name.c_str());
|
||||
}
|
||||
else if (value & 1) {
|
||||
LOG_F(
|
||||
ERROR,
|
||||
"%s err: BAR0 block size determination not \
|
||||
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());
|
||||
}
|
||||
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());
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this->base_addr = value & 0xFFF80000;
|
||||
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);
|
||||
@ -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;
|
||||
|
||||
switch(offset >> 8) {
|
||||
switch (offset >> 8) {
|
||||
case 8:
|
||||
res = this->snd_out_dma->reg_read(offset & 0xFF, size);
|
||||
break;
|
||||
@ -101,9 +96,8 @@ uint32_t HeathrowIC::dma_read(uint32_t offset, int size)
|
||||
return res;
|
||||
}
|
||||
|
||||
void HeathrowIC::dma_write(uint32_t offset, uint32_t value, int size)
|
||||
{
|
||||
switch(offset >> 8) {
|
||||
void HeathrowIC::dma_write(uint32_t offset, uint32_t value, int size) {
|
||||
switch (offset >> 8) {
|
||||
case 8:
|
||||
this->snd_out_dma->reg_write(offset & 0xFF, value, size);
|
||||
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;
|
||||
|
||||
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:
|
||||
if (sub_addr >= 0x60) {
|
||||
res = this->nvram->read_byte((offset - 0x60000) >> 4);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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:
|
||||
if (sub_addr >= 0x60) {
|
||||
this->nvram->write_byte((offset - 0x60000) >> 4, value);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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;
|
||||
|
||||
switch (offset & 0xFF) {
|
||||
@ -221,8 +210,7 @@ uint32_t HeathrowIC::mio_ctrl_read(uint32_t offset, int size)
|
||||
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) {
|
||||
case 0x14:
|
||||
LOG_F(9, "read from MIO:Int_Mask2 register \n");
|
||||
|
@ -26,17 +26,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
/** types of different HW components */
|
||||
enum HWCompType : int {
|
||||
UNKNOWN = 0, /* unknown component type */
|
||||
MEM_CTRL = 10, /* memory controller */
|
||||
ROM = 20, /* read-only memory */
|
||||
RAM = 30, /* random access memory */
|
||||
MMIO_DEV = 40, /* memory mapped I/O device */
|
||||
PCI_HOST = 50, /* PCI host */
|
||||
PCI_DEV = 51, /* PCI device */
|
||||
I2C_HOST = 60, /* I2C host */
|
||||
I2C_DEV = 61, /* I2C device */
|
||||
ADB_HOST = 70, /* ADB host */
|
||||
ADB_DEV = 71, /* ADB device */
|
||||
UNKNOWN = 0, /* unknown component type */
|
||||
MEM_CTRL = 10, /* memory controller */
|
||||
ROM = 20, /* read-only memory */
|
||||
RAM = 30, /* random access memory */
|
||||
MMIO_DEV = 40, /* memory mapped I/O device */
|
||||
PCI_HOST = 50, /* PCI host */
|
||||
PCI_DEV = 51, /* PCI device */
|
||||
I2C_HOST = 60, /* I2C host */
|
||||
I2C_DEV = 61, /* I2C device */
|
||||
ADB_HOST = 70, /* ADB host */
|
||||
ADB_DEV = 71, /* ADB device */
|
||||
};
|
||||
|
||||
|
||||
@ -45,8 +45,12 @@ class HWComponent {
|
||||
public:
|
||||
virtual ~HWComponent() = default;
|
||||
|
||||
virtual std::string get_name(void) { return this->name; };
|
||||
virtual void set_name(std::string name) { this->name = name; };
|
||||
virtual std::string get_name(void) {
|
||||
return this->name;
|
||||
};
|
||||
virtual void set_name(std::string name) {
|
||||
this->name = name;
|
||||
};
|
||||
|
||||
virtual bool supports_type(HWCompType type) = 0;
|
||||
|
||||
|
@ -27,26 +27,30 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef I2C_H
|
||||
#define I2C_H
|
||||
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
|
||||
/** Base class for I2C devices */
|
||||
class I2CDevice {
|
||||
public:
|
||||
virtual void start_transaction() = 0;
|
||||
virtual void start_transaction() = 0;
|
||||
virtual bool send_subaddress(uint8_t sub_addr) = 0;
|
||||
virtual bool send_byte(uint8_t data) = 0;
|
||||
virtual bool receive_byte(uint8_t *p_data) = 0;
|
||||
virtual bool send_byte(uint8_t data) = 0;
|
||||
virtual bool receive_byte(uint8_t* p_data) = 0;
|
||||
};
|
||||
|
||||
/** Base class for I2C hosts */
|
||||
class I2CBus {
|
||||
public:
|
||||
I2CBus() { std::memset(this->dev_list, 0, sizeof(this->dev_list)); };
|
||||
~I2CBus() { std::memset(this->dev_list, 0, sizeof(this->dev_list)); };
|
||||
I2CBus() {
|
||||
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]) {
|
||||
throw std::invalid_argument(std::string("I2C address already taken!"));
|
||||
}
|
||||
@ -77,7 +81,7 @@ public:
|
||||
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]) {
|
||||
return false; /* no device -> no acknowledge */
|
||||
}
|
||||
@ -85,7 +89,7 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
I2CDevice *dev_list[128]; /* list of registered I2C devices */
|
||||
I2CDevice* dev_list[128]; /* list of registered I2C devices */
|
||||
};
|
||||
|
||||
#endif /* I2C_H */
|
||||
|
@ -22,9 +22,9 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef MACHINE_ID_H
|
||||
#define MACHINE_ID_H
|
||||
|
||||
#include <cinttypes>
|
||||
#include "hwcomponent.h"
|
||||
#include "mmiodevice.h"
|
||||
#include <cinttypes>
|
||||
|
||||
/**
|
||||
@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 {
|
||||
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;
|
||||
|
||||
bool supports_type(HWCompType type) {
|
||||
@ -52,10 +54,10 @@ public:
|
||||
};
|
||||
|
||||
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)
|
||||
{}; /* not writable */
|
||||
void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size){}; /* not writable */
|
||||
|
||||
private:
|
||||
uint16_t id;
|
||||
|
@ -51,16 +51,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef 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 "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
|
||||
@ -86,19 +86,22 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
VIA-CUDA register space: 0x00016000, size: 0x00002000
|
||||
*/
|
||||
|
||||
class HeathrowIC : public PCIDevice
|
||||
{
|
||||
class HeathrowIC : public PCIDevice {
|
||||
public:
|
||||
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 */
|
||||
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);
|
||||
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);
|
||||
|
||||
/* MMIO device methods */
|
||||
uint32_t read(uint32_t reg_start, uint32_t offset, int size);
|
||||
@ -113,17 +116,23 @@ protected:
|
||||
|
||||
private:
|
||||
uint8_t pci_cfg_hdr[256] = {
|
||||
0x6B, 0x10, // vendor ID: Apple Computer Inc.
|
||||
0x10, 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
|
||||
0x6B,
|
||||
0x10, // vendor ID: Apple Computer Inc.
|
||||
0x10,
|
||||
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
|
||||
// class code is reported in OF property "class-code" as 0xff0000
|
||||
0x00, // standard programming
|
||||
0x00, // subclass code
|
||||
0xFF, // class code: unassigned
|
||||
0x00, 0x00, // unknown defaults
|
||||
0x00, 0x00 // unknown defaults
|
||||
0x00, // standard programming
|
||||
0x00, // subclass code
|
||||
0xFF, // class code: unassigned
|
||||
0x00,
|
||||
0x00, // unknown defaults
|
||||
0x00,
|
||||
0x00 // unknown defaults
|
||||
};
|
||||
|
||||
uint32_t int_mask2;
|
||||
@ -132,14 +141,14 @@ private:
|
||||
uint32_t int_mask1;
|
||||
uint32_t int_clear1;
|
||||
uint32_t int_levels1;
|
||||
uint32_t feat_ctrl; // features control register
|
||||
uint32_t feat_ctrl; // features control register
|
||||
|
||||
/* device cells */
|
||||
ViaCuda *viacuda; /* VIA cell with Cuda MCU attached to it */
|
||||
NVram *nvram; /* NVRAM cell */
|
||||
AWACDevice *screamer; /* Screamer audio codec instance */
|
||||
ViaCuda* viacuda; /* VIA cell with Cuda MCU attached to it */
|
||||
NVram* nvram; /* NVRAM cell */
|
||||
AWACDevice* screamer; /* Screamer audio codec instance */
|
||||
|
||||
DMAChannel *snd_out_dma;
|
||||
DMAChannel* snd_out_dma;
|
||||
};
|
||||
|
||||
#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/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <algorithm> // to shut up MSVC errors (:
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm> // to shut up MSVC errors (:
|
||||
|
||||
#include "memctrlbase.h"
|
||||
|
||||
|
||||
MemCtrlBase::~MemCtrlBase()
|
||||
{
|
||||
for (auto ® : mem_regions) {
|
||||
MemCtrlBase::~MemCtrlBase() {
|
||||
for (auto& reg : mem_regions) {
|
||||
if (reg)
|
||||
delete(reg);
|
||||
delete (reg);
|
||||
}
|
||||
this->mem_regions.clear();
|
||||
this->address_map.clear();
|
||||
}
|
||||
|
||||
|
||||
AddressMapEntry *MemCtrlBase::find_range(uint32_t addr)
|
||||
{
|
||||
for (auto &entry : address_map) {
|
||||
AddressMapEntry* MemCtrlBase::find_range(uint32_t addr) {
|
||||
for (auto& entry : address_map) {
|
||||
if (addr >= entry.start && addr <= entry.end)
|
||||
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,
|
||||
uint32_t dest_addr, uint32_t type, uint8_t init_val = 0)
|
||||
{
|
||||
bool MemCtrlBase::add_mem_region(
|
||||
uint32_t start_addr, uint32_t size, uint32_t dest_addr, uint32_t type, uint8_t init_val = 0) {
|
||||
AddressMapEntry entry;
|
||||
|
||||
/* error if a memory region for the given range already exists */
|
||||
if (find_range(start_addr) || find_range(start_addr + size))
|
||||
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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
{
|
||||
AddressMapEntry *ref_entry;
|
||||
bool MemCtrlBase::set_data(uint32_t reg_addr, const uint8_t* data, uint32_t size) {
|
||||
AddressMapEntry* ref_entry;
|
||||
uint32_t cpy_size;
|
||||
|
||||
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,
|
||||
MMIODevice *dev_instance)
|
||||
{
|
||||
bool MemCtrlBase::add_mmio_region(uint32_t start_addr, uint32_t size, MMIODevice* dev_instance) {
|
||||
AddressMapEntry entry;
|
||||
|
||||
/* error if another region for the given range already exists */
|
||||
|
@ -22,27 +22,27 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef MEMORY_CONTROLLER_BASE_H
|
||||
#define MEMORY_CONTROLLER_BASE_H
|
||||
|
||||
#include "mmiodevice.h"
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "mmiodevice.h"
|
||||
|
||||
enum RangeType {
|
||||
RT_ROM = 1, /* read-only memory */
|
||||
RT_RAM = 2, /* random access memory */
|
||||
RT_MMIO = 4, /* memory mapped I/O */
|
||||
RT_MIRROR = 8 /* region mirror (content of another region is acessible
|
||||
at some other address) */
|
||||
RT_ROM = 1, /* read-only memory */
|
||||
RT_RAM = 2, /* random access memory */
|
||||
RT_MMIO = 4, /* memory mapped I/O */
|
||||
RT_MIRROR = 8 /* region mirror (content of another region is acessible
|
||||
at some other address) */
|
||||
};
|
||||
|
||||
/** Defines the format for the address map entry. */
|
||||
typedef struct AddressMapEntry {
|
||||
uint32_t start; /* first address of the corresponding range */
|
||||
uint32_t end; /* last address of the corresponding range */
|
||||
uint32_t mirror; /* mirror address for RT_MIRROR */
|
||||
uint32_t type; /* range type */
|
||||
MMIODevice* devobj; /* pointer to device object */
|
||||
unsigned char* mem_ptr; /* direct pointer to data for memory objects */
|
||||
uint32_t start; /* first address of the corresponding range */
|
||||
uint32_t end; /* last address of the corresponding range */
|
||||
uint32_t mirror; /* mirror address for RT_MIRROR */
|
||||
uint32_t type; /* range type */
|
||||
MMIODevice* devobj; /* pointer to device object */
|
||||
unsigned char* mem_ptr; /* direct pointer to data for memory objects */
|
||||
} AddressMapEntry;
|
||||
|
||||
|
||||
@ -55,18 +55,18 @@ public:
|
||||
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_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:
|
||||
bool add_mem_region(uint32_t start_addr, uint32_t size, uint32_t dest_addr,
|
||||
uint32_t type, uint8_t init_val);
|
||||
bool add_mem_region(
|
||||
uint32_t start_addr, uint32_t size, uint32_t dest_addr, uint32_t type, uint8_t init_val);
|
||||
|
||||
private:
|
||||
std::vector<uint8_t *> mem_regions;
|
||||
std::vector<uint8_t*> mem_regions;
|
||||
std::vector<AddressMapEntry> address_map;
|
||||
};
|
||||
|
||||
|
@ -22,16 +22,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef MMIO_DEVICE_H
|
||||
#define MMIO_DEVICE_H
|
||||
|
||||
#include "hwcomponent.h"
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
#include "hwcomponent.h"
|
||||
|
||||
/** Abstract class representing a simple, memory-mapped I/O device */
|
||||
class MMIODevice : public HWComponent {
|
||||
public:
|
||||
virtual uint32_t read(uint32_t reg_start, uint32_t offset, int size) = 0;
|
||||
virtual uint32_t read(uint32_t reg_start, uint32_t offset, int size) = 0;
|
||||
virtual void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size) = 0;
|
||||
virtual ~MMIODevice() = default;
|
||||
virtual ~MMIODevice() = default;
|
||||
};
|
||||
|
||||
#endif /* MMIO_DEVICE_H */
|
||||
|
@ -24,20 +24,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
Author: Max Poliakovski
|
||||
*/
|
||||
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
|
||||
#include "memreadwrite.h"
|
||||
#include "memctrlbase.h"
|
||||
#include "mmiodevice.h"
|
||||
#include "hwcomponent.h"
|
||||
#include "memctrlbase.h"
|
||||
#include "memreadwrite.h"
|
||||
#include "mmiodevice.h"
|
||||
#include "mpc106.h"
|
||||
|
||||
|
||||
MPC106::MPC106() : MemCtrlBase(), PCIDevice("Grackle PCI host bridge")
|
||||
{
|
||||
MPC106::MPC106() : MemCtrlBase(), PCIDevice("Grackle PCI host bridge") {
|
||||
this->name = "Grackle";
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
MPC106::~MPC106()
|
||||
{
|
||||
MPC106::~MPC106() {
|
||||
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 ||
|
||||
type == HWCompType::PCI_HOST || type == HWCompType::PCI_DEV) {
|
||||
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;
|
||||
|
||||
if (reg_start == 0xFE000000) {
|
||||
@ -78,10 +74,9 @@ 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);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -91,8 +86,7 @@ uint32_t MPC106::read(uint32_t reg_start, uint32_t offset, int size)
|
||||
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) {
|
||||
/* broadcast I/O request to devices that support I/O space
|
||||
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);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (offset < 0x200000) {
|
||||
this->config_addr = value;
|
||||
}
|
||||
else {
|
||||
if (this->config_addr & 0x80) // process only if bit E (enable) is set
|
||||
} else {
|
||||
if (this->config_addr & 0x80) // process only if bit E (enable) is set
|
||||
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;
|
||||
|
||||
bus_num = (this->config_addr >> 8) & 0xFF;
|
||||
if (bus_num) {
|
||||
LOG_F(ERROR, "%s err: read attempt from non-local PCI bus, config_addr = %x \n", \
|
||||
this->name.c_str(), this->config_addr);
|
||||
LOG_F(
|
||||
ERROR,
|
||||
"%s err: read attempt from non-local PCI bus, config_addr = %x \n",
|
||||
this->name.c_str(),
|
||||
this->config_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -129,13 +123,17 @@ uint32_t MPC106::pci_read(uint32_t size)
|
||||
fun_num = (this->config_addr >> 16) & 0x07;
|
||||
reg_offs = (this->config_addr >> 24) & 0xFC;
|
||||
|
||||
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
||||
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
||||
return this->pci_cfg_read(reg_offs, size);
|
||||
} else {
|
||||
if (this->pci_0_bus.count(dev_num)) {
|
||||
return this->pci_0_bus[dev_num]->pci_cfg_read(reg_offs, size);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
@ -143,14 +141,16 @@ uint32_t MPC106::pci_read(uint32_t size)
|
||||
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;
|
||||
|
||||
bus_num = (this->config_addr >> 8) & 0xFF;
|
||||
if (bus_num) {
|
||||
LOG_F(ERROR, "%s err: write attempt to non-local PCI bus, config_addr = %x \n",
|
||||
this->name.c_str(), this->config_addr);
|
||||
LOG_F(
|
||||
ERROR,
|
||||
"%s err: write attempt to non-local PCI bus, config_addr = %x \n",
|
||||
this->name.c_str(),
|
||||
this->config_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -158,25 +158,27 @@ void MPC106::pci_write(uint32_t value, uint32_t size)
|
||||
fun_num = (this->config_addr >> 16) & 0x07;
|
||||
reg_offs = (this->config_addr >> 24) & 0xFC;
|
||||
|
||||
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
||||
if (dev_num == 0 && fun_num == 0) { // dev_num 0 is assigned to myself
|
||||
this->pci_cfg_write(reg_offs, value, size);
|
||||
} else {
|
||||
if (this->pci_0_bus.count(dev_num)) {
|
||||
this->pci_0_bus[dev_num]->pci_cfg_write(reg_offs, value, size);
|
||||
} else {
|
||||
LOG_F(ERROR, "%s err: write attempt to non-existing PCI device %d \n", \
|
||||
this->name.c_str(), dev_num);
|
||||
LOG_F(
|
||||
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
|
||||
LOG_F(9, "read from Grackle register %08X\n", reg_offs);
|
||||
#endif
|
||||
|
||||
switch(size) {
|
||||
switch (size) {
|
||||
case 1:
|
||||
return this->my_pci_cfg_hdr[reg_offs];
|
||||
break;
|
||||
@ -193,26 +195,25 @@ uint32_t MPC106::pci_cfg_read(uint32_t reg_offs, uint32_t size)
|
||||
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
|
||||
LOG_F(9, "write %08X to Grackle register %08X\n", value, reg_offs);
|
||||
#endif
|
||||
|
||||
// FIXME: implement write-protection for read-only registers
|
||||
switch(size) {
|
||||
switch (size) {
|
||||
case 1:
|
||||
this->my_pci_cfg_hdr[reg_offs] = value & 0xFF;
|
||||
this->my_pci_cfg_hdr[reg_offs] = value & 0xFF;
|
||||
break;
|
||||
case 2:
|
||||
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] = (value >> 8) & 0xFF;
|
||||
this->my_pci_cfg_hdr[reg_offs + 1] = value & 0xFF;
|
||||
break;
|
||||
case 4:
|
||||
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+2] = (value >> 8) & 0xFF;
|
||||
this->my_pci_cfg_hdr[reg_offs+3] = value & 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 + 2] = (value >> 8) & 0xFF;
|
||||
this->my_pci_cfg_hdr[reg_offs + 3] = value & 0xFF;
|
||||
break;
|
||||
default:
|
||||
LOG_F(ERROR, "MPC106 read error: invalid size parameter %d \n", size);
|
||||
@ -226,9 +227,8 @@ 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)
|
||||
{
|
||||
if (this->pci_0_bus.count(dev_num)) // is dev_num already registered?
|
||||
bool MPC106::pci_register_device(int dev_num, PCIDevice* dev_instance) {
|
||||
if (this->pci_0_bus.count(dev_num)) // is dev_num already registered?
|
||||
return false;
|
||||
|
||||
this->pci_0_bus[dev_num] = dev_instance;
|
||||
@ -242,31 +242,29 @@ bool MPC106::pci_register_device(int dev_num, PCIDevice *dev_instance)
|
||||
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!
|
||||
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 ram_size = 0;
|
||||
|
||||
uint8_t bank_en = this->my_pci_cfg_hdr[0xA0];
|
||||
uint8_t bank_en = this->my_pci_cfg_hdr[0xA0];
|
||||
|
||||
for (int bank = 0; bank < 8; bank++) {
|
||||
if (bank_en & (1 << bank)) {
|
||||
if (bank < 4) {
|
||||
mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x80]);
|
||||
mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x80]);
|
||||
ext_mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x88]);
|
||||
mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x90]);
|
||||
ext_mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x98]);
|
||||
mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x90]);
|
||||
ext_mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x98]);
|
||||
} else {
|
||||
mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x84]);
|
||||
mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x84]);
|
||||
ext_mem_start = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x8C]);
|
||||
mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x94]);
|
||||
ext_mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x9C]);
|
||||
mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x94]);
|
||||
ext_mem_end = READ_DWORD_LE_A(&this->my_pci_cfg_hdr[0x9C]);
|
||||
}
|
||||
bank_start = (((ext_mem_start >> bank * 8) & 3) << 30) |
|
||||
(((mem_start >> bank * 8) & 0xFF) << 20);
|
||||
|
155
devices/mpc106.h
155
devices/mpc106.h
@ -35,17 +35,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef MPC106_H_
|
||||
#define MPC106_H_
|
||||
|
||||
#include <cinttypes>
|
||||
#include <unordered_map>
|
||||
#include "hwcomponent.h"
|
||||
#include "memctrlbase.h"
|
||||
#include "mmiodevice.h"
|
||||
#include "pcidevice.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:
|
||||
MPC106();
|
||||
~MPC106();
|
||||
@ -56,7 +55,7 @@ public:
|
||||
void write(uint32_t reg_start, uint32_t offset, uint32_t value, int size);
|
||||
|
||||
/* 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:
|
||||
/* PCI access */
|
||||
@ -67,110 +66,102 @@ protected:
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
private:
|
||||
uint8_t my_pci_cfg_hdr[256] = {
|
||||
0x57, 0x10, // vendor ID: Motorola
|
||||
0x02, 0x00, // device ID: MPC106
|
||||
0x06, 0x00, // PCI command
|
||||
0x80, 0x00, // PCI status
|
||||
0x40, // revision ID: 4.0
|
||||
0x00, // standard programming
|
||||
0x00, // subclass code: host bridge
|
||||
0x06, // class code: bridge device
|
||||
0x08, // cache line size
|
||||
0x00, // latency timer
|
||||
0x00, // header type
|
||||
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,
|
||||
0x00, //Interrupt line
|
||||
0x00, //Interrupt pin
|
||||
0x00, //MIN GNT
|
||||
0x00, //MAX LAT
|
||||
0x00, //Bus number
|
||||
0x00, //Subordinate bus number
|
||||
0x00, //Discount counter
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x00, 0x00, 0x00, //Performance monitor command
|
||||
0x00, 0x00, //Performance monitor mode control
|
||||
0x57, 0x10, // vendor ID: Motorola
|
||||
0x02, 0x00, // device ID: MPC106
|
||||
0x06, 0x00, // PCI command
|
||||
0x80, 0x00, // PCI status
|
||||
0x40, // revision ID: 4.0
|
||||
0x00, // standard programming
|
||||
0x00, // subclass code: host bridge
|
||||
0x06, // class code: bridge device
|
||||
0x08, // cache line size
|
||||
0x00, // latency timer
|
||||
0x00, // header type
|
||||
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,
|
||||
0x00, // Interrupt line
|
||||
0x00, // Interrupt pin
|
||||
0x00, // MIN GNT
|
||||
0x00, // MAX LAT
|
||||
0x00, // Bus number
|
||||
0x00, // Subordinate bus number
|
||||
0x00, // Discount counter
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // Performance monitor command
|
||||
0x00, 0x00, // Performance monitor mode control
|
||||
0xFF, 0xFF,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00, //Performance monitor counter 0
|
||||
0x00, 0x00, 0x00, 0x00, //Performance monitor counter 1
|
||||
0x00, 0x00, 0x00, 0x00, //Performance monitor counter 2
|
||||
0x00, 0x00, 0x00, 0x00, //Performance monitor counter 3
|
||||
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 0
|
||||
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 1
|
||||
0x00, 0x00, 0x00, 0x00, // Performance monitor counter 2
|
||||
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, //Power mgt config 2
|
||||
0xCD, //default value for ODCR
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
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, //Memory Ending Address
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //Extended Memory Ending Address
|
||||
0x00, 0x00, // Power mgt config 1
|
||||
0x00, // Power mgt config 2
|
||||
0xCD, // default value for ODCR
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 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, // 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,
|
||||
0x00, //Memory page mode
|
||||
0x00, // Memory page mode
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
|
||||
0x10, 0x00, 0x00, 0xFF, // PICR1
|
||||
0x0C, 0x06, 0x0C, 0x00, // PICR2
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, //ECC single-bit error counter
|
||||
0x00, //ECC single-bit error trigger
|
||||
0x04, //Alternate OS visible paramaters 1
|
||||
0x01, //Alternate OS visible paramaters 2
|
||||
0x10, 0x00, 0x00, 0xFF, // PICR1
|
||||
0x0C, 0x06, 0x0C, 0x00, // PICR2
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, // ECC single-bit error counter
|
||||
0x00, // ECC single-bit error trigger
|
||||
0x04, // Alternate OS visible paramaters 1
|
||||
0x01, // Alternate OS visible paramaters 2
|
||||
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
|
||||
0x01, //Error enabling 1
|
||||
0x00, //Error detection 1
|
||||
0x01, // Error enabling 1
|
||||
0x00, // Error detection 1
|
||||
0xFF,
|
||||
0x00, //60x bus error status
|
||||
0x00, //Error enabling 2
|
||||
0x00, //Error detection 2
|
||||
0x00, // 60x bus error status
|
||||
0x00, // Error enabling 2
|
||||
0x00, // Error detection 2
|
||||
0xFF,
|
||||
0x00, //PCI bus error status
|
||||
0x00, 0x00, 0x00, 0x00, //60x/PCI ERROR address
|
||||
0x00, // PCI bus error status
|
||||
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,
|
||||
|
||||
0x42, 0x00, 0xFF, 0x0F, //Emulation support config 1
|
||||
0x00, 0x00, 0x00, 0x00, //Modified memory status (no clear)
|
||||
0x20, 0x00, 0x00, 0x00, //Emulation support config 2
|
||||
0x00, 0x00, 0x00, 0x00, //Modified memory status (clear)
|
||||
0x42, 0x00, 0xFF, 0x0F, // Emulation support config 1
|
||||
0x00, 0x00, 0x00, 0x00, // Modified memory status (no clear)
|
||||
0x20, 0x00, 0x00, 0x00, // Emulation support config 2
|
||||
0x00, 0x00, 0x00, 0x00, // Modified memory status (clear)
|
||||
|
||||
0x00, 0x00, 0x02, 0xFF, //Memory ctrl config 1
|
||||
0x03, 0x00, 0x00, 0x00, //Memory ctrl config 2
|
||||
0x00, 0x00, 0x00, 0x00, //Memory ctrl config 3
|
||||
0x00, 0x00, 0x10, 0x00 //Memory ctrl config 4
|
||||
0x00, 0x00, 0x02, 0xFF, // Memory ctrl config 1
|
||||
0x03, 0x00, 0x00, 0x00, // Memory ctrl config 2
|
||||
0x00, 0x00, 0x00, 0x00, // Memory ctrl config 3
|
||||
0x00, 0x00, 0x10, 0x00 // Memory ctrl config 4
|
||||
};
|
||||
|
||||
uint32_t config_addr;
|
||||
//uint32_t config_data;
|
||||
// uint32_t config_data;
|
||||
|
||||
std::unordered_map<int, PCIDevice*> pci_0_bus;
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <cinttypes>
|
||||
#include "nvram.h"
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
|
||||
/** @file Non-volatile RAM implementation.
|
||||
*/
|
||||
@ -34,8 +34,7 @@ using namespace std;
|
||||
/** the signature for NVRAM backing file identification. */
|
||||
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->ram_size = ram_size;
|
||||
|
||||
@ -44,35 +43,30 @@ NVram::NVram(std::string file_name, uint32_t ram_size)
|
||||
this->init();
|
||||
}
|
||||
|
||||
NVram::~NVram()
|
||||
{
|
||||
NVram::~NVram() {
|
||||
this->save();
|
||||
if (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]);
|
||||
}
|
||||
|
||||
void NVram::write_byte(uint32_t offset, uint8_t val)
|
||||
{
|
||||
void NVram::write_byte(uint32_t offset, uint8_t val) {
|
||||
this->storage[offset] = val;
|
||||
}
|
||||
|
||||
void NVram::init() {
|
||||
char sig[sizeof(NVRAM_FILE_ID)];
|
||||
char sig[sizeof(NVRAM_FILE_ID)];
|
||||
uint16_t data_size;
|
||||
|
||||
ifstream f(this->file_name, ios::in | ios::binary);
|
||||
|
||||
if (f.fail() || !f.read(sig, sizeof(NVRAM_FILE_ID)) || \
|
||||
!f.read((char *)&data_size, sizeof(data_size)) || \
|
||||
memcmp(sig, NVRAM_FILE_ID, sizeof(NVRAM_FILE_ID)) || \
|
||||
data_size != this->ram_size || \
|
||||
!f.read((char *)this->storage, this->ram_size))
|
||||
{
|
||||
if (f.fail() || !f.read(sig, sizeof(NVRAM_FILE_ID)) ||
|
||||
!f.read((char*)&data_size, sizeof(data_size)) ||
|
||||
memcmp(sig, NVRAM_FILE_ID, sizeof(NVRAM_FILE_ID)) || data_size != this->ram_size ||
|
||||
!f.read((char*)this->storage, this->ram_size)) {
|
||||
LOG_F(WARNING, "Could not restore NVRAM content from the given file. \n");
|
||||
memset(this->storage, 0, sizeof(this->ram_size));
|
||||
}
|
||||
@ -80,16 +74,15 @@ void NVram::init() {
|
||||
f.close();
|
||||
}
|
||||
|
||||
void NVram::save()
|
||||
{
|
||||
void NVram::save() {
|
||||
ofstream f(this->file_name, ios::out | ios::binary);
|
||||
|
||||
/* write file identification */
|
||||
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 */
|
||||
f.write((char *)this->storage, this->ram_size);
|
||||
f.write((char*)this->storage, this->ram_size);
|
||||
|
||||
f.close();
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef NVRAM_H
|
||||
#define NVRAM_H
|
||||
|
||||
#include <string>
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
|
||||
/** @file Non-volatile RAM emulation.
|
||||
|
||||
@ -31,22 +31,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
automatically saved to and restored from the dedicated file.
|
||||
*/
|
||||
|
||||
class NVram
|
||||
{
|
||||
class NVram {
|
||||
public:
|
||||
NVram(std::string file_name = "nvram.bin", uint32_t ram_size = 8192);
|
||||
~NVram();
|
||||
|
||||
uint8_t read_byte(uint32_t offset);
|
||||
void write_byte(uint32_t offset, uint8_t value);
|
||||
void write_byte(uint32_t offset, uint8_t value);
|
||||
|
||||
private:
|
||||
std::string file_name; /* file name for the backing file. */
|
||||
uint16_t ram_size; /* NVRAM size. */
|
||||
uint8_t* storage;
|
||||
uint16_t ram_size; /* NVRAM size. */
|
||||
uint8_t* storage;
|
||||
|
||||
void init();
|
||||
void save();
|
||||
void init();
|
||||
void save();
|
||||
};
|
||||
|
||||
#endif /* NVRAM_H */
|
||||
|
@ -22,51 +22,57 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef PCI_DEVICE_H
|
||||
#define PCI_DEVICE_H
|
||||
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
#include "mmiodevice.h"
|
||||
#include "pcihost.h"
|
||||
#include <cinttypes>
|
||||
#include <string>
|
||||
|
||||
/* convert little-endian DWORD to big-endian DWORD */
|
||||
#define LE2BE(x) (x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24)
|
||||
|
||||
/** PCI configuration space registers offsets */
|
||||
enum {
|
||||
CFG_REG_CMD = 0x04, // command/status register
|
||||
CFG_REG_BAR0 = 0x10, // base address register 0
|
||||
CFG_REG_BAR1 = 0x14, // base address register 1
|
||||
CFG_REG_BAR2 = 0x18, // base address register 2
|
||||
CFG_REG_BAR3 = 0x1C, // base address register 3
|
||||
CFG_REG_BAR4 = 0x20, // base address register 4
|
||||
CFG_REG_BAR5 = 0x24, // base address register 5
|
||||
CFG_EXP_BASE = 0x30, // expansion ROM base
|
||||
CFG_REG_CMD = 0x04, // command/status register
|
||||
CFG_REG_BAR0 = 0x10, // base address register 0
|
||||
CFG_REG_BAR1 = 0x14, // base address register 1
|
||||
CFG_REG_BAR2 = 0x18, // base address register 2
|
||||
CFG_REG_BAR3 = 0x1C, // base address register 3
|
||||
CFG_REG_BAR4 = 0x20, // base address register 4
|
||||
CFG_REG_BAR5 = 0x24, // base address register 5
|
||||
CFG_EXP_BASE = 0x30, // expansion ROM base
|
||||
};
|
||||
|
||||
|
||||
class PCIDevice : public MMIODevice {
|
||||
public:
|
||||
PCIDevice(std::string name) { this->pci_name = name; };
|
||||
PCIDevice(std::string name) {
|
||||
this->pci_name = name;
|
||||
};
|
||||
virtual ~PCIDevice() = default;
|
||||
|
||||
virtual bool supports_io_space(void) = 0;
|
||||
|
||||
/* I/O space access methods */
|
||||
virtual bool pci_io_read(uint32_t offset, uint32_t size, uint32_t* res)
|
||||
{ return false; };
|
||||
virtual bool pci_io_read(uint32_t offset, uint32_t size, uint32_t* res) {
|
||||
return false;
|
||||
};
|
||||
|
||||
virtual bool pci_io_write(uint32_t offset, uint32_t value, uint32_t size)
|
||||
{ return false; };
|
||||
virtual bool pci_io_write(uint32_t offset, uint32_t value, uint32_t size) {
|
||||
return false;
|
||||
};
|
||||
|
||||
/* configuration space access methods */
|
||||
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 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 set_host(PCIHost* host_instance) { this->host_instance = host_instance; };
|
||||
virtual void set_host(PCIHost* host_instance) {
|
||||
this->host_instance = host_instance;
|
||||
};
|
||||
|
||||
protected:
|
||||
std::string pci_name; // human-readable device name
|
||||
PCIHost *host_instance; // host bridge instance to call back
|
||||
uint32_t base_addr; // base address register 0
|
||||
std::string pci_name; // human-readable device name
|
||||
PCIHost* host_instance; // host bridge instance to call back
|
||||
uint32_t base_addr; // base address register 0
|
||||
};
|
||||
|
||||
#endif /* PCI_DEVICE_H */
|
||||
|
@ -3,13 +3,12 @@
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
class PCIDevice; // forward declaration to prevent errors
|
||||
class PCIDevice; // forward declaration to prevent errors
|
||||
|
||||
class PCIHost {
|
||||
public:
|
||||
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,
|
||||
PCIDevice *obj) = 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, PCIDevice* obj) = 0;
|
||||
};
|
||||
|
||||
#endif /* PCI_HOST_H */
|
||||
|
@ -47,31 +47,31 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef 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 "i2c.h"
|
||||
#include <cinttypes>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
|
||||
enum RAMType : int {
|
||||
SDRAM = 4
|
||||
};
|
||||
enum RAMType : int { SDRAM = 4 };
|
||||
|
||||
|
||||
class SpdSdram168 : public HWComponent, public I2CDevice {
|
||||
public:
|
||||
SpdSdram168(uint8_t addr) {
|
||||
this->dev_addr = addr;
|
||||
this->pos = 0;
|
||||
this->pos = 0;
|
||||
};
|
||||
|
||||
~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) {
|
||||
switch(capacity_megs) {
|
||||
switch (capacity_megs) {
|
||||
case 32:
|
||||
this->eeprom_data[3] = 0xC; /* 12 rows */
|
||||
this->eeprom_data[4] = 0x8; /* 8 columns */
|
||||
@ -95,11 +95,12 @@ public:
|
||||
default:
|
||||
throw std::invalid_argument(std::string("Unsupported capacity!"));
|
||||
}
|
||||
LOG_F(INFO, "SDRAM capacity set to %dMB, I2C addr = 0x%X",
|
||||
capacity_megs, this->dev_addr);
|
||||
LOG_F(INFO, "SDRAM capacity set to %dMB, I2C addr = 0x%X", capacity_megs, this->dev_addr);
|
||||
};
|
||||
|
||||
void start_transaction() { this->pos = 0; };
|
||||
void start_transaction() {
|
||||
this->pos = 0;
|
||||
};
|
||||
|
||||
bool send_subaddress(uint8_t sub_addr) {
|
||||
this->pos = sub_addr;
|
||||
@ -112,7 +113,7 @@ public:
|
||||
return true;
|
||||
};
|
||||
|
||||
bool receive_byte(uint8_t *p_data) {
|
||||
bool receive_byte(uint8_t* p_data) {
|
||||
if (this->pos >= this->eeprom_data[0]) {
|
||||
this->pos = 0; /* attempt to read past SPD data should wrap around */
|
||||
}
|
||||
@ -123,18 +124,18 @@ public:
|
||||
|
||||
private:
|
||||
uint8_t dev_addr; /* I2C address */
|
||||
int pos; /* actual read position */
|
||||
int pos; /* actual read position */
|
||||
|
||||
/* EEPROM content */
|
||||
uint8_t eeprom_data[256] = {
|
||||
128, /* number of bytes present */
|
||||
8, /* log2(EEPROM size) */
|
||||
128, /* number of bytes present */
|
||||
8, /* log2(EEPROM size) */
|
||||
RAMType::SDRAM, /* memory type */
|
||||
|
||||
/* the following fields will be set up in set_capacity() */
|
||||
0, /* number of row addresses */
|
||||
0, /* number of column addresses */
|
||||
0 /* number of banks */
|
||||
0 /* number of banks */
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -24,15 +24,14 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
Author: Max Poliakovski 2019
|
||||
*/
|
||||
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include <cinttypes>
|
||||
#include "viacuda.h"
|
||||
#include "adb.h"
|
||||
#include <cinttypes>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
ViaCuda::ViaCuda()
|
||||
{
|
||||
ViaCuda::ViaCuda() {
|
||||
this->name = "ViaCuda";
|
||||
|
||||
/* FIXME: is this the correct
|
||||
@ -44,7 +43,7 @@ ViaCuda::ViaCuda()
|
||||
this->via_regs[VIA_T1LH] = 0xFF;
|
||||
this->via_regs[VIA_IER] = 0x7F;
|
||||
|
||||
//PRAM Pre-Initialization
|
||||
// PRAM Pre-Initialization
|
||||
this->pram_obj = new NVram("pram.bin", 256);
|
||||
|
||||
this->adb_obj = new ADB_Bus();
|
||||
@ -52,14 +51,12 @@ ViaCuda::ViaCuda()
|
||||
this->init();
|
||||
}
|
||||
|
||||
ViaCuda::~ViaCuda()
|
||||
{
|
||||
ViaCuda::~ViaCuda() {
|
||||
if (this->pram_obj)
|
||||
delete (this->pram_obj);
|
||||
}
|
||||
|
||||
void ViaCuda::init()
|
||||
{
|
||||
void ViaCuda::init() {
|
||||
this->old_tip = 0;
|
||||
this->old_byteack = 0;
|
||||
this->treq = 1;
|
||||
@ -68,8 +65,7 @@ void ViaCuda::init()
|
||||
this->poll_rate = 11;
|
||||
}
|
||||
|
||||
uint8_t ViaCuda::read(int reg)
|
||||
{
|
||||
uint8_t ViaCuda::read(int reg) {
|
||||
uint8_t res;
|
||||
|
||||
LOG_F(9, "Read VIA reg %x \n", (uint32_t)reg);
|
||||
@ -92,8 +88,7 @@ uint8_t ViaCuda::read(int reg)
|
||||
return res;
|
||||
}
|
||||
|
||||
void ViaCuda::write(int reg, uint8_t value)
|
||||
{
|
||||
void ViaCuda::write(int reg, uint8_t value) {
|
||||
switch (reg & 0xF) {
|
||||
case VIA_B:
|
||||
this->via_regs[VIA_B] = value;
|
||||
@ -120,8 +115,7 @@ void ViaCuda::write(int reg, uint8_t value)
|
||||
this->via_regs[VIA_ACR] = value;
|
||||
break;
|
||||
case VIA_IER:
|
||||
this->via_regs[VIA_IER] = (value & 0x80) ? value & 0x7F
|
||||
: this->via_regs[VIA_IER] & ~value;
|
||||
this->via_regs[VIA_IER] = (value & 0x80) ? value & 0x7F : this->via_regs[VIA_IER] & ~value;
|
||||
LOG_F(INFO, "VIA_IER updated to %d \n", (uint32_t)this->via_regs[VIA_IER]);
|
||||
print_enabled_ints();
|
||||
break;
|
||||
@ -130,9 +124,8 @@ void ViaCuda::write(int reg, uint8_t value)
|
||||
}
|
||||
}
|
||||
|
||||
void ViaCuda::print_enabled_ints()
|
||||
{
|
||||
const char *via_int_src[] = { "CA2", "CA1", "SR", "CB2", "CB1", "T2", "T1" };
|
||||
void ViaCuda::print_enabled_ints() {
|
||||
const char* via_int_src[] = {"CA2", "CA1", "SR", "CB2", "CB1", "T2", "T1"};
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (this->via_regs[VIA_IER] & (1 << i))
|
||||
@ -140,24 +133,21 @@ void ViaCuda::print_enabled_ints()
|
||||
}
|
||||
}
|
||||
|
||||
inline bool ViaCuda::ready()
|
||||
{
|
||||
inline bool ViaCuda::ready() {
|
||||
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;
|
||||
}
|
||||
|
||||
void ViaCuda::write(uint8_t new_state)
|
||||
{
|
||||
void ViaCuda::write(uint8_t new_state) {
|
||||
if (!ready()) {
|
||||
LOG_F(WARNING, "Cuda not ready! \n");
|
||||
return;
|
||||
}
|
||||
|
||||
int new_tip = !!(new_state & CUDA_TIP);
|
||||
int new_tip = !!(new_state & CUDA_TIP);
|
||||
int new_byteack = !!(new_state & CUDA_BYTEACK);
|
||||
|
||||
/* return if there is no state change */
|
||||
@ -166,7 +156,7 @@ void ViaCuda::write(uint8_t new_state)
|
||||
|
||||
LOG_F(9, "Cuda state changed! \n");
|
||||
|
||||
this->old_tip = new_tip;
|
||||
this->old_tip = new_tip;
|
||||
this->old_byteack = new_byteack;
|
||||
|
||||
if (new_tip) {
|
||||
@ -183,8 +173,7 @@ void ViaCuda::write(uint8_t new_state)
|
||||
}
|
||||
|
||||
this->in_count = 0;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_F(9, "Cuda: enter sync state \n");
|
||||
this->via_regs[VIA_B] &= ~CUDA_TREQ; /* assert TREQ */
|
||||
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 */
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (this->via_regs[VIA_ACR] & 0x10) { /* data transfer: Host --> Cuda */
|
||||
if (this->in_count < 16) {
|
||||
this->in_buf[this->in_count++] = this->via_regs[VIA_SR];
|
||||
assert_sr_int(); /* tell the system we've read the data */
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_F(WARNING, "Cuda input buffer exhausted! \n");
|
||||
}
|
||||
}
|
||||
else { /* data transfer: Cuda --> Host */
|
||||
} else { /* data transfer: Cuda --> Host */
|
||||
(this->*out_handler)();
|
||||
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 */
|
||||
void ViaCuda::null_out_handler()
|
||||
{
|
||||
void ViaCuda::null_out_handler() {
|
||||
this->via_regs[VIA_SR] = 0;
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
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++];
|
||||
}
|
||||
else if (this->is_open_ended) {
|
||||
} else if (this->is_open_ended) {
|
||||
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->*out_handler)();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_F(9, "Sending last byte");
|
||||
this->out_count = 0;
|
||||
this->via_regs[VIA_B] |= CUDA_TREQ; /* negate TREQ */
|
||||
@ -238,33 +220,30 @@ void ViaCuda::out_buf_handler()
|
||||
}
|
||||
}
|
||||
|
||||
void ViaCuda::response_header(uint32_t pkt_type, uint32_t pkt_flag)
|
||||
{
|
||||
this->out_buf[0] = pkt_type;
|
||||
this->out_buf[1] = pkt_flag;
|
||||
this->out_buf[2] = this->in_buf[1]; /* copy original cmd */
|
||||
this->out_count = 3;
|
||||
this->out_pos = 0;
|
||||
this->out_handler = &ViaCuda::out_buf_handler;
|
||||
void ViaCuda::response_header(uint32_t pkt_type, uint32_t pkt_flag) {
|
||||
this->out_buf[0] = pkt_type;
|
||||
this->out_buf[1] = pkt_flag;
|
||||
this->out_buf[2] = this->in_buf[1]; /* copy original cmd */
|
||||
this->out_count = 3;
|
||||
this->out_pos = 0;
|
||||
this->out_handler = &ViaCuda::out_buf_handler;
|
||||
this->next_out_handler = &ViaCuda::null_out_handler;
|
||||
this->is_open_ended = false;
|
||||
this->is_open_ended = false;
|
||||
}
|
||||
|
||||
void ViaCuda::error_response(uint32_t error)
|
||||
{
|
||||
this->out_buf[0] = CUDA_PKT_ERROR;
|
||||
this->out_buf[1] = error;
|
||||
this->out_buf[2] = this->in_buf[0];
|
||||
this->out_buf[3] = this->in_buf[1]; /* copy original cmd */
|
||||
this->out_count = 4;
|
||||
this->out_pos = 0;
|
||||
this->out_handler = &ViaCuda::out_buf_handler;
|
||||
void ViaCuda::error_response(uint32_t error) {
|
||||
this->out_buf[0] = CUDA_PKT_ERROR;
|
||||
this->out_buf[1] = error;
|
||||
this->out_buf[2] = this->in_buf[0];
|
||||
this->out_buf[3] = this->in_buf[1]; /* copy original cmd */
|
||||
this->out_count = 4;
|
||||
this->out_pos = 0;
|
||||
this->out_handler = &ViaCuda::out_buf_handler;
|
||||
this->next_out_handler = &ViaCuda::null_out_handler;
|
||||
this->is_open_ended = false;
|
||||
this->is_open_ended = false;
|
||||
}
|
||||
|
||||
void ViaCuda::process_packet()
|
||||
{
|
||||
void ViaCuda::process_packet() {
|
||||
if (this->in_count < 2) {
|
||||
LOG_F(ERROR, "Cuda: invalid packet (too few data)!\n");
|
||||
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)
|
||||
{
|
||||
int adb_dev = cmd_byte >> 4; //2 for keyboard, 3 for mouse
|
||||
int cmd = cmd_byte & 0xF;
|
||||
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 cmd = cmd_byte & 0xF;
|
||||
|
||||
if(!cmd) {
|
||||
if (!cmd) {
|
||||
LOG_F(9, "Cuda: ADB SendReset command requested\n");
|
||||
response_header(CUDA_PKT_ADB, 0);
|
||||
}
|
||||
else if (cmd == 1) {
|
||||
} else if (cmd == 1) {
|
||||
LOG_F(9, "Cuda: ADB Flush command requested\n");
|
||||
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");
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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");
|
||||
response_header(CUDA_PKT_ADB, 0);
|
||||
int adb_reg = cmd_byte & 0x3;
|
||||
if (adb_obj->talk(adb_dev, adb_reg, this->in_buf[2])) {
|
||||
response_header(CUDA_PKT_ADB, 0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
response_header(CUDA_PKT_ADB, 2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_F(ERROR, "Cuda: unsupported ADB command 0x%x \n", 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) {
|
||||
case CUDA_START_STOP_AUTOPOLL:
|
||||
if (this->in_buf[2]) {
|
||||
LOG_F(INFO, "Cuda: autopoll started, rate: %dms", this->poll_rate);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LOG_F(INFO, "Cuda: autopoll stopped");
|
||||
}
|
||||
response_header(CUDA_PKT_PSEUDO, 0);
|
||||
@ -371,8 +341,8 @@ void ViaCuda::pseudo_command(int cmd, int data_count)
|
||||
case CUDA_COMB_FMT_I2C:
|
||||
response_header(CUDA_PKT_PSEUDO, 0);
|
||||
if (this->in_count >= 5) {
|
||||
i2c_comb_transaction(this->in_buf[2], this->in_buf[3], this->in_buf[4],
|
||||
&this->in_buf[5], this->in_count - 5);
|
||||
i2c_comb_transaction(
|
||||
this->in_buf[2], this->in_buf[3], this->in_buf[4], &this->in_buf[5], this->in_count - 5);
|
||||
}
|
||||
break;
|
||||
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 */
|
||||
void ViaCuda::i2c_handler()
|
||||
{
|
||||
void ViaCuda::i2c_handler() {
|
||||
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,
|
||||
int in_bytes)
|
||||
{
|
||||
void ViaCuda::i2c_simple_transaction(uint8_t dev_addr, const uint8_t* in_buf, int in_bytes) {
|
||||
int op_type = dev_addr & 1; /* 0 - write to device, 1 - read from device */
|
||||
|
||||
dev_addr >>= 1; /* strip RD/WR bit */
|
||||
@ -415,16 +382,15 @@ void ViaCuda::i2c_simple_transaction(uint8_t dev_addr, const uint8_t* in_buf,
|
||||
}
|
||||
|
||||
if (op_type) { /* read request initiate an open ended transaction */
|
||||
this->curr_i2c_addr = dev_addr;
|
||||
this->out_handler = &ViaCuda::out_buf_handler;
|
||||
this->curr_i2c_addr = dev_addr;
|
||||
this->out_handler = &ViaCuda::out_buf_handler;
|
||||
this->next_out_handler = &ViaCuda::i2c_handler;
|
||||
this->is_open_ended = true;
|
||||
this->is_open_ended = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ViaCuda::i2c_comb_transaction(uint8_t dev_addr, uint8_t sub_addr,
|
||||
uint8_t dev_addr1, const uint8_t* in_buf, int in_bytes)
|
||||
{
|
||||
void ViaCuda::i2c_comb_transaction(
|
||||
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 */
|
||||
|
||||
if ((dev_addr & 0xFE) != (dev_addr1 & 0xFE)) {
|
||||
@ -460,9 +426,9 @@ void ViaCuda::i2c_comb_transaction(uint8_t dev_addr, uint8_t sub_addr,
|
||||
if (!op_type) { /* return dummy response for writes */
|
||||
LOG_F(WARNING, "Combined I2C - write request!");
|
||||
} else {
|
||||
this->curr_i2c_addr = dev_addr;
|
||||
this->out_handler = &ViaCuda::out_buf_handler;
|
||||
this->curr_i2c_addr = dev_addr;
|
||||
this->out_handler = &ViaCuda::out_buf_handler;
|
||||
this->next_out_handler = &ViaCuda::i2c_handler;
|
||||
this->is_open_ended = true;
|
||||
this->is_open_ended = true;
|
||||
}
|
||||
}
|
||||
|
@ -45,10 +45,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef VIACUDA_H
|
||||
#define VIACUDA_H
|
||||
|
||||
#include "hwcomponent.h"
|
||||
#include "nvram.h"
|
||||
#include "adb.h"
|
||||
#include "hwcomponent.h"
|
||||
#include "i2c.h"
|
||||
#include "nvram.h"
|
||||
|
||||
/** VIA register offsets. */
|
||||
enum {
|
||||
@ -88,14 +88,14 @@ enum {
|
||||
|
||||
/** Cuda pseudo commands. */
|
||||
enum {
|
||||
CUDA_START_STOP_AUTOPOLL = 0x01, /* start/stop device auto-polling */
|
||||
CUDA_READ_PRAM = 0x07, /* read parameter RAM */
|
||||
CUDA_WRITE_PRAM = 0x0C, /* write parameter RAM */
|
||||
CUDA_SET_AUTOPOLL_RATE = 0x14, /* set auto-polling rate */
|
||||
CUDA_GET_AUTOPOLL_RATE = 0x16, /* get auto-polling rate */
|
||||
CUDA_READ_WRITE_I2C = 0x22, /* read/write I2C device */
|
||||
CUDA_COMB_FMT_I2C = 0x25, /* combined format I2C transaction */
|
||||
CUDA_OUT_PB0 = 0x26, /* output one bit to Cuda's PB0 line */
|
||||
CUDA_START_STOP_AUTOPOLL = 0x01, /* start/stop device auto-polling */
|
||||
CUDA_READ_PRAM = 0x07, /* read parameter RAM */
|
||||
CUDA_WRITE_PRAM = 0x0C, /* write parameter RAM */
|
||||
CUDA_SET_AUTOPOLL_RATE = 0x14, /* set auto-polling rate */
|
||||
CUDA_GET_AUTOPOLL_RATE = 0x16, /* get auto-polling rate */
|
||||
CUDA_READ_WRITE_I2C = 0x22, /* read/write I2C device */
|
||||
CUDA_COMB_FMT_I2C = 0x25, /* combined format I2C transaction */
|
||||
CUDA_OUT_PB0 = 0x26, /* output one bit to Cuda's PB0 line */
|
||||
};
|
||||
|
||||
/** Cuda error codes. */
|
||||
@ -107,8 +107,7 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
class ViaCuda : public HWComponent, public I2CBus
|
||||
{
|
||||
class ViaCuda : public HWComponent, public I2CBus {
|
||||
public:
|
||||
ViaCuda();
|
||||
~ViaCuda();
|
||||
@ -134,7 +133,7 @@ private:
|
||||
int32_t out_pos;
|
||||
uint8_t poll_rate;
|
||||
|
||||
bool is_open_ended;
|
||||
bool is_open_ended;
|
||||
uint8_t curr_i2c_addr;
|
||||
|
||||
void (ViaCuda::*out_handler)(void);
|
||||
@ -150,7 +149,7 @@ private:
|
||||
void assert_sr_int();
|
||||
void write(uint8_t new_state);
|
||||
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 process_packet();
|
||||
void process_adb_command(uint8_t cmd_byte, int data_count);
|
||||
@ -162,8 +161,8 @@ private:
|
||||
|
||||
/* I2C related methods */
|
||||
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,
|
||||
const uint8_t* in_buf, int in_bytes);
|
||||
void i2c_comb_transaction(
|
||||
uint8_t dev_addr, uint8_t sub_addr, uint8_t dev_addr1, const uint8_t* in_buf, int in_bytes);
|
||||
};
|
||||
|
||||
#endif /* VIACUDA_H */
|
||||
|
@ -1,14 +1,13 @@
|
||||
#include "machinebase.h"
|
||||
#include "devices/hwcomponent.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include "machinebase.h"
|
||||
#include "devices/hwcomponent.h"
|
||||
|
||||
std::unique_ptr<MachineBase> gMachineObj = 0;
|
||||
|
||||
|
||||
MachineBase::MachineBase(std::string name)
|
||||
{
|
||||
MachineBase::MachineBase(std::string name) {
|
||||
this->name = name;
|
||||
|
||||
/* initialize internal maps */
|
||||
@ -17,9 +16,8 @@ MachineBase::MachineBase(std::string name)
|
||||
this->aliases.clear();
|
||||
}
|
||||
|
||||
MachineBase::~MachineBase()
|
||||
{
|
||||
for(auto it = this->comp_map.begin(); it != this->comp_map.end(); it++) {
|
||||
MachineBase::~MachineBase() {
|
||||
for (auto it = this->comp_map.begin(); it != this->comp_map.end(); it++) {
|
||||
delete it->second;
|
||||
}
|
||||
this->comp_map.clear();
|
||||
@ -27,8 +25,7 @@ MachineBase::~MachineBase()
|
||||
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)) {
|
||||
LOG_F(ERROR, "Component %s already exists!", name.c_str());
|
||||
return false;
|
||||
@ -39,8 +36,7 @@ bool MachineBase::add_component(std::string name, HWComponent *dev_obj)
|
||||
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)) {
|
||||
LOG_F(ERROR, "Subdevice %s already exists!", name.c_str());
|
||||
return false;
|
||||
@ -51,13 +47,11 @@ bool MachineBase::add_subdevice(std::string name, HWComponent *dev_obj)
|
||||
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;
|
||||
}
|
||||
|
||||
HWComponent *MachineBase::get_comp_by_name(std::string name)
|
||||
{
|
||||
HWComponent* MachineBase::get_comp_by_name(std::string name) {
|
||||
if (this->aliases.count(name)) {
|
||||
name = this->aliases[name];
|
||||
}
|
||||
@ -73,15 +67,14 @@ 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;
|
||||
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)) {
|
||||
comp_name = it->first;
|
||||
found = true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -90,10 +83,10 @@ HWComponent *MachineBase::get_comp_by_type(HWCompType type)
|
||||
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)) {
|
||||
comp_name = it->first;
|
||||
found = true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -27,27 +27,26 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#ifndef MACHINE_BASE_H
|
||||
#define MACHINE_BASE_H
|
||||
|
||||
#include "devices/hwcomponent.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "devices/hwcomponent.h"
|
||||
|
||||
class MachineBase
|
||||
{
|
||||
class MachineBase {
|
||||
public:
|
||||
MachineBase(std::string name);
|
||||
~MachineBase();
|
||||
|
||||
bool add_component(std::string name, HWComponent *dev_obj);
|
||||
bool add_subdevice(std::string name, HWComponent *dev_obj);
|
||||
bool add_component(std::string name, HWComponent* dev_obj);
|
||||
bool add_subdevice(std::string name, HWComponent* dev_obj);
|
||||
void add_alias(std::string name, std::string alias);
|
||||
HWComponent *get_comp_by_name(std::string name);
|
||||
HWComponent *get_comp_by_type(HWCompType type);
|
||||
HWComponent* get_comp_by_name(std::string name);
|
||||
HWComponent* get_comp_by_type(HWCompType type);
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::map<std::string, HWComponent *>comp_map;
|
||||
std::map<std::string, HWComponent *>subdev_map;
|
||||
std::map<std::string, HWComponent*> comp_map;
|
||||
std::map<std::string, HWComponent*> subdev_map;
|
||||
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
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include "memreadwrite.h"
|
||||
#include "machinefactory.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;
|
||||
|
||||
@ -43,61 +43,58 @@ using namespace std;
|
||||
or 0x30C064 (Nubus Macs).
|
||||
*/
|
||||
static const map<uint32_t, string> rom_identity = {
|
||||
{0x416C6368, "Performa 6400"}, //Alchemy
|
||||
{0x416C6368, "Performa 6400"}, // Alchemy
|
||||
//{"Come", "PowerBook 2400"}, //Comet
|
||||
{0x436F7264, "Power Mac 5200/6200 series"}, //Cordyceps
|
||||
{0x47617A65, "Power Mac 6500"}, //Gazelle
|
||||
{0x476F7373, "Power Mac G3 Beige"}, //Gossamer
|
||||
{0x436F7264, "Power Mac 5200/6200 series"}, // Cordyceps
|
||||
{0x47617A65, "Power Mac 6500"}, // Gazelle
|
||||
{0x476F7373, "Power Mac G3 Beige"}, // Gossamer
|
||||
{0x47525820, "PowerBook G3 Wallstreet"},
|
||||
//{"Hoop", "PowerBook 3400"}, //Hooper
|
||||
{0x50425820, "PowerBook Pre-G3"},
|
||||
{0x50444D20, "Nubus Power Mac or WGS"}, //Piltdown Man (6100/7100/8100)
|
||||
{0x50697020, "Bandai Pippin"}, //Pippin
|
||||
{0x50444D20, "Nubus Power Mac or WGS"}, // Piltdown Man (6100/7100/8100)
|
||||
{0x50697020, "Bandai Pippin"}, // Pippin
|
||||
//{"Powe", "Generic Power Mac"}, //PowerMac?
|
||||
//{"Spar", "20th Anniversay Mac"}, //Spartacus
|
||||
{0x544E5420, "Power Mac 7xxxx/8xxx series"}, //Trinitrotoluene :-)
|
||||
{0x5A616E7A, "Power Mac 4400/7220"}, //Zanzibar
|
||||
{0x544E5420, "Power Mac 7xxxx/8xxx series"}, // Trinitrotoluene :-)
|
||||
{0x5A616E7A, "Power Mac 4400/7220"}, // Zanzibar
|
||||
//{"????", "A clone, perhaps?"} //N/A (Placeholder ID)
|
||||
};
|
||||
|
||||
|
||||
int create_machine_for_id(uint32_t id)
|
||||
{
|
||||
switch(id) {
|
||||
case 0x476F7373:
|
||||
create_gossamer();
|
||||
break;
|
||||
default:
|
||||
LOG_F(ERROR, "Unknown machine ID: %X", id);
|
||||
return -1;
|
||||
int create_machine_for_id(uint32_t id) {
|
||||
switch (id) {
|
||||
case 0x476F7373:
|
||||
create_gossamer();
|
||||
break;
|
||||
default:
|
||||
LOG_F(ERROR, "Unknown machine ID: %X", id);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Read ROM file content and transfer it to the dedicated ROM region */
|
||||
void load_rom(ifstream& rom_file, uint32_t file_size)
|
||||
{
|
||||
unsigned char *sysrom_mem = new unsigned char[file_size];
|
||||
void load_rom(ifstream& rom_file, uint32_t file_size) {
|
||||
unsigned char* sysrom_mem = new unsigned char[file_size];
|
||||
|
||||
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 *>
|
||||
(gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
|
||||
MemCtrlBase* mem_ctrl = dynamic_cast<MemCtrlBase*>(
|
||||
gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL));
|
||||
|
||||
mem_ctrl->set_data(0xFFC00000, sysrom_mem, file_size);
|
||||
delete[] sysrom_mem;
|
||||
}
|
||||
|
||||
|
||||
int create_machine_for_rom(const char* rom_filepath)
|
||||
{
|
||||
int create_machine_for_rom(const char* rom_filepath) {
|
||||
ifstream rom_file;
|
||||
uint32_t file_size, config_info_offset, rom_id;
|
||||
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()) {
|
||||
LOG_F(ERROR, "Cound not open the specified ROM file.");
|
||||
rom_file.close();
|
||||
@ -108,7 +105,7 @@ int create_machine_for_rom(const char* rom_filepath)
|
||||
file_size = rom_file.tellg();
|
||||
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.");
|
||||
rom_file.close();
|
||||
return -1;
|
||||
@ -117,7 +114,7 @@ int create_machine_for_rom(const char* rom_filepath)
|
||||
/* read config info offset from file */
|
||||
config_info_offset = 0;
|
||||
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);
|
||||
|
||||
/* rewind to ConfigInfo.BootstrapVersion field */
|
||||
@ -135,8 +132,7 @@ int create_machine_for_rom(const char* rom_filepath)
|
||||
}
|
||||
|
||||
/* convert BootstrapVersion string to ROM ID */
|
||||
rom_id = (rom_id_str[5] << 24) | (rom_id_str[6] << 16) |
|
||||
(rom_id_str[7] << 8) | rom_id_str[8];
|
||||
rom_id = (rom_id_str[5] << 24) | (rom_id_str[6] << 16) | (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());
|
||||
|
||||
|
@ -24,33 +24,31 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
Author: Max Poliakovski
|
||||
*/
|
||||
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include "machinebase.h"
|
||||
#include "cpu/ppc/ppcemu.h"
|
||||
#include "devices/mpc106.h"
|
||||
#include "devices/atirage.h"
|
||||
#include "devices/machineid.h"
|
||||
#include "devices/macio.h"
|
||||
#include "devices/viacuda.h"
|
||||
#include "devices/mpc106.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)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
int create_gossamer()
|
||||
{
|
||||
int create_gossamer() {
|
||||
if (gMachineObj) {
|
||||
LOG_F(ERROR, "Global machine object not empty!");
|
||||
return -1;
|
||||
@ -66,17 +64,17 @@ int create_gossamer()
|
||||
gMachineObj->add_alias("Grackle", "PCI_Host");
|
||||
|
||||
/* 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 */
|
||||
gMachineObj->add_component("MachineID", new GossamerID(0x3d8c));
|
||||
grackle_obj->add_mmio_region(0xFF000004, 4096,
|
||||
dynamic_cast<MMIODevice *>(gMachineObj->get_comp_by_name("MachineID")));
|
||||
grackle_obj->add_mmio_region(
|
||||
0xFF000004, 4096, dynamic_cast<MMIODevice*>(gMachineObj->get_comp_by_name("MachineID")));
|
||||
|
||||
/* add the Heathrow I/O controller */
|
||||
gMachineObj->add_component("Heathrow", new HeathrowIC);
|
||||
grackle_obj->pci_register_device(16,
|
||||
dynamic_cast<PCIDevice *>(gMachineObj->get_comp_by_name("Heathrow")));
|
||||
grackle_obj->pci_register_device(
|
||||
16, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("Heathrow")));
|
||||
|
||||
/* allocate ROM region */
|
||||
if (!grackle_obj->add_rom_region(0xFFC00000, 0x400000)) {
|
||||
@ -85,14 +83,14 @@ int create_gossamer()
|
||||
}
|
||||
|
||||
/* configure RAM slots */
|
||||
setup_ram_slot("RAM_DIMM_1", 0x57, 64); /* RAM slot 1 -> 64MB by default */
|
||||
setup_ram_slot("RAM_DIMM_2", 0x56, 0); /* RAM slot 2 -> empty by default */
|
||||
setup_ram_slot("RAM_DIMM_3", 0x55, 0); /* RAM slot 3 -> empty by default */
|
||||
setup_ram_slot("RAM_DIMM_1", 0x57, 64); /* RAM slot 1 -> 64MB by default */
|
||||
setup_ram_slot("RAM_DIMM_2", 0x56, 0); /* RAM slot 2 -> empty by default */
|
||||
setup_ram_slot("RAM_DIMM_3", 0x55, 0); /* RAM slot 3 -> empty by default */
|
||||
|
||||
/* register ATI 3D Rage Pro video card with the PCI host bridge */
|
||||
gMachineObj->add_component("ATIRage", new ATIRage(ATI_RAGE_PRO_DEV_ID));
|
||||
grackle_obj->pci_register_device(18,
|
||||
dynamic_cast<PCIDevice *>(gMachineObj->get_comp_by_name("ATIRage")));
|
||||
grackle_obj->pci_register_device(
|
||||
18, dynamic_cast<PCIDevice*>(gMachineObj->get_comp_by_name("ATIRage")));
|
||||
|
||||
/* Init virtual CPU and request MPC750 CPU aka G3 */
|
||||
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/>.
|
||||
*/
|
||||
|
||||
//The main runfile - main.cpp
|
||||
//This is where the magic begins
|
||||
// The main runfile - main.cpp
|
||||
// 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 "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/loguru/loguru.hpp>
|
||||
|
||||
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 << "Written by divingkatae, (c) 2019. " << 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];
|
||||
cout << checker << endl;
|
||||
|
||||
if ((checker == "1") || (checker == "realtime") || \
|
||||
(checker == "-realtime") || (checker == "/realtime")) {
|
||||
if ((checker == "1") || (checker == "realtime") || (checker == "-realtime") ||
|
||||
(checker == "/realtime")) {
|
||||
loguru::g_stderr_verbosity = loguru::Verbosity_OFF;
|
||||
loguru::g_preamble_date = false;
|
||||
loguru::g_preamble_time = false;
|
||||
loguru::g_preamble_thread = false;
|
||||
loguru::init(argc, argv);
|
||||
loguru::add_file("dingusppc.log", loguru::Append, 0);
|
||||
//Replace the above line with this for maximum debugging detail:
|
||||
//loguru::add_file("dingusppc.log", loguru::Append, loguru::Verbosity_MAX);
|
||||
}
|
||||
else if ((checker == "debugger") || (checker == "/debugger") ||
|
||||
(checker == "-debugger")) {
|
||||
// Replace the above line with this for maximum debugging detail:
|
||||
// loguru::add_file("dingusppc.log", loguru::Append, loguru::Verbosity_MAX);
|
||||
} else if ((checker == "debugger") || (checker == "/debugger") || (checker == "-debugger")) {
|
||||
loguru::g_stderr_verbosity = 0;
|
||||
loguru::g_preamble_date = 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.close();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
while (std::getline(config_input, line)) {
|
||||
sin.str(line.substr(line.find("=") + 1));
|
||||
if (line.find("rompath") != std::string::npos) {
|
||||
sin >> rom_file;
|
||||
}
|
||||
else if (line.find("diskpath") != std::string::npos) {
|
||||
} else if (line.find("diskpath") != std::string::npos) {
|
||||
sin >> disk_file;
|
||||
}
|
||||
else if (line.find("ramsize") != std::string::npos) {
|
||||
} else if (line.find("ramsize") != std::string::npos) {
|
||||
sin >> ram_size;
|
||||
}
|
||||
else if (line.find("machine_gestalt") != std::string::npos) {
|
||||
} else if (line.find("machine_gestalt") != std::string::npos) {
|
||||
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;
|
||||
}
|
||||
else if (line.find("video_card") != std::string::npos) {
|
||||
} else if (line.find("video_card") != std::string::npos) {
|
||||
sin >> video_card_id;
|
||||
}
|
||||
sin.clear();
|
||||
@ -117,20 +107,18 @@ int main(int argc, char **argv)
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if (SDL_Init(SDL_INIT_AUDIO)){
|
||||
if (SDL_Init(SDL_INIT_AUDIO)) {
|
||||
LOG_F(ERROR, "SDL_Init error: %s", SDL_GetError());
|
||||
goto bail;
|
||||
}
|
||||
|
||||
if ((checker == "1") || (checker == "realtime") || \
|
||||
(checker == "-realtime") || (checker == "/realtime")) {
|
||||
if ((checker == "1") || (checker == "realtime") || (checker == "-realtime") ||
|
||||
(checker == "/realtime")) {
|
||||
ppc_exec();
|
||||
} else if ((checker == "debugger") || (checker == "/debugger") ||
|
||||
(checker == "-debugger")) {
|
||||
} else if ((checker == "debugger") || (checker == "/debugger") || (checker == "-debugger")) {
|
||||
enter_debugger();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
std::cout << " " << endl;
|
||||
std::cout << "Please enter one of the following commands when " << endl;
|
||||
std::cout << "booting up DingusPPC... " << endl;
|
||||
|
@ -5,102 +5,98 @@
|
||||
#ifndef MEM_READ_WRITE_H
|
||||
#define MEM_READ_WRITE_H
|
||||
|
||||
#include <cinttypes>
|
||||
#include "endianswap.h"
|
||||
#include <cinttypes>
|
||||
|
||||
/* 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) */
|
||||
#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) */
|
||||
#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) */
|
||||
#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) */
|
||||
#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) */
|
||||
#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) */
|
||||
#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) */
|
||||
#define READ_DWORD_BE_U(addr) (((addr)[0] << 24) | ((addr)[1] << 16) | \
|
||||
((addr)[2] << 8) | (addr)[3])
|
||||
#define READ_DWORD_BE_U(addr) (((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
|
||||
|
||||
/* read an unaligned big-endian QWORD (32bit) */
|
||||
#define READ_QWORD_BE_U(addr) (((addr)[0] << 56) | ((addr)[1] << 48) | \
|
||||
((addr)[2] << 40) | ((addr)[3] << 32) | \
|
||||
((addr)[4] << 24) | ((addr)[5] << 16) | \
|
||||
((addr)[6] << 8) | (addr)[7])
|
||||
#define READ_QWORD_BE_U(addr) \
|
||||
(((addr)[0] << 56) | ((addr)[1] << 48) | ((addr)[2] << 40) | ((addr)[3] << 32) | \
|
||||
((addr)[4] << 24) | ((addr)[5] << 16) | ((addr)[6] << 8) | (addr)[7])
|
||||
|
||||
/* 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) */
|
||||
#define READ_DWORD_LE_U(addr) (((addr)[3] << 24) | ((addr)[2] << 16) | \
|
||||
((addr)[1] << 8) | (addr)[0])
|
||||
#define READ_DWORD_LE_U(addr) (((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
|
||||
|
||||
/* read an unaligned little-endian DWORD (32bit) */
|
||||
#define READ_QWORD_LE_U(addr) (((addr)[7] << 56) | ((addr)[6] << 48) | \
|
||||
((addr)[5] << 40) | ((addr)[4] << 32) | \
|
||||
((addr)[3] << 24) | ((addr)[2] << 16) | \
|
||||
((addr)[1] << 8) | (addr)[0])
|
||||
#define READ_QWORD_LE_U(addr) \
|
||||
(((addr)[7] << 56) | ((addr)[6] << 48) | ((addr)[5] << 40) | ((addr)[4] << 32) | \
|
||||
((addr)[3] << 24) | ((addr)[2] << 16) | ((addr)[1] << 8) | (addr)[0])
|
||||
|
||||
|
||||
/* 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) */
|
||||
#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) */
|
||||
#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) */
|
||||
#define WRITE_WORD_BE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[1] = (val) & 0xFF; \
|
||||
} while(0)
|
||||
#define WRITE_WORD_BE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[1] = (val)&0xFF; \
|
||||
} while (0)
|
||||
|
||||
/* write an unaligned big-endian DWORD (32bit) */
|
||||
#define WRITE_DWORD_BE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = ((val) >> 24) & 0xFF; \
|
||||
(addr)[1] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[2] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[3] = (val) & 0xFF; \
|
||||
} while(0)
|
||||
#define WRITE_DWORD_BE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = ((val) >> 24) & 0xFF; \
|
||||
(addr)[1] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[2] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[3] = (val)&0xFF; \
|
||||
} while (0)
|
||||
|
||||
/* 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) */
|
||||
#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) */
|
||||
#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) */
|
||||
#define WRITE_WORD_LE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = (val) & 0xFF; \
|
||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||
} while(0)
|
||||
#define WRITE_WORD_LE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = (val)&0xFF; \
|
||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||
} while (0)
|
||||
|
||||
/* write an unaligned little-endian DWORD (32bit) */
|
||||
#define WRITE_DWORD_LE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = (val) & 0xFF; \
|
||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[2] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[3] = ((val) >> 24) & 0xFF; \
|
||||
} while(0)
|
||||
#define WRITE_DWORD_LE_U(addr, val) \
|
||||
do { \
|
||||
(addr)[0] = (val)&0xFF; \
|
||||
(addr)[1] = ((val) >> 8) & 0xFF; \
|
||||
(addr)[2] = ((val) >> 16) & 0xFF; \
|
||||
(addr)[3] = ((val) >> 24) & 0xFF; \
|
||||
} while (0)
|
||||
|
||||
#endif /* MEM_READ_WRITE_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user